Skip to content

Commit

Permalink
Merge pull request beeware#1778 from freakboy3742/containers
Browse files Browse the repository at this point in the history
Modify container handling for GTK
  • Loading branch information
mhsmith authored Feb 23, 2023
2 parents 9c960db + ae5e438 commit b851bc0
Show file tree
Hide file tree
Showing 23 changed files with 261 additions and 390 deletions.
1 change: 1 addition & 0 deletions changes/1778.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The mapping between Pack layout and HTML/CSS has been formalized.
6 changes: 5 additions & 1 deletion core/src/toga/style/applicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ class TogaApplicator:
def __init__(self, widget):
self.widget = widget

def refresh(self):
# print("RE-EVALUATE LAYOUT", self.widget)
self.widget.refresh()

def set_bounds(self):
# print("LAYOUT", self.widget, self.widget.layout)
# print("APPLY LAYOUT", self.widget, self.widget.layout)
self.widget._impl.set_bounds(
self.widget.layout.absolute_content_left,
self.widget.layout.absolute_content_top,
Expand Down
111 changes: 91 additions & 20 deletions core/src/toga/style/pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,15 @@ def apply(self, prop, value):
else:
value = LEFT
self._applicator.set_text_alignment(value)
if prop == "text_direction":
elif prop == "text_direction":
if self.text_align is None:
self._applicator.set_text_alignment(RIGHT if value == RTL else LEFT)
elif prop == "color":
self._applicator.set_color(value)
elif prop == "background_color":
self._applicator.set_background_color(value)
elif prop == "visibility":
hidden = False
if value == HIDDEN:
hidden = True
self._applicator.set_hidden(hidden)
self._applicator.set_hidden(value == HIDDEN)
elif prop in (
"font_family",
"font_size",
Expand All @@ -121,20 +118,24 @@ def apply(self, prop, value):
weight=self.font_weight,
)
)
else:
# Any other style change will cause a change in layout geometry,
# so perform a refresh.
self._applicator.refresh()

def layout(self, node, viewport):
# Precompute `scale_factor` by providing it as a default param.
def scale(value, scale_factor=viewport.dpi / viewport.baseline_dpi):
return int(value * scale_factor)

self._layout_node(node, viewport.width, viewport.height, scale)
node.layout.content_top = node.style.padding_top
node.layout.content_bottom = node.style.padding_bottom
self._layout_node(node, viewport.width, viewport.height, scale, root=True)
node.layout.content_top = scale(node.style.padding_top)
node.layout.content_bottom = scale(node.style.padding_bottom)

node.layout.content_left = node.style.padding_left
node.layout.content_right = node.style.padding_right
node.layout.content_left = scale(node.style.padding_left)
node.layout.content_right = scale(node.style.padding_right)

def _layout_node(self, node, alloc_width, alloc_height, scale):
def _layout_node(self, node, alloc_width, alloc_height, scale, root=False):
self.__class__._depth += 1
# self._debug("COMPUTE LAYOUT for", node, "available", alloc_width, alloc_height)

Expand Down Expand Up @@ -197,6 +198,11 @@ def _layout_node(self, node, alloc_width, alloc_height, scale):
node, available_width, available_height, scale
)

if root:
# self._debug("ROOT NODE")
width = max(width, available_width)
height = max(height, available_height)

else:
# self._debug("NO CHILDREN", available_width)
width = available_width
Expand Down Expand Up @@ -526,6 +532,52 @@ def _layout_column_children(self, node, available_width, available_height, scale

def __css__(self):
css = []
# display
if self.display == NONE:
css.append("display: none;")
else:
# if self.display != NONE, it must be pack; it will inherit
# the pack definition from the Toga stylesheet.
pass

# visibility
if self.visibility != VISIBLE:
css.append(f"visibility: {self.visibility}")

# direction
css.append(f"flex-direction: {self.direction.lower()};")

# alignment
if self.direction == ROW:
if self.alignment:
if self.alignment == LEFT:
css.append("align-items: start;")
elif self.alignment == RIGHT:
css.append("align-items: end;")
elif self.alignment == CENTER:
css.append("align-items: center;")
else:
if self.alignment:
if self.alignment == TOP:
css.append("align-items: start;")
elif self.alignment == BOTTOM:
css.append("align-items: end;")
elif self.alignment == CENTER:
css.append("align-items: center;")

# width/flex
if self.width:
css.append(f"width: {self.width}px;")
elif self.direction == ROW:
css.append(f"flex: {self.flex} 0 0;")

# height/flex
if self.height:
css.append(f"width: {self.width}px;")
elif self.direction == COLUMN:
css.append(f"flex: {self.flex} 0 0;")

# padding_*
if self.padding_top:
css.append(f"margin-top: {self.padding_top}px;")
if self.padding_bottom:
Expand All @@ -534,15 +586,34 @@ def __css__(self):
css.append(f"margin-left: {self.padding_left}px;")
if self.padding_right:
css.append(f"margin-right: {self.padding_right}px;")
if self.width:
css.append(f"width: {self.width}px;")
else:
if self.flex:
css.append(f"flex: {self.flex} 0 0%;")
else:
css.append("flex: 0 0 0%;")
if self.direction:
css.append(f"flex-direction: {self.direction.lower()};")

# color
if self.color:
css.append(f"color: {self.color};")

# background_color
if self.background_color:
css.append(f"background-color: {self.background_color};")

# text_align
if self.text_align:
css.append(f"text-align: {self.text_align}")

# text_direction
if self.text_direction != LTR:
css.append(f"text-direction: {self.text_direction}")

# font-*
if self.font_family != SYSTEM:
css.append(f"font-family: {self.font_family};")
if self.font_size != SYSTEM_DEFAULT_FONT_SIZE:
css.append(f"font-size: {self.font_size};")
if self.font_weight != NORMAL:
css.append(f"font-weight: {self.font_weight};")
if self.font_style != NORMAL:
css.append(f"font-style: {self.font_style};")
if self.font_variant != NORMAL:
css.append(f"font-variant: {self.font_variant};")

return " ".join(css)

Expand Down
4 changes: 3 additions & 1 deletion core/src/toga/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,9 @@ def refresh(self):
self._root.refresh()
else:
self.refresh_sublayouts()
super().refresh(self._impl.viewport)
# We can't compute a layout until we have a viewport
if self._impl.viewport:
super().refresh(self._impl.viewport)

def refresh_sublayouts(self):
for child in self.children:
Expand Down
6 changes: 3 additions & 3 deletions core/src/toga/widgets/optioncontainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,11 @@ def __init__(
# End backwards compatibility.
######################################################################

self._content = OptionList(self)
self._on_select = None
self._impl = self.factory.OptionContainer(interface=self)

self.on_select = on_select
self._content = OptionList(self)
if content:
for text, widget in content:
self.add(text, widget)
Expand All @@ -318,11 +318,11 @@ def __init__(

@property
def content(self):
"""The sub layouts of the `SplitContainer`.
"""The sub layouts of the `OptionContainer`.
Returns:
A OptionList ``list`` of :class:`~toga.OptionItem`. Each element of the list
is a sub layout of the `SplitContainer`
is a sub layout of the `OptionContainer`
Raises:
ValueError: If the list is less than two elements long.
Expand Down
Loading

0 comments on commit b851bc0

Please sign in to comment.