using System; using System.Collections.Generic; using System.Text; using System.ComponentModel.Design; using System.Collections; using System.Windows.Forms.Design.Behavior; using System.Windows.Forms; using System.Drawing; using System.ComponentModel; namespace DevComponents.DotNetBar.Layout.Design { public class LayoutItemBaseDesigner : ComponentDesigner { #region Constructor /// /// Initializes a new instance of the LayoutItemBaseDesigner class. /// public LayoutItemBaseDesigner() { } #endregion #region Implementation public override void Initialize(System.ComponentModel.IComponent component) { base.Initialize(component); ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService)); if (selectionService != null) selectionService.SelectionChanged += SelectionChanged; BehaviorService behaviorService = (BehaviorService)GetService(typeof(BehaviorService)); Adorner designerActionAdorner = new Adorner(); behaviorService.Adorners.Add(designerActionAdorner); LayoutItemGlyph glyph = new LayoutItemGlyph(behaviorService, (LayoutItemBase)component); designerActionAdorner.Glyphs.Add(glyph); } protected override void Dispose(bool disposing) { ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService)); if (selectionService != null) selectionService.SelectionChanged -= SelectionChanged; base.Dispose(disposing); } private void OnComponentRemoved(object sender, ComponentEventArgs e) { if (e.Component == this.Component) { LayoutItemBase item = e.Component as LayoutItemBase; LayoutGroup parent = item.Parent as LayoutGroup; LayoutControl lc = null; if (parent != null) lc = parent.GetLayoutControl(); if (item != null && parent != null && parent.Items.Contains(item)) { IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService)); if (cc != null) cc.OnComponentChanging(parent, TypeDescriptor.GetProperties(parent)["Items"]); parent.Items.Remove(item); if (cc != null) cc.OnComponentChanged(parent, TypeDescriptor.GetProperties(parent)["Items"], null, null); if (lc != null) { lc.Invalidate(); IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost)); if (host != null) { IDesigner designer = host.GetDesigner(lc); if (designer is LayoutControlDesigner) { ((LayoutControlDesigner)designer).SelectionRefresh(); } } } } } } private void SelectionChanged(object sender, EventArgs e) { bool selected = false; ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService)); if (selectionService.PrimarySelection == this.Component) selected = true; else { ICollection selectedComponents = selectionService.GetSelectedComponents(); foreach (object o in selectedComponents) { if (o == this.Component) { selected = true; break; } } } LayoutItemBase item = (LayoutItemBase)this.Component; item.IsSelected = selected; } public override System.Collections.ICollection AssociatedComponents { get { LayoutGroup group = this.Component as LayoutGroup; if (group == null) return base.AssociatedComponents; List items = new List(); group.Items.CopyTo(items); return items; } } protected override void PreFilterProperties(IDictionary properties) { base.PreFilterProperties(properties); properties["Visible"] = TypeDescriptor.CreateProperty(typeof(LayoutItemBaseDesigner), (PropertyDescriptor)properties["Visible"], new Attribute[] { new DefaultValueAttribute(true), new BrowsableAttribute(true), new CategoryAttribute("Appearance")}); } /// /// Gets or sets whether item is visible. /// [DefaultValue(true), Browsable(true), Category("Appearance"), Description("Indicates visiblity of the item.")] public bool Visible { get { return (bool)ShadowProperties["Visible"]; } set { // this value is not passed to the actual control this.ShadowProperties["Visible"] = value; } } #endregion } class LayoutItemGlyph : Glyph { LayoutItemBase _Item; BehaviorService _BehaviorSvc; public LayoutItemGlyph(BehaviorService behaviorSvc, LayoutItemBase item) : base(new LayoutItemBehavior()) { _BehaviorSvc = behaviorSvc; _Item = item; } public LayoutItemBase 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.GetLayoutControl() != null) { Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetLayoutControl()); if (_Item is LayoutControlItem) bounds = _Item.ActualTextBounds; else bounds = _Item.Bounds; bounds.Offset(edge); } return bounds; } } public Rectangle CompleteBounds { get { Rectangle bounds = Rectangle.Empty; if (_Item != null && _Item.GetLayoutControl() != null) { Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetLayoutControl()); bounds = _Item.Bounds; 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; } private bool GetIsItemVisible() { if (_Item == null) return false; LayoutControl lc = _Item.GetLayoutControl(); if (lc != null) { if (!lc.Visible) return false; if (lc.Parent != null && !lc.Parent.Visible) return false; if(lc.Parent is TabControlPanel && ((TabControlPanel)lc.Parent).TabItem!=null && !((TabControlPanel)lc.Parent).TabItem.IsSelected) return false; if (lc.Parent is SuperTabControlPanel && ((SuperTabControlPanel)lc.Parent).TabItem != null && !((SuperTabControlPanel)lc.Parent).TabItem.IsSelected) return false; } return true; } 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 (Pen pen = new Pen(SelectionColor)) { pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; g.DrawRectangle(pen, r); } } else if ((!_Item.TextVisible || string.IsNullOrEmpty(_Item.Text)) && GetIsItemVisible()) { Rectangle r = CompleteBounds; r.Width--; r.Height--; Graphics g = pe.Graphics; using (Pen pen = new Pen(SelectableColor)) { pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; g.DrawRectangle(pen, r); } } } } private static readonly Color SelectableColor = ColorHelpers.GetColor(0x8C8C91); private static readonly Color SelectionColor = ColorHelpers.GetColor(0x696969); // By providing our own behavior we can do something interesting // when the user clicks or manipulates our glyph. class LayoutItemBehavior : Behavior { //public override bool OnMouseUp(Glyph g, MouseButtons button) //{ // //MessageBox.Show("Hey, you clicked the mouse here"); // //return true; // indicating we processed this event. // return base.OnMouseUp(g, button); //} private Point _MouseDownLocation = Point.Empty; public override bool OnMouseDown(Glyph g, MouseButtons button, Point mouseLoc) { LayoutItemGlyph itemGlyph = (LayoutItemGlyph)g; if (itemGlyph._Item != null && itemGlyph._Item.Site != null && (!itemGlyph._Item.IsSelected || itemGlyph._Item is LayoutGroup)) { LayoutItemBase item = itemGlyph._Item; IComponent selectItem = item; if (item is LayoutGroup) { LayoutControl lc = item.GetLayoutControl(); if (lc == null) return base.OnMouseDown(g, button, mouseLoc); Point loc = lc.PointToClient(Control.MousePosition); LayoutItemBase itemAt = lc.HitTest(loc); if (itemAt != null && itemAt != item && itemAt.Site != null) { // Selection is selecting something inside of group selectItem = itemAt; if (itemAt is LayoutControlItem) { LayoutControlItem lci = (LayoutControlItem)itemAt; if (lci.Control != null && lci.Control.ClientRectangle.Contains(lci.Control.PointToClient(Control.MousePosition)) && lci.Control.Site != null) selectItem = lci.Control; } } // No need to re-select if (selectItem == itemGlyph._Item && itemGlyph.Item.IsSelected) return base.OnMouseDown(g, button, mouseLoc); } ISelectionService selectionService = (ISelectionService)selectItem.Site.GetService(typeof(ISelectionService)); if (selectionService != null && selectItem != null) { selectionService.SetSelectedComponents(new IComponent[] { selectItem }); return true; } } return base.OnMouseDown(g, button, mouseLoc); } public override bool OnMouseUp(Glyph g, MouseButtons button) { _MouseDownLocation = Point.Empty; return base.OnMouseUp(g, button); } public override bool OnMouseMove(Glyph g, MouseButtons button, Point mouseLoc) { if (button == MouseButtons.Left && _MouseDownLocation.IsEmpty) _MouseDownLocation = mouseLoc; if (button == MouseButtons.Left && !_MouseDownLocation.IsEmpty && (Math.Abs(mouseLoc.X - _MouseDownLocation.X) > 1 || Math.Abs(mouseLoc.Y - _MouseDownLocation.Y) > 1)) { LayoutItemGlyph glyph = g as LayoutItemGlyph; if (glyph != null && glyph.Item != null) { ISelectionService selectionService = GetSelectionService(glyph.Item); if (selectionService != null && selectionService.PrimarySelection == glyph.Item && selectionService.GetSelectedComponents().Count == 1) { _MouseDownLocation = Point.Empty; this.DropSource.QueryContinueDrag += new QueryContinueDragEventHandler(this.QueryContinueDrag); this.DropSource.DoDragDrop(new LayoutItemDataObject(glyph.Item), DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Scroll); } } } return false;// base.OnMouseMove(g, button, mouseLoc); } public override void OnDragDrop(Glyph g, DragEventArgs e) { if (e.Data is LayoutItemDataObject) { LayoutItemDataObject d = (LayoutItemDataObject)e.Data; LayoutControl lc = d.DragComponent.GetLayoutControl(); if (lc != null) { lc.HideInsertMarker(); LayoutItemBase item = d.DragComponent; ISelectionService selectionService = GetSelectionService(item); IDesignerHost host = GetDesignerHostService(item); IComponentChangeService cc = GetComponentChangeService(item); if (selectionService != null && host != null && cc != null) { HitTestInsertInfo info = lc.GetHitTestInsertInfo(item, lc.PointToClient(new Point(e.X, e.Y))); if (info.Parent != null) { DesignerTransaction dt = host.CreateTransaction("Moving Layout Control Item"); cc.OnComponentChanging(lc, TypeDescriptor.GetProperties(lc)["RootGroup"]); //lc.Text = string.Format("Moving at B: {0}", info.InsertIndex); //lc.Invalidate(); if (info.Parent != item.Parent) { LayoutGroup group = (LayoutGroup)item.Parent; if (group != lc.RootGroup) cc.OnComponentChanging(group, TypeDescriptor.GetProperties(lc)["Items"]); group.Items.Remove(item); if (group != lc.RootGroup) cc.OnComponentChanged(group, TypeDescriptor.GetProperties(lc)["Items"], null, null); if (info.Parent != lc.RootGroup) cc.OnComponentChanging(info.Parent, TypeDescriptor.GetProperties(lc)["Items"]); if (info.InsertIndex >= 0) info.Parent.Items.Insert(info.InsertIndex, item); else info.Parent.Items.Add(item); if (info.Parent != lc.RootGroup) cc.OnComponentChanged(info.Parent, TypeDescriptor.GetProperties(lc)["Items"], null, null); } else { if (info.Parent != lc.RootGroup) cc.OnComponentChanging(info.Parent, TypeDescriptor.GetProperties(lc)["Items"]); info.Parent.Items.Move(item, info.InsertIndex); if (info.Parent != lc.RootGroup) cc.OnComponentChanged(info.Parent, TypeDescriptor.GetProperties(lc)["Items"], null, null); } cc.OnComponentChanged(lc, TypeDescriptor.GetProperties(lc)["RootGroup"], null, null); dt.Commit(); lc.PerformLayout(); lc.Invalidate(true); IDesigner designer = host.GetDesigner(lc); if (designer is LayoutControlDesigner) ((LayoutControlDesigner)designer).SelectionRefresh(); } } } } base.OnDragDrop(g, e); } public override void OnDragLeave(Glyph g, EventArgs e) { LayoutItemGlyph glyph = g as LayoutItemGlyph; if (glyph != null && glyph.Item != null) { LayoutControl lc = glyph.Item.GetLayoutControl(); if (lc != null) lc.HideInsertMarker(); } base.OnDragLeave(g, e); } public override void OnDragOver(Glyph g, DragEventArgs e) { if (e.Data is LayoutItemDataObject) { e.Effect = DragDropEffects.Move; LayoutItemDataObject d = (LayoutItemDataObject)e.Data; LayoutControl lc = d.DragComponent.GetLayoutControl(); if (lc != null) { HitTestInsertInfo info = lc.GetHitTestInsertInfo(d.DragComponent, lc.PointToClient(new Point(e.X, e.Y))); if (!info.InsertMarkerBounds.IsEmpty) lc.ShowInsertMarker(info.InsertMarkerBounds); else lc.HideInsertMarker(); e.Effect = DragDropEffects.Move; return; } } e.Effect = DragDropEffects.None; return; base.OnDragOver(g, e); } public override void OnDragEnter(Glyph g, DragEventArgs e) { if (e.Data is LayoutItemDataObject) { e.Effect = DragDropEffects.Move; } else e.Effect = DragDropEffects.None; return; base.OnDragEnter(g, e); } private void QueryContinueDrag(object sender, QueryContinueDragEventArgs e) { if ((e.Action != DragAction.Continue) && e.EscapePressed) { e.Action = DragAction.Cancel; //ToolStripItem glyphItem = sender as ToolStripItem; //this.SetParentDesignerValuesForDragDrop(glyphItem, false, Point.Empty); //ISelectionService selectionService = this.GetSelectionService(glyphItem); //if (selectionService != null) //{ // selectionService.SetSelectedComponents(new IComponent[] { glyphItem }, SelectionTypes.Auto); //} //ToolStripDesigner.dragItem = null; } } private ISelectionService GetSelectionService(LayoutItemBase item) { if (item.Site != null) { return (ISelectionService)item.Site.GetService(typeof(ISelectionService)); } return null; } private IDesignerHost GetDesignerHostService(LayoutItemBase item) { if (item.Site != null) { return (IDesignerHost)item.Site.GetService(typeof(IDesignerHost)); } return null; } private IComponentChangeService GetComponentChangeService(LayoutItemBase item) { if (item.Site != null) { return (IComponentChangeService)item.Site.GetService(typeof(IComponentChangeService)); } return null; } private Control _DropSource = null; private Control DropSource { get { if (_DropSource == null) { _DropSource = new Control(); } return _DropSource; } } } } #region LayoutItemDataObject internal class LayoutItemDataObject : DataObject { private LayoutItemBase _DragComponent; // Methods internal LayoutItemDataObject(LayoutItemBase dragComponents) { _DragComponent = dragComponents; } // Properties internal LayoutItemBase DragComponent { get { return _DragComponent; } } } #endregion }