#ifndef UI_CORE_BOX_H_ #define UI_CORE_BOX_H_ #pragma once namespace ui { class Box; class UILIB_API Layout { public: Layout(); Layout& operator=(const Layout& r) = delete; virtual ~Layout() {} /** * @brief 设置所有者 * @return 无 */ void SetOwner(Box* pOwner); /** * @brief 设置浮动状态下的坐标信息 * @param[in] pControl 控件句柄 * @param[in] rcContainer 要设置的位置信息 * @return 返回控件最终的位置信息 */ static CSize SetFloatPos(Control* pControl, UiRect rcContainer); /** * @brief 设置布局属性 * @param[in] strName 要设置的属性名 * @param[in] strValue 要设置的属性值 * @return true 设置成功,false 属性不存在 */ virtual bool SetAttribute(const std::wstring& strName, const std::wstring& strValue); /** * @brief 调整内部所有控件的位置信息 * @param[in] items 控件列表 * @param[in] rc 当前容器位置信息 * @return 返回排列后最终盒子的宽度和高度信息 */ virtual CSize ArrangeChild(const std::vector& items, UiRect rc); /** * @brief 根据内部子控件大小调整容器自身大小 * @param[in] items 控件列表 * @param[in] szAvailable 子控件允许的最大宽度 * @return 返回排列后最终盒子的宽度和高度信息 */ virtual CSize AjustSizeByChild(const std::vector& items, CSize szAvailable); /** * @brief 获取内边距 * @return 返回内边距四边的大小 */ virtual UiRect GetPadding() const; /** * @brief 设置内边距,相当于设置客户区 * @param[in] rcPadding 内边距数据 * @param[in] bNeedDpiScale 是否根据 DPI 自适应,默认为 true * @return 无 */ virtual void SetPadding(UiRect rcPadding, bool bNeedDpiScale = true); /** * @brief 获取子控件之间的额外边距 * @return 返回额外间距的数值 */ virtual int GetChildMargin() const; /** * @brief 设置子控件之间的额外边距 * @param[in] iMargin 要设置的边距数值 * @return 无 */ virtual void SetChildMargin(int iMargin); /** * @brief 获取除了内边距外的可用范围 * @return 返回可用范围位置信息 */ UiRect GetInternalPos() const; protected: UiRect m_rcPadding; int m_iChildMargin; Box *m_pOwner; }; ///////////////////////////////////////////////////////////////////////////////////// // class ScrollBar; class UILIB_API Box : public Control { public: Box(Layout* pLayout = new Layout()); Box(const Box& r); Box& operator=(const Box& r) = delete; virtual ~Box(); public: /// 重写父类接口,提供个性化功能。方法具体说明请查看 Control 控件 */ virtual void SetWindow(Window* pManager, Box* pParent, bool bInit = true) override; virtual void SetAttribute(const std::wstring& strName, const std::wstring& strValue) override; virtual void SetPos(UiRect rc) override; virtual void HandleMessageTemplate(EventArgs& msg) override; virtual void PaintChild(IRenderContext* pRender, const UiRect& rcPaint) override; virtual void SetVisible_(bool bVisible) override; virtual void SetInternVisible(bool bVisible = true) override; virtual void SetEnabled(bool bEnabled) override; virtual CSize EstimateSize(CSize szAvailable) override; virtual Control* FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags, CPoint scrollPos = CPoint()) override; virtual void InvokeLoadImageCache() override; virtual void UnLoadImageCache() override; virtual void ClearImageCache() override; virtual UINT GetControlFlags() const override; /// 容器自有方法 /** * @brief 查找指定子控件 * @param[in] pstrSubControlName 子控件名称 * @return 返回子控件指针 */ Control* FindSubControl(const std::wstring& pstrSubControlName); /** * @brief 查找下一个可选控件的索引(面向 list、combo) * @param[in] iIndex 指定要起始查找的索引 * @param[in] bForward true 为递增查找, false 为递减查找 * @return 下一个可选控件的索引,返回 -1 为没有可选控件 */ virtual int FindSelectable(int iIndex, bool bForward = true) const; /** * @brief 根据索引查找指定控件 * @param[in] iIndex 控件索引 * @return 返回控件指针 */ virtual Control* GetItemAt(std::size_t iIndex) const; /** * @brief 根据控件指针获取索引 * @param[in] pControl 控件指针 * @return 返回 pControl 所指向的控件索引 */ virtual int GetItemIndex(Control* pControl) const; /** * @brief 设置控件索引(内部会重新排列控件位置) * @param[in] pControl 控件指针 * @param[in] iIndex 要设置的索引值 * @return 返回 true 设置成功,false 设置失败 */ virtual bool SetItemIndex(Control* pControl, std::size_t iIndex); /** * @brief 获取子控件数量 * @return 返回子控件数量 */ virtual int GetCount() const; /** * @brief 添加一个控件到容器中 * @param[in] pControl 控件指针 * @return 返回 true 添加成功,false 为添加失败 */ virtual bool Add(Control* pControl); /** * @brief 向指定位置添加一个控件 * @param[in] pControl 控件指针 * @param[in] iIndex 在该索引之后插入控件 * @return 返回 true 为添加成功,false 为添加失败 */ virtual bool AddAt(Control* pControl, std::size_t iIndex); /** * @brief 根据控件指针从容器中移除一个控件 * @param[in] pControl 控件的指针 * @return 返回 true 为移除成功,false 为移除失败(控件可能不存在) */ virtual bool Remove(Control* pControl); /** * @brief 根据控件索引从容器中移除一个控件 * @param[in] iIndex 要移除的控件索引 * @return 返回 true 为移除成功,false 为移除失败(索引值太小或超出了子控件总数) */ virtual bool RemoveAt(std::size_t iIndex); /** * @brief 移除所有子控件 * @return 无 */ virtual void RemoveAll(); /** * @brief 交换子控件位置 * @param[in] pChild1 子控件1 指针 * @param[in] pChild2 子控件2 指针 * @return 无 */ void SwapChild(Control* pChild1, Control* pChild2); /** * @brief 重置一个子控件位置 * @param[in] pChild 控件指针 * @param[in] iIndex 要重置的位置 * @return 无 */ void ResetChildIndex(Control* pChild, std::size_t iIndex); /** * @brief 判断是否自动销毁 * @return true 为自动销毁,false 为不自动销毁 */ virtual bool IsAutoDestroy() const; /** * @brief 设置控件是否自动销毁 * @param[in] bAuto true 为自动销毁,false 为不自动销毁 * @return 无 */ virtual void SetAutoDestroy(bool bAuto); /** * @brief 判断窗口关闭后是否自动销毁 * @return true 为自动销毁,false 为不自动销毁 */ virtual bool IsDelayedDestroy() const; /** * @brief 设置窗口关闭后是否自动销毁 * @param[in] bDelayed true 为自动销毁,false 为不自动销毁 * @return 无 */ virtual void SetDelayedDestroy(bool bDelayed); /** * @brief 获取容器是否响应鼠标操作 * @return true 为响应,false 为不响应 */ virtual bool IsMouseChildEnabled() const; /** * @brief 设置容器响应鼠标操作 * @param[in] bEnable 设置为 true 为响应鼠标操作,设置为 false 为不响应,默认为 true * @return 无 */ virtual void SetMouseChildEnabled(bool bEnable = true); /** * @brief 获取容器布局对象指针 * @return 返回容器关联的布局对象指针 */ virtual Layout* GetLayout() const; /** * @brief 重新关联布局对象 * @param[in] pLayout 布局对象指针 * @return 无 */ virtual void RetSetLayout(Layout* pLayout); /** * @brief 获取内边距的位置信息 * @return 返回内边距的位置信息 */ virtual UiRect GetPaddingPos() const; /** * @brief 绑定事件处理函数 * @param[in] eventType 事件类型 * @return callback 指定回调函数 */ void AttachBubbledEvent(EventType eventType, const EventCallback& callback) { OnBubbledEvent[eventType] += callback; } private: friend WindowBuilder; /** * @brief 绑定 XML 中编写的 Event 和 BubbleEvent 事件的处理函数 * @param[in] eventType 事件类型 * @return callback 指定回调函数 */ void AttachXmlBubbledEvent(EventType eventType, const EventCallback& callback) { OnXmlBubbledEvent[eventType] += callback; } EventMap OnXmlBubbledEvent; protected: std::unique_ptr m_pLayout; bool m_bAutoDestroy; bool m_bDelayedDestroy; bool m_bMouseChildEnabled; std::vector m_items; EventMap OnBubbledEvent; }; /// 带有垂直或水平滚动条的容器,使容器可以容纳更多内容 class UILIB_API ScrollableBox : public Box { public: ScrollableBox(Layout* pLayout); ScrollableBox(const ScrollableBox& r); ScrollableBox& operator=(const ScrollableBox& r) = delete; virtual void SetAttribute(const std::wstring& pstrName, const std::wstring& pstrValue) override; virtual void SetPos(UiRect rc) override; virtual void HandleMessage(EventArgs& event) override; virtual bool MouseEnter(EventArgs& msg) override; virtual bool MouseLeave(EventArgs& msg) override; virtual void PaintChild(IRenderContext* pRender, const UiRect& rcPaint) override; virtual void SetMouseEnabled(bool bEnable = true) override; virtual void SetWindow(Window* pManager, Box* pParent, bool bInit) override; virtual Control* FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags, CPoint scrollPos = CPoint()) override; virtual void ClearImageCache() override; /** * @brief 获取滚动条位置 * @return 返回滚动条的位置信息 */ virtual CSize GetScrollPos() const; /** * @brief 获取滚动条的范围 * @return 返回滚动条的范围信息 */ virtual CSize GetScrollRange() const; /** * @brief 设置滚动条位置 * @param[in] szPos 要设置的位置数据 * @return 无 */ virtual void SetScrollPos(CSize szPos); /** * @brief 设置滚动条 Y 轴坐标 * @param[in] y 要设置的 Y 轴坐标数值 * @return 无 */ virtual void SetScrollPosY(int y); /** * @brief 设置滚动条 X 轴坐标 * @param[in] x 要设置的 X 轴坐标数值 * @return 无 */ virtual void SetScrollPosX(int x); /** * @brief 向上滚动滚动条 * @param[in] deltaValue 滚动距离,默认为 DUI_NOSET_VALUE * @param[in] withAnimation 是否附带动画效果,默认为 true * @return 无 */ virtual void LineUp(int detaValue = DUI_NOSET_VALUE, bool withAnimation = true); /** * @brief 向下滚动滚动条 * @param[in] deltaValue 滚动距离,默认为 DUI_NOSET_VALUE * @param[in] withAnimation 是否附带动画效果,默认为 true * @return 无 */ virtual void LineDown(int detaValue = DUI_NOSET_VALUE, bool withAnimation = true); /** * @brief 向左滚动滚动条 * @param[in] deltaValue 滚动距离,默认为 DUI_NOSET_VALUE * @return 无 */ virtual void LineLeft(int detaValue = DUI_NOSET_VALUE); /** * @brief 向右滚动滚动条 * @param[in] deltaValue 滚动距离,默认为 DUI_NOSET_VALUE * @return 无 */ virtual void LineRight(int detaValue = DUI_NOSET_VALUE); /** * @brief 向上滚动一个页面大小的距离 * @return 无 */ virtual void PageUp(); /** * @brief 向下滚动一个页面大小的距离 * @return 无 */ virtual void PageDown(); /** * @brief 回到滚动条最上方 * @return 无 */ virtual void HomeUp(); /** * @brief 滚动到最下方位置 * @param[in] arrange 是否重置滚动条位置,默认为 true * @param[in] withAnimation 是否包含动画特效,默认为 true * @return 无 */ virtual void EndDown(bool arrange = true, bool withAnimation = true); /** * @brief 向左滚动一个页面大小的距离 * @return 无 */ virtual void PageLeft(); /** * @brief 向右滚动一个页面大小的距离 * @return 无 */ virtual void PageRight(); /** * @brief 滚动到最左侧 * @return 无 */ virtual void HomeLeft(); /** * @brief 滚动到最右侧 * @return 无 */ virtual void EndRight(); /** * @brief 触摸向上滚动(响应 WM_TOUCH 消息) * @param[in] deltaValue 滚动距离 * @return 无 */ virtual void TouchUp(int deltaValue); /** * @brief 触摸向下滚动(响应 WM_TOUCH 消息) * @param[in] deltaValue 滚动距离 * @return 无 */ virtual void TouchDown(int deltaValue); /** * @brief 启用滚动条 * @param[in] bEnableVertical 是否启用垂直滚动条,默认为 true * @param[in] bEnableHorizontal 是否启用水平滚动条,默认为 true * @return 无 */ virtual void EnableScrollBar(bool bEnableVertical = true, bool bEnableHorizontal = false); /** * @brief 获取垂直滚动条对象指针 * @return 返回垂直滚动条对象指针 */ virtual ScrollBar* GetVerticalScrollBar() const; /** * @brief 获取水平滚动条对象指针 * @return 返回水平滚动条对象指针 */ virtual ScrollBar* GetHorizontalScrollBar() const; /** * @brief 待补充 * @param[in] 待补充 * @return 待补充 */ virtual void ProcessVScrollBar(UiRect rc, int cyRequired); /** * @brief 待补充 * @param[in] 待补充 * @return 待补充 */ virtual void ProcessHScrollBar(UiRect rc, int cxRequired); /** * @brief 判断垂直滚动条是否有效 * @return 返回 true 表示有效,否则 false 为无效 */ bool IsVScrollBarValid() const; /** * @brief 判断水平滚动条是否有效 * @return 返回 true 表示有效,否则 false 为无效 */ bool IsHScrollBarValid() const; /** * @brief 待补充 * @param[in] 待补充 * @return 待补充 */ void ReomveLastItemAnimation(); /** * @brief 待补充 * @param[in] 待补充 * @return 待补充 */ void PlayRenderOffsetYAnimation(int nRenderY); /** * @brief 是否已经在底部 * @return 返回 true 表示已经在底部,否则为 false */ bool IsAtEnd() const; /** * @brief 是否锁定到底部 * @return 回 true 表示锁定在底部,否则为 false */ bool IsHoldEnd() const; /** * @brief 设置滚动条是否始终锁定到底部位置 * @param[in] bHoldEnd 设置 true 表示锁定,false 为不锁定 * @return 无 */ void SetHoldEnd(bool bHoldEnd); /** * @brief 获取垂直滚动条滚动步长 * @return 返回滚动步长 */ int GetVerScrollUnitPixels() const; /** * @brief 设置垂直滚动条滚动步长 * @param[in] nUnitPixels 要设置的步长 * @return 无 */ void SetVerScrollUnitPixels(int nUnitPixels); /** * @brief 获取横向滚动条滚动步长 * @return 返回滚动步长 */ int GetHorScrollUnitPixels() const; /** * @brief 设置横向滚动条滚动步长 * @param[in] nUnitPixels 要设置的步长 * @return 无 */ void SetHorScrollUnitPixels(int nUnitPixels); /** * @brief 获取容器的滚动条是否悬浮在子控件上面 * @return 返回 true 表示悬浮在滚动条上,否则为 false */ bool GetScrollBarFloat() const; /** * @brief 设置容器的滚动条是否悬浮在子控件上面 * @param[in] bScrollBarFloat true 表示悬浮在滚动条上,false 表示不悬浮在控件上 * @return 无 */ void SetScrollBarFloat(bool bScrollBarFloat); /** * @brief 获取滚动条的外边距 * @return 返回边距信息 */ UiRect GetScrollBarPadding() const; /** * @brief 设置滚动条的外边距,可以让滚动条不占满容器 * @param[in] rcScrollBarPadding 要设置的边距 * @return 无 */ void SetScrollBarPadding(UiRect rcScrollBarPadding); /** * @brief 待补充 * @param[in] 待补充 * @return 待补充 */ bool GetDefaultDisplayScrollbar() const; /** * @brief 待补充 * @param[in] 待补充 * @return 待补充 */ void SetDefaultDisplayScrollbar(bool bDefaultDisplay); /** * @brief 监听滚动条位置变化事件 * @param[in] callback 有变化后通知的回调函数 * @return 无 */ void AttachScrollChange(const EventCallback& callback) { OnEvent[kEventScrollChange] += callback; } protected: /** * @brief 计算所需的尺寸 * @param[in] rc 当前位置信息 * @return 返回所需尺寸大小 */ virtual CSize CalcRequiredSize(const UiRect& rc); /** * @brief 加载图片缓存,仅供 ScrollableBox 内部使用 * @param[in] bFromTopLeft 暂无意义 * @return 无 */ void LoadImageCache(bool bFromTopLeft); private: /** * @brief 待补充 * @param[in] 待补充 * @return 待补充 */ void SetPosInternally(UiRect rc); protected: std::unique_ptr m_pVerticalScrollBar; std::unique_ptr m_pHorizontalScrollBar; int m_nVerScrollUnitPixels; int m_nHerScrollUnitPixels; bool m_bScrollProcess; // 防止SetPos循环调用 bool m_bHoldEnd; bool m_bScrollBarFloat; bool m_bDefaultDisplayScrollbar; UiRect m_rcScrollBarPadding; CPoint m_ptLastTouchPos; AnimationPlayer m_scrollAnimation; AnimationPlayer m_renderOffsetYAnimation; }; } // namespace ui #endif // UI_CORE_BOX_H_