/src/Core/PdnBaseForm.cs
C# | 1039 lines | 782 code | 170 blank | 87 comment | 132 complexity | be56126cee1725101f213495c0a804ad MD5 | raw file
- /////////////////////////////////////////////////////////////////////////////////
- // Paint.NET //
- // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
- // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
- // See src/Resources/Files/License.txt for full licensing and attribution //
- // details. //
- // . //
- /////////////////////////////////////////////////////////////////////////////////
-
- using System.Linq;
- using PaintDotNet.Base;
- using PaintDotNet.SystemLayer;
- using System;
- using System.Drawing;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Resources;
- using System.Threading;
- using System.Windows.Forms;
-
- namespace PaintDotNet
- {
- /// <summary>
- /// This Form class is used to fix a few bugs in Windows Forms, and to add a few performance
- /// enhancements, such as disabling opacity != 1.0 when running in a remote TS/RD session.
- /// We derive from this class instead of Windows.Forms.Form directly.
- /// </summary>
- public class PdnBaseForm
- : Form,
- ISnapManagerHost
- {
- static PdnBaseForm()
- {
- Application.EnterThreadModal += ApplicationEnterThreadModal;
- Application.LeaveThreadModal += ApplicationLeaveThreadModal;
- ApplicationEnterThreadModal(null, EventArgs.Empty);
- }
-
- // This set keeps track of forms which cannot be the current modal form.
- private static readonly Stack<List<Form>> ParentModalForms = new Stack<List<Form>>();
-
- private static bool IsInParentModalForms(Form form)
- {
- return ParentModalForms.Any(formList => formList.Any(parentModalForm => parentModalForm == form));
- }
-
- private static List<Form> GetAllPeerForms(Form form)
- {
- if (form == null)
- {
- return new List<Form>();
- }
-
- if (form.Owner != null)
- {
- return GetAllPeerForms(form.Owner);
- }
-
- var forms = new List<Form> {form};
- forms.AddRange(form.OwnedForms);
-
- return forms;
- }
-
- private static void ApplicationEnterThreadModal(object sender, EventArgs e)
- {
- Form activeForm = ActiveForm;
- List<Form> allPeerForms = GetAllPeerForms(activeForm);
- ParentModalForms.Push(allPeerForms);
- }
-
- private static void ApplicationLeaveThreadModal(object sender, EventArgs e)
- {
- ParentModalForms.Pop();
- }
-
- protected override void OnShown(EventArgs e)
- {
- IsShown = true;
- Tracing.LogFeature("ShowDialog(" + GetType().FullName + ")");
- base.OnShown(e);
- }
-
- public bool IsShown { get; private set; }
-
- private bool _enableOpacity = true;
- private double _ourOpacity = 1.0; // store opacity setting so that when we go from disabled->enabled opacity we can set the correct value
- private SnapManager _snapManager;
- private IContainer components;
- private bool _instanceEnableOpacity = true;
- private static bool _globalEnableOpacity = true;
- private readonly FormEx _formEx;
- private bool _processFormHotKeyMutex; // if we're already processing a form hotkey, don't let other hotkeys execute.
-
- private static Dictionary<Keys, Function<bool, Keys>> _hotkeyRegistrar;
-
- /// <summary>
- /// Registers a form-wide hot key, and a callback for when the key is pressed.
- /// The callback must be an instance method on a Control. Whatever Form the Control
- /// is on will process the hotkey, as long as the Form is derived from PdnBaseForm.
- /// </summary>
- public static void RegisterFormHotKey(Keys keys, Function<bool, Keys> callback)
- {
- var targetAsComponent = callback.Target as IComponent;
- var targetAsHotKeyTarget = callback.Target as IHotKeyTarget;
-
- if (targetAsComponent == null && targetAsHotKeyTarget == null)
- {
- throw new ArgumentException("target instance must implement IComponent or IHotKeyTarget", "callback");
- }
-
- if (_hotkeyRegistrar == null)
- {
- _hotkeyRegistrar = new Dictionary<Keys, Function<bool, Keys>>();
- }
-
- Function<bool, Keys> theDelegate;
-
- if (_hotkeyRegistrar.ContainsKey(keys))
- {
- theDelegate = _hotkeyRegistrar[keys];
- theDelegate += callback;
- _hotkeyRegistrar[keys] = theDelegate;
- }
- else
- {
- theDelegate = new Function<bool, Keys>(callback);
- _hotkeyRegistrar.Add(keys, theDelegate);
- }
-
- if (targetAsComponent != null)
- {
- targetAsComponent.Disposed += TargetAsComponentDisposed;
- }
- else
- {
- targetAsHotKeyTarget.Disposed += TargetAsHotKeyTargetDisposed;
- }
- }
-
- private static bool ShouldProcessHotKey(Keys keys)
- {
- Keys keyOnly = keys & ~Keys.Modifiers;
-
- if (keyOnly == Keys.Back ||
- keyOnly == Keys.Delete ||
- keyOnly == Keys.Left ||
- keyOnly == Keys.Right ||
- keyOnly == Keys.Up ||
- keyOnly == Keys.Down ||
- keys == (Keys.Control | Keys.A) || // select all
- keys == (Keys.Control | Keys.Z) || // undo
- keys == (Keys.Control | Keys.Y) || // redo
- keys == (Keys.Control | Keys.X) || // cut
- keys == (Keys.Control | Keys.C) || // copy
- keys == (Keys.Control | Keys.V) || // paste
- keys == (Keys.Shift | Keys.Delete) || // cut (left-handed)
- keys == (Keys.Control | Keys.Insert) || // copy (left-handed)
- keys == (Keys.Shift | Keys.Insert) // paste (left-handed)
- )
- {
- Control focused = Utility.FindFocus();
-
- if (focused is TextBox || focused is ComboBox || focused is UpDownBase)
- {
- return false;
- }
- }
-
- return true;
- }
-
- private static void TargetAsComponentDisposed(object sender, EventArgs e)
- {
- ((IComponent)sender).Disposed -= TargetAsComponentDisposed;
- RemoveDisposedTarget(sender);
- }
-
- private static void TargetAsHotKeyTargetDisposed(object sender, EventArgs e)
- {
- ((IHotKeyTarget)sender).Disposed -= TargetAsHotKeyTargetDisposed;
- RemoveDisposedTarget(sender);
- }
-
- static void RemoveDisposedTarget(object sender)
- {
- // Control was disposed, but it never unregistered for its hotkeys!
- var keysList = new List<Keys>(_hotkeyRegistrar.Keys);
-
- foreach (Keys keys in keysList)
- {
- Function<bool, Keys> theMultiDelegate = _hotkeyRegistrar[keys];
-
- foreach (Delegate theDelegate in
- theMultiDelegate.GetInvocationList().Where(theDelegate => ReferenceEquals(theDelegate.Target, sender)))
- {
- UnregisterFormHotKey(keys, (Function<bool, Keys>)theDelegate);
- }
- }
- }
-
- public static void UnregisterFormHotKey(Keys keys, Function<bool, Keys> callback)
- {
- if (_hotkeyRegistrar == null) return;
- Function<bool, Keys> theDelegate = _hotkeyRegistrar[keys];
- theDelegate -= callback;
- _hotkeyRegistrar[keys] = theDelegate;
-
- var targetAsComponent = callback.Target as IComponent;
- if (targetAsComponent != null)
- {
- targetAsComponent.Disposed -= TargetAsComponentDisposed;
- }
-
- var targetAsHotKeyTarget = callback.Target as IHotKeyTarget;
- if (targetAsHotKeyTarget != null)
- {
- targetAsHotKeyTarget.Disposed -= TargetAsHotKeyTargetDisposed;
- }
-
- if (theDelegate.GetInvocationList().Length == 0)
- {
- _hotkeyRegistrar.Remove(keys);
- }
-
- if (_hotkeyRegistrar.Count == 0)
- {
- _hotkeyRegistrar = null;
- }
- }
-
- public void Flash()
- {
- UI.FlashForm(this);
- }
-
- public void RestoreWindow()
- {
- if (WindowState == FormWindowState.Minimized)
- {
- UI.RestoreWindow(this);
- }
- }
-
- /// <summary>
- /// Returns the currently active modal form if the process is in the foreground and is active.
- /// </summary>
- /// <remarks>
- /// If Form.ActiveForm is modeless, we search up the chain of owner forms
- /// to find its modeless owner form.
- /// </remarks>
- public static Form CurrentModalForm
- {
- get
- {
- Form theForm = ActiveForm;
-
- while (theForm != null && !theForm.Modal && theForm.Owner != null)
- {
- theForm = theForm.Owner;
- }
-
- return theForm;
- }
- }
-
- /// <summary>
- /// Gets whether the current form is the processes' top level modal form.
- /// </summary>
- public bool IsCurrentModalForm
- {
- get
- {
- if (IsInParentModalForms(this))
- {
- return false;
- }
-
- if (ContainsFocus)
- {
- return true;
- }
-
- if (OwnedForms.Any(ownedForm => ownedForm.ContainsFocus))
- {
- return true;
- }
-
- return (this == CurrentModalForm);
- }
- }
-
- private static bool IsTargetFormActive(object target)
- {
- Control targetControl = null;
-
- {
- var asControl = target as Control;
-
- if (asControl != null)
- {
- targetControl = asControl;
- }
- }
-
- if (targetControl == null)
- {
- var asIFormAssociate = target as IFormAssociate;
-
- if (asIFormAssociate != null)
- {
- targetControl = asIFormAssociate.AssociatedForm;
- }
- }
-
- // target is not a control, or a type of non-control that we recognize as hosted by a control
- if (targetControl == null)
- {
- return false;
- }
-
- Form targetForm = targetControl.FindForm();
-
- // target is not on a form
- if (targetForm == null)
- {
- return false;
- }
-
- // is the target on the currently active form?
- Form activeModalForm = CurrentModalForm;
-
- return targetForm == activeModalForm;
-
- // Nope.
- }
-
- private static object GetConcreteTarget(object target)
- {
- var asDelegate = target as Delegate;
-
- return asDelegate == null ? target : GetConcreteTarget(asDelegate.Target);
- }
-
- private bool ProcessFormHotKey(Keys keyData)
- {
- bool processed = false;
-
- if (_processFormHotKeyMutex)
- {
- processed = true;
- }
- else
- {
- _processFormHotKeyMutex = true;
-
- try
- {
- if (_hotkeyRegistrar != null && _hotkeyRegistrar.ContainsKey(keyData))
- {
- Function<bool, Keys> theDelegate = _hotkeyRegistrar[keyData];
- Delegate[] invokeList = theDelegate.GetInvocationList();
-
- for (int i = invokeList.Length - 1; i >= 0; --i)
- {
- var invokeMe = (Function<bool, Keys>)invokeList[i];
- object concreteTarget = GetConcreteTarget(invokeMe.Target);
-
- if (!IsTargetFormActive(concreteTarget)) continue;
- bool result = invokeMe(keyData);
-
- if (!result) continue;
- // The callback handled the key.
- processed = true;
- break;
- }
- }
- }
-
- finally
- {
- _processFormHotKeyMutex = false;
- }
- }
-
- return processed;
- }
-
- private void OnProcessCmdKeyRelay(object sender, FormEx.ProcessCmdKeyEventArgs e)
- {
- bool handled = e.Handled;
-
- if (handled) return;
- handled = ProcessCmdKeyData(e.KeyData);
- e.Handled = handled;
- }
-
- public bool RelayProcessCmdKey(ref Message msg, Keys keyData)
- {
- return ProcessCmdKeyData(keyData);
- }
-
- protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
- {
- bool processed = ProcessCmdKeyData(keyData);
-
- if (!processed)
- {
- processed = base.ProcessCmdKey(ref msg, keyData);
- }
-
- return processed;
- }
-
- private bool ProcessCmdKeyData(Keys keyData)
- {
- bool shouldHandle = ShouldProcessHotKey(keyData);
-
- if (shouldHandle)
- {
- bool processed = ProcessFormHotKey(keyData);
- return processed;
- }
- return false;
- }
-
- public static void UpdateAllForms()
- {
- try
- {
- foreach (Form form in Application.OpenForms)
- {
- try
- {
- form.Update();
- }
-
- catch (Exception)
- {
- }
- }
- }
-
- catch (InvalidOperationException)
- {
- }
- }
-
- protected override void OnHelpRequested(HelpEventArgs hevent)
- {
- if (!hevent.Handled)
- {
- Utility.ShowHelp(this);
- hevent.Handled = true;
- }
-
- base.OnHelpRequested(hevent);
- }
-
- public static EventHandler EnableOpacityChanged;
- private static void OnEnableOpacityChanged()
- {
- if (EnableOpacityChanged != null)
- {
- EnableOpacityChanged(null, EventArgs.Empty);
- }
- }
-
- public bool EnableInstanceOpacity
- {
- get
- {
- return _instanceEnableOpacity;
- }
-
- set
- {
- _instanceEnableOpacity = value;
- DecideOpacitySetting();
- }
- }
-
- /// <summary>
- /// Gets or sets a flag that enables or disables opacity for all PdnBaseForm instances.
- /// If a particular form's EnableInstanceOpacity property is false, that will override
- /// this property being 'true'.
- /// </summary>
- public static bool EnableOpacity
- {
- get
- {
- return _globalEnableOpacity;
- }
-
- set
- {
- _globalEnableOpacity = value;
- OnEnableOpacityChanged();
- }
- }
-
- /// <summary>
- /// Gets or sets the titlebar rendering behavior for when the form is deactivated.
- /// </summary>
- /// <remarks>
- /// If this property is false, the titlebar will be rendered in a different color when the form
- /// is inactive as opposed to active. If this property is true, it will always render with the
- /// active style. If the whole application is deactivated, the title bar will still be drawn in
- /// an inactive state.
- /// </remarks>
- public bool ForceActiveTitleBar
- {
- get
- {
- return _formEx.ForceActiveTitleBar;
- }
-
- set
- {
- _formEx.ForceActiveTitleBar = value;
- }
- }
-
- private readonly ThreadPriority _originalPriority;
-
- protected override void OnScroll(ScrollEventArgs se)
- {
- Thread.CurrentThread.Priority = _originalPriority;
- base.OnScroll(se);
- }
-
- public PdnBaseForm()
- {
- _originalPriority = Thread.CurrentThread.Priority;
- Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
-
- UI.InitScaling(this);
-
- SuspendLayout();
- InitializeComponent();
-
- _formEx = new FormEx(this, RealWndProc);
- Controls.Add(_formEx);
- _formEx.Visible = false;
- DecideOpacitySetting();
- ResumeLayout(false);
-
- _formEx.ProcessCmdKeyRelay += OnProcessCmdKeyRelay;
- }
-
- protected override void OnLoad(EventArgs e)
- {
- if (!DesignMode)
- {
- LoadResources();
- }
-
- base.OnLoad(e);
- }
-
- public virtual void LoadResources()
- {
- if (DesignMode) return;
- string stringName = Name + ".Localized";
- string stringValue = StringsResourceManager.GetString(stringName);
-
- if (stringValue == null)
- {
- }
- else
- {
- try
- {
- bool boolValue = bool.Parse(stringValue);
-
- if (boolValue)
- {
- LoadLocalizedResources();
- }
- }
-
- catch (Exception)
- {
- }
- }
- }
-
- protected virtual ResourceManager StringsResourceManager
- {
- get
- {
- return PdnResources.Strings;
- }
- }
-
- private void LoadLocalizedResources()
- {
- LoadLocalizedResources(Name, this);
- }
-
- private static void ParsePair(string theString, out int x, out int y)
- {
- string[] split = theString.Split(',');
- x = int.Parse(split[0]);
- y = int.Parse(split[1]);
- }
-
- private void LoadLocalizedResources(string baseName, Control control)
- {
- // Text
- string textStringName = baseName + ".Text";
- string textString = StringsResourceManager.GetString(textStringName);
-
- if (textString != null)
- {
- control.Text = textString;
- }
-
- // Location
- string locationStringName = baseName + ".Location";
- string locationString = StringsResourceManager.GetString(locationStringName);
-
- if (locationString != null)
- {
- try
- {
- int x;
- int y;
-
- ParsePair(locationString, out x, out y);
- control.Location = new Point(x, y);
- }
-
- catch (Exception ex)
- {
- Tracing.Ping(locationStringName + " is invalid: " + locationString + ", exception: " + ex.ToString());
- }
- }
-
- // Size
- string sizeStringName = baseName + ".Size";
- string sizeString = StringsResourceManager.GetString(sizeStringName);
-
- if (sizeString != null)
- {
- try
- {
- int width;
- int height;
-
- ParsePair(sizeString, out width, out height);
- control.Size = new Size(width, height);
- }
-
- catch (Exception ex)
- {
- Tracing.Ping(sizeStringName + " is invalid: " + sizeString + ", exception: " + ex.ToString());
- }
- }
-
- // Recurse
- foreach (Control child in control.Controls)
- {
- if (child.Name == null || child.Name.Length > 0)
- {
- string newBaseName = baseName + "." + child.Name;
- LoadLocalizedResources(newBaseName, child);
- }
- else
- {
- Tracing.Ping("Name property not set for an instance of " + child.GetType().Name + " within " + baseName);
- }
- }
- }
-
- protected override void OnClosing(CancelEventArgs e)
- {
- base.OnClosing(e);
-
- if (!e.Cancel)
- {
- ForceActiveTitleBar = false;
- }
- }
-
- private void EnableOpacityChangedHandler(object sender, EventArgs e)
- {
- DecideOpacitySetting();
- }
-
- protected override void OnHandleCreated(EventArgs e)
- {
- base.OnHandleCreated (e);
-
- EnableOpacityChanged += EnableOpacityChangedHandler;
- UserSessions.SessionChanged += UserSessionsSessionChanged;
- DecideOpacitySetting();
- }
-
- protected override void OnHandleDestroyed(EventArgs e)
- {
- base.OnHandleDestroyed(e);
-
- EnableOpacityChanged -= EnableOpacityChangedHandler;
- UserSessions.SessionChanged -= UserSessionsSessionChanged;
- }
-
- /// <summary>
- /// Clean up any resources being used.
- /// </summary>
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (components != null)
- {
- components.Dispose();
- components = null;
- }
- }
-
- base.Dispose(disposing);
- }
-
- /// <summary>
- /// Sets the opacity of the form.
- /// </summary>
- /// <param name="newOpacity">The new opacity value.</param>
- /// <remarks>
- /// Depending on the system configuration, this request may be ignored. For example,
- /// when running within a Terminal Service (or Remote Desktop) session, opacity will
- /// always be set to 1.0 for performance reasons.
- /// </remarks>
- public new double Opacity
- {
- get
- {
- return _ourOpacity;
- }
-
- set
- {
- if (_enableOpacity)
- {
- // Bypassing Form.Opacity eliminates a "black flickering" that occurs when
- // the form transitions from Opacity=1.0 to Opacity != 1.0, or vice versa.
- // It appears to be a result of toggling the WS_EX_LAYERED style, or the
- // fact that Form.Opacity re-applies visual styles when this value transition
- // takes place.
- UI.SetFormOpacity(this, value);
- }
-
- _ourOpacity = value;
- }
- }
-
- /// <summary>
- /// Decides whether or not to have opacity be enabled.
- /// </summary>
- private void DecideOpacitySetting()
- {
- if (UserSessions.IsRemote || !_globalEnableOpacity || !EnableInstanceOpacity)
- {
- if (_enableOpacity)
- {
- try
- {
- UI.SetFormOpacity(this, 1.0);
- }
-
- // This fails in certain odd situations (bug #746), so we just eat the exception.
- catch (Win32Exception)
- {
- }
- }
-
- _enableOpacity = false;
- }
- else
- {
- if (!_enableOpacity)
- {
- // This fails in certain odd situations (bug #746), so we just eat the exception.
- try
- {
- UI.SetFormOpacity(this, _ourOpacity);
- }
-
- catch (Win32Exception)
- {
- }
- }
-
- _enableOpacity = true;
- }
- }
-
- public double ScreenAspect
- {
- get
- {
- Rectangle bounds = Screen.FromControl(this).Bounds;
- double aspect = (double)bounds.Width / (double)bounds.Height;
- return aspect;
- }
- }
-
- #region Windows Form Designer generated code
- /// <summary>
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- /// </summary>
- private void InitializeComponent()
- {
- this.components = new System.ComponentModel.Container();
- this.SuspendLayout();
- //
- // PdnBaseForm
- //
- this.AutoScaleDimensions = new SizeF(96F, 96F);
- this.AutoScaleMode = AutoScaleMode.Dpi;
- this.ClientSize = new System.Drawing.Size(291, 270);
- this.Name = "PdnBaseForm";
- this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
- this.Text = "PdnBaseForm";
- this.ResumeLayout(false);
-
- }
- #endregion
-
- public event MovingEventHandler Moving;
- protected virtual void OnMoving(MovingEventArgs mea)
- {
- if (Moving != null)
- {
- Moving(this, mea);
- }
- }
-
- public event CancelEventHandler QueryEndSession;
- protected virtual void OnQueryEndSession(CancelEventArgs e)
- {
- if (QueryEndSession != null)
- {
- QueryEndSession(this, e);
- }
- }
-
- private void UserSessionsSessionChanged(object sender, EventArgs e)
- {
- DecideOpacitySetting();
- }
-
- void RealWndProc(ref Message m)
- {
- OurWndProc(ref m);
- }
-
- protected override void WndProc(ref Message m)
- {
- if (_formEx == null)
- {
- base.WndProc(ref m);
- }
- else if (!_formEx.HandleParentWndProc(ref m))
- {
- OurWndProc(ref m);
- }
- }
-
- private void OurWndProc(ref Message m)
- {
- switch (m.Msg)
- {
- case 0x0216: // WM_MOVING
- unsafe
- {
- var p = (int *)m.LParam;
- Rectangle rect = Rectangle.FromLTRB(p[0], p[1], p[2], p[3]);
-
- var mea = new MovingEventArgs(rect);
- OnMoving(mea);
-
- p[0] = mea.Rectangle.Left;
- p[1] = mea.Rectangle.Top;
- p[2] = mea.Rectangle.Right;
- p[3] = mea.Rectangle.Bottom;
-
- m.Result = new IntPtr(1);
- }
- break;
-
- // WinForms doesn't handle this message correctly and wrongly returns 0 instead of 1.
- case 0x0011: // WM_QUERYENDSESSION
- var e = new CancelEventArgs();
- OnQueryEndSession(e);
- m.Result = e.Cancel ? IntPtr.Zero : new IntPtr(1);
- break;
-
- default:
- base.WndProc(ref m);
- break;
- }
- }
-
- public SnapManager SnapManager
- {
- get { return _snapManager ?? (_snapManager = new SnapManager()); }
- }
-
- public Size ClientSizeToWindowSize(Size clientSize)
- {
- Size baseClientSize = ClientSize;
- Size baseWindowSize = Size;
-
- int extraWidth = baseWindowSize.Width - baseClientSize.Width;
- int extraHeight = baseWindowSize.Height - baseClientSize.Height;
-
- var windowSize = new Size(clientSize.Width + extraWidth, clientSize.Height + extraHeight);
- return windowSize;
- }
-
- public Size WindowSizeToClientSize(Size windowSize)
- {
- Size baseClientSize = ClientSize;
- Size baseWindowSize = Size;
-
- int extraWidth = baseWindowSize.Width - baseClientSize.Width;
- int extraHeight = baseWindowSize.Height - baseClientSize.Height;
- var clientSize = new Size(windowSize.Width - extraWidth, windowSize.Height - extraHeight);
-
- return clientSize;
- }
-
- public Rectangle ClientBoundsToWindowBounds(Rectangle clientBounds)
- {
- Rectangle currentBounds = Bounds;
- Rectangle currentClientBounds = RectangleToScreen(ClientRectangle);
-
- var newWindowBounds = new Rectangle(
- clientBounds.Left - (currentClientBounds.Left - currentBounds.Left),
- clientBounds.Top - (currentClientBounds.Top - currentBounds.Top),
- clientBounds.Width + (currentBounds.Width - currentClientBounds.Width),
- clientBounds.Height + (currentBounds.Height - currentClientBounds.Height));
-
- return newWindowBounds;
- }
-
- public Rectangle WindowBoundsToClientBounds(Rectangle windowBounds)
- {
- Rectangle currentBounds = Bounds;
- Rectangle currentClientBounds = RectangleToScreen(ClientRectangle);
-
- var newClientBounds = new Rectangle(
- windowBounds.Left + (currentClientBounds.Left - currentBounds.Left),
- windowBounds.Top + (currentClientBounds.Top - currentBounds.Top),
- windowBounds.Width - (currentBounds.Width - currentClientBounds.Width),
- windowBounds.Height - (currentBounds.Height - currentClientBounds.Height));
-
- return newClientBounds;
- }
-
- public void EnsureFormIsOnScreen()
- {
- if (WindowState == FormWindowState.Maximized)
- {
- return;
- }
-
- if (WindowState == FormWindowState.Minimized)
- {
- return;
- }
-
- Screen ourScreen;
-
- try
- {
- ourScreen = Screen.FromControl(this);
- }
-
- catch (Exception)
- {
- ourScreen = null;
- }
-
- if (ourScreen == null)
- {
- ourScreen = Screen.PrimaryScreen;
- }
-
- Rectangle currentBounds = Bounds;
- Rectangle newBounds = EnsureRectIsOnScreen(ourScreen, currentBounds);
- Bounds = newBounds;
- }
-
- public static Rectangle EnsureRectIsOnScreen(Screen screen, Rectangle bounds)
- {
- Rectangle newBounds = bounds;
- Rectangle screenBounds = screen.WorkingArea;
-
- // Make sure the bottom and right do not fall off the edge, by moving the bounds
- if (newBounds.Right > screenBounds.Right)
- {
- newBounds.X -= (newBounds.Right - screenBounds.Right);
- }
-
- if (newBounds.Bottom > screenBounds.Bottom)
- {
- newBounds.Y -= (newBounds.Bottom - screenBounds.Bottom);
- }
-
- // Make sure the top and left haven't fallen off, by moving
- if (newBounds.Left < screenBounds.Left)
- {
- newBounds.X = screenBounds.Left;
- }
-
- if (newBounds.Top < screenBounds.Top)
- {
- newBounds.Y = screenBounds.Top;
- }
-
- // Make sure that we are not too wide / tall, by resizing
- if (newBounds.Right > screenBounds.Right)
- {
- newBounds.Width -= (newBounds.Right - screenBounds.Right);
- }
-
- if (newBounds.Bottom > screenBounds.Bottom)
- {
- newBounds.Height -= (newBounds.Bottom - screenBounds.Bottom);
- }
-
- // All done.
- return newBounds;
- }
- }
- }