216 lines
7.1 KiB
Python
216 lines
7.1 KiB
Python
"""
|
|
Dashboard Tile Components
|
|
|
|
This module provides tile widgets for the dashboard interface.
|
|
|
|
Overview:
|
|
- Tiles are interactive components that display an icon, label, and status
|
|
- When clicked, tiles show their detailed content in the dashboard's content area
|
|
- Tiles can switch between mini (compact) and maxi (full) views
|
|
- Two tile types are available: Tile (standard) and TileSpecial (custom layouts)
|
|
|
|
Architecture:
|
|
- Tile: Standard tile with icon, label, properties, and optional menu button
|
|
- TileSpecial: Custom tile that can switch between different view layouts
|
|
- Both tiles communicate with the parent dashboard to show content
|
|
|
|
Usage:
|
|
- Create tiles with appropriate properties and add them to the dashboard
|
|
- The dashboard handles content switching and tile state management
|
|
- Tiles automatically notify the dashboard when clicked
|
|
"""
|
|
|
|
from fabric.widgets.box import Box
|
|
from fabric.widgets.button import Button
|
|
from fabric.widgets.label import Label
|
|
from fabric.widgets.stack import Stack
|
|
from fabric.widgets.revealer import Revealer
|
|
from gi.repository import Gdk
|
|
import utils.icons as icons
|
|
|
|
|
|
def add_hover_cursor(widget):
|
|
"""Add hover cursor functionality to a widget."""
|
|
widget.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK)
|
|
widget.connect(
|
|
"enter-notify-event",
|
|
lambda w, e: w.get_window().set_cursor(
|
|
Gdk.Cursor.new_from_name(w.get_display(), "pointer")
|
|
)
|
|
if w.get_window()
|
|
else None,
|
|
)
|
|
widget.connect(
|
|
"leave-notify-event",
|
|
lambda w, e: w.get_window().set_cursor(None) if w.get_window() else None,
|
|
)
|
|
|
|
|
|
class Tile(Box):
|
|
"""
|
|
A dashboard tile widget that displays an icon, label, and properties.
|
|
|
|
When clicked, the tile notifies the dashboard to show its detailed content
|
|
in the dashboard's content area instead of expanding inline.
|
|
|
|
Args:
|
|
menu (bool): Whether this tile has a menu button
|
|
markup (str): Icon markup to display
|
|
label (str): Text label for the tile
|
|
props (Label): Properties widget to show tile status
|
|
**kwargs: Additional widget arguments
|
|
"""
|
|
|
|
def __init__(self, *, menu: bool, markup: str, label: str, props: Label, **kwargs):
|
|
# Setup CSS classes
|
|
default_classes = ["tile"]
|
|
extra_classes = kwargs.pop("style_classes", [])
|
|
all_classes = default_classes + extra_classes
|
|
|
|
super().__init__(style_classes=all_classes, v_align="start", **kwargs)
|
|
|
|
# Store tile properties
|
|
self.props = props
|
|
self.toggle = False # Track if tile is active
|
|
self.dashboard_instance = None # Reference to parent dashboard
|
|
|
|
# Create tile components
|
|
self._create_tile_icon(markup)
|
|
self._create_tile_content(label)
|
|
self._create_tile_layout(menu)
|
|
|
|
def _create_tile_icon(self, markup: str):
|
|
"""Create the tile's icon label."""
|
|
self.icon = Label(style_classes="tile-icon", markup=markup)
|
|
|
|
def _create_tile_content(self, label: str):
|
|
"""Create the tile's text content area."""
|
|
self.tile_label = Label(
|
|
style_classes="tile-label", label=label, h_align="start"
|
|
)
|
|
|
|
# Container for label and properties
|
|
content_box = Box(
|
|
style_classes="tile-type",
|
|
orientation="v",
|
|
v_expand=True,
|
|
h_expand=True,
|
|
v_align="center",
|
|
children=[self.tile_label, self.props],
|
|
)
|
|
|
|
# Make the type_box clickable using a button
|
|
self.type_box = Button(
|
|
style_classes="tile-content-button",
|
|
h_expand=True,
|
|
v_expand=True,
|
|
child=content_box,
|
|
on_clicked=self.handle_click,
|
|
)
|
|
# Add hover cursor to the content area
|
|
add_hover_cursor(self.type_box)
|
|
|
|
def _create_tile_layout(self, has_menu: bool):
|
|
"""Create the tile's layout structure."""
|
|
# Create menu button if needed
|
|
if has_menu:
|
|
self.menu_button = Button(
|
|
style_classes="tile-button",
|
|
h_expand=True,
|
|
child=Label(style_classes="tile-icon", markup=icons.chevron_right),
|
|
on_clicked=self.handle_click,
|
|
)
|
|
# Add hover cursor to menu button
|
|
add_hover_cursor(self.menu_button)
|
|
content_children = [self.type_box, self.menu_button]
|
|
else:
|
|
content_children = [self.type_box]
|
|
|
|
# Create revealer for smooth transitions
|
|
self.content_button = Revealer(
|
|
transition_duration=150,
|
|
transition_type="slide-left",
|
|
h_expand=True,
|
|
child=Box(children=content_children),
|
|
child_revealed=True,
|
|
)
|
|
|
|
# Create the main tile view
|
|
self.normal_view = Box(children=[self.icon, self.content_button])
|
|
|
|
# Create placeholder menu (content is shown in dashboard content area)
|
|
self.menu = Box(
|
|
style_classes="tile-menu",
|
|
children=[
|
|
Label(label="Tile content will be shown in dashboard content area")
|
|
],
|
|
)
|
|
|
|
# Stack to switch between normal and menu views
|
|
self.stack = Stack(
|
|
transition_type="crossfade",
|
|
transition_duration=150,
|
|
h_expand=True,
|
|
children=[self.normal_view, self.menu],
|
|
)
|
|
|
|
self.children = self.stack
|
|
|
|
def handle_click(self, *_):
|
|
"""
|
|
Handle tile click events.
|
|
|
|
When clicked, the tile toggles its active state and notifies the dashboard
|
|
to show/hide its content in the dashboard's content area.
|
|
"""
|
|
self.toggle = not self.toggle
|
|
print(f"Tile {self.get_name()} clicked, toggle: {self.toggle}")
|
|
|
|
# Notify dashboard to handle content switching
|
|
if self.dashboard_instance:
|
|
self.dashboard_instance.handle_tile_menu_expand(
|
|
self.get_name(), self.toggle
|
|
)
|
|
|
|
|
|
class TileSpecial(Box):
|
|
"""
|
|
A special tile widget that can switch between normal and mini views.
|
|
|
|
This tile type is used for components that need different layouts
|
|
in normal vs compact modes (e.g., media player).
|
|
|
|
Args:
|
|
mini_props: Widget(s) to show in mini view
|
|
props: Widget(s) to show in normal view
|
|
**kwargs: Additional widget arguments
|
|
"""
|
|
|
|
def __init__(self, *, mini_props, props, **kwargs):
|
|
super().__init__(**kwargs)
|
|
|
|
# Store view components
|
|
self.props = props
|
|
self.mini_props = mini_props
|
|
self.toggle = False
|
|
|
|
# Create view containers
|
|
self._create_views()
|
|
self._setup_layout()
|
|
|
|
def _create_views(self):
|
|
"""Create the normal and collapsed view containers."""
|
|
self.normal_view = Box(children=self.props)
|
|
self.collapsed_view = Box(children=self.mini_props)
|
|
|
|
def _setup_layout(self):
|
|
"""Setup the stack layout for switching between views."""
|
|
self.stack = Stack(
|
|
transition_type="crossfade",
|
|
transition_duration=150,
|
|
h_expand=True,
|
|
v_align="start",
|
|
children=[self.normal_view, self.collapsed_view],
|
|
)
|
|
self.children = self.stack
|