On 2009-03-31 at 19:20:39 [+0200], Sean Healy <jalopeura@xxxxxxxxxxx> wrote: > Here's that same code in the context of the function. I can't see that > any controls are being added outside of the layout system. > > BView * > DefaultMediaTheme::MakeViewFor(BParameterGroup& group, const BRect* > hintRect) > { > CALLED(); > > if (group.Flags() & B_HIDDEN_PARAMETER) > return NULL; > > BRect rect; > if (hintRect != NULL) > rect = *hintRect; You should probably ignore the hintRect now, when changing everything to use layouting. > GroupView *view = new GroupView(rect, group.Name()); > > BGroupLayout* viewLayout = new BGroupLayout(B_VERTICAL, 5); > viewLayout->SetInsets(5,5,5,5); > viewLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(5)); > view->SetLayout(viewLayout); I don't know what else GroupView does, but if it does nothing special, just replace this with BGroupView and get the layout via BGroupView::GroupLayout(); > // Create the parameter views - but don't add them yet > > rect.OffsetTo(B_ORIGIN); > rect.InsetBySelf(5, 5); ... no more BRect stuff. :-) > BList views; > for (int32 i = 0; i < group.CountParameters(); i++) { > BParameter *parameter = group.ParameterAt(i); > if (parameter == NULL) > continue; > > BView *parameterView = MakeSelfHostingViewFor(*parameter, > hintRect ? &rect : NULL); > if (parameterView == NULL) > continue; > parameterView->SetViewColor(view->ViewColor()); > parameterView->SetViewColor(255,0,0); > // ToDo: dunno why this is needed, but the controls // > sometimes (!) have a white background without it > > views.AddItem(parameterView); > } > > // Identify a title view, and add it at the top if present > > TitleView *titleView = dynamic_cast<TitleView *>((BView > *)views.ItemAt(0)); if (titleView != NULL) { > //view->AddChild(titleView); > viewLayout->AddView(titleView); > rect.OffsetBy(0, titleView->Bounds().Height()); > } > > // Add the sub-group views > > rect.right = rect.left + 20; > rect.bottom = rect.top + 20; Again, no more messing with rects... > float lastHeight = 0; > > for (int32 i = 0; i < group.CountGroups(); i++) { > BParameterGroup *subGroup = group.GroupAt(i); > if (subGroup == NULL) > continue; > > BView *groupView = MakeViewFor(*subGroup, &rect); > if (groupView == NULL) > continue; > > if (i > 0) { > // add separator view > BRect separatorRect(groupView->Frame()); > separatorRect.left -= 3; > separatorRect.right = separatorRect.left + 1; > if (lastHeight > separatorRect.Height()) > separatorRect.bottom = separatorRect.top + lastHeight; > > //view->AddChild(new SeparatorView(separatorRect)); > viewLayout->AddView(new SeparatorView(separatorRect)); You probably need to change SeparatorView to give it a layout-friendly constructor - ie, taking no BRect and using the no BRect-version of the BView constructor. This will change the resizing mode of the view to B_FOLLOW_NONE and the flags will include B_SUPPORTS_LAYOUT. > } > > //view->AddChild(groupView); > viewLayout->AddView(groupView); > > rect.OffsetBy(groupView->Bounds().Width() + 5, 0); > > lastHeight = groupView->Bounds().Height(); > if (lastHeight > rect.Height()) > rect.bottom = rect.top + lastHeight - 1; Skip all the BRect calculations. > } > > view->ResizeTo(rect.left + 10, rect.bottom + 5); > view->SetContentBounds(view->Bounds()); This should not be needed anymore. > if (group.CountParameters() == 0) > return view; > > // add the parameter views part of the group > > if (group.CountGroups() > 0) { > rect.top = rect.bottom + 10; > rect.bottom = rect.top + 20; > } > > bool center = false; > > for (int32 i = 0; i < views.CountItems(); i++) { > BView *parameterView = static_cast<BView *>(views.ItemAt(i)); > > if (parameterView->Bounds().Width() + 5 > rect.Width()) > rect.right = parameterView->Bounds().Width() + rect.left + 5; > > // we don't need to add the title view again > if (parameterView == titleView) > continue; > > // if there is a BChannelSlider (ToDo: or any vertical slider?) > // the views will be centered > if (dynamic_cast<BChannelSlider *>(parameterView) != NULL) > center = true; > > parameterView->MoveTo(parameterView->Frame().left, rect.top); > //view->AddChild(parameterView); > viewLayout->AddView(parameterView); > > rect.OffsetBy(0, parameterView->Bounds().Height() + 5); Again, remove all the rect calculations. BChannelSlider will need to be adopted to support layouting. This was somewhere on my TODO list, I could help you with that, if you want me to. :-) > } > > if (views.CountItems() > (titleView != NULL ? 1 : 0)) > view->ResizeTo(rect.right + 5, rect.top + 5); Again, should be removed. > // center the parameter views if needed, and tweak some views > > float width = view->Bounds().Width(); > > for (int32 i = 0; i < views.CountItems(); i++) { > BView *subView = static_cast<BView *>(views.ItemAt(i)); BRect > frame = subView->Frame(); > > if (center) > subView->MoveTo((width - frame.Width()) / 2, frame.top); > else { > // tweak the PopUp views to look better > if (dynamic_cast<BOptionPopUp *>(subView) != NULL) > subView->ResizeTo(width, frame.Height()); > } > } Remove all the above as well. > viewLayout->AddItem(BSpaceLayoutItem::CreateGlue()); > view->SetContentBounds(view->Bounds()); Content bounds will be automatically calculated, just remove that from GroupView, if you still need to use it at all. > return view; > } > > > The external functions that create the views return instances of > MenuFields, CheckBoxes, and StringControls, not custom controls. However, > here are the custom controls used in the function above: > > TitleView::TitleView(BRect frame, const char *title) > // : BView(frame, title, B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW) > // : BView(frame, title, 0, B_WILL_DRAW) > : BView(frame, title, 0, B_WILL_DRAW) Yep, do not use the BRect BView constructor. Just name and flags: : BView(title, B_WILL_DRAW) > { > fTitle = strdup(title); > SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); > SetLowColor(ViewColor()); > } > > > TitleView::~TitleView() > { > free((char *)fTitle); > } > > > void > TitleView::Draw(BRect updateRect) > { > BRect rect(Bounds()); > > SetDrawingMode(B_OP_COPY); > SetHighColor(240, 240, 240); > DrawString(fTitle, BPoint(rect.left + 1, rect.bottom - 8)); > > SetDrawingMode(B_OP_OVER); > SetHighColor(80, 20, 20); > DrawString(fTitle, BPoint(rect.left, rect.bottom - 9)); > } > > > void > TitleView::GetPreferredSize(float *_width, float *_height) { > if (_width) > *_width = StringWidth(fTitle) + 2; > > if (_height) { > font_height fontHeight; > GetFontHeight(&fontHeight); > > *_height = fontHeight.ascent + fontHeight.descent + > fontHeight.leading > + 8; > } > } You can probably just keep this, or you can replace that with MinSize(), MaxSize() and PreferredSize() implementations. But I believe the BView implementations fall back to using GetPreferredSize() anyways. > > > > > > > GroupView::GroupView(BRect frame, const char *name) > : BView(frame, name, B_FOLLOW_NONE, B_WILL_DRAW) > { > SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); > } > > > GroupView::~GroupView() > { > } > > > void > GroupView::AttachedToWindow() > { > for (int32 i = CountChildren(); i-- > 0;) { > BControl *control = dynamic_cast<BControl *>(ChildAt(i)); if > (control == NULL) > continue; > > control->SetTarget(control); > } > } > > > void > GroupView::AllAttached() > { > } > > > void > GroupView::GetPreferredSize(float *_width, float *_height) { > if (_width) > *_width = fContentBounds.Width(); > > if (_height) > *_height = fContentBounds.Height(); > } > > > BSize > GroupView::MinSize() > { > return BSize(100, 100); > } > > > BSize > GroupView::PreferredSize() > { > return MinSize(); > } > > > BSize > GroupView::MaxSize() > { > BSize max; > GetPreferredSize(&max.width, &max.height); > return max; > } > > > void > GroupView::SetContentBounds(BRect bounds) > { > fContentBounds = bounds; > } Ah yes. So it looks like you can simply remove GroupView and use BGroupView instead. > SeparatorView::SeparatorView(BRect frame) > : BView(frame, "-", B_FOLLOW_NONE, B_WILL_DRAW) Use the layout-friendly constructor here again. > { > fVertical = frame.Width() < frame.Height(); > SetViewColor(B_TRANSPARENT_COLOR); > } > > > SeparatorView::~SeparatorView() > { > } > > > void > SeparatorView::Draw(BRect updateRect) > { > rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR); BRect rect = > updateRect & Bounds(); > > SetHighColor(tint_color(color, B_DARKEN_1_TINT)); > if (fVertical) > StrokeLine(BPoint(0, rect.top), BPoint(0, rect.bottom)); > else > StrokeLine(BPoint(rect.left, 0), BPoint(rect.right, 0)); > > SetHighColor(tint_color(color, B_LIGHTEN_1_TINT)); if (fVertical) > StrokeLine(BPoint(1, rect.top), BPoint(1, rect.bottom)); > else > StrokeLine(BPoint(rect.left, 1), BPoint(rect.right, 1)); > } And you probably need to implement MinSize, PreferredSize() and MaxSize() again. Best regards, -Stephan