mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
refactor(ui): decouple ChatBox from image dependencies, allow custom TextField backgrounds
TextField's background is now a generic `Widget` pointer, enabling use of any widget (e.g., `Rect`, `Image`) as background. `ChatBox` no longer creates its own `TextField`; it accepts one via `set_text_field`. Removed `set_d_image` and `set_default_image` in favor of `set_background`. Added a shared default image constant in `default_image.hpp`. Updated `host_game_ui.cpp`, `join_game_ui.cpp`, and `world_ui_manager.cpp` to construct backgrounds accordingly.
This commit is contained in:
@@ -24,9 +24,8 @@ public:
|
||||
std::string& get_input_text();
|
||||
float width() const override;
|
||||
float height() const override;
|
||||
void set_d_image(TextureManager& m);
|
||||
void set_text_field(std::unique_ptr<TextField> text_field);
|
||||
void set_typing(bool typing, bool finished);
|
||||
void set_app(App* app);
|
||||
template <typename F> ChatBox& set_on_finish(F&& f) {
|
||||
m_text_field->set_on_finish(std::forward<F>(f));
|
||||
return *this;
|
||||
|
||||
5
include/Cubed/ui/default_image.hpp
Normal file
5
include/Cubed/ui/default_image.hpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
namespace Cubed {
|
||||
static constexpr const char* DEFAULT_TEXT_FIELD_IMAGE =
|
||||
"texture/ui/textfield001.png";
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/ui/image.hpp"
|
||||
#include "Cubed/ui/label.hpp"
|
||||
#include "Cubed/ui/rect.hpp"
|
||||
#include "Cubed/ui/widget.hpp"
|
||||
@@ -22,13 +21,13 @@ public:
|
||||
TextField& set_width(float width);
|
||||
TextField& set_height(float height);
|
||||
TextField& set_show_text(const std::string& text);
|
||||
TextField& set_background_image(const std::string& path,
|
||||
TextureManager& texture_manager);
|
||||
TextField& set_default_image(TextureManager& texture_manager);
|
||||
TextField& set_background(std::unique_ptr<Widget> background);
|
||||
TextField& set_auto_scale(bool auto_scale);
|
||||
TextField& set_app(App* app);
|
||||
TextField& set_typing(bool typing, bool finished);
|
||||
TextField& clear_input();
|
||||
TextField& set_fill_width(bool fill);
|
||||
TextField& set_fill_height(bool fill);
|
||||
bool handle_mouse_move_event(const MouseMoveEvent& e) override;
|
||||
bool handle_mouse_button_event(const MouseButtonEvent& e) override;
|
||||
bool handle_text_input_event(const TextInputEvent& e) override;
|
||||
@@ -46,11 +45,9 @@ private:
|
||||
static constexpr float DEFAULT_SCALE = 3.0f;
|
||||
static constexpr float TEXT_SCALE = 0.6f;
|
||||
static constexpr float CURSOR_INTERVAL = 0.5f;
|
||||
static constexpr const char* DEFAULT_TEXT_FIELD_IMAGE =
|
||||
"texture/ui/textfield001.png";
|
||||
|
||||
App* m_app = nullptr;
|
||||
std::unique_ptr<Image> m_background;
|
||||
std::unique_ptr<Widget> m_background;
|
||||
std::unique_ptr<Label> m_foreground;
|
||||
std::unique_ptr<Rect> m_cursor;
|
||||
float m_cursor_timer = 0.0f;
|
||||
@@ -62,6 +59,8 @@ private:
|
||||
float m_width = NORMAL_TEXTFIELD_WIDTH;
|
||||
float m_height = NORMAL_TEXTFIELD_HEIGHT;
|
||||
float m_scale = DEFAULT_SCALE;
|
||||
bool m_fill_width = false;
|
||||
bool m_fill_height = false;
|
||||
|
||||
std::string m_input_text;
|
||||
std::string m_show_text;
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
|
||||
#include "Cubed/tools/text_tools.hpp"
|
||||
namespace Cubed {
|
||||
ChatBox::ChatBox(Widget* parent) : Widget(parent) {
|
||||
|
||||
m_text_field = std::make_unique<TextField>(this);
|
||||
m_text_field->set_anchor(Anchor::BOTTOM_LEFT);
|
||||
}
|
||||
ChatBox::ChatBox(Widget* parent) : Widget(parent) {}
|
||||
|
||||
void ChatBox::add_message(ChatMessage& message) {
|
||||
while (m_messages.size() > MAX_MESSGAES_SUM) {
|
||||
@@ -27,7 +23,10 @@ void ChatBox::add_message(ChatMessage& message) {
|
||||
|
||||
ChatBox& ChatBox::set_scale(float scale) {
|
||||
m_scale = scale;
|
||||
m_text_field->set_scale(scale);
|
||||
if (m_text_field) {
|
||||
m_text_field->set_scale(scale);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
ChatBox& ChatBox::set_text_scale(float scale) {
|
||||
@@ -41,7 +40,6 @@ ChatBox& ChatBox::set_text_scale(float scale) {
|
||||
}
|
||||
ChatBox& ChatBox::set_width(float width) {
|
||||
m_width = width;
|
||||
m_text_field->set_width(width);
|
||||
return *this;
|
||||
}
|
||||
ChatBox& ChatBox::set_show_lines(int lines) {
|
||||
@@ -63,17 +61,25 @@ float ChatBox::height() const {
|
||||
// Height is dynamically calculated, no scaling needed
|
||||
return m_height;
|
||||
}
|
||||
void ChatBox::set_d_image(TextureManager& m) {
|
||||
m_text_field->set_default_image(m);
|
||||
|
||||
void ChatBox::set_text_field(std::unique_ptr<TextField> text_field) {
|
||||
m_text_field = std::move(text_field);
|
||||
}
|
||||
|
||||
void ChatBox::set_typing(bool typing, bool finished) {
|
||||
m_text_field->set_typing(typing, finished);
|
||||
if (m_text_field) {
|
||||
m_text_field->set_typing(typing, finished);
|
||||
m_text_field->set_visible(typing);
|
||||
}
|
||||
}
|
||||
void ChatBox::set_app(App* app) { m_text_field->set_app(app); }
|
||||
|
||||
void ChatBox::layout() {
|
||||
int y = m_text_field->height() + m_spacing;
|
||||
int y;
|
||||
if (m_text_field) {
|
||||
y = m_text_field->height() + m_spacing;
|
||||
} else {
|
||||
y = m_spacing;
|
||||
}
|
||||
int line = 0;
|
||||
// Shift upward sequentially starting from the latest
|
||||
for (auto it = m_messages.rbegin(); it != m_messages.rend(); ++it) {
|
||||
@@ -100,7 +106,10 @@ void ChatBox::on_update(float dt) {
|
||||
}
|
||||
|
||||
void ChatBox::on_render(Renderer& renderer) {
|
||||
m_text_field->render(renderer);
|
||||
if (m_text_field) {
|
||||
m_text_field->render(renderer);
|
||||
}
|
||||
|
||||
for (auto it = m_messages.rbegin(); it != m_messages.rend(); ++it) {
|
||||
if (!it->label) {
|
||||
continue;
|
||||
@@ -111,7 +120,7 @@ void ChatBox::on_render(Renderer& renderer) {
|
||||
}
|
||||
}
|
||||
bool ChatBox::handle_text_input_event(const TextInputEvent& e) {
|
||||
if (m_text_field->handle_text_input_event(e)) {
|
||||
if (m_text_field && m_text_field->handle_text_input_event(e)) {
|
||||
return true;
|
||||
}
|
||||
return Widget::handle_text_input_event(e);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Cubed/scene/scene_manager.hpp"
|
||||
#include "Cubed/ui/button.hpp"
|
||||
#include "Cubed/ui/column_layout.hpp"
|
||||
#include "Cubed/ui/default_image.hpp"
|
||||
#include "Cubed/ui/image.hpp"
|
||||
#include "Cubed/ui/text_field.hpp"
|
||||
namespace Cubed {
|
||||
@@ -48,7 +49,10 @@ void HostGameUI::init() {
|
||||
auto& text_seed = layout.add_child<TextField>();
|
||||
text_seed.set_show_text(tr("hostgame.world_seed"));
|
||||
text_seed.set_app(&m_scene.scene_manager().app());
|
||||
text_seed.set_default_image(texture_manager);
|
||||
std::unique_ptr<Image> back = std::make_unique<Image>(&text_seed);
|
||||
back->set_fill(true).set_image(DEFAULT_TEXT_FIELD_IMAGE,
|
||||
texture_manager);
|
||||
text_seed.set_background(std::move(back));
|
||||
text_seed.set_on_finish([this, &text_seed]() {
|
||||
unsigned seed = 0;
|
||||
auto& text = text_seed.input_text();
|
||||
@@ -67,7 +71,10 @@ void HostGameUI::init() {
|
||||
}
|
||||
{
|
||||
auto& text_port = layout.add_child<TextField>();
|
||||
text_port.set_default_image(texture_manager);
|
||||
std::unique_ptr<Image> back = std::make_unique<Image>(&text_port);
|
||||
back->set_fill(true).set_image(DEFAULT_TEXT_FIELD_IMAGE,
|
||||
texture_manager);
|
||||
text_port.set_background(std::move(back));
|
||||
text_port.set_show_text(tr("hostgame.port"));
|
||||
text_port.set_app(&m_scene.scene_manager().app());
|
||||
text_port.set_on_finish([this, &text_port]() {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Cubed/scene/join_game_scene.hpp"
|
||||
#include "Cubed/ui/button.hpp"
|
||||
#include "Cubed/ui/column_layout.hpp"
|
||||
#include "Cubed/ui/default_image.hpp"
|
||||
#include "Cubed/ui/text_field.hpp"
|
||||
namespace Cubed {
|
||||
JoinGameUI::JoinGameUI(JoinGameScene& scene) : m_scene(scene) {}
|
||||
@@ -45,7 +46,10 @@ void JoinGameUI::init() {
|
||||
{
|
||||
auto& text_ip = layout.add_child<TextField>();
|
||||
text_ip.set_show_text(tr("joingame.server_ip"));
|
||||
text_ip.set_default_image(texture_manager);
|
||||
std::unique_ptr<Image> back = std::make_unique<Image>(&text_ip);
|
||||
back->set_fill(true).set_image(DEFAULT_TEXT_FIELD_IMAGE,
|
||||
texture_manager);
|
||||
text_ip.set_background(std::move(back));
|
||||
text_ip.set_app(&m_scene.scene_manager().app());
|
||||
text_ip.set_on_finish([this, &text_ip]() {
|
||||
auto& ip = text_ip.input_text();
|
||||
|
||||
@@ -11,11 +11,6 @@ constexpr float DELTA_CUROUR_HEIGHT = 10.0f;
|
||||
|
||||
namespace Cubed {
|
||||
TextField::TextField(Widget* parent) : Widget(parent) {
|
||||
|
||||
m_background = std::make_unique<Image>(this);
|
||||
m_background->set_fill(true);
|
||||
m_background->set_anchor(Anchor::TOP_LEFT);
|
||||
|
||||
m_foreground = std::make_unique<Label>(this);
|
||||
m_foreground->set_anchor(Anchor::CENTER_LEFT);
|
||||
m_foreground->set_offset({10, 0});
|
||||
@@ -62,6 +57,14 @@ void TextField::on_render(Renderer& renderer) {
|
||||
}
|
||||
}
|
||||
void TextField::on_update(float dt) {
|
||||
|
||||
if (m_fill_height) {
|
||||
m_height = m_parent ? m_parent->height() : m_window_height;
|
||||
}
|
||||
if (m_fill_width) {
|
||||
m_width = m_parent ? m_parent->width() : m_window_width;
|
||||
}
|
||||
|
||||
m_cursor_timer += dt;
|
||||
if (m_cursor_timer >= CURSOR_INTERVAL) {
|
||||
m_cursor_timer = 0.0f;
|
||||
@@ -105,11 +108,24 @@ void TextField::update_input_area() {
|
||||
|
||||
TextField& TextField::set_scale(float scale) {
|
||||
m_scale = scale;
|
||||
m_cursor->set_height(std::max(1.0f, height() - DELTA_CUROUR_HEIGHT));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
float TextField::width() const { return m_width * m_scale; }
|
||||
float TextField::height() const { return m_height * m_scale; }
|
||||
float TextField::width() const {
|
||||
|
||||
if (m_fill_width) {
|
||||
return m_width;
|
||||
}
|
||||
return m_width * m_scale;
|
||||
}
|
||||
float TextField::height() const {
|
||||
if (m_fill_height) {
|
||||
return m_height;
|
||||
}
|
||||
return m_height * m_scale;
|
||||
}
|
||||
|
||||
TextField& TextField::set_width(float width) {
|
||||
m_width = width;
|
||||
@@ -127,14 +143,10 @@ TextField& TextField::set_show_text(const std::string& text) {
|
||||
update_show_text();
|
||||
return *this;
|
||||
}
|
||||
TextField& TextField::set_background_image(const std::string& path,
|
||||
TextureManager& texture_manager) {
|
||||
m_background->set_image(path, texture_manager);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextField& TextField::set_default_image(TextureManager& texture_manager) {
|
||||
return set_background_image(DEFAULT_TEXT_FIELD_IMAGE, texture_manager);
|
||||
TextField& TextField::set_background(std::unique_ptr<Widget> background) {
|
||||
m_background = std::move(background);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextField& TextField::set_auto_scale(bool auto_scale) {
|
||||
@@ -164,6 +176,15 @@ TextField& TextField::clear_input() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextField& TextField::set_fill_width(bool fill) {
|
||||
m_fill_width = fill;
|
||||
return *this;
|
||||
}
|
||||
TextField& TextField::set_fill_height(bool fill) {
|
||||
m_fill_height = fill;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void TextField::start_typing() {
|
||||
if (m_app) {
|
||||
m_app->start_text_input();
|
||||
|
||||
@@ -31,14 +31,21 @@ void WorldUIManager::init() {
|
||||
m_widgets.try_emplace("crosshair", &crosshair);
|
||||
|
||||
auto& chat_box = m_root_widget->add_child<ChatBox>();
|
||||
auto text_field = std::make_unique<TextField>(&chat_box);
|
||||
text_field->set_anchor(Anchor::BOTTOM_LEFT);
|
||||
auto rect = std::make_unique<Rect>(text_field.get());
|
||||
rect->set_color(Color::GRAY).set_alpha(0.6f).set_fill(true);
|
||||
text_field->set_background(std::move(rect))
|
||||
.set_app(&m_scene.scene_manager().app())
|
||||
.set_fill_width(true)
|
||||
.set_visible(false);
|
||||
chat_box.set_text_field(std::move(text_field));
|
||||
chat_box.set_spacing(15);
|
||||
chat_box.set_anchor(Anchor::BOTTOM_LEFT);
|
||||
chat_box.set_offset({0, -10});
|
||||
chat_box.set_width(200);
|
||||
chat_box.set_scale(2.0f);
|
||||
chat_box.set_text_scale(0.6f);
|
||||
chat_box.set_d_image(m_scene.scene_manager().app().texture_manager());
|
||||
chat_box.set_app(&m_scene.scene_manager().app());
|
||||
chat_box.set_on_finish([this, &chat_box]() {
|
||||
ChatMessage message{m_scene.client_world().get_player().get_name(),
|
||||
std::move(chat_box.get_input_text()), 0};
|
||||
|
||||
Reference in New Issue
Block a user