2 * Copyright 2007-2008, Christof Lutteroth, lutteroth@cs.auckland.ac.nz
3 * Copyright 2007-2008, James Kim, jkim202@ec.auckland.ac.nz
4 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
5 * Distributed under the terms of the MIT License.
11 #include <Alignment.h>
12 #include <ControlLook.h>
15 #include "ALMLayout.h"
16 #include "RowColumnManager.h"
21 using namespace LinearProgramming
;
32 * Gets the left tab of the area.
34 * @return the left tab of the area
44 * Gets the right tab of the area.
46 * @return the right tab of the area
56 * Gets the top tab of the area.
66 * Gets the bottom tab of the area.
76 * Sets the left tab of the area.
78 * @param left the left tab of the area
81 Area::SetLeft(BReference
<XTab
> left
)
85 fMinContentWidth
->SetLeftSide(-1.0, fLeft
, 1.0, fRight
);
86 if (fMaxContentWidth
!= NULL
)
87 fMaxContentWidth
->SetLeftSide(-1.0, fLeft
, 1.0, fRight
);
88 fRowColumnManager
->TabsChanged(this);
90 fLayoutItem
->Layout()->InvalidateLayout();
95 * Sets the right tab of the area.
97 * @param right the right tab of the area
100 Area::SetRight(BReference
<XTab
> right
)
104 fMinContentWidth
->SetLeftSide(-1.0, fLeft
, 1.0, fRight
);
105 if (fMaxContentWidth
!= NULL
)
106 fMaxContentWidth
->SetLeftSide(-1.0, fLeft
, 1.0, fRight
);
107 fRowColumnManager
->TabsChanged(this);
109 fLayoutItem
->Layout()->InvalidateLayout();
114 * Sets the top tab of the area.
117 Area::SetTop(BReference
<YTab
> top
)
121 fMinContentHeight
->SetLeftSide(-1.0, fTop
, 1.0, fBottom
);
122 if (fMaxContentHeight
!= NULL
)
123 fMaxContentHeight
->SetLeftSide(-1.0, fTop
, 1.0, fBottom
);
124 fRowColumnManager
->TabsChanged(this);
126 fLayoutItem
->Layout()->InvalidateLayout();
131 * Sets the bottom tab of the area.
134 Area::SetBottom(BReference
<YTab
> bottom
)
138 fMinContentHeight
->SetLeftSide(-1.0, fTop
, 1.0, fBottom
);
139 if (fMaxContentHeight
!= NULL
)
140 fMaxContentHeight
->SetLeftSide(-1.0, fTop
, 1.0, fBottom
);
141 fRowColumnManager
->TabsChanged(this);
143 fLayoutItem
->Layout()->InvalidateLayout();
148 * Gets the row that defines the top and bottom tabs.
158 * Gets the column that defines the left and right tabs.
161 Area::GetColumn() const
168 * The reluctance with which the area's content shrinks below its preferred size.
169 * The bigger the less likely is such shrinking.
172 Area::ShrinkPenalties() const
174 return fShrinkPenalties
;
179 * The reluctance with which the area's content grows over its preferred size.
180 * The bigger the less likely is such growth.
183 Area::GrowPenalties() const
185 return fGrowPenalties
;
190 Area::SetShrinkPenalties(BSize shrink
) {
191 fShrinkPenalties
= shrink
;
193 fLayoutItem
->Layout()->InvalidateLayout();
198 Area::SetGrowPenalties(BSize grow
)
200 fGrowPenalties
= grow
;
202 fLayoutItem
->Layout()->InvalidateLayout();
207 * Gets aspect ratio of the area's content.
210 Area::ContentAspectRatio() const
212 return fContentAspectRatio
;
217 * Sets aspect ratio of the area's content.
218 * May be different from the aspect ratio of the area.
221 Area::SetContentAspectRatio(double ratio
)
223 fContentAspectRatio
= ratio
;
224 if (fContentAspectRatio
<= 0) {
225 delete fContentAspectRatioC
;
226 fContentAspectRatioC
= NULL
;
227 } else if (fContentAspectRatioC
== NULL
) {
228 fContentAspectRatioC
= fLS
->AddConstraint(-1.0, fLeft
, 1.0, fRight
,
229 ratio
, fTop
, -ratio
, fBottom
, kEQ
, 0.0);
231 fContentAspectRatioC
->SetLeftSide(-1.0, fLeft
, 1.0, fRight
, ratio
,
232 fTop
, -ratio
, fBottom
);
234 /* called during BALMLayout::ItemUnarchived */
235 if (BLayout
* layout
= fLayoutItem
->Layout())
236 layout
->InvalidateLayout();
241 Area::GetInsets(float* left
, float* top
, float* right
, float* bottom
) const
244 *left
= fLeftTopInset
.Width();
246 *top
= fLeftTopInset
.Height();
248 *right
= fRightBottomInset
.Width();
250 *bottom
= fRightBottomInset
.Height();
255 * Gets left inset between area and its content.
258 Area::LeftInset() const
260 if (fLeftTopInset
.IsWidthSet())
261 return fLeftTopInset
.Width();
263 BALMLayout
* layout
= static_cast<BALMLayout
*>(fLayoutItem
->Layout());
264 return layout
->InsetForTab(fLeft
.Get());
269 * Gets top inset between area and its content.
272 Area::TopInset() const
274 if (fLeftTopInset
.IsHeightSet())
275 return fLeftTopInset
.Height();
277 BALMLayout
* layout
= static_cast<BALMLayout
*>(fLayoutItem
->Layout());
278 return layout
->InsetForTab(fTop
.Get());
283 * Gets right inset between area and its content.
286 Area::RightInset() const
288 if (fRightBottomInset
.IsWidthSet())
289 return fRightBottomInset
.Width();
291 BALMLayout
* layout
= static_cast<BALMLayout
*>(fLayoutItem
->Layout());
292 return layout
->InsetForTab(fRight
.Get());
297 * Gets bottom inset between area and its content.
300 Area::BottomInset() const
302 if (fRightBottomInset
.IsHeightSet())
303 return fRightBottomInset
.Height();
305 BALMLayout
* layout
= static_cast<BALMLayout
*>(fLayoutItem
->Layout());
306 return layout
->InsetForTab(fBottom
.Get());
311 Area::SetInsets(float insets
)
313 if (insets
!= B_SIZE_UNSET
)
314 insets
= BControlLook::ComposeSpacing(insets
);
316 fLeftTopInset
.Set(insets
, insets
);
317 fRightBottomInset
.Set(insets
, insets
);
318 fLayoutItem
->Layout()->InvalidateLayout();
323 Area::SetInsets(float horizontal
, float vertical
)
325 if (horizontal
!= B_SIZE_UNSET
)
326 horizontal
= BControlLook::ComposeSpacing(horizontal
);
327 if (vertical
!= B_SIZE_UNSET
)
328 vertical
= BControlLook::ComposeSpacing(vertical
);
330 fLeftTopInset
.Set(horizontal
, horizontal
);
331 fRightBottomInset
.Set(vertical
, vertical
);
332 fLayoutItem
->Layout()->InvalidateLayout();
337 Area::SetInsets(float left
, float top
, float right
, float bottom
)
339 if (left
!= B_SIZE_UNSET
)
340 left
= BControlLook::ComposeSpacing(left
);
341 if (right
!= B_SIZE_UNSET
)
342 right
= BControlLook::ComposeSpacing(right
);
343 if (top
!= B_SIZE_UNSET
)
344 top
= BControlLook::ComposeSpacing(top
);
345 if (bottom
!= B_SIZE_UNSET
)
346 bottom
= BControlLook::ComposeSpacing(bottom
);
348 fLeftTopInset
.Set(left
, top
);
349 fRightBottomInset
.Set(right
, bottom
);
350 fLayoutItem
->Layout()->InvalidateLayout();
355 * Sets left inset between area and its content.
358 Area::SetLeftInset(float left
)
360 fLeftTopInset
.width
= left
;
361 fLayoutItem
->Layout()->InvalidateLayout();
366 * Sets top inset between area and its content.
369 Area::SetTopInset(float top
)
371 fLeftTopInset
.height
= top
;
372 fLayoutItem
->Layout()->InvalidateLayout();
377 * Sets right inset between area and its content.
380 Area::SetRightInset(float right
)
382 fRightBottomInset
.width
= right
;
383 fLayoutItem
->Layout()->InvalidateLayout();
388 * Sets bottom inset between area and its content.
391 Area::SetBottomInset(float bottom
)
393 fRightBottomInset
.height
= bottom
;
394 fLayoutItem
->Layout()->InvalidateLayout();
399 Area::ToString() const
401 BString string
= "Area(";
402 string
+= fLeft
->ToString();
404 string
+= fTop
->ToString();
406 string
+= fRight
->ToString();
408 string
+= fBottom
->ToString();
415 * Sets the width of the area to be the same as the width of the given area
418 * @param area the area that should have the same width
419 * @return the same-width constraint
422 Area::SetWidthAs(Area
* area
, float factor
)
424 return fLS
->AddConstraint(-1.0, fLeft
, 1.0, fRight
, factor
, area
->Left(),
425 -factor
, area
->Right(), kEQ
, 0.0);
430 * Sets the height of the area to be the same as the height of the given area
433 * @param area the area that should have the same height
434 * @return the same-height constraint
437 Area::SetHeightAs(Area
* area
, float factor
)
439 return fLS
->AddConstraint(-1.0, fTop
, 1.0, fBottom
, factor
, area
->Top(),
440 -factor
, area
->Bottom(), kEQ
, 0.0);
445 Area::InvalidateSizeConstraints()
447 // check if if we are initialized
451 BSize minSize
= fLayoutItem
->MinSize();
452 BSize maxSize
= fLayoutItem
->MaxSize();
454 _UpdateMinSizeConstraint(minSize
);
455 _UpdateMaxSizeConstraint(maxSize
);
462 return BRect(round(fLeft
->Value()), round(fTop
->Value()),
463 round(fRight
->Value()), round(fBottom
->Value()));
469 * Removes the area from its specification.
473 delete fMinContentWidth
;
474 delete fMaxContentWidth
;
475 delete fMinContentHeight
;
476 delete fMaxContentHeight
;
477 delete fContentAspectRatioC
;
481 static int32 sAreaID
= 0;
492 * Uses XTabs and YTabs.
494 Area::Area(BLayoutItem
* item
)
504 fShrinkPenalties(5, 5),
505 fGrowPenalties(5, 5),
506 fContentAspectRatio(-1),
507 fRowColumnManager(NULL
),
508 fMinContentWidth(NULL
),
509 fMaxContentWidth(NULL
),
510 fMinContentHeight(NULL
),
511 fMaxContentHeight(NULL
),
512 fContentAspectRatioC(NULL
)
526 Area::SetID(int32 id
)
533 * Initialize variables.
536 Area::_Init(LinearSpec
* ls
, XTab
* left
, YTab
* top
, XTab
* right
, YTab
* bottom
,
537 RowColumnManager
* manager
)
545 fRowColumnManager
= manager
;
547 // adds the two essential constraints of the area that make sure that the
548 // left x-tab is really to the left of the right x-tab, and the top y-tab
549 // really above the bottom y-tab
550 fMinContentWidth
= ls
->AddConstraint(-1.0, fLeft
, 1.0, fRight
, kGE
, 0);
551 fMinContentHeight
= ls
->AddConstraint(-1.0, fTop
, 1.0, fBottom
, kGE
, 0);
553 InvalidateSizeConstraints();
558 Area::_Init(LinearSpec
* ls
, Row
* row
, Column
* column
, RowColumnManager
* manager
)
560 _Init(ls
, column
->Left(), row
->Top(), column
->Right(),
561 row
->Bottom(), manager
);
569 * Perform layout on the area.
572 Area::_DoLayout(const BPoint
& offset
)
574 // check if if we are initialized
578 if (!fLayoutItem
->IsVisible())
579 fLayoutItem
->AlignInFrame(BRect(0, 0, -1, -1));
581 BRect
areaFrame(Frame());
582 areaFrame
.left
+= LeftInset();
583 areaFrame
.right
-= RightInset();
584 areaFrame
.top
+= TopInset();
585 areaFrame
.bottom
-= BottomInset();
587 fLayoutItem
->AlignInFrame(areaFrame
.OffsetBySelf(offset
));
592 Area::_UpdateMinSizeConstraint(BSize min
)
594 if (!fLayoutItem
->IsVisible()) {
595 fMinContentHeight
->SetRightSide(-1);
596 fMinContentWidth
->SetRightSide(-1);
603 width
= min
.Width() + LeftInset() + RightInset();
605 height
= min
.Height() + TopInset() + BottomInset();
607 fMinContentWidth
->SetRightSide(width
);
608 fMinContentHeight
->SetRightSide(height
);
613 Area::_UpdateMaxSizeConstraint(BSize max
)
615 if (!fLayoutItem
->IsVisible()) {
616 if (fMaxContentHeight
!= NULL
)
617 fMaxContentHeight
->SetRightSide(B_SIZE_UNLIMITED
);
618 if (fMaxContentWidth
!= NULL
)
619 fMaxContentWidth
->SetRightSide(B_SIZE_UNLIMITED
);
623 max
.width
+= LeftInset() + RightInset();
624 max
.height
+= TopInset() + BottomInset();
626 const double kPriority
= 100;
627 // we only need max constraints if the alignment is full height/width
628 // otherwise we can just align the item in the free space
629 BAlignment alignment
= fLayoutItem
->Alignment();
630 double priority
= kPriority
;
631 if (alignment
.Vertical() == B_ALIGN_USE_FULL_HEIGHT
)
634 if (max
.Height() < 20000) {
635 if (fMaxContentHeight
== NULL
) {
636 fMaxContentHeight
= fLS
->AddConstraint(-1.0, fTop
, 1.0, fBottom
,
637 kLE
, max
.Height(), priority
, priority
);
639 fMaxContentHeight
->SetRightSide(max
.Height());
640 fMaxContentHeight
->SetPenaltyNeg(priority
);
641 fMaxContentHeight
->SetPenaltyPos(priority
);
644 delete fMaxContentHeight
;
645 fMaxContentHeight
= NULL
;
648 priority
= kPriority
;
649 if (alignment
.Horizontal() == B_ALIGN_USE_FULL_WIDTH
)
652 if (max
.Width() < 20000) {
653 if (fMaxContentWidth
== NULL
) {
654 fMaxContentWidth
= fLS
->AddConstraint(-1.0, fLeft
, 1.0, fRight
, kLE
,
655 max
.Width(), priority
, priority
);
657 fMaxContentWidth
->SetRightSide(max
.Width());
658 fMaxContentWidth
->SetPenaltyNeg(priority
);
659 fMaxContentWidth
->SetPenaltyPos(priority
);
662 delete fMaxContentWidth
;
663 fMaxContentWidth
= NULL
;