哇靠,太复杂了。用控件吧,很简单的。我有个源码,你看<br><br>{*****************************************************************************}<br>{ }<br>{ TAppBar Class v1.4 }<br>{ implements Application Desktop Toolbar }<br>{ (based on J.Richter's CAppBar MFC Class) }<br>{ }<br>{ Copyright (c) 1997/98 Paolo Giacomuzzi }<br>{ e-mail: paolo.giacomuzzi@usa.net }<br>{ http://www.geocities.com/SiliconValley/9486 }<br>{ }<br>{*****************************************************************************}<br><br><br>unit AppBar;<br><br><br>interface<br><br><br>uses<br> Windows, Messages, SysUtils, Classes, Forms, Dialogs, Controls, ExtCtrls,<br> ShellApi, Registry;<br><br><br>const<br> // AppBar's user notification message<br> WM_APPBARNOTIFY = WM_USER + 100;<br><br> // Timer interval<br> SLIDE_DEF_TIMER_INTERVAL = 400; // milliseconds<br><br> // Defaults<br> AB_DEF_SIZE_INC = 1;<br> AB_DEF_DOCK_SIZE = 32;<br> AB_DEF_ROOT_KEY = HKEY_CURRENT_USER;<br> AB_DEF_KEY_NAME = 'Software/AppBar/1.4/Delphi';<br><br><br>type<br> // You can send to the Windows shell one of the following messages:<br> // Message Description<br> // -------------- --------------------------------------------------<br> // ABM_NEW Register a new AppBar to the system<br> // ABM_REMOVE Remove a previously created AppBar from the system<br> // ABM_QUERYPOS Query the AppBar position<br> // ABM_SETPOS Set the AppBar position<br> // ABM_GETSTATE Get the edge the Appbar is docked to<br> // ABM_GETTASKBARPOS Get the Explorer Taskbar position<br> // ABM_ACTIVATE Activate the AppBar<br> // ABM_GETAUTOHIDEBAR Query if AppBar has Auto-hide behavior<br> // ABM_SETAUTOHIDEBAR Set the AppBar's Auto-hide behavior<br><br> // The ABM_message constants are defined in SHELLAPI.PAS as follows:<br> // ABM_NEW = $00000000;<br> // ABM_REMOVE = $00000001;<br> // ABM_QUERYPOS = $00000002;<br> // ABM_SETPOS = $00000003;<br> // ABM_GETSTATE = $00000004;<br> // ABM_GETTASKBARPOS = $00000005;<br> // ABM_ACTIVATE = $00000006;<br> // ABM_GETAUTOHIDEBAR = $00000007;<br> // ABM_SETAUTOHIDEBAR = $00000008;<br> // ABM_WINDOWPOSCHANGED = $00000009;<br><br> // The following enumerated type defines the constants in the table<br> TAppBarMessage = (abmNew, abmRemove, abmQueryPos, abmSetPos, abmGetState,<br> abmGetTaskBarPos, abmActivate, abmGetAutoHideBar,<br> abmSetAutoHideBar, abmWindowPosChanged);<br><br> // An AppBar can be in one of 6 states shown in the table below:<br> // State Description<br> // ----------- -----------------------------------------------------<br> // ABE_UNKNOWN The Appbar is in an unknown state<br> // (usually during construction/destruction)<br> // ABE_FLOAT The AppBar is floating on the screen<br> // ABE_LEFT The Appbar is docked on the left edge of the screen<br> // ABE_TOP The Appbar is docked on the top edge of the screen<br> // ABE_RIGHT The Appbar is docked on the right edge of the screen<br> // ABE_BOTTOM The Appbar is docked on the bottom edge of the screen<br><br> // The ABE_edge state constants are defined in SHELLAPI.PAS as follows:<br> // ABE_LEFT = 0;<br> // ABE_TOP = 1;<br> // ABE_RIGHT = 2;<br> // ABE_BOTTOM = 3;<br><br> // The ABE_UNKNOWN and ABE_FLOAT constants are defined here as follows:<br> // ABE_UNKNOWN = 4;<br> // ABE_FLOAT = 5;<br><br> // The following enumerated type defines the constants in the table<br> // (Values are mutually exclusive)<br> TAppBarEdge = (abeLeft, abeTop, abeRight, abeBottom, abeUnknown, abeFloat);<br><br> // An AppBar can have several behavior flags as shown below:<br> // Flag Description<br> // --------------------------- -----------------------------------<br> // ABF_ALLOWLEFT Allow dock on left of screen<br> // ABF_ALLOWRIGHT Allow dock on right of screen<br> // ABF_ALLOWTOP Allow dock on top of screen<br> // ABF_ALLOWBOTTOM Allow dock on bottom of screen<br> // ABF_ALLOWFLOAT Allow float in the middle of screen<br><br> // The following enumerated type defines the constants in the table<br> TAppBarFlag = (abfAllowLeft, abfAllowTop, abfAllowRight, abfAllowBottom,<br> abfAllowFloat);<br> TAppBarFlags = set of TAppBarFlag;<br><br> // The following enumerated type defines the AppBar behavior in the Taskbar<br> TAppBarTaskEntry = (abtShow, abtHide, abtFloatDependent);<br><br> // The record below contains all of the AppBar settings that<br> // can be saved/loaded in/from the Registry<br> TAppBarSettings = record<br> cbSize : DWORD; // Size of this structure<br> abEdge : TAppBarEdge; // ABE_UNKNOWN, ABE_FLOAT, or ABE_edge<br> abFlags : TAppBarFlags; // ABF_* flags<br> bAutohide : Boolean; // Should AppBar be auto-hidden when docked?<br> bAlwaysOnTop : Boolean; // Should AppBar always be on top?<br> bSlideEffect : Boolean; // Should AppBar slide?<br> nTimerInterval : Integer; // Slide Timer Interval (determines speed)<br> szSizeInc : TSize; // Discrete width/height size increments<br> szDockSize : TSize; // Width/Height for docked bar<br> rcFloat : TRect; // Floating rectangle in screen coordinates<br> nMinWidth : Integer; // Min allowed width<br> nMinHeight : Integer; // Min allowed height<br> nMaxWidth : Integer; // Max allowed width<br> nMaxHeight : Integer; // Max allowed height<br> szMinDockSize : TSize; // Min Width/Height when docked<br> szMaxDockSize : TSize; // Max Width/Height when docked<br> abTaskEntry : TAppBarTaskEntry; // AppBar behavior in the Taskbar<br> end;<br><br> // The record below contains the settings location in the registry<br> TAppBarSettingsLocation = record<br> nRootKey : Integer; // HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE<br> KeyName : String; // Key Name starting from root<br> end;<br><br> // TAppBar class ////////////////////////////////////////////////////////////<br> TAppBar = class(TForm)<br><br> private<br><br> { Internal implementation state variables }<br><br> // This AppBar's settings info<br> FABS : TAppBarSettings;<br><br> // We need a member variable which tracks the proposed edge of the<br> // AppBar while the user is moving it, deciding where to position it.<br> // While not moving, this member must contain ABE_UNKNOWN so that<br> // GetEdge returns the current edge contained in FABS.abEdge.<br> // While moving the AppBar, FabEdgeProposedPrev contains the<br> // proposed edge based on the position of the AppBar. The proposed<br> // edge becomes the new edge when the user stops moving the AppBar.<br> FabEdgeProposedPrev : TAppBarEdge;<br><br> // We need a member variable which tracks whether a full screen<br> // application window is open<br> FbFullScreenAppOpen : Boolean;<br><br> // We need a member variable which tracks whether our autohide window<br> // is visible or not<br> FbAutoHideIsVisible : Boolean;<br><br> // We need a timer to to determine when the AppBar should be re-hidden<br> FTimer : TTimer;<br><br> // We need a member variable to store the settings location in the registry<br> FabSettingsLocation : TAppBarSettingsLocation;<br><br> { Internal implementation functions }<br><br> // Modifies window creation flags<br> procedure CreateParams (var Params: TCreateParams); override;<br><br> // These functions encapsulate the shell's SHAppBarMessage function<br> function AppBarMessage (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge;<br> lParam : LPARAM;<br> bRect : Boolean;<br> var rc : TRect) : UINT;<br><br> function AppBarMessage1 (abMessage : TAppBarMessage) : UINT;<br><br> function AppBarMessage2 (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge) : UINT;<br><br> function AppBarMessage3 (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge;<br> lParam : LPARAM) : UINT;<br><br> function AppBarMessage4 (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge;<br> lParam : LPARAM;<br> var rc : TRect) : UINT;<br><br> // Gets a edge (ABE_FLOAT or ABE_edge) from a point (screen coordinates)<br> function CalcProposedState (var pt : TSmallPoint) : TAppBarEdge;<br><br> // Gets a retangle position (screen coordinates) from a proposed state<br> procedure GetRect (abEdgeProposed : TAppBarEdge; var rcProposed : TRect);<br><br> // Adjusts the AppBar's location to account for autohide<br> // Returns TRUE if rectangle was adjusted<br> function AdjustLocationForAutohide (bShow : Boolean;<br> var rc : TRect) : Boolean;<br><br> // If AppBar is Autohide and docked, shows/hides the AppBar<br> procedure ShowHiddenAppBar (bShow : Boolean);<br><br> // When Autohide AppBar is shown/hidden, slides in/out of view<br> procedure SlideWindow (var rcEnd : TRect);<br><br> // Returns which edge we're autohidden on or ABE_UNKNOWN<br> function GetAutohideEdge : TAppBarEdge;<br><br> // Returns a TSmallPoint that gives the cursor position in screen coords<br> function GetMessagePosition : TSmallPoint;<br><br> // Changes the style of a window (translated from AfxModifyStyle)<br> function ModifyStyle (hWnd : THandle;<br> nStyleOffset : Integer;<br> dwRemove : DWORD;<br> dwAdd : DWORD;<br> nFlags : UINT) : Boolean;<br><br> protected<br><br> { Property selector functions }<br><br> // Retrieves the AppBar's edge. If the AppBar is being positioned, its<br> // proposed state is returned instead<br> function GetEdge : TAppBarEdge;<br><br> // Changes the AppBar's edge to ABE_UNKNOWN, ABE_FLOAT or an ABE_edge<br> procedure SetEdge (abEdge : TAppBarEdge);<br><br> // Changes the slide time interval<br> procedure SetSlideTime (nInterval : Integer);<br><br> { Overridable functions }<br><br> // Called when the AppBar's proposed state changes<br> procedure OnAppBarStateChange (bProposed : Boolean;<br> abEdgeProposed : TAppBarEdge); virtual;<br><br> // Called if user attempts to dock an Autohide AppBar on<br> // an edge that already contains an Autohide AppBar<br> procedure OnAppBarForcedToDocked; virtual;<br><br> // Called when AppBar gets an ABN_FULLSCREENAPP notification<br> procedure OnABNFullScreenApp (bOpen : Boolean); virtual;<br><br> // Called when AppBar gets an ABN_POSCHANGED notification<br> procedure OnABNPosChanged; virtual;<br><br> // Called when AppBar gets an ABN_WINDOWARRANGE notification<br> procedure OnABNWindowArrange (bBeginning : Boolean); virtual;<br><br> { Message handlers }<br><br> // Called when the AppBar receives a WM_APPBARNOTIFY window message<br> procedure OnAppBarCallbackMsg(var Msg : TMessage); message WM_APPBARNOTIFY;<br><br> // Called when the AppBar form is first created<br> procedure OnCreate (var Msg: TWMCreate); message WM_CREATE;<br><br> // Called when the AppBar form is about to be destroyed<br> procedure OnDestroy (var Msg : TWMDestroy); message WM_DESTROY;<br><br> // Called when the AppBar receives a WM_WINDOWPOSCHANGED message<br> procedure OnWindowPosChanged (var Msg : TWMWindowPosChanged);<br> message WM_WINDOWPOSCHANGED;<br><br> // Called when the AppBar receives a WM_ACTIVATE message<br> procedure OnActivate (var Msg : TWMActivate); message WM_ACTIVATE;<br><br> // Called every timer tick<br> procedure OnAppBarTimer (Sender : TObject);<br><br> // Called when the AppBar receives a WM_NCMOUSEMOVE message<br> procedure OnNcMouseMove (var Msg : TWMNCMouseMove); message WM_NCMOUSEMOVE;<br><br> // Called when the AppBar receives a WM_NCHITTEST message<br> procedure OnNcHitTest (var Msg: TWMNCHitTest); message WM_NCHITTEST;<br><br> // Called when the AppBar receives a WM_ENTERSIZEMOVE message<br> procedure OnEnterSizeMove (var Msg : TMessage); message WM_ENTERSIZEMOVE;<br><br> // Called when the AppBar receives a WM_EXITSIZEMOVE message<br> procedure OnExitSizeMove (var Msg : TMessage); message WM_EXITSIZEMOVE;<br><br> // Called when the AppBar receives a WM_MOVING message<br> procedure OnMoving (var Msg : TMessage); message WM_MOVING;<br><br> // Called when the AppBar receives a WM_SIZING message<br> procedure OnSizing (var Msg : TMessage); message WM_SIZING;<br><br> // Called when the AppBar receives a WM_GETMINMAXINFO message<br> procedure OnGetMinMaxInfo (var Msg : TWMGetMinMaxInfo);<br> message WM_GETMINMAXINFO;<br><br> { AppBar-specific helper functions }<br><br> // Returns TRUE if abEdge is ABE_LEFT or ABE_RIGHT, else FALSE is returned<br> function IsEdgeLeftOrRight (abEdge : TAppBarEdge) : Boolean;<br><br> // Returns TRUE if abEdge is ABE_TOP or ABE_BOTTOM, else FALSE is returned<br> function IsEdgeTopOrBottom (abEdge : TAppBarEdge) : Boolean;<br><br> // Returns TRUE if abEdge is ABE_FLOAT, else FALSE is returned<br> function IsFloating (abEdge : TAppBarEdge) : Boolean;<br><br> // Returns TRUE if abFlags contain an at least allowed edge to dock on<br> function IsDockable (abFlags : TAppBarFlags) : Boolean;<br><br> // Returns TRUE if abFlags contain abfAllowLeft and abfAllowRight<br> function IsDockableVertically (abFlags : TAppBarFlags) : Boolean;<br><br> // Returns TRUE if abFlags contain abfAllowTop and abfAllowBottom<br> function IsDockableHorizontally (abFlags : TAppBarFlags) : Boolean;<br><br> // Forces the shell to update its AppBar list and the workspace area<br> procedure ResetSystemKnowledge;<br><br> // Returns a proposed edge or ABE_FLOAT based on ABF_* flags and a<br> // point specified in screen coordinates<br> function GetEdgeFromPoint (abFlags : TAppBarFlags;<br> pt : TSmallPoint) : TAppBarEdge;<br><br> public<br><br> { Public member functions }<br><br> // Constructs an AppBar<br> constructor Create (Owner : TComponent); override;<br><br> // Destroys a previously created AppBar<br> destructor Destroy; override;<br><br> // Forces the AppBar's visual appearance to match its internal state<br> procedure UpdateBar; virtual;<br><br> // Loads settings from the registry at RootKey and KeyName location.<br> // Returns TRUE if the settings are available, else FALSE<br> function LoadSettings : Boolean; virtual;<br><br> // Saves settings into the registry at RootKey and KeyName location.<br> // Returns TRUE if succeeded, else FALSE<br> function SaveSettings : Boolean; virtual;<br><br> published<br><br> { Properties }<br><br> // Allowed dockable edges<br> property Flags : TAppBarFlags read FABS.abFlags write FABS.abFlags;<br><br> // Horizontal size increment<br> property HorzSizeInc : Integer read FABS.szSizeInc.cx<br> write FABS.szSizeInc.cx;<br> // Vertical size increment<br> property VertSizeInc : Integer read FABS.szSizeInc.cy<br> write FABS.szSizeInc.cy;<br> // Edge to dock on<br> property Edge : TAppBarEdge read GetEdge write SetEdge;<br><br> // Auto-hide On/Off<br> property AutoHide : Boolean read FABS.bAutohide write FABS.bAutohide;<br><br> // Always On Top On/Off<br> property AlwaysOnTop : Boolean read FABS.bAlwaysOnTop<br> write FABS.bAlwaysOnTop;<br> // Slide Effect On/Off<br> property SlideEffect : Boolean read FABS.bSlideEffect<br> write FABS.bSlideEffect;<br> // Slide Time<br> property SlideTime : Integer read FABS.nTimerInterval write SetSlideTime;<br><br> // Horizontal size when docked on left or right<br> property HorzDockSize : Integer read FABS.szDockSize.cy<br> write FABS.szDockSize.cy;<br><br> // Vertical size when docked on top or bottom<br> property VertDockSize : Integer read FABS.szDockSize.cx<br> write FABS.szDockSize.cx;<br><br> // AppBar coordinates when floating<br> property FloatLeft : Integer read FABS.rcFloat.Left<br> write FABS.rcFloat.Left;<br> property FloatTop : Integer read FABS.rcFloat.Top<br> write FABS.rcFloat.Top;<br> property FloatRight : Integer read FABS.rcFloat.Right<br> write FABS.rcFloat.Right;<br> property FloatBottom : Integer read FABS.rcFloat.Bottom<br> write FABS.rcFloat.Bottom;<br><br> // AppBar MinMax dimensions when floating<br> property MinWidth : Integer read FABS.nMinWidth write FABS.nMinWidth;<br> property MinHeight : Integer read FABS.nMinHeight write FABS.nMinHeight;<br> property MaxWidth : Integer read FABS.nMaxWidth write FABS.nMaxWidth;<br> property MaxHeight : Integer read FABS.nMaxHeight write FABS.nMaxHeight;<br><br> // Min Height when docked horizontally<br> property MinHorzDockSize : Integer read FABS.szMinDockSize.cy<br> write FABS.szMinDockSize.cy;<br><br> // Min Width when docked vertically<br> property MinVertDockSize : Integer read FABS.szMinDockSize.cx<br> write FABS.szMinDockSize.cx;<br><br> // Max Height when docked horizontally<br> property MaxHorzDockSize : Integer read FABS.szMaxDockSize.cy<br> write FABS.szMaxDockSize.cy;<br><br> // Max Width when docked vertically<br> property MaxVertDockSize : Integer read FABS.szMaxDockSize.cx<br> write FABS.szMaxDockSize.cx;<br><br> // AppBar behavior in the Window Taskbar<br> property TaskEntry : TAppBarTaskEntry read FABS.abTaskEntry<br> write FABS.abTaskEntry;<br><br> // RootKey in the registry where settings should be loaded/saved<br> property RootKey : Integer read FabSettingsLocation.nRootKey<br> write FabSettingsLocation.nRootKey;<br><br> // KeyName in the registry where settings should be loaded/saved<br> property KeyName : String read FabSettingsLocation.KeyName<br> write FabSettingsLocation.KeyName;<br><br> end;<br><br><br>implementation<br><br><br>{ Internal implementation functions }<br><br><br>// TAppBar.CreateParams ///////////////////////////////////////////////////////<br>procedure TAppBar.CreateParams (var Params: TCreateParams);<br>var<br> dwAdd, dwRemove, dwAddEx, dwRemoveEx : DWORD;<br>begin<br> // Call the inherited first<br> inherited CreateParams(Params);<br><br> // Styles to be added<br> dwAdd := 0;<br> dwAddEx := WS_EX_TOOLWINDOW;<br><br> // Styles to be removed<br> dwRemove := WS_SYSMENU or WS_MAXIMIZEBOX or WS_MINIMIZEBOX;<br> dwRemoveEx := WS_EX_APPWINDOW;<br><br> // Modify style flags<br> with Params do begin<br> Style := Style and (not dwRemove);<br> Style := Style or dwAdd;<br> ExStyle := ExStyle and (not dwRemoveEx);<br> ExStyle := ExStyle or dwAddEx;<br> end;<br>end;<br><br><br>// TAppBar.AppBarMessage //////////////////////////////////////////////////////<br>function TAppBar.AppBarMessage (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge;<br> lParam : LPARAM;<br> bRect : Boolean;<br> var rc : TRect) : UINT;<br>var<br> abd : TAppBarData;<br>begin<br> // Initialize an APPBARDATA structure<br> abd.cbSize := sizeof(abd);<br> abd.hWnd := Handle;<br> abd.uCallbackMessage := WM_APPBARNOTIFY;<br> abd.uEdge := Ord(abEdge);<br> if bRect then<br> abd.rc := rc<br> else<br> abd.rc := Rect(0, 0, 0, 0);<br> abd.lParam := lParam;<br> Result := SHAppBarMessage(Ord(abMessage), abd);<br><br> // If the caller passed a rectangle, return the updated rectangle<br> if bRect then<br> rc := abd.rc;<br>end;<br><br><br>// TAppBar.AppBarMessage1 /////////////////////////////////////////////////////<br>function TAppBar.AppBarMessage1 (abMessage : TAppBarMessage) : UINT;<br>var<br> rc : TRect;<br>begin<br> Result := AppBarMessage(abMessage, abeFloat, 0, False, rc);<br>end;<br><br><br>// TAppBar.AppBarMessage2 /////////////////////////////////////////////////////<br>function TAppBar.AppBarMessage2 (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge) : UINT;<br>var<br> rc : TRect;<br>begin<br> Result := AppBarMessage(abMessage, abEdge, 0, False, rc);<br>end;<br><br><br>// TAppBar.AppBarMessage3 /////////////////////////////////////////////////////<br>function TAppBar.AppBarMessage3 (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge;<br> lParam : LPARAM) : UINT;<br>var<br> rc : TRect;<br>begin<br> Result := AppBarMessage(abMessage, abEdge, lParam, False, rc);<br>end;<br><br><br>// TAppBar.AppBarMessage4 /////////////////////////////////////////////////////<br>function TAppBar.AppBarMessage4 (abMessage : TAppBarMessage;<br> abEdge : TAppBarEdge;<br> lParam : LPARAM;<br> var rc : TRect) : UINT;<br>begin<br> Result := AppBarMessage(abMessage, abEdge, lParam, True, rc);<br>end;<br><br><br>// TAppBar.CalcProposedState //////////////////////////////////////////////////<br>function TAppBar.CalcProposedState (var pt : TSmallPoint) : TAppBarEdge;<br>var<br> bForceFloat : Boolean;<br>begin<br> // Force the AppBar to float if the user is holding down the Ctrl key<br> // and the AppBar's style allows floating<br> bForceFloat := ((GetKeyState(VK_CONTROL) and $8000) <> 0) and<br> (abfAllowFloat in FABS.abFlags);<br> if bForceFloat then<br> Result := abeFloat<br> else<br> Result := GetEdgeFromPoint(FABS.abFlags, pt);<br>end;<br><br><br>// TAppBar.GetRect ////////////////////////////////////////////////////////////<br>procedure TAppBar.GetRect (abEdgeProposed : TAppBarEdge;<br> var rcProposed : TRect);<br>begin<br> // This function finds the x, y, cx, cy of the AppBar window<br> if abEdgeProposed = abeFloat then begin<br> // The AppBar is floating, the proposed rectangle is correct<br> end else begin<br> // The AppBar is docked or auto-hide<br> // Set dimensions to full screen<br> with rcProposed do begin<br> Left := 0;<br> Top := 0;<br> Right := GetSystemMetrics(SM_CXSCREEN);<br> Bottom := GetSystemMetrics(SM_CYSCREEN);<br> end;<br><br> // Subtract off what we want from the full screen dimensions<br> if not FABS.bAutohide then<br> // Ask the shell where we can dock<br> AppBarMessage4(abmQueryPos, abEdgeProposed, LPARAM(False), rcProposed);<br><br> case abEdgeProposed of<br> abeLeft:<br> rcProposed.Right := rcProposed.Left + FABS.szDockSize.cx;<br> abeTop:<br> rcProposed.Bottom := rcProposed.Top + FABS.szDockSize.cy;<br> abeRight:<br> rcProposed.Left := rcProposed.Right - FABS.szDockSize.cx;<br> abeBottom:<br> rcProposed.Top := rcProposed.Bottom - FABS.szDockSize.cy;<br> end; // end of case<br><br> end; // end of else<br>end;<br><br><br>// TAppBar.AdjustLocationForAutohide //////////////////////////////////////////<br>function TAppBar.AdjustLocationForAutohide (bShow : Boolean;<br> var rc : TRect) : Boolean;<br>var<br> x, y : Integer;<br> cxVisibleBorder, cyVisibleBorder : Integer;<br>begin<br> if ((GetEdge = abeUnknown) or (GetEdge = abeFloat) or<br> (not FABS.bAutohide)) then begin<br> // If we are not docked on an edge OR we are not auto-hidden, there is<br> // nothing for us to do; just return<br> Result := False;<br> Exit;<br> end;<br><br> // Showing/hiding doesn't change our size; only our position<br> x := 0; y := 0; // Assume a position of (0, 0)<br><br> if bShow then<br> // If we are on the right or bottom, calculate our visible position<br> case GetEdge of<br> abeRight:<br> x := GetSystemMetrics(SM_CXSCREEN) - (rc.Right - rc.Left);<br> abeBottom:<br> y := GetSystemMetrics(SM_CYSCREEN) - (rc.Bottom - rc.Top);<br> end<br> else begin<br> // Keep a part of the AppBar visible at all times<br> cxVisibleBorder := 2 * GetSystemMetrics(SM_CXBORDER);<br> cyVisibleBorder := 2 * GetSystemMetrics(SM_CYBORDER);<br><br> // Calculate our x or y coordinate so that only the border is visible<br> case GetEdge of<br> abeLeft:<br> x := -((rc.Right - rc.Left) - cxVisibleBorder);<br> abeRight:<br> x := GetSystemMetrics(SM_CXSCREEN) - cxVisibleBorder;<br> abeTop:<br> y := -((rc.Bottom - rc.Top) - cyVisibleBorder);<br> abeBottom:<br> y := GetSystemMetrics(SM_CYSCREEN) - cyVisibleBorder;<br> end;<br> end;<br><br> with rc do begin<br> Right := x + (Right - Left);<br> Bottom := y + (Bottom - Top);<br> Left := x;<br> Top := y;<br> end;<br><br> Result := True;<br>end;<br><br><br>// TAppBar.ShowHiddenAppBar ///////////////////////////////////////////////////<br>procedure TAppBar.ShowHiddenAppBar (bShow : Boolean);<br>var<br> rc : TRect;<br>begin<br> // Get our window location in screen coordinates<br> GetWindowRect(Handle, rc);<br><br> // Assume that we are visible<br> FbAutoHideIsVisible := True;<br><br> if AdjustLocationForAutohide(bShow, rc) then begin<br> // the rectangle was adjusted, we are an autohide bar<br> // Remember whether we are visible or not<br> FbAutoHideIsVisible := bShow;<br><br> // Slide window in from or out to the edge<br> SlideWindow(rc);<br> end;<br>end;<br><br><br>// TAppBar.SlideWindow ////////////////////////////////////////////////////////<br>procedure TAppBar.SlideWindow (var rcEnd : TRect);<br>var<br> bFullDragOn : LongBool;<br> rcStart : TRect;<br> dwTimeStart, dwTimeEnd, dwTime : DWORD;<br> x, y, w, h : Integer;<br>begin<br> // Only slide the window if the user has FullDrag turned on<br> SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @bFullDragOn, 0);<br><br> // Get the current window position<br> GetWindowRect(Handle, rcStart);<br> if (FABS.bSlideEffect and bFullDragOn and<br> ((rcStart.Left <> rcEnd.Left  
or<br> (rcStart.Top <> rcEnd.Top ) or<br> (rcStart.Right <> rcEnd.Right ) or<br> (rcStart.Bottom <> rcEnd.Bottom))) then begin<br><br> // Get our starting and ending time<br> dwTimeStart := GetTickCount;<br> dwTimeEnd := dwTimeStart + FABS.nTimerInterval;<br> dwTime := dwTimeStart;<br> while (dwTime < dwTimeEnd) do begin<br> // While we are still sliding, calculate our new position<br> x := rcStart.Left - (rcStart.Left - rcEnd.Left)<br> * Integer(dwTime - dwTimeStart) div FABS.nTimerInterval;<br><br> y := rcStart.Top - (rcStart.Top - rcEnd.Top)<br> * Integer(dwTime - dwTimeStart) div FABS.nTimerInterval;<br><br> w := (rcStart.Right - rcStart.Left)<br> - ((rcStart.Right - rcStart.Left) - (rcEnd.Right - rcEnd.Left))<br> * Integer(dwTime - dwTimeStart) div FABS.nTimerInterval;<br><br> h := (rcStart.Bottom - rcStart.Top)<br> - ((rcStart.Bottom - rcStart.Top) - (rcEnd.Bottom - rcEnd.Top))<br> * Integer(dwTime - dwTimeStart) div FABS.nTimerInterval;<br><br> // Show the window at its changed position<br> SetWindowPos(Handle, 0, x, y, w, h,<br> SWP_NOZORDER or SWP_NOACTIVATE or SWP_DRAWFRAME);<br> UpdateWindow(Handle);<br> dwTime := GetTickCount;<br> end;<br> end;<br><br> // Make sure that the window is at its final position<br> Left := rcEnd.Left;<br> Top := rcEnd.Top;<br> Width := rcEnd.Right - rcEnd.Left;<br> Height := rcEnd.Bottom - rcEnd.Top;<br>end;<br><br><br>// TAppBar.GetAutohideEdge ////////////////////////////////////////////////////<br>function TAppBar.GetAutohideEdge : TAppBarEdge;<br>begin<br> if Handle = AppBarMessage2(abmGetAutoHideBar, abeLeft) then<br> Result := abeLeft<br> else if Handle = AppBarMessage2(abmGetAutoHideBar, abeTop) then<br> Result := abeTop<br> else if Handle = AppBarMessage2(abmGetAutoHideBar, abeRight) then<br> Result := abeRight<br> else if Handle = AppBarMessage2(abmGetAutoHideBar, abeBottom) then<br> Result := abeBottom<br> else<br> // NOTE: If AppBar is docked but not auto-hidden, we return ABE_UNKNOWN<br> Result := abeUnknown;<br>end;<br><br><br>// TAppBar.GetMessagePosition /////////////////////////////////////////////////<br>function TAppBar.GetMessagePosition : TSmallPoint;<br>var<br> pt : TSmallPoint;<br> dw : DWORD;<br>begin<br> dw := GetMessagePos;<br> pt.X := SHORT(dw);<br> pt.Y := SHORT((dw and $FFFF0000) shr 16);<br> Result := pt;<br>end;<br><br><br>// TAppBar.ModifyStyle ////////////////////////////////////////////////////////<br>function TAppBar.ModifyStyle (hWnd : THandle;<br> nStyleOffset : Integer;<br> dwRemove : DWORD;<br> dwAdd : DWORD;<br> nFlags : UINT) : Boolean;<br>var<br> dwStyle : DWORD;<br> dwNewStyle : DWORD;<br>begin<br> dwStyle := GetWindowLong(hWnd, nStyleOffset);<br> dwNewStyle := (dwStyle and (not dwRemove)) or dwAdd;<br><br> if dwStyle = dwNewStyle then begin<br> Result := False;<br> Exit;<br> end;<br><br> SetWindowLong(hWnd, nStyleOffset, dwNewStyle);<br><br> if nFlags <> 0 then<br> SetWindowPos(hWnd, 0, 0, 0, 0, 0,<br> SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or nFlags);<br><br> Result := True;<br>end;<br><br><br>{ Property selector functions }<br><br><br>// TAppBar.GetEdge ////////////////////////////////////////////////////////////<br>function TAppBar.GetEdge : TAppBarEdge;<br>begin<br> if FabEdgeProposedPrev <> abeUnknown then<br> Result := FabEdgeProposedPrev<br> else<br> Result := FABS.abEdge;<br>end;<br><br><br>// TAppBar.SetEdge ////////////////////////////////////////////////////////////<br>procedure TAppBar.SetEdge (abEdge : TAppBarEdge);<br>var<br> abCurrentEdge : TAppBarEdge;<br> currentRect : TRect;<br> rc : TRect;<br> hWnd : THandle;<br>begin<br> // If the AppBar is registered as auto-hide, unregister it<br> abCurrentEdge := GetAutohideEdge;<br><br> if abCurrentEdge <> abeUnknown then<br> // Our AppBar is auto-hidden, unregister it<br> AppBarMessage3(abmSetAutoHideBar, abCurrentEdge, LPARAM(False));<br><br> // Save the new requested state<br> FABS.abEdge := abEdge;<br><br> case abEdge of<br><br> abeUnknown: begin<br> // We are being completely unregistered.<br> // Probably, the AppBar window is being destroyed.<br> // If the AppBar is registered as NOT auto-hide, unregister it<br> AppBarMessage1(abmRemove);<br> end;<br><br> abeFloat: begin<br> // We are floating and therefore are just a regular window.<br> // Tell the shell that the docked AppBar should be of 0x0 dimensions<br> // so that the workspace is not affected by the AppBar<br> currentRect := Rect(0, 0, 0, 0);<br> AppBarMessage4(abmSetPos, abEdge, LPARAM(False), currentRect);<br> Left := FABS.rcFloat.Left;<br> Top := FABS.rcFloat.Top;<br> Width := FABS.rcFloat.Right - FABS.rcFloat.Left;<br> Height := FABS.rcFloat.Bottom - FABS.rcFloat.Top;<br> end;<br><br> else begin<br> if FABS.bAutohide and<br> (AppBarMessage3(abmSetAutoHideBar,<br> GetEdge,<br> LPARAM(True)) = 0) then begin<br> // We couldn't set the AppBar on a new edge, let's dock it instead<br> FABS.bAutohide := False;<br> // Call a virtual function to let derived classes know that the AppBar<br> // changed from auto-hide to docked<br> OnAppBarForcedToDocked;<br> end;<br><br> GetRect(GetEdge, rc);<br> if FABS.bAutohide then begin<br> currentRect := Rect(0, 0, 0, 0);<br> AppBarMessage4(abmSetPos, abeLeft, LPARAM(False), currentRect);<br> end else begin<br> // Tell the shell where the AppBar is<br> AppBarMessage4(abmSetPos, abEdge, LPARAM(False), rc);<br> end;<br><br> AdjustLocationForAutohide(FbAutoHideIsVisible, rc);<br><br> // Slide window in from or out to the edge<br> SlideWindow(rc);<br><br> end; // end of else<br><br> end; // end of case<br><br> // Set the AppBar's z-order appropriately<br> hWnd := HWND_NOTOPMOST; // Assume normal Z-Order<br> if FABS.bAlwaysOnTop then begin<br> // If we are supposed to be always-on-top, put us there<br> hWnd := HWND_TOPMOST;<br> if FbFullScreenAppOpen then<br> // But, if a full-screen window is opened, put ourself at the bottom<br> // of the z-order so that we don't cover the full-screen window<br> hWnd := HWND_BOTTOM;<br> end;<br> SetWindowPos(Handle,<br> hWnd,<br> 0, 0, 0, 0,<br> SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);<br><br> // Make sure that any auto-hide appbars stay on top of us after we move<br> // even though our activation state has not changed<br> AppBarMessage1(abmActivate);<br><br> // Tell our derived class that there is a state change<br> OnAppBarStateChange(False, abEdge);<br><br> // Show or hide the taskbar entry depending on AppBar position<br> case FABS.abTaskEntry of<br> abtShow :<br> ShowWindow(Application.Handle, SW_SHOW);<br> abtHide :<br> ShowWindow(Application.Handle, SW_HIDE);<br> abtFloatDependent :<br> case abEdge of<br> abeFloat:<br> ShowWindow(Application.Handle, SW_SHOW);<br> abeLeft, abeTop, abeRight, abeBottom :<br> ShowWindow(Application.Handle, SW_HIDE);<br> end;<br> end;<br>end;<br><br><br>// TAppBar.SetSlideTime ///////////////////////////////////////////////////////<br>procedure TAppBar.SetSlideTime (nInterval : Integer);<br>begin<br> FABS.nTimerInterval := nInterval;<br> FTimer.Interval := nInterval;<br>end;<br><br><br>{ Overridable functions }<br><br><br>// TAppBar.OnAppBarStateChange ////////////////////////////////////////////////<br>procedure TAppBar.OnAppBarStateChange (bProposed : Boolean;<br> abEdgeProposed : TAppBarEdge);<br>var<br> bFullDragOn : LongBool;<br>begin<br> // Find out if the user has FullDrag turned on<br> SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @bFullDragOn, 0);<br><br> // If FullDrag is turned on OR the appbar has changed position<br> if bFullDragOn or not bProposed then begin<br> if abEdgeProposed = abeFloat then<br> // Show the window adornments<br> ModifyStyle(Handle,<br> GWL_STYLE,<br> 0,<br> WS_CAPTION or WS_SYSMENU,<br> SWP_DRAWFRAME)<br> else<br> // Hide the window adornments<br> ModifyStyle(Handle,<br> GWL_STYLE,<br> WS_CAPTION or WS_SYSMENU,<br> 0,<br> SWP_DRAWFRAME);<br> end;<br>end;<br><br><br>// TAppBar.OnAppBarForcedToDocked /////////////////////////////////////////////<br>procedure TAppBar.OnAppBarForcedToDocked;<br>const<br> CRLF = #10#13;<br>begin<br> // Display the application name as the message box caption text.<br> MessageDlg('There is already an auto hidden window on this edge.' + CRLF +<br> 'Only one auto hidden window is allowed on each edge.',<br> mtInformation,<br> [mbOk],<br> 0);<br>end;<br><br>// TAppBar.OnABNFullScreenApp /////////////////////////////////////////////////<br>procedure TAppBar.OnABNFullScreenApp (bOpen : Boolean);<br>begin<br> // This function is called when a FullScreen window is openning or<br> // closing. A FullScreen window is a top-level window that has its caption<br> // above the top of the screen allowing the entire screen to be occupied<br> // by the window's client area.<br><br> // If the AppBar is a topmost window when a FullScreen window is activated,<br> // we need to change our window to a non-topmost window so that the AppBar<br> // doesn't cover the FullScreen window's client area.<br><br> // If the FullScreen window is closing, we need to set the AppBar's<br> // Z-Order back to when the user wants it to be.<br> FbFullScreenAppOpen := bOpen;<br> UpdateBar;<br>end;<br><br><br>// TAppBar.OnABNPosChanged ////////////////////////////////////////////////////<br>procedure TAppBar.OnABNPosChanged;<br>begin<br> // The TaskBar or another AppBar has changed its size or position<br> if (GetEdge <> abeFloat) and (not FABS.bAutohide) then<br> // If we're not floating and we're not auto-hidden, we have to<br> // reposition our window<br> UpdateBar;<br>end;<br><br><br>// TAppBar.OnABNWindowArrange /////////////////////////////////////////////////<br>procedure TAppBar.OnABNWindowArrange (bBeginning : Boolean);<br>begin<br> // This function intentionally left blank<br>end;<br><br><br>{ Message handlers }<br><br><br>// TAppBar.OnAppBarCallbackMsg ////////////////////////////////////////////////<br>procedure TAppBar.OnAppBarCallbackMsg (var Msg : TMessage);<br>begin<br> case Msg.WParam of<br><br> ABN_FULLSCREENAPP:<br> OnABNFullScreenApp(Msg.LParam <> 0);<br><br> ABN_POSCHANGED:<br> OnABNPosChanged;<br><br> ABN_WINDOWARRANGE:<br> OnABNWindowArrange(Msg.LParam <> 0);<br> end;<br>end;<br><br><br>// TAppBar.OnCreate ///////////////////////////////////////////////////////////<br>procedure TAppBar.OnCreate (var Msg : TWMCreate);<br>var<br> hMenu : THandle;<br>begin<br> inherited;<br> // Associate a timer with the AppBar. The timer is used to determine<br> // when a visible, inactive, auto-hide AppBar should be re-hidden<br> FTimer := TTimer.Create(Self);<br> with FTimer do begin<br> Interval := FABS.nTimerInterval;<br> OnTimer := OnAppBarTimer;<br> Enabled := True;<br> end;<br><br> // Save the initial position of the floating AppBar<br> FABS.rcFloat.Left := Left;<br> FABS.rcFloat.Top := Top;<br><br> // Register our AppBar window with the Shell<br> AppBarMessage1(abmNew);<br><br> // Update AppBar internal state<br> UpdateBar;<br><br> // Save the initial size of the floating AppBar<br> PostMessage(Handle, WM_ENTERSIZEMOVE, 0, 0);<br> PostMessage(Handle, WM_EXITSIZEMOVE, 0, 0);<br><br> // Remove system menu<br> hMenu := GetSystemMenu(Handle, False);<br> DeleteMenu(hMenu, SC_RESTORE, MF_BYCOMMAND);<br> DeleteMenu(hMenu, SC_MINIMIZE, MF_BYCOMMAND);<br> DeleteMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND);<br>end;<br><br><br>// TAppBar.OnDestroy //////////////////////////////////////////////////////////<br>procedure TAppBar.OnDestroy (var Msg : TWMDestroy);<br>begin<br> // Free the Autohide timer<br> FTimer.Enabled := False;<br> FTimer.Free;<br> // Unregister our AppBar window with the Shell<br> SetEdge(abeUnknown);<br> inherited;<br>end;<br><br><br>// TAppBar.OnWindowPosChanged /////////////////////////////////////////////////<br>procedure TAppBar.OnWindowPosChanged (var Msg : TWMWindowPosChanged);<br>begin<br> inherited;<br> // When our window changes position, tell the Shell so that any<br> // auto-hidden AppBar on our edge stays on top of our window making it<br> // always accessible to the user<br> AppBarMessage1(abmWindowPosChanged);<br>end;<br><br><br>// TAppBar.OnActivate /////////////////////////////////////////////////////////<br>procedure TAppBar.OnActivate (var Msg : TWMActivate);<br>begin<br> inherited;<br> if Msg.Active = WA_INACTIVE then<br> // Hide the AppBar if we are docked and auto-hidden<br> ShowHiddenAppBar(False);<br> // When our window changes position, tell the Shell so that any<br> // auto-hidden AppBar on our edge stays on top of our window making it<br> // always accessible to the user.<br> AppBarMessage1(abmActivate);<br>end;<br><br><br>// TAppBar.OnAppBarTimer //////////////////////////////////////////////////////<br>procedure TAppBar.OnAppBarTimer (Sender : TObject);<br>var<br> pt : TSmallPoint;<br> rc : TRect;<br>begin<br> if GetActiveWindow <> Handle then begin<br> // Possibly hide the AppBar if we are not the active window<br> // Get the position of the mouse and the AppBar's position<br> // Everything must be in screen coordinates<br> pt := GetMessagePosition;<br> GetWindowRect(Handle, rc);<br> // Add a little margin around the AppBar<br> InflateRect(rc,<br> 2 * GetSystemMetrics(SM_CXDOUBLECLK),<br> 2 * GetSystemMetrics(SM_CYDOUBLECLK));<br> if not PtInRect(rc, SmallPointToPoint(pt)) then<br> // If the mouse is NOT over the AppBar, hide the AppBar<br> ShowHiddenAppBar(False);<br> end;<br> inherited;<br>end;<br><br><br>// TAppBar.OnNcMouseMove //////////////////////////////////////////////////////<br>procedure TAppBar.OnNcMouseMove (var Msg : TWMNCMouseMove);<br>begin<br> // If we are a docked, auto-hidden AppBar, shown us<br> // when the user moves over our non-client area<br> ShowHiddenAppBar(True);<br> inherited;<br>end;<br><br><br>// TAppBar.OnNcHitTest ////////////////////////////////////////////////////////<br>procedure TAppBar.OnNcHitTest (var Msg: TWMNCHitTest);<br>var<br> u : UINT;<br> bPrimaryMouseBtnDown : Boolean;<br> rcClient : TRect;<br> pt : TPoint;<br> vKey : Integer;<br>begin<br> // Find out what the system thinks is the hit test code<br> inherited;<br> u := Msg.Result;<br><br> // NOTE: If the user presses the secondary mouse button, pretend that the<br> // user clicked on the client area so that we get WM_CONTEXTMENU messages<br> if GetSystemMetrics(SM_SWAPBUTTON) <> 0 then<br> vKey := VK_RBUTTON<br> else<br> vKey := VK_LBUTTON;<br> bPrimaryMouseBtnDown := ((GetAsyncKeyState(vKey) and $8000) <> 0);<br><br> pt.X := Msg.XPos;<br> pt.Y := Msg.YPos;<br> pt := ScreenToClient(pt);<br> if (u = HTCLIENT) and bPrimaryMouseBtnDown<br> and (ControlAtPos(pt, False) = nil) then<br> // User clicked in client area, allow AppBar to move. We get this<br> // behavior by pretending that the user clicked on the caption area<br> u := HTCAPTION;<br><br> // If the AppBar is floating and the hittest code is a resize code...<br> if ((GetEdge = abeFloat) and<br> (HTSIZEFIRST <= u) and (u <= HTSIZELAST)) then begin<br> case u of<br> HTLEFT, HTRIGHT:<br> if FABS.szSizeInc.cx = 0<br> then u := HTBORDER;<br> HTTOP, HTBOTTOM:<br> if FABS.szSizeInc.cy = 0<br> then u := HTBORDER;<br> HTTOPLEFT:<br> if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTBORDER<br> else if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy <> 0)<br> then u := HTTOP<br> else if (FABS.szSizeInc.cx <> 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTLEFT;<br> HTTOPRIGHT:<br> if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTBORDER<br> else if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy <> 0)<br> then u := HTTOP<br> else if (FABS.szSizeInc.cx <> 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTRIGHT;<br> HTBOTTOMLEFT:<br> if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTBORDER<br> else if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy <> 0)<br> then u := HTBOTTOM<br> else if (FABS.szSizeInc.cx <> 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTLEFT;<br> HTBOTTOMRIGHT:<br> if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTBORDER<br> else if (FABS.szSizeInc.cx = 0) and (FABS.szSizeInc.cy <> 0)<br> then u := HTBOTTOM<br> else if (FABS.szSizeInc.cx <> 0) and (FABS.szSizeInc.cy = 0)<br> then u := HTRIGHT;<br> end;<br> end;<br><br> // When the AppBar is docked, the user can resize only one edge.<br> // This next section determines which edge the user can resize.<br> // To allow resizing, the AppBar window must have the WS_THICKFRAME style<br><br> // If the AppBar is docked and the hittest code is a resize code...<br> if ((GetEdge <> abeFloat) and (GetEdge <> abeUnknown) and<br> (HTSIZEFIRST <= u) and (u <= HTSIZELAST)) then begin<br><br> if (IsEdgeLeftOrRight(GetEdge) and (FABS.szSizeInc.cx = 0)) or<br> (not IsEdgeLeftOrRight(GetEdge) and (FABS.szSizeInc.cy = 0)) then begin<br> // If the width/height size increment is zero, then resizing is NOT<br> // allowed for the edge that the AppBar is docked on<br> u := HTBORDER; // Pretend that the mouse is not on a resize border<br> end else begin<br> // Resizing IS allowed for the edge that the AppBar is docked on<br> // Get the location of the appbar's client area in screen coordinates<br> rcClient := GetClientRect;<br> pt.X := rcClient.Left;<br> pt.Y := rcClient.Top;<br> pt := ClientToScreen(pt);<br> rcClient.Left := pt.X;<br> rcClient.Top := pt.Y;<br> pt.X := rcClient.Right;<br> pt.Y := rcClient.Bottom;<br> pt := ClientToScreen(pt);<br> rcClient.Right := pt.X;<br> rcClient.Bottom := pt.Y;<br><br> u := HTBORDER; // Assume that we can't resize<br> case GetEdge of<br> abeLeft:<br> if Msg.XPos > rcClient.Right then<br> u := HTRIGHT;<br> abeTop:<br> if Msg.YPos > rcClient.Bottom then<br> u := HTBOTTOM;<br> abeRight:<br> if Msg.XPos < rcClient.Left then<br> u := HTLEFT;<br> abeBottom:<br> if Msg.YPos < rcClient.Top then<br> u := HTTOP;<br> end; // end of case<br> end; // end of else<br> end;<br><br> // Return the hittest code<br> Msg.Result := u;<br>end;<br><br><br>// TAppBar.OnEnterSizeMove ////////////////////////////////////////////////////<br>procedure TAppBar.OnEnterSizeMove (var Msg : TMessage);<br>begin<br> // The user started moving/resizing the AppBar, save its current state<br> FabEdgeProposedPrev := GetEdge;<br>end;<br><br><br>// TAppBar.OnExitSizeMove /////////////////////////////////////////////////////<br>procedure TAppBar.OnExitSizeMove (var Msg : TMessage);<br>var<br> abEdgeProposedPrev : TAppBarEdge;<br> rc, rcWorkArea : TRect;<br> w, h : Integer;<br>begin<br> // The user stopped moving/resizing the AppBar, set the new state<br> // Save the new proposed state of the AppBar<br> abEdgeProposedPrev := FabEdgeProposedPrev;<br><br> // Set the proposed state back to unknown. This causes GetState<br> // to return the current state rather than the proposed state<br> FabEdgeProposedPrev := abeUnknown;<br><br> // Get the location of the window in screen coordinates<br> GetWindowRect(Handle, rc);<br><br> // If the AppBar's state has changed...<br> if GetEdge = abEdgeProposedPrev then<br> case GetEdge of<br> abeLeft, abeRight:<br> // Save the new width of the docked AppBar<br> FABS.szDockSize.cx := rc.Right - rc.Left;<br> abeTop, abeBottom:<br> // Save the new height of the docked AppBar<br> FABS.szDockSize.cy := rc.Bottom - rc.Top;<br> end;<br><br> // Always save the new position of the floating AppBar<br> if abEdgeProposedPrev = abeFloat then begin<br> // If AppBar was floating and keeps floating...<br> if GetEdge = abeFloat then begin<br> FABS.rcFloat := rc;<br> // If AppBar was docked and is going to float...<br> end else begin<br> // Propose width and height depending on the current window position<br> w := rc.Right - rc.Left;<br> h := rc.Bottom - rc.Top;<br> // Adjust width and height<br> SystemParametersInfo(SPI_GETWORKAREA, 0, @rcWorkArea, 0);<br> if (w >= (rcWorkArea.Right - rcWorkArea.Left)) or<br> (h >= (rcWorkArea.Bottom - rcWorkArea.Top)) then begin<br> w := FABS.rcFloat.Right - FABS.rcFloat.Left;<br> h := FABS.rcFloat.Bottom - FABS.rcFloat.Top;<br> end;<br> // Save new floating position<br> FABS.rcFloat.Left := rc.Left;<br> FABS.rcFloat.Top := rc.Top;<br> FABS.rcFloat.Right := rc.Left + w;<br> FABS.rcFloat.Bottom := rc.Top + h;<br> end;<br> end;<br><br> // After setting the dimensions, set the AppBar to the proposed state<br> SetEdge(abEdgeProposedPrev);<br>end;<br><br><br>// TAppBar.OnMoving ///////////////////////////////////////////////////////////<br>procedure TAppBar.OnMoving (var Msg : TMessage);<br>var<br> prc : PRect;<br> pt : TSmallPoint;<br> abEdgeProposed : TAppBarEdge;<br> w, h : Integer;<br>begin<br> // We control the moving of the AppBar. For example, if the mouse moves<br> // close to an edge, we want to dock the AppBar<br> // The lParam contains the window's position proposed by the system<br> prc := PRect(Msg.LParam);<br><br> // Get the location of the mouse cursor<br> pt := GetMessagePosition;<br><br> // Where should the AppBar be based on the mouse position?<br> abEdgeProposed := CalcProposedState(pt);<br><br> if ((FabEdgeProposedPrev <> abeFloat) and<br> (abEdgeProposed = abeFloat)) then begin<br> // While moving, the user took us from a docked/autohidden state to<br> // the float state. We have to calculate a rectangle location so that<br> // the mouse cursor stays inside the window.<br> prc^ := FABS.rcFloat;<br> w := prc^.Right - prc^.Left;<br> h := prc^.Bottom - prc^.Top;<br> with prc^ do begin<br> Left := pt.X - w div 2;<br> Top := pt.Y;<br> Right := pt.X - w div 2 + w;<br> Bottom := pt.Y + h;<br> end;<br> end;<br><br> // Remember the most-recently proposed state<br> FabEdgeProposedPrev := abEdgeProposed;<br><br> // Tell the system where to move the window based on the proposed state<br> GetRect(abEdgeProposed, prc^);<br><br> // Tell our derived class that there is a proposed state change<br> OnAppBarStateChange(True, abEdgeProposed);<br>end;<br><br><br>// TAppBar.OnSizing ///////////////////////////////////////////////////////////<br>procedure TAppBar.OnSizing (var Msg : TMessage);<br>var<br> prc : PRect;<br> rcBorder : TRect;<br> nWidthNew, nHeightNew : Integer;<br>begin<br> // We control the sizing of the AppBar. For example, if the user re-sizes<br> // an edge, we want to change the size in discrete increments.<br> // The lParam contains the window's position proposed by the system<br> prc := PRect(Msg.LParam);<br><br> // Get the minimum allowed size of the window depending on current edge.<br> // This is the width/height of the window that must always be present<br> with FABS do<br> case abEdge of<br> abeFloat:<br> rcBorder := Rect(0, 0, nMinWidth, nMinHeight);<br> else<br> rcBorder := Rect(0, 0, szMinDockSize.cx, szMinDockSize.cy);<br> end;<br><br> // We force the window to resize in discrete units set by the FABS.szSizeInc<br> // member. From the new, proposed window dimensions passed to us, round<br> // the width/height to the nearest discrete unit<br> if FABS.szSizeInc.cx <> 0 then<br> nWidthNew := ((prc^.Right - prc^.Left) - (rcBorder.Right - rcBorder.Left)<br> + FABS.szSizeInc.cx div 2) div FABS.szSizeInc.cx<br> * FABS.szSizeInc.cx + (rcBorder.Right - rcBorder.Left)<br> else<br> nWidthNew := prc^.Right - prc^.Left;<br><br> if FABS.szSizeInc.cy <> 0 then<br> nHeightNew := ((prc^.Bottom - prc^.Top) - (rcBorder.Bottom - rcBorder.Top)<br> + FABS.szSizeInc.cy div 2) div FABS.szSizeInc.cy<br> * FABS.szSizeInc.cy + (rcBorder.Bottom - rcBorder.Top)<br> else<br> nHeightNew := prc^.Bottom - prc^.Top;<br><br> // Adjust the rectangle's dimensions<br> case Msg.wParam of<br> WMSZ_LEFT:<br> prc^.Left := prc^.Right - nWidthNew;<br><br> WMSZ_TOP:<br> prc^.Top := prc^.Bottom - nHeightNew;<br><br> WMSZ_RIGHT:<br> prc^.Right := prc^.Left + nWidthNew;<br><br> WMSZ_BOTTOM:<br> prc^.Bottom := prc^.Top + nHeightNew;<br><br> WMSZ_BOTTOMLEFT: begin<br> prc^.Bottom := prc^.Top + nHeightNew;<br> prc^.Left := prc^.Right - nWidthNew;<br> end;<br><br> WMSZ_BOTTOMRIGHT: begin<br> prc^.Bottom := prc^.Top + nHeightNew;<br> prc^.Right := prc^.Left + nWidthNew;<br> end;<br><br> WMSZ_TOPLEFT: begin<br> prc^.Left := prc^.Right - nWidthNew;<br> prc^.Top := prc^.Bottom - nHeightNew;<br> end;<br><br> WMSZ_TOPRIGHT: begin<br> prc^.Top := prc^.Bottom - nHeightNew;<br> prc^.Right := prc^.Left + nWidthNew;<br> end;<br> end; // end of case<br>end;<br><br><br>// TAppBar.OnGetMinMaxInfo ////////////////////////////////////////////////////<br>procedure TAppBar.OnGetMinMaxInfo (var Msg : TWMGetMinMaxInfo);<br>begin<br> if GetEdge = abeFloat then<br> with Msg.MinMaxInfo^ do begin<br> ptMinTrackSize.X := FABS.nMinWidth;<br> ptMinTrackSize.Y := FABS.nMinHeight;<br> ptMaxTrackSize.X := FABS.nMaxWidth;<br> ptMaxTrackSize.Y := FABS.nMaxHeight;<br> end<br> else<br> with Msg.MinMaxInfo^ do begin<br> ptMinTrackSize.X := FABS.szMinDockSize.cx;<br> ptMinTrackSize.Y := FABS.szMinDockSize.cy;<br> ptMaxTrackSize.X := GetSystemMetrics(SM_CXSCREEN);<br> ptMaxTrackSize.Y := GetSystemMetrics(SM_CYSCREEN);<br> if not IsEdgeTopOrBottom(GetEdge) then<br> ptMaxTrackSize.X := FABS.szMaxDockSize.cx;<br> if not IsEdgeLeftOrRight(GetEdge) then<br> ptMaxTrackSize.Y := FABS.szMaxDockSize.cy;<br> end;<br>end;<br><br><br>{ AppBar-specific helper functions }<br><br><br>// TAppBar.IsEdgeLeftOrRight //////////////////////////////////////////////////<br>function TAppBar.IsEdgeLeftOrRight (abEdge : TAppBarEdge) : Boolean;<br>begin<br> Result := (abEdge in [abeLeft, abeRight]);<br>end;<br><br><br>// TAppBar.IsEdgeTopOrBottom //////////////////////////////////////////////////<br>function TAppBar.IsEdgeTopOrBottom (abEdge : TAppBarEdge) : Boolean;<br>begin<br> Result := (abEdge in [abeTop, abeBottom]);<br>end;<br><br><br>// TAppBar.IsFloating /////////////////////////////////////////////////////////<br>function TAppBar.IsFloating (abEdge : TAppBarEdge) : Boolean;<br>begin<br> Result := (abEdge = abeFloat);<br>end;<br><br><br>// TAppBar.IsDockable /////////////////////////////////////////////////////////<br>function TAppBar.IsDockable (abFlags : TAppBarFlags) : Boolean;<br>begin<br> Result := ((abFlags * [abfAllowLeft .. abfAllowBottom]) <> []);<br>end;<br><br><br>// TAppBar.IsDockableVertically ///////////////////////////////////////////////<br>function TAppBar.IsDockableVertically (abFlags : TAppBarFlags) : Boolean;<br>begin<br> Result := ((abFlags * [abfAllowLeft, abfAllowRight]) <> []);<br>end;<br><br><br>// TAppBar.IsDockableHorizontally /////////////////////////////////////////////<br>function TAppBar.IsDockableHorizontally (abFlags : TAppBarFlags) : Boolean;<br>begin<br> Result := ((abFlags * [abfAllowTop, abfAllowBottom]) <> []);<br>end;<br><br><br>// TAppBar.ResetSystemKnowledge ///////////////////////////////////////////////<br>procedure TAppBar.ResetSystemKnowledge;<br>{$ifdef DEBUG}<br>var<br> abd : TAppBarData;<br>begin<br> abd.cbSize := sizeof(abd);<br> abd.hWnd := 0;<br> SHAppBarMessage(ABM_REMOVE, abd);<br>end;<br>{$else}<br>begin<br> // nothing to do when not in debug mode<br>end;<br>{$endif}<br><br><br>// TAppBar.GetEdgeFromPoint ///////////////////////////////////////////////////<br>function TAppBar.GetEdgeFromPoint (abFlags : TAppBarFlags;<br> pt : TSmallPoint) : TAppBarEdge;<br>var<br> rc : TRect;<br> cxScreen : Integer;<br> cyScreen : Integer;<br> ptCenter : TSmallPoint;<br> ptOffset : TSmallPoint;<br> bIsLeftOrRight : Boolean;<br> abSubstEdge : TAppBarEdge;<br>begin<br> // Let's get floating out of the way first<br> if abfAllowFloat in abFlags then begin<br><br> // Get the rectangle that bounds the size of the screen<br> // minus any docked (but not-autohidden) AppBars<br> SystemParametersInfo(SPI_GETWORKAREA, 0, @rc, 0);<br><br> // Leave a 1/2 width/height-of-a-scrollbar gutter around the workarea<br> InflateRect(rc,<br> -GetSystemMetrics(SM_CXVSCROLL),<br> -GetSystemMetrics(SM_CYHSCROLL));<br><br> // If the point is in the adjusted workarea OR no edges are allowed<br> if PtInRect(rc, SmallPointToPoint(pt)) or<br> not IsDockable(abFlags) then begin<br> // The AppBar should float<br> Result := abeFloat;<br> Exit;<br> end;<br> end;<br><br> // If we get here, the AppBar should be docked; determine the proper edge<br> // Get the dimensions of the screen<br> cxScreen := GetSystemMetrics(SM_CXSCREEN);<br> cyScreen := GetSystemMetrics(SM_CYSCREEN);<br><br> // Find the center of the screen<br> ptCenter.X := cxScreen div 2;<br> ptCenter.Y := cyScreen div 2;<br><br> // Find the distance from the point to the center<br> ptOffset.X := pt.X - ptCenter.X;<br> ptOffset.Y := pt.Y - ptCenter.Y;<br><br> // Determine if the point is farther from the left/right or top/bottom<br> bIsLeftOrRight :=<br> ((Abs(ptOffset.Y) * cxScreen) <= (Abs(ptOffset.X) * cyScreen));<br><br> // Propose an edge<br> if bIsLeftOrRight then begin<br> if 0 <= ptOffset.X then<br> Result := abeRight<br> else<br> Result := abeLeft;<br> end else begin<br> if 0 <= ptOffset.Y then<br> Result := abeBottom<br> else<br> Result := abeTop;<br> end;<br><br> // Calculate an edge substitute<br> if abfAllowFloat in abFlags then<br> abSubstEdge := abeFloat<br> else<br> abSubstEdge := FABS.abEdge;<br><br> // Check if the proposed edge is allowed. If not, return the edge substitute<br> case Result of<br> abeLeft : if not (abfAllowLeft in abFlags) then Result := abSubstEdge;<br> abeTop : if not (abfAllowTop in abFlags) then Result := abSubstEdge;<br> abeRight : if not (abfAllowRight in abFlags) then Result := abSubstEdge;<br> abeBottom: if not (abfAllowBottom in abFlags) then Result := abSubstEdge;<br> end;<br><br>end;<br><br><br>{ Public member functions }<br><br><br>// TAppBar.Create /////////////////////////////////////////////////////////////<br>constructor TAppBar.Create (Owner : TComponent);<br>begin<br> // Force the shell to update its list of AppBars and the workarea.<br> // This is a precaution and is very useful when debugging. If you create<br> // an AppBar and then just terminate the application, the shell still<br> // thinks that the AppBar exists and the user's workarea is smaller than<br> // it should be. When a new AppBar is created, calling this function<br> // fixes the user's workarea.<br> ResetSystemKnowledge;<br><br> // Set default state of AppBar to float with no width & height<br> FABS.cbSize := sizeof(TAppBarSettings);<br> FABS.abEdge := abeFloat;<br> FABS.abFlags := [abfAllowLeft .. abfAllowFloat];<br> FABS.bAutohide := False;<br> FABS.bAlwaysOnTop := True;<br> FABS.bSlideEffect := True;<br> FABS.nTimerInterval := SLIDE_DEF_TIMER_INTERVAL;<br> FABS.szSizeInc.cx := AB_DEF_SIZE_INC;<br> FABS.szSizeInc.cy := AB_DEF_SIZE_INC;<br> FABS.szDockSize.cx := AB_DEF_DOCK_SIZE;<br> FABS.szDockSize.cy := AB_DEF_DOCK_SIZE;<br> FABS.rcFloat.Left := 0;<br> FABS.rcFloat.Top := 0;<br> FABS.rcFloat.Right := 0;<br> FABS.rcFloat.Bottom := 0;<br> FABS.nMinWidth := 0;<br> FABS.nMinHeight := 0;<br> FABS.nMaxWidth := GetSystemMetrics(SM_CXSCREEN);<br> FABS.nMaxHeight := GetSystemMetrics(SM_CYSCREEN);<br> FABS.szMinDockSize.cx := 0;<br> FABS.szMinDockSize.cy := 0;<br> FABS.szMaxDockSize.cx := GetSystemMetrics(SM_CXSCREEN) div 2;<br> FABS.szMaxDockSize.cy := GetSystemMetrics(SM_CYSCREEN) div 2;<br> FABS.abTaskEntry := abtFloatDependent;<br> FabEdgeProposedPrev := abeUnknown;<br> FbFullScreenAppOpen := False;<br> FbAutoHideIsVisible := False;<br><br> // Set default location of the settings in the registry<br> with FabSettingsLocation do begin<br> RootKey := AB_DEF_ROOT_KEY;<br> KeyName := AB_DEF_KEY_NAME;<br> end;<br><br> // Call base class<br> inherited Create(Owner);<br>end;<br><br><br>// TAppBar.Destroy ////////////////////////////////////////////////////////////<br>destructor TAppBar.Destroy;<br>begin<br> ResetSystemKnowledge;<br><br> // Call base class<br> inherited Destroy;<br>end;<br><br><br>// TAppBar.UpdateBar //////////////////////////////////////////////////////////<br>procedure TAppBar.UpdateBar;<br>begin<br> SetEdge(GetEdge);<br>end;<br><br>// TAppBar.LoadSettings ///////////////////////////////////////////////////////<br>function TAppBar.LoadSettings : Boolean;<br>var<br> reg : TRegistry;<br> abs : TAppBarSettings;<br>begin<br> // Set the default return value<br> Result := False;<br> // Create a TRegistry object<br> reg := TRegistry.Create;<br> // Set the RootKey<br> reg.RootKey := FabSettingsLocation.nRootKey;<br> // Open the KeyName<br> if reg.OpenKey(FabSettingsLocation.KeyName, False) then<br> // Load the FABS record from the 'default' value<br> if reg.ReadBinaryData('', abs, sizeof(abs)) = sizeof(abs) then begin<br> FABS := abs;<br> Result := True;<br> end;<br> // Free the TRegistry object<br> reg.Destroy<br>end;<br><br>// TAppBar.SaveSettings ///////////////////////////////////////////////////////<br>function TAppBar.SaveSettings : Boolean;<br>var<br> reg : TRegistry;<br>begin<br> // Set the default return value<br> Result := False;<br> // Create a TRegistry object<br> reg := TRegistry.Create;<br> // Set the RootKey<br> reg.RootKey := FabSettingsLocation.nRootKey;<br> // Open the KeyName, creating it if not exists<br> if reg.OpenKey(FabSettingsLocation.KeyName, True) then begin<br> // Save the FABS record in the 'default' value<br> reg.WriteBinaryData('', FABS, sizeof(FABS));<br> Result := True;<br> end;<br> // Free the TRegistry object<br> reg.Destroy<br>end;<br><br>end.<br><br>