/*******************************************************************************
* Copyright(c) 2014 DongkeSoft All rights reserved. / Confidential
* 类的信息:
* 1.程序名称:NativeMethods.cs
* 2.功能描述:
* 编辑履历:
* 作者 日期 版本 修改内容
* 陈晓野 2014/09/04 1.00 新建
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using VS = System.Windows.Forms.VisualStyles;
/*
Base class for custom tooltips.
Office-2007-like tooltip class.
*/
namespace Dongke.IBOSS.PRD.Basics.BaseControls
{
///
/// CodeProject.com "Simple pop-up control" "http://www.codeproject.com/cs/miscctrl/simplepopup.asp".
/// Represents a pop-up window.
///
[ToolboxItem(false)]
//[CLSCompliant(true)]
public partial class Popup : ToolStripDropDown
{
#region " Fields & Properties "
private Control content;
///
/// Gets the content of the pop-up.
///
public Control Content
{
get { return content; }
}
private bool fade;
///
/// Gets a value indicating whether the uses the fade effect.
///
/// true if pop-up uses the fade effect; otherwise, false.
/// To use the fade effect, the FocusOnOpen property also has to be set to true.
public bool UseFadeEffect
{
get { return fade; }
set
{
if (fade == value) return;
fade = value;
}
}
private bool focusOnOpen = true;
///
/// Gets or sets a value indicating whether to focus the content after the pop-up has been opened.
///
/// true if the content should be focused after the pop-up has been opened; otherwise, false.
/// If the FocusOnOpen property is set to false, then pop-up cannot use the fade effect.
public bool FocusOnOpen
{
get { return focusOnOpen; }
set { focusOnOpen = value; }
}
private bool acceptAlt = true;
///
/// Gets or sets a value indicating whether presing the alt key should close the pop-up.
///
/// true if presing the alt key does not close the pop-up; otherwise, false.
public bool AcceptAlt
{
get { return acceptAlt; }
set { acceptAlt = value; }
}
private Popup ownerPopup;
private Popup childPopup;
private bool _resizable;
private bool resizable;
///
/// Gets or sets a value indicating whether this is resizable.
///
/// true if resizable; otherwise, false.
public bool Resizable
{
get { return resizable && _resizable; }
set { resizable = value; }
}
private ToolStripControlHost host;
private Size minSize;
///
/// Gets or sets the size that is the lower limit that can specify.
///
/// An ordered pair of type representing the width and height of a rectangle.
public new Size MinimumSize
{
get { return minSize; }
set { minSize = value; }
}
private Size maxSize;
///
/// Gets or sets the size that is the upper limit that can specify.
///
/// An ordered pair of type representing the width and height of a rectangle.
public new Size MaximumSize
{
get { return maxSize; }
set { maxSize = value; }
}
///
/// Gets parameters of a new window.
///
/// An object of type used when creating a new window.
protected override CreateParams CreateParams
{
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= NativeMethods.WS_EX_NOACTIVATE;
return cp;
}
}
#endregion
#region " Constructors "
///
/// Initializes a new instance of the class.
///
/// The content of the pop-up.
///
/// Pop-up will be disposed immediately after disposion of the content control.
///
/// is null.
public Popup(Control content)
{
if (content == null)
{
throw new ArgumentNullException("content");
}
this.content = content;
this.fade = SystemInformation.IsMenuAnimationEnabled && SystemInformation.IsMenuFadeEnabled;
this._resizable = true;
InitializeComponent();
AutoSize = false;
DoubleBuffered = true;
ResizeRedraw = true;
host = new ToolStripControlHost(content);
Padding = Margin = host.Padding = host.Margin = Padding.Empty;
MinimumSize = content.MinimumSize;
content.MinimumSize = content.Size;
MaximumSize = content.MaximumSize;
content.MaximumSize = content.Size;
Size = content.Size;
content.Location = Point.Empty;
Items.Add(host);
content.Disposed += delegate(object sender, EventArgs e)
{
content = null;
Dispose(true);
};
content.RegionChanged += delegate(object sender, EventArgs e)
{
UpdateRegion();
};
content.Paint += delegate(object sender, PaintEventArgs e)
{
PaintSizeGrip(e);
};
UpdateRegion();
}
#endregion
#region " Methods "
///
/// Processes a dialog box key.
///
/// One of the values that represents the key to process.
///
/// true if the key was processed by the control; otherwise, false.
///
protected override bool ProcessDialogKey(Keys keyData)
{
if (acceptAlt && ((keyData & Keys.Alt) == Keys.Alt)) return false;
return base.ProcessDialogKey(keyData);
}
///
/// Updates the pop-up region.
///
protected void UpdateRegion()
{
if (this.Region != null)
{
this.Region.Dispose();
this.Region = null;
}
if (content.Region != null)
{
this.Region = content.Region.Clone();
}
}
///
/// Shows pop-up window below the specified control.
///
/// The control below which the pop-up will be shown.
///
/// When there is no space below the specified control, the pop-up control is shown above it.
///
/// is null.
public void Show(Control control)
{
if (control == null)
{
throw new ArgumentNullException("control");
}
SetOwnerItem(control);
Show(control, control.ClientRectangle);
}
///
/// Shows pop-up window below the specified area of specified control.
///
/// The control used to compute screen location of specified area.
/// The area of control below which the pop-up will be shown.
///
/// When there is no space below specified area, the pop-up control is shown above it.
///
/// is null.
public void Show(Control control, Rectangle area)
{
if (control == null)
{
throw new ArgumentNullException("control");
}
SetOwnerItem(control);
resizableTop = resizableRight = false;
Point location = control.PointToScreen(new Point(area.Left, area.Top + area.Height));
Rectangle screen = Screen.FromControl(control).WorkingArea;
if (location.X + Size.Width > (screen.Left + screen.Width))
{
resizableRight = true;
location.X = (screen.Left + screen.Width) - Size.Width;
}
if (location.Y + Size.Height > (screen.Top + screen.Height))
{
resizableTop = true;
location.Y -= Size.Height + area.Height;
}
location = control.PointToClient(location);
Show(control, location, ToolStripDropDownDirection.BelowRight);
}
private const int frames = 1;
private const int totalduration = 0; // ML : 2007-11-05 : was 100 but caused a flicker.
private const int frameduration = totalduration / frames;
///
/// Adjusts the size of the owner to accommodate the if the owner is currently displayed, or clears and resets active child controls of the if the is not currently displayed.
///
/// true if the owner is currently displayed; otherwise, false.
protected override void SetVisibleCore(bool visible)
{
double opacity = Opacity;
if (visible && fade && focusOnOpen) Opacity = 0;
base.SetVisibleCore(visible);
if (!visible || !fade || !focusOnOpen) return;
for (int i = 1; i <= frames; i++)
{
if (i > 1)
{
System.Threading.Thread.Sleep(frameduration);
}
Opacity = opacity * (double)i / (double)frames;
}
Opacity = opacity;
}
private bool resizableTop;
private bool resizableRight;
private void SetOwnerItem(Control control)
{
if (control == null)
{
return;
}
if (control is Popup)
{
Popup popupControl = control as Popup;
ownerPopup = popupControl;
ownerPopup.childPopup = this;
OwnerItem = popupControl.Items[0];
return;
}
if (control.Parent != null)
{
SetOwnerItem(control.Parent);
}
}
///
/// Raises the event.
///
/// An that contains the event data.
protected override void OnSizeChanged(EventArgs e)
{
content.MinimumSize = Size;
content.MaximumSize = Size;
content.Size = Size;
content.Location = Point.Empty;
base.OnSizeChanged(e);
}
///
/// Raises the event.
///
/// A that contains the event data.
protected override void OnOpening(CancelEventArgs e)
{
if (content.IsDisposed || content.Disposing)
{
e.Cancel = true;
return;
}
UpdateRegion();
base.OnOpening(e);
}
///
/// Raises the event.
///
/// An that contains the event data.
protected override void OnOpened(EventArgs e)
{
if (ownerPopup != null)
{
ownerPopup._resizable = false;
}
if (focusOnOpen)
{
content.Focus();
}
base.OnOpened(e);
}
protected override void OnClosed(ToolStripDropDownClosedEventArgs e)
{
if (ownerPopup != null)
{
ownerPopup._resizable = true;
}
base.OnClosed(e);
}
public DateTime LastClosedTimeStamp = DateTime.Now;
protected override void OnVisibleChanged(EventArgs e)
{
if (Visible == false)
LastClosedTimeStamp = DateTime.Now;
base.OnVisibleChanged(e);
}
#endregion
#region " Resizing Support "
///
/// Processes Windows messages.
///
/// The Windows to process.
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
if (InternalProcessResizing(ref m, false))
{
return;
}
base.WndProc(ref m);
}
///
/// Processes the resizing messages.
///
/// The message.
/// true, if the WndProc method from the base class shouldn't be invoked.
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public bool ProcessResizing(ref Message m)
{
return InternalProcessResizing(ref m, true);
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
private bool InternalProcessResizing(ref Message m, bool contentControl)
{
if (m.Msg == NativeMethods.WM_NCACTIVATE && m.WParam != IntPtr.Zero && childPopup != null && childPopup.Visible)
{
childPopup.Hide();
}
if (!Resizable)
{
return false;
}
if (m.Msg == NativeMethods.WM_NCHITTEST)
{
return OnNcHitTest(ref m, contentControl);
}
else if (m.Msg == NativeMethods.WM_GETMINMAXINFO)
{
return OnGetMinMaxInfo(ref m);
}
return false;
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
private bool OnGetMinMaxInfo(ref Message m)
{
NativeMethods.MINMAXINFO minmax = (NativeMethods.MINMAXINFO)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.MINMAXINFO));
minmax.maxTrackSize = this.MaximumSize;
minmax.minTrackSize = this.MinimumSize;
Marshal.StructureToPtr(minmax, m.LParam, false);
return true;
}
private bool OnNcHitTest(ref Message m, bool contentControl)
{
int x = NativeMethods.LOWORD(m.LParam);
int y = NativeMethods.HIWORD(m.LParam);
Point clientLocation = PointToClient(new Point(x, y));
GripBounds gripBouns = new GripBounds(contentControl ? content.ClientRectangle : ClientRectangle);
IntPtr transparent = new IntPtr(NativeMethods.HTTRANSPARENT);
if (resizableTop)
{
if (resizableRight && gripBouns.TopLeft.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTTOPLEFT;
return true;
}
if (!resizableRight && gripBouns.TopRight.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTTOPRIGHT;
return true;
}
if (gripBouns.Top.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTTOP;
return true;
}
}
else
{
if (resizableRight && gripBouns.BottomLeft.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTBOTTOMLEFT;
return true;
}
if (!resizableRight && gripBouns.BottomRight.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTBOTTOMRIGHT;
return true;
}
if (gripBouns.Bottom.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTBOTTOM;
return true;
}
}
if (resizableRight && gripBouns.Left.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTLEFT;
return true;
}
if (!resizableRight && gripBouns.Right.Contains(clientLocation))
{
m.Result = contentControl ? transparent : (IntPtr)NativeMethods.HTRIGHT;
return true;
}
return false;
}
private VS.VisualStyleRenderer sizeGripRenderer;
///
/// Paints the size grip.
///
/// The instance containing the event data.
public void PaintSizeGrip(PaintEventArgs e)
{
if (e == null || e.Graphics == null || !resizable)
{
return;
}
Size clientSize = content.ClientSize;
if (Application.RenderWithVisualStyles)
{
if (this.sizeGripRenderer == null)
{
this.sizeGripRenderer = new VS.VisualStyleRenderer(VS.VisualStyleElement.Status.Gripper.Normal);
}
this.sizeGripRenderer.DrawBackground(e.Graphics, new Rectangle(clientSize.Width - 0x10, clientSize.Height - 0x10, 0x10, 0x10));
}
else
{
ControlPaint.DrawSizeGrip(e.Graphics, content.BackColor, clientSize.Width - 0x10, clientSize.Height - 0x10, 0x10, 0x10);
}
}
#endregion
}
}