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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|