diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index bd36c109a..f10fd3e86 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -117,6 +117,12 @@ table, td { text-align: left; } +hr { + min-height: 1dp; + background-color: gray; + margin: 0.5em 0; +} + center { text-align: center; } diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index b77a3cc8f..389a2228b 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -88,6 +88,15 @@ class EE_API String { return hash; } + static constexpr String::HashType hashToLower( const char* str, Int64 len ) { + String::HashType hash = 5381; + while ( --len >= 0 ) { + int c = *str++; + hash = ( ( hash << 5 ) + hash ) + ( c >= 'A' && c <= 'Z' ? c + 32 : c ); + } + return hash; + } + /** Escape string sequence */ static String escape( const String& str ); @@ -104,6 +113,18 @@ class EE_API String { * String( "text" ) ) */ static String::HashType hash( const String& str ); + /** @return string hash to lower. Assumes ASCII */ + static String::HashType hashToLower( const std::string& str ); + + /** @return string hash to lower. Assumes ASCII */ + static String::HashType hashToLower( const std::string_view& str ); + + /** @return string hash to lower. Assumes ASCII */ + static String::HashType hashToLower( const String::View& str ); + + /** @return string hash to lower. Assumes ASCII */ + static String::HashType hashToLower( const String& str ); + /** @return If the value passed is a character */ static bool isCharacter( const int& value ); diff --git a/include/eepp/system/color.hpp b/include/eepp/system/color.hpp index 0ba9c0749..b4e2c97fb 100644 --- a/include/eepp/system/color.hpp +++ b/include/eepp/system/color.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -220,7 +221,7 @@ class EE_API Color : public tColor { static Color fromString( std::string str ); - static bool isColorString( std::string str, bool searchColorNames = true ); + static bool isColorString( std::string_view str, bool searchColorNames = true ); static bool isColorString( String::View str, bool searchColorNames = true ); @@ -400,9 +401,13 @@ class EE_API Color : public tColor { private: static UnorderedMap sColors; + static UnorderedMap sColorHash; static UnorderedMap sColorMap; static void initColorMap(); + + template + static bool isColorStringT( StringType str, bool searchColorNames ); }; typedef Color ColorA; diff --git a/include/eepp/system/functionstring.hpp b/include/eepp/system/functionstring.hpp index 4e2300baf..3ce0f169e 100644 --- a/include/eepp/system/functionstring.hpp +++ b/include/eepp/system/functionstring.hpp @@ -2,21 +2,36 @@ #define EE_SYSTEM_FUNCTIONSTRING_HPP #include +#include +#include + +#include #include -#include + +template +concept AllowedFunctionString = + std::same_as || std::same_as; namespace EE { namespace System { class EE_API FunctionString { public: - static FunctionString parse( const std::string& function ); + using Parameters = SmallVector; + using TypeStringVector = SmallVector; - FunctionString( const std::string& name, const std::vector& parameters, - const std::vector& typeStringData ); + static FunctionString parse( std::string_view function ); + + static FunctionString parse( String::View function ); + + FunctionString( const std::string& name, const Parameters& parameters, + const TypeStringVector& typeStringData ); + + FunctionString( const std::string& name, Parameters&& parameters, + TypeStringVector&& typeStringData ); const std::string& getName() const; - const std::vector& getParameters() const; + const Parameters& getParameters() const; bool parameterWasString( Uint32 index ) const; @@ -24,8 +39,10 @@ class EE_API FunctionString { protected: std::string name; - std::vector parameters; - std::vector typeStringData; + Parameters parameters; + TypeStringVector typeStringData; + + template static FunctionString parse( StringType function ); }; }} // namespace EE::System diff --git a/include/eepp/system/luapattern.hpp b/include/eepp/system/luapattern.hpp index 9aca1dd3e..fb70b2009 100644 --- a/include/eepp/system/luapattern.hpp +++ b/include/eepp/system/luapattern.hpp @@ -15,13 +15,13 @@ class EE_API LuaPattern : public PatternMatcher { static std::string_view getURIPattern(); static std::string matchesAny( const std::vector& stringvec, - const std::string_view& pattern ); + std::string_view pattern ); - static std::string match( const std::string& string, const std::string_view& pattern ); + static std::string match( std::string_view string, std::string_view pattern ); - static Range firstMatch( const std::string& string, const std::string_view& pattern ); + static Range firstMatch( std::string_view string, std::string_view pattern ); - static bool hasMatches( const std::string& string, const std::string_view& pattern ); + static bool hasMatches( std::string_view string, std::string_view pattern ); LuaPattern( std::string_view pattern, Uint32 options = Options::None ); diff --git a/include/eepp/ui/uirichtext.hpp b/include/eepp/ui/uirichtext.hpp index f5a01c756..471ca5b34 100644 --- a/include/eepp/ui/uirichtext.hpp +++ b/include/eepp/ui/uirichtext.hpp @@ -28,6 +28,8 @@ class EE_API UIRichText : public UILayout { static UIRichText* NewBr(); + static UIRichText* NewHr(); + static UIRichText* NewDiv() { return UIRichText::NewWithTag( "div" ); }; static UIRichText* NewPre() { return UIRichText::NewWithTag( "pre" ); }; diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 333633cf0..31dc7b025 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -658,6 +658,27 @@ String::HashType String::hash( const String& str ) { str.size() * sizeof( String::StringBaseType ) ); } +String::HashType String::hashToLower( const std::string& str ) { + return String::hashToLower( str.c_str(), str.length() ); +} + +String::HashType String::hashToLower( const std::string_view& str ) { + return String::hashToLower( str.data(), str.length() ); +} + +String::HashType String::hashToLower( const String::View& str ) { + String::HashType hash = 5381; + for ( size_t i = 0; i < str.size(); ++i ) { + int c = str[i]; + hash = ( ( hash << 5 ) + hash ) + ( c >= 'A' && c <= 'Z' ? c + 32 : c ); + } + return hash; +} + +String::HashType String::hashToLower( const String& str ) { + return String::hashToLower( str.view() ); +} + bool String::isCharacter( const int& value ) { return ( value >= 32 && value <= 126 ) || ( value >= 161 && value <= 255 ) || ( value == 9 ); } @@ -1332,7 +1353,8 @@ bool String::istartsWith( String::View haystack, String::View needle ) { bool String::istartsWith( const char* haystack, const char* needle ) { size_t needleLen = strlen( needle ); - if ( needleLen > strlen( haystack ) ) return false; + if ( needleLen > strlen( haystack ) ) + return false; return std::equal( needle, needle + needleLen, haystack, []( char c1, char c2 ) { return std::tolower( c1 ) == std::tolower( c2 ); } ); diff --git a/src/eepp/graphics/text.cpp b/src/eepp/graphics/text.cpp index fda99383b..fc94a4d91 100644 --- a/src/eepp/graphics/text.cpp +++ b/src/eepp/graphics/text.cpp @@ -1703,6 +1703,9 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl return; } + if ( mColors.empty() ) + return; + Texture* texture = mFontStyleConfig.Font->getTexture( mFontStyleConfig.CharacterSize ); if ( !texture ) return; diff --git a/src/eepp/system/color.cpp b/src/eepp/system/color.cpp index b281d49eb..c2d48a2cd 100644 --- a/src/eepp/system/color.cpp +++ b/src/eepp/system/color.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -18,6 +19,7 @@ template inline T _round( T r ) { } // namespace UnorderedMap Color::sColors; +UnorderedMap Color::sColorHash; UnorderedMap Color::sColorMap; // Keep the old defined colors @@ -686,10 +688,10 @@ Color Color::fromString( std::string str ) { return Color::Transparent; } } else if ( String::startsWith( str, "@color/" ) ) { - std::string colorName( String::toLower( str.substr( 7 ) ) ); - const auto& it = sColors.find( colorName ); + std::string_view colorName( std::string_view( str ).substr( 7 ) ); + const auto& it = sColorHash.find( String::hashToLower( colorName ) ); - if ( it != sColors.end() ) { + if ( it != sColorHash.end() ) { return it->second; } else { return Color::Transparent; @@ -701,10 +703,9 @@ Color Color::fromString( std::string str ) { if ( it != sColorMap.end() ) return it->second; } else { - String::toLowerInPlace( str ); - const auto& it = sColors.find( str ); + const auto& it = sColorHash.find( String::hashToLower( str ) ); - if ( it != sColors.end() ) { + if ( it != sColorHash.end() ) { return it->second; } else { return Color::Transparent; @@ -714,42 +715,8 @@ Color Color::fromString( std::string str ) { return Color::Transparent; } -bool Color::isColorString( std::string str, bool searchColorNames ) { - if ( str.empty() ) - return false; - - if ( str[0] == '#' ) - return validHexColorString( str ); - - if ( searchColorNames ) { - String::toLowerInPlace( str ); - initColorMap(); - auto it = sColorMap.find( String::hash( str ) ); - if ( it != sColorMap.end() ) - return true; - } - - if ( String::istartsWith( str, "rgb(" ) ) - return true; - else if ( String::istartsWith( str, "rgba(" ) ) - return true; - else if ( String::istartsWith( str, "hsl(" ) ) - return true; - else if ( String::istartsWith( str, "hsla(" ) ) - return true; - else if ( String::istartsWith( str, "hsv(" ) ) - return true; - else if ( String::istartsWith( str, "hsva(" ) ) - return true; - else if ( String::istartsWith( str, "@color/" ) ) - return true; - else if ( sColors.find( str ) != sColors.end() ) - return true; - - return false; -} - -bool Color::isColorString( String::View str, bool searchColorNames ) { +template +bool Color::isColorStringT( StringType str, bool searchColorNames ) { if ( str.empty() ) return false; @@ -759,43 +726,94 @@ bool Color::isColorString( String::View str, bool searchColorNames ) { if ( searchColorNames && str.size() <= 32 ) { initColorMap(); - String::HashType hash = 5381; - for ( size_t i = 0; i < str.size(); ++i ) - hash = ( ( hash << 5 ) + hash ) + std::tolower( str[i] ); - auto it = sColorMap.find( hash ); - if ( it != sColorMap.end() ) + String::HashType hash = String::hashToLower( str ); + if ( sColorMap.find( hash ) != sColorMap.end() ) return true; - std::string lowerStr( String( str ).toUtf8() ); - String::toLowerInPlace( lowerStr ); - if ( sColors.find( lowerStr ) != sColors.end() ) + if ( sColorHash.find( hash ) != sColorHash.end() ) return true; } - if ( String::istartsWith( str, "rgb(" ) ) - return true; - else if ( String::istartsWith( str, "rgba(" ) ) - return true; - else if ( String::istartsWith( str, "hsl(" ) ) - return true; - else if ( String::istartsWith( str, "hsla(" ) ) - return true; - else if ( String::istartsWith( str, "hsv(" ) ) - return true; - else if ( String::istartsWith( str, "hsva(" ) ) - return true; - else if ( String::istartsWith( str, "@color/" ) ) - return true; + if ( String::istartsWith( str, "@color/" ) ) { + std::string utf8Str; + if constexpr ( std::is_same_v ) { + if ( LuaPattern::hasMatches( String( str ).toUtf8(), "@color/[%w_][%w_-]+" ) ) { + return true; + } + } else { + if ( LuaPattern::hasMatches( str, "@color/[%w_][%w_-]+" ) ) { + return true; + } + } + } + + if ( str.back() == ')' ) { + FunctionString func = FunctionString::parse( str ); + + if ( !func.isEmpty() ) { + std::string name = func.getName(); + String::toLowerInPlace( name ); + + if ( name == "rgb" || name == "rgba" || name == "hsl" || name == "hsla" || + name == "hsv" || name == "hsva" ) { + + const auto& params = func.getParameters(); + if ( params.empty() || params.size() > 4 ) + return false; + + for ( const auto& param : params ) { + if ( param.empty() ) + return false; + + bool hasFunc = false; + static const char* allowedFuncs[] = { + "var(", "calc(", "min(", "max(", "clamp(", "env(", "color-mix(", "color(" }; + + for ( const char* f : allowedFuncs ) { + if ( param.find( f ) != std::string::npos ) { + hasFunc = true; + break; + } + } + + if ( hasFunc ) + continue; + + for ( auto c : param ) { + if ( !( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || + ( c >= '0' && c <= '9' ) || c == '.' || c == '%' || c == '-' || + c == '+' || c == ' ' || c == '/' ) ) { + return false; + } + } + } + + return true; + } + } + } return false; } +bool Color::isColorString( std::string_view str, bool searchColorNames ) { + return isColorStringT( str, searchColorNames ); +} + +bool Color::isColorString( String::View str, bool searchColorNames ) { + return isColorStringT( str, searchColorNames ); +} + void Color::registerColor( const std::string& name, const Color& color ) { - sColors[String::toLower( name )] = color; + std::string lowerName( String::toLower( name ) ); + sColors[lowerName] = color; + sColorHash[String::hash( lowerName )] = color; } bool Color::unregisterColor( const std::string& name ) { - return sColors.erase( String::toLower( name ) ) > 0; + std::string lowerName( String::toLower( name ) ); + sColorHash.erase( String::hash( lowerName ) ); + return sColors.erase( lowerName ) > 0; } bool Color::validHexColorString( String::View hexColor ) { diff --git a/src/eepp/system/functionstring.cpp b/src/eepp/system/functionstring.cpp index 161f66605..5649ca71c 100644 --- a/src/eepp/system/functionstring.cpp +++ b/src/eepp/system/functionstring.cpp @@ -4,32 +4,54 @@ namespace EE { namespace System { -FunctionString FunctionString::parse( const std::string& function ) { +#include +#include + +template +FunctionString FunctionString::parse( StringType function ) { + using CharType = typename StringType::value_type; + size_t funcSep = function.find( '(' ); - if ( funcSep == std::string::npos ) + if ( funcSep == StringType::npos ) return FunctionString( "", {}, {} ); - std::string funcName = function.substr( 0, funcSep ); - String::trimInPlace( funcName ); + auto funcName = String::trim( function.substr( 0, funcSep ) ); + Parameters funcParameters; + TypeStringVector typeStringData; - std::vector funcParameters; - std::vector typeStringData; - - std::string parametersString = function.substr( funcSep + 1 ); + auto parametersString = function.substr( funcSep + 1 ); size_t paramClose = parametersString.find_last_of( ')' ); - if ( paramClose == std::string::npos ) + if ( paramClose == StringType::npos ) return FunctionString( "", {}, {} ); parametersString = parametersString.substr( 0, paramClose ); bool stateParsingString = false; - std::string buffer = ""; - char prevChar = 0; + std::basic_string buffer; + CharType prevChar = 0; + bool currentParamIsString = false; int parenDepth = 0; + auto pushBufferToParams = [&]() { + if constexpr ( std::same_as ) { + if ( !currentParamIsString ) + String::trimInPlace( buffer ); + funcParameters.push_back( buffer ); + } else { + std::string utf8Buffer = String( buffer ).toUtf8(); + if ( !currentParamIsString ) + String::trimInPlace( utf8Buffer ); + funcParameters.push_back( utf8Buffer ); + } + typeStringData.push_back( currentParamIsString ); + buffer.clear(); + currentParamIsString = false; + }; + for ( size_t i = 0; i < parametersString.length(); ++i ) { - char c = parametersString[i]; + + CharType c = parametersString[i]; if ( !stateParsingString ) { if ( c == '(' ) { @@ -37,19 +59,14 @@ FunctionString FunctionString::parse( const std::string& function ) { buffer += c; } else if ( c == ')' ) { if ( parenDepth == 0 ) - break; // early exit, last ) wasn't the function closure + break; if ( parenDepth > 0 ) parenDepth--; buffer += c; } else if ( c == ',' ) { if ( parenDepth == 0 ) { if ( !buffer.empty() ) { - if ( !currentParamIsString ) - String::trimInPlace( buffer ); - funcParameters.push_back( buffer ); - typeStringData.push_back( currentParamIsString ); - buffer = ""; - currentParamIsString = false; + pushBufferToParams(); } } else { buffer += c; @@ -84,25 +101,39 @@ FunctionString FunctionString::parse( const std::string& function ) { } } - if ( !buffer.empty() ) { - if ( !currentParamIsString ) - String::trimInPlace( buffer ); - funcParameters.push_back( buffer ); - typeStringData.push_back( currentParamIsString ); - } + if ( !buffer.empty() ) + pushBufferToParams(); - return FunctionString( funcName, funcParameters, typeStringData ); + if constexpr ( std::same_as ) { + return FunctionString( std::string{ funcName }, funcParameters, typeStringData ); + } else { + return FunctionString( String( funcName ).toUtf8(), funcParameters, typeStringData ); + } } -FunctionString::FunctionString( const std::string& name, const std::vector& parameters, - const std::vector& typeStringData ) : +FunctionString FunctionString::parse( std::string_view function ) { + return parse( function ); +} + +FunctionString FunctionString::parse( String::View function ) { + return parse( function ); +} + +FunctionString::FunctionString( const std::string& name, const Parameters& parameters, + const TypeStringVector& typeStringData ) : name( name ), parameters( parameters ), typeStringData( typeStringData ) {} +FunctionString::FunctionString( const std::string& name, Parameters&& parameters, + TypeStringVector&& typeStringData ) : + name( name ), + parameters( std::move( parameters ) ), + typeStringData( std::move( typeStringData ) ) {} + const std::string& FunctionString::getName() const { return name; } -const std::vector& FunctionString::getParameters() const { +const FunctionString::Parameters& FunctionString::getParameters() const { return parameters; } diff --git a/src/eepp/system/luapattern.cpp b/src/eepp/system/luapattern.cpp index 987f61ff2..3fb851824 100644 --- a/src/eepp/system/luapattern.cpp +++ b/src/eepp/system/luapattern.cpp @@ -35,16 +35,16 @@ std::string_view LuaPattern::getURIPattern() { return "%w+://[%w_.~!*:@&+$/?%%#-]-%w[-.%w]*%.%w%w%w?%w?:?%d*/?[%w_.~!*:@&+$/?%%#=-]*"sv; } -std::string LuaPattern::match( const std::string& string, const std::string_view& pattern ) { +std::string LuaPattern::match( std::string_view string, std::string_view pattern ) { LuaPattern matcher( pattern ); int start = 0, end = 0; - if ( matcher.find( string, start, end ) ) - return string.substr( start, end - start ); + if ( matcher.find( string.data(), start, end, 0, string.size() ) ) + return std::string{ string.substr( start, end - start ) }; return ""; } std::string LuaPattern::matchesAny( const std::vector& stringvec, - const std::string_view& pattern ) { + std::string_view pattern ) { LuaPattern matcher( pattern ); int start = 0, end = 0; for ( const auto& str : stringvec ) { @@ -55,16 +55,15 @@ std::string LuaPattern::matchesAny( const std::vector& stringvec, return ""; } -PatternMatcher::Range LuaPattern::firstMatch( const std::string& string, - const std::string_view& pattern ) { +PatternMatcher::Range LuaPattern::firstMatch( std::string_view string, std::string_view pattern ) { LuaPattern matcher( pattern ); int start = 0, end = 0; - if ( matcher.find( string, start, end ) ) + if ( matcher.find( string.data(), start, end, 0, string.size() ) ) return { start, end }; return { -1, -1 }; } -bool LuaPattern::hasMatches( const std::string& string, const std::string_view& pattern ) { +bool LuaPattern::hasMatches( std::string_view string, std::string_view pattern ) { return LuaPattern::firstMatch( string, pattern ).isValid(); } diff --git a/src/eepp/ui/css/drawableimageparser.cpp b/src/eepp/ui/css/drawableimageparser.cpp index e3aeae294..91a89538b 100644 --- a/src/eepp/ui/css/drawableimageparser.cpp +++ b/src/eepp/ui/css/drawableimageparser.cpp @@ -66,7 +66,7 @@ void DrawableImageParser::registerBaseParsers() { RectangleDrawable* drawable = RectangleDrawable::New(); RectColors rectColors; - const std::vector& params( functionType.getParameters() ); + const auto& params( functionType.getParameters() ); if ( Color::isColorString( params.at( 0 ) ) && params.size() >= 2 ) { rectColors.TopLeft = rectColors.TopRight = Color::fromString( params.at( 0 ) ); @@ -112,7 +112,7 @@ void DrawableImageParser::registerBaseParsers() { CircleDrawable* drawable = CircleDrawable::New(); - const std::vector& params( functionType.getParameters() ); + const auto& params( functionType.getParameters() ); CSS::StyleSheetLength length( params[0] ); drawable->setRadius( node->convertLength( length, size.getWidth() / 2.f ) ); @@ -145,7 +145,7 @@ void DrawableImageParser::registerBaseParsers() { RectColors rectColors; std::vector colors; - const std::vector& params( functionType.getParameters() ); + const auto& params( functionType.getParameters() ); for ( size_t i = 0; i < params.size(); i++ ) { std::string param( String::toLower( params[i] ) ); @@ -207,7 +207,7 @@ void DrawableImageParser::registerBaseParsers() { std::vector colors; std::vector vertices; - const std::vector& params( functionType.getParameters() ); + const auto& params( functionType.getParameters() ); Float lineWidth = PixelDensity::dpToPx( 1.f ); for ( size_t i = 0; i < params.size(); i++ ) { @@ -277,7 +277,7 @@ void DrawableImageParser::registerBaseParsers() { std::vector colors; std::vector vertices; - const std::vector& params( functionType.getParameters() ); + const auto& params( functionType.getParameters() ); Float lineWidth = PixelDensity::dpToPx( 1.f ); for ( size_t i = 0; i < params.size(); i++ ) { diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 931ce41b6..f94872eeb 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -662,14 +662,14 @@ void TextDocument::guessIndentType() { int guessCountdown = 10; for ( size_t i = start; i < end; i++ ) { const String& text = mLines[i].getText(); - std::string match = - LuaPattern::match( text.size() > 128 ? text.substr( 0, 12 ) : text, "^ +" ); + std::string match = LuaPattern::match( + text.size() > 128 ? text.substr( 0, 128 ).toUtf8() : text.toUtf8(), "^ +" ); if ( !match.empty() ) { guessSpaces++; guessWidth[match.size()]++; guessCountdown--; } else { - match = LuaPattern::match( mLines[i].getText(), "^\t+" ); + match = LuaPattern::match( mLines[i].getText().toUtf8(), "^\t+" ); if ( !match.empty() ) { guessTabs++; guessCountdown--; diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 795c7200b..7a3e00895 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -312,6 +312,10 @@ void UINode::setMaxSizeEq( const std::string& maxWidthEq, const std::string& max if ( mMaxWidthEq != maxWidthEq || mMaxHeightEq != maxHeightEq ) { mMaxWidthEq = maxWidthEq; mMaxHeightEq = maxHeightEq; + if ( mMaxWidthEq == "none" ) + mMaxWidthEq.clear(); + if ( mMaxHeightEq == "none" ) + mMaxHeightEq.clear(); setSize( mDpSize ); } } @@ -319,6 +323,8 @@ void UINode::setMaxSizeEq( const std::string& maxWidthEq, const std::string& max void UINode::setMaxWidthEq( const std::string& maxWidthEq ) { if ( mMaxWidthEq != maxWidthEq ) { mMaxWidthEq = maxWidthEq; + if ( mMaxWidthEq == "none" ) + mMaxWidthEq.clear(); onSizeChange(); } } @@ -330,6 +336,8 @@ const std::string& UINode::getMaxHeightEq() const { void UINode::setMaxHeightEq( const std::string& maxHeightEq ) { if ( mMaxHeightEq != maxHeightEq ) { mMaxHeightEq = maxHeightEq; + if ( mMaxHeightEq == "none" ) + mMaxHeightEq.clear(); onSizeChange(); } } diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 73f4c6649..463b61cfa 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -17,9 +17,9 @@ namespace EE { namespace UI { class UILineBreak : public UIRichText { public: - static UILineBreak* New() { return eeNew( UILineBreak, () ); } + static UILineBreak* New( const std::string& tag = "" ) { return eeNew( UILineBreak, ( tag ) ); } - UILineBreak() : UIRichText( "br " ) {} + UILineBreak( const std::string& tag = "br" ) : UIRichText( tag ) {} virtual Uint32 getType() const { return UI_TYPE_BR; } @@ -32,6 +32,10 @@ UIRichText* UIRichText::NewBr() { return UILineBreak::New(); }; +UIRichText* UIRichText::NewHr() { + return UILineBreak::New( "hr" ); +}; + UIRichText* UIRichText::New() { return eeNew( UIRichText, () ); } diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 44e0876f3..0999a3b32 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -155,6 +155,7 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["h5"] = UIRichText::NewH5; registeredWidget["h6"] = UIRichText::NewH6; registeredWidget["br"] = UIRichText::NewBr; + registeredWidget["hr"] = UIRichText::NewHr; registeredWidget["ul"] = [] { return UILinearLayout::NewVerticalWidthMatchParent( "ul" ); }; registeredWidget["ol"] = [] { return UILinearLayout::NewVerticalWidthMatchParent( "ol" ); }; registeredWidget["li"] = UIRichText::NewListItem; diff --git a/src/examples/ui_html/ui_html.cpp b/src/examples/ui_html/ui_html.cpp index 293df629e..5fbea4026 100644 --- a/src/examples/ui_html/ui_html.cpp +++ b/src/examples/ui_html/ui_html.cpp @@ -14,6 +14,9 @@ EE_MAIN_FUNC int main( int argc, char** argv ) { { 'c', "prefers-color-scheme" } ); args::Flag hnDark( parser, "hn-dark", "Force a custom CSS style for Hacker News site to be dark.", { "hn-dark" } ); + args::Flag benchmarkMode( parser, "benchmark-mode", + "Render as much as possible to measure the rendering performance.", + { "benchmark-mode" } ); try { parser.ParseCLI( Sys::parseArguments( argc, argv ) ); @@ -30,7 +33,10 @@ EE_MAIN_FUNC int main( int argc, char** argv ) { return EXIT_FAILURE; } - UIApplication app( { 1280, 720, "eepp - UI HTML Example" } ); + UIApplication app( + { 1280, 720, "eepp - UI HTML Example" }, UIApplication::Settings(), + ContextSettings( + false, benchmarkMode.Get() ? 0 : ContextSettings::FrameRateLimitScreenRefreshRate ) ); Log::instance()->setLogLevelThreshold( LogLevel::Debug ); Log::instance()->setLogToStdOut( true ); @@ -223,5 +229,20 @@ EE_MAIN_FUNC int main( int argc, char** argv ) { } } ); + if ( benchmarkMode.Get() ) { + app.getWindow()->runMainLoop( [&app]() { + app.getWindow()->getInput()->update(); + SceneManager::instance()->update(); + app.getWindow()->clear(); + SceneManager::instance()->draw(); + auto tm = app.getUI()->getUIThemeManager(); + String fps( String::format( "FPS: %d", app.getWindow()->getFPS() ) ); + Text::draw( fps, Vector2f::Zero, tm->getDefaultFont(), tm->getDefaultFontSize(), + Color::magenta, 0, 0, Color::Black, Color::Black, Vector2f{ 1, 1 }, 4, + TextHints::AllAscii ); + app.getWindow()->display(); + } ); + return EXIT_SUCCESS; + } return app.run(); }