#ifndef __UI_BUTTON_WIDGET_HPP__ #define __UI_BUTTON_WIDGET_HPP__ #include #include #include "UiWidget.hpp" namespace jdi { /** * @brief 按钮图标(非 `NONE` 时按钮**只画图标**,忽略文本)。 * * 图标用矢量绘制(不用字体里的符号):`⚙` 这类字符在中文/西文回退字体里 * 宽高与基线各不相同,会出现"图标忽大忽小、垂直不居中"的问题。 */ enum class UiButtonIcon : int { NONE = 0, /**< 无图标(只画文本)。 */ GEAR = 1 /**< 齿轮:设置菜单入口。 */ }; /** * @brief 一个"文字按钮"控件(工具栏按钮的原语)。 * * 视觉规则与旧 `Toolbar` 的按钮**逐像素一致**: * * 主按钮(`primary`)= 强调色实底 + `textOnAccent` 文字,按下 / 悬停时整体提亮或压暗; * * 普通按钮 = 透明底 + 1px 描边,可切换按钮选中时用 `accentSoft` 底 + `accent` 描边; * * 禁用时底色回退为工具栏底色、文字用 `textMuted`、描边与底色混 50%。 * * 交互:按下即 `CaptureMouse()` 并进入按下态;**在自身范围内**松开才触发 `onClick` *(与"按住移开再松开 = 放弃"的既有语义一致)。 */ class UiButtonWidget : public UiWidget { public: UiButtonWidget() = default; /** @brief 一次性注入绘制资源与外观参数(尺寸由 `OnMeasure` 按文本实测得出)。 */ void Configure(const UiFonts* fonts, const Theme* theme, float scale, std::wstring label, bool primary, bool toggle, float textPadding, float height); /** @brief 设置图标(`NONE` 表示回到纯文本按钮)。 */ void SetIcon(UiButtonIcon icon); /** @brief 当前图标。 */ UiButtonIcon Icon() const { return m_icon; } /** @brief 修改文本(宽度会在下一次 `InvalidateMeasure` 后重新实测)。 */ void SetLabel(std::wstring label); /** @brief 文本(只读)。 */ const std::wstring& Label() const { return m_label; } /** @brief 设置可切换按钮的选中态。 */ void SetChecked(bool checked); /** @brief 选中态。 */ bool Checked() const { return m_checked; } /** @brief 是否可切换按钮。 */ bool IsToggle() const { return m_toggle; } /** @brief 设置可用性(禁用时不可点、不可命中)。 */ void SetEnabled(bool enabled); /** @brief 是否可用。 */ bool Enabled() const { return m_enabled; } /** @brief 是否处于按下态(按下未松开)。 */ bool Pressed() const { return m_pressed; } /** @brief 放弃当前按下(指针离开窗口等不会再收到抬起的情形)。 */ void CancelPress(); /** * @brief 按钮**内容**(文本或图标)实际占用的矩形(客户区坐标)。 * * 内容按居中绘制,因此它的矩形与按钮矩形不同:调试层用它显示"文字/图标本身的边界"。 * 未摆放或文本为空时返回空矩形。 * * @return 内容矩形(客户区坐标)。 */ gd::RectF ContentRect() const; /** @brief 点击回调(在自身范围内松开时触发)。 */ std::function onClick; /** @brief 工具栏底色(普通按钮的底色与禁用配色都以它为基准)。 */ void SetCanvasColor(std::uint32_t color) { m_canvasColor = color; } protected: gd::SizeF OnMeasure(const UiMeasureContext& ctx) override; void OnPaint(UiPaintContext& ctx) override; UiEventResult OnEvent(UiEvent& event) override; HCURSOR OnQueryCursor(int x, int y) override; std::uint64_t ContentKey() const override; private: const UiFonts* m_fonts = nullptr; /**< 字体。 */ const Theme* m_theme = nullptr; /**< 主题。 */ float m_scale = 1.0f; /**< 缩放系数。 */ std::wstring m_label; /**< 按钮文本。 */ UiButtonIcon m_icon = UiButtonIcon::NONE; /**< 按钮图标(非 `NONE` 时忽略文本)。 */ bool m_primary = false; /**< 主按钮(强调色实底)。 */ bool m_toggle = false; /**< 是否可切换。 */ bool m_checked = false; /**< 可切换按钮的选中态。 */ bool m_enabled = true; /**< 是否可用。 */ bool m_pressed = false; /**< 按下态。 */ float m_textPadding = 14.0f; /**< 左右内边距(逻辑像素)。 */ float m_height = 30.0f; /**< 按钮高度(逻辑像素)。 */ std::uint32_t m_canvasColor = 0; /**< 工具栏底色(配色基准)。 */ }; } // namespace jdi #endif // __UI_BUTTON_WIDGET_HPP__