Skip to content

Commit 6135170

Browse files
committed
feat(workspaces): add toggle workspace layer functionality
- Introduced a new toggle for workspace layers, allowing users to switch between tiling and floating modes. - Updated validation schema and default settings to accommodate the new feature. - Enhanced documentation to reflect the changes in workspace configuration options.
1 parent 9c9f048 commit 6135170

File tree

4 files changed

+85
-14
lines changed

4 files changed

+85
-14
lines changed

docs/widgets/(Widget)-Komorebi-Workspaces.md

+12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
| `label_workspace_populated_btn` | string | `'{index}'` | The format string for the populated workspace button. |
88
| `label_default_name` | string | `''` | The default name for workspaces. |
99
| `label_float_override` | string | `'Override Active'` | The label to display when Komorebi is Float Override Active. |
10+
| `toggle_workspace_layer` | dict | `{'enabled': false, 'tiling_label': 'Tiling', 'floating_label': 'Floating'}` | Controls toggling between tiling and floating layers. |
1011
| `hide_if_offline` | boolean | `false` | Whether to hide the widget if Komorebi is offline. |
1112
| `label_zero_index` | boolean | `false` | Whether to use zero-based indexing for workspace labels. |
1213
| `hide_empty_workspaces` | boolean | `false` | Whether to hide empty workspaces. |
@@ -28,6 +29,10 @@ komorebi_workspaces:
2829
hide_empty_workspaces: false
2930
hide_if_offline: false
3031
animation: true
32+
toggle_workspace_layer:
33+
enabled: false
34+
tiling_label: "Tiling"
35+
floating_label: "Floating"
3136
container_padding:
3237
top: 0
3338
left: 8
@@ -42,6 +47,10 @@ komorebi_workspaces:
4247
- **label_workspace_populated_btn:** The format string for the populated workspace button, can be icon, {name} or {index}.
4348
- **label_default_name:** The default name for workspaces.
4449
- **label_float_override:** The label to display when Komorebi is Float Override Active.
50+
- **toggle_workspace_layer:** Controls toggling between tiling and floating layers.
51+
- **enabled:** Whether to enable the workspace layer toggle functionality.
52+
- **tiling_label:** The label to display for the tiling layer.
53+
- **floating_label:** The label to display for the floating layer.
4554
- **hide_if_offline:** Whether to hide the widget if Komorebi is offline.
4655
- **label_zero_index:** Whether to use zero-based indexing for workspace labels.
4756
- **hide_empty_workspaces:** Whether to hide empty workspaces.
@@ -59,6 +68,9 @@ komorebi_workspaces:
5968
.komorebi-workspaces .ws-btn.button-1 {} /*Style for first button.*/
6069
.komorebi-workspaces .ws-btn.button-2 {} /*Style for second button.*/
6170
.komorebi-workspaces .float-override {} /*Style for float override text and icon.*/
71+
.komorebi-workspaces .workspace-layer {} /*Style for workspace layer text and icon.*/
72+
.komorebi-workspaces .workspace-layer.tiling {} /*Style for workspace layer text and icon when in tiling mode.*/
73+
.komorebi-workspaces .workspace-layer.floating {} /*Style for workspace layer text and icon when in floating mode.*/
6274
```
6375

6476
> [!NOTE]

src/core/event_enums.py

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class KomorebiEvent(Event):
2626
ToggleMonocle = "ToggleMonocle"
2727
ToggleMaximise = "ToggleMaximise"
2828
TogglePause = "TogglePause"
29+
ToggleWorkspaceLayer = "ToggleWorkspaceLayer"
2930
EnsureWorkspaces = "EnsureWorkspaces"
3031
CycleFocusMonitor = "CycleFocusMonitor"
3132
CycleFocusWorkspace = "CycleFocusWorkspace"

src/core/validation/widgets/komorebi/workspaces.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
'label_workspace_populated_btn': '{index}',
66
'label_default_name': '',
77
'label_float_override': 'Override Active',
8+
'toggle_workspace_layer': {'enabled': False, 'tiling_label': "Tiling", 'floating_label': "Floating"},
89
'hide_if_offline': False,
910
'label_zero_index': False,
1011
'hide_empty_workspaces': False,
@@ -37,6 +38,24 @@
3738
'type': 'string',
3839
'default': DEFAULTS['label_float_override']
3940
},
41+
'toggle_workspace_layer': {
42+
'type': 'dict',
43+
'default': DEFAULTS['toggle_workspace_layer'],
44+
'schema': {
45+
'enabled': {
46+
'type': 'boolean',
47+
'default': DEFAULTS['toggle_workspace_layer']['enabled']
48+
},
49+
'tiling_label': {
50+
'type': 'string',
51+
'default': DEFAULTS['toggle_workspace_layer']['tiling_label']
52+
},
53+
'floating_label': {
54+
'type': 'string',
55+
'default': DEFAULTS['toggle_workspace_layer']['floating_label']
56+
}
57+
}
58+
},
4059
'hide_if_offline': {
4160
'type': 'boolean',
4261
'default': DEFAULTS['hide_if_offline']
@@ -49,7 +68,7 @@
4968
'type': 'boolean',
5069
'default': DEFAULTS['hide_empty_workspaces']
5170
},
52-
'animation': {
71+
'animation': {
5372
'type': 'boolean',
5473
'default': DEFAULTS['animation']
5574
},
@@ -58,4 +77,4 @@
5877
'default': DEFAULTS['container_padding'],
5978
'required': False
6079
}
61-
}
80+
}

src/core/widgets/komorebi/workspaces.py

+51-12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class WorkspaceButton(QPushButton):
2626

2727
def __init__(self, workspace_index: int, parent_widget: 'WorkspaceWidget', label: str = None, active_label: str = None, populated_label: str = None, animation: bool = False):
2828
super().__init__()
29+
self._animation_initialized = False
2930
self.komorebic = KomorebiClient()
3031
self.workspace_index = workspace_index
3132
self.parent_widget = parent_widget
@@ -66,13 +67,13 @@ def activate_workspace(self):
6667
try:
6768
self.komorebic.activate_workspace(self.parent_widget._komorebi_screen['index'], self.workspace_index)
6869
if self._animation:
69-
self.animate_buttons()
70+
pass
71+
#self.animate_buttons()
7072
except Exception:
7173
logging.exception(f"Failed to focus workspace at index {self.workspace_index}")
7274

73-
def animate_buttons(self, duration=200, step=120):
74-
#Store the initial width if not already stored
75-
#we need this to animate the width back to the initial width
75+
def animate_buttons(self, duration=200, step=30):
76+
# Store the initial width if not already stored (to enable reverse animations)
7677
if not hasattr(self, '_initial_width'):
7778
self._initial_width = self.width()
7879

@@ -81,7 +82,6 @@ def animate_buttons(self, duration=200, step=120):
8182

8283
step_duration = int(duration / step)
8384
width_increment = (target_width - self._current_width) / step
84-
8585
self._current_step = 0
8686

8787
def update_width():
@@ -90,14 +90,16 @@ def update_width():
9090
self.setFixedWidth(int(self._current_width))
9191
self._current_step += 1
9292
else:
93+
# Animation done: stop timer and set to target exactly
9394
self._animation_timer.stop()
9495
self.setFixedWidth(target_width)
9596

9697
# Stop any existing timer before starting a new one to prevent conflicts
9798
if hasattr(self, '_animation_timer') and self._animation_timer.isActive():
9899
self._animation_timer.stop()
99100

100-
self._animation_timer = QTimer()
101+
# Parent the timer to the widget to avoid potential memory leaks
102+
self._animation_timer = QTimer(self)
101103
self._animation_timer.timeout.connect(update_width)
102104
self._animation_timer.start(step_duration)
103105

@@ -117,6 +119,7 @@ def __init__(
117119
label_workspace_populated_btn: str,
118120
label_default_name: str,
119121
label_float_override: str,
122+
toggle_workspace_layer: dict,
120123
hide_if_offline: bool,
121124
label_zero_index: bool,
122125
hide_empty_workspaces: bool,
@@ -131,6 +134,7 @@ def __init__(
131134
self._label_workspace_populated_btn = label_workspace_populated_btn
132135
self._label_default_name = label_default_name
133136
self._label_float_override = label_float_override
137+
self._toggle_workspace_layer = toggle_workspace_layer
134138
self._label_zero_index = label_zero_index
135139
self._hide_if_offline = hide_if_offline
136140
self._padding = container_padding
@@ -146,7 +150,8 @@ def __init__(
146150
KomorebiEvent.CycleFocusMonitor.value,
147151
KomorebiEvent.FocusMonitorWorkspaceNumber.value,
148152
KomorebiEvent.FocusMonitorNumber.value,
149-
KomorebiEvent.FocusWorkspaceNumber.value
153+
KomorebiEvent.FocusWorkspaceNumber.value,
154+
KomorebiEvent.ToggleWorkspaceLayer.value
150155
]
151156
self._update_buttons_event_watchlist = [
152157
KomorebiEvent.EnsureWorkspaces.value,
@@ -159,8 +164,7 @@ def __init__(
159164
KomorebiEvent.Unmanage.value,
160165
KomorebiEvent.WatchConfiguration.value,
161166
KomorebiEvent.WorkspaceName.value,
162-
KomorebiEvent.Cloak.value,
163-
#KomorebiEvent.CloseWorkspace.value
167+
KomorebiEvent.Cloak.value
164168
]
165169
# Disable default mouse event handling inherited from BaseWidget
166170
self.mousePressEvent = None
@@ -188,6 +192,11 @@ def __init__(
188192
self.float_override_label.hide()
189193
self.widget_layout.addWidget(self.float_override_label)
190194

195+
if self._toggle_workspace_layer['enabled']:
196+
self.workspace_layer_label = QLabel()
197+
self.workspace_layer_label.setProperty("class", "workspace-layer")
198+
self.widget_layout.addWidget(self.workspace_layer_label)
199+
191200
self._register_signals_and_events()
192201

193202
def _register_signals_and_events(self):
@@ -255,7 +264,10 @@ def _on_komorebi_update_event(self, event: dict, state: dict) -> None:
255264
for workspace_index in unknown_indexes:
256265
self._try_remove_workspace_button(workspace_index)
257266
self._add_or_update_buttons()
258-
267+
268+
if event['type'] == KomorebiEvent.FocusChange.value:
269+
self._get_workspace_layer(self._curr_workspace_index)
270+
259271
# Show float override label if float override is active
260272
if state.get('float_override') and self._label_float_override:
261273
self.float_override_label.show()
@@ -301,6 +313,31 @@ def _get_workspace_new_status(self, workspace) -> WorkspaceStatus:
301313
else:
302314
return WORKSPACE_STATUS_EMPTY
303315

316+
def _get_workspace_layer(self, workspace_index: int) -> None:
317+
"""
318+
This function is used to get the workspace layer by index. (toggle-workspace-layer)
319+
Also updates the label's CSS class based on current layer.
320+
"""
321+
if self._toggle_workspace_layer['enabled']:
322+
workspace = self._komorebic.get_workspace_by_index(self._komorebi_screen, workspace_index)
323+
if workspace and 'layer' in workspace:
324+
# Set base class plus layer-specific class
325+
layer_type = workspace['layer'].lower() # Either "tiling" or "floating"
326+
self.workspace_layer_label.setProperty("class", f"workspace-layer {layer_type}")
327+
328+
# Set appropriate label text
329+
if workspace['layer'] == 'Tiling':
330+
self.workspace_layer_label.setText(self._toggle_workspace_layer['tiling_label'])
331+
elif workspace['layer'] == 'Floating':
332+
self.workspace_layer_label.setText(self._toggle_workspace_layer['floating_label'])
333+
self.workspace_layer_label.style().unpolish(self.workspace_layer_label)
334+
self.workspace_layer_label.style().polish(self.workspace_layer_label)
335+
else:
336+
self.workspace_layer_label.setProperty("class", "workspace-layer")
337+
self.workspace_layer_label.setText("")
338+
self.workspace_layer_label.style().unpolish(self.workspace_layer_label)
339+
self.workspace_layer_label.style().polish(self.workspace_layer_label)
340+
304341
def _update_button(self, workspace_btn: WorkspaceButton) -> None:
305342
workspace_index = workspace_btn.workspace_index
306343
workspace = self._komorebic.get_workspace_by_index(self._komorebi_screen, workspace_index)
@@ -311,13 +348,15 @@ def _update_button(self, workspace_btn: WorkspaceButton) -> None:
311348
workspace_btn.show()
312349
if workspace_btn.status != workspace_status:
313350
workspace_btn.update_and_redraw(workspace_status)
314-
if self._animation:
351+
if self._animation and workspace_btn._animation_initialized:
315352
workspace_btn.animate_buttons()
316353
workspace_btn.update_visible_buttons()
354+
self._get_workspace_layer(workspace_index)
355+
workspace_btn._animation_initialized = True
317356

318357
def _add_or_update_buttons(self) -> None:
319358
buttons_added = False
320-
for workspace_index, workspace in enumerate(self._komorebi_workspaces):
359+
for workspace_index, _ in enumerate(self._komorebi_workspaces):
321360
try:
322361
button = self._workspace_buttons[workspace_index]
323362
self._update_button(button)

0 commit comments

Comments
 (0)