From d22a9b23a18bbd4d060fdcc8a5f2a4b0074107ef Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 23 Oct 2023 11:48:28 -0400 Subject: [PATCH] layout: Create an adaptable Layout widget I'm planning to build on this widget over the next several releases. It'll eventually be fully adaptable to window size changes made by the user. Signed-off-by: Anna Schumaker --- emmental/layout.py | 45 ++++++++++++++++++++++++++++++ tests/test_layout.py | 65 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 emmental/layout.py create mode 100644 tests/test_layout.py diff --git a/emmental/layout.py b/emmental/layout.py new file mode 100644 index 0000000..8e10f8b --- /dev/null +++ b/emmental/layout.py @@ -0,0 +1,45 @@ +# Copyright 2023 (c) Anna Schumaker. +"""Our adaptable layout that can rearrange widgets as the window is resized.""" +from gi.repository import GObject +from gi.repository import Gtk +from gi.repository import Adw + + +class Layout(Adw.Bin): + """A widget that can rearrange based on window dimensions.""" + + show_sidebar = GObject.Property(type=bool, default=False) + + wide_view = GObject.Property(type=bool, default=False) + + def __init__(self, *, content: Gtk.Widget = None, + sidebar: Gtk.Widget = None): + """Initialize our Layout widget.""" + super().__init__() + self._split_view = Adw.OverlaySplitView(content=content, + sidebar=sidebar, + collapsed=not self.wide_view) + self.props.child = self._split_view + + self.bind_property("show-sidebar", self._split_view, "show-sidebar", + GObject.BindingFlags.BIDIRECTIONAL) + self.bind_property("wide-view", self._split_view, "collapsed", + GObject.BindingFlags.INVERT_BOOLEAN) + + @GObject.Property(type=Gtk.Widget) + def content(self) -> Gtk.Widget: + """Get the content widget for the Layout.""" + return self._split_view.props.content + + @content.setter + def content(self, widget: Gtk.Widget) -> None: + self._split_view.props.content = widget + + @GObject.Property(type=Gtk.Widget) + def sidebar(self) -> Gtk.Widget: + """Get the sidebar widget for the Layout.""" + return self._split_view.props.sidebar + + @sidebar.setter + def sidebar(self, widget: Gtk.Widget) -> None: + self._split_view.props.sidebar = widget diff --git a/tests/test_layout.py b/tests/test_layout.py new file mode 100644 index 0000000..f4789ef --- /dev/null +++ b/tests/test_layout.py @@ -0,0 +1,65 @@ +# Copyright 2023 (c) Anna Schumaker. +"""Tests our adaptable layout widget.""" +import unittest +import emmental.layout +from gi.repository import Gtk +from gi.repository import Adw + + +class TestLayout(unittest.TestCase): + """Test case for our adaptable layout.""" + + def setUp(self): + """Set up common variables.""" + self.layout = emmental.layout.Layout() + + def test_init(self): + """Check that the layout is set up properly.""" + self.assertIsInstance(self.layout, Adw.Bin) + self.assertIsInstance(self.layout._split_view, Adw.OverlaySplitView) + self.assertTrue(self.layout._split_view.props.collapsed) + + def test_wide_view(self): + """Test the layout when we have a wide window.""" + self.assertFalse(self.layout.wide_view) + self.assertEqual(self.layout.props.child, self.layout._split_view) + + self.layout.wide_view = True + self.assertFalse(self.layout._split_view.props.collapsed) + + def test_content(self): + """Test the content widget property.""" + self.assertIsNone(self.layout.content) + + widget = Gtk.Label() + self.layout.content = widget + self.assertEqual(self.layout._split_view.props.content, widget) + self.assertEqual(self.layout.content, widget) + + widget2 = Gtk.Label() + layout2 = emmental.layout.Layout(content=widget2) + self.assertEqual(layout2.content, widget2) + + def test_sidebar(self): + """Test the sidebar widget property.""" + self.assertIsNone(self.layout.sidebar) + + widget = Gtk.Label() + self.layout.sidebar = widget + self.assertEqual(self.layout._split_view.props.sidebar, widget) + self.assertEqual(self.layout.sidebar, widget) + + widget2 = Gtk.Label() + layout2 = emmental.layout.Layout(sidebar=widget2) + self.assertEqual(layout2.sidebar, widget2) + + def test_show_sidebar(self): + """Test the show-sidebar property.""" + self.assertFalse(self.layout.show_sidebar) + self.assertFalse(self.layout._split_view.props.show_sidebar) + + self.layout.show_sidebar = True + self.assertTrue(self.layout._split_view.props.show_sidebar) + + self.layout._split_view.props.show_sidebar = False + self.assertFalse(self.layout.show_sidebar)