aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Design/UISelectionService.cs
diff options
context:
space:
mode:
authorMichaelTheShifter <[email protected]>2016-07-20 09:40:36 -0400
committerMichaelTheShifter <[email protected]>2016-07-20 09:40:36 -0400
commitd40fed5ce2bc806a91245adb18039634eac13ed0 (patch)
treef1d7168aee6db109ac2c738ad18c9db667a6ba69 /source/ShiftUI/Design/UISelectionService.cs
parentf1856e8ed30ed882229fd3fa2a4038122a5fb441 (diff)
downloadshiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.gz
shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.bz2
shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.zip
Move ShiftUI source code to ShiftOS
This'll be a lot easier to work on.
Diffstat (limited to 'source/ShiftUI/Design/UISelectionService.cs')
-rw-r--r--source/ShiftUI/Design/UISelectionService.cs532
1 files changed, 532 insertions, 0 deletions
diff --git a/source/ShiftUI/Design/UISelectionService.cs b/source/ShiftUI/Design/UISelectionService.cs
new file mode 100644
index 0000000..78a722b
--- /dev/null
+++ b/source/ShiftUI/Design/UISelectionService.cs
@@ -0,0 +1,532 @@
+//
+// ShiftUI.Design.UISelectionService
+//
+// Authors:
+// Ivan N. Zlatev (contact i-nZ.net)
+//
+// (C) 2007 Ivan N. Zlatev
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using ShiftUI;
+
+namespace ShiftUI.Design
+{
+
+ internal class UISelectionService : IUISelectionService
+ {
+
+ private IServiceProvider _serviceProvider;
+ private DesignerTransaction _transaction;
+ private ISelectionService _selectionService;
+
+ public UISelectionService (IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ throw new ArgumentNullException ("serviceProvider");
+
+ _serviceProvider = serviceProvider;
+ _transaction = null;
+
+ _selectionService = serviceProvider.GetService (typeof (ISelectionService)) as ISelectionService;
+ if (_selectionService == null) {
+ IServiceContainer serviceContainer = serviceProvider.GetService (typeof (IServiceContainer)) as IServiceContainer;
+ _selectionService = new UISelectionService (serviceContainer) as ISelectionService;
+ serviceContainer.AddService (typeof (ISelectionService), (ISelectionService) _selectionService);
+ }
+
+ _selectionService.SelectionChanged += new EventHandler (OnSelectionChanged);
+ }
+
+ private ISelectionService SelectionService {
+ get { return _selectionService; }
+ }
+
+ private object GetService (Type service)
+ {
+ return _serviceProvider.GetService (service);
+ }
+
+ public bool SelectionInProgress {
+ get { return _selecting; }
+ }
+
+ public bool DragDropInProgress {
+ get { return _dragging; }
+ }
+
+ public bool ResizeInProgress{
+ get { return _resizing; }
+ }
+
+
+ public bool SetCursor (int x, int y)
+ {
+ bool modified = false;
+ // if moving mouse around - set cursor if mouse is hovering a selectionframes' grabhandles
+ //
+ SelectionFrame frame = GetSelectionFrameAt (x, y);
+ if (frame != null && frame.HitTest (x, y) && frame.SetCursor (x, y))
+ modified = true;
+
+ return modified;
+ }
+
+
+ public void MouseDragBegin (Widget container, int x, int y)
+ {
+ // * start resizing the selection frame
+ // * start selecting
+ //
+ SelectionFrame frame = GetSelectionFrameAt (x, y);
+
+ if (frame != null && frame.HitTest (x, y)) {
+ this.SelectionService.SetSelectedComponents (new IComponent[] { frame.Widget });
+ if (_transaction == null) {
+ IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
+ _transaction = host.CreateTransaction ("Resize " +
+ (this.SelectionService.SelectionCount == 1 ? ((IComponent)this.SelectionService.PrimarySelection).Site.Name : "controls"));
+ }
+ this.ResizeBegin (x, y);
+ }
+ else {
+ SelectionBegin (container, x, y);
+ }
+ }
+
+ public void MouseDragMove (int x, int y)
+ {
+ if (_selecting)
+ SelectionContinue (x, y);
+ else if (_resizing)
+ ResizeContinue (x, y);
+ }
+
+ public void MouseDragEnd (bool cancel)
+ {
+ if (_selecting)
+ SelectionEnd (cancel);
+ else if (_resizing) {
+ ResizeEnd (cancel);
+ if (_transaction != null) {
+ if (cancel)
+ _transaction.Cancel ();
+ else
+ _transaction.Commit ();
+ _transaction = null;
+ }
+ }
+
+ if (Cursor.Current != Cursors.Default)
+ Cursor.Current = Cursors.Default;
+ }
+
+
+#region Dragging
+ private bool _dragging = false;
+ private Point _prevMousePosition;
+ private bool _firstMove = false;
+
+ // container coordinates (primary selection's)
+ //
+ public void DragBegin ()
+ {
+ // Console.WriteLine ("DragBegin");
+ if (_transaction == null) {
+ IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
+ _transaction = host.CreateTransaction ("Move " +
+ (this.SelectionService.SelectionCount == 1? ((IComponent)this.SelectionService.PrimarySelection).Site.Name : "controls"));
+ }
+ _dragging = true;
+ _firstMove = true;
+ if (this.SelectionService.PrimarySelection != null)
+ ((Widget)this.SelectionService.PrimarySelection).DoDragDrop (new WidgetDataObject ((Widget)this.SelectionService.PrimarySelection), DragDropEffects.All);
+ }
+
+ // container cordinates
+ //
+ public void DragOver (Widget container, int x, int y)
+ {
+ // Console.WriteLine ("DragOver");
+ if (_dragging) {
+ if (_firstMove) {
+ _prevMousePosition = new Point (x, y);
+ _firstMove = false;
+ }
+ else {
+ int dx = x - _prevMousePosition.X;
+ int dy = y - _prevMousePosition.Y;
+ MoveSelection (container, dx, dy);
+ _prevMousePosition = new Point (x, y);
+
+ // Repaint everything >_<
+ //
+ IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
+ if (host != null && host.RootComponent != null)
+ ((Widget)host.RootComponent).Refresh ();
+ //container.Refresh ();
+ }
+ }
+ }
+
+ // container coordinates
+ //
+ public void DragDrop (bool cancel, Widget container, int x, int y)
+ {
+ // Console.WriteLine ("UISelectionService.DragDrop: in " + container.Site.Name);
+ if (_dragging) {
+ int dx = x - _prevMousePosition.X;
+ int dy = y - _prevMousePosition.Y;
+
+ MoveSelection (container, dx, dy);
+ _dragging = false;
+
+ // Repaint everything
+ //
+ IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
+ if (host != null && host.RootComponent != null)
+ ((Widget)host.RootComponent).Refresh ();
+ // Send mouse up message to the primary selection
+ // Else for parentcontroldesigner there is no mouseup event and it doesn't set allow drop back to false
+ //
+ Native.SendMessage (((Widget)this.SelectionService.PrimarySelection).Handle, Native.Msg.WM_LBUTTONUP, (IntPtr) 0, (IntPtr) 0);
+ if (_transaction != null) {
+ if (cancel)
+ _transaction.Cancel ();
+ else
+ _transaction.Commit ();
+ _transaction = null;
+ }
+ }
+ }
+
+ private void MoveSelection (Widget container, int dx, int dy)
+ {
+ bool reparent = false;
+ Widget oldParent = null;
+
+ if (((Widget)this.SelectionService.PrimarySelection).Parent != container && !this.SelectionService.GetComponentSelected (container)) {
+ reparent = true;
+ oldParent = ((Widget)this.SelectionService.PrimarySelection).Parent;
+ }
+
+ // FIXME: Should check selectionstyle per control to determine if it's locked...
+ // if locked -> don't move
+ //
+ ICollection selection = this.SelectionService.GetSelectedComponents ();
+ foreach (Component component in selection) {
+ Widget control = component as Widget;
+ if (reparent)
+ TypeDescriptor.GetProperties (control)["Parent"].SetValue (control, container);
+
+ PropertyDescriptor property = TypeDescriptor.GetProperties (control)["Location"];
+ Point location = (Point) property.GetValue (control);
+ location.X += dx;
+ location.Y += dy;
+ property.SetValue (control, location);
+ }
+
+ if (reparent) {
+ oldParent.Invalidate (false);
+ oldParent.Update ();
+ }
+ }
+#endregion
+
+
+#region Selection
+
+ private bool _selecting = false;
+ private Widget _selectionContainer = null;
+ private Point _initialMousePosition;
+ private Rectangle _selectionRectangle;
+ // XXX
+ private ArrayList _selectionFrames = new ArrayList ();
+
+
+ public Rectangle SelectionBounds {
+ get { return _selectionRectangle; }
+ }
+
+ // container coordinates
+ //
+ private void SelectionBegin (Widget container, int x, int y)
+ {
+ // Console.WriteLine ("SelectionBegin");
+ _selecting = true;
+ _selectionContainer = container;
+ _prevMousePosition = new Point (x, y);
+ _initialMousePosition = _prevMousePosition;
+ _selectionRectangle = new Rectangle (x , y, 0, 0);
+ }
+
+ private void SelectionContinue (int x, int y)
+ {
+ // Console.WriteLine ("SelectionContinue");
+ if (_selecting) {
+ // right to right
+ //
+ if (x > _selectionRectangle.Right) {
+ _selectionRectangle.Width = x - _selectionRectangle.X;
+ }
+ // right to left
+ else if (x > _selectionRectangle.X && x < _selectionRectangle.Right &&
+ x < _prevMousePosition.X) {
+
+ _selectionRectangle.Width = x - _selectionRectangle.X;
+ }
+ // left to left - f
+ else if (x < _selectionRectangle.X) {
+
+ // hasn't flipped
+ if (_prevMousePosition.X > _selectionRectangle.X) {
+ _selectionRectangle.X = _initialMousePosition.X;
+ _selectionRectangle.Width = 0;
+ }
+ else {
+ _selectionRectangle.Width += _selectionRectangle.X - x;
+ _selectionRectangle.X = x;
+ }
+ }
+ // left to right - f
+ else if (x > _selectionRectangle.X && x < _selectionRectangle.Right &&
+ x > _prevMousePosition.X) {
+
+ if (_prevMousePosition.X < _selectionRectangle.X) {
+ _selectionRectangle.X = _initialMousePosition.X;
+ _selectionRectangle.Width = 0;
+ }
+ else {
+ _selectionRectangle.Width -= x - _selectionRectangle.X;
+ _selectionRectangle.X = x;
+ }
+ }
+
+
+ if (y > _selectionRectangle.Bottom) {
+ _selectionRectangle.Height = y - _selectionRectangle.Y;
+ }
+ else if (y > _selectionRectangle.Y && y < _selectionRectangle.Bottom &&
+ y < _prevMousePosition.Y) {
+
+ _selectionRectangle.Height = y - _selectionRectangle.Y;
+
+ }
+ else if (y < _selectionRectangle.Y) {
+ if (_prevMousePosition.Y > _selectionRectangle.Y) {
+ _selectionRectangle.Y = _initialMousePosition.Y;
+ _selectionRectangle.Height = 0;
+ }
+ else {
+ _selectionRectangle.Height += _selectionRectangle.Y - y;
+ _selectionRectangle.Y = y;
+ }
+ }
+ else if (y > _selectionRectangle.Y && y < _selectionRectangle.Bottom &&
+ y > _prevMousePosition.Y) {
+
+ if (_prevMousePosition.Y < _selectionRectangle.Y) {
+ _selectionRectangle.Y = _initialMousePosition.Y;
+ _selectionRectangle.Height = 0;
+ }
+ else {
+ _selectionRectangle.Height -= y - _selectionRectangle.Y;
+ _selectionRectangle.Y = y;
+ }
+ }
+
+ _prevMousePosition.X = x;
+ _prevMousePosition.Y = y;
+
+ _selectionContainer.Refresh ();
+ }
+ }
+
+ private void SelectionEnd (bool cancel)
+ {
+ // Console.WriteLine ("SelectionEnd");
+ _selecting = false;
+ ICollection selectedWidgets = GetWidgetsIn (_selectionRectangle);
+ // do not change selection if nothing has changed
+ //
+ if (selectedWidgets.Count != 0)
+ this.SelectionService.SetSelectedComponents (selectedWidgets, SelectionTypes.Replace);
+
+ _selectionContainer.Refresh ();
+ }
+#endregion
+
+
+#region Resizing
+ private SelectionFrame _selectionFrame;
+ private bool _resizing = false;
+
+ private void ResizeBegin (int x, int y)
+ {
+ // Console.WriteLine ("ResizeBegin");
+ _resizing = true;
+ _selectionFrame = this.GetSelectionFrameAt (x, y);
+ _selectionFrame.ResizeBegin (x, y);
+ }
+
+ private void ResizeContinue (int x, int y)
+ {
+ // Console.WriteLine ("ResizeContinue");
+ Rectangle deltaBounds = _selectionFrame.ResizeContinue (x, y);
+ ICollection selection = this.SelectionService.GetSelectedComponents ();
+
+ foreach (IComponent component in selection) {
+ if (component is Widget) {
+ SelectionFrame frame = GetSelectionFrameFor ((Widget)component);
+ if (frame != _selectionFrame)
+ frame.Resize (deltaBounds);
+ }
+ }
+
+ }
+
+ private void ResizeEnd (bool cancel)
+ {
+ // Console.WriteLine ("ResizeEnd");
+ _selectionFrame.ResizeEnd (cancel);
+ _resizing = false;
+ }
+
+
+ private SelectionFrame GetSelectionFrameAt (int x, int y)
+ {
+ SelectionFrame result = null;
+
+ foreach (SelectionFrame frame in _selectionFrames) {
+ if (frame.Bounds.Contains (new Point (x, y))) {
+ result = frame;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ private SelectionFrame GetSelectionFrameFor (Widget control)
+ {
+ foreach (SelectionFrame frame in _selectionFrames) {
+ if (control == frame.Widget)
+ return frame;
+ }
+ return null;
+ }
+#endregion
+
+ public bool AdornmentsHitTest (Widget control, int x, int y)
+ {
+ SelectionFrame frame = GetSelectionFrameAt (x, y);
+ if (frame != null)
+ return frame.HitTest (x, y);
+
+ return false;
+ }
+
+ // This method is called by all ParentWidgetDesigner.OnPaintAdornments.
+ // Selection frames are drawn in the parent container of the primary selection
+ // selection rectangle is drawn in the primary selection
+ //
+ public void PaintAdornments (Widget container, Graphics gfx)
+ {
+ IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
+
+ if (host == null || !(this.SelectionService.PrimarySelection is Widget))
+ return;
+
+ if ((Widget)this.SelectionService.PrimarySelection == container) {
+ if (_selecting) {
+ Color negativeColor = Color.FromArgb ((byte)~(_selectionContainer.BackColor.R),
+ (byte)~(_selectionContainer.BackColor.G),
+ (byte)~(_selectionContainer.BackColor.B));
+ DrawSelectionRectangle (gfx, _selectionRectangle, negativeColor);
+ }
+ }
+ else if (((Widget)this.SelectionService.PrimarySelection).Parent == container) {
+ foreach (SelectionFrame frame in _selectionFrames)
+ frame.OnPaint (gfx);
+ }
+ }
+
+
+ private void DrawSelectionRectangle (Graphics gfx, Rectangle frame, Color color)
+ {
+ Pen pen = new Pen (color);
+ pen.DashStyle = DashStyle.Dash;
+ gfx.DrawRectangle (pen, frame);
+ }
+
+
+ private void OnSelectionChanged (object sender, EventArgs args)
+ {
+ ICollection selection = this.SelectionService.GetSelectedComponents ();
+
+ if (_selectionFrames.Count == 0) {
+ foreach (Component component in selection) {
+ _selectionFrames.Add (new SelectionFrame ((Widget) component));
+ } // this code should get executed only once! (when initial primary selection is set)
+ } else {
+ int i = 0;
+ foreach (Component component in selection) {
+ if (i >= _selectionFrames.Count)
+ _selectionFrames.Add (new SelectionFrame ((Widget) component));
+ else
+ ((SelectionFrame)_selectionFrames[i]).Widget = (Widget) component;
+ i++;
+ }
+ if (i < _selectionFrames.Count)
+ _selectionFrames.RemoveRange (i, _selectionFrames.Count - i);
+ }
+ // Refresh the whole design surface (including the view)
+ //
+ IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
+ Widget root = host.RootComponent as Widget;
+ if (root != null) {
+ if (root.Parent != null)
+ root.Parent.Refresh ();
+ else
+ root.Refresh ();
+ }
+ }
+
+ private ICollection GetWidgetsIn (Rectangle rect)
+ {
+ ArrayList selectedWidgets = new ArrayList ();
+
+ foreach (Widget control in _selectionContainer.Widgets) {
+ if (rect.Contains (control.Bounds) || rect.IntersectsWith (control.Bounds))
+ selectedWidgets.Add (control);
+ }
+ return selectedWidgets;
+ }
+
+ }
+}