Unravel Engine C++ Reference
Loading...
Searching...
No Matches
ui_bindings.cpp
Go to the documentation of this file.
1// UIDocumentComponent, UIDocument, UIElement, and UI event registries (shared Rml helpers).
3#include "script_bindings.h"
4
5#include "../script_interop.h"
6#include "../script_system.h"
7
12#include <RmlUi/Core/Element.h>
13#include <RmlUi/Core/ElementDocument.h>
14#include <RmlUi/Core/ElementText.h>
15#include <RmlUi/Core/Event.h>
16#include <RmlUi/Core/EventListener.h>
17#include <sstream>
18
19namespace unravel
20{
21namespace
22{
23
24//-------------------------------------------------------------------------
25/*
26
27 _ _ _____ _____ _____ _ _ __ __ ______ _ _ _______
28 | | | |_ _| | __ \ /\ / ____| | | | \/ | ____| \ | |__ __|
29 | | | | | | | | | | / \ | | | | | | \ / | |__ | \| | | |
30 | | | | | | | | | |/ /\ \ | | | | | | |\/| | __| | . ` | | |
31 | |__| |_| |_ | |__| / ____ \| |____| |__| | | | | |____| |\ | | |
32 \____/|_____| |_____/_/ \_\\_____|\____/|_| |_|______|_| \_| |_|
33
34
35*/
36//-------------------------------------------------------------------------
37
38auto internal_m2n_ui_document_get_asset(entt::entity id) -> hpp::uuid
39{
41 {
42 return comp->asset.uid();
43 }
44
45 return {};
46}
47
48void internal_m2n_ui_document_set_asset(entt::entity id, const hpp::uuid& uid)
49{
51 {
52 auto& ctx = engine::context();
53 auto& am = ctx.get_cached<asset_manager>();
54
55 auto asset = am.get_asset<ui_tree>(uid);
56 comp->asset = asset;
57 }
58}
59
60auto internal_m2n_ui_document_is_loaded(entt::entity id) -> bool
61{
63 {
64 return comp->is_loaded();
65 }
66
67 return false;
68}
69
70auto internal_m2n_ui_document_is_enabled(entt::entity id) -> bool
71{
73 {
74 return comp->is_enabled();
75 }
76
77 return false;
78}
79
80void internal_m2n_ui_document_set_enabled(entt::entity id, bool enabled)
81{
83 {
84 comp->set_enabled(enabled);
85 }
86}
87void internal_m2n_ui_document_close(entt::entity id)
88{
90 {
91 if(comp->document)
92 {
93 comp->document->Close();
94 comp->document = nullptr;
95 }
96 }
97}
98
99auto internal_m2n_ui_document_get_title(entt::entity id) -> const std::string&
100{
102 {
103 if(comp->document)
104 {
105 return comp->document->GetTitle();
106 }
107 }
108
109 static const std::string empty;
110 return empty;
111}
112
113void internal_m2n_ui_document_set_title(entt::entity id, const std::string& title)
114{
116 {
117 if(comp->document)
118 {
119 comp->document->SetTitle(title);
120 }
121 }
122}
123
124//-------------------------------------------------------------------------
125/*
126
127 ______ _ ______ __ __ ______ _ _ _______
128 | ____| | | ____| \/ | ____| \ | |__ __|
129 | |__ | | | |__ | \ / | |__ | \| | | |
130 | __| | | | __| | |\/| | __| | . ` | | |
131 | |____| |____| |____| | | | |____| |\ | | |
132 |______|______|______|_| |_|______|_| \_| |_|
133
134
135*/
136//-------------------------------------------------------------------------
137
138// Helper function to get UI element safely
139auto get_ui_element_safe(entt::entity entity_id, const std::string& element_id) -> Rml::Element*
140{
141 if(auto comp = safe_get_component<ui_document_component>(entity_id))
142 {
143 if(comp->document)
144 {
145 return comp->document->GetElementById(element_id);
146 }
147 }
148 return nullptr;
149}
150
151
152//-------------------------------------------------------------------------
153/*
154
155 ______ _ _ ______ _ _ _______ _____ _ _ ____ _____ _ __ _____
156 | ____| | | | ____| \ | |__ __| / ____| /\ | | | | | _ \ /\ / ____| |/ // ____|
157 | |__ | | | | |__ | \| | | | | | / \ | | | | | |_) | / \ | | | ' /| (___
158 | __| | | | | __| | . ` | | | | | / /\ \ | | | | | _ < / /\ \| | | < \___ \
159 | |____| |__| | |____| |\ | | | | |____ / ____ \| |____| |____| |_) / ____ \ |____| . \ ____) |
160 |______|\____/|______|_| \_| |_| \_____/_/ \_\______|______|____/_/ \_\_____|_|\_\_____/
161
162
163*/
164//-------------------------------------------------------------------------
165
166template<typename T>
167void dispatch_ui_event_to_manager(const T& event_data)
168{
169 try
170 {
171 const auto& ctx = engine::context();
172 const auto& script_cache = ctx.get_cached<script_system>().get_cache();
173
174 if(!script_cache.ui_dispatch_event_method.valid())
175 {
176 APPLOG_ERROR("UIEventManager.InternalDispatchEvent method not found");
177 return;
178 }
179
180 auto method_invoker =
181 dotnet::make_method_invoker<void(const T&)>(script_cache.ui_dispatch_event_method, false);
182 method_invoker(event_data);
183 }
184 catch (const dotnet::exception& e)
185 {
186 APPLOG_ERROR("C# exception dispatching UI event: {}", e.what());
187 }
188 catch (const std::exception& e)
189 {
190 APPLOG_ERROR("Error dispatching UI event: {}", e.what());
191 }
192}
193
194
195
196// UI Event Type Classification
197enum class ui_event_type
198{
199 unknown,
200 key,
201 textinput,
202 pointer,
203 change,
204 value
205};
206
207// Determine UI event type for efficient dispatch
208auto get_ui_event_type(const Rml::Event& event) -> ui_event_type
209{
210 const auto event_id = event.GetId();
211
212 // Check key events first (most common check)
213 if (event_id == Rml::EventId::Keydown || event_id == Rml::EventId::Keyup)
214 {
215 return ui_event_type::key;
216 }
217
218 // Check text input events
219 if (event_id == Rml::EventId::Textinput)
220 {
221 return ui_event_type::textinput;
222 }
223
224 // Check pointer events
225 if (event_id == Rml::EventId::Click || event_id == Rml::EventId::Mousedown || event_id == Rml::EventId::Mouseup ||
226 event_id == Rml::EventId::Mousemove || event_id == Rml::EventId::Mouseover || event_id == Rml::EventId::Mouseout ||
227 event_id == Rml::EventId::Mousescroll || event_id == Rml::EventId::Dblclick || event_id == Rml::EventId::Drag ||
228 event_id == Rml::EventId::Dragstart || event_id == Rml::EventId::Dragover || event_id == Rml::EventId::Dragdrop)
229 {
230 return ui_event_type::pointer;
231 }
232
233 // Check change events (need to examine the event more closely)
234 if (event_id == Rml::EventId::Change)
235 {
236 auto value_str = event.GetParameter<std::string>("value", "");
237 if (!value_str.empty())
238 {
239 // If the element doesn't have min/max attributes, it's likely a text input or similar (change event)
240 if (auto* element = event.GetCurrentElement())
241 {
242 if (!element->HasAttribute("min") && !element->HasAttribute("max"))
243 {
244 return ui_event_type::change;
245 }
246 else
247 {
248 // Has min/max attributes, likely a slider (value event)
249 return ui_event_type::value;
250 }
251 }
252 }
253 }
254
255 return ui_event_type::unknown;
256}
257
258
259// Fill base event data common to all event types
260void fill_base_event_data(dotnetpp_backend::managed_interface::ui_event_base& event_data,
261 const Rml::Event& event,
262 Rml::Element* target_element,
263 Rml::Element* current_element)
264{
265 event_data.native_ptr = reinterpret_cast<std::intptr_t>(&event);
266 event_data.target_element_id = target_element->GetId();
267 event_data.target_element_ptr = reinterpret_cast<std::intptr_t>(target_element);
268 event_data.current_element_id = current_element->GetId();
269 event_data.current_element_ptr = reinterpret_cast<std::intptr_t>(current_element);
270 event_data.event_type = event.GetType();
271 event_data.phase = static_cast<int>(event.GetPhase());
272}
273
274// Dispatch key event to C# UIEventManager
275void dispatch_key_event_to_manager(const Rml::Event& event,
276 Rml::Element* target_element,
277 Rml::Element* current_element)
278{
279
280 // Create key event data
282 fill_base_event_data(key_event_data, event, target_element, current_element);
283
284 // Fill key-specific data based on actual RmlUi parameters
285 auto key_identifier = event.GetParameter<int>("key_identifier", 0);
286 key_event_data.key_code = RmlEngine::convert_rml_key_to_input(static_cast<Rml::Input::KeyIdentifier>(key_identifier));
287 key_event_data.ctrl_key = event.GetParameter<int>("ctrl_key", 0) > 0;
288 key_event_data.shift_key = event.GetParameter<int>("shift_key", 0) > 0;
289 key_event_data.alt_key = event.GetParameter<int>("alt_key", 0) > 0;
290 key_event_data.meta_key = event.GetParameter<int>("meta_key", 0) > 0;
291
292 dispatch_ui_event_to_manager(key_event_data);
293}
294
295// Dispatch pointer event to C# UIEventManager
296void dispatch_pointer_event_to_manager(const Rml::Event& event,
297 Rml::Element* target_element,
298 Rml::Element* current_element)
299{
300
301 // Create pointer event data
303 fill_base_event_data(pointer_event_data, event, target_element, current_element);
304
305 // Fill pointer-specific data based on actual RmlUi parameters
306 pointer_event_data.x = event.GetParameter<float>("mouse_x", 0.0f);
307 pointer_event_data.y = event.GetParameter<float>("mouse_y", 0.0f);
308 pointer_event_data.button = event.GetParameter<int>("button", -1);
309 pointer_event_data.ctrl_key = event.GetParameter<int>("ctrl_key", 0) > 0;
310 pointer_event_data.shift_key = event.GetParameter<int>("shift_key", 0) > 0;
311 pointer_event_data.alt_key = event.GetParameter<int>("alt_key", 0) > 0;
312 pointer_event_data.meta_key = event.GetParameter<int>("meta_key", 0) > 0;
313 pointer_event_data.delta_x = event.GetParameter<float>("wheel_delta_x", 0.0f);
314 pointer_event_data.delta_y = event.GetParameter<float>("wheel_delta_y", 0.0f);
315
316 dispatch_ui_event_to_manager(pointer_event_data);
317
318}
319
320// Dispatch text input event to C# UIEventManager
321void dispatch_textinput_event_to_manager(const Rml::Event& event,
322 Rml::Element* target_element,
323 Rml::Element* current_element)
324{
325 // Create text input event data
327 fill_base_event_data(textinput_event_data, event, target_element, current_element);
328
329
330 // Fill text input-specific data
331 textinput_event_data.text = event.GetParameter<std::string>("text", "");
332 textinput_event_data.ctrl_key = event.GetParameter<int>("ctrl_key", 0) > 0;
333 textinput_event_data.shift_key = event.GetParameter<int>("shift_key", 0) > 0;
334 textinput_event_data.alt_key = event.GetParameter<int>("alt_key", 0) > 0;
335 textinput_event_data.meta_key = event.GetParameter<int>("meta_key", 0) > 0;
336
337
338 dispatch_ui_event_to_manager(textinput_event_data);
339}
340
341// Dispatch value event to C# UIEventManager
342void dispatch_value_event_to_manager(const Rml::Event& event,
343 Rml::Element* target_element,
344 Rml::Element* current_element)
345{
346
347 // Create value event data
349 fill_base_event_data(value_event_data, event, target_element, current_element);
350
351 // Fill value-specific data
352 value_event_data.value = event.GetParameter<float>("value", 0);
353
354 if(auto* slider_element = event.GetCurrentElement())
355 {
356 value_event_data.min_value = slider_element->GetAttribute<float>("min", 0);
357 value_event_data.max_value = slider_element->GetAttribute<float>("max", 0);
358 value_event_data.step = slider_element->GetAttribute<float>("step", 0);
359 }
360
361 dispatch_ui_event_to_manager(value_event_data);
362}
363
364// Dispatch change event to C# UIEventManager
365void dispatch_change_event_to_manager(const Rml::Event& event,
366 Rml::Element* target_element,
367 Rml::Element* current_element)
368{
369
370 // Create change event data
372 fill_base_event_data(change_event_data, event, target_element, current_element);
373
374 // Fill change-specific data
375 change_event_data.value = event.GetParameter<std::string>("value", "");
376
377 dispatch_ui_event_to_manager(change_event_data);
378
379}
380
381// Dispatch base event to C# UIEventManager (fallback)
382void dispatch_base_event_to_manager(const Rml::Event& event,
383 Rml::Element* target_element,
384 Rml::Element* current_element)
385{
387 fill_base_event_data(event_data, event, target_element, current_element);
388 dispatch_ui_event_to_manager(event_data);
389}
390
391// Global event listener that dispatches all UI events to C# UIEventManager
392class ui_global_event_listener : public Rml::EventListener
393{
394 Rml::Event* current_event_ = nullptr;
395public:
396 void ProcessEvent(Rml::Event& event) override
397 {
398 current_event_ = &event;
399 try
400 {
401 // Get event information
402 auto* target_element = event.GetTargetElement();
403 if (!target_element)
404 {
405 return;
406 }
407
408 auto* current_element = event.GetCurrentElement();
409 if (!current_element)
410 {
411 return;
412 }
413
414 // Determine event type and dispatch accordingly using efficient switch
415 const auto event_type = get_ui_event_type(event);
416
417 switch (event_type)
418 {
419 case ui_event_type::key:
420 dispatch_key_event_to_manager(event, target_element, current_element);
421 break;
422
423 case ui_event_type::textinput:
424 dispatch_textinput_event_to_manager(event, target_element, current_element);
425 break;
426
427 case ui_event_type::pointer:
428 dispatch_pointer_event_to_manager(event, target_element, current_element);
429 break;
430
431 case ui_event_type::change:
432 dispatch_change_event_to_manager(event, target_element, current_element);
433 break;
434
435 case ui_event_type::value:
436 dispatch_value_event_to_manager(event, target_element, current_element);
437 break;
438
439 case ui_event_type::unknown:
440 default:
441 // Fallback to base event for unknown types
442 dispatch_base_event_to_manager(event, target_element, current_element);
443 break;
444 }
445 }
446 catch (const std::exception& e)
447 {
448 APPLOG_ERROR("Error processing UI event: {}", e.what());
449 }
450 current_event_ = nullptr;
451 }
452
453 // Allow access to current event for propagation control
454 auto get_current_event() const -> Rml::Event*
455 {
456 return current_event_;
457 }
458};
459
460// Global event listener instance
461ui_global_event_listener g_ui_global_listener;
462
463// Ensure a native event listener is attached to the element for the given event type
464void internal_m2n_ui_ensure_native_event_listener(std::intptr_t element_ptr, const std::string& event_type)
465{
466 if (element_ptr == 0)
467 {
468 return;
469 }
470
471 try
472 {
473 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
474
475 // Add event listener to the element
476 // Note: RmlUi handles duplicate listeners internally, so it's safe to call this multiple times
477 element->AddEventListener(event_type, &g_ui_global_listener);
478
479 APPLOG_TRACE("Ensured native UI event listener: element='{}', event='{}'", element->GetId(), event_type);
480 }
481 catch (const dotnet::exception& e)
482 {
483 APPLOG_ERROR("C# exception ensuring native UI event listener: {}", e.what());
484 }
485 catch (const std::exception& e)
486 {
487 APPLOG_ERROR("Error ensuring native UI event listener: {}", e.what());
488 }
489}
490
491// Stop event propagation - called from C# UIEventBase.StopPropagation()
492void internal_m2n_ui_stop_propagation(std::intptr_t native_ptr)
493{
494 try
495 {
496
497 auto* current_event = g_ui_global_listener.get_current_event();
498 if (current_event && current_event == reinterpret_cast<Rml::Event*>(native_ptr))
499 {
500 current_event->StopPropagation();
501 }
502 else
503 {
504 APPLOG_WARNING("No current UI event to stop propagation on");
505 }
506
507 }
508 catch (const std::exception& e)
509 {
510 APPLOG_ERROR("Error stopping UI event propagation: {}", e.what());
511 }
512}
513
514// Stop immediate event propagation - called from C# UIEventBase.StopImmediatePropagation()
515void internal_m2n_ui_stop_immediate_propagation(std::intptr_t native_ptr)
516{
517 try
518 {
519 auto* current_event = g_ui_global_listener.get_current_event();
520 if (current_event)
521 {
522 current_event->StopImmediatePropagation();
523 }
524 else
525 {
526 APPLOG_WARNING("No current UI event to stop immediate propagation on");
527 }
528 }
529 catch (const std::exception& e)
530 {
531 APPLOG_ERROR("Error stopping UI event immediate propagation: {}", e.what());
532 }
533}
534
535//-------------------------------------------------------------------------
536/*
537
538 _ _ _____ __ _______ _____ _____ ______ _____ _____
539 | | | |_ _| \ \ / / __ \ /\ | __ \| __ \| ____| __ \ / ____|
540 | | | | | | \ \ /\ / /| |__) | / \ | |__) | |__) | |__ | |__) || (___
541 | | | | | | \ \/ \/ / | _ / / /\ \ | ___/| ___/| __| | _ / \___ \
542 | |__| |_| |_ \ /\ / | | \ \ / ____ \ | | | | | |____| | \ \ ____) |
543 \____/|_____| \/ \/ |_| \_\/_/ \_\|_| |_| |______|_| \_\|_____/
544
545
546*/
547//-------------------------------------------------------------------------
548
549// Helper function to validate element pointer by checking if it exists in the owner entity's UI document
550auto validate_ui_element_wrapper(std::intptr_t element_ptr, entt::entity owner_entity) -> bool
551{
552 if (element_ptr == 0)
553 {
554 return false;
555 }
556
557 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
558
559 // Check if this element exists in the owner entity's UI document
560 if (auto comp = safe_get_component<ui_document_component>(owner_entity))
561 {
562 if (comp->document)
563 {
564 // Check if this element belongs to this document
565 return comp->document->Contains(element);
566 }
567 }
568
569 return false;
570}
571
572// Helper function to validate document pointer by checking if it matches the owner entity's UI component
573auto validate_ui_document_wrapper(std::intptr_t document_ptr, entt::entity owner_entity) -> bool
574{
575 if (document_ptr == 0)
576 {
577 return false;
578 }
579
580 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
581
582 // Check if this document exists in the owner entity's UI component
583 if (auto comp = safe_get_component<ui_document_component>(owner_entity))
584 {
585 if (comp->document && comp->document == document)
586 {
587 return true;
588 }
589 }
590
591 return false;
592}
593
594//-------------------------------------------------------------------------
595// UI Document Wrapper Functions
596//-------------------------------------------------------------------------
597
598auto internal_m2n_ui_document_get_wrapper(entt::entity entity_id) -> std::intptr_t
599{
600 if (auto comp = safe_get_component<ui_document_component>(entity_id))
601 {
602 if (comp->document)
603 {
604 return reinterpret_cast<std::intptr_t>(comp->document);
605 }
606 }
607 return 0;
608}
609
610auto internal_m2n_ui_document_get_element_wrapper_by_id(std::intptr_t document_ptr, entt::entity owner_entity, const std::string& element_id) -> std::intptr_t
611{
612 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
613 {
614 return 0;
615 }
616
617 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
618 auto* element = document->GetElementById(element_id);
619 return reinterpret_cast<std::intptr_t>(element);
620}
621
622auto internal_m2n_ui_document_query_selector_wrapper(std::intptr_t document_ptr, entt::entity owner_entity, const std::string& selector) -> std::intptr_t
623{
624 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
625 {
626 return 0;
627 }
628
629 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
630 auto element = document->QuerySelector(selector);
631 if (element)
632 {
633 return reinterpret_cast<std::intptr_t>(element);
634 }
635
636 return 0;
637}
638
639// Get element ID from element pointer
640auto internal_m2n_ui_element_wrapper_get_id(std::intptr_t element_ptr, entt::entity owner_entity) -> std::string
641{
642 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
643 {
644 return "";
645 }
646
647 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
648 return element->GetId();
649}
650
651//-------------------------------------------------------------------------
652// UI Document Wrapper Methods
653//-------------------------------------------------------------------------
654
655auto internal_m2n_ui_document_wrapper_is_valid(std::intptr_t document_ptr, entt::entity owner_entity) -> bool
656{
657 return validate_ui_document_wrapper(document_ptr, owner_entity);
658}
659
660auto internal_m2n_ui_document_wrapper_get_title(std::intptr_t document_ptr, entt::entity owner_entity) -> std::string
661{
662 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
663 {
664 return "";
665 }
666
667 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
668 return document->GetTitle();
669}
670
671void internal_m2n_ui_document_wrapper_set_title(std::intptr_t document_ptr, entt::entity owner_entity, const std::string& title)
672{
673 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
674 {
675 return;
676 }
677
678 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
679 document->SetTitle(title);
680}
681
682auto internal_m2n_ui_document_wrapper_is_visible(std::intptr_t document_ptr, entt::entity owner_entity) -> bool
683{
684 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
685 {
686 return false;
687 }
688
689 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
690 return document->IsVisible();
691}
692
693void internal_m2n_ui_document_wrapper_show(std::intptr_t document_ptr, entt::entity owner_entity)
694{
695 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
696 {
697 return;
698 }
699
700 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
701 document->Show();
702}
703
704void internal_m2n_ui_document_wrapper_hide(std::intptr_t document_ptr, entt::entity owner_entity)
705{
706 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
707 {
708 return;
709 }
710
711 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
712 document->Hide();
713}
714
715void internal_m2n_ui_document_wrapper_close(std::intptr_t document_ptr, entt::entity owner_entity)
716{
717 if (!validate_ui_document_wrapper(document_ptr, owner_entity))
718 {
719 return;
720 }
721
722 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
723 document->Close();
724}
725
726//-------------------------------------------------------------------------
727// UI Element Wrapper Methods
728//-------------------------------------------------------------------------
729
730auto internal_m2n_ui_element_wrapper_is_valid(std::intptr_t element_ptr, entt::entity owner_entity) -> bool
731{
732 return validate_ui_element_wrapper(element_ptr, owner_entity);
733}
734
735auto internal_m2n_ui_element_wrapper_get_inner_rml(std::intptr_t element_ptr, entt::entity owner_entity) -> std::string
736{
737 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
738 {
739 return "";
740 }
741
742 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
743 return element->GetInnerRML();
744}
745
746void internal_m2n_ui_element_wrapper_set_inner_rml(std::intptr_t element_ptr, entt::entity owner_entity, const std::string& rml)
747{
748 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
749 {
750 return;
751 }
752
753 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
754 auto* element_text = rmlui_dynamic_cast<Rml::ElementText*>(element);
755
756 if(!element_text)
757 {
758 if(auto* first_child = element->GetFirstChild())
759 {
760 element_text = rmlui_dynamic_cast<Rml::ElementText*>(first_child);
761 }
762 }
763
764 if(element_text)
765 {
766 element_text->SetText(rml);
767 }
768 else
769 {
770 auto current_rml = element->GetInnerRML();
771 if(current_rml != rml)
772 {
773 element->SetInnerRML(rml);
774 }
775 }
776}
777
778auto internal_m2n_ui_element_wrapper_is_visible(std::intptr_t element_ptr, entt::entity owner_entity) -> bool
779{
780 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
781 {
782 return false;
783 }
784
785 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
786 return element->IsVisible();
787}
788
789void internal_m2n_ui_element_wrapper_set_visible(std::intptr_t element_ptr, entt::entity owner_entity, bool visible)
790{
791 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
792 {
793 return;
794 }
795
796 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
797 if (visible)
798 {
799 element->SetProperty("display", "block");
800 }
801 else
802 {
803 element->SetProperty("display", "none");
804 }
805}
806
807auto internal_m2n_ui_element_wrapper_get_attribute(std::intptr_t element_ptr, entt::entity owner_entity, const std::string& attribute_name) -> std::string
808{
809 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
810 {
811 return "";
812 }
813
814 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
815 return element->GetAttribute<Rml::String>(attribute_name, "");
816}
817
818void internal_m2n_ui_element_wrapper_set_attribute(std::intptr_t element_ptr, entt::entity owner_entity, const std::string& attribute_name, const std::string& value)
819{
820 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
821 {
822 return;
823 }
824
825 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
826 element->SetAttribute(attribute_name, value);
827}
828
829void internal_m2n_ui_element_wrapper_remove_attribute(std::intptr_t element_ptr, entt::entity owner_entity, const std::string& attribute_name)
830{
831 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
832 {
833 return;
834 }
835
836 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
837 element->RemoveAttribute(attribute_name);
838}
839
840auto internal_m2n_ui_element_wrapper_has_attribute(std::intptr_t element_ptr, entt::entity owner_entity, const std::string& attribute_name) -> bool
841{
842 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
843 {
844 return false;
845 }
846
847 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
848 return element->HasAttribute(attribute_name);
849}
850
851void internal_m2n_ui_element_wrapper_set_class(std::intptr_t element_ptr, entt::entity owner_entity, const std::string& class_name, bool activate)
852{
853 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
854 {
855 return;
856 }
857
858 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
859 element->SetClass(class_name, activate);
860}
861
862auto internal_m2n_ui_element_wrapper_is_class_set(std::intptr_t element_ptr, entt::entity owner_entity, const std::string& class_name) -> bool
863{
864 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
865 {
866 return false;
867 }
868
869 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
870 return element->IsClassSet(class_name);
871}
872
873void internal_m2n_ui_element_wrapper_sync_transform_to_entity(std::intptr_t element_ptr, entt::entity owner_entity, entt::entity transform_entity)
874{
875 auto transform = get_entity_from_id(transform_entity);
876 if (!transform)
877 {
878 return;
879 }
880
881 auto* transform_comp = transform.try_get<transform_component>();
882 if (!transform_comp)
883 {
884 return;
885 }
886
887 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
888 {
889 return;
890 }
891
892 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
893
894 const auto& matrix = transform_comp->get_transform_global().get_matrix();
895 std::stringstream s;
896
897 float perspective = transform_comp->get_perspective_global().w;
898 if (perspective > 0)
899 {
900 s << "perspective(" << perspective << "dp) ";
901 }
902 s << "matrix3d(" << matrix[0][0] << ", " << matrix[0][1] << ", " << matrix[0][2] << ", " << matrix[0][3] << ", " << matrix[1][0] << ", " << matrix[1][1] << ", " << matrix[1][2] << ", " << matrix[1][3] << ", " << matrix[2][0] << ", " << matrix[2][1] << ", " << matrix[2][2] << ", " << matrix[2][3] << ", " << matrix[3][0] << ", " << matrix[3][1] << ", " << matrix[3][2] << ", " << matrix[3][3] << ")";
903 element->SetProperty("transform", s.str());
904}
905
906void internal_m2n_ui_element_wrapper_focus(std::intptr_t element_ptr, entt::entity owner_entity)
907{
908 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
909 {
910 return;
911 }
912
913 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
914 element->Focus();
915}
916
917void internal_m2n_ui_element_wrapper_blur(std::intptr_t element_ptr, entt::entity owner_entity)
918{
919 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
920 {
921 return;
922 }
923
924 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
925 element->Blur();
926}
927
928void internal_m2n_ui_element_wrapper_click(std::intptr_t element_ptr, entt::entity owner_entity)
929{
930 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
931 {
932 return;
933 }
934
935 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
936 element->Click();
937}
938
939void internal_m2n_ui_element_wrapper_scroll_into_view(std::intptr_t element_ptr, entt::entity owner_entity, bool align_with_top)
940{
941 if (!validate_ui_element_wrapper(element_ptr, owner_entity))
942 {
943 return;
944 }
945
946 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
947 element->ScrollIntoView(align_with_top);
948}
949
950
951} // namespace
952
954{
955
956 APPLOG_TRACE("{}", __func__);
957 {
958 auto reg = dotnet::internal_call_registry("Unravel.Core.UIDocumentComponent");
959 reg.add_internal_call("internal_m2n_ui_document_get_asset", dotnet_internal_call(internal_m2n_ui_document_get_asset));
960 reg.add_internal_call("internal_m2n_ui_document_set_asset", dotnet_internal_call(internal_m2n_ui_document_set_asset));
961 reg.add_internal_call("internal_m2n_ui_document_is_loaded", dotnet_internal_call(internal_m2n_ui_document_is_loaded));
962 reg.add_internal_call("internal_m2n_ui_document_is_enabled", dotnet_internal_call(internal_m2n_ui_document_is_enabled));
963 reg.add_internal_call("internal_m2n_ui_document_set_enabled", dotnet_internal_call(internal_m2n_ui_document_set_enabled));
964 reg.add_internal_call("internal_m2n_ui_document_close", dotnet_internal_call(internal_m2n_ui_document_close));
965 reg.add_internal_call("internal_m2n_ui_document_get_title", dotnet_internal_call(internal_m2n_ui_document_get_title));
966 reg.add_internal_call("internal_m2n_ui_document_set_title", dotnet_internal_call(internal_m2n_ui_document_set_title));
967 reg.add_internal_call("internal_m2n_ui_document_get_wrapper", dotnet_internal_call(internal_m2n_ui_document_get_wrapper));
968 }
969}
970
972{
973 APPLOG_TRACE("{}", __func__);
974 {
975 auto reg = dotnet::internal_call_registry("Unravel.Core.UIDocument");
976 reg.add_internal_call("internal_m2n_ui_document_wrapper_is_valid", dotnet_internal_call(internal_m2n_ui_document_wrapper_is_valid));
977 reg.add_internal_call("internal_m2n_ui_document_wrapper_get_title", dotnet_internal_call(internal_m2n_ui_document_wrapper_get_title));
978 reg.add_internal_call("internal_m2n_ui_document_wrapper_set_title", dotnet_internal_call(internal_m2n_ui_document_wrapper_set_title));
979 reg.add_internal_call("internal_m2n_ui_document_wrapper_is_visible", dotnet_internal_call(internal_m2n_ui_document_wrapper_is_visible));
980 reg.add_internal_call("internal_m2n_ui_document_wrapper_show", dotnet_internal_call(internal_m2n_ui_document_wrapper_show));
981 reg.add_internal_call("internal_m2n_ui_document_wrapper_hide", dotnet_internal_call(internal_m2n_ui_document_wrapper_hide));
982 reg.add_internal_call("internal_m2n_ui_document_wrapper_close", dotnet_internal_call(internal_m2n_ui_document_wrapper_close));
983 reg.add_internal_call("internal_m2n_ui_document_wrapper_get_element_by_id", dotnet_internal_call(internal_m2n_ui_document_get_element_wrapper_by_id));
984 reg.add_internal_call("internal_m2n_ui_document_wrapper_query_selector", dotnet_internal_call(internal_m2n_ui_document_query_selector_wrapper));
985 reg.add_internal_call("internal_m2n_ui_document_wrapper_query_selector_all", dotnet_internal_call(internal_m2n_ui_document_query_selector_wrapper));
986 }
987}
988
990{
991 APPLOG_TRACE("{}", __func__);
992 {
993 auto reg = dotnet::internal_call_registry("Unravel.Core.UIElement");
994 reg.add_internal_call("internal_m2n_ui_element_wrapper_is_valid", dotnet_internal_call(internal_m2n_ui_element_wrapper_is_valid));
995 reg.add_internal_call("internal_m2n_ui_element_wrapper_get_inner_rml", dotnet_internal_call(internal_m2n_ui_element_wrapper_get_inner_rml));
996 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_inner_rml", dotnet_internal_call(internal_m2n_ui_element_wrapper_set_inner_rml));
997 reg.add_internal_call("internal_m2n_ui_element_wrapper_is_visible", dotnet_internal_call(internal_m2n_ui_element_wrapper_is_visible));
998 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_visible", dotnet_internal_call(internal_m2n_ui_element_wrapper_set_visible));
999 reg.add_internal_call("internal_m2n_ui_element_wrapper_get_attribute", dotnet_internal_call(internal_m2n_ui_element_wrapper_get_attribute));
1000 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_attribute", dotnet_internal_call(internal_m2n_ui_element_wrapper_set_attribute));
1001 reg.add_internal_call("internal_m2n_ui_element_wrapper_remove_attribute", dotnet_internal_call(internal_m2n_ui_element_wrapper_remove_attribute));
1002 reg.add_internal_call("internal_m2n_ui_element_wrapper_has_attribute", dotnet_internal_call(internal_m2n_ui_element_wrapper_has_attribute));
1003 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_class", dotnet_internal_call(internal_m2n_ui_element_wrapper_set_class));
1004 reg.add_internal_call("internal_m2n_ui_element_wrapper_is_class_set", dotnet_internal_call(internal_m2n_ui_element_wrapper_is_class_set));
1005 reg.add_internal_call("internal_m2n_ui_element_wrapper_sync_transform_to_entity", dotnet_internal_call(internal_m2n_ui_element_wrapper_sync_transform_to_entity));
1006 reg.add_internal_call("internal_m2n_ui_element_wrapper_focus", dotnet_internal_call(internal_m2n_ui_element_wrapper_focus));
1007 reg.add_internal_call("internal_m2n_ui_element_wrapper_blur", dotnet_internal_call(internal_m2n_ui_element_wrapper_blur));
1008 reg.add_internal_call("internal_m2n_ui_element_wrapper_click", dotnet_internal_call(internal_m2n_ui_element_wrapper_click));
1009 reg.add_internal_call("internal_m2n_ui_element_wrapper_scroll_into_view", dotnet_internal_call(internal_m2n_ui_element_wrapper_scroll_into_view));
1010 reg.add_internal_call("internal_m2n_ui_element_wrapper_get_id", dotnet_internal_call(internal_m2n_ui_element_wrapper_get_id));
1011 }
1012}
1013
1015{
1016 APPLOG_TRACE("{}", __func__);
1017 {
1018 auto reg = dotnet::internal_call_registry("Unravel.Core.UIEventManager");
1019 reg.add_internal_call("internal_m2n_ui_ensure_native_event_listener", dotnet_internal_call(internal_m2n_ui_ensure_native_event_listener));
1020 }
1021 {
1022 auto reg = dotnet::internal_call_registry("Unravel.Core.UIEventBase");
1023 reg.add_internal_call("internal_m2n_ui_stop_propagation", dotnet_internal_call(internal_m2n_ui_stop_propagation));
1024 reg.add_internal_call("internal_m2n_ui_stop_immediate_propagation", dotnet_internal_call(internal_m2n_ui_stop_immediate_propagation));
1025 }
1026}
1027
1028} // namespace unravel
event_type event
const char * title
#define APPLOG_WARNING(...)
Definition logging.h:19
#define APPLOG_ERROR(...)
Definition logging.h:20
#define APPLOG_TRACE(...)
Definition logging.h:17
bgfx::Transform transform
Definition graphics.h:42
auto convert_rml_key_to_input(Rml::Input::KeyIdentifier rml_key) -> input::key_code
Convert RmlUi key identifier to engine input key code.
void register_ui_document_script_bindings()
void register_ui_element_script_bindings()
void register_ui_event_script_bindings()
void register_ui_document_component_script_bindings()
auto get_entity_from_id(entt::entity id) -> entt::handle
auto safe_get_component(entt::entity id) -> T *
static auto context() -> rtti::context &
Definition engine.cpp:111
bool enabled