mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-08 20:24:47 -04:00
Split out string/number components
This commit is contained in:
@@ -1470,12 +1470,16 @@ set(DUSK_FILES
|
||||
src/dusk/ui/editor.hpp
|
||||
src/dusk/ui/event.cpp
|
||||
src/dusk/ui/event.hpp
|
||||
src/dusk/ui/number_button.cpp
|
||||
src/dusk/ui/number_button.hpp
|
||||
src/dusk/ui/pane.cpp
|
||||
src/dusk/ui/pane.hpp
|
||||
src/dusk/ui/select_button.cpp
|
||||
src/dusk/ui/select_button.hpp
|
||||
src/dusk/ui/settings.cpp
|
||||
src/dusk/ui/settings.hpp
|
||||
src/dusk/ui/string_button.cpp
|
||||
src/dusk/ui/string_button.hpp
|
||||
src/dusk/ui/ui.hpp
|
||||
src/dusk/ui/ui.cpp
|
||||
src/dusk/ui/window.hpp
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "component.hpp"
|
||||
|
||||
#include "aurora/lib/dolphin/gd/gd.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
static aurora::Module Log{"dusk::ui::component"};
|
||||
|
||||
Component::Component(Rml::Element* root) : mRoot(root) {}
|
||||
|
||||
|
||||
+15
-230
@@ -1,19 +1,16 @@
|
||||
#include "editor.hpp"
|
||||
|
||||
#include <RmlUi/Core.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "aurora/lib/dolphin/gd/gd.hpp"
|
||||
#include "button.hpp"
|
||||
#include "number_button.hpp"
|
||||
#include "pane.hpp"
|
||||
#include "select_button.hpp"
|
||||
|
||||
#include <charconv>
|
||||
#include "string_button.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
namespace {
|
||||
aurora::Module Log{"dusk::ui::editor"};
|
||||
|
||||
bool has_save_data() {
|
||||
return dComIfGs_getSaveData() != nullptr;
|
||||
@@ -181,218 +178,6 @@ bool handle_editor_action(const Rml::VariantList& arguments) {
|
||||
|
||||
} // namespace
|
||||
|
||||
class ControlledSelectButton : public SelectButton {
|
||||
public:
|
||||
ControlledSelectButton(Rml::Element* parent, Props props)
|
||||
: SelectButton(parent, std::move(props)) {}
|
||||
|
||||
void update() override {
|
||||
set_disabled(is_disabled());
|
||||
set_value_label(format_value());
|
||||
SelectButton::update();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Rml::String format_value() = 0;
|
||||
virtual bool is_disabled() { return false; }
|
||||
};
|
||||
|
||||
class BaseStringButton : public ControlledSelectButton {
|
||||
public:
|
||||
struct Props {
|
||||
Rml::String key;
|
||||
Rml::String type = "text";
|
||||
int maxLength = -1;
|
||||
};
|
||||
|
||||
BaseStringButton(Rml::Element* parent, Props props)
|
||||
: ControlledSelectButton(parent, {std::move(props.key)}), mType(std::move(props.type)),
|
||||
mMaxLength(props.maxLength) {
|
||||
mInputListeners.reserve(3);
|
||||
}
|
||||
|
||||
void update() override {
|
||||
if (mPendingStopEditing) {
|
||||
stop_editing(mPendingCommit, mPendingRefocusRoot);
|
||||
}
|
||||
ControlledSelectButton::update();
|
||||
}
|
||||
|
||||
void start_editing() {
|
||||
if (mInputElem != nullptr) {
|
||||
return;
|
||||
}
|
||||
auto* doc = mRoot->GetOwnerDocument();
|
||||
auto elemPtr = doc->CreateElement("input");
|
||||
mInputElem = rmlui_dynamic_cast<Rml::ElementFormControlInput*>(elemPtr.get());
|
||||
if (mInputElem == nullptr) {
|
||||
return;
|
||||
}
|
||||
mInputElem->SetAttribute("type", mType);
|
||||
mInputElem->SetAttribute("value", format_value());
|
||||
if (mMaxLength > -1) {
|
||||
mInputElem->SetAttribute("maxlength", mMaxLength);
|
||||
}
|
||||
mRoot->AppendChild(std::move(elemPtr));
|
||||
mValueElem->SetProperty(Rml::PropertyId::Visibility, Rml::Style::Visibility::Hidden);
|
||||
mInputElem->Focus(true);
|
||||
const int end = static_cast<int>(Rml::StringUtilities::LengthUTF8(mInputElem->GetValue()));
|
||||
mInputElem->SetSelectionRange(0, end);
|
||||
set_selected(true);
|
||||
mInputListeners.emplace_back(std::make_unique<ScopedEventListener>(
|
||||
mInputElem, Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd == NavCommand::Confirm) {
|
||||
request_stop_editing(true, true);
|
||||
event.StopImmediatePropagation();
|
||||
} else if (cmd == NavCommand::Cancel) {
|
||||
request_stop_editing(false, true);
|
||||
event.StopImmediatePropagation();
|
||||
}
|
||||
}));
|
||||
mInputListeners.emplace_back(std::make_unique<ScopedEventListener>(
|
||||
mInputElem, Rml::EventId::Click, [](Rml::Event& event) { event.StopPropagation(); }));
|
||||
mInputListeners.emplace_back(std::make_unique<ScopedEventListener>(mInputElem,
|
||||
Rml::EventId::Blur, [this](Rml::Event&) { request_stop_editing(true, false); }));
|
||||
}
|
||||
|
||||
void request_stop_editing(bool commit, bool refocusRoot) {
|
||||
mPendingStopEditing = true;
|
||||
mPendingCommit = commit;
|
||||
mPendingRefocusRoot = refocusRoot;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool handle_nav_command(NavCommand cmd) override {
|
||||
if (cmd == NavCommand::Confirm) {
|
||||
if (mInputElem == nullptr) {
|
||||
start_editing();
|
||||
} else {
|
||||
request_stop_editing(true, true);
|
||||
}
|
||||
return true;
|
||||
} else if (cmd == NavCommand::Cancel) {
|
||||
request_stop_editing(false, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void set_value(Rml::String value) = 0;
|
||||
|
||||
private:
|
||||
void stop_editing(bool commit = true, bool refocusRoot = false) {
|
||||
if (mInputElem == nullptr) {
|
||||
return;
|
||||
}
|
||||
mPendingStopEditing = false;
|
||||
if (commit) {
|
||||
set_value(mInputElem->GetValue());
|
||||
}
|
||||
mInputListeners.clear();
|
||||
mRoot->RemoveChild(mInputElem);
|
||||
mInputElem = nullptr;
|
||||
mValueElem->SetProperty(Rml::PropertyId::Visibility, Rml::Style::Visibility::Visible);
|
||||
set_selected(false);
|
||||
if (refocusRoot) {
|
||||
mRoot->Focus(true);
|
||||
}
|
||||
}
|
||||
|
||||
Rml::ElementFormControlInput* mInputElem = nullptr;
|
||||
std::vector<std::unique_ptr<ScopedEventListener> > mInputListeners;
|
||||
Rml::String mType;
|
||||
int mMaxLength;
|
||||
bool mPendingStopEditing = false;
|
||||
bool mPendingCommit = true;
|
||||
bool mPendingRefocusRoot = false;
|
||||
};
|
||||
|
||||
class StringButton : public BaseStringButton {
|
||||
public:
|
||||
struct Props {
|
||||
Rml::String key;
|
||||
std::function<Rml::String()> getValue;
|
||||
std::function<void(Rml::String)> setValue;
|
||||
int maxLength = -1;
|
||||
};
|
||||
|
||||
StringButton(Rml::Element* parent, Props props)
|
||||
: BaseStringButton(parent,
|
||||
{
|
||||
.key = std::move(props.key),
|
||||
.maxLength = props.maxLength,
|
||||
}),
|
||||
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)) {}
|
||||
|
||||
protected:
|
||||
Rml::String format_value() override { return mGetValue(); }
|
||||
void set_value(Rml::String value) override {
|
||||
if (mSetValue) {
|
||||
mSetValue(std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<Rml::String()> mGetValue;
|
||||
std::function<void(Rml::String)> mSetValue;
|
||||
};
|
||||
|
||||
struct IntSelectProps {
|
||||
Rml::String key;
|
||||
std::function<int()> getValue;
|
||||
std::function<void(int)> setValue;
|
||||
int min = 0;
|
||||
int max = INT_MAX;
|
||||
int step = 1;
|
||||
};
|
||||
|
||||
class IntSelectButton : public BaseStringButton {
|
||||
public:
|
||||
using Props = IntSelectProps;
|
||||
|
||||
IntSelectButton(Rml::Element* parent, Props props)
|
||||
: BaseStringButton(parent, {.key = std::move(props.key), .type = "number"}),
|
||||
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
|
||||
mMin(props.min), mMax(props.max), mStep(props.step) {}
|
||||
|
||||
protected:
|
||||
Rml::String format_value() override { return fmt::to_string(mGetValue()); }
|
||||
void set_value(Rml::String value) override {
|
||||
if (!mSetValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
int parsedValue = 0;
|
||||
const char* begin = value.data();
|
||||
const char* end = begin + value.size();
|
||||
const auto result = std::from_chars(begin, end, parsedValue);
|
||||
if (result.ec != std::errc() || result.ptr != end) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSetValue(std::clamp(parsedValue, mMin, mMax));
|
||||
}
|
||||
|
||||
bool handle_nav_command(NavCommand cmd) override {
|
||||
if (cmd == NavCommand::Left) {
|
||||
mSetValue(std::clamp(mGetValue() - mStep, mMin, mMax));
|
||||
return true;
|
||||
} else if (cmd == NavCommand::Right) {
|
||||
mSetValue(std::clamp(mGetValue() + mStep, mMin, mMax));
|
||||
return true;
|
||||
}
|
||||
return BaseStringButton::handle_nav_command(cmd);
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<int()> mGetValue;
|
||||
std::function<void(int)> mSetValue;
|
||||
int mMin;
|
||||
int mMax;
|
||||
int mStep;
|
||||
};
|
||||
|
||||
EditorWindow::EditorWindow() {
|
||||
add_tab("Player Status", [this](Rml::Element* content) {
|
||||
auto& leftPane = add_child<Pane>(content, Pane::Direction::Vertical);
|
||||
@@ -411,33 +196,33 @@ EditorWindow::EditorWindow() {
|
||||
.setValue = set_horse_name,
|
||||
.maxLength = 16,
|
||||
});
|
||||
leftPane.add_child<IntSelectButton>(leftPane.root(),
|
||||
IntSelectButton::Props{
|
||||
leftPane.add_child<NumberButton>(leftPane.root(),
|
||||
NumberButton::Props{
|
||||
.key = "Max Health",
|
||||
.getValue = [] { return get_player_status()->getMaxLife(); },
|
||||
.setValue = [](int value) { return get_player_status()->setMaxLife(value); },
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
});
|
||||
leftPane.add_child<IntSelectButton>(leftPane.root(),
|
||||
IntSelectButton::Props{
|
||||
leftPane.add_child<NumberButton>(leftPane.root(),
|
||||
NumberButton::Props{
|
||||
.key = "Health",
|
||||
.getValue = [] { return get_player_status()->getLife(); },
|
||||
.setValue = [](int value) { return get_player_status()->setLife(value); },
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
});
|
||||
leftPane.add_child<IntSelectButton>(leftPane.root(),
|
||||
IntSelectButton::Props{
|
||||
leftPane.add_child<NumberButton>(leftPane.root(),
|
||||
NumberButton::Props{
|
||||
.key = "Max Oil",
|
||||
.getValue = [] { return get_player_status()->getMaxOil(); },
|
||||
.setValue = [](int value) { return get_player_status()->setMaxOil(value); },
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
});
|
||||
leftPane.add_child<IntSelectButton>(leftPane.root(),
|
||||
IntSelectButton::Props{
|
||||
leftPane.add_child<NumberButton>(leftPane.root(),
|
||||
NumberButton::Props{
|
||||
.key = "Oil",
|
||||
.getValue = [] { return get_player_status()->getOil(); },
|
||||
.setValue = [](int value) { return get_player_status()->setOil(value); },
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
.max = UINT16_MAX, // TODO: actual max
|
||||
});
|
||||
|
||||
leftPane.add_section("Equipment");
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "number_button.hpp"
|
||||
|
||||
#include <charconv>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
NumberButton::NumberButton(Rml::Element* parent, Props props)
|
||||
: BaseStringButton(parent, {.key = std::move(props.key), .type = "number"}),
|
||||
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)), mMin(props.min),
|
||||
mMax(props.max), mStep(props.step) {}
|
||||
|
||||
Rml::String NumberButton::format_value() {
|
||||
return fmt::to_string(mGetValue());
|
||||
}
|
||||
|
||||
void NumberButton::set_value(Rml::String value) {
|
||||
if (!mSetValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
int parsedValue = 0;
|
||||
const char* begin = value.data();
|
||||
const char* end = begin + value.size();
|
||||
const auto result = std::from_chars(begin, end, parsedValue);
|
||||
if (result.ec != std::errc() || result.ptr != end) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSetValue(std::clamp(parsedValue, mMin, mMax));
|
||||
}
|
||||
|
||||
bool NumberButton::handle_nav_command(NavCommand cmd) {
|
||||
if (cmd == NavCommand::Left) {
|
||||
mSetValue(std::clamp(mGetValue() - mStep, mMin, mMax));
|
||||
return true;
|
||||
} else if (cmd == NavCommand::Right) {
|
||||
mSetValue(std::clamp(mGetValue() + mStep, mMin, mMax));
|
||||
return true;
|
||||
}
|
||||
return BaseStringButton::handle_nav_command(cmd);
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "string_button.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class NumberButton : public BaseStringButton {
|
||||
public:
|
||||
struct Props {
|
||||
Rml::String key;
|
||||
std::function<int()> getValue;
|
||||
std::function<void(int)> setValue;
|
||||
int min = 0;
|
||||
int max = INT_MAX;
|
||||
int step = 1;
|
||||
};
|
||||
|
||||
NumberButton(Rml::Element* parent, Props props);
|
||||
|
||||
protected:
|
||||
Rml::String format_value() override;
|
||||
void set_value(Rml::String value) override;
|
||||
bool handle_nav_command(NavCommand cmd) override;
|
||||
|
||||
private:
|
||||
std::function<int()> mGetValue;
|
||||
std::function<void(int)> mSetValue;
|
||||
int mMin;
|
||||
int mMax;
|
||||
int mStep;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
@@ -94,4 +94,10 @@ bool SelectButton::handle_nav_command(NavCommand cmd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ControlledSelectButton::update() {
|
||||
set_disabled(is_disabled());
|
||||
set_value_label(format_value());
|
||||
SelectButton::update();
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -5,20 +5,16 @@
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class SelectButton;
|
||||
|
||||
struct SelectButtonProps {
|
||||
Rml::String key;
|
||||
Rml::String value;
|
||||
bool selected = false;
|
||||
bool disabled = false;
|
||||
};
|
||||
|
||||
class SelectButton : public Component {
|
||||
public:
|
||||
using Props = SelectButtonProps;
|
||||
struct Props {
|
||||
Rml::String key;
|
||||
Rml::String value;
|
||||
bool selected = false;
|
||||
bool disabled = false;
|
||||
};
|
||||
|
||||
SelectButton(Rml::Element* parent, SelectButtonProps props);
|
||||
SelectButton(Rml::Element* parent, Props props);
|
||||
|
||||
bool focus() override;
|
||||
|
||||
@@ -26,16 +22,27 @@ public:
|
||||
bool get_selected() const { return mProps.selected; }
|
||||
void set_disabled(bool disabled);
|
||||
bool get_disabled() const { return mProps.disabled; }
|
||||
|
||||
void set_value_label(const Rml::String& value);
|
||||
|
||||
protected:
|
||||
void update_props(Props props);
|
||||
virtual bool handle_nav_command(NavCommand cmd);
|
||||
|
||||
SelectButtonProps mProps;
|
||||
Props mProps;
|
||||
Rml::Element* mKeyElem = nullptr;
|
||||
Rml::Element* mValueElem = nullptr;
|
||||
};
|
||||
|
||||
class ControlledSelectButton : public SelectButton {
|
||||
public:
|
||||
ControlledSelectButton(Rml::Element* parent, Props props)
|
||||
: SelectButton(parent, std::move(props)) {}
|
||||
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
virtual Rml::String format_value() = 0;
|
||||
virtual bool is_disabled() { return false; }
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#include "string_button.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
BaseStringButton::BaseStringButton(Rml::Element* parent, Props props)
|
||||
: ControlledSelectButton(parent, {std::move(props.key)}), mType(std::move(props.type)),
|
||||
mMaxLength(props.maxLength) {
|
||||
mInputListeners.reserve(3);
|
||||
}
|
||||
|
||||
void BaseStringButton::update() {
|
||||
if (mPendingStopEditing) {
|
||||
stop_editing(mPendingCommit, mPendingRefocusRoot);
|
||||
}
|
||||
ControlledSelectButton::update();
|
||||
}
|
||||
|
||||
void BaseStringButton::start_editing() {
|
||||
if (mInputElem != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create input element
|
||||
auto* doc = mRoot->GetOwnerDocument();
|
||||
auto elemPtr = doc->CreateElement("input");
|
||||
mInputElem = rmlui_dynamic_cast<Rml::ElementFormControlInput*>(elemPtr.get());
|
||||
if (mInputElem == nullptr) {
|
||||
return;
|
||||
}
|
||||
mInputElem->SetAttribute("type", mType);
|
||||
mInputElem->SetAttribute("value", format_value());
|
||||
if (mMaxLength > -1) {
|
||||
mInputElem->SetAttribute("maxlength", mMaxLength);
|
||||
}
|
||||
mRoot->AppendChild(std::move(elemPtr));
|
||||
|
||||
// Hide value element
|
||||
mValueElem->SetProperty(Rml::PropertyId::Visibility, Rml::Style::Visibility::Hidden);
|
||||
|
||||
// Focus and select text within input
|
||||
mInputElem->Focus(true);
|
||||
const int end = static_cast<int>(Rml::StringUtilities::LengthUTF8(mInputElem->GetValue()));
|
||||
mInputElem->SetSelectionRange(0, end);
|
||||
|
||||
// Mark button as selected to indicate "active"
|
||||
set_selected(true);
|
||||
|
||||
// Register input listeners
|
||||
mInputListeners.emplace_back(std::make_unique<ScopedEventListener>(
|
||||
mInputElem, Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd == NavCommand::Confirm) {
|
||||
request_stop_editing(true, true);
|
||||
event.StopImmediatePropagation();
|
||||
} else if (cmd == NavCommand::Cancel) {
|
||||
request_stop_editing(false, true);
|
||||
event.StopImmediatePropagation();
|
||||
}
|
||||
}));
|
||||
mInputListeners.emplace_back(std::make_unique<ScopedEventListener>(
|
||||
mInputElem, Rml::EventId::Click, [](Rml::Event& event) { event.StopPropagation(); }));
|
||||
mInputListeners.emplace_back(std::make_unique<ScopedEventListener>(mInputElem,
|
||||
Rml::EventId::Blur, [this](Rml::Event&) { request_stop_editing(true, false); }));
|
||||
}
|
||||
|
||||
void BaseStringButton::request_stop_editing(bool commit, bool refocusRoot) {
|
||||
mPendingStopEditing = true;
|
||||
mPendingCommit = commit;
|
||||
mPendingRefocusRoot = refocusRoot;
|
||||
}
|
||||
|
||||
bool BaseStringButton::handle_nav_command(NavCommand cmd) {
|
||||
if (cmd == NavCommand::Confirm) {
|
||||
if (mInputElem == nullptr) {
|
||||
start_editing();
|
||||
} else {
|
||||
request_stop_editing(true, true);
|
||||
}
|
||||
return true;
|
||||
} else if (cmd == NavCommand::Cancel) {
|
||||
request_stop_editing(false, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseStringButton::stop_editing(bool commit, bool refocusRoot) {
|
||||
if (mInputElem == nullptr) {
|
||||
return;
|
||||
}
|
||||
mPendingStopEditing = false;
|
||||
if (commit) {
|
||||
set_value(mInputElem->GetValue());
|
||||
}
|
||||
mInputListeners.clear();
|
||||
mRoot->RemoveChild(mInputElem);
|
||||
mInputElem = nullptr;
|
||||
|
||||
// Restore value element
|
||||
mValueElem->SetProperty(Rml::PropertyId::Visibility, Rml::Style::Visibility::Visible);
|
||||
|
||||
set_selected(false);
|
||||
if (refocusRoot) {
|
||||
mRoot->Focus(true);
|
||||
}
|
||||
}
|
||||
|
||||
StringButton::StringButton(Rml::Element* parent, Props props)
|
||||
: BaseStringButton(parent, {.key = std::move(props.key), .maxLength = props.maxLength}),
|
||||
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)) {}
|
||||
|
||||
} // namespace dusk::ui
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "select_button.hpp"
|
||||
|
||||
#include <RmlUi/Config/Config.h>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class BaseStringButton : public ControlledSelectButton {
|
||||
public:
|
||||
struct Props {
|
||||
Rml::String key;
|
||||
Rml::String type = "text";
|
||||
int maxLength = -1;
|
||||
};
|
||||
|
||||
BaseStringButton(Rml::Element* parent, Props props);
|
||||
void update() override;
|
||||
void start_editing();
|
||||
void request_stop_editing(bool commit, bool refocusRoot);
|
||||
|
||||
protected:
|
||||
bool handle_nav_command(NavCommand cmd) override;
|
||||
virtual void set_value(Rml::String value) = 0;
|
||||
|
||||
private:
|
||||
void stop_editing(bool commit = true, bool refocusRoot = false);
|
||||
|
||||
Rml::ElementFormControlInput* mInputElem = nullptr;
|
||||
std::vector<std::unique_ptr<ScopedEventListener> > mInputListeners;
|
||||
Rml::String mType;
|
||||
int mMaxLength;
|
||||
bool mPendingStopEditing = false;
|
||||
bool mPendingCommit = true;
|
||||
bool mPendingRefocusRoot = false;
|
||||
};
|
||||
|
||||
class StringButton : public BaseStringButton {
|
||||
public:
|
||||
struct Props {
|
||||
Rml::String key;
|
||||
std::function<Rml::String()> getValue;
|
||||
std::function<void(Rml::String)> setValue;
|
||||
int maxLength = -1;
|
||||
};
|
||||
|
||||
StringButton(Rml::Element* parent, Props props);
|
||||
|
||||
protected:
|
||||
Rml::String format_value() override { return mGetValue(); }
|
||||
void set_value(Rml::String value) override {
|
||||
if (mSetValue) {
|
||||
mSetValue(std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<Rml::String()> mGetValue;
|
||||
std::function<void(Rml::String)> mSetValue;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
Reference in New Issue
Block a user