From 7821816d09c12460223534e1b3c2c7842e0914ed Mon Sep 17 00:00:00 2001 From: 283375 Date: Sat, 18 Nov 2023 23:05:10 +0800 Subject: [PATCH] wip: navigation components --- requirements.dev.txt | 1 + tests/__init__.py | 0 tests/ui/__init__.py | 0 tests/ui/navigation/__init__.py | 0 tests/ui/navigation/test_navhost.py | 31 ++++++++++++++ ui/components/__init__.py | 0 ui/navigation/navhost.py | 15 ++++++- ui/navigation/navitem.py | 3 ++ .../mainwindow => navigation}/navsidebar.py | 41 ++++++++++++------- 9 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/ui/__init__.py create mode 100644 tests/ui/navigation/__init__.py create mode 100644 tests/ui/navigation/test_navhost.py create mode 100644 ui/components/__init__.py rename ui/{components/mainwindow => navigation}/navsidebar.py (83%) diff --git a/requirements.dev.txt b/requirements.dev.txt index afaaaec..d0033b2 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -2,3 +2,4 @@ black == 23.7.0 isort == 5.12.0 imageio==2.31.4 Nuitka==1.8.4 +pytest==7.4.3 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/ui/__init__.py b/tests/ui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/ui/navigation/__init__.py b/tests/ui/navigation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/ui/navigation/test_navhost.py b/tests/ui/navigation/test_navhost.py new file mode 100644 index 0000000..ddd3df2 --- /dev/null +++ b/tests/ui/navigation/test_navhost.py @@ -0,0 +1,31 @@ +from ui.navigation.navhost import NavHost +from ui.navigation.navitem import NavItem + + +class TestNavHost: + def test_auto_append_parent(self): + navHost = NavHost() + + navHost.registerNavItem(NavItem(id="aaa.bbb.ccc.ddd")) + + navItems = navHost.navItems + + assert NavItem(id="aaa.bbb.ccc.ddd") in navItems + assert NavItem(id="aaa.bbb.ccc") in navItems + assert NavItem(id="aaa.bbb") in navItems + assert NavItem(id="aaa") in navItems + + def test_auto_select_child(self): + navHost = NavHost() + + navHost.registerNavItem(NavItem(id="aaa")) + navHost.registerNavItem(NavItem(id="bbb")) + + assert navHost.currentNavItem.id == "aaa" + + navHost.registerNavItem(NavItem(id="aaa.bbb")) + navHost.registerNavItem(NavItem(id="aaa.ccc")) + + navHost.navigate("aaa") + + assert navHost.currentNavItem.id == "aaa.bbb" diff --git a/ui/components/__init__.py b/ui/components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ui/navigation/navhost.py b/ui/navigation/navhost.py index 079179f..0a0f64b 100644 --- a/ui/navigation/navhost.py +++ b/ui/navigation/navhost.py @@ -24,11 +24,23 @@ class NavHost(QObject): super().__init__(parent) self.__navItems: list[NavItem] = [] + self.__cachedNavItems: list[NavItem] = [] self.__currentNavItem: NavItem = None + def __flushCachedNavItems(self): + navItems = set(self.__navItems) + + for item in self.__navItems: + parts = item.id.split(".") + for i in range(1, len(parts)): + parentItemId = ".".join(parts[:i]) + navItems.add(NavItem(id=parentItemId)) + + self.__cachedNavItems = list(navItems) + @property def navItems(self) -> list[NavItem]: - return self.__navItems + return self.__cachedNavItems @property def currentNavItem(self) -> NavItem: @@ -101,6 +113,7 @@ class NavHost(QObject): def registerNavItem(self, item: NavItem): self.__navItems.append(item) + self.__flushCachedNavItems() self.navItemsChanged.emit() def navigate(self, navItemId: str): diff --git a/ui/navigation/navitem.py b/ui/navigation/navitem.py index 90817d5..1c2cbf0 100644 --- a/ui/navigation/navitem.py +++ b/ui/navigation/navitem.py @@ -12,3 +12,6 @@ class NavItem: def text(self): return QCoreApplication.translate("NavItem", f"{self.id}.title") + + def __hash__(self): + return hash(self.id) diff --git a/ui/components/mainwindow/navsidebar.py b/ui/navigation/navsidebar.py similarity index 83% rename from ui/components/mainwindow/navsidebar.py rename to ui/navigation/navsidebar.py index 7e245c8..4041767 100644 --- a/ui/components/mainwindow/navsidebar.py +++ b/ui/navigation/navsidebar.py @@ -1,4 +1,4 @@ -from PySide6.QtCore import QModelIndex, Qt, Slot +from PySide6.QtCore import QModelIndex, Qt, Signal, Slot from PySide6.QtGui import QFont, QIcon, QKeySequence, QShortcut from PySide6.QtWidgets import ( QListWidget, @@ -8,7 +8,7 @@ from PySide6.QtWidgets import ( QWidget, ) -from ui.navigation.navhost import NavItem, navHost +from ui.navigation.navhost import NavHost, NavItem, navHost from ui.widgets.slidingstackedwidget import SlidingStackedWidget @@ -69,18 +69,14 @@ class NavigationWidget(QWidget): class NavigationSideBar(QWidget): - def __init__(self, parent=None): + navItemActivated = Signal(NavItem) + + def __init__(self, parent=None, navHost=navHost): super().__init__(parent) - self.navHost = navHost - - navHost.navItemsChanged.connect(self.reloadNavWidget) - navHost.activated.connect(self.navItemActivated) - + self.navHost = None self.navigateUpKeyboardShortcut = QShortcut( - QKeySequence(Qt.Modifier.ALT | Qt.Key.Key_Left), - self, - self.navHost.navigateUp, + QKeySequence(Qt.Modifier.ALT | Qt.Key.Key_Left), self, lambda: True ) self.verticalLayout = QVBoxLayout(self) @@ -88,7 +84,6 @@ class NavigationSideBar(QWidget): self.navigateUpButton = QPushButton(QIcon(":/icons/back.svg"), "") self.navigateUpButton.setFlat(True) self.navigateUpButton.setFixedHeight(20) - self.navigateUpButton.clicked.connect(self.navHost.navigateUp) self.verticalLayout.addWidget(self.navigateUpButton) self.slidingStackedWidget = SlidingStackedWidget(self) @@ -101,11 +96,29 @@ class NavigationSideBar(QWidget): navItemListWidget.activated.connect(self.navItemListWidgetActivatedProxy) self.slidingStackedWidget.addWidget(navItemListWidget) + self.setNavHost(navHost) self.reloadNavWidget() + def setNavHost(self, navHost: NavHost): + if self.navHost is not None: + self.navHost.navItemsChanged.disconnect(self.reloadNavWidget) + self.navHost.activated.disconnect(self.navItemChanged) + self.navigateUpKeyboardShortcut.activated.disconnect( + self.navHost.navigateUp + ) + self.navigateUpButton.clicked.disconnect(self.navHost.navigateUp) + + self.navHost = navHost + + self.navHost.navItemsChanged.connect(self.reloadNavWidget) + self.navHost.activated.connect(self.navItemChanged) + self.navigateUpKeyboardShortcut.activated.connect(self.navHost.navigateUp) + self.navigateUpButton.clicked.connect(self.navHost.navigateUp) + @Slot(QModelIndex) def navItemListWidgetActivatedProxy(self, index: QModelIndex): self.navHost.navigate(index.data(NavItemListWidget.NavItemRole).id) + self.navItemActivated.emit(index.data(NavItemListWidget.NavItemRole)) def fillNavItemListWidget( self, currentNavItem: NavItem, listWidget: NavItemListWidget @@ -123,10 +136,10 @@ class NavigationSideBar(QWidget): self.fillNavItemListWidget( self.navHost.currentNavItem, self.slidingStackedWidget.widget(0) ) - self.navItemActivated(self.navHost.currentNavItem, self.navHost.currentNavItem) + self.navItemChanged(self.navHost.currentNavItem, self.navHost.currentNavItem) @Slot(NavItem, NavItem) - def navItemActivated(self, oldNavItem: NavItem, newNavItem: NavItem): + def navItemChanged(self, oldNavItem: NavItem, newNavItem: NavItem): # update navigateUpButton text if newNavItemParent := self.navHost.getNavItemRelatives(newNavItem.id).parent: self.navigateUpButton.setText(newNavItemParent.text())