Merge branch 'main' into update-gfx-pipeline

This commit is contained in:
MihailRis
2025-06-28 14:18:53 +03:00
18 changed files with 409 additions and 118 deletions
+2
View File
@@ -89,6 +89,8 @@ namespace gui {
void updateTooltip(float delta);
void resetTooltip();
public:
static constexpr int CONTEXT_MENU_ZINDEX = 999;
GUI(Engine& engine);
~GUI();
+10 -22
View File
@@ -34,14 +34,12 @@ Button::Button(
const onaction& action,
glm::vec2 size
)
: Panel(gui, size, padding, 0) {
if (size.y < 0.0f) {
size = glm::vec2(
glm::max(padding.x + padding.z + text.length() * 8, size.x),
glm::max(padding.y + padding.w + 16, size.y)
);
: Panel(gui, size, padding, 0.0f) {
if (size.x < 0.0f || size.y < 0.0f) {
setContentSize({text.length() * 8, 16});
} else {
setSize(size);
}
setSize(size);
if (action) {
listenAction(action);
@@ -50,13 +48,12 @@ Button::Button(
label = std::make_shared<Label>(gui, text);
label->setAlign(Align::center);
label->setSize(
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
);
label->setSize(getContentSize());
label->setInteractive(false);
add(label);
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
setPressedColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.95f));
setHoverColor({0.05f, 0.1f, 0.15f, 0.75f});
setPressedColor({0.0f, 0.0f, 0.0f, 0.95f});
}
void Button::setText(std::wstring text) {
@@ -72,19 +69,10 @@ std::wstring Button::getText() const {
return L"";
}
Button* Button::textSupplier(wstringsupplier supplier) {
if (label) {
label->textSupplier(std::move(supplier));
}
return this;
}
void Button::refresh() {
Panel::refresh();
if (label) {
label->setSize(
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
);
label->setSize(getContentSize());
}
}
-2
View File
@@ -33,8 +33,6 @@ namespace gui {
virtual void setText(std::wstring text);
virtual std::wstring getText() const;
virtual Button* textSupplier(wstringsupplier supplier);
virtual void refresh() override;
};
}
+11
View File
@@ -27,6 +27,17 @@ int Panel::getMinLength() const {
return minLength;
}
void Panel::setContentSize(const glm::ivec2& contentSize) {
setSize(glm::vec2(
glm::max(padding.x + padding.z + contentSize.x, size.x),
glm::max(padding.y + padding.w + contentSize.y, size.y)
));
}
glm::vec2 Panel::getContentSize() const {
return size - glm::vec2(padding.z + padding.x, padding.w + padding.y);
}
void Panel::cropToContent() {
if (maxLength > 0.0f) {
setSize(glm::vec2(
+6
View File
@@ -27,6 +27,12 @@ namespace gui {
virtual void setMinLength(int value);
int getMinLength() const;
/// @brief .setSize wrapper automatically applying padding to size
/// @param size element size excluding padding
void setContentSize(const glm::ivec2& size);
/// @return element size excluding padding
glm::vec2 getContentSize() const;
protected:
int minLength = 0;
int maxLength = 0;
+84
View File
@@ -0,0 +1,84 @@
#include "SelectBox.hpp"
#include "Label.hpp"
#include "assets/Assets.hpp"
#include "graphics/ui/GUI.hpp"
#include "graphics/ui/elements/Panel.hpp"
#include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp"
using namespace gui;
SelectBox::SelectBox(
GUI& gui,
std::vector<Option>&& options,
Option selected,
int contentWidth,
const glm::vec4& padding
)
: Button(gui, selected.text, padding, nullptr, glm::vec2(contentWidth, -1)),
options(std::move(options)) {
listenAction([this](GUI& gui) {
auto panel = std::make_shared<Panel>(gui, getSize());
panel->setPos(calcPos() + glm::vec2(0, size.y));
for (const auto& option : this->options) {
auto button = std::make_shared<Button>(
gui, option.text, glm::vec4(10.0f), nullptr, glm::vec2(-1.0f)
);
button->listenFocus([this, option](GUI& gui) {
setSelected(option);
changeCallbacks.notify(gui, option.value);
});
panel->add(button);
}
panel->setZIndex(GUI::CONTEXT_MENU_ZINDEX);
gui.setFocus(panel);
panel->listenDefocus([panel=panel.get()](GUI& gui) {
gui.remove(panel);
});
gui.add(panel);
});
}
void SelectBox::listenChange(onstringchange&& callback) {
changeCallbacks.listen(std::move(callback));
}
void SelectBox::setSelected(const Option& selected) {
this->selected = selected;
this->label->setText(selected.text);
}
const SelectBox::Option& SelectBox::getSelected() const {
return selected;
}
const std::vector<SelectBox::Option>& SelectBox::getOptions() const {
return options;
}
void SelectBox::setOptions(std::vector<Option>&& options) {
this->options = std::move(options);
}
void SelectBox::drawBackground(const DrawContext& pctx, const Assets&) {
glm::vec2 pos = calcPos();
auto batch = pctx.getBatch2D();
batch->untexture();
batch->setColor(calcColor());
batch->rect(pos.x, pos.y, size.x, size.y);
batch->setColor({1.0f, 1.0f, 1.0f, 0.333f});
int paddingRight = padding.w;
int widthHalf = 8;
int heightHalf = 4;
batch->triangle(
pos.x + size.x - paddingRight - widthHalf * 2,
pos.y + size.y / 2.0f - heightHalf,
pos.x + size.x - paddingRight,
pos.y + size.y / 2.0f - heightHalf,
pos.x + size.x - paddingRight - widthHalf,
pos.y + size.y / 2.0f + heightHalf
);
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include "Button.hpp"
namespace gui {
class Label;
class SelectBox : public Button {
public:
struct Option {
std::string value;
std::wstring text;
};
private:
std::vector<Option> options;
Option selected {};
StringCallbacksSet changeCallbacks;
public:
SelectBox(
GUI& gui,
std::vector<Option>&& elements,
Option selected,
int contentWidth,
const glm::vec4& padding
);
void listenChange(onstringchange&& callback);
void setSelected(const Option& selected);
const Option& getSelected() const;
const std::vector<Option>& getOptions() const;
void setOptions(std::vector<Option>&& options);
void drawBackground(const DrawContext& pctx, const Assets&) override;
};
}
+14 -6
View File
@@ -21,25 +21,33 @@ namespace gui {
using onaction = std::function<void(GUI&)>;
using onnumberchange = std::function<void(GUI&, double)>;
using onstringchange = std::function<void(GUI&, const std::string&)>;
class ActionsSet {
std::unique_ptr<std::vector<onaction>> callbacks;
template<typename... Args>
class CallbacksSet {
public:
void listen(const onaction& callback) {
using Func = std::function<void(Args...)>;
private:
std::unique_ptr<std::vector<Func>> callbacks;
public:
void listen(const Func& callback) {
if (callbacks == nullptr) {
callbacks = std::make_unique<std::vector<onaction>>();
callbacks = std::make_unique<std::vector<Func>>();
}
callbacks->push_back(callback);
}
void notify(GUI& gui) {
void notify(Args&&... args) {
if (callbacks) {
for (auto& callback : *callbacks) {
callback(gui);
callback(std::forward<Args>(args)...);
}
}
}
};
using ActionsSet = CallbacksSet<GUI&>;
using StringCallbacksSet = CallbacksSet<GUI&, const std::string&>;
enum class Align {
left, center, right,
+72 -4
View File
@@ -11,6 +11,7 @@
#include "elements/TextBox.hpp"
#include "elements/SplitBox.hpp"
#include "elements/TrackBar.hpp"
#include "elements/SelectBox.hpp"
#include "elements/Image.hpp"
#include "elements/InlineFrame.hpp"
#include "elements/InputBindBox.hpp"
@@ -30,7 +31,7 @@
using namespace gui;
static Align align_from_string(const std::string& str, Align def) {
static Align align_from_string(std::string_view str, Align def) {
if (str == "left") return Align::left;
if (str == "center") return Align::center;
if (str == "right") return Align::right;
@@ -151,7 +152,7 @@ static void read_uinode(
if (element.has("pressed-color")) {
node.setPressedColor(element.attr("pressed-color").asColor());
}
std::string alignName = element.attr("align", "").getText();
const auto& alignName = element.attr("align", "").getText();
node.setAlign(align_from_string(alignName, node.getAlign()));
if (element.has("gravity")) {
@@ -287,8 +288,11 @@ static std::wstring parse_inner_text(
const xml::xmlelement& element, const std::string& context
) {
std::wstring text = L"";
if (element.size() == 1) {
std::string source = element.sub(0).getInnerText();
for (const auto& elem : element.getElements()) {
if (!elem->isText()) {
continue;
}
std::string source = elem->getInnerText();
util::trim(source);
text = util::str2wstr_utf8(source);
if (text[0] == '@') {
@@ -298,6 +302,7 @@ static std::wstring parse_inner_text(
text = langs::get(text.substr(1), util::str2wstr_utf8(context));
}
}
break;
}
return text;
}
@@ -426,6 +431,68 @@ static std::shared_ptr<UINode> read_button(
return button;
}
static std::shared_ptr<UINode> read_select(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto& gui = reader.getGUI();
glm::vec4 padding = element.attr("padding", "10").asVec4();
int contentWidth = element.attr("width", "100").asInt();
auto& elements = element.getElements();
std::vector<SelectBox::Option> options;
SelectBox::Option selected;
for (const auto& elem : elements) {
const auto& tag = elem->getTag();
if (tag != "option") {
continue;
}
auto value = elem->attr("value").getText();
auto text = parse_inner_text(*elem, reader.getContext());
options.push_back(SelectBox::Option {std::move(value), std::move(text)});
}
if (element.has("selected")) {
auto selectedValue = element.attr("selected").getText();
selected.value = selectedValue;
selected.text = L"";
for (const auto& option : options) {
if (option.value == selectedValue) {
selected.text = option.text;
}
}
if (selected.text.empty()) {
selected.text = util::str2wstr_utf8(selected.value);
}
}
auto innerText = parse_inner_text(element, "");
if (!innerText.empty()) {
selected.text = innerText;
}
auto selectBox = std::make_shared<SelectBox>(
gui,
std::move(options),
std::move(selected),
contentWidth,
std::move(padding)
);
if (element.has("onselect")) {
auto callback = scripting::create_string_consumer(
reader.getEnvironment(),
element.attr("onselect").getText(),
reader.getFilename()
);
selectBox->listenChange(
[callback=std::move(callback)](GUI&, const std::string& value) {
callback(value);
});
}
read_panel_impl(reader, element, *selectBox, false);
return selectBox;
}
static std::shared_ptr<UINode> read_check_box(
UiXmlReader& reader, const xml::xmlelement& element
) {
@@ -796,6 +863,7 @@ UiXmlReader::UiXmlReader(gui::GUI& gui, scriptenv&& env) : gui(gui), env(std::mo
add("label", read_label);
add("panel", read_panel);
add("button", read_button);
add("select", read_select);
add("textbox", read_text_box);
add("pagebox", read_page_box);
add("splitbox", read_split_box);