/** * @file XTPScrollable.h * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ /** @cond */ #if !defined(__XTPSCROLLABLE_H__) # define __XTPSCROLLABLE_H__ /** @endcond */ # if _MSC_VER > 1000 # pragma once # endif // _MSC_VER > 1000 # include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" /** @cond */ struct IXTPScrollable; class _XTP_EXT_CLASS CXTPScrollHost { public: explicit CXTPScrollHost(); ~CXTPScrollHost(); protected: BOOL InitializeScrollHost(IXTPScrollable* pScrollable, DWORD dwInitialStyle, DWORD dwInitialExStyle); void UninitializeScrollHost(); void SetScrollBarTheme(XTPScrollBarTheme nTheme); void EnableDefaultBorderDrawing(BOOL bEnable); BOOL IsScrollHostInitialized() const; BOOL OnHostWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); BOOL OnHostDefWindowProc(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); LRESULT SendControlMessage(UINT message, WPARAM wParam, LPARAM lParam); CWnd* GetEmbeddedControl(); private: CScrollBar* CreateBar(DWORD style, CWnd* pParent); void Layout(); void SynchronizeScrollBar(int nBar, PBOOL pbRequiresLayout = NULL, BOOL bInInit = FALSE); static LRESULT CALLBACK CtrlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT OnCtrlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL OnStyleChanging(WPARAM wParam, LPARAM lParam, LRESULT* pResult); BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); BOOL OnScroll(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); void FilterStyles(); # ifdef _XTP_INCLUDE_CONTROLS BOOL OnSetTheme(WPARAM wParam, LPARAM lParam, LRESULT* pResult); # endif BOOL OnCtrlMouseWheel(WPARAM wParam, LPARAM lParam, LRESULT* pResult); BOOL OnCtrlMouseHWheel(WPARAM wParam, LPARAM lParam, LRESULT* pResult); private: IXTPScrollable* m_pScrollable; CScrollBar* m_bars[2]; SCROLLINFO m_scrollInfo[2]; BOOL m_bLeftBar; BOOL m_bInitialized; CWnd* m_pControl; WNDPROC m_pfnCtrlProc; CWnd m_oldControl; CWnd* m_pGapCtrl; BOOL m_bEnableDefaultBorder; int m_nAccumulatedWheelDelta; int m_nAccumulatedHWheelDelta; BOOL m_bInLayout; DWORD m_dwCurrentCtlStyle; DWORD m_dwCurrentCtlExStyle; static CFont m_Font; static CXTPGlobalAtom m_propAtom; }; AFX_INLINE BOOL CXTPScrollHost::IsScrollHostInitialized() const { return m_bInitialized; } AFX_INLINE CWnd* CXTPScrollHost::GetEmbeddedControl() { return m_pControl; } /** @endcond */ /** * @brief * This interface is to be implemented only by special scrollable controls * that require overriding of scroll bars using CXTPScrollable adaptor and for which * the default implementation of this interface by CXTPScrollable does not work. * @see * CXTPScrollable */ struct IXTPScrollable { /** * @brief * Handles object destruction */ virtual ~IXTPScrollable() { } /** * @brief * Obtains scrollable control window reference. * @return * Scrollable control window reference. */ virtual CWnd& GetWnd() = 0; /** * @brief * Returns TRUE if the control has vertical scroll bar for the combination of styles * specified. * @param dwStyle Window style bits. * @param dwExStyle Window extended style bits. * @return * TRUE if the control has vertical scroll bar for the combination of styles specified, * otherwise the return value is FALSE. */ virtual BOOL HasVScroll(DWORD dwStyle, DWORD dwExStyle) const = 0; /** * @brief * Returns TRUE if the control has horizontal scroll bar for the combination of styles * specified. * @param dwStyle Window style bits. * @param dwExStyle Window extended style bits. * @return * TRUE if the control has horizontal scroll bar for the combination of styles specified, * otherwise the return value is FALSE. */ virtual BOOL HasHScroll(DWORD dwStyle, DWORD dwExStyle) const = 0; /** * @brief * Returns TRUE if the control has vertical scroll bar on the left side for the combination * of * styles specified. * @param dwStyle Window style bits. * @param dwExStyle Window extended style bits. * @return * TRUE if the control has vertical scroll bar on the left side for the combination of * styles * specified, FALSE indicates scroll bar on the right side. */ virtual BOOL HasLeftScrollbar(DWORD dwStyle, DWORD dwExStyle) const = 0; /** * @brief * Disables/removes standard scroll bars so that custom scroll bars created via this * interface could be used. */ virtual void DisableScrollbars() = 0; /** * @brief * Disables/removes standard scroll bars so that custom scroll bars created via this * interface could be used. * @param wnd Window for which scrollbars must be disabled. */ virtual void DisableScrollbars(CWnd& wnd) = 0; /** * @brief * Creates a new scroll bar object. * @return * A new instance of a scroll bar object that is derived from CScrollBar. It's caller's * responsibility to handle object lifetime. */ virtual CScrollBar* CreateBar() const = 0; /** * @brief * Creates a close instance of the control itself. * @return * A new instance of the control object. It's caller's * responsibility to handle object lifetime. */ virtual CWnd* CreateControl() const = 0; /** * @brief * Filters supplied window style if needed. The method is called every * time a change in window style is detected. * @param dwStyle Current style bits. * @return * Modified style bits or the original value if no change in style * is required. */ virtual DWORD FilterStyle(DWORD dwStyle) const = 0; /** * @brief * Filters supplied extended window style if needed. The method is * called every time a change in extended window style is detected. * @param dwExStyle Current extended style bits. * @return * Modified extended style bits or the original value if no change in * extended style is required. */ virtual DWORD FilterExStyle(DWORD dwExStyle) const = 0; /** * @brief * Determines if mouse wheel handling logic must be overridden by scroll * host when a hosted control is not able to handle mouse wheel interaction * when its scroll bars are disabled. * @return * TRUE if scroll host is to provide its own default implementation of * mouse wheel rotation handling. For default dehavior determined by the * hosted control the return value must be FALSE. */ virtual BOOL RequiresMouseWheelOverriding() const = 0; }; /** * @brief * The adaptor class for a scrollable control for which standard scroll bars * have to be overriden. * @param Base Class name of the base control class. * @see * IXTPScrollable */ template class CXTPScrollable : public Base , public CXTPScrollHost , public IXTPScrollable { public: /** * @brief * Initializes a scrollable object instance. */ CXTPScrollable(); # if (1310 < _MSC_VER) using Base::Create; using Base::CreateEx; # endif /** * @brief * Creates a scrollable control window. * @param lpszClassName Pointer to a null-terminated string that contains the name of a * registered * system window class; or the name of a predefined system window class. * @param lpszWindowName Pointer to a null-terminated string that contains the window display * name; * otherwise NULL for no window display name. * @param dwStyle Bitwise combination (OR) of window styles. The WS_POPUP option is not a * valid * style. * @param rect The size and location of the window relative to the top-left corner of * the parent * window. * @param pParentWnd Pointer to the parent window. * @param nID ID of the window. * @param pContext Pointer to a CCreateContext structure that is used to customize the * document-view * architecture for the application. * @return * TRUE if the window is successfully created, otherwise the return value is FALSE. */ virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); /** * @brief * Creates a scrollable control window. * @param dwExStyle Bitwise combination(OR) of extended window styles; otherwise NULL for * the default extended window style. * @param lpszClassName Pointer to a null-terminated string that contains the name of a * registered system window class; or the name of a predefined system * window class. * @param lpszWindowName Pointer to a null-terminated string that contains the window display * name; otherwise NULL for no window display name. * @param dwStyle Bitwise combination (OR) of window styles. The WS_POPUP option is not a * valid style. * @param x The initial horizontal distance of the window from the left side of the * screen or the parent window. * @param y The initial vertical distance of the window from the top of the screen * or the parent window. * @param nWidth The width, in pixels, of the window. * @param nHeight The height, in pixels, of the window. * @param hWndParent Handle to the parent window. * @param nIDorHMenu ID or menu handle for the window. * @param lpParam Points to the data referenced by the lpCreateParams field of the * CREATESTRUCT structure. * @return * TRUE if the window is successfully created, otherwise the return value is FALSE. */ virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam = NULL); /** * @brief * Creates a scrollable control window. * @param dwExStyle Bitwise combination(OR) of extended window styles; otherwise NULL for * the default extended window style. * @param lpszClassName Pointer to a null-terminated string that contains the name of a * registered system window class; or the name of a predefined system * window class. * @param lpszWindowName Pointer to a null-terminated string that contains the window display * name; otherwise NULL for no window display name. * @param dwStyle Bitwise combination (OR) of window styles. The WS_POPUP option is not a * valid style. * @param rect The size and location of the window relative to the top-left corner of * the parent window. * @param pParentWnd Pointer to the parent window. * @param nID ID of the window. * @param lpParam Points to the data referenced by the lpCreateParams field of the * CREATESTRUCT structure. * @return * TRUE if the window is successfully created, otherwise the return value is FALSE. */ virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam = NULL); /** * @brief * Performs one time custom scroll bars intitialization. In most common use cases there is * no need to * call it manually as intitialization is performed automatically on window creation or DDX * binding. * @return * TRUE if scroll bars are initialized successfully. */ BOOL InitScrollBars(); /** * @brief * Sets custom scroll bars theme. * @param nTheme scroll bar theme identifier. */ void SetScrollBarTheme(XTPScrollBarTheme nTheme); /** * @brief * Enables or disables default border drawing for a host control. * Enabled by default. * @param bEnable TRUE to enable default border drawing, FALSE to disable it. */ void EnableDefaultBorderDrawing(BOOL bEnable = TRUE); private: virtual CWnd& GetWnd(); virtual BOOL HasVScroll(DWORD dwStyle, DWORD dwExStyle) const; virtual BOOL HasHScroll(DWORD dwStyle, DWORD dwExStyle) const; virtual BOOL HasLeftScrollbar(DWORD dwStyle, DWORD dwExStyle) const; virtual void DisableScrollbars(); virtual void DisableScrollbars(CWnd& wnd); virtual CScrollBar* CreateBar() const; virtual CWnd* CreateControl() const; virtual DWORD FilterStyle(DWORD dwStyle) const; virtual DWORD FilterExStyle(DWORD dwStyle) const; virtual BOOL RequiresMouseWheelOverriding() const; /** @cond */ protected: virtual void PreSubclassWindow(); virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); /** @endcond */ private: DWORD m_dwInitialStyle; DWORD m_dwInitialExStyle; }; /** @cond */ template AFX_INLINE CXTPScrollable::CXTPScrollable() : m_dwInitialStyle(0) , m_dwInitialExStyle(0) { } template AFX_INLINE BOOL CXTPScrollable::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext /*= NULL*/) { if (0 == m_dwInitialStyle) m_dwInitialStyle = dwStyle | WS_CHILD; // The window being created will be destroyed right away so it should be OK to bypass // Base::Create call and call CWnd::Create directly. if (!CWnd::Create(lpszClassName, lpszWindowName, dwStyle & ~WS_VISIBLE, rect, pParentWnd, nID, pContext)) return FALSE; if (!IsScrollHostInitialized()) { VERIFY(CXTPScrollHost::InitializeScrollHost(this, m_dwInitialStyle, 0)); m_dwInitialStyle = 0; } return TRUE; } template AFX_INLINE BOOL CXTPScrollable::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam /*= NULL*/) { if (0 == m_dwInitialStyle) m_dwInitialStyle = dwStyle | WS_CHILD; if (0 == m_dwInitialExStyle) m_dwInitialExStyle = dwExStyle; // The window being created will be destroyed right away so it should be OK to bypass // Base::CreateEx call and call CWnd::CreateEx directly. if (!CWnd::CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle & ~WS_VISIBLE, x, y, nWidth, nHeight, hWndParent, nIDorHMenu, lpParam)) return FALSE; if (!IsScrollHostInitialized()) { VERIFY(CXTPScrollHost::InitializeScrollHost(this, m_dwInitialStyle, m_dwInitialExStyle)); m_dwInitialStyle = 0; m_dwInitialExStyle = 0; } return TRUE; } template AFX_INLINE BOOL CXTPScrollable::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam /*= NULL*/) { if (0 == m_dwInitialStyle) m_dwInitialStyle = dwStyle | WS_CHILD; if (0 == m_dwInitialExStyle) m_dwInitialExStyle = dwExStyle; // The window being created will be destroyed right away so it should be OK to bypass // Base::CreateEx call and call CWnd::CreateEx directly. if (!CWnd::CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle & ~WS_VISIBLE, rect, pParentWnd, nID, lpParam)) return FALSE; if (!IsScrollHostInitialized()) { VERIFY(CXTPScrollHost::InitializeScrollHost(this, m_dwInitialStyle, m_dwInitialExStyle)); m_dwInitialStyle = 0; m_dwInitialExStyle = 0; } return TRUE; } template AFX_INLINE BOOL CXTPScrollable::InitScrollBars() { if (IsScrollHostInitialized()) return TRUE; _ASSERTE(::IsWindow(*this)); return CXTPScrollHost::InitializeScrollHost(this, CObject::GetStyle(), CObject::GetExStyle()); } template AFX_INLINE void CXTPScrollable::SetScrollBarTheme(XTPScrollBarTheme nTheme) { CXTPScrollHost::SetScrollBarTheme(nTheme); } template AFX_INLINE void CXTPScrollable::EnableDefaultBorderDrawing(BOOL bEnable /*= TRUE*/) { CXTPScrollHost::EnableDefaultBorderDrawing(bEnable); } template AFX_INLINE CWnd& CXTPScrollable::GetWnd() { return *this; } template AFX_INLINE BOOL CXTPScrollable::HasVScroll(DWORD dwStyle, DWORD dwExStyle) const { UNREFERENCED_PARAMETER(dwExStyle); return 0 != (dwStyle & WS_VSCROLL); } template AFX_INLINE BOOL CXTPScrollable::HasHScroll(DWORD dwStyle, DWORD dwExStyle) const { UNREFERENCED_PARAMETER(dwExStyle); return 0 != (dwStyle & WS_HSCROLL); } template AFX_INLINE BOOL CXTPScrollable::HasLeftScrollbar(DWORD dwStyle, DWORD dwExStyle) const { UNREFERENCED_PARAMETER(dwStyle); return 0 != (dwExStyle & WS_EX_LEFTSCROLLBAR); } template AFX_INLINE void CXTPScrollable::DisableScrollbars() { DisableScrollbars(*this); } template AFX_INLINE void CXTPScrollable::DisableScrollbars(CWnd& wnd) { wnd.ModifyStyle(WS_VSCROLL | WS_HSCROLL, 0); wnd.ModifyStyleEx(WS_EX_LEFTSCROLLBAR, 0); } template AFX_INLINE CScrollBar* CXTPScrollable::CreateBar() const { return new CXTPScrollBarCtrl(); } template AFX_INLINE CWnd* CXTPScrollable::CreateControl() const { return new Base(); } template AFX_INLINE DWORD CXTPScrollable::FilterStyle(DWORD dwStyle) const { return dwStyle; } template AFX_INLINE DWORD CXTPScrollable::FilterExStyle(DWORD dwExStyle) const { return dwExStyle; } template AFX_INLINE BOOL CXTPScrollable::RequiresMouseWheelOverriding() const { return FALSE; } template AFX_INLINE void CXTPScrollable::PreSubclassWindow() { Base::PreSubclassWindow(); if (!IsScrollHostInitialized()) { // If window has coordinates it is assumed the window is fully // created and the calls is not made from HCBT_CREATEWND. CRect rc; ::GetWindowRect(CXTPScrollable::m_hWnd, &rc); if (0 != rc.top || 0 != rc.left || 0 != rc.bottom || 0 != rc.right) VERIFY(CXTPScrollHost::InitializeScrollHost(this, CXTPScrollable::GetStyle(), CXTPScrollable::GetExStyle())); } } template AFX_INLINE LRESULT CXTPScrollable::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (!IsScrollHostInitialized()) return Base::DefWindowProc(message, wParam, lParam); LRESULT lResult = 0; if (CXTPScrollHost::OnHostDefWindowProc(message, wParam, lParam, &lResult)) return lResult; return ::DefWindowProc(CXTPScrollable::m_hWnd, message, wParam, lParam); } template AFX_INLINE BOOL CXTPScrollable::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { if (!IsScrollHostInitialized()) return Base::OnWndMsg(message, wParam, lParam, pResult); if (CXTPScrollHost::OnHostWndMsg(message, wParam, lParam, pResult)) return TRUE; // Base implementation must not be called as the control is already stolen. return CWnd::OnWndMsg(message, wParam, lParam, pResult); } /** @endcond */ # include "Common/Base/Diagnostic/XTPEnableNoisyWarnings.h" /** @cond */ #endif // !defined(__XTPSCROLLABLE_H__) /** @endcond */