Coverage for src / ezqt_app / domain / ports / main_window.py: 50.00%

6 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-26 07:07 +0000

1# /////////////////////////////////////////////////////////////// 

2# DOMAIN.PORTS.MAIN_WINDOW - Main window structural contract 

3# Project: ezqt_app 

4# /////////////////////////////////////////////////////////////// 

5 

6"""Structural Protocol for the main application window. 

7 

8UI services interact with the main window through this contract instead of 

9``Any``. This makes all required attributes explicit and enables static 

10analysis without coupling the domain layer to PySide6 at runtime (all Qt 

11imports are guarded by ``TYPE_CHECKING``). 

12 

13Sub-protocols model the ``window.ui.*`` sub-objects accessed by UI services. 

14""" 

15 

16from __future__ import annotations 

17 

18# /////////////////////////////////////////////////////////////// 

19# IMPORTS 

20# /////////////////////////////////////////////////////////////// 

21# Standard library imports 

22from typing import TYPE_CHECKING, Any, Protocol 

23 

24if TYPE_CHECKING: 

25 from PySide6.QtCore import QPoint, QPropertyAnimation, QSize, Qt 

26 from PySide6.QtGui import QIcon 

27 from PySide6.QtWidgets import ( 

28 QGraphicsDropShadowEffect, 

29 QSizeGrip, 

30 QToolButton, 

31 QWidget, 

32 ) 

33 

34 

35# /////////////////////////////////////////////////////////////// 

36# SUB-PROTOCOLS — window.ui.* 

37# /////////////////////////////////////////////////////////////// 

38class StyleSheetWidgetProtocol(Protocol): 

39 """Minimal contract for the style-sheet target widget (``ui.style_sheet``).""" 

40 

41 def setStyleSheet(self, style: str) -> None: ... 

42 

43 

44class AppMarginsLayoutProtocol(Protocol): 

45 """Minimal contract for the outer margin layout (``ui.app_margins_layout``).""" 

46 

47 def setContentsMargins( 

48 self, left: int, top: int, right: int, bottom: int 

49 ) -> None: ... 

50 

51 

52class _AppButtonProtocol(Protocol): 

53 """Minimal contract for a single header action button.""" 

54 

55 clicked: Any # PySide6 Signal — typed as Any to stay Qt-agnostic 

56 

57 def hide(self) -> None: ... 

58 def setToolTip(self, tip: str) -> None: ... 

59 def setIcon(self, icon: QIcon) -> None: ... 

60 

61 

62class HeaderContainerProtocol(Protocol): 

63 """Minimal contract for the title-bar / header widget (``ui.header_container``).""" 

64 

65 minimize_btn: _AppButtonProtocol 

66 maximize_restore_btn: _AppButtonProtocol 

67 close_btn: _AppButtonProtocol 

68 mouseDoubleClickEvent: Any # settable event handler 

69 mouseMoveEvent: Any # settable event handler 

70 

71 def set_app_name(self, name: str) -> None: ... 

72 def set_app_description(self, description: str) -> None: ... 

73 def set_settings_panel_open(self, is_open: bool) -> None: ... 

74 

75 

76class _SizeGripSlotProtocol(Protocol): 

77 """Minimal contract for the size-grip placeholder in the bottom bar.""" 

78 

79 def hide(self) -> None: ... 

80 def show(self) -> None: ... 

81 

82 

83class BottomBarProtocol(Protocol): 

84 """Minimal contract for the bottom status bar (``ui.bottom_bar``).""" 

85 

86 size_grip_spacer: _SizeGripSlotProtocol 

87 

88 

89class _TopMenuProtocol(Protocol): 

90 """Minimal contract for the top-menu widget (``ui.menu_container.top_menu``).""" 

91 

92 def findChildren(self, child_type: type[QToolButton]) -> list[QToolButton]: ... 

93 

94 

95class MenuContainerProtocol(Protocol): 

96 """Minimal contract for the collapsible left menu (``ui.menu_container``).""" 

97 

98 top_menu: _TopMenuProtocol 

99 toggle_button: Any 

100 

101 def width(self) -> int: ... 

102 def get_extended_width(self) -> int: ... 

103 def get_shrink_width(self) -> int: ... 

104 

105 

106class SettingsPanelProtocol(Protocol): 

107 """Minimal contract for the settings slide-in panel (``ui.settings_panel``).""" 

108 

109 def width(self) -> int: ... 

110 def get_theme_selector(self) -> Any: ... 

111 

112 

113class PageContainerProtocol(Protocol): 

114 """Minimal contract for the central page receptacle (``ui.pages_container``).""" 

115 

116 def add_page(self, name: str) -> QWidget: ... 

117 def set_current_widget(self, widget: QWidget) -> None: ... 

118 

119 

120class BgAppProtocol(Protocol): 

121 """Minimal contract for the background app widget (``ui.bg_app_frame``).""" 

122 

123 def setGraphicsEffect(self, effect: QGraphicsDropShadowEffect) -> None: ... 

124 

125 

126class MainUiProtocol(Protocol): 

127 """Aggregated contract for the ``window.ui`` object.""" 

128 

129 style_sheet: StyleSheetWidgetProtocol 

130 app_margins_layout: AppMarginsLayoutProtocol 

131 header_container: HeaderContainerProtocol 

132 bottom_bar: BottomBarProtocol 

133 menu_container: MenuContainerProtocol 

134 settings_panel: SettingsPanelProtocol 

135 pages_container: PageContainerProtocol 

136 bg_app_frame: BgAppProtocol 

137 

138 

139# /////////////////////////////////////////////////////////////// 

140# SUB-PROTOCOL — window grips 

141# /////////////////////////////////////////////////////////////// 

142class GripProtocol(Protocol): 

143 """Minimal contract for a custom resize grip handle.""" 

144 

145 def hide(self) -> None: ... 

146 def show(self) -> None: ... 

147 def setGeometry(self, x: int, y: int, w: int, h: int) -> None: ... 

148 

149 

150# /////////////////////////////////////////////////////////////// 

151# MAIN PROTOCOL 

152# /////////////////////////////////////////////////////////////// 

153class MainWindowProtocol(Protocol): 

154 """Structural contract expected by UI services from the main application window. 

155 

156 Services use this type instead of ``Any`` for their *window* parameters, 

157 making all accessed attributes explicit and verifiable by static analysis. 

158 

159 Attributes that are *written* by services (grips, shadow, animations…) are 

160 included because other services read them later; their presence is guaranteed 

161 by the call ordering in the boot sequence. 

162 """ 

163 

164 # ── UI sub-object ────────────────────────────────────────── 

165 ui: MainUiProtocol 

166 

167 # ── Custom resize grips (set + read by services) ─────────── 

168 left_grip: GripProtocol 

169 right_grip: GripProtocol 

170 top_grip: GripProtocol 

171 bottom_grip: GripProtocol 

172 

173 # ── Dynamic state attributes (set by services) ───────────── 

174 dragPos: QPoint 

175 shadow: QGraphicsDropShadowEffect 

176 sizegrip: QSizeGrip 

177 menu_animation: QPropertyAnimation 

178 settings_animation: QPropertyAnimation 

179 

180 # ── Standard QWidget / QMainWindow methods ───────────────── 

181 def showMaximized(self) -> None: ... 

182 def showNormal(self) -> None: ... 

183 def showMinimized(self) -> None: ... 

184 def close(self) -> bool: ... 

185 def resize(self, w: int, h: int) -> None: ... 

186 def move(self, pos: QPoint) -> None: ... 

187 def pos(self) -> QPoint: ... 

188 def width(self) -> int: ... 

189 def height(self) -> int: ... 

190 def setMinimumSize(self, size: QSize) -> None: ... 

191 def setWindowFlags(self, flags: Qt.WindowType) -> None: ... 

192 def setAttribute(self, attribute: Qt.WidgetAttribute) -> None: ...