Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions recompui/src/base/ui_game_option.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ namespace recompui {
}

void GameOption::process_event(const Event &e) {
if (event_callback != nullptr) {
bool cancel = event_callback(e);
if (cancel) {
return;
}
}

switch (e.type) {
case EventType::Click:
if (is_enabled()) {
Expand Down Expand Up @@ -116,4 +123,8 @@ namespace recompui {
void GameOption::set_callback(std::function<void()> new_callback) {
callback = new_callback;
}

void GameOption::set_event_callback(std::function<bool(const Event& e)> new_callback) {
event_callback = new_callback;
}
}
2 changes: 2 additions & 0 deletions recompui/src/base/ui_game_option.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace recompui {
private:
std::string title;
std::function<void()> callback;
std::function<bool(const Event& e)> event_callback = nullptr;
protected:
Label *label;
void set_styles();
Expand All @@ -19,6 +20,7 @@ namespace recompui {
GameOption(ResourceId rid, Element* parent, const std::string& title, std::function<void()> callback, GameOptionsMenuLayout layout);
void set_title(const std::string& new_title);
void set_callback(std::function<void()> new_callback);
void set_event_callback(std::function<bool(const Event& e)> new_callback);
Label* get_label() { return label; }
// These are public so you can modify them.
Style hover_style;
Expand Down
129 changes: 129 additions & 0 deletions recompui/src/elements/ui_style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,135 @@ namespace recompui {
set_property(Rml::PropertyId::Focus, focusable ? Rml::Style::Focus::Auto : Rml::Style::Focus::None);
}

const std::unordered_map<Style::DecoratorType, const std::string> Style::decorator_type_names = {
{Style::DecoratorType::TiledHorizontal , "tiled-horizontal"},
{Style::DecoratorType::TiledVertical , "tiled-vertical"},
{Style::DecoratorType::TiledBox , "tiled-box"},
{Style::DecoratorType::Image , "image"},
{Style::DecoratorType::NinePatch , "ninepatch"},
{Style::DecoratorType::Gradient , "gradient"},
{Style::DecoratorType::HorizontalGradient , "horizontal-gradient"},
{Style::DecoratorType::VerticalGradient , "vertical-gradient"},
{Style::DecoratorType::Shader , "shader"},
{Style::DecoratorType::LinearGradient , "linear-gradient"},
{Style::DecoratorType::RepeatingLinearGradient , "repeating-linear-gradient"},
{Style::DecoratorType::RadialGradient , "radial-gradient"},
{Style::DecoratorType::RepeatingRadialGradient , "repeating-radial-gradient"},
{Style::DecoratorType::ConicGradient , "conic-gradient"},
{Style::DecoratorType::RepeatingConicGradient , "repeating-conic-gradient"},
};

Rml::DecoratorsPtr Style::get_existing_decorators() {
if (property_map.find(Rml::PropertyId::Decorator) != property_map.end()) {
auto cur_decorators = property_map[Rml::PropertyId::Decorator].Get<Rml::DecoratorsPtr>();
if (cur_decorators != nullptr) {
return cur_decorators;
}
}

return nullptr;
}

Rml::DecoratorInstancer* Style::get_decorator_instancer(DecoratorType decorator_type) {
std::string decorator_type_name = decorator_type_names.at(decorator_type);
return Rml::Factory::GetDecoratorInstancer(decorator_type_name);
}

void Style::set_decorator(DecoratorType decorator_type, Rml::PropertyDictionary properties) {
Rml::DecoratorDeclarationList decorators;
Rml::DecoratorsPtr existing_decorator = get_existing_decorators();
bool found_existing = false;
std::string decorator_type_name = decorator_type_names.at(decorator_type);

// BoxArea::Padding is rmlui default but we default containers to Border, so matching for now.
Rml::BoxArea paint_area = Rml::BoxArea::Border;

Rml::DecoratorInstancer* instancer = Rml::Factory::GetDecoratorInstancer(decorator_type_name);

if (existing_decorator != nullptr) {
auto& existing_decorators = existing_decorator->list;
for (int i = 0; i < existing_decorators.size(); i++) {
if (existing_decorators[i].type == decorator_type_name) {
decorators.list.emplace_back(Rml::DecoratorDeclaration{
existing_decorators[i].type,
existing_decorators[i].instancer,
std::move(properties),
paint_area
});
found_existing = true;
} else {
decorators.list.emplace_back(existing_decorators[i]);
}
}
}

if (!found_existing) {
const Rml::PropertySpecification& specification = instancer->GetPropertySpecification();
specification.SetPropertyDefaults(properties);
decorators.list.emplace_back(Rml::DecoratorDeclaration{
decorator_type_name,
instancer,
std::move(properties),
paint_area
});
}

set_property(
Rml::PropertyId::Decorator,
Rml::Property(
Rml::Variant(Rml::MakeShared<Rml::DecoratorDeclarationList>((std::move(decorators)))),
Rml::Unit::DECORATOR
)
);
}

Rml::PropertyDictionary Style::create_decorator_properties(
Style::DecoratorType decorator_type,
std::initializer_list<std::pair<const Rml::String, Rml::Property>> props_to_set,
bool set_defaults
) {
Rml::PropertyDictionary properties;
Rml::DecoratorInstancer* instancer = get_decorator_instancer(decorator_type);
const Rml::PropertySpecification &prop_spec = instancer->GetPropertySpecification();
for (const auto& prop : props_to_set) {
properties.SetProperty(prop_spec.GetProperty(prop.first)->GetId(), prop.second);
}
if (set_defaults) {
prop_spec.SetPropertyDefaults(properties);
}
return properties;
}

void Style::set_decorator_horizontal_gradient(const Color &color_left, const Color &color_right) {
Rml::PropertyDictionary properties = create_decorator_properties(DecoratorType::HorizontalGradient, {
{ "start-color", color_left.to_rml_property() },
{ "stop-color", color_right.to_rml_property() }
});

set_decorator(DecoratorType::HorizontalGradient, properties);
}
void Style::set_decorator_horizontal_gradient(recompui::theme::color color_left, recompui::theme::color color_right, int opacity_left, int opacity_right) {
set_decorator_horizontal_gradient(
get_theme_color_with_opacity(color_left, opacity_left),
get_theme_color_with_opacity(color_right, opacity_right)
);
}

void Style::set_decorator_vertical_gradient(const Color &color_top, const Color &color_bottom) {
Rml::PropertyDictionary properties = create_decorator_properties(DecoratorType::VerticalGradient, {
{ "start-color", color_top.to_rml_property() },
{ "stop-color", color_bottom.to_rml_property() }
});

set_decorator(DecoratorType::VerticalGradient, properties);
}
void Style::set_decorator_vertical_gradient(recompui::theme::color color_top, recompui::theme::color color_bottom, int opacity_left, int opacity_right) {
set_decorator_vertical_gradient(
get_theme_color_with_opacity(color_top, opacity_left),
get_theme_color_with_opacity(color_bottom, opacity_right)
);
}

Rml::TransformPtr Style::get_existing_transform() {
if (property_map.find(Rml::PropertyId::Transform) != property_map.end()) {
auto curTransform = property_map[Rml::PropertyId::Transform].Get<Rml::TransformPtr>();
Expand Down
50 changes: 50 additions & 0 deletions recompui/src/elements/ui_style.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,50 @@ namespace recompui {
private:
std::map<Rml::PropertyId, Rml::Property> property_map;
Rml::TransformPtr get_existing_transform();
Rml::DecoratorsPtr get_existing_decorators();

// Various ways of applying effects to containers. These are built
// into RmlUI but some require custom implementations.
// It isn't worth exposing all at once, so instead we'll have methods.
// See: https://mikke89.github.io/RmlUiDoc/pages/rcss/decorators.html
enum class DecoratorType {
TiledHorizontal,
TiledVertical,
TiledBox,
Image,
NinePatch,
// (deprecated, use horizontal-gradient or vertical-gradient)
Gradient,
HorizontalGradient,
VerticalGradient,
// Custom shader, see DecoratorShader and https://mikke89.github.io/RmlUiDoc/pages/rcss/decorators/shader.html
// Requires implementation in recompui renderer. Currently not supported in recompui.
Shader,
// Not supported: needs implementation in recompui renderer
LinearGradient,
// Not supported: needs implementation in recompui renderer
RepeatingLinearGradient,
// Not supported: needs implementation in recompui renderer
RadialGradient,
// Not supported: needs implementation in recompui renderer
RepeatingRadialGradient,
// Not supported: needs implementation in recompui renderer
ConicGradient,
// Not supported: needs implementation in recompui renderer
RepeatingConicGradient,
};
static const std::unordered_map<Style::DecoratorType, const std::string> decorator_type_names;
Rml::DecoratorInstancer* get_decorator_instancer(Style::DecoratorType decorator_type);
// Helper to create decorator properties since decorator properties are unique to each decorator type.
// Note: `props_to_set` is a list of property name to rml property pairs, with each pair like:
// `{ "start-color", Rml::Property(Rml::Colourb(r, g, b, a), Rml::Unit::COLOUR) }`
Rml::PropertyDictionary create_decorator_properties(
Style::DecoratorType decorator_type,
std::initializer_list<std::pair<const Rml::String, Rml::Property>> props_to_set,
bool set_defaults = true
);
void set_decorator(DecoratorType decorator_type, Rml::PropertyDictionary properties);

void set_or_add_transformation(const Rml::TransformPrimitive& primitive);

// Used with display_hide and display_show to restore the intended display value if wanting to
Expand Down Expand Up @@ -141,6 +185,12 @@ namespace recompui {
void set_pointer_events(PointerEvents pointer_events);
virtual bool is_element() { return false; }
ResourceId get_resource_id() { return resource_id; }

void set_decorator_horizontal_gradient(const Color &color_left, const Color &color_right);
void set_decorator_horizontal_gradient(recompui::theme::color color_left, recompui::theme::color color_right, int opacity_left = ThemeDefaultOpacity, int opacity_right = ThemeDefaultOpacity);

void set_decorator_vertical_gradient(const Color &color_top, const Color &color_bottom);
void set_decorator_vertical_gradient(recompui::theme::color color_top, recompui::theme::color color_bottom, int opacity_left = ThemeDefaultOpacity, int opacity_right = ThemeDefaultOpacity);
};

} // namespace recompui
6 changes: 6 additions & 0 deletions recompui/src/elements/ui_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <stdint.h>
#include <variant>

#include "RmlUi/Core.h"

namespace recompui {

constexpr std::string_view checked_state = "checked";
Expand All @@ -17,6 +19,10 @@ namespace recompui {
uint8_t g = 255;
uint8_t b = 255;
uint8_t a = 255;

Rml::Property to_rml_property() const {
return Rml::Property(Rml::Colourb(r, g, b, a), Rml::Unit::COLOUR);
}
};

enum class Cursor {
Expand Down