def test_layout_with_insets(self): layout = StackLayout() container = Frame(self.context, layout) container.bounds = Bounds(0, 0, 100, 100) child1 = Panel(self.context) child1.bounds = Bounds(10, 10, 20, 20) child1.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) child2 = Panel(self.context) child2.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) child2.preferred_size_override = Some(Dimension(80, 60)) container.add(child1) container.add(child2, fill=False) def test(padding: Insets): layout.padding = padding self.assertEqual(True, container.layout_pending) self.context.process() self.assertEqual(False, container.layout_pending) name = f"stack-{padding.top},{padding.right},{padding.bottom},{padding.left}" self.assertImage(name, self.context) for p in [ Insets(10, 10, 10, 10), Insets(15, 0, 15, 0), Insets(0, 10, 20, 0) ]: test(p)
def test_children(self): container = Container(self.context) children = [] rv.observe(container, "children").subscribe(children.append) child1 = Panel(self.context) child2 = Panel(self.context) self.assertEqual([()], children) container.add(child1) self.assertEqual((child1, ), container.children) self.assertEqual([(), (child1, )], children) container.add(child2) self.assertEqual((child1, child2), container.children) self.assertEqual([(), (child1, ), (child1, child2)], children) container.remove(child1) self.assertEqual((child2, ), container.children)
def setUp(self) -> None: super().setUp() self.container = Frame(self.context, AnchorLayout()) self.container.bounds = Bounds(0, 0, 100, 100) self.child = Panel(self.context) self.child.preferred_size_override = Some(Dimension(40, 30)) self.child.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1))
def test_items(self): layout = BorderLayout() container = Frame(self.context, layout) child1 = Panel(self.context) child2 = Panel(self.context) child3 = Panel(self.context) child4 = Panel(self.context) child5 = Panel(self.context) container.add(child1) container.add(child2, Border.Left) container.add(child3, Border.Top, Insets(2, 2, 2, 2)) container.add(child4, Border.Right, padding=Insets(5, 5, 5, 5)) container.add(child5, region=Border.Bottom, padding=Insets(10, 10, 10, 10)) def assert_item(item: BorderItem, child: Component, border: Border, padding: Insets) -> None: self.assertEqual(child, item.component.unwrap()) self.assertEqual(border, item.border) self.assertEqual(padding, item.padding) assert_item(layout.areas[Border.Center], child1, Border.Center, Insets(0, 0, 0, 0)) assert_item(layout.areas[Border.Top], child3, Border.Top, Insets(2, 2, 2, 2)) assert_item(layout.areas[Border.Right], child4, Border.Right, Insets(5, 5, 5, 5)) assert_item(layout.areas[Border.Bottom], child5, Border.Bottom, Insets(10, 10, 10, 10)) assert_item(layout.areas[Border.Left], child2, Border.Left, Insets(0, 0, 0, 0)) container.add(child1, Border.Right) container.remove(child2) container.remove(child3) assert_item(layout.areas[Border.Right], child1, Border.Right, Insets(0, 0, 0, 0)) # noinspection PyTypeChecker children = Fold.collect_all( map(lambda a: a.component, layout.areas.values()), Some( ())).unwrap() self.assertEqual({child5, child1}, set(children)) self.assertEqual(Nothing, layout.areas[Border.Top].component) self.assertEqual(Some(child1), layout.areas[Border.Right].component) self.assertEqual(Some(child5), layout.areas[Border.Bottom].component) self.assertEqual(Nothing, layout.areas[Border.Left].component)
def test_layout(self): container = Frame(self.context, AbsoluteLayout()) container.bounds = Bounds(30, 30, 200, 200) child1 = Panel(self.context) child1.bounds = Bounds(10, 10, 20, 20) child2 = Panel(self.context) child2.bounds = Bounds(50, 60, 20, 20) container.add(child1) container.add(child2) self.assertEqual(False, container.valid) self.context.process() self.assertEqual(True, container.valid) self.assertEqual(Bounds(10, 10, 20, 20), child1.bounds) self.assertEqual(Bounds(50, 60, 20, 20), child2.bounds) self.assertEqual(Dimension(0, 0), container.minimum_size) self.assertEqual(Dimension(0, 0), container.preferred_size) container.bounds = Bounds(20, 20, 100, 100) child1.minimum_size_override = Some(Dimension(400, 400)) child2.bounds = Bounds(-30, -40, 50, 50) self.assertEqual(False, container.valid) self.context.process() self.assertEqual(True, container.valid) self.assertEqual(Bounds(10, 10, 400, 400), child1.bounds) self.assertEqual(Bounds(-30, -40, 50, 50), child2.bounds) self.assertEqual(Dimension(0, 0), container.minimum_size)
def test_draw_children(self): window = Frame(self.context) window.bounds = Bounds(10, 20, 80, 60) window.set_color(StyleKeys.Background, RGBA(0.5, 0.5, 0.5, 1)) child1 = Panel(self.context) child1.bounds = Bounds(10, 10, 40, 40) child1.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) child2 = Panel(self.context) child2.bounds = Bounds(30, 30, 40, 40) child2.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) window.add(child1) window.add(child2) self.context.process() self.assertImage("draw_children", self.context)
def test_register_ui(self): laf = self.context.look_and_feel class CustomPanelUI(ComponentUI[Panel]): def draw(self, g: Graphics, component: T) -> None: pass laf.register_ui(Panel, CustomPanelUI) panel_ui = laf.create_ui(Panel(self.context)) container_ui = laf.create_ui(Container(self.context)) self.assertTrue(isinstance(panel_ui, CustomPanelUI)) self.assertFalse(isinstance(container_ui, CustomPanelUI))
def test_draw(self): self.context.look_and_feel.set_color("Panel.background", RGBA(0, 0, 1, 0.5)) window = Window(self.context) window.bounds = Bounds(0, 0, 100, 100) panel1 = Panel(self.context) panel1.bounds = Bounds(20, 20, 40, 60) panel2 = Panel(self.context) panel2.bounds = Bounds(50, 40, 40, 40) panel2.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) window.add(panel1) window.add(panel2) self.context.process() self.assertImage("draw", self.context)
def test_validation(self): container = Frame(self.context) container.bounds = Bounds(30, 30, 200, 200) child = Panel(self.context) child.bounds = Bounds(10, 10, 20, 20) container.validate() self.assertEqual(True, container.valid) container.add(child) self.assertEqual(False, container.valid) container.validate() child.bounds = Bounds(10, 10, 30, 30) self.assertEqual(False, container.valid) container.validate() child.preferred_size_override = Some(Dimension(60, 60)) self.assertEqual(False, container.valid) container.validate() child.minimum_size_override = Some(Dimension(10, 10)) self.assertEqual(False, container.valid) container.validate() child.visible = False self.assertEqual(False, container.valid) container.validate() container.remove(child) self.assertEqual(False, container.valid)
class AnchorLayoutTest(UITestCase): def setUp(self) -> None: super().setUp() self.container = Frame(self.context, AnchorLayout()) self.container.bounds = Bounds(0, 0, 100, 100) self.child = Panel(self.context) self.child.preferred_size_override = Some(Dimension(40, 30)) self.child.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) def test_no_anchor(self): self.context.process() self.assertImage("no-anchor", self.context) self.child.preferred_size_override = Some(Dimension(120, 130)) self.context.process() self.assertImage("no-anchor-over-sized", self.context) self.child.minimum_size_override = Some(Dimension(60, 40)) self.container.bounds = Bounds(0, 0, 50, 50) self.context.process() self.assertImage("no-anchor-min-size", self.context) def test_constraints(self): self.container.add(self.child, Anchor(Direction.Right, 15)) self.context.process() self.assertImage("constraints", self.context) self.container.add(self.child, Direction.Right, 15) self.context.process() self.assertImage("constraints", self.context) self.container.add(self.child, direction=Direction.Right, distance=15) self.context.process() self.assertImage("constraints", self.context) def test_edges(self): for direction in Direction: for distance in [0, 10]: prefix = f"edge-{direction.name}-{distance}" self._perform_test(prefix, self.container, self.child, Anchor(direction, distance)) def test_corners(self): corners = ( (Anchor(Direction.Top), Anchor(Direction.Right)), (Anchor(Direction.Right), Anchor(Direction.Bottom)), (Anchor(Direction.Left), Anchor(Direction.Bottom)), (Anchor(Direction.Left), Anchor(Direction.Top))) for (c1, c2) in corners: for distance in [0, 10]: prefix = f"corner-{c1.direction.name}-{c2.direction.name}-{distance}" self._perform_test( prefix, self.container, self.child, Anchor(c1.direction, distance), Anchor(c2.direction, distance)) def test_stretch(self): stretches = ((True, False), (False, True), (True, True)) for (horizontal, vertical) in stretches: for distance in [0, 10]: anchors = () if horizontal: name = "both" if vertical else "horizontal" anchors += (Anchor(Direction.Left, distance), Anchor(Direction.Right, distance)) else: name = "vertical" if vertical else "none" if vertical: anchors += (Anchor(Direction.Top, distance), Anchor(Direction.Bottom, distance)) prefix = f"stretch-{name}-{distance}" self._perform_test(prefix, self.container, self.child, *anchors) def test_stretch_three_corners(self): for direction in Direction: for distance in [0, 10]: anchors = [Anchor(d, distance) for d in Direction if d != direction] prefix = f"stretch-except-{direction.name}-{distance}" self._perform_test(prefix, self.container, self.child, *anchors) def _perform_test(self, prefix: str, parent: Container, child: Component, *anchors: Anchor): child.preferred_size_override = Some(Dimension(60, 40)) parent.add(child, *anchors) parent.bounds = Bounds(0, 0, 100, 100) self.context.process() self.assertImage(prefix, self.context) parent.bounds = Bounds(0, 0, 60, 60) self.context.process() self.assertImage(f"{prefix}-half-size", self.context) child.preferred_size_override = Some(Dimension(80, 60)) child.minimum_size_override = Some(Dimension(60, 30)) self.context.process() self.assertImage(f"{prefix}-min-size", self.context) parent.bounds = Bounds(0, 0, 100, 100) self.context.process() self.assertImage(f"{prefix}-pref-size", self.context)
def test_nested_layout(self): box = Frame(self.context, VBoxLayout()) box.bounds = Bounds(0, 0, 100, 100) child1 = Panel(self.context) child1.preferred_size_override = Some(Dimension(50, 20)) child1.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) box.add(child1) child2 = Panel(self.context, BorderLayout()) top = Panel(self.context) top.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) top.preferred_size_override = Some(Dimension(0, 20)) child2.add(top, Border.Top) right = Panel(self.context) right.set_color(StyleKeys.Background, RGBA(0, 1, 0, 1)) right.preferred_size_override = Some(Dimension(15, 0)) child2.add(right, Border.Right) bottom = Panel(self.context) bottom.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) bottom.preferred_size_override = Some(Dimension(0, 15)) child2.add(bottom, Border.Bottom) left = Panel(self.context) left.set_color(StyleKeys.Background, RGBA(1, 1, 1, 1)) left.preferred_size_override = Some(Dimension(5, 0)) child2.add(left, Border.Left) center = Panel(self.context) center.set_color(StyleKeys.Background, RGBA(0, 0, 0, 1)) center.preferred_size_override = Some(Dimension(60, 20)) child2.add(center, Border.Center) box.add(child2) child3 = Panel(self.context) child3.preferred_size_override = Some(Dimension(40, 20)) child3.minimum_size_override = Some(Dimension(20, 10)) child3.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) box.add(child3) self.assertEqual(True, box.layout_pending) self.context.process() self.assertEqual(False, box.layout_pending) self.assertImage("nested_layout", self.context) left.minimum_size_override = Some(Dimension(40, 0)) top.preferred_size_override = Some(Dimension(0, 10)) self.assertEqual(True, box.layout_pending) self.context.process() self.assertEqual(False, box.layout_pending) self.assertImage("nested_layout_resize_nested_child", self.context) bottom.visible = False self.assertEqual(True, box.layout_pending) self.context.process() self.assertEqual(False, box.layout_pending) self.assertImage("nested_layout_hide_nested_child", self.context)
def start(self, args: dict): from alleycat.ui.blender import UI self.context = UI().create_context() window = Frame(self.context, BorderLayout()) window.bounds = Bounds(160, 70, 280, 200) panel = Panel(self.context, HBoxLayout()) panel.set_color(StyleKeys.Background, RGBA(0.3, 0.3, 0.3, 0.8)) window.add(panel, padding=Insets(10, 10, 10, 10)) icon = Canvas(self.context, self.context.toolkit.images["cat.png"]) icon.minimum_size_override = Some(Dimension(64, 64)) panel.add(icon) label = Label(self.context, text_size=18) label.set_color(StyleKeys.Text, RGBA(1, 1, 1, 1)) panel.add(label) button1 = LabelButton(self.context, text_size=16, text="Button 1") button2 = LabelButton(self.context, text_size=16, text="Button 2") buttons = Panel(self.context, HBoxLayout(spacing=10, direction=BoxDirection.Reverse)) buttons.add(button2) buttons.add(button1) window.add(buttons, Border.Bottom, Insets(0, 10, 10, 10)) def handle_button(button: str): if len(button) > 0: label.text = f"{button} is pressed" panel.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) else: label.text = "" panel.set_color(StyleKeys.Background, RGBA(0.1, 0.1, 0.1, 0.8)) button1_active = button1.observe("active").pipe( ops.map(lambda v: "Button 1" if v else "")) button2_active = button2.observe("active").pipe( ops.map(lambda v: "Button 2" if v else "")) button_active = rx.combine_latest(button1_active, button2_active).pipe( ops.map(lambda v: v[0] + v[1])) button_active.subscribe(handle_button, on_error=self.context.error_handler) window.draggable = True window.resizable = True
def create_panel_ui(): return laf.create_ui(Panel(self.context))
def test_hbox_hide_child(self): container = Frame(self.context, HBoxLayout()) container.bounds = Bounds(0, 0, 100, 100) child1 = Panel(self.context) child1.preferred_size_override = Some(Dimension(20, 50)) child1.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) container.add(child1) child2 = Panel(self.context) child2.preferred_size_override = Some(Dimension(15, 60)) child2.minimum_size_override = Some(Dimension(15, 60)) child2.set_color(StyleKeys.Background, RGBA(0, 1, 0, 1)) container.add(child2) child3 = Panel(self.context) child3.preferred_size_override = Some(Dimension(30, 40)) child3.minimum_size_override = Some(Dimension(10, 20)) child3.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) container.add(child3) def test(visibility: Sequence[bool]): child1.visible = visibility[0] child2.visible = visibility[1] child3.visible = visibility[2] self.assertEqual(True, container.layout_pending) self.context.process() self.assertEqual(False, container.layout_pending) name = f"hbox-visibility-{'-'.join(map(str, visibility))}" self.assertImage(name, self.context) for v1 in [True, False]: for v2 in [True, False]: for v3 in [True, False]: test((v1, v2, v3))
def test_hbox_layout(self): layout = HBoxLayout() container = Frame(self.context, layout) container.bounds = Bounds(5, 5, 90, 90) child1 = Panel(self.context) child1.preferred_size_override = Some(Dimension(20, 50)) child1.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) container.add(child1) child2 = Panel(self.context) child2.preferred_size_override = Some(Dimension(15, 60)) child2.minimum_size_override = Some(Dimension(15, 60)) child2.set_color(StyleKeys.Background, RGBA(0, 1, 0, 1)) container.add(child2) child3 = Panel(self.context) child3.preferred_size_override = Some(Dimension(30, 40)) child3.minimum_size_override = Some(Dimension(10, 20)) child3.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) container.add(child3) def test(direction: BoxDirection, spacing: float, padding: Insets, align: BoxAlign): container.bounds = Bounds(5, 5, 90, 90) layout.spacing = spacing layout.padding = padding layout.align = align self.assertEqual(True, container.layout_pending) self.context.process() self.assertEqual(False, container.layout_pending) (top, right, bottom, left) = padding.tuple prefix = f"hbox-{direction.name}-{spacing}-{top},{right},{bottom},{left}-{align.name}-" self.assertImage(prefix + "full-size", self.context) container.bounds = Bounds(5, 5, 45, 45) self.assertEqual(True, container.layout_pending) self.context.process() self.assertEqual(False, container.layout_pending) self.assertImage(prefix + "half-size", self.context) for d in BoxDirection: for s in [0, 10]: for p in [Insets(0, 0, 0, 0), Insets(15, 20, 10, 5)]: for a in BoxAlign: test(d, s, p, a)
def create_container(self, areas: Set[Border]) -> Container: container = Frame(self.context, BorderLayout()) container.bounds = Bounds(5, 5, 90, 90) if Border.Top in areas: top = Panel(self.context) top.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) top.preferred_size_override = Some(Dimension(0, 20)) container.add(top, Border.Top) if Border.Right in areas: right = Panel(self.context) right.set_color(StyleKeys.Background, RGBA(0, 1, 0, 1)) right.preferred_size_override = Some(Dimension(15, 0)) container.add(right, Border.Right) if Border.Bottom in areas: bottom = Panel(self.context) bottom.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) bottom.preferred_size_override = Some(Dimension(0, 20)) container.add(bottom, Border.Bottom) if Border.Left in areas: left = Panel(self.context) left.set_color(StyleKeys.Background, RGBA(1, 1, 1, 1)) left.preferred_size_override = Some(Dimension(5, 0)) container.add(left, Border.Left) if Border.Center in areas: center = Panel(self.context) center.set_color(StyleKeys.Background, RGBA(0, 0, 0, 1)) container.add(center, Border.Center) return container
def test_layout(self): container = Frame(self.context, StackLayout()) container.bounds = Bounds(0, 0, 100, 100) child1 = Panel(self.context) child1.bounds = Bounds(10, 10, 20, 20) child1.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) child2 = Panel(self.context) child2.set_color(StyleKeys.Background, RGBA(0, 0, 1, 1)) child2.preferred_size_override = Some(Dimension(80, 60)) child3 = Panel(self.context) child3.set_color(StyleKeys.Background, RGBA(0, 1, 0, 1)) child3.preferred_size_override = Some(Dimension(60, 40)) container.add(child1) container.add(child2, fill=False) container.add(child3, False) self.context.process() self.assertImage("stack", self.context) child4 = Panel(self.context) child4.set_color(StyleKeys.Background, RGBA(0, 1, 1, 1)) container.add(child4, fill=True) self.context.process() self.assertImage("stack-fill", self.context) container.add(child3, True) self.context.process() self.assertImage("stack-fill2", self.context)