Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / WinForms / System / WinForms / Design / ComponentTray.cs / 1 / ComponentTray.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms.Design {
using System.Runtime.Serialization.Formatters;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Diagnostics;
using System;
using System.Collections;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using Microsoft.Win32;
using System.Drawing;
using System.Design;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.ComponentModel;
using System.Windows.Forms.Design.Behavior;
using System.Diagnostics.CodeAnalysis;
///
///
///
/// Provides the component tray UI for the form designer.
///
[
ToolboxItem(false),
DesignTimeVisible(false),
ProvideProperty("Location", typeof(IComponent)),
ProvideProperty("TrayLocation", typeof(IComponent)), // VSWhidbey# 420631
]
public class ComponentTray : ScrollableControl, IExtenderProvider, ISelectionUIHandler, IOleDragClient {
///
///
///
///
private static readonly Point InvalidPoint = new Point(int.MinValue, int.MinValue);
private IServiceProvider serviceProvider; // Where services come from.
private Point whiteSpace = Point.Empty; // space to leave between components.
private Size grabHandle = Size.Empty; // Size of the grab handles.
private ArrayList controls; // List of items in the tray in the order of their layout.
private SelectionUIHandler dragHandler; // the thing responsible for handling mouse drags
private ISelectionUIService selectionUISvc; // selectiuon UI; we use this a lot
private IToolboxService toolboxService; // cached for drag/drop
///
///
/// Provides drag and drop functionality through OLE.
///
internal OleDragDropHandler oleDragDropHandler; // handler class for ole drag drop operations.
private IDesigner mainDesigner; // the designer that is associated with this tray
private IEventHandlerService eventHandlerService = null; // Event Handler service to handle keyboard and focus.
private bool queriedTabOrder;
private MenuCommand tabOrderCommand;
private ICollection selectedObjects;
// Services that we use on a high enough frequency to merit caching.
//
private IMenuCommandService menuCommandService;
private CommandSet privateCommandSet=null;
private InheritanceUI inheritanceUI;
private Point mouseDragStart = InvalidPoint; // the starting location of a drag
private Point mouseDragEnd = InvalidPoint; // the ending location of a drag
private Rectangle mouseDragWorkspace = Rectangle.Empty; // a temp work rectangle we cache for perf
private ToolboxItem mouseDragTool; // the tool that's being dragged; only for drag/drop
private Point mouseDropLocation = InvalidPoint; // where the tool was dropped
private bool showLargeIcons = false;// Show Large icons or not.
private bool autoArrange = false; // allows for auto arranging icons.
private Point autoScrollPosBeforeDragging = Point.Empty;//Used to return the correct scroll pos. after a drag
// Component Tray Context menu items...
///
///
/// [To be supplied.]
///
private MenuCommand menucmdArrangeIcons = null;
///
///
/// [To be supplied.]
///
private MenuCommand menucmdLineupIcons = null;
///
///
/// [To be supplied.]
///
private MenuCommand menucmdLargeIcons = null;
private bool fResetAmbient = false;
private ComponentTrayGlyphManager glyphManager;//used to manage any glyphs added to the tray
///
///
/// Creates a new component tray. The component tray
/// will monitor component additions and removals and create
/// appropriate UI objects in its space.
///
[SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
public ComponentTray(IDesigner mainDesigner, IServiceProvider serviceProvider) {
this.AutoScroll = true;
this.mainDesigner = mainDesigner;
this.serviceProvider = serviceProvider;
this.AllowDrop = true;
Text = "ComponentTray"; // makes debugging easier
SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
controls = new ArrayList();
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
IExtenderProviderService es = (IExtenderProviderService)GetService(typeof(IExtenderProviderService));
Debug.Assert(es != null, "Component tray wants an extender provider service, but there isn't one.");
if (es != null) {
es.AddExtenderProvider(this);
}
if (GetService(typeof(IEventHandlerService)) == null) {
if (host != null) {
eventHandlerService = new EventHandlerService(this);
host.AddService(typeof(IEventHandlerService), eventHandlerService);
}
}
IMenuCommandService mcs = MenuService;
if (mcs != null) {
Debug.Assert(menucmdArrangeIcons == null, "Non-Null Menu Command for ArrangeIcons");
Debug.Assert(menucmdLineupIcons == null, "Non-Null Menu Command for LineupIcons");
Debug.Assert(menucmdLargeIcons == null, "Non-Null Menu Command for LargeIcons");
menucmdArrangeIcons = new MenuCommand(new EventHandler(OnMenuArrangeIcons), StandardCommands.ArrangeIcons);
menucmdLineupIcons = new MenuCommand(new EventHandler(OnMenuLineupIcons), StandardCommands.LineupIcons);
menucmdLargeIcons = new MenuCommand(new EventHandler(OnMenuShowLargeIcons), StandardCommands.ShowLargeIcons);
menucmdArrangeIcons.Checked = AutoArrange;
menucmdLargeIcons.Checked = ShowLargeIcons;
mcs.AddCommand(menucmdArrangeIcons);
mcs.AddCommand(menucmdLineupIcons);
mcs.AddCommand(menucmdLargeIcons);
}
IComponentChangeService componentChangeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (componentChangeService != null) {
componentChangeService.ComponentRemoved += new ComponentEventHandler(this.OnComponentRemoved);
}
IUIService uiService = (IUIService)GetService(typeof(IUIService));
if (uiService != null) {
Color styleColor;
//Can't use 'as' here since Color is a value type
if (uiService.Styles["VsColorDesignerTray"] is Color) {
styleColor = (Color) uiService.Styles["VsColorDesignerTray"];
}
else if (uiService.Styles["HighlightColor"] is Color) {
// Since v1, we have had code here that checks for HighlightColor, so some hosts (like WinRes)
// have been setting it. If VsColorDesignerTray isn't present, we look for HighlightColor
// for backward compat.
styleColor = (Color) uiService.Styles["HighlightColor"];
}
else {
//No style color provided? Let's pick a default.
styleColor = SystemColors.Info;
}
BackColor = styleColor;
Font = (Font)uiService.Styles["DialogFont"];
}
ISelectionService selSvc = (ISelectionService)GetService(typeof(ISelectionService));
if (selSvc != null) {
selSvc.SelectionChanged += new EventHandler(OnSelectionChanged);
}
// Listen to the SystemEvents so that we can resync selection based on display settings etc.
SystemEvents.DisplaySettingsChanged += new EventHandler(this.OnSystemSettingChanged);
SystemEvents.InstalledFontsChanged += new EventHandler(this.OnSystemSettingChanged);
SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.OnUserPreferenceChanged);
// Listen to refresh events from TypeDescriptor. If a component gets refreshed, we re-query
// and will hide/show the view based on the DesignerView attribute.
//
TypeDescriptor.Refreshed += new RefreshEventHandler(OnComponentRefresh);
BehaviorService behSvc = GetService(typeof(BehaviorService)) as BehaviorService;
if(behSvc != null) {
//this object will manage any glyphs that get added to our tray
glyphManager = new ComponentTrayGlyphManager(selSvc, behSvc);
}
}
///
///
/// [To be supplied.]
///
public bool AutoArrange {
get {
return autoArrange;
}
set {
if (autoArrange != value) {
autoArrange = value;
menucmdArrangeIcons.Checked = value;
if (autoArrange) {
DoAutoArrange(true);
}
}
}
}
///
///
///
/// Gets the number of compnents contained within this tray.
///
///
public int ComponentCount {
get {
return Controls.Count;
}
}
internal virtual SelectionUIHandler DragHandler {
get {
if (dragHandler == null) {
dragHandler = new TraySelectionUIHandler(this);
}
return dragHandler;
}
}
///
///
/// Internally exposes a way for sited components to add
/// glyphs to the component tray.
///
internal GlyphCollection SelectionGlyphs {
get {
if(glyphManager != null) {
return glyphManager.SelectionGlyphs;
} else {
return null;
}
}
}
private InheritanceUI InheritanceUI {
get {
if (inheritanceUI == null) {
inheritanceUI = new InheritanceUI();
}
return inheritanceUI;
}
}
///
///
/// Retrieves the menu editor service, which we cache for speed.
///
private IMenuCommandService MenuService {
get {
if (menuCommandService == null) {
menuCommandService = (IMenuCommandService)GetService(typeof(IMenuCommandService));
}
return menuCommandService;
}
}
///
///
/// Determines whether the tray will show large icon view or not.
///
public bool ShowLargeIcons {
get {
return showLargeIcons;
}
set {
if (showLargeIcons != value) {
showLargeIcons = value;
menucmdLargeIcons.Checked = ShowLargeIcons;
ResetTrayControls();
Invalidate(true);
}
}
}
///
///
/// Determines if the tab order UI is active. When tab order is active, the tray is locked in
/// a "read only" mode.
///
private bool TabOrderActive {
get {
if (!queriedTabOrder) {
queriedTabOrder = true;
IMenuCommandService mcs = MenuService;
if (mcs != null) {
tabOrderCommand = mcs.FindCommand(MenuCommands.TabOrder);
}
}
if (tabOrderCommand != null) {
return tabOrderCommand.Checked;
}
return false;
}
}
///
///
///
/// Indicates whether the window is visible.
///
internal bool IsWindowVisible {
get {
if (this.IsHandleCreated) {
return NativeMethods.IsWindowVisible(this.Handle);
}
return false;
}
}
internal Size ParentGridSize {
get {
ParentControlDesigner designer = mainDesigner as ParentControlDesigner;
if (designer != null) {
return designer.ParentGridSize;
}
return new Size(8, 8);
}
}
///
///
/// Adds a component to the tray.
///
public virtual void AddComponent(IComponent component) {
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
// Ignore components that cannot be added to the tray
if (!CanDisplayComponent(component)) {
return;
}
// And designate us as the selection UI handler for the
// control.
//
if (selectionUISvc == null) {
selectionUISvc = (ISelectionUIService)GetService(typeof(ISelectionUIService));
// If there is no selection service, then we will provide our own.
//
if (selectionUISvc == null) {
selectionUISvc = new SelectionUIService(host);
host.AddService(typeof(ISelectionUIService), selectionUISvc);
//privateCommandSet = new CommandSet(mainDesigner.Component.Site);
}
grabHandle = selectionUISvc.GetAdornmentDimensions(AdornmentType.GrabHandle);
}
// Create a new instance of a tray control.
//
TrayControl trayctl = new TrayControl(this, component);
SuspendLayout();
try {
// Add it to us.
//
Controls.Add(trayctl);
controls.Add(trayctl);
// CanExtend can actually be called BEFORE the component is added to the ComponentTray.
// ToolStrip is such as scenario:
// 1. Add a timer to the Tray.
// 2. Add a ToolStrip.
// 3. ToolStripDesigner.Initialize will be called before ComponentTray.AddComponent,
// so the ToolStrip is not yet added to the tray.
// 4. TooStripDesigner.Initialize calls GetProperties, which causes our CanExtend to be called.
// 5. CanExtend will return false, since the component has not yet been added.
// 6. This causes all sorts of badness/
// Fix is to refresh.
TypeDescriptor.Refresh(component);
if (host != null && !host.Loading) {
PositionControl(trayctl);
}
if (selectionUISvc != null) {
selectionUISvc.AssignSelectionUIHandler(component, this);
}
InheritanceAttribute attr = trayctl.InheritanceAttribute;
if (attr.InheritanceLevel != InheritanceLevel.NotInherited) {
InheritanceUI iui = InheritanceUI;
if (iui != null) {
iui.AddInheritedControl(trayctl, attr.InheritanceLevel);
}
}
}
finally {
ResumeLayout();
}
if (host != null && !host.Loading) {
ScrollControlIntoView(trayctl);
}
}
///
///
///
///
/// Gets whether or not this extender provider can extend the given
/// component. We only extend components that have been added
/// to our UI.
///
///
bool IExtenderProvider.CanExtend(object component) {
IComponent comp = component as IComponent;
return (comp != null) && (TrayControl.FromComponent(comp) != null);
}
///
protected virtual bool CanCreateComponentFromTool(ToolboxItem tool) {
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
Debug.Assert(host != null, "Service object could not provide us with a designer host.");
// Disallow controls to be added to the component tray.
Type compType = host.GetType(tool.TypeName);
if (compType == null)
return true;
if (!compType.IsSubclassOf(typeof(Control))) {
return true;
}
Type designerType = GetDesignerType(compType, typeof(IDesigner));
if (typeof(ControlDesigner).IsAssignableFrom(designerType)) {
return false;
}
return true;
}
///
///
/// This method determines if a UI representation for the given component should be provided.
/// If it returns true, then the component will get a glyph in the tray area. If it returns
/// false, then the component will not actually be added to the tray. The default
/// implementation looks for DesignTimeVisibleAttribute.Yes on the component's class.
///
protected virtual bool CanDisplayComponent(IComponent component) {
return TypeDescriptor.GetAttributes(component).Contains(DesignTimeVisibleAttribute.Yes);
}
///
///
/// [To be supplied.]
///
public void CreateComponentFromTool(ToolboxItem tool) {
if (!CanCreateComponentFromTool(tool)) {
return;
}
// We invoke the drag drop handler for this. This implementation is shared between all designers that
// create components.
//
GetOleDragHandler().CreateTool(tool, null, 0, 0, 0, 0, false, false);
}
///
///
/// Displays the given exception to the user.
///
protected void DisplayError(Exception e) {
IUIService uis = (IUIService)GetService(typeof(IUIService));
if (uis != null) {
uis.ShowError(e);
}
else {
string message = e.Message;
if (message == null || message.Length == 0) {
message = e.ToString();
}
RTLAwareMessageBox.Show(null, message, null, MessageBoxButtons.OK, MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1, 0);
}
}
//
///
///
///
/// Disposes of the resources (other than memory) used by the component tray object.
///
///
protected override void Dispose(bool disposing) {
if (disposing && controls != null) {
IExtenderProviderService es = (IExtenderProviderService)GetService(typeof(IExtenderProviderService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(es != null, "IExtenderProviderService not found");
if (es != null) {
es.RemoveExtenderProvider(this);
}
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
if (eventHandlerService != null) {
if (host != null) {
host.RemoveService(typeof(IEventHandlerService));
eventHandlerService = null;
}
}
IComponentChangeService componentChangeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (componentChangeService != null) {
componentChangeService.ComponentRemoved -= new ComponentEventHandler(this.OnComponentRemoved);
}
TypeDescriptor.Refreshed -= new RefreshEventHandler(OnComponentRefresh);
SystemEvents.DisplaySettingsChanged -= new EventHandler(this.OnSystemSettingChanged);
SystemEvents.InstalledFontsChanged -= new EventHandler(this.OnSystemSettingChanged);
SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.OnUserPreferenceChanged);
IMenuCommandService mcs = MenuService;
if (mcs != null) {
Debug.Assert(menucmdArrangeIcons != null, "Null Menu Command for ArrangeIcons");
Debug.Assert(menucmdLineupIcons != null, "Null Menu Command for LineupIcons");
Debug.Assert(menucmdLargeIcons != null, "Null Menu Command for LargeIcons");
mcs.RemoveCommand(menucmdArrangeIcons);
mcs.RemoveCommand(menucmdLineupIcons);
mcs.RemoveCommand(menucmdLargeIcons);
}
if (privateCommandSet != null) {
privateCommandSet.Dispose();
// If we created a private command set, we also added a selection ui service to the host
if (host != null) {
host.RemoveService(typeof(ISelectionUIService));
}
}
selectionUISvc = null;
if (inheritanceUI != null) {
inheritanceUI.Dispose();
inheritanceUI = null;
}
serviceProvider = null;
controls.Clear();
controls = null;
if (glyphManager != null) {
glyphManager.Dispose();
glyphManager = null;
}
}
base.Dispose(disposing);
}
private void DoAutoArrange(bool dirtyDesigner) {
if (controls == null || controls.Count <= 0) {
return;
}
controls.Sort(new AutoArrangeComparer());
SuspendLayout();
//Reset the autoscroll position before auto arranging.
//This way, when OnLayout gets fired after this, we won't
//have to move every component again. Note that sync'ing
//the selection will automatically select & scroll into view
//the right components
this.AutoScrollPosition = new Point(0,0);
try {
Control prevCtl = null;
bool positionedGlobal = true;
foreach(Control ctl in controls) {
if (!ctl.Visible)
continue;
// If we're auto arranging, always move the control. If not,
// move the control only if it was never given a position. This
// auto arranges it until the user messes with it, or until its
// position is saved into the resx.
// (if one control is no longer positioned, move all the other one as
// we don't want them to go under one another)
if (autoArrange) {
PositionInNextAutoSlot(ctl as TrayControl, prevCtl, dirtyDesigner);
}
else if (!((TrayControl)ctl).Positioned || !positionedGlobal) {
PositionInNextAutoSlot(ctl as TrayControl, prevCtl, false);
positionedGlobal = false;
}
prevCtl = ctl;
}
if (selectionUISvc != null) {
selectionUISvc.SyncSelection();
}
}
finally {
ResumeLayout();
}
}
private void DoLineupIcons() {
if (autoArrange)
return;
bool oldValue = autoArrange;
autoArrange = true;
try {
DoAutoArrange(true);
}
finally {
autoArrange = oldValue;
}
}
///
///
/// Draws a rubber band at the given coordinates. The coordinates
/// can be transposed.
///
private void DrawRubber(Point start, Point end) {
mouseDragWorkspace.X = Math.Min(start.X, end.X);
mouseDragWorkspace.Y = Math.Min(start.Y, end.Y);
mouseDragWorkspace.Width = Math.Abs(end.X - start.X);
mouseDragWorkspace.Height = Math.Abs(end.Y - start.Y);
mouseDragWorkspace = RectangleToScreen(mouseDragWorkspace);
ControlPaint.DrawReversibleFrame(mouseDragWorkspace, BackColor, FrameStyle.Dashed);
}
internal void FocusDesigner() {
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
if (host != null && host.RootComponent != null) {
IRootDesigner rd = host.GetDesigner(host.RootComponent) as IRootDesigner;
if (rd != null) {
ViewTechnology[] techs = rd.SupportedTechnologies;
if (techs.Length > 0) {
Control view = rd.GetView(techs[0]) as Control;
if (view != null) {
view.Focus();
}
}
}
}
}
///
///
/// Finds the array of components within the given rectangle. This uses the rectangle to
/// find controls within our frame, and then uses those controls to find the actual
/// components. It returns an object array so the output can be directly fed into
/// the selection service.
///
private object[] GetComponentsInRect(Rectangle rect) {
ArrayList list = new ArrayList();
int controlCount = Controls.Count;
for (int i = 0; i < controlCount; i++) {
Control child = Controls[i];
Rectangle bounds = child.Bounds;
TrayControl tc = child as TrayControl;
if (tc != null && bounds.IntersectsWith(rect)) {
list.Add(tc.Component);
}
}
return list.ToArray();
}
private Type GetDesignerType(Type t, Type designerBaseType)
{
Type designerType = null;
// Get the set of attributes for this type
//
AttributeCollection attributes = TypeDescriptor.GetAttributes(t);
for (int i = 0; i < attributes.Count; i++)
{
DesignerAttribute da = attributes[i] as DesignerAttribute;
if (da != null)
{
Type attributeBaseType = Type.GetType(da.DesignerBaseTypeName);
if (attributeBaseType != null && attributeBaseType == designerBaseType)
{
bool foundService = false;
ITypeResolutionService tr = (ITypeResolutionService)GetService(typeof(ITypeResolutionService));
if (tr != null)
{
foundService = true;
designerType = tr.GetType(da.DesignerTypeName);
}
if (!foundService)
{
designerType = Type.GetType(da.DesignerTypeName);
}
if (designerType != null)
{
break;
}
}
}
}
return designerType;
}
///
///
/// Returns the drag dimensions needed to move the currently selected
/// component one way or the other.
///
internal Size GetDragDimensions() {
// This is a really gross approximation of the correct diemensions.
//
if (AutoArrange) {
ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
IComponent comp = null;
if (ss != null) {
comp = (IComponent)ss.PrimarySelection;
}
Control control = null;
if (comp != null) {
control = ((IOleDragClient)this).GetControlForComponent(comp);
}
if (control == null && controls.Count > 0) {
control = (Control)controls[0];
}
if (control != null) {
Size s = control.Size;
s.Width += 2 * whiteSpace.X;
s.Height += 2 * whiteSpace.Y;
return s;
}
}
return new Size(10, 10);
}
///
///
/// Similar to GetNextControl on Control, this method returns the next
/// component in the tray, given a starting component. It will return
/// null if the end (or beginning, if forward is false) of the list
/// is encountered.
///
public IComponent GetNextComponent(IComponent component, bool forward) {
for (int i = 0; i < controls.Count; i++) {
TrayControl control = (TrayControl)controls[i];
if (control.Component == component) {
int targetIndex = (forward ? i + 1 : i - 1);
if (targetIndex >= 0 && targetIndex < controls.Count) {
return((TrayControl)controls[targetIndex]).Component;
}
// Reached the end of the road.
return null;
}
}
// If we got here then the component isn't in our list. Prime the
// caller with either the first or the last.
if (controls.Count > 0) {
int targetIndex = (forward ? 0 : controls.Count -1);
return((TrayControl)controls[targetIndex]).Component;
}
return null;
}
internal virtual OleDragDropHandler GetOleDragHandler() {
if (oleDragDropHandler == null) {
oleDragDropHandler = new TrayOleDragDropHandler(this.DragHandler, this.serviceProvider, this);
}
return oleDragDropHandler;
}
///
///
/// Accessor method for the location extender property. We offer this extender
/// to all non-visual components.
///
[
Category("Layout"),
Localizable(false),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription("ControlLocationDescr"),
DesignOnly(true),
]
[SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
public Point GetLocation(IComponent receiver) {
// We shouldn't really end up here, but if we do....
PropertyDescriptor loc = TypeDescriptor.GetProperties(receiver.GetType())["Location"];
if (loc != null) {
// In this case the component already had a Location property, and what the caller
// wants is the underlying components Location, not the tray location. Why?
// Because we now use TrayLocation.
return (Point)(loc.GetValue(receiver));
}
else {
// If the component didn't already have a Location property, then the caller
// really wants the tray location. Could be a 3rd party vendor.
return GetTrayLocation(receiver);
}
}
///
///
/// Accessor method for the location extender property. We offer this extender
/// to all non-visual components.
///
[
Category("Layout"),
Localizable(false),
Browsable(false),
SRDescription("ControlLocationDescr"),
DesignOnly(true),
]
public Point GetTrayLocation(IComponent receiver) {
Control c = TrayControl.FromComponent(receiver);
if (c == null) {
Debug.Fail("Anything we're extending should have a component view.");
return new Point();
}
Point loc = c.Location;
Point autoScrollLoc = this.AutoScrollPosition;
return new Point(loc.X - autoScrollLoc.X, loc.Y - autoScrollLoc.Y);
}
///
///
///
/// Gets the requsted service type.
///
///
protected override object GetService(Type serviceType) {
object service = null;
Debug.Assert(serviceProvider != null, "Trying to access services too late or too early.");
if (serviceProvider != null) {
service = serviceProvider.GetService(serviceType);
}
return service;
}
///
///
/// Returns the traycontrol representing the IComponent. If no
/// traycontrol is found, this returns null. This is used identify
/// bounds for the DesignerAction UI.
///
internal TrayControl GetTrayControlFromComponent(IComponent comp) {
return TrayControl.FromComponent(comp);
}
///
///
/// Returns true if the given componenent is being shown on the tray.
///
public bool IsTrayComponent(IComponent comp) {
if (TrayControl.FromComponent(comp) == null) {
return false;
}
foreach (Control control in this.Controls) {
TrayControl tc = control as TrayControl;
if (tc != null && tc.Component == comp) {
return true;
}
}
return false;
}
///
///
/// Called when a component's metadata is invalidated. We re-query here and will show/hide
/// the control's tray control based on the new metadata.
///
private void OnComponentRefresh(RefreshEventArgs e) {
IComponent component = e.ComponentChanged as IComponent;
if (component != null) {
TrayControl control = TrayControl.FromComponent(component);
if (control != null) {
bool shouldDisplay = CanDisplayComponent(component);
if (shouldDisplay != control.Visible || !shouldDisplay) {
control.Visible = shouldDisplay;
Rectangle bounds = control.Bounds;
bounds.Inflate(grabHandle);
bounds.Inflate(grabHandle);
Invalidate(bounds);
PerformLayout();
}
}
}
}
///
///
/// Called when a component is removed from the container.
///
private void OnComponentRemoved(object sender, ComponentEventArgs cevent) {
RemoveComponent(cevent.Component);
}
///
///
/// Called from CommandSet's OnMenuPaste method. This will allow us to properly adjust the location
/// of the components in the tray after we've incorreclty set them by deserializing the design time
/// properties (and hence called SetValue(c, myBadLocation) on the location property).
///
internal void UpdatePastePositions(ArrayList components) {
foreach (TrayControl c in components) {
if (!CanDisplayComponent(c.Component)) {
return;
}
if (mouseDropLocation == InvalidPoint) {
Control prevCtl = null;
if (controls.Count > 1) {
prevCtl = (Control)controls[controls.Count-1];
}
PositionInNextAutoSlot(c, prevCtl, true);
}
else {
PositionControl(c);
}
c.BringToFront();
}
}
///
///
/// Called when we are to display our context menu for this component.
///
private void OnContextMenu(int x, int y, bool useSelection) {
if (!TabOrderActive) {
Capture = false;
IMenuCommandService mcs = MenuService;
if (mcs != null) {
Capture = false;
Cursor.Clip = Rectangle.Empty;
ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService));
if (useSelection && s != null && !(1 == s.SelectionCount && s.PrimarySelection == mainDesigner.Component)) {
mcs.ShowContextMenu(MenuCommands.TraySelectionMenu, x, y);
}
else {
mcs.ShowContextMenu(MenuCommands.ComponentTrayMenu, x, y);
}
}
}
}
///
///
/// [To be supplied.]
///
protected override void OnMouseDoubleClick(MouseEventArgs e) {
//give our glyphs first chance at this
if (glyphManager != null && glyphManager.OnMouseDoubleClick(e)) {
//handled by a glyph - so don't send to the comp tray
return;
}
base.OnDoubleClick(e);
if (!TabOrderActive) {
OnLostCapture();
IEventBindingService eps = (IEventBindingService)GetService(typeof(IEventBindingService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(eps != null, "IEventBindingService not found");
if (eps != null) {
eps.ShowCode();
}
}
}
///
///
/// Inheriting classes should override this method to handle this event.
/// Call base.onGiveFeedback to send this event to any registered event listeners.
///
protected override void OnGiveFeedback(GiveFeedbackEventArgs gfevent) {
base.OnGiveFeedback(gfevent);
GetOleDragHandler().DoOleGiveFeedback(gfevent);
}
///
///
/// Called in response to a drag drop for OLE drag and drop. Here we
/// drop a toolbox component on our parent control.
///
protected override void OnDragDrop(DragEventArgs de) {
// This will be used once during PositionComponent to place the component
// at the drop point. It is automatically set to null afterwards, so further
// components appear after the first one dropped.
//
mouseDropLocation = PointToClient(new Point(de.X, de.Y));
autoScrollPosBeforeDragging = this.AutoScrollPosition;//save the scroll position
if (mouseDragTool != null) {
ToolboxItem tool = mouseDragTool;
mouseDragTool = null;
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(GetService(typeof(IDesignerHost)) != null, "IDesignerHost not found");
try {
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
IDesigner designer = host.GetDesigner(host.RootComponent);
IToolboxUser itu = designer as IToolboxUser;
if (itu != null) {
itu.ToolPicked(tool);
}
else {
CreateComponentFromTool(tool);
}
}
catch (Exception e) {
DisplayError(e);
if (ClientUtils.IsCriticalException(e)) {
throw;
}
}
catch {
}
de.Effect = DragDropEffects.Copy;
}
else {
GetOleDragHandler().DoOleDragDrop(de);
}
mouseDropLocation = InvalidPoint;
ResumeLayout();
}
///
///
/// Called in response to a drag enter for OLE drag and drop.
///
protected override void OnDragEnter(DragEventArgs de) {
if (!TabOrderActive) {
SuspendLayout();
if (toolboxService == null) {
toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
}
OleDragDropHandler dragDropHandler = GetOleDragHandler();
Object[] dragComps = dragDropHandler.GetDraggingObjects(de);
// Only assume the items came from the ToolBox if dragComps == null
//
if (toolboxService != null && dragComps == null) {
mouseDragTool = toolboxService.DeserializeToolboxItem(de.Data, (IDesignerHost)GetService(typeof(IDesignerHost)));
}
if (mouseDragTool != null) {
Debug.Assert(0 != (int)(de.AllowedEffect & (DragDropEffects.Move | DragDropEffects.Copy)), "DragDropEffect.Move | .Copy isn't allowed?");
if ((int)(de.AllowedEffect & DragDropEffects.Move) != 0) {
de.Effect = DragDropEffects.Move;
}
else {
de.Effect = DragDropEffects.Copy;
}
}
else {
dragDropHandler.DoOleDragEnter(de);
}
}
}
///
///
/// Called when a drag-drop operation leaves the control designer view
///
///
protected override void OnDragLeave(EventArgs e) {
mouseDragTool = null;
GetOleDragHandler().DoOleDragLeave();
ResumeLayout();
}
///
///
/// Called when a drag drop object is dragged over the control designer view
///
protected override void OnDragOver(DragEventArgs de) {
if (mouseDragTool != null) {
Debug.Assert(0!=(int)(de.AllowedEffect & DragDropEffects.Copy), "DragDropEffect.Move isn't allowed?");
de.Effect = DragDropEffects.Copy;
}
else {
GetOleDragHandler().DoOleDragOver(de);
}
}
///
///
///
/// Forces the layout of any docked or anchored child controls.
///
protected override void OnLayout(LayoutEventArgs levent) {
DoAutoArrange(false);
// make sure selection service redraws
Invalidate(true);
base.OnLayout(levent);
}
///
///
/// This is called when we lose capture. Here we get rid of any
/// rubber band we were drawing. You should put any cleanup
/// code in here.
///
protected virtual void OnLostCapture() {
if (mouseDragStart != InvalidPoint) {
Cursor.Clip = Rectangle.Empty;
if (mouseDragEnd != InvalidPoint) {
DrawRubber(mouseDragStart, mouseDragEnd);
mouseDragEnd = InvalidPoint;
}
mouseDragStart = InvalidPoint;
}
}
private void OnMenuArrangeIcons(object sender, EventArgs e) {
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
DesignerTransaction t = null;
try {
t = host.CreateTransaction(SR.GetString(SR.TrayAutoArrange));
PropertyDescriptor trayAAProp = TypeDescriptor.GetProperties(mainDesigner.Component)["TrayAutoArrange"];
if (trayAAProp != null) {
trayAAProp.SetValue(mainDesigner.Component, !AutoArrange);
}
}
finally {
if (t != null)
t.Commit();
}
}
private void OnMenuShowLargeIcons(object sender, EventArgs e) {
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
DesignerTransaction t = null;
try {
t = host.CreateTransaction(SR.GetString(SR.TrayShowLargeIcons));
PropertyDescriptor trayIconProp = TypeDescriptor.GetProperties(mainDesigner.Component)["TrayLargeIcon"];
if (trayIconProp != null) {
trayIconProp.SetValue(mainDesigner.Component, !ShowLargeIcons);
}
}
finally {
if (t != null)
t.Commit();
}
}
private void OnMenuLineupIcons(object sender, EventArgs e) {
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
DesignerTransaction t = null;
try {
t = host.CreateTransaction(SR.GetString(SR.TrayLineUpIcons));
DoLineupIcons();
}
finally {
if (t != null)
t.Commit();
}
}
///
/// Used to forward messages from the related ComponentTray Glyph
/// to this ComponentTray class.
///
internal void OnMessage(ref Message m) {
this.WndProc(ref m);
}
///
///
/// Inheriting classes should override this method to handle this event.
/// Call base.onMouseDown to send this event to any registered event listeners.
///
protected override void OnMouseDown(MouseEventArgs e) {
//give our glyphs first chance at this
if (glyphManager != null && glyphManager.OnMouseDown(e)) {
//handled by a glyph - so don't send to the comp tray
return;
}
base.OnMouseDown(e);
if (!TabOrderActive) {
if (toolboxService == null) {
toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
}
FocusDesigner();
if (e.Button == MouseButtons.Left && toolboxService != null) {
ToolboxItem tool = toolboxService.GetSelectedToolboxItem((IDesignerHost)GetService(typeof(IDesignerHost)));
if (tool != null) {
// mouseDropLocation is checked in PositionControl, which should get called as a result of adding a new
// component. This allows us to set the position without flickering, while still providing support for auto
// layout if the control was double clicked or added through extensibility.
//
mouseDropLocation = new Point(e.X, e.Y);
try {
CreateComponentFromTool(tool);
toolboxService.SelectedToolboxItemUsed();
}
catch (Exception ex) {
DisplayError(ex);
if (ClientUtils.IsCriticalException(ex)) {
throw;
}
}
catch {
}
mouseDropLocation = InvalidPoint;
return;
}
}
// If it is the left button, start a rubber band drag to laso
// controls.
//
if (e.Button == MouseButtons.Left) {
mouseDragStart = new Point(e.X, e.Y);
Capture = true;
Cursor.Clip = RectangleToScreen(ClientRectangle);
}
else {
try {
ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(ss != null, "ISelectionService not found");
if (ss != null) {
ss.SetSelectedComponents(new object[] {mainDesigner.Component});
}
}
catch (Exception ex) {
// nothing we can really do here; just eat it.
if (ClientUtils.IsCriticalException(ex)) {
throw;
}
}
catch {
}
}
}
}
///
///
/// Inheriting classes should override this method to handle this event.
/// Call base.onMouseMove to send this event to any registered event listeners.
///
protected override void OnMouseMove(MouseEventArgs e) {
//give our glyphs first chance at this
if (glyphManager != null && glyphManager.OnMouseMove(e)) {
//handled by a glyph - so don't send to the comp tray
return;
}
base.OnMouseMove(e);
// If we are dragging, then draw our little rubber band.
//
if (mouseDragStart != InvalidPoint) {
if (mouseDragEnd != InvalidPoint) {
DrawRubber(mouseDragStart, mouseDragEnd);
}
else {
mouseDragEnd = new Point(0, 0);
}
mouseDragEnd.X = e.X;
mouseDragEnd.Y = e.Y;
DrawRubber(mouseDragStart, mouseDragEnd);
}
}
///
///
/// Inheriting classes should override this method to handle this event.
/// Call base.onMouseUp to send this event to any registered event listeners.
///
protected override void OnMouseUp(MouseEventArgs e) {
//give our glyphs first chance at this
if (glyphManager != null && glyphManager.OnMouseUp(e)) {
//handled by a glyph - so don't send to the comp tray
return;
}
if (mouseDragStart != InvalidPoint && e.Button == MouseButtons.Left) {
object[] comps = null;
Capture = false;
Cursor.Clip = Rectangle.Empty;
if (mouseDragEnd != InvalidPoint) {
DrawRubber(mouseDragStart, mouseDragEnd);
Rectangle rect = new Rectangle();
rect.X = Math.Min(mouseDragStart.X, e.X);
rect.Y = Math.Min(mouseDragStart.Y, e.Y);
rect.Width = Math.Abs(e.X - mouseDragStart.X);
rect.Height = Math.Abs(e.Y - mouseDragStart.Y);
comps = GetComponentsInRect(rect);
mouseDragEnd = InvalidPoint;
}
else {
comps = new object[0];
}
if (comps.Length == 0) {
comps = new object[] {mainDesigner.Component};
}
try {
ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(ss != null, "ISelectionService not found");
if (ss != null) {
ss.SetSelectedComponents(comps);
}
}
catch (Exception ex) {
// nothing we can really do here; just eat it.
if (ClientUtils.IsCriticalException(ex)) {
throw;
}
}
catch {
}
mouseDragStart = InvalidPoint;
}
base.OnMouseUp(e);
}
///
///
/// [To be supplied.]
///
protected override void OnPaint(PaintEventArgs pe) {
if (fResetAmbient) {
fResetAmbient = false;
IUIService uiService = (IUIService)GetService(typeof(IUIService));
if (uiService != null) {
Color styleColor;
//Can't use 'as' here since Color is a value type
if (uiService.Styles["VsColorDesignerTray"] is Color) {
styleColor = (Color) uiService.Styles["VsColorDesignerTray"];
}
else if (uiService.Styles["HighlightColor"] is Color) {
// Since v1, we have had code here that checks for HighlightColor, so some hosts (like WinRes)
// have been setting it. If VsColorDesignerTray isn't present, we look for HighlightColor
// for backward compat.
styleColor = (Color) uiService.Styles["HighlightColor"];
}
else {
//No style color provided? Let's pick a default.
styleColor = SystemColors.Info;
}
BackColor = styleColor;
Font = (Font)uiService.Styles["DialogFont"];
}
}
base.OnPaint(pe);
Graphics gr = pe.Graphics;
// Now, if we have a selection, paint it
//
if (selectedObjects != null) {
bool first = true;//indicates the first iteration of our foreach loop
foreach(object o in selectedObjects) {
Control c = ((IOleDragClient)this).GetControlForComponent(o);
if (c != null && c.Visible) {
Rectangle innerRect = c.Bounds;
NoResizeHandleGlyph glyph = new NoResizeHandleGlyph(innerRect, SelectionRules.None, first, null);
DesignerUtils.DrawSelectionBorder(gr, DesignerUtils.GetBoundsForNoResizeSelectionType(innerRect, SelectionBorderGlyphType.Top));
DesignerUtils.DrawSelectionBorder(gr, DesignerUtils.GetBoundsForNoResizeSelectionType(innerRect, SelectionBorderGlyphType.Bottom));
DesignerUtils.DrawSelectionBorder(gr, DesignerUtils.GetBoundsForNoResizeSelectionType(innerRect, SelectionBorderGlyphType.Left));
DesignerUtils.DrawSelectionBorder(gr, DesignerUtils.GetBoundsForNoResizeSelectionType(innerRect, SelectionBorderGlyphType.Right));
// Need to draw this one last
DesignerUtils.DrawNoResizeHandle(gr, glyph.Bounds, first, glyph);
}
first = false;
}
}
//paint any glyphs
if(glyphManager != null) {
glyphManager.OnPaintGlyphs(pe);
}
}
private void OnSelectionChanged(object sender, EventArgs e) {
selectedObjects = ((ISelectionService)sender).GetSelectedComponents();
object primary = ((ISelectionService)sender).PrimarySelection;
Invalidate();
// Accessibility information
//
foreach(object selObj in selectedObjects) {
IComponent component = selObj as IComponent;
if (component != null) {
Control c = TrayControl.FromComponent(component);
if (c != null) {
Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "MSAA: SelectionAdd, traycontrol = " + c.ToString());
UnsafeNativeMethods.NotifyWinEvent((int)AccessibleEvents.SelectionAdd, new HandleRef(c, c.Handle), NativeMethods.OBJID_CLIENT, 0);
}
}
}
IComponent comp = primary as IComponent;
if (comp != null) {
Control c = TrayControl.FromComponent(comp);
if (c != null && IsHandleCreated) {
this.ScrollControlIntoView(c);
UnsafeNativeMethods.NotifyWinEvent((int)AccessibleEvents.Focus, new HandleRef(c, c.Handle), NativeMethods.OBJID_CLIENT, 0);
}
if(glyphManager != null) {
glyphManager.SelectionGlyphs.Clear();
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
foreach(object selObj in selectedObjects) {
IComponent selectedComponent = selObj as IComponent;
if(selectedComponent!= null && !(host.GetDesigner(selectedComponent) is ControlDesigner)) { // don't want to do it for controls that are also in the tray
GlyphCollection glyphs = glyphManager.GetGlyphsForComponent(selectedComponent);
if (glyphs != null && glyphs.Count > 0) {
SelectionGlyphs.AddRange(glyphs);
}
}
}
}
}
}
///
///
/// Sets the cursor. You may override this to set your own
/// cursor.
///
protected virtual void OnSetCursor() {
if (toolboxService == null) {
toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
}
if (toolboxService == null || !toolboxService.SetCursor()) {
Cursor.Current = Cursors.Default;
}
}
private delegate void AsyncInvokeHandler(bool children);
private void OnSystemSettingChanged(object sender, EventArgs e) {
fResetAmbient = true;
ResetTrayControls();
BeginInvoke(new AsyncInvokeHandler(Invalidate), new object[] {true});
}
private void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) {
fResetAmbient = true;
ResetTrayControls();
BeginInvoke(new AsyncInvokeHandler(Invalidate), new object[] {true});
}
///
///
/// Sets the given control to the correct position on our
/// surface. You may override this to perform your own
/// positioning.
///
private void PositionControl(TrayControl c) {
Debug.Assert(c.Visible, "TrayControl for " + c.Component + " should not be positioned");
if (!autoArrange) {
if (mouseDropLocation != InvalidPoint) {
if (!c.Location.Equals(mouseDropLocation))
c.Location = mouseDropLocation;
}
else {
Control prevCtl = null;
if (controls.Count > 1) {
// PositionControl can be called when all the controls have been added
// (from IOleDragClient.AddComponent), so we can't use the old
// way of looking up the previous control (prevCtl = controls[controls.Count - 2]
int index = controls.IndexOf(c);
Debug.Assert(index >= 1, "Got the wrong index, how could that be?");
if (index >= 1) {
prevCtl = (Control)controls[index - 1];
}
}
PositionInNextAutoSlot(c, prevCtl, true);
}
}
else {
if (mouseDropLocation != InvalidPoint) {
RearrangeInAutoSlots(c, mouseDropLocation);
}
else {
Control prevCtl = null;
if (controls.Count > 1) {
int index = controls.IndexOf(c);
Debug.Assert(index >= 1, "Got the wrong index, how could that be?");
if (index >= 1) {
prevCtl = (Control)controls[index - 1];
}
}
PositionInNextAutoSlot(c, prevCtl, true);
}
}
}
private bool PositionInNextAutoSlot(TrayControl c, Control prevCtl, bool dirtyDesigner) {
Debug.Assert(c.Visible, "TrayControl for " + c.Component + " should not be positioned");
if (whiteSpace.IsEmpty) {
Debug.Assert(selectionUISvc != null, "No SelectionUIService available for tray.");
whiteSpace = new Point(selectionUISvc.GetAdornmentDimensions(AdornmentType.GrabHandle));
whiteSpace.X = whiteSpace.X * 2 + 3;
whiteSpace.Y = whiteSpace.Y * 2 + 3;
}
if (prevCtl == null) {
Rectangle display = DisplayRectangle;
Point newLoc = new Point(display.X + whiteSpace.X, display.Y + whiteSpace.Y);
if (!c.Location.Equals(newLoc)) {
c.Location = newLoc;
if (dirtyDesigner) {
IComponent comp = c.Component;
Debug.Assert(comp != null, "Component for the TrayControl is null");
PropertyDescriptor ctlLocation = TypeDescriptor.GetProperties(comp)["TrayLocation"];
if (ctlLocation != null) {
Point autoScrollLoc = this.AutoScrollPosition;
newLoc = new Point(newLoc.X - autoScrollLoc.X, newLoc.Y - autoScrollLoc.Y);
ctlLocation.SetValue(comp, newLoc);
}
}
else {
c.Location = newLoc;
}
return true;
}
}
else {
// Calcuate the next location for this control.
//
Rectangle bounds = prevCtl.Bounds;
Point newLoc = new Point(bounds.X + bounds.Width + whiteSpace.X, bounds.Y);
// Check to see if it goes over the edge of our window. If it does,
// then wrap it.
//
if (newLoc.X + c.Size.Width > Size.Width) {
newLoc.X = whiteSpace.X;
newLoc.Y += bounds.Height + whiteSpace.Y;
}
if (!c.Location.Equals(newLoc)) {
if (dirtyDesigner) {
IComponent comp = c.Component;
Debug.Assert(comp != null, "Component for the TrayControl is null");
PropertyDescriptor ctlLocation = TypeDescriptor.GetProperties(comp)["TrayLocation"];
if (ctlLocation != null) {
Point autoScrollLoc = this.AutoScrollPosition;
newLoc = new Point(newLoc.X - autoScrollLoc.X, newLoc.Y - autoScrollLoc.Y);
ctlLocation.SetValue(comp, newLoc);
}
}
else {
c.Location = newLoc;
}
return true;
}
}
return false;
}
///
///
/// Removes a component from the tray.
///
public virtual void RemoveComponent(IComponent component) {
TrayControl c = TrayControl.FromComponent(component);
if (c != null) {
try {
InheritanceAttribute attr = c.InheritanceAttribute;
if (attr.InheritanceLevel != InheritanceLevel.NotInherited && inheritanceUI != null) {
inheritanceUI.RemoveInheritedControl(c);
}
if (controls != null) {
int index = controls.IndexOf(c);
if (index != -1)
controls.RemoveAt(index);
}
}
finally {
c.Dispose();
}
}
}
private void ResetTrayControls() {
ControlCollection children = (ControlCollection)this.Controls;
if (children == null)
return;
for (int i = 0; i < children.Count; ++i) {
TrayControl tc = children[i] as TrayControl;
if (tc != null) {
tc.fRecompute = true;
}
}
}
///
///
/// Accessor method for the location extender property. We offer this extender
/// to all non-visual components.
///
public void SetLocation(IComponent receiver, Point location) {
// This really should only be called when we are loading.
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
if (host != null && host.Loading) {
// If we are loading, and we get called here, that's because we have provided
// the extended Location property. In this case we are loading an old project,
// and what we are really setting is the tray location.
SetTrayLocation(receiver, location);
}
else {
// we are not loading
PropertyDescriptor loc = TypeDescriptor.GetProperties(receiver.GetType())["Location"];
if (loc != null) {
// so if the component already had the Location property, what the caller wants
// is really the underlying component's Location property.
loc.SetValue(receiver, location);
}
else {
// if the component didn't have a Location property, then the caller
// really wanted the tray location.
SetTrayLocation(receiver, location);
}
}
}
///
///
/// Accessor method for the location extender property. We offer this extender
/// to all non-visual components.
///
public void SetTrayLocation(IComponent receiver, Point location) {
TrayControl c = TrayControl.FromComponent(receiver);
if (c == null) {
Debug.Fail("Anything we're extending should have a component view.");
return;
}
if (c.Parent == this) {
Point autoScrollLoc = this.AutoScrollPosition;
location = new Point(location.X + autoScrollLoc.X, location.Y + autoScrollLoc.Y);
if (c.Visible) {
RearrangeInAutoSlots(c, location);
}
}
else if (!c.Location.Equals(location)) {
c.Location = location;
c.Positioned = true;
}
}
///
///
/// We override our base class's WndProc to monitor certain messages.
///
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case NativeMethods.WM_CANCELMODE:
// When we get cancelmode (i.e. you tabbed away to another window)
// then we want to cancel any pending drag operation!
//
OnLostCapture();
break;
case NativeMethods.WM_SETCURSOR:
OnSetCursor();
return;
case NativeMethods.WM_HSCROLL:
case NativeMethods.WM_VSCROLL:
// When we scroll, we reposition a control without causing a
// property change event. Therefore, we must tell the
// selection UI service to sync itself.
//
base.WndProc(ref m);
if (selectionUISvc != null) {
selectionUISvc.SyncSelection();
}
return;
case NativeMethods.WM_STYLECHANGED:
// When the scroll bars first appear, we need to
// invalidate so we properly paint our grid.
//
Invalidate();
break;
case NativeMethods.WM_CONTEXTMENU:
// Pop a context menu for the composition designer.
//
int x = NativeMethods.Util.SignedLOWORD((int)m.LParam);
int y = NativeMethods.Util.SignedHIWORD((int)m.LParam);
if (x == -1 && y == -1) {
// for shift-F10
Point mouse = Control.MousePosition;
x = mouse.X;
y = mouse.Y;
}
OnContextMenu(x, y, true);
break;
case NativeMethods.WM_NCHITTEST:
if(glyphManager != null) {
// Get a hit test on any glyhs that we are managing
// this way - we know where to route appropriate
// messages
Point pt = new Point((short)NativeMethods.Util.LOWORD((int)m.LParam),
(short)NativeMethods.Util.HIWORD((int)m.LParam));
NativeMethods.POINT pt1 = new NativeMethods.POINT();
pt1.x = 0;
pt1.y = 0;
NativeMethods.MapWindowPoints(IntPtr.Zero, Handle, pt1, 1);
pt.Offset(pt1.x, pt1.y);
glyphManager.GetHitTest(pt);
}
base.WndProc(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
///
///
///
/// Checks if the client is read only. That is, if components can
/// be added or removed from the designer.
///
bool IOleDragClient.CanModifyComponents {
get {
return true;
}
}
///
///
IComponent IOleDragClient.Component {
get{
return mainDesigner.Component;
}
}
///
///
///
/// Adds a component to the tray.
///
bool IOleDragClient.AddComponent(IComponent component, string name, bool firstAdd) {
IOleDragClient oleDragClient = mainDesigner as IOleDragClient;
// the designer for controls decides what to do here
if (oleDragClient != null) {
try {
oleDragClient.AddComponent(component, name, firstAdd);
PositionControl(TrayControl.FromComponent(component));
mouseDropLocation = InvalidPoint;
return true;
}
catch {
}
}
else {
// for webforms (98109) just add the component directly to the host
//
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
try {
if (host != null && host.Container != null) {
if (host.Container.Components[name] != null) {
name = null;
}
host.Container.Add(component, name);
return true;
}
}
catch {
}
}
Debug.Fail("Don't know how to add component!");
return false;
}
///
///
///
///
/// Gets the control view instance for the given component.
/// For Win32 designer, this will often be the component itself.
///
///
Control IOleDragClient.GetControlForComponent(object component) {
IComponent comp = component as IComponent;
if (comp != null) {
return TrayControl.FromComponent(comp);
}
Debug.Fail("component is not IComponent");
return null;
}
///
///
///
///
/// Gets the control view instance for the designer that
/// is hosting the drag.
///
///
Control IOleDragClient.GetDesignerControl() {
return this;
}
///
///
///
/// Checks if it is valid to drop this type of a component on this client.
///
bool IOleDragClient.IsDropOk(IComponent component) {
return true;
}
///
///
///
/// Begins a drag operation. A designer should examine the list of components
/// to see if it wants to support the drag. If it does, it should return
/// true. If it returns true, the designer should provide
/// UI feedback about the drag at this time. Typically, this feedback consists
/// of an inverted rectangle for each component, or a caret if the component
/// is text.
///
bool ISelectionUIHandler.BeginDrag(object[] components, SelectionRules rules, int initialX, int initialY) {
if (TabOrderActive) {
return false;
}
bool result = DragHandler.BeginDrag(components, rules, initialX, initialY);
if (result) {
if (!GetOleDragHandler().DoBeginDrag(components, rules, initialX, initialY)) {
return false;
}
}
return result;
}
///
///
///
/// Called when the user has moved the mouse. This will only be called on
/// the designer that returned true from beginDrag. The designer
/// should update its UI feedback here.
///
void ISelectionUIHandler.DragMoved(object[] components, Rectangle offset) {
DragHandler.DragMoved(components, offset);
}
///
///
///
/// Called when the user has completed the drag. The designer should
/// remove any UI feedback it may be providing.
///
void ISelectionUIHandler.EndDrag(object[] components, bool cancel) {
DragHandler.EndDrag(components, cancel);
GetOleDragHandler().DoEndDrag(components, cancel);
//Here, after the drag is finished and after we have resumed layout,
//adjust the location of the components we dragged by the scroll offset
//
if (!this.autoScrollPosBeforeDragging.IsEmpty) {
foreach (IComponent comp in components) {
TrayControl tc = TrayControl.FromComponent(comp);
if (tc != null) {
this.SetTrayLocation(comp, new Point(tc.Location.X - this.autoScrollPosBeforeDragging.X, tc.Location.Y - this.autoScrollPosBeforeDragging.Y));
}
}
this.AutoScrollPosition = new Point(-this.autoScrollPosBeforeDragging.X, -this.autoScrollPosBeforeDragging.Y);
}
}
///
///
///
///
/// Gets the shape of the component. The component's shape should be in
/// absolute coordinates and in pixels, where 0,0 is the upper left corner of
/// the screen.
///
///
Rectangle ISelectionUIHandler.GetComponentBounds(object component) {
// We render the selection UI glyph ourselves.
return Rectangle.Empty;
}
///
///
///
///
/// Gets a set of rules concerning the movement capabilities of a component.
/// This should be one or more flags from the SelectionRules class. If no designer
/// provides rules for a component, the component will not get any UI services.
///
///
SelectionRules ISelectionUIHandler.GetComponentRules(object component) {
return SelectionRules.Visible | SelectionRules.Moveable;
}
///
///
///
///
/// Gets the rectangle that any selection adornments should be clipped
/// to. This is normally the client area (in screen coordinates) of the
/// container.
///
///
Rectangle ISelectionUIHandler.GetSelectionClipRect(object component) {
if (IsHandleCreated) {
return RectangleToScreen(ClientRectangle);
}
return Rectangle.Empty;
}
///
///
void ISelectionUIHandler.OleDragEnter(DragEventArgs de) {
GetOleDragHandler().DoOleDragEnter(de);
}
///
///
void ISelectionUIHandler.OleDragDrop(DragEventArgs de) {
GetOleDragHandler().DoOleDragDrop(de);
}
///
///
void ISelectionUIHandler.OleDragOver(DragEventArgs de) {
GetOleDragHandler().DoOleDragOver(de);
}
///
///
void ISelectionUIHandler.OleDragLeave() {
GetOleDragHandler().DoOleDragLeave();
}
///
///
///
/// Handle a double-click on the selection rectangle
/// of the given component.
///
void ISelectionUIHandler.OnSelectionDoubleClick(IComponent component) {
if (!TabOrderActive) {
TrayControl tc = ((IOleDragClient)this).GetControlForComponent(component) as TrayControl;
if (tc != null) {
tc.ViewDefaultEvent(component);
}
}
}
///
///
///
/// Queries to see if a drag operation
/// is valid on this handler for the given set of components.
/// If it returns true, BeginDrag will be called immediately after.
///
bool ISelectionUIHandler.QueryBeginDrag(object[] components, SelectionRules rules, int initialX, int initialY) {
return DragHandler.QueryBeginDrag(components, rules, initialX, initialY);
}
internal void RearrangeInAutoSlots(Control c, Point pos) {
#if DEBUG
int index = controls.IndexOf(c);
Debug.Assert(index != -1, "Add control to the list of controls before autoarranging.!!!");
Debug.Assert(this.Visible == c.Visible, "TrayControl for " + ((TrayControl)c).Component + " should not be positioned");
#endif // DEBUG
TrayControl tc = (TrayControl)c;
tc.Positioned = true;
tc.Location = pos;
}
///
///
///
/// Shows the context menu for the given component.
///
void ISelectionUIHandler.ShowContextMenu(IComponent component) {
Point cur = Control.MousePosition;
OnContextMenu(cur.X, cur.Y, true);
}
///
///
/// This class privately manages all componenttray-related
/// glyphs in a simlar fashion to the BehaviorService.
///
private class ComponentTrayGlyphManager {
private Adorner traySelectionAdorner;//we'll use a single adorner to manage the glyphs
private Glyph hitTestedGlyph;//the last glyph we hit tested (can be null)
private ISelectionService selSvc;//we need the selection service fo r the hover behavior
private BehaviorService behaviorSvc;
///
/// Constructor that simply creates an empty adorner.
///
public ComponentTrayGlyphManager(ISelectionService selSvc, BehaviorService behaviorSvc) {
this.selSvc = selSvc;
this.behaviorSvc = behaviorSvc;
traySelectionAdorner = new Adorner();
}
///
/// This is how we publically expose our glyph collection
/// so that other designer services can 'add value'.
///
public GlyphCollection SelectionGlyphs {
get {
return traySelectionAdorner.Glyphs;
}
}
///
/// Clears teh adorner of glyphs.
///
public void Dispose() {
if (traySelectionAdorner != null) {
traySelectionAdorner.Glyphs.Clear();
traySelectionAdorner = null;
}
}
///
/// Retrieves a list of glyphs associated with the component.
///
public GlyphCollection GetGlyphsForComponent(IComponent comp) {
GlyphCollection glyphs = new GlyphCollection();
if(behaviorSvc != null && comp != null) {
if(behaviorSvc.DesignerActionUI != null) {
Glyph g = behaviorSvc.DesignerActionUI.GetDesignerActionGlyph(comp);
if(g!=null) {
glyphs.Add(g);
}
}
}
return glyphs;
}
///
/// Called from the tray's NCHITTEST message in the WndProc.
/// We use this to loop through our glyphs and identify which
/// one is successfully hit tested. From here, we know where
/// to send our messages.
///
public Cursor GetHitTest(Point p) {
for (int i = 0; i < traySelectionAdorner.Glyphs.Count; i++) {
Cursor hitTestCursor = traySelectionAdorner.Glyphs[i].GetHitTest(p);
if (hitTestCursor != null) {
hitTestedGlyph = traySelectionAdorner.Glyphs[i];
return hitTestCursor;
}
}
hitTestedGlyph = null;
return null;
}
///
/// Called when the tray receives this mouse message. Here,
/// we'll give our glyphs the first chance to repsond to the message
// before the tray even sees it.
///
public bool OnMouseDoubleClick(MouseEventArgs e) {
if (hitTestedGlyph != null && hitTestedGlyph.Behavior != null) {
return hitTestedGlyph.Behavior.OnMouseDoubleClick(hitTestedGlyph, e.Button, new Point(e.X, e.Y));
}
return false;
}
///
/// Called when the tray receives this mouse message. Here,
/// we'll give our glyphs the first chance to repsond to the message
// before the tray even sees it.
///
public bool OnMouseDown(MouseEventArgs e) {
if (hitTestedGlyph != null && hitTestedGlyph.Behavior != null) {
return hitTestedGlyph.Behavior.OnMouseDown(hitTestedGlyph, e.Button, new Point(e.X, e.Y));
}
return false;
}
///
/// Called when the tray receives this mouse message. Here,
/// we'll give our glyphs the first chance to repsond to the message
// before the tray even sees it.
///
public bool OnMouseMove(MouseEventArgs e) {
if (hitTestedGlyph != null && hitTestedGlyph.Behavior != null) {
return hitTestedGlyph.Behavior.OnMouseMove(hitTestedGlyph, e.Button, new Point(e.X, e.Y));
}
return false;
}
///
/// Called when the tray receives this mouse message. Here,
/// we'll give our glyphs the first chance to repsond to the message
// before the tray even sees it.
///
public bool OnMouseUp(MouseEventArgs e) {
if (hitTestedGlyph != null && hitTestedGlyph.Behavior != null) {
return hitTestedGlyph.Behavior.OnMouseUp(hitTestedGlyph, e.Button);
}
return false;
}
///
/// Called when the comp tray or any tray control paints.
/// This will simply enumerate through the glyphs in our
/// Adorner and ask them to paint
///
public void OnPaintGlyphs(PaintEventArgs pe) {
//Paint any glyphs our tray adorner has
foreach (Glyph g in traySelectionAdorner.Glyphs) {
g.Paint(pe);
}
}
///
/// Called when a tray control's location has changed.
/// We'll loop through our glyphs and invalidate any
/// that are associated with the component.
///
public void UpdateLocation(TrayControl trayControl) {
foreach (Glyph g in traySelectionAdorner.Glyphs) {
//only look at glyphs that derive from designerglyph base (actions)
DesignerActionGlyph desGlyph = g as DesignerActionGlyph;
if (desGlyph != null && ((DesignerActionBehavior)(desGlyph.Behavior)).RelatedComponent.Equals(trayControl.Component)) {
desGlyph.UpdateAlternativeBounds(trayControl.Bounds);
}
}
}
}
///
///
///
/// TrayOleDragDropHandler provides the Ole Drag-drop handler for the
/// component tray.
///
private class TrayOleDragDropHandler : OleDragDropHandler {
public TrayOleDragDropHandler(SelectionUIHandler selectionHandler, IServiceProvider serviceProvider, IOleDragClient client) :
base(selectionHandler, serviceProvider, client) {
}
protected override bool CanDropDataObject(IDataObject dataObj) {
ICollection comps = null;
if (dataObj != null) {
ComponentDataObjectWrapper cdow = dataObj as ComponentDataObjectWrapper;
if (cdow != null) {
ComponentDataObject cdo = (ComponentDataObject) cdow.InnerData;
comps = cdo.Components;
}
else {
try {
object serializationData = dataObj.GetData(OleDragDropHandler.DataFormat, true);
if (serializationData == null) {
return false;
}
IDesignerSerializationService ds = (IDesignerSerializationService)GetService(typeof(IDesignerSerializationService));
if (ds == null) {
return false;
}
comps = ds.Deserialize(serializationData);
}
catch (Exception e) {
if (ClientUtils.IsCriticalException(e)) {
throw;
}
// we return false on any exception
}
catch {
}
}
}
if (comps != null && comps.Count > 0) {
foreach(object comp in comps) {
if (comp is Point) {
continue;
}
if (comp is Control || !(comp is IComponent)) {
return false;
}
}
return true;
}
return false;
}
}
internal class AutoArrangeComparer : IComparer {
int IComparer.Compare(object o1, object o2) {
Debug.Assert(o1 != null && o2 != null, "Null objects sent for comparison!!!");
Point tcLoc1 = ((Control)o1).Location;
Point tcLoc2 = ((Control)o2).Location;
int width = ((Control)o1).Width / 2;
int height = ((Control)o1).Height / 2;
// If they are at the same location, they are equal.
if (tcLoc1.X == tcLoc2.X && tcLoc1.Y == tcLoc2.Y) {
return 0;
}
// Is the first control lower than the 2nd...
if (tcLoc1.Y + height <= tcLoc2.Y)
return -1;
// Is the 2nd control lower than the first...
if (tcLoc2.Y + height <= tcLoc1.Y)
return 1;
// Which control is left of the other...
return((tcLoc1.X <= tcLoc2.X) ? -1 : 1);
}
}
///
///
///
/// The tray control is the UI we show for each component in the tray.
///
internal class TrayControl : Control {
// Values that define this tray control
//
private IComponent component; // the component this control is representing
private Image toolboxBitmap; // the bitmap used to represent the component
private int cxIcon; // the dimensions of the bitmap
private int cyIcon; // the dimensions of the bitmap
private InheritanceAttribute inheritanceAttribute;
// Services that we use often enough to cache.
//
private ComponentTray tray;
// transient values that are used during mouse drags
//
private Point mouseDragLast = InvalidPoint; // the last position of the mouse during a drag.
private bool mouseDragMoved; // has the mouse been moved during this drag?
private bool ctrlSelect = false; // was the ctrl key down on the mouse down?
private bool positioned = false; // Have we given this control an explicit location yet?
private const int whiteSpace = 5;
private int borderWidth;
internal bool fRecompute = false; // This flag tells the TrayControl that it needs to retrieve
// the font and the background color before painting.
///
///
/// Creates a new TrayControl based on the component.
///
public TrayControl(ComponentTray tray, IComponent component) {
this.tray = tray;
this.component = component;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.Selectable, false);
borderWidth = SystemInformation.BorderSize.Width;
UpdateIconInfo();
IComponentChangeService cs = (IComponentChangeService)tray.GetService(typeof(IComponentChangeService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(cs != null, "IComponentChangeService not found");
if (cs != null) {
cs.ComponentRename += new ComponentRenameEventHandler(this.OnComponentRename);
}
ISite site = component.Site;
string name = null;
if (site != null) {
name = site.Name;
IDictionaryService ds = (IDictionaryService)site.GetService(typeof(IDictionaryService));
Debug.Assert(ds != null, "ComponentTray relies on IDictionaryService, which is not available.");
if (ds != null) {
ds.SetValue(GetType(), this);
}
}
if (name == null) {
// We always want name to have something in it, so we default to
// the class name. This way the design instance contains something
// semi-intuitive if we don't have a site.
//
name = component.GetType().Name;
}
Text = name;
inheritanceAttribute = (InheritanceAttribute)TypeDescriptor.GetAttributes(component)[typeof(InheritanceAttribute)];
TabStop = false;
}
///
///
/// Retrieves the compnent this control is representing.
///
public IComponent Component {
get {
return component;
}
}
public override Font Font {
get {
/*
IDesignerHost host = (IDesignerHost)tray.GetService(typeof(IDesignerHost));
if (host != null && host.GetRootComponent() is Control) {
Control c = (Control)host.GetRootComponent();
return c.Font;
}
*/
return tray.Font;
}
}
public InheritanceAttribute InheritanceAttribute {
get {
return inheritanceAttribute;
}
}
public bool Positioned {
get {
return positioned;
}
set {
positioned = value;
}
}
///
///
/// Adjusts the size of the control based on the contents.
///
//
private void AdjustSize(bool autoArrange) {
//
Graphics gr = CreateGraphics();
try {
Size sz = Size.Ceiling(gr.MeasureString(Text, Font));
Rectangle rc = Bounds;
if (tray.ShowLargeIcons) {
rc.Width = Math.Max(cxIcon, sz.Width) + 4 * borderWidth + 2 * whiteSpace;
rc.Height = cyIcon + 2 * whiteSpace + sz.Height + 4 * borderWidth;
}
else {
rc.Width = cxIcon + sz.Width + 4 * borderWidth + 2 * whiteSpace;
rc.Height = Math.Max(cyIcon, sz.Height) + 4 * borderWidth;
}
Bounds = rc;
Invalidate();
}
finally {
if (gr != null) {
gr.Dispose();
}
}
if(tray.glyphManager != null) {
tray.glyphManager.UpdateLocation(this);
}
}
protected override AccessibleObject CreateAccessibilityInstance() {
return new TrayControlAccessibleObject(this, tray);
}
///
///
/// Destroys this control. Views automatically destroy themselves when they
/// are removed from the design container.
///
protected override void Dispose(bool disposing) {
if (disposing) {
ISite site = component.Site;
if (site != null) {
IComponentChangeService cs = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(cs != null, "IComponentChangeService not found");
if (cs != null) {
cs.ComponentRename -= new ComponentRenameEventHandler(this.OnComponentRename);
}
IDictionaryService ds = (IDictionaryService)site.GetService(typeof(IDictionaryService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(ds != null, "IDictionaryService not found");
if (ds != null) {
ds.SetValue(typeof(TrayControl), null);
}
}
}
base.Dispose(disposing);
}
///
///
/// Retrieves the tray control object for the given component.
///
public static TrayControl FromComponent(IComponent component) {
TrayControl c = null;
if (component == null) {
return null;
}
ISite site = component.Site;
if (site != null) {
IDictionaryService ds = (IDictionaryService)site.GetService(typeof(IDictionaryService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(ds != null, "IDictionaryService not found");
if (ds != null) {
c = (TrayControl)ds.GetValue(typeof(TrayControl));
}
}
return c;
}
///
///
/// Delegate that is called in response to a name change. Here we update our own
/// stashed version of the name, recalcuate our size and repaint.
///
private void OnComponentRename(object sender, ComponentRenameEventArgs e) {
if (e.Component == this.component) {
Text = e.NewName;
AdjustSize(true);
}
}
///
///
/// Overrides handle creation notification for a control. Here we just ensure
/// that we're the proper size.
///
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
AdjustSize(false);
}
///
///
/// Called in response to a double-click of the left mouse button. The
/// default behavior here calls onDoubleClick on IMouseHandler
///
protected override void OnDoubleClick(EventArgs e) {
base.OnDoubleClick(e);
if (!tray.TabOrderActive) {
IDesignerHost host = (IDesignerHost)tray.GetService(typeof(IDesignerHost));
Debug.Assert(host != null, "Component tray does not have access to designer host.");
if (host != null) {
mouseDragLast = InvalidPoint;
Capture = false;
// We try to get a designer for the component and let it view the
// event. If this fails, then we'll try to do it ourselves.
//
IDesigner designer = host.GetDesigner(component);
if (designer == null) {
ViewDefaultEvent(component);
}
else {
designer.DoDefaultAction();
}
}
}
}
///
/// Terminates our drag operation.
///
private void OnEndDrag(bool cancel) {
mouseDragLast = InvalidPoint;
if (!mouseDragMoved) {
if (ctrlSelect) {
ISelectionService sel = (ISelectionService)tray.GetService(typeof(ISelectionService));
if (sel != null) {
sel.SetSelectedComponents(new object[] {this.Component}, SelectionTypes.Primary);
}
ctrlSelect = false;
}
return;
}
mouseDragMoved = false;
ctrlSelect = false;
Capture = false;
OnSetCursor();
// And now finish the drag.
//
Debug.Assert(tray.selectionUISvc != null, "We shouldn't be able to begin a drag without this");
if (tray.selectionUISvc != null && tray.selectionUISvc.Dragging) {
tray.selectionUISvc.EndDrag(cancel);
}
}
///
///
/// Called when the mouse button is pressed down. Here, we provide drag
/// support for the component.
///
protected override void OnMouseDown(MouseEventArgs me) {
base.OnMouseDown(me);
if (!tray.TabOrderActive) {
tray.FocusDesigner();
// If this is the left mouse button, then begin a drag.
//
if (me.Button == MouseButtons.Left) {
Capture = true;
mouseDragLast = PointToScreen(new Point(me.X, me.Y));
// If the CTRL key isn't down, select this component,
// otherwise, we wait until the mouse up
//
// Make sure the component is selected
//
ctrlSelect = NativeMethods.GetKeyState((int)Keys.ControlKey) != 0;
if (!ctrlSelect) {
ISelectionService sel = (ISelectionService)tray.GetService(typeof(ISelectionService));
// Make sure the component is selected
//
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(sel != null, "ISelectionService not found");
if (sel != null) {
sel.SetSelectedComponents(new object[] {this.Component}, SelectionTypes.Primary);
}
}
}
}
}
///
///
/// Called when the mouse is moved over the component. We update our drag
/// information here if we're dragging the component around.
///
protected override void OnMouseMove(MouseEventArgs me) {
base.OnMouseMove(me);
if (mouseDragLast == InvalidPoint) {
return;
}
if (!mouseDragMoved) {
Size minDrag = SystemInformation.DragSize;
Size minDblClick = SystemInformation.DoubleClickSize;
minDrag.Width = Math.Max(minDrag.Width, minDblClick.Width);
minDrag.Height = Math.Max(minDrag.Height, minDblClick.Height);
// we have to make sure the mouse moved farther than
// the minimum drag distance before we actually start
// the drag
//
Point newPt = PointToScreen(new Point(me.X, me.Y));
if (mouseDragLast == InvalidPoint ||
(Math.Abs(mouseDragLast.X - newPt.X) < minDrag.Width &&
Math.Abs(mouseDragLast.Y - newPt.Y) < minDrag.Height)) {
return;
}
else {
mouseDragMoved = true;
// we're on the move, so we're not in a ctrlSelect
//
ctrlSelect = false;
}
}
try {
// Make sure the component is selected
//
ISelectionService sel = (ISelectionService)tray.GetService(typeof(ISelectionService));
if (sel != null) {
sel.SetSelectedComponents(new object[] {this.Component}, SelectionTypes.Primary);
}
// Notify the selection service that all the components are in the "mouse down" mode.
//
if (tray.selectionUISvc != null && tray.selectionUISvc.BeginDrag(SelectionRules.Visible | SelectionRules.Moveable, mouseDragLast.X, mouseDragLast.Y)) {
OnSetCursor();
}
}
finally {
mouseDragMoved = false;
mouseDragLast = InvalidPoint;
}
}
///
///
/// Called when the mouse button is released. Here, we finish our drag
/// if one was started.
///
protected override void OnMouseUp(MouseEventArgs me) {
base.OnMouseUp(me);
OnEndDrag(false);
}
///
///
/// Called when we are to display our context menu for this component.
///
private void OnContextMenu(int x, int y) {
if (!tray.TabOrderActive) {
Capture = false;
// Ensure that this component is selected.
//
ISelectionService s = (ISelectionService)tray.GetService(typeof(ISelectionService));
if (s != null && !s.GetComponentSelected(component)) {
s.SetSelectedComponents(new object[] {component}, SelectionTypes.Replace);
}
IMenuCommandService mcs = tray.MenuService;
if (mcs != null) {
Capture = false;
Cursor.Clip = Rectangle.Empty;
mcs.ShowContextMenu(MenuCommands.TraySelectionMenu, x, y);
}
}
}
///
///
/// Painting for our control.
///
protected override void OnPaint(PaintEventArgs e) {
if (fRecompute) {
fRecompute = false;
UpdateIconInfo();
}
base.OnPaint(e);
Rectangle rc = ClientRectangle;
rc.X += whiteSpace + borderWidth;
rc.Y += borderWidth;
rc.Width -= (2 * borderWidth + whiteSpace);
rc.Height -= 2 * borderWidth;
StringFormat format = new StringFormat();
Brush foreBrush = new SolidBrush(ForeColor);
try {
format.Alignment = StringAlignment.Center;
if (tray.ShowLargeIcons) {
if (null != toolboxBitmap) {
int x = rc.X + (rc.Width - cxIcon)/2;
int y = rc.Y + whiteSpace;
e.Graphics.DrawImage(toolboxBitmap, new Rectangle(x, y, cxIcon, cyIcon));
}
rc.Y += (cyIcon + whiteSpace);
rc.Height -= cyIcon;
e.Graphics.DrawString(Text, Font, foreBrush, rc, format);
}
else {
if (null != toolboxBitmap) {
int y = rc.Y + (rc.Height - cyIcon)/2;
e.Graphics.DrawImage(toolboxBitmap, new Rectangle(rc.X, y, cxIcon, cyIcon));
}
rc.X += (cxIcon + borderWidth);
rc.Width -= cxIcon;
rc.Y += 3;
e.Graphics.DrawString(Text, Font, foreBrush, rc);
}
}
finally {
if (format != null) {
format.Dispose();
}
if (foreBrush != null) {
foreBrush.Dispose();
}
}
// If this component is being inherited, paint it as such
//
if (!InheritanceAttribute.NotInherited.Equals(inheritanceAttribute)) {
InheritanceUI iui = tray.InheritanceUI;
if (iui != null) {
e.Graphics.DrawImage(iui.InheritanceGlyph, 0, 0);
}
}
}
///
///
/// Overrides control's FontChanged. Here we re-adjust our size if the font changes.
///
protected override void OnFontChanged(EventArgs e) {
AdjustSize(true);
base.OnFontChanged(e);
}
///
///
/// Overrides control's LocationChanged. Here, we make sure that any glyphs associated
/// with us are also relocated.
///
protected override void OnLocationChanged(EventArgs e) {
if(tray.glyphManager != null) {
tray.glyphManager.UpdateLocation(this);
}
}
///
///
/// Overrides control's TextChanged. Here we re-adjust our size if the font changes.
///
protected override void OnTextChanged(EventArgs e) {
AdjustSize(true);
base.OnTextChanged(e);
}
///
///
/// Called each time the cursor needs to be set. The ControlDesigner behavior here
/// will set the cursor to one of three things:
/// 1. If the selection UI service shows a locked selection, or if there is no location
/// property on the control, then the default arrow will be set.
/// 2. Otherwise, the four headed arrow will be set to indicate that the component can
/// be clicked and moved.
/// 3. If the user is currently dragging a component, the crosshair cursor will be used
/// instead of the four headed arrow.
///
private void OnSetCursor() {
// Check that the component is not locked.
//
PropertyDescriptor prop = TypeDescriptor.GetProperties(component)["Locked"];
if (prop != null && ((bool)prop.GetValue(component)) == true) {
Cursor.Current = Cursors.Default;
return;
}
// Ask the tray to see if the tab order UI is not running.
//
if (tray.TabOrderActive) {
Cursor.Current = Cursors.Default;
return;
}
if (mouseDragMoved) {
Cursor.Current = Cursors.Default;
}
else if (mouseDragLast != InvalidPoint) {
Cursor.Current = Cursors.Cross;
}
else {
Cursor.Current = Cursors.SizeAll;
}
}
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
if (!tray.AutoArrange ||
(specified & BoundsSpecified.Width) == BoundsSpecified.Width ||
(specified & BoundsSpecified.Height) == BoundsSpecified.Height) {
base.SetBoundsCore(x, y, width, height, specified);
}
Rectangle bounds = Bounds;
Size parentGridSize = tray.ParentGridSize;
if (Math.Abs(bounds.X - x) > parentGridSize.Width || Math.Abs(bounds.Y - y) > parentGridSize.Height) {
base.SetBoundsCore(x, y, width, height, specified);
}
}
///
///
/// [To be supplied.]
///
protected override void SetVisibleCore(bool value) {
if (value && !tray.CanDisplayComponent(this.component))
return;
base.SetVisibleCore(value);
}
public override string ToString() {
return "ComponentTray: " + component.ToString();
}
internal void UpdateIconInfo() {
ToolboxBitmapAttribute attr = (ToolboxBitmapAttribute)TypeDescriptor.GetAttributes(component)[typeof(ToolboxBitmapAttribute)];
if (attr != null) {
toolboxBitmap = attr.GetImage(component, tray.ShowLargeIcons);
}
// Get the size of the bitmap so we can size our
// component correctly.
//
if (null == toolboxBitmap) {
cxIcon = 0;
cyIcon = SystemInformation.IconSize.Height;
}
else {
Size sz = toolboxBitmap.Size;
cxIcon = sz.Width;
cyIcon = sz.Height;
}
AdjustSize(true);
}
///
///
/// This creates a method signature in the source code file for the
/// default event on the component and navigates the user's cursor
/// to that location.
///
public virtual void ViewDefaultEvent(IComponent component) {
EventDescriptor defaultEvent = TypeDescriptor.GetDefaultEvent(component);
PropertyDescriptor defaultPropEvent = null;
string handler = null;
bool eventChanged = false;
IEventBindingService eps = (IEventBindingService)GetService(typeof(IEventBindingService));
if (CompModSwitches.CommonDesignerServices.Enabled) Debug.Assert(eps != null, "IEventBindingService not found");
if (eps != null) {
defaultPropEvent = eps.GetEventProperty(defaultEvent);
}
// If we couldn't find a property for this event, or if the property is read only, then
// abort and just show the code.
//
if (defaultPropEvent == null || defaultPropEvent.IsReadOnly) {
if (eps != null) {
eps.ShowCode();
}
return;
}
handler = (string)defaultPropEvent.GetValue(component);
// If there is no handler set, set one now.
//
if (handler == null) {
eventChanged = true;
handler = eps.CreateUniqueMethodName(component, defaultEvent);
}
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
DesignerTransaction trans = null;
try {
if (host != null) {
trans = host.CreateTransaction(SR.GetString(SR.WindowsFormsAddEvent, defaultEvent.Name));
}
// Save the new value... BEFORE navigating to it!
//
if (eventChanged && defaultPropEvent != null) {
defaultPropEvent.SetValue(component, handler);
// make sure set succeded (may fail if under SCC)
// if (defaultPropEvent.GetValue(component) != handler) {
// return;
// }
}
eps.ShowCode(component, defaultEvent);
}
finally {
if (trans != null) {
trans.Commit();
}
}
}
///
///
/// This method should be called by the extending designer for each message
/// the control would normally receive. This allows the designer to pre-process
/// messages before allowing them to be routed to the control.
///
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case NativeMethods.WM_SETCURSOR:
// We always handle setting the cursor ourselves.
//
OnSetCursor();
break;
case NativeMethods.WM_CONTEXTMENU:
// We must handle this ourselves. Control only allows
// regular Windows Forms context menus, which doesn't do us much
// good. Also, control's button up processing calls DefwndProc
// first, which causes a right mouse up to be routed as a
// WM_CONTEXTMENU. If we don't respond to it here, this
// message will be bubbled up to our parent, which would
// pop up a container context menu instead of our own.
//
int x = NativeMethods.Util.SignedLOWORD((int)m.LParam);
int y = NativeMethods.Util.SignedHIWORD((int)m.LParam);
if (x == -1 && y == -1) {
// for shift-F10
Point mouse = Control.MousePosition;
x = mouse.X;
y = mouse.Y;
}
OnContextMenu(x, y);
break;
case NativeMethods.WM_NCHITTEST:
if(tray.glyphManager != null) {
//Make sure tha we send our glyphs hit test messages
//over the TrayControls too
Point pt = new Point((short)NativeMethods.Util.LOWORD((int)m.LParam),
(short)NativeMethods.Util.HIWORD((int)m.LParam));
NativeMethods.POINT pt1 = new NativeMethods.POINT();
pt1.x = 0;
pt1.y = 0;
NativeMethods.MapWindowPoints(IntPtr.Zero, Handle, pt1, 1);
pt.Offset(pt1.x, pt1.y);
pt.Offset(this.Location.X, this.Location.Y);//offset the loc of the traycontrol -so now we're in comptray coords
tray.glyphManager.GetHitTest(pt);
}
base.WndProc(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
private class TrayControlAccessibleObject : ControlAccessibleObject
{
ComponentTray tray;
public TrayControlAccessibleObject(TrayControl owner, ComponentTray tray) : base(owner) {
this.tray = tray;
}
private IComponent Component {
get
{
return ((TrayControl)Owner).Component;
}
}
public override AccessibleStates State {
get
{
AccessibleStates state = base.State;
ISelectionService s = (ISelectionService)tray.GetService(typeof(ISelectionService));
if (s != null) {
if (s.GetComponentSelected(Component)) {
state |= AccessibleStates.Selected;
}
if (s.PrimarySelection == Component) {
state |= AccessibleStates.Focused;
}
}
return state;
}
}
}
}
///
///
/// This class inherits from the abstract SelectionUIHandler
/// class to provide a selection UI implementation for the
/// component tray.
///
private class TraySelectionUIHandler : SelectionUIHandler {
private ComponentTray tray;
private Size snapSize = Size.Empty;
///
///
/// Creates a new selection UI handler for the given
/// component tray.
///
public TraySelectionUIHandler(ComponentTray tray) {
this.tray = tray;
snapSize = new Size();
}
///
///
/// Called when the user has started the drag.
///
public override bool BeginDrag(object[] components, SelectionRules rules, int initialX, int initialY) {
bool value = base.BeginDrag(components, rules, initialX, initialY);
tray.SuspendLayout();
return value;
}
///
///
/// Called when the user has completed the drag. The designer should
/// remove any UI feedback it may be providing.
///
public override void EndDrag(object[] components, bool cancel) {
base.EndDrag(components, cancel);
tray.ResumeLayout();
}
///
///
/// Retrieves the base component for the selection handler.
///
protected override IComponent GetComponent() {
return tray;
}
///
///
/// Retrieves the base component's UI control for the selection handler.
///
protected override Control GetControl() {
return tray;
}
///
///
/// Retrieves the UI control for the given component.
///
protected override Control GetControl(IComponent component) {
return TrayControl.FromComponent(component);
}
///
///
/// Retrieves the current grid snap size we should snap objects
/// to.
///
protected override Size GetCurrentSnapSize() {
return snapSize;
}
///
///
/// We use this to request often-used services.
///
protected override object GetService(Type serviceType) {
return tray.GetService(serviceType);
}
///
///
/// Determines if the selection UI handler should attempt to snap
/// objects to a grid.
///
protected override bool GetShouldSnapToGrid() {
return false;
}
///
///
/// Given a rectangle, this updates the dimensions of it
/// with any grid snaps and returns a new rectangle. If
/// no changes to the rectangle's size were needed, this
/// may return the same rectangle.
///
public override Rectangle GetUpdatedRect(Rectangle originalRect, Rectangle dragRect, bool updateSize) {
return dragRect;
}
///
///
/// Asks the handler to set the appropriate cursor
///
public override void SetCursor() {
tray.OnSetCursor();
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Query.cs
- QueryReaderSettings.cs
- HttpCookieCollection.cs
- TimeIntervalCollection.cs
- SqlRewriteScalarSubqueries.cs
- GeneralTransform3DGroup.cs
- LayoutUtils.cs
- IMembershipProvider.cs
- NetCodeGroup.cs
- LifetimeServices.cs
- WebPartDisplayMode.cs
- altserialization.cs
- QueryContinueDragEvent.cs
- EventLogEntryCollection.cs
- HttpCachePolicyElement.cs
- RemoteHelper.cs
- RawStylusInputReport.cs
- XamlToRtfWriter.cs
- KnownTypes.cs
- StandardBindingReliableSessionElement.cs
- DigitalSignatureProvider.cs
- MarkupExtensionSerializer.cs
- AssemblyInfo.cs
- HwndProxyElementProvider.cs
- CommonProperties.cs
- ViewManager.cs
- ListViewGroupConverter.cs
- DataSetMappper.cs
- CodeTypeReference.cs
- DocumentCollection.cs
- PropertyHelper.cs
- DesignerCategoryAttribute.cs
- control.ime.cs
- Menu.cs
- SamlDoNotCacheCondition.cs
- ClockGroup.cs
- HeaderedContentControl.cs
- SevenBitStream.cs
- DataTableCollection.cs
- dtdvalidator.cs
- FrameworkContentElementAutomationPeer.cs
- Window.cs
- LinkedList.cs
- OlePropertyStructs.cs
- NativeCppClassAttribute.cs
- TraceSection.cs
- OledbConnectionStringbuilder.cs
- StylusLogic.cs
- Splitter.cs
- StringPropertyBuilder.cs
- DesignerActionUIService.cs
- WindowsPrincipal.cs
- EdmType.cs
- ApplicationInterop.cs
- SHA256Managed.cs
- MethodToken.cs
- DbModificationClause.cs
- IBuiltInEvidence.cs
- ChannelServices.cs
- TableLayoutSettingsTypeConverter.cs
- CommonObjectSecurity.cs
- CodePageEncoding.cs
- hresults.cs
- StrokeDescriptor.cs
- TypeGeneratedEventArgs.cs
- CommonDialog.cs
- SoapSchemaExporter.cs
- HtmlShim.cs
- HeaderCollection.cs
- Rotation3D.cs
- Shape.cs
- ResourceProviderFactory.cs
- GlyphingCache.cs
- XPathBinder.cs
- Token.cs
- PolicyUtility.cs
- GuidelineCollection.cs
- SerializerDescriptor.cs
- BuildResult.cs
- TdsEnums.cs
- IndexExpression.cs
- TabRenderer.cs
- CapabilitiesRule.cs
- ConstraintEnumerator.cs
- HtmlInputCheckBox.cs
- EraserBehavior.cs
- SubMenuStyleCollection.cs
- SqlConnectionStringBuilder.cs
- SchemaConstraints.cs
- Zone.cs
- CharacterString.cs
- ImageUrlEditor.cs
- XmlSchemaExporter.cs
- CredentialCache.cs
- SelectionEditingBehavior.cs
- TagNameToTypeMapper.cs
- EmbeddedMailObjectsCollection.cs
- SqlTriggerAttribute.cs
- Request.cs
- HtmlFormParameterReader.cs