[f-spot/icon-view-cleanup: 3/4] Factor Selection and Collection handling out of IconView to CollectionCellGridView
- From: Mike Gemünde <mgemuende src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [f-spot/icon-view-cleanup: 3/4] Factor Selection and Collection handling out of IconView to CollectionCellGridView
- Date: Mon, 16 Aug 2010 09:08:45 +0000 (UTC)
commit 238d1d56b063308e64e985ebb4d626f4032f8a59
Author: Mike Gemünde <mike gemuende de>
Date: Sat Aug 14 13:43:21 2010 +0200
Factor Selection and Collection handling out of IconView to CollectionCellGridView
.../MainApp/FSpot.UI.Dialog/AdjustTimeDialog.cs | 2 +-
.../FSpot.Widgets/CollectionCellGridView.cs | 555 ++++++++++++
src/Clients/MainApp/FSpot.Widgets/IconView.cs | 880 +------------------
.../MainApp/FSpot.Widgets/ScalingIconView.cs | 2 +-
.../MainApp/FSpot.Widgets/SelectionCollection.cs | 341 ++++++++
src/Clients/MainApp/FSpot/SingleView.cs | 2 +-
src/Clients/MainApp/Makefile.am | 2 +
7 files changed, 948 insertions(+), 836 deletions(-)
---
diff --git a/src/Clients/MainApp/FSpot.UI.Dialog/AdjustTimeDialog.cs b/src/Clients/MainApp/FSpot.UI.Dialog/AdjustTimeDialog.cs
index 39c9cde..d0bb2ab 100644
--- a/src/Clients/MainApp/FSpot.UI.Dialog/AdjustTimeDialog.cs
+++ b/src/Clients/MainApp/FSpot.UI.Dialog/AdjustTimeDialog.cs
@@ -254,7 +254,7 @@ namespace FSpot.UI.Dialog {
void HandleSelectionChanged (IBrowsableCollection sender)
{
if (sender.Count > 0) {
- view.Item.Index = ((FSpot.Widgets.IconView.SelectionCollection)sender).Ids[0];
+ view.Item.Index = ((FSpot.Widgets.SelectionCollection)sender).Ids[0];
}
}
diff --git a/src/Clients/MainApp/FSpot.Widgets/CollectionCellGridView.cs b/src/Clients/MainApp/FSpot.Widgets/CollectionCellGridView.cs
new file mode 100644
index 0000000..abbc5ff
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/CollectionCellGridView.cs
@@ -0,0 +1,555 @@
+/*
+ * CollectionGridView.cs
+ *
+ * Author(s)
+ * Etore Perazzoli
+ * Larry Ewing <lewing novell com>
+ * Stephane Delcroix <stephane delcroix org>
+ * Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+
+using Gtk;
+using Gdk;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+
+ // TODO: This event ahndler is a hack. The default event from a widget
+ // (DragBegin) should be used, but therfore, the event must be fired
+ // correctly.
+ public delegate void StartDragHandler (object o, StartDragArgs args);
+
+ public class StartDragArgs {
+ public Event Event { get; set; }
+ public uint Button { get; set; }
+
+ public StartDragArgs (uint but, Event evt) {
+ this.Button = but;
+ this.Event = evt;
+ }
+ }
+
+ /// <summary>
+ /// This class extends CellGridView to provide a grid view for a photo collection with selection.
+ /// </summary>
+ public abstract class CollectionGridView : CellGridView
+ {
+
+#region Public Properties
+
+ public IBrowsableCollection Collection {
+ get; private set;
+ }
+
+ public SelectionCollection Selection {
+ get; private set;
+ }
+
+ // Focus Handling
+ private int real_focus_cell;
+ public int FocusCell {
+ get { return real_focus_cell; }
+ set {
+ if (value != real_focus_cell) {
+ value = Math.Max (value, 0);
+ value = Math.Min (value, Collection.Count - 1);
+ InvalidateCell (value);
+ InvalidateCell (real_focus_cell);
+ real_focus_cell = value;
+ }
+ }
+ }
+
+#endregion
+
+#region Constructors
+
+ public CollectionGridView (IntPtr raw) : base (raw)
+ {
+ }
+
+ public CollectionGridView (IBrowsableCollection collection) : base ()
+ {
+ Collection = collection;
+ Selection = new SelectionCollection (Collection);
+
+ Collection.Changed += delegate (IBrowsableCollection sender) {
+ //suppress_scroll = true;
+ QueueResize ();
+ };
+
+ Selection.DetailedChanged += delegate(IBrowsableCollection sender, Int32 [] ids) {
+ if (ids == null)
+ QueueDraw ();
+ else
+ foreach (int id in ids)
+ InvalidateCell (id);
+ };
+
+ ButtonPressEvent += new ButtonPressEventHandler (HandleButtonPressEvent);
+ ButtonReleaseEvent += new ButtonReleaseEventHandler (HandleButtonReleaseEvent);
+ KeyPressEvent += new KeyPressEventHandler (HandleKeyPressEvent);
+
+ MotionNotifyEvent += new MotionNotifyEventHandler (HandleSelectMotionNotify);
+
+ AddEvents ((int) EventMask.KeyPressMask
+ | (int) EventMask.KeyReleaseMask
+ | (int) EventMask.ButtonPressMask
+ | (int) EventMask.ButtonReleaseMask
+ | (int) EventMask.PointerMotionMask
+ | (int) EventMask.PointerMotionHintMask);
+
+ CanFocus = true;
+ }
+
+#endregion
+
+#region Implementation of Base Class Layout Properties
+
+ protected override int CellCount {
+ get {
+ if (Collection == null)
+ return 0;
+
+ return Collection.Count;
+ }
+ }
+
+#endregion
+
+#region Event Handlers
+
+ public event EventHandler<BrowsableEventArgs> DoubleClicked;
+
+ // TODO: hack. See definition of StartDragHandler
+ public event StartDragHandler StartDrag;
+
+#endregion
+
+#region Drawing Methods
+
+ protected override void DrawCell (int cell_num, Rectangle expose_area)
+ {
+ bool selected = Selection.Contains (cell_num);
+ bool focussed = FocusCell == cell_num;
+
+ Rectangle cell_area = CellBounds (cell_num);
+
+ DrawPhoto (cell_num, cell_area, expose_area, selected, focussed);
+ }
+
+ protected abstract void DrawPhoto (int cell_num, Rectangle cell_area, Rectangle expose_area, bool selected, bool focussed);
+
+ protected override bool OnExposeEvent (Gdk.EventExpose args)
+ {
+ bool ret = base.OnExposeEvent (args);
+
+ foreach (Rectangle area in args.Region.GetRectangles ()) {
+ DrawSelection (area);
+ }
+
+ return ret;
+ }
+
+ private void DrawSelection (Rectangle expose_area)
+ {
+ if ( ! isRectSelection)
+ return;
+
+ Gdk.Rectangle region;
+ if ( ! expose_area.Intersect (rect_select, out region))
+ return;
+
+ // draw selection
+ using (Cairo.Context cairo_g = CairoHelper.Create (BinWindow)) {
+
+ Gdk.Color color = Style.Background(StateType.Selected);
+ cairo_g.Color = new Cairo.Color (color.Red/65535.0, color.Green/65535.0, color.Blue/65535.0, 0.5);
+ cairo_g.Rectangle (region.X, region.Y, region.Width, region.Height);
+ cairo_g.Fill ();
+
+ }
+
+ //((IDisposable) cairo_g.Target).Dispose ();
+ //((IDisposable) cairo_g).Dispose ();
+ }
+
+#endregion
+
+#region Utility Methods
+
+ // TODO: move this to SelectionCollection
+ public void SelectAllCells ()
+ {
+ Selection.Add (0, Collection.Count - 1);
+ }
+
+ protected virtual void ContextMenu (ButtonPressEventArgs args, int cell_num)
+ {
+ }
+
+#endregion
+
+#region Event Handler
+
+ // TODO: the following code need to be cleaned up.
+ // TODO: rubberband selection behaves different than Gtk.IconView. This needs to be fixed.
+ // TODO: selection by clicks behaves different than Gtk.IconView. This needs to be fixed.
+
+ private void HandleButtonPressEvent (object obj, ButtonPressEventArgs args)
+ {
+ int cell_num = CellAtPosition ((int) args.Event.X, (int) args.Event.Y, false, false);
+
+ args.RetVal = true;
+
+ start_select_event = args.Event;
+ start_press_x = (int) args.Event.X;
+ start_press_y = (int) args.Event.Y;
+ isRectSelection = false;
+ isDragDrop = false;
+
+ switch (args.Event.Type) {
+ case EventType.TwoButtonPress:
+ if (args.Event.Button != 1 ||
+ (args.Event.State & (ModifierType.ControlMask | ModifierType.ShiftMask)) != 0)
+ return;
+ if (DoubleClicked != null)
+ DoubleClicked (this, new BrowsableEventArgs (cell_num, null));
+ return;
+
+ case EventType.ButtonPress:
+ GrabFocus ();
+ // on a cell : context menu if button 3
+ // cell selection is done on button release
+ if (args.Event.Button == 3){
+ ContextMenu (args, cell_num);
+ return;
+ } else args.RetVal = false;
+
+ break;
+
+ default:
+ args.RetVal = false;
+ break;
+ }
+ }
+
+ private void HandleButtonReleaseEvent (object sender, ButtonReleaseEventArgs args)
+ {
+ if (isRectSelection) {
+ // remove scrolling and rectangular selection
+ if (scroll_timeout != 0) {
+ GLib.Source.Remove (scroll_timeout);
+ scroll_timeout = 0;
+ }
+ SelectMotion ();
+
+ isRectSelection = false;
+ if (BinWindow != null) {
+ BinWindow.InvalidateRect (rect_select, false);
+ BinWindow.ProcessUpdates (true);
+ }
+ rect_select = new Rectangle();
+ } else if (!isDragDrop) {
+ int cell_num = CellAtPosition ((int) args.Event.X, (int) args.Event.Y, false, true);
+ if (cell_num != -1) {
+ if ((args.Event.State & ModifierType.ControlMask) != 0) {
+ Selection.ToggleCell (cell_num);
+ } else if ((args.Event.State & ModifierType.ShiftMask) != 0) {
+ Selection.Add (FocusCell, cell_num);
+ } else {
+ Selection.Clear ();
+ Selection.Add (cell_num);
+ }
+ FocusCell = cell_num;
+ }
+ }
+ isDragDrop = false;
+ }
+
+ // rectangle of dragging selection
+ private Rectangle rect_select;
+
+ 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;
+
+ // during pointer motion, select/toggle pictures between initial x/y (param)
+ // and current x/y (get pointer)
+ private void SelectMotion ()
+ {
+ 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;
+
+ // Restore initial selection
+ var initial_selection = Selection.ToBitArray();
+ Selection.Clear (false);
+ 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;
+
+
+ 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);
+
+ // 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>();
+ for (int i = 0; i < selection_changed.Length; i++)
+ if (selection_changed.Get(i))
+ changed.Add (i);
+ if (selection_changed.Length != 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()
+ {
+ 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
+ double newVadj = Vadjustment.Value;
+ if (deltaVscroll < 130)
+ deltaVscroll += 15;
+
+ if (new_y <= 0) {
+ newVadj -= deltaVscroll;
+ if (newVadj < 0)
+ newVadj = 0;
+ } else if ((new_y > Allocation.Height) &&
+ (newVadj < Vadjustment.Upper - Allocation.Height - deltaVscroll))
+ newVadj += deltaVscroll;
+ Vadjustment.Value = newVadj;
+ Vadjustment.ChangeValue();
+
+ // do again selection after scroll
+ SelectMotion ();
+
+ // stop firing timeout when no button pressed
+ return (new_mod & (ModifierType.Button1Mask | ModifierType.Button3Mask)) != 0;
+ }
+
+ 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;
+ }
+ }
+ }
+ }
+
+
+ private void HandleKeyPressEvent (object sender, KeyPressEventArgs args)
+ {
+ int focus_old = FocusCell;
+ args.RetVal = true;
+
+ bool shift = ModifierType.ShiftMask == (args.Event.State & ModifierType.ShiftMask);
+ bool control = ModifierType.ControlMask == (args.Event.State & ModifierType.ControlMask);
+
+ switch (args.Event.Key) {
+ case Gdk.Key.Down:
+ case Gdk.Key.J:
+ case Gdk.Key.j:
+ FocusCell += VisibleColums;
+ break;
+
+ case Gdk.Key.Left:
+ case Gdk.Key.H:
+ case Gdk.Key.h:
+ if (control && shift)
+ FocusCell -= FocusCell % VisibleColums;
+ else
+ FocusCell--;
+ break;
+
+ case Gdk.Key.Right:
+ case Gdk.Key.L:
+ case Gdk.Key.l:
+ if (control && shift)
+ FocusCell += VisibleColums - (FocusCell % VisibleColums) - 1;
+ else
+ FocusCell++;
+ break;
+
+ case Gdk.Key.Up:
+ case Gdk.Key.K:
+ case Gdk.Key.k:
+ FocusCell -= VisibleColums;
+ break;
+
+ case Gdk.Key.Page_Up:
+ FocusCell -= VisibleColums * VisibleRows;
+ break;
+
+ case Gdk.Key.Page_Down:
+ FocusCell += VisibleColums * VisibleRows;
+ break;
+
+ case Gdk.Key.Home:
+ FocusCell = 0;
+ break;
+
+ case Gdk.Key.End:
+ FocusCell = Collection.Count - 1;
+ break;
+
+ case Gdk.Key.R:
+ case Gdk.Key.r:
+ FocusCell = new Random().Next(0, Collection.Count - 1);
+ break;
+
+ case Gdk.Key.space:
+ Selection.ToggleCell (FocusCell);
+ break;
+
+ case Gdk.Key.Return:
+ if (DoubleClicked != null)
+ DoubleClicked (this, new BrowsableEventArgs (FocusCell, null));
+ break;
+
+ default:
+ args.RetVal = false;
+ return;
+ }
+
+ if (shift) {
+ if (focus_old != FocusCell && Selection.Contains (focus_old) && Selection.Contains (FocusCell))
+ Selection.Remove (FocusCell, focus_old);
+ else
+ Selection.Add (focus_old, FocusCell);
+
+ } else if (!control) {
+ Selection.Clear ();
+ Selection.Add (FocusCell);
+ }
+
+ ScrollTo (FocusCell);
+ }
+
+#endregion
+
+ }
+}
+
diff --git a/src/Clients/MainApp/FSpot.Widgets/IconView.cs b/src/Clients/MainApp/FSpot.Widgets/IconView.cs
index a5a9171..3d8eee7 100644
--- a/src/Clients/MainApp/FSpot.Widgets/IconView.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/IconView.cs
@@ -24,20 +24,8 @@ using FSpot.Platform;
namespace FSpot.Widgets
{
- public class StartDragArgs {
- public Event Event { get; set; }
- public uint Button { get; set; }
- public StartDragArgs (uint but, Event evt) {
- this.Button = but;
- this.Event = evt;
- }
- }
-
- public delegate void StartDragHandler (object o, StartDragArgs args);
-
-
- public class IconView : CellGridView
+ public class IconView : CollectionGridView
{
// Public properties.
@@ -46,9 +34,7 @@ namespace FSpot.Widgets
#region Public Events
// Public events.
- public event EventHandler<BrowsableEventArgs> DoubleClicked;
public event EventHandler ZoomChanged;
- public event StartDragHandler StartDrag;
#endregion
@@ -117,15 +103,6 @@ namespace FSpot.Widgets
#region Implement base class layout properties
- protected override int CellCount {
- get {
- if (collection == null)
- return 0;
-
- return collection.Count;
- }
- }
-
protected override int CellHeight {
get {
int cell_height = ThumbnailHeight + 2 * cell_border_width;
@@ -248,456 +225,42 @@ namespace FSpot.Widgets
// Various other layout values.
protected int cell_details;
- // Focus Handling
- private int real_focus_cell;
- public int FocusCell {
- set {
- if (value != real_focus_cell) {
- value = Math.Max (value, 0);
- value = Math.Min (value, collection.Count - 1);
- InvalidateCell (value);
- InvalidateCell (real_focus_cell);
- real_focus_cell = value;
- }
- }
- get {
- return real_focus_cell;
- }
- }
-
// Public API.
public IconView (IntPtr raw) : base (raw) {}
- protected IconView () : base ()
+ public IconView (IBrowsableCollection collection) : base (collection)
{
- cache = new FSpot.PixbufCache ();
- cache.OnPixbufLoaded += HandlePixbufLoaded;
-
- ButtonPressEvent += new ButtonPressEventHandler (HandleButtonPressEvent);
- ButtonReleaseEvent += new ButtonReleaseEventHandler (HandleButtonReleaseEvent);
- KeyPressEvent += new KeyPressEventHandler (HandleKeyPressEvent);
- ScrollEvent += new ScrollEventHandler(HandleScrollEvent);
- MotionNotifyEvent += new MotionNotifyEventHandler (HandleSelectMotionNotify);
-
- Destroyed += HandleDestroyed;
-
- AddEvents (
- (int) EventMask.KeyPressMask
- | (int) EventMask.KeyReleaseMask
- | (int) EventMask.PointerMotionMask
- | (int) EventMask.PointerMotionHintMask
- | (int) EventMask.ButtonPressMask
- | (int) EventMask.ButtonReleaseMask);
-
- CanFocus = true;
- }
-
- public IconView (IBrowsableCollection collection) : this ()
- {
- this.collection = collection;
- this.selection = new SelectionCollection (collection);
+ cache = new FSpot.PixbufCache ();
+ cache.OnPixbufLoaded += HandlePixbufLoaded;
Name = "ImageContainer";
- collection.Changed += HandleChanged;
- collection.ItemsChanged += HandleItemsChanged;
-
- selection.DetailedChanged += HandleSelectionChanged;
- }
-
- private void HandleSelectionChanged (IBrowsableCollection collection, int [] ids)
- {
- if (ids == null)
- QueueDraw ();
- else
- foreach (int id in ids)
- InvalidateCell (id);
- }
-
- private void HandleChanged (IBrowsableCollection sender)
- {
- // FIXME we should probably try to merge the selection forward
- // but it needs some thought to be efficient.
- //suppress_scroll = true;
- QueueResize ();
- }
-
- private void HandleItemsChanged (IBrowsableCollection sender, BrowsableEventArgs args)
- {
- foreach (int item in args.Items) {
- if (args.Changes.DataChanged)
- UpdateThumbnail (item);
- InvalidateCell (item);
- }
- }
-
- //
- // IPhotoSelection
- //
+ Collection.ItemsChanged += HandleItemsChanged;
- protected IBrowsableCollection collection;
- public IBrowsableCollection Collection {
- get {
- return collection;
- }
- }
+ ScrollEvent += new ScrollEventHandler(HandleScrollEvent);
- protected SelectionCollection selection;
- public SelectionCollection Selection {
- get {
- return selection;
- }
+ Destroyed += HandleDestroyed;
}
- // FIXME right now a selection change triggers a complete view redraw
- // This should be optimized away by directly notifyiing the view of changed
- // indexes rather than having the view connect to the collection.Changed event.
- public class SelectionCollection : IBrowsableCollection {
- IBrowsableCollection parent;
- Hashtable selected_cells;
- BitArray bit_array;
- int [] selection;
- IPhoto [] items;
- IPhoto [] old;
-
- public SelectionCollection (IBrowsableCollection collection)
- {
- this.selected_cells = new Hashtable ();
- this.parent = collection;
- this.bit_array = new BitArray (this.parent.Count);
- this.parent.Changed += HandleParentChanged;
- this.parent.ItemsChanged += HandleParentItemsChanged;
- }
-
- private void HandleParentChanged (IBrowsableCollection collection)
- {
- IPhoto [] local = old;
- selected_cells.Clear ();
- bit_array = new BitArray (parent.Count);
- ClearCached ();
-
- if (old != null) {
- int i = 0;
-
- for (i = 0; i < local.Length; i++) {
- int parent_index = parent.IndexOf (local [i]);
- if (parent_index >= 0)
- this.Add (parent_index, false);
- }
- }
-
- // Call the directly so that we don't reset old immediately this way the old selection
- // set isn't actually lost until we change it.
- if (this.Changed != null)
- Changed (this);
-
- if (this.DetailedChanged != null)
- DetailedChanged (this, null);
-
- }
-
- public void MarkChanged (int item, IBrowsableItemChanges changes)
- {
- // Forward the change event up to our parent
- // we'll fire the event when the parent calls us back
- parent.MarkChanged ((int) selected_cells [item], changes);
- }
-
- private void HandleParentItemsChanged (IBrowsableCollection collection, BrowsableEventArgs args)
- {
- if (this.ItemsChanged == null)
- return;
-
- ArrayList local_ids = new ArrayList ();
- foreach (int parent_index in args.Items) {
- // If the item isn't part of the selection ignore it
- if (!this.Contains (collection [parent_index]))
- return;
-
- int local_index = this.IndexOf (parent_index);
- if (local_index >= 0)
- local_ids.Add (local_index);
- }
-
- if (local_ids.Count == 0)
- return;
-
- int [] items = (int [])local_ids.ToArray (typeof (int));
- ItemsChanged (this, new BrowsableEventArgs (items, args.Changes));
- }
-
- public BitArray ToBitArray () {
- return bit_array;
- }
-
- public int [] Ids {
- get {
- if (selection != null)
- return selection;
-
- selection = new int [selected_cells.Count];
-
- int i = 0;
- foreach (int cell in selected_cells.Values)
- selection [i ++] = cell;
-
- Array.Sort (selection);
- return selection;
- }
- }
-
- public IPhoto this [int index] {
- get {
- int [] ids = this.Ids;
- return parent [ids[index]];
- }
- }
-
- public IPhoto [] Items {
- get {
- if (items != null)
- return items;
-
- int [] ids = this.Ids;
- items = new IPhoto [ids.Length];
- for (int i = 0; i < items.Length; i++) {
- items [i] = parent [ids[i]];
- }
- return items;
- }
- }
-
- public void Clear ()
- {
- Clear (true);
- }
-
- public void Clear (bool update)
- {
- int [] ids = Ids;
- selected_cells.Clear ();
- bit_array.SetAll (false);
- SignalChange (ids);
- }
-
- public void Add (IPhoto item)
- {
- if (this.Contains (item))
- return;
-
- int index = parent.IndexOf (item);
- this.Add (index);
- }
-
- public int Count {
- get {
- return selected_cells.Count;
- }
- }
-
- public bool Contains (IPhoto item)
- {
- return selected_cells.ContainsKey (item);
- }
-
- public bool Contains (int num)
- {
- if (num < 0 || num > parent.Count)
- return false;
-
- return this.Contains (parent [num]);
- }
-
- public void Add (int num)
- {
- this.Add (num, true);
- }
-
- public void Add (int num, bool notify)
- {
- if (num == -1)
- return;
-
- if (this.Contains (num))
- return;
-
- IPhoto item = parent [num];
- selected_cells [item] = num;
- bit_array.Set (num, true);
-
- if (notify)
- SignalChange (new int [] {num});
- }
-
- public void Add (int start, int end)
- {
- if (start == -1 || end == -1)
- return;
-
- int current = Math.Min (start, end);
- int final = Math.Max (start, end);
- int count = final - current + 1;
- int [] ids = new int [count];
-
- for (int i = 0; i < count; i++) {
- this.Add (current, false);
- ids [i] = current;
- current++;
- }
-
- SignalChange (ids);
- }
-
- public void Remove (int cell, bool notify)
- {
- IPhoto item = parent [cell];
- if (item != null)
- this.Remove (item, notify);
-
- }
- public void Remove (IPhoto item)
- {
- Remove (item, true);
- }
-
- public void Remove (int cell)
- {
- Remove (cell, true);
- }
-
- private void Remove (IPhoto item, bool notify)
- {
- if (item == null)
- return;
-
- int parent_index = (int) selected_cells [item];
- selected_cells.Remove (item);
- bit_array.Set (parent_index, false);
-
- if (notify)
- SignalChange (new int [] {parent_index});
- }
-
- // Remove a range, except the start entry
- public void Remove (int start, int end)
- {
- if (start == -1 || end == -1)
- return;
-
- int current = Math.Min (start + 1, end);
- int final = Math.Max (start - 1, end);
- int count = final - current + 1;
- int [] ids = new int [count];
-
- for (int i = 0; i < count; i++) {
- this.Remove (current, false);
- ids [i] = current;
- current++;
- }
-
- SignalChange (ids);
- }
-
- public int IndexOf (int parent_index)
- {
- return System.Array.IndexOf (this.Ids, parent_index);
- }
-
- public int IndexOf (IPhoto item)
- {
- if (!this.Contains (item))
- return -1;
-
- int parent_index = (int) selected_cells [item];
- return System.Array.IndexOf (Ids, parent_index);
- }
-
- private void ToggleCell (int cell_num, bool notify)
- {
- if (Contains (cell_num))
- Remove (cell_num, notify);
- else
- Add (cell_num, notify);
- }
-
- public void ToggleCell (int cell_num)
- {
- ToggleCell (cell_num, true);
- }
-
- public void SelectionInvert ()
- {
- int [] changed_cell = new int[parent.Count];
- for (int i = 0; i < parent.Count; i++) {
- ToggleCell (i, false);
- changed_cell[i] = i;
- }
-
- SignalChange (changed_cell);
- }
-
- public void SelectRect (int start_row, int end_row, int start_line, int end_line, int cells_per_row)
- {
- for (int row = start_row; row < end_row; row++)
- for (int line = start_line; line < end_line; line++) {
- int index = line*cells_per_row + row;
- if (index < parent.Count)
- Add (index, false);
- }
- }
-
- public void ToggleRect (int start_row, int end_row, int start_line, int end_line, int cells_per_row)
- {
- for (int row = start_row; row < end_row; row++)
- for (int line = start_line; line < end_line; line++) {
- int index = line*cells_per_row + row;
- if (index < parent.Count)
- ToggleCell (index, false);
- }
- }
-
-
- public event IBrowsableCollectionChangedHandler Changed;
- public event IBrowsableCollectionItemsChangedHandler ItemsChanged;
-
- public delegate void DetailedCollectionChanged (IBrowsableCollection collection, int [] ids);
- public event DetailedCollectionChanged DetailedChanged;
-
- private void ClearCached ()
- {
- selection = null;
- items = null;
- }
-
- public void SignalChange (int [] ids)
- {
- ClearCached ();
- old = this.Items;
-
-
- if (Changed != null)
- Changed (this);
+ private void HandleItemsChanged (IBrowsableCollection sender, BrowsableEventArgs args)
+ {
+ foreach (int item in args.Items) {
+ if (args.Changes.DataChanged)
+ UpdateThumbnail (item);
+ InvalidateCell (item);
+ }
+ }
- if (DetailedChanged!= null)
- DetailedChanged (this, ids);
- }
- }
// Updating.
public void UpdateThumbnail (int thumbnail_num)
{
- IPhoto photo = collection [thumbnail_num];
+ IPhoto photo = Collection [thumbnail_num];
cache.Remove (photo.DefaultVersion.Uri);
InvalidateCell (thumbnail_num);
}
- // Private utility methods.
- public void SelectAllCells ()
- {
- selection.Add (0, collection.Count - 1);
- }
-
// Layout and drawing.
/* protected virtual void UpdateLayout ()
{
@@ -810,65 +373,59 @@ namespace FSpot.Widgets
return expansion;
}
- // rectangle of dragging selection
- private Rectangle rect_select;
-
System.Collections.Hashtable date_layouts = new Hashtable ();
// FIXME Cache the GCs?
- protected override void DrawCell (int thumbnail_num, Gdk.Rectangle area)
+ protected override void DrawPhoto (int cell_num, Rectangle cell_area, Rectangle expose_area, bool selected, bool focussed)
{
- Gdk.Rectangle bounds = CellBounds (thumbnail_num);
-
- if (!bounds.Intersect (area, out area))
+ if (!cell_area.Intersect (expose_area, out expose_area))
return;
- IPhoto photo = collection [thumbnail_num];
+ IPhoto photo = Collection [cell_num];
FSpot.PixbufCache.CacheEntry entry = cache.Lookup (photo.DefaultVersion.Uri);
if (entry == null)
- cache.Request (photo.DefaultVersion.Uri, thumbnail_num, ThumbnailWidth, ThumbnailHeight);
+ cache.Request (photo.DefaultVersion.Uri, cell_num, ThumbnailWidth, ThumbnailHeight);
else
- entry.Data = thumbnail_num;
+ entry.Data = cell_num;
- bool selected = selection.Contains (thumbnail_num);
StateType cell_state = selected ? (HasFocus ? StateType.Selected : StateType.Active) : State;
if (cell_state != State)
Style.PaintBox (Style, BinWindow, cell_state,
- ShadowType.Out, area, this, "IconView",
- bounds.X, bounds.Y,
- bounds.Width - 1, bounds.Height - 1);
+ ShadowType.Out, expose_area, this, "IconView",
+ cell_area.X, cell_area.Y,
+ cell_area.Width - 1, cell_area.Height - 1);
- Gdk.Rectangle focus = Gdk.Rectangle.Inflate (bounds, -3, -3);
+ Gdk.Rectangle focus = Gdk.Rectangle.Inflate (cell_area, -3, -3);
- if (HasFocus && thumbnail_num == FocusCell) {
+ if (HasFocus && focussed) {
Style.PaintFocus(Style, BinWindow,
- cell_state, area,
+ cell_state, expose_area,
this, null,
focus.X, focus.Y,
focus.Width, focus.Height);
}
Gdk.Rectangle region = Gdk.Rectangle.Zero;
- Gdk.Rectangle image_bounds = Gdk.Rectangle.Inflate (bounds, -cell_border_width, -cell_border_width);
- int expansion = ThrobExpansion (thumbnail_num, selected);
+ Gdk.Rectangle image_bounds = Gdk.Rectangle.Inflate (cell_area, -cell_border_width, -cell_border_width);
+ int expansion = ThrobExpansion (cell_num, selected);
Gdk.Pixbuf thumbnail = null;
if (entry != null)
thumbnail = entry.ShallowCopyPixbuf ();
Gdk.Rectangle draw = Gdk.Rectangle.Zero;
- if (Gdk.Rectangle.Inflate (image_bounds, expansion + 1, expansion + 1).Intersect (area, out image_bounds) && thumbnail != null) {
+ if (Gdk.Rectangle.Inflate (image_bounds, expansion + 1, expansion + 1).Intersect (expose_area, out image_bounds) && thumbnail != null) {
PixbufUtils.Fit (thumbnail, ThumbnailWidth, ThumbnailHeight,
true, out region.Width, out region.Height);
- region.X = (int) (bounds.X + (bounds.Width - region.Width) / 2);
- region.Y = (int) bounds.Y + ThumbnailHeight - region.Height + cell_border_width;
+ region.X = (int) (cell_area.X + (cell_area.Width - region.Width) / 2);
+ region.Y = (int) cell_area.Y + ThumbnailHeight - region.Height + cell_border_width;
if (Math.Abs (region.Width - thumbnail.Width) > 1
&& Math.Abs (region.Height - thumbnail.Height) > 1)
- cache.Reload (entry, thumbnail_num, thumbnail.Width, thumbnail.Height);
+ cache.Reload (entry, cell_num, thumbnail.Width, thumbnail.Height);
region = Gdk.Rectangle.Inflate (region, expansion, expansion);
Pixbuf temp_thumbnail;
@@ -909,12 +466,12 @@ namespace FSpot.Widgets
if (!temp_thumbnail.HasAlpha)
Style.PaintShadow (Style, BinWindow, cell_state,
- ShadowType.Out, area, this,
+ ShadowType.Out, expose_area, this,
"IconView",
draw.X, draw.Y,
draw.Width, draw.Height);
- if (region.Intersect (area, out draw)) {
+ if (region.Intersect (expose_area, out draw)) {
Cms.Profile screen_profile;
if (FSpot.ColorManagement.Profiles.TryGetValue (Preferences.Get<string> (Preferences.COLOR_MANAGEMENT_DISPLAY_PROFILE), out screen_profile)) {
Pixbuf t = temp_thumbnail.Copy ();
@@ -969,9 +526,9 @@ namespace FSpot.Widgets
layout.GetPixelSize (out layout_bounds.Width, out layout_bounds.Height);
- layout_bounds.Y = bounds.Y + bounds.Height -
+ layout_bounds.Y = cell_area.Y + cell_area.Height -
cell_border_width - layout_bounds.Height + tag_icon_vspacing;
- layout_bounds.X = bounds.X + (bounds.Width - layout_bounds.Width) / 2;
+ layout_bounds.X = cell_area.X + (cell_area.Width - layout_bounds.Width) / 2;
if (DisplayTags)
layout_bounds.Y -= tag_icon_size;
@@ -980,9 +537,9 @@ namespace FSpot.Widgets
layout_bounds.Y -= Style.FontDescription.MeasureTextHeight (PangoContext);
}
- if (layout_bounds.Intersect (area, out region)) {
+ if (layout_bounds.Intersect (expose_area, out region)) {
Style.PaintLayout (Style, BinWindow, cell_state,
- true, area, this, "IconView",
+ true, expose_area, this, "IconView",
layout_bounds.X, layout_bounds.Y,
layout);
}
@@ -996,15 +553,15 @@ namespace FSpot.Widgets
layout.GetPixelSize (out layout_bounds.Width, out layout_bounds.Height);
- layout_bounds.Y = bounds.Y + bounds.Height - cell_border_width - layout_bounds.Height + tag_icon_vspacing;
- layout_bounds.X = bounds.X + (bounds.Width - layout_bounds.Width) / 2;
+ layout_bounds.Y = cell_area.Y + cell_area.Height - cell_border_width - layout_bounds.Height + tag_icon_vspacing;
+ layout_bounds.X = cell_area.X + (cell_area.Width - layout_bounds.Width) / 2;
if (DisplayTags)
layout_bounds.Y -= tag_icon_size;
- if (layout_bounds.Intersect (area, out region)) {
+ if (layout_bounds.Intersect (expose_area, out region)) {
Style.PaintLayout (Style, BinWindow, cell_state,
- true, area, this, "IconView",
+ true, expose_area, this, "IconView",
layout_bounds.X, layout_bounds.Y,
layout);
}
@@ -1015,8 +572,8 @@ namespace FSpot.Widgets
Tag [] tags = photo.Tags;
Gdk.Rectangle tag_bounds;
- tag_bounds.X = bounds.X + (bounds.Width + tag_icon_hspacing - tags.Length * (tag_icon_size + tag_icon_hspacing)) / 2;
- tag_bounds.Y = bounds.Y + bounds.Height - cell_border_width - tag_icon_size + tag_icon_vspacing;
+ tag_bounds.X = cell_area.X + (cell_area.Width + tag_icon_hspacing - tags.Length * (tag_icon_size + tag_icon_hspacing)) / 2;
+ tag_bounds.Y = cell_area.Y + cell_area.Height - cell_border_width - tag_icon_size + tag_icon_vspacing;
tag_bounds.Width = tag_icon_size;
tag_bounds.Height = tag_icon_size;
@@ -1035,7 +592,7 @@ namespace FSpot.Widgets
if (icon == null)
continue;
- if (tag_bounds.Intersect (area, out region)) {
+ if (tag_bounds.Intersect (expose_area, out region)) {
Pixbuf scaled_icon;
if (icon.Width == tag_bounds.Width) {
scaled_icon = icon;
@@ -1067,7 +624,7 @@ namespace FSpot.Widgets
protected override void PreloadCell (int cell_num)
{
- var photo = collection [cell_num];
+ var photo = Collection [cell_num];
var entry = cache.Lookup (photo.DefaultVersion.Uri);
if (entry == null)
@@ -1192,349 +749,6 @@ namespace FSpot.Widgets
SetColors ();
}
-/* protected override void OnSizeAllocated (Gdk.Rectangle allocation)
- {
- scroll_value = (Vadjustment.Value)/ (Vadjustment.Upper);
- scroll = !suppress_scroll;
- suppress_scroll = false;
- UpdateLayout (allocation);
- base.OnSizeAllocated (allocation);
- }*/
-
-
- 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;
-
- // during pointer motion, select/toggle pictures between initial x/y (param)
- // and current x/y (get pointer)
- private void SelectMotion ()
- {
-/* 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;
-
- // Restore initial selection
- BitArray initial_selection = selection.ToBitArray();
- selection.Clear (false);
- foreach (int i in start_select_selection)
- selection.Add (i, false);
-
- // Select or toggle according to modifiers
- int start_row = (start_x - BORDER_SIZE) / cell_width;
- int start_line = (start_y - BORDER_SIZE) / cell_height;
- int end_row = (end_x - BORDER_SIZE + cell_width - 1) / cell_width;
- int end_line = (end_y - BORDER_SIZE + 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;
-
-
- 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);
-
- // fire events for cells which have changed selection flag
- BitArray new_selection = selection.ToBitArray();
- BitArray selection_changed = initial_selection.Xor (new_selection);
- System.Collections.Generic.List<int> changed = new System.Collections.Generic.List<int>();
- for (int i = 0; i < selection_changed.Length; i++)
- if (selection_changed.Get(i))
- changed.Add (i);
- if (selection_changed.Length != 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()
- {
- 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
- double newVadj = Vadjustment.Value;
- if (deltaVscroll < 130)
- deltaVscroll += 15;
-
- if (new_y <= 0) {
- newVadj -= deltaVscroll;
- if (newVadj < 0)
- newVadj = 0;
- } else if ((new_y > Allocation.Height) &&
- (newVadj < Vadjustment.Upper - Allocation.Height - deltaVscroll))
- newVadj += deltaVscroll;
- Vadjustment.Value = newVadj;
- Vadjustment.ChangeValue();
-
- // do again selection after scroll
- SelectMotion ();
-
- // stop firing timeout when no button pressed
- return (new_mod & (ModifierType.Button1Mask | ModifierType.Button3Mask)) != 0;
- }
-
- 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;
- }
- }
- }
- }
-
- private void HandleButtonPressEvent (object obj, ButtonPressEventArgs args)
- {
- int cell_num = CellAtPosition ((int) args.Event.X, (int) args.Event.Y, false, false);
-
- args.RetVal = true;
-
- start_select_event = args.Event;
- start_press_x = (int) args.Event.X;
- start_press_y = (int) args.Event.Y;
- isRectSelection = false;
- isDragDrop = false;
-
- switch (args.Event.Type) {
- case EventType.TwoButtonPress:
- if (args.Event.Button != 1 ||
- (args.Event.State & (ModifierType.ControlMask | ModifierType.ShiftMask)) != 0)
- return;
- if (DoubleClicked != null)
- DoubleClicked (this, new BrowsableEventArgs (cell_num, null));
- return;
-
- case EventType.ButtonPress:
- GrabFocus ();
- // on a cell : context menu if button 3
- // cell selection is done on button release
- if (args.Event.Button == 3){
- ContextMenu (args, cell_num);
- return;
- } else args.RetVal = false;
-
- break;
-
- default:
- args.RetVal = false;
- break;
- }
- }
-
- protected virtual void ContextMenu (ButtonPressEventArgs args, int cell_num)
- {
- }
-
- private void HandleButtonReleaseEvent (object sender, ButtonReleaseEventArgs args)
- {
- if (isRectSelection) {
- // remove scrolling and rectangular selection
- if (scroll_timeout != 0) {
- GLib.Source.Remove (scroll_timeout);
- scroll_timeout = 0;
- }
- SelectMotion ();
-
- isRectSelection = false;
- if (BinWindow != null) {
- BinWindow.InvalidateRect (rect_select, false);
- BinWindow.ProcessUpdates (true);
- }
- rect_select = new Rectangle();
- } else if (!isDragDrop) {
- int cell_num = CellAtPosition ((int) args.Event.X, (int) args.Event.Y, false, true);
- if (cell_num != -1) {
- if ((args.Event.State & ModifierType.ControlMask) != 0) {
- selection.ToggleCell (cell_num);
- } else if ((args.Event.State & ModifierType.ShiftMask) != 0) {
- selection.Add (FocusCell, cell_num);
- } else {
- selection.Clear ();
- selection.Add (cell_num);
- }
- FocusCell = cell_num;
- }
- }
- isDragDrop = false;
- }
-
- private void HandleKeyPressEvent (object sender, KeyPressEventArgs args)
- {
- int focus_old;
- args.RetVal = true;
- bool shift = ModifierType.ShiftMask == (args.Event.State & ModifierType.ShiftMask);
- bool control = ModifierType.ControlMask == (args.Event.State & ModifierType.ControlMask);
-
- focus_old = FocusCell;
- switch (args.Event.Key) {
- case Gdk.Key.Down:
- case Gdk.Key.J:
- case Gdk.Key.j:
- FocusCell += VisibleColums;
- break;
- case Gdk.Key.Left:
- case Gdk.Key.H:
- case Gdk.Key.h:
- if (control && shift)
- FocusCell -= FocusCell % VisibleColums;
- else
- FocusCell--;
- break;
- case Gdk.Key.Right:
- case Gdk.Key.L:
- case Gdk.Key.l:
- if (control && shift)
- FocusCell += VisibleColums - (FocusCell % VisibleColums) - 1;
- else
- FocusCell++;
- break;
- case Gdk.Key.Up:
- case Gdk.Key.K:
- case Gdk.Key.k:
- FocusCell -= VisibleColums;
- break;
- case Gdk.Key.Page_Up:
- FocusCell -= VisibleColums * VisibleRows;
- break;
- case Gdk.Key.Page_Down:
- FocusCell += VisibleColums * VisibleRows;
- break;
- case Gdk.Key.Home:
- FocusCell = 0;
- break;
- case Gdk.Key.End:
- FocusCell = collection.Count - 1;
- break;
- case Gdk.Key.R:
- case Gdk.Key.r:
- FocusCell = new Random().Next(0, collection.Count - 1);
- break;
- case Gdk.Key.space:
- selection.ToggleCell (FocusCell);
- break;
- case Gdk.Key.Return:
- if (DoubleClicked != null)
- DoubleClicked (this, new BrowsableEventArgs (FocusCell, null));
- break;
- default:
- args.RetVal = false;
- return;
- }
-
- if (shift) {
- if (focus_old != FocusCell && selection.Contains (focus_old) && selection.Contains (FocusCell))
- selection.Remove (FocusCell, focus_old);
- else
- selection.Add (focus_old, FocusCell);
- } else if (!control) {
- selection.Clear ();
- selection.Add (FocusCell);
- }
-
- ScrollTo (FocusCell);
- }
-
private void HandleDestroyed (object sender, System.EventArgs args)
{
cache.OnPixbufLoaded -= HandlePixbufLoaded;
diff --git a/src/Clients/MainApp/FSpot.Widgets/ScalingIconView.cs b/src/Clients/MainApp/FSpot.Widgets/ScalingIconView.cs
index 0e992e7..39ad688 100644
--- a/src/Clients/MainApp/FSpot.Widgets/ScalingIconView.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/ScalingIconView.cs
@@ -14,7 +14,7 @@ namespace FSpot.Widgets {
public class ScalingIconView : IconView {
protected ScalingIconView (IntPtr raw) : base (raw) {}
- public ScalingIconView () : base () { }
+ //public ScalingIconView () : base () { }
public ScalingIconView (IBrowsableCollection collection) : base (collection) { }
/*protected override void UpdateLayout ()
diff --git a/src/Clients/MainApp/FSpot.Widgets/SelectionCollection.cs b/src/Clients/MainApp/FSpot.Widgets/SelectionCollection.cs
new file mode 100644
index 0000000..5c0451d
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/SelectionCollection.cs
@@ -0,0 +1,341 @@
+using System;
+using System.Collections;
+
+using FSpot.Core;
+
+namespace FSpot.Widgets
+{
+ public class SelectionCollection : IBrowsableCollection
+ {
+ IBrowsableCollection parent;
+ Hashtable selected_cells;
+ BitArray bit_array;
+ int [] selection;
+ IPhoto [] items;
+ IPhoto [] old;
+
+ public SelectionCollection (IBrowsableCollection collection)
+ {
+ this.selected_cells = new Hashtable ();
+ this.parent = collection;
+ this.bit_array = new BitArray (this.parent.Count);
+ this.parent.Changed += HandleParentChanged;
+ this.parent.ItemsChanged += HandleParentItemsChanged;
+ }
+
+ private void HandleParentChanged (IBrowsableCollection collection)
+ {
+ IPhoto [] local = old;
+ selected_cells.Clear ();
+ bit_array = new BitArray (parent.Count);
+ ClearCached ();
+
+ if (old != null) {
+ int i = 0;
+
+ for (i = 0; i < local.Length; i++) {
+ int parent_index = parent.IndexOf (local [i]);
+ if (parent_index >= 0)
+ this.Add (parent_index, false);
+ }
+ }
+
+ // Call the directly so that we don't reset old immediately this way the old selection
+ // set isn't actually lost until we change it.
+ if (this.Changed != null)
+ Changed (this);
+
+ if (this.DetailedChanged != null)
+ DetailedChanged (this, null);
+
+ }
+
+ public void MarkChanged (int item, IBrowsableItemChanges changes)
+ {
+ // Forward the change event up to our parent
+ // we'll fire the event when the parent calls us back
+ parent.MarkChanged ((int) selected_cells [item], changes);
+ }
+
+ private void HandleParentItemsChanged (IBrowsableCollection collection, BrowsableEventArgs args)
+ {
+ if (this.ItemsChanged == null)
+ return;
+
+ ArrayList local_ids = new ArrayList ();
+ foreach (int parent_index in args.Items) {
+ // If the item isn't part of the selection ignore it
+ if (!this.Contains (collection [parent_index]))
+ return;
+
+ int local_index = this.IndexOf (parent_index);
+ if (local_index >= 0)
+ local_ids.Add (local_index);
+ }
+
+ if (local_ids.Count == 0)
+ return;
+
+ int [] items = (int [])local_ids.ToArray (typeof (int));
+ ItemsChanged (this, new BrowsableEventArgs (items, args.Changes));
+ }
+
+ public BitArray ToBitArray () {
+ return bit_array;
+ }
+
+ public int [] Ids {
+ get {
+ if (selection != null)
+ return selection;
+
+ selection = new int [selected_cells.Count];
+
+ int i = 0;
+ foreach (int cell in selected_cells.Values)
+ selection [i ++] = cell;
+
+ Array.Sort (selection);
+ return selection;
+ }
+ }
+
+ public IPhoto this [int index] {
+ get {
+ int [] ids = this.Ids;
+ return parent [ids[index]];
+ }
+ }
+
+ public IPhoto [] Items {
+ get {
+ if (items != null)
+ return items;
+
+ int [] ids = this.Ids;
+ items = new IPhoto [ids.Length];
+ for (int i = 0; i < items.Length; i++) {
+ items [i] = parent [ids[i]];
+ }
+ return items;
+ }
+ }
+
+ public void Clear ()
+ {
+ Clear (true);
+ }
+
+ public void Clear (bool update)
+ {
+ int [] ids = Ids;
+ selected_cells.Clear ();
+ bit_array.SetAll (false);
+ SignalChange (ids);
+ }
+
+ public void Add (IPhoto item)
+ {
+ if (this.Contains (item))
+ return;
+
+ int index = parent.IndexOf (item);
+ this.Add (index);
+ }
+
+ public int Count {
+ get {
+ return selected_cells.Count;
+ }
+ }
+
+ public bool Contains (IPhoto item)
+ {
+ return selected_cells.ContainsKey (item);
+ }
+
+ public bool Contains (int num)
+ {
+ if (num < 0 || num > parent.Count)
+ return false;
+
+ return this.Contains (parent [num]);
+ }
+
+ public void Add (int num)
+ {
+ this.Add (num, true);
+ }
+
+ public void Add (int num, bool notify)
+ {
+ if (num == -1)
+ return;
+
+ if (this.Contains (num))
+ return;
+
+ IPhoto item = parent [num];
+ selected_cells [item] = num;
+ bit_array.Set (num, true);
+
+ if (notify)
+ SignalChange (new int [] {num});
+ }
+
+ public void Add (int start, int end)
+ {
+ if (start == -1 || end == -1)
+ return;
+
+ int current = Math.Min (start, end);
+ int final = Math.Max (start, end);
+ int count = final - current + 1;
+ int [] ids = new int [count];
+
+ for (int i = 0; i < count; i++) {
+ this.Add (current, false);
+ ids [i] = current;
+ current++;
+ }
+
+ SignalChange (ids);
+ }
+
+ public void Remove (int cell, bool notify)
+ {
+ IPhoto item = parent [cell];
+ if (item != null)
+ this.Remove (item, notify);
+
+ }
+
+ public void Remove (IPhoto item)
+ {
+ Remove (item, true);
+ }
+
+ public void Remove (int cell)
+ {
+ Remove (cell, true);
+ }
+
+ private void Remove (IPhoto item, bool notify)
+ {
+ if (item == null)
+ return;
+
+ int parent_index = (int) selected_cells [item];
+ selected_cells.Remove (item);
+ bit_array.Set (parent_index, false);
+
+ if (notify)
+ SignalChange (new int [] {parent_index});
+ }
+
+ // Remove a range, except the start entry
+ public void Remove (int start, int end)
+ {
+ if (start == -1 || end == -1)
+ return;
+
+ int current = Math.Min (start + 1, end);
+ int final = Math.Max (start - 1, end);
+ int count = final - current + 1;
+ int [] ids = new int [count];
+
+ for (int i = 0; i < count; i++) {
+ this.Remove (current, false);
+ ids [i] = current;
+ current++;
+ }
+
+ SignalChange (ids);
+ }
+
+ public int IndexOf (int parent_index)
+ {
+ return System.Array.IndexOf (this.Ids, parent_index);
+ }
+
+ public int IndexOf (IPhoto item)
+ {
+ if (!this.Contains (item))
+ return -1;
+
+ int parent_index = (int) selected_cells [item];
+ return System.Array.IndexOf (Ids, parent_index);
+ }
+
+ private void ToggleCell (int cell_num, bool notify)
+ {
+ if (Contains (cell_num))
+ Remove (cell_num, notify);
+ else
+ Add (cell_num, notify);
+ }
+
+ public void ToggleCell (int cell_num)
+ {
+ ToggleCell (cell_num, true);
+ }
+
+ public void SelectionInvert ()
+ {
+ int [] changed_cell = new int[parent.Count];
+ for (int i = 0; i < parent.Count; i++) {
+ ToggleCell (i, false);
+ changed_cell[i] = i;
+ }
+
+ SignalChange (changed_cell);
+ }
+
+ public void SelectRect (int start_row, int end_row, int start_line, int end_line, int cells_per_row)
+ {
+ for (int row = start_row; row < end_row; row++)
+ for (int line = start_line; line < end_line; line++) {
+ int index = line*cells_per_row + row;
+ if (index < parent.Count)
+ Add (index, false);
+ }
+ }
+
+ public void ToggleRect (int start_row, int end_row, int start_line, int end_line, int cells_per_row)
+ {
+ for (int row = start_row; row < end_row; row++)
+ for (int line = start_line; line < end_line; line++) {
+ int index = line*cells_per_row + row;
+ if (index < parent.Count)
+ ToggleCell (index, false);
+ }
+ }
+
+
+ public event IBrowsableCollectionChangedHandler Changed;
+ public event IBrowsableCollectionItemsChangedHandler ItemsChanged;
+
+ public delegate void DetailedCollectionChanged (IBrowsableCollection collection, int [] ids);
+ public event DetailedCollectionChanged DetailedChanged;
+
+ private void ClearCached ()
+ {
+ selection = null;
+ items = null;
+ }
+
+ public void SignalChange (int [] ids)
+ {
+ ClearCached ();
+ old = this.Items;
+
+
+ if (Changed != null)
+ Changed (this);
+
+ if (DetailedChanged!= null)
+ DetailedChanged (this, ids);
+ }
+ }
+}
+
diff --git a/src/Clients/MainApp/FSpot/SingleView.cs b/src/Clients/MainApp/FSpot/SingleView.cs
index 9f21414..da395db 100644
--- a/src/Clients/MainApp/FSpot/SingleView.cs
+++ b/src/Clients/MainApp/FSpot/SingleView.cs
@@ -252,7 +252,7 @@ namespace FSpot {
{
if (selection.Count > 0) {
- image_view.Item.Index = ((FSpot.Widgets.IconView.SelectionCollection)selection).Ids[0];
+ image_view.Item.Index = ((FSpot.Widgets.SelectionCollection)selection).Ids[0];
zoom_scale.Value = image_view.NormalizedZoom;
}
diff --git a/src/Clients/MainApp/Makefile.am b/src/Clients/MainApp/Makefile.am
index 8e6ef75..6f05eb6 100644
--- a/src/Clients/MainApp/Makefile.am
+++ b/src/Clients/MainApp/Makefile.am
@@ -89,6 +89,7 @@ SOURCES = \
FSpot.UI.Dialog/ThreadProgressDialog.cs \
FSpot.Widgets/CellGridView.cs \
FSpot.Widgets/CellRendererTextProgress.cs \
+ FSpot.Widgets/CollectionCellGridView.cs \
FSpot.Widgets/EditorPage.cs \
FSpot.Widgets/Filmstrip.cs \
FSpot.Widgets/FindBar.cs \
@@ -105,6 +106,7 @@ SOURCES = \
FSpot.Widgets/QueryView.cs \
FSpot.Widgets/RatingMenuItem.cs \
FSpot.Widgets/ScalingIconView.cs \
+ FSpot.Widgets/SelectionCollection.cs \
FSpot.Widgets/Sharpener.cs \
FSpot.Widgets/Sidebar.cs \
FSpot.Widgets/SlideShow.cs \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]