Window.py PySide6 Custom QMainWindow — Frameless Window with Animated Panels
Window.py defines the AbdhWindow class, a fully customized QMainWindow subclass for
the PySideAbdhUI framework. It provides a frameless window with a hand-crafted titlebar,
collapsible left and right side-panel systems, smooth property-based animations for all
transitions, and a manual edge/corner resize implementation that replaces the broken
QSizeGrip approach commonly used in Qt frameless windows. The entire module is designed
to serve as the top-level application shell into which other framework components
(pages, navigation, widgets) are plugged.
The key design philosophy behind AbdhWindow is that the window should never be
auto-resized by Qt's internal layout system when child widgets change their
sizeHint. To enforce this, a size-lock mechanism pins the window to its current
dimensions (by setting both minimum and maximum size) and only unlocks it during
user-initiated operations such as edge-drag resizing or maximize/restore animations.
This eliminates the common problem of the window growing uncontrollably when a tree
widget or other dynamic content expands.
Architecture & Layout
The window uses a QGridLayout with a 2-row × 3-column structure. This grid layout is the
foundation for positioning the titlebar, side panels, and the main content area. Every
widget is placed at a specific cell in the grid, and column stretch factors control how
extra horizontal space is distributed. The following diagram illustrates the layout:
The titlebar spans all three columns in row 0. The left panel occupies column 0 across
both rows. The right panel occupies column 2 across both rows. The central stacked widget
(which hosts the application pages) sits at [1,1] and receives all extra horizontal space
via setColumnStretch(1, 1). This ensures that when the window is resized, only the
content area grows or shrinks, while the side panels maintain their fixed or animated widths.
Note: The titlebar is added to the grid after the other widgets but visually sits on top because QGridLayout Z-order follows insertion order — later additions are drawn on top. This ensures the titlebar overlaps the top edge of both side panels for a seamless visual appearance.
Dependencies
The module relies on the following external and internal dependencies. Understanding these
imports is essential for comprehending the full functionality available to AbdhWindow:
| Module | Components Used | Purpose |
|---|---|---|
os |
os.path.exists |
Checking if a stylesheet file exists before loading it. |
PySide6.QtWidgets |
QSizePolicy, QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QPushButton, QLabel, QFrame |
Core widget and layout classes for building the entire UI structure. |
PySide6.QtCore |
Qt, QPropertyAnimation, QParallelAnimationGroup, QEasingCurve, QRect, QSize, QPoint, QEvent |
Animation framework, geometry types, event types, and alignment/flags. |
PySide6.QtGui |
QPainter, QBrush, QColor, QPixmap, QPainterPath, QMouseEvent, QIcon |
Custom painting (rounded corners), image handling, mouse event types, icons. |
.Widgets |
StackedWidget |
Internal custom stacked widget with page navigation (back/forward). |
.utils |
get_icon |
Internal utility for loading SVG/icon resources by name. |
Class: AbdhWindow
AbdhWindow inherits from QMainWindow
Inherits QMainWindow
and is the primary top-level window class of the PySideAbdhUI framework. It completely
replaces the native window chrome with a custom frameless implementation, providing:
- Custom titlebar — with logo, navigation buttons (back/forward), title label, settings button, minimize, maximize/restore, and close.
- Collapsible left panel — operates in two modes: pinned (always visible, auto-close disabled) and overlay/unpinned (collapses to icon-only strip, auto-closes on outside click).
- Collapsible right panel — settings/details panel that starts at zero width and toggles on demand.
- Animated transitions — all panel open/close, maximize/restore, and first-show use
QPropertyAnimationwith easing curves. - Manual edge/corner resize — full 8-direction resizing with appropriate cursor shapes, replacing the unreliable
QSizeGrip. - Size-lock mechanism — prevents Qt's layout system from auto-growing the window.
- Fade-in animation — the window fades and slides in when first shown.
Class Attributes
These constants define the visual dimensions and behavior thresholds for the window.
They are class-level attributes shared across all instances of AbdhWindow:
| Attribute | Type | Default | Description |
|---|---|---|---|
control_button_size |
QSize |
QSize(40, 32) |
Dimensions for the window control buttons (minimize, maximize, close) in the titlebar. |
logo_size |
QSize |
QSize(32, 32) |
Dimensions for the application logo displayed in the top-left of the titlebar. |
pane_width |
int |
250 |
The full expanded width of side panels (both left and right) when they are open. |
pane_min_width |
int |
48 |
The collapsed width of the left panel in overlay mode — just enough to show icons. |
titlebar_height |
int |
42 |
Fixed height of the custom titlebar widget in pixels. |
RESIZE_MARGIN |
int |
8 |
Pixel distance from the window edge within which the cursor is considered to be near an edge for resizing. This defines the invisible resize grab zone. |
MIN_WINDOW_WIDTH |
int |
400 |
Absolute minimum width the window can be resized to. Prevents the window from becoming unusably narrow. |
MIN_WINDOW_HEIGHT |
int |
300 |
Absolute minimum height the window can be resized to. Ensures content remains visible. |
Constructor: __init__
AbdhWindow.__init__(self)
Public
Initializes the window by calling super().__init__(), then configures the
frameless window appearance and sets up all internal state variables. The constructor
does not build any UI widgets — that is deferred to the initUI() method.
Key initialization steps:
- Frameless window flag — Sets
Qt.WindowType.FramelessWindowHintto remove the native window border, andQt.WindowType.Windowto ensure it is still treated as a top-level window. - Translucent background — Enables
WA_TranslucentBackgroundso the rounded-corner painting inpaintEventproduces actual transparency at the corners. - Golden ratio sizing — Calculates the initial window size as
screen_dimension × 1.618 × 0.5, giving approximately 80.9% of the screen dimension. This creates a visually pleasing initial window size. - Centered positioning — The window is positioned at the horizontal center and slightly above vertical center (70% of calculated Y) for a more natural screen placement.
- State initialization — All resize state, drag state, panel state, and size-lock flags are set to their default values.
Important: Calling show() before initUI() will raise a RuntimeError. The show() method is overridden to check self.initialized before proceeding.
Size Lock System
The size-lock system is a critical architectural feature that prevents Qt's layout engine from
automatically growing the window when internal widgets change their size hints. This is a common
problem in Qt applications where, for example, a QTreeWidget with expanding nodes pushes
the window boundary outward. The solution implemented here is to lock the window to its exact
current size by setting both minimumSize and maximumSize to the current dimensions.
When the layout recalculates, it finds that the window cannot grow, so it reflows inside the
locked boundary instead.
The system works as a state machine: the window is normally locked, and is only briefly unlocked during animations (maximize/restore, fade-in) or edge-drag resizing. After each operation completes, the window is re-locked at its new size.
_lock_size(self)
Private
Locks the window to its current size by setting both minimumSize and maximumSize
to the current self.size(). This is the only reliable way to prevent Qt's layout
system from auto-growing the window when internal widgets change their sizeHint.
The layout will reflow inside the locked window boundary instead of pushing it outward.
Also sets self._size_locked = True for tracking purposes.
_unlock_size(self)
Private
Relaxes the size constraints so that user-initiated resize operations (edge drag,
maximize/restore animations) can change the window size. The minimum size is set to
MIN_WINDOW_WIDTH × MIN_WINDOW_HEIGHT (400×300) and the maximum size is set to
QWIDGETSIZE_MAX (16777215×16777215). After the operation completes, the window
must be re-locked by calling _lock_size().
_connect_lock_after_animation(self, animation: QPropertyAnimation)
Private
Convenience method that connects an animation's finished signal to
_lock_size, ensuring the window is automatically re-locked as soon as the
animation completes. Any previous _lock_size connection on this animation
is disconnected first to avoid duplicate calls, which could cause issues if the
same animation object is reused.
| Parameter | Type | Description |
|---|---|---|
animation | QPropertyAnimation | The animation whose finished signal should trigger a size lock. |
UI Initialization
initUI(self, app_title: str = 'PySideAbdhUI Application', direction=Qt.LayoutDirection.LeftToRight, logo: QPixmap = None)
Public
Constructs and assembles the entire window UI. This method must be called after
constructing the AbdhWindow instance and before calling show(). It creates
all widgets, layouts, and connections that make up the window.
| Parameter | Type | Default | Description |
|---|---|---|---|
app_title | str | 'PySideAbdhUI Application' | The text displayed in the titlebar and used as the window title. |
direction | Qt.LayoutDirection | LeftToRight | The layout direction for the main widget, supporting RTL languages. |
logo | QPixmap | None | An optional logo pixmap displayed in the titlebar. If None, the logo label remains empty. |
Initialization sequence:
- Central widget — Creates a
QWidgetwith the CSS classwindow-background-layerand sets it as the central widget with zero content margins. - Grid layout — Creates a
QGridLayoutwith zero margins and zero spacing for a pixel-perfect layout. - Left panel — Creates a
QFramewith CSS classleft-sidebar-background-layer, fixed width ofpane_width(250px), and aQVBoxLayoutwith top margin equal totitlebar_heightto avoid overlap. - Right panel — Creates a
QFramewith CSS classright-sidebar-background-layer, starting at zero width (collapsed by default), with aQVBoxLayoutand a stretch at the bottom for flexible content placement. - Toggle button — Creates the hamburger-menu toggle button that expands/collapses the left panel, and a pin button that switches between pinned and overlay modes.
- Stacked widget — Creates a
StackedWidget(custom class from.Widgets) for hosting application pages with back/forward navigation. - Titlebar — Calls
_create_titlebar()to build the custom titlebar with all control buttons. - Grid placement — Adds all widgets to the grid layout in the correct positions with proper alignment and span values.
- Column stretch — Sets column stretch factors: 0 for left panel, 1 for content, 0 for right panel.
- Mouse tracking — Enables mouse tracking for edge-resize cursor feedback.
- Animation setup — Creates the main
QPropertyAnimationobject for maximize/restore withOutQuadeasing and 175ms duration. - Event filter — Installs a global event filter on
QApplication.instance()to detect clicks outside panels and manage resize cursors.
Note: After initUI() completes, self.initialized is set to True, which allows the show() method to proceed. If show() is called without initialization, a RuntimeError is raised.
show(self)
Override
Overrides the default QMainWindow.show() to add an initialization guard. If
initUI() has not been called yet (self.initialized is False), it
raises a RuntimeError with a descriptive message. Otherwise, it calls
super().show() to display the window normally.
Panel Toggling
The left panel supports two distinct modes of operation, each providing a different user experience for sidebar interaction. The right panel operates as a simple toggle (open/close). Understanding these modes is essential for correctly integrating the window into an application.
Left Panel Modes
-
Pinned mode (
self.overlay = False): The left panel occupies column 0 only (col-span = 1). It stays visible and does not auto-close. The toggle button animates the panel between full width (pane_width) and minimum width (pane_min_width) while staying in the same grid column. The content area shifts accordingly. -
Overlay / Unpinned mode (
self.overlay = True): The left panel is placed at column 0 with col-span = 2, so it overlays the content area. The panel collapses topane_min_width(48px — just enough for icons) and auto-closes when the user clicks outside of it (handled by the event filter). The stacked widget gets a left margin equal topane_min_widthso its content is not hidden behind the panel.
toggle_overlay(self)
Public
Toggles the left panel between pinned and overlay mode. When switching to overlay mode,
the panel is removed from the grid and re-added with col-span = 2, its width is fixed
to pane_min_width, and the stacked widget receives a left margin to avoid
content occlusion. When switching back to pinned mode, the panel is re-added with
col-span = 1 and the stacked widget's left margin is reset to 0. The pin button is
hidden in overlay mode since pinning is only relevant in the expanded state.
animate_content(self, frame: QFrame, stack: StackedWidget)
Public
Animates the left panel open/closed with a smooth width transition. The behavior differs depending on whether the panel is in overlay or pinned mode:
- Overlay mode: Calls
toggle_frame()for a simple width toggle between 0 andpane_width. - Pinned mode: Creates a
QParallelAnimationGroupthat simultaneously animates bothminimumWidthandmaximumWidthof the panel. This dual-animation approach prevents layout conflicts where Qt might auto-adjust one property while the other is being animated. The animation usesInOutQuadeasing over 400ms for a natural feel.
After the animation completes, the stacked widget's width constraints are reset
(minimum to 0, maximum to QWIDGETSIZE_MAX) so it can freely expand when the
window is resized. The expanded flag is toggled and the pin button visibility
is updated accordingly.
| Parameter | Type | Description |
|---|---|---|
frame | QFrame | The left panel frame to animate (typically self.left_panel). |
stack | StackedWidget | The stacked content widget whose constraints are reset after animation. |
toggle_frame(self, sender: QFrame, min: int)
Public
A generic panel toggle method that animates any QFrame between collapsed and
expanded widths. If the frame's current width is less than pane_width, it
animates open to pane_width; otherwise, it animates closed to the given
min value. The animation uses OutCubic easing over 400ms for a
smooth deceleration effect.
Before starting a new animation, any running animation on the sender is stopped
to prevent conflicts. The animation object is scheduled for deletion after it
finishes via deleteLater().
| Parameter | Type | Description |
|---|---|---|
sender | QFrame | The panel frame to toggle (e.g., self.right_panel). |
min | int | The collapsed width to animate to. Typically 0 for the right panel or pane_min_width for the left panel. |
Known Limitation: This method only animates minimumWidth, not maximumWidth. A commented-out alternative implementation that animates both properties in parallel exists in the source code but is not currently active. This can cause layout jitter if internal widgets have large size hints.
open_settings(self)
Public
Convenience method that calls toggle_frame(self.right_panel, 0) to toggle
the right (settings) panel open or closed. The collapsed width is 0, meaning the
panel completely disappears when closed.
Animation System
AbdhWindow uses Qt's QPropertyAnimation framework extensively for smooth visual
transitions. All animations are property-based, meaning they interpolate a specific Qt
property of a widget over time. The following animation types are used:
| Animation Type | Property | Easing Curve | Duration | Context |
|---|---|---|---|---|
| Geometry | b"geometry" |
OutQuad |
175 ms | Maximize/restore transitions |
| Minimum width | b"minimumWidth" |
InOutQuad |
400 ms | Left panel expand/collapse (pinned mode) |
| Maximum width | b"maximumWidth" |
InOutQuad |
400 ms | Left panel expand/collapse (pinned mode, parallel) |
| Minimum width | b"minimumWidth" |
OutCubic |
400 ms | Generic panel toggle (toggle_frame) |
| Window opacity | b"windowOpacity" |
OutQuad |
500 ms | Fade-in on first show |
| Geometry | b"geometry" |
OutQuad |
500 ms | Slide-in on first show (parallel with opacity) |
The QParallelAnimationGroup is used in the left panel pinned-mode animation to run
the minimum and maximum width animations simultaneously, preventing layout conflicts.
The fade-in animation also runs opacity and geometry animations in parallel for a combined
fade-and-slide effect.
animate_fadeIn(self)
Private
Performs a combined fade-in and slide-in animation when the window is shown for the first time. Two animations run in parallel:
- Opacity animation: Transitions
windowOpacityfrom 0.0 to 1.0 over 500ms withOutQuadeasing, creating a smooth fade-in from transparent to fully opaque. - Geometry animation: Starts the window 50 pixels above its final position and slides it down to the target geometry over 500ms with
OutQuadeasing, creating a subtle slide-in effect.
Before starting, the size lock is unlocked so the geometry animation can move the
window. After the geometry animation finishes, the size is re-locked via
_connect_lock_after_animation(). This method is called from showEvent()
only when self.first_show is True.
Maximize / Restore
The maximize/restore system provides animated full-screen and windowed transitions without using the native window manager's maximize function. This is necessary because the window is frameless and the native maximize behavior would not respect the custom rounded corners and layout. The system stores the "original" (pre-maximize) geometry and animates between it and the full available screen geometry.
toggle_maximize_restore(self)
Public
Toggles between maximized and restored states. If currently maximized, it calls
animate_restore() and changes the maximize button icon to a single square.
If currently windowed, it calls animate_maximize() and changes the icon to
a double-square. The is_maximized flag is toggled after the call.
animate_maximize(self)
Private
Animates the window from its current geometry to the full available screen geometry
(excluding the taskbar). Before animating, the current geometry is saved as
original_geometry — but with bounds checking to ensure the stored geometry
is valid. Specifically, if the window is already wider/taller than the screen or
positioned off-screen, the geometry is clamped to ensure a valid restore target.
The animation uses the main self.animation object with OutQuad easing
over 175ms. After completion, the window is re-locked via
_connect_lock_after_animation().
animate_restore(self)
Private
Animates the window from its current (maximized) geometry back to the stored
original_geometry. Uses the same self.animation object with
OutQuad easing over 175ms. After completion, the window is re-locked.
Edge & Corner Resize
Since the window is frameless, there is no native border to grab for resizing. The
AbdhWindow class implements a complete manual resize system that detects when the
cursor is near the window's edges or corners, changes the cursor shape accordingly, and
handles mouse drag to resize the window from any of 8 directions (4 edges + 4 corners).
This replaces the commonly used QSizeGrip approach, which only provides a single
bottom-right resize handle and has known issues with frameless windows.
_get_resize_direction(self, pos) -> str | None
Private
Determines which edge or corner the cursor is near based on the mouse position
relative to the window boundaries. The RESIZE_MARGIN (8 pixels) defines the
invisible grab zone around the window perimeter. Corners take priority over edges
in the detection logic.
| Parameter | Type | Description |
|---|---|---|
pos | QPoint | The mouse position in window-local coordinates. |
'top_left', 'top_right', 'bottom_left', 'bottom_right', 'left', 'right', 'top', 'bottom', or None if the cursor is not near any edge.
_cursor_for_direction(self, direction) -> Qt.CursorShape
Private
Maps a resize direction string to the appropriate Qt cursor shape. Horizontal
edges use SizeHorCursor, vertical edges use SizeVerCursor, and
diagonal corners use SizeFDiagCursor or SizeBDiagCursor depending
on the diagonal direction. Returns ArrowCursor for unrecognized directions.
| Direction | Cursor Shape | Visual |
|---|---|---|
left, right | SizeHorCursor | Horizontal double arrow ↔ |
top, bottom | SizeVerCursor | Vertical double arrow ↕ |
top_left, bottom_right | SizeFDiagCursor | Forward diagonal ↖↘ |
top_right, bottom_left | SizeBDiagCursor | Backward diagonal ↗↙ |
_do_resize(self, global_pos)
Private
Performs the actual resize based on the stored direction and the mouse position
delta. It calculates the new geometry by adjusting the appropriate edges of the
stored _resize_start_geo rectangle. Each direction flag in
_resize_dir (e.g., 'left', 'top') is checked independently,
which allows corner resizing to modify two edges simultaneously.
Minimum size constraints (MIN_WINDOW_WIDTH and MIN_WINDOW_HEIGHT) are
enforced: if resizing would make the window smaller than the minimum, the
corresponding edge is not moved. After setting the geometry, the main layout
is explicitly activated via self.main_widget.layout().activate() to
force an immediate reflow so the stacked widget expands/contracts to fill
the new window size.
| Parameter | Type | Description |
|---|---|---|
global_pos | QPoint | The current global mouse position. |
Event System
AbdhWindow overrides several Qt event handlers and installs a global event filter to
implement its frameless window behavior. The event system handles: first-show fade-in
animation, custom painting of rounded corners, cursor management for edge resizing,
auto-closing panels on outside clicks, window dragging from the titlebar, and edge/corner
resizing.
Mouse Events
mousePressEvent(self, event: QMouseEvent)
Override
Handles left-button mouse press events with two distinct behaviors:
- Edge/corner resize initiation: If the cursor is near an edge or corner (determined by
_get_resize_direction()) and the window is not maximized, the resize state is initialized. The size lock is unlocked, the resize direction and starting geometry/position are stored, and the resize cursor is locked for the entire drag operation. - Titlebar drag initiation: If the click is not near an edge, the drag start position is stored as the offset between the global cursor position and the window's top-left corner. This offset is used in
mouseMoveEvent()to move the window smoothly.
mouseDoubleClickEvent(self, event)
Override
Handles double-click events on the titlebar area. If the double-click occurs
within the titlebar height (self.titlebar_height) from the top of the window,
it triggers toggle_maximize_restore(). This mimics the standard Windows/macOS
behavior of double-clicking the titlebar to maximize/restore the window.
mouseMoveEvent(self, event: QMouseEvent)
Override
Handles left-button mouse move events with two behaviors:
- Resizing: If
self._resizingisTrue, calls_do_resize()with the current global position to update the window geometry. - Titlebar dragging: If a drag start position exists and the cursor is within the titlebar's Y range, the window is moved to follow the cursor. If the window is maximized, it is first restored to windowed mode before dragging begins, allowing the user to "pull" the window out of maximized state — a common UX pattern.
Note: Cursor management for hover (no button pressed) is handled in eventFilter(), not here. mouseMoveEvent only fires when the mouse is over the window's own area — child widgets consume the events. The event filter catches ALL mouse-move events so the resize cursor is always shown/hidden correctly.
mouseReleaseEvent(self, event)
Override
Handles left-button mouse release events. If the user was resizing
(self._resizing is True), the resize state is reset and the
window is re-locked to its new size via _lock_size(). The cursor is
also unset, allowing the eventFilter to set the correct cursor on the
next hover move. The drag start position is always cleared on release.
showEvent(self, event)
Override
Triggers the fade-in animation when the window is shown for the first time.
If self.first_show is True, it sets it to False and
calls animate_fadeIn(). Subsequent show events (e.g., after minimizing
and restoring) do not trigger the animation.
paintEvent(self, event)
Override
Custom paint event that draws a rounded rectangle over the entire window area.
This is necessary because the window is frameless with a translucent background,
so without custom painting the corners would show the desktop or other windows
behind. The method uses QPainter with antialiasing to draw a
QPainterPath containing a rounded rect (8px radius), filled with the
window palette's background color.
leaveEvent(self, event)
Override
Resets the cursor to the default arrow when the mouse leaves the window entirely. This prevents the resize cursor from persisting when the mouse moves away from the window edge without being over any child widget.
Global Event Filter
eventFilter(self, obj, event) -> bool
Override
A global event filter installed on QApplication.instance() that handles
two critical functions that cannot be implemented in regular event handlers:
1. Cursor Management (MouseMove, no buttons)
When the mouse moves without any buttons pressed, the filter checks if the cursor
is near a window edge or corner. If so, it sets the appropriate resize cursor.
If not, it unsets the cursor. This must be in the event filter (not
mouseMoveEvent) because mouseMoveEvent only fires when the mouse is
directly over the window's own area — not over child widgets. Without the event
filter, the resize cursor would get "stuck" or appear over child widgets that
inherit the parent's cursor. The filter is only active when the window is not
maximized and is visible.
2. Auto-Close Panels on Outside Click (MouseButtonPress)
When a mouse button press is detected anywhere in the application, the filter checks whether the click target is one of the control buttons (toggle, pin, settings, maximize, minimize, close). If it is, the event is passed through normally. Otherwise:
- Right panel: If the right panel is open (width > 0) and the click is outside its geometry, it is auto-closed via
toggle_frame(). - Left panel (overlay mode): If the left panel is in overlay mode and expanded, and the click is outside its geometry, it is auto-collapsed via
animate_content().
Helper Methods
_create_titlebar(self, title_text: str, title_logo: QPixmap) -> QWidget
Private
Builds the custom titlebar widget with all its child widgets and layout. The
titlebar is a QWidget with object name Titlebar, fixed height of
titlebar_height (42px), and a QHBoxLayout containing the following
widgets from left to right:
| Widget | Property | Icon | Signal |
|---|---|---|---|
| Logo label | CSS class: default | — | — |
| Back button | grouped_mini | arrow-left | stacked_widget.go_back |
| Forward button | grouped_mini | arrow-right | stacked_widget.go_next |
| Title label | caption | — | — |
| Stretch | — | — | — |
| Settings button | grouped_mini | settings | toggle_frame(right_panel, 0) |
| Minimize button | grouped_mini | minus | showMinimized |
| Maximize button | grouped_mini | square | toggle_maximize_restore |
| Close button | closebutton | x | close |
All buttons use the grouped_mini CSS class (except the close button which uses
closebutton) and are aligned to the top of the titlebar. The layout direction
is forced to LeftToRight regardless of the application's layout direction,
ensuring the window controls always appear on the right side.
| Parameter | Type | Description |
|---|---|---|
title_text | str | The text displayed in the title label. |
title_logo | QPixmap | Optional logo pixmap; scaled to logo_size (32×32) with aspect ratio preservation. |
QWidget — The fully constructed titlebar widget.
switch_settings_button(self, on: bool = True)
Public
Shows or hides the settings button in the titlebar. This is useful when a particular page or application state does not require a settings panel.
| Parameter | Type | Default | Description |
|---|---|---|---|
on | bool | True | If True, the settings button is visible; if False, it is hidden. |
switch_navigations(self, on: bool = True)
Public
Shows or hides both the back and forward navigation buttons in the titlebar simultaneously. This is useful for pages that do not support navigation history.
| Parameter | Type | Default | Description |
|---|---|---|---|
on | bool | True | If True, both navigation buttons are visible; if False, both are hidden. |
set_direction(self, direction: Qt.LayoutDirection = Qt.LayoutDirection.LeftToRight)
Public
Sets the layout direction of the stacked widget, enabling right-to-left (RTL)
support for languages like Arabic or Hebrew. The titlebar and side panels are
not affected — they maintain their forced LeftToRight direction.
| Parameter | Type | Default | Description |
|---|---|---|---|
direction | Qt.LayoutDirection | LeftToRight | The layout direction for the content area. |
update_navigation_buttons(self, can_go_back: bool, can_go_forward: bool)
Public
Independently controls the visibility of the back and forward navigation buttons. This is typically called after a page navigation event to reflect the current navigation history state — the back button is visible only if there is a previous page to return to, and the forward button is visible only if there is a next page.
| Parameter | Type | Description |
|---|---|---|
can_go_back | bool | If True, the back button is shown; otherwise hidden. |
can_go_forward | bool | If True, the forward button is shown; otherwise hidden. |
add_right_panel_item(self, item: QWidget)
Public
Inserts a widget into the right panel layout, positioned before the bottom stretch.
The stretch was added during initialization with addStretch(1), so new items
are inserted at index count - 1 to appear above the stretch. This ensures
that content is always pushed to the top of the panel with flexible space at the bottom.
| Parameter | Type | Description |
|---|---|---|
item | QWidget | The widget to add to the right panel. |
add_left_panel_item(self, item: QWidget)
Public
Appends a widget to the end of the left panel layout. Widgets are added in order
from top to bottom, after the toggle and pin buttons that were added during
initUI().
| Parameter | Type | Description |
|---|---|---|
item | QWidget | The widget to add to the left panel. |
left_panel_item(self, index: int) -> QWidget
Public
Returns the widget at the given index in the left panel layout. This is useful for accessing or modifying previously added panel items.
| Parameter | Type | Description |
|---|---|---|
index | int | The zero-based index of the item in the left panel layout. |
QWidget — The widget at the specified index.
Page & Style Helpers
add_page(self, page_widget: QWidget)
Public
Adds a page widget to the central stacked widget. Pages are managed by the
StackedWidget class, which provides navigation history (back/forward)
functionality. The first page added becomes the initially visible page. Each
subsequent page is hidden until navigated to via the stacked widget's methods.
| Parameter | Type | Description |
|---|---|---|
page_widget | QWidget | The page widget to add. It should contain the full UI for one application screen. |
apply_style(self, style_sheet: str)
Public
Applies a Qt style sheet string directly to the window. This is the programmatic way to set styles, useful for dynamically generated or modified style sheets. The style sheet affects the window and all its child widgets.
| Parameter | Type | Description |
|---|---|---|
style_sheet | str | A valid Qt style sheet (QSS) string to apply. |
load_style(self, file_name: str = 'default') -> str | None
Public
Loads a Qt style sheet from an external file and applies it to the window. The
file is read as UTF-8 text. If the file does not exist, a warning is printed
to the console and None is returned. This method is useful for separating
style definitions from application code and allowing runtime theme switching.
| Parameter | Type | Default | Description |
|---|---|---|---|
file_name | str | 'default' | Path to the QSS file to load. |
None otherwise.
Full Method Index
Complete reference of all methods in the AbdhWindow class, organized by visibility
and category:
| Method | Visibility | Category | Brief Description |
|---|---|---|---|
__init__ | Public | Constructor | Initialize window state and frameless flags |
initUI | Public | Initialization | Build the entire UI structure |
show | Override | Initialization | Show with initialization guard |
_lock_size | Private | Size Lock | Lock window to current size |
_unlock_size | Private | Size Lock | Unlock for user-initiated resize |
_connect_lock_after_animation | Private | Size Lock | Auto-lock after animation finishes |
toggle_overlay | Public | Panel | Toggle pinned/overlay mode for left panel |
animate_content | Public | Panel | Animate left panel open/close |
toggle_frame | Public | Panel | Generic panel toggle with animation |
open_settings | Public | Panel | Toggle right (settings) panel |
toggle_maximize_restore | Public | Maximize | Toggle between maximized and restored |
animate_maximize | Private | Maximize | Animate to full-screen geometry |
animate_restore | Private | Maximize | Animate to stored windowed geometry |
animate_fadeIn | Private | Animation | Fade-in + slide-in on first show |
_get_resize_direction | Private | Resize | Detect edge/corner from cursor position |
_cursor_for_direction | Private | Resize | Map direction to cursor shape |
_do_resize | Private | Resize | Apply geometry change during drag |
mousePressEvent | Override | Event | Initiate resize or titlebar drag |
mouseDoubleClickEvent | Override | Event | Maximize/restore on titlebar double-click |
mouseMoveEvent | Override | Event | Perform resize or window drag |
mouseReleaseEvent | Override | Event | End resize, re-lock size |
showEvent | Override | Event | Trigger fade-in on first show |
paintEvent | Override | Event | Draw rounded rectangle background |
leaveEvent | Override | Event | Reset cursor when mouse leaves |
eventFilter | Override | Event | Cursor management + auto-close panels |
_create_titlebar | Private | Helper | Build custom titlebar widget |
switch_settings_button | Public | Helper | Show/hide settings button |
switch_navigations | Public | Helper | Show/hide back & forward buttons |
set_direction | Public | Helper | Set content layout direction (RTL support) |
update_navigation_buttons | Public | Helper | Individually control nav button visibility |
add_right_panel_item | Public | Helper | Add widget to right panel |
add_left_panel_item | Public | Helper | Add widget to left panel |
left_panel_item | Public | Helper | Get widget at index in left panel |
add_page | Public | Page/Style | Add page to stacked widget |
apply_style | Public | Page/Style | Apply QSS string to window |
load_style | Public | Page/Style | Load and apply QSS from file |
CSS Class Reference: The window uses CSS class properties (not object names) to match stylesheet selectors. Key CSS classes used include: window-background-layer (main widget), left-sidebar-background-layer (left panel), right-sidebar-background-layer (right panel), grouped_mini (small control buttons), closebutton (close button), and caption (title label). The titlebar widget uses objectName Titlebar instead.