commit
b3a5ea8e06
@ -308,7 +308,7 @@ dv::value Parser::parseObject(dv::value&& object, int indent) {
|
|||||||
object[std::string(name)] = parseFullValue(indent);
|
object[std::string(name)] = parseFullValue(indent);
|
||||||
skipEmptyLines();
|
skipEmptyLines();
|
||||||
}
|
}
|
||||||
return object;
|
return std::move(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
dv::value yaml::parse(std::string_view filename, std::string_view source) {
|
dv::value yaml::parse(std::string_view filename, std::string_view source) {
|
||||||
|
|||||||
@ -333,6 +333,15 @@ void Batch2D::rect(
|
|||||||
vertex(v1, glm::vec2(0, 0), r2,g2,b2,1.0f);
|
vertex(v1, glm::vec2(0, 0), r2,g2,b2,1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Batch2D::triangle(float x1, float y1, float x2, float y2, float x3, float y3) {
|
||||||
|
if (index + 3 >= capacity) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
vertex({x1, y1}, {x1, y1}, color.r, color.g, color.b, color.a);
|
||||||
|
vertex({x2, y2}, {x2, y2}, color.r, color.g, color.b, color.a);
|
||||||
|
vertex({x3, y3}, {x3, y3}, color.r, color.g, color.b, color.a);
|
||||||
|
}
|
||||||
|
|
||||||
void Batch2D::sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint){
|
void Batch2D::sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint){
|
||||||
rect(x, y, w, h, region.u1, region.v1, region.u2-region.u1, region.v2-region.v1, tint.r, tint.g, tint.b, tint.a);
|
rect(x, y, w, h, region.u1, region.v1, region.u2-region.u1, region.v2-region.v1, tint.r, tint.g, tint.b, tint.a);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,6 +117,8 @@ public:
|
|||||||
float r4, float g4, float b4, int sh
|
float r4, float g4, float b4, int sh
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void triangle(float x1, float y1, float x2, float y2, float x3, float y3);
|
||||||
|
|
||||||
void flush() override;
|
void flush() override;
|
||||||
|
|
||||||
void lineWidth(float width);
|
void lineWidth(float width);
|
||||||
|
|||||||
@ -89,6 +89,8 @@ namespace gui {
|
|||||||
void updateTooltip(float delta);
|
void updateTooltip(float delta);
|
||||||
void resetTooltip();
|
void resetTooltip();
|
||||||
public:
|
public:
|
||||||
|
static constexpr int CONTEXT_MENU_ZINDEX = 999;
|
||||||
|
|
||||||
GUI(Engine& engine);
|
GUI(Engine& engine);
|
||||||
~GUI();
|
~GUI();
|
||||||
|
|
||||||
|
|||||||
@ -34,14 +34,12 @@ Button::Button(
|
|||||||
const onaction& action,
|
const onaction& action,
|
||||||
glm::vec2 size
|
glm::vec2 size
|
||||||
)
|
)
|
||||||
: Panel(gui, size, padding, 0) {
|
: Panel(gui, size, padding, 0.0f) {
|
||||||
if (size.y < 0.0f) {
|
if (size.x < 0.0f || size.y < 0.0f) {
|
||||||
size = glm::vec2(
|
setContentSize({text.length() * 8, 16});
|
||||||
glm::max(padding.x + padding.z + text.length() * 8, size.x),
|
} else {
|
||||||
glm::max(padding.y + padding.w + 16, size.y)
|
setSize(size);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
setSize(size);
|
|
||||||
|
|
||||||
if (action) {
|
if (action) {
|
||||||
listenAction(action);
|
listenAction(action);
|
||||||
@ -50,13 +48,12 @@ Button::Button(
|
|||||||
|
|
||||||
label = std::make_shared<Label>(gui, text);
|
label = std::make_shared<Label>(gui, text);
|
||||||
label->setAlign(Align::center);
|
label->setAlign(Align::center);
|
||||||
label->setSize(
|
label->setSize(getContentSize());
|
||||||
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
|
|
||||||
);
|
|
||||||
label->setInteractive(false);
|
label->setInteractive(false);
|
||||||
add(label);
|
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) {
|
void Button::setText(std::wstring text) {
|
||||||
@ -72,19 +69,10 @@ std::wstring Button::getText() const {
|
|||||||
return L"";
|
return L"";
|
||||||
}
|
}
|
||||||
|
|
||||||
Button* Button::textSupplier(wstringsupplier supplier) {
|
|
||||||
if (label) {
|
|
||||||
label->textSupplier(std::move(supplier));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Button::refresh() {
|
void Button::refresh() {
|
||||||
Panel::refresh();
|
Panel::refresh();
|
||||||
if (label) {
|
if (label) {
|
||||||
label->setSize(
|
label->setSize(getContentSize());
|
||||||
size - glm::vec2(padding.z + padding.x, padding.w + padding.y)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,8 +33,6 @@ namespace gui {
|
|||||||
virtual void setText(std::wstring text);
|
virtual void setText(std::wstring text);
|
||||||
virtual std::wstring getText() const;
|
virtual std::wstring getText() const;
|
||||||
|
|
||||||
virtual Button* textSupplier(wstringsupplier supplier);
|
|
||||||
|
|
||||||
virtual void refresh() override;
|
virtual void refresh() override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,17 @@ int Panel::getMinLength() const {
|
|||||||
return minLength;
|
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() {
|
void Panel::cropToContent() {
|
||||||
if (maxLength > 0.0f) {
|
if (maxLength > 0.0f) {
|
||||||
setSize(glm::vec2(
|
setSize(glm::vec2(
|
||||||
|
|||||||
@ -27,6 +27,12 @@ namespace gui {
|
|||||||
|
|
||||||
virtual void setMinLength(int value);
|
virtual void setMinLength(int value);
|
||||||
int getMinLength() const;
|
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:
|
protected:
|
||||||
int minLength = 0;
|
int minLength = 0;
|
||||||
int maxLength = 0;
|
int maxLength = 0;
|
||||||
|
|||||||
84
src/graphics/ui/elements/SelectBox.cpp
Normal file
84
src/graphics/ui/elements/SelectBox.cpp
Normal 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
src/graphics/ui/elements/SelectBox.hpp
Normal file
39
src/graphics/ui/elements/SelectBox.hpp
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -21,25 +21,33 @@ namespace gui {
|
|||||||
|
|
||||||
using onaction = std::function<void(GUI&)>;
|
using onaction = std::function<void(GUI&)>;
|
||||||
using onnumberchange = std::function<void(GUI&, double)>;
|
using onnumberchange = std::function<void(GUI&, double)>;
|
||||||
|
using onstringchange = std::function<void(GUI&, const std::string&)>;
|
||||||
|
|
||||||
class ActionsSet {
|
template<typename... Args>
|
||||||
std::unique_ptr<std::vector<onaction>> callbacks;
|
class CallbacksSet {
|
||||||
public:
|
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) {
|
if (callbacks == nullptr) {
|
||||||
callbacks = std::make_unique<std::vector<onaction>>();
|
callbacks = std::make_unique<std::vector<Func>>();
|
||||||
}
|
}
|
||||||
callbacks->push_back(callback);
|
callbacks->push_back(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void notify(GUI& gui) {
|
void notify(Args&&... args) {
|
||||||
if (callbacks) {
|
if (callbacks) {
|
||||||
for (auto& callback : *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 {
|
enum class Align {
|
||||||
left, center, right,
|
left, center, right,
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "elements/TextBox.hpp"
|
#include "elements/TextBox.hpp"
|
||||||
#include "elements/SplitBox.hpp"
|
#include "elements/SplitBox.hpp"
|
||||||
#include "elements/TrackBar.hpp"
|
#include "elements/TrackBar.hpp"
|
||||||
|
#include "elements/SelectBox.hpp"
|
||||||
#include "elements/Image.hpp"
|
#include "elements/Image.hpp"
|
||||||
#include "elements/InlineFrame.hpp"
|
#include "elements/InlineFrame.hpp"
|
||||||
#include "elements/InputBindBox.hpp"
|
#include "elements/InputBindBox.hpp"
|
||||||
@ -30,7 +31,7 @@
|
|||||||
|
|
||||||
using namespace gui;
|
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 == "left") return Align::left;
|
||||||
if (str == "center") return Align::center;
|
if (str == "center") return Align::center;
|
||||||
if (str == "right") return Align::right;
|
if (str == "right") return Align::right;
|
||||||
@ -151,7 +152,7 @@ static void read_uinode(
|
|||||||
if (element.has("pressed-color")) {
|
if (element.has("pressed-color")) {
|
||||||
node.setPressedColor(element.attr("pressed-color").asColor());
|
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()));
|
node.setAlign(align_from_string(alignName, node.getAlign()));
|
||||||
|
|
||||||
if (element.has("gravity")) {
|
if (element.has("gravity")) {
|
||||||
@ -287,8 +288,11 @@ static std::wstring parse_inner_text(
|
|||||||
const xml::xmlelement& element, const std::string& context
|
const xml::xmlelement& element, const std::string& context
|
||||||
) {
|
) {
|
||||||
std::wstring text = L"";
|
std::wstring text = L"";
|
||||||
if (element.size() == 1) {
|
for (const auto& elem : element.getElements()) {
|
||||||
std::string source = element.sub(0).getInnerText();
|
if (!elem->isText()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string source = elem->getInnerText();
|
||||||
util::trim(source);
|
util::trim(source);
|
||||||
text = util::str2wstr_utf8(source);
|
text = util::str2wstr_utf8(source);
|
||||||
if (text[0] == '@') {
|
if (text[0] == '@') {
|
||||||
@ -298,6 +302,7 @@ static std::wstring parse_inner_text(
|
|||||||
text = langs::get(text.substr(1), util::str2wstr_utf8(context));
|
text = langs::get(text.substr(1), util::str2wstr_utf8(context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@ -426,6 +431,68 @@ static std::shared_ptr<UINode> read_button(
|
|||||||
return 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(
|
static std::shared_ptr<UINode> read_check_box(
|
||||||
UiXmlReader& reader, const xml::xmlelement& element
|
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("label", read_label);
|
||||||
add("panel", read_panel);
|
add("panel", read_panel);
|
||||||
add("button", read_button);
|
add("button", read_button);
|
||||||
|
add("select", read_select);
|
||||||
add("textbox", read_text_box);
|
add("textbox", read_text_box);
|
||||||
add("pagebox", read_page_box);
|
add("pagebox", read_page_box);
|
||||||
add("splitbox", read_split_box);
|
add("splitbox", read_split_box);
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "graphics/ui/elements/Canvas.hpp"
|
#include "graphics/ui/elements/Canvas.hpp"
|
||||||
#include "graphics/ui/elements/CheckBox.hpp"
|
#include "graphics/ui/elements/CheckBox.hpp"
|
||||||
#include "graphics/ui/elements/Image.hpp"
|
#include "graphics/ui/elements/Image.hpp"
|
||||||
|
#include "graphics/ui/elements/SelectBox.hpp"
|
||||||
#include "graphics/ui/elements/InventoryView.hpp"
|
#include "graphics/ui/elements/InventoryView.hpp"
|
||||||
#include "graphics/ui/elements/Menu.hpp"
|
#include "graphics/ui/elements/Menu.hpp"
|
||||||
#include "graphics/ui/elements/Panel.hpp"
|
#include "graphics/ui/elements/Panel.hpp"
|
||||||
@ -225,6 +226,8 @@ static int p_is_checked(UINode* node, lua::State* L) {
|
|||||||
static int p_get_value(UINode* node, lua::State* L) {
|
static int p_get_value(UINode* node, lua::State* L) {
|
||||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||||
return lua::pushnumber(L, bar->getValue());
|
return lua::pushnumber(L, bar->getValue());
|
||||||
|
} else if (auto box = dynamic_cast<SelectBox*>(node)) {
|
||||||
|
return lua::pushstring(L, box->getSelected().value);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -509,6 +512,28 @@ static int p_get_scroll(UINode* node, lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int p_get_options(UINode* node, lua::State* L) {
|
||||||
|
if (auto selectbox = dynamic_cast<SelectBox*>(node)) {
|
||||||
|
const auto& options = selectbox->getOptions();
|
||||||
|
size_t size = options.size();
|
||||||
|
lua::createtable(L, size, 0);
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
const auto& option = options[i];
|
||||||
|
lua::createtable(L, 0, 2);
|
||||||
|
|
||||||
|
lua::pushstring(L, option.value);
|
||||||
|
lua::setfield(L, "value");
|
||||||
|
|
||||||
|
lua::pushwstring(L, option.text);
|
||||||
|
lua::setfield(L, "text");
|
||||||
|
|
||||||
|
lua::rawseti(L, i + 1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int l_gui_getattr(lua::State* L) {
|
static int l_gui_getattr(lua::State* L) {
|
||||||
if (!lua::isstring(L, 1)) {
|
if (!lua::isstring(L, 1)) {
|
||||||
throw std::runtime_error("document name is not a string");
|
throw std::runtime_error("document name is not a string");
|
||||||
@ -595,6 +620,7 @@ static int l_gui_getattr(lua::State* L) {
|
|||||||
{"data", p_get_data},
|
{"data", p_get_data},
|
||||||
{"parent", p_get_parent},
|
{"parent", p_get_parent},
|
||||||
{"region", p_get_region},
|
{"region", p_get_region},
|
||||||
|
{"options", p_get_options},
|
||||||
};
|
};
|
||||||
auto func = getters.find(attr);
|
auto func = getters.find(attr);
|
||||||
if (func != getters.end()) {
|
if (func != getters.end()) {
|
||||||
@ -706,9 +732,45 @@ static void p_set_region(UINode* node, lua::State* L, int idx) {
|
|||||||
image->setRegion(UVRegion(vec.x, vec.y, vec.z, vec.w));
|
image->setRegion(UVRegion(vec.x, vec.y, vec.z, vec.w));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void p_set_options(UINode* node, lua::State* L, int idx) {
|
||||||
|
if (auto selectbox = dynamic_cast<SelectBox*>(node)) {
|
||||||
|
if (!lua::istable(L, idx)) {
|
||||||
|
throw std::runtime_error("options table expected");
|
||||||
|
}
|
||||||
|
std::vector<SelectBox::Option> options;
|
||||||
|
size_t size = lua::objlen(L, idx);
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
lua::rawgeti(L, i + 1, idx);
|
||||||
|
|
||||||
|
SelectBox::Option option;
|
||||||
|
|
||||||
|
lua::getfield(L, "value");
|
||||||
|
option.value = lua::require_string(L, -1);
|
||||||
|
lua::pop(L);
|
||||||
|
|
||||||
|
lua::getfield(L, "text");
|
||||||
|
option.text = lua::require_wstring(L, -1);
|
||||||
|
lua::pop(L, 2);
|
||||||
|
|
||||||
|
options.push_back(std::move(option));
|
||||||
|
}
|
||||||
|
selectbox->setOptions(std::move(options));
|
||||||
|
}
|
||||||
|
}
|
||||||
static void p_set_value(UINode* node, lua::State* L, int idx) {
|
static void p_set_value(UINode* node, lua::State* L, int idx) {
|
||||||
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
if (auto bar = dynamic_cast<TrackBar*>(node)) {
|
||||||
bar->setValue(lua::tonumber(L, idx));
|
bar->setValue(lua::tonumber(L, idx));
|
||||||
|
} else if (auto selectbox = dynamic_cast<SelectBox*>(node)) {
|
||||||
|
auto value = lua::require_lstring(L, idx);
|
||||||
|
const auto& options = selectbox->getOptions();
|
||||||
|
for (const auto& option : options) {
|
||||||
|
if (option.value == value) {
|
||||||
|
selectbox->setSelected(option);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectbox->setSelected(SelectBox::Option {
|
||||||
|
std::string(value), util::str2wstr_utf8(value)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void p_set_min(UINode* node, lua::State* L, int idx) {
|
static void p_set_min(UINode* node, lua::State* L, int idx) {
|
||||||
@ -842,6 +904,7 @@ static int l_gui_setattr(lua::State* L) {
|
|||||||
{"cursor", p_set_cursor},
|
{"cursor", p_set_cursor},
|
||||||
{"focused", p_set_focused},
|
{"focused", p_set_focused},
|
||||||
{"region", p_set_region},
|
{"region", p_set_region},
|
||||||
|
{"options", p_set_options},
|
||||||
};
|
};
|
||||||
auto func = setters.find(attr);
|
auto func = setters.find(attr);
|
||||||
if (func != setters.end()) {
|
if (func != setters.end()) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "coders/json.hpp"
|
#include "coders/json.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "util/type_helpers.hpp"
|
||||||
#include "lua/lua_engine.hpp"
|
#include "lua/lua_engine.hpp"
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
@ -58,18 +59,44 @@ key_handler scripting::create_key_handler(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
wstringconsumer scripting::create_wstring_consumer(
|
template<typename T, int(pushfunc)(lua::State*, remove_const_ref_if_primitive_t<const T&>)>
|
||||||
|
std::function<void(const T&)> create_consumer(
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
) {
|
) {
|
||||||
return [=](const std::wstring& x) {
|
return [=](const T& x) {
|
||||||
if (auto L = process_callback(env, src, file)) {
|
if (auto L = process_callback(env, src, file)) {
|
||||||
lua::pushwstring(L, x);
|
pushfunc(L, x);
|
||||||
lua::call_nothrow(L, 1);
|
lua::call_nothrow(L, 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
wstringsupplier scripting::create_wstring_supplier(
|
wstringconsumer scripting::create_wstring_consumer(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return create_consumer<std::wstring, lua::pushwstring>(env, src, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
stringconsumer scripting::create_string_consumer(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return create_consumer<std::string, lua::pushstring>(env, src, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolconsumer scripting::create_bool_consumer(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return create_consumer<bool, lua::pushboolean>(env, src, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
doubleconsumer scripting::create_number_consumer(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return create_consumer<number_t, lua::pushnumber>(env, src, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, T(tovalueFunc)(lua::State*, int)>
|
||||||
|
std::function<T()> create_supplier(
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
) {
|
) {
|
||||||
return [=]() {
|
return [=]() {
|
||||||
@ -77,14 +104,32 @@ wstringsupplier scripting::create_wstring_supplier(
|
|||||||
if (lua::isfunction(L, -1)) {
|
if (lua::isfunction(L, -1)) {
|
||||||
lua::call_nothrow(L, 0);
|
lua::call_nothrow(L, 0);
|
||||||
}
|
}
|
||||||
auto str = lua::require_wstring(L, -1);
|
auto str = tovalueFunc(L, -1);
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
return std::wstring();
|
return T {};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wstringsupplier scripting::create_wstring_supplier(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return create_supplier<std::wstring, lua::require_wstring>(env, src, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolsupplier scripting::create_bool_supplier(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return create_supplier<bool, lua::toboolean>(env, src, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
doublesupplier scripting::create_number_supplier(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return create_supplier<number_t, lua::tonumber>(env, src, file);
|
||||||
|
}
|
||||||
|
|
||||||
wstringchecker scripting::create_wstring_validator(
|
wstringchecker scripting::create_wstring_validator(
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
) {
|
) {
|
||||||
@ -97,60 +142,6 @@ wstringchecker scripting::create_wstring_validator(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
boolconsumer scripting::create_bool_consumer(
|
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
|
||||||
) {
|
|
||||||
return [=](bool x) {
|
|
||||||
if (auto L = process_callback(env, src, file)) {
|
|
||||||
lua::pushboolean(L, x);
|
|
||||||
lua::call_nothrow(L, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
boolsupplier scripting::create_bool_supplier(
|
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
|
||||||
) {
|
|
||||||
return [=]() {
|
|
||||||
if (auto L = process_callback(env, src, file)) {
|
|
||||||
if (lua::isfunction(L, -1)) {
|
|
||||||
lua::call_nothrow(L, 0);
|
|
||||||
}
|
|
||||||
bool x = lua::toboolean(L, -1);
|
|
||||||
lua::pop(L);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
doubleconsumer scripting::create_number_consumer(
|
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
|
||||||
) {
|
|
||||||
return [=](double x) {
|
|
||||||
if (auto L = process_callback(env, src, file)) {
|
|
||||||
lua::pushnumber(L, x);
|
|
||||||
lua::call_nothrow(L, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
doublesupplier scripting::create_number_supplier(
|
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
|
||||||
) {
|
|
||||||
return [=]() {
|
|
||||||
if (auto L = process_callback(env, src, file)) {
|
|
||||||
if (lua::isfunction(L, -1)) {
|
|
||||||
lua::call_nothrow(L, 0);
|
|
||||||
}
|
|
||||||
auto x = lua::tonumber(L, -1);
|
|
||||||
lua::pop(L);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
return 0.0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
int_array_consumer scripting::create_int_array_consumer(
|
int_array_consumer scripting::create_int_array_consumer(
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -23,6 +23,12 @@ namespace scripting {
|
|||||||
const std::string& file = "[string]"
|
const std::string& file = "[string]"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
stringconsumer create_string_consumer(
|
||||||
|
const scriptenv& env,
|
||||||
|
const std::string& src,
|
||||||
|
const std::string& file = "[string]"
|
||||||
|
);
|
||||||
|
|
||||||
wstringconsumer create_wstring_consumer(
|
wstringconsumer create_wstring_consumer(
|
||||||
const scriptenv& env,
|
const scriptenv& env,
|
||||||
const std::string& src,
|
const std::string& src,
|
||||||
|
|||||||
27
src/util/type_helpers.hpp
Normal file
27
src/util/type_helpers.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct remove_const_ref_if_primitive {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct remove_const_ref_if_primitive<const T&> {
|
||||||
|
using stripped_type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
|
||||||
|
using type = typename std::conditional<std::is_fundamental<stripped_type>::value,
|
||||||
|
stripped_type,
|
||||||
|
const T&>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct remove_const_ref_if_primitive<const T> {
|
||||||
|
using stripped_type = typename std::remove_const<T>::type;
|
||||||
|
using type = typename std::conditional<std::is_fundamental<stripped_type>::value,
|
||||||
|
stripped_type,
|
||||||
|
const T>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using remove_const_ref_if_primitive_t = typename remove_const_ref_if_primitive<T>::type;
|
||||||
Loading…
x
Reference in New Issue
Block a user