[haiku-development] Re: Layout problems
- From: Sean Healy <jalopeura@xxxxxxxxxxx>
- To: haiku-development@xxxxxxxxxxxxx
- Date: Tue, 31 Mar 2009 19:06:57 +0200
Stephan Assmus wrote:
From your pictures and description, I don't understand which views exactly
are 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));
}
Other related posts: