mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Add support for --var: var(--other-var).
Reset global definition for body and html elements when new styles are loaded (required when these elements have only variable definitions).
This commit is contained in:
@@ -40,6 +40,8 @@ class EE_API ElementDefinition : NonCopyable {
|
||||
bool mStructurallyVolatile;
|
||||
|
||||
void findVariables( const CSS::StyleSheetStyle* style );
|
||||
|
||||
void resolveVariables();
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::CSS
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <eepp/system/functionstring.hpp>
|
||||
#include <eepp/ui/css/elementdefinition.hpp>
|
||||
|
||||
namespace EE { namespace UI { namespace CSS {
|
||||
@@ -70,6 +71,8 @@ void ElementDefinition::refresh() {
|
||||
findVariables( styleSheetStyle );
|
||||
}
|
||||
|
||||
resolveVariables();
|
||||
|
||||
for ( auto& property : mProperties )
|
||||
mPropertyIds.insert( property.first );
|
||||
}
|
||||
@@ -78,11 +81,68 @@ void ElementDefinition::findVariables( const StyleSheetStyle* style ) {
|
||||
for ( const auto& vars : style->getVariables() ) {
|
||||
const StyleSheetVariable& variable = vars.second;
|
||||
const auto& it = mVariables.find( variable.getNameHash() );
|
||||
|
||||
if ( it == mVariables.end() || variable.getSpecificity() >= it->second.getSpecificity() ) {
|
||||
mVariables[variable.getNameHash()] = variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resolveVarValue( std::string& value, const StyleSheetVariables& variables,
|
||||
UnorderedSet<String::HashType>& visited, int depth = 0 ) {
|
||||
static constexpr int maxDepth = 32;
|
||||
if ( depth > maxDepth )
|
||||
return;
|
||||
|
||||
std::string::size_type tokenStart = 0;
|
||||
|
||||
while ( true ) {
|
||||
tokenStart = value.find( "var(", tokenStart );
|
||||
if ( tokenStart == std::string::npos )
|
||||
return;
|
||||
|
||||
std::string::size_type tokenEnd = String::findCloseBracket( value, tokenStart, '(', ')' );
|
||||
if ( tokenEnd == std::string::npos )
|
||||
return;
|
||||
|
||||
std::string varDef( value, tokenStart, tokenEnd + 1 - tokenStart );
|
||||
System::FunctionString functionType = System::FunctionString::parse( varDef );
|
||||
|
||||
if ( functionType.getParameters().empty() ) {
|
||||
tokenStart = tokenEnd;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool resolved = false;
|
||||
for ( auto& param : functionType.getParameters() ) {
|
||||
if ( String::startsWith( param, "--" ) ) {
|
||||
auto it = variables.find( String::hash( param ) );
|
||||
if ( it != variables.end() &&
|
||||
visited.find( it->second.getNameHash() ) == visited.end() ) {
|
||||
visited.insert( it->second.getNameHash() );
|
||||
std::string deepValue( it->second.getValue() );
|
||||
resolveVarValue( deepValue, variables, visited, depth + 1 );
|
||||
String::replaceAll( value, varDef, deepValue );
|
||||
resolved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( resolved )
|
||||
tokenStart = 0;
|
||||
else
|
||||
tokenStart = tokenEnd;
|
||||
}
|
||||
}
|
||||
|
||||
void ElementDefinition::resolveVariables() {
|
||||
static UnorderedSet<String::HashType> visited;
|
||||
for ( auto& varPair : mVariables ) {
|
||||
std::string value( varPair.second.getValue() );
|
||||
visited.clear();
|
||||
resolveVarValue( value, mVariables, visited );
|
||||
varPair.second.setValue( value );
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace EE::UI::CSS
|
||||
|
||||
@@ -422,6 +422,14 @@ void UISceneNode::updateStyleSheet( bool forceReloadStyle ) {
|
||||
if ( mRoot && mRoot->getUIStyle() )
|
||||
mRoot->getUIStyle()->resetGlobalDefinition();
|
||||
|
||||
auto bodies = mRoot->findAllByType( UI_TYPE_HTML_BODY );
|
||||
for ( auto body : bodies )
|
||||
body->asType<UIWidget>()->getUIStyle()->resetGlobalDefinition();
|
||||
|
||||
auto htmls = mRoot->findAllByType( UI_TYPE_HTML_HTML );
|
||||
for ( auto html : htmls )
|
||||
html->asType<UIWidget>()->getUIStyle()->resetGlobalDefinition();
|
||||
|
||||
if ( mRoot && mediaChanged )
|
||||
mRoot->reportStyleStateChangeRecursive( false, false );
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "utest.hpp"
|
||||
#include <eepp/graphics/font.hpp>
|
||||
#include <eepp/graphics/fontmanager.hpp>
|
||||
#include <eepp/graphics/pixeldensity.hpp>
|
||||
#include <eepp/scene/node.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/ui/css/stylesheet.hpp>
|
||||
@@ -354,8 +355,7 @@ UTEST( CSSUnits, ExChWithFont ) {
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash() ), 1.f );
|
||||
|
||||
Graphics::Font* font =
|
||||
app.getUI()->getUIThemeManager()->getDefaultFont();
|
||||
Graphics::Font* font = app.getUI()->getUIThemeManager()->getDefaultFont();
|
||||
EXPECT_TRUE( font != nullptr );
|
||||
|
||||
Float elFontSize = 24.f;
|
||||
@@ -374,49 +374,163 @@ UTEST( CSSUnits, ExChWithFont ) {
|
||||
EXPECT_NE( fallback, resultCh );
|
||||
}
|
||||
|
||||
UTEST( CSSUnits, Integration ) {
|
||||
for ( Float scale : { 1.f, 1.5f, 2.f } ) {
|
||||
UTEST_PRINT_STEP( String::format( "SCALE %.1f", scale ).c_str() );
|
||||
UIApplication app( WindowSettings( 800, 600, "eepp - CSS Units Ex/Ch Integration Test",
|
||||
WindowStyle::Default, WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings(
|
||||
Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), scale ) );
|
||||
UTEST( CSSVariables, VariableReferencesSimple ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 800, 600, "eepp - CSS Var Ref Test 1", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash() ), 1 );
|
||||
|
||||
std::string xml = R"(
|
||||
std::string xml = R"(
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.text {
|
||||
font-size: 20px;
|
||||
}
|
||||
#exbox {
|
||||
width: 10ex;
|
||||
height: 2ex;
|
||||
}
|
||||
#chbox {
|
||||
width: 10ch;
|
||||
height: 2ch;
|
||||
body {
|
||||
--primary: #FF0000;
|
||||
--text-color: var(--primary);
|
||||
color: var(--text-color);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="exbox" class="text">x</div>
|
||||
<div id="chbox" class="text">0</div>
|
||||
<div id="testdiv">Test text</div>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
)";
|
||||
|
||||
UIWidget* root = app.getUI()->loadLayoutFromString( xml );
|
||||
EXPECT_TRUE( root != nullptr );
|
||||
UIWidget* root = app.getUI()->loadLayoutFromString( xml );
|
||||
EXPECT_TRUE( root != nullptr );
|
||||
|
||||
UIRichText* exbox = root->querySelector( "#exbox" )->asType<UIRichText>();
|
||||
EXPECT_TRUE( exbox != nullptr );
|
||||
EXPECT_GT( exbox->getPixelsSize().getWidth(), 0.f );
|
||||
EXPECT_GT( exbox->getPixelsSize().getHeight(), 0.f );
|
||||
UIRichText* div = root->querySelector( "#testdiv" )->asType<UIRichText>();
|
||||
EXPECT_TRUE( div != nullptr );
|
||||
|
||||
UIRichText* chbox = root->querySelector( "#chbox" )->asType<UIRichText>();
|
||||
EXPECT_TRUE( chbox != nullptr );
|
||||
EXPECT_GT( chbox->getPixelsSize().getWidth(), 0.f );
|
||||
EXPECT_GT( chbox->getPixelsSize().getHeight(), 0.f );
|
||||
}
|
||||
EXPECT_TRUE( Color( "#FF0000" ) == div->getFontColor() );
|
||||
}
|
||||
|
||||
UTEST( CSSVariables, VariableReferencesChain ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 800, 600, "eepp - CSS Var Ref Test 2", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash() ), 1 );
|
||||
|
||||
std::string xml = R"(
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
--a: #00FF00;
|
||||
--b: var(--a);
|
||||
--c: var(--b);
|
||||
color: var(--c);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="testdiv">Test text</div>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
UIWidget* root = app.getUI()->loadLayoutFromString( xml );
|
||||
EXPECT_TRUE( root != nullptr );
|
||||
|
||||
UIRichText* div = root->querySelector( "#testdiv" )->asType<UIRichText>();
|
||||
EXPECT_TRUE( div != nullptr );
|
||||
|
||||
EXPECT_TRUE( Color( "#00FF00" ) == div->getFontColor() );
|
||||
}
|
||||
|
||||
UTEST( CSSVariables, VariableReferencesWithPadding ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 800, 600, "eepp - CSS Var Ref Test 3", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash() ), 1 );
|
||||
|
||||
std::string xml = R"(
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
#testdiv {
|
||||
--base: 20px;
|
||||
--spacing: var(--base);
|
||||
padding: var(--spacing);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="testdiv">Test text</div>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
UIWidget* root = app.getUI()->loadLayoutFromString( xml );
|
||||
EXPECT_TRUE( root != nullptr );
|
||||
|
||||
UIWidget* div = root->querySelector( "#testdiv" );
|
||||
EXPECT_TRUE( div != nullptr );
|
||||
|
||||
Float padding = PixelDensity::dpToPx( div->getPadding().Left );
|
||||
EXPECT_NEAR( 20.f, padding, 1.f );
|
||||
}
|
||||
|
||||
UTEST( CSSVariables, VariableReferencesMultiple ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 800, 600, "eepp - CSS Var Ref Test 4", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash() ), 1 );
|
||||
|
||||
std::string xml = R"(
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
#testdiv {
|
||||
--color1: #0000FF;
|
||||
--color2: var(--color1);
|
||||
--color3: var(--color2);
|
||||
color: var(--color3);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="testdiv">Test text</div>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
UIWidget* root = app.getUI()->loadLayoutFromString( xml );
|
||||
EXPECT_TRUE( root != nullptr );
|
||||
|
||||
UIRichText* div = root->querySelector( "#testdiv" )->asType<UIRichText>();
|
||||
EXPECT_TRUE( div != nullptr );
|
||||
|
||||
EXPECT_TRUE( Color( "#0000FF" ) == div->getFontColor() );
|
||||
}
|
||||
|
||||
UTEST( CSSVariables, VariableReferencesCircular ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 800, 600, "eepp - CSS Var Ref Test 5", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash() ), 1 );
|
||||
|
||||
std::string xml = R"(
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
--x: var(--y);
|
||||
--y: var(--x);
|
||||
color: var(--x, #FF0000);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="testdiv">Test text</div>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
UIWidget* root = app.getUI()->loadLayoutFromString( xml );
|
||||
EXPECT_TRUE( root != nullptr );
|
||||
|
||||
UIRichText* div = root->querySelector( "#testdiv" )->asType<UIRichText>();
|
||||
EXPECT_TRUE( div != nullptr );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user