mirror of
https://github.com/libratbag/piper.git
synced 2026-04-21 14:57:46 -04:00
Introduce perspectives to manage different screens
The welcome and error screens both require a different "perspective" into Piper, while being in the same window. For this reason, we introduce a titlebar and a regular stack and the concept of a "perspective", which is defined as a certain view into Piper. A perspective needs to implement an interface of sorts of two methods: one to retrieve its string name, and another to retrieve its widget titlebar. Different scenarios can then show different perspectives, that have full control over the main widget and the titlebar displayed. This commit introduces the MousePerspective, which is a perspective showing the mouse configuration. Future commits will add an ErrorPerspective and a WelcomePerspective, and even further into the future we can add a KeyboardPerspective as well.
This commit is contained in:
committed by
Peter Hutterer
parent
d452c50e6b
commit
52bb5e3781
@@ -7,9 +7,10 @@
|
||||
<file preprocess="xml-stripblanks">AboutDialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/ButtonDialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/ButtonRow.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/MousePerspective.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/LedDialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/OptionButton.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/ProfileRow.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/ProfileRow.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/ResolutionRow.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/ResolutionsPage.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/Window.ui</file>
|
||||
|
||||
202
data/ui/MousePerspective.ui
Normal file
202
data/ui/MousePerspective.ui
Normal file
@@ -0,0 +1,202 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.20.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<template class="MousePerspective" parent="GtkOverlay">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="transition_duration">400</property>
|
||||
<property name="transition_type">slide-left-right</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="index">-1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="overlay">
|
||||
<object class="GtkRevealer" id="notification_commit">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="transition_duration">100</property>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="notification_commit_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_right">30</property>
|
||||
<property name="margin_end">30</property>
|
||||
<property name="label" translatable="yes">Failed to commit changes to the device</property>
|
||||
<property name="ellipsize">middle</property>
|
||||
<property name="max_width_chars">50</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="notification_commit_close">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="relief">none</property>
|
||||
<signal name="clicked" handler="_on_notification_commit_close_clicked" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">window-close-symbolic</property>
|
||||
<property name="icon_size">2</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="app-notification"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<object class="GtkHeaderBar" id="_titlebar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Select another profile</property>
|
||||
<property name="popover">popover_profiles</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_profile">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Profile 1</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="track_visited_links">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Commit the changes to the device</property>
|
||||
<signal name="clicked" handler="_on_save_button_clicked" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-save-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="titlebar"/>
|
||||
</style>
|
||||
</object>
|
||||
<object class="GtkPopover" id="popover_profiles">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">2</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<property name="propagate_natural_width">True</property>
|
||||
<property name="propagate_natural_height">True</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="listbox_profiles">
|
||||
<property name="width_request">180</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Click to switch to another profile</property>
|
||||
<signal name="row-activated" handler="_on_profile_row_activated" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_profile_button">
|
||||
<property name="label" translatable="yes">Add profile</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Add a new profile to the device</property>
|
||||
<signal name="clicked" handler="_on_add_profile_button_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -2,203 +2,27 @@
|
||||
<!-- Generated with glade 3.20.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkPopover" id="popover_profiles">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">2</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<property name="propagate_natural_width">True</property>
|
||||
<property name="propagate_natural_height">True</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="listbox_profiles">
|
||||
<property name="width_request">180</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Click to switch to another profile</property>
|
||||
<signal name="row-activated" handler="_on_profile_row_activated" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_profile_button">
|
||||
<property name="label" translatable="yes">Add profile</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Add a new profile to the device</property>
|
||||
<signal name="clicked" handler="_on_add_profile_button_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<template class="Window" parent="GtkApplicationWindow">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkOverlay">
|
||||
<object class="GtkStack" id="stack_perspectives">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="transition_duration">300</property>
|
||||
<property name="transition_type">crossfade</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="transition_duration">400</property>
|
||||
<property name="transition_type">slide-left-right</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="index">-1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="overlay">
|
||||
<object class="GtkRevealer" id="notification_commit">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="transition_duration">100</property>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="notification_commit_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_right">30</property>
|
||||
<property name="margin_end">30</property>
|
||||
<property name="label" translatable="yes">Failed to commit changes to the device</property>
|
||||
<property name="ellipsize">middle</property>
|
||||
<property name="max_width_chars">50</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="notification_commit_close">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="relief">none</property>
|
||||
<signal name="clicked" handler="_on_notification_commit_close_clicked" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">window-close-symbolic</property>
|
||||
<property name="icon_size">2</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="app-notification"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<object class="GtkStack" id="stack_titlebar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<property name="hhomogeneous">False</property>
|
||||
<property name="vhomogeneous">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Select another profile</property>
|
||||
<property name="popover">popover_profiles</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_profile">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Profile 1</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="track_visited_links">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Commit the changes to the device</property>
|
||||
<signal name="clicked" handler="_on_save_button_clicked" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-save-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
133
piper/mouseperspective.py
Normal file
133
piper/mouseperspective.py
Normal file
@@ -0,0 +1,133 @@
|
||||
# Copyright (C) 2017 Jente Hidskes <hjdskes@gmail.com>
|
||||
#
|
||||
# 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 .buttonspage import ButtonsPage
|
||||
from .gi_composites import GtkTemplate
|
||||
from .profilerow import ProfileRow
|
||||
from .ratbagd import RatbagErrorCode, RatbagdDevice
|
||||
from .resolutionspage import ResolutionsPage
|
||||
from .ledspage import LedsPage
|
||||
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import GLib, GObject, Gtk
|
||||
|
||||
|
||||
@GtkTemplate(ui="/org/freedesktop/Piper/ui/MousePerspective.ui")
|
||||
class MousePerspective(Gtk.Overlay):
|
||||
"""The perspective to configure a mouse."""
|
||||
|
||||
__gtype_name__ = "MousePerspective"
|
||||
|
||||
_titlebar = GtkTemplate.Child()
|
||||
stack = GtkTemplate.Child()
|
||||
notification_commit = GtkTemplate.Child()
|
||||
listbox_profiles = GtkTemplate.Child()
|
||||
label_profile = GtkTemplate.Child()
|
||||
add_profile_button = GtkTemplate.Child()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Instantiates a new MousePerspective."""
|
||||
Gtk.Overlay.__init__(self, *args, **kwargs)
|
||||
self.init_template()
|
||||
self._device = None
|
||||
self._notification_commit_timeout_id = 0
|
||||
|
||||
@GObject.Property
|
||||
def name(self):
|
||||
"""The name of this perspective."""
|
||||
return "mouse_perspective"
|
||||
|
||||
@GObject.Property
|
||||
def titlebar(self):
|
||||
"""The titlebar to this perspective."""
|
||||
return self._titlebar
|
||||
|
||||
def set_device(self, device):
|
||||
self._device = device
|
||||
capabilities = device.capabilities
|
||||
|
||||
self.stack.foreach(Gtk.Widget.destroy)
|
||||
if RatbagdDevice.CAP_RESOLUTION in capabilities:
|
||||
self.stack.add_titled(ResolutionsPage(device), "resolutions", _("Resolutions"))
|
||||
if RatbagdDevice.CAP_BUTTON in capabilities:
|
||||
self.stack.add_titled(ButtonsPage(device), "buttons", _("Buttons"))
|
||||
if RatbagdDevice.CAP_LED in capabilities:
|
||||
self.stack.add_titled(LedsPage(device), "leds", _("LEDs"))
|
||||
|
||||
active_profile = device.active_profile
|
||||
self.label_profile.set_label(_("Profile {}").format(active_profile.index + 1))
|
||||
|
||||
# Find the first profile that is enabled. If there is none, disable the
|
||||
# add button.
|
||||
left = next((p for p in device.profiles if not p.enabled), None)
|
||||
self.add_profile_button.set_sensitive(left is not None)
|
||||
|
||||
for profile in device.profiles:
|
||||
profile.connect("notify::enabled", self._on_profile_notify_enabled)
|
||||
row = ProfileRow(profile)
|
||||
self.listbox_profiles.insert(row, profile.index)
|
||||
if profile == active_profile:
|
||||
self.listbox_profiles.select_row(row)
|
||||
|
||||
def _hide_notification_commit(self):
|
||||
if self._notification_commit_timeout_id is not 0:
|
||||
GLib.Source.remove(self._notification_commit_timeout_id)
|
||||
self._notification_commit_timeout_id = 0
|
||||
self.notification_commit.set_reveal_child(False)
|
||||
|
||||
def _show_notification_commit(self):
|
||||
self.notification_commit.set_reveal_child(True)
|
||||
self._notification_commit_timeout_id = GLib.timeout_add_seconds(5,
|
||||
self._on_notification_commit_timeout)
|
||||
|
||||
def _on_notification_commit_timeout(self):
|
||||
self._hide_notification_commit()
|
||||
return False
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_save_button_clicked(self, button):
|
||||
status = self._device.commit()
|
||||
if not status == RatbagErrorCode.RATBAG_SUCCESS:
|
||||
self._show_notification_commit()
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_notification_commit_close_clicked(self, button):
|
||||
self._hide_notification_commit()
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_profile_row_activated(self, listbox, row):
|
||||
row.set_active()
|
||||
self.label_profile.set_label(row.name)
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_add_profile_button_clicked(self, button):
|
||||
# Enable the first disabled profile we find.
|
||||
for profile in self._device.profiles:
|
||||
if profile.enabled:
|
||||
continue
|
||||
profile.enabled = True
|
||||
if profile == self._device.profiles[-1]:
|
||||
self.add_profile_button.set_sensitive(False)
|
||||
break
|
||||
|
||||
def _on_profile_notify_enabled(self, profile, pspec):
|
||||
# We're only interested in the case where the last profile is disabled,
|
||||
# so that we can reset the sensitivity of the add button.
|
||||
if not profile.enabled and profile == self._device.profiles[-1]:
|
||||
self.add_profile_button.set_sensitive(True)
|
||||
149
piper/window.py
149
piper/window.py
@@ -16,12 +16,8 @@
|
||||
|
||||
from gettext import gettext as _
|
||||
|
||||
from .buttonspage import ButtonsPage
|
||||
from .gi_composites import GtkTemplate
|
||||
from .profilerow import ProfileRow
|
||||
from .ratbagd import RatbagErrorCode, RatbagdDevice
|
||||
from .resolutionspage import ResolutionsPage
|
||||
from .ledspage import LedsPage
|
||||
from .mouseperspective import MousePerspective
|
||||
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
@@ -31,17 +27,13 @@ from gi.repository import GLib, Gtk
|
||||
@GtkTemplate(ui="/org/freedesktop/Piper/ui/Window.ui")
|
||||
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 ButtonsPage and a
|
||||
LedsPage."""
|
||||
window. This window displays the different perspectives (error, mouse and
|
||||
welcome) that each present their own behavior."""
|
||||
|
||||
__gtype_name__ = "Window"
|
||||
|
||||
stack = GtkTemplate.Child()
|
||||
notification_commit = GtkTemplate.Child()
|
||||
listbox_profiles = GtkTemplate.Child()
|
||||
label_profile = GtkTemplate.Child()
|
||||
add_profile_button = GtkTemplate.Child()
|
||||
stack_titlebar = GtkTemplate.Child()
|
||||
stack_perspectives = GtkTemplate.Child()
|
||||
|
||||
def __init__(self, ratbag, *args, **kwargs):
|
||||
"""Instantiates a new Window.
|
||||
@@ -51,112 +43,41 @@ class Window(Gtk.ApplicationWindow):
|
||||
Gtk.ApplicationWindow.__init__(self, *args, **kwargs)
|
||||
self.init_template()
|
||||
|
||||
perspectives = [MousePerspective()]
|
||||
for perspective in perspectives:
|
||||
self._add_perspective(perspective)
|
||||
|
||||
if ratbag is None:
|
||||
self._present_error_dialog("Cannot connect to ratbagd")
|
||||
return
|
||||
self._present_error_perspective(_("Cannot connect to ratbagd"))
|
||||
elif len(ratbag.devices) == 0:
|
||||
self._present_error_perspective(_("Cannot find any devices"))
|
||||
elif len(ratbag.devices) == 1:
|
||||
self._present_mouse_perspective(ratbag.devices[0])
|
||||
else:
|
||||
self._present_welcome_perspective(ratbag.devices)
|
||||
|
||||
self._ratbag = ratbag
|
||||
self._device = self._fetch_ratbag_device()
|
||||
if self._device is None:
|
||||
self._present_error_dialog("No devices found")
|
||||
return
|
||||
def _add_perspective(self, perspective):
|
||||
self.stack_perspectives.add_named(perspective, perspective.name)
|
||||
self.stack_titlebar.add_named(perspective.titlebar, perspective.name)
|
||||
|
||||
self._setup_pages()
|
||||
self._setup_profiles()
|
||||
def _present_welcome_perspective(self, devices):
|
||||
# Present the welcome perspective for the user to select one of their
|
||||
# devices.
|
||||
pass
|
||||
|
||||
def _setup_pages(self):
|
||||
def _present_mouse_perspective(self, device):
|
||||
# Present the mouse configuration perspective for the given device.
|
||||
try:
|
||||
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"))
|
||||
mouse_perspective = self.stack_perspectives.get_child_by_name("mouse_perspective")
|
||||
mouse_perspective.set_device(device)
|
||||
|
||||
self.stack_titlebar.set_visible_child_name(mouse_perspective.name)
|
||||
self.stack_perspectives.set_visible_child_name(mouse_perspective.name)
|
||||
except ValueError as e:
|
||||
self._present_error_dialog(e)
|
||||
self._present_error_perspective(e)
|
||||
except GLib.Error as e:
|
||||
self._present_error_dialog(e.message)
|
||||
self._present_error_perspective(e.message)
|
||||
|
||||
def _setup_profiles(self):
|
||||
active_profile = self._device.active_profile
|
||||
self.label_profile.set_label(_("Profile {}").format(active_profile.index + 1))
|
||||
|
||||
# Find the first profile that is enabled. If there is none, disable the
|
||||
# add button.
|
||||
left = next((p for p in self._device.profiles if not p.enabled), None)
|
||||
self.add_profile_button.set_sensitive(left is not None)
|
||||
|
||||
for profile in self._device.profiles:
|
||||
profile.connect("notify::enabled", self._on_profile_notify_enabled)
|
||||
row = ProfileRow(profile)
|
||||
self.listbox_profiles.insert(row, profile.index)
|
||||
if profile == active_profile:
|
||||
self.listbox_profiles.select_row(row)
|
||||
|
||||
def _present_error_dialog(self, message):
|
||||
# Present an error dialog informing the user of any errors.
|
||||
# TODO: this should be something in the window, not a print
|
||||
print("Cannot create window: {}".format(message))
|
||||
|
||||
def _fetch_ratbag_device(self):
|
||||
"""Get the first ratbag device available. If there are multiple
|
||||
devices, an error message is printed and we default to the first
|
||||
one. Otherwise, an error is shown and we return None.
|
||||
"""
|
||||
# TODO: replace with better implementation once we go for the welcome screen.
|
||||
if len(self._ratbag.devices) == 0:
|
||||
print("Could not find any devices. Do you have anything vaguely mouse-looking plugged in?")
|
||||
return None
|
||||
elif len(self._ratbag.devices) > 1:
|
||||
print("Ooops, can't deal with more than one device. My bad.")
|
||||
for d in self._ratbag.devices[1:]:
|
||||
print("Ignoring device {}".format(d.name))
|
||||
return self._ratbag.devices[0]
|
||||
|
||||
def _hide_notification_commit(self):
|
||||
if self._notification_commit_timeout_id is not 0:
|
||||
GLib.Source.remove(self._notification_commit_timeout_id)
|
||||
self._notification_commit_timeout_id = 0
|
||||
self.notification_commit.set_reveal_child(False)
|
||||
|
||||
def _show_notification_commit(self):
|
||||
self.notification_commit.set_reveal_child(True)
|
||||
self._notification_commit_timeout_id = GLib.timeout_add_seconds(5,
|
||||
self._on_notification_commit_timeout)
|
||||
|
||||
def _on_notification_commit_timeout(self):
|
||||
self._hide_notification_commit()
|
||||
return False
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_save_button_clicked(self, button):
|
||||
status = self._device.commit()
|
||||
if not status == RatbagErrorCode.RATBAG_SUCCESS:
|
||||
self._show_notification_commit()
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_notification_commit_close_clicked(self, button):
|
||||
self._hide_notification_commit()
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_profile_row_activated(self, listbox, row):
|
||||
row.set_active()
|
||||
self.label_profile.set_label(row.name)
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def _on_add_profile_button_clicked(self, button):
|
||||
# Enable the first disabled profile we find.
|
||||
for profile in self._device.profiles:
|
||||
if profile.enabled:
|
||||
continue
|
||||
profile.enabled = True
|
||||
if profile == self._device.profiles[-1]:
|
||||
self.add_profile_button.set_sensitive(False)
|
||||
break
|
||||
|
||||
def _on_profile_notify_enabled(self, profile, pspec):
|
||||
# We're only interested in the case where the last profile is disabled,
|
||||
# so that we can reset the sensitivity of the add button.
|
||||
if not profile.enabled and profile == self._device.profiles[-1]:
|
||||
self.add_profile_button.set_sensitive(True)
|
||||
def _present_error_perspective(self, message):
|
||||
# Present the error perspective informing the user of any errors.
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user