mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Introducing UITextNode, a native text node representation within the eepp UI hierarchy. This solves issues where text content incorrectly intercepts CSS structural pseudo-classes (like :nth-child and :first-of-type) because it was previously wrapped in standard UIWidget components (UITextSpan).
In standard web browsers, a `Node` represents anything in the DOM (including text), whereas an `Element` represents an HTML tag. CSS selectors strictly filter by `Element`. Currently, `eepp`'s CSS engine (`StyleSheetSpecification`) evaluates selectors directly against `Node` sibling counts (`getNodeIndex()`, `getChildCount()`). By distinguishing between "Widgets" (Elements) and "Text Nodes" at the node level, we updated these selectors to count only true structural elements, matching web standards with zero performance overhead.
This commit is contained in:
@@ -79,7 +79,8 @@ enum NodeFlags {
|
||||
NODE_FLAG_LOADING = ( 1 << 27 ),
|
||||
NODE_FLAG_CLOSING_CHILDREN = ( 1 << 28 ),
|
||||
NODE_FLAG_DISABLE_CLICK_FOCUS = ( 1 << 29 ),
|
||||
NODE_FLAG_FREE_USE = ( 1 << 30 )
|
||||
NODE_FLAG_TEXTNODE = ( 1 << 30 ),
|
||||
NODE_FLAG_FREE_USE = ( 1 << 31 )
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -209,6 +210,9 @@ class EE_API Node : public Transformable {
|
||||
*/
|
||||
virtual bool isType( const Uint32& type ) const;
|
||||
|
||||
/** @return True if this node is a UITextNode, false otherwise. */
|
||||
bool isTextNode() const;
|
||||
|
||||
/**
|
||||
* @brief Posts a message to this node and its ancestors.
|
||||
*
|
||||
|
||||
@@ -131,6 +131,7 @@ enum UINodeType {
|
||||
UI_TYPE_HTML_LIST_ITEM,
|
||||
UI_TYPE_HTML_IMAGE,
|
||||
UI_TYPE_SVG,
|
||||
UI_TYPE_TEXTNODE,
|
||||
UI_TYPE_MODULES = 10000,
|
||||
UI_TYPE_TERMINAL = 10001,
|
||||
UI_TYPE_USER = 200000,
|
||||
|
||||
35
include/eepp/ui/uitextnode.hpp
Normal file
35
include/eepp/ui/uitextnode.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef EE_UI_UITEXTNODE_HPP
|
||||
#define EE_UI_UITEXTNODE_HPP
|
||||
|
||||
#include <eepp/ui/uiwidget.hpp>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
class EE_API UITextNode : public UIWidget {
|
||||
public:
|
||||
static UITextNode* New();
|
||||
|
||||
UITextNode();
|
||||
|
||||
virtual ~UITextNode();
|
||||
|
||||
virtual Uint32 getType() const;
|
||||
|
||||
virtual bool isType( const Uint32& type ) const;
|
||||
|
||||
virtual void draw();
|
||||
|
||||
virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
|
||||
const Uint32& propertyIndex = 0 ) const;
|
||||
|
||||
const String& getText() const;
|
||||
|
||||
void setText( const String& text );
|
||||
|
||||
protected:
|
||||
String mText;
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
#endif
|
||||
@@ -800,6 +800,21 @@ class EE_API UIWidget : public UINode {
|
||||
*/
|
||||
std::vector<const char*> getStyleSheetPseudoClassesStrings() const;
|
||||
|
||||
/** @return True if the widget is not a text node. */
|
||||
bool isWidgetElement() const;
|
||||
|
||||
/** @return The index of this element among its sibling elements. */
|
||||
Uint32 getElementIndex() const;
|
||||
|
||||
/** @return The index of this element among its sibling elements of the same type. */
|
||||
Uint32 getElementOfTypeIndex() const;
|
||||
|
||||
/** @return The number of child elements. */
|
||||
Uint32 getChildElementCount() const;
|
||||
|
||||
/** @return The number of child elements of the specified type. */
|
||||
Uint32 getChildElementOfTypeCount( const Uint32& type ) const;
|
||||
|
||||
/**
|
||||
* @brief Resets all CSS classes and removes them.
|
||||
*
|
||||
|
||||
@@ -1064,6 +1064,10 @@ bool Node::isWidget() const {
|
||||
return 0 != ( mNodeFlags & NODE_FLAG_WIDGET );
|
||||
}
|
||||
|
||||
bool Node::isTextNode() const {
|
||||
return 0 != ( mNodeFlags & NODE_FLAG_TEXTNODE );
|
||||
}
|
||||
|
||||
bool Node::isWindow() const {
|
||||
return 0 != ( mNodeFlags & NODE_FLAG_WINDOW );
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <eepp/ui/uihtmlwidget.hpp>
|
||||
#include <eepp/ui/uirichtext.hpp>
|
||||
#include <eepp/ui/uistyle.hpp>
|
||||
#include <eepp/ui/uitextnode.hpp>
|
||||
#include <eepp/ui/uitextspan.hpp>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
@@ -131,11 +132,26 @@ void BlockLayouter::positionRichTextChildren( Graphics::RichText* rt ) {
|
||||
|
||||
Int64 curCharIdx = 0;
|
||||
|
||||
auto processWidget = [&]( UIWidget* widget, auto& processWidgetRef ) -> Rectf {
|
||||
auto processNode = [&]( Node* node, auto& processNodeRef ) -> Rectf {
|
||||
constexpr Float maxF = std::numeric_limits<Float>::max();
|
||||
constexpr Float lowF = std::numeric_limits<Float>::lowest();
|
||||
Rectf bounds( maxF, maxF, lowF, lowF );
|
||||
|
||||
// UITextNode is a logical marker; its text is rendered by the
|
||||
// RichText engine — just advance the character index and return
|
||||
// empty bounds so it does not affect any widget's geometry.
|
||||
if ( node->isTextNode() ) {
|
||||
curCharIdx += static_cast<UITextNode*>( node )->getText().length();
|
||||
return bounds;
|
||||
}
|
||||
|
||||
if ( !node->isWidget() )
|
||||
return bounds;
|
||||
|
||||
UIWidget* widget = node->asType<UIWidget>();
|
||||
|
||||
// Accumulate ancestor positions so the widget can be placed
|
||||
// relative to the container (mContainer).
|
||||
Vector2f offset;
|
||||
Node* p = widget->getParent();
|
||||
while ( p && p != mContainer ) {
|
||||
@@ -181,12 +197,14 @@ void BlockLayouter::positionRichTextChildren( Graphics::RichText* rt ) {
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into children. UITextNode children advance
|
||||
// curCharIdx but contribute no geometry (they are logical
|
||||
// markers only). Widget children get their own position
|
||||
// and hit-boxes.
|
||||
Node* spanChild = widget->getFirstChild();
|
||||
while ( spanChild != NULL ) {
|
||||
if ( spanChild->isWidget() ) {
|
||||
bounds.expand(
|
||||
processWidgetRef( spanChild->asType<UIWidget>(), processWidgetRef ) );
|
||||
}
|
||||
if ( spanChild->isWidget() )
|
||||
bounds.expand( processNodeRef( spanChild, processNodeRef ) );
|
||||
spanChild = spanChild->getNextNode();
|
||||
}
|
||||
|
||||
@@ -241,12 +259,10 @@ void BlockLayouter::positionRichTextChildren( Graphics::RichText* rt ) {
|
||||
|
||||
child = mContainer->getFirstChild();
|
||||
while ( NULL != child ) {
|
||||
if ( child->isWidget() ) {
|
||||
bool isOutOfFlow = child->isType( UI_TYPE_HTML_WIDGET ) &&
|
||||
child->asType<UIHTMLWidget>()->isOutOfFlow();
|
||||
if ( !isOutOfFlow )
|
||||
processWidget( child->asType<UIWidget>(), processWidget );
|
||||
}
|
||||
bool isOutOfFlow =
|
||||
child->isType( UI_TYPE_HTML_WIDGET ) && child->asType<UIHTMLWidget>()->isOutOfFlow();
|
||||
if ( !isOutOfFlow )
|
||||
processNode( child, processNode );
|
||||
child = child->getNextNode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,7 +553,7 @@ void StyleSheetSpecification::registerDefaultNodeSelectors() {
|
||||
};
|
||||
mNodeSelectors["first-child"] = []( const UIWidget* node, int, int,
|
||||
const FunctionString& ) -> bool {
|
||||
return NULL != node->getParent() && node->getParent()->getFirstChild() == node;
|
||||
return NULL != node->getParent() && node->getElementIndex() == 0;
|
||||
};
|
||||
mNodeSelectors["enabled"] = []( const UIWidget* node, int, int,
|
||||
const FunctionString& ) -> bool { return node->isEnabled(); };
|
||||
@@ -561,69 +561,69 @@ void StyleSheetSpecification::registerDefaultNodeSelectors() {
|
||||
const FunctionString& ) -> bool { return !node->isEnabled(); };
|
||||
mNodeSelectors["first-of-type"] = []( const UIWidget* node, int, int,
|
||||
const FunctionString& ) -> bool {
|
||||
Node* child = NULL != node->getParent() ? node->getParent()->getFirstChild() : NULL;
|
||||
Uint32 type = node->getType();
|
||||
while ( NULL != child ) {
|
||||
if ( type == child->getType() ) {
|
||||
return child == node;
|
||||
}
|
||||
child = child->getNextNode();
|
||||
};
|
||||
return false;
|
||||
return NULL != node->getParent() && node->getElementOfTypeIndex() == 0;
|
||||
};
|
||||
mNodeSelectors["last-child"] = []( const UIWidget* node, int, int,
|
||||
const FunctionString& ) -> bool {
|
||||
return NULL != node->getParent() && node->getParent()->getLastChild() == node;
|
||||
if ( NULL == node->getParent() || !node->getParent()->isWidget() )
|
||||
return false;
|
||||
Node* child = node->getParent()->getLastChild();
|
||||
while ( NULL != child ) {
|
||||
if ( child->isWidget() && !static_cast<UIWidget*>( child )->isTextNode() )
|
||||
return child == node;
|
||||
child = child->getPrevNode();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
mNodeSelectors["last-of-type"] = []( const UIWidget* node, int, int,
|
||||
const FunctionString& ) -> bool {
|
||||
Node* child = NULL != node->getParent() ? node->getParent()->getLastChild() : NULL;
|
||||
if ( NULL == node->getParent() || !node->getParent()->isWidget() )
|
||||
return false;
|
||||
Uint32 type = node->getType();
|
||||
Node* child = node->getParent()->getLastChild();
|
||||
while ( NULL != child ) {
|
||||
if ( type == child->getType() ) {
|
||||
if ( child->getType() == type && child->isWidget() &&
|
||||
!static_cast<UIWidget*>( child )->isTextNode() )
|
||||
return child == node;
|
||||
}
|
||||
child = child->getPrevNode();
|
||||
};
|
||||
}
|
||||
return false;
|
||||
};
|
||||
mNodeSelectors["only-child"] = []( const UIWidget* node, int, int,
|
||||
const FunctionString& ) -> bool {
|
||||
return NULL != node->getParent() && node->getParent()->getChildCount() == 1;
|
||||
return NULL != node->getParent() && node->getParent()->isWidget() &&
|
||||
static_cast<const UIWidget*>( node->getParent() )->getChildElementCount() == 1;
|
||||
};
|
||||
mNodeSelectors["only-of-type"] = []( const UIWidget* node, int, int,
|
||||
const FunctionString& ) -> bool {
|
||||
Node* child = NULL != node->getParent() ? node->getParent()->getFirstChild() : NULL;
|
||||
Uint32 type = node->getType();
|
||||
Uint32 typeCount = 0;
|
||||
while ( NULL != child ) {
|
||||
if ( child->getType() == type ) {
|
||||
typeCount++;
|
||||
}
|
||||
if ( typeCount > 1 )
|
||||
return false;
|
||||
child = child->getNextNode();
|
||||
};
|
||||
return typeCount == 1;
|
||||
return NULL != node->getParent() && node->getParent()->isWidget() &&
|
||||
static_cast<const UIWidget*>( node->getParent() )
|
||||
->getChildElementOfTypeCount( node->getType() ) == 1;
|
||||
};
|
||||
mNodeSelectors["nth-child"] = []( const UIWidget* node, int a, int b,
|
||||
const FunctionString& ) -> bool {
|
||||
return isNth( a, b, node->getNodeIndex() + 1 );
|
||||
return isNth( a, b, node->getElementIndex() + 1 );
|
||||
};
|
||||
mNodeSelectors["nth-last-child"] = []( const UIWidget* node, int a, int b,
|
||||
const FunctionString& ) -> bool {
|
||||
return isNth( a, b, node->getChildCount() - node->getNodeIndex() );
|
||||
return node->getParent() != NULL && node->getParent()->isWidget()
|
||||
? isNth(
|
||||
a, b,
|
||||
static_cast<const UIWidget*>( node->getParent() )->getChildElementCount() -
|
||||
node->getElementIndex() )
|
||||
: false;
|
||||
};
|
||||
mNodeSelectors["nth-of-type"] = []( const UIWidget* node, int a, int b,
|
||||
const FunctionString& ) -> bool {
|
||||
return isNth( a, b, node->getNodeOfTypeIndex() + 1 );
|
||||
return isNth( a, b, node->getElementOfTypeIndex() + 1 );
|
||||
};
|
||||
mNodeSelectors["nth-last-of-type"] = []( const UIWidget* node, int a, int b,
|
||||
const FunctionString& ) -> bool {
|
||||
return node->getParent() != NULL
|
||||
return node->getParent() != NULL && node->getParent()->isWidget()
|
||||
? isNth( a, b,
|
||||
node->getParent()->getChildOfTypeCount( node->getType() ) -
|
||||
node->getNodeOfTypeIndex() )
|
||||
static_cast<const UIWidget*>( node->getParent() )
|
||||
->getChildElementOfTypeCount( node->getType() ) -
|
||||
node->getElementOfTypeIndex() )
|
||||
: false;
|
||||
};
|
||||
mNodeSelectors["checked"] = []( const UIWidget* node, int, int,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <eepp/ui/uirichtext.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uistyle.hpp>
|
||||
#include <eepp/ui/uitextnode.hpp>
|
||||
#include <eepp/ui/uitextspan.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
#include <eepp/ui/uiwidgetcreator.hpp>
|
||||
@@ -549,9 +550,8 @@ void UIRichText::loadFromXmlNode( const pugi::xml_node& node ) {
|
||||
} else if ( child.type() == pugi::node_pcdata ) {
|
||||
String text = Tools::HTMLFormatter::collapseXmlWhitespace( child.value(), child );
|
||||
if ( !text.empty() ) {
|
||||
UITextSpan* span = UITextSpan::New();
|
||||
UITextNode* span = UITextNode::New();
|
||||
span->setParent( this );
|
||||
span->setInheritedStyle( mRichText.getFontStyleConfig() );
|
||||
span->setText( text );
|
||||
}
|
||||
}
|
||||
@@ -596,8 +596,7 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri
|
||||
richText.clear();
|
||||
Float maxWidth = 0;
|
||||
if ( container->getLayoutWidthPolicy() == SizePolicy::WrapContent ) {
|
||||
maxWidth = container->getMatchParentWidth() -
|
||||
container->getPixelsContentOffset().Left -
|
||||
maxWidth = container->getMatchParentWidth() - container->getPixelsContentOffset().Left -
|
||||
container->getPixelsContentOffset().Right;
|
||||
} else {
|
||||
maxWidth = container->getPixelsSize().getWidth() -
|
||||
@@ -634,7 +633,29 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri
|
||||
}
|
||||
}
|
||||
|
||||
auto processWidget = [&]( UIWidget* widget, auto& processWidgetRef ) -> void {
|
||||
auto processNode = [&]( Node* node, auto& processNodeRef ) -> void {
|
||||
if ( node->isTextNode() ) {
|
||||
UITextNode* textNode = static_cast<UITextNode*>( node );
|
||||
if ( !textNode->getText().empty() ) {
|
||||
FontStyleConfig style;
|
||||
if ( node->getParent()->isType( UI_TYPE_TEXTSPAN ) ) {
|
||||
style = node->getParent()->asType<UITextSpan>()->getFontStyleConfig();
|
||||
} else if ( node->getParent()->isType( UI_TYPE_RICHTEXT ) ) {
|
||||
style =
|
||||
node->getParent()->asType<UIRichText>()->getRichText().getFontStyleConfig();
|
||||
} else {
|
||||
style = richText.getFontStyleConfig();
|
||||
}
|
||||
richText.addSpan( textNode->getText(), style );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !node->isWidget() )
|
||||
return;
|
||||
|
||||
UIWidget* widget = node->asType<UIWidget>();
|
||||
|
||||
if ( widget->isType( UI_TYPE_HTML_WIDGET ) &&
|
||||
widget->asType<UIHTMLWidget>()->isMergeable() ) {
|
||||
UITextSpan* span = widget->asType<UITextSpan>();
|
||||
@@ -648,7 +669,7 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri
|
||||
bool isOutOfFlow = spanChild->isType( UI_TYPE_HTML_WIDGET ) &&
|
||||
spanChild->asType<UIHTMLWidget>()->isOutOfFlow();
|
||||
if ( !isOutOfFlow )
|
||||
processWidgetRef( spanChild->asType<UIWidget>(), processWidgetRef );
|
||||
processNodeRef( spanChild, processNodeRef );
|
||||
spanChild = spanChild->getNextNode();
|
||||
}
|
||||
} else if ( widget->isType( UI_TYPE_BR ) ) {
|
||||
@@ -712,7 +733,7 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri
|
||||
bool isOutOfFlow =
|
||||
child->isType( UI_TYPE_HTML_WIDGET ) && child->asType<UIHTMLWidget>()->isOutOfFlow();
|
||||
if ( !isOutOfFlow )
|
||||
processWidget( child->asType<UIWidget>(), processWidget );
|
||||
processNode( child, processNode );
|
||||
child = child->getNextNode();
|
||||
}
|
||||
}
|
||||
|
||||
56
src/eepp/ui/uitextnode.cpp
Normal file
56
src/eepp/ui/uitextnode.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <eepp/ui/uistyle.hpp>
|
||||
#include <eepp/ui/uitextnode.hpp>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
UITextNode* UITextNode::New() {
|
||||
return eeNew( UITextNode, () );
|
||||
}
|
||||
|
||||
UITextNode::UITextNode() : UIWidget( "textnode" ) {
|
||||
mNodeFlags |= NODE_FLAG_TEXTNODE;
|
||||
mFlags |= UI_HTML_ELEMENT;
|
||||
}
|
||||
|
||||
UITextNode::~UITextNode() {}
|
||||
|
||||
Uint32 UITextNode::getType() const {
|
||||
return UI_TYPE_TEXTNODE;
|
||||
}
|
||||
|
||||
bool UITextNode::isType( const Uint32& type ) const {
|
||||
return UITextNode::getType() == type ? true : UIWidget::isType( type );
|
||||
}
|
||||
|
||||
void UITextNode::draw() {
|
||||
// Text nodes do not draw themselves; their parent handles rendering
|
||||
}
|
||||
|
||||
std::string UITextNode::getPropertyString( const PropertyDefinition* propertyDef,
|
||||
const Uint32& propertyIndex ) const {
|
||||
if ( NULL == propertyDef )
|
||||
return "";
|
||||
|
||||
const StyleSheetProperty* prop = getUIStyle()->getProperty( propertyDef->getPropertyId() );
|
||||
if ( prop )
|
||||
return prop->value();
|
||||
|
||||
if ( propertyDef->isInherited() && getParent() && getParent()->isWidget() )
|
||||
return static_cast<UIWidget*>( getParent() )
|
||||
->getPropertyString( propertyDef, propertyIndex );
|
||||
|
||||
return UIWidget::getPropertyString( propertyDef, propertyIndex );
|
||||
}
|
||||
|
||||
const String& UITextNode::getText() const {
|
||||
return mText;
|
||||
}
|
||||
|
||||
void UITextNode::setText( const String& text ) {
|
||||
if ( mText != text ) {
|
||||
mText = text;
|
||||
notifyLayoutAttrChange();
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace EE::UI
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <eepp/ui/uiborderdrawable.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uitextspan.hpp>
|
||||
#include <eepp/ui/uitextnode.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
#include <eepp/ui/uiwidgetcreator.hpp>
|
||||
|
||||
@@ -411,9 +412,8 @@ void UITextSpan::loadFromXmlNode( const pugi::xml_node& node ) {
|
||||
} else if ( child.type() == pugi::node_pcdata ) {
|
||||
String text = Tools::HTMLFormatter::collapseXmlWhitespace( child.value(), child );
|
||||
if ( !text.empty() ) {
|
||||
UITextSpan* span = UITextSpan::New();
|
||||
UITextNode* span = UITextNode::New();
|
||||
span->setParent( this );
|
||||
span->setInheritedStyle( mRichText.getFontStyleConfig() );
|
||||
span->setText( text );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -997,6 +997,64 @@ std::vector<const char*> UIWidget::getStyleSheetPseudoClassesStrings() const {
|
||||
return StyleSheetSelectorRule::fromPseudoClass( mPseudoClasses );
|
||||
}
|
||||
|
||||
bool UIWidget::isWidgetElement() const {
|
||||
return !isTextNode();
|
||||
}
|
||||
|
||||
Uint32 UIWidget::getElementIndex() const {
|
||||
Uint32 index = 0;
|
||||
if ( NULL != mParentNode ) {
|
||||
Node* parentChild = mParentNode->getFirstChild();
|
||||
while ( parentChild != NULL ) {
|
||||
if ( parentChild == this )
|
||||
return index;
|
||||
if ( parentChild->isWidget() && !parentChild->isTextNode() )
|
||||
index++;
|
||||
parentChild = parentChild->getNextNode();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Uint32 UIWidget::getElementOfTypeIndex() const {
|
||||
Uint32 index = 0;
|
||||
if ( NULL != mParentNode ) {
|
||||
Node* parentChild = mParentNode->getFirstChild();
|
||||
Uint32 type = getType();
|
||||
while ( parentChild != NULL ) {
|
||||
if ( parentChild == this )
|
||||
return index;
|
||||
if ( parentChild->getType() == type && parentChild->isWidget() &&
|
||||
!parentChild->isTextNode() )
|
||||
index++;
|
||||
parentChild = parentChild->getNextNode();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Uint32 UIWidget::getChildElementCount() const {
|
||||
Uint32 count = 0;
|
||||
Node* child = mChild;
|
||||
while ( NULL != child ) {
|
||||
if ( child->isWidget() && !child->isTextNode() )
|
||||
count++;
|
||||
child = child->getNextNode();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Uint32 UIWidget::getChildElementOfTypeCount( const Uint32& type ) const {
|
||||
Uint32 count = 0;
|
||||
Node* child = mChild;
|
||||
while ( NULL != child ) {
|
||||
if ( child->getType() == type && child->isWidget() && !child->isTextNode() )
|
||||
count++;
|
||||
child = child->getNextNode();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void UIWidget::updatePseudoClasses() {
|
||||
mPseudoClasses = 0;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <eepp/ui/uirichtext.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uitextspan.hpp>
|
||||
#include <eepp/ui/uitextnode.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
#include <eepp/window/engine.hpp>
|
||||
|
||||
@@ -666,8 +667,8 @@ UTEST( UIRichText, WhitespaceCollapseCodeTest ) {
|
||||
bool foundDotSpace = false;
|
||||
Node* child = rt->getFirstChild();
|
||||
while ( child ) {
|
||||
if ( child->isWidget() && child->isType( UI_TYPE_TEXTSPAN ) ) {
|
||||
UI::UITextSpan* span = static_cast<UI::UITextSpan*>( child );
|
||||
if ( child->isTextNode() ) {
|
||||
UI::UITextNode* span = static_cast<UI::UITextNode*>( child );
|
||||
if ( span->getText() == ". " ) {
|
||||
foundDotSpace = true;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,10 @@ UTEST( CSSInheritance, ComputedFontSize ) {
|
||||
UIWidget* childWidget = child->asType<UIWidget>();
|
||||
std::string pxStr = childWidget->getPropertyString(
|
||||
StyleSheetSpecification::instance()->getProperty( PropertyId::FontSize ) );
|
||||
EXPECT_NEAR( 32u * scale, childWidget->asType<UITextSpan>()->getFontSize(), 1.f );
|
||||
EXPECT_FALSE( pxStr.empty() );
|
||||
EXPECT_NEAR( 32u * scale,
|
||||
childWidget->lengthFromValue( StyleSheetProperty( "font-size", pxStr ) ),
|
||||
1.f );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1091
src/tests/unit_tests/uitextnode_test.cpp
Normal file
1091
src/tests/unit_tests/uitextnode_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user