87 lines
3.4 KiB
Python
87 lines
3.4 KiB
Python
## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/
|
|
##
|
|
## This program is free software; you can redistribute it and/or modify
|
|
## it under the terms of the GNU General Public License as published by
|
|
## the Free Software Foundation; either version 2 of the License, or
|
|
## (at your option) any later version.
|
|
##
|
|
## This program is distributed in the hope that it will be useful,
|
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
## GNU General Public License for more details.
|
|
##
|
|
## You should have received a copy of the GNU General Public License along
|
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
"""Singleton dialog hosting a PerKeyEditor for one sink at a time."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from enum import Enum
|
|
|
|
import gi
|
|
|
|
gi.require_version("Gtk", "3.0")
|
|
from gi.repository import Gtk # NOQA: E402
|
|
|
|
from solaar.i18n import _ # NOQA: E402
|
|
|
|
from .editor import PerKeyEditor # NOQA: E402
|
|
from .layout import Layout # NOQA: E402
|
|
from .protocol import PerKeyColorSink # NOQA: E402
|
|
|
|
|
|
class GtkSignal(Enum):
|
|
DELETE_EVENT = "delete-event"
|
|
|
|
|
|
class PerKeyEditorDialog:
|
|
_instance: "PerKeyEditorDialog | None" = None
|
|
|
|
def __init__(self) -> None:
|
|
self._window = Gtk.Window()
|
|
self._window.set_title(_("Per-key Lighting"))
|
|
# No default size or geometry hints — the editor's content size
|
|
# (driven by KeyboardCanvas's size_request) determines the window size
|
|
# via the ScrolledWindow's propagate_natural_size. Wide keyboards open
|
|
# large; small mice open small.
|
|
self._window.connect(GtkSignal.DELETE_EVENT.value, self._on_delete)
|
|
self._editor: PerKeyEditor | None = None
|
|
self._wrapper = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
|
|
self._wrapper.set_border_width(8)
|
|
self._window.add(self._wrapper)
|
|
|
|
def _on_delete(self, _w, _e) -> bool:
|
|
self._window.hide()
|
|
if self._editor is not None:
|
|
self._editor.shutdown()
|
|
self._wrapper.remove(self._editor)
|
|
self._editor = None
|
|
return True
|
|
|
|
def present(self, sink: PerKeyColorSink, layout: Layout | None) -> None:
|
|
if self._editor is not None:
|
|
self._editor.shutdown()
|
|
self._wrapper.remove(self._editor)
|
|
self._editor = None
|
|
self._editor = PerKeyEditor(sink, layout)
|
|
self._wrapper.pack_start(self._editor, True, True, 0)
|
|
self._wrapper.show_all()
|
|
self._window.set_title(_("Per-key Lighting") + " — " + sink.title)
|
|
# Ask GTK what the wrapper actually wants to be — the canvas's
|
|
# size_request propagates up through ScrolledWindow + editor VBox
|
|
# (toolbar + scrolled canvas) + the wrapper's border, so the
|
|
# natural size already accounts for every layout contribution
|
|
# rather than hardcoding "toolbar ~50, border 8 each side".
|
|
_min, nat = self._wrapper.get_preferred_size()
|
|
if nat.width > 0 and nat.height > 0:
|
|
self._window.resize(nat.width, nat.height)
|
|
self._window.present()
|
|
|
|
|
|
def get_dialog() -> PerKeyEditorDialog:
|
|
if PerKeyEditorDialog._instance is None:
|
|
PerKeyEditorDialog._instance = PerKeyEditorDialog()
|
|
return PerKeyEditorDialog._instance
|