refactor(ui): 移除UI组件的链式调用方法并重构文档注释

重构所有UI组件头文件,移除链式调用构建器方法
为UI组件添加详细的文档注释,说明各方法和属性的用途
调整部分实现文件的结构,使其更加清晰易读
This commit is contained in:
ChestnutYueyue 2026-02-13 16:52:57 +08:00
parent b78c493590
commit 866fd4b1ff
15 changed files with 964 additions and 846 deletions

View File

@ -32,35 +32,6 @@ public:
static Ptr<Button> create(const std::string &text); static Ptr<Button> create(const std::string &text);
static Ptr<Button> create(const std::string &text, Ptr<FontAtlas> font); static Ptr<Button> create(const std::string &text, Ptr<FontAtlas> font);
// ------------------------------------------------------------------------
// 链式调用构建器方法
// ------------------------------------------------------------------------
Button *withPosition(float x, float y);
Button *withPosition(const Vec2 &pos);
Button *withAnchor(float x, float y);
Button *withAnchor(const Vec2 &anchor);
Button *withText(const std::string &text);
Button *withFont(Ptr<FontAtlas> font);
Button *withTextColor(const Color &color);
Button *withBackgroundColor(const Color &normal, const Color &hover,
const Color &pressed);
Button *withSize(float width, float height);
Button *withPadding(const Vec2 &padding);
Button *withPadding(float x, float y);
Button *withBorder(const Color &color, float width);
Button *withCornerRadius(float radius);
Button *withRoundedCornersEnabled(bool enabled);
Button *withHoverCursor(CursorShape cursor);
// ------------------------------------------------------------------------
// 链式调用 - 坐标空间设置
// ------------------------------------------------------------------------
Button *withCoordinateSpace(CoordinateSpace space);
Button *withScreenPosition(float x, float y);
Button *withScreenPosition(const Vec2 &pos);
Button *withCameraOffset(float x, float y);
Button *withCameraOffset(const Vec2 &offset);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 文字内容 // 文字内容
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -77,6 +48,7 @@ public:
// 内边距 // 内边距
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setPadding(const Vec2 &padding); void setPadding(const Vec2 &padding);
void setPadding(float x, float y);
Vec2 getPadding() const { return padding_; } Vec2 getPadding() const { return padding_; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -18,45 +18,45 @@ public:
static Ptr<CheckBox> create(const std::string &label); static Ptr<CheckBox> create(const std::string &label);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 链式调用构建器方法 // 选中状态
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
CheckBox *withPosition(float x, float y);
CheckBox *withPosition(const Vec2 &pos);
CheckBox *withAnchor(float x, float y);
CheckBox *withAnchor(const Vec2 &anchor);
CheckBox *withText(const std::string &text);
CheckBox *withFont(Ptr<FontAtlas> font);
CheckBox *withTextColor(const Color &color);
CheckBox *withSize(float width, float height);
// ------------------------------------------------------------------------
// 链式调用 - 坐标空间设置
// ------------------------------------------------------------------------
CheckBox *withCoordinateSpace(CoordinateSpace space);
CheckBox *withScreenPosition(float x, float y);
CheckBox *withScreenPosition(const Vec2 &pos);
CheckBox *withCameraOffset(float x, float y);
CheckBox *withCameraOffset(const Vec2 &offset);
void setChecked(bool checked); void setChecked(bool checked);
bool isChecked() const { return checked_; } bool isChecked() const { return checked_; }
void toggle(); void toggle();
// ------------------------------------------------------------------------
// 标签设置
// ------------------------------------------------------------------------
void setLabel(const std::string &label); void setLabel(const std::string &label);
const std::string &getLabel() const { return label_; } const std::string &getLabel() const { return label_; }
// ------------------------------------------------------------------------
// 字体设置
// ------------------------------------------------------------------------
void setFont(Ptr<FontAtlas> font); void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; } Ptr<FontAtlas> getFont() const { return font_; }
// ------------------------------------------------------------------------
// 文字颜色
// ------------------------------------------------------------------------
void setTextColor(const Color &color); void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; } Color getTextColor() const { return textColor_; }
// ------------------------------------------------------------------------
// 复选框尺寸
// ------------------------------------------------------------------------
void setBoxSize(float size); void setBoxSize(float size);
float getBoxSize() const { return boxSize_; } float getBoxSize() const { return boxSize_; }
// ------------------------------------------------------------------------
// 间距
// ------------------------------------------------------------------------
void setSpacing(float spacing); void setSpacing(float spacing);
float getSpacing() const { return spacing_; } float getSpacing() const { return spacing_; }
// ------------------------------------------------------------------------
// 颜色设置
// ------------------------------------------------------------------------
void setCheckedColor(const Color &color); void setCheckedColor(const Color &color);
Color getCheckedColor() const { return checkedColor_; } Color getCheckedColor() const { return checkedColor_; }
@ -66,6 +66,9 @@ public:
void setCheckMarkColor(const Color &color); void setCheckMarkColor(const Color &color);
Color getCheckMarkColor() const { return checkMarkColor_; } Color getCheckMarkColor() const { return checkMarkColor_; }
// ------------------------------------------------------------------------
// 回调设置
// ------------------------------------------------------------------------
void setOnStateChange(Function<void(bool)> callback); void setOnStateChange(Function<void(bool)> callback);
Rect getBoundingBox() const override; Rect getBoundingBox() const override;

View File

@ -23,27 +23,6 @@ public:
static Ptr<Label> create(const std::string &text); static Ptr<Label> create(const std::string &text);
static Ptr<Label> create(const std::string &text, Ptr<FontAtlas> font); static Ptr<Label> create(const std::string &text, Ptr<FontAtlas> font);
// ------------------------------------------------------------------------
// 链式调用构建器方法
// ------------------------------------------------------------------------
Label *withPosition(float x, float y);
Label *withPosition(const Vec2 &pos);
Label *withAnchor(float x, float y);
Label *withAnchor(const Vec2 &anchor);
Label *withText(const std::string &text);
Label *withFont(Ptr<FontAtlas> font);
Label *withTextColor(const Color &color);
Label *withFontSize(int size);
// ------------------------------------------------------------------------
// 坐标空间设置(链式调用)
// ------------------------------------------------------------------------
Label *withCoordinateSpace(CoordinateSpace space);
Label *withScreenPosition(float x, float y);
Label *withScreenPosition(const Vec2 &pos);
Label *withCameraOffset(float x, float y);
Label *withCameraOffset(const Vec2 &offset);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 文本内容 // 文本内容
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -143,17 +122,14 @@ private:
HorizontalAlign hAlign_ = HorizontalAlign::Left; HorizontalAlign hAlign_ = HorizontalAlign::Left;
VerticalAlign vAlign_ = VerticalAlign::Top; VerticalAlign vAlign_ = VerticalAlign::Top;
// 阴影
bool shadowEnabled_ = false; bool shadowEnabled_ = false;
Color shadowColor_ = Color(0.0f, 0.0f, 0.0f, 0.5f); Color shadowColor_ = Color(0.0f, 0.0f, 0.0f, 0.5f);
Vec2 shadowOffset_ = Vec2(2.0f, 2.0f); Vec2 shadowOffset_ = Vec2(2.0f, 2.0f);
// 描边
bool outlineEnabled_ = false; bool outlineEnabled_ = false;
Color outlineColor_ = Colors::Black; Color outlineColor_ = Colors::Black;
float outlineWidth_ = 1.0f; float outlineWidth_ = 1.0f;
// 多行
bool multiLine_ = false; bool multiLine_ = false;
float lineSpacing_ = 1.0f; float lineSpacing_ = 1.0f;
float maxWidth_ = 0.0f; float maxWidth_ = 0.0f;

View File

@ -21,21 +21,6 @@ public:
static Ptr<ProgressBar> create(); static Ptr<ProgressBar> create();
static Ptr<ProgressBar> create(float min, float max, float value); static Ptr<ProgressBar> create(float min, float max, float value);
// ------------------------------------------------------------------------
// 链式调用构建器方法 - 坐标空间支持
// ------------------------------------------------------------------------
ProgressBar *withPosition(float x, float y);
ProgressBar *withPosition(const Vec2 &pos);
ProgressBar *withAnchor(float x, float y);
ProgressBar *withAnchor(const Vec2 &anchor);
ProgressBar *withSize(float width, float height);
ProgressBar *withProgress(float progress);
ProgressBar *withCoordinateSpace(CoordinateSpace space);
ProgressBar *withScreenPosition(float x, float y);
ProgressBar *withScreenPosition(const Vec2 &pos);
ProgressBar *withCameraOffset(float x, float y);
ProgressBar *withCameraOffset(const Vec2 &offset);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 数值范围 // 数值范围
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -18,40 +18,44 @@ public:
static Ptr<RadioButton> create(const std::string &label); static Ptr<RadioButton> create(const std::string &label);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 链式调用构建器方法 // 选择状态
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
RadioButton *withPosition(float x, float y);
RadioButton *withPosition(const Vec2 &pos);
RadioButton *withAnchor(float x, float y);
RadioButton *withAnchor(const Vec2 &anchor);
RadioButton *withText(const std::string &text);
RadioButton *withFont(Ptr<FontAtlas> font);
RadioButton *withTextColor(const Color &color);
RadioButton *withSize(float width, float height);
RadioButton *withCoordinateSpace(CoordinateSpace space);
RadioButton *withScreenPosition(float x, float y);
RadioButton *withScreenPosition(const Vec2 &pos);
RadioButton *withCameraOffset(float x, float y);
RadioButton *withCameraOffset(const Vec2 &offset);
void setSelected(bool selected); void setSelected(bool selected);
bool isSelected() const { return selected_; } bool isSelected() const { return selected_; }
// ------------------------------------------------------------------------
// 标签设置
// ------------------------------------------------------------------------
void setLabel(const std::string &label); void setLabel(const std::string &label);
const std::string &getLabel() const { return label_; } const std::string &getLabel() const { return label_; }
// ------------------------------------------------------------------------
// 字体设置
// ------------------------------------------------------------------------
void setFont(Ptr<FontAtlas> font); void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; } Ptr<FontAtlas> getFont() const { return font_; }
// ------------------------------------------------------------------------
// 文字颜色
// ------------------------------------------------------------------------
void setTextColor(const Color &color); void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; } Color getTextColor() const { return textColor_; }
// ------------------------------------------------------------------------
// 圆形尺寸
// ------------------------------------------------------------------------
void setCircleSize(float size); void setCircleSize(float size);
float getCircleSize() const { return circleSize_; } float getCircleSize() const { return circleSize_; }
// ------------------------------------------------------------------------
// 间距
// ------------------------------------------------------------------------
void setSpacing(float spacing); void setSpacing(float spacing);
float getSpacing() const { return spacing_; } float getSpacing() const { return spacing_; }
// ------------------------------------------------------------------------
// 颜色设置
// ------------------------------------------------------------------------
void setSelectedColor(const Color &color); void setSelectedColor(const Color &color);
Color getSelectedColor() const { return selectedColor_; } Color getSelectedColor() const { return selectedColor_; }
@ -61,9 +65,15 @@ public:
void setDotColor(const Color &color); void setDotColor(const Color &color);
Color getDotColor() const { return dotColor_; } Color getDotColor() const { return dotColor_; }
// ------------------------------------------------------------------------
// 分组
// ------------------------------------------------------------------------
void setGroupId(int groupId); void setGroupId(int groupId);
int getGroupId() const { return groupId_; } int getGroupId() const { return groupId_; }
// ------------------------------------------------------------------------
// 回调设置
// ------------------------------------------------------------------------
void setOnStateChange(Function<void(bool)> callback); void setOnStateChange(Function<void(bool)> callback);
Rect getBoundingBox() const override; Rect getBoundingBox() const override;
@ -86,7 +96,7 @@ private:
Color unselectedColor_ = Color(0.3f, 0.3f, 0.3f, 1.0f); Color unselectedColor_ = Color(0.3f, 0.3f, 0.3f, 1.0f);
Color dotColor_ = Colors::White; Color dotColor_ = Colors::White;
int groupId_ = 0; // 用于分组,同组内只能选一个 int groupId_ = 0;
bool pressed_ = false; bool pressed_ = false;
Function<void(bool)> onStateChange_; Function<void(bool)> onStateChange_;

View File

@ -18,41 +18,45 @@ public:
static Ptr<Slider> create(float min, float max, float value); static Ptr<Slider> create(float min, float max, float value);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 链式调用构建器方法 // 数值范围
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
Slider *withPosition(float x, float y);
Slider *withPosition(const Vec2 &pos);
Slider *withAnchor(float x, float y);
Slider *withAnchor(const Vec2 &anchor);
Slider *withSize(float width, float height);
Slider *withMinValue(float min);
Slider *withMaxValue(float max);
Slider *withValue(float value);
Slider *withCoordinateSpace(CoordinateSpace space);
Slider *withScreenPosition(float x, float y);
Slider *withScreenPosition(const Vec2 &pos);
Slider *withCameraOffset(float x, float y);
Slider *withCameraOffset(const Vec2 &offset);
void setRange(float min, float max); void setRange(float min, float max);
float getMin() const { return min_; } float getMin() const { return min_; }
float getMax() const { return max_; } float getMax() const { return max_; }
// ------------------------------------------------------------------------
// 当前值
// ------------------------------------------------------------------------
void setValue(float value); void setValue(float value);
float getValue() const { return value_; } float getValue() const { return value_; }
// ------------------------------------------------------------------------
// 步进值
// ------------------------------------------------------------------------
void setStep(float step); void setStep(float step);
float getStep() const { return step_; } float getStep() const { return step_; }
// ------------------------------------------------------------------------
// 方向
// ------------------------------------------------------------------------
void setVertical(bool vertical); void setVertical(bool vertical);
bool isVertical() const { return vertical_; } bool isVertical() const { return vertical_; }
// ------------------------------------------------------------------------
// 轨道尺寸
// ------------------------------------------------------------------------
void setTrackSize(float size); void setTrackSize(float size);
float getTrackSize() const { return trackSize_; } float getTrackSize() const { return trackSize_; }
// ------------------------------------------------------------------------
// 滑块尺寸
// ------------------------------------------------------------------------
void setThumbSize(float size); void setThumbSize(float size);
float getThumbSize() const { return thumbSize_; } float getThumbSize() const { return thumbSize_; }
// ------------------------------------------------------------------------
// 颜色设置
// ------------------------------------------------------------------------
void setTrackColor(const Color &color); void setTrackColor(const Color &color);
Color getTrackColor() const { return trackColor_; } Color getTrackColor() const { return trackColor_; }
@ -68,12 +72,18 @@ public:
void setThumbPressedColor(const Color &color); void setThumbPressedColor(const Color &color);
Color getThumbPressedColor() const { return thumbPressedColor_; } Color getThumbPressedColor() const { return thumbPressedColor_; }
// ------------------------------------------------------------------------
// 显示设置
// ------------------------------------------------------------------------
void setShowThumb(bool show); void setShowThumb(bool show);
bool isShowThumb() const { return showThumb_; } bool isShowThumb() const { return showThumb_; }
void setShowFill(bool show); void setShowFill(bool show);
bool isShowFill() const { return showFill_; } bool isShowFill() const { return showFill_; }
// ------------------------------------------------------------------------
// 文本显示
// ------------------------------------------------------------------------
void setTextEnabled(bool enabled); void setTextEnabled(bool enabled);
bool isTextEnabled() const { return textEnabled_; } bool isTextEnabled() const { return textEnabled_; }
@ -86,6 +96,9 @@ public:
void setTextFormat(const std::string &format); void setTextFormat(const std::string &format);
const std::string &getTextFormat() const { return textFormat_; } const std::string &getTextFormat() const { return textFormat_; }
// ------------------------------------------------------------------------
// 回调设置
// ------------------------------------------------------------------------
void setOnValueChange(Function<void(float)> callback); void setOnValueChange(Function<void(float)> callback);
void setOnDragStart(Function<void()> callback); void setOnDragStart(Function<void()> callback);
void setOnDragEnd(Function<void()> callback); void setOnDragEnd(Function<void()> callback);
@ -104,7 +117,7 @@ private:
float min_ = 0.0f; float min_ = 0.0f;
float max_ = 100.0f; float max_ = 100.0f;
float value_ = 50.0f; float value_ = 50.0f;
float step_ = 0.0f; // 0表示无步进 float step_ = 0.0f;
bool vertical_ = false; bool vertical_ = false;
float trackSize_ = 6.0f; float trackSize_ = 6.0f;

View File

@ -41,19 +41,6 @@ public:
static Ptr<Text> createFormat(const char *fmt, ...); static Ptr<Text> createFormat(const char *fmt, ...);
static Ptr<Text> createFormat(Ptr<FontAtlas> font, const char *fmt, ...); static Ptr<Text> createFormat(Ptr<FontAtlas> font, const char *fmt, ...);
// ------------------------------------------------------------------------
// 链式调用构建器方法
// ------------------------------------------------------------------------
Text *withPosition(float x, float y);
Text *withPosition(const Vec2 &pos);
Text *withAnchor(float x, float y);
Text *withAnchor(const Vec2 &anchor);
Text *withTextColor(const Color &color);
Text *withFont(Ptr<FontAtlas> font);
Text *withFontSize(int size);
Text *withAlignment(Alignment align);
Text *withVerticalAlignment(VerticalAlignment align);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 文字内容 // 文字内容
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -78,20 +65,6 @@ public:
updateSpatialIndex(); updateSpatialIndex();
} }
// 链式调用的格式化方法
// 注意由于C++可变参数的限制,链式调用需要单独设置格式和值
Text *withFormattedText(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char buffer[256];
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
text_ = buffer;
sizeDirty_ = true;
updateSpatialIndex();
return this;
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 字体 // 字体
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -127,15 +100,6 @@ public:
Rect getBoundingBox() const override; Rect getBoundingBox() const override;
// ------------------------------------------------------------------------
// 链式调用 - 坐标空间设置
// ------------------------------------------------------------------------
Text *withCoordinateSpace(CoordinateSpace space);
Text *withScreenPosition(float x, float y);
Text *withScreenPosition(const Vec2 &pos);
Text *withCameraOffset(float x, float y);
Text *withCameraOffset(const Vec2 &offset);
protected: protected:
void onDrawWidget(RenderBackend &renderer) override; void onDrawWidget(RenderBackend &renderer) override;

View File

@ -11,8 +11,10 @@ namespace extra2d {
// Button 实现 // Button 实现
// ============================================================================ // ============================================================================
/**
* @brief
*/
Button::Button() { Button::Button() {
// 按钮默认锚点为左上角这样setPosition(0, 0)会在左上角显示
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
setSpatialIndexed(false); setSpatialIndexed(false);
@ -46,133 +48,49 @@ Button::Button() {
}); });
} }
/**
* @brief
* @param text
*/
Button::Button(const std::string &text) : Button() { text_ = text; } Button::Button(const std::string &text) : Button() { text_ = text; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 静态创建方法 // 静态创建方法
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/**
* @brief
* @return
*/
Ptr<Button> Button::create() { return makePtr<Button>(); } Ptr<Button> Button::create() { return makePtr<Button>(); }
/**
* @brief
* @param text
* @return
*/
Ptr<Button> Button::create(const std::string &text) { Ptr<Button> Button::create(const std::string &text) {
return makePtr<Button>(text); return makePtr<Button>(text);
} }
/**
* @brief
* @param text
* @param font
* @return
*/
Ptr<Button> Button::create(const std::string &text, Ptr<FontAtlas> font) { Ptr<Button> Button::create(const std::string &text, Ptr<FontAtlas> font) {
auto btn = makePtr<Button>(text); auto btn = makePtr<Button>(text);
btn->setFont(font); btn->setFont(font);
return btn; return btn;
} }
// ------------------------------------------------------------------------
// 链式调用构建器方法
// ------------------------------------------------------------------------
Button *Button::withPosition(float x, float y) {
setPosition(x, y);
return this;
}
Button *Button::withPosition(const Vec2 &pos) {
setPosition(pos);
return this;
}
Button *Button::withAnchor(float x, float y) {
setAnchor(x, y);
return this;
}
Button *Button::withAnchor(const Vec2 &anchor) {
setAnchor(anchor);
return this;
}
Button *Button::withText(const std::string &text) {
setText(text);
return this;
}
Button *Button::withFont(Ptr<FontAtlas> font) {
setFont(font);
return this;
}
Button *Button::withTextColor(const Color &color) {
setTextColor(color);
return this;
}
Button *Button::withBackgroundColor(const Color &normal, const Color &hover,
const Color &pressed) {
setBackgroundColor(normal, hover, pressed);
return this;
}
Button *Button::withSize(float width, float height) {
setSize(width, height);
return this;
}
Button *Button::withPadding(const Vec2 &padding) {
setPadding(padding);
return this;
}
Button *Button::withPadding(float x, float y) {
setPadding(Vec2(x, y));
return this;
}
Button *Button::withBorder(const Color &color, float width) {
setBorder(color, width);
return this;
}
Button *Button::withCornerRadius(float radius) {
setCornerRadius(radius);
return this;
}
Button *Button::withRoundedCornersEnabled(bool enabled) {
setRoundedCornersEnabled(enabled);
return this;
}
Button *Button::withHoverCursor(CursorShape cursor) {
setHoverCursor(cursor);
return this;
}
// ------------------------------------------------------------------------
// 链式调用 - 坐标空间设置
// ------------------------------------------------------------------------
Button *Button::withCoordinateSpace(CoordinateSpace space) {
setCoordinateSpace(space);
return this;
}
Button *Button::withScreenPosition(float x, float y) {
setScreenPosition(x, y);
return this;
}
Button *Button::withScreenPosition(const Vec2 &pos) {
setScreenPosition(pos);
return this;
}
Button *Button::withCameraOffset(float x, float y) {
setCameraOffset(x, y);
return this;
}
Button *Button::withCameraOffset(const Vec2 &offset) {
setCameraOffset(offset);
return this;
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 普通设置方法 // 普通设置方法
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/**
* @brief
* @param text
*/
void Button::setText(const std::string &text) { void Button::setText(const std::string &text) {
text_ = text; text_ = text;
if (font_ && getSize().empty()) { if (font_ && getSize().empty()) {
@ -181,6 +99,10 @@ void Button::setText(const std::string &text) {
} }
} }
/**
* @brief
* @param font
*/
void Button::setFont(Ptr<FontAtlas> font) { void Button::setFont(Ptr<FontAtlas> font) {
font_ = font; font_ = font;
if (font_ && getSize().empty() && !text_.empty()) { if (font_ && getSize().empty() && !text_.empty()) {
@ -189,6 +111,10 @@ void Button::setFont(Ptr<FontAtlas> font) {
} }
} }
/**
* @brief Vec2版本
* @param padding
*/
void Button::setPadding(const Vec2 &padding) { void Button::setPadding(const Vec2 &padding) {
padding_ = padding; padding_ = padding;
if (font_ && getSize().empty() && !text_.empty()) { if (font_ && getSize().empty() && !text_.empty()) {
@ -197,8 +123,27 @@ void Button::setPadding(const Vec2 &padding) {
} }
} }
/**
* @brief
* @param x X方向内边距
* @param y Y方向内边距
*/
void Button::setPadding(float x, float y) {
setPadding(Vec2(x, y));
}
/**
* @brief
* @param color
*/
void Button::setTextColor(const Color &color) { textColor_ = color; } void Button::setTextColor(const Color &color) { textColor_ = color; }
/**
* @brief
* @param normal
* @param hover
* @param pressed
*/
void Button::setBackgroundColor(const Color &normal, const Color &hover, void Button::setBackgroundColor(const Color &normal, const Color &hover,
const Color &pressed) { const Color &pressed) {
bgNormal_ = normal; bgNormal_ = normal;
@ -206,29 +151,58 @@ void Button::setBackgroundColor(const Color &normal, const Color &hover,
bgPressed_ = pressed; bgPressed_ = pressed;
} }
/**
* @brief
* @param color
* @param width
*/
void Button::setBorder(const Color &color, float width) { void Button::setBorder(const Color &color, float width) {
borderColor_ = color; borderColor_ = color;
borderWidth_ = width; borderWidth_ = width;
} }
/**
* @brief
* @param radius
*/
void Button::setCornerRadius(float radius) { void Button::setCornerRadius(float radius) {
cornerRadius_ = std::max(0.0f, radius); cornerRadius_ = std::max(0.0f, radius);
} }
/**
* @brief
* @param enabled
*/
void Button::setRoundedCornersEnabled(bool enabled) { void Button::setRoundedCornersEnabled(bool enabled) {
roundedCornersEnabled_ = enabled; roundedCornersEnabled_ = enabled;
} }
/**
* @brief 使Alpha遮罩进行点击检测
* @param enabled
*/
void Button::setUseAlphaMaskForHitTest(bool enabled) { void Button::setUseAlphaMaskForHitTest(bool enabled) {
useAlphaMaskForHitTest_ = enabled; useAlphaMaskForHitTest_ = enabled;
} }
/**
* @brief
* @param callback
*/
void Button::setOnClick(Function<void()> callback) { void Button::setOnClick(Function<void()> callback) {
onClick_ = std::move(callback); onClick_ = std::move(callback);
} }
/**
* @brief
* @param enabled
*/
void Button::setToggleMode(bool enabled) { toggleMode_ = enabled; } void Button::setToggleMode(bool enabled) { toggleMode_ = enabled; }
/**
* @brief
* @param on
*/
void Button::setOn(bool on) { void Button::setOn(bool on) {
if (isOn_ != on) { if (isOn_ != on) {
isOn_ = on; isOn_ = on;
@ -238,12 +212,24 @@ void Button::setOn(bool on) {
} }
} }
/**
* @brief
*/
void Button::toggle() { setOn(!isOn_); } void Button::toggle() { setOn(!isOn_); }
/**
* @brief
* @param callback
*/
void Button::setOnStateChange(Function<void(bool)> callback) { void Button::setOnStateChange(Function<void(bool)> callback) {
onStateChange_ = std::move(callback); onStateChange_ = std::move(callback);
} }
/**
* @brief
* @param textOff
* @param textOn
*/
void Button::setStateText(const std::string &textOff, void Button::setStateText(const std::string &textOff,
const std::string &textOn) { const std::string &textOn) {
textOff_ = textOff; textOff_ = textOff;
@ -251,14 +237,29 @@ void Button::setStateText(const std::string &textOff,
useStateText_ = true; useStateText_ = true;
} }
/**
* @brief
* @param colorOff
* @param colorOn
*/
void Button::setStateTextColor(const Color &colorOff, const Color &colorOn) { void Button::setStateTextColor(const Color &colorOff, const Color &colorOn) {
textColorOff_ = colorOff; textColorOff_ = colorOff;
textColorOn_ = colorOn; textColorOn_ = colorOn;
useStateTextColor_ = true; useStateTextColor_ = true;
} }
/**
* @brief
* @param cursor
*/
void Button::setHoverCursor(CursorShape cursor) { hoverCursor_ = cursor; } void Button::setHoverCursor(CursorShape cursor) { hoverCursor_ = cursor; }
/**
* @brief
* @param normal
* @param hover
* @param pressed
*/
void Button::setBackgroundImage(Ptr<Texture> normal, Ptr<Texture> hover, void Button::setBackgroundImage(Ptr<Texture> normal, Ptr<Texture> hover,
Ptr<Texture> pressed) { Ptr<Texture> pressed) {
imgNormal_ = normal; imgNormal_ = normal;
@ -273,6 +274,11 @@ void Button::setBackgroundImage(Ptr<Texture> normal, Ptr<Texture> hover,
} }
} }
/**
* @brief
* @param texture
* @param rect
*/
void Button::setBackgroundImage(Ptr<Texture> texture, const Rect &rect) { void Button::setBackgroundImage(Ptr<Texture> texture, const Rect &rect) {
imgNormal_ = texture; imgNormal_ = texture;
imgHover_ = texture; imgHover_ = texture;
@ -289,6 +295,15 @@ void Button::setBackgroundImage(Ptr<Texture> texture, const Rect &rect) {
} }
} }
/**
* @brief
* @param offNormal
* @param onNormal
* @param offHover
* @param onHover
* @param offPressed
* @param onPressed
*/
void Button::setStateBackgroundImage( void Button::setStateBackgroundImage(
Ptr<Texture> offNormal, Ptr<Texture> onNormal, Ptr<Texture> offHover, Ptr<Texture> offNormal, Ptr<Texture> onNormal, Ptr<Texture> offHover,
Ptr<Texture> onHover, Ptr<Texture> offPressed, Ptr<Texture> onPressed) { Ptr<Texture> onHover, Ptr<Texture> offPressed, Ptr<Texture> onPressed) {
@ -309,6 +324,10 @@ void Button::setStateBackgroundImage(
} }
} }
/**
* @brief
* @param mode
*/
void Button::setBackgroundImageScaleMode(ImageScaleMode mode) { void Button::setBackgroundImageScaleMode(ImageScaleMode mode) {
scaleMode_ = mode; scaleMode_ = mode;
if (useImageBackground_ && scaleMode_ == ImageScaleMode::Original && if (useImageBackground_ && scaleMode_ == ImageScaleMode::Original &&
@ -318,12 +337,25 @@ void Button::setBackgroundImageScaleMode(ImageScaleMode mode) {
} }
} }
/**
* @brief Vec2版本
* @param size
*/
void Button::setCustomSize(const Vec2 &size) { setSize(size.x, size.y); } void Button::setCustomSize(const Vec2 &size) { setSize(size.x, size.y); }
/**
* @brief
* @param width
* @param height
*/
void Button::setCustomSize(float width, float height) { void Button::setCustomSize(float width, float height) {
setSize(width, height); setSize(width, height);
} }
/**
* @brief
* @return
*/
Rect Button::getBoundingBox() const { Rect Button::getBoundingBox() const {
auto pos = getRenderPosition(); auto pos = getRenderPosition();
auto anchor = getAnchor(); auto anchor = getAnchor();
@ -342,6 +374,12 @@ Rect Button::getBoundingBox() const {
return Rect(x0, y0, w, h); return Rect(x0, y0, w, h);
} }
/**
* @brief
* @param buttonSize
* @param imageSize
* @return
*/
Vec2 Button::calculateImageSize(const Vec2 &buttonSize, const Vec2 &imageSize) { Vec2 Button::calculateImageSize(const Vec2 &buttonSize, const Vec2 &imageSize) {
switch (scaleMode_) { switch (scaleMode_) {
case ImageScaleMode::Original: case ImageScaleMode::Original:
@ -367,11 +405,15 @@ Vec2 Button::calculateImageSize(const Vec2 &buttonSize, const Vec2 &imageSize) {
return imageSize; return imageSize;
} }
/**
* @brief
* @param renderer
* @param rect
*/
void Button::drawBackgroundImage(RenderBackend &renderer, const Rect &rect) { void Button::drawBackgroundImage(RenderBackend &renderer, const Rect &rect) {
Texture *texture = nullptr; Texture *texture = nullptr;
Rect srcRect; Rect srcRect;
// 如果使用状态图片,根据 isOn_ 状态选择对应的图片
if (useStateImages_) { if (useStateImages_) {
if (isOn_) { if (isOn_) {
if (pressed_ && imgOnPressed_) { if (pressed_ && imgOnPressed_) {
@ -395,7 +437,6 @@ void Button::drawBackgroundImage(RenderBackend &renderer, const Rect &rect) {
static_cast<float>(texture->getHeight())); static_cast<float>(texture->getHeight()));
} }
} else { } else {
// 使用普通图片背景
if (pressed_ && imgPressed_) { if (pressed_ && imgPressed_) {
texture = imgPressed_.get(); texture = imgPressed_.get();
srcRect = useTextureRect_ srcRect = useTextureRect_
@ -433,6 +474,13 @@ void Button::drawBackgroundImage(RenderBackend &renderer, const Rect &rect) {
Vec2::Zero()); Vec2::Zero());
} }
/**
* @brief
* @param renderer
* @param rect
* @param color
* @param radius
*/
void Button::drawRoundedRect(RenderBackend &renderer, const Rect &rect, void Button::drawRoundedRect(RenderBackend &renderer, const Rect &rect,
const Color &color, float radius) { const Color &color, float radius) {
float maxRadius = std::min(rect.size.width, rect.size.height) * 0.5f; float maxRadius = std::min(rect.size.width, rect.size.height) * 0.5f;
@ -489,6 +537,13 @@ void Button::drawRoundedRect(RenderBackend &renderer, const Rect &rect,
} }
} }
/**
* @brief
* @param renderer
* @param rect
* @param color
* @param radius
*/
void Button::fillRoundedRect(RenderBackend &renderer, const Rect &rect, void Button::fillRoundedRect(RenderBackend &renderer, const Rect &rect,
const Color &color, float radius) { const Color &color, float radius) {
float maxRadius = std::min(rect.size.width, rect.size.height) * 0.5f; float maxRadius = std::min(rect.size.width, rect.size.height) * 0.5f;
@ -556,6 +611,10 @@ void Button::fillRoundedRect(RenderBackend &renderer, const Rect &rect,
renderer.fillPolygon(vertices, color); renderer.fillPolygon(vertices, color);
} }
/**
* @brief
* @param renderer
*/
void Button::onDrawWidget(RenderBackend &renderer) { void Button::onDrawWidget(RenderBackend &renderer) {
Rect rect = getBoundingBox(); Rect rect = getBoundingBox();
if (rect.empty()) { if (rect.empty()) {
@ -563,7 +622,6 @@ void Button::onDrawWidget(RenderBackend &renderer) {
} }
if (useImageBackground_) { if (useImageBackground_) {
// 使用图片背景时不绘制纯色背景和边框
drawBackgroundImage(renderer, rect); drawBackgroundImage(renderer, rect);
} else { } else {
renderer.endSpriteBatch(); renderer.endSpriteBatch();
@ -583,7 +641,6 @@ void Button::onDrawWidget(RenderBackend &renderer) {
renderer.beginSpriteBatch(); renderer.beginSpriteBatch();
// 纯色背景模式下才绘制边框
renderer.endSpriteBatch(); renderer.endSpriteBatch();
if (borderWidth_ > 0.0f) { if (borderWidth_ > 0.0f) {
@ -598,7 +655,6 @@ void Button::onDrawWidget(RenderBackend &renderer) {
} }
if (font_) { if (font_) {
// 确定要显示的文字
std::string textToDraw; std::string textToDraw;
if (useStateText_) { if (useStateText_) {
textToDraw = isOn_ ? textOn_ : textOff_; textToDraw = isOn_ ? textOn_ : textOff_;
@ -606,7 +662,6 @@ void Button::onDrawWidget(RenderBackend &renderer) {
textToDraw = text_; textToDraw = text_;
} }
// 确定文字颜色
Color colorToUse; Color colorToUse;
if (useStateTextColor_) { if (useStateTextColor_) {
colorToUse = isOn_ ? textColorOn_ : textColorOff_; colorToUse = isOn_ ? textColorOn_ : textColorOff_;

View File

@ -4,92 +4,37 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*/
CheckBox::CheckBox() { CheckBox::CheckBox() {
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
setSize(boxSize_, boxSize_); setSize(boxSize_, boxSize_);
} }
/**
* @brief
* @return
*/
Ptr<CheckBox> CheckBox::create() { Ptr<CheckBox> CheckBox::create() {
return makePtr<CheckBox>(); return makePtr<CheckBox>();
} }
/**
* @brief
* @param label
* @return
*/
Ptr<CheckBox> CheckBox::create(const std::string &label) { Ptr<CheckBox> CheckBox::create(const std::string &label) {
auto cb = makePtr<CheckBox>(); auto cb = makePtr<CheckBox>();
cb->setLabel(label); cb->setLabel(label);
return cb; return cb;
} }
// ------------------------------------------------------------------------ /**
// 链式调用构建器方法 * @brief
// ------------------------------------------------------------------------ * @param checked
CheckBox *CheckBox::withPosition(float x, float y) { */
setPosition(x, y);
return this;
}
CheckBox *CheckBox::withPosition(const Vec2 &pos) {
setPosition(pos);
return this;
}
CheckBox *CheckBox::withAnchor(float x, float y) {
setAnchor(x, y);
return this;
}
CheckBox *CheckBox::withAnchor(const Vec2 &anchor) {
setAnchor(anchor);
return this;
}
CheckBox *CheckBox::withText(const std::string &text) {
setLabel(text);
return this;
}
CheckBox *CheckBox::withFont(Ptr<FontAtlas> font) {
setFont(font);
return this;
}
CheckBox *CheckBox::withTextColor(const Color &color) {
setTextColor(color);
return this;
}
CheckBox *CheckBox::withSize(float width, float height) {
setSize(width, height);
return this;
}
// ------------------------------------------------------------------------
// 链式调用 - 坐标空间设置
// ------------------------------------------------------------------------
CheckBox *CheckBox::withCoordinateSpace(CoordinateSpace space) {
setCoordinateSpace(space);
return this;
}
CheckBox *CheckBox::withScreenPosition(float x, float y) {
setScreenPosition(x, y);
return this;
}
CheckBox *CheckBox::withScreenPosition(const Vec2 &pos) {
setScreenPosition(pos);
return this;
}
CheckBox *CheckBox::withCameraOffset(float x, float y) {
setCameraOffset(x, y);
return this;
}
CheckBox *CheckBox::withCameraOffset(const Vec2 &offset) {
setCameraOffset(offset);
return this;
}
void CheckBox::setChecked(bool checked) { void CheckBox::setChecked(bool checked) {
if (checked_ != checked) { if (checked_ != checked) {
checked_ = checked; checked_ = checked;
@ -99,46 +44,89 @@ void CheckBox::setChecked(bool checked) {
} }
} }
/**
* @brief
*/
void CheckBox::toggle() { void CheckBox::toggle() {
setChecked(!checked_); setChecked(!checked_);
} }
/**
* @brief
* @param label
*/
void CheckBox::setLabel(const std::string &label) { void CheckBox::setLabel(const std::string &label) {
label_ = label; label_ = label;
} }
/**
* @brief
* @param font
*/
void CheckBox::setFont(Ptr<FontAtlas> font) { void CheckBox::setFont(Ptr<FontAtlas> font) {
font_ = font; font_ = font;
} }
/**
* @brief
* @param color
*/
void CheckBox::setTextColor(const Color &color) { void CheckBox::setTextColor(const Color &color) {
textColor_ = color; textColor_ = color;
} }
/**
* @brief
* @param size
*/
void CheckBox::setBoxSize(float size) { void CheckBox::setBoxSize(float size) {
boxSize_ = size; boxSize_ = size;
} }
/**
* @brief
* @param spacing
*/
void CheckBox::setSpacing(float spacing) { void CheckBox::setSpacing(float spacing) {
spacing_ = spacing; spacing_ = spacing;
} }
/**
* @brief
* @param color
*/
void CheckBox::setCheckedColor(const Color &color) { void CheckBox::setCheckedColor(const Color &color) {
checkedColor_ = color; checkedColor_ = color;
} }
/**
* @brief
* @param color
*/
void CheckBox::setUncheckedColor(const Color &color) { void CheckBox::setUncheckedColor(const Color &color) {
uncheckedColor_ = color; uncheckedColor_ = color;
} }
/**
* @brief
* @param color
*/
void CheckBox::setCheckMarkColor(const Color &color) { void CheckBox::setCheckMarkColor(const Color &color) {
checkMarkColor_ = color; checkMarkColor_ = color;
} }
/**
* @brief
* @param callback
*/
void CheckBox::setOnStateChange(Function<void(bool)> callback) { void CheckBox::setOnStateChange(Function<void(bool)> callback) {
onStateChange_ = callback; onStateChange_ = callback;
} }
/**
* @brief
* @return
*/
Rect CheckBox::getBoundingBox() const { Rect CheckBox::getBoundingBox() const {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
float width = boxSize_; float width = boxSize_;
@ -151,16 +139,18 @@ Rect CheckBox::getBoundingBox() const {
return Rect(pos.x, pos.y, width, boxSize_); return Rect(pos.x, pos.y, width, boxSize_);
} }
/**
* @brief
* @param renderer
*/
void CheckBox::onDrawWidget(RenderBackend &renderer) { void CheckBox::onDrawWidget(RenderBackend &renderer) {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
// 绘制复选框
Rect boxRect(pos.x, pos.y + (getSize().height - boxSize_) * 0.5f, boxSize_, boxSize_); Rect boxRect(pos.x, pos.y + (getSize().height - boxSize_) * 0.5f, boxSize_, boxSize_);
Color boxColor = checked_ ? checkedColor_ : uncheckedColor_; Color boxColor = checked_ ? checkedColor_ : uncheckedColor_;
renderer.fillRect(boxRect, boxColor); renderer.fillRect(boxRect, boxColor);
renderer.drawRect(boxRect, Colors::White, 1.0f); renderer.drawRect(boxRect, Colors::White, 1.0f);
// 绘制勾选标记
if (checked_) { if (checked_) {
float padding = boxSize_ * 0.2f; float padding = boxSize_ * 0.2f;
float x1 = boxRect.origin.x + padding; float x1 = boxRect.origin.x + padding;
@ -170,18 +160,21 @@ void CheckBox::onDrawWidget(RenderBackend &renderer) {
float x3 = boxRect.origin.x + boxSize_ - padding; float x3 = boxRect.origin.x + boxSize_ - padding;
float y3 = boxRect.origin.y + padding; float y3 = boxRect.origin.y + padding;
// 简化的勾选标记绘制
renderer.drawLine(Vec2(x1, y1), Vec2(x2, y2), checkMarkColor_, 2.0f); renderer.drawLine(Vec2(x1, y1), Vec2(x2, y2), checkMarkColor_, 2.0f);
renderer.drawLine(Vec2(x2, y2), Vec2(x3, y3), checkMarkColor_, 2.0f); renderer.drawLine(Vec2(x2, y2), Vec2(x3, y3), checkMarkColor_, 2.0f);
} }
// 绘制标签
if (!label_.empty() && font_) { if (!label_.empty() && font_) {
Vec2 textPos(pos.x + boxSize_ + spacing_, pos.y); Vec2 textPos(pos.x + boxSize_ + spacing_, pos.y);
renderer.drawText(*font_, label_, textPos, textColor_); renderer.drawText(*font_, label_, textPos, textColor_);
} }
} }
/**
* @brief
* @param event
* @return
*/
bool CheckBox::onMousePress(const MouseEvent &event) { bool CheckBox::onMousePress(const MouseEvent &event) {
if (event.button == MouseButton::Left) { if (event.button == MouseButton::Left) {
pressed_ = true; pressed_ = true;
@ -190,6 +183,11 @@ bool CheckBox::onMousePress(const MouseEvent &event) {
return false; return false;
} }
/**
* @brief
* @param event
* @return
*/
bool CheckBox::onMouseRelease(const MouseEvent &event) { bool CheckBox::onMouseRelease(const MouseEvent &event) {
if (event.button == MouseButton::Left && pressed_) { if (event.button == MouseButton::Left && pressed_) {
pressed_ = false; pressed_ = false;

View File

@ -4,178 +4,196 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*/
Label::Label() { Label::Label() {
// 标签默认锚点为左上角
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
} }
/**
* @brief
* @param text
*/
Label::Label(const std::string &text) : text_(text) { Label::Label(const std::string &text) : text_(text) {
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
sizeDirty_ = true; sizeDirty_ = true;
} }
/**
* @brief
* @return
*/
Ptr<Label> Label::create() { Ptr<Label> Label::create() {
return makePtr<Label>(); return makePtr<Label>();
} }
/**
* @brief
* @param text
* @return
*/
Ptr<Label> Label::create(const std::string &text) { Ptr<Label> Label::create(const std::string &text) {
return makePtr<Label>(text); return makePtr<Label>(text);
} }
/**
* @brief
* @param text
* @param font
* @return
*/
Ptr<Label> Label::create(const std::string &text, Ptr<FontAtlas> font) { Ptr<Label> Label::create(const std::string &text, Ptr<FontAtlas> font) {
auto label = makePtr<Label>(text); auto label = makePtr<Label>(text);
label->setFont(font); label->setFont(font);
return label; return label;
} }
// ------------------------------------------------------------------------ /**
// 链式调用构建器方法 * @brief
// ------------------------------------------------------------------------ * @param text
Label *Label::withPosition(float x, float y) { */
setPosition(x, y);
return this;
}
Label *Label::withPosition(const Vec2 &pos) {
setPosition(pos);
return this;
}
Label *Label::withAnchor(float x, float y) {
setAnchor(x, y);
return this;
}
Label *Label::withAnchor(const Vec2 &anchor) {
setAnchor(anchor);
return this;
}
Label *Label::withText(const std::string &text) {
setText(text);
return this;
}
Label *Label::withFont(Ptr<FontAtlas> font) {
setFont(font);
return this;
}
Label *Label::withTextColor(const Color &color) {
setTextColor(color);
return this;
}
Label *Label::withFontSize(int size) {
setFontSize(size);
return this;
}
// ------------------------------------------------------------------------
// 坐标空间设置(链式调用)
// ------------------------------------------------------------------------
Label *Label::withCoordinateSpace(CoordinateSpace space) {
setCoordinateSpace(space);
return this;
}
Label *Label::withScreenPosition(float x, float y) {
setScreenPosition(x, y);
return this;
}
Label *Label::withScreenPosition(const Vec2 &pos) {
setScreenPosition(pos);
return this;
}
Label *Label::withCameraOffset(float x, float y) {
setCameraOffset(x, y);
return this;
}
Label *Label::withCameraOffset(const Vec2 &offset) {
setCameraOffset(offset);
return this;
}
void Label::setText(const std::string &text) { void Label::setText(const std::string &text) {
text_ = text; text_ = text;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param font
*/
void Label::setFont(Ptr<FontAtlas> font) { void Label::setFont(Ptr<FontAtlas> font) {
font_ = font; font_ = font;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param color
*/
void Label::setTextColor(const Color &color) { void Label::setTextColor(const Color &color) {
textColor_ = color; textColor_ = color;
} }
/**
* @brief
* @param size
*/
void Label::setFontSize(int size) { void Label::setFontSize(int size) {
fontSize_ = size; fontSize_ = size;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param align
*/
void Label::setHorizontalAlign(HorizontalAlign align) { void Label::setHorizontalAlign(HorizontalAlign align) {
hAlign_ = align; hAlign_ = align;
} }
/**
* @brief
* @param align
*/
void Label::setVerticalAlign(VerticalAlign align) { void Label::setVerticalAlign(VerticalAlign align) {
vAlign_ = align; vAlign_ = align;
} }
/**
* @brief
* @param enabled
*/
void Label::setShadowEnabled(bool enabled) { void Label::setShadowEnabled(bool enabled) {
shadowEnabled_ = enabled; shadowEnabled_ = enabled;
} }
/**
* @brief
* @param color
*/
void Label::setShadowColor(const Color &color) { void Label::setShadowColor(const Color &color) {
shadowColor_ = color; shadowColor_ = color;
} }
/**
* @brief
* @param offset
*/
void Label::setShadowOffset(const Vec2 &offset) { void Label::setShadowOffset(const Vec2 &offset) {
shadowOffset_ = offset; shadowOffset_ = offset;
} }
/**
* @brief
* @param enabled
*/
void Label::setOutlineEnabled(bool enabled) { void Label::setOutlineEnabled(bool enabled) {
outlineEnabled_ = enabled; outlineEnabled_ = enabled;
} }
/**
* @brief
* @param color
*/
void Label::setOutlineColor(const Color &color) { void Label::setOutlineColor(const Color &color) {
outlineColor_ = color; outlineColor_ = color;
} }
/**
* @brief
* @param width
*/
void Label::setOutlineWidth(float width) { void Label::setOutlineWidth(float width) {
outlineWidth_ = width; outlineWidth_ = width;
} }
/**
* @brief
* @param multiLine
*/
void Label::setMultiLine(bool multiLine) { void Label::setMultiLine(bool multiLine) {
multiLine_ = multiLine; multiLine_ = multiLine;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param spacing
*/
void Label::setLineSpacing(float spacing) { void Label::setLineSpacing(float spacing) {
lineSpacing_ = spacing; lineSpacing_ = spacing;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param maxWidth
*/
void Label::setMaxWidth(float maxWidth) { void Label::setMaxWidth(float maxWidth) {
maxWidth_ = maxWidth; maxWidth_ = maxWidth;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @return
*/
Vec2 Label::getTextSize() const { Vec2 Label::getTextSize() const {
updateCache(); updateCache();
return cachedSize_; return cachedSize_;
} }
/**
* @brief
* @return
*/
float Label::getLineHeight() const { float Label::getLineHeight() const {
if (font_) { if (font_) {
return font_->getLineHeight() * lineSpacing_; return font_->getLineHeight() * lineSpacing_;
@ -183,6 +201,9 @@ float Label::getLineHeight() const {
return static_cast<float>(fontSize_) * lineSpacing_; return static_cast<float>(fontSize_) * lineSpacing_;
} }
/**
* @brief
*/
void Label::updateCache() const { void Label::updateCache() const {
if (!sizeDirty_ || !font_) { if (!sizeDirty_ || !font_) {
return; return;
@ -208,6 +229,10 @@ void Label::updateCache() const {
sizeDirty_ = false; sizeDirty_ = false;
} }
/**
* @brief
* @return
*/
std::vector<std::string> Label::splitLines() const { std::vector<std::string> Label::splitLines() const {
std::vector<std::string> lines; std::vector<std::string> lines;
if (text_.empty()) { if (text_.empty()) {
@ -219,17 +244,14 @@ std::vector<std::string> Label::splitLines() const {
return lines; return lines;
} }
// 按换行符分割
size_t start = 0; size_t start = 0;
size_t end = text_.find('\n'); size_t end = text_.find('\n');
while (end != std::string::npos) { while (end != std::string::npos) {
std::string line = text_.substr(start, end - start); std::string line = text_.substr(start, end - start);
// 如果单行超过最大宽度,需要自动换行
Vec2 lineSize = font_->measureText(line); Vec2 lineSize = font_->measureText(line);
if (lineSize.x > maxWidth_) { if (lineSize.x > maxWidth_) {
// 简单实现:按字符逐个尝试
std::string currentLine; std::string currentLine;
for (size_t i = 0; i < line.length(); ++i) { for (size_t i = 0; i < line.length(); ++i) {
std::string testLine = currentLine + line[i]; std::string testLine = currentLine + line[i];
@ -252,7 +274,6 @@ std::vector<std::string> Label::splitLines() const {
end = text_.find('\n', start); end = text_.find('\n', start);
} }
// 处理最后一行
if (start < text_.length()) { if (start < text_.length()) {
std::string line = text_.substr(start); std::string line = text_.substr(start);
Vec2 lineSize = font_->measureText(line); Vec2 lineSize = font_->measureText(line);
@ -279,16 +300,18 @@ std::vector<std::string> Label::splitLines() const {
return lines; return lines;
} }
/**
* @brief
* @return
*/
Vec2 Label::calculateDrawPosition() const { Vec2 Label::calculateDrawPosition() const {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
Vec2 size = getTextSize(); Vec2 size = getTextSize();
Size widgetSize = getSize(); Size widgetSize = getSize();
// 如果设置了控件大小,使用控件大小作为对齐参考
float refWidth = widgetSize.empty() ? size.x : widgetSize.width; float refWidth = widgetSize.empty() ? size.x : widgetSize.width;
float refHeight = widgetSize.empty() ? size.y : widgetSize.height; float refHeight = widgetSize.empty() ? size.y : widgetSize.height;
// 水平对齐
switch (hAlign_) { switch (hAlign_) {
case HorizontalAlign::Center: case HorizontalAlign::Center:
pos.x += (refWidth - size.x) * 0.5f; pos.x += (refWidth - size.x) * 0.5f;
@ -301,7 +324,6 @@ Vec2 Label::calculateDrawPosition() const {
break; break;
} }
// 垂直对齐
switch (vAlign_) { switch (vAlign_) {
case VerticalAlign::Middle: case VerticalAlign::Middle:
pos.y += (refHeight - size.y) * 0.5f; pos.y += (refHeight - size.y) * 0.5f;
@ -317,6 +339,12 @@ Vec2 Label::calculateDrawPosition() const {
return pos; return pos;
} }
/**
* @brief
* @param renderer
* @param position
* @param color
*/
void Label::drawText(RenderBackend &renderer, const Vec2 &position, const Color &color) { void Label::drawText(RenderBackend &renderer, const Vec2 &position, const Color &color) {
if (!font_ || text_.empty()) { if (!font_ || text_.empty()) {
return; return;
@ -336,6 +364,10 @@ void Label::drawText(RenderBackend &renderer, const Vec2 &position, const Color
} }
} }
/**
* @brief
* @return
*/
Rect Label::getBoundingBox() const { Rect Label::getBoundingBox() const {
if (!font_ || text_.empty()) { if (!font_ || text_.empty()) {
return Rect(); return Rect();
@ -351,6 +383,10 @@ Rect Label::getBoundingBox() const {
return Rect(pos.x, pos.y, size.x, size.y); return Rect(pos.x, pos.y, size.x, size.y);
} }
/**
* @brief
* @param renderer
*/
void Label::onDrawWidget(RenderBackend &renderer) { void Label::onDrawWidget(RenderBackend &renderer) {
if (!font_ || text_.empty()) { if (!font_ || text_.empty()) {
return; return;
@ -358,13 +394,11 @@ void Label::onDrawWidget(RenderBackend &renderer) {
Vec2 pos = calculateDrawPosition(); Vec2 pos = calculateDrawPosition();
// 绘制阴影
if (shadowEnabled_) { if (shadowEnabled_) {
Vec2 shadowPos = pos + shadowOffset_; Vec2 shadowPos = pos + shadowOffset_;
drawText(renderer, shadowPos, shadowColor_); drawText(renderer, shadowPos, shadowColor_);
} }
// 绘制描边简化实现向8个方向偏移绘制
if (outlineEnabled_) { if (outlineEnabled_) {
float w = outlineWidth_; float w = outlineWidth_;
drawText(renderer, pos + Vec2(-w, -w), outlineColor_); drawText(renderer, pos + Vec2(-w, -w), outlineColor_);
@ -377,7 +411,6 @@ void Label::onDrawWidget(RenderBackend &renderer) {
drawText(renderer, pos + Vec2(w, w), outlineColor_); drawText(renderer, pos + Vec2(w, w), outlineColor_);
} }
// 绘制主文本
drawText(renderer, pos, textColor_); drawText(renderer, pos, textColor_);
} }

View File

@ -5,15 +5,29 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*/
ProgressBar::ProgressBar() { ProgressBar::ProgressBar() {
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
setSize(200.0f, 20.0f); setSize(200.0f, 20.0f);
} }
/**
* @brief
* @return
*/
Ptr<ProgressBar> ProgressBar::create() { Ptr<ProgressBar> ProgressBar::create() {
return makePtr<ProgressBar>(); return makePtr<ProgressBar>();
} }
/**
* @brief
* @param min
* @param max
* @param value
* @return
*/
Ptr<ProgressBar> ProgressBar::create(float min, float max, float value) { Ptr<ProgressBar> ProgressBar::create(float min, float max, float value) {
auto bar = makePtr<ProgressBar>(); auto bar = makePtr<ProgressBar>();
bar->setRange(min, max); bar->setRange(min, max);
@ -21,71 +35,21 @@ Ptr<ProgressBar> ProgressBar::create(float min, float max, float value) {
return bar; return bar;
} }
// ============================================================================ /**
// 链式调用构建器方法实现 * @brief
// ============================================================================ * @param min
* @param max
ProgressBar *ProgressBar::withPosition(float x, float y) { */
setPosition(x, y);
return this;
}
ProgressBar *ProgressBar::withPosition(const Vec2 &pos) {
setPosition(pos);
return this;
}
ProgressBar *ProgressBar::withAnchor(float x, float y) {
setAnchor(x, y);
return this;
}
ProgressBar *ProgressBar::withAnchor(const Vec2 &anchor) {
setAnchor(anchor);
return this;
}
ProgressBar *ProgressBar::withSize(float width, float height) {
setSize(width, height);
return this;
}
ProgressBar *ProgressBar::withProgress(float progress) {
setValue(min_ + progress * (max_ - min_));
return this;
}
ProgressBar *ProgressBar::withCoordinateSpace(CoordinateSpace space) {
setCoordinateSpace(space);
return this;
}
ProgressBar *ProgressBar::withScreenPosition(float x, float y) {
setScreenPosition(x, y);
return this;
}
ProgressBar *ProgressBar::withScreenPosition(const Vec2 &pos) {
setScreenPosition(pos);
return this;
}
ProgressBar *ProgressBar::withCameraOffset(float x, float y) {
setCameraOffset(x, y);
return this;
}
ProgressBar *ProgressBar::withCameraOffset(const Vec2 &offset) {
setCameraOffset(offset);
return this;
}
void ProgressBar::setRange(float min, float max) { void ProgressBar::setRange(float min, float max) {
min_ = min; min_ = min;
max_ = max; max_ = max;
setValue(value_); setValue(value_);
} }
/**
* @brief
* @param value
*/
void ProgressBar::setValue(float value) { void ProgressBar::setValue(float value) {
value_ = std::clamp(value, min_, max_); value_ = std::clamp(value, min_, max_);
@ -98,85 +62,165 @@ void ProgressBar::setValue(float value) {
} }
} }
/**
* @brief
* @return 0.0-1.0
*/
float ProgressBar::getPercent() const { float ProgressBar::getPercent() const {
if (max_ <= min_) return 0.0f; if (max_ <= min_) return 0.0f;
return (displayValue_ - min_) / (max_ - min_); return (displayValue_ - min_) / (max_ - min_);
} }
/**
* @brief
* @param dir
*/
void ProgressBar::setDirection(Direction dir) { void ProgressBar::setDirection(Direction dir) {
direction_ = dir; direction_ = dir;
} }
/**
* @brief
* @param color
*/
void ProgressBar::setBackgroundColor(const Color &color) { void ProgressBar::setBackgroundColor(const Color &color) {
bgColor_ = color; bgColor_ = color;
} }
/**
* @brief
* @param color
*/
void ProgressBar::setFillColor(const Color &color) { void ProgressBar::setFillColor(const Color &color) {
fillColor_ = color; fillColor_ = color;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setGradientFillEnabled(bool enabled) { void ProgressBar::setGradientFillEnabled(bool enabled) {
gradientEnabled_ = enabled; gradientEnabled_ = enabled;
} }
/**
* @brief
* @param color
*/
void ProgressBar::setFillColorEnd(const Color &color) { void ProgressBar::setFillColorEnd(const Color &color) {
fillColorEnd_ = color; fillColorEnd_ = color;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setSegmentedColorsEnabled(bool enabled) { void ProgressBar::setSegmentedColorsEnabled(bool enabled) {
segmentedColorsEnabled_ = enabled; segmentedColorsEnabled_ = enabled;
} }
/**
* @brief
* @param percentThreshold
* @param color
*/
void ProgressBar::addColorSegment(float percentThreshold, const Color &color) { void ProgressBar::addColorSegment(float percentThreshold, const Color &color) {
colorSegments_.push_back({percentThreshold, color}); colorSegments_.push_back({percentThreshold, color});
std::sort(colorSegments_.begin(), colorSegments_.end(), std::sort(colorSegments_.begin(), colorSegments_.end(),
[](const auto &a, const auto &b) { return a.first > b.first; }); [](const auto &a, const auto &b) { return a.first > b.first; });
} }
/**
* @brief
*/
void ProgressBar::clearColorSegments() { void ProgressBar::clearColorSegments() {
colorSegments_.clear(); colorSegments_.clear();
} }
/**
* @brief
* @param radius
*/
void ProgressBar::setCornerRadius(float radius) { void ProgressBar::setCornerRadius(float radius) {
cornerRadius_ = radius; cornerRadius_ = radius;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setRoundedCornersEnabled(bool enabled) { void ProgressBar::setRoundedCornersEnabled(bool enabled) {
roundedCornersEnabled_ = enabled; roundedCornersEnabled_ = enabled;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setBorderEnabled(bool enabled) { void ProgressBar::setBorderEnabled(bool enabled) {
borderEnabled_ = enabled; borderEnabled_ = enabled;
} }
/**
* @brief
* @param color
*/
void ProgressBar::setBorderColor(const Color &color) { void ProgressBar::setBorderColor(const Color &color) {
borderColor_ = color; borderColor_ = color;
} }
/**
* @brief
* @param width
*/
void ProgressBar::setBorderWidth(float width) { void ProgressBar::setBorderWidth(float width) {
borderWidth_ = width; borderWidth_ = width;
} }
/**
* @brief
* @param padding
*/
void ProgressBar::setPadding(float padding) { void ProgressBar::setPadding(float padding) {
padding_ = padding; padding_ = padding;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setTextEnabled(bool enabled) { void ProgressBar::setTextEnabled(bool enabled) {
textEnabled_ = enabled; textEnabled_ = enabled;
} }
/**
* @brief
* @param font
*/
void ProgressBar::setFont(Ptr<FontAtlas> font) { void ProgressBar::setFont(Ptr<FontAtlas> font) {
font_ = font; font_ = font;
} }
/**
* @brief
* @param color
*/
void ProgressBar::setTextColor(const Color &color) { void ProgressBar::setTextColor(const Color &color) {
textColor_ = color; textColor_ = color;
} }
/**
* @brief
* @param format
*/
void ProgressBar::setTextFormat(const std::string &format) { void ProgressBar::setTextFormat(const std::string &format) {
textFormat_ = format; textFormat_ = format;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setAnimatedChangeEnabled(bool enabled) { void ProgressBar::setAnimatedChangeEnabled(bool enabled) {
animatedChangeEnabled_ = enabled; animatedChangeEnabled_ = enabled;
if (!enabled) { if (!enabled) {
@ -184,34 +228,66 @@ void ProgressBar::setAnimatedChangeEnabled(bool enabled) {
} }
} }
/**
* @brief
* @param speed
*/
void ProgressBar::setAnimationSpeed(float speed) { void ProgressBar::setAnimationSpeed(float speed) {
animationSpeed_ = speed; animationSpeed_ = speed;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setDelayedDisplayEnabled(bool enabled) { void ProgressBar::setDelayedDisplayEnabled(bool enabled) {
delayedDisplayEnabled_ = enabled; delayedDisplayEnabled_ = enabled;
} }
/**
* @brief
* @param seconds
*/
void ProgressBar::setDelayTime(float seconds) { void ProgressBar::setDelayTime(float seconds) {
delayTime_ = seconds; delayTime_ = seconds;
} }
/**
* @brief
* @param color
*/
void ProgressBar::setDelayedFillColor(const Color &color) { void ProgressBar::setDelayedFillColor(const Color &color) {
delayedFillColor_ = color; delayedFillColor_ = color;
} }
/**
* @brief
* @param enabled
*/
void ProgressBar::setStripedEnabled(bool enabled) { void ProgressBar::setStripedEnabled(bool enabled) {
stripedEnabled_ = enabled; stripedEnabled_ = enabled;
} }
/**
* @brief
* @param color
*/
void ProgressBar::setStripeColor(const Color &color) { void ProgressBar::setStripeColor(const Color &color) {
stripeColor_ = color; stripeColor_ = color;
} }
/**
* @brief
* @param speed
*/
void ProgressBar::setStripeSpeed(float speed) { void ProgressBar::setStripeSpeed(float speed) {
stripeSpeed_ = speed; stripeSpeed_ = speed;
} }
/**
* @brief
* @return
*/
Color ProgressBar::getCurrentFillColor() const { Color ProgressBar::getCurrentFillColor() const {
if (segmentedColorsEnabled_ && !colorSegments_.empty()) { if (segmentedColorsEnabled_ && !colorSegments_.empty()) {
float percent = getPercent(); float percent = getPercent();
@ -224,6 +300,10 @@ Color ProgressBar::getCurrentFillColor() const {
return fillColor_; return fillColor_;
} }
/**
* @brief
* @return
*/
std::string ProgressBar::formatText() const { std::string ProgressBar::formatText() const {
std::string result = textFormat_; std::string result = textFormat_;
@ -246,10 +326,18 @@ std::string ProgressBar::formatText() const {
return result; return result;
} }
/**
* @brief
* @return
*/
Rect ProgressBar::getBoundingBox() const { Rect ProgressBar::getBoundingBox() const {
return Rect(getPosition().x, getPosition().y, getSize().width, getSize().height); return Rect(getPosition().x, getPosition().y, getSize().width, getSize().height);
} }
/**
* @brief
* @param deltaTime
*/
void ProgressBar::onUpdate(float deltaTime) { void ProgressBar::onUpdate(float deltaTime) {
if (animatedChangeEnabled_ && displayValue_ != value_) { if (animatedChangeEnabled_ && displayValue_ != value_) {
float diff = value_ - displayValue_; float diff = value_ - displayValue_;
@ -285,25 +373,26 @@ void ProgressBar::onUpdate(float deltaTime) {
} }
} }
/**
* @brief
* @param renderer
*/
void ProgressBar::onDrawWidget(RenderBackend &renderer) { void ProgressBar::onDrawWidget(RenderBackend &renderer) {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
Size size = getSize(); Size size = getSize();
// 计算实际绘制区域
float bgX = pos.x + padding_; float bgX = pos.x + padding_;
float bgY = pos.y + padding_; float bgY = pos.y + padding_;
float bgW = size.width - padding_ * 2; float bgW = size.width - padding_ * 2;
float bgH = size.height - padding_ * 2; float bgH = size.height - padding_ * 2;
Rect bgRect(bgX, bgY, bgW, bgH); Rect bgRect(bgX, bgY, bgW, bgH);
// 绘制背景
if (roundedCornersEnabled_) { if (roundedCornersEnabled_) {
fillRoundedRect(renderer, bgRect, bgColor_, cornerRadius_); fillRoundedRect(renderer, bgRect, bgColor_, cornerRadius_);
} else { } else {
renderer.fillRect(bgRect, bgColor_); renderer.fillRect(bgRect, bgColor_);
} }
// 计算填充区域
float percent = getPercent(); float percent = getPercent();
float fillX = bgX, fillY = bgY, fillW = bgW, fillH = bgH; float fillX = bgX, fillY = bgY, fillW = bgW, fillH = bgH;
@ -325,7 +414,6 @@ void ProgressBar::onDrawWidget(RenderBackend &renderer) {
} }
Rect fillRect(fillX, fillY, fillW, fillH); Rect fillRect(fillX, fillY, fillW, fillH);
// 绘制延迟显示效果
if (delayedDisplayEnabled_ && delayedValue_ > displayValue_) { if (delayedDisplayEnabled_ && delayedValue_ > displayValue_) {
float delayedPercent = (delayedValue_ - min_) / (max_ - min_); float delayedPercent = (delayedValue_ - min_) / (max_ - min_);
float delayedX = bgX, delayedY = bgY, delayedW = bgW, delayedH = bgH; float delayedX = bgX, delayedY = bgY, delayedW = bgW, delayedH = bgH;
@ -355,7 +443,6 @@ void ProgressBar::onDrawWidget(RenderBackend &renderer) {
} }
} }
// 绘制填充
if (fillW > 0 && fillH > 0) { if (fillW > 0 && fillH > 0) {
Color fillColor = getCurrentFillColor(); Color fillColor = getCurrentFillColor();
@ -370,7 +457,6 @@ void ProgressBar::onDrawWidget(RenderBackend &renderer) {
} }
} }
// 绘制边框
if (borderEnabled_) { if (borderEnabled_) {
if (roundedCornersEnabled_) { if (roundedCornersEnabled_) {
drawRoundedRect(renderer, bgRect, borderColor_, cornerRadius_); drawRoundedRect(renderer, bgRect, borderColor_, cornerRadius_);
@ -379,7 +465,6 @@ void ProgressBar::onDrawWidget(RenderBackend &renderer) {
} }
} }
// 绘制文本
if (textEnabled_ && font_) { if (textEnabled_ && font_) {
std::string text = formatText(); std::string text = formatText();
Vec2 textSize = font_->measureText(text); Vec2 textSize = font_->measureText(text);
@ -393,14 +478,33 @@ void ProgressBar::onDrawWidget(RenderBackend &renderer) {
} }
} }
/**
* @brief
* @param renderer
* @param rect
* @param color
* @param radius
*/
void ProgressBar::drawRoundedRect(RenderBackend &renderer, const Rect &rect, const Color &color, float radius) { void ProgressBar::drawRoundedRect(RenderBackend &renderer, const Rect &rect, const Color &color, float radius) {
renderer.drawRect(rect, color, borderWidth_); renderer.drawRect(rect, color, borderWidth_);
} }
/**
* @brief
* @param renderer
* @param rect
* @param color
* @param radius
*/
void ProgressBar::fillRoundedRect(RenderBackend &renderer, const Rect &rect, const Color &color, float radius) { void ProgressBar::fillRoundedRect(RenderBackend &renderer, const Rect &rect, const Color &color, float radius) {
renderer.fillRect(rect, color); renderer.fillRect(rect, color);
} }
/**
* @brief
* @param renderer
* @param rect
*/
void ProgressBar::drawStripes(RenderBackend &renderer, const Rect &rect) { void ProgressBar::drawStripes(RenderBackend &renderer, const Rect &rect) {
const float stripeWidth = 10.0f; const float stripeWidth = 10.0f;
const float spacing = 20.0f; const float spacing = 20.0f;

View File

@ -4,95 +4,37 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*/
RadioButton::RadioButton() { RadioButton::RadioButton() {
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
setSize(circleSize_, circleSize_); setSize(circleSize_, circleSize_);
} }
/**
* @brief
* @return
*/
Ptr<RadioButton> RadioButton::create() { Ptr<RadioButton> RadioButton::create() {
return makePtr<RadioButton>(); return makePtr<RadioButton>();
} }
/**
* @brief
* @param label
* @return
*/
Ptr<RadioButton> RadioButton::create(const std::string &label) { Ptr<RadioButton> RadioButton::create(const std::string &label) {
auto rb = makePtr<RadioButton>(); auto rb = makePtr<RadioButton>();
rb->setLabel(label); rb->setLabel(label);
return rb; return rb;
} }
// ------------------------------------------------------------------------ /**
// 链式调用构建器方法 * @brief
// ------------------------------------------------------------------------ * @param selected
RadioButton *RadioButton::withPosition(float x, float y) { */
setPosition(x, y);
return this;
}
RadioButton *RadioButton::withPosition(const Vec2 &pos) {
setPosition(pos);
return this;
}
RadioButton *RadioButton::withAnchor(float x, float y) {
setAnchor(x, y);
return this;
}
RadioButton *RadioButton::withAnchor(const Vec2 &anchor) {
setAnchor(anchor);
return this;
}
RadioButton *RadioButton::withText(const std::string &text) {
setLabel(text);
return this;
}
RadioButton *RadioButton::withFont(Ptr<FontAtlas> font) {
setFont(font);
return this;
}
RadioButton *RadioButton::withTextColor(const Color &color) {
setTextColor(color);
return this;
}
RadioButton *RadioButton::withSize(float width, float height) {
setSize(width, height);
return this;
}
// ------------------------------------------------------------------------
// 链式调用 - 坐标空间设置
// ------------------------------------------------------------------------
RadioButton *RadioButton::withCoordinateSpace(CoordinateSpace space) {
setCoordinateSpace(space);
return this;
}
RadioButton *RadioButton::withScreenPosition(float x, float y) {
setScreenPosition(x, y);
return this;
}
RadioButton *RadioButton::withScreenPosition(const Vec2 &pos) {
setScreenPosition(pos);
return this;
}
RadioButton *RadioButton::withCameraOffset(float x, float y) {
setCameraOffset(x, y);
return this;
}
RadioButton *RadioButton::withCameraOffset(const Vec2 &offset) {
setCameraOffset(offset);
return this;
}
// ------------------------------------------------------------------------
// 普通设置方法
// ------------------------------------------------------------------------
void RadioButton::setSelected(bool selected) { void RadioButton::setSelected(bool selected) {
if (selected_ != selected) { if (selected_ != selected) {
selected_ = selected; selected_ = selected;
@ -102,46 +44,90 @@ void RadioButton::setSelected(bool selected) {
} }
} }
/**
* @brief
* @param label
*/
void RadioButton::setLabel(const std::string &label) { void RadioButton::setLabel(const std::string &label) {
label_ = label; label_ = label;
} }
/**
* @brief
* @param font
*/
void RadioButton::setFont(Ptr<FontAtlas> font) { void RadioButton::setFont(Ptr<FontAtlas> font) {
font_ = font; font_ = font;
} }
/**
* @brief
* @param color
*/
void RadioButton::setTextColor(const Color &color) { void RadioButton::setTextColor(const Color &color) {
textColor_ = color; textColor_ = color;
} }
/**
* @brief
* @param size
*/
void RadioButton::setCircleSize(float size) { void RadioButton::setCircleSize(float size) {
circleSize_ = size; circleSize_ = size;
} }
/**
* @brief
* @param spacing
*/
void RadioButton::setSpacing(float spacing) { void RadioButton::setSpacing(float spacing) {
spacing_ = spacing; spacing_ = spacing;
} }
/**
* @brief
* @param color
*/
void RadioButton::setSelectedColor(const Color &color) { void RadioButton::setSelectedColor(const Color &color) {
selectedColor_ = color; selectedColor_ = color;
} }
/**
* @brief
* @param color
*/
void RadioButton::setUnselectedColor(const Color &color) { void RadioButton::setUnselectedColor(const Color &color) {
unselectedColor_ = color; unselectedColor_ = color;
} }
/**
* @brief
* @param color
*/
void RadioButton::setDotColor(const Color &color) { void RadioButton::setDotColor(const Color &color) {
dotColor_ = color; dotColor_ = color;
} }
/**
* @brief ID
* @param groupId ID
*/
void RadioButton::setGroupId(int groupId) { void RadioButton::setGroupId(int groupId) {
groupId_ = groupId; groupId_ = groupId;
} }
/**
* @brief
* @param callback
*/
void RadioButton::setOnStateChange(Function<void(bool)> callback) { void RadioButton::setOnStateChange(Function<void(bool)> callback) {
onStateChange_ = callback; onStateChange_ = callback;
} }
/**
* @brief
* @return
*/
Rect RadioButton::getBoundingBox() const { Rect RadioButton::getBoundingBox() const {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
float width = circleSize_; float width = circleSize_;
@ -154,30 +140,36 @@ Rect RadioButton::getBoundingBox() const {
return Rect(pos.x, pos.y, width, circleSize_); return Rect(pos.x, pos.y, width, circleSize_);
} }
/**
* @brief
* @param renderer
*/
void RadioButton::onDrawWidget(RenderBackend &renderer) { void RadioButton::onDrawWidget(RenderBackend &renderer) {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
float centerX = pos.x + circleSize_ * 0.5f; float centerX = pos.x + circleSize_ * 0.5f;
float centerY = pos.y + getSize().height * 0.5f; float centerY = pos.y + getSize().height * 0.5f;
float radius = circleSize_ * 0.5f; float radius = circleSize_ * 0.5f;
// 绘制外圆
Color circleColor = selected_ ? selectedColor_ : unselectedColor_; Color circleColor = selected_ ? selectedColor_ : unselectedColor_;
renderer.drawCircle(Vec2(centerX, centerY), radius, circleColor, true); renderer.drawCircle(Vec2(centerX, centerY), radius, circleColor, true);
renderer.drawCircle(Vec2(centerX, centerY), radius, Colors::White, false, 1.0f); renderer.drawCircle(Vec2(centerX, centerY), radius, Colors::White, false, 1.0f);
// 绘制内圆点
if (selected_) { if (selected_) {
float dotRadius = radius * 0.4f; float dotRadius = radius * 0.4f;
renderer.drawCircle(Vec2(centerX, centerY), dotRadius, dotColor_, true); renderer.drawCircle(Vec2(centerX, centerY), dotRadius, dotColor_, true);
} }
// 绘制标签
if (!label_.empty() && font_) { if (!label_.empty() && font_) {
Vec2 textPos(pos.x + circleSize_ + spacing_, pos.y); Vec2 textPos(pos.x + circleSize_ + spacing_, pos.y);
renderer.drawText(*font_, label_, textPos, textColor_); renderer.drawText(*font_, label_, textPos, textColor_);
} }
} }
/**
* @brief
* @param event
* @return
*/
bool RadioButton::onMousePress(const MouseEvent &event) { bool RadioButton::onMousePress(const MouseEvent &event) {
if (event.button == MouseButton::Left) { if (event.button == MouseButton::Left) {
pressed_ = true; pressed_ = true;
@ -186,6 +178,11 @@ bool RadioButton::onMousePress(const MouseEvent &event) {
return false; return false;
} }
/**
* @brief
* @param event
* @return
*/
bool RadioButton::onMouseRelease(const MouseEvent &event) { bool RadioButton::onMouseRelease(const MouseEvent &event) {
if (event.button == MouseButton::Left && pressed_) { if (event.button == MouseButton::Left && pressed_) {
pressed_ = false; pressed_ = false;
@ -208,6 +205,10 @@ bool RadioButton::onMouseRelease(const MouseEvent &event) {
// RadioButtonGroup 实现 // RadioButtonGroup 实现
// ============================================================================ // ============================================================================
/**
* @brief
* @param button
*/
void RadioButtonGroup::addButton(RadioButton *button) { void RadioButtonGroup::addButton(RadioButton *button) {
if (button && std::find(buttons_.begin(), buttons_.end(), button) == buttons_.end()) { if (button && std::find(buttons_.begin(), buttons_.end(), button) == buttons_.end()) {
buttons_.push_back(button); buttons_.push_back(button);
@ -223,6 +224,10 @@ void RadioButtonGroup::addButton(RadioButton *button) {
} }
} }
/**
* @brief
* @param button
*/
void RadioButtonGroup::removeButton(RadioButton *button) { void RadioButtonGroup::removeButton(RadioButton *button) {
auto it = std::find(buttons_.begin(), buttons_.end(), button); auto it = std::find(buttons_.begin(), buttons_.end(), button);
if (it != buttons_.end()) { if (it != buttons_.end()) {
@ -233,15 +238,17 @@ void RadioButtonGroup::removeButton(RadioButton *button) {
} }
} }
/**
* @brief
* @param button
*/
void RadioButtonGroup::selectButton(RadioButton *button) { void RadioButtonGroup::selectButton(RadioButton *button) {
if (selectedButton_ == button) return; if (selectedButton_ == button) return;
// 取消之前的选择
if (selectedButton_) { if (selectedButton_) {
selectedButton_->setSelected(false); selectedButton_->setSelected(false);
} }
// 选择新的按钮
selectedButton_ = button; selectedButton_ = button;
if (button) { if (button) {
button->setSelected(true); button->setSelected(true);
@ -252,6 +259,10 @@ void RadioButtonGroup::selectButton(RadioButton *button) {
} }
} }
/**
* @brief
* @param callback
*/
void RadioButtonGroup::setOnSelectionChange(Function<void(RadioButton*)> callback) { void RadioButtonGroup::setOnSelectionChange(Function<void(RadioButton*)> callback) {
onSelectionChange_ = callback; onSelectionChange_ = callback;
} }

View File

@ -5,15 +5,29 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*/
Slider::Slider() { Slider::Slider() {
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
setSize(200.0f, 20.0f); setSize(200.0f, 20.0f);
} }
/**
* @brief
* @return
*/
Ptr<Slider> Slider::create() { Ptr<Slider> Slider::create() {
return makePtr<Slider>(); return makePtr<Slider>();
} }
/**
* @brief
* @param min
* @param max
* @param value
* @return
*/
Ptr<Slider> Slider::create(float min, float max, float value) { Ptr<Slider> Slider::create(float min, float max, float value) {
auto slider = makePtr<Slider>(); auto slider = makePtr<Slider>();
slider->setRange(min, max); slider->setRange(min, max);
@ -21,153 +35,21 @@ Ptr<Slider> Slider::create(float min, float max, float value) {
return slider; return slider;
} }
// ============================================================================
// 链式调用构建器方法实现
// ============================================================================
/** /**
* @brief * @brief
* @param x X坐标
* @param y Y坐标
* @return this指针
*/
Slider *Slider::withPosition(float x, float y) {
setPosition(x, y);
return this;
}
/**
* @brief Vec2坐标
* @param pos
* @return this指针
*/
Slider *Slider::withPosition(const Vec2 &pos) {
setPosition(pos);
return this;
}
/**
* @brief
* @param x X锚点0-1
* @param y Y锚点0-1
* @return this指针
*/
Slider *Slider::withAnchor(float x, float y) {
setAnchor(x, y);
return this;
}
/**
* @brief Vec2坐标
* @param anchor
* @return this指针
*/
Slider *Slider::withAnchor(const Vec2 &anchor) {
setAnchor(anchor);
return this;
}
/**
* @brief
* @param width
* @param height
* @return this指针
*/
Slider *Slider::withSize(float width, float height) {
setSize(width, height);
return this;
}
/**
* @brief
* @param min * @param min
* @return this指针
*/
Slider *Slider::withMinValue(float min) {
min_ = min;
setValue(value_);
return this;
}
/**
* @brief
* @param max * @param max
* @return this指针
*/ */
Slider *Slider::withMaxValue(float max) {
max_ = max;
setValue(value_);
return this;
}
/**
* @brief
* @param value
* @return this指针
*/
Slider *Slider::withValue(float value) {
setValue(value);
return this;
}
/**
* @brief
* @param space
* @return this指针
*/
Slider *Slider::withCoordinateSpace(CoordinateSpace space) {
setCoordinateSpace(space);
return this;
}
/**
* @brief
* @param x X屏幕坐标
* @param y Y屏幕坐标
* @return this指针
*/
Slider *Slider::withScreenPosition(float x, float y) {
setScreenPosition(x, y);
return this;
}
/**
* @brief Vec2坐标
* @param pos
* @return this指针
*/
Slider *Slider::withScreenPosition(const Vec2 &pos) {
setScreenPosition(pos);
return this;
}
/**
* @brief
* @param x X偏移量
* @param y Y偏移量
* @return this指针
*/
Slider *Slider::withCameraOffset(float x, float y) {
setCameraOffset(x, y);
return this;
}
/**
* @brief Vec2坐标
* @param offset
* @return this指针
*/
Slider *Slider::withCameraOffset(const Vec2 &offset) {
setCameraOffset(offset);
return this;
}
void Slider::setRange(float min, float max) { void Slider::setRange(float min, float max) {
min_ = min; min_ = min;
max_ = max; max_ = max;
setValue(value_); setValue(value_);
} }
/**
* @brief
* @param value
*/
void Slider::setValue(float value) { void Slider::setValue(float value) {
float newValue = std::clamp(value, min_, max_); float newValue = std::clamp(value, min_, max_);
if (step_ > 0.0f) { if (step_ > 0.0f) {
@ -182,6 +64,10 @@ void Slider::setValue(float value) {
} }
} }
/**
* @brief
* @param step
*/
void Slider::setStep(float step) { void Slider::setStep(float step) {
step_ = step; step_ = step;
if (step_ > 0.0f) { if (step_ > 0.0f) {
@ -189,78 +75,155 @@ void Slider::setStep(float step) {
} }
} }
/**
* @brief
* @param vertical
*/
void Slider::setVertical(bool vertical) { void Slider::setVertical(bool vertical) {
vertical_ = vertical; vertical_ = vertical;
} }
/**
* @brief
* @param size
*/
void Slider::setTrackSize(float size) { void Slider::setTrackSize(float size) {
trackSize_ = size; trackSize_ = size;
} }
/**
* @brief
* @param size
*/
void Slider::setThumbSize(float size) { void Slider::setThumbSize(float size) {
thumbSize_ = size; thumbSize_ = size;
} }
/**
* @brief
* @param color
*/
void Slider::setTrackColor(const Color &color) { void Slider::setTrackColor(const Color &color) {
trackColor_ = color; trackColor_ = color;
} }
/**
* @brief
* @param color
*/
void Slider::setFillColor(const Color &color) { void Slider::setFillColor(const Color &color) {
fillColor_ = color; fillColor_ = color;
} }
/**
* @brief
* @param color
*/
void Slider::setThumbColor(const Color &color) { void Slider::setThumbColor(const Color &color) {
thumbColor_ = color; thumbColor_ = color;
} }
/**
* @brief
* @param color
*/
void Slider::setThumbHoverColor(const Color &color) { void Slider::setThumbHoverColor(const Color &color) {
thumbHoverColor_ = color; thumbHoverColor_ = color;
} }
/**
* @brief
* @param color
*/
void Slider::setThumbPressedColor(const Color &color) { void Slider::setThumbPressedColor(const Color &color) {
thumbPressedColor_ = color; thumbPressedColor_ = color;
} }
/**
* @brief
* @param show
*/
void Slider::setShowThumb(bool show) { void Slider::setShowThumb(bool show) {
showThumb_ = show; showThumb_ = show;
} }
/**
* @brief
* @param show
*/
void Slider::setShowFill(bool show) { void Slider::setShowFill(bool show) {
showFill_ = show; showFill_ = show;
} }
/**
* @brief
* @param enabled
*/
void Slider::setTextEnabled(bool enabled) { void Slider::setTextEnabled(bool enabled) {
textEnabled_ = enabled; textEnabled_ = enabled;
} }
/**
* @brief
* @param font
*/
void Slider::setFont(Ptr<FontAtlas> font) { void Slider::setFont(Ptr<FontAtlas> font) {
font_ = font; font_ = font;
} }
/**
* @brief
* @param color
*/
void Slider::setTextColor(const Color &color) { void Slider::setTextColor(const Color &color) {
textColor_ = color; textColor_ = color;
} }
/**
* @brief
* @param format
*/
void Slider::setTextFormat(const std::string &format) { void Slider::setTextFormat(const std::string &format) {
textFormat_ = format; textFormat_ = format;
} }
/**
* @brief
* @param callback
*/
void Slider::setOnValueChange(Function<void(float)> callback) { void Slider::setOnValueChange(Function<void(float)> callback) {
onValueChange_ = callback; onValueChange_ = callback;
} }
/**
* @brief
* @param callback
*/
void Slider::setOnDragStart(Function<void()> callback) { void Slider::setOnDragStart(Function<void()> callback) {
onDragStart_ = callback; onDragStart_ = callback;
} }
/**
* @brief
* @param callback
*/
void Slider::setOnDragEnd(Function<void()> callback) { void Slider::setOnDragEnd(Function<void()> callback) {
onDragEnd_ = callback; onDragEnd_ = callback;
} }
/**
* @brief
* @return
*/
Rect Slider::getBoundingBox() const { Rect Slider::getBoundingBox() const {
return Rect(getPosition().x, getPosition().y, getSize().width, getSize().height); return Rect(getPosition().x, getPosition().y, getSize().width, getSize().height);
} }
/**
* @brief
* @param value
* @return
*/
float Slider::valueToPosition(float value) const { float Slider::valueToPosition(float value) const {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
Size size = getSize(); Size size = getSize();
@ -274,6 +237,11 @@ float Slider::valueToPosition(float value) const {
} }
} }
/**
* @brief
* @param pos
* @return
*/
float Slider::positionToValue(float pos) const { float Slider::positionToValue(float pos) const {
Vec2 widgetPos = getPosition(); Vec2 widgetPos = getPosition();
Size size = getSize(); Size size = getSize();
@ -289,6 +257,10 @@ float Slider::positionToValue(float pos) const {
return min_ + percent * (max_ - min_); return min_ + percent * (max_ - min_);
} }
/**
* @brief
* @return
*/
Rect Slider::getThumbRect() const { Rect Slider::getThumbRect() const {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
Size size = getSize(); Size size = getSize();
@ -312,6 +284,10 @@ Rect Slider::getThumbRect() const {
} }
} }
/**
* @brief
* @return
*/
Rect Slider::getTrackRect() const { Rect Slider::getTrackRect() const {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
Size size = getSize(); Size size = getSize();
@ -333,6 +309,10 @@ Rect Slider::getTrackRect() const {
} }
} }
/**
* @brief
* @return
*/
std::string Slider::formatText() const { std::string Slider::formatText() const {
std::string result = textFormat_; std::string result = textFormat_;
@ -353,18 +333,25 @@ std::string Slider::formatText() const {
return result; return result;
} }
/**
* @brief
* @param value
* @return
*/
float Slider::snapToStep(float value) const { float Slider::snapToStep(float value) const {
float steps = std::round((value - min_) / step_); float steps = std::round((value - min_) / step_);
return min_ + steps * step_; return min_ + steps * step_;
} }
/**
* @brief
* @param renderer
*/
void Slider::onDrawWidget(RenderBackend &renderer) { void Slider::onDrawWidget(RenderBackend &renderer) {
Rect trackRect = getTrackRect(); Rect trackRect = getTrackRect();
// 绘制轨道背景
renderer.fillRect(trackRect, trackColor_); renderer.fillRect(trackRect, trackColor_);
// 绘制填充部分
if (showFill_) { if (showFill_) {
float percent = (value_ - min_) / (max_ - min_); float percent = (value_ - min_) / (max_ - min_);
float fillX = trackRect.origin.x; float fillX = trackRect.origin.x;
@ -383,7 +370,6 @@ void Slider::onDrawWidget(RenderBackend &renderer) {
renderer.fillRect(fillRect, fillColor_); renderer.fillRect(fillRect, fillColor_);
} }
// 绘制滑块
if (showThumb_) { if (showThumb_) {
Rect thumbRect = getThumbRect(); Rect thumbRect = getThumbRect();
Color thumbColor = thumbColor_; Color thumbColor = thumbColor_;
@ -398,7 +384,6 @@ void Slider::onDrawWidget(RenderBackend &renderer) {
renderer.drawRect(thumbRect, Colors::White, 1.0f); renderer.drawRect(thumbRect, Colors::White, 1.0f);
} }
// 绘制文本
if (textEnabled_ && font_) { if (textEnabled_ && font_) {
std::string text = formatText(); std::string text = formatText();
Vec2 textSize = font_->measureText(text); Vec2 textSize = font_->measureText(text);
@ -414,6 +399,11 @@ void Slider::onDrawWidget(RenderBackend &renderer) {
} }
} }
/**
* @brief
* @param event
* @return
*/
bool Slider::onMousePress(const MouseEvent &event) { bool Slider::onMousePress(const MouseEvent &event) {
if (event.button == MouseButton::Left) { if (event.button == MouseButton::Left) {
Rect thumbRect = getThumbRect(); Rect thumbRect = getThumbRect();
@ -426,7 +416,6 @@ bool Slider::onMousePress(const MouseEvent &event) {
return true; return true;
} }
// 点击轨道直接跳转
Rect trackRect = getTrackRect(); Rect trackRect = getTrackRect();
if (trackRect.containsPoint(Point(event.x, event.y))) { if (trackRect.containsPoint(Point(event.x, event.y))) {
float newValue = positionToValue(vertical_ ? event.y : event.x); float newValue = positionToValue(vertical_ ? event.y : event.x);
@ -441,6 +430,11 @@ bool Slider::onMousePress(const MouseEvent &event) {
return false; return false;
} }
/**
* @brief
* @param event
* @return
*/
bool Slider::onMouseRelease(const MouseEvent &event) { bool Slider::onMouseRelease(const MouseEvent &event) {
if (event.button == MouseButton::Left && dragging_) { if (event.button == MouseButton::Left && dragging_) {
dragging_ = false; dragging_ = false;
@ -452,6 +446,11 @@ bool Slider::onMouseRelease(const MouseEvent &event) {
return false; return false;
} }
/**
* @brief
* @param event
* @return
*/
bool Slider::onMouseMove(const MouseEvent &event) { bool Slider::onMouseMove(const MouseEvent &event) {
if (dragging_) { if (dragging_) {
float newValue = positionToValue(vertical_ ? event.y : event.x); float newValue = positionToValue(vertical_ ? event.y : event.x);
@ -459,7 +458,6 @@ bool Slider::onMouseMove(const MouseEvent &event) {
return true; return true;
} }
// 检查悬停
Rect thumbRect = getThumbRect(); Rect thumbRect = getThumbRect();
bool wasHovered = hovered_; bool wasHovered = hovered_;
hovered_ = thumbRect.containsPoint(Point(event.x, event.y)); hovered_ = thumbRect.containsPoint(Point(event.x, event.y));
@ -467,10 +465,16 @@ bool Slider::onMouseMove(const MouseEvent &event) {
return hovered_ != wasHovered; return hovered_ != wasHovered;
} }
/**
* @brief
*/
void Slider::onMouseEnter() { void Slider::onMouseEnter() {
hovered_ = true; hovered_ = true;
} }
/**
* @brief
*/
void Slider::onMouseLeave() { void Slider::onMouseLeave() {
hovered_ = false; hovered_ = false;
} }

View File

@ -1,136 +1,93 @@
#include <extra2d/ui/text.h>
#include <extra2d/graphics/render_backend.h>
#include <extra2d/core/string.h>
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <extra2d/core/string.h>
#include <extra2d/graphics/render_backend.h>
#include <extra2d/ui/text.h>
namespace extra2d { namespace extra2d {
Text::Text() { /**
// 文字默认锚点为左上角这样setPosition(0, 0)会在左上角显示 * @brief
setAnchor(0.0f, 0.0f); */
} Text::Text() { setAnchor(0.0f, 0.0f); }
/**
* @brief
* @param text
*/
Text::Text(const std::string &text) : text_(text) { Text::Text(const std::string &text) : text_(text) {
sizeDirty_ = true; sizeDirty_ = true;
// 文字默认锚点为左上角这样setPosition(0, 0)会在左上角显示
setAnchor(0.0f, 0.0f); setAnchor(0.0f, 0.0f);
} }
// ------------------------------------------------------------------------ /**
// 链式调用构建器方法 * @brief
// ------------------------------------------------------------------------ * @param text
Text *Text::withPosition(float x, float y) { */
setPosition(x, y);
return this;
}
Text *Text::withPosition(const Vec2 &pos) {
setPosition(pos);
return this;
}
Text *Text::withAnchor(float x, float y) {
setAnchor(x, y);
return this;
}
Text *Text::withAnchor(const Vec2 &anchor) {
setAnchor(anchor);
return this;
}
Text *Text::withTextColor(const Color &color) {
setTextColor(color);
return this;
}
Text *Text::withFont(Ptr<FontAtlas> font) {
setFont(font);
return this;
}
Text *Text::withFontSize(int size) {
setFontSize(size);
return this;
}
Text *Text::withAlignment(Alignment align) {
setAlignment(align);
return this;
}
Text *Text::withVerticalAlignment(VerticalAlignment align) {
setVerticalAlignment(align);
return this;
}
// ------------------------------------------------------------------------
// 链式调用 - 坐标空间设置
// ------------------------------------------------------------------------
Text *Text::withCoordinateSpace(CoordinateSpace space) {
setCoordinateSpace(space);
return this;
}
Text *Text::withScreenPosition(float x, float y) {
setScreenPosition(x, y);
return this;
}
Text *Text::withScreenPosition(const Vec2 &pos) {
setScreenPosition(pos);
return this;
}
Text *Text::withCameraOffset(float x, float y) {
setCameraOffset(x, y);
return this;
}
Text *Text::withCameraOffset(const Vec2 &offset) {
setCameraOffset(offset);
return this;
}
// ------------------------------------------------------------------------
// 普通设置方法
// ------------------------------------------------------------------------
void Text::setText(const std::string &text) { void Text::setText(const std::string &text) {
text_ = text; text_ = text;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param font
*/
void Text::setFont(Ptr<FontAtlas> font) { void Text::setFont(Ptr<FontAtlas> font) {
font_ = font; font_ = font;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param color
*/
void Text::setTextColor(const Color &color) { color_ = color; } void Text::setTextColor(const Color &color) { color_ = color; }
/**
* @brief
* @param size
*/
void Text::setFontSize(int size) { void Text::setFontSize(int size) {
fontSize_ = size; fontSize_ = size;
sizeDirty_ = true; sizeDirty_ = true;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param align
*/
void Text::setAlignment(Alignment align) { void Text::setAlignment(Alignment align) {
alignment_ = align; alignment_ = align;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @param align
*/
void Text::setVerticalAlignment(VerticalAlignment align) { void Text::setVerticalAlignment(VerticalAlignment align) {
verticalAlignment_ = align; verticalAlignment_ = align;
updateSpatialIndex(); updateSpatialIndex();
} }
/**
* @brief
* @return
*/
Vec2 Text::getTextSize() const { Vec2 Text::getTextSize() const {
updateCache(); updateCache();
return cachedSize_; return cachedSize_;
} }
/**
* @brief
* @return
*/
float Text::getLineHeight() const { float Text::getLineHeight() const {
if (font_) { if (font_) {
return font_->getLineHeight(); return font_->getLineHeight();
@ -138,6 +95,9 @@ float Text::getLineHeight() const {
return static_cast<float>(fontSize_); return static_cast<float>(fontSize_);
} }
/**
* @brief
*/
void Text::updateCache() const { void Text::updateCache() const {
if (!sizeDirty_ || !font_) { if (!sizeDirty_ || !font_) {
return; return;
@ -147,22 +107,22 @@ void Text::updateCache() const {
sizeDirty_ = false; sizeDirty_ = false;
} }
/**
* @brief
* @return
*/
Vec2 Text::calculateDrawPosition() const { Vec2 Text::calculateDrawPosition() const {
Vec2 pos = getPosition(); Vec2 pos = getPosition();
Vec2 textSize = getTextSize(); Vec2 textSize = getTextSize();
Size widgetSize = getSize(); Size widgetSize = getSize();
Vec2 anchor = getAnchor(); Vec2 anchor = getAnchor();
// 如果设置了控件大小,使用控件大小作为对齐参考
float refWidth = widgetSize.empty() ? textSize.x : widgetSize.width; float refWidth = widgetSize.empty() ? textSize.x : widgetSize.width;
float refHeight = widgetSize.empty() ? textSize.y : widgetSize.height; float refHeight = widgetSize.empty() ? textSize.y : widgetSize.height;
// 锚点调整:锚点(0.5, 0.5)表示文本中心在pos位置
// 需要将文本向左上方偏移锚点比例 * 文本大小
pos.x -= textSize.x * anchor.x; pos.x -= textSize.x * anchor.x;
pos.y -= textSize.y * anchor.y; pos.y -= textSize.y * anchor.y;
// 水平对齐(仅在设置了控件大小时生效)
if (!widgetSize.empty()) { if (!widgetSize.empty()) {
switch (alignment_) { switch (alignment_) {
case Alignment::Center: case Alignment::Center:
@ -177,7 +137,6 @@ Vec2 Text::calculateDrawPosition() const {
} }
} }
// 垂直对齐(仅在设置了控件大小时生效)
if (!widgetSize.empty()) { if (!widgetSize.empty()) {
switch (verticalAlignment_) { switch (verticalAlignment_) {
case VerticalAlignment::Middle: case VerticalAlignment::Middle:
@ -195,19 +154,37 @@ Vec2 Text::calculateDrawPosition() const {
return pos; return pos;
} }
/**
* @brief
* @return
*/
Ptr<Text> Text::create() { return makePtr<Text>(); } Ptr<Text> Text::create() { return makePtr<Text>(); }
/**
* @brief
* @param text
* @return
*/
Ptr<Text> Text::create(const std::string &text) { return makePtr<Text>(text); } Ptr<Text> Text::create(const std::string &text) { return makePtr<Text>(text); }
/**
* @brief
* @param text
* @param font
* @return
*/
Ptr<Text> Text::create(const std::string &text, Ptr<FontAtlas> font) { Ptr<Text> Text::create(const std::string &text, Ptr<FontAtlas> font) {
auto t = makePtr<Text>(text); auto t = makePtr<Text>(text);
t->setFont(font); t->setFont(font);
return t; return t;
} }
// ------------------------------------------------------------------------ /**
// 格式化创建方法 * @brief
// ------------------------------------------------------------------------ * @param fmt
* @param ...
* @return
*/
Ptr<Text> Text::createFormat(const char *fmt, ...) { Ptr<Text> Text::createFormat(const char *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
@ -217,6 +194,13 @@ Ptr<Text> Text::createFormat(const char *fmt, ...) {
return makePtr<Text>(buffer); return makePtr<Text>(buffer);
} }
/**
* @brief
* @param font
* @param fmt
* @param ...
* @return
*/
Ptr<Text> Text::createFormat(Ptr<FontAtlas> font, const char *fmt, ...) { Ptr<Text> Text::createFormat(Ptr<FontAtlas> font, const char *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
@ -228,6 +212,10 @@ Ptr<Text> Text::createFormat(Ptr<FontAtlas> font, const char *fmt, ...) {
return t; return t;
} }
/**
* @brief
* @return
*/
Rect Text::getBoundingBox() const { Rect Text::getBoundingBox() const {
if (!font_ || text_.empty()) { if (!font_ || text_.empty()) {
return Rect(); return Rect();
@ -243,6 +231,10 @@ Rect Text::getBoundingBox() const {
return Rect(pos.x, pos.y, size.x, size.y); return Rect(pos.x, pos.y, size.x, size.y);
} }
/**
* @brief
* @param renderer
*/
void Text::onDrawWidget(RenderBackend &renderer) { void Text::onDrawWidget(RenderBackend &renderer) {
if (!font_ || text_.empty()) { if (!font_ || text_.empty()) {
return; return;

View File

@ -2,7 +2,6 @@
using namespace extra2d; using namespace extra2d;
// ============================================================================ // ============================================================================
// Hello World 场景 // Hello World 场景
// ============================================================================ // ============================================================================
@ -33,34 +32,34 @@ public:
// 创建 "你好世界" 文本组件 - 使用屏幕空间(固定位置,不随相机移动) // 创建 "你好世界" 文本组件 - 使用屏幕空间(固定位置,不随相机移动)
auto text1 = Text::create("你好世界", font_); auto text1 = Text::create("你好世界", font_);
text1->withCoordinateSpace(CoordinateSpace::Screen) text1->setCoordinateSpace(CoordinateSpace::Screen);
->withScreenPosition(640.0f, 360.0f) // 屏幕中心 text1->setScreenPosition(640.0f, 360.0f); // 屏幕中心
->withAnchor(0.5f, 0.5f) // 中心锚点,让文字中心对准位置 text1->setAnchor(0.5f, 0.5f); // 中心锚点,让文字中心对准位置
->withTextColor(Color(1.0f, 1.0f, 1.0f, 1.0f)); text1->setTextColor(Color(1.0f, 1.0f, 1.0f, 1.0f));
addChild(text1); addChild(text1);
// 创建提示文本组件 - 使用屏幕空间,固定在屏幕底部 // 创建提示文本组件 - 使用屏幕空间,固定在屏幕底部
auto text2 = Text::create("退出按键START 按钮)", font_); auto text2 = Text::create("退出按键START 按钮)", font_);
text2->withCoordinateSpace(CoordinateSpace::Screen) text2->setCoordinateSpace(CoordinateSpace::Screen);
->withScreenPosition(640.0f, 650.0f) // 屏幕底部 text2->setScreenPosition(640.0f, 650.0f); // 屏幕底部
->withAnchor(0.5f, 0.5f) text2->setAnchor(0.5f, 0.5f);
->withTextColor(Color(1.0f, 1.0f, 0.0f, 1.0f)); text2->setTextColor(Color(1.0f, 1.0f, 0.0f, 1.0f));
addChild(text2); addChild(text2);
// 创建相机空间文本 - 跟随相机但保持相对偏移 // 创建相机空间文本 - 跟随相机但保持相对偏移
auto text3 = Text::create("相机空间文本", font_); auto text3 = Text::create("相机空间文本", font_);
text3->withCoordinateSpace(CoordinateSpace::Camera) text3->setCoordinateSpace(CoordinateSpace::Camera);
->withCameraOffset(50.0f, 50.0f) // 相机左上角偏移屏幕坐标系Y向下 text3->setCameraOffset(50.0f, 50.0f); // 相机左上角偏移屏幕坐标系Y向下
->withAnchor(0.0f, 0.0f) // 左上角锚点,文字从指定位置开始显示 text3->setAnchor(0.0f, 0.0f); // 左上角锚点,文字从指定位置开始显示
->withTextColor(Color(0.0f, 1.0f, 1.0f, 1.0f)); text3->setTextColor(Color(0.0f, 1.0f, 1.0f, 1.0f));
addChild(text3); addChild(text3);
// 创建世界空间文本 - 随相机移动(默认行为) // 创建世界空间文本 - 随相机移动(默认行为)
auto text4 = Text::create("世界空间文本", font_); auto text4 = Text::create("世界空间文本", font_);
text4->withCoordinateSpace(CoordinateSpace::World) text4->setCoordinateSpace(CoordinateSpace::World);
->withPosition(100.0f, 100.0f) // 世界坐标 text4->setPosition(100.0f, 100.0f); // 世界坐标
->withAnchor(0.0f, 0.0f) // 左上角锚点,文字从指定位置开始显示 text4->setAnchor(0.0f, 0.0f); // 左上角锚点,文字从指定位置开始显示
->withTextColor(Color(1.0f, 0.5f, 0.5f, 1.0f)); text4->setTextColor(Color(1.0f, 0.5f, 0.5f, 1.0f));
addChild(text4); addChild(text4);
} }
@ -89,8 +88,7 @@ private:
// 程序入口 // 程序入口
// ============================================================================ // ============================================================================
int main(int argc, char **argv) int main(int argc, char **argv) {
{
// 初始化日志系统 // 初始化日志系统
Logger::init(); Logger::init();
Logger::setLevel(LogLevel::Debug); Logger::setLevel(LogLevel::Debug);