Skip to content

Commit

Permalink
Implement Flex.align_self (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshKarpel authored Jul 28, 2023
1 parent 21bfa08 commit 0dfecf1
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 7 deletions.
5 changes: 5 additions & 0 deletions codegen/generate_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@ def literal_vals(obj: object, field: str) -> tuple[str, ...]:

generated_lines.append("")

for a in literal_vals(Flex, "align_self"):
generated_lines.append(f'align_self_{a.replace("-", "_")} = Style(layout=Flex(align_self="{a}"))')

generated_lines.append("")

generated_lines.append("weight_none = Style(layout=Flex(weight=None))")
for n in N:
if n <= 0:
Expand Down
38 changes: 31 additions & 7 deletions reprisal/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def height(self) -> int:
class LayoutBox(ForbidExtras):
element: AnyElement
dims: BoxDimensions = Field(default_factory=BoxDimensions)
parent: LayoutBox | None
children: list[LayoutBox] = Field(default_factory=list)

def walk_from_bottom(self) -> Iterator[AnyElement]:
Expand Down Expand Up @@ -245,15 +246,34 @@ def first_pass(self) -> None:
self.dims.content.height = max(self.dims.content.height, child_box.dims.height())

def second_pass(self) -> None:
style = self.element.style
layout = style.layout
parent = self.parent

# TODO: positions

# TODO: align self
# handle align self
if layout.position == "relative" and parent:
if parent.element.style.layout.direction == "row":
match layout.align_self:
case "center":
self.dims.content.y += (parent.dims.content.height - self.dims.height()) // 2
case "end":
self.dims.content.y += parent.dims.content.height - self.dims.height()
case "stretch":
self.dims.content.height = parent.dims.content.height - self.dims.vertical_edge_width()
elif parent.element.style.layout.direction == "column":
match layout.align_self:
case "center":
self.dims.content.x += (parent.dims.content.width - self.dims.width()) // 2
case "end":
self.dims.content.x += parent.dims.content.width - self.dims.width()
case "stretch":
self.dims.content.width = parent.dims.content.width - self.dims.horizontal_edge_width()

# calculate available width for children, minus how much they use,
# then divide that between them based on the content justification
# We are in the parent, justifying the children!
style = self.element.style
layout = style.layout

available_width = self.dims.content.width
available_height = self.dims.content.height
Expand Down Expand Up @@ -415,6 +435,10 @@ def second_pass(self) -> None:
# alignment (cross-axis placement)
# content width/height of self, but full width/height of children
for child in relative_children:
# Skip children that will align themselves
if child.element.style.layout.align_self != "none":
continue

if layout.direction == "row":
if layout.align_children == "center":
# TODO: these floordivs aren't great
Expand All @@ -433,16 +457,16 @@ def second_pass(self) -> None:
child.dims.content.width = self.dims.content.width - child.dims.horizontal_edge_width()


def build_layout_tree(element: AnyElement) -> LayoutBox:
def build_layout_tree(element: AnyElement, parent: LayoutBox | None = None) -> LayoutBox:
if element.style.hidden:
raise Exception("Root element cannot have layout='hidden'")

children = []
box = LayoutBox(element=element, parent=parent)
for child in element.children:
if isinstance(child, Component):
raise Exception("Layout tree must be built from concrete Elements, not Components")

if not child.style.hidden == "hidden":
children.append(build_layout_tree(child))
box.children.append(build_layout_tree(element=child, parent=box))

return LayoutBox(element=element, children=children)
return box
1 change: 1 addition & 0 deletions reprisal/styles/styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ class Flex(StyleFragment):
"end",
"stretch",
] = "start"
align_self: Literal["none", "start", "center", "end", "stretch"] = "none"


class Style(StyleFragment):
Expand Down
6 changes: 6 additions & 0 deletions reprisal/styles/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,12 @@
align_children_end = Style(layout=Flex(align_children="end"))
align_children_stretch = Style(layout=Flex(align_children="stretch"))

align_self_none = Style(layout=Flex(align_self="none"))
align_self_start = Style(layout=Flex(align_self="start"))
align_self_center = Style(layout=Flex(align_self="center"))
align_self_end = Style(layout=Flex(align_self="end"))
align_self_stretch = Style(layout=Flex(align_self="stretch"))

weight_none = Style(layout=Flex(weight=None))
weight_1 = Style(layout=Flex(weight=1))
weight_2 = Style(layout=Flex(weight=2))
Expand Down

0 comments on commit 0dfecf1

Please sign in to comment.