feat(ui): add button enable/disable and reset on re-enter

Prevent double-clicking on buttons that push new scenes by disabling them on click and re-enabling when the UI manager's on_re_enter is called.
This commit is contained in:
2026-07-15 15:47:20 +08:00
parent 7c991f9f5e
commit 94d3989e0a
8 changed files with 50 additions and 15 deletions

View File

@@ -31,7 +31,7 @@ public:
Button& set_text(const std::string& text); Button& set_text(const std::string& text);
Button& set_auto_scale(bool auto_scale); Button& set_auto_scale(bool auto_scale);
Button& set_enable(bool enable);
float scale() const; float scale() const;
template <typename F> Button& set_clicked(F&& f) { template <typename F> Button& set_clicked(F&& f) {
m_clicked = std::forward<F>(f); m_clicked = std::forward<F>(f);
@@ -49,6 +49,7 @@ private:
std::unique_ptr<Image> m_background; std::unique_ptr<Image> m_background;
std::unique_ptr<Label> m_foreground; std::unique_ptr<Label> m_foreground;
bool m_hovered = false; bool m_hovered = false;
bool m_enable = true;
float m_width = NORMAL_BUTTON_WIDTH; float m_width = NORMAL_BUTTON_WIDTH;
float m_height = NORMAL_BUTTON_HEIGHT; float m_height = NORMAL_BUTTON_HEIGHT;
float m_scale = DEFAULT_SCALE; float m_scale = DEFAULT_SCALE;

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Cubed/ui/button.hpp"
#include "Cubed/ui/ui_manager.hpp" #include "Cubed/ui/ui_manager.hpp"
namespace Cubed { namespace Cubed {
@@ -15,8 +16,10 @@ public:
~MainMenuUIManager(); ~MainMenuUIManager();
void init() override; void init() override;
void on_re_enter();
private: private:
MainMenuScene& m_scene; MainMenuScene& m_scene;
std::vector<Button*> m_pending_enable;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Cubed/ui/button.hpp"
#include "Cubed/ui/ui_manager.hpp" #include "Cubed/ui/ui_manager.hpp"
namespace Cubed { namespace Cubed {
class WorldScene; class WorldScene;
@@ -11,8 +12,10 @@ public:
PauseMenuUIManager& operator=(PauseMenuUIManager&&) = delete; PauseMenuUIManager& operator=(PauseMenuUIManager&&) = delete;
PauseMenuUIManager(WorldScene& scene); PauseMenuUIManager(WorldScene& scene);
void init() override; void init() override;
void on_re_enter();
private: private:
WorldScene& m_scene; WorldScene& m_scene;
std::vector<Button*> m_pending_enable;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -21,6 +21,7 @@ bool MainMenuScene::handle_event(const Event& e) {
void MainMenuScene::on_enter() { m_ui_manager.init(); } void MainMenuScene::on_enter() { m_ui_manager.init(); }
void MainMenuScene::on_leave() {} void MainMenuScene::on_leave() {}
void MainMenuScene::on_re_enter() { void MainMenuScene::on_re_enter() {
m_ui_manager.on_re_enter();
auto width = m_scene_manager.app().renderer().window_width(); auto width = m_scene_manager.app().renderer().window_width();
auto height = m_scene_manager.app().renderer().window_height(); auto height = m_scene_manager.app().renderer().window_height();

View File

@@ -131,6 +131,7 @@ void WorldScene::on_leave() {
} }
void WorldScene::on_re_enter() { void WorldScene::on_re_enter() {
m_pasue_menu.on_re_enter();
m_client_world.reload_config(); m_client_world.reload_config();
auto width = m_scene_manager.app().renderer().window_width(); auto width = m_scene_manager.app().renderer().window_width();
auto height = m_scene_manager.app().renderer().window_height(); auto height = m_scene_manager.app().renderer().window_height();

View File

@@ -28,11 +28,13 @@ void Button::on_render(Renderer& renderer) {
} }
bool Button::handle_mouse_move_event(const MouseMoveEvent& e) { bool Button::handle_mouse_move_event(const MouseMoveEvent& e) {
auto p = pos(); if (m_enable) {
if (e.xpos >= p.x && e.xpos <= p.x + width() && e.ypos >= p.y && auto p = pos();
e.ypos <= p.y + height()) { if (e.xpos >= p.x && e.xpos <= p.x + width() && e.ypos >= p.y &&
m_hovered = true; e.ypos <= p.y + height()) {
return true; m_hovered = true;
return true;
}
} }
m_hovered = false; m_hovered = false;
@@ -40,7 +42,7 @@ bool Button::handle_mouse_move_event(const MouseMoveEvent& e) {
} }
bool Button::handle_mouse_button_event(const MouseButtonEvent& e) { bool Button::handle_mouse_button_event(const MouseButtonEvent& e) {
if (e.action == KeyAction::PRESS && e.key == MouseKey::LEFT_BUTTON) { if (e.action == KeyAction::PRESS && e.key == MouseKey::LEFT_BUTTON) {
if (m_hovered && m_clicked) { if (m_hovered && m_clicked && m_enable) {
m_clicked(); m_clicked();
return true; return true;
@@ -91,7 +93,10 @@ Button& Button::set_auto_scale(bool auto_scale) {
m_auto_scale = auto_scale; m_auto_scale = auto_scale;
return *this; return *this;
} }
Button& Button::set_enable(bool enable) {
m_enable = enable;
return *this;
}
void Button::update_text_scale() { void Button::update_text_scale() {
if (!m_auto_scale) { if (!m_auto_scale) {
m_foreground->set_scale(TEXT_SCALE); m_foreground->set_scale(TEXT_SCALE);

View File

@@ -33,18 +33,22 @@ void MainMenuUIManager::init() {
start_game_button.set_background_image("texture/ui/button001.png", start_game_button.set_background_image("texture/ui/button001.png",
texture_manager); texture_manager);
start_game_button.set_text("Start Game"); start_game_button.set_text("Start Game");
start_game_button.set_clicked([this]() { start_game_button.set_clicked([this, &start_game_button]() {
start_game_button.set_enable(false);
m_scene.scene_manager().request_push(SceneType::WORLD); m_scene.scene_manager().request_push(SceneType::WORLD);
}); });
m_pending_enable.emplace_back(&start_game_button);
} }
{ {
auto& button = layout.add_child<Button>(); auto& button = layout.add_child<Button>();
button.set_default_image(texture_manager); button.set_default_image(texture_manager);
button.set_text("Settings"); button.set_text("Settings");
button.set_clicked([this]() { button.set_clicked([this, &button]() {
button.set_enable(false);
m_scene.scene_manager().request_push(SceneType::SETTINGS); m_scene.scene_manager().request_push(SceneType::SETTINGS);
}); });
m_pending_enable.emplace_back(&button);
} }
{ {
@@ -53,9 +57,11 @@ void MainMenuUIManager::init() {
button.set_background_image("texture/ui/button001.png", button.set_background_image("texture/ui/button001.png",
texture_manager); texture_manager);
button.set_text("Credits"); button.set_text("Credits");
button.set_clicked([this]() { button.set_clicked([this, &button]() {
button.set_enable(false);
m_scene.scene_manager().request_push(SceneType::CREDITS); m_scene.scene_manager().request_push(SceneType::CREDITS);
}); });
m_pending_enable.emplace_back(&button);
} }
{ {
auto& exit_game = layout.add_child<Button>(); auto& exit_game = layout.add_child<Button>();
@@ -87,4 +93,10 @@ void MainMenuUIManager::init() {
m_root_widget = std::move(image); m_root_widget = std::move(image);
} }
void MainMenuUIManager::on_re_enter() {
for (Button* b : m_pending_enable) {
b->set_enable(true);
}
}
} // namespace Cubed } // namespace Cubed

View File

@@ -32,9 +32,11 @@ void PauseMenuUIManager::init() {
auto& button = layout.add_child<Button>(); auto& button = layout.add_child<Button>();
button.set_default_image(texture_manager); button.set_default_image(texture_manager);
button.set_text("Settings"); button.set_text("Settings");
button.set_clicked([this]() { button.set_clicked([this, &button]() {
button.set_enable(false);
m_scene.scene_manager().request_push(SceneType::SETTINGS); m_scene.scene_manager().request_push(SceneType::SETTINGS);
}); });
m_pending_enable.emplace_back(&button);
} }
{ {
@@ -43,11 +45,18 @@ void PauseMenuUIManager::init() {
back_main.set_background_image("texture/ui/button001.png", back_main.set_background_image("texture/ui/button001.png",
texture_manager); texture_manager);
back_main.set_text("Return to Menu"); back_main.set_text("Return to Menu");
back_main.set_clicked( back_main.set_clicked([this, &back_main]() {
[this]() { m_scene.scene_manager().request_pop(); }); back_main.set_enable(false);
m_scene.scene_manager().request_pop();
});
m_pending_enable.emplace_back(&back_main);
} }
m_root_widget = std::move(rect); m_root_widget = std::move(rect);
} }
void PauseMenuUIManager::on_re_enter() {
for (Button* b : m_pending_enable) {
b->set_enable(true);
}
}
} // namespace Cubed } // namespace Cubed