feat(ui): add item slot tooltip and make window size static

This commit is contained in:
2026-07-21 19:51:04 +08:00
parent 68f7924f07
commit 234746babb
16 changed files with 73 additions and 34 deletions

View File

@@ -12,4 +12,7 @@ enum class Anchor {
BOTTOM_LEFT, BOTTOM_LEFT,
BOTTOM_CENTER, BOTTOM_CENTER,
BOTTOM_RIGHT, BOTTOM_RIGHT,
FOLLOW_MOUSE
}; };

View File

@@ -2,6 +2,7 @@
#include "Cubed/gameplay/block.hpp" #include "Cubed/gameplay/block.hpp"
#include "Cubed/ui/image.hpp" #include "Cubed/ui/image.hpp"
#include "Cubed/ui/label.hpp"
#include "Cubed/ui/widget.hpp" #include "Cubed/ui/widget.hpp"
namespace Cubed { namespace Cubed {
class TextureManager; class TextureManager;
@@ -21,9 +22,13 @@ private:
static constexpr const char* DEFAULT_SLOT_PATH = "texture/ui/slot.png"; static constexpr const char* DEFAULT_SLOT_PATH = "texture/ui/slot.png";
void on_render(Renderer& renderer) override; void on_render(Renderer& renderer) override;
void on_update(float dt) override; void on_update(float dt) override;
bool handle_mouse_move_event(const MouseMoveEvent& e) override;
bool handle_window_resize_event(const WindowResizeEvent& e) override;
std::unique_ptr<Image> m_background; std::unique_ptr<Image> m_background;
std::unique_ptr<Image> m_foreground; std::unique_ptr<Image> m_foreground;
std::unique_ptr<Label> m_label;
BlockType m_block_type; BlockType m_block_type;
float m_scale = 1.0f; float m_scale = 1.0f;
bool m_hovered = false;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -31,7 +31,7 @@ public:
virtual void render(Renderer& renderer); virtual void render(Renderer& renderer);
virtual Widget& set_anchor(Anchor anchor); virtual Widget& set_anchor(Anchor anchor);
virtual Widget& set_offset(glm::ivec2 offset); virtual Widget& set_offset(glm::ivec2 offset);
virtual Widget& set_window_size(int width, int height); static void set_window_size(int width, int height);
virtual Widget& set_visible(bool visible); virtual Widget& set_visible(bool visible);
// Returns the final display size // Returns the final display size
@@ -65,8 +65,8 @@ public:
protected: protected:
Widget* m_parent = nullptr; Widget* m_parent = nullptr;
float m_window_height = 0.0f; static inline float m_window_height = 0.0f;
float m_window_width = 0.0f; static inline float m_window_width = 0.0f;
// Center is at the top-left corner, position is at the top-left corner // Center is at the top-left corner, position is at the top-left corner
Anchor m_anchor = Anchor::TOP_LEFT; Anchor m_anchor = Anchor::TOP_LEFT;
@@ -99,6 +99,7 @@ private:
*/ */
std::array<std::unique_ptr<Widget>, 4> m_border; std::array<std::unique_ptr<Widget>, 4> m_border;
TraversalOrder m_order = TraversalOrder::BACK_TO_FRONT; TraversalOrder m_order = TraversalOrder::BACK_TO_FRONT;
glm::vec2 m_mouse_pos;
float m_width = 0.0f; float m_width = 0.0f;
float m_height = 0.0f; float m_height = 0.0f;
}; };

View File

@@ -611,7 +611,7 @@ void App::handle_window_focus(bool focused) {
} }
void App::handle_window_resize(int width, int height) { void App::handle_window_resize(int width, int height) {
Widget::set_window_size(width, height);
dispatch_event(WindowResizeEvent{width, height}); dispatch_event(WindowResizeEvent{width, height});
d_rep("window_size", "Window W: {} H: {}", width, height); d_rep("window_size", "Window W: {} H: {}", width, height);
Logger::info("Window Reshape W: {} H: {}", width, height); Logger::info("Window Reshape W: {} H: {}", width, height);

View File

@@ -19,12 +19,11 @@ std::unique_ptr<DebugCollector>& DebugCollector::get_ptr() {
return instance; return instance;
} }
void DebugCollector::destory() { get_ptr().reset(); } void DebugCollector::destory() { get_ptr().reset(); }
void DebugCollector::init(int width, int height) { void DebugCollector::init(int, int) {
constexpr float SCALE = 0.7f; constexpr float SCALE = 0.7f;
constexpr Color COLOR = Color::GRAY; constexpr Color COLOR = Color::GRAY;
constexpr float ALPHA = 0.6f; constexpr float ALPHA = 0.6f;
m_widget.set_window_size(width, height);
m_widget.set_spacing(15); m_widget.set_spacing(15);
m_widget.set_anchor(Anchor::TOP_LEFT); m_widget.set_anchor(Anchor::TOP_LEFT);
m_widget.set_offset({0, 5}); m_widget.set_offset({0, 5});

View File

@@ -13,14 +13,12 @@ namespace Cubed {
CreditsUI::CreditsUI(CreditsScene& scene) : m_scene(scene) {} CreditsUI::CreditsUI(CreditsScene& scene) : m_scene(scene) {}
void CreditsUI::init() { void CreditsUI::init() {
auto& renderer = m_scene.scene_manager().app().renderer();
auto image = std::make_unique<Image>(nullptr); auto image = std::make_unique<Image>(nullptr);
image image
->set_image("texture/ui/background.png", ->set_image("texture/ui/background.png",
m_scene.scene_manager().app().texture_manager(), false) m_scene.scene_manager().app().texture_manager(), false)
.set_anchor(Anchor::TOP_LEFT) .set_anchor(Anchor::TOP_LEFT)
.set_window_size(renderer.window_width(), renderer.window_height())
.set_fill_parent(true); .set_fill_parent(true);
auto& rect = image->add_child<Rect>(); auto& rect = image->add_child<Rect>();

View File

@@ -10,10 +10,8 @@ ErrorUI::ErrorUI(WorldScene& scene) : m_scene(scene) {}
void ErrorUI::init() { void ErrorUI::init() {
auto bi = std::make_unique<Image>(nullptr); auto bi = std::make_unique<Image>(nullptr);
auto& renderer = m_scene.scene_manager().app().renderer();
auto& texture_manager = m_scene.scene_manager().app().texture_manager(); auto& texture_manager = m_scene.scene_manager().app().texture_manager();
bi->set_window_size(renderer.window_width(), renderer.window_height());
bi->set_anchor(Anchor::TOP_LEFT); bi->set_anchor(Anchor::TOP_LEFT);
bi->set_image("texture/ui/background.png", texture_manager, false); bi->set_image("texture/ui/background.png", texture_manager, false);
bi->set_fill_parent(true); bi->set_fill_parent(true);

View File

@@ -13,10 +13,8 @@ namespace Cubed {
HostGameUI::HostGameUI(HostGameScene& scene) : m_scene(scene) {} HostGameUI::HostGameUI(HostGameScene& scene) : m_scene(scene) {}
void HostGameUI::init() { void HostGameUI::init() {
auto bi = std::make_unique<Image>(nullptr); auto bi = std::make_unique<Image>(nullptr);
auto& renderer = m_scene.scene_manager().app().renderer();
auto& texture_manager = m_scene.scene_manager().app().texture_manager(); auto& texture_manager = m_scene.scene_manager().app().texture_manager();
bi->set_window_size(renderer.window_width(), renderer.window_height());
bi->set_anchor(Anchor::TOP_LEFT); bi->set_anchor(Anchor::TOP_LEFT);
bi->set_image("texture/ui/background.png", texture_manager, false); bi->set_image("texture/ui/background.png", texture_manager, false);
bi->set_fill_parent(true); bi->set_fill_parent(true);

View File

@@ -11,10 +11,8 @@ InventoryUI::InventoryUI(WorldScene& scene) : m_scene(scene) {}
void InventoryUI::init() { void InventoryUI::init() {
auto back = std::make_unique<Rect>(nullptr); auto back = std::make_unique<Rect>(nullptr);
auto& renderer = m_scene.scene_manager().app().renderer();
auto& texture_manager = m_scene.scene_manager().app().texture_manager();
back->set_window_size(renderer.window_width(), renderer.window_height()); auto& texture_manager = m_scene.scene_manager().app().texture_manager();
back->set_anchor(Anchor::TOP_LEFT); back->set_anchor(Anchor::TOP_LEFT);
back->set_color(Color::BLACK).set_alpha(0.7f); back->set_color(Color::BLACK).set_alpha(0.7f);
back->set_fill_parent(true); back->set_fill_parent(true);

View File

@@ -8,6 +8,10 @@ ItemSlot::ItemSlot(Widget* parent) : Widget(parent) {
m_foreground->set_texture(nullptr, false).set_fill_parent(true); m_foreground->set_texture(nullptr, false).set_fill_parent(true);
Widget::set_width(DEFAULT_WIDTH); Widget::set_width(DEFAULT_WIDTH);
Widget::set_height(DEFAULT_HEIGHT); Widget::set_height(DEFAULT_HEIGHT);
m_label = std::make_unique<Label>(this);
m_label->set_scale(0.6f);
m_label->set_anchor(Anchor::FOLLOW_MOUSE);
m_label->set_visible(false);
} }
ItemSlot& ItemSlot::set_default_background(TextureManager& texture_manager) { ItemSlot& ItemSlot::set_default_background(TextureManager& texture_manager) {
@@ -22,6 +26,7 @@ ItemSlot& ItemSlot::set_scale(float scale) {
ItemSlot& ItemSlot::set_item(BlockType id, const Texture* texture) { ItemSlot& ItemSlot::set_item(BlockType id, const Texture* texture) {
m_foreground->set_texture(texture, false); m_foreground->set_texture(texture, false);
m_block_type = id; m_block_type = id;
m_label->set_text(BlockManager::name_form_id(id));
return *this; return *this;
} }
float ItemSlot::width() const { float ItemSlot::width() const {
@@ -45,6 +50,9 @@ void ItemSlot::on_render(Renderer& renderer) {
if (m_foreground) { if (m_foreground) {
m_foreground->render(renderer); m_foreground->render(renderer);
} }
if (m_label) {
m_label->render(renderer);
}
} }
void ItemSlot::on_update(float dt) { void ItemSlot::on_update(float dt) {
@@ -54,7 +62,44 @@ void ItemSlot::on_update(float dt) {
if (m_foreground) { if (m_foreground) {
m_foreground->update(dt); m_foreground->update(dt);
} }
if (m_label) {
m_label->update(dt);
}
Widget::on_update(dt); Widget::on_update(dt);
} }
bool ItemSlot::handle_mouse_move_event(const MouseMoveEvent& e) {
auto p = pos();
if (e.xpos >= p.x && e.xpos <= p.x + width() && e.ypos >= p.y &&
e.ypos <= p.y + height()) {
m_hovered = true;
m_label->set_visible(true);
} else {
m_hovered = false;
m_label->set_visible(false);
}
if (m_label && m_label->handle_mouse_move_event(e)) {
return true;
}
if (m_foreground && m_foreground->handle_mouse_move_event(e)) {
return true;
}
if (m_background && m_background->handle_mouse_move_event(e)) {
return true;
}
return Widget::handle_mouse_move_event(e);
}
bool ItemSlot::handle_window_resize_event(const WindowResizeEvent& e) {
if (m_label && m_label->handle_window_resize_event(e)) {
}
if (m_foreground && m_foreground->handle_window_resize_event(e)) {
}
if (m_background && m_background->handle_window_resize_event(e)) {
}
return Widget::handle_window_resize_event(e);
}
} // namespace Cubed } // namespace Cubed

View File

@@ -11,10 +11,8 @@ namespace Cubed {
JoinGameUI::JoinGameUI(JoinGameScene& scene) : m_scene(scene) {} JoinGameUI::JoinGameUI(JoinGameScene& scene) : m_scene(scene) {}
void JoinGameUI::init() { void JoinGameUI::init() {
auto bi = std::make_unique<Image>(nullptr); auto bi = std::make_unique<Image>(nullptr);
auto& renderer = m_scene.scene_manager().app().renderer();
auto& texture_manager = m_scene.scene_manager().app().texture_manager(); auto& texture_manager = m_scene.scene_manager().app().texture_manager();
bi->set_window_size(renderer.window_width(), renderer.window_height());
bi->set_anchor(Anchor::TOP_LEFT); bi->set_anchor(Anchor::TOP_LEFT);
bi->set_image("texture/ui/background.png", texture_manager, false); bi->set_image("texture/ui/background.png", texture_manager, false);
bi->set_fill_parent(true); bi->set_fill_parent(true);

View File

@@ -2,7 +2,6 @@
#include "Cubed/app.hpp" #include "Cubed/app.hpp"
#include "Cubed/localization.hpp" #include "Cubed/localization.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/main_menu_scene.hpp" #include "Cubed/scene/main_menu_scene.hpp"
#include "Cubed/scene/scene_manager.hpp" #include "Cubed/scene/scene_manager.hpp"
#include "Cubed/ui/button.hpp" #include "Cubed/ui/button.hpp"
@@ -21,13 +20,10 @@ void MainMenuUIManager::init() {
image->set_fill_parent(true); image->set_fill_parent(true);
image->set_anchor(Anchor::TOP_LEFT); image->set_anchor(Anchor::TOP_LEFT);
image->set_image("texture/ui/background.png", texture_manager, false); image->set_image("texture/ui/background.png", texture_manager, false);
auto& renderer = m_scene.scene_manager().app().renderer();
image->set_window_size(renderer.window_width(), renderer.window_height());
auto& layout = image->add_child<ColumnLayout>(); auto& layout = image->add_child<ColumnLayout>();
layout.set_spacing(20); layout.set_spacing(20);
layout.set_anchor(Anchor::CENTER); layout.set_anchor(Anchor::CENTER);
layout.set_window_size(renderer.window_width(), renderer.window_height());
{ {
auto& start_game_button = layout.add_child<Button>(); auto& start_game_button = layout.add_child<Button>();

View File

@@ -1,6 +1,5 @@
#include "Cubed/app.hpp" #include "Cubed/app.hpp"
#include "Cubed/localization.hpp" #include "Cubed/localization.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/scene_manager.hpp" #include "Cubed/scene/scene_manager.hpp"
#include "Cubed/scene/world_scene.hpp" #include "Cubed/scene/world_scene.hpp"
#include "Cubed/ui/button.hpp" #include "Cubed/ui/button.hpp"
@@ -16,8 +15,6 @@ void PauseMenuUIManager::init() {
rect->set_color(Color::BLACK); rect->set_color(Color::BLACK);
rect->set_alpha(0.7f); rect->set_alpha(0.7f);
rect->set_anchor(Anchor::TOP_LEFT); rect->set_anchor(Anchor::TOP_LEFT);
auto& renderer = m_scene.scene_manager().app().renderer();
rect->set_window_size(renderer.window_width(), renderer.window_height());
auto& texture_manager = m_scene.scene_manager().app().texture_manager(); auto& texture_manager = m_scene.scene_manager().app().texture_manager();
auto& layout = rect->add_child<ColumnLayout>(); auto& layout = rect->add_child<ColumnLayout>();
layout.set_anchor(Anchor::CENTER); layout.set_anchor(Anchor::CENTER);

View File

@@ -15,10 +15,8 @@ namespace Cubed {
SettingsUI::SettingsUI(SettingsScene& scene) : m_scene(scene) {} SettingsUI::SettingsUI(SettingsScene& scene) : m_scene(scene) {}
void SettingsUI::init() { void SettingsUI::init() {
auto bi = std::make_unique<Image>(nullptr); auto bi = std::make_unique<Image>(nullptr);
auto& renderer = m_scene.scene_manager().app().renderer();
auto& texture_manager = m_scene.scene_manager().app().texture_manager(); auto& texture_manager = m_scene.scene_manager().app().texture_manager();
bi->set_window_size(renderer.window_width(), renderer.window_height());
bi->set_anchor(Anchor::TOP_LEFT); bi->set_anchor(Anchor::TOP_LEFT);
bi->set_image("texture/ui/background.png", texture_manager, false); bi->set_image("texture/ui/background.png", texture_manager, false);
bi->set_fill_parent(true); bi->set_fill_parent(true);

View File

@@ -109,8 +109,16 @@ glm::vec2 Widget::compute_position() const {
case Anchor::BOTTOM_RIGHT: case Anchor::BOTTOM_RIGHT:
pos = {parent_w - W, parent_h - H}; pos = {parent_w - W, parent_h - H};
break; break;
case Anchor::FOLLOW_MOUSE:
pos = m_mouse_pos;
if (pos.x + W > m_window_width) {
pos.x -= W;
}
if (pos.y + H > m_window_height) {
pos.y -= H;
}
} }
if (m_parent) { if (m_parent && m_anchor != Anchor::FOLLOW_MOUSE) {
pos += m_parent->pos(); pos += m_parent->pos();
} }
pos += m_offset; pos += m_offset;
@@ -154,10 +162,10 @@ Widget& Widget::set_offset(glm::ivec2 offset) {
m_offset = offset; m_offset = offset;
return *this; return *this;
} }
Widget& Widget::set_window_size(int width, int height) { void Widget::set_window_size(int width, int height) {
m_window_height = height; m_window_height = height;
m_window_width = width; m_window_width = width;
return *this; return;
} }
Widget& Widget::set_visible(bool visible) { Widget& Widget::set_visible(bool visible) {
@@ -269,8 +277,6 @@ bool Widget::handle_mouse_wheel_event(const MouseWheelEvent& e) {
} }
bool Widget::handle_window_resize_event(const WindowResizeEvent& e) { bool Widget::handle_window_resize_event(const WindowResizeEvent& e) {
set_window_size(e.width, e.height);
if (m_order == TraversalOrder::BACK_TO_FRONT) { if (m_order == TraversalOrder::BACK_TO_FRONT) {
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if ((*it)->handle_window_resize_event(e)) { if ((*it)->handle_window_resize_event(e)) {
@@ -288,6 +294,8 @@ bool Widget::handle_window_resize_event(const WindowResizeEvent& e) {
} }
bool Widget::handle_mouse_move_event(const MouseMoveEvent& e) { bool Widget::handle_mouse_move_event(const MouseMoveEvent& e) {
m_mouse_pos.x = e.xpos;
m_mouse_pos.y = e.ypos;
if (m_order == TraversalOrder::BACK_TO_FRONT) { if (m_order == TraversalOrder::BACK_TO_FRONT) {
for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
if ((*it)->handle_mouse_move_event(e)) { if ((*it)->handle_mouse_move_event(e)) {

View File

@@ -17,10 +17,7 @@ void WorldUIManager::init() {
m_root_widget = std::make_unique<Widget>(nullptr); m_root_widget = std::make_unique<Widget>(nullptr);
m_root_widget->set_fill_parent(true); m_root_widget->set_fill_parent(true);
auto& renderer = m_scene.scene_manager().app().renderer();
m_root_widget->set_window_size(renderer.window_width(),
renderer.window_height());
auto& texture_manager = m_scene.scene_manager().app().texture_manager(); auto& texture_manager = m_scene.scene_manager().app().texture_manager();
auto& crosshair = m_root_widget->add_child<Image>(); auto& crosshair = m_root_widget->add_child<Image>();