469 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			469 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections;
 | |
| using System.Collections.Generic;
 | |
| using System.ComponentModel;
 | |
| using System.ComponentModel.Design;
 | |
| using System.Drawing;
 | |
| using System.Reflection;
 | |
| using System.Text;
 | |
| using System.Windows.Forms;
 | |
| using System.Windows.Forms.Design;
 | |
| using System.Windows.Forms.Design.Behavior;
 | |
| 
 | |
| namespace DevComponents.DotNetBar.Design
 | |
| {
 | |
|     public class ComponentDesignerWithAction : ComponentDesigner
 | |
| 
 | |
|     {
 | |
|         private Adorner _DesignerActionAdorner = null;
 | |
| 
 | |
|         public override void Initialize(System.ComponentModel.IComponent component)
 | |
|         {
 | |
|             base.Initialize(component);
 | |
| 
 | |
|             if (DesignerActionUIEnabled)
 | |
|             {
 | |
|                 ISelectionService selectionService = (ISelectionService) GetService(typeof(ISelectionService));
 | |
|                 if (selectionService != null)
 | |
|                     selectionService.SelectionChanged += SelectionChanged;
 | |
| 
 | |
|                 _DesignerActionAdorner = new Adorner();
 | |
| 
 | |
|                 // If our component is removed we need to clean-up
 | |
|                 IComponentChangeService cc = (IComponentChangeService) GetService(typeof(IComponentChangeService));
 | |
|                 if (cc != null)
 | |
|                 {
 | |
|                     cc.ComponentRemoving += ComponentRemoving;
 | |
|                     cc.ComponentRemoved += ComponentRemoved;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void ComponentRemoved(object sender, ComponentEventArgs e)
 | |
|         {
 | |
|             if (e.Component is BaseItem)
 | |
|             {
 | |
|                 BaseItem parent = this.Component as BaseItem;
 | |
|                 BaseItem item = e.Component as BaseItem;
 | |
|                 if (item != null && parent != null && parent.SubItems.Contains(item))
 | |
|                 {
 | |
|                     IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService));
 | |
|                     if (cc != null)
 | |
|                         cc.OnComponentChanging(parent, TypeDescriptor.GetProperties(parent)["SubItems"]);
 | |
|                     parent.SubItems.Remove(item);
 | |
|                     if (cc != null)
 | |
|                         cc.OnComponentChanged(parent, TypeDescriptor.GetProperties(parent)["SubItems"], null, null);
 | |
|                     this.RecalcLayout();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public virtual void RecalcLayout()
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         private void ComponentRemoving(object sender, ComponentEventArgs e)
 | |
|         {
 | |
|             if(e.Component == this.Component)
 | |
|                 RemoveGlyph();
 | |
|         }
 | |
| 
 | |
|         protected override void Dispose(bool disposing)
 | |
|         {
 | |
|             if (DesignerActionUIEnabled)
 | |
|             {
 | |
|                 ISelectionService selectionService = (ISelectionService) GetService(typeof(ISelectionService));
 | |
|                 if (selectionService != null)
 | |
|                     selectionService.SelectionChanged -= SelectionChanged;
 | |
| 
 | |
|                 IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService));
 | |
|                 if (cc != null)
 | |
|                 {
 | |
|                     cc.ComponentRemoving -= ComponentRemoving;
 | |
|                     cc.ComponentRemoved -= ComponentRemoved;
 | |
|                 }
 | |
|             }
 | |
|             base.Dispose(disposing);
 | |
|         }
 | |
| 
 | |
|         public bool IsSelected = false;
 | |
| 
 | |
|         private void SelectionChanged(object sender, EventArgs e)
 | |
|         {
 | |
|             bool selected = false;
 | |
|             ISelectionService selectionService = (ISelectionService) GetService(typeof(ISelectionService));
 | |
|             if (selectionService == null) return;
 | |
| 
 | |
|             if (selectionService.PrimarySelection == this.Component)
 | |
|                 selected = true;
 | |
|             else
 | |
|             {
 | |
|                 ICollection selectedComponents = selectionService.GetSelectedComponents();
 | |
|                 foreach (object o in selectedComponents)
 | |
|                 {
 | |
|                     if (o.Equals(this.Component))
 | |
|                     {
 | |
|                         selected = true;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             OnDesignerSelectionChanged(selected);
 | |
| 
 | |
|             if (selected)
 | |
|             {
 | |
|                 Control hostControl = GetContainerControl();
 | |
|                 if (hostControl != null)
 | |
|                 {
 | |
|                     Rectangle itemScreenBounds = hostControl.RectangleToScreen(ComponentBounds);
 | |
|                     _DesignerGlyph = CreateDesignerGlyphWrapper((Component) this.Component, GetParentControl(),
 | |
|                         itemScreenBounds,
 | |
|                         this.ActionLists);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 RemoveGlyph();
 | |
|             }
 | |
|             IsSelected = selected;
 | |
|         }
 | |
| 
 | |
|         protected virtual Rectangle ComponentBounds
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 BaseItem item = this.Component as BaseItem;
 | |
|                 if (item != null)
 | |
|                     return item.Bounds;
 | |
|                 return Rectangle.Empty;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public virtual Control GetHostControl()
 | |
|         {
 | |
|             return GetParentControl();
 | |
|         }
 | |
| 
 | |
|         protected virtual Control GetParentControl()
 | |
|         {
 | |
|             return GetContainerControl();
 | |
|         }
 | |
| 
 | |
|         protected virtual Control GetContainerControl()
 | |
|         {
 | |
|             BaseItem item = this.Component as BaseItem;
 | |
|             if (item != null)
 | |
|                 return (Control) item.ContainerControl;
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         protected virtual void OnDesignerSelectionChanged(bool isSelected)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         protected virtual bool DesignerActionUIEnabled
 | |
|         {
 | |
|             get { return true; }
 | |
|         }
 | |
| 
 | |
|         private Glyph _DesignerGlyph = null;
 | |
| 
 | |
|         private void RemoveGlyph()
 | |
|         {
 | |
|             BehaviorService svc = (BehaviorService) this.GetService(typeof(BehaviorService));
 | |
|             if (svc == null) return;
 | |
|             _DesignerActionAdorner.Glyphs.Clear();
 | |
|             if (svc.Adorners.Contains(_DesignerActionAdorner))
 | |
|                 svc.Adorners.Remove(_DesignerActionAdorner);
 | |
|             if (_ActionListToolStrip != null)
 | |
|                 _ActionListToolStrip.LocationChanged -= HostLocationChanged;
 | |
|             _ActionListToolStrip = null;
 | |
|             InvalidateDesignerSurface();
 | |
|         }
 | |
| 
 | |
|         private void InvalidateDesignerSurface()
 | |
|         {
 | |
|             BehaviorService behaviorService = (BehaviorService) GetService(typeof(BehaviorService));
 | |
|             if (behaviorService == null) return;
 | |
|             object actionUi = GetActionUI(behaviorService);
 | |
|             if (actionUi == null) return;
 | |
|             object mainParentWindow = ReflectionHelpers.GetValueField(actionUi, "mainParentWindow",
 | |
|                 BindingFlags.Instance | BindingFlags.NonPublic);
 | |
|             if (mainParentWindow is IWin32Window)
 | |
|             {
 | |
|                 WinApi.RedrawWindow(((IWin32Window) mainParentWindow).Handle, IntPtr.Zero, IntPtr.Zero,
 | |
|                     (uint) (WinApi.RedrawWindowFlags.RDW_INVALIDATE | WinApi.RedrawWindowFlags.RDW_ALLCHILDREN));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private ToolStripDropDown _ActionListToolStrip = null;
 | |
| 
 | |
|         private Glyph CreateDesignerGlyphWrapper(Component targetComponent, Control ownerControl,
 | |
|             Rectangle screenBounds, DesignerActionListCollection actionLists)
 | |
|         {
 | |
|             BehaviorService behaviorService = (BehaviorService) GetService(typeof(BehaviorService));
 | |
| 
 | |
|             if (targetComponent != null && behaviorService != null && actionLists != null)
 | |
|             {
 | |
|                 try
 | |
|                 {
 | |
|                     object actionUi = GetActionUI(behaviorService);
 | |
|                     FieldInfo fieldInfo1 = ReflectionHelpers.GetFieldInfo(actionUi, "designerActionHost",
 | |
|                         BindingFlags.Instance | BindingFlags.NonPublic);
 | |
|                     ToolStripDropDown designerActionHost = null;
 | |
|                     object mainParentWindow = ReflectionHelpers.GetValueField(actionUi, "mainParentWindow",
 | |
|                         BindingFlags.Instance | BindingFlags.NonPublic);
 | |
|                     if (!(fieldInfo1.GetValue(actionUi) is ToolStripDropDown))
 | |
|                     {
 | |
|                         ConstructorInfo constructorInfo = ReflectionHelpers.GetConstructorInfo(fieldInfo1.FieldType,
 | |
|                             new Type[2]
 | |
|                             {
 | |
|                                 actionUi.GetType(),
 | |
|                                 typeof(IWin32Window)
 | |
|                             });
 | |
|                         designerActionHost = constructorInfo.Invoke(new object[2]
 | |
|                         {
 | |
|                             actionUi,
 | |
|                             mainParentWindow
 | |
|                         }) as ToolStripDropDown;
 | |
|                         designerActionHost.AutoSize = false;
 | |
|                         designerActionHost.Padding = System.Windows.Forms.Padding.Empty;
 | |
|                         designerActionHost.Renderer = (ToolStripRenderer) new NoBorderRenderer();
 | |
|                         designerActionHost.Text = "DesignerActionTopLevelForm";
 | |
|                         fieldInfo1.SetValue(actionUi, (object) designerActionHost);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         designerActionHost = fieldInfo1.GetValue(actionUi) as ToolStripDropDown;
 | |
|                     }
 | |
|                     Glyph glyph = ReflectionHelpers.InvokeMethod(actionUi, "GetDesignerActionGlyph",
 | |
|                         BindingFlags.Instance | BindingFlags.NonPublic, new object[2]
 | |
|                         {
 | |
|                             (object) targetComponent,
 | |
|                             (object) actionLists
 | |
|                         }) as Glyph;
 | |
|                     if (glyph != null)
 | |
|                     {
 | |
|                         BarUtilities.InvokeDelayed(new MethodInvoker(delegate { SetGlyphBounds(glyph, screenBounds, behaviorService); }), 100);
 | |
|                         if (designerActionHost != null)
 | |
|                         {
 | |
|                             designerActionHost.LocationChanged += HostLocationChanged;
 | |
|                             Point p = new Point(glyph.Bounds.Right, glyph.Bounds.Y);
 | |
|                             designerActionHost.Bounds =
 | |
|                                 new Rectangle(behaviorService.AdornerWindowPointToScreen(p), designerActionHost.Size);
 | |
|                         }
 | |
|                         FieldInfo fieldInfo2 = ReflectionHelpers.GetFieldInfo((object) glyph.Behavior,
 | |
|                             "serviceProvider", BindingFlags.Instance | BindingFlags.NonPublic);
 | |
|                         GlyphServiceProvider glyphServiceProvider =
 | |
|                             new GlyphServiceProvider((IServiceProvider) fieldInfo2.GetValue((object) glyph.Behavior));
 | |
|                         fieldInfo2.SetValue((object) glyph.Behavior, (object) glyphServiceProvider);
 | |
|                         //SmartTagInfoCache.Default.Add(info.TargetComponent, new SmartTagCacheElement(glyph, info.TargetComponent, (Control)null, actionUi, info.BehaviorService));
 | |
|                         behaviorService.Adorners.Add(_DesignerActionAdorner);
 | |
|                         _DesignerActionAdorner.Glyphs.Add(glyph);
 | |
|                         //TestGlyph testGlyph = new TestGlyph(behaviorService, this);
 | |
|                         //_DesignerActionAdorner.Glyphs.Add(testGlyph);
 | |
|                         if (mainParentWindow is Control) ((Control) mainParentWindow).Invalidate();
 | |
|                     }
 | |
|                     if (mainParentWindow is IWin32Window)
 | |
|                     {
 | |
|                         WinApi.RedrawWindow(((IWin32Window) mainParentWindow).Handle, IntPtr.Zero, IntPtr.Zero,
 | |
|                             (uint) (WinApi.RedrawWindowFlags.RDW_INVALIDATE |
 | |
|                                     WinApi.RedrawWindowFlags.RDW_ALLCHILDREN));
 | |
|                     }
 | |
|                     if (_ActionListToolStrip != designerActionHost)
 | |
|                     {
 | |
|                         if (_ActionListToolStrip != null)
 | |
|                             _ActionListToolStrip.LocationChanged -= HostLocationChanged;
 | |
|                         _ActionListToolStrip = designerActionHost;
 | |
|                     }
 | |
|                     return glyph;
 | |
|                 }
 | |
|                 catch
 | |
|                 {
 | |
|                     return (Glyph) null;
 | |
|                 }
 | |
|             }
 | |
|             return (Glyph) null;
 | |
|         }
 | |
| 
 | |
|         private bool _SettingBounds = false;
 | |
| 
 | |
|         private void HostLocationChanged(object sender, EventArgs e)
 | |
|         {
 | |
|             if (_SettingBounds) return;
 | |
| 
 | |
|             ToolStripDropDown toolStripDropDown = sender as ToolStripDropDown;
 | |
|             BehaviorService svc = (BehaviorService) this.GetService(typeof(BehaviorService));
 | |
|             if (toolStripDropDown == null || _DesignerGlyph == null || svc == null)
 | |
|                 return;
 | |
|             _SettingBounds = true;
 | |
|             Point p = new Point(_DesignerGlyph.Bounds.Right, _DesignerGlyph.Bounds.Y);
 | |
|             Rectangle r = new Rectangle(svc.AdornerWindowPointToScreen(p), toolStripDropDown.Size);
 | |
|             toolStripDropDown.Bounds = r;
 | |
|             _SettingBounds = false;
 | |
|         }
 | |
| 
 | |
|         private void SetGlyphBounds(Glyph gl, Rectangle itemBounds, BehaviorService behaviorService)
 | |
|         {
 | |
|             Size glyphSize = GetGlyphSize();
 | |
|             Point adornerWindow = behaviorService.ScreenToAdornerWindow(new Point(itemBounds.Right - 6, itemBounds.Y));
 | |
|             Point p = behaviorService.ScreenToAdornerWindow(Point.Empty);
 | |
|             ReflectionHelpers.SetValueField((object) gl, "bounds",
 | |
|                 BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField,
 | |
|                 (object) new Rectangle(adornerWindow, glyphSize));
 | |
|             InvalidateDesignerSurface();
 | |
|         }
 | |
| 
 | |
|         private class NoBorderRenderer : ToolStripProfessionalRenderer
 | |
|         {
 | |
|             public NoBorderRenderer()
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
 | |
|             {
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private object GetActionUI(BehaviorService behaviorService)
 | |
|         {
 | |
|             if (behaviorService == null)
 | |
|                 return null;
 | |
|             return ReflectionHelpers.GetValueProperty((object) behaviorService, "DesignerActionUI",
 | |
|                 BindingFlags.Instance | BindingFlags.NonPublic);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         private Rectangle GetGlyphBounds(Rectangle componentBounds)
 | |
|         {
 | |
|             Size glyphSize = GetGlyphSize();
 | |
|             return new Rectangle(componentBounds.Right - glyphSize.Width, componentBounds.Y, glyphSize.Width,
 | |
|                 glyphSize.Height);
 | |
|         }
 | |
| 
 | |
|         private Size GetGlyphSize()
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 Type type = typeof(ControlDesigner).Assembly.GetType("System.Windows.Forms.DpiHelper");
 | |
|                 if (type != (Type) null)
 | |
|                 {
 | |
|                     if ((bool) type.GetProperty("IsScalingRequired", BindingFlags.Static | BindingFlags.Public)
 | |
|                         .GetValue((object) null, (object[]) null))
 | |
|                     {
 | |
|                         object[] parameters = new object[2]
 | |
|                         {
 | |
|                             (object) new Bitmap(10, 10),
 | |
|                             (object) 0
 | |
|                         };
 | |
|                         type.GetMethod("ScaleBitmapLogicalToDevice", BindingFlags.Static | BindingFlags.Public)
 | |
|                             .Invoke((object) null, parameters);
 | |
|                         return ((Image) parameters[0]).Size;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception e)
 | |
|             {
 | |
|                 Console.WriteLine(e);
 | |
|             }
 | |
|             return new Size(10, 10);
 | |
|         }
 | |
| 
 | |
|         class TestBehavior : Behavior
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         class TestGlyph : Glyph
 | |
|         {
 | |
|             ComponentDesignerWithAction _Item;
 | |
|             BehaviorService _BehaviorSvc;
 | |
| 
 | |
|             public TestGlyph(BehaviorService behaviorSvc, ComponentDesignerWithAction item)
 | |
|                 :
 | |
|                 base(new TestBehavior())
 | |
|             {
 | |
|                 _BehaviorSvc = behaviorSvc;
 | |
|                 _Item = item;
 | |
|             }
 | |
| 
 | |
|             public ComponentDesignerWithAction Item
 | |
|             {
 | |
|                 get { return _Item; }
 | |
|             }
 | |
| 
 | |
|             public override Rectangle Bounds
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     // Glyph coordinates are in adorner window coordinates, so we must map using the behavior service.
 | |
|                     Rectangle bounds = Rectangle.Empty;
 | |
|                     if (_Item != null && _Item.GetHostControl() != null)
 | |
|                     {
 | |
|                         Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetHostControl());
 | |
| 
 | |
|                         bounds = _Item.ComponentBounds;
 | |
|                         bounds.Offset(edge);
 | |
|                     }
 | |
| 
 | |
|                     return bounds;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
| 
 | |
|             public override Cursor GetHitTest(Point p)
 | |
|             {
 | |
|                 if (_Item != null && !_Item.IsSelected)
 | |
|                     return null;
 | |
|                 // GetHitTest is called to see if the point is 
 | |
|                 // within this glyph.  This gives us a chance to decide 
 | |
|                 // what cursor to show.  Returning null from here means 
 | |
|                 // the mouse pointer is not currently inside of the glyph. 
 | |
|                 // Returning a valid cursor here indicates the pointer is 
 | |
|                 // inside the glyph, and also enables our Behavior property 
 | |
|                 // as the active behavior. 
 | |
|                 if (Bounds.Contains(p))
 | |
|                 {
 | |
|                     return Cursors.SizeAll;
 | |
|                 }
 | |
| 
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             public Rectangle CompleteBounds
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     Rectangle bounds = Rectangle.Empty;
 | |
|                     if (_Item != null && _Item.GetHostControl() != null)
 | |
|                     {
 | |
|                         Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetContainerControl());
 | |
|                         bounds = _Item.ComponentBounds;
 | |
|                         bounds.Offset(edge);
 | |
|                     }
 | |
|                     return bounds;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public override void Paint(PaintEventArgs pe)
 | |
|             {
 | |
|                 // Draw our glyph
 | |
|                 if (_Item != null)
 | |
|                 {
 | |
|                     if (_Item.IsSelected)
 | |
|                     {
 | |
|                         Rectangle r = CompleteBounds;
 | |
|                         r.Width--;
 | |
|                         r.Height--;
 | |
|                         Graphics g = pe.Graphics;
 | |
|                         using(SolidBrush brush=new SolidBrush(Color.FromArgb(129,Color.Red)))
 | |
|                         {
 | |
|                             g.FillRectangle(brush, r);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |