Stephan Assmus wrote:
From your pictures and description, I don't understand which views exactlyare the problem. Could you post your code? You can also send it to me in private, if you prefer.
Basically the problem is that the view on top contains a single line of text and is expanding to fill all the available area, so everything is shoved to the bottom of the containing view.
I was hoping someone would have had a similar problem in the past and know how to point me in the right direction. I didn't want to post code because there's a lot of it.
Adding a GroupLayout to an existing container control: 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);The child controls are created on the fly, so in a loop I add them to the layout, but first I make the background red so I can see which controls are taking up all the space:
parameterView->SetViewColor(255,0,0); <snip> //view->AddChild(parameterView); viewLayout->AddView(parameterView); After the loop, I tried adding some glue, but it didn't help. viewLayout->AddItem(BSpaceLayoutItem::CreateGlue());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; 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); // Create the parameter views - but don't add them yet rect.OffsetTo(B_ORIGIN); rect.InsetBySelf(5, 5); 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; 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)); } //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; } view->ResizeTo(rect.left + 10, rect.bottom + 5); view->SetContentBounds(view->Bounds()); 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); } if (views.CountItems() > (titleView != NULL ? 1 : 0)) view->ResizeTo(rect.right + 5, rect.top + 5); // 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()); } } viewLayout->AddItem(BSpaceLayoutItem::CreateGlue()); view->SetContentBounds(view->Bounds()); 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) { 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; } } 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; } SeparatorView::SeparatorView(BRect frame) : BView(frame, "-", B_FOLLOW_NONE, B_WILL_DRAW) { 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)); }