[f-spot/icon-view-cleanup: 23/24] cleanup the rectangular selection a bit



commit c8c9c76cd3715575ba30a7af0b75118d78bc95d9
Author: Mike Gemünde <mike gemuende de>
Date:   Mon Aug 16 21:54:33 2010 +0200

    cleanup the rectangular selection a bit

 src/Clients/MainApp/FSpot.Widgets/CellGridView.cs  |    5 +
 .../FSpot.Widgets/CollectionCellGridView.cs        |  246 ++++++++++----------
 .../MainApp/FSpot.Widgets/SelectionCollection.cs   |    4 +-
 3 files changed, 129 insertions(+), 126 deletions(-)
---
diff --git a/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs b/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs
index 8ed2cd8..2fb47f9 100644
--- a/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs
@@ -161,6 +161,11 @@ namespace FSpot.Widgets
 
 #region Public Methods
 
+        public int CellAtPosition (Point p)
+        {
+            return CellAtPosition (p.X, p.Y);
+        }
+
         public int CellAtPosition (int x, int y)
         {
             return CellAtPosition (x, y, true, false);
diff --git a/src/Clients/MainApp/FSpot.Widgets/CollectionCellGridView.cs b/src/Clients/MainApp/FSpot.Widgets/CollectionCellGridView.cs
index abbc5ff..0f5f365 100644
--- a/src/Clients/MainApp/FSpot.Widgets/CollectionCellGridView.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/CollectionCellGridView.cs
@@ -11,6 +11,7 @@
  */
 
 using System;
+using System.Collections.Generic;
 
 using Gtk;
 using Gdk;
@@ -81,7 +82,6 @@ namespace FSpot.Widgets
             Selection = new SelectionCollection (Collection);
 
             Collection.Changed += delegate (IBrowsableCollection sender) {
-                //suppress_scroll = true;
                 QueueResize ();
             };
 
@@ -210,8 +210,10 @@ namespace FSpot.Widgets
             args.RetVal = true;
 
             start_select_event = args.Event;
-            start_press_x = (int) args.Event.X;
-            start_press_y = (int) args.Event.Y;
+
+            selection_start = new Point ((int) args.Event.X, (int) args.Event.Y);
+            selection_modifier = args.Event.State;
+
             isRectSelection = false;
             isDragDrop = false;
 
@@ -249,7 +251,6 @@ namespace FSpot.Widgets
                     GLib.Source.Remove (scroll_timeout);
                     scroll_timeout = 0;
                 }
-                SelectMotion ();
 
                 isRectSelection = false;
                 if (BinWindow != null) {
@@ -276,55 +277,59 @@ namespace FSpot.Widgets
 
         // rectangle of dragging selection
         private Rectangle rect_select;
+        private Point selection_start;
+        private Point selection_end;
+        private ModifierType selection_modifier;
 
         private bool isRectSelection = false;
         private bool isDragDrop = false;
 
-        // initial click and scroll value
-        private int start_select_x, start_select_y, start_select_vadj, start_select_hadj;
         // initial selection
         private int[] start_select_selection;
         // initial event used to detect drag&drop
         private EventButton start_select_event;
         // timer using when scrolling selection
         private uint scroll_timeout = 0;
-        // initial click
-            private int start_press_x, start_press_y;
+
+        private Rectangle BoundedRectangle (Point p1, Point p2)
+        {
+            return new Rectangle (Math.Min (p1.X, p2.X),
+                                  Math.Min (p1.Y, p2.Y),
+                                  Math.Abs (p1.X - p2.X) + 1,
+                                  Math.Abs (p1.Y- p2.Y) + 1);
+        }
+
+        protected Point GetPointer ()
+        {
+            int x, y;
+            GetPointer (out x, out y);
+
+            return new Point (x + (int) Hadjustment.Value, y + (int) Vadjustment.Value);
+        }
 
         // during pointer motion, select/toggle pictures between initial x/y (param)
         // and current x/y (get pointer)
-        private void SelectMotion ()
+        private void UpdateRubberband ()
         {
-            int x2, y2;
-            Gdk.ModifierType mod;
-            Display.GetPointer (out x2, out y2, out mod);
-            GetPointer (out x2, out y2);
-
-            // check new coord
-            int x1 = start_select_x;
-            if (x1 < 0)
-                x1 = 0;
-            int y1 = start_select_y;
-            if (y1 < 0)
-                y1 = 0;
-            if (y1 > Allocation.Height)
-                y1 = (int) Allocation.Height;
-            x1 += start_select_hadj;
-            y1 += start_select_vadj;
-
-            if (x2 < 0)
-                x2 = 0;
-            if (y2 < 0)
-                y2 = 0;
-            if (y2 > Allocation.Height)
-                y2 = (int) Allocation.Height;
-            x2 += (int) Hadjustment.Value;
-            y2 += (int) Vadjustment.Value;
-
-            int start_x = x1 < x2 ? x1 : x2;
-            int end_x =   x1 > x2 ? x1 : x2;
-            int start_y = y1 < y2 ? y1 : y2;
-            int end_y =   y1 > y2 ? y1 : y2;
+            // determine old and new selection
+            var old_selection = rect_select;
+            selection_end = GetPointer ();
+            var new_selection = BoundedRectangle (selection_start, selection_end);
+
+            // determine region to invalidate
+            var region = Region.Rectangle (old_selection);
+            region.Xor (Region.Rectangle (new_selection));
+            region.Shrink (-1, -1);
+
+            BinWindow.InvalidateRegion (region, true);
+
+            rect_select = new_selection;
+            UpdateRubberbandSelection ();
+        }
+
+        private void UpdateRubberbandSelection ()
+        {
+            var selected_area = BoundedRectangle (selection_start, selection_end);
 
             // Restore initial selection
             var initial_selection = Selection.ToBitArray();
@@ -332,59 +337,48 @@ namespace FSpot.Widgets
             foreach (int i in start_select_selection)
                 Selection.Add (i, false);
 
-            // Select or toggle according to modifiers
-            int start_row  = (start_x - BorderSize) / cell_width;
-            int start_line = (start_y - BorderSize) / cell_height;
-            int end_row    = (end_x - BorderSize + cell_width - 1) / cell_width;
-            int end_line   = (end_y - BorderSize + cell_height - 1) / cell_height;
-            if (start_row > cells_per_row)
-                start_row = cells_per_row;
-            if (end_row > cells_per_row)
-                end_row = cells_per_row;
-
+            // Set selection
+            int first = -1;
+            foreach (var cell_num in CellsInRect (selected_area)) {
+                if (first == -1)
+                    first = cell_num;
 
-            FocusCell = start_line * cells_per_row + start_row;
-
-            if ((mod & ModifierType.ControlMask) == 0)
-                Selection.SelectRect (start_row, end_row, start_line, end_line, cells_per_row);
-            else
-                Selection.ToggleRect (start_row, end_row, start_line, end_line, cells_per_row);
+                if ((selection_modifier & ModifierType.ControlMask) == 0)
+                    Selection.Add (cell_num, false);
+                else
+                    Selection.ToggleCell (cell_num, false);
+            }
+            if (first != -1)
+                FocusCell = first;
 
             // fire events for cells which have changed selection flag
             var new_selection = Selection.ToBitArray();
             var selection_changed = initial_selection.Xor (new_selection);
-            System.Collections.Generic.List<int> changed = new System.Collections.Generic.List<int>();
+            var changed = new List<int>();
             for (int i = 0; i < selection_changed.Length; i++)
                 if (selection_changed.Get(i))
                     changed.Add (i);
-            if (selection_changed.Length != 0)
+            if (changed.Count != 0)
                 Selection.SignalChange (changed.ToArray());
-
-            // redraw selection box
-            if (BinWindow != null) {
-                BinWindow.InvalidateRect (rect_select, true); // old selection
-                rect_select = new Rectangle (start_x, start_y, end_x - start_x, end_y - start_y);
-                BinWindow.InvalidateRect (rect_select, true); // new selection
-                BinWindow.ProcessUpdates (true);
-            }
         }
 
         // if scroll is required, a timeout is fired
         // until the button is release or the pointer is
         // in window again
         private int deltaVscroll;
-        private bool HandleMotionTimeout()
+        private bool HandleMotionTimeout ()
         {
             int new_x, new_y;
-            ModifierType new_mod;
-            Display.GetPointer (out new_x, out new_y, out new_mod);
-            GetPointer (out new_x, out new_y);
 
-            // do scroll
+           // do scroll
             double newVadj = Vadjustment.Value;
             if (deltaVscroll < 130)
                 deltaVscroll += 15;
 
+            Gdk.ModifierType new_mod;
+            Display.GetPointer (out new_x, out new_y, out new_mod);
+            GetPointer (out new_x, out new_y);
+
             if (new_y <= 0) {
                 newVadj -= deltaVscroll;
                 if (newVadj < 0)
@@ -393,10 +387,10 @@ namespace FSpot.Widgets
                    (newVadj < Vadjustment.Upper - Allocation.Height - deltaVscroll))
                 newVadj += deltaVscroll;
             Vadjustment.Value = newVadj;
-            Vadjustment.ChangeValue();
 
-            // do again selection after scroll
-            SelectMotion ();
+            UpdateRubberband ();// (new Point (new_x + (int) Hadjustment.Value, new_y + (int) Vadjustment.Value));
+
+            Vadjustment.ChangeValue ();
 
             // stop firing timeout when no button pressed
             return (new_mod & (ModifierType.Button1Mask | ModifierType.Button3Mask)) != 0;
@@ -404,58 +398,62 @@ namespace FSpot.Widgets
 
         private void HandleSelectMotionNotify (object sender, MotionNotifyEventArgs args)
         {
-            if ((args.Event.State & (ModifierType.Button1Mask | ModifierType.Button3Mask)) != 0 ) {
-                if (Gtk.Drag.CheckThreshold (this, start_press_x, start_press_y,
-                                 (int) args.Event.X, (int) args.Event.Y))
-                    if (isRectSelection) {
-                        // scroll if out of window
-                        double d_x, d_y;
-                        deltaVscroll = 30;
-                        if (EventHelper.GetCoords (args.Event, out d_x, out d_y)) {
-                            int new_y = (int) d_y;
-                            if ((new_y <= 0) || (new_y >= Allocation.Height)) {
-                                if (scroll_timeout == 0)
-                                    scroll_timeout = GLib.Timeout.Add (100, new GLib.TimeoutHandler (HandleMotionTimeout));
-                            }
-                        } else if (scroll_timeout != 0) {
-                            GLib.Source.Remove (scroll_timeout);
-                            scroll_timeout = 0;
-                        }
-
-                        // handle selection
-                        SelectMotion ();
-                    } else  {
-                        int cell_num = CellAtPosition (start_press_x, start_press_y, false, false);
-                        if (Selection.Contains (cell_num)) {
-                            // on a selected cell : do drag&drop
-                            isDragDrop = true;
-                            if (StartDrag != null) {
-                                uint but;
-                                if ((args.Event.State & ModifierType.Button1Mask) != 0)
-                                    but = 1;
-                                else
-                                    but = 3;
-                                StartDrag (this, new StartDragArgs(but, start_select_event));
-                            }
-                        } else {
-                            // not on a selected cell : do rectangular select
-                            isRectSelection = true;
-                            start_select_hadj = (int) Hadjustment.Value;
-                            start_select_vadj = (int) Vadjustment.Value;
-                            start_select_x = start_press_x - start_select_hadj;
-                            start_select_y = start_press_y - start_select_vadj;
-
-                            // ctrl : toggle selected, shift : keep selected
-                            if ((args.Event.State & (ModifierType.ShiftMask | ModifierType.ControlMask)) == 0)
-                                Selection.Clear ();
-
-                            start_select_selection = Selection.Ids; // keep initial selection
-                            // no rect draw at beginning
-                            rect_select = new Rectangle ();
-
-                            args.RetVal = false;
-                        }
+            if ((args.Event.State & (ModifierType.Button1Mask | ModifierType.Button3Mask)) == 0)
+                return;
+
+            if (! Gtk.Drag.CheckThreshold (this, selection_start.X, selection_start.Y,
+                                       (int) args.Event.X, (int) args.Event.Y))
+                return;
+
+            if (isRectSelection) {
+                // scroll if out of window
+                double d_x, d_y;
+                deltaVscroll = 30;
+                if (EventHelper.GetCoords (args.Event, out d_x, out d_y)) {
+                    int new_y = (int) d_y;
+                    if ((new_y <= 0) || (new_y >= Allocation.Height)) {
+                        if (scroll_timeout == 0)
+                            scroll_timeout = GLib.Timeout.Add (100, new GLib.TimeoutHandler (HandleMotionTimeout));
+                    } else if (scroll_timeout != 0) {
+                        GLib.Source.Remove (scroll_timeout);
+                        scroll_timeout = 0;
                     }
+                } else if (scroll_timeout != 0) {
+                    GLib.Source.Remove (scroll_timeout);
+                    scroll_timeout = 0;
+                }
+
+                // handle selection
+                UpdateRubberband ();
+                //SelectMotion (new Point ((int) args.Event.X, (int) args.Event.Y));
+            } else  {
+                int cell_num = CellAtPosition (selection_start);
+
+                if (Selection.Contains (cell_num)) {
+                    // on a selected cell : do drag&drop
+                    isDragDrop = true;
+                    if (StartDrag != null) {
+                        uint but;
+                        if ((args.Event.State & ModifierType.Button1Mask) != 0)
+                            but = 1;
+                        else
+                            but = 3;
+                        StartDrag (this, new StartDragArgs(but, start_select_event));
+                    }
+                } else {
+                    // not on a selected cell : do rectangular select
+                    isRectSelection = true;
+
+                    // ctrl : toggle selected, shift : keep selected
+                    if ((args.Event.State & (ModifierType.ShiftMask | ModifierType.ControlMask)) == 0)
+                        Selection.Clear ();
+
+                    start_select_selection = Selection.Ids; // keep initial selection
+                    // no rect draw at beginning
+                    rect_select = Rectangle.Zero;
+
+                    args.RetVal = false;
+                }
             }
         }
 
diff --git a/src/Clients/MainApp/FSpot.Widgets/SelectionCollection.cs b/src/Clients/MainApp/FSpot.Widgets/SelectionCollection.cs
index 5c0451d..e65e45e 100644
--- a/src/Clients/MainApp/FSpot.Widgets/SelectionCollection.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/SelectionCollection.cs
@@ -81,7 +81,7 @@ namespace FSpot.Widgets
         }
 
         public BitArray ToBitArray () {
-            return bit_array;
+            return new BitArray (bit_array);
         }
 
         public int [] Ids {
@@ -267,7 +267,7 @@ namespace FSpot.Widgets
             return System.Array.IndexOf (Ids, parent_index);
         }
 
-        private void ToggleCell (int cell_num, bool notify)
+        public void ToggleCell (int cell_num, bool notify)
         {
             if (Contains (cell_num))
                 Remove (cell_num, notify);



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