[gnome-break-timer/gtk-4: 2/2] Fix OverlayArrow being misaligned when offscreen




commit 89b265085f2b60484397faa724ab4a5d100813a0
Author: Dylan McCall <dylan dylanmccall ca>
Date:   Sun Jul 31 00:04:39 2022 -0700

    Fix OverlayArrow being misaligned when offscreen
    
    The coordinates of the target widget were being calculated from the
    arrow widget, which is drawn inside a leaflet page that slides across
    the screen. To solve this problem, we calculate the coordinates based on
    the leaflet page's parent widget.
    
    This is a bit crude, but there is a reasonable path from this state to
    something more broadly useful.

 src/settings/panels/WelcomePanel.vala  |  2 +-
 src/settings/widgets/OverlayArrow.vala | 92 ++++++++++++++++++----------------
 2 files changed, 51 insertions(+), 43 deletions(-)
---
diff --git a/src/settings/panels/WelcomePanel.vala b/src/settings/panels/WelcomePanel.vala
index 9a8e70c..9354f7c 100644
--- a/src/settings/panels/WelcomePanel.vala
+++ b/src/settings/panels/WelcomePanel.vala
@@ -93,7 +93,7 @@ private class WelcomePanel : Gtk.Box {
     }
 
     private void build_overlay_arrow (Gtk.Overlay overlay, Gtk.Widget arrow_source, Gtk.Widget arrow_target) 
{
-        var arrow = new OverlayArrow (arrow_source, arrow_target);
+        var arrow = new OverlayArrow (arrow_source, arrow_target, this.stack);
         overlay.add_overlay (arrow);
     }
 }
diff --git a/src/settings/widgets/OverlayArrow.vala b/src/settings/widgets/OverlayArrow.vala
index 1f84f95..8351283 100644
--- a/src/settings/widgets/OverlayArrow.vala
+++ b/src/settings/widgets/OverlayArrow.vala
@@ -20,38 +20,46 @@
 
 namespace BreakTimer.Settings.Widgets {
 
-/* FIXME: This widget is stealing clicks when it is used in an overlay */
-
 public class OverlayArrow : Gtk.DrawingArea {
     private Gtk.Widget from_widget;
     private Gtk.Widget to_widget;
+    private Gtk.Widget align_widget;
 
-    public OverlayArrow (Gtk.Widget from_widget, Gtk.Widget to_widget) {
-        GLib.Object ();
+    private enum ArrowDirection {
+        UP,
+        RIGHT,
+        DOWN,
+        LEFT
+    }
 
-        // this.set_has_window (false);
+    /**
+     * Creates an OverlayArrow, which draws an arrow from one widget to another.
+     * from_widget: a widget to start the arrow from
+     * to_widget: a widget to end the arrow at
+     * align_widget: a widget to measure coordinates for the target widget, if
+     *               in case from_widget slides into view from elsewhere.
+     */
+    public OverlayArrow (Gtk.Widget from_widget, Gtk.Widget to_widget, Gtk.Widget align_widget) {
+        GLib.Object (sensitive: false);
 
         this.set_halign (Gtk.Align.FILL);
         this.set_valign (Gtk.Align.FILL);
 
         this.from_widget = from_widget;
         this.to_widget = to_widget;
+        this.align_widget = align_widget;
 
         this.set_draw_func (this.on_draw_cb);
     }
 
     private void on_draw_cb (Gtk.DrawingArea widget, Cairo.Context cr, int width, int height) {
-        // FIXME: ARE THESE THE SAME AS GIVEN WIDTH AND HEIGHT?
         int max_width = this.get_allocated_width ();
         int max_height = this.get_allocated_height ();
 
-        double from_x, from_y;
-        this.get_from_coordinates (out from_x, out from_y);
+        double from_x, from_y, to_x, to_y;
+        this.get_from_to_coordinates (out from_x, out from_y, out to_x, out to_y);
         from_x = from_x.clamp (0, max_width);
         from_y = from_y.clamp (0, max_height);
-
-        double to_x, to_y;
-        this.get_to_coordinates (out to_x, out to_y);
         to_x = to_x.clamp (0, max_width);
         to_y = to_y.clamp (0, max_height);
 
@@ -75,48 +83,48 @@ public class OverlayArrow : Gtk.DrawingArea {
         cr.stroke ();
     }
 
-    private void get_points_offset (out double offset_x, out double offset_y) {
+    private void get_from_to_coordinates (out double from_x, out double from_y, out double to_x, out double 
to_y) {
+        Gtk.Allocation from_allocation;
         Gtk.Allocation to_allocation;
+        this.from_widget.get_allocation (out from_allocation);
         this.to_widget.get_allocation (out to_allocation);
-        this.from_widget.translate_coordinates (this.to_widget, to_allocation.width/2, 
to_allocation.width/2, out offset_x, out offset_y);
-    }
 
-    private void get_from_coordinates (out double from_x, out double from_y) {
-        // Is to_widget to the right or to the left?
-        Gtk.Allocation from_allocation;
-        this.from_widget.get_allocation (out from_allocation);
+        double from_middle_y, from_start_x, from_end_x;
+        double to_middle_x, to_top_y, to_bottom_y;
+
+        this.from_widget.translate_coordinates (this, 0, from_allocation.height/2, null, out from_middle_y);
+        this.from_widget.translate_coordinates (this, -this.from_widget.margin_start, 0, out from_start_x, 
null);
+        this.from_widget.translate_coordinates (this, from_allocation.width + this.from_widget.margin_end, 
0, out from_end_x, null);
 
-        double offset_x, offset_y;
-        this.get_points_offset (out offset_x, out offset_y);
+        this.to_widget.translate_coordinates (this.align_widget, to_allocation.width/2, 0, out to_middle_x, 
null);
+        this.to_widget.translate_coordinates (this.align_widget, 0, -this.to_widget.margin_top, null, out 
to_top_y);
+        this.to_widget.translate_coordinates (this.align_widget, 0, to_allocation.height + 
this.to_widget.margin_bottom, null, out to_bottom_y);
 
-        double from_local_x, from_local_y;
-        if (offset_x > 0) {
-            from_local_x = 0;
-            from_local_y = from_allocation.height / 2;
+        double distance_from_start = to_middle_x - from_start_x;
+        double distance_from_end = from_end_x - to_middle_x;
+
+        if (distance_from_start < distance_from_end) {
+            // Draw an arrow to the left
+            from_x = from_start_x;
+            to_x = to_middle_x;
         } else {
-            from_local_x = from_allocation.width;
-            from_local_y = from_allocation.height / 2;
+            // Draw an arrow to the right
+            from_x = from_end_x;
+            to_x = to_middle_x;
         }
-        this.from_widget.translate_coordinates (this, from_local_x, from_local_y, out from_x, out from_y);
-    }
-
-    private void get_to_coordinates (out double to_x, out double to_y) {
-        // Is to_widget to the right or to the left?
-        Gtk.Allocation to_allocation;
-        this.to_widget.get_allocation (out to_allocation);
 
-        double offset_x, offset_y;
-        this.get_points_offset (out offset_x, out offset_y);
+        double distance_to_top = from_middle_y - to_top_y;
+        double distance_to_bottom = to_bottom_y - from_middle_y;
 
-        double to_local_x, to_local_y;
-        if (offset_y > 0) {
-            to_local_x = to_allocation.width / 2;
-            to_local_y = to_allocation.height;
+        if (distance_to_top < distance_to_bottom) {
+            // Draw an arrow to the bottom
+            from_y = from_middle_y;
+            to_y = to_top_y;
         } else {
-            to_local_x = to_allocation.width / 2;
-            to_local_y = 0;
+            // Draw an arrow to the top
+            from_y = from_middle_y;
+            to_y = to_bottom_y;
         }
-        this.to_widget.translate_coordinates (this, to_local_x, to_local_y, out to_x, out to_y);
     }
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]