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 @@
- 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)