using SmartCoalApplication.Base; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; namespace SmartCoalApplication.SystemLayer { public static class UI { private static bool initScales = false; private static float xScale; private static float yScale; public static void FlashForm(Form form) { IntPtr hWnd = form.Handle; SafeNativeMethods.FlashWindow(hWnd, false); SafeNativeMethods.FlashWindow(hWnd, false); GC.KeepAlive(form); } public static int GetExtendedFrameBounds(Form window) { GC.KeepAlive(window); return 0; } private static void InitScaleFactors(Control c) { if (c == null) { xScale = 1.0f; yScale = 1.0f; } else { using (Graphics g = c.CreateGraphics()) { xScale = g.DpiX / 96.0f; yScale = g.DpiY / 96.0f; } } initScales = true; } public static void InitScaling(Control c) { if (!initScales) { InitScaleFactors(c); } } public static float ScaleWidth(float width) { return (float)Math.Round(width * GetXScaleFactor()); } public static int ScaleWidth(int width) { return (int)Math.Round((float)width * GetXScaleFactor()); } public static int ScaleHeight(int height) { return (int)Math.Round((float)height * GetYScaleFactor()); } public static float ScaleHeight(float height) { return (float)Math.Round(height * GetYScaleFactor()); } public static Size ScaleSize(Size size) { return new Size(ScaleWidth(size.Width), ScaleHeight(size.Height)); } public static Point ScalePoint(Point pt) { return new Point(ScaleWidth(pt.X), ScaleHeight(pt.Y)); } public static float GetXScaleFactor() { if (!initScales) { throw new InvalidOperationException("Must call InitScaling() first"); } return xScale; } public static float GetYScaleFactor() { if (!initScales) { throw new InvalidOperationException("Must call InitScaling() first"); } return yScale; } public static void DrawCommandButton( Graphics graphics, PushButtonState state, Rectangle rect, Color backColor, Control childControl) { VisualStyleElement element = null; int alpha = 255; if (element == null) { switch (state) { case PushButtonState.Default: element = VisualStyleElement.Button.PushButton.Default; alpha = 95; break; case PushButtonState.Disabled: element = VisualStyleElement.Button.PushButton.Disabled; break; case PushButtonState.Hot: element = VisualStyleElement.Button.PushButton.Hot; break; case PushButtonState.Normal: alpha = 0; element = VisualStyleElement.Button.PushButton.Normal; break; case PushButtonState.Pressed: element = VisualStyleElement.Button.PushButton.Pressed; break; default: throw new InvalidEnumArgumentException(); } } if (element != null) { try { VisualStyleRenderer renderer = new VisualStyleRenderer(element); renderer.DrawParentBackground(graphics, rect, childControl); renderer.DrawBackground(graphics, rect); } catch (Exception) { element = null; } } if (element == null) { ButtonRenderer.DrawButton(graphics, rect, state); } if (alpha != 255) { using (Brush backBrush = new SolidBrush(Color.FromArgb(255 - alpha, backColor))) { CompositingMode oldCM = graphics.CompositingMode; try { graphics.CompositingMode = CompositingMode.SourceOver; graphics.FillRectangle(backBrush, rect); } finally { graphics.CompositingMode = oldCM; } } } } /// /// Sets the control's redraw state. /// /// The control whose state should be modified. /// The new state for redrawing ability. /// /// Note to implementors: This method is used by SuspendControlPainting() and ResumeControlPainting(). /// This may be implemented as a no-op. /// private static void SetControlRedrawImpl(Control control, bool enabled) { SafeNativeMethods.SendMessageW(control.Handle, NativeConstants.WM_SETREDRAW, enabled ? new IntPtr(1) : IntPtr.Zero, IntPtr.Zero); GC.KeepAlive(control); } private static Dictionary controlRedrawStack = new Dictionary(); /// /// Suspends the control's ability to draw itself. /// /// The control to suspend drawing for. /// /// When drawing is suspended, any painting performed in the control's WM_PAINT, OnPaint(), /// WM_ERASEBKND, or OnPaintBackground() handlers is completely ignored. Invalidation rectangles /// are not accumulated during this period, so when drawing is resumed (with /// ResumeControlPainting()), it is usually a good idea to call Invalidate(true) on the control. /// This method must be matched at a later time by a corresponding call to ResumeControlPainting(). /// If you call SuspendControlPainting() multiple times for the same control, then you must /// call ResumeControlPainting() once for each call. /// Note to implementors: Do not modify this method. Instead, modify SetControlRedrawImpl(), /// which may be implemented as a no-op. /// public static void SuspendControlPainting(Control control) { int pushCount; if (controlRedrawStack.TryGetValue(control, out pushCount)) { ++pushCount; } else { pushCount = 1; } if (pushCount == 1) { SetControlRedrawImpl(control, false); } controlRedrawStack[control] = pushCount; } /// /// Resumes the control's ability to draw itself. /// /// The control to suspend drawing for. /// /// This method must be matched by a preceding call to SuspendControlPainting(). If that method /// was called multiple times, then this method must be called a corresponding number of times /// in order to enable drawing. /// This method must be matched at a later time by a corresponding call to ResumeControlPainting(). /// If you call SuspendControlPainting() multiple times for the same control, then you must /// call ResumeControlPainting() once for each call. /// Note to implementors: Do not modify this method. Instead, modify SetControlRedrawImpl(), /// which may be implemented as a no-op. /// public static void ResumeControlPainting(Control control) { int pushCount; if (controlRedrawStack.TryGetValue(control, out pushCount)) { --pushCount; } else { throw new InvalidOperationException("There was no previous matching SuspendControlPainting() for this control"); } if (pushCount == 0) { SetControlRedrawImpl(control, true); controlRedrawStack.Remove(control); } else { controlRedrawStack[control] = pushCount; } } /// /// Queries whether painting is enabled for the given control. /// /// The control to query suspension for. /// /// false if the control's painting has been suspended via a call to SuspendControlPainting(), /// otherwise true. /// /// /// You may use the return value of this method to optimize away painting. If this /// method returns false, then you may skip your entire OnPaint() method. This saves /// processor time by avoiding all of the non-painting drawing and resource initialization /// and destruction that is typically contained in OnPaint(). /// This method assumes painting suspension is being exclusively managed with Suspend- /// and ResumeControlPainting(). /// public static bool IsControlPaintingEnabled(Control control) { int pushCount; if (!controlRedrawStack.TryGetValue(control, out pushCount)) { pushCount = 0; } return (pushCount == 0); } private static IntPtr hRgn = SafeNativeMethods.CreateRectRgn(0, 0, 1, 1); public static Rectangle[] GetUpdateRegion(Control control) { SafeNativeMethods.GetUpdateRgn(control.Handle, hRgn, false); Rectangle[] scans; int area; PdnGraphics.GetRegionScans(hRgn, out scans, out area); GC.KeepAlive(control); return scans; } public static void SetFormOpacity(Form form, double opacity) { if (opacity < 0.0 || opacity > 1.0) { throw new ArgumentOutOfRangeException("opacity", "must be in the range [0, 1]"); } uint exStyle = SafeNativeMethods.GetWindowLongW(form.Handle, NativeConstants.GWL_EXSTYLE); byte bOldAlpha = 255; if ((exStyle & NativeConstants.GWL_EXSTYLE) != 0) { uint dwOldKey; uint dwOldFlags; bool result = SafeNativeMethods.GetLayeredWindowAttributes(form.Handle, out dwOldKey, out bOldAlpha, out dwOldFlags); } byte bNewAlpha = (byte)(opacity * 255.0); uint newExStyle = exStyle; if (bNewAlpha != 255) { newExStyle |= NativeConstants.WS_EX_LAYERED; } if (newExStyle != exStyle || (newExStyle & NativeConstants.WS_EX_LAYERED) != 0) { if (newExStyle != exStyle) { SafeNativeMethods.SetWindowLongW(form.Handle, NativeConstants.GWL_EXSTYLE, newExStyle); } if ((newExStyle & NativeConstants.WS_EX_LAYERED) != 0) { SafeNativeMethods.SetLayeredWindowAttributes(form.Handle, 0, bNewAlpha, NativeConstants.LWA_ALPHA); } } GC.KeepAlive(form); } internal static bool ClickThroughWndProc(ref Message m) { bool returnVal = false; if (m.Msg == NativeConstants.WM_MOUSEACTIVATE) { if (m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT) { m.Result = (IntPtr)NativeConstants.MA_ACTIVATE; returnVal = true; } } return returnVal; } public static bool IsOurAppActive { get { foreach (Form form in Application.OpenForms) { if (form == Form.ActiveForm) { return true; } } return false; } } private static VisualStyleClass DetermineVisualStyleClass() { return DetermineVisualStyleClassImpl(); } private static VisualStyleClass DetermineVisualStyleClassImpl() { VisualStyleClass vsClass; if (!VisualStyleInformation.IsSupportedByOS) { vsClass = VisualStyleClass.Classic; } else if (!VisualStyleInformation.IsEnabledByUser) { vsClass = VisualStyleClass.Classic; } else if (0 == string.Compare(VisualStyleInformation.Author, "MSX", StringComparison.InvariantCulture) && 0 == string.Compare(VisualStyleInformation.DisplayName, "Aero style", StringComparison.InvariantCulture)) { vsClass = VisualStyleClass.Aero; } else if (0 == string.Compare(VisualStyleInformation.Company, "Microsoft Corporation", StringComparison.InvariantCulture) && 0 == string.Compare(VisualStyleInformation.Author, "Microsoft Design Team", StringComparison.InvariantCulture)) { if (0 == string.Compare(VisualStyleInformation.DisplayName, "Windows XP style", StringComparison.InvariantCulture) || // Luna 0 == string.Compare(VisualStyleInformation.DisplayName, "Zune Style", StringComparison.InvariantCulture) || // Zune 0 == string.Compare(VisualStyleInformation.DisplayName, "Media Center style", StringComparison.InvariantCulture)) // Royale { vsClass = VisualStyleClass.Luna; } else { vsClass = VisualStyleClass.Other; } } else { vsClass = VisualStyleClass.Other; } return vsClass; } public static VisualStyleClass VisualStyleClass { get { return DetermineVisualStyleClass(); } } public static bool HideAllScrollBar(Control control) { return SafeNativeMethods.ShowScrollBar(control.Handle, 3, false); } public static bool HideHorizontalScrollBar(Control control) { return SafeNativeMethods.ShowScrollBar(control.Handle, NativeConstants.SB_HORZ, false); } public static bool HideVerticalScrollBar(Control control) { return SafeNativeMethods.ShowScrollBar(control.Handle, NativeConstants.SB_VERT, false); } public static void RestoreWindow(IWin32Window window) { IntPtr hWnd = window.Handle; SafeNativeMethods.ShowWindow(hWnd, NativeConstants.SW_RESTORE); GC.KeepAlive(window); } public static void DisableCloseBox(IWin32Window window) { IntPtr hWnd = window.Handle; IntPtr hMenu = SafeNativeMethods.GetSystemMenu(hWnd, false); if (hMenu == IntPtr.Zero) { throw new Win32Exception("GetSystemMenu() returned NULL"); } int result = SafeNativeMethods.EnableMenuItem( hMenu, NativeConstants.SC_CLOSE, NativeConstants.MF_BYCOMMAND | NativeConstants.MF_GRAYED); bool bResult = SafeNativeMethods.DrawMenuBar(hWnd); if (!bResult) { throw new Win32Exception("DrawMenuBar returned FALSE"); } GC.KeepAlive(window); } internal static void InvokeThroughModalTrampoline(IWin32Window owner, Procedure invokeMe) { using (Form modalityFix = new Form()) { modalityFix.ShowInTaskbar = false; modalityFix.TransparencyKey = modalityFix.BackColor; UI.SetFormOpacity(modalityFix, 0); modalityFix.ControlBox = false; modalityFix.FormBorderStyle = FormBorderStyle.None; Control ownerAsControl = owner as Control; if (ownerAsControl != null) { Form ownerForm = ownerAsControl.FindForm(); if (ownerForm != null) { Rectangle clientRect = ownerForm.RectangleToScreen(ownerForm.ClientRectangle); modalityFix.Icon = ownerForm.Icon; modalityFix.Location = clientRect.Location; modalityFix.Size = clientRect.Size; modalityFix.StartPosition = FormStartPosition.Manual; } } modalityFix.Shown += delegate (object sender, EventArgs e) { invokeMe(modalityFix); modalityFix.Close(); }; modalityFix.ShowDialog(owner); GC.KeepAlive(modalityFix); } } public static void EnableShield(Button button, bool enableShield) { IntPtr hWnd = button.Handle; SafeNativeMethods.SendMessageW( hWnd, NativeConstants.BCM_SETSHIELD, IntPtr.Zero, enableShield ? new IntPtr(1) : IntPtr.Zero); GC.KeepAlive(button); } } }