From 96a77f024baf11655472f36025b15dfa97afbe45 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Jul 2017 10:23:30 +0200 Subject: [PATCH] Add ButtonsPage to configure buttons This commit adds the initial buttons page and a skeleton configuration dialog to configure button mappings. --- data/piper.gresource.xml | 1 + data/ui/ButtonDialog.ui | 163 +++++++++++++++++++++++++++++++++++++++ piper/buttondialog.py | 62 +++++++++++++++ piper/buttonspage.py | 76 ++++++++++++++++++ piper/window.py | 7 +- 5 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 data/ui/ButtonDialog.ui create mode 100644 piper/buttondialog.py create mode 100644 piper/buttonspage.py diff --git a/data/piper.gresource.xml b/data/piper.gresource.xml index a55c336..d64585e 100644 --- a/data/piper.gresource.xml +++ b/data/piper.gresource.xml @@ -4,6 +4,7 @@ 404.svg AboutDialog.ui + ui/ButtonDialog.ui ui/LedDialog.ui ui/OptionButton.ui ui/ResolutionRow.ui diff --git a/data/ui/ButtonDialog.ui b/data/ui/ButtonDialog.ui new file mode 100644 index 0000000..4ebd15a --- /dev/null +++ b/data/ui/ButtonDialog.ui @@ -0,0 +1,163 @@ + + + + + + diff --git a/piper/buttondialog.py b/piper/buttondialog.py new file mode 100644 index 0000000..6279636 --- /dev/null +++ b/piper/buttondialog.py @@ -0,0 +1,62 @@ +# Copyright (C) 2017 Jente Hidskes +# +# 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. + +from .gi_composites import GtkTemplate + +import gi +gi.require_version("Gtk", "3.0") +from gi.repository import GObject, Gtk + + +@GtkTemplate(ui="/org/freedesktop/Piper/ui/ButtonDialog.ui") +class ButtonDialog(Gtk.Dialog): + """A Gtk.Dialog subclass to implement the dialog that shows the + configuration options for button mappings.""" + + __gtype_name__ = "ButtonDialog" + + _BUTTON_TYPE_TO_PAGE = { + RatbagdButton.ACTION_TYPE_BUTTON: "mapping", + RatbagdButton.ACTION_TYPE_SPECIAL: "special", + RatbagdButton.ACTION_TYPE_KEY: "mapping", + RatbagdButton.ACTION_TYPE_MACRO: "macro", + } + + stack = GtkTemplate.Child() + + def __init__(self, ratbagd_button, *args, **kwargs): + """Instantiates a new ButtonDialog. + + @param ratbagd_button The button to configure, as ratbagd.RatbagdButton. + """ + Gtk.Dialog.__init__(self, *args, **kwargs) + self.init_template() + self._button = ratbagd_button + self._action_type = self._button.action_type + + self._init_ui() + + def _init_ui(self): + action_types = self._button.action_types + for action_type in action_types: + page = self._BUTTON_TYPE_TO_PAGE[action_type] + self.stack.get_child_by_name(page).set_visible(True) + if self._action_type == action_type: + self.stack.set_visible_child_name(page) + + @GObject.Property + def action_type(self): + return self._action_type diff --git a/piper/buttonspage.py b/piper/buttonspage.py new file mode 100644 index 0000000..f23cd4b --- /dev/null +++ b/piper/buttonspage.py @@ -0,0 +1,76 @@ +# Copyright (C) 2017 Jente Hidskes +# +# 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. + +from gettext import gettext as _ + +from .buttondialog import ButtonDialog +from .mousemap import MouseMap +from .optionbutton import OptionButton + +import gi +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + + +class ButtonsPage(Gtk.Box): + """The second stack page, exposing the button configuration.""" + + __gtype_name__ = "ButtonsPage" + + def __init__(self, ratbagd_device, *args, **kwargs): + """Instantiates a new ButtonsPage. + + @param ratbag_device The ratbag device to configure, as + ratbagd.RatbagdDevice + """ + Gtk.Box.__init__(self, *args, **kwargs) + self._device = ratbagd_device + self._init_ui() + + def _init_ui(self): + profile = self._find_active_profile() + + mousemap = MouseMap("#Buttons", self._device, spacing=20, border_width=20) + self.pack_start(mousemap, True, True, 0) + + sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) + for ratbagd_button in profile.buttons: + index = ratbagd_button.index + # TODO: add the correct *mapping to the label + button = OptionButton(_("Button {}").format(index)) + button.connect("clicked", self._on_button_clicked, ratbagd_button) + mousemap.add(button, "#button{}".format(index)) + sizegroup.add_widget(button) + + def _on_button_clicked(self, button, ratbagd_button): + # Presents the ButtonDialog to configure the mouse button corresponding + # to the clicked button. + dialog = ButtonDialog(ratbagd_button, transient_for=self.get_toplevel()) + dialog.connect("response", self._on_dialog_response, ratbagd_button) + dialog.present() + + def _on_dialog_response(self, dialog, response, ratbagd_button): + # The user either pressed cancel or apply. If it's apply, apply the + # changes before closing the dialog, otherwise just close the dialog. + if response == Gtk.ResponseType.APPLY: + print("Apply") + dialog.destroy() + + def _find_active_profile(self): + # Finds the active profile, which is guaranteed to exist. + for profile in self._device.profiles: + if profile.is_active: + return profile diff --git a/piper/window.py b/piper/window.py index ad26914..ed95d9c 100644 --- a/piper/window.py +++ b/piper/window.py @@ -16,6 +16,7 @@ from gettext import gettext as _ +from .buttonspage import ButtonsPage from .gi_composites import GtkTemplate from .ratbagd import RatbagErrorCode, RatbagdDevice from .resolutionspage import ResolutionsPage @@ -30,8 +31,8 @@ from gi.repository import GLib, Gtk class Window(Gtk.ApplicationWindow): """A Gtk.ApplicationWindow subclass to implement the main application window. This Window contains the overlay for the in-app notifications, the - headerbar and the stack holding a ResolutionsPage, a ButtonPage and a - LEDPage.""" + headerbar and the stack holding a ResolutionsPage, a ButtonsPage and a + LedsPage.""" __gtype_name__ = "ApplicationWindow" @@ -60,6 +61,8 @@ class Window(Gtk.ApplicationWindow): capabilities = self._device.capabilities if RatbagdDevice.CAP_RESOLUTION in capabilities: self.stack.add_titled(ResolutionsPage(self._device), "resolutions", _("Resolutions")) + if RatbagdDevice.CAP_BUTTON in capabilities: + self.stack.add_titled(ButtonsPage(self._device), "buttons", _("Buttons")) if RatbagdDevice.CAP_LED in capabilities: self.stack.add_titled(LedsPage(self._device), "leds", _("LEDs")) except ValueError as e: