#ifndef __TAB_BAR_HPP__ #define __TAB_BAR_HPP__ #include #include #include #include #include #include "PaintUtil.hpp" #include "Theme.hpp" namespace jdi { /** * @brief 标签栏交互结果。 */ struct TabBarResult { /** * @brief 交互动作类型。 */ enum class Type : int { NONE = 0, /**< 未触发任何动作。 */ SELECT, /**< 切换到指定标签页。 */ CLOSE, /**< 关闭指定标签页。 */ ADD, /**< 新建标签页。 */ CONTEXT /**< 请求弹出标签页上下文菜单。 */ }; Type type = Type::NONE; /**< 动作类型。 */ int index = -1; /**< 标签页下标(ADD 时无意义)。 */ int screenX = 0; /**< 上下文菜单请求的屏幕横坐标。 */ int screenY = 0; /**< 上下文菜单请求的屏幕纵坐标。 */ }; /** * @brief 顶部标签栏:支持多视图切换、新建与关闭。 */ class TabBar { public: TabBar(); /** * @brief 绑定字体与主题资源。 * @param [IN] fonts 字体集合,需在标签栏生命周期内保持有效。 * @param [IN] theme 主题配色,需在标签栏生命周期内保持有效。 */ void Setup(const UiFonts* fonts, const Theme* theme); /** * @brief 设置 DPI 缩放比例。 * @param [IN] scale 缩放比例(1.0 对应 96 DPI)。 */ void SetScale(float scale); /** * @brief 更新标签页名称集合。 * @param [IN] names 标签页名称列表。 */ void SetTabs(const std::vector& names); /** * @brief 设置当前激活的标签页下标。 * @param [IN] index 标签页下标,-1 表示无激活页。 */ void SetActiveIndex(int index); /** * @brief 计算标签栏期望高度。 * @return 期望高度(像素)。 */ float DesiredHeight() const; /** * @brief 按给定区域重新排布标签与按钮。 * @param [IN] area 标签栏可用区域。 */ void Layout(const gd::RectF& area); /** * @brief 绘制标签栏。 * @param [IN,OUT] g 绘图上下文。 */ void Paint(gd::Graphics& g); /** * @brief 处理鼠标移动。 * @param [IN] x 客户区横坐标。 * @param [IN] y 客户区纵坐标。 * @return 悬停状态发生变化返回 true。 */ bool OnMouseMove(int x, int y); /** * @brief 处理鼠标左键按下。 * @param [IN] x 客户区横坐标。 * @param [IN] y 客户区纵坐标。 * @return 命中可点击元素返回 true。 */ bool OnLButtonDown(int x, int y); /** * @brief 处理鼠标左键抬起并给出交互结果。 * @param [IN] x 客户区横坐标。 * @param [IN] y 客户区纵坐标。 * @param [OUT] result 交互结果。 * @return 视觉状态发生变化返回 true。 */ bool OnLButtonUp(int x, int y, TabBarResult& result); /** * @brief 处理鼠标右键按下(请求标签页上下文菜单)。 * @param [IN] x 客户区横坐标。 * @param [IN] y 客户区纵坐标。 * @param [IN] screenX 屏幕横坐标。 * @param [IN] screenY 屏幕纵坐标。 * @param [OUT] result 交互结果。 * @return 命中标签页返回 true。 */ bool OnRButtonDown(int x, int y, int screenX, int screenY, TabBarResult& result); /** * @brief 处理鼠标离开标签栏。 * @return 视觉状态发生变化返回 true。 */ bool OnMouseLeave(); /** * @brief 判断坐标是否落在标签栏区域内。 * @param [IN] x 客户区横坐标。 * @param [IN] y 客户区纵坐标。 * @return 落在区域内返回 true。 */ bool HitTest(int x, int y) const; private: /** * @brief 单个标签页的布局信息。 */ struct TabItem { std::wstring name; /**< 标签页名称。 */ gd::RectF rect; /**< 标签整体矩形。 */ gd::RectF closeRect; /**< 关闭按钮矩形。 */ }; /** * @brief 判断坐标命中的标签页下标。 * @param [IN] x 客户区横坐标。 * @param [IN] y 客户区纵坐标。 * @return 标签页下标,未命中返回 -1。 */ int TabAtPoint(int x, int y) const; const UiFonts* m_fonts = nullptr; /**< 字体资源。 */ const Theme* m_theme = nullptr; /**< 主题资源。 */ float m_scale = 1.0f; /**< DPI 缩放比例。 */ std::vector m_tabs; /**< 标签页布局集合。 */ gd::RectF m_addRect; /**< 新建按钮矩形。 */ gd::RectF m_area; /**< 标签栏整体区域。 */ int m_activeIndex = -1; /**< 当前激活标签页下标。 */ int m_hoverIndex = -1; /**< 当前悬停标签页下标。 */ bool m_hoverClose = false; /**< 是否悬停在关闭按钮上。 */ bool m_hoverAdd = false; /**< 是否悬停在新建按钮上。 */ int m_pressedIndex = -1; /**< 当前按下的标签页下标。 */ bool m_pressedClose = false; /**< 是否按在关闭按钮上。 */ bool m_pressedAdd = false; /**< 是否按在新建按钮上。 */ }; } // namespace jdi #endif // __TAB_BAR_HPP__