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