Boblysan

Boblysan

  • NA
  • 66
  • 0

APPBAR - Base class - Please help!

Jan 21 2005 1:38 AM
Ok, I ran across this AppBar class that works extremely well. Unfortunately, I am having a difficult time trying to figure out how to make things happen the way I'd like. My goal is to place a toolbar control on the AppBar form and have the orientation of the toolbar changed based on the horizontal / vertical screen alignment of the AppBar. It doesn't seem like this should be that difficult but I have been unable to figure it out as of yet. I have spent many hours on MSDN reading through the APPBAR docs and still have had no luck. How can I note which edge of the screen the appbar successfully docs to and then perform some action? The action I perform I can take care. My issue up to this point has been with following exactly where the code goes and determining how to trigger based on this event. (event = which edge did the appbar just doc to?) The code I found is listed below.. (long) ------------------------------------------------------------------------------------------------------------ // Contributed by Dean Cleaver - [[email protected]] // a base class for implementing a dockable Windows App-Bar // Much of the code ported from a C/C++ implementation by Jeffrey Richter #region Copyright © 2002-2004 The Genghis Group /* * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from the * use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not claim * that you wrote the original software. If you use this software in a product, * an acknowledgment in the product documentation is IsRequired, as shown here: * * Portions Copyright © 2002-2004 The Genghis Group (http://www.genghisgroup.com/). * * 2. No substantial portion of the source code of this library may be redistributed * without the express written permission of the copyright holders, where * "substantial" is defined as enough code to be recognizably from this library. */ #endregion #region History // 4/15/2003 - Initial Version #endregion using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Design; using System.Globalization; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Windows.Forms; using System.Windows.Forms.Design; namespace Genghis.Windows.Forms { /// /// Summary description for AppBar. /// public class AppBarForm : System.Windows.Forms.Form { // The header from the original cpp file this was generated from. // Most of the credit belongs to Jeffrey Richter /****************************************************************************** Module name: AppBar.cpp Written by: Jeffrey Richter Purpose: AppBar base class implementation file. ******************************************************************************/ #region Private Structures [StructLayout(LayoutKind.Sequential)] private struct POINT { public int X; public int Y; public POINT(int X, int Y) { this.X = X; this.Y = Y; } public POINT(int pos) { this.X = pos & 0xFFFF; this.Y = (pos >> 16) & 0xFFFF; } } [StructLayout(LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; public RECT(int left, int top, int right, int bottom) { this.left = left; this.right = right; this.top = top; this.bottom = bottom; } public int Width { get {return right - left;} } public int Height { get {return bottom - top;} } public static bool operator != (RECT o1, RECT o2) { if (o1.left != o2.left) return true; if (o1.right != o2.right) return true; if (o1.top != o2.top) return true; if (o1.bottom != o2.bottom) return true; return false; } public static bool operator == (RECT o1, RECT o2) { if (o1.left != o2.left) return false; if (o1.right != o2.right) return false; if (o1.top != o2.top) return false; if (o1.bottom != o2.bottom) return false; return false; } public override bool Equals(object o) { try { RECT o2 = (RECT) o; return this == o2; } catch { return false; } } public override int GetHashCode() { return base.GetHashCode(); } } [StructLayout(LayoutKind.Sequential)] private struct APPBARSTATE { public int size; // Size of this structure public int state; // ABE_UNKNOWN, ABE_FLOAT, or ABE_edge public bool autoHide; // Should AppBar be auto-hidden when docked? public bool alwaysOnTop; // Should AppBar always be on top? public int dockSizeHorizontal; public int dockSizeVertical; public RECT floatRect; // Floating rectangle (in screen coordinates) public int taskBarState; public int dockFlags; // See the ABF_* flags above public SIZE sizeInc; // Descrete width/height size increments public int proposedState; public bool fullScreenAppOpen; public bool autoHideIsVisible; } [StructLayout(LayoutKind.Sequential)] private struct APPBARDATA { public int size; public int hWnd; public int callbackMessage; public int edge; public RECT position; public int lParam; // message specific } [StructLayout(LayoutKind.Sequential)] private struct SIZE { public int cx; public int cy; public SIZE(int cx, int cy) { this.cx = cx; this.cy = cy; } } #endregion #region Private Constants private const int ABE_LEFT = 0; private const int ABE_TOP = 1; private const int ABE_RIGHT = 2; private const int ABE_BOTTOM = 3; private const int ABE_UNKNOWN = 4; private const int ABE_FLOAT = 5; private const int ABF_ALLOWLEFT = 0x00000001; private const int ABF_ALLOWRIGHT = 0x00000004; private const int ABF_ALLOWTOP = 0x00000002; private const int ABF_ALLOWBOTTOM = 0x00000008; private const int ABF_ALLOWFLOAT = 0x00000010; private const int ABF_ALLOWLEFTRIGHT = (ABF_ALLOWLEFT | ABF_ALLOWRIGHT); private const int ABF_ALLOWTOPBOTTOM = (ABF_ALLOWTOP | ABF_ALLOWBOTTOM); private const int ABF_ALLOWANYEDGE = (ABF_ALLOWLEFTRIGHT | ABF_ALLOWTOPBOTTOM); private const int ABF_ALLOWANYWHERE = (ABF_ALLOWANYEDGE | ABF_ALLOWFLOAT); private const int ABF_MIMICTASKBARAUTOHIDE = 0x00000020; private const int ABF_MIMICTASKBARALWAYSONTOP = 0x00000040; private const int ABM_NEW = 0x00000000; private const int ABM_REMOVE = 0x00000001; private const int ABM_QUERYPOS = 0x00000002; private const int ABM_SETPOS = 0x00000003; private const int ABM_GETSTATE = 0x00000004; private const int ABM_GETTASKBARPOS = 0x00000005; private const int ABM_ACTIVATE = 0x00000006; private const int ABM_GETAUTOHIDEBAR = 0x00000007; private const int ABM_SETAUTOHIDEBAR = 0x00000008; private const int ABM_WINDOWPOSCHANGED = 0x00000009; private const int ABN_FULLSCREENAPP = 0x2; private const int ABN_POSCHANGED = 0x1; private const int ABN_STATECHANGE = 0x0; private const int ABN_WINDOWARRANGE = 0x3; // lParam == TRUE means hide private const int ABS_AUTOHIDE = 0x0000001; private const int ABS_ALWAYSONTOP = 0x0000002; private const int AUTOHIDETIMERINTERVAL = 400; private const int AUTOHIDETIMERID = 1; private const short GWL_STYLE = (-16); private const short GWL_EXSTYLE = (-20); private const int HTBORDER = 18; private const int HTBOTTOM = 15; private const int HTBOTTOMLEFT = 16; private const int HTBOTTOMRIGHT = 17; private const int HTCAPTION = 2; private const int HTCLIENT = 1; private const int HTERROR = (-2); private const int HTGROWBOX = 4; private const int HTHSCROLL = 6; private const int HTLEFT = 10; private const int HTMAXBUTTON = 9; private const int HTMENU = 5; private const int HTMINBUTTON = 8; private const int HTNOWHERE = 0; private const int HTREDUCE = HTMINBUTTON; private const int HTRIGHT = 11; private const int HTSIZE = HTGROWBOX; private const int HTSIZEFIRST = HTLEFT; private const int HTSIZELAST = HTBOTTOMRIGHT; private const int HTSYSMENU = 3; private const int HTTOP = 12; private const int HTTOPLEFT = 13; private const int HTTOPRIGHT = 14; private const int HTTRANSPARENT = (-1); private const int HTVSCROLL = 7; private const int HTZOOM = HTMAXBUTTON; private const int HWND_TOP = 0; private const int HWND_BOTTOM = 1; private const int HWND_TOPMOST = -1; private const int HWND_NOTOPMOST = -2; private const int SM_SWAPBUTTON = 23; private const int SM_CXDOUBLECLK = 36; private const int SM_CYDOUBLECLK = 37; private const int SM_CXVSCROLL = 2; private const int SM_CXHSCROLL = 21; private const int SM_CYHSCROLL = 3; private const int SM_CXSCREEN = 0; private const int SM_CYSCREEN = 1; private const int SM_CXBORDER = 5; private const int SM_CYBORDER = 6; private const int SPI_GETDRAGFULLWINDOWS = 38; private const int SPI_GETWORKAREA = 48; private const int SWP_NOSIZE = 0x0001; private const int SWP_NOMOVE = 0x0002; private const int SWP_NOZORDER = 0x0004; private const int SWP_NOREDRAW = 0x0008; private const int SWP_NOACTIVATE = 0x0010; private const int SWP_FRAMECHANGED =0x0020; private const int SWP_DRAWFRAME = SWP_FRAMECHANGED; private const int VK_CONTROL = 0x11; private const int VK_RBUTTON = 0x2; private const int VK_LBUTTON = 0x1; private const int WA_INACTIVE = 0; private const int WMSZ_LEFT = 1; private const int WMSZ_RIGHT = 2; private const int WMSZ_TOP = 3; private const int WMSZ_TOPLEFT = 4; private const int WMSZ_TOPRIGHT = 5; private const int WMSZ_BOTTOM = 6; private const int WMSZ_BOTTOMLEFT = 7; private const int WMSZ_BOTTOMRIGHT = 8; private const int WM_NULL = 0x0000; private const int WM_CREATE = 0x0001; private const int WM_DESTROY = 0x0002; private const int WM_MOVE = 0x0003; private const int WM_SIZE = 0x0005; private const int WM_ACTIVATE = 0x0006; private const int WM_SETFOCUS = 0x0007; private const int WM_KILLFOCUS = 0x0008; private const int WM_ENABLE = 0x000A; private const int WM_SETREDRAW = 0x000B; private const int WM_SETTEXT = 0x000C; private const int WM_GETTEXT = 0x000D; private const int WM_GETTEXTLENGTH = 0x000E; private const int WM_PAINT = 0x000F; private const int WM_CLOSE = 0x0010; private const int WM_QUERYENDSESSION = 0x0011; private const int WM_QUIT = 0x0012; private const int WM_QUERYOPEN = 0x0013; private const int WM_ERASEBKGND = 0x0014; private const int WM_SYSCOLORCHANGE = 0x0015; private const int WM_ENDSESSION = 0x0016; private const int WM_SHOWWINDOW = 0x0018; private const int WM_CTLCOLOR = 0x0019; private const int WM_WININICHANGE = 0x001A; private const int WM_SETTINGCHANGE = 0x001A; private const int WM_DEVMODECHANGE = 0x001B; private const int WM_ACTIVATEAPP = 0x001C; private const int WM_FONTCHANGE = 0x001D; private const int WM_TIMECHANGE = 0x001E; private const int WM_CANCELMODE = 0x001F; private const int WM_SETCURSOR = 0x0020; private const int WM_MOUSEACTIVATE = 0x0021; private const int WM_CHILDACTIVATE = 0x0022; private const int WM_QUEUESYNC = 0x0023; private const int WM_GETMINMAXINFO = 0x0024; private const int WM_PAINTICON = 0x0026; private const int WM_ICONERASEBKGND = 0x0027; private const int WM_NEXTDLGCTL = 0x0028; private const int WM_SPOOLERSTATUS = 0x002A; private const int WM_DRAWITEM = 0x002B; private const int WM_MEASUREITEM = 0x002C; private const int WM_DELETEITEM = 0x002D; private const int WM_VKEYTOITEM = 0x002E; private const int WM_CHARTOITEM = 0x002F; private const int WM_SETFONT = 0x0030; private const int WM_GETFONT = 0x0031; private const int WM_SETHOTKEY = 0x0032; private const int WM_GETHOTKEY = 0x0033; private const int WM_QUERYDRAGICON = 0x0037; private const int WM_COMPAREITEM = 0x0039; private const int WM_GETOBJECT = 0x003D; private const int WM_COMPACTING = 0x0041; private const int WM_COMMNOTIFY = 0x0044 ; private const int WM_WINDOWPOSCHANGING = 0x0046; private const int WM_WINDOWPOSCHANGED = 0x0047; private const int WM_POWER = 0x0048; private const int WM_COPYDATA = 0x004A; private const int WM_CANCELJOURNAL = 0x004B; private const int WM_NOTIFY = 0x004E; private const int WM_INPUTLANGCHANGEREQUEST = 0x0050; private const int WM_INPUTLANGCHANGE = 0x0051; private const int WM_TCARD = 0x0052; private const int WM_HELP = 0x0053; private const int WM_USERCHANGED = 0x0054; private const int WM_NOTIFYFORMAT = 0x0055; private const int WM_CONTEXTMENU = 0x007B; private const int WM_STYLECHANGING = 0x007C; private const int WM_STYLECHANGED = 0x007D; private const int WM_DISPLAYCHANGE = 0x007E; private const int WM_GETICON = 0x007F; private const int WM_SETICON = 0x0080; private const int WM_NCCREATE = 0x0081; private const int WM_NCDESTROY = 0x0082; private const int WM_NCCALCSIZE = 0x0083; private const int WM_NCHITTEST = 0x0084; private const int WM_NCPAINT = 0x0085; private const int WM_NCACTIVATE = 0x0086; private const int WM_GETDLGCODE = 0x0087; private const int WM_SYNCPAINT = 0x0088; private const int WM_NCMOUSEMOVE = 0x00A0; private const int WM_NCLBUTTONDOWN = 0x00A1; private const int WM_NCLBUTTONUP = 0x00A2; private const int WM_NCLBUTTONDBLCLK = 0x00A3; private const int WM_NCRBUTTONDOWN = 0x00A4; private const int WM_NCRBUTTONUP = 0x00A5; private const int WM_NCRBUTTONDBLCLK = 0x00A6; private const int WM_NCMBUTTONDOWN = 0x00A7; private const int WM_NCMBUTTONUP = 0x00A8; private const int WM_NCMBUTTONDBLCLK = 0x00A9; private const int WM_KEYDOWN = 0x0100; private const int WM_KEYUP = 0x0101; private const int WM_CHAR = 0x0102; private const int WM_DEADCHAR = 0x0103; private const int WM_SYSKEYDOWN = 0x0104; private const int WM_SYSKEYUP = 0x0105; private const int WM_SYSCHAR = 0x0106; private const int WM_SYSDEADCHAR = 0x0107; private const int WM_KEYLAST = 0x0108; private const int WM_IME_STARTCOMPOSITION = 0x010D; private const int WM_IME_ENDCOMPOSITION = 0x010E; private const int WM_IME_COMPOSITION = 0x010F; private const int WM_IME_KEYLAST = 0x010F; private const int WM_INITDIALOG = 0x0110; private const int WM_COMMAND = 0x0111; private const int WM_SYSCOMMAND = 0x0112; private const int WM_TIMER = 0x0113; private const int WM_HSCROLL = 0x0114; private const int WM_VSCROLL = 0x0115; private const int WM_INITMENU = 0x0116; private const int WM_INITMENUPOPUP = 0x0117; private const int WM_MENUSELECT = 0x011F; private const int WM_MENUCHAR = 0x0120; private const int WM_ENTERIDLE = 0x0121; private const int WM_MENURBUTTONUP = 0x0122; private const int WM_MENUDRAG = 0x0123; private const int WM_MENUGETOBJECT = 0x0124; private const int WM_UNINITMENUPOPUP = 0x0125; private const int WM_MENUCOMMAND = 0x0126; private const int WM_CTLCOLORMSGBOX = 0x0132; private const int WM_CTLCOLOREDIT = 0x0133; private const int WM_CTLCOLORLISTBOX = 0x0134; private const int WM_CTLCOLORBTN = 0x0135; private const int WM_CTLCOLORDLG = 0x0136; private const int WM_CTLCOLORSCROLLBAR = 0x0137; private const int WM_CTLCOLORSTATIC = 0x0138; private const int WM_MOUSEMOVE = 0x0200; private const int WM_LBUTTONDOWN = 0x0201; private const int WM_LBUTTONUP = 0x0202; private const int WM_LBUTTONDBLCLK = 0x0203; private const int WM_RBUTTONDOWN = 0x0204; private const int WM_RBUTTONUP = 0x0205; private const int WM_RBUTTONDBLCLK = 0x0206; private const int WM_MBUTTONDOWN = 0x0207; private const int WM_MBUTTONUP = 0x0208; private const int WM_MBUTTONDBLCLK = 0x0209; private const int WM_MOUSEWHEEL = 0x020A; private const int WM_PARENTNOTIFY = 0x0210; private const int WM_ENTERMENULOOP = 0x0211; private const int WM_EXITMENULOOP = 0x0212; private const int WM_NEXTMENU = 0x0213; private const int WM_SIZING = 0x0214; private const int WM_CAPTURECHANGED = 0x0215; private const int WM_MOVING = 0x0216; private const int WM_DEVICECHANGE = 0x0219; private const int WM_MDICREATE = 0x0220; private const int WM_MDIDESTROY = 0x0221; private const int WM_MDIACTIVATE = 0x0222; private const int WM_MDIRESTORE = 0x0223; private const int WM_MDINEXT = 0x0224; private const int WM_MDIMAXIMIZE = 0x0225; private const int WM_MDITILE = 0x0226; private const int WM_MDICASCADE = 0x0227; private const int WM_MDIICONARRANGE = 0x0228; private const int WM_MDIGETACTIVE = 0x0229; private const int WM_MDISETMENU = 0x0230; private const int WM_ENTERSIZEMOVE = 0x0231; private const int WM_EXITSIZEMOVE = 0x0232; private const int WM_DROPFILES = 0x0233; private const int WM_MDIREFRESHMENU = 0x0234; private const int WM_IME_SETCONTEXT = 0x0281; private const int WM_IME_NOTIFY = 0x0282; private const int WM_IME_CONTROL = 0x0283; private const int WM_IME_COMPOSITIONFULL = 0x0284; private const int WM_IME_SELECT = 0x0285; private const int WM_IME_CHAR = 0x0286; private const int WM_IME_REQUEST = 0x0288; private const int WM_IME_KEYDOWN = 0x0290; private const int WM_IME_KEYUP = 0x0291; private const int WM_MOUSEHOVER = 0x02A1; private const int WM_MOUSELEAVE = 0x02A3; private const int WM_CUT = 0x0300; private const int WM_COPY = 0x0301; private const int WM_PASTE = 0x0302; private const int WM_CLEAR = 0x0303; private const int WM_UNDO = 0x0304; private const int WM_RENDERFORMAT = 0x0305; private const int WM_RENDERALLFORMATS = 0x0306; private const int WM_DESTROYCLIPBOARD = 0x0307; private const int WM_DRAWCLIPBOARD = 0x0308; private const int WM_PAINTCLIPBOARD = 0x0309; private const int WM_VSCROLLCLIPBOARD = 0x030A; private const int WM_SIZECLIPBOARD = 0x030B; private const int WM_ASKCBFORMATNAME = 0x030C; private const int WM_CHANGECBCHAIN = 0x030D; private const int WM_HSCROLLCLIPBOARD = 0x030E; private const int WM_QUERYNEWPALETTE = 0x030F; private const int WM_PALETTEISCHANGING = 0x0310; private const int WM_PALETTECHANGED = 0x0311; private const int WM_HOTKEY = 0x0312; private const int WM_PRINT = 0x0317; private const int WM_PRINTCLIENT = 0x0318; private const int WM_HANDHELDFIRST = 0x0358; private const int WM_HANDHELDLAST = 0x035F; private const int WM_AFXFIRST = 0x0360; private const int WM_AFXLAST = 0x037F; private const int WM_PENWINFIRST = 0x0380; private const int WM_PENWINLAST = 0x038F; private const int WM_APP = 0x8000; private const int WM_USER = 0x0400; private const int WM_REFLECT = WM_USER + 0x1c00; private const int WM_APPBARNOTIFY = WM_USER + 100; private const int WS_CAPTION = 0x00C00000; private const int WS_SYSMENU = 0x00080000; #endregion #region Private API Functions [DllImport("user32.dll", SetLastError=true)] private static extern int AdjustWindowRectEx(ref RECT lpRect, int dsStyle, int bMenu, int dwEsStyle); [DllImport("user32.dll", SetLastError=true)] private static extern int ClientToScreen(IntPtr hwnd, ref POINT lpPoint); [DllImport("user32.dll", SetLastError=true)] private static extern Int16 GetAsyncKeyState(int vKey); [DllImport("user32.dll", SetLastError=true)] private static extern int GetClientRect(IntPtr hwnd, ref RECT rect); [DllImport("user32.dll", SetLastError=true)] private static extern int GetKeyState(Int16 nVirtKey); [DllImport("user32.dll", SetLastError=true)] private static extern int GetMessagePos(); [DllImport("user32.dll", SetLastError=true)] private static extern int GetSystemMetrics(int nIndex); [DllImport("kernel32.dll", SetLastError=true)] private static extern int GetTickCount(); [DllImport("user32.dll", SetLastError=true)] private static extern int GetWindowLong(IntPtr hwnd, Int16 nIndex); [DllImport("user32.dll", SetLastError=true)] private static extern int GetWindowRect(IntPtr hwnd, ref RECT rect); [DllImport("user32.dll", SetLastError=true)] private static extern int InflateRect(ref RECT rect, int x, int y); [DllImport("User32.dll", SetLastError=true)] private static extern int KillTimer(IntPtr hwnd, int nIDEvent); [DllImport("User32.dll", CharSet=CharSet.Auto)] private static extern bool ReleaseCapture(); [DllImport("Kernel32.dll", SetLastError=true)] private static extern void RtlMoveMemory(ref RECT Destination, IntPtr Source, int Length); [DllImport("Kernel32.dll", SetLastError=true)] private static extern void RtlMoveMemory(IntPtr Destination, ref RECT Source, int Length); [DllImport("user32.dll", CharSet=CharSet.Auto)] private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); [DllImport("user32.dll", SetLastError=true)] private static extern int SetTimer(IntPtr hWnd, int nIDEvent, int uElapse, int lpTimerFunc); [DllImport("User32.dll", CharSet=CharSet.Auto)] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll", SetLastError=true)] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int Width, int Height, int flags); [DllImport("shell32.dll", SetLastError=true)] private static extern int SHAppBarMessage(int message, ref APPBARDATA pData); [DllImport("user32.dll", SetLastError=true)] private static extern int SystemParametersInfoA(int uAction, int uParam, ref bool lpvParam, int fuWinIni); [DllImport("user32.dll", SetLastError=true)] private static extern int SystemParametersInfoA(int uAction, int uParam, ref RECT lpvParam, int fuWinIni); [DllImport("user32.dll", SetLastError=true)] private static extern int UpdateWindow(IntPtr hwnd); #endregion #region Public Enumerations /// /// Enumeration for the edge that the AppBar attaches to /// public enum AppBarEdge { Left = ABE_LEFT, Top = ABE_TOP, Right = ABE_RIGHT, Bottom = ABE_BOTTOM, Unknown = ABE_UNKNOWN, Float = ABE_FLOAT } /// /// Enumerations for the docking options /// [FlagsAttribute()] public enum DockFlags { AllowLeft = ABF_ALLOWLEFT, AllowTop = ABF_ALLOWTOP, AllowRight = ABF_ALLOWRIGHT, AllowBottom = ABF_ALLOWBOTTOM, AllowFloat = ABF_ALLOWFLOAT } #endregion #region Public Properties /// /// The edges the app bar can attach to /// [TypeConverterAttribute(typeof(DockFlagConverter)), Editor(typeof(DockFlagEditor), typeof(UITypeEditor)), Category("AppBar"), DefaultValue(DockFlags.AllowFloat), Description("The edges the app bar can attach to")] public DockFlags DockOptions { get {return (DockFlags) this.appBarState.dockFlags;} set {this.appBarState.dockFlags = (int) value;} } /// /// The increments by which the AppBar can be resized horizontally /// [Category("AppBar"), DefaultValue(0), Description("The increments by which the AppBar can be resized horizontally")] public int HorzSizeInc { get {return this.appBarState.sizeInc.cx;} set {this.appBarState.sizeInc.cx = value;} } /// /// The increments by which the AppBar can be resized vertically /// [Category("AppBar"), DefaultValue(0), Description("The increments by which the AppBar can be resized vertically")] public int VertSizeInc { get {return this.appBarState.sizeInc.cy;} set {this.appBarState.sizeInc.cy = value;} } /// /// The default starting position of the AppBar /// [Category("AppBar"), DefaultValue(AppBarEdge.Float), Description("The default starting position of the AppBar")] public AppBarEdge Edge { get {return (AppBarEdge) this.appBarState.state;} set {this.appBarState.state = (int) value;} } /// /// Whether or not the AppBar hides and then slides out from the edge /// [Category("AppBar"), DefaultValue(false), Description("Whether or not the AppBar hides and then slides out from the edge")] public bool AutoHide { get {return this.appBarState.autoHide;} set {this.appBarState.autoHide = value;} } /// /// Whether the AppBar is always on top /// [Category("AppBar"), DefaultValue(false), Description("Whether the AppBar is always on top")] public bool AlwaysOnTop { get {return this.appBarState.alwaysOnTop;} set {this.appBarState.alwaysOnTop = value;} } /// /// The width of the AppBar when docked on the side /// [Category("AppBar"), DefaultValue(0), Description("The width of the AppBar when docked on the side")] public int HorzDockSize { get {return this.appBarState.dockSizeHorizontal;} set {this.appBarState.dockSizeHorizontal = value;} } /// /// The height of the AppBar when docked on the top or bottom /// [Category("AppBar"), DefaultValue(0), Description("The height of the AppBar when docked on the top or bottom")] public int VertDockSize { get {return this.appBarState.dockSizeVertical;} set {this.appBarState.dockSizeVertical = value;} } #endregion #region Private Variables private APPBARSTATE appBarState; private bool initializing = false; private bool moving = false; private System.ComponentModel.IContainer components; #endregion #region Constructors public AppBarForm() { this.initializing = true; components = null; // // Required for Windows Form Designer support // InitializeComponent(); // // TODO: Add any constructor code after InitializeComponent call // // Force the shell to update its list of AppBars and the workarea. // This is a precaution and is very useful when debugging. If you create // an AppBar and then just terminate the application, the shell still // thinks that the AppBar exists and the user's workarea is smaller than // it should be. When a new AppBar is created, calling this function // fixes the user's workarea. // Set default state of AppBar to docked on bottom with no width & height this.appBarState = new APPBARSTATE(); this.appBarState.size = Marshal.SizeOf(this.appBarState); //if (this.DesignMode) this.appBarState.state = ABE_FLOAT; this.appBarState.autoHide = false; this.appBarState.alwaysOnTop = false; this.appBarState.dockSizeHorizontal = 30; this.appBarState.dockSizeVertical = 30; this.appBarState.taskBarState = AppBarMessage(ABM_GETSTATE); this.appBarState.dockFlags = ABF_ALLOWANYWHERE; this.appBarState.sizeInc = new SIZE(0, 0); // Don't allow re-sizing this.appBarState.proposedState = ABE_UNKNOWN; this.appBarState.fullScreenAppOpen = false; this.appBarState.autoHideIsVisible = false; this.appBarState.floatRect = new RECT(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); this.initializing = false; } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #endregion #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { // // AppBarForm // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(400, 270); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; this.Location = new System.Drawing.Point(500, 500); this.Name = "AppBarForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.AppBar_MouseDown); this.Load += new System.EventHandler(this.AppBarForm_Load); this.LocationChanged += new System.EventHandler(this.AppBarForm_LocationChanged); } #endregion #region Private Functions private int GetAutohideEdge() { for (int edge = ABE_LEFT; edge <= ABE_BOTTOM; edge++) { if (this.Handle.ToInt32() == AppBarMessage(ABM_GETAUTOHIDEBAR, edge)) { // We are an auto-hide AppBar and we found our edge. return edge; } } // NOTE: If AppBar is docked but not auto-hidden, we return ABE_UNKNOWN return ABE_UNKNOWN; } private bool ModifyStyle(Int16 styleOffset, int remove, int add, int flags) { int style = GetWindowLong(this.Handle, styleOffset); int newStyle = (style & (~ remove)) | add; if (style == newStyle) return false; SetWindowLong(this.Handle, styleOffset, newStyle); if (flags != 0) SetWindowPos(this.Handle, new IntPtr(0), 0, 0, 0, 0, ((SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE) | flags)); return true; } private void MimicState (int stateChangedMask, int state) { bool anyChange = false; // Assume that nothing changes // If the autohide state changed AND our style allows // us to mimic the Autohide state if (((stateChangedMask & ABS_AUTOHIDE) != 0) && ((this.appBarState.dockFlags & ABF_MIMICTASKBARAUTOHIDE) != 0)) { bool autoHide = (ABS_AUTOHIDE & state) != 0; // If our state doesn't match, change our state if (this.appBarState.autoHide != autoHide) { this.appBarState.autoHide = autoHide; anyChange = true; } } // If the AlwaysOnTop state changed AND our style allows // us to mimic the AlwaysOnTop state/ if (((stateChangedMask & ABS_ALWAYSONTOP) != 0) && ((this.appBarState.dockFlags & ABF_MIMICTASKBARALWAYSONTOP) != 0)) { // If our state doesn't match, change our state this.appBarState.alwaysOnTop = (ABS_ALWAYSONTOP & state) != 0; anyChange = true; } if (anyChange) { SetState(); ShowHiddenAppBar(false); } } private void SetState(int state) { if (this.DesignMode) return; // If the AppBar is registered as auto-hide, unregister it. int edge = GetAutohideEdge(); RECT currentRect; RECT position = new RECT(); if (edge != ABE_UNKNOWN) { // Our AppBar is auto-hidden, unregister it. AppBarMessage(ABM_SETAUTOHIDEBAR, edge, 0); } // Save the new requested state this.appBarState.state = state; switch (state) { case ABE_UNKNOWN: // We are being completely unregisterred. // Probably, the AppBar window is being destroyed. // If the AppBar is registered as NOT auto-hide, unregister it. AppBarMessage(ABM_REMOVE); break; case ABE_FLOAT: // We are floating and therefore are just a regular window. // Tell the shell that the docked AppBar should be of 0x0 dimensions // so that the workspace is not affected by the AppBar. currentRect = new RECT(0, 0, 0, 0); AppBarMessage(ABM_SETPOS, state, 0, ref currentRect); SetWindowPos(this.Handle, IntPtr.Zero, this.appBarState.floatRect.left, this.appBarState.floatRect.top, this.appBarState.floatRect.Width, this.appBarState.floatRect.Height, SWP_NOZORDER | SWP_NOACTIVATE); break; default: if (this.appBarState.autoHide & !(Convert.ToBoolean(AppBarMessage(ABM_SETAUTOHIDEBAR, GetState(), 1), CultureInfo.InvariantCulture))) { // We couldn't set the AppBar on a new edge, let's dock it instead. this.appBarState.autoHide = false; // Call a virtual function to let derived classes know that the AppBar // changed from auto-hide to docked. OnAppBarForcedToDocked(); } GetRect(GetState(), ref position); if (this.appBarState.autoHide) { currentRect = new RECT(0,0,0,0); AppBarMessage(ABM_SETPOS, ABE_LEFT, 0, ref currentRect); } else { // Tell the shell where the AppBar is. AppBarMessage(ABM_SETPOS, state, 0, ref position); } AdjustLocationForAutohide(this.appBarState.autoHideIsVisible, ref position); // Slide window in from or out to the edge SlideWindow(position); break; } // Set the AppBar's z-order appropriately IntPtr pwnd = new IntPtr(HWND_NOTOPMOST); // Assume normal Z-Order if (this.appBarState.alwaysOnTop) { // If we are supposed to be always-on-top, put us there. pwnd = new IntPtr(HWND_TOPMOST); if (this.appBarState.fullScreenAppOpen) { // But, if a full-screen window is opened, put ourself at the bottom // of the z-order so that we don't cover the full-screen window pwnd = new IntPtr(HWND_BOTTOM); } } SetWindowPos(this.Handle, pwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); // Make sure that any auto-hide appabrs stay on top of us after we move // even though our activation state has not changed. AppBarMessage(ABM_ACTIVATE); // Tell our derived class that there is a state change AppBarStateChange(false, state); } private void SetState() { SetState(GetState()); } private int AppBarMessage (int message, int edge /*= ABE_FLOAT*/, int lParam /*= 0*/, ref RECT position /*= null*/) { // Initialize an APPBARDATA structure. APPBARDATA abd = new APPBARDATA(); abd.size = Marshal.SizeOf(abd); abd.hWnd = this.Handle.ToInt32(); abd.callbackMessage = WM_APPBARNOTIFY; abd.edge = edge; abd.position = position; abd.lParam = lParam; int result = SHAppBarMessage(message, ref abd); // If the caller passed a rectangle, return the updated rectangle. position = abd.position; return result; } private int AppBarMessage (int message, int edge /*= ABE_FLOAT*/, int lParam /*= 0*/) { // Initialize an APPBARDATA structure. APPBARDATA abd = new APPBARDATA(); abd.size = Marshal.SizeOf(abd); abd.hWnd = this.Handle.ToInt32(); abd.callbackMessage = WM_APPBARNOTIFY; abd.edge = edge; abd.position = new RECT(0, 0, 0, 0); abd.lParam = lParam; int result = SHAppBarMessage(message, ref abd); // If the caller passed a rectangle, return the updated rectangle. return result; } private int AppBarMessage(int message) { return AppBarMessage(message, ABE_FLOAT, 0); } private int AppBarMessage(int message, int edge) { return AppBarMessage(message, edge, 0); } private int CalcProposedState (POINT point) { // Force the AppBar to float if the user is holding down the Ctrl key // and the AppBar's style allows floating. bool fForceFloat = ((GetKeyState(VK_CONTROL) & 0x8000) != 0) && ((this.appBarState.dockFlags & ABF_ALLOWFLOAT) != 0); return (fForceFloat ? ABE_FLOAT : GetEdgeFromPoint(this.appBarState.dockFlags, point)); } private void GetRect (int stateProposed, ref RECT rectProposed) { // This function finds the x, y, cx, cy of the AppBar window if (ABE_FLOAT == stateProposed) { // The AppBar is floating, the proposed rectangle is correct } else { // The AppBar is docked or auto-hide // Set dimensions to full screen. rectProposed = new RECT(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); // Subtract off what we want from the full screen dimensions if (!this.appBarState.autoHide) { // Ask the shell where we can dock. AppBarMessage(ABM_QUERYPOS, stateProposed, 0, ref rectProposed); } switch (stateProposed) { case ABE_LEFT: rectProposed.right = rectProposed.left + this.appBarState.dockSizeHorizontal; break; case ABE_TOP: rectProposed.bottom = rectProposed.top + this.appBarState.dockSizeVertical; break; case ABE_RIGHT: rectProposed.left = rectProposed.right - this.appBarState.dockSizeHorizontal; break; case ABE_BOTTOM: rectProposed.top = rectProposed.bottom - this.appBarState.dockSizeVertical; break; } } } private bool AdjustLocationForAutohide (bool show, ref RECT rect) { if ((GetState() == ABE_UNKNOWN) || (GetState() == ABE_FLOAT) || !this.appBarState.autoHide) { // If we are not docked on an edge OR we are not auto-hidden, there is // nothing for us to do; just return. return false; } // Showing/hiding doesn't change our size; only our position. int x = 0; int y = 0; // Assume a position of (0, 0) if (show) { // If we are on the right or bottom, calculate our visible position switch (GetState()) { case ABE_RIGHT: x = GetSystemMetrics(SM_CXSCREEN) - rect.Width; break; case ABE_BOTTOM: y = GetSystemMetrics(SM_CYSCREEN) - rect.Height; break; } } else { // Keep a part of the AppBar visible at all times int cxVisibleBorder = 2 * GetSystemMetrics(SM_CXBORDER); int cyVisibleBorder = 2 * GetSystemMetrics(SM_CYBORDER); // Calculate our x or y coordinate so that only the border is visible switch (GetState()) { case ABE_LEFT: x = -(rect.Width - cxVisibleBorder); break; case ABE_RIGHT: x = GetSystemMetrics(SM_CXSCREEN) - cxVisibleBorder; break; case ABE_TOP: y = -(rect.Height - cyVisibleBorder); break; case ABE_BOTTOM: y = GetSystemMetrics(SM_CYSCREEN) - cyVisibleBorder; break; } } rect = new RECT(x, y, x + rect.Width, y + rect.Height); return true; } private void ShowHiddenAppBar (bool show /*= true*/) { // Get our window location in screen coordinates. RECT position = new RECT(); GetWindowRect(this.Handle, ref position); this.appBarState.autoHideIsVisible = true; // Assume that we are visible if (AdjustLocationForAutohide(show, ref position)) { // the rectangle was adjusted, we are an autohide bar // Rememebr whether we are visible or not. this.appBarState.autoHideIsVisible = show; // Slide window in from or out to the edge SlideWindow(position); } if (show) // Associate a timer with the AppBar. The timer is used to determine // when a visible, inactive, auto-hide AppBar should be re-hidden. SetTimer(this.Handle, AUTOHIDETIMERID, AUTOHIDETIMERINTERVAL, 0); else { // Must have just hidden it, so don't bother with the timer for a while KillTimer(this.Handle, AUTOHIDETIMERID); } } private void SlideWindow(RECT rectEnd) { bool fullDragOn = false; // Only slide the window if the user has FullDrag turned on SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, ref fullDragOn, 0); // Get the current window position RECT rectStart = new RECT(); GetWindowRect(this.Handle, ref rectStart); if (fullDragOn && (rectStart != rectEnd)) { // Get our starting and ending time. int timeStart = GetTickCount(); int timeEnd = timeStart + AUTOHIDETIMERINTERVAL; int time; while ((time = GetTickCount()) < timeEnd) { // While we are still sliding, calculate our new position int x = rectStart.left - (rectStart.left - rectEnd.left) * (time - timeStart) / AUTOHIDETIMERINTERVAL; int y = rectStart.top - (rectStart.top - rectEnd.top) * (time - timeStart) / AUTOHIDETIMERINTERVAL; int nWidth = rectStart.Width - (rectStart.Width - rectEnd.Width) * (time - timeStart) / AUTOHIDETIMERINTERVAL; int nHeight = rectStart.Height - (rectStart.Height - rectEnd.Height) * (time - timeStart) / AUTOHIDETIMERINTERVAL; // Show the window at its changed position SetWindowPos(this.Handle, IntPtr.Zero, x, y, nWidth, nHeight, SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); UpdateWindow(this.Handle); } } // Make sure that the window is at its final position SetWindowPos(this.Handle, IntPtr.Zero, rectEnd.left, rectEnd.top, rectEnd.Width, rectEnd.Height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); UpdateWindow(this.Handle); } private static int GetEdgeFromPoint (int flags, POINT point) { int state = ABE_FLOAT; // Assume that the AppBar is floating // Let's get floating out of the way first if ((flags & ABF_ALLOWFLOAT) != 0) { // Get the rectangle that bounds the size of the screen // minus any docked (but not-autohidden) AppBars. RECT position = new RECT(); SystemParametersInfoA(SPI_GETWORKAREA, 0, ref position, 0); // Leave a 1/2 width/height-of-a-scrollbar gutter around the workarea InflateRect(ref position, -GetSystemMetrics(SM_CXVSCROLL), -GetSystemMetrics(SM_CYHSCROLL)); if (PtInRect(position, point) || ((flags & ABF_ALLOWANYEDGE) == 0)) { // If the point is in the adjusted workarea // OR no edges are allowed. return state; // The AppBar should float } } // If we get here, the AppBar should be docked; determine the proper edge // Get the dimensions of the screen int cxScreen = GetSystemMetrics(SM_CXSCREEN); int cyScreen = GetSystemMetrics(SM_CYSCREEN); // Find the center of the screen POINT pointCenter = new POINT(cxScreen / 2, cyScreen / 2); // Find the distance from the point to the center POINT pointOffset = new POINT(point.X - pointCenter.X, point.Y - pointCenter.Y); // Determine if the point is farther from the left/right or top/bottom bool isLeftOrRight = (Math.Abs(pointOffset.Y) * cxScreen) <= (Math.Abs(pointOffset.X) * cyScreen); // If (it should be left/right, AND we allow left/right) // OR we don't allow top/bottom if ((isLeftOrRight && ((flags & ABF_ALLOWLEFTRIGHT) != 0)) || ((flags & ABF_ALLOWTOPBOTTOM) == 0)) { state = (0 <= pointOffset.X) ? ABE_RIGHT : ABE_LEFT; } else { state = (0 <= pointOffset.Y) ? ABE_BOTTOM : ABE_TOP; } return state; // Return calculated edge } private int GetState () { return ((this.appBarState.proposedState != ABE_UNKNOWN) ? this.appBarState.proposedState : this.appBarState.state); } private bool IsEdgeLeftOrRight (int edge) { return ((edge == ABE_LEFT) || (edge == ABE_RIGHT)); } private void ClientToScreen(IntPtr hwnd, ref RECT rect) { POINT point = new POINT(); point.X = rect.left; point.Y = rect.top; ClientToScreen(hwnd, ref point); rect.left = point.X; rect.top = point.Y; point.X = rect.right; point.Y = rect.bottom; ClientToScreen(hwnd, ref point); rect.right = point.X; rect.bottom = point.Y; } private int GetStyle() { return GetWindowLong(this.Handle, GWL_STYLE); } private int GetExStyle() { return GetWindowLong(this.Handle, GWL_EXSTYLE); } private static bool PtInRect (RECT rect, POINT point) { if (point.X < rect.left | point.X > rect.right) return false; if (point.Y < rect.top | point.Y > rect.bottom) return false; return true; } private void AppBarStateChange (bool proposed, int stateProposed) { bool fullDragOn = false; // Find out if (the user has FullDrag turned on SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, ref fullDragOn, 0); // If FullDrag is turned on OR the appbar has changed position if ((fullDragOn | ! proposed) & !(stateProposed == ABE_UNKNOWN)) { if (stateProposed == ABE_FLOAT) // Show the window adornments ModifyStyle((short) GWL_STYLE, 0, (WS_CAPTION | WS_SYSMENU), (SWP_DRAWFRAME)); else // Hide the window adornments ModifyStyle((short) GWL_STYLE, (WS_CAPTION | WS_SYSMENU), 0, (SWP_DRAWFRAME)); } OnAppBarStateChange(proposed, stateProposed); } private void ABNFullScreenApp (bool open) { // This function is called when a FullScreen window is openning or // closing. A FullScreen window is a top-level window that has its caption // above the top of the screen allowing the entire screen to be occupied // by the window's client area. // If the AppBar is a topmost window when a FullScreen windiw is activated, // we need to change our window to a non-topmost window so that the AppBar // doesn't cover the FullScreen window's client area. // If the FullScreen window is closing, we need to set the AppBar's // Z-Order back to when the user wants it to be. if (this.appBarState.fullScreenAppOpen != open) { this.appBarState.fullScreenAppOpen = open; SetState(); } OnAbnFullScreenApp(open); } private void ABNPosChanged () { // The TaskBar or another AppBar has changed its size or position. if ((GetState() != ABE_FLOAT) && !this.appBarState.autoHide) { // If we're not floating and we're not auto-hidden, we have to // reposition our window. SetState(); } OnAbnPosChanged(); } private void ABNWindowArrange(bool beginning) { OnAbnWindowArrange(beginning); } private void ABNStateChange (int stateChangedMask, int state) { // Make our state mimic the taskbar's state. MimicState(stateChangedMask, state); OnAbnStateChange(stateChangedMask, state); } #endregion #region Protected Functions protected void OnMouseDown() { ReleaseCapture(); SendMessage(this.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0); } protected virtual void OnAppBarStateChange(bool proposed, int proposedState) { // This function intentionally left blank. } protected virtual void OnAppBarForcedToDocked() { // Display the ppBar's caption text as the message box caption text. string sz = "AppBar"; //GetWindowText(this.Handle, sz); MessageBox.Show(null, "There is already an auto hidden window on this edge.\r\nOnly one auto hidden window is allowed on each edge.", sz,MessageBoxButtons.OK, MessageBoxIcon.Stop); } protected virtual void OnAbnWindowArrange (bool beginning) { // This function intentionally left blank. } protected virtual void OnAbnStateChange (int stateChangedMask, int state) { // This function intentionally left blank. } protected virtual void OnAbnFullScreenApp (bool open) { // This function intentionally left blank. } private void OnAbnPosChanged () { // This function intentionally left blank. } #endregion #region Message Processors [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { case WM_APPBARNOTIFY: OnAppBarCallbackMsg(ref m); break; case WM_CREATE: OnCreate(ref m); return; case WM_DESTROY: OnDestroy(ref m); return; case WM_TIMER: OnTimer(ref m); return; case WM_NCHITTEST: OnNcHitTest(ref m); return; case WM_ENTERSIZEMOVE: this.moving = true; OnEnterSizeMove(ref m); Debug.WriteLine("OnEnterSizeMove"); break; case WM_EXITSIZEMOVE: OnExitSizeMove(ref m); this.moving = false; Debug.WriteLine("OnExitSizeMove"); break; case WM_NCMOUSEMOVE: OnNcMouseMove(ref m); return; case WM_WINDOWPOSCHANGED: OnWindowPosChanged(ref m); Debug.WriteLine("OnWindowPosChanged"); return; case WM_MOVING: OnMoving(ref m); Debug.WriteLine("OnMoving"); break; case WM_ACTIVATE: OnActivate(ref m); return; case WM_SIZING: OnSizing(ref m); Debug.WriteLine("OnSizing"); break; } base.WndProc(ref m); } // Called when the AppBar recieves a WM_APPBARNOTIFY window message private void OnAppBarCallbackMsg (ref Message message) { switch (message.WParam.ToInt32()) { case ABN_FULLSCREENAPP: ABNFullScreenApp(Convert.ToBoolean(message.WParam.ToInt32(), CultureInfo.InvariantCulture)); break; case ABN_POSCHANGED: ABNPosChanged(); break; case ABN_WINDOWARRANGE: ABNWindowArrange(Convert.ToBoolean(message.WParam.ToInt32(), CultureInfo.InvariantCulture)); break; case ABN_STATECHANGE: // The shell sends ABN_STATECHANGE notifications at inappropriate // times. So, we remember the TaskBar's current state and set // a mask indicating which states have actually changed. This mask // and the state information is passed to the derived class. // Get the state of the Taskbar int taskBarState = AppBarMessage(ABM_GETSTATE); // Prepare a mask indicating which states have changed. The code in // the derived class should only act on the states that have changed. int stateChangedMask = 0; if ((taskBarState & ABS_ALWAYSONTOP) != (this.appBarState.taskBarState & ABS_ALWAYSONTOP)) { stateChangedMask |= ABS_ALWAYSONTOP; } if ((taskBarState & ABS_AUTOHIDE) != (this.appBarState.taskBarState & ABS_AUTOHIDE)) { stateChangedMask |= ABS_AUTOHIDE; } // Call the derived class ABNStateChange(stateChangedMask, taskBarState); // Save the TaskBar's state so that we can see exactly which states // change the next time be get an ABN_STATECHANGE notification. this.appBarState.taskBarState = taskBarState; break; } message.Result = new IntPtr(0); } private void OnCreate(ref Message message) { //if (CDialog::OnCreate(lpCreateStruct) == -1) // return(-1); base.WndProc(ref message); // Register our AppBar window with the Shell AppBarMessage(ABM_NEW); // Force the AppBar to mimic the state of the TaskBar // Assume that all states have changed MimicState(ABS_ALWAYSONTOP | ABS_AUTOHIDE, this.appBarState.taskBarState); message.Result = new IntPtr(0); } private void OnDestroy(ref Message message) { //// CDialog::OnDestroy(); base.WndProc(ref message); // Kill the Autohide timer KillTimer(this.Handle, AUTOHIDETIMERID); // Unregister our AppBar window with the Shell SetState(ABE_UNKNOWN); } private void OnWindowPosChanged(ref Message message) { // CDialog::OnWindowPosChanged(lpwndpos); base.WndProc(ref message); // When our window changes position, tell the Shell so that any // auto-hidden AppBar on our edge stays on top of our window making it // always accessible to the user. AppBarMessage(ABM_WINDOWPOSCHANGED); } private void OnActivate(ref Message message) { //// CDialog::OnActivate(nState, pWndOther, bMinimized); base.WndProc(ref message); if ((message.WParam.ToInt32() & 0xFFFF) == WA_INACTIVE) { // Hide the AppBar if we are docked and auto-hidden ShowHiddenAppBar(false); } // When our window changes position, tell the Shell so that any // auto-hidden AppBar on our edge stays on top of our window making it // always accessible to the user. AppBarMessage(ABM_ACTIVATE); } private void OnTimer(ref Message message) { // Get the position of the mouse and the AppBar's position // Everything must be in screen coordinates. POINT point = new POINT(GetMessagePos()); RECT position = new RECT(); GetWindowRect(this.Handle, ref position); // Add a little margin around the AppBar InflateRect(ref position, 2 * GetSystemMetrics(SM_CXDOUBLECLK), 2 * GetSystemMetrics(SM_CYDOUBLECLK)); if (!PtInRect(position, point)) { // If the mouse is NOT over the AppBar, hide the AppBar ShowHiddenAppBar(false); } } private void OnNcMouseMove(ref Message message) { // If we are a docked, auto-hidden AppBar, shown us // when the user moves over our non-client area ShowHiddenAppBar(true); //// CDialog::OnNcMouseMove(nHitTest, point); base.WndProc(ref message); } private void OnNcHitTest(ref Message message) { // Find out what the system thinks is the hit test code //// int hitResult = CDialog::OnNcHitTest(point); base.WndProc(ref message); int hitResult = message.Result.ToInt32(); // NOTE: If the user presses the secondary mouse button, pretend that the // user clicked on the client area so that we get WM_CONTEXTMENU messages bool primaryMouseBtnDown = Convert.ToBoolean((GetAsyncKeyState(GetSystemMetrics(SM_SWAPBUTTON) != 0 ? VK_RBUTTON : VK_LBUTTON) & 0x8000) != 0, CultureInfo.InvariantCulture); if ((hitResult == HTCLIENT) && primaryMouseBtnDown) { // User clicked in client area, allow AppBar to move. We get this // behavior by pretending that the user clicked on the caption area. hitResult = HTCAPTION; } // When the AppBar is docked, the user can resize only one edge. // This next section determines which edge the user can resize. // To allow resizing, the AppBar window must have the WS_THICKFRAME style. // If the AppBar is docked and the hittest code is a resize code... if ((GetState() != ABE_FLOAT) && (GetState() != ABE_UNKNOWN) && (HTSIZEFIRST <= hitResult) && (hitResult <= HTSIZELAST)) { if (0 == (IsEdgeLeftOrRight(GetState()) ? this.appBarState.sizeInc.cx : this.appBarState.sizeInc.cy)) { // If the width/height size increment is zero, then resizing is NOT // allowed for the edge that the AppBar is docked on. hitResult = HTBORDER; // Pretend that the mouse is not on a resize border } else { // Resizing IS allowed for the edge that the AppBar is docked on. // Get the location of the appbar's client area in screen coordinates. RECT rect = new RECT(); GetClientRect(this.Handle, ref rect); ClientToScreen(this.Handle, ref rect); hitResult = HTBORDER; // Assume that we can't resize POINT point = new POINT(message.LParam.ToInt32()); switch (GetState()) { case ABE_LEFT: if (point.X > rect.right) hitResult = HTRIGHT; break; case ABE_TOP: if (point.Y > rect.bottom) hitResult = HTBOTTOM; break; case ABE_RIGHT: if (point.X < rect.left) hitResult = HTLEFT; break; case ABE_BOTTOM: if (point.Y < rect.top) hitResult = HTTOP; break; } } } message.Result = new IntPtr(hitResult); // Return the hittest code } private void OnEnterSizeMove(ref Message message) { // The user started moving/resizing the AppBar, save its current state. this.appBarState.proposedState = GetState(); message.Result = new IntPtr(0); } private void OnExitSizeMove(ref Message message) { // The user stopped moving/resizing the AppBar, set the new state. // Save the new proposed state of the AppBar. int proposedState = this.appBarState.proposedState; // Set the proposed state back to unknown. This causes GetState // to return the current state rather than the proposed state. this.appBarState.proposedState = ABE_UNKNOWN; // Get the location of the window in screen coordinates RECT position = new RECT(); GetWindowRect(this.Handle, ref position); // If the AppBar's state has changed... if (GetState() == proposedState) { switch (GetState()) { case ABE_UNKNOWN: break; case ABE_LEFT: case ABE_RIGHT: // Save the new width of the docked AppBar this.appBarState.dockSizeHorizontal = position.Width; break; case ABE_TOP: case ABE_BOTTOM: this.appBarState.dockSizeVertical = position.Height; break; } } // Always save the new position of the floating AppBar if (proposedState == ABE_FLOAT) { position.right = position.left + this.appBarState.floatRect.Width; position.bottom = position.top + this.appBarState.floatRect.Height; this.appBarState.floatRect = position; } // After setting the dimensions, set the AppBar to the proposed state SetState(proposedState); if (this.moving) this.Visible = true; message.Result = new IntPtr(0); } private void OnMoving(ref Message message) { // We control the moving of the AppBar. For example, if the mouse moves // close to an edge, we want to dock the AppBar. // The lParam contains the window's position proposed by the system RECT rect = new RECT(); RtlMoveMemory(ref rect, message.LParam, Marshal.SizeOf(rect)); // Get the location of the mouse cursor POINT point = new POINT(GetMessagePos()); // Where should the AppBar be based on the mouse position? int stateProposed = CalcProposedState(point); if ((this.appBarState.proposedState != ABE_FLOAT) && (stateProposed == ABE_FLOAT)) { // While moving, the user took us from a docked/autohidden state to // the float state. We have to calculate a rectangle location so that // the mouse cursor stays inside the window. rect = this.appBarState.floatRect; rect = new RECT(point.X - rect.Width / 2, point.Y, (point.X - rect.Width / 2) + rect.Width, point.Y + rect.Height); } // Remember the most-recently proposed state this.appBarState.proposedState = stateProposed; // Tell the system where to move the window based on the proposed state GetRect(stateProposed, ref rect); // Tell our derived class that there is a proposed state change AppBarStateChange(true, stateProposed); RtlMoveMemory(message.LParam, ref rect, Marshal.SizeOf(rect)); message.Result = new IntPtr(0); } private void OnSizing(ref Message message) { // We control the sizing of the AppBar. For example, if the user re-sizes // an edge, we want to change the size in descrete increments. // The lParam contains the window's position proposed by the system RECT rect = new RECT(); RtlMoveMemory(ref rect, message.LParam, Marshal.SizeOf(rect)); // Get the minimum size of the window assuming it has no client area. // This is the width/height of the window that must always be present RECT rectBorder = new RECT(0, 0, 0, 0); AdjustWindowRectEx(ref rectBorder, GetStyle(), 0, GetExStyle()); // We force the window to resize in discrete units set by the this.appBarState.sizeInc // member. From the new, proposed window dimensions passed to us, round // the width/height to the nearest discrete unit. int newWidth; int newHeight; if (this.appBarState.sizeInc.cx != 0) newWidth = ((rect.Width - rectBorder.Width) + this.appBarState.sizeInc.cx / 2) / this.appBarState.sizeInc.cx * this.appBarState.sizeInc.cx + rectBorder.Width; else newWidth = rect.right - rect.left; if (this.appBarState.sizeInc.cy != 0) newHeight = ((rect.Height - rectBorder.Height) + this.appBarState.sizeInc.cy / 2) / this.appBarState.sizeInc.cy * this.appBarState.sizeInc.cy + rectBorder.Height; else newHeight = rect.bottom - rect.top; // Adjust the rectangle's dimensions switch (message.WParam.ToInt32()) { case WMSZ_LEFT: rect.left = rect.right - newWidth; break; case WMSZ_TOP: rect.top = rect.bottom - newHeight; break; case WMSZ_RIGHT: rect.right = rect.left + newWidth; break; case WMSZ_BOTTOM: rect.bottom = rect.top + newHeight; break; case WMSZ_BOTTOMLEFT: rect.bottom = rect.top + newHeight; rect.left = rect.right - newWidth; break; case WMSZ_BOTTOMRIGHT: rect.bottom = rect.top + newHeight; rect.right = rect.left + newWidth; break; case WMSZ_TOPLEFT: rect.left = rect.right - newWidth; rect.top = rect.bottom - newHeight; break; case WMSZ_TOPRIGHT: rect.top = rect.bottom - newHeight; rect.right = rect.left + newWidth; break; } RtlMoveMemory(message.LParam, ref rect, Marshal.SizeOf(rect)); message.Result = new IntPtr(0); } #endregion #region Event Handlers private void AppBar_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { // Trap the mousedown to allow moving the form by clicking on the client area. OnMouseDown(); } private void AppBarForm_LocationChanged(object sender, System.EventArgs e) { // Trap when the forms location is set from the inheriting forms properties. // Basically, this event fires once for the AppBar class, but initializing will be true // It fires again when the inheriting form sets it's location. At this time, we record // the location and size of the form, and then disable this event from firing again if (!this.initializing) { this.appBarState.floatRect.left = this.Left; this.appBarState.floatRect.top = this.Top; this.appBarState.floatRect.right = this.Right; this.appBarState.floatRect.bottom = this.Bottom; this.LocationChanged -= new System.EventHandler(this.AppBarForm_LocationChanged); } } private void AppBarForm_Load(object sender, System.EventArgs e) { if (!this.DesignMode) SetState(this.appBarState.state); } #endregion #region Custom Editor /// /// This code is courtesy of Jose Castanedo of Janus Systems /// www.janusys.com /// Provides a custom editor for the Docking Flags which displays as a drop down list with check /// boxes allowing the user to select one or more options /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] public class DockFlagConverter : TypeConverter { /// /// Constructor takes no arguments /// public DockFlagConverter() { } public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context,Type type) { if (type == typeof(string)) { return true; } else { return base.CanConvertTo(type); } } public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context,System.Globalization.CultureInfo culture,object value,Type destinationType) { if (value == null) { return string.Empty; } else { Type type = value.GetType(); string strValue = string.Empty; Array values = Enum.GetValues(type); if (type == typeof(DockFlags)) { for(int i = 0; i 0) strValue += ", "; strValue += values.GetValue(i).ToString(); } } } } } return strValue; } } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] public class DockFlagEditor : System.Drawing.Design.UITypeEditor { private IWindowsFormsEditorService edSvc = null; public DockFlagEditor() { } protected virtual void SetEditorProps(object value,System.Windows.Forms.CheckedListBox editor) { Type type = value.GetType(); Array values = Enum.GetValues(type); for (int i = 0; i < values.Length; i++) { editor.Items.Add(values.GetValue(i)); if ((int) values.GetValue(i) != 0) { if (((int) value & (int) values.GetValue(i)) == (int) values.GetValue(i)) { editor.SetItemChecked(i, true); } } else { if ((int) value == 0) { editor.SetItemChecked(i, true); } } } editor.BorderStyle = System.Windows.Forms.BorderStyle.None; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { if (context != null && context.Instance != null && provider != null) { edSvc = (IWindowsFormsEditorService) provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null) { System.Windows.Forms.CheckedListBox listBox = new System.Windows.Forms.CheckedListBox(); listBox.CheckOnClick = true; this.SetEditorProps(value, listBox); edSvc.DropDownControl(listBox); if (value.GetType() == typeof(DockFlags)) { DockFlags proposedValue = DockFlags.AllowFloat; for(int i=0; i

Answers (1)