Add menu stuff

This commit is contained in:
zbyv 2026-03-11 20:07:02 +01:00
parent 3e284af672
commit b6f6b28c98
4 changed files with 246 additions and 0 deletions

View File

@ -199,6 +199,12 @@ void gui::Context::DrawText(std::string_view text, const glm::vec2& pos, uint32_
} }
} }
void gui::Context::DrawTextAligned(std::string_view text, const glm::vec2& pos, const glm::vec2& align, uint32_t color, float scale)
{
auto size = MeasureText(text) * scale;
DrawText(text, pos + size * align, color, scale);
}
void gui::Context::Render() void gui::Context::Render()
{ {
va_.SetVBOData(vertices_.data(), vertices_.size() * sizeof(vertices_[0])); va_.SetVBOData(vertices_.data(), vertices_.size() * sizeof(vertices_[0]));

View File

@ -36,6 +36,7 @@ public:
glm::vec2 MeasureText(std::string_view text); glm::vec2 MeasureText(std::string_view text);
void DrawText(std::string_view text, const glm::vec2& pos, uint32_t color = 0xFFFFFFFF, float scale = 1.0f); void DrawText(std::string_view text, const glm::vec2& pos, uint32_t color = 0xFFFFFFFF, float scale = 1.0f);
void DrawTextAligned(std::string_view text, const glm::vec2& pos, const glm::vec2& align, uint32_t color = 0xFFFFFFFF, float scale = 1.0f);
void Render(); void Render();

120
src/gui/menu.cpp Normal file
View File

@ -0,0 +1,120 @@
#include "menu.hpp"
#include <cstring>
// Menu
void gui::Menu::Draw(Context& ctx, const glm::vec2& pos) const
{
// TODO: draw bg
glm::vec2 cursor = pos;
for (size_t i = 0; i < items_.size(); ++i)
{
items_[i]->Draw(DrawMenuItemArgs(ctx, cursor, focus_ == i));
cursor.y += items_[i]->GetSize().y;
}
}
void gui::Menu::Input(MenuInput in)
{
switch (in)
{
case MI_UP:
SwitchFocus(-1);
break;
case MI_DOWN:
SwitchFocus(1);
break;
default:
if (!items_.empty())
items_[focus_]->Input(in);
break;
}
}
glm::vec2 gui::Menu::MeasureSize() const
{
glm::vec2 size(0.0f);
for (const auto& item : items_)
{
const auto& itemsize = item->GetSize();
size.x = glm::max(size.x, itemsize.x);
size.y += itemsize.y;
}
return size;
}
void gui::Menu::SwitchFocus(int dir)
{
if (items_.empty())
return;
focus_ = (focus_ + items_.size() + dir) % items_.size();
}
// ButtonMenuItem
gui::ButtonMenuItem::ButtonMenuItem(std::string text, std::function<void()> click_cb)
: text_(std::move(text)), click_cb_(std::move(click_cb))
{
size_ = glm::vec2(500.0f, 30.0f);
}
void gui::ButtonMenuItem::Draw(const DrawMenuItemArgs& args) const
{
Super::Draw(args);
glm::vec2 center = args.pos + glm::vec2(0.0f, size_.y * 0.5f);
args.ctx.DrawTextAligned(text_, center, glm::vec2(0.0f, -0.5f), args.focused ? COLOR_FOCUSED : COLOR_INACTIVE);
}
void gui::ButtonMenuItem::Input(MenuInput in)
{
if (in == MI_ENTER && click_cb_)
click_cb_();
}
// SelectMenuItem
gui::SelectMenuItem::SelectMenuItem(std::string text, std::function<void()> click_cb,
std::function<void(int)> switch_cb)
: ButtonMenuItem(std::move(text), std::move(click_cb)), switch_cb_(std::move(switch_cb))
{
}
void gui::SelectMenuItem::Draw(const DrawMenuItemArgs& args) const
{
Super::Draw(args);
char buffer[128];
size_t len = snprintf(buffer, sizeof(buffer), "< %s >", select_text_.c_str());
glm::vec2 center_right = args.pos + glm::vec2(size_.x, size_.y * 0.5f);
args.ctx.DrawTextAligned(std::string_view(buffer, len), center_right, glm::vec2(-1.0f, -0.5f),
args.focused ? COLOR_FOCUSED : COLOR_INACTIVE);
}
void gui::SelectMenuItem::Input(MenuInput in)
{
switch (in)
{
case MI_LEFT:
if (switch_cb_)
switch_cb_(-1);
break;
case MI_RIGHT:
if (switch_cb_)
switch_cb_(1);
break;
default:
Super::Input(in);
break;
}
}

119
src/gui/menu.hpp Normal file
View File

@ -0,0 +1,119 @@
#pragma once
#include <vector>
#include <concepts>
#include "context.hpp"
namespace gui
{
enum MenuInput
{
MI_UP,
MI_DOWN,
MI_LEFT,
MI_RIGHT,
MI_BACK,
MI_ENTER,
};
class MenuItem;
struct DrawMenuItemArgs
{
Context& ctx;
glm::vec2 pos;
bool focused;
DrawMenuItemArgs(Context& ctx, const glm::vec2& pos, bool focused) : ctx(ctx), pos(pos), focused(focused) {}
};
class Menu
{
public:
Menu() = default;
template <std::derived_from<MenuItem> T, typename... TArgs>
T& Add(TArgs&&... args)
{
auto item = std::make_unique<T>(std::forward<TArgs>(args)...);
auto& item_ref = *item;
items_.emplace_back(std::move(item));
return item_ref;
}
void Draw(Context& ctx, const glm::vec2& pos) const;
void Input(MenuInput in);
glm::vec2 MeasureSize() const;
private:
void SwitchFocus(int dir);
private:
std::vector<std::unique_ptr<MenuItem>> items_;
size_t focus_ = 0;
};
class MenuItem
{
public:
constexpr static uint32_t COLOR_INACTIVE = 0xFFFFFFFF;
constexpr static uint32_t COLOR_FOCUSED = 0xFF00FFFF;
MenuItem() = default;
virtual void Draw(const DrawMenuItemArgs& args) const {}
virtual void Input(MenuInput in) {}
const glm::vec2& GetSize() const { return size_; }
virtual ~MenuItem() = default;
protected:
glm::vec2 size_;
};
class ButtonMenuItem : public MenuItem
{
public:
using Super = MenuItem;
ButtonMenuItem(std::string text, std::function<void()> click_cb);
virtual void Draw(const DrawMenuItemArgs& args) const override;
virtual void Input(MenuInput in) override;
virtual ~ButtonMenuItem() = default;
private:
std::string text_;
std::function<void()> click_cb_;
};
class SelectMenuItem : public ButtonMenuItem
{
public:
using Super = ButtonMenuItem;
SelectMenuItem(std::string text, std::function<void()> click_cb, std::function<void(int)> switch_cb);
virtual void Draw(const DrawMenuItemArgs& args) const override;
virtual void Input(MenuInput in) override;
void SetSelectionText(std::string select_text) { select_text_ = std::move(select_text); }
virtual ~SelectMenuItem() = default;
protected:
std::string select_text_;
std::function<void(int)> switch_cb_;
};
}