mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2025-10-30 08:03:03 +00:00
Implement navigation and focus styling for new UI framework (no manual overrides yet)
This commit is contained in:
parent
0b48ab9324
commit
67e1ddb70b
20 changed files with 315 additions and 27 deletions
|
|
@ -183,6 +183,7 @@ set (SOURCES
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/ui_api.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/ui_api.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/ui_api_events.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/ui_api_events.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/ui_api_images.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/ui_api_images.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ui/ui_utils.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/util/hsv.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/util/hsv.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/core/ui_context.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/core/ui_context.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/elements/ui_button.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/elements/ui_button.cpp
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ namespace recompui {
|
||||||
resource_slotmap resources;
|
resource_slotmap resources;
|
||||||
Rml::ElementDocument* document;
|
Rml::ElementDocument* document;
|
||||||
Element root_element;
|
Element root_element;
|
||||||
|
Element* autofocus_element = nullptr;
|
||||||
std::vector<Element*> loose_elements;
|
std::vector<Element*> loose_elements;
|
||||||
std::unordered_set<ResourceId> to_update;
|
std::unordered_set<ResourceId> to_update;
|
||||||
bool captures_input = true;
|
bool captures_input = true;
|
||||||
|
|
@ -72,6 +73,8 @@ enum class ContextErrorType {
|
||||||
DestroyResourceInWrongContext,
|
DestroyResourceInWrongContext,
|
||||||
DestroyResourceNotFound,
|
DestroyResourceNotFound,
|
||||||
GetDocumentInvalidContext,
|
GetDocumentInvalidContext,
|
||||||
|
GetAutofocusInvalidContext,
|
||||||
|
SetAutofocusInvalidContext,
|
||||||
InternalError,
|
InternalError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -134,6 +137,12 @@ void context_error(recompui::ContextId id, ContextErrorType type) {
|
||||||
case ContextErrorType::GetDocumentInvalidContext:
|
case ContextErrorType::GetDocumentInvalidContext:
|
||||||
error_message = "Attempted to get the document of an invalid UI context";
|
error_message = "Attempted to get the document of an invalid UI context";
|
||||||
break;
|
break;
|
||||||
|
case ContextErrorType::GetAutofocusInvalidContext:
|
||||||
|
error_message = "Attempted to get the autofocus element of an invalid UI context";
|
||||||
|
break;
|
||||||
|
case ContextErrorType::SetAutofocusInvalidContext:
|
||||||
|
error_message = "Attempted to set the autofocus element of an invalid UI context";
|
||||||
|
break;
|
||||||
case ContextErrorType::InternalError:
|
case ContextErrorType::InternalError:
|
||||||
error_message = "Internal error in UI context";
|
error_message = "Internal error in UI context";
|
||||||
break;
|
break;
|
||||||
|
|
@ -572,6 +581,28 @@ recompui::Element* recompui::ContextId::get_root_element() {
|
||||||
return &ctx->root_element;
|
return &ctx->root_element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recompui::Element* recompui::ContextId::get_autofocus_element() {
|
||||||
|
std::lock_guard lock{ context_state.all_contexts_lock };
|
||||||
|
|
||||||
|
Context* ctx = context_state.all_contexts.get(context_slotmap::key{ slot_id });
|
||||||
|
if (ctx == nullptr) {
|
||||||
|
context_error(*this, ContextErrorType::GetAutofocusInvalidContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx->autofocus_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recompui::ContextId::set_autofocus_element(Element* element) {
|
||||||
|
std::lock_guard lock{ context_state.all_contexts_lock };
|
||||||
|
|
||||||
|
Context* ctx = context_state.all_contexts.get(context_slotmap::key{ slot_id });
|
||||||
|
if (ctx == nullptr) {
|
||||||
|
context_error(*this, ContextErrorType::SetAutofocusInvalidContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->autofocus_element = element;
|
||||||
|
}
|
||||||
|
|
||||||
recompui::ContextId recompui::get_current_context() {
|
recompui::ContextId recompui::get_current_context() {
|
||||||
// Ensure a context is currently opened by this thread.
|
// Ensure a context is currently opened by this thread.
|
||||||
if (opened_context_id == ContextId::null()) {
|
if (opened_context_id == ContextId::null()) {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ namespace recompui {
|
||||||
|
|
||||||
Rml::ElementDocument* get_document();
|
Rml::ElementDocument* get_document();
|
||||||
Element* get_root_element();
|
Element* get_root_element();
|
||||||
|
Element* get_autofocus_element();
|
||||||
|
void set_autofocus_element(Element* element);
|
||||||
|
|
||||||
void open();
|
void open();
|
||||||
bool open_if_not_already();
|
bool open_if_not_already();
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@
|
||||||
|
|
||||||
namespace recompui {
|
namespace recompui {
|
||||||
|
|
||||||
Button::Button(Element *parent, const std::string &text, ButtonStyle style) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable), "button", true) {
|
Button::Button(Element *parent, const std::string &text, ButtonStyle style) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable, EventType::Focus), "button", true) {
|
||||||
this->style = style;
|
this->style = style;
|
||||||
|
|
||||||
|
enable_focus();
|
||||||
|
|
||||||
set_text(text);
|
set_text(text);
|
||||||
set_display(Display::Block);
|
set_display(Display::Block);
|
||||||
set_padding(23.0f);
|
set_padding(23.0f);
|
||||||
|
|
@ -21,6 +23,7 @@ namespace recompui {
|
||||||
set_color(Color{ 204, 204, 204, 255 });
|
set_color(Color{ 204, 204, 204, 255 });
|
||||||
set_tab_index(TabIndex::Auto);
|
set_tab_index(TabIndex::Auto);
|
||||||
hover_style.set_color(Color{ 242, 242, 242, 255 });
|
hover_style.set_color(Color{ 242, 242, 242, 255 });
|
||||||
|
focus_style.set_color(Color{ 242, 242, 242, 255 });
|
||||||
disabled_style.set_color(Color{ 204, 204, 204, 128 });
|
disabled_style.set_color(Color{ 204, 204, 204, 128 });
|
||||||
hover_disabled_style.set_color(Color{ 242, 242, 242, 128 });
|
hover_disabled_style.set_color(Color{ 242, 242, 242, 128 });
|
||||||
|
|
||||||
|
|
@ -34,6 +37,8 @@ namespace recompui {
|
||||||
set_background_color({ 185, 125, 242, background_opacity });
|
set_background_color({ 185, 125, 242, background_opacity });
|
||||||
hover_style.set_border_color({ 185, 125, 242, border_hover_opacity });
|
hover_style.set_border_color({ 185, 125, 242, border_hover_opacity });
|
||||||
hover_style.set_background_color({ 185, 125, 242, background_hover_opacity });
|
hover_style.set_background_color({ 185, 125, 242, background_hover_opacity });
|
||||||
|
focus_style.set_border_color({ 185, 125, 242, border_hover_opacity });
|
||||||
|
focus_style.set_background_color({ 185, 125, 242, background_hover_opacity });
|
||||||
disabled_style.set_border_color({ 185, 125, 242, border_opacity / 4 });
|
disabled_style.set_border_color({ 185, 125, 242, border_opacity / 4 });
|
||||||
disabled_style.set_background_color({ 185, 125, 242, background_opacity / 4 });
|
disabled_style.set_background_color({ 185, 125, 242, background_opacity / 4 });
|
||||||
hover_disabled_style.set_border_color({ 185, 125, 242, border_hover_opacity / 4 });
|
hover_disabled_style.set_border_color({ 185, 125, 242, border_hover_opacity / 4 });
|
||||||
|
|
@ -45,6 +50,8 @@ namespace recompui {
|
||||||
set_background_color({ 23, 214, 232, background_opacity });
|
set_background_color({ 23, 214, 232, background_opacity });
|
||||||
hover_style.set_border_color({ 23, 214, 232, border_hover_opacity });
|
hover_style.set_border_color({ 23, 214, 232, border_hover_opacity });
|
||||||
hover_style.set_background_color({ 23, 214, 232, background_hover_opacity });
|
hover_style.set_background_color({ 23, 214, 232, background_hover_opacity });
|
||||||
|
focus_style.set_border_color({ 23, 214, 232, border_hover_opacity });
|
||||||
|
focus_style.set_background_color({ 23, 214, 232, background_hover_opacity });
|
||||||
disabled_style.set_border_color({ 23, 214, 232, border_opacity / 4 });
|
disabled_style.set_border_color({ 23, 214, 232, border_opacity / 4 });
|
||||||
disabled_style.set_background_color({ 23, 214, 232, background_opacity / 4 });
|
disabled_style.set_background_color({ 23, 214, 232, background_opacity / 4 });
|
||||||
hover_disabled_style.set_border_color({ 23, 214, 232, border_hover_opacity / 4 });
|
hover_disabled_style.set_border_color({ 23, 214, 232, border_hover_opacity / 4 });
|
||||||
|
|
@ -57,6 +64,7 @@ namespace recompui {
|
||||||
}
|
}
|
||||||
|
|
||||||
add_style(&hover_style, hover_state);
|
add_style(&hover_style, hover_state);
|
||||||
|
add_style(&focus_style, focus_state);
|
||||||
add_style(&disabled_style, disabled_state);
|
add_style(&disabled_style, disabled_state);
|
||||||
add_style(&hover_disabled_style, { hover_state, disabled_state });
|
add_style(&hover_disabled_style, { hover_state, disabled_state });
|
||||||
|
|
||||||
|
|
@ -78,6 +86,9 @@ namespace recompui {
|
||||||
case EventType::Enable:
|
case EventType::Enable:
|
||||||
set_style_enabled(disabled_state, !std::get<EventEnable>(e.variant).active);
|
set_style_enabled(disabled_state, !std::get<EventEnable>(e.variant).active);
|
||||||
break;
|
break;
|
||||||
|
case EventType::Focus:
|
||||||
|
set_style_enabled(focus_state, std::get<EventFocus>(e.variant).active);
|
||||||
|
break;
|
||||||
case EventType::Update:
|
case EventType::Update:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace recompui {
|
||||||
protected:
|
protected:
|
||||||
ButtonStyle style = ButtonStyle::Primary;
|
ButtonStyle style = ButtonStyle::Primary;
|
||||||
Style hover_style;
|
Style hover_style;
|
||||||
|
Style focus_style;
|
||||||
Style disabled_style;
|
Style disabled_style;
|
||||||
Style hover_disabled_style;
|
Style hover_disabled_style;
|
||||||
std::list<std::function<void()>> pressed_callbacks;
|
std::list<std::function<void()>> pressed_callbacks;
|
||||||
|
|
@ -23,6 +24,7 @@ namespace recompui {
|
||||||
Button(Element *parent, const std::string &text, ButtonStyle style);
|
Button(Element *parent, const std::string &text, ButtonStyle style);
|
||||||
void add_pressed_callback(std::function<void()> callback);
|
void add_pressed_callback(std::function<void()> callback);
|
||||||
Style* get_hover_style() { return &hover_style; }
|
Style* get_hover_style() { return &hover_style; }
|
||||||
|
Style* get_focus_style() { return &focus_style; }
|
||||||
Style* get_disabled_style() { return &disabled_style; }
|
Style* get_disabled_style() { return &disabled_style; }
|
||||||
Style* get_hover_disabled_style() { return &hover_disabled_style; }
|
Style* get_hover_disabled_style() { return &hover_disabled_style; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ void Element::register_event_listeners(uint32_t events_enabled) {
|
||||||
this->events_enabled = events_enabled;
|
this->events_enabled = events_enabled;
|
||||||
|
|
||||||
if (events_enabled & Events(EventType::Click)) {
|
if (events_enabled & Events(EventType::Click)) {
|
||||||
base->AddEventListener(Rml::EventId::Mousedown, this);
|
base->AddEventListener(Rml::EventId::Click, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events_enabled & Events(EventType::Focus)) {
|
if (events_enabled & Events(EventType::Focus)) {
|
||||||
|
|
@ -94,11 +94,20 @@ void Element::register_event_listeners(uint32_t events_enabled) {
|
||||||
if (events_enabled & Events(EventType::Text)) {
|
if (events_enabled & Events(EventType::Text)) {
|
||||||
base->AddEventListener(Rml::EventId::Change, this);
|
base->AddEventListener(Rml::EventId::Change, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (events_enabled & Events(EventType::Navigate)) {
|
||||||
|
base->AddEventListener(Rml::EventId::Keydown, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Element::apply_style(Style *style) {
|
void Element::apply_style(Style *style) {
|
||||||
for (auto it : style->property_map) {
|
for (auto it : style->property_map) {
|
||||||
base->SetProperty(it.first, it.second);
|
// Skip redundant SetProperty calls to prevent dirtying unnecessary state.
|
||||||
|
// This avoids expensive layout operations when a simple color-only style is applied.
|
||||||
|
const Rml::Property* cur_value = base->GetLocalProperty(it.first);
|
||||||
|
if (*cur_value != it.second) {
|
||||||
|
base->SetProperty(it.first, it.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,9 +164,25 @@ void Element::ProcessEvent(Rml::Event &event) {
|
||||||
|
|
||||||
// Events that are processed during any phase.
|
// Events that are processed during any phase.
|
||||||
switch (event.GetId()) {
|
switch (event.GetId()) {
|
||||||
case Rml::EventId::Mousedown:
|
case Rml::EventId::Click:
|
||||||
handle_event(Event::click_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f)));
|
handle_event(Event::click_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f)));
|
||||||
break;
|
break;
|
||||||
|
case Rml::EventId::Keydown:
|
||||||
|
switch ((Rml::Input::KeyIdentifier)event.GetParameter<int>("key_identifier", 0)) {
|
||||||
|
case Rml::Input::KeyIdentifier::KI_LEFT:
|
||||||
|
handle_event(Event::navigate_event(NavDirection::Left));
|
||||||
|
break;
|
||||||
|
case Rml::Input::KeyIdentifier::KI_UP:
|
||||||
|
handle_event(Event::navigate_event(NavDirection::Up));
|
||||||
|
break;
|
||||||
|
case Rml::Input::KeyIdentifier::KI_RIGHT:
|
||||||
|
handle_event(Event::navigate_event(NavDirection::Right));
|
||||||
|
break;
|
||||||
|
case Rml::Input::KeyIdentifier::KI_DOWN:
|
||||||
|
handle_event(Event::navigate_event(NavDirection::Down));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Rml::EventId::Drag:
|
case Rml::EventId::Drag:
|
||||||
handle_event(Event::drag_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f), DragPhase::Move));
|
handle_event(Event::drag_event(event.GetParameter("mouse_x", 0.0f), event.GetParameter("mouse_y", 0.0f), DragPhase::Move));
|
||||||
break;
|
break;
|
||||||
|
|
@ -218,6 +243,15 @@ void Element::process_event(const Event &) {
|
||||||
// Does nothing by default.
|
// Does nothing by default.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Element::enable_focus() {
|
||||||
|
set_property(Rml::PropertyId::TabIndex, Rml::Style::TabIndex::Auto);
|
||||||
|
set_property(Rml::PropertyId::Focus, Rml::Style::Focus::Auto);
|
||||||
|
set_property(Rml::PropertyId::NavUp, Rml::Style::Nav::Auto);
|
||||||
|
set_property(Rml::PropertyId::NavDown, Rml::Style::Nav::Auto);
|
||||||
|
set_property(Rml::PropertyId::NavLeft, Rml::Style::Nav::Auto);
|
||||||
|
set_property(Rml::PropertyId::NavRight, Rml::Style::Nav::Auto);
|
||||||
|
}
|
||||||
|
|
||||||
void Element::clear_children() {
|
void Element::clear_children() {
|
||||||
if (children.empty()) {
|
if (children.empty()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -352,6 +386,10 @@ void Element::set_style_enabled(std::string_view style_name, bool enable) {
|
||||||
apply_styles();
|
apply_styles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Element::is_style_enabled(std::string_view style_name) {
|
||||||
|
return style_active_set.contains(style_name);
|
||||||
|
}
|
||||||
|
|
||||||
float Element::get_absolute_left() {
|
float Element::get_absolute_left() {
|
||||||
return base->GetAbsoluteLeft();
|
return base->GetAbsoluteLeft();
|
||||||
}
|
}
|
||||||
|
|
@ -409,6 +447,10 @@ double Element::get_input_value_double() {
|
||||||
}, value);
|
}, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Element::focus() {
|
||||||
|
base->Focus();
|
||||||
|
}
|
||||||
|
|
||||||
void Element::queue_update() {
|
void Element::queue_update() {
|
||||||
ContextId cur_context = get_current_context();
|
ContextId cur_context = get_current_context();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ private:
|
||||||
void add_child(Element *child);
|
void add_child(Element *child);
|
||||||
void register_event_listeners(uint32_t events_enabled);
|
void register_event_listeners(uint32_t events_enabled);
|
||||||
void apply_style(Style *style);
|
void apply_style(Style *style);
|
||||||
void apply_styles();
|
|
||||||
void propagate_disabled(bool disabled);
|
void propagate_disabled(bool disabled);
|
||||||
void handle_event(const Event &e);
|
void handle_event(const Event &e);
|
||||||
|
|
||||||
|
|
@ -76,6 +75,8 @@ public:
|
||||||
void set_input_text(std::string_view text);
|
void set_input_text(std::string_view text);
|
||||||
void set_src(std::string_view src);
|
void set_src(std::string_view src);
|
||||||
void set_style_enabled(std::string_view style_name, bool enabled);
|
void set_style_enabled(std::string_view style_name, bool enabled);
|
||||||
|
bool is_style_enabled(std::string_view style_name);
|
||||||
|
void apply_styles();
|
||||||
bool is_element() override { return true; }
|
bool is_element() override { return true; }
|
||||||
float get_absolute_left();
|
float get_absolute_left();
|
||||||
float get_absolute_top();
|
float get_absolute_top();
|
||||||
|
|
@ -83,6 +84,8 @@ public:
|
||||||
float get_client_top();
|
float get_client_top();
|
||||||
float get_client_width();
|
float get_client_width();
|
||||||
float get_client_height();
|
float get_client_height();
|
||||||
|
void enable_focus();
|
||||||
|
void focus();
|
||||||
void queue_update();
|
void queue_update();
|
||||||
void register_callback(ContextId context, PTR(void) callback, PTR(void) userdata);
|
void register_callback(ContextId context, PTR(void) callback, PTR(void) userdata);
|
||||||
uint32_t get_input_value_u32();
|
uint32_t get_input_value_u32();
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
#include "overloaded.h"
|
#include "overloaded.h"
|
||||||
#include "ui_radio.h"
|
#include "ui_radio.h"
|
||||||
|
#include "../ui_utils.h"
|
||||||
|
|
||||||
namespace recompui {
|
namespace recompui {
|
||||||
|
|
||||||
// RadioOption
|
// RadioOption
|
||||||
|
|
||||||
RadioOption::RadioOption(Element *parent, std::string_view name, uint32_t index) : Element(parent, Events(EventType::Click, EventType::Focus, EventType::Hover, EventType::Enable), "label", true) {
|
RadioOption::RadioOption(Element *parent, std::string_view name, uint32_t index) : Element(parent, Events(EventType::Click, EventType::Focus, EventType::Hover, EventType::Enable, EventType::Update), "label", true) {
|
||||||
this->index = index;
|
this->index = index;
|
||||||
|
|
||||||
|
enable_focus();
|
||||||
set_text(name);
|
set_text(name);
|
||||||
set_cursor(Cursor::Pointer);
|
set_cursor(Cursor::Pointer);
|
||||||
set_font_size(20.0f);
|
set_font_size(20.0f);
|
||||||
|
|
@ -24,9 +26,11 @@ namespace recompui {
|
||||||
hover_style.set_color(Color{ 255, 255, 255, 204 });
|
hover_style.set_color(Color{ 255, 255, 255, 204 });
|
||||||
checked_style.set_color(Color{ 255, 255, 255, 255 });
|
checked_style.set_color(Color{ 255, 255, 255, 255 });
|
||||||
checked_style.set_border_color(Color{ 242, 242, 242, 255 });
|
checked_style.set_border_color(Color{ 242, 242, 242, 255 });
|
||||||
|
pulsing_style.set_border_color(Color{ 23, 214, 232, 244 });
|
||||||
|
|
||||||
add_style(&hover_style, { hover_state });
|
add_style(&hover_style, { hover_state });
|
||||||
add_style(&checked_style, { checked_state });
|
add_style(&checked_style, { checked_state });
|
||||||
|
add_style(&pulsing_style, { focus_state });
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioOption::set_pressed_callback(std::function<void(uint32_t)> callback) {
|
void RadioOption::set_pressed_callback(std::function<void(uint32_t)> callback) {
|
||||||
|
|
@ -48,6 +52,22 @@ namespace recompui {
|
||||||
case EventType::Enable:
|
case EventType::Enable:
|
||||||
set_style_enabled(disabled_state, !std::get<EventEnable>(e.variant).active);
|
set_style_enabled(disabled_state, !std::get<EventEnable>(e.variant).active);
|
||||||
break;
|
break;
|
||||||
|
case EventType::Focus:
|
||||||
|
{
|
||||||
|
bool active = std::get<EventFocus>(e.variant).active;
|
||||||
|
set_style_enabled(focus_state, active);
|
||||||
|
if (active) {
|
||||||
|
queue_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EventType::Update:
|
||||||
|
if (is_style_enabled(focus_state)) {
|
||||||
|
pulsing_style.set_color(recompui::get_pulse_color(750));
|
||||||
|
apply_styles();
|
||||||
|
queue_update();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ namespace recompui {
|
||||||
private:
|
private:
|
||||||
Style hover_style;
|
Style hover_style;
|
||||||
Style checked_style;
|
Style checked_style;
|
||||||
|
Style pulsing_style;
|
||||||
std::function<void(uint32_t)> pressed_callback = nullptr;
|
std::function<void(uint32_t)> pressed_callback = nullptr;
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "overloaded.h"
|
#include "overloaded.h"
|
||||||
#include "ui_slider.h"
|
#include "ui_slider.h"
|
||||||
|
#include "../ui_utils.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
|
|
@ -45,7 +46,6 @@ namespace recompui {
|
||||||
|
|
||||||
void Slider::update_circle_position() {
|
void Slider::update_circle_position() {
|
||||||
double ratio = std::clamp((value - min_value) / (max_value - min_value), 0.0, 1.0);
|
double ratio = std::clamp((value - min_value) / (max_value - min_value), 0.0, 1.0);
|
||||||
float slider_relative_left = slider_element->get_absolute_left() - get_absolute_left();
|
|
||||||
circle_element->set_left(ratio * 100.0, Unit::Percent);
|
circle_element->set_left(ratio * 100.0, Unit::Percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +72,42 @@ namespace recompui {
|
||||||
}, val);
|
}, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Slider::Slider(Element *parent, SliderType type) : Element(parent) {
|
void Slider::process_event(const Event& e) {
|
||||||
|
switch (e.type) {
|
||||||
|
case EventType::Focus:
|
||||||
|
{
|
||||||
|
bool active = std::get<EventFocus>(e.variant).active;
|
||||||
|
circle_element->set_style_enabled(focus_state, active);
|
||||||
|
if (active) {
|
||||||
|
queue_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EventType::Update:
|
||||||
|
if (circle_element->is_style_enabled(focus_state)) {
|
||||||
|
circle_element->set_background_color(recompui::get_pulse_color(750));
|
||||||
|
queue_update();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
circle_element->set_background_color(Color{ 204, 204, 204, 255 });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EventType::Navigate:
|
||||||
|
{
|
||||||
|
NavDirection dir = std::get<EventNavigate>(e.variant).direction;
|
||||||
|
if (dir == NavDirection::Left) {
|
||||||
|
do_step(false);
|
||||||
|
}
|
||||||
|
else if (dir == NavDirection::Right) {
|
||||||
|
do_step(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider::Slider(Element *parent, SliderType type) : Element(parent, Events(EventType::Focus, EventType::Update, EventType::Navigate)) {
|
||||||
this->type = type;
|
this->type = type;
|
||||||
|
|
||||||
set_display(Display::Flex);
|
set_display(Display::Flex);
|
||||||
|
|
@ -80,6 +115,10 @@ namespace recompui {
|
||||||
set_text_align(TextAlign::Left);
|
set_text_align(TextAlign::Left);
|
||||||
set_min_width(120.0f);
|
set_min_width(120.0f);
|
||||||
|
|
||||||
|
enable_focus();
|
||||||
|
set_nav_none(NavDirection::Left);
|
||||||
|
set_nav_none(NavDirection::Right);
|
||||||
|
|
||||||
ContextId context = get_current_context();
|
ContextId context = get_current_context();
|
||||||
|
|
||||||
value_label = context.create_element<Label>(this, "0", LabelStyle::Small);
|
value_label = context.create_element<Label>(this, "0", LabelStyle::Small);
|
||||||
|
|
@ -87,8 +126,10 @@ namespace recompui {
|
||||||
value_label->set_min_width(60.0f);
|
value_label->set_min_width(60.0f);
|
||||||
value_label->set_max_width(60.0f);
|
value_label->set_max_width(60.0f);
|
||||||
|
|
||||||
slider_element = context.create_element<Element>(this);
|
slider_element = context.create_element<Clickable>(this, true);
|
||||||
slider_element->set_flex(1.0f, 0.0f);
|
slider_element->set_flex(1.0f, 0.0f);
|
||||||
|
slider_element->add_pressed_callback([this](float x, float y){ bar_clicked(x, y); focus(); });
|
||||||
|
slider_element->add_dragged_callback([this](float x, float y, recompui::DragPhase phase){ bar_dragged(x, y, phase); focus(); });
|
||||||
|
|
||||||
{
|
{
|
||||||
bar_element = context.create_element<Clickable>(slider_element, true);
|
bar_element = context.create_element<Clickable>(slider_element, true);
|
||||||
|
|
@ -96,8 +137,8 @@ namespace recompui {
|
||||||
bar_element->set_height(2.0f);
|
bar_element->set_height(2.0f);
|
||||||
bar_element->set_margin_top(8.0f);
|
bar_element->set_margin_top(8.0f);
|
||||||
bar_element->set_background_color(Color{ 255, 255, 255, 50 });
|
bar_element->set_background_color(Color{ 255, 255, 255, 50 });
|
||||||
bar_element->add_pressed_callback([this](float x, float y){ bar_clicked(x, y); });
|
bar_element->add_pressed_callback([this](float x, float y){ bar_clicked(x, y); focus(); });
|
||||||
bar_element->add_dragged_callback([this](float x, float y, recompui::DragPhase phase){ bar_dragged(x, y, phase); });
|
bar_element->add_dragged_callback([this](float x, float y, recompui::DragPhase phase){ bar_dragged(x, y, phase); focus(); });
|
||||||
|
|
||||||
circle_element = context.create_element<Clickable>(bar_element, true);
|
circle_element = context.create_element<Clickable>(bar_element, true);
|
||||||
circle_element->set_position(Position::Relative);
|
circle_element->set_position(Position::Relative);
|
||||||
|
|
@ -108,7 +149,8 @@ namespace recompui {
|
||||||
circle_element->set_margin_left(-8.0f);
|
circle_element->set_margin_left(-8.0f);
|
||||||
circle_element->set_background_color(Color{ 204, 204, 204, 255 });
|
circle_element->set_background_color(Color{ 204, 204, 204, 255 });
|
||||||
circle_element->set_border_radius(8.0f);
|
circle_element->set_border_radius(8.0f);
|
||||||
circle_element->add_dragged_callback([this](float x, float y, recompui::DragPhase phase){ circle_dragged(x, y, phase); });
|
circle_element->add_pressed_callback([this](float, float){ focus(); });
|
||||||
|
circle_element->add_dragged_callback([this](float x, float y, recompui::DragPhase phase){ circle_dragged(x, y, phase); focus(); });
|
||||||
circle_element->set_cursor(Cursor::Pointer);
|
circle_element->set_cursor(Cursor::Pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,4 +196,18 @@ namespace recompui {
|
||||||
value_changed_callbacks.emplace_back(callback);
|
value_changed_callbacks.emplace_back(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Slider::do_step(bool increment) {
|
||||||
|
double new_value = value;
|
||||||
|
if (increment) {
|
||||||
|
new_value += step_value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_value -= step_value;
|
||||||
|
}
|
||||||
|
new_value = std::clamp(new_value, min_value, max_value);
|
||||||
|
if (new_value != value) {
|
||||||
|
set_value_internal(new_value, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace recompui
|
} // namespace recompui
|
||||||
|
|
@ -15,7 +15,7 @@ namespace recompui {
|
||||||
private:
|
private:
|
||||||
SliderType type = SliderType::Percent;
|
SliderType type = SliderType::Percent;
|
||||||
Label *value_label = nullptr;
|
Label *value_label = nullptr;
|
||||||
Element *slider_element = nullptr;
|
Clickable *slider_element = nullptr;
|
||||||
Clickable *bar_element = nullptr;
|
Clickable *bar_element = nullptr;
|
||||||
Clickable *circle_element = nullptr;
|
Clickable *circle_element = nullptr;
|
||||||
double value = 50.0;
|
double value = 50.0;
|
||||||
|
|
@ -34,6 +34,9 @@ namespace recompui {
|
||||||
void set_input_value(const ElementValue& val) override;
|
void set_input_value(const ElementValue& val) override;
|
||||||
ElementValue get_element_value() override { return get_value(); }
|
ElementValue get_element_value() override { return get_value(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void process_event(const Event &e) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Slider(Element *parent, SliderType type);
|
Slider(Element *parent, SliderType type);
|
||||||
virtual ~Slider();
|
virtual ~Slider();
|
||||||
|
|
@ -46,6 +49,7 @@ namespace recompui {
|
||||||
void set_step_value(double v);
|
void set_step_value(double v);
|
||||||
double get_step_value() const;
|
double get_step_value() const;
|
||||||
void add_value_changed_callback(std::function<void(double)> callback);
|
void add_value_changed_callback(std::function<void(double)> callback);
|
||||||
|
void do_step(bool increment);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace recompui
|
} // namespace recompui
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,22 @@ namespace recompui {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Rml::PropertyId nav_to_property(NavDirection dir) {
|
||||||
|
switch (dir) {
|
||||||
|
case NavDirection::Up:
|
||||||
|
return Rml::PropertyId::NavUp;
|
||||||
|
case NavDirection::Right:
|
||||||
|
return Rml::PropertyId::NavRight;
|
||||||
|
case NavDirection::Down:
|
||||||
|
return Rml::PropertyId::NavDown;
|
||||||
|
case NavDirection::Left:
|
||||||
|
return Rml::PropertyId::NavLeft;
|
||||||
|
default:
|
||||||
|
assert(false && "Unknown nav direction.");
|
||||||
|
return Rml::PropertyId::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Style::set_property(Rml::PropertyId property_id, const Rml::Property &property) {
|
void Style::set_property(Rml::PropertyId property_id, const Rml::Property &property) {
|
||||||
property_map[property_id] = property;
|
property_map[property_id] = property;
|
||||||
}
|
}
|
||||||
|
|
@ -471,6 +487,12 @@ namespace recompui {
|
||||||
case FlexDirection::Column:
|
case FlexDirection::Column:
|
||||||
set_property(Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column);
|
set_property(Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column);
|
||||||
break;
|
break;
|
||||||
|
case FlexDirection::RowReverse:
|
||||||
|
set_property(Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::RowReverse);
|
||||||
|
break;
|
||||||
|
case FlexDirection::ColumnReverse:
|
||||||
|
set_property(Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::ColumnReverse);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false && "Unknown flex direction.");
|
assert(false && "Unknown flex direction.");
|
||||||
break;
|
break;
|
||||||
|
|
@ -556,5 +578,22 @@ namespace recompui {
|
||||||
void Style::set_font_family(std::string_view family) {
|
void Style::set_font_family(std::string_view family) {
|
||||||
set_property(Rml::PropertyId::FontFamily, Rml::Property(Rml::String{ family }, Rml::Unit::UNKNOWN));
|
set_property(Rml::PropertyId::FontFamily, Rml::Property(Rml::String{ family }, Rml::Unit::UNKNOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Style::set_nav_auto(NavDirection dir) {
|
||||||
|
set_property(nav_to_property(dir), Rml::Style::Nav::Auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Style::set_nav_none(NavDirection dir) {
|
||||||
|
set_property(nav_to_property(dir), Rml::Style::Nav::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Style::set_tab_index_auto() {
|
||||||
|
set_property(Rml::PropertyId::TabIndex, Rml::Style::Nav::Auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Style::set_tab_index_none() {
|
||||||
|
set_property(Rml::PropertyId::TabIndex, Rml::Style::Nav::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace recompui
|
} // namespace recompui
|
||||||
|
|
@ -94,6 +94,11 @@ namespace recompui {
|
||||||
void set_drag(Drag drag);
|
void set_drag(Drag drag);
|
||||||
void set_tab_index(TabIndex focus);
|
void set_tab_index(TabIndex focus);
|
||||||
void set_font_family(std::string_view family);
|
void set_font_family(std::string_view family);
|
||||||
|
// TODO set_nav with Element*
|
||||||
|
void set_nav_auto(NavDirection dir);
|
||||||
|
void set_nav_none(NavDirection dir);
|
||||||
|
void set_tab_index_auto();
|
||||||
|
void set_tab_index_none();
|
||||||
virtual bool is_element() { return false; }
|
virtual bool is_element() { return false; }
|
||||||
ResourceId get_resource_id() { return resource_id; }
|
ResourceId get_resource_id() { return resource_id; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
namespace recompui {
|
namespace recompui {
|
||||||
|
|
||||||
Toggle::Toggle(Element *parent) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable), "button") {
|
Toggle::Toggle(Element *parent) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Enable), "button") {
|
||||||
|
enable_focus();
|
||||||
|
|
||||||
set_width(162.0f);
|
set_width(162.0f);
|
||||||
set_height(72.0f);
|
set_height(72.0f);
|
||||||
set_border_radius(36.0f);
|
set_border_radius(36.0f);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ namespace recompui {
|
||||||
|
|
||||||
constexpr std::string_view checked_state = "checked";
|
constexpr std::string_view checked_state = "checked";
|
||||||
constexpr std::string_view hover_state = "hover";
|
constexpr std::string_view hover_state = "hover";
|
||||||
|
constexpr std::string_view focus_state = "focus";
|
||||||
constexpr std::string_view disabled_state = "disabled";
|
constexpr std::string_view disabled_state = "disabled";
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
|
|
@ -31,6 +32,7 @@ namespace recompui {
|
||||||
Drag,
|
Drag,
|
||||||
Text,
|
Text,
|
||||||
Update,
|
Update,
|
||||||
|
Navigate,
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,6 +43,13 @@ namespace recompui {
|
||||||
End
|
End
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class NavDirection {
|
||||||
|
Up,
|
||||||
|
Right,
|
||||||
|
Down,
|
||||||
|
Left
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Enum, typename = std::enable_if_t<std::is_enum_v<Enum>>>
|
template <typename Enum, typename = std::enable_if_t<std::is_enum_v<Enum>>>
|
||||||
constexpr uint32_t Events(Enum first) {
|
constexpr uint32_t Events(Enum first) {
|
||||||
return 1u << static_cast<uint32_t>(first);
|
return 1u << static_cast<uint32_t>(first);
|
||||||
|
|
@ -78,7 +87,11 @@ namespace recompui {
|
||||||
std::string text;
|
std::string text;
|
||||||
};
|
};
|
||||||
|
|
||||||
using EventVariant = std::variant<EventClick, EventFocus, EventHover, EventEnable, EventDrag, EventText, std::monostate>;
|
struct EventNavigate {
|
||||||
|
NavDirection direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
using EventVariant = std::variant<EventClick, EventFocus, EventHover, EventEnable, EventDrag, EventText, EventNavigate, std::monostate>;
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
EventType type;
|
EventType type;
|
||||||
|
|
@ -133,6 +146,13 @@ namespace recompui {
|
||||||
e.variant = std::monostate{};
|
e.variant = std::monostate{};
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Event navigate_event(NavDirection direction) {
|
||||||
|
Event e;
|
||||||
|
e.type = EventType::Navigate;
|
||||||
|
e.variant = EventNavigate{ direction };
|
||||||
|
return e;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Display {
|
enum class Display {
|
||||||
|
|
@ -173,7 +193,9 @@ namespace recompui {
|
||||||
|
|
||||||
enum class FlexDirection {
|
enum class FlexDirection {
|
||||||
Row,
|
Row,
|
||||||
Column
|
Column,
|
||||||
|
RowReverse,
|
||||||
|
ColumnReverse
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AlignItems {
|
enum class AlignItems {
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ ModEntryButton::ModEntryButton(Element *parent, uint32_t mod_index) : Element(pa
|
||||||
this->mod_index = mod_index;
|
this->mod_index = mod_index;
|
||||||
|
|
||||||
set_drag(Drag::Drag);
|
set_drag(Drag::Drag);
|
||||||
|
enable_focus();
|
||||||
|
|
||||||
ContextId context = get_current_context();
|
ContextId context = get_current_context();
|
||||||
view = context.create_element<ModEntryView>(this);
|
view = context.create_element<ModEntryView>(this);
|
||||||
|
|
@ -145,13 +146,12 @@ void ModEntryButton::set_selected(bool selected) {
|
||||||
void ModEntryButton::process_event(const Event& e) {
|
void ModEntryButton::process_event(const Event& e) {
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case EventType::Click:
|
case EventType::Click:
|
||||||
|
case EventType::Focus:
|
||||||
selected_callback(mod_index);
|
selected_callback(mod_index);
|
||||||
break;
|
break;
|
||||||
case EventType::Hover:
|
case EventType::Hover:
|
||||||
view->set_style_enabled(hover_state, std::get<EventHover>(e.variant).active);
|
view->set_style_enabled(hover_state, std::get<EventHover>(e.variant).active);
|
||||||
break;
|
break;
|
||||||
case EventType::Focus:
|
|
||||||
break;
|
|
||||||
case EventType::Drag:
|
case EventType::Drag:
|
||||||
drag_callback(mod_index, std::get<EventDrag>(e.variant));
|
drag_callback(mod_index, std::get<EventDrag>(e.variant));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -124,13 +124,16 @@ void recompui::init_prompt_context() {
|
||||||
prompt_state.confirm_button->set_text_align(TextAlign::Center);
|
prompt_state.confirm_button->set_text_align(TextAlign::Center);
|
||||||
prompt_state.confirm_button->set_color(Color{ 204, 204, 204, 255 });
|
prompt_state.confirm_button->set_color(Color{ 204, 204, 204, 255 });
|
||||||
prompt_state.confirm_button->add_pressed_callback(run_confirm_callback);
|
prompt_state.confirm_button->add_pressed_callback(run_confirm_callback);
|
||||||
// TODO nav: autofocus
|
|
||||||
// TODO nav: nav-left: none; nav-right: cancel_button
|
|
||||||
|
|
||||||
Style* confirm_hover_style = prompt_state.confirm_button->get_hover_style();
|
Style* confirm_hover_style = prompt_state.confirm_button->get_hover_style();
|
||||||
confirm_hover_style->set_border_color(Color{ 69, 208, 67, 255 });
|
confirm_hover_style->set_border_color(Color{ 69, 208, 67, 255 });
|
||||||
confirm_hover_style->set_background_color(Color{ 69, 208, 67, 76 });
|
confirm_hover_style->set_background_color(Color{ 69, 208, 67, 76 });
|
||||||
confirm_hover_style->set_color(Color{ 242, 242, 242, 255 });
|
confirm_hover_style->set_color(Color{ 242, 242, 242, 255 });
|
||||||
|
|
||||||
|
Style* confirm_focus_style = prompt_state.confirm_button->get_focus_style();
|
||||||
|
confirm_focus_style->set_border_color(Color{ 69, 208, 67, 255 });
|
||||||
|
confirm_focus_style->set_background_color(Color{ 69, 208, 67, 76 });
|
||||||
|
confirm_focus_style->set_color(Color{ 242, 242, 242, 255 });
|
||||||
|
|
||||||
prompt_state.cancel_button = context.create_element<Button>(prompt_state.prompt_controls, "", ButtonStyle::Primary);
|
prompt_state.cancel_button = context.create_element<Button>(prompt_state.prompt_controls, "", ButtonStyle::Primary);
|
||||||
prompt_state.cancel_button->set_min_width(185.0f, Unit::Dp);
|
prompt_state.cancel_button->set_min_width(185.0f, Unit::Dp);
|
||||||
|
|
@ -141,13 +144,18 @@ void recompui::init_prompt_context() {
|
||||||
prompt_state.cancel_button->set_text_align(TextAlign::Center);
|
prompt_state.cancel_button->set_text_align(TextAlign::Center);
|
||||||
prompt_state.cancel_button->set_color(Color{ 204, 204, 204, 255 });
|
prompt_state.cancel_button->set_color(Color{ 204, 204, 204, 255 });
|
||||||
prompt_state.cancel_button->add_pressed_callback(run_cancel_callback);
|
prompt_state.cancel_button->add_pressed_callback(run_cancel_callback);
|
||||||
// TODO nav: nav-left: confirm_button; nav-right: none
|
|
||||||
|
|
||||||
Style* cancel_hover_style = prompt_state.cancel_button->get_hover_style();
|
Style* cancel_hover_style = prompt_state.cancel_button->get_hover_style();
|
||||||
cancel_hover_style->set_border_color(Color{ 248, 96, 57, 255 });
|
cancel_hover_style->set_border_color(Color{ 248, 96, 57, 255 });
|
||||||
cancel_hover_style->set_background_color(Color{ 248, 96, 57, 76 });
|
cancel_hover_style->set_background_color(Color{ 248, 96, 57, 76 });
|
||||||
cancel_hover_style->set_color(Color{ 242, 242, 242, 255 });
|
cancel_hover_style->set_color(Color{ 242, 242, 242, 255 });
|
||||||
|
|
||||||
|
Style* cancel_focus_style = prompt_state.cancel_button->get_focus_style();
|
||||||
|
cancel_focus_style->set_border_color(Color{ 248, 96, 57, 255 });
|
||||||
|
cancel_focus_style->set_background_color(Color{ 248, 96, 57, 76 });
|
||||||
|
cancel_focus_style->set_color(Color{ 242, 242, 242, 255 });
|
||||||
|
|
||||||
|
|
||||||
context.close();
|
context.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,6 +200,10 @@ void style_button(recompui::Button* button, recompui::ButtonVariant variant) {
|
||||||
recompui::Style* hover_style = button->get_hover_style();
|
recompui::Style* hover_style = button->get_hover_style();
|
||||||
hover_style->set_border_color(hover_border_color);
|
hover_style->set_border_color(hover_border_color);
|
||||||
hover_style->set_background_color(hover_background_color);
|
hover_style->set_background_color(hover_background_color);
|
||||||
|
|
||||||
|
recompui::Style* focus_style = button->get_focus_style();
|
||||||
|
focus_style->set_border_color(hover_border_color);
|
||||||
|
focus_style->set_background_color(hover_background_color);
|
||||||
|
|
||||||
recompui::Color disabled_color { 255, 255, 255, 0.6f * 255 };
|
recompui::Color disabled_color { 255, 255, 255, 0.6f * 255 };
|
||||||
recompui::Style* disabled_style = button->get_disabled_style();
|
recompui::Style* disabled_style = button->get_disabled_style();
|
||||||
|
|
@ -200,6 +212,13 @@ void style_button(recompui::Button* button, recompui::ButtonVariant variant) {
|
||||||
|
|
||||||
// Must be called while prompt_state.mutex is locked.
|
// Must be called while prompt_state.mutex is locked.
|
||||||
void show_prompt(std::function<void()>& prev_cancel_action, bool focus_on_cancel) {
|
void show_prompt(std::function<void()>& prev_cancel_action, bool focus_on_cancel) {
|
||||||
|
if (focus_on_cancel) {
|
||||||
|
prompt_state.ui_context.set_autofocus_element(prompt_state.cancel_button);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prompt_state.ui_context.set_autofocus_element(prompt_state.confirm_button);
|
||||||
|
}
|
||||||
|
|
||||||
if (!recompui::is_context_shown(prompt_state.ui_context)) {
|
if (!recompui::is_context_shown(prompt_state.ui_context)) {
|
||||||
recompui::show_context(prompt_state.ui_context, "");
|
recompui::show_context(prompt_state.ui_context, "");
|
||||||
}
|
}
|
||||||
|
|
@ -209,13 +228,6 @@ void show_prompt(std::function<void()>& prev_cancel_action, bool focus_on_cancel
|
||||||
prev_cancel_action();
|
prev_cancel_action();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focus_on_cancel) {
|
|
||||||
// TODO nav: focus cancel button
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO nav: focus confirm button
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void recompui::open_choice_prompt(
|
void recompui::open_choice_prompt(
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,10 @@ public:
|
||||||
|
|
||||||
document->PullToFront();
|
document->PullToFront();
|
||||||
document->Show();
|
document->Show();
|
||||||
|
recompui::Element* default_element = context.get_autofocus_element();
|
||||||
|
if (default_element) {
|
||||||
|
default_element->focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hide_context(recompui::ContextId context) {
|
void hide_context(recompui::ContextId context) {
|
||||||
|
|
|
||||||
20
src/ui/ui_utils.cpp
Normal file
20
src/ui/ui_utils.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "ultramodern/ultramodern.hpp"
|
||||||
|
|
||||||
|
#include "ui_utils.h"
|
||||||
|
|
||||||
|
recompui::Color recompui::lerp_color(const recompui::Color& a, const recompui::Color& b, float factor) {
|
||||||
|
return recompui::Color{
|
||||||
|
static_cast<uint8_t>(std::lerp(float(a.r), float(b.r), factor)),
|
||||||
|
static_cast<uint8_t>(std::lerp(float(a.g), float(b.g), factor)),
|
||||||
|
static_cast<uint8_t>(std::lerp(float(a.b), float(b.b), factor)),
|
||||||
|
static_cast<uint8_t>(std::lerp(float(a.a), float(b.a), factor)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
recompui::Color recompui::get_pulse_color(uint32_t pulse_milliseconds) {
|
||||||
|
uint64_t millis = std::chrono::duration_cast<std::chrono::milliseconds>(ultramodern::time_since_start()).count();
|
||||||
|
uint32_t anim_offset = millis % pulse_milliseconds;
|
||||||
|
|
||||||
|
float factor = std::abs((2.0f * anim_offset / pulse_milliseconds) - 1.0f);
|
||||||
|
return lerp_color(Color{ 23, 214, 232, 255 }, Color{ 162, 239, 246, 255 }, factor);
|
||||||
|
}
|
||||||
11
src/ui/ui_utils.h
Normal file
11
src/ui/ui_utils.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef __UI_UTILS_H__
|
||||||
|
#define __UI_UTILS_H__
|
||||||
|
|
||||||
|
#include "elements/ui_types.h"
|
||||||
|
|
||||||
|
namespace recompui {
|
||||||
|
Color lerp_color(const Color& a, const Color& b, float factor);
|
||||||
|
Color get_pulse_color(uint32_t millisecond_period);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Reference in a new issue