2
0

ElementDataModels.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #include "ElementDataModels.h"
  2. #include "../../Include/RmlUi/Core/Context.h"
  3. #include "../../Include/RmlUi/Core/Core.h"
  4. #include "../../Include/RmlUi/Core/DataModelHandle.h"
  5. #include "../../Include/RmlUi/Core/DataVariable.h"
  6. #include "../../Include/RmlUi/Core/StyleSheet.h"
  7. #include "../../Include/RmlUi/Core/StyleSheetSpecification.h"
  8. #include "../../Include/RmlUi/Core/SystemInterface.h"
  9. #include "CommonSource.h"
  10. #include "DataModelsSource.h"
  11. #include <algorithm>
  12. namespace Rml {
  13. namespace Debugger {
  14. static void ReadDataVariableRecursive(String& out_rml, const int indent_level, const DataVariable variable)
  15. {
  16. constexpr int max_num_child_elements = 50;
  17. String indent_child_element;
  18. for (int i = 0; i <= indent_level; i++)
  19. indent_child_element += "&nbsp;&nbsp;";
  20. switch (variable.Type())
  21. {
  22. case DataVariableType::Scalar:
  23. {
  24. Variant variant;
  25. if (!variable.Get(variant))
  26. out_rml += "<em>(unreadable)</em>";
  27. else if (variant.GetType() == Variant::NONE)
  28. out_rml += "<em>(none)</em>";
  29. else if (variant.GetType() == Variant::BOOL)
  30. out_rml += variant.Get<bool>() ? "true" : "false";
  31. else
  32. out_rml += StringUtilities::EncodeRml(variant.Get<String>());
  33. out_rml += "<br/>";
  34. }
  35. break;
  36. case DataVariableType::Array:
  37. {
  38. const int size = variable.Size();
  39. out_rml += "Array (" + ToString(variable.Size()) + ")<br/>";
  40. for (int i = 0; i < size; i++)
  41. {
  42. if (i >= max_num_child_elements)
  43. {
  44. out_rml += indent_child_element + "<span class='name'>[...]</span><br/>";
  45. break;
  46. }
  47. out_rml += indent_child_element + "<span class='name'>[" + ToString(i) + "]</span>: ";
  48. DataVariable child_variable = variable.Child(DataAddressEntry(i));
  49. ReadDataVariableRecursive(out_rml, indent_level + 1, child_variable);
  50. }
  51. }
  52. break;
  53. case DataVariableType::Struct:
  54. {
  55. const StringList members = Detail::DataVariableAccessor::GetDefinition(variable)->ReflectMemberNames();
  56. out_rml += "Struct (" + ToString(members.size()) + ")<br/>";
  57. for (const String& member_name : members)
  58. {
  59. if (std::distance(&members.front(), &member_name) >= max_num_child_elements)
  60. {
  61. out_rml += indent_child_element + "<span class='name'>[...]</span><br/>";
  62. break;
  63. }
  64. out_rml += indent_child_element + "<span class='name'>." + member_name + "</span>: ";
  65. DataVariable child_variable = variable.Child(DataAddressEntry(member_name));
  66. ReadDataVariableRecursive(out_rml, indent_level + 1, child_variable);
  67. }
  68. }
  69. break;
  70. }
  71. }
  72. ElementDataModels::ElementDataModels(const String& tag) : ElementDebugDocument(tag) {}
  73. ElementDataModels::~ElementDataModels()
  74. {
  75. RemoveEventListener(EventId::Click, this);
  76. }
  77. bool ElementDataModels::Initialise(Context* target_context)
  78. {
  79. SetInnerRML(data_models_rml);
  80. SetId("rmlui-debug-data-models");
  81. AddEventListener(EventId::Click, this);
  82. SharedPtr<StyleSheetContainer> style_sheet = Factory::InstanceStyleSheetString(String(common_rcss) + String(data_models_rcss));
  83. if (!style_sheet)
  84. return false;
  85. SetStyleSheetContainer(std::move(style_sheet));
  86. SetDebugContext(target_context);
  87. return true;
  88. }
  89. void ElementDataModels::Reset()
  90. {
  91. SetDebugContext(nullptr);
  92. }
  93. void ElementDataModels::SetDebugContext(Context* new_debug_context)
  94. {
  95. debug_context = new_debug_context;
  96. }
  97. void ElementDataModels::OnUpdate()
  98. {
  99. if (!IsVisible() || !debug_context)
  100. return;
  101. const double t = GetSystemInterface()->GetElapsedTime();
  102. const float dt = (float)(t - previous_update_time);
  103. constexpr float update_interval = 0.3f;
  104. if (dt > update_interval)
  105. {
  106. previous_update_time = t;
  107. UpdateContent();
  108. }
  109. }
  110. void ElementDataModels::ProcessEvent(Event& event)
  111. {
  112. if (!IsVisible())
  113. return;
  114. Element* target_element = event.GetTargetElement();
  115. if (target_element->GetOwnerDocument() != this)
  116. return;
  117. if (event == EventId::Click)
  118. {
  119. const String& id = event.GetTargetElement()->GetId();
  120. if (id == "close_button")
  121. Hide();
  122. event.StopPropagation();
  123. }
  124. }
  125. void ElementDataModels::UpdateContent()
  126. {
  127. RMLUI_ASSERT(debug_context);
  128. Element* models_content_element = GetElementById("content");
  129. SmallOrderedMap<String, String> new_model_rml_map;
  130. const UnorderedMap<String, DataModelConstructor> data_models = debug_context->GetDataModels();
  131. for (const auto& name_model_pair : data_models)
  132. {
  133. const String& model_name = name_model_pair.first;
  134. const DataModelConstructor& model_constructor = name_model_pair.second;
  135. String& model_rml = new_model_rml_map[model_name];
  136. model_rml += "<div class='model'>";
  137. model_rml += "<h2>" + model_name + "</h2>";
  138. model_rml += "<div class='model-content'>";
  139. const UnorderedMap<String, DataVariable>& variables = Detail::DataModelConstructorAccessor::GetAllVariables(model_constructor);
  140. for (const auto& name_variable_pair : variables)
  141. {
  142. const String& name = name_variable_pair.first;
  143. const DataVariable& variable = name_variable_pair.second;
  144. model_rml += "<span class='name'>" + name + "</span>: ";
  145. ReadDataVariableRecursive(model_rml, 0, variable);
  146. }
  147. if (variables.empty())
  148. model_rml += "<em>No data variables in data model.</em><br/>";
  149. model_rml += "</div>";
  150. model_rml += "</div>";
  151. }
  152. if (new_model_rml_map != model_rml_map)
  153. {
  154. model_rml_map = std::move(new_model_rml_map);
  155. String models_rml;
  156. for (const auto& name_rml_pair : model_rml_map)
  157. models_rml += name_rml_pair.second;
  158. if (data_models.empty())
  159. models_rml = "<em>No data models in context.</em>";
  160. models_content_element->SetInnerRML(models_rml);
  161. }
  162. }
  163. } // namespace Debugger
  164. } // namespace Rml