Skip to content

Commit

Permalink
Merge pull request #78 from beeware/min-width
Browse files Browse the repository at this point in the history
Add support for min_width/height attributes on layout nodes.
  • Loading branch information
mhsmith authored Aug 15, 2023
2 parents 9542c55 + fce167b commit 2740046
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 13 deletions.
1 change: 1 addition & 0 deletions changes/78.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Layout nodes can now track the minimum permitted layout size in addition to the current actual layout size.
12 changes: 12 additions & 0 deletions src/travertino/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ def _reset(self):
# layout *at all*.
self.visible = True

# Minimum width and height of the content box.
self.min_content_width = 0
self.min_content_height = 0

# Width and height of the content box.
self.content_width = 0
self.content_height = 0
Expand Down Expand Up @@ -108,10 +112,18 @@ def _origin_left(self, value):
def width(self):
return self._content_left + self.content_width + self.content_right

@property
def min_width(self):
return self._content_left + self.min_content_width + self.content_right

@property
def height(self):
return self._content_top + self.content_height + self.content_bottom

@property
def min_height(self):
return self._content_top + self.min_content_height + self.content_bottom

######################################################################
# Content box properties
######################################################################
Expand Down
107 changes: 94 additions & 13 deletions tests/test_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ class IntrinsicSize(BaseIntrinsicSize):
class Box(BaseBox):
pass

def layout(self, root, viewport):
# A simple layout scheme that allocats twice the viewport size.
root.layout.content_width = viewport.width * 2
root.layout.content_height = viewport.height * 2


class ViewportTests(TestCase):
def test_default(self):
Expand All @@ -40,24 +35,32 @@ def setUp(self):
self.maxDiff = None

self.grandchild1_1 = Node(style=Style())
self.grandchild1_1.layout.min_content_width = 5
self.grandchild1_1.layout.content_width = 10
self.grandchild1_1.layout.min_content_height = 8
self.grandchild1_1.layout.content_height = 16

self.grandchild1_2 = Node(style=Style())

self.child1 = Node(
style=Style(), children=[self.grandchild1_1, self.grandchild1_2]
)
self.child1.layout.min_content_width = 5
self.child1.layout.content_width = 10
self.child1.layout.min_content_height = 8
self.child1.layout.content_height = 16
self.child2 = Node(style=Style(), children=[])

self.node = Node(style=Style(), children=[self.child1, self.child2])
self.node.layout.min_content_width = 5
self.node.layout.content_width = 10
self.node.layout.min_content_height = 8
self.node.layout.content_height = 16

def assertLayout(self, box, expected):
actual = {
"origin": (box._origin_left, box._origin_top),
"min_size": (box.min_width, box.min_height),
"size": (box.width, box.height),
"content": (box.content_width, box.content_height),
"relative": (
Expand Down Expand Up @@ -86,6 +89,7 @@ def test_initial(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (5, 8),
"size": (10, 16),
"content": (10, 16),
"relative": (0, 0, 0, 0),
Expand All @@ -100,6 +104,7 @@ def test_set_content_top(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (5, 13),
"size": (10, 21),
"content": (10, 16),
"relative": (5, 0, 0, 0),
Expand All @@ -114,6 +119,7 @@ def test_set_content_top(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (5, 15),
"size": (10, 23),
"content": (10, 16),
"relative": (7, 0, 0, 0),
Expand All @@ -128,6 +134,7 @@ def test_set_content_left(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (10, 8),
"size": (15, 16),
"content": (10, 16),
"relative": (0, 0, 0, 5),
Expand All @@ -142,20 +149,52 @@ def test_set_content_left(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (12, 8),
"size": (17, 16),
"content": (10, 16),
"relative": (0, 0, 0, 7),
"absolute": (0, 17, 16, 7),
},
)

def test_set_min_content_width(self):
self.node.layout.min_content_width = 8

self.assertLayout(
self.node.layout,
{
"origin": (0, 0),
"min_size": (8, 8),
"size": (10, 16),
"content": (10, 16),
"relative": (0, 0, 0, 0),
"absolute": (0, 10, 16, 0),
},
)

# Set the min width to a new value
self.node.layout.min_content_width = 9

self.assertLayout(
self.node.layout,
{
"origin": (0, 0),
"min_size": (9, 8),
"size": (10, 16),
"content": (10, 16),
"relative": (0, 0, 0, 0),
"absolute": (0, 10, 16, 0),
},
)

def test_set_content_width(self):
self.node.layout.content_width = 5

self.assertLayout(
self.node.layout,
{
"origin": (0, 0),
"min_size": (5, 8),
"size": (5, 16),
"content": (5, 16),
"relative": (0, 0, 0, 0),
Expand All @@ -170,38 +209,71 @@ def test_set_content_width(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (5, 8),
"size": (7, 16),
"content": (7, 16),
"relative": (0, 0, 0, 0),
"absolute": (0, 7, 16, 0),
},
)

def test_set_min_content_height(self):
self.node.layout.min_content_height = 7

self.assertLayout(
self.node.layout,
{
"origin": (0, 0),
"min_size": (5, 7),
"size": (10, 16),
"content": (10, 16),
"relative": (0, 0, 0, 0),
"absolute": (0, 10, 16, 0),
},
)

# Set the min height to a new value
self.node.layout.min_content_height = 8

self.assertLayout(
self.node.layout,
{
"origin": (0, 0),
"min_size": (5, 8),
"size": (10, 16),
"content": (10, 16),
"relative": (0, 0, 0, 0),
"absolute": (0, 10, 16, 0),
},
)

def test_set_content_height(self):
self.node.layout.content_height = 5
self.node.layout.content_height = 10

self.assertLayout(
self.node.layout,
{
"origin": (0, 0),
"size": (10, 5),
"content": (10, 5),
"min_size": (5, 8),
"size": (10, 10),
"content": (10, 10),
"relative": (0, 0, 0, 0),
"absolute": (0, 10, 5, 0),
"absolute": (0, 10, 10, 0),
},
)

# Set the height to a new value
self.node.layout.content_height = 7
self.node.layout.content_height = 12

self.assertLayout(
self.node.layout,
{
"origin": (0, 0),
"size": (10, 7),
"content": (10, 7),
"min_size": (5, 8),
"size": (10, 12),
"content": (10, 12),
"relative": (0, 0, 0, 0),
"absolute": (0, 10, 7, 0),
"absolute": (0, 10, 12, 0),
},
)

Expand All @@ -219,6 +291,7 @@ def test_descendent_offsets(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (13, 15),
"size": (18, 23),
"content": (10, 16),
"relative": (7, 0, 0, 8),
Expand All @@ -230,6 +303,7 @@ def test_descendent_offsets(self):
self.child1.layout,
{
"origin": (8, 7),
"min_size": (15, 17),
"size": (20, 25),
"content": (10, 16),
"relative": (9, 0, 0, 10),
Expand All @@ -241,6 +315,7 @@ def test_descendent_offsets(self):
self.grandchild1_1.layout,
{
"origin": (18, 16),
"min_size": (17, 19),
"size": (22, 27),
"content": (10, 16),
"relative": (11, 0, 0, 12),
Expand All @@ -257,6 +332,7 @@ def test_descendent_offsets(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (13, 15),
"size": (18, 23),
"content": (10, 16),
"relative": (7, 0, 0, 8),
Expand All @@ -268,6 +344,7 @@ def test_descendent_offsets(self):
self.child1.layout,
{
"origin": (8, 7),
"min_size": (15, 17),
"size": (20, 25),
"content": (10, 16),
"relative": (9, 0, 0, 10),
Expand All @@ -279,6 +356,7 @@ def test_descendent_offsets(self):
self.grandchild1_1.layout,
{
"origin": (18, 16),
"min_size": (19, 21),
"size": (24, 29),
"content": (10, 16),
"relative": (13, 0, 0, 14),
Expand All @@ -295,6 +373,7 @@ def test_descendent_offsets(self):
self.node.layout,
{
"origin": (0, 0),
"min_size": (13, 15),
"size": (18, 23),
"content": (10, 16),
"relative": (7, 0, 0, 8),
Expand All @@ -306,6 +385,7 @@ def test_descendent_offsets(self):
self.child1.layout,
{
"origin": (8, 7),
"min_size": (21, 23),
"size": (26, 31),
"content": (10, 16),
"relative": (15, 0, 0, 16),
Expand All @@ -317,6 +397,7 @@ def test_descendent_offsets(self):
self.grandchild1_1.layout,
{
"origin": (24, 22),
"min_size": (19, 21),
"size": (24, 29),
"content": (10, 16),
"relative": (13, 0, 0, 14),
Expand Down

0 comments on commit 2740046

Please sign in to comment.