def test_draw_with_padding(self): image = self.context.toolkit.images[FixturePath] window = Frame(self.context) window.bounds = Bounds(0, 0, 100, 100) canvas = Canvas(self.context, image) canvas.set_color(StyleKeys.Background, RGBA(1, 0, 0, 1)) window.add(canvas) def assert_padding(size: Dimension, padding: Insets): (w, h) = size.tuple (top, right, bottom, left) = padding.tuple canvas.bounds = Bounds(0, 0, w, h) canvas.padding = padding self.context.process() self.assertImage( f"draw_with_padding-{top},{right},{bottom},{left}-{w}x{h}", self.context, tolerance=Tolerance) assert_padding(Dimension(100, 100), Insets(0, 0, 0, 0)) assert_padding(Dimension(100, 100), Insets(10, 5, 3, 15)) assert_padding(Dimension(64, 64), Insets(0, 0, 0, 0)) assert_padding(Dimension(64, 64), Insets(10, 5, 3, 15))
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_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 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 test_style(lookup: StyleLookup): canvas.validate() lookup.set_insets("NonExistentKey", Insets(10, 10, 10, 10)) self.assertEqual(True, canvas.valid) canvas.validate() lookup.set_insets(StyleKeys.Padding, Insets(10, 10, 10, 10)) self.assertEqual(False, canvas.valid)
def test_insets_init(self): self.assertEqual(5, Insets(5, 10, 120, 0).top) self.assertEqual(30, Insets(15, 30, 0, 30.5).right) self.assertEqual(120, Insets(5, 10, 120, 0).bottom) self.assertEqual(30.5, Insets(15, 30, 0, 30.5).left) with self.assertRaises(ValueError) as cm_top: Insets(-10, 0, 10, 30) self.assertEqual("Argument 'top' must be zero or a positive number.", cm_top.exception.args[0]) with self.assertRaises(ValueError) as cm_right: Insets(20, -1, 10, 0) self.assertEqual("Argument 'right' must be zero or a positive number.", cm_right.exception.args[0]) with self.assertRaises(ValueError) as cm_bottom: Insets(5, 0, -15, 30) self.assertEqual( "Argument 'bottom' must be zero or a positive number.", cm_bottom.exception.args[0]) with self.assertRaises(ValueError) as cm_left: Insets(0, 0, 40, -30) self.assertEqual("Argument 'left' must be zero or a positive number.", cm_left.exception.args[0])
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 draw_component(self, g: Graphics, component: Canvas) -> None: super().draw_component(g, component) if component.image == Nothing: return image = component.image.unwrap() padding = component.resolve_insets(StyleKeys.Padding).value_or( Insets(0, 0, 0, 0)) + component.padding (x, y, w, h) = component.bounds.tuple bounds = Bounds(x + padding.left, y + padding.top, max(w - padding.left - padding.right, 0), max(h - padding.top - padding.bottom, 0)) (iw, ih) = image.size.tuple (w, h) = bounds.size.tuple if iw == 0 or ih == 0 or w == 0 or h == 0: return (x, y) = bounds.location.tuple sw = w / iw sh = h / ih sx = x / sw sy = y / sh g.scale(sw, sh) g.set_source_surface(image.surface, sx, sy) g.paint()
def draw_text(self, g: Graphics, component: Label, font: FontFace, color: RGBA) -> None: text = component.text size = component.text_size extents = component.context.toolkit.fonts.text_extent(text, font, size) padding = component.resolve_insets(StyleKeys.Padding).value_or( Insets(0, 0, 0, 0)) (x, y, w, h) = component.bounds.tuple rh = self._ratio_for_align[component.text_align] rv = self._ratio_for_align[component.text_vertical_align] tx = (w - extents.width - padding.left - padding.right) * rh + x + padding.left ty = (h - extents.height - padding.top - padding.bottom) * rv + extents.height + y + padding.top g.set_font_face(font) g.set_font_size(size) # FIXME: Temporary workaround until we get a better way of handling text shadows. if component.shadow: g.move_to(tx + 1, ty + 1) g.set_source_rgba(0, 0, 0, 0.8) g.show_text(text) g.move_to(tx, ty) g.set_source_rgba(color.r, color.g, color.b, color.a) g.show_text(text)
def test_style(lookup: StyleLookup): button.validate() lookup.set_font("NonExistentKey", fonts["Font1"]) lookup.set_insets("NonExistentKey", Insets(10, 10, 10, 10)) self.assertEqual(True, button.valid) lookup.set_font(StyleKeys.Text, fonts["Font1"]) self.assertEqual(False, button.valid) button.validate() lookup.set_insets(StyleKeys.Padding, Insets(10, 10, 10, 10)) self.assertEqual(False, button.valid)
def test_insets_unpack(self): (top, right, bottom, left) = Insets(10, 30, 5, 20) self.assertEqual(10, top) self.assertEqual(30, right) self.assertEqual(5, bottom) self.assertEqual(20, left)
def test_insets_copy(self): self.assertEqual(Insets(15, 20, 0, 30), Insets(15, 10, 30, 30).copy(right=20, bottom=0)) self.assertEqual(Insets(20, 10, 0, 30), Insets(10, 10, 0, 10).copy(top=20, left=30)) self.assertEqual( Insets(5, 10, 0, 30), Insets(0, 0, 20, 40).copy(top=5, right=10, bottom=0, left=30)) self.assertEqual(Insets(20, 10, 5, 30), Insets(20, 10, 5, 30).copy())
def __init__(self, context: Context, image: Optional[Image] = None, padding: Insets = Insets(0, 0, 0, 0), visible: bool = True) -> None: self.image = Maybe.from_optional(image) self.padding = padding super().__init__(context, visible)
def test_on_style_change(self): lookup = StyleLookup() changes = [] lookup.on_style_change.subscribe(changes.append) self.assertEqual([], changes) lookup.set_color("color1", RGBA(1, 0, 0, 1)) lookup.set_color("color1", RGBA(1, 0, 0, 1)) # Should ignore duplicated requests. self.assertEqual( [ColorChangeEvent(lookup, "color1", Some(RGBA(1, 0, 0, 1)))], changes) lookup.set_color("color2", RGBA(0, 1, 0, 1)) self.assertEqual( [ColorChangeEvent(lookup, "color2", Some(RGBA(0, 1, 0, 1)))], changes[1:]) lookup.set_color("color2", RGBA(0, 1, 1, 1)) self.assertEqual( [ColorChangeEvent(lookup, "color2", Some(RGBA(0, 1, 1, 1)))], changes[2:]) font = ToyFontFace("Sans") lookup.set_font("font1", font) self.assertEqual([FontChangeEvent(lookup, "font1", Some(font))], changes[3:]) lookup.clear_color("color1") lookup.clear_font("font1") self.assertEqual([ColorChangeEvent(lookup, "color1", Nothing)], changes[4:5]) self.assertEqual([FontChangeEvent(lookup, "font1", Nothing)], changes[5:]) padding = Insets(5, 5, 5, 5) lookup.set_insets("padding", padding) self.assertEqual([InsetsChangeEvent(lookup, "padding", Some(padding))], changes[6:]) lookup.clear_insets("padding") self.assertEqual([InsetsChangeEvent(lookup, "padding", Nothing)], changes[7:])
def __init__(self, toolkit: Toolkit) -> None: super().__init__(toolkit) def with_prefix(key: str, prefix: str) -> str: return str.join(".", [prefix, key]) active_color = RGBA(0.3, 0.7, 0.3, 1) highlight_color = RGBA(0.9, 0.8, 0.5, 1) self.set_font("text", toolkit.fonts.fallback_font) self.set_color(with_prefix(StyleKeys.Background, "Window"), RGBA(0, 0, 0, 0.8)) self.set_color(with_prefix(StyleKeys.Border, "Window"), active_color) self.set_color(with_prefix(StyleKeys.Background, "Overlay"), RGBA(0, 0, 0, 0)) self.set_color(with_prefix(StyleKeys.Border, "Overlay"), RGBA(0, 0, 0, 0)) self.set_color(with_prefix(StyleKeys.Border, "Button"), active_color) self.set_color(with_prefix(StyleKeys.BorderHover, "Button"), highlight_color) self.set_color(with_prefix(StyleKeys.BackgroundActive, "Button"), active_color) self.set_color(with_prefix(StyleKeys.BorderActive, "Button"), active_color) self.set_color(StyleKeys.Text, RGBA(0.8, 0.8, 0.8, 1)) self.set_color(with_prefix(StyleKeys.TextHover, "Button"), highlight_color) self.set_color(with_prefix(StyleKeys.TextActive, "Button"), RGBA(0, 0, 0, 1)) self.set_insets(StyleKeys.Padding, Insets(10, 10, 10, 10)) self.set_insets(with_prefix(StyleKeys.Padding, "Overlay"), Insets(0, 0, 0, 0)) self.register_ui(Window, GlassWindowUI) self.register_ui(Frame, GlassFrameUI) self.register_ui(Panel, GlassPanelUI) self.register_ui(LabelButton, GlassLabelButtonUI) self.register_ui(Button, GlassButtonUI) self.register_ui(Label, GlassLabelUI) self.register_ui(Canvas, GlassCanvasUI)
def test_lookup_insets(self): lookup = StyleLookup() padding = Insets(5, 5, 5, 5) margin = Insets(10, 10, 10, 10) padding_key = "padding" margin_key = "margin" lookup.set_insets(padding_key, padding) lookup.set_insets(margin_key, margin) self.assertEqual(Nothing, lookup.get_insets("button_padding")) self.assertEqual(padding, lookup.get_insets(padding_key).unwrap()) self.assertEqual(margin, lookup.get_insets(margin_key).unwrap()) lookup.clear_insets(padding_key) self.assertEqual(Nothing, lookup.get_insets(padding_key))
def __init__(self, border: Border) -> None: if border is None: raise ValueError("Argument 'border' is required.") self.component: Maybe[Component] = Nothing self.padding: Insets = Insets(0, 0, 0, 0) self._border = border super().__init__()
def __init__(self, spacing: float = 0, padding: Insets = Insets(0, 0, 0, 0), align: BoxAlign = BoxAlign.Center, direction: BoxDirection = BoxDirection.Forward) -> None: if spacing < 0: raise ValueError( "Argument 'spacing' should be zero or a positive number.") super().__init__() self.spacing = spacing self.padding = padding self.align = align self.direction = direction
def add(self, child: Component, *args, **kwargs) -> None: @safe def parse(a, key) -> ResultE[Any]: return a[key] region: Border = parse(args, 0) \ .lash(lambda _: parse(kwargs, "region")) \ .value_or(Border.Center) # type:ignore padding: Insets = parse(args, 1) \ .lash(lambda _: parse(kwargs, "padding")) \ .value_or(Insets(0, 0, 0, 0)) # type:ignore super().add(child, *args, **kwargs) area = self.areas[region] area.component = Some(child) area.padding = padding
def test_preferred_size(self): def test_with_padding(padding: Insets): with LabelButton(self.context) as button: calculated = [] button.set_insets(StyleKeys.Padding, padding) button.validate() pw = padding.left + padding.right ph = padding.top + padding.bottom rv.observe(button.preferred_size).subscribe(calculated.append) self.assertEqual(Nothing, button.preferred_size_override) self.assertEqual(Dimension(pw, ph), button.preferred_size) self.assertEqual([Dimension(pw, ph)], calculated) button.text = "Test" button.validate() self.assertEqual(2, len(calculated)) self.assertEqual(Nothing, button.preferred_size_override) self.assertAlmostEqual(20.02 + pw, button.preferred_size.width, delta=TextTolerance) self.assertAlmostEqual(7.227 + ph, button.preferred_size.height, delta=TextTolerance) self.assertEqual(2, len(calculated)) self.assertAlmostEqual(20.02 + pw, calculated[1].width, delta=TextTolerance) self.assertAlmostEqual(7.227 + ph, calculated[1].height, delta=TextTolerance) button.text_size = 15 button.validate() self.assertEqual(3, len(calculated)) self.assertEqual(Nothing, button.preferred_size_override) self.assertAlmostEqual(30.03 + pw, button.preferred_size.width, delta=TextTolerance) self.assertAlmostEqual(10.840 + ph, button.preferred_size.height, delta=TextTolerance) self.assertEqual(3, len(calculated)) self.assertAlmostEqual(30.03 + pw, calculated[2].width, delta=TextTolerance) self.assertAlmostEqual(10.840 + ph, calculated[2].height, delta=TextTolerance) button.preferred_size_override = Some(Dimension(80, 50)) button.validate() self.assertEqual(Some(Dimension(80, 50)), button.preferred_size_override) self.assertEqual(Dimension(80, 50), button.preferred_size) self.assertEqual(4, len(calculated)) self.assertEqual(Dimension(80, 50), calculated[3]) button.preferred_size_override = Some(Dimension(10, 10)) button.validate() self.assertEqual(calculated[2], button.preferred_size) self.assertEqual(5, len(calculated)) self.assertEqual(calculated[2], calculated[4]) button.minimum_size_override = Some(Dimension(400, 360)) button.validate() self.assertEqual(Dimension(400, 360), button.preferred_size) self.assertEqual(6, len(calculated)) self.assertEqual(Dimension(400, 360), calculated[5]) for p in [Insets(0, 0, 0, 0), Insets(5, 5, 5, 5), Insets(10, 5, 0, 3)]: test_with_padding(p)
def __init__(self, spacing: float = 0, padding: Insets = Insets(0, 0, 0, 0), align: BoxAlign = BoxAlign.Center, direction: BoxDirection = BoxDirection.Forward) -> None: super().__init__(spacing, padding, align, direction)
def test_minimum_size(self): def test_with_padding(padding: Insets): with Label(self.context) as label: calculated = [] label.set_insets(StyleKeys.Padding, padding) label.validate() pw = padding.left + padding.right ph = padding.top + padding.bottom rv.observe(label.minimum_size).subscribe(calculated.append) self.assertEqual(Nothing, label.minimum_size_override) self.assertEqual(Dimension(pw, ph), label.minimum_size) self.assertEqual([Dimension(pw, ph)], calculated) label.text = "Test" label.validate() self.assertEqual(2, len(calculated)) self.assertEqual(Nothing, label.minimum_size_override) self.assertAlmostEqual(20.02 + pw, label.minimum_size.width, delta=TextTolerance) self.assertAlmostEqual(7.227 + ph, label.minimum_size.height, delta=TextTolerance) self.assertAlmostEqual(20.02 + pw, calculated[1].width, delta=TextTolerance) self.assertAlmostEqual(7.227 + ph, calculated[1].height, delta=TextTolerance) self.assertEqual( Bounds(0, 0, calculated[1].width, calculated[1].height), label.bounds) label.text_size = 15 label.validate() self.assertEqual(3, len(calculated)) self.assertEqual(Nothing, label.minimum_size_override) self.assertAlmostEqual(30.03 + pw, label.minimum_size.width, delta=TextTolerance) self.assertAlmostEqual(10.840 + ph, label.minimum_size.height, delta=TextTolerance) self.assertAlmostEqual(30.03 + pw, calculated[2].width, delta=TextTolerance) self.assertAlmostEqual(10.840 + ph, calculated[2].height, delta=TextTolerance) label.bounds = Bounds(10, 20, 60, 40) self.assertEqual(Bounds(10, 20, 60, 40), label.bounds) label.minimum_size_override = Some(Dimension(80, 50)) label.validate() self.assertEqual(Some(Dimension(80, 50)), label.minimum_size_override) self.assertEqual(Dimension(80, 50), label.minimum_size) self.assertAlmostEqual(30.03 + pw, calculated[2].width, delta=TextTolerance) self.assertAlmostEqual(10.840 + ph, calculated[2].height, delta=TextTolerance) self.assertEqual(Bounds(10, 20, 80, 50), label.bounds) label.bounds = Bounds(0, 0, 30, 40) self.assertEqual(Bounds(0, 0, 80, 50), label.bounds) for p in [Insets(0, 0, 0, 0), Insets(5, 5, 5, 5), Insets(10, 5, 0, 3)]: test_with_padding(p)
def test_insets_operations(self): self.assertEqual(Insets(5, 10, 25, 30), Insets(0, 0, 10, 20) + Insets(5, 10, 15, 10)) self.assertEqual(Insets(20, 15, 5, 10), Insets(15, 10, 0, 5) + 5) self.assertEqual(Insets(0, 0, 0, 10), Insets(0, 5, 10, 20) - Insets(5, 10, 15, 10)) self.assertEqual(Insets(5, 0, 10, 0), Insets(15, 10, 20, 5) - 10) self.assertEqual(Insets(0, 20, 10, 60), Insets(0, 10, 5, 30) * 2) self.assertEqual(Insets(10, 0, 5, 2.5), Insets(20, 0, 10, 5) / 2)
def padding(self, component: Canvas) -> Insets: return component.resolve_insets(StyleKeys.Padding).value_or( Insets(0, 0, 0, 0))
def clip_bounds(self, component: T) -> Bounds: border = GlassLookAndFeel.BorderThickness * 0.5 return super().clip_bounds(component) + Insets(border, border, border, border)
def test_insets_from_tuple(self): self.assertEqual(Insets(30, 0, 50, 40), Insets.from_tuple((30, 0, 50, 40)))
def test_insets_to_tuple(self): self.assertEqual((30, 20, 15, 5), Insets(30, 20, 15, 5).tuple)
def __init__(self, padding: Insets = Insets(0, 0, 0, 0)) -> None: super().__init__() # noinspection PyTypeChecker self.padding = padding
def test_bounds_operations(self): self.assertEqual(Bounds(0, 0, 100, 200), Bounds(0, 0, 100, 200) + Point(20, 30)) self.assertEqual(Bounds(0, 0, 100, 230), Bounds(0, 0, 100, 200) + Point(80, 230)) self.assertEqual(Bounds(0, 0, 120, 230), Bounds(0, 0, 100, 200) + Point(120, 230)) self.assertEqual(Bounds(-20, 0, 120, 200), Bounds(0, 0, 100, 200) + Point(-20, 30)) self.assertEqual(Bounds(-20, -30, 120, 230), Bounds(0, 0, 100, 200) + Point(-20, -30)) self.assertEqual(Bounds(0, 0, 50, 40), Bounds(0, 0, 30, 30) + Bounds(20, 10, 30, 30)) self.assertEqual(Bounds(-10, -20, 50, 30), Bounds(0, 0, 30, 30) + Bounds(-10, -20, 50, 30)) self.assertEqual(Bounds(0, 0, 30, 30), Bounds(0, 0, 30, 30) + Bounds(10, 10, 20, 10)) self.assertEqual(Bounds(20, 40, 200, 400), Bounds(20, 40, 100, 200) * 2) self.assertEqual(Bounds(20, 40, 100, 200), Bounds(20, 40, 200, 400) / 2) self.assertEqual(Nothing, Bounds(10, 20, 100, 60) & Bounds(120, 20, 100, 60)) self.assertEqual(Nothing, Bounds(10, 20, 100, 60) & Bounds(-120, 20, 100, 60)) self.assertEqual(Nothing, Bounds(10, 20, 100, 60) & Bounds(10, 90, 100, 60)) self.assertEqual(Nothing, Bounds(10, 20, 100, 60) & Bounds(10, -50, 100, 60)) self.assertEqual(Bounds(10, 20, 30, 20), (Bounds(10, 20, 100, 60) & Bounds(-60, -20, 100, 60)).unwrap()) self.assertEqual(Bounds(60, 20, 50, 20), (Bounds(10, 20, 100, 60) & Bounds(60, -20, 100, 60)).unwrap()) self.assertEqual(Bounds(60, 40, 50, 40), (Bounds(10, 20, 100, 60) & Bounds(60, 40, 100, 60)).unwrap()) self.assertEqual(Bounds(10, 40, 30, 40), (Bounds(10, 20, 100, 60) & Bounds(-60, 40, 100, 60)).unwrap()) self.assertEqual(Bounds(40, 30, 70, 40), (Bounds(10, 20, 100, 60) & Bounds(40, 30, 100, 40)).unwrap()) self.assertEqual(Bounds(10, 30, 70, 40), (Bounds(10, 20, 100, 60) & Bounds(-20, 30, 100, 40)).unwrap()) self.assertEqual(Bounds(20, 20, 80, 20), (Bounds(10, 20, 100, 60) & Bounds(20, -20, 80, 60)).unwrap()) self.assertEqual(Bounds(20, 40, 80, 40), (Bounds(10, 20, 100, 60) & Bounds(20, 40, 80, 60)).unwrap()) self.assertEqual(Bounds(30, 40, 50, 20), (Bounds(10, 20, 100, 60) & Bounds(30, 40, 50, 20)).unwrap()) self.assertEqual(Bounds(-10, 15, 130, 70), Bounds(10, 20, 100, 60) + Insets(5, 10, 5, 20)) self.assertEqual(Bounds(15, 40, 85, 0), Bounds(10, 20, 100, 60) - Insets(20, 10, 50, 5))