From 0773bbcbca0b0099cb85309a1fefc1687bf1f88e Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Jul 2017 12:30:52 +0200 Subject: [PATCH] ButtonDialog: add button map page --- data/ui/ButtonDialog.ui | 90 +++++++++++++++++++++++++++++++---------- piper/buttondialog.py | 45 +++++++++++++++++++-- piper/buttonspage.py | 7 +++- piper/ratbagd.py | 11 +++++ 4 files changed, 126 insertions(+), 27 deletions(-) diff --git a/data/ui/ButtonDialog.ui b/data/ui/ButtonDialog.ui index 4ebd15a..7c3aabd 100644 --- a/data/ui/ButtonDialog.ui +++ b/data/ui/ButtonDialog.ui @@ -43,34 +43,80 @@ False + True vertical + 6 - + + True + False + Button- and key mappings allow you to assign to a physical mouse button another +logical mouse button or a sequence of keypresses. This way you may for example +make the right mouse button perform a left click, or execute the keystroke Ctrl+R with +a click on the right mouse button. + center + True + False + + + True + True + 0 + + + + + True + False + + + True + False + Assign another logical mouse button to this button + end + True + + + + False + + + + + False + True + end + 0 + + + + + True + False + start + Assign a button mapping: + False + + + False + True + 1 + + + + + False + True + 1 + - button - Button Mapping - - - - - False - vertical - - - - - - - - - key - Key Mapping - 1 + mapping + Mapping @@ -87,7 +133,7 @@ special Key Sequence - 2 + 1 @@ -104,7 +150,7 @@ macro Custom - 3 + 2 diff --git a/piper/buttondialog.py b/piper/buttondialog.py index 6279636..1dcff7a 100644 --- a/piper/buttondialog.py +++ b/piper/buttondialog.py @@ -14,7 +14,10 @@ # 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 .gi_composites import GtkTemplate +from .ratbagd import RatbagdButton import gi gi.require_version("Gtk", "3.0") @@ -36,20 +39,24 @@ class ButtonDialog(Gtk.Dialog): } stack = GtkTemplate.Child() + combo_mapping = GtkTemplate.Child() - def __init__(self, ratbagd_button, *args, **kwargs): + def __init__(self, ratbagd_button, buttons, *args, **kwargs): """Instantiates a new ButtonDialog. @param ratbagd_button The button to configure, as ratbagd.RatbagdButton. + @param buttons The buttons on this device, as [ratbagd.RatbagdButton]. """ Gtk.Dialog.__init__(self, *args, **kwargs) self.init_template() self._button = ratbagd_button self._action_type = self._button.action_type + self._button_mapping = ratbagd_button.mapping - self._init_ui() + self._init_mapping_page(buttons) + self._activate_current_page() - def _init_ui(self): + def _activate_current_page(self): action_types = self._button.action_types for action_type in action_types: page = self._BUTTON_TYPE_TO_PAGE[action_type] @@ -57,6 +64,38 @@ class ButtonDialog(Gtk.Dialog): if self._action_type == action_type: self.stack.set_visible_child_name(page) + def _init_mapping_page(self, buttons): + # Initializes the mapping stack page. First adds the semantic + # description of all buttons' logical button assignments to the combobox + # (activating the current applied item, if any) and secondly it adds the + # item that triggers a key map configuration. + for button in buttons: + key, name = self._get_button_key_and_name(button) + self.combo_mapping.append(key, name) + if self._button_mapping > 0 and button == self._button: + self.combo_mapping.set_active_id(key) + + def _get_button_key_and_name(self, button): + if button.index in RatbagdButton.BUTTON_DESCRIPTION: + name = RatbagdButton.BUTTON_DESCRIPTION[button.index] + else: + name = _("Button {} click").format(button.index) + return str(button.index + 1), name # Logical buttons are 1-indexed. + + @GtkTemplate.Callback + def _on_mapping_changed(self, combo): + tree_iter = combo.get_active_iter() + if tree_iter is None: + return + model = combo.get_model() + mapping = int(model[tree_iter][1]) + if mapping != self._button_mapping: + self._button_mapping = mapping + @GObject.Property def action_type(self): return self._action_type + + @GObject.Property + def button_mapping(self): + return self._button_mapping diff --git a/piper/buttonspage.py b/piper/buttonspage.py index f23cd4b..2b61c08 100644 --- a/piper/buttonspage.py +++ b/piper/buttonspage.py @@ -19,6 +19,7 @@ from gettext import gettext as _ from .buttondialog import ButtonDialog from .mousemap import MouseMap from .optionbutton import OptionButton +from .ratbagd import RatbagdButton import gi gi.require_version("Gtk", "3.0") @@ -58,7 +59,8 @@ class ButtonsPage(Gtk.Box): 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()) + buttons = self._find_active_profile().buttons + dialog = ButtonDialog(ratbagd_button, buttons, transient_for=self.get_toplevel()) dialog.connect("response", self._on_dialog_response, ratbagd_button) dialog.present() @@ -66,7 +68,8 @@ class ButtonsPage(Gtk.Box): # 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") + if dialog.action_type == RatbagdButton.ACTION_TYPE_BUTTON: + ratbagd_button.mapping = dialog.button_mapping dialog.destroy() def _find_active_profile(self): diff --git a/piper/ratbagd.py b/piper/ratbagd.py index 932ba7b..3d06d80 100644 --- a/piper/ratbagd.py +++ b/piper/ratbagd.py @@ -25,6 +25,7 @@ import os import sys from enum import IntEnum +from gettext import gettext as _ from gi.repository import Gio, GLib, GObject @@ -519,6 +520,16 @@ class RatbagdButton(_RatbagdDBus): TYPE_PROFILE_UP = 22 TYPE_PROFILE_DOWN = 23 + """A table mapping a button's index to its usual function as defined by X + and the common desktop environments.""" + BUTTON_DESCRIPTION = { + 0: _("Left mouse button click"), + 1: _("Right mouse button click"), + 2: _("Middle mouse button click"), + 3: _("Backward"), + 4: _("Forward"), + } + def __init__(self, object_path): _RatbagdDBus.__init__(self, "Button", object_path)