524 lines
16 KiB
C#
524 lines
16 KiB
C#
#if NETFRAMEWORK || WINDOWS
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Permissions;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
using System.Windows.Forms.VisualStyles;
|
|
|
|
namespace PopupTool
|
|
{
|
|
[ToolboxItem(false)]
|
|
public class Popup : ToolStripDropDown
|
|
{
|
|
public Control Content
|
|
{
|
|
get
|
|
{
|
|
return this.content;
|
|
}
|
|
}
|
|
|
|
public bool UseFadeEffect
|
|
{
|
|
get
|
|
{
|
|
return this.fade;
|
|
}
|
|
set
|
|
{
|
|
if (this.fade != value)
|
|
{
|
|
this.fade = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool FocusOnOpen
|
|
{
|
|
get
|
|
{
|
|
return this.focusOnOpen;
|
|
}
|
|
set
|
|
{
|
|
this.focusOnOpen = value;
|
|
}
|
|
}
|
|
public bool AcceptAlt
|
|
{
|
|
get
|
|
{
|
|
return this.acceptAlt;
|
|
}
|
|
set
|
|
{
|
|
this.acceptAlt = value;
|
|
}
|
|
}
|
|
|
|
public bool Resizable
|
|
{
|
|
get
|
|
{
|
|
return this.resizable && this._resizable;
|
|
}
|
|
set
|
|
{
|
|
this.resizable = value;
|
|
}
|
|
}
|
|
|
|
public new Size MinimumSize
|
|
{
|
|
get
|
|
{
|
|
return this.minSize;
|
|
}
|
|
set
|
|
{
|
|
this.minSize = value;
|
|
}
|
|
}
|
|
|
|
public new Size MaximumSize
|
|
{
|
|
get
|
|
{
|
|
return this.maxSize;
|
|
}
|
|
set
|
|
{
|
|
this.maxSize = value;
|
|
}
|
|
}
|
|
public bool IsOpen
|
|
{
|
|
get
|
|
{
|
|
return this._isOpen;
|
|
}
|
|
}
|
|
|
|
protected override CreateParams CreateParams
|
|
{
|
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
|
get
|
|
{
|
|
CreateParams createParams = base.CreateParams;
|
|
createParams.ExStyle |= 134217728;
|
|
return createParams;
|
|
}
|
|
}
|
|
|
|
public Popup(Control content)
|
|
{
|
|
EventHandler handler = null;
|
|
EventHandler handler2 = null;
|
|
PaintEventHandler handler3 = null;
|
|
this.focusOnOpen = true;
|
|
this.acceptAlt = true;
|
|
if (ReferenceEquals(content, null))
|
|
{
|
|
throw new ArgumentNullException("content");
|
|
}
|
|
this.content = content;
|
|
this.fade = SystemInformation.IsMenuAnimationEnabled && SystemInformation.IsMenuFadeEnabled;
|
|
this._resizable = true;
|
|
this.AutoSize = false;
|
|
this.DoubleBuffered = true;
|
|
base.ResizeRedraw = true;
|
|
this.host = new ToolStripControlHost(content);
|
|
Padding padding1 = this.host.Margin = Padding.Empty;
|
|
Padding padding2 = this.host.Padding = padding1;
|
|
base.Padding = base.Margin = padding2;
|
|
this.MinimumSize = content.MinimumSize;
|
|
content.MinimumSize = content.Size;
|
|
this.MaximumSize = content.MaximumSize;
|
|
content.MaximumSize = content.Size;
|
|
base.Size = content.Size;
|
|
content.Location = Point.Empty;
|
|
this.Items.Add(this.host);
|
|
if (handler == null)
|
|
{
|
|
handler = delegate (object sender, EventArgs e) {
|
|
content = null;
|
|
this.Dispose(true);
|
|
};
|
|
}
|
|
content.Disposed += handler;
|
|
if (handler2 == null)
|
|
{
|
|
handler2 = (sender, e) => this.UpdateRegion();
|
|
}
|
|
content.RegionChanged += handler2;
|
|
if (handler3 == null)
|
|
{
|
|
handler3 = (sender, e) => this.PaintSizeGrip(e);
|
|
}
|
|
content.Paint += handler3;
|
|
this.UpdateRegion();
|
|
}
|
|
|
|
protected override bool ProcessDialogKey(Keys keyData)
|
|
{
|
|
if (this.acceptAlt && (keyData & Keys.Alt) == Keys.Alt)
|
|
{
|
|
if ((keyData & Keys.F4) != Keys.F4)
|
|
{
|
|
return false;
|
|
}
|
|
base.Close();
|
|
}
|
|
return base.ProcessDialogKey(keyData);
|
|
}
|
|
|
|
protected void UpdateRegion()
|
|
{
|
|
if (base.Region != null)
|
|
{
|
|
base.Region.Dispose();
|
|
base.Region = null;
|
|
}
|
|
if (this.content.Region != null)
|
|
{
|
|
base.Region = this.content.Region.Clone();
|
|
}
|
|
}
|
|
|
|
public void Show(Control control)
|
|
{
|
|
this.Show(control, control.ClientRectangle);
|
|
}
|
|
|
|
public void Show(Control control, bool center)
|
|
{
|
|
this.Show(control, control.ClientRectangle, center);
|
|
}
|
|
|
|
public void Show(Control control, Rectangle area)
|
|
{
|
|
this.Show(control, area, false);
|
|
}
|
|
|
|
public void Show(Control control, Rectangle area, bool center)
|
|
{
|
|
if (control == null)
|
|
{
|
|
throw new ArgumentNullException("control");
|
|
}
|
|
this.SetOwnerItem(control);
|
|
this.resizableTop = (this.resizableLeft = false);
|
|
Point point = control.PointToScreen(new Point(area.Left, area.Top + area.Height));
|
|
Rectangle workingArea = Screen.FromControl(control).WorkingArea;
|
|
if (center)
|
|
{
|
|
if (point.X + (area.Width + base.Size.Width) / 2 > workingArea.Right)
|
|
{
|
|
this.resizableLeft = true;
|
|
point.X = workingArea.Right - base.Size.Width;
|
|
}
|
|
else
|
|
{
|
|
this.resizableLeft = true;
|
|
point.X -= (base.Size.Width - area.Width) / 2;
|
|
}
|
|
}
|
|
else if (point.X + base.Size.Width > workingArea.Left + workingArea.Width)
|
|
{
|
|
this.resizableLeft = true;
|
|
point.X = workingArea.Left + workingArea.Width - base.Size.Width;
|
|
}
|
|
if (point.Y + base.Size.Height > workingArea.Top + workingArea.Height)
|
|
{
|
|
this.resizableTop = true;
|
|
point.Y -= base.Size.Height + area.Height;
|
|
}
|
|
point = control.PointToClient(point);
|
|
base.Show(control, point, ToolStripDropDownDirection.BelowRight);
|
|
}
|
|
|
|
protected override void SetVisibleCore(bool visible)
|
|
{
|
|
double opacity = base.Opacity;
|
|
if (visible && this.fade && this.focusOnOpen)
|
|
{
|
|
base.Opacity = 0.0;
|
|
}
|
|
base.SetVisibleCore(visible);
|
|
if (visible && this.fade && this.focusOnOpen)
|
|
{
|
|
for (int i = 1; i <= 5; i++)
|
|
{
|
|
if (i > 1)
|
|
{
|
|
Thread.Sleep(20);
|
|
}
|
|
base.Opacity = opacity * (double)i / 5.0;
|
|
}
|
|
base.Opacity = opacity;
|
|
}
|
|
}
|
|
|
|
private void SetOwnerItem(Control control)
|
|
{
|
|
if (control != null)
|
|
{
|
|
if (control is Popup)
|
|
{
|
|
Popup popup = control as Popup;
|
|
this.ownerPopup = popup;
|
|
this.ownerPopup.childPopup = this;
|
|
base.OwnerItem = popup.Items[0];
|
|
}
|
|
else if (control.Parent != null)
|
|
{
|
|
this.SetOwnerItem(control.Parent);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnSizeChanged(EventArgs e)
|
|
{
|
|
this.content.MinimumSize = base.Size;
|
|
this.content.MaximumSize = base.Size;
|
|
this.content.Size = base.Size;
|
|
this.content.Location = Point.Empty;
|
|
base.OnSizeChanged(e);
|
|
}
|
|
|
|
protected override void OnOpening(CancelEventArgs e)
|
|
{
|
|
if (this.content.IsDisposed || this.content.Disposing)
|
|
{
|
|
e.Cancel = true;
|
|
}
|
|
else
|
|
{
|
|
this.UpdateRegion();
|
|
base.OnOpening(e);
|
|
}
|
|
}
|
|
|
|
protected override void OnOpened(EventArgs e)
|
|
{
|
|
if (this.ownerPopup != null)
|
|
{
|
|
this.ownerPopup._resizable = false;
|
|
}
|
|
if (this.focusOnOpen)
|
|
{
|
|
this.content.Focus();
|
|
}
|
|
this._isOpen = true;
|
|
base.OnOpened(e);
|
|
}
|
|
|
|
protected override void OnClosed(ToolStripDropDownClosedEventArgs e)
|
|
{
|
|
if (this.ownerPopup != null)
|
|
{
|
|
this.ownerPopup._resizable = true;
|
|
}
|
|
this._isOpen = false;
|
|
base.OnClosed(e);
|
|
}
|
|
|
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
if (!this.InternalProcessResizing(ref m, false))
|
|
{
|
|
base.WndProc(ref m);
|
|
}
|
|
}
|
|
|
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
|
public bool ProcessResizing(ref Message m)
|
|
{
|
|
return this.InternalProcessResizing(ref m, true);
|
|
}
|
|
|
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
|
private bool InternalProcessResizing(ref Message m, bool contentControl)
|
|
{
|
|
if (m.Msg == 134 && m.WParam != IntPtr.Zero && this.childPopup != null && this.childPopup.Visible)
|
|
{
|
|
this.childPopup.Hide();
|
|
}
|
|
bool result;
|
|
if (!this.Resizable)
|
|
{
|
|
result = false;
|
|
}
|
|
else if (m.Msg == 132)
|
|
{
|
|
result = this.OnNcHitTest(ref m, contentControl);
|
|
}
|
|
else
|
|
{
|
|
result = (m.Msg == 36 && this.OnGetMinMaxInfo(ref m));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
|
private bool OnGetMinMaxInfo(ref Message m)
|
|
{
|
|
UnsafeMethods.MINMAXINFO minmaxinfo = (UnsafeMethods.MINMAXINFO)Marshal.PtrToStructure(m.LParam, typeof(UnsafeMethods.MINMAXINFO));
|
|
minmaxinfo.maxTrackSize = this.MaximumSize;
|
|
minmaxinfo.minTrackSize = this.MinimumSize;
|
|
Marshal.StructureToPtr(minmaxinfo, m.LParam, false);
|
|
return true;
|
|
}
|
|
|
|
private bool OnNcHitTest(ref Message m, bool contentControl)
|
|
{
|
|
int x = UnsafeMethods.LOWORD(m.LParam);
|
|
int y = UnsafeMethods.HIWORD(m.LParam);
|
|
Point pt = base.PointToClient(new Point(x, y));
|
|
GripBounds gripBounds = new GripBounds(contentControl ? this.content.ClientRectangle : base.ClientRectangle);
|
|
IntPtr intPtr = new IntPtr(-1);
|
|
if (this.resizableTop)
|
|
{
|
|
if (this.resizableLeft && gripBounds.TopLeft.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)13));
|
|
return true;
|
|
}
|
|
if (!this.resizableLeft && gripBounds.TopRight.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)14));
|
|
return true;
|
|
}
|
|
if (gripBounds.Top.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)12));
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this.resizableLeft && gripBounds.BottomLeft.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)16));
|
|
return true;
|
|
}
|
|
if (!this.resizableLeft && gripBounds.BottomRight.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)17));
|
|
return true;
|
|
}
|
|
if (gripBounds.Bottom.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)15));
|
|
return true;
|
|
}
|
|
}
|
|
bool result;
|
|
if (this.resizableLeft && gripBounds.Left.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)10));
|
|
result = true;
|
|
}
|
|
else if (!this.resizableLeft && gripBounds.Right.Contains(pt))
|
|
{
|
|
m.Result = (contentControl ? intPtr : ((IntPtr)11));
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void PaintSizeGrip(PaintEventArgs e)
|
|
{
|
|
if (e != null && e.Graphics != null && this.resizable)
|
|
{
|
|
Size clientSize = this.content.ClientSize;
|
|
using (Bitmap bitmap = new Bitmap(16, 16))
|
|
{
|
|
using (Graphics graphics = Graphics.FromImage(bitmap))
|
|
{
|
|
if (Application.RenderWithVisualStyles)
|
|
{
|
|
if (this.sizeGripRenderer == null)
|
|
{
|
|
this.sizeGripRenderer = new VisualStyleRenderer(VisualStyleElement.Status.Gripper.Normal);
|
|
}
|
|
this.sizeGripRenderer.DrawBackground(graphics, new Rectangle(0, 0, 16, 16));
|
|
}
|
|
else
|
|
{
|
|
ControlPaint.DrawSizeGrip(graphics, this.content.BackColor, 0, 0, 16, 16);
|
|
}
|
|
}
|
|
GraphicsState gstate = e.Graphics.Save();
|
|
e.Graphics.ResetTransform();
|
|
if (this.resizableTop)
|
|
{
|
|
if (this.resizableLeft)
|
|
{
|
|
e.Graphics.RotateTransform(180f);
|
|
e.Graphics.TranslateTransform((float)(-(float)clientSize.Width), (float)(-(float)clientSize.Height));
|
|
}
|
|
else
|
|
{
|
|
e.Graphics.ScaleTransform(1f, -1f);
|
|
e.Graphics.TranslateTransform(0f, (float)(-(float)clientSize.Height));
|
|
}
|
|
}
|
|
else if (this.resizableLeft)
|
|
{
|
|
e.Graphics.ScaleTransform(-1f, 1f);
|
|
e.Graphics.TranslateTransform((float)(-(float)clientSize.Width), 0f);
|
|
}
|
|
e.Graphics.DrawImage(bitmap, clientSize.Width - 16, clientSize.Height - 16 + 1, 16, 16);
|
|
e.Graphics.Restore(gstate);
|
|
}
|
|
}
|
|
}
|
|
|
|
private const int frames = 5;
|
|
|
|
private const int totalduration = 100;
|
|
|
|
private const int frameduration = 20;
|
|
|
|
private Control content;
|
|
|
|
private bool fade;
|
|
|
|
private bool focusOnOpen = true;
|
|
|
|
private bool acceptAlt = true;
|
|
|
|
private Popup ownerPopup;
|
|
|
|
private Popup childPopup;
|
|
|
|
private bool _resizable;
|
|
|
|
private bool resizable;
|
|
|
|
private ToolStripControlHost host;
|
|
|
|
private Size minSize;
|
|
|
|
private Size maxSize;
|
|
|
|
private bool _isOpen;
|
|
|
|
private bool resizableTop;
|
|
|
|
private bool resizableLeft;
|
|
|
|
private VisualStyleRenderer sizeGripRenderer;
|
|
}
|
|
}
|
|
#endif |