Added a bit of layout management to the test views framework. The maximum
size of the view tested can now be overridden explicitly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21142 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
476d4befd7
commit
376d3e5804
@ -19,7 +19,9 @@
|
|||||||
|
|
||||||
// internal messages
|
// internal messages
|
||||||
enum {
|
enum {
|
||||||
MSG_2D_SLIDER_VALUE_CHANGED = '2dsv',
|
MSG_LAYOUT_CONTAINER = 'layc',
|
||||||
|
MSG_2D_SLIDER_VALUE_CHANGED = '2dsv',
|
||||||
|
MSG_UNLIMITED_MAX_SIZE_CHANGED = 'usch',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -35,12 +37,23 @@ operator+(const BPoint& p, const BSize& size)
|
|||||||
// View
|
// View
|
||||||
class View {
|
class View {
|
||||||
public:
|
public:
|
||||||
|
View()
|
||||||
|
: fFrame(0, 0, 0, 0),
|
||||||
|
fContainer(NULL),
|
||||||
|
fParent(NULL),
|
||||||
|
fChildren(),
|
||||||
|
fViewColor(B_TRANSPARENT_32_BIT),
|
||||||
|
fLayoutValid(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
View(BRect frame)
|
View(BRect frame)
|
||||||
: fFrame(frame),
|
: fFrame(frame),
|
||||||
fContainer(NULL),
|
fContainer(NULL),
|
||||||
fParent(NULL),
|
fParent(NULL),
|
||||||
fChildren(),
|
fChildren(),
|
||||||
fViewColor(B_TRANSPARENT_32_BIT)
|
fViewColor(B_TRANSPARENT_32_BIT),
|
||||||
|
fLayoutValid(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +74,12 @@ public:
|
|||||||
|
|
||||||
FrameChanged(oldFrame, frame);
|
FrameChanged(oldFrame, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// relayout if necessary
|
||||||
|
if (!fLayoutValid) {
|
||||||
|
Layout();
|
||||||
|
fLayoutValid = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BRect Frame() const
|
BRect Frame() const
|
||||||
@ -96,6 +115,26 @@ public:
|
|||||||
return Frame().Size();
|
return Frame().Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BSize(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize PreferredSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BAlignment Alignment()
|
||||||
|
{
|
||||||
|
return BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
BPoint LocationInContainer() const
|
BPoint LocationInContainer() const
|
||||||
{
|
{
|
||||||
BPoint location = fFrame.LeftTop();
|
BPoint location = fFrame.LeftTop();
|
||||||
@ -155,6 +194,7 @@ public:
|
|||||||
child->_AddedToParent(this);
|
child->_AddedToParent(this);
|
||||||
|
|
||||||
child->Invalidate();
|
child->Invalidate();
|
||||||
|
InvalidateLayout();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -177,6 +217,8 @@ public:
|
|||||||
child->_RemovingFromParent();
|
child->_RemovingFromParent();
|
||||||
fChildren.RemoveItem(index);
|
fChildren.RemoveItem(index);
|
||||||
|
|
||||||
|
InvalidateLayout();
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,6 +282,20 @@ public:
|
|||||||
Invalidate(Bounds());
|
Invalidate(Bounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void InvalidateLayout()
|
||||||
|
{
|
||||||
|
if (fLayoutValid) {
|
||||||
|
fLayoutValid = false;
|
||||||
|
if (fParent)
|
||||||
|
fParent->InvalidateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLayoutValid() const
|
||||||
|
{
|
||||||
|
return fLayoutValid;
|
||||||
|
}
|
||||||
|
|
||||||
void SetViewColor(rgb_color color)
|
void SetViewColor(rgb_color color)
|
||||||
{
|
{
|
||||||
fViewColor = color;
|
fViewColor = color;
|
||||||
@ -273,6 +329,13 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Layout()
|
||||||
|
{
|
||||||
|
// simply trigger relayouting the children
|
||||||
|
for (int32 i = 0; View* child = ChildAt(i); i++)
|
||||||
|
child->SetFrame(child->Frame());
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void _AddedToParent(View* parent)
|
virtual void _AddedToParent(View* parent)
|
||||||
{
|
{
|
||||||
@ -314,9 +377,6 @@ protected:
|
|||||||
|
|
||||||
void _Draw(BView* container, BRect updateRect)
|
void _Draw(BView* container, BRect updateRect)
|
||||||
{
|
{
|
||||||
//printf("%p->View::_Draw(): ", this);
|
|
||||||
//updateRect.PrintToStream();
|
|
||||||
|
|
||||||
// compute the clipping region
|
// compute the clipping region
|
||||||
BRegion region(Bounds());
|
BRegion region(Bounds());
|
||||||
for (int32 i = 0; View* child = ChildAt(i); i++)
|
for (int32 i = 0; View* child = ChildAt(i); i++)
|
||||||
@ -367,6 +427,7 @@ private:
|
|||||||
View* fParent;
|
View* fParent;
|
||||||
BList fChildren;
|
BList fChildren;
|
||||||
rgb_color fViewColor;
|
rgb_color fViewColor;
|
||||||
|
bool fLayoutValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -382,6 +443,34 @@ public:
|
|||||||
_AddedToContainer(this);
|
_AddedToContainer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void InvalidateLayout()
|
||||||
|
{
|
||||||
|
if (View::IsLayoutValid()) {
|
||||||
|
View::InvalidateLayout();
|
||||||
|
|
||||||
|
// trigger asynchronous re-layout
|
||||||
|
if (Window())
|
||||||
|
Window()->PostMessage(MSG_LAYOUT_CONTAINER, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case MSG_LAYOUT_CONTAINER:
|
||||||
|
View::Layout();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BView::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void AllAttached()
|
||||||
|
{
|
||||||
|
Window()->PostMessage(MSG_LAYOUT_CONTAINER, this);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void Draw(BRect updateRect)
|
virtual void Draw(BRect updateRect)
|
||||||
{
|
{
|
||||||
View::_Draw(this, updateRect);
|
View::_Draw(this, updateRect);
|
||||||
@ -587,8 +676,8 @@ private:
|
|||||||
// WrapperView
|
// WrapperView
|
||||||
class WrapperView : public View {
|
class WrapperView : public View {
|
||||||
public:
|
public:
|
||||||
WrapperView(BRect frame, BView* view)
|
WrapperView(BView* view)
|
||||||
: View(frame),
|
: View(),
|
||||||
fView(view),
|
fView(view),
|
||||||
fInsets(1, 1, 1, 1)
|
fInsets(1, 1, 1, 1)
|
||||||
{
|
{
|
||||||
@ -600,17 +689,17 @@ public:
|
|||||||
return fView;
|
return fView;
|
||||||
}
|
}
|
||||||
|
|
||||||
BSize MinSize() const
|
virtual BSize MinSize()
|
||||||
{
|
{
|
||||||
return _FromViewSize(fView->MinSize());
|
return _FromViewSize(fView->MinSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
BSize MaxSize() const
|
virtual BSize MaxSize()
|
||||||
{
|
{
|
||||||
return _FromViewSize(fView->MaxSize());
|
return _FromViewSize(fView->MaxSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
BSize PreferredSize() const
|
virtual BSize PreferredSize()
|
||||||
{
|
{
|
||||||
return _FromViewSize(fView->PreferredSize());
|
return _FromViewSize(fView->PreferredSize());
|
||||||
}
|
}
|
||||||
@ -673,13 +762,14 @@ private:
|
|||||||
// StringView
|
// StringView
|
||||||
class StringView : public View {
|
class StringView : public View {
|
||||||
public:
|
public:
|
||||||
StringView(BRect frame, const char* string)
|
StringView(const char* string)
|
||||||
: View(frame),
|
: View(),
|
||||||
fString(string),
|
fString(string),
|
||||||
fAlignment(B_ALIGN_LEFT),
|
fAlignment(B_ALIGN_LEFT),
|
||||||
fStringAscent(0),
|
fStringAscent(0),
|
||||||
fStringDescent(0),
|
fStringDescent(0),
|
||||||
fStringWidth(0)
|
fStringWidth(0),
|
||||||
|
fExplicitMinSize(B_SIZE_UNSET, B_SIZE_UNSET)
|
||||||
{
|
{
|
||||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
fTextColor = (rgb_color){ 0, 0, 0, 255 };
|
fTextColor = (rgb_color){ 0, 0, 0, 255 };
|
||||||
@ -691,6 +781,7 @@ public:
|
|||||||
|
|
||||||
_UpdateStringMetrics();
|
_UpdateStringMetrics();
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
InvalidateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetAlignment(alignment align)
|
void SetAlignment(alignment align)
|
||||||
@ -707,9 +798,19 @@ public:
|
|||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
BSize PreferredSize() const
|
virtual BSize MinSize()
|
||||||
{
|
{
|
||||||
return BSize(fStringWidth - 1, fStringAscent + fStringDescent - 1);
|
BSize size(fExplicitMinSize);
|
||||||
|
if (!size.IsWidthSet())
|
||||||
|
size.width = fStringWidth - 1;
|
||||||
|
if (!size.IsHeightSet())
|
||||||
|
size.height = fStringAscent + fStringDescent - 1;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetExplicitMinSize(BSize size)
|
||||||
|
{
|
||||||
|
fExplicitMinSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void AddedToContainer()
|
virtual void AddedToContainer()
|
||||||
@ -767,6 +868,511 @@ private:
|
|||||||
float fStringAscent;
|
float fStringAscent;
|
||||||
float fStringDescent;
|
float fStringDescent;
|
||||||
float fStringWidth;
|
float fStringWidth;
|
||||||
|
BSize fExplicitMinSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// CheckBox
|
||||||
|
class CheckBox : public View, public BInvoker {
|
||||||
|
public:
|
||||||
|
CheckBox(BMessage* message = NULL, BMessenger target = BMessenger())
|
||||||
|
: View(BRect(0, 0, 12, 12)),
|
||||||
|
BInvoker(message, target),
|
||||||
|
fSelected(false),
|
||||||
|
fPressed(false)
|
||||||
|
{
|
||||||
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSelected(bool selected)
|
||||||
|
{
|
||||||
|
if (selected != fSelected) {
|
||||||
|
fSelected = selected;
|
||||||
|
Invalidate();
|
||||||
|
|
||||||
|
// send the message
|
||||||
|
if (Message()) {
|
||||||
|
BMessage message(*Message());
|
||||||
|
message.AddBool("selected", IsSelected());
|
||||||
|
InvokeNotify(&message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSelected() const
|
||||||
|
{
|
||||||
|
return fSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BSize(12, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BView* container, BRect updateRect)
|
||||||
|
{
|
||||||
|
BRect rect(Bounds());
|
||||||
|
|
||||||
|
if (fPressed)
|
||||||
|
container->SetHighColor((rgb_color){ 120, 0, 0, 255 });
|
||||||
|
else
|
||||||
|
container->SetHighColor((rgb_color){ 0, 0, 0, 255 });
|
||||||
|
|
||||||
|
container->StrokeRect(rect);
|
||||||
|
|
||||||
|
if (fPressed ? fPressedSelected : fSelected) {
|
||||||
|
rect.InsetBy(2, 2);
|
||||||
|
container->StrokeLine(rect.LeftTop(), rect.RightBottom());
|
||||||
|
container->StrokeLine(rect.RightTop(), rect.LeftBottom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
if (fPressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fPressed = true;
|
||||||
|
fPressedSelected = fSelected;
|
||||||
|
_PressedUpdate(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseUp(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
if (!fPressed || (buttons & B_PRIMARY_MOUSE_BUTTON))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_PressedUpdate(where);
|
||||||
|
fPressed = false;
|
||||||
|
SetSelected(fPressedSelected);
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
if (!fPressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_PressedUpdate(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _PressedUpdate(BPoint where)
|
||||||
|
{
|
||||||
|
bool pressedSelected = Bounds().Contains(where) ^ fSelected;
|
||||||
|
if (pressedSelected != fPressedSelected) {
|
||||||
|
fPressedSelected = pressedSelected;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool fSelected;
|
||||||
|
bool fPressed;
|
||||||
|
bool fPressedSelected;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// GroupView
|
||||||
|
class GroupView : public View {
|
||||||
|
public:
|
||||||
|
GroupView(enum orientation orientation, int32 lineCount = 1)
|
||||||
|
: View(BRect(0, 0, 0, 0)),
|
||||||
|
fOrientation(orientation),
|
||||||
|
fLineCount(lineCount),
|
||||||
|
fColumnSpacing(0),
|
||||||
|
fRowSpacing(0),
|
||||||
|
fInsets(0, 0, 0, 0),
|
||||||
|
fMinMaxValid(false),
|
||||||
|
fColumnInfos(NULL),
|
||||||
|
fRowInfos(NULL)
|
||||||
|
{
|
||||||
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
|
||||||
|
if (fLineCount < 1)
|
||||||
|
fLineCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~GroupView()
|
||||||
|
{
|
||||||
|
delete fColumnInfos;
|
||||||
|
delete fRowInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSpacing(float horizontal, float vertical)
|
||||||
|
{
|
||||||
|
if (horizontal != fColumnSpacing || vertical != fRowSpacing) {
|
||||||
|
fColumnSpacing = horizontal;
|
||||||
|
fRowSpacing = vertical;
|
||||||
|
|
||||||
|
InvalidateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInsets(float left, float top, float right, float bottom)
|
||||||
|
{
|
||||||
|
BRect newInsets(left, top, right, bottom);
|
||||||
|
if (newInsets != fInsets) {
|
||||||
|
fInsets = newInsets;
|
||||||
|
InvalidateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
_ValidateMinMax();
|
||||||
|
return _AddInsetsAndSpacing(BSize(fMinWidth - 1, fMinHeight - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
_ValidateMinMax();
|
||||||
|
return _AddInsetsAndSpacing(BSize(fMaxWidth - 1, fMaxHeight - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize PreferredSize()
|
||||||
|
{
|
||||||
|
_ValidateMinMax();
|
||||||
|
return _AddInsetsAndSpacing(BSize(fPreferredWidth - 1,
|
||||||
|
fPreferredHeight - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BAlignment Alignment()
|
||||||
|
{
|
||||||
|
return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void Layout()
|
||||||
|
{
|
||||||
|
_ValidateMinMax();
|
||||||
|
// actually a little late already
|
||||||
|
|
||||||
|
BSize size = _SubtractInsetsAndSpacing(Size());
|
||||||
|
_LayoutLine(size.IntegerWidth() + 1, fColumnInfos, fColumnCount);
|
||||||
|
_LayoutLine(size.IntegerHeight() + 1, fRowInfos, fRowCount);
|
||||||
|
|
||||||
|
// layout children
|
||||||
|
BPoint location = fInsets.LeftTop();
|
||||||
|
for (int32 column = 0; column < fColumnCount; column++) {
|
||||||
|
LayoutInfo& columnInfo = fColumnInfos[column];
|
||||||
|
location.y = fInsets.top;
|
||||||
|
for (int32 row = 0; row < fRowCount; row++) {
|
||||||
|
View* child = _ChildAt(column, row);
|
||||||
|
if (!child)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// get the grid cell frame
|
||||||
|
BRect cellFrame(location,
|
||||||
|
BSize(columnInfo.size - 1, fRowInfos[row].size - 1));
|
||||||
|
|
||||||
|
// align the child frame in the grid cell
|
||||||
|
BRect childFrame = BLayoutUtils::AlignInFrame(cellFrame,
|
||||||
|
child->MaxSize(), child->Alignment());
|
||||||
|
|
||||||
|
// layout child
|
||||||
|
child->SetFrame(childFrame);
|
||||||
|
|
||||||
|
location.y += fRowInfos[row].size + fRowSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.x += columnInfo.size + fColumnSpacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct LayoutInfo {
|
||||||
|
int32 min;
|
||||||
|
int32 max;
|
||||||
|
int32 preferred;
|
||||||
|
int32 size;
|
||||||
|
|
||||||
|
LayoutInfo()
|
||||||
|
: min(0),
|
||||||
|
max(B_SIZE_UNLIMITED),
|
||||||
|
preferred(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddConstraints(float addMin, float addMax, float addPreferred)
|
||||||
|
{
|
||||||
|
if (addMin >= min)
|
||||||
|
min = (int32)addMin + 1;
|
||||||
|
if (addMax <= max)
|
||||||
|
max = (int32)addMax + 1;
|
||||||
|
if (addPreferred >= preferred)
|
||||||
|
preferred = (int32)addPreferred + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Normalize()
|
||||||
|
{
|
||||||
|
if (max > min)
|
||||||
|
max = min;
|
||||||
|
if (preferred < min)
|
||||||
|
preferred = min;
|
||||||
|
if (preferred > max)
|
||||||
|
preferred = max;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _ValidateMinMax()
|
||||||
|
{
|
||||||
|
if (fMinMaxValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
delete fColumnInfos;
|
||||||
|
delete fRowInfos;
|
||||||
|
|
||||||
|
fColumnCount = _ColumnCount();
|
||||||
|
fRowCount = _RowCount();
|
||||||
|
|
||||||
|
fColumnInfos = new LayoutInfo[fColumnCount];
|
||||||
|
fRowInfos = new LayoutInfo[fRowCount];
|
||||||
|
|
||||||
|
// collect the children's min/max constraints
|
||||||
|
for (int32 column = 0; column < fColumnCount; column++) {
|
||||||
|
for (int32 row = 0; row < fRowCount; row++) {
|
||||||
|
View* child = _ChildAt(column, row);
|
||||||
|
if (!child)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BSize min = child->MinSize();
|
||||||
|
BSize max = child->MaxSize();
|
||||||
|
BSize preferred = child->PreferredSize();
|
||||||
|
|
||||||
|
// apply constraints to column/row info
|
||||||
|
fColumnInfos[column].AddConstraints(min.width, max.width,
|
||||||
|
preferred.width);
|
||||||
|
fRowInfos[row].AddConstraints(min.height, max.height,
|
||||||
|
preferred.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize the column/row constraints and compute sum min/max
|
||||||
|
fMinWidth = 0;
|
||||||
|
fMinHeight = 0;
|
||||||
|
fMaxWidth = 0;
|
||||||
|
fMaxHeight = 0;
|
||||||
|
fPreferredWidth = 0;
|
||||||
|
fPreferredHeight = 0;
|
||||||
|
|
||||||
|
for (int32 column = 0; column < fColumnCount; column++) {
|
||||||
|
fColumnInfos[column].Normalize();
|
||||||
|
fMinWidth = BLayoutUtils::AddSizesInt32(fMinWidth,
|
||||||
|
fColumnInfos[column].min);
|
||||||
|
fMaxWidth = BLayoutUtils::AddSizesInt32(fMaxWidth,
|
||||||
|
fColumnInfos[column].max);
|
||||||
|
fPreferredWidth = BLayoutUtils::AddSizesInt32(fPreferredWidth,
|
||||||
|
fColumnInfos[column].preferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 row = 0; row < fRowCount; row++) {
|
||||||
|
fRowInfos[row].Normalize();
|
||||||
|
fMinHeight = BLayoutUtils::AddSizesInt32(fMinHeight,
|
||||||
|
fRowInfos[row].min);
|
||||||
|
fMaxHeight = BLayoutUtils::AddSizesInt32(fMaxHeight,
|
||||||
|
fRowInfos[row].max);
|
||||||
|
fPreferredHeight = BLayoutUtils::AddSizesInt32(fPreferredHeight,
|
||||||
|
fRowInfos[row].preferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
fMinMaxValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _LayoutLine(int32 size, LayoutInfo* infos, int32 infoCount)
|
||||||
|
{
|
||||||
|
BList infosToLayout;
|
||||||
|
for (int32 i = 0; i < infoCount; i++) {
|
||||||
|
infos[i].size = 0;
|
||||||
|
infosToLayout.AddItem(infos + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distribute the available space over the infos. Each iteration we
|
||||||
|
// try to distribute the remaining space evenly. We respect min and
|
||||||
|
// max constraints, though, add up the space we failed to assign
|
||||||
|
// due to the constraints, and use the sum as remaining space for the
|
||||||
|
// next iteration (can be negative). Then we ignore infos that can't
|
||||||
|
// shrink or grow anymore (depending on what would be needed).
|
||||||
|
while (!infosToLayout.IsEmpty()) {
|
||||||
|
BList canShrinkInfos;
|
||||||
|
BList canGrowInfos;
|
||||||
|
|
||||||
|
int32 sizeDiff = 0;
|
||||||
|
int32 infosToLayoutCount = infosToLayout.CountItems();
|
||||||
|
for (int32 i = 0; i < infosToLayoutCount; i++) {
|
||||||
|
LayoutInfo* info = (LayoutInfo*)infosToLayout.ItemAt(i);
|
||||||
|
info->size += (i + 1) * size / infosToLayoutCount
|
||||||
|
- i * size / infosToLayoutCount;
|
||||||
|
if (info->size < info->min) {
|
||||||
|
sizeDiff -= info->min - info->size;
|
||||||
|
info->size = info->min;
|
||||||
|
} else if (info->size > info->max) {
|
||||||
|
sizeDiff += info->size - info->max;
|
||||||
|
info->size = info->max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->size > info->min)
|
||||||
|
canShrinkInfos.AddItem(info);
|
||||||
|
if (info->size < info->max)
|
||||||
|
canGrowInfos.AddItem(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeDiff;
|
||||||
|
if (size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
infosToLayout = canGrowInfos;
|
||||||
|
else
|
||||||
|
infosToLayout = canShrinkInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If unassigned space is remaining, that means, that the group has
|
||||||
|
// been resized beyond its max size. We distribute the excess space
|
||||||
|
// evenly.
|
||||||
|
if (size > 0) {
|
||||||
|
for (int32 i = 0; i < infoCount; i++) {
|
||||||
|
infos[i].size += (i + 1) * size / infoCount
|
||||||
|
- i * size / infoCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize _AddInsetsAndSpacing(BSize size)
|
||||||
|
{
|
||||||
|
size.width = BLayoutUtils::AddDistances(size.width,
|
||||||
|
fInsets.left + fInsets.right - 1
|
||||||
|
+ (fColumnCount - 1) * fColumnSpacing);
|
||||||
|
size.height = BLayoutUtils::AddDistances(size.height,
|
||||||
|
fInsets.top + fInsets.bottom - 1
|
||||||
|
+ (fRowCount - 1) * fRowSpacing);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize _SubtractInsetsAndSpacing(BSize size)
|
||||||
|
{
|
||||||
|
size.width = BLayoutUtils::SubtractDistances(size.width,
|
||||||
|
fInsets.left + fInsets.right - 1
|
||||||
|
+ (fColumnCount - 1) * fColumnSpacing);
|
||||||
|
size.height = BLayoutUtils::SubtractDistances(size.height,
|
||||||
|
fInsets.top + fInsets.bottom - 1
|
||||||
|
+ (fRowCount - 1) * fRowSpacing);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 _RowCount() const
|
||||||
|
{
|
||||||
|
int32 childCount = CountChildren();
|
||||||
|
int32 count;
|
||||||
|
if (fOrientation == B_HORIZONTAL)
|
||||||
|
count = min_c(fLineCount, childCount);
|
||||||
|
else
|
||||||
|
count = (childCount + fLineCount - 1) / fLineCount;
|
||||||
|
|
||||||
|
return max_c(count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 _ColumnCount() const
|
||||||
|
{
|
||||||
|
int32 childCount = CountChildren();
|
||||||
|
int32 count;
|
||||||
|
if (fOrientation == B_HORIZONTAL)
|
||||||
|
count = (childCount + fLineCount - 1) / fLineCount;
|
||||||
|
else
|
||||||
|
count = min_c(fLineCount, childCount);
|
||||||
|
|
||||||
|
return max_c(count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
View* _ChildAt(int32 column, int32 row) const
|
||||||
|
{
|
||||||
|
if (fOrientation == B_HORIZONTAL)
|
||||||
|
return ChildAt(column * fLineCount + row);
|
||||||
|
else
|
||||||
|
return ChildAt(row * fLineCount + column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum orientation fOrientation;
|
||||||
|
int32 fLineCount;
|
||||||
|
float fColumnSpacing;
|
||||||
|
float fRowSpacing;
|
||||||
|
BRect fInsets;
|
||||||
|
bool fMinMaxValid;
|
||||||
|
int32 fMinWidth;
|
||||||
|
int32 fMinHeight;
|
||||||
|
int32 fMaxWidth;
|
||||||
|
int32 fMaxHeight;
|
||||||
|
int32 fPreferredWidth;
|
||||||
|
int32 fPreferredHeight;
|
||||||
|
LayoutInfo* fColumnInfos;
|
||||||
|
LayoutInfo* fRowInfos;
|
||||||
|
int32 fColumnCount;
|
||||||
|
int32 fRowCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Glue
|
||||||
|
class Glue : public View {
|
||||||
|
public:
|
||||||
|
Glue()
|
||||||
|
: View()
|
||||||
|
{
|
||||||
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Strut
|
||||||
|
class Strut : public View {
|
||||||
|
public:
|
||||||
|
Strut(float pixelWidth, float pixelHeight)
|
||||||
|
: View(),
|
||||||
|
fSize(pixelWidth >= 0 ? pixelWidth - 1 : B_SIZE_UNSET,
|
||||||
|
pixelHeight >= 0 ? pixelHeight - 1 : B_SIZE_UNSET)
|
||||||
|
{
|
||||||
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BLayoutUtils::ComposeSize(fSize, BSize(-1, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return BLayoutUtils::ComposeSize(fSize,
|
||||||
|
BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BSize fSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// HStrut
|
||||||
|
class HStrut : public Strut {
|
||||||
|
public:
|
||||||
|
HStrut(float width)
|
||||||
|
: Strut(width, -1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// VStrut
|
||||||
|
class VStrut : public Strut {
|
||||||
|
public:
|
||||||
|
VStrut(float height)
|
||||||
|
: Strut(-1, height)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -789,10 +1395,10 @@ public:
|
|||||||
view->SetViewColor((rgb_color){200, 200, 240, 255});
|
view->SetViewColor((rgb_color){200, 200, 240, 255});
|
||||||
|
|
||||||
// wrapper view
|
// wrapper view
|
||||||
fWrapperView = new WrapperView(BRect(10, 10, 100, 100),
|
fWrapperView = new WrapperView(
|
||||||
new BButton(BRect(0, 0, 9, 9), "test button", "Ooh, press me!",
|
new BButton(BRect(0, 0, 9, 9), "test button", "Ooh, press me!",
|
||||||
(BMessage*)NULL, B_FOLLOW_NONE));
|
(BMessage*)NULL, B_FOLLOW_NONE));
|
||||||
fWrapperView->GetView()->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
|
fWrapperView->SetLocation(BPoint(10, 10));
|
||||||
view->AddChild(fWrapperView);
|
view->AddChild(fWrapperView);
|
||||||
fWrapperView->SetSize(fWrapperView->PreferredSize());
|
fWrapperView->SetSize(fWrapperView->PreferredSize());
|
||||||
|
|
||||||
@ -804,78 +1410,58 @@ fWrapperView->GetView()->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIM
|
|||||||
|
|
||||||
_UpdateSliderConstraints();
|
_UpdateSliderConstraints();
|
||||||
|
|
||||||
// size labels
|
|
||||||
|
|
||||||
// min label
|
|
||||||
rect.top = rect.bottom + 10;
|
|
||||||
rect.bottom = rect.top + 10;
|
|
||||||
StringView* minLabel = new StringView(rect, "min: ");
|
|
||||||
minLabel->SetAlignment(B_ALIGN_RIGHT);
|
|
||||||
fViewContainer->View::AddChild(minLabel);
|
|
||||||
minLabel->SetSize(minLabel->PreferredSize());
|
|
||||||
BRect minFrame(minLabel->Frame());
|
|
||||||
|
|
||||||
// max label
|
|
||||||
rect = minFrame.OffsetToCopy(minFrame.LeftBottom() + BPoint(0, 8));
|
|
||||||
StringView* maxLabel = new StringView(rect, "max: ");
|
|
||||||
maxLabel->SetAlignment(B_ALIGN_RIGHT);
|
|
||||||
fViewContainer->View::AddChild(maxLabel);
|
|
||||||
maxLabel->SetSize(maxLabel->PreferredSize());
|
|
||||||
BRect maxFrame(maxLabel->Frame());
|
|
||||||
|
|
||||||
// preferred label
|
|
||||||
rect = maxFrame.OffsetToCopy(maxFrame.LeftBottom() + BPoint(0, 8));
|
|
||||||
StringView* preferredLabel = new StringView(rect, "preferred: ");
|
|
||||||
preferredLabel->SetAlignment(B_ALIGN_RIGHT);
|
|
||||||
fViewContainer->View::AddChild(preferredLabel);
|
|
||||||
preferredLabel->SetSize(preferredLabel->PreferredSize());
|
|
||||||
BRect preferredFrame(preferredLabel->Frame());
|
|
||||||
|
|
||||||
// preferred label
|
|
||||||
rect = preferredFrame.OffsetToCopy(preferredFrame.LeftBottom()
|
|
||||||
+ BPoint(0, 8));
|
|
||||||
StringView* currentLabel = new StringView(rect, "current: ");
|
|
||||||
currentLabel->SetAlignment(B_ALIGN_RIGHT);
|
|
||||||
fViewContainer->View::AddChild(currentLabel);
|
|
||||||
currentLabel->SetSize(currentLabel->PreferredSize());
|
|
||||||
BRect currentFrame(currentLabel->Frame());
|
|
||||||
|
|
||||||
float labelWidth = max_c(minFrame.Width(), maxFrame.Width());
|
|
||||||
labelWidth = max_c(labelWidth, preferredFrame.Width());
|
|
||||||
labelWidth = max_c(labelWidth, currentFrame.Width());
|
|
||||||
BSize labelSize(labelWidth, minLabel->Size().height);
|
|
||||||
minLabel->SetSize(labelSize);
|
|
||||||
maxLabel->SetSize(labelSize);
|
|
||||||
preferredLabel->SetSize(labelSize);
|
|
||||||
currentLabel->SetSize(labelSize);
|
|
||||||
|
|
||||||
// size views
|
// size views
|
||||||
|
GroupView* sizeViewsGroup = new GroupView(B_VERTICAL, 6);
|
||||||
|
sizeViewsGroup->SetSpacing(0, 8);
|
||||||
|
fViewContainer->View::AddChild(sizeViewsGroup);
|
||||||
|
|
||||||
// min
|
// min
|
||||||
_CreateSizeViews(minFrame.LeftTop() + BPoint(labelWidth + 1, 0),
|
_CreateSizeViews(sizeViewsGroup, "min: ", fMinWidthView,
|
||||||
fMinWidthView, fMinHeightView);
|
fMinHeightView);
|
||||||
|
|
||||||
// max
|
// max (with checkbox)
|
||||||
_CreateSizeViews(maxFrame.LeftTop() + BPoint(labelWidth + 1, 0),
|
GroupView* unlimitedMaxGroup = new GroupView(B_HORIZONTAL);
|
||||||
fMaxWidthView, fMaxHeightView);
|
fUnlimitedMaxSizeCheckBox = new CheckBox(
|
||||||
|
new BMessage(MSG_UNLIMITED_MAX_SIZE_CHANGED), this);
|
||||||
|
unlimitedMaxGroup->AddChild(fUnlimitedMaxSizeCheckBox);
|
||||||
|
unlimitedMaxGroup->AddChild(new StringView(" override"));
|
||||||
|
|
||||||
|
_CreateSizeViews(sizeViewsGroup, "max: ", fMaxWidthView,
|
||||||
|
fMaxHeightView, unlimitedMaxGroup);
|
||||||
|
|
||||||
// preferred
|
// preferred
|
||||||
_CreateSizeViews(preferredFrame.LeftTop() + BPoint(labelWidth + 1, 0),
|
_CreateSizeViews(sizeViewsGroup, "preferred: ", fPreferredWidthView,
|
||||||
fPreferredWidthView, fPreferredHeightView);
|
fPreferredHeightView);
|
||||||
|
|
||||||
// current
|
// current
|
||||||
_CreateSizeViews(currentFrame.LeftTop() + BPoint(labelWidth + 1, 0),
|
_CreateSizeViews(sizeViewsGroup, "current: ", fCurrentWidthView,
|
||||||
fCurrentWidthView, fCurrentHeightView);
|
fCurrentHeightView);
|
||||||
|
|
||||||
|
sizeViewsGroup->SetFrame(BRect(BPoint(rect.left, rect.bottom + 10),
|
||||||
|
sizeViewsGroup->PreferredSize()));
|
||||||
|
|
||||||
_UpdateSizeViews();
|
_UpdateSizeViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void DispatchMessage(BMessage* message, BHandler* handler)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case B_LAYOUT_WINDOW:
|
||||||
|
if (!fWrapperView->GetView()->IsLayoutValid()) {
|
||||||
|
_UpdateSliderConstraints();
|
||||||
|
_UpdateSizeViews();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BWindow::DispatchMessage(message, handler);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void MessageReceived(BMessage* message)
|
virtual void MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
switch (message->what) {
|
switch (message->what) {
|
||||||
case MSG_2D_SLIDER_VALUE_CHANGED:
|
case MSG_2D_SLIDER_VALUE_CHANGED:
|
||||||
{
|
{
|
||||||
// message->PrintToStream();
|
|
||||||
BPoint sliderLocation(fSliderView->Location());
|
BPoint sliderLocation(fSliderView->Location());
|
||||||
BPoint wrapperLocation(fWrapperView->Location());
|
BPoint wrapperLocation(fWrapperView->Location());
|
||||||
BSize size(sliderLocation.x - wrapperLocation.x - 1,
|
BSize size(sliderLocation.x - wrapperLocation.x - 1,
|
||||||
@ -885,6 +1471,16 @@ fWrapperView->GetView()->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIM
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MSG_UNLIMITED_MAX_SIZE_CHANGED:
|
||||||
|
if (fUnlimitedMaxSizeCheckBox->IsSelected()) {
|
||||||
|
fWrapperView->GetView()->SetExplicitMaxSize(
|
||||||
|
BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
|
||||||
|
} else {
|
||||||
|
fWrapperView->GetView()->SetExplicitMaxSize(
|
||||||
|
BSize(B_SIZE_UNSET, B_SIZE_UNSET));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BWindow::MessageReceived(message);
|
BWindow::MessageReceived(message);
|
||||||
break;
|
break;
|
||||||
@ -913,30 +1509,39 @@ private:
|
|||||||
fSliderView->SetLocationRange(minSliderLocation, maxSliderLocation);
|
fSliderView->SetLocationRange(minSliderLocation, maxSliderLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _CreateSizeViews(BPoint location, StringView*& widthView,
|
void _CreateSizeViews(View* group, const char* labelText,
|
||||||
StringView*& heightView)
|
StringView*& widthView, StringView*& heightView,
|
||||||
|
View* additionalView = NULL)
|
||||||
{
|
{
|
||||||
|
// label
|
||||||
|
StringView* label = new StringView(labelText);
|
||||||
|
label->SetAlignment(B_ALIGN_RIGHT);
|
||||||
|
group->AddChild(label);
|
||||||
|
|
||||||
// width view
|
// width view
|
||||||
BRect rect(location, location + BPoint(10, 10));
|
widthView = new StringView("9999999999.9");
|
||||||
widthView = new StringView(rect, "9999999999.9");
|
|
||||||
widthView->SetAlignment(B_ALIGN_RIGHT);
|
widthView->SetAlignment(B_ALIGN_RIGHT);
|
||||||
fViewContainer->View::AddChild(widthView);
|
group->AddChild(widthView);
|
||||||
widthView->SetSize(widthView->PreferredSize());
|
widthView->SetExplicitMinSize(widthView->PreferredSize());
|
||||||
|
|
||||||
// "," label
|
// "," label
|
||||||
rect = widthView->Frame();
|
StringView* labelView = new StringView(", ");
|
||||||
rect.OffsetTo(rect.RightTop() + BPoint(1, 0));
|
group->AddChild(labelView);
|
||||||
StringView* labelView = new StringView(rect, ", ");
|
|
||||||
fViewContainer->View::AddChild(labelView);
|
|
||||||
labelView->SetSize(labelView->PreferredSize());
|
|
||||||
|
|
||||||
// height view
|
// height view
|
||||||
rect = labelView->Frame();
|
heightView = new StringView("9999999999.9");
|
||||||
rect.OffsetTo(rect.RightTop() + BPoint(1, 0));
|
|
||||||
heightView = new StringView(rect, "9999999999.9");
|
|
||||||
heightView->SetAlignment(B_ALIGN_RIGHT);
|
heightView->SetAlignment(B_ALIGN_RIGHT);
|
||||||
fViewContainer->View::AddChild(heightView);
|
group->AddChild(heightView);
|
||||||
heightView->SetSize(heightView->PreferredSize());
|
heightView->SetExplicitMinSize(heightView->PreferredSize());
|
||||||
|
|
||||||
|
// spacing
|
||||||
|
group->AddChild(new HStrut(20));
|
||||||
|
|
||||||
|
// glue or unlimited max size check box
|
||||||
|
if (additionalView)
|
||||||
|
group->AddChild(additionalView);
|
||||||
|
else
|
||||||
|
group->AddChild(new Glue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _UpdateSizeView(StringView* view, float size)
|
void _UpdateSizeView(StringView* view, float size)
|
||||||
@ -980,6 +1585,7 @@ private:
|
|||||||
StringView* fPreferredHeightView;
|
StringView* fPreferredHeightView;
|
||||||
StringView* fCurrentWidthView;
|
StringView* fCurrentWidthView;
|
||||||
StringView* fCurrentHeightView;
|
StringView* fCurrentHeightView;
|
||||||
|
CheckBox* fUnlimitedMaxSizeCheckBox;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user