(source_element))
{
const String& text_content = text_element->GetText();
attributes += CreateString(text_content.size() + 32, "Text: %s
", text_content.c_str());
}
}
if (attributes.empty())
{
while (attributes_content->HasChildNodes())
attributes_content->RemoveChild(attributes_content->GetChild(0));
attributes_rml.clear();
}
else if (attributes != attributes_rml)
{
attributes_content->SetInnerRML(attributes);
attributes_rml = std::move(attributes);
}
}
// Set the properties
if (Element* properties_content = GetElementById("properties-content"))
{
String properties;
if (source_element != nullptr)
BuildElementPropertiesRML(properties, source_element, source_element);
if (properties.empty())
{
while (properties_content->HasChildNodes())
properties_content->RemoveChild(properties_content->GetChild(0));
properties_rml.clear();
}
else if (properties != properties_rml)
{
properties_content->SetInnerRML(properties);
properties_rml = std::move(properties);
}
}
// Set the events
if (Element* events_content = GetElementById("events-content"))
{
String events;
if (source_element != nullptr)
{
events = source_element->GetEventDispatcherSummary();
}
if (events.empty())
{
while (events_content->HasChildNodes())
events_content->RemoveChild(events_content->GetChild(0));
events_rml.clear();
}
else if (events != events_rml)
{
events_content->SetInnerRML(events);
events_rml = std::move(events);
}
}
// Set the position
if (Element* position_content = GetElementById("position-content"))
{
String position;
if (source_element)
{
const Vector2f element_offset = source_element->GetRelativeOffset(BoxArea::Border);
const auto& box = source_element->GetBox();
const Vector2f element_size = source_element->GetBox().GetSize(BoxArea::Border);
Element* offset_parent = source_element->GetOffsetParent();
const String offset_parent_rml =
(offset_parent ? StringUtilities::EncodeRml(offset_parent->GetAddress(false, false)) : String("none"));
auto box_string = [&box](BoxDirection direction) {
const BoxEdge edge1 = (direction == BoxDirection::Horizontal ? BoxEdge::Left : BoxEdge::Top);
const BoxEdge edge2 = (direction == BoxDirection::Horizontal ? BoxEdge::Right : BoxEdge::Bottom);
const float content_size = (direction == BoxDirection::Horizontal ? box.GetSize().x : box.GetSize().y);
const String edge1_str = ToString(box.GetEdge(BoxArea::Margin, edge1)) + "|" + ToString(box.GetEdge(BoxArea::Border, edge1)) + "|" +
ToString(box.GetEdge(BoxArea::Padding, edge1));
const String edge2_str = ToString(box.GetEdge(BoxArea::Padding, edge2)) + "|" + ToString(box.GetEdge(BoxArea::Border, edge2)) + "|" +
ToString(box.GetEdge(BoxArea::Margin, edge2));
return CreateString(256, "%s <%s> %s", edge1_str.c_str(), ToString(content_size).c_str(), edge2_str.c_str());
};
position = "left: " + ToString(element_offset.x) + "px
" + //
"top: " + ToString(element_offset.y) + "px
" + //
"width: " + ToString(element_size.x) + "px
" + //
"height: " + ToString(element_size.y) + "px
" + //
"offset parent: " + offset_parent_rml + "
" + //
"box-x (px): " + box_string(BoxDirection::Horizontal) + "
" + //
"box-y (px): " + box_string(BoxDirection::Vertical);
}
if (position != position_rml)
{
position_content->SetInnerRML(position);
position_rml = std::move(position);
}
}
// Set the ancestors
if (Element* ancestors_content = GetElementById("ancestors-content"))
{
String ancestors;
Element* element_ancestor = nullptr;
if (source_element != nullptr)
element_ancestor = source_element->GetParentNode();
int ancestor_depth = 1;
while (element_ancestor)
{
String ancestor_name = element_ancestor->GetAddress(false, false);
ancestors += CreateString(ancestor_name.size() + 32, "%s
", ancestor_depth, ancestor_name.c_str());
element_ancestor = element_ancestor->GetParentNode();
ancestor_depth++;
}
if (ancestors.empty())
{
while (ancestors_content->HasChildNodes())
ancestors_content->RemoveChild(ancestors_content->GetFirstChild());
ancestors_rml.clear();
}
else if (ancestors != ancestors_rml)
{
ancestors_content->SetInnerRML(ancestors);
ancestors_rml = std::move(ancestors);
}
}
// Set the children
if (Element* children_content = GetElementById("children-content"))
{
String children;
if (source_element != nullptr)
{
const int num_dom_children = (source_element->GetNumChildren(false));
for (int i = 0; i < source_element->GetNumChildren(true); i++)
{
Element* child = source_element->GetChild(i);
// If this is a debugger document, do not show it.
if (IsDebuggerElement(child))
continue;
String child_name = child->GetAddress(false, false);
auto document = rmlui_dynamic_cast(child);
if (document && !document->GetTitle().empty())
child_name += " (" + document->GetTitle() + ')';
const char* non_dom_string = (i >= num_dom_children ? " class=\"non_dom\"" : "");
children += CreateString(child_name.size() + 40, "%s
", i, non_dom_string, child_name.c_str());
}
}
if (children.empty())
{
while (children_content->HasChildNodes())
children_content->RemoveChild(children_content->GetChild(0));
children_rml.clear();
}
else if (children != children_rml)
{
children_content->SetInnerRML(children);
children_rml = std::move(children);
}
}
}
void ElementInfo::BuildElementPropertiesRML(String& property_rml, Element* element, Element* primary_element)
{
NamedPropertyList property_list;
for (auto it = element->IterateLocalProperties(); !it.AtEnd(); ++it)
{
PropertyId property_id = it.GetId();
const String& property_name = it.GetName();
const Property* prop = &it.GetProperty();
// Check that this property isn't overridden or just not inherited.
if (primary_element->GetProperty(property_id) != prop)
continue;
property_list.push_back(NamedProperty{property_name, prop});
}
std::sort(property_list.begin(), property_list.end(), [](const NamedProperty& a, const NamedProperty& b) {
if (a.second->source && !b.second->source)
return false;
if (!a.second->source && b.second->source)
return true;
if (a.second->specificity < b.second->specificity)
return false;
if (a.second->specificity > b.second->specificity)
return true;
if (a.second->definition && !b.second->definition)
return false;
if (!a.second->definition && b.second->definition)
return true;
const String& a_name = StyleSheetSpecification::GetPropertyName(a.second->definition->GetId());
const String& b_name = StyleSheetSpecification::GetPropertyName(b.second->definition->GetId());
return a_name < b_name;
});
if (!property_list.empty())
{
// Print the 'inherited from ...' header if we're not the primary element.
if (element != primary_element)
{
property_rml += "inherited from " + element->GetAddress(false, false) + "
";
}
const PropertySource* previous_source = nullptr;
bool first_iteration = true;
for (auto& named_property : property_list)
{
auto& source = named_property.second->source;
if (source.get() != previous_source || first_iteration)
{
previous_source = source.get();
first_iteration = false;
// Print the rule name header.
if (source)
{
String str_line_number;
TypeConverter::Convert(source->line_number, str_line_number);
property_rml += "" + source->rule_name + "
";
property_rml += "" + source->path + " : " + str_line_number + "
";
}
else
{
property_rml += "inline
";
}
}
BuildPropertyRML(property_rml, named_property.first, named_property.second);
}
}
if (element->GetParentNode() != nullptr)
BuildElementPropertiesRML(property_rml, element->GetParentNode(), primary_element);
}
void ElementInfo::BuildPropertyRML(String& property_rml, const String& name, const Property* property)
{
const String property_value = property->ToString();
property_rml += "" + name + ": " + property_value + "
";
}
void ElementInfo::UpdateTitle()
{
auto title_content = GetElementById("title-content");
auto enable_select = GetElementById("enable_element_select");
auto show_source = GetElementById("show_source");
auto update_source = GetElementById("update_source");
if (title_content && enable_select && show_source && update_source)
{
if (enable_select->IsPseudoClassSet("hover"))
title_content->SetInnerRML("(select elements)");
else if (show_source->IsPseudoClassSet("hover"))
title_content->SetInnerRML("(draw element dimensions)");
else if (update_source->IsPseudoClassSet("hover"))
title_content->SetInnerRML("(update info continuously)");
else if (source_element)
title_content->SetInnerRML(source_element->GetTagName());
else
title_content->SetInnerRML("Element Information");
}
}
bool ElementInfo::IsDebuggerElement(Element* element)
{
return element->GetOwnerDocument()->GetId().find("rmlui-debug-") == 0;
}
} // namespace Debugger
} // namespace Rml