From 149f0c3ec14e535eb93804e9dc1b5098393d25f4 Mon Sep 17 00:00:00 2001 From: Dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 25 May 2024 19:21:43 +0100 Subject: [PATCH 01/17] Add dpi_entry GtkEntry objects to UI file and Python. Find and apply closest resolution in self.resolutions. [Needed?] Store value on textbox focus in. [Needed?] Do not apply DPI value if the same as previous value. DPI entry and resolution sliders affect each others' values. --- data/ui/ResolutionRow.ui | 11 +++++++++- piper/resolutionrow.py | 43 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/data/ui/ResolutionRow.ui b/data/ui/ResolutionRow.ui index 0fca3c81..242704d2 100644 --- a/data/ui/ResolutionRow.ui +++ b/data/ui/ResolutionRow.ui @@ -16,12 +16,21 @@ False 12 6 + + + True + start + 5 + + + + True False start - 0 DPI + DPI True diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 8c295e8f..9835900f 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -22,6 +22,7 @@ class ResolutionRow(Gtk.ListBoxRow): active_label: Gtk.Label = Gtk.Template.Child() # type: ignore disable_button: Gtk.Button = Gtk.Template.Child() # type: ignore dpi_label: Gtk.Label = Gtk.Template.Child() # type: ignore + dpi_entry: Gtk.Entry = Gtk.Template.Child() # type: ignore revealer: Gtk.Revealer = Gtk.Template.Child() # type: ignore scale: Gtk.Scale = Gtk.Template.Child() # type: ignore @@ -33,6 +34,7 @@ def __init__(self, resolution: RatbagdResolution, *args, **kwargs) -> None: self._resolution = resolution self.resolutions = resolution.resolutions + self.previous_dpi_entry_value = None self._scale_handler = self.scale.connect( "value-changed", self._on_scale_value_changed ) @@ -49,6 +51,7 @@ def __init__(self, resolution: RatbagdResolution, *args, **kwargs) -> None: connect_signal_with_weak_ref( self, resolution, "notify::resolution", self._on_profile_resolution_changed ) + self.dpi_entry.connect("focus-in-event", self._on_entry_focus_in) # Get resolution capabilities and update internal values. if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in resolution.capabilities: @@ -60,6 +63,12 @@ def __init__(self, resolution: RatbagdResolution, *args, **kwargs) -> None: res = resolution.resolution[0] minres = resolution.resolutions[0] maxres = resolution.resolutions[-1] + res_num_chars = len(str(maxres)) + + # Set the max width and length for the DPI text boxes, based on the max res value. + self.dpi_entry.set_size_request(res_num_chars, 1) + self.dpi_entry.set_max_length(res_num_chars) + with self.scale.handler_block(self._scale_handler): self.scale.props.adjustment.configure(res, minres, maxres, 50, 50, 0) self.scale.set_value(res) @@ -82,6 +91,7 @@ def _on_change_value( value = lo if value - lo < hi - value else hi scale.set_value(value) + self.dpi_entry.set_text(str(value)) # libratbag provides a fake-exponential range with the deltas # increasing as the resolution goes up. Make sure we set our @@ -94,6 +104,35 @@ def _on_change_value( return True + @Gtk.Template.Callback("_on_insert_dpi_entry_text") + def _on_insert_dpi_entry_text(self, entry, text, length, position): + # Remove any non-numeric characters from the input + new_text = "".join([c for c in text if c.isdigit()]) + if new_text != text: + entry.stop_emission("insert-text") + entry.insert_text(new_text, len(new_text)) + + @Gtk.Template.Callback("_on_dpi_entry_activate") + def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: + # The DPI entry has been changed, update the scale and RatbagdResolution's resolution. + try: + res = int(entry.get_text()) + # Get the resolution closest to what has been entered + closest_res = min(self.resolutions, key=lambda x: abs(x - res)) + entry.set_text(str(closest_res)) + if closest_res != self.previous_dpi_entry_value: + self._on_dpi_values_changed(res=res) + with self.scale.handler_block(self._scale_handler): + self.scale.set_value(res) + except ValueError: + # If the input is not a valid integer, reset to the current value. + entry.set_text(str(self._resolution.resolution[0])) + + def _on_entry_focus_in(self, entry, event): + # Store previous value + self.previous_dpi_entry_value = int(entry.get_text()) + return False # Continue handling the event + def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: # The disable button has been toggled, update RatbagdResolution. self._resolution.set_disabled(togglebutton.get_active()) @@ -153,7 +192,7 @@ def _on_dpi_values_changed(self, res: Optional[int] = None) -> None: if res is None: res = self._resolution.resolution[0] new_res = (res, res) if self.CAP_SEPARATE_XY_RESOLUTION else (res,) - self.dpi_label.set_text(f"{res} DPI") + self.dpi_entry.set_text(str(res)) # Only update new resolution if changed if new_res != self._resolution.resolution: @@ -165,4 +204,4 @@ def _on_profile_resolution_changed( with self.scale.handler_block(self._scale_handler): res = resolution.resolution[0] self.scale.set_value(res) - self.dpi_label.set_text(f"{res} DPI") + self.dpi_entry.set_text(str(res)) From d426383b8f7af8aba86935894a385898a0b32e51 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 25 May 2024 20:32:42 +0100 Subject: [PATCH 02/17] Remove pointless recursive logic. Remove focus methods. --- piper/resolutionrow.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 9835900f..84effbd6 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -51,7 +51,6 @@ def __init__(self, resolution: RatbagdResolution, *args, **kwargs) -> None: connect_signal_with_weak_ref( self, resolution, "notify::resolution", self._on_profile_resolution_changed ) - self.dpi_entry.connect("focus-in-event", self._on_entry_focus_in) # Get resolution capabilities and update internal values. if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in resolution.capabilities: @@ -107,10 +106,8 @@ def _on_change_value( @Gtk.Template.Callback("_on_insert_dpi_entry_text") def _on_insert_dpi_entry_text(self, entry, text, length, position): # Remove any non-numeric characters from the input - new_text = "".join([c for c in text if c.isdigit()]) - if new_text != text: + if not text.isdigit(): entry.stop_emission("insert-text") - entry.insert_text(new_text, len(new_text)) @Gtk.Template.Callback("_on_dpi_entry_activate") def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: @@ -128,11 +125,6 @@ def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: # If the input is not a valid integer, reset to the current value. entry.set_text(str(self._resolution.resolution[0])) - def _on_entry_focus_in(self, entry, event): - # Store previous value - self.previous_dpi_entry_value = int(entry.get_text()) - return False # Continue handling the event - def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: # The disable button has been toggled, update RatbagdResolution. self._resolution.set_disabled(togglebutton.get_active()) From 845465da0b532b56101f2cb6f16ac1b586d68d00 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 25 May 2024 21:02:46 +0100 Subject: [PATCH 03/17] Calculate DPI text box width based on max supported resolution. --- data/ui/ResolutionRow.ui | 1 - piper/resolutionrow.py | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/data/ui/ResolutionRow.ui b/data/ui/ResolutionRow.ui index 242704d2..4c1b5ad7 100644 --- a/data/ui/ResolutionRow.ui +++ b/data/ui/ResolutionRow.ui @@ -20,7 +20,6 @@ True start - 5 diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 84effbd6..b592bb4a 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -65,7 +65,7 @@ def __init__(self, resolution: RatbagdResolution, *args, **kwargs) -> None: res_num_chars = len(str(maxres)) # Set the max width and length for the DPI text boxes, based on the max res value. - self.dpi_entry.set_size_request(res_num_chars, 1) + self.dpi_entry.set_width_chars(res_num_chars) self.dpi_entry.set_max_length(res_num_chars) with self.scale.handler_block(self._scale_handler): @@ -104,7 +104,7 @@ def _on_change_value( return True @Gtk.Template.Callback("_on_insert_dpi_entry_text") - def _on_insert_dpi_entry_text(self, entry, text, length, position): + def _on_insert_dpi_entry_text(self, entry, text, _length, _position): # Remove any non-numeric characters from the input if not text.isdigit(): entry.stop_emission("insert-text") @@ -117,8 +117,10 @@ def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: # Get the resolution closest to what has been entered closest_res = min(self.resolutions, key=lambda x: abs(x - res)) entry.set_text(str(closest_res)) + if closest_res != self.previous_dpi_entry_value: self._on_dpi_values_changed(res=res) + with self.scale.handler_block(self._scale_handler): self.scale.set_value(res) except ValueError: @@ -180,7 +182,7 @@ def toggle_revealer(self) -> None: def _on_dpi_values_changed(self, res: Optional[int] = None) -> None: # Freeze the notify::resolution signal from firing and - # update dpi label and resolution values. + # update DPI text box and resolution values. if res is None: res = self._resolution.resolution[0] new_res = (res, res) if self.CAP_SEPARATE_XY_RESOLUTION else (res,) From e0ffb07d5c3755b16ae80d2501eb393e34524840 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 25 May 2024 21:38:43 +0100 Subject: [PATCH 04/17] Renamed methods/signals to be consistent with current convention. --- data/ui/ResolutionRow.ui | 2 +- piper/resolutionrow.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/ui/ResolutionRow.ui b/data/ui/ResolutionRow.ui index 4c1b5ad7..8d08791e 100644 --- a/data/ui/ResolutionRow.ui +++ b/data/ui/ResolutionRow.ui @@ -21,7 +21,7 @@ True start - + diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index b592bb4a..dd85efd1 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -103,8 +103,8 @@ def _on_change_value( return True - @Gtk.Template.Callback("_on_insert_dpi_entry_text") - def _on_insert_dpi_entry_text(self, entry, text, _length, _position): + @Gtk.Template.Callback("_on_dpi_entry_insert_text") + def _on_dpi_entry_insert_text(self, entry, text, _length, _position): # Remove any non-numeric characters from the input if not text.isdigit(): entry.stop_emission("insert-text") From 24cc50118a53807c00bf3f7f9e66cc1492600587 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 25 May 2024 22:47:30 +0100 Subject: [PATCH 05/17] Add a 'focus-in-event' signal to the DPI entry field. Pass reference to ResolutionsPage when initialising ResolutionRow. Use reference to invoke `ResolutionsPage._on_row_activated()`. Do not toggle Revealer on DPI entry text box focus-in-event if Revealer is already expanded. Grammar: dpi -> DPI --- data/ui/ResolutionRow.ui | 3 ++- piper/resolutionrow.py | 58 +++++++++++++++++++++++----------------- piper/resolutionspage.py | 2 +- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/data/ui/ResolutionRow.ui b/data/ui/ResolutionRow.ui index 8d08791e..760db865 100644 --- a/data/ui/ResolutionRow.ui +++ b/data/ui/ResolutionRow.ui @@ -22,6 +22,7 @@ start + @@ -74,7 +75,7 @@ True True - Set this resolution's dpi + Set this resolution's DPI 0 0 False diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index dd85efd1..d06ee628 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -29,9 +29,12 @@ class ResolutionRow(Gtk.ListBoxRow): CAP_SEPARATE_XY_RESOLUTION = False CAP_DISABLE = False - def __init__(self, resolution: RatbagdResolution, *args, **kwargs) -> None: + def __init__( + self, resolution: RatbagdResolution, resolutions_page, *args, **kwargs + ) -> None: Gtk.ListBoxRow.__init__(self, *args, **kwargs) + self.resolutions_page = resolutions_page self._resolution = resolution self.resolutions = resolution.resolutions self.previous_dpi_entry_value = None @@ -103,30 +106,6 @@ def _on_change_value( return True - @Gtk.Template.Callback("_on_dpi_entry_insert_text") - def _on_dpi_entry_insert_text(self, entry, text, _length, _position): - # Remove any non-numeric characters from the input - if not text.isdigit(): - entry.stop_emission("insert-text") - - @Gtk.Template.Callback("_on_dpi_entry_activate") - def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: - # The DPI entry has been changed, update the scale and RatbagdResolution's resolution. - try: - res = int(entry.get_text()) - # Get the resolution closest to what has been entered - closest_res = min(self.resolutions, key=lambda x: abs(x - res)) - entry.set_text(str(closest_res)) - - if closest_res != self.previous_dpi_entry_value: - self._on_dpi_values_changed(res=res) - - with self.scale.handler_block(self._scale_handler): - self.scale.set_value(res) - except ValueError: - # If the input is not a valid integer, reset to the current value. - entry.set_text(str(self._resolution.resolution[0])) - def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: # The disable button has been toggled, update RatbagdResolution. self._resolution.set_disabled(togglebutton.get_active()) @@ -192,6 +171,35 @@ def _on_dpi_values_changed(self, res: Optional[int] = None) -> None: if new_res != self._resolution.resolution: self._resolution.resolution = new_res + @Gtk.Template.Callback("_on_dpi_entry_insert_text") + def _on_dpi_entry_insert_text(self, entry, text, _length, _position): + # Remove any non-numeric characters from the input + if not text.isdigit(): + entry.stop_emission("insert-text") + + @Gtk.Template.Callback("_on_dpi_entry_activate") + def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: + # The DPI entry has been changed, update the scale and RatbagdResolution's resolution. + try: + res = int(entry.get_text()) + # Get the resolution closest to what has been entered + closest_res = min(self.resolutions, key=lambda x: abs(x - res)) + entry.set_text(str(closest_res)) + + if closest_res != self.previous_dpi_entry_value: + self._on_dpi_values_changed(res=res) + + with self.scale.handler_block(self._scale_handler): + self.scale.set_value(res) + except ValueError: + # If the input is not a valid integer, reset to the current value. + entry.set_text(str(self._resolution.resolution[0])) + + @Gtk.Template.Callback("_on_dpi_entry_focus_in") + def _on_dpi_entry_focus_in(self, entry, event_focus): + if not self.revealer.get_reveal_child(): + self.resolutions_page._on_row_activated(None, self) + def _on_profile_resolution_changed( self, resolution: RatbagdResolution, pspec: GObject.ParamSpec ) -> None: diff --git a/piper/resolutionspage.py b/piper/resolutionspage.py index d5e3477f..1dd2fc14 100644 --- a/piper/resolutionspage.py +++ b/piper/resolutionspage.py @@ -63,7 +63,7 @@ def __init__( self.listbox.foreach(Gtk.Widget.destroy) for resolution in profile.resolutions: - row = ResolutionRow(resolution) + row = ResolutionRow(resolution, self) self.listbox.insert(row, resolution.index) @Gtk.Template.Callback("_on_row_activated") From 095308eea00bc1e66d4c748f4e683796c7d7ae11 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 25 May 2024 23:22:37 +0100 Subject: [PATCH 06/17] Add type hints. Prefix unused vars with underscores. Actioned suggested import order from linter. --- piper/resolutionrow.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index d06ee628..516a127d 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -4,11 +4,11 @@ import gi +from gi.repository import GObject, Gdk, Gtk # noqa from .ratbagd import RatbagdResolution from .util.gobject import connect_signal_with_weak_ref gi.require_version("Gtk", "3.0") -from gi.repository import GObject, Gdk, Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ResolutionRow.ui") @@ -114,12 +114,12 @@ def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: self._on_status_changed(self._resolution, pspec=None) @Gtk.Template.Callback("_on_active_button_clicked") - def _on_active_button_clicked(self, togglebutton: Gtk.Button) -> None: + def _on_active_button_clicked(self, _togglebutton: Gtk.Button) -> None: # The set active button has been clicked, update RatbagdResolution. self._resolution.set_active() @Gtk.Template.Callback("_on_scroll_event") - def _on_scroll_event(self, widget: Gtk.Widget, event: Gdk.EventScroll) -> bool: + def _on_scroll_event(self, widget: Gtk.Widget, _event: Gdk.EventScroll) -> bool: # Prevent a scroll in the list to get caught by the scale. GObject.signal_stop_emission_by_name(widget, "scroll-event") return False @@ -172,7 +172,9 @@ def _on_dpi_values_changed(self, res: Optional[int] = None) -> None: self._resolution.resolution = new_res @Gtk.Template.Callback("_on_dpi_entry_insert_text") - def _on_dpi_entry_insert_text(self, entry, text, _length, _position): + def _on_dpi_entry_insert_text( + self, entry: Gtk.Entry, text: str, _length: int, _position: int + ): # Remove any non-numeric characters from the input if not text.isdigit(): entry.stop_emission("insert-text") @@ -196,12 +198,12 @@ def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: entry.set_text(str(self._resolution.resolution[0])) @Gtk.Template.Callback("_on_dpi_entry_focus_in") - def _on_dpi_entry_focus_in(self, entry, event_focus): + def _on_dpi_entry_focus_in(self, _entry: Gtk.Entry, _event_focus: Gdk.EventFocus): if not self.revealer.get_reveal_child(): self.resolutions_page._on_row_activated(None, self) def _on_profile_resolution_changed( - self, resolution: RatbagdResolution, pspec: GObject.ParamSpec + self, resolution: RatbagdResolution, _pspec: GObject.ParamSpec ) -> None: with self.scale.handler_block(self._scale_handler): res = resolution.resolution[0] From 9c076c9900d54821df37f0d8a15ef1de341b7077 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 25 May 2024 23:38:35 +0100 Subject: [PATCH 07/17] Actually apply the closest res value (oops). Apply the res value on focus-out-event. --- data/ui/ResolutionRow.ui | 1 + piper/resolutionrow.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/data/ui/ResolutionRow.ui b/data/ui/ResolutionRow.ui index 760db865..89481b82 100644 --- a/data/ui/ResolutionRow.ui +++ b/data/ui/ResolutionRow.ui @@ -23,6 +23,7 @@ + diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 516a127d..d8444193 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -189,7 +189,7 @@ def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: entry.set_text(str(closest_res)) if closest_res != self.previous_dpi_entry_value: - self._on_dpi_values_changed(res=res) + self._on_dpi_values_changed(res=closest_res) with self.scale.handler_block(self._scale_handler): self.scale.set_value(res) @@ -202,6 +202,11 @@ def _on_dpi_entry_focus_in(self, _entry: Gtk.Entry, _event_focus: Gdk.EventFocus if not self.revealer.get_reveal_child(): self.resolutions_page._on_row_activated(None, self) + @Gtk.Template.Callback("_on_dpi_entry_focus_out") + def _on_dpi_entry_focus_out(self, entry: Gtk.Entry, _event_focus: Gdk.EventFocus): + # Apply the DPI value on focus out + self._on_dpi_entry_activate(entry) + def _on_profile_resolution_changed( self, resolution: RatbagdResolution, _pspec: GObject.ParamSpec ) -> None: From a13acce548ce299824676b445bd4e667037a9d00 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sun, 26 May 2024 02:23:39 +0100 Subject: [PATCH 08/17] Toggle allow editing of DPI entry if 'disable' button clicked. --- piper/resolutionrow.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index d8444193..eeaade0b 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -108,7 +108,9 @@ def _on_change_value( def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: # The disable button has been toggled, update RatbagdResolution. - self._resolution.set_disabled(togglebutton.get_active()) + is_active = togglebutton.get_active() + self._resolution.set_disabled(is_active) + self.dpi_entry.set_editable(not is_active) # Update UI self._on_status_changed(self._resolution, pspec=None) From 2226ae62aeefc179f57096d3ec97437262c270ee Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sun, 26 May 2024 18:00:30 +0100 Subject: [PATCH 09/17] Use set_sensitive() on DPI entry. --- piper/resolutionrow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index eeaade0b..0395aabc 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -110,7 +110,6 @@ def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: # The disable button has been toggled, update RatbagdResolution. is_active = togglebutton.get_active() self._resolution.set_disabled(is_active) - self.dpi_entry.set_editable(not is_active) # Update UI self._on_status_changed(self._resolution, pspec=None) @@ -150,10 +149,12 @@ def _on_status_changed( self.disable_button.set_active(True) self.active_button.set_sensitive(False) self.dpi_label.set_sensitive(False) + self.dpi_entry.set_sensitive(False) self.scale.set_sensitive(False) else: self.disable_button.set_active(False) self.dpi_label.set_sensitive(True) + self.dpi_entry.set_sensitive(True) self.scale.set_sensitive(True) def toggle_revealer(self) -> None: From 280d7e683e218180ab373190c2f42c86c15489bf Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Mon, 27 May 2024 22:43:35 +0100 Subject: [PATCH 10/17] rm pointless var. --- piper/resolutionrow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 0395aabc..026714e6 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -108,8 +108,7 @@ def _on_change_value( def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: # The disable button has been toggled, update RatbagdResolution. - is_active = togglebutton.get_active() - self._resolution.set_disabled(is_active) + self._resolution.set_disabled(togglebutton.get_active()) # Update UI self._on_status_changed(self._resolution, pspec=None) From 1b0043b61e5568c26c5bb23bdeb13e587936e2ef Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 1 Jun 2024 15:55:49 +0100 Subject: [PATCH 11/17] Create custom class for DPI text entry to circumvent assertion warning. Grab DPIEntry focus when revealing ResolutionRow. Revert import order. Removed unused 'previous DPI value' var. Remove 'private' convention underscore from ResolutionsPage._on_row_activate(). Remove callback method for DPI entry on ResolutionRow. UI file uses DPIEntry. Remove insert-text signal for DPIEntry from UI file. --- data/ui/ResolutionRow.ui | 3 +-- piper/resolutionrow.py | 49 ++++++++++++++++++++++++++++------------ piper/resolutionspage.py | 2 +- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/data/ui/ResolutionRow.ui b/data/ui/ResolutionRow.ui index 89481b82..071d26d6 100644 --- a/data/ui/ResolutionRow.ui +++ b/data/ui/ResolutionRow.ui @@ -17,11 +17,10 @@ 12 6 - + True start - diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 026714e6..90dd1b87 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -3,12 +3,40 @@ from typing import Optional import gi +import warnings -from gi.repository import GObject, Gdk, Gtk # noqa from .ratbagd import RatbagdResolution from .util.gobject import connect_signal_with_weak_ref gi.require_version("Gtk", "3.0") +from gi.repository import GObject, Gdk, Gtk # noqa + + +class _DPIEntry(Gtk.Entry, Gtk.Editable): + """ + A subclass of Gtk.Entry with an overridden method for input validation. + + This class addresses a specific bug in the handling of parameters in pygobject when + using signals. For Gtk.Entry, the 'position' parameter is incorrect when handling + the 'insert-text' signal, causing an assertion warning to be logged. By using this + subclass, we can override the 'insert-text' logic to correctly handle the position + parameter and avoid the warning. + + Inheriting from Gtk.Entry ensures that the overridden method applies only to instances + of this class, rather than affecting all Gtk.Entry objects in the application. + """ + + __gtype_name__ = "DPIEntry" + + def do_insert_text(self, new_text: str, new_text_length: int, position: int) -> int: + """Overrides the default Gtk.Editable insert-text handler to validate + numerical input.""" + if not new_text.isdigit(): + self.stop_emission("insert-text") + return position + + self.get_buffer().insert_text(position, new_text, new_text_length) + return position + new_text_length @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ResolutionRow.ui") @@ -22,7 +50,7 @@ class ResolutionRow(Gtk.ListBoxRow): active_label: Gtk.Label = Gtk.Template.Child() # type: ignore disable_button: Gtk.Button = Gtk.Template.Child() # type: ignore dpi_label: Gtk.Label = Gtk.Template.Child() # type: ignore - dpi_entry: Gtk.Entry = Gtk.Template.Child() # type: ignore + dpi_entry: _DPIEntry = Gtk.Template.Child() # type: ignore revealer: Gtk.Revealer = Gtk.Template.Child() # type: ignore scale: Gtk.Scale = Gtk.Template.Child() # type: ignore @@ -37,7 +65,6 @@ def __init__( self.resolutions_page = resolutions_page self._resolution = resolution self.resolutions = resolution.resolutions - self.previous_dpi_entry_value = None self._scale_handler = self.scale.connect( "value-changed", self._on_scale_value_changed ) @@ -160,6 +187,8 @@ def toggle_revealer(self) -> None: # Toggles the revealer to show or hide the configuration widgets. reveal = not self.revealer.get_reveal_child() self.revealer.set_reveal_child(reveal) + if reveal: + self.dpi_entry.grab_focus() def _on_dpi_values_changed(self, res: Optional[int] = None) -> None: # Freeze the notify::resolution signal from firing and @@ -173,14 +202,6 @@ def _on_dpi_values_changed(self, res: Optional[int] = None) -> None: if new_res != self._resolution.resolution: self._resolution.resolution = new_res - @Gtk.Template.Callback("_on_dpi_entry_insert_text") - def _on_dpi_entry_insert_text( - self, entry: Gtk.Entry, text: str, _length: int, _position: int - ): - # Remove any non-numeric characters from the input - if not text.isdigit(): - entry.stop_emission("insert-text") - @Gtk.Template.Callback("_on_dpi_entry_activate") def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: # The DPI entry has been changed, update the scale and RatbagdResolution's resolution. @@ -189,9 +210,7 @@ def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: # Get the resolution closest to what has been entered closest_res = min(self.resolutions, key=lambda x: abs(x - res)) entry.set_text(str(closest_res)) - - if closest_res != self.previous_dpi_entry_value: - self._on_dpi_values_changed(res=closest_res) + self._on_dpi_values_changed(res=closest_res) with self.scale.handler_block(self._scale_handler): self.scale.set_value(res) @@ -202,7 +221,7 @@ def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: @Gtk.Template.Callback("_on_dpi_entry_focus_in") def _on_dpi_entry_focus_in(self, _entry: Gtk.Entry, _event_focus: Gdk.EventFocus): if not self.revealer.get_reveal_child(): - self.resolutions_page._on_row_activated(None, self) + self.resolutions_page.on_row_activated(None, self) @Gtk.Template.Callback("_on_dpi_entry_focus_out") def _on_dpi_entry_focus_out(self, entry: Gtk.Entry, _event_focus: Gdk.EventFocus): diff --git a/piper/resolutionspage.py b/piper/resolutionspage.py index 1dd2fc14..6f5326bb 100644 --- a/piper/resolutionspage.py +++ b/piper/resolutionspage.py @@ -67,7 +67,7 @@ def __init__( self.listbox.insert(row, resolution.index) @Gtk.Template.Callback("_on_row_activated") - def _on_row_activated(self, listbox: Gtk.ListBox, row: ResolutionRow) -> None: + def on_row_activated(self, _listbox: Gtk.ListBox, row: ResolutionRow) -> None: if row is self._last_activated_row: self._last_activated_row = None row.toggle_revealer() From 2fef94b9a27b8c1fd4bd2f8e66a2e0614c81ba75 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 1 Jun 2024 15:56:02 +0100 Subject: [PATCH 12/17] Line lengths --- piper/resolutionrow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 90dd1b87..72afa865 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -29,8 +29,8 @@ class _DPIEntry(Gtk.Entry, Gtk.Editable): __gtype_name__ = "DPIEntry" def do_insert_text(self, new_text: str, new_text_length: int, position: int) -> int: - """Overrides the default Gtk.Editable insert-text handler to validate - numerical input.""" + """Overrides the default Gtk.Editable insert-text handler to validate numerical + input.""" if not new_text.isdigit(): self.stop_emission("insert-text") return position From 1fad6ffd298b65050a92e0aed7a2b824ff82ddfc Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 1 Jun 2024 16:04:11 +0100 Subject: [PATCH 13/17] Removed unused import. Underscored unused parameter (PEP convention). --- piper/resolutionrow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 72afa865..04dcb6a5 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -3,7 +3,6 @@ from typing import Optional import gi -import warnings from .ratbagd import RatbagdResolution from .util.gobject import connect_signal_with_weak_ref @@ -157,7 +156,7 @@ def _on_scale_value_changed(self, scale: Gtk.Scale) -> None: self._on_dpi_values_changed(res=res) def _on_status_changed( - self, resolution: RatbagdResolution, pspec: Optional[GObject.ParamSpec] + self, resolution: RatbagdResolution, _pspec: Optional[GObject.ParamSpec] ) -> None: # The resolution's status changed, update UI. self._on_dpi_values_changed() From 60975bc284470d34220c367f76057c1579617eb8 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 1 Jun 2024 16:11:41 +0100 Subject: [PATCH 14/17] Reverted underscore convention as to not break existing stuff. --- piper/resolutionrow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 04dcb6a5..cd45439d 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -156,7 +156,7 @@ def _on_scale_value_changed(self, scale: Gtk.Scale) -> None: self._on_dpi_values_changed(res=res) def _on_status_changed( - self, resolution: RatbagdResolution, _pspec: Optional[GObject.ParamSpec] + self, resolution: RatbagdResolution, pspec: Optional[GObject.ParamSpec] ) -> None: # The resolution's status changed, update UI. self._on_dpi_values_changed() From 9565ff9a049834e9538afb6593fd1607f68039f2 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 1 Jun 2024 16:15:00 +0100 Subject: [PATCH 15/17] Use underscore convention, but also use it when invoking the method. --- piper/resolutionrow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index cd45439d..4225fc2c 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -103,7 +103,7 @@ def __init__( if resolution.is_disabled: with self.disable_button.handler_block(self._disabled_button_handler): self.disable_button.set_active(True) - self._on_status_changed(resolution, pspec=None) + self._on_status_changed(resolution, _pspec=None) @Gtk.Template.Callback("_on_change_value") def _on_change_value( @@ -137,7 +137,7 @@ def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: self._resolution.set_disabled(togglebutton.get_active()) # Update UI - self._on_status_changed(self._resolution, pspec=None) + self._on_status_changed(self._resolution, _pspec=None) @Gtk.Template.Callback("_on_active_button_clicked") def _on_active_button_clicked(self, _togglebutton: Gtk.Button) -> None: @@ -156,7 +156,7 @@ def _on_scale_value_changed(self, scale: Gtk.Scale) -> None: self._on_dpi_values_changed(res=res) def _on_status_changed( - self, resolution: RatbagdResolution, pspec: Optional[GObject.ParamSpec] + self, resolution: RatbagdResolution, _pspec: Optional[GObject.ParamSpec] ) -> None: # The resolution's status changed, update UI. self._on_dpi_values_changed() From 07c642be2318ca321671a4c79b075b22dbcf2cf4 Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 1 Jun 2024 16:20:01 +0100 Subject: [PATCH 16/17] Renamed handler name for ResolutionsPage to match method. --- data/ui/ResolutionsPage.ui | 2 +- piper/resolutionspage.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/ui/ResolutionsPage.ui b/data/ui/ResolutionsPage.ui index 9f7807c8..8c6a5103 100644 --- a/data/ui/ResolutionsPage.ui +++ b/data/ui/ResolutionsPage.ui @@ -38,7 +38,7 @@ True False none - + True diff --git a/piper/resolutionspage.py b/piper/resolutionspage.py index 6f5326bb..7823f17b 100644 --- a/piper/resolutionspage.py +++ b/piper/resolutionspage.py @@ -66,7 +66,7 @@ def __init__( row = ResolutionRow(resolution, self) self.listbox.insert(row, resolution.index) - @Gtk.Template.Callback("_on_row_activated") + @Gtk.Template.Callback("on_row_activated") def on_row_activated(self, _listbox: Gtk.ListBox, row: ResolutionRow) -> None: if row is self._last_activated_row: self._last_activated_row = None From ac607f376175834f043f906ab53029bf93ca129e Mon Sep 17 00:00:00 2001 From: dan <64416644+brittle-bones@users.noreply.github.com> Date: Sat, 1 Jun 2024 16:28:10 +0100 Subject: [PATCH 17/17] Clarified docstring. --- piper/resolutionrow.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/piper/resolutionrow.py b/piper/resolutionrow.py index 4225fc2c..2e2e37c6 100644 --- a/piper/resolutionrow.py +++ b/piper/resolutionrow.py @@ -21,8 +21,9 @@ class _DPIEntry(Gtk.Entry, Gtk.Editable): subclass, we can override the 'insert-text' logic to correctly handle the position parameter and avoid the warning. - Inheriting from Gtk.Entry ensures that the overridden method applies only to instances - of this class, rather than affecting all Gtk.Entry objects in the application. + Inheriting from Gtk.Editable in addition to Gtk.Entry ensures that the overridden + method applies only to instances of this class, rather than affecting all + Gtk.Entry objects in the application. """ __gtype_name__ = "DPIEntry"