Custom element registration

This commit is contained in:
2026-07-12 23:47:59 -05:00
parent 7f1c94f6a9
commit 5e485a9c43
9 changed files with 150 additions and 1 deletions

View File

@@ -22,17 +22,22 @@ add_library(rmlui_backend STATIC
vendor/rmlui_backend/RmlUi_Renderer_GL3.cpp vendor/rmlui_backend/RmlUi_Renderer_GL3.cpp
) )
file(GLOB_RECURSE PAGE_SOURCES CONFIGURE_DEPENDS "src/pages/*.cpp")
file(GLOB_RECURSE ELEMENT_SOURCES CONFIGURE_DEPENDS "src/elements/*.cpp")
add_executable(${PROJECT_NAME} add_executable(${PROJECT_NAME}
src/main.cpp src/main.cpp
src/app.cpp src/app.cpp
src/lua_app_api.cpp src/lua_app_api.cpp
src/page.cpp src/page.cpp
src/pages/test_page.cpp ${PAGE_SOURCES}
${ELEMENT_SOURCES}
) )
target_include_directories(${PROJECT_NAME} PRIVATE target_include_directories(${PROJECT_NAME} PRIVATE
src src
src/elements
vendor/rmlui_backend vendor/rmlui_backend
${FREETYPE_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS}
) )

View File

View File

@@ -0,0 +1,28 @@
TestPage = {}
local maxHp = 100
local currentHp = 100
function TestPage.Damage(event)
currentHp = currentHp - 5
local document = event.current_element.owner_document
local target = document:GetElementById("hp-bar")
if target then
target:SetAttribute("current", currentHp)
end
end
function TestPage.Heal(event)
currentHp = currentHp + 5
local document = event.current_element.owner_document
local target = document:GetElementById("hp-bar")
if target then
target:SetAttribute("current", currentHp)
end
end

View File

@@ -1,3 +1,17 @@
#page-root h1 { #page-root h1 {
color: red; color: red;
}
.healthbar-track {
display: block;
width: 200px;
height: 16px;
background-color: #3c3c3c;
border: 1px #666666;
}
.healthbar-fill {
display: block;
height: 100%;
background-color: #ffffff;
} }

View File

@@ -4,4 +4,10 @@
<button id="test-btn">Button clicked: {{counter}} times</button> <button id="test-btn">Button clicked: {{counter}} times</button>
<p>If you have a .rcss file with the same name as the page in the pages directory, it will be loaded at runtime so you can add custom styling to a page, which is why the header is red on this page only.</p> <p>If you have a .rcss file with the same name as the page in the pages directory, it will be loaded at runtime so you can add custom styling to a page, which is why the header is red on this page only.</p>
<p>This next section demonstates two things, the custom <code>"healthbar"</code> rml element, and scoped lua with the damage and heal buttons</p>
<healthbar id="hp-bar" current="100" max="100"></healthbar>
<button onclick="TestPage.Damage(event)">Damage</button>
<button onclick="TestPage.Heal(event)">Heal</button>
</div> </div>

22
src/element_registry.hpp Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include <RmlUi/Core/ElementInstancer.h>
#include <RmlUi/Core/Factory.h>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
class ElementRegistry {
public:
template <typename T>
void Register(const std::string& tag) {
static_assert(std::is_base_of<Rml::Element, T>::value, "T must derive from Rml::Element");
auto instancer = std::make_unique<Rml::ElementInstancerGeneric<T>>();
Rml::Factory::RegisterElementInstancer(tag, instancer.get());
instancers.push_back(std::move(instancer));
}
private:
std::vector<std::unique_ptr<Rml::ElementInstancer>> instancers;
};

View File

@@ -0,0 +1,51 @@
#include "health_bar_element.hpp"
#include <RmlUi/Core/Factory.h>
#include <RmlUi/Core/ID.h>
#include <RmlUi/Core/Math.h>
#include <RmlUi/Core/Property.h>
#include <RmlUi/Core/Types.h>
#include <RmlUi/Core/Unit.h>
HealthBarElement::HealthBarElement(const Rml::String& tag) : Rml::Element(tag) {
Rml::XMLAttributes attributes;
Rml::ElementPtr track = Rml::Factory::InstanceElement(this, "div", "div", attributes);
track->SetClass("healthbar-track", true);
Rml::ElementPtr fillElement = Rml::Factory::InstanceElement(this, "div", "div", attributes);
fillElement->SetClass("healthbar-fill", true);
fill = fillElement.get();
track->AppendChild(std::move(fillElement));
AppendChild(std::move(track));
UpdateFill();
}
void HealthBarElement::OnAttributeChange(const Rml::ElementAttributes &changed_attributes) {
Rml::Element::OnAttributeChange(changed_attributes);
if (changed_attributes.find("current") != changed_attributes.end() ||
changed_attributes.find("max") != changed_attributes.end()) {
UpdateFill();
}
}
void HealthBarElement::UpdateFill() {
int current = GetAttribute<int>("current", 0);
int max = GetAttribute<int>("max", 100);
if (max <= 0) max = 1;
float pct = Rml::Math::Clamp(static_cast<float>(current) / static_cast<float>(max), 0.0f, 1.0f) * 100.0f;
if (fill) {
fill->SetProperty(Rml::PropertyId::Width, Rml::Property(pct, Rml::Unit::PERCENT));
if (current >= 90) {
fill->SetProperty(Rml::PropertyId::BackgroundColor, Rml::Property("#33cc33", Rml::Unit::COLOUR));
} else if (current >= 50) {
fill->SetProperty(Rml::PropertyId::BackgroundColor, Rml::Property("#cccc33", Rml::Unit::COLOUR));
} else if (current >= 0) {
fill->SetProperty(Rml::PropertyId::BackgroundColor, Rml::Property("#cc3333", Rml::Unit::COLOUR));
}
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <RmlUi/Core/Element.h>
#include <RmlUi/Core/Types.h>
class HealthBarElement : public Rml::Element {
public:
explicit HealthBarElement(const Rml::String& tag);
void OnAttributeChange(const Rml::ElementAttributes &changed_attributes) override;
private:
void UpdateFill();
Rml::Element* fill = nullptr;
};

View File

@@ -13,14 +13,21 @@
#include <RmlUi/Lua/Lua.h> #include <RmlUi/Lua/Lua.h>
#include <memory> #include <memory>
#include "app.hpp" #include "app.hpp"
#include "element_registry.hpp"
#include "pages/test_page.hpp" #include "pages/test_page.hpp"
#include "ButtonClickListener.hpp" #include "ButtonClickListener.hpp"
#include "lui_app_api.hpp" #include "lui_app_api.hpp"
#include "elements/health_bar_element.hpp"
static bool is_initalized = false; static bool is_initalized = false;
static bool is_running = false; static bool is_running = false;
static Rml::Context *ctx; static Rml::Context *ctx;
static App *app; static App *app;
static ElementRegistry elementRegistry;
void RegisterElements() {
elementRegistry.Register<HealthBarElement>("healthbar");
}
bool InitalizeApplication() { bool InitalizeApplication() {
if (!Backend::Initialize("RmlUi App Template", 800, 600, true)) { if (!Backend::Initialize("RmlUi App Template", 800, 600, true)) {
@@ -55,6 +62,8 @@ bool InitalizeApplication() {
AppLuaApi *lua_app_api = new AppLuaApi(app, L); AppLuaApi *lua_app_api = new AppLuaApi(app, L);
lua_app_api->RegisterLuaBindings(); lua_app_api->RegisterLuaBindings();
RegisterElements();
std::cout << "Application initalized...\n"; std::cout << "Application initalized...\n";
return true; return true;