[california] Double-click to edit event: Bug #735942



commit f4b0a52b28c248b9a47e87c381431a9e82058e5b
Author: Jim Nelson <jim yorba org>
Date:   Tue Oct 21 19:05:27 2014 -0700

    Double-click to edit event: Bug #735942
    
    Works in both Week and Month view.

 src/host/host-main-window.vala            |    7 +++++++
 src/toolkit/toolkit-button-connector.vala |    8 +++-----
 src/toolkit/toolkit-button-event.vala     |   29 +++++++++++++++++++++++++++++
 src/util/util-scheduled.vala              |    6 ++++++
 src/view/month/month-grid.vala            |   17 ++++++++---------
 src/view/view-controllable.vala           |    7 +++++++
 src/view/week/week-grid.vala              |   10 +++++++---
 7 files changed, 67 insertions(+), 17 deletions(-)
---
diff --git a/src/host/host-main-window.vala b/src/host/host-main-window.vala
index dcbfb84..3f01741 100644
--- a/src/host/host-main-window.vala
+++ b/src/host/host-main-window.vala
@@ -297,6 +297,7 @@ public class MainWindow : Gtk.ApplicationWindow {
             current_controller.request_create_timed_event.disconnect(on_request_create_timed_event);
             current_controller.request_create_all_day_event.disconnect(on_request_create_all_day_event);
             current_controller.request_display_event.disconnect(on_request_display_event);
+            current_controller.request_edit_event.disconnect(on_request_edit_event);
             current_controller.notify[View.Controllable.PROP_IS_VIEWING_TODAY].disconnect(
                 on_is_viewing_today_changed);
             
@@ -311,6 +312,7 @@ public class MainWindow : Gtk.ApplicationWindow {
             current_controller.request_create_timed_event.connect(on_request_create_timed_event);
             current_controller.request_create_all_day_event.connect(on_request_create_all_day_event);
             current_controller.request_display_event.connect(on_request_display_event);
+            current_controller.request_edit_event.connect(on_request_edit_event);
             current_controller.notify[View.Controllable.PROP_IS_VIEWING_TODAY].connect(
                 on_is_viewing_today_changed);
             on_is_viewing_today_changed();
@@ -494,6 +496,11 @@ public class MainWindow : Gtk.ApplicationWindow {
         show_deck_popover(relative_to, for_location, deck);
     }
     
+    private void on_request_edit_event(Component.Event event, Gtk.Widget relative_to,
+        Gdk.Point? for_location) {
+        on_edit_event(event, true);
+    }
+    
     private void edit_event(Component.Event event, bool is_update) {
         // use Idle loop so popovers have a chance to hide before bringing up DeckWindow
         Idle.add(() => {
diff --git a/src/toolkit/toolkit-button-connector.vala b/src/toolkit/toolkit-button-connector.vala
index 9fa6bd6..753c855 100644
--- a/src/toolkit/toolkit-button-connector.vala
+++ b/src/toolkit/toolkit-button-connector.vala
@@ -189,6 +189,8 @@ public class ButtonConnector : EventConnector {
                     ButtonEvent? details = button_states.get(widget);
                     if (details == null) {
                         details = new ButtonEvent(widget, event);
+                        details.clicked.connect(synthesize_click);
+                        
                         button_states.set(widget, details);
                     } else {
                         details.update_press(widget, event);
@@ -210,11 +212,8 @@ public class ButtonConnector : EventConnector {
                 // update saved state (if any) with release info and synthesize click
                 if (button_states != null) {
                     ButtonEvent? details = button_states.get(widget);
-                    if (details != null) {
+                    if (details != null)
                         details.update_release(widget, event);
-                        
-                        synthesize_click(details);
-                    }
                 }
             break;
         }
@@ -223,7 +222,6 @@ public class ButtonConnector : EventConnector {
     }
     
     private void synthesize_click(ButtonEvent details) {
-        // use Accept flags to indicate which signal(s) to fire
         bool result = Toolkit.PROPAGATE;
         switch (details.press_type) {
             case Gdk.EventType.BUTTON_PRESS:
diff --git a/src/toolkit/toolkit-button-event.vala b/src/toolkit/toolkit-button-event.vala
index 25319a0..f78a3fa 100644
--- a/src/toolkit/toolkit-button-event.vala
+++ b/src/toolkit/toolkit-button-event.vala
@@ -67,6 +67,8 @@ public enum Button {
  */
 
 public class ButtonEvent : BaseObject {
+    private const int SYNTHESIZED_CLICK_MSEC = 125;
+    
     /**
      * The Gtk.Widget the button press occurred on.
      *
@@ -97,6 +99,12 @@ public class ButtonEvent : BaseObject {
     private Gdk.Point _release_point = Gdk.Point();
     public Gdk.Point release_point { get { return _release_point; } }
     
+    // Indicates a full click-through has been received or a click has been synthesized after a
+    // delay.
+    internal signal void clicked();
+    
+    private Scheduled? scheduled_click = null;
+    
     internal ButtonEvent(Gtk.Widget widget, Gdk.EventButton press_event) {
         this.widget = widget;
         button = Button.from_button_event(press_event);
@@ -105,6 +113,18 @@ public class ButtonEvent : BaseObject {
         _press_point.y = (int) press_event.y;
     }
     
+    ~ButtonEvent() {
+        cancel_click();
+    }
+    
+    private void cancel_click() {
+        if (scheduled_click == null)
+            return;
+        
+        scheduled_click.cancel();
+        scheduled_click = null;
+    }
+    
     // Update state with the next button press
     internal void update_press(Gtk.Widget widget, Gdk.EventButton press_event) {
         assert(this.widget == widget);
@@ -113,6 +133,8 @@ public class ButtonEvent : BaseObject {
         press_type = press_event.type;
         _press_point.x = (int) press_event.x;
         _press_point.y = (int) press_event.y;
+        
+        cancel_click();
     }
     
     // Update state with the next button release and start the release timer
@@ -122,6 +144,13 @@ public class ButtonEvent : BaseObject {
         
         _release_point.x = (int) release_event.x;
         _release_point.y = (int) release_event.y;
+        
+        cancel_click();
+        
+        if (press_type == Gdk.EventType.3BUTTON_PRESS)
+            clicked();
+        else
+            scheduled_click = new Scheduled.once_after_msec(SYNTHESIZED_CLICK_MSEC, () => { clicked(); });
     }
     
     public override string to_string() {
diff --git a/src/util/util-scheduled.vala b/src/util/util-scheduled.vala
index 6f5498e..bd7fe57 100644
--- a/src/util/util-scheduled.vala
+++ b/src/util/util-scheduled.vala
@@ -176,6 +176,9 @@ public class Scheduled : BaseObject {
     }
     
     private bool on_once() {
+        if (is_executing || source_id == 0)
+            return false;
+        
         is_executing = true;
         schedule_once();
         is_executing = false;
@@ -187,6 +190,9 @@ public class Scheduled : BaseObject {
     }
     
     private bool on_continuous() {
+        if (is_executing || source_id == 0)
+            return false;
+        
         is_executing = true;
         Reschedule reschedule = schedule_continuous();
         is_executing = false;
diff --git a/src/view/month/month-grid.vala b/src/view/month/month-grid.vala
index 47444d2..a7db6ad 100644
--- a/src/view/month/month-grid.vala
+++ b/src/view/month/month-grid.vala
@@ -345,15 +345,14 @@ private class Grid : Gtk.Grid {
         if (press_cell != release_cell)
             return Toolkit.PROPAGATE;
         
-        // if an existing event is double-clicked, ignore, as the single click handler is displaying
-        // it (but stop propagation)
-        if (release_cell.get_event_at(release_cell_point) != null)
-            return Toolkit.STOP;
-        
-        Toolkit.set_toplevel_cursor(this, null);
-        
-        owner.request_create_all_day_event(new Calendar.DateSpan(press_cell.date, release_cell.date),
-            release_cell, release_cell_point);
+        // if an existing event is double-clicked, open for editing, otherwise create new event
+        Component.Event? event = release_cell.get_event_at(release_cell_point);
+        if (event != null) {
+            owner.request_edit_event(event, release_cell, release_cell_point);
+        } else {
+            owner.request_create_all_day_event(new Calendar.DateSpan(press_cell.date, release_cell.date),
+                release_cell, release_cell_point);
+        }
         
         return Toolkit.STOP;
     }
diff --git a/src/view/view-controllable.vala b/src/view/view-controllable.vala
index 53ed7de..863a0fa 100644
--- a/src/view/view-controllable.vala
+++ b/src/view/view-controllable.vala
@@ -82,6 +82,13 @@ public interface Controllable : Object {
         Gdk.Point? for_location);
     
     /**
+     * Signal from the { link Controllable} that the { link Component.Event} editor should be
+     * opened.
+     */
+    public signal void request_edit_event(Component.Event event, Gtk.Widget relative_to,
+        Gdk.Point? for_location);
+    
+    /**
      * Returns the { link Container} that should be used to display the { link Controllable}'s
      * contents.
      *
diff --git a/src/view/week/week-grid.vala b/src/view/week/week-grid.vala
index 9ee6a7a..2996e5c 100644
--- a/src/view/week/week-grid.vala
+++ b/src/view/week/week-grid.vala
@@ -375,9 +375,13 @@ internal class Grid : Gtk.Box {
         
         Common.InstanceContainer instance_container = (Common.InstanceContainer) details.widget;
         
-        // if an event is at this location, don't process
-        if (instance_container.get_event_at(details.press_point) != null)
-            return Toolkit.PROPAGATE;
+        // if an event is at this location, open for editing
+        Component.Event? event = instance_container.get_event_at(details.press_point);
+        if (event != null) {
+            owner.request_edit_event(event, instance_container, details.release_point);
+            
+            return Toolkit.STOP;
+        }
         
         Toolkit.set_toplevel_cursor(instance_container, null);
         


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