Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / WinForms / System / WinForms / Design / DesignerUtils.cs / 1 / DesignerUtils.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms.Design {
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Design;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms.Design.Behavior;
using System.Windows.Forms;
using System.Globalization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
///
///
///
/// Contains designer utilities.
///
///
internal static class DesignerUtils {
private static Size minDragSize = Size.Empty;
//brush used to draw a 'hover' state over a designer action glyph
private static SolidBrush hoverBrush = new SolidBrush(Color.FromArgb(50, SystemColors.Highlight));
//brush used to draw the resizeable selection borders around controls/components
private static HatchBrush selectionBorderBrush = new HatchBrush(HatchStyle.Percent50, SystemColors.ControlDarkDark, Color.Transparent);
//Pens and Brushes used via GDI to render our grabhandles
private static IntPtr grabHandleFillBrushPrimary = SafeNativeMethods.CreateSolidBrush(ColorTranslator.ToWin32(SystemColors.Window));
private static IntPtr grabHandleFillBrush = SafeNativeMethods.CreateSolidBrush(ColorTranslator.ToWin32(SystemColors.ControlText));
private static IntPtr grabHandlePenPrimary = SafeNativeMethods.CreatePen(NativeMethods.PS_SOLID, 1, ColorTranslator.ToWin32(SystemColors.ControlText));
private static IntPtr grabHandlePen = SafeNativeMethods.CreatePen(NativeMethods.PS_SOLID, 1,ColorTranslator.ToWin32(SystemColors.Window));
//The box-like image used as the user is dragging comps from the toolbox
//
private static Bitmap boxImage = null;
public static int BOXIMAGESIZE = 16;
// selection border size
//
public static int SELECTIONBORDERSIZE = 1;
// Although the selection border is only 1, we actually want a 3 pixel hittestarea
public static int SELECTIONBORDERHITAREA = 3;
// We want to make sure that the 1 pixel selectionborder is centered on the handles.
// The fact that the border is actually 3 pixels wide works like magic.
// If you draw a picture, then you will see why.
//grabhandle size (diameter)
public static int HANDLESIZE = 7;
//how much should the grabhandle overlap the control
public static int HANDLEOVERLAP = 2;
//we want the selection border to be centered on a grabhandle, so how much do
//we need to offset the border from the control to make that happen
public static int SELECTIONBORDEROFFSET = ((HANDLESIZE - SELECTIONBORDERSIZE)/2) - HANDLEOVERLAP;
//no-resize handle size (diameter)
public static int NORESIZEHANDLESIZE = 5;
//we want the selection border to be centered on a grabhandle, so how much do
//we need to offset the border from the control to make that happen
public static int NORESIZEBORDEROFFSET = ((NORESIZEHANDLESIZE - SELECTIONBORDERSIZE)/2);
//lock handle height
public static int LOCKHANDLEHEIGHT = 9;
//total lock handle width
public static int LOCKHANDLEWIDTH = 7;
//how much should the lockhandle overlap the control
public static int LOCKHANDLEOVERLAP = 2;
//we want the selection border to be centered on the no-resize handle, so calculate how many pixels we need
//to offset the selection border from the control -- since the handle is not square, we need one in each direction
public static int LOCKEDSELECTIONBORDEROFFSET_Y = ((LOCKHANDLEHEIGHT - SELECTIONBORDERSIZE) / 2) - LOCKHANDLEOVERLAP;
public static int LOCKEDSELECTIONBORDEROFFSET_X = ((LOCKHANDLEWIDTH - SELECTIONBORDERSIZE) / 2) - LOCKHANDLEOVERLAP;
// upper rectangle size (diameter)
public static int LOCKHANDLESIZE_UPPER = 5;
// lower rectangle size
public static int LOCKHANDLEHEIGHT_LOWER = 6;
public static int LOCKHANDLEWIDTH_LOWER = 7;
//Offset used when drawing the upper rect of a lock handle
public static int LOCKHANDLEUPPER_OFFSET = (LOCKHANDLEWIDTH_LOWER - LOCKHANDLESIZE_UPPER) / 2;
//Offset used when drawing the lower rect of a lock handle
public static int LOCKHANDLELOWER_OFFSET = (LOCKHANDLEHEIGHT - LOCKHANDLEHEIGHT_LOWER);
public static int CONTAINERGRABHANDLESIZE = 15;
//delay for showing snaplines on keyboard movements
public static int SNAPELINEDELAY = 1000;
//min new row/col style size for the table layout panel
public static int MINIMUMSTYLESIZE = 20;
public static int MINIMUMSTYLEPERCENT = 50;
//min width/height used to create bitmap to paint control into.
public static int MINCONTROLBITMAPSIZE = 1;
//min size for row/col style during a resize drag operation
public static int MINUMUMSTYLESIZEDRAG = 8;
//min # of rows/cols for the tablelayoutpanel when it is newly created
public static int DEFAULTROWCOUNT = 2;
public static int DEFAULTCOLUMNCOUNT = 2;
//size of the col/row grab handle glyphs for teh table layout panel
public static int RESIZEGLYPHSIZE = 4;
//default value for Form padding if it has not been set in the designer (usability study request)
public static int DEFAULTFORMPADDING = 9;
//use these value to signify ANY of the right, top, left, center, or bottom alignments with the ContentAlignment enum.
public static readonly ContentAlignment anyTopAlignment = ContentAlignment.TopLeft | ContentAlignment.TopCenter | ContentAlignment.TopRight;
/* UNUSED: private static readonly ContentAlignment anyBottom = ContentAlignment.BottomLeft | ContentAlignment.BottomCenter | ContentAlignment.BottomRight;*/
public static readonly ContentAlignment anyMiddleAlignment = ContentAlignment.MiddleLeft | ContentAlignment.MiddleCenter | ContentAlignment.MiddleRight;
///
/// Used when the user clicks and drags a toolbox item
/// onto the documentdesigner - this is the small box that
/// is painted beneath the mouse pointer.
///
public static Image BoxImage {
get {
if (boxImage == null) {
boxImage = new Bitmap(BOXIMAGESIZE, BOXIMAGESIZE, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(boxImage)) {
g.FillRectangle(new SolidBrush(SystemColors.InactiveBorder), 0, 0, BOXIMAGESIZE, BOXIMAGESIZE);
g.DrawRectangle(new Pen(SystemColors.ControlDarkDark), 0, 0, BOXIMAGESIZE-1, BOXIMAGESIZE-1);
}
}
return boxImage;
}
}
///
/// Used by Designer action glyphs to render a
/// 'mouse hover' state.
///
public static Brush HoverBrush {
get {
return hoverBrush;
}
}
///
/// Demand created size used to determine how far the user
/// needs to drag the mouse before a drag operation starts.
///
public static Size MinDragSize {
get {
if (minDragSize == Size.Empty) {
Size minDrag = SystemInformation.DragSize;
Size minDblClick = SystemInformation.DoubleClickSize;
minDragSize.Width = Math.Max(minDrag.Width, minDblClick.Width);
minDragSize.Height = Math.Max(minDrag.Height, minDblClick.Height);
}
return minDragSize;
}
}
public static Point LastCursorPoint {
get {
int lastXY = SafeNativeMethods.GetMessagePos();
return new Point(NativeMethods.Util.SignedLOWORD(lastXY),NativeMethods.Util.SignedHIWORD(lastXY)) ;
}
}
// Recreate the brushes - behaviorservice calls this when the user preferences changes
public static void SyncBrushes() {
hoverBrush.Dispose();
hoverBrush = new SolidBrush(Color.FromArgb(50, SystemColors.Highlight));
selectionBorderBrush.Dispose();
selectionBorderBrush = new HatchBrush(HatchStyle.Percent50, SystemColors.ControlDarkDark, Color.Transparent);
SafeNativeMethods.DeleteObject(new HandleRef(null, grabHandleFillBrushPrimary));
grabHandleFillBrushPrimary = SafeNativeMethods.CreateSolidBrush(ColorTranslator.ToWin32(SystemColors.Window));
SafeNativeMethods.DeleteObject(new HandleRef(null, grabHandleFillBrush));
grabHandleFillBrush = SafeNativeMethods.CreateSolidBrush(ColorTranslator.ToWin32(SystemColors.ControlText));
SafeNativeMethods.DeleteObject(new HandleRef(null, grabHandlePenPrimary));
grabHandlePenPrimary = SafeNativeMethods.CreatePen(NativeMethods.PS_SOLID, 1, ColorTranslator.ToWin32(SystemColors.ControlText));
SafeNativeMethods.DeleteObject(new HandleRef(null, grabHandlePen));
grabHandlePen = SafeNativeMethods.CreatePen(NativeMethods.PS_SOLID, 1,ColorTranslator.ToWin32(SystemColors.Window));
}
///
/// Draws a ControlDarkDark border around the given image.
///
private static void DrawDragBorder(Graphics g, Size imageSize, int borderSize, Color backColor) {
Pen pen = SystemPens.ControlDarkDark;
if (backColor != Color.Empty && backColor.GetBrightness() < .5) {
pen = SystemPens.ControlLight;
}
//draw a border w/o the corners connecting
g.DrawLine(pen, 1, 0, imageSize.Width -2, 0);
g.DrawLine(pen, 1, imageSize.Height -1, imageSize.Width -2, imageSize.Height - 1);
g.DrawLine(pen, 0, 1, 0, imageSize.Height-2);
g.DrawLine(pen, imageSize.Width -1, 1, imageSize.Width - 1, imageSize.Height - 2);
//loop through drawing inner-rects until we get the proper thickness
for (int i =1; i < borderSize; i ++) {
g.DrawRectangle(pen, i,i, imageSize.Width - (2 + i), imageSize.Height -(2 + i));
}
}
///
/// Used for drawing the borders around controls that are being resized
///
public static void DrawResizeBorder(Graphics g, Region resizeBorder, Color backColor) {
Brush brush = SystemBrushes.ControlDarkDark;
if (backColor != Color.Empty && backColor.GetBrightness() < .5) {
brush = SystemBrushes.ControlLight;
}
g.FillRegion(brush, resizeBorder);
}
///
/// Used for drawing the frame when doing a mouse drag
///
public static void DrawFrame(Graphics g, Region resizeBorder, FrameStyle style, Color backColor) {
Brush brush;
Color color = SystemColors.ControlDarkDark;
if (backColor != Color.Empty && backColor.GetBrightness() < .5) {
color = SystemColors.ControlLight;
}
switch (style) {
case FrameStyle.Dashed:
brush = new HatchBrush(HatchStyle.Percent50, color, Color.Transparent);
break;
case FrameStyle.Thick:
default:
brush = new SolidBrush(color);
break;
}
g.FillRegion(brush, resizeBorder);
}
///
/// Used for drawing the grabhandles around sizeable selected controls and components.
///
public static void DrawGrabHandle(Graphics graphics, Rectangle bounds, bool isPrimary, Glyph glyph) {
IntPtr hDC = graphics.GetHdc();
try {
//set our pen and brush based on primary selection
IntPtr oldBrush = SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, isPrimary ? grabHandleFillBrushPrimary : grabHandleFillBrush));
IntPtr oldPen = SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, isPrimary ? grabHandlePenPrimary: grabHandlePen));
//draw our rounded rect grabhandle
SafeNativeMethods.RoundRect(new HandleRef(glyph, hDC), bounds.Left, bounds.Top, bounds.Right, bounds.Bottom, 2, 2);
//restore old pen and brush
SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, oldBrush));
SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, oldPen));
}
finally {
graphics.ReleaseHdcInternal(hDC);
}
}
///
/// Used for drawing the no-resize handle for non-resizeable selected controls and components.
///
public static void DrawNoResizeHandle(Graphics graphics, Rectangle bounds, bool isPrimary, Glyph glyph) {
IntPtr hDC = graphics.GetHdc();
try {
//set our pen and brush based on primary selection
IntPtr oldBrush = SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, isPrimary ? grabHandleFillBrushPrimary : grabHandleFillBrush));
IntPtr oldPen = SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, grabHandlePenPrimary));
//draw our rect no-resize handle
SafeNativeMethods.Rectangle(new HandleRef(glyph, hDC), bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
//restore old pen and brush
SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, oldBrush));
SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, oldPen));
}
finally {
graphics.ReleaseHdcInternal(hDC);
}
}
///
/// Used for drawing the lock handle for locked selected controls and components.
///
public static void DrawLockedHandle(Graphics graphics, Rectangle bounds, bool isPrimary, Glyph glyph) {
IntPtr hDC = graphics.GetHdc();
try {
IntPtr oldPen = SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, grabHandlePenPrimary));
// Upper rect - upper rect is always filled with the primary brush
IntPtr oldBrush = SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, grabHandleFillBrushPrimary));
SafeNativeMethods.RoundRect(new HandleRef(glyph, hDC), bounds.Left+LOCKHANDLEUPPER_OFFSET, bounds.Top,
bounds.Left + LOCKHANDLEUPPER_OFFSET + LOCKHANDLESIZE_UPPER, bounds.Top + LOCKHANDLESIZE_UPPER,2,2);
// Lower rect - its fillbrush depends on the primary selection
SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, isPrimary ? grabHandleFillBrushPrimary : grabHandleFillBrush));
SafeNativeMethods.Rectangle(new HandleRef(glyph, hDC), bounds.Left, bounds.Top+LOCKHANDLELOWER_OFFSET, bounds.Right, bounds.Bottom);
//restore old pen and brush
SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, oldBrush));
SafeNativeMethods.SelectObject(new HandleRef(glyph, hDC), new HandleRef(glyph, oldPen));
}
finally {
graphics.ReleaseHdcInternal(hDC);
}
}
///
/// Uses the lockedBorderBrush to draw a 'locked' border on the
/// given Graphics at the specified bounds.
///
public static void DrawSelectionBorder(Graphics graphics, Rectangle bounds) {
graphics.FillRectangle(selectionBorderBrush, bounds);
}
///
/// Used to generate an image that represents the given control. First, this method will call
/// the 'GenerateSnapShotWithWM_PRINT' method on the control. If we believe that this
/// method did not return us a valid image (caused by some comctl/ax controls not properly
/// responding to a wm_print) then we will attempt to do a bitblt of the control instead.
///
public static void GenerateSnapShot(Control control, ref Image image, int borderSize, double opacity, Color backColor) {
//GenerateSnapShot will return a boolean value indicating if the control
//returned an image or not...
if (!GenerateSnapShotWithWM_PRINT(control, ref image)) {
//here, we failed to get the image on wmprint - so try bitblt
GenerateSnapShotWithBitBlt(control, ref image) ;
//if we still failed - we'll just fall though, put up a border around an empty area and
//call it good enough
}
//set the opacity
if (opacity < 1.0 && opacity > 0.0) {
//make this semi-transparent
SetImageAlpha((Bitmap)image, opacity);
}
//draw a drag border around this thing
if (borderSize > 0) {
using (Graphics g = Graphics.FromImage(image)) {
DrawDragBorder(g, image.Size, borderSize, backColor);
}
}
}
///
/// Retrieves the width and height of a selection border grab handle.
/// Designers may need this to properly position their user interfaces.
///
public static Size GetAdornmentDimensions(AdornmentType adornmentType) {
switch (adornmentType) {
case AdornmentType.GrabHandle:
return new Size(HANDLESIZE, HANDLESIZE);
case AdornmentType.ContainerSelector:
case AdornmentType.Maximum:
return new Size(CONTAINERGRABHANDLESIZE, CONTAINERGRABHANDLESIZE);
}
return new Size(0, 0);
}
public static bool UseSnapLines(IServiceProvider provider) {
bool useSnapLines = true;
object optionValue = null;
DesignerOptionService options = provider.GetService(typeof(DesignerOptionService)) as DesignerOptionService;
if (options != null) {
PropertyDescriptor snaplinesProp = options.Options.Properties["UseSnapLines"];
if (snaplinesProp != null) {
optionValue = snaplinesProp.GetValue(null);
}
}
if (optionValue != null && optionValue is bool) {
useSnapLines = (bool)optionValue;
}
return useSnapLines;
}
public static object GetOptionValue(IServiceProvider provider, string name) {
object optionValue = null;
if (provider != null) {
DesignerOptionService desOpts = provider.GetService(typeof(DesignerOptionService)) as DesignerOptionService;
if (desOpts != null) {
PropertyDescriptor prop = desOpts.Options.Properties[name];
if (prop != null) {
optionValue = prop.GetValue(null);
}
}
else {
IDesignerOptionService optSvc = provider.GetService(typeof(IDesignerOptionService)) as IDesignerOptionService;
if (optSvc != null) {
optionValue = optSvc.GetOptionValue("WindowsFormsDesigner\\General", name);
}
}
}
return optionValue;
}
///
/// Uses BitBlt to geta snapshot of the control
///
public static void GenerateSnapShotWithBitBlt(Control control, ref Image image) {
//get the DC's and create our image
HandleRef hWnd = new HandleRef(control, control.Handle);
IntPtr controlDC = UnsafeNativeMethods.GetDC(hWnd);
image = new Bitmap(Math.Max(control.Width, MINCONTROLBITMAPSIZE), Math.Max(control.Height, MINCONTROLBITMAPSIZE), System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics gDest = Graphics.FromImage(image)) {
//VSWhidbey #378593
if (control.BackColor == Color.Transparent) {
gDest.Clear(SystemColors.Control);
}
IntPtr destDC = gDest.GetHdc();
//perform our bitblit operation to push the image into the dest bitmap
SafeNativeMethods.BitBlt(destDC, 0, 0, image.Width, image.Height, controlDC, 0, 0, 0xcc0020/*RasterOp.SOURCE*/);
//clean up all our handles and what not
gDest.ReleaseHdc(destDC);
}
}
///
/// Uses WM_PRINT to get a snapshot of the control. This method will return true if the control
// properly responded to the wm_print message.
///
public static bool GenerateSnapShotWithWM_PRINT(Control control, ref Image image) {
IntPtr hWnd = control.Handle;
image = new Bitmap(Math.Max(control.Width, MINCONTROLBITMAPSIZE), Math.Max(control.Height, MINCONTROLBITMAPSIZE), System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
//VSWhidbey #378593
//Have to do this BEFORE we set the testcolor.
if (control.BackColor == Color.Transparent) {
using (Graphics g = Graphics.FromImage(image)) {
g.Clear(SystemColors.Control);
}
}
//To validate that the control responded to the wm_print message, we pre-populate the
//bitmap with a colored center pixel. We assume that the control _did not_ respond to
//wm_print if these center pixel is still this value
Color testColor = Color.FromArgb(255,252,186,238);
((Bitmap)image).SetPixel(image.Width /2, image.Height /2, testColor);
using (Graphics g = Graphics.FromImage(image)) {
IntPtr hDc = g.GetHdc();
//send the actual wm_print message
NativeMethods.SendMessage(hWnd, NativeMethods.WM_PRINT, hDc, (IntPtr)(NativeMethods.PRF_CHILDREN | NativeMethods.PRF_CLIENT | NativeMethods.PRF_ERASEBKGND | NativeMethods.PRF_NONCLIENT));
g.ReleaseHdc(hDc);
}
//now check to see if our center pixel was cleared, if not then our wm_print failed
if (((Bitmap)image).GetPixel(image.Width /2, image.Height / 2).Equals(testColor)) {
//wm_print failed
return false;
}
return true;
}
///
/// Used by the Glyphs and ComponentTray to determine the Top, Left, Right, Bottom and Body
/// bound rects related to their original bounds and bordersize.
///
public static Rectangle GetBoundsForSelectionType(Rectangle originalBounds, SelectionBorderGlyphType type, int borderSize) {
Rectangle bounds = Rectangle.Empty;
switch (type) {
case SelectionBorderGlyphType.Top:
bounds = new Rectangle(originalBounds.Left - borderSize, originalBounds.Top - borderSize, originalBounds.Width + 2*borderSize, borderSize);
break;
case SelectionBorderGlyphType.Bottom:
bounds = new Rectangle(originalBounds.Left - borderSize, originalBounds.Bottom, originalBounds.Width + 2*borderSize, borderSize);
break;
case SelectionBorderGlyphType.Left:
bounds = new Rectangle(originalBounds.Left - borderSize, originalBounds.Top - borderSize, borderSize, originalBounds.Height + 2*borderSize);
break;
case SelectionBorderGlyphType.Right:
bounds = new Rectangle(originalBounds.Right, originalBounds.Top - borderSize, borderSize, originalBounds.Height + 2*borderSize);
break;
case SelectionBorderGlyphType.Body:
bounds = originalBounds;
break;
}
return bounds;
}
///
/// Used by the Glyphs and ComponentTray to determine the Top, Left, Right, Bottom and Body
/// bound rects related to their original bounds and bordersize.
///
/// Offset - how many pixels between the border glyph and the control
///
private static Rectangle GetBoundsForSelectionType(Rectangle originalBounds, SelectionBorderGlyphType type, int bordersize, int offset) {
Rectangle bounds = GetBoundsForSelectionType(originalBounds, type, bordersize);
if (offset != 0) {
switch (type) {
case SelectionBorderGlyphType.Top:
bounds.Offset(-offset, -offset);
bounds.Width += 2*offset;
break;
case SelectionBorderGlyphType.Bottom:
bounds.Offset(-offset, offset);
bounds.Width += 2*offset;
break;
case SelectionBorderGlyphType.Left:
bounds.Offset(-offset, -offset);
bounds.Height += 2*offset;
break;
case SelectionBorderGlyphType.Right:
bounds.Offset(offset, -offset);
bounds.Height += 2*offset;
break;
case SelectionBorderGlyphType.Body:
bounds = originalBounds;
break;
}
}
return bounds;
}
///
/// Used by the Glyphs and ComponentTray to determine the Top, Left, Right, Bottom and Body
/// bound rects related to their original bounds and bordersize.
///
public static Rectangle GetBoundsForSelectionType(Rectangle originalBounds, SelectionBorderGlyphType type) {
return GetBoundsForSelectionType(originalBounds, type, DesignerUtils.SELECTIONBORDERSIZE, SELECTIONBORDEROFFSET);
}
public static Rectangle GetBoundsForNoResizeSelectionType(Rectangle originalBounds, SelectionBorderGlyphType type) {
return GetBoundsForSelectionType(originalBounds, type, DesignerUtils.SELECTIONBORDERSIZE, NORESIZEBORDEROFFSET);
}
///
/// Identifes where the text baseline for our control which should be
/// based on bounds, padding, font, and textalignment.
///
public static int GetTextBaseline(Control ctrl, ContentAlignment alignment) {
//determine the actual client area we are working in (w/padding)
Rectangle face = ctrl.ClientRectangle;
//get the font metrics via gdi
int fontAscent = 0;
int fontHeight = 0;
using (Graphics g = ctrl.CreateGraphics()) {
IntPtr dc = g.GetHdc();
IntPtr hFont = ctrl.Font.ToHfont();
IntPtr hFontOld;
try {
hFontOld = SafeNativeMethods.SelectObject(new HandleRef(ctrl, dc), new HandleRef(ctrl, hFont));
NativeMethods.TEXTMETRIC metrics = new NativeMethods.TEXTMETRIC();
SafeNativeMethods.GetTextMetrics(new HandleRef(ctrl, dc), metrics);
//add the font ascent to the baseline
fontAscent = metrics.tmAscent + 1;
fontHeight = metrics.tmHeight;
SafeNativeMethods.SelectObject(new HandleRef(ctrl, dc), new HandleRef(ctrl, hFontOld));
}
finally {
SafeNativeMethods.DeleteObject(new HandleRef(ctrl.Font, hFont));
g.ReleaseHdc(dc);
}
}
//now add it all up
if ((alignment & anyTopAlignment) != 0) {
return face.Top + fontAscent;
}
else if ((alignment & anyMiddleAlignment) != 0) {
return face.Top + (face.Height / 2) - (fontHeight/2) + fontAscent;
}
else {
return face.Bottom - fontHeight + fontAscent;
}
}
///
/// Called by the ParentControlDesigner when creating a new
/// control - this will update the new control's bounds with the
/// proper toolbox/snapline information that has been stored
/// off
//
/// isMirrored - Is the ParentControlDesigner mirrored? If so, we need
/// to offset for that. This is because all snapline stuff is done
/// using a LTR coordinate system
///
public static Rectangle GetBoundsFromToolboxSnapDragDropInfo(ToolboxSnapDragDropEventArgs e, Rectangle originalBounds, bool isMirrored) {
Rectangle newBounds = originalBounds;
//this should always be the case 'cause we don't
//create 'e' unless we have an offset
if (e.Offset != Point.Empty) {
//snap either up or down depending on offset
if ((e.SnapDirections & ToolboxSnapDragDropEventArgs.SnapDirection.Top) != 0) {
newBounds.Y += e.Offset.Y;//snap to top - so move up our bounds
}
else if ((e.SnapDirections & ToolboxSnapDragDropEventArgs.SnapDirection.Bottom) != 0) {
newBounds.Y = originalBounds.Y - originalBounds.Height + e.Offset.Y;
}
//snap either left or right depending on offset
if (!isMirrored) {
if ((e.SnapDirections & ToolboxSnapDragDropEventArgs.SnapDirection.Left) != 0) {
newBounds.X += e.Offset.X;//snap to left-
}
else if ((e.SnapDirections & ToolboxSnapDragDropEventArgs.SnapDirection.Right) != 0) {
newBounds.X = originalBounds.X - originalBounds.Width + e.Offset.X;
}
}
else {
// ParentControlDesigner is RTL, that means that the origin is upper-right, not upper-left
if ((e.SnapDirections & ToolboxSnapDragDropEventArgs.SnapDirection.Left) != 0) {
// e.Offset.X is negative when we snap to left
newBounds.X = originalBounds.X - originalBounds.Width - e.Offset.X;
}
else if ((e.SnapDirections & ToolboxSnapDragDropEventArgs.SnapDirection.Right) != 0) {
// e.Offset.X is positive when we snao to right
newBounds.X -= e.Offset.X;
}
}
}
return newBounds;
}
///
/// Determine a unique site name for a component, starting from a base name. Return value
/// should be passed into the Container.Add() method. If null is returned, this just means
/// "let container generate a default name based on component type".
///
public static String GetUniqueSiteName(IDesignerHost host, String name) {
// Item has no explicit name, so let host generate a type-based name instead
if (String.IsNullOrEmpty(name)) {
return null;
}
// Get the name creation service from the designer host
INameCreationService nameCreationService = (INameCreationService) host.GetService(typeof(INameCreationService));
if (nameCreationService == null) {
return null;
}
// See if desired name is already in use
object existingComponent = host.Container.Components[name];
if (existingComponent == null) {
// Name is not in use - but make sure that it contains valid characters before using it!
return nameCreationService.IsValidName(name) ? name : null;
}
else {
// Name is in use (and therefore basically valid), so start appending numbers
String nameN = name;
for (int i = 1; !nameCreationService.IsValidName(nameN); ++i) {
nameN = name + i.ToString(CultureInfo.InvariantCulture);
}
return nameN;
}
}
///
/// Applies the given opacity to the image
///
private static unsafe void SetImageAlpha(Bitmap b, double opacity)
{
if (opacity == 1.0)
{
return;
}
byte[] alphaValues = new byte[256];
// precompute all the possible alpha values
// into an array so we don't do multiplications in the loop
//
for (int i = 0; i < alphaValues.Length; i++)
{
alphaValues[i] = (byte)(i * opacity);
}
// lock the data in ARGB format.
//
BitmapData data = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
try
{
// compute the number of pixels that we're modifying.
//
int pixels = data.Height * data.Width;
int* pPixels = (int*)data.Scan0;
// have the compiler figure out where to stop for us
// by doing the pointer math
//
byte* maxAddr = (byte*)(pPixels + pixels);
// now run through the pixels only modifyng the A byte,
//
for (byte* addr = (byte*)(pPixels)+3; addr < maxAddr; addr += 4)
{
// the new value is just an index into our precomputed
// value array from above.
//
*addr = alphaValues[*addr];
}
}
finally
{
// now, apply the data back to the bitmap.
//
b.UnlockBits(data);
}
}
///
/// This method removes types that are generics from the input collection
///
public static ICollection FilterGenericTypes(ICollection types) {
if (types == null || types.Count == 0)
return types;
//now we get each Type and add it to the destination collection if its not a generic
ArrayList final = new ArrayList(types.Count);
foreach (Type t in types) {
if (!t.ContainsGenericParameters) {
final.Add(t);
}
}
return final;
}
///
/// Checks the given container, substituting any nested container with its owning container.
/// Ensures that a SplitterPanel in a SplitContainer returns the same container as other form
/// components, since SplitContainer sites its two SplitterPanels inside a nested container.
///
public static IContainer CheckForNestedContainer(IContainer container) {
NestedContainer nestedContainer = container as NestedContainer;
if (nestedContainer != null) {
return nestedContainer.Owner.Site.Container;
}
else {
return container;
}
}
///
///
/// Used to create copies of the objects that we are dragging in a drag operation
///
///
public static ICollection CopyDragObjects(ICollection objects, IServiceProvider svcProvider) {
if (objects == null || svcProvider == null) {
Debug.Fail("Invalid parameter passed to DesignerUtils.CopyObjects.");
return null;
}
Cursor oldCursor = Cursor.Current;
try {
Cursor.Current = Cursors.WaitCursor;
ComponentSerializationService css = svcProvider.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
IDesignerHost host = svcProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
Debug.Assert(css != null, "No component serialization service -- we cannot copy the objects");
Debug.Assert(host != null, "No host -- we cannot copy the objects");
if (css != null && host != null) {
SerializationStore store = null;
store = css.CreateStore();
// Get all the objects, meaning we want the children too
ICollection copyObjects = GetCopySelection(objects, host);
// The serialization service does not (yet) handle serializing collections
foreach (IComponent comp in copyObjects) {
css.Serialize(store, comp);
}
store.Close();
copyObjects = css.Deserialize(store);
// Now, copyObjects contains a flattened list of all the controls contained
// in the original drag objects, that's not what we want to return.
// We only want to return the root drag objects, so that the caller gets
// an identical copy - identical in terms of objects.Count
ArrayList newObjects = new ArrayList(objects.Count);
foreach (IComponent comp in copyObjects) {
Control c = comp as Control;
if (c != null && c.Parent == null) {
newObjects.Add(comp);
}
else if (c == null) { // this happens when we are dragging a toolstripitem
//
ToolStripItem item = comp as ToolStripItem;
if (item != null && item.GetCurrentParent() == null) {
newObjects.Add(comp);
}
}
}
Debug.Assert(newObjects.Count == objects.Count, "Why is the count of the copied objects not the same?");
return newObjects;
}
}
finally {
Cursor.Current = oldCursor;
}
return null;
}
private static ICollection GetCopySelection(ICollection objects, IDesignerHost host) {
if (objects == null || host == null) {
return null;
}
ArrayList copySelection = new ArrayList();
foreach (IComponent comp in objects) {
copySelection.Add(comp);
GetAssociatedComponents(comp, host, copySelection);
}
return copySelection;
}
internal static void GetAssociatedComponents(IComponent component, IDesignerHost host, ArrayList list) {
if (host == null) {
return;
}
ComponentDesigner designer = host.GetDesigner(component) as ComponentDesigner;
if (designer == null) {
return;
}
foreach (IComponent childComp in designer.AssociatedComponents) {
if (childComp.Site != null)
{
list.Add(childComp);
GetAssociatedComponents(childComp, host, list);
}
}
}
}
}
// 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
- CodeDirectiveCollection.cs
- UnsafeNativeMethods.cs
- JumpTask.cs
- ContainerVisual.cs
- Property.cs
- AnchoredBlock.cs
- QueryConverter.cs
- UnsafeNativeMethods.cs
- PropertyChangeTracker.cs
- DataGridViewRowStateChangedEventArgs.cs
- Point3DKeyFrameCollection.cs
- ViewManager.cs
- DockPanel.cs
- Model3DCollection.cs
- ExceptionUtil.cs
- XmlUtilWriter.cs
- DynamicObject.cs
- wmiprovider.cs
- COM2IDispatchConverter.cs
- StorageEntitySetMapping.cs
- BrowserCapabilitiesFactory.cs
- PageBreakRecord.cs
- GenerateScriptTypeAttribute.cs
- ImageAutomationPeer.cs
- DataKeyArray.cs
- ClientUrlResolverWrapper.cs
- RegexCode.cs
- HostedTransportConfigurationBase.cs
- DataViewManagerListItemTypeDescriptor.cs
- BinaryReader.cs
- XPathNode.cs
- DataGridViewCellToolTipTextNeededEventArgs.cs
- ProcessInputEventArgs.cs
- FaultFormatter.cs
- WebPartAddingEventArgs.cs
- QueryAccessibilityHelpEvent.cs
- PartialTrustHelpers.cs
- Utils.cs
- ListViewItemMouseHoverEvent.cs
- DefaultObjectMappingItemCollection.cs
- ResourceDisplayNameAttribute.cs
- SQLInt32.cs
- ExtensionElementCollection.cs
- __ConsoleStream.cs
- ListQueryResults.cs
- FileLoadException.cs
- FixedPage.cs
- AsyncOperationManager.cs
- DataGridViewHitTestInfo.cs
- FontEmbeddingManager.cs
- DesigntimeLicenseContextSerializer.cs
- GradientStop.cs
- SQLMoney.cs
- DataBoundLiteralControl.cs
- XPathDocumentIterator.cs
- ResizeGrip.cs
- ProxyHwnd.cs
- SymbolUsageManager.cs
- MessageBox.cs
- SmiContextFactory.cs
- Quad.cs
- StructuredProperty.cs
- WarningException.cs
- ExpressionReplacer.cs
- Grant.cs
- ViewStateException.cs
- FaultConverter.cs
- EllipticalNodeOperations.cs
- GetResponse.cs
- EventItfInfo.cs
- BitmapScalingModeValidation.cs
- HwndProxyElementProvider.cs
- ObjectCloneHelper.cs
- SecurityContextSecurityTokenResolver.cs
- PropertyToken.cs
- HttpHandlerAction.cs
- FullTextBreakpoint.cs
- ServiceNameElement.cs
- GridViewCancelEditEventArgs.cs
- DataSpaceManager.cs
- OdbcTransaction.cs
- TreeNodeCollection.cs
- XhtmlBasicFormAdapter.cs
- ImageDrawing.cs
- PostBackOptions.cs
- BidPrivateBase.cs
- WebBrowserPermission.cs
- TranslateTransform3D.cs
- InvokeMethodActivity.cs
- DataGridViewToolTip.cs
- WebPartConnectionsConnectVerb.cs
- CookieParameter.cs
- TreeWalkHelper.cs
- ListViewSelectEventArgs.cs
- FrameworkElementFactoryMarkupObject.cs
- SignatureDescription.cs
- CodeBlockBuilder.cs
- DataContext.cs
- PageRequestManager.cs
- ByeMessage11.cs