// ========================================================================== // Class Specification : COXAppBar // ========================================================================== // // OXAppBar.h // Version: 9.3 // // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// // Desciption : // // Class COXAppBar provides functionality of Windows shell application bar // It is a template class and use CWnd derived class as a parent. // COXAppBar has two constructors - one for generic CWnd derived class // and another one for CDialog derived class. It is easy to use. // To start use it call Register(TRUE). To Load prevous state call LoadState(), // that returns TRUE on success, otherwise you can suply your own parameters. // If you want to dock window on certain edge you can use function SetEdge(). // The two important state are Autohidden and AlwaysOnTop. To set or remove these // features call SetAutoHide() or SetAlwaysOnTop() with appropriate value - TRUE or FALSE // Any edge can be excluded from docking state by function SetBarStyle() // To see appbar styles use GetBarStyle(). You can also exclude ABE_FLOAT state, // so your appbar always will be docked to some edge. Additional functionality is // provided by OX_APPBARS_DIFFERENT_DIMS. This flag (set on by default) indicate // the appbar will provide different width and height for every state. // Addidtional customization: set the width of the appbar in hidden state, // time the autohidden appbar will wait while inactive until begin slide to hidden state, // dimensions in any state and others . // // To unregister appbar call Register(FALSE). // Note: you must provide default constructor for your class will be used by COXAppBar //Dependences: //Header files //#include "OXRegistryValFile.h" //#include "OXAppBar.h" //Cpp files: //"OXRegistryValFile.cpp" #if !defined(_OXAPPBAR_H__) #define _OXAPPBAR_H__ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "OXDllExt.h" #include "OXRegistryValFile.h" #include "OXMainRes.h" #include "UTB64Bit.h" /////////////////////////////////////////////////////////////////////////////// //definitions const int OX_APPBAR_VERSION=0x0011; //two additional styles #define ABE_UNKNOWN 0x101 #define ABE_FLOAT 0x102 //default definitions #define SLIDING_TIME 10 //time to slide window in autohide state #define MIN_DIMENSION 2 //width of the appbar in hidden state #define IDT_AUTOHIDE 1 //timer id for autohide state #define DEFAULT_DIMENSION 28//default dimension of the appbar (width for right-left, //height for top-bottom) #define DIM_TO_FLOAT 10 //how many pixels should be mouse away from docked //appbar to switch to float state #define DIM_TO_DOCK 40 //how many pixels should be mouse near to an edge //to switch from float state to docking state #define DIM_CAPTION 6 //pixels from top of the window in float state to the cursor #define TIMER_INTERVAL 100 //milliseconds - how much time will wait inactive autohidden //bar to start to move to hide ///////////////////////////////////////////////////////////////////////////// //the styles can be set #define OX_APPBARS_LEFT 0x01 //can dock on the left #define OX_APPBARS_TOP 0x02 //can dock on the top #define OX_APPBARS_RIGHT 0x04 //can dock on the right #define OX_APPBARS_BOTTOM 0x08 //can dock on the bottom #define OX_APPBARS_ALL_EDGES (OX_APPBARS_LEFT | OX_APPBARS_TOP | OX_APPBARS_RIGHT | OX_APPBARS_BOTTOM) #define OX_APPBARS_FLOAT 0x10 //can float #define OX_APPBARS_DIFFERENT_DIMS 0x020 //remember different dimensions //for every edge #define OX_APPBARS_ALLS (OX_APPBARS_ALL_EDGES | OX_APPBARS_FLOAT | OX_APPBARS_DIFFERENT_DIMS) typedef struct sMouse { CPoint pt;//current mouse position BOOL bButtonDown;//TRUE on button down sMouse::sMouse(): pt(0,0), bButtonDown(FALSE){} }tMouse; typedef struct sBarData { BOOL bRegistered;//TRUE when registered BOOL bOnTop;//TRUE when the bar has WS_EX_TOPMOST style BOOL bAutoHideDesired;//TRUE, if SHOULD BE in autohide state (may be in not //the state due to error to set autohide state, but this //variable means desired state that will be set on the edge) BOOL bHiding;//TRUE while sliding the bar BOOL bHidden;//TRUE if hidden in autohide style, FALSE otherwise UINT nWidth;//default width of the bar UINT nHeight;//default height of the bar UINT nLeft;//width of the bar on the left edge UINT nTop;//height of the bar on the top edge UINT nRight;//width of the bar on the right edge UINT nBottom;//height of the bar on the bottom edge UINT nEdge;//edge the bar will be docked on or ABE_FLOAT, ABE_UNKNOWN UINT nDockEdge;//edge the bar is docked on, no ABE_FLOAT or ABE_UNKNOWN is allowed DWORD dwStyle;//styles applicable to the bar sBarData(): bRegistered(FALSE), bOnTop(FALSE), bAutoHideDesired(FALSE), bHiding(FALSE), bHidden(FALSE), nWidth(DEFAULT_DIMENSION), nHeight(DEFAULT_DIMENSION), nLeft(DEFAULT_DIMENSION), nTop(DEFAULT_DIMENSION), nRight(DEFAULT_DIMENSION), nBottom(DEFAULT_DIMENSION), nEdge(ABE_UNKNOWN), nDockEdge(NULL), dwStyle(OX_APPBARS_ALLS) {} }tBarData; ///////////////////////////////////////////////////////////////////////////// // COXAppBar window template class OX_CLASS_DECL COXAppBar : public PARENTWND { // public functions public: // --- In : // --- Out : // --- Returns : // --- Effect : Constructs the object COXAppBar(); // --- In : nId - resource ID of the dialog // pParent - pointer to the parent window // --- Out : // --- Returns : // --- Effect : Constructs the object (for CDialog derived class) COXAppBar(UINT nId, CWnd* pParent=NULL); // --- In : // --- Out : // --- Returns : // --- Effect : Destructor virtual ~COXAppBar(); // --- In : // --- Out : // --- Returns : pointer to structure tBarData // --- Effect : returns pointer to tBarData inline const tBarData* GetBarData() const {return &m_BarData;} // --- In : nWidth - new default width // --- Out : // --- Returns : // --- Effect : sets new default width for the appbar inline void SetDefaultWidth(UINT nWidth) {m_BarData.nWidth=nWidth;} // --- In : nHeight - new default height // --- Out : // --- Returns : // --- Effect : sets new default height for the appbar inline void SetDefaultHeight(UINT nHeight){m_BarData.nHeight=nHeight;} // --- In : // --- Out : // --- Returns : a count of timer ticks the window slides on 1 pixel // --- Effect : call this function to retrieve the sliding time inline UINT GetSlidingTime() const {return m_nSlidingTime;} // --- In : nSlidingTime - a count of timer ticks the window slides on 1 pixel // --- Out : // --- Returns : // --- Effect : call this function to change the sliding time inline void SetSlidingTime(UINT nSlidingTime) {m_nSlidingTime=nSlidingTime;} // --- In : // --- Out : // --- Returns : width of the appbar while hidden // --- Effect : call this function to get width of the appbar in hidden state inline UINT GetHiddenWidth() const { return m_nHiddenWidth;} // --- In : nHiddenWidth - new width of the appbar in hidden state // --- Out : // --- Returns : // --- Effect : call this function to set new width of the appbar in hidden state inline void SetHiddenWidth(UINT nHiddenWidth) {m_nHiddenWidth=nHiddenWidth;} // --- In : nToFloat - difference (pixels) between cursor and edge // of the appbar when appbar will switch to the float state // --- Out : // --- Returns : // --- Effect : call this function to set new value to switch to float state inline void SetPointToFloat(UINT nToFloat) {m_nToFloat=nToFloat;} // --- In : // --- Out : // --- Returns : current difference (pixels) between cursor and edge // of the appbar when appbar will switch to the float state // --- Effect : call this function to get current value to switch to float state inline UINT GetPointToFloat() const {return m_nToFloat;} // --- In : nToDock - difference (pixels) between cursor and screen edge // when appbar will switch to the docking state // --- Out : // --- Returns : // --- Effect : call this function to set new value to switch to docking state inline void SetPointToDock(UINT nToDock) {m_nToDock=nToDock;} // --- In : // --- Out : // --- Returns : difference (pixels) between cursor and screen edge // when appbar will switch to the docking state // --- Effect : call this function to get the value the appbar // will switch to docking state inline UINT GetPointToDock() const {return m_nToDock;} // --- In : nTimerInterval - time the appbar will remain unhidden // while inactive untill start to sliding // --- Out : // --- Returns : // --- Effect : sets new timer interval value inline void SetTimerInterval(UINT nTimerInterval) {m_nTimerInterval=nTimerInterval;} // --- In : // --- Out : // --- Returns : - time the appbar will remain unhidden // while inactive untill start to sliding // --- Effect : call this function to retrieve the value of timer interval inline UINT GetTimerInterval() const {return m_nTimerInterval;} // --- In : dwStyle - new styles of the appbar // The valid styles are: // OX_APPBARS_LEFT - the appbar can dock // on the left edge of the screen // OX_APPBARS_TOP - the appbar can dock // on the top edge of the screen // OX_APPBARS_RIGHT - the appbar can dock // on the right edge of the screen // OX_APPBARS_BOTTOM - the appbar can dock // on the bottom // OX_APPBARS_ALL_EDGES - the appbar can dock // on all edges of the screen // OX_APPBARS_FLOAT - the appbar can float // OX_APPBARS_DIFFERENT_DIMS - the appbar has // different dimensions for every edge // OX_APPBARS_ALLS - all posible styles // --- Out : // --- Returns : // --- Effect : sets new styles for the appbar inline void SetBarStyle(DWORD dwStyle) { m_BarData.dwStyle=(dwStyle & OX_APPBARS_ALLS); } // --- In : // --- Out : // --- Returns : the appbar styles (See description function SetBarStyle()) // --- Effect : returns the appbar styles inline DWORD GetBarStyle () const {return m_BarData.dwStyle;} // --- In : // --- Out : // --- Returns : TRUE if autobar is in autohidden state. The appbar // may actually be hidden or unhidden at this moment (if is in // autohidden state). // To check actual state see variable // bHidden in bar data (GetBarData()). There is a difference // between autohide state and desired autohide state. // Once you call SetAutoHide(TRUE), the desired state // (bAutoHideDesired in bar data - call GetBarData()) will // remain TRUE untill next call SetAutoHide(FALSE). This is // because the system can has only one autohidden bar per edge. // So, if there was not posibility to set autohidden state on // this edge, this function will return FALSE, while bAutoHideDesired // will be TRUE. Next time the edge has been changed bAutoHideDesired // will forced to set autohide state on the new edge. // --- Effect : returns TRUE if the appbar is in autohidden state on this edge BOOL IsAutoHidden(); // --- In : // --- Out : // --- Returns : TRUE, if the appbar is floating, FALSE othewise. // --- Effect : call this function to check floating state of the appabar inline BOOL IsFloating() const {return (BOOL) (m_BarData.nEdge==ABE_FLOAT);} // --- In : // --- Out : // --- Returns : TRUE, if the appbar is in topmost state // --- Effect : call this function to define if the appbar is // in topmost state inline BOOL IsAlwaysOnTop() const {return m_BarData.bOnTop;} // --- In : // --- Out : // --- Returns : TRUE, if appbar is registered, FALSE otherwise // --- Effect : call this function to define if the appbar is registered inline BOOL IsRegistered () const {return m_BarData.bRegistered;} // --- In : // --- Out : // --- Returns : the edge appbar is docking on or ABE_FLOAT, if floating // --- Effect : call this function to get the edge // appbar is docking on, if any inline UINT GetEdge() const { return m_BarData.nEdge;} // --- In : bOnTop - TRUE to set as topmost window, FALSE to remove // --- Out : // --- Returns : // --- Effect : call this function to change topmost style of the appbar void SetAlwaysOnTop(BOOL bOnTop); // --- In : nEdge - the edge appbar should be docked on or float // --- Out : // --- Returns : // --- Effect : call this function to change the edge of the appbar BOOL SetEdge(UINT nEdge); // --- In : bHide - TRUE to set autohide style, FALSE to remove // --- Out : // --- Returns : TRUE on success, FALSE otherwise. // --- Effect : Sets or removes autohidden state. The variable // bHide will determine the autohidden state on all edges // (See description of IsAutoHidden() function) BOOL SetAutoHide(BOOL bHide); // --- In : bRegister - TRUE to register the appbar, FALSE to remove // --- Out : // --- Returns : TRUE on success, FALSE if the system // could not register or the appbar has been registered // so far // --- Effect : Call this function to register or unregister appbar. // The best way is before call this function // call function IsRegistered() to check out the status // of the appbar BOOL Register(BOOL bRegister=TRUE); void SetDockDimension(UINT nEdge, UINT nWidth) { switch (nEdge) { case ABE_TOP: m_BarData.nTop=nWidth; break; case ABE_LEFT: m_BarData.nLeft=nWidth; break; case ABE_BOTTOM: m_BarData.nBottom=nWidth; break; case ABE_RIGHT: m_BarData.nRight=nWidth; break; default: ASSERT(FALSE); } } //protected functions protected: // --- In : nEdge // --- Out : // --- Returns : // --- Effect : Do nothing. Override this function // if you need to handle changes of the edges // the appbar switching to virtual void OnSetEdge(UINT nEdge) { UNREFERENCED_PARAMETER(nEdge);} // --- In : // --- Out : // --- Returns : TRUE on succes, FALSE otherwise // --- Effect : Call this function to restore last // saved state of the appbar virtual BOOL LoadState(); // --- In : // --- Out : // --- Returns : // --- Effect : Call this function to save appbar to the registry // before call Register(FALSE); virtual void SaveState(); // --- In : // --- Out : // --- Returns : // --- Effect : override this function if you want provide // popup menu on mouse right-click virtual void DoPopupMenu(){/* do nothing - override to provide your own menu*/} virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam ); void Float(APPBARDATA* pData); void UnFloat(APPBARDATA* pData); void AppBarCallback(UINT uMsg, WPARAM wParam, LPARAM lParam); void PosChanged(); void SetPosition(APPBARDATA* pBarData, BOOL bMove); void QueryPosition(RECT* pRect); void UnHide(); void Hide(); UINT GetProposedEdge(); void GetEndRect(CRect& rect); void GetProposedRect(CRect& rect); BOOL CanContinue(CRect& rctCurrent, CRect& rctEnd); void SlideWindow(); void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); int OnCreate(LPCREATESTRUCT lpCreateStruct); void OnDestroy(); void OnLButtonDown(UINT nFlags, CPoint point); void OnLButtonUp(UINT nFlags, CPoint point); void OnMouseMove(UINT nFlags, CPoint point); void OnMove(int x, int y); LRESULT OnNcHitTest(CPoint point); void OnRButtonDown(UINT nFlags, CPoint point); void OnTimer(UINT nIDEvent); void OnWindowPosChanged(WINDOWPOS FAR* lpwndpos); void OnExitSizeMoveLoop(); //protected members protected: CRect m_rctFloat; //coordinates of the window in the float state int m_nOffset;//switches between -1 and 1 indicating in what side slide tMouse m_stMouse;//position and state of the cursor tBarData m_BarData;//data related to the bar BOOL m_bSizeable;//to remember WS_THICKFRAME style while the bar is hidden UINT m_nSlidingTime;//defines speed to slide UINT m_nHiddenWidth;//defines width of the window in the hidden state UINT m_nTimerInterval;//time to wait to start sliding bar while the bar is inactive UINT m_nToDock;//offset cursor from an edge that will be treated as switch to docking state UINT m_nToFloat;//offset cursor from the docking frame to switch to float BOOL m_bFloating;//TRUE while floating }; /* ========================================================================= ======================IMPLEMENTATION===================================== ========================================================================= */ ///////////////////////////////////////////////////////////////////////////// // COXAppBar //////////////////////////////////////////// //constructor for generic CWnd derived class template COXAppBar::COXAppBar() { ASSERT(PARENTWND::IsKindOf(RUNTIME_CLASS(CWnd))); m_nOffset=0; m_bSizeable=FALSE; m_nSlidingTime=SLIDING_TIME; m_nHiddenWidth=MIN_DIMENSION; m_nTimerInterval=TIMER_INTERVAL; m_nToDock=DIM_TO_DOCK; m_nToFloat=DIM_TO_FLOAT; m_bFloating=FALSE; } //////////////////////////////////////////// //constructor for CDialog derived classes template COXAppBar::COXAppBar(UINT nId, CWnd* pParent): PARENTWND(nId, pParent) { m_nOffset=0; m_bSizeable=FALSE; m_nSlidingTime=TIMER_INTERVAL; m_nHiddenWidth=MIN_DIMENSION; m_nTimerInterval=TIMER_INTERVAL; m_nToDock=DIM_TO_DOCK; m_nToFloat=DIM_TO_FLOAT; m_bFloating=FALSE; } /////////////////////////////////////// //destructor template COXAppBar::~COXAppBar() { } ///////////////////////////////////////////////////////////////////////////// // COXAppBar message handlers ///////////////////////////////////// //cannot define message handler in //template class - working with //WindowProc() template LRESULT COXAppBar::WindowProc( UINT message, WPARAM wParam, LPARAM lParam ) { #if defined (_WINDLL) #if defined (_AFXDLL) AFX_MANAGE_STATE(AfxGetAppModuleState()); #else AFX_MANAGE_STATE(AfxGetStaticModuleState()); #endif #endif switch (message) { case WM_ACTIVATE: { OnActivate(LOWORD(wParam), (CWnd*) CWnd::FromHandle((HWND) lParam), (BOOL) HIWORD(wParam)); return NULL; } case WM_CREATE: { return OnCreate((LPCREATESTRUCT) lParam); } case WM_DESTROY: { OnDestroy(); return NULL; } case WM_LBUTTONDOWN: { CPoint point(LOWORD(lParam), HIWORD(lParam)); OnLButtonDown((UINT) wParam, point); return NULL; } case WM_LBUTTONUP: { CPoint point(LOWORD(lParam), HIWORD(lParam)); OnLButtonUp((UINT) wParam, point); return NULL; } case WM_MOUSEMOVE: { CPoint point(LOWORD(lParam), HIWORD(lParam)); OnMouseMove((UINT) wParam, point); return NULL; } case WM_MOVE: { OnMove(LOWORD(lParam), HIWORD(lParam)); return NULL; } case WM_NCHITTEST: { CPoint point(LOWORD(lParam), HIWORD(lParam)); return OnNcHitTest(point); } case WM_RBUTTONDOWN: { CPoint point(LOWORD(lParam), HIWORD(lParam)); OnRButtonDown((UINT) wParam, point); return NULL; } case WM_EXITSIZEMOVE: { OnExitSizeMoveLoop(); return NULL; } break; case WM_TIMER: { OnTimer((UINT) wParam); return NULL; } case WM_WINDOWPOSCHANGED: { OnWindowPosChanged((WINDOWPOS*) lParam); return NULL; } default: { return PARENTWND::WindowProc(message, wParam, lParam); } } } ////////////////////////////////////////////////// //handlers for WindowProc() ////////////////////////////////////////////////// //OnActivate(): if the bar is autohidden, Hide() //or UnHide() it depends on the message template void COXAppBar::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { PARENTWND::OnActivate(nState, pWndOther, bMinimized); ASSERT(PARENTWND::m_hWnd); APPBARDATA data; ZeroMemory((void*) &data, sizeof(data)); data.cbSize=sizeof(APPBARDATA); data.hWnd=PARENTWND::m_hWnd; SHAppBarMessage(ABM_ACTIVATE, &data); if (!IsAutoHidden()) return; switch (nState) { case WA_ACTIVE: case WA_CLICKACTIVE: if (m_BarData.bHidden) UnHide(); break; case WA_INACTIVE: if (!m_BarData.bHidden) Hide(); break; } } ////////////////////////////////////////// //OnCreate(): load default bar rect for //floating state and SetTimer() for autohidden state template int COXAppBar::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (PARENTWND::OnCreate(lpCreateStruct) == -1) return -1; PARENTWND::GetWindowRect(&m_rctFloat); PARENTWND::SetTimer(IDT_AUTOHIDE,m_nTimerInterval,NULL); return 0; } ///////////////////////////////////////// //ONDestroy(): Unregister and KillTimer() template void COXAppBar::OnDestroy() { Register(FALSE); PARENTWND::KillTimer(IDT_AUTOHIDE); PARENTWND::OnDestroy(); } ////////////////////////////////////////// //OnLButtonDown(): start capture if registered template void COXAppBar::OnLButtonDown(UINT nFlags, CPoint point) { if (IsRegistered()) { m_stMouse.bButtonDown=TRUE; ::GetCursorPos(&m_stMouse.pt); SetCapture(); } PARENTWND::OnLButtonDown(nFlags, point); } /////////////////////////////////////////////////// //OnLButtonUp(): ReleaseCapture() if was registared template void COXAppBar::OnLButtonUp(UINT nFlags, CPoint point) { if (IsRegistered()) { m_stMouse.bButtonDown=FALSE; ::GetCursorPos(&m_stMouse.pt); ReleaseCapture(); } PARENTWND::OnLButtonUp(nFlags, point); } //////////////////////////////////////////////////// //OnMouseMove() if registered: //move window if is in float state, //UnHide() if in hidden state. //Check for new appropriate edge. template void COXAppBar::OnMouseMove(UINT nFlags, CPoint point) { if (!IsRegistered()) { PARENTWND::OnMouseMove(nFlags, point); return; } if (IsAutoHidden() && m_BarData.bHidden) { UnHide(); return; } if (!m_stMouse.bButtonDown || m_BarData.nEdge==ABE_UNKNOWN) return; //get current position CPoint pt; ::GetCursorPos(&pt); if (m_BarData.nEdge==ABE_FLOAT) { APPBARDATA data; ZeroMemory((void*) &data, sizeof(data)); data.cbSize=sizeof(data); data.hWnd=PARENTWND::m_hWnd; data.uEdge=m_BarData.nEdge; CRect rect; PARENTWND::GetWindowRect(&rect); CSize size; size=pt-m_stMouse.pt; rect.OffsetRect(size); m_stMouse.pt=pt; data.rc=rect; SetPosition(&data,TRUE); return; } m_stMouse.pt=pt; UINT nNewEdge=GetProposedEdge(); if (nNewEdge!=m_BarData.nEdge) SetEdge(nNewEdge); PARENTWND::OnMouseMove(nFlags, point); } ////////////////////////////////////////////// //OnMove(): update cursor position template void COXAppBar::OnMove(int x, int y) { CWnd::OnMove(x, y); CPoint pt; ::GetCursorPos(&pt); m_stMouse.pt=pt; } ////////////////////////////////////////////// //OnNcHitTest(): handling to allow move window //by mouse not only with caption, but all client area template LRESULT COXAppBar::OnNcHitTest(CPoint point) { UINT nHitTest; nHitTest = PtrToUint(CWnd::OnNcHitTest(point)); if (!IsRegistered()) return nHitTest; if (m_BarData.nEdge==ABE_FLOAT) { if (nHitTest==HTCLIENT || nHitTest==HTCAPTION) return HTCLIENT; else return nHitTest; } if ((m_BarData.nEdge == ABE_TOP) && (nHitTest == HTBOTTOM)) return HTBOTTOM; if ((m_BarData.nEdge == ABE_BOTTOM) && (nHitTest == HTTOP)) return HTTOP; if ((m_BarData.nEdge == ABE_LEFT) && (nHitTest == HTRIGHT)) return HTRIGHT; if ((m_BarData.nEdge == ABE_RIGHT) && (nHitTest == HTLEFT)) return HTLEFT; return HTCLIENT; } ///////////////////////////////////////////////// //OnRButtonDown() Popup menu if cursor is in client area template void COXAppBar::OnRButtonDown(UINT nFlags, CPoint point) { CRect rct; PARENTWND::GetClientRect(&rct); if (rct.PtInRect(point)) { DoPopupMenu(); PARENTWND::OnRButtonDown(nFlags, point); } } /////////////////////////////////////////////// //OnExitSizeMoveLoop(): Update current position template void COXAppBar::OnExitSizeMoveLoop() { if (!m_BarData.bHiding && !m_BarData.bHidden) { CRect rect; PARENTWND::GetWindowRect(&rect); switch (m_BarData.nEdge) { case ABE_LEFT: m_BarData.nWidth=rect.Width(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nLeft=rect.Width(); break; case ABE_TOP: m_BarData.nHeight=rect.Height(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nTop=rect.Height(); break; case ABE_RIGHT: m_BarData.nWidth=rect.Width(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nRight=rect.Width(); break; case ABE_BOTTOM: m_BarData.nHeight=rect.Height(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nBottom=rect.Height(); break; } if (!IsAutoHidden()) { APPBARDATA data; ZeroMemory((void*) &data,sizeof(data)); data.cbSize=sizeof(data); data.hWnd=PARENTWND::m_hWnd; data.uEdge=m_BarData.nEdge; data.rc=rect; SetPosition(&data, TRUE); } } } ///////////////////////////////////////////////// //OnTimer(): In autohidden state hide window, if //is inactive template void COXAppBar::OnTimer(UINT nIDEvent) { if (IsAutoHidden() && !m_BarData.bHidden && !m_BarData.bHiding) { if (::GetActiveWindow()!=PARENTWND::m_hWnd) { CPoint pt; ::GetCursorPos(&pt); CRect rct; PARENTWND::GetWindowRect(&rct); rct.InflateRect(MIN_DIMENSION,MIN_DIMENSION); if (!rct.PtInRect(pt)) Hide(); } } PARENTWND::OnTimer(nIDEvent); } /////////////////////////////////////////// //OnWindowPosChanged() - update current position template void COXAppBar::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) { PARENTWND::OnWindowPosChanged(lpwndpos); if (!IsRegistered() || m_BarData.bHiding) return; APPBARDATA data; CRect rect; PARENTWND::GetWindowRect(&rect); ZeroMemory(&data, sizeof(data)); data.cbSize = sizeof(APPBARDATA); data.rc=rect; data.uEdge = m_BarData.nEdge; data.hWnd=PARENTWND::m_hWnd; SHAppBarMessage (ABM_WINDOWPOSCHANGED, &data); switch(m_BarData.nEdge) { case ABE_FLOAT: { m_rctFloat=rect; UINT nNewEdge=GetProposedEdge(); if (nNewEdge!=m_BarData.nEdge) SetEdge(nNewEdge); } break; case ABE_LEFT: if (!m_BarData.bHidden) { m_BarData.nWidth=rect.Width(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nLeft=m_BarData.nWidth; } break; case ABE_TOP: if (!m_BarData.bHidden) { m_BarData.nHeight=rect.Height(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nTop=m_BarData.nHeight; } break; case ABE_RIGHT: if (!m_BarData.bHidden) { m_BarData.nWidth=rect.Width(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nRight=m_BarData.nWidth; } break; case ABE_BOTTOM: if (!m_BarData.bHidden) { m_BarData.nHeight=rect.Height(); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) m_BarData.nBottom=m_BarData.nHeight; } break; } } //////////////////////////////////////// //IsAutoHidden(): defines is bar in autohidden state //There is a difference between autohidden state and //variable m_BarData.bAutoHideDesired - the variable //is always TRUE if last call was SetAutoHide(TRUE) //and FALSE if last call was SetAutoHide(FALSE) regardless //of actual autohidden state that returns IsAutoHidden(). //Every time the docked edge is changed the program will try //to make the bar autohidden if the variable is TRUE template BOOL COXAppBar::IsAutoHidden() { ASSERT(::IsWindow(PARENTWND::m_hWnd)); if (!IsRegistered()) return FALSE; APPBARDATA data; ZeroMemory(&data, sizeof(data)); data.cbSize = sizeof(APPBARDATA); data.uEdge = m_BarData.nEdge; data.hWnd=PARENTWND::m_hWnd; HWND hWnd=(HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &data); return (BOOL) (hWnd==data.hWnd); } ///////////////////////////////////////////// //QueryPosition(): query position for appbar template void COXAppBar::QueryPosition(RECT* pRect) { ASSERT(::IsWindow(PARENTWND::m_hWnd)); APPBARDATA data; ZeroMemory(&data, sizeof(data)); data.cbSize = sizeof(APPBARDATA); data.rc=*pRect; data.uEdge = m_BarData.nEdge; data.hWnd=PARENTWND::m_hWnd; SHAppBarMessage(ABM_QUERYPOS, &data); switch (data.uEdge) { case ABE_LEFT: data.rc.right = data.rc.left+pRect->right-pRect->left; break; case ABE_RIGHT: data.rc.left = data.rc.right-pRect->right+pRect->left; break; case ABE_TOP: data.rc.bottom = data.rc.top + pRect->bottom-pRect->top; break; case ABE_BOTTOM: data.rc.top = data.rc.bottom - pRect->bottom+pRect->top; break; } *pRect = data.rc; } ///////////////////////////////////////////////////// //SetPosition(): sets the appbar in specified position //regarding with result of query position template void COXAppBar::SetPosition(APPBARDATA* pBarData, BOOL bMove) { ASSERT(::IsWindow(PARENTWND::m_hWnd)); APPBARDATA data; ZeroMemory(&data, sizeof(data)); data.cbSize = sizeof(APPBARDATA); data.rc=pBarData->rc; data.uEdge = pBarData->uEdge; data.hWnd=PARENTWND::m_hWnd; QueryPosition(&data.rc); if (data.uEdge !=ABE_FLOAT && data.uEdge!=ABE_UNKNOWN) SHAppBarMessage(ABM_SETPOS, &data); if (bMove) { PARENTWND::MoveWindow(pBarData->rc.left, pBarData->rc.top, pBarData->rc.right - pBarData->rc.left, pBarData->rc.bottom - pBarData->rc.top, TRUE); } } ////////////////////////////////////////////////// //PosChanged(): handler for notification message - //windows tell us move the appbar template void COXAppBar::PosChanged() { SetEdge(m_BarData.nEdge); } ////////////////////////////////////////////////// //AppBarCallback(): handler for notification messages template void COXAppBar::AppBarCallback (UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND hwndZOrder = NULL; APPBARDATA data; ZeroMemory((void*) &data,sizeof(data)); data.cbSize=sizeof(data); data.hWnd=PARENTWND::m_hWnd; switch (wParam) { case ABN_STATECHANGE: break; case ABN_FULLSCREENAPP: if (lParam) { //Move the appbar to the bottom of the z-order. hwndZOrder = GetWindow (m_data.hWnd, GW_HWNDPREV); SetWindowPos(data.hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } else { //Restore the Z-order SetWindowPos(m_data.hWnd, IsAlwaysOnTop() ? HWND_TOPMOST : hwndZOrder, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); hwndZOrder = NULL; } break; case ABN_POSCHANGED: PosChanged (); break; } } //////////////////////////////////////////////////////////// //Register(): this function registers/unregisters the appbar. template BOOL COXAppBar::Register(BOOL bRegister) { ASSERT(PARENTWND::m_hWnd); APPBARDATA data; ZeroMemory((void*) &data, sizeof(data)); data.cbSize=sizeof(APPBARDATA); data.hWnd=PARENTWND::m_hWnd; if (bRegister) { data.uCallbackMessage = OX_APPBAR; m_BarData.bRegistered = PtrToInt(SHAppBarMessage (ABM_NEW, &data)); if (m_BarData.bRegistered) { m_bFloating=FALSE; if (m_BarData.nEdge==ABE_UNKNOWN ) SetEdge(ABE_FLOAT); else { int nEdge=m_BarData.nEdge; m_BarData.nEdge=ABE_UNKNOWN; SetEdge(nEdge); } } return m_BarData.bRegistered; } else { SaveState(); m_BarData.bRegistered = !SHAppBarMessage(ABM_REMOVE, &data); m_bFloating=FALSE; return !m_BarData.bRegistered; } } /////////////////////////////////////////////////// //SetAutoHide(): sets or remove autohide mode template BOOL COXAppBar::SetAutoHide(BOOL bHide) { ASSERT(PARENTWND::m_hWnd); CRect rect; APPBARDATA data; ZeroMemory((void*) &data, sizeof(data)); data.cbSize=sizeof(APPBARDATA); data.hWnd=PARENTWND::m_hWnd; data.uEdge = m_BarData.nEdge; m_BarData.bAutoHideDesired=bHide; HWND hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &data); if (bHide) { if (hwndAutoHide != NULL) { TRACE0("The system has autohidden appbar on this edge so far\r\n"); return FALSE; } data.lParam = TRUE; if (!SHAppBarMessage(ABM_SETAUTOHIDEBAR, &data)) { TRACE0("Error to set autohidden bar\r\n"); return FALSE; } if (m_BarData.nEdge!=ABE_FLOAT) { PARENTWND::GetWindowRect(&rect); GetEndRect(rect); data.rc=rect; SetPosition(&data, FALSE); } } else { if (hwndAutoHide != data.hWnd) { TRACE0 ("The window is not hidden\r\n"); return FALSE; } data.lParam = FALSE; if (!SHAppBarMessage(ABM_SETAUTOHIDEBAR, &data)) { TRACE0 ("Error to unhide appbar\r\n"); return FALSE; } PARENTWND::GetWindowRect(&rect); switch (m_BarData.nEdge) { case ABE_LEFT: rect.right=rect.left+m_BarData.nWidth; break; case ABE_TOP: rect.bottom=rect.top+m_BarData.nHeight; break; case ABE_RIGHT: rect.left=rect.right-m_BarData.nWidth; break; case ABE_BOTTOM: rect.top=rect.bottom-m_BarData.nHeight; break; default: return TRUE; } data.rc=rect; SetPosition(&data,TRUE); } return TRUE; } /////////////////////////////////////////////// //SetEdge(): call this function to set desired edge template BOOL COXAppBar::SetEdge(UINT nEdge) { //only for changing edge if (nEdge==m_BarData.nEdge || !IsRegistered()) return FALSE; switch (nEdge) { case ABE_UNKNOWN: ASSERT(FALSE); return FALSE; case ABE_FLOAT: if (!(m_BarData.dwStyle & OX_APPBARS_FLOAT)) return FALSE; break; case ABE_TOP: if (!(m_BarData.dwStyle & OX_APPBARS_TOP)) return FALSE; m_BarData.nDockEdge=ABE_TOP; break; case ABE_LEFT: if (!(m_BarData.dwStyle & OX_APPBARS_LEFT)) return FALSE; m_BarData.nDockEdge=ABE_LEFT; break; case ABE_RIGHT: if (!(m_BarData.dwStyle & OX_APPBARS_RIGHT)) return FALSE; m_BarData.nDockEdge=ABE_RIGHT; break; case ABE_BOTTOM: if (!(m_BarData.dwStyle & OX_APPBARS_BOTTOM)) return FALSE; m_BarData.nDockEdge=ABE_BOTTOM; break; } if (IsAutoHidden()) { SetAutoHide(FALSE); m_BarData.bAutoHideDesired=TRUE; } m_BarData.nEdge=nEdge; CRect rect; ASSERT(PARENTWND::m_hWnd); PARENTWND::GetWindowRect(&rect); APPBARDATA data; ZeroMemory((void*) &data, sizeof(data)); data.cbSize=sizeof(APPBARDATA); data.hWnd=PARENTWND::m_hWnd; data.uEdge=m_BarData.nEdge; if ( nEdge==ABE_FLOAT) Float(&data); else UnFloat(&data); GetProposedRect(rect); data.rc=rect; if (nEdge!=ABE_FLOAT) { SetPosition(&data, TRUE); if (m_BarData.bAutoHideDesired) SetAutoHide(TRUE); } else PARENTWND::MoveWindow(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); OnSetEdge(m_BarData.nEdge); return TRUE; } ////////////////////////////////////////////////////// //SetAlwaysOnTop(): sets or remove always_on_top style template void COXAppBar::SetAlwaysOnTop(BOOL bOnTop) { ::SetWindowPos(PARENTWND::m_hWnd, (bOnTop) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); m_BarData.bOnTop = bOnTop; } /////////////////////////////////////////////////// //Hide(): hides the window in autohidden state template void COXAppBar::Hide() { if (!IsAutoHidden()) return; CRect rect; PARENTWND::GetWindowRect(&rect); GetEndRect(rect); m_nOffset=-1; m_BarData.nEdge=m_BarData.nEdge; m_BarData.bHiding=TRUE; SlideWindow(); m_BarData.bHidden=TRUE; m_BarData.bHiding=FALSE; DWORD dwStyle=PARENTWND::GetStyle(); if (dwStyle & WS_THICKFRAME) { m_bSizeable=TRUE; PARENTWND::ModifyStyle(WS_THICKFRAME,0); } if (IsAutoHidden()) { APPBARDATA data; ZeroMemory((void*) &data, sizeof(data)); data.cbSize=sizeof(data); data.hWnd=PARENTWND::m_hWnd; data.rc=rect; data.uEdge=m_BarData.nEdge; SetPosition(&data, TRUE); } } //////////////////////////////////// //UnHide(): unhidethe window in autohidden state template void COXAppBar::UnHide() { if (!IsAutoHidden()) return; m_nOffset=1; m_BarData.nEdge=m_BarData.nEdge; m_BarData.bHiding=TRUE; SlideWindow(); m_BarData.bHiding = FALSE; m_BarData.bHidden=FALSE; if (m_bSizeable) PARENTWND::ModifyStyle(0,WS_THICKFRAME); } /////////////////////////////////////////////////////// //LoadState(): loads last saved state from the registry template BOOL COXAppBar::LoadState() { COXRegistryValFile regfile( HKEY_CURRENT_USER, AfxGetAppName(), _T("AppBar")); CArchive ar(®file, CArchive::load); BOOL bRet=FALSE; if (regfile.GetLength()>0) { int nVersion; ar >> nVersion; if (nVersion!=OX_APPBAR_VERSION) return FALSE; BOOL bRegistered; ar >> bRegistered; if (bRegistered) { if(!IsRegistered()) Register(TRUE); } else { if (IsRegistered()) Register(FALSE); } BOOL bOnTop; BOOL bAutoHide; ar >> bOnTop; ar >> bAutoHide; ar >> m_BarData.nWidth; ar >> m_BarData.nHeight; ar >> m_BarData.nLeft; ar >> m_BarData.nTop; ar >> m_BarData.nRight; ar >> m_BarData.nBottom; UINT nEdge; //UINT nDockEdge; ar >> nEdge;//m_BarData.nEdge; ar >> m_BarData.nDockEdge; ar >> m_BarData.dwStyle; ar >> m_nSlidingTime; ar >> m_nHiddenWidth; ar >> m_nTimerInterval; ar >> m_nToDock; ar >> m_nToFloat; ar >> m_rctFloat.left; ar >> m_rctFloat.top; ar >> m_rctFloat.right; ar >> m_rctFloat.bottom; if (IsRegistered()) { SetEdge(nEdge); SetAutoHide(bAutoHide); SetAlwaysOnTop(bOnTop); } bRet=TRUE; } ar.Close(); return bRet; } /////////////////////////////////////////////////// //SaveState(): save the state to the registry template void COXAppBar::SaveState() { COXRegistryValFile regfile( HKEY_CURRENT_USER, AfxGetAppName(), _T("AppBar")); CArchive ar(®file, CArchive::store); ar << OX_APPBAR_VERSION; ar << m_BarData.bRegistered; ar << m_BarData.bOnTop; ar << m_BarData.bAutoHideDesired; ar << m_BarData.nWidth; ar << m_BarData.nHeight; ar << m_BarData.nLeft; ar << m_BarData.nTop; ar << m_BarData.nRight; ar << m_BarData.nBottom; ar << m_BarData.nEdge; ar << m_BarData.nDockEdge; ar << m_BarData.dwStyle; ar << m_nSlidingTime; ar << m_nHiddenWidth; ar << m_nTimerInterval; ar << m_nToDock; ar << m_nToFloat; ar << m_rctFloat.left; ar << m_rctFloat.top; ar << m_rctFloat.right; ar << m_rctFloat.bottom; ar.Close(); } //////////////////////////////////////////////////// //SlideWindow(): slides the window in autohidden state //hiding/unhiding template void COXAppBar::SlideWindow() { CRect rctCurrent; PARENTWND::GetWindowRect(&rctCurrent); CRect rctEnd=rctCurrent; GetEndRect(rctEnd); DWORD dwCount=::GetTickCount(); while(CanContinue(rctCurrent,rctEnd)) { if ((dwCount-::GetTickCount())>m_nSlidingTime) { dwCount=::GetTickCount(); switch (m_BarData.nEdge) { case ABE_TOP: rctCurrent.bottom+=m_nOffset; break; case ABE_BOTTOM: rctCurrent.top-=m_nOffset; break; case ABE_LEFT: rctCurrent.right+=m_nOffset; break; case ABE_RIGHT: rctCurrent.left-=m_nOffset; break; } PARENTWND::MoveWindow(&rctCurrent); } } PARENTWND::MoveWindow(&rctEnd); } //////////////////////////////////////////////////// //CanContinue(): helper function for SlideWindow() //returns FALSE when appbar rect reached final position template BOOL COXAppBar::CanContinue(CRect& rctCurrent, CRect& rctEnd) { switch (m_BarData.nEdge) { case ABE_TOP: case ABE_BOTTOM: if (m_BarData.bHidden) return (BOOL) (rctCurrent.Height()rctEnd.Height()); case ABE_LEFT: case ABE_RIGHT: if (m_BarData.bHidden) return (BOOL) (rctCurrent.Width()rctEnd.Width()); default: ASSERT(FALSE); } return FALSE; } //////////////////////////////////////////////////// //GetEndRect(): helper function returns rectangle //appbar should reach while hiding/unhiding depends //on docking edge template void COXAppBar::GetEndRect(CRect& rect) { switch (m_BarData.nEdge) { case ABE_TOP: if (m_BarData.bHidden) rect.bottom=rect.top+m_BarData.nHeight; else rect.bottom=rect.top+GetHiddenWidth(); break; case ABE_BOTTOM: if (m_BarData.bHidden) rect.top=rect.bottom-m_BarData.nHeight; else rect.top=rect.bottom-GetHiddenWidth(); break; case ABE_LEFT: if (m_BarData.bHidden) rect.right=rect.left+m_BarData.nWidth; else rect.right=rect.left+GetHiddenWidth(); break; case ABE_RIGHT: if (m_BarData.bHidden) rect.left=rect.right-m_BarData.nWidth; else rect.left=rect.right-GetHiddenWidth(); break; } } ////////////////////////////////////////////////////// //GetProposedRect(): returns proposed rect for the edge //the appbar will switch to template void COXAppBar::GetProposedRect(CRect& rect) { rect.left=0; rect.top=0; rect.right=::GetSystemMetrics(SM_CXSCREEN); rect.bottom=::GetSystemMetrics(SM_CYSCREEN); if (m_BarData.dwStyle & OX_APPBARS_DIFFERENT_DIMS) { switch (m_BarData.nEdge) { case ABE_UNKNOWN: ASSERT(FALSE); break; case ABE_FLOAT: { CPoint pt; ::GetCursorPos(&pt); rect.left=pt.x-(m_rctFloat.right-m_rctFloat.left)/2; rect.right=rect.left+m_rctFloat.right-m_rctFloat.left; rect.top=pt.y-DIM_CAPTION; rect.bottom=rect.top+m_rctFloat.bottom-m_rctFloat.top; } break; case ABE_LEFT: rect.right=m_BarData.nLeft; break; case ABE_TOP: rect.bottom=m_BarData.nTop; break; case ABE_RIGHT: rect.left=rect.right-m_BarData.nRight; break; case ABE_BOTTOM: rect.top=rect.bottom-m_BarData.nBottom; break; } return; } switch (m_BarData.nEdge) { case ABE_UNKNOWN: ASSERT(FALSE); break; case ABE_FLOAT: PARENTWND::GetWindowRect(&rect); break; case ABE_LEFT: rect.right=m_BarData.nWidth; break; case ABE_TOP: rect.bottom=m_BarData.nHeight; break; case ABE_RIGHT: rect.left=rect.right-m_BarData.nWidth; break; case ABE_BOTTOM: rect.top=rect.bottom-m_BarData.nHeight; break; } } //////////////////////////////////////////////////// //GetProposedEdge(): propose the edge depends on current //placement of the appbar and position of the mouse, //while button pressed template UINT COXAppBar::GetProposedEdge() { POINT pt; CRect rectScreen; rectScreen.top=0; rectScreen.left=0; rectScreen.right = GetSystemMetrics(SM_CXSCREEN); rectScreen.bottom = GetSystemMetrics(SM_CYSCREEN); VERIFY(GetCursorPos(&pt)); CRect rectCurrent; PARENTWND::GetWindowRect(&rectCurrent); UINT nNewEdge=m_BarData.nEdge; UINT nLeftRight; UINT nTopBottom; UINT nDiffr=rectScreen.right; switch (m_BarData.nEdge) { case ABE_UNKNOWN: return ABE_UNKNOWN; case ABE_TOP: case ABE_LEFT: case ABE_RIGHT: case ABE_BOTTOM: if (!(m_BarData.dwStyle & OX_APPBARS_FLOAT)) { if (m_BarData.dwStyle & (OX_APPBARS_LEFT | OX_APPBARS_RIGHT)) nLeftRight=(pt.x>(rectScreen.right/2))?ABE_RIGHT:ABE_LEFT; else if (m_BarData.dwStyle & OX_APPBARS_LEFT) nLeftRight=ABE_LEFT; else if (m_BarData.dwStyle & OX_APPBARS_RIGHT) nLeftRight=ABE_RIGHT; else nLeftRight=ABE_UNKNOWN; if (m_BarData.dwStyle & (OX_APPBARS_TOP | OX_APPBARS_RIGHT)) nTopBottom=(pt.y>(rectScreen.bottom/2))?ABE_BOTTOM:ABE_TOP; else if (m_BarData.dwStyle & OX_APPBARS_TOP) nTopBottom=ABE_TOP; else if (m_BarData.dwStyle & OX_APPBARS_BOTTOM) nTopBottom=ABE_BOTTOM; else nTopBottom=ABE_UNKNOWN; switch( nLeftRight) { case ABE_UNKNOWN: if (nTopBottom==ABE_UNKNOWN) { ASSERT(FALSE); return m_BarData.nEdge; } return nTopBottom; case ABE_LEFT: if (nTopBottom==ABE_UNKNOWN) return ABE_LEFT; if (nTopBottom==ABE_TOP) { return (pt.x*rectScreen.Height() void COXAppBar::Float(APPBARDATA* pData) { SHAppBarMessage(ABM_REMOVE, pData); m_bFloating=TRUE; } ////////////////////////////////////////////////// //UnFloat() registers the appbar after floating template void COXAppBar::UnFloat(APPBARDATA* pData) { ASSERT(IsRegistered()); if (m_bFloating) m_bFloating=!SHAppBarMessage(ABM_NEW,pData); } ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(_OXAPPBAR_H__)