X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fstyling%2Fstyle-manager-impl.cpp;h=e6ad82f730f102d0fb5a53a85319c3f3dc4d0389;hp=08d61fdccb36a2a68970d8656bb477dd411df9f5;hb=faef4e5740c0024bf3041182a799a2d2395c8787;hpb=5b3cf0e6742934674bdf62bbe15af00e39eae566 diff --git a/dali-toolkit/internal/styling/style-manager-impl.cpp b/dali-toolkit/internal/styling/style-manager-impl.cpp index 08d61fd..e6ad82f 100644 --- a/dali-toolkit/internal/styling/style-manager-impl.cpp +++ b/dali-toolkit/internal/styling/style-manager-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,54 +18,60 @@ #include "style-manager-impl.h" // EXTERNAL INCLUDES -#include -#include -#include +#include #include +#include +#include +#include // INTERNAL INCLUDES -#include -#include -#include +#include +#include #include +#include +#include +#include namespace { - -const char* LANDSCAPE_QUALIFIER = "landscape"; +//const char* LANDSCAPE_QUALIFIER = "landscape"; const char* PORTRAIT_QUALIFIER = "portrait"; -const char* FONT_SIZE_QUALIFIER = "font-size-"; +const char* FONT_SIZE_QUALIFIER = "fontsize"; + +const char* DEFAULT_THEME_FILE_NAME = "dali-toolkit-default-theme.json"; + +const char* PACKAGE_PATH_KEY = "PACKAGE_PATH"; +const char* APPLICATION_RESOURCE_PATH_KEY = "APPLICATION_RESOURCE_PATH"; -const char* DEFAULT_THEME = DALI_STYLE_DIR "dali-toolkit-default-theme.json"; +const char* DEFAULT_TOOLKIT_PACKAGE_PATH = "/toolkit/"; -const char* PACKAGE_PATH_KEY = "PACKAGE_PATH"; -const char* DEFAULT_PACKAGE_PATH = DALI_DATA_READ_ONLY_DIR "/toolkit/"; +static constexpr int32_t COUNT_BROKEN_IMAGE_MAX = 3; + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_STYLE"); +#endif } // namespace namespace Dali { - namespace Toolkit { - namespace Internal { - namespace { - BaseHandle Create() { BaseHandle handle = StyleManager::Get(); - if ( !handle ) + if(!handle) { - SingletonService singletonService( SingletonService::Get() ); - if ( singletonService ) + SingletonService singletonService(SingletonService::Get()); + if(singletonService) { - Toolkit::StyleManager manager = Toolkit::StyleManager( new Internal::StyleManager() ); - singletonService.Register( typeid( manager ), manager ); + Toolkit::StyleManager manager = Toolkit::StyleManager(new Internal::StyleManager()); + singletonService.Register(typeid(manager), manager); handle = manager; } } @@ -73,7 +79,7 @@ BaseHandle Create() return handle; } -DALI_TYPE_REGISTRATION_BEGIN_CREATE( Toolkit::StyleManager, Dali::BaseHandle, Create, true ) +DALI_TYPE_REGISTRATION_BEGIN_CREATE(Toolkit::StyleManager, Dali::BaseHandle, Create, true) DALI_TYPE_REGISTRATION_END() } // namespace @@ -82,15 +88,15 @@ Toolkit::StyleManager StyleManager::Get() { Toolkit::StyleManager manager; - SingletonService singletonService( SingletonService::Get() ); - if ( singletonService ) + SingletonService singletonService(SingletonService::Get()); + if(singletonService) { // Check whether the style manager is already created - Dali::BaseHandle handle = singletonService.GetSingleton( typeid( Toolkit::StyleManager ) ); - if( handle ) + Dali::BaseHandle handle = singletonService.GetSingleton(typeid(Toolkit::StyleManager)); + if(handle) { // If so, downcast the handle of singleton - manager = Toolkit::StyleManager( dynamic_cast< StyleManager* >( handle.GetObjectPtr() ) ); + manager = Toolkit::StyleManager(dynamic_cast(handle.GetObjectPtr())); } } @@ -98,25 +104,32 @@ Toolkit::StyleManager StyleManager::Get() } StyleManager::StyleManager() -: mOrientationDegrees( 0 ), // Portrait - mDefaultFontSize( -1 ), - mThemeFile( DEFAULT_THEME ), - mFeedbackStyle( NULL ) +: mDefaultFontSize(-1), + mDefaultFontFamily(""), + mDefaultThemeFilePath(), + mFeedbackStyle(nullptr) { // Add theme builder constants - mThemeBuilderConstants[ PACKAGE_PATH_KEY ] = DEFAULT_PACKAGE_PATH; + const std::string dataReadOnlyDir = AssetManager::GetDaliDataReadOnlyPath(); + mThemeBuilderConstants[PACKAGE_PATH_KEY] = dataReadOnlyDir + DEFAULT_TOOLKIT_PACKAGE_PATH; + mThemeBuilderConstants[APPLICATION_RESOURCE_PATH_KEY] = Application::GetResourcePath(); mStyleMonitor = StyleMonitor::Get(); - if( mStyleMonitor ) + if(mStyleMonitor) { - mStyleMonitor.StyleChangeSignal().Connect( this, &StyleManager::StyleMonitorChange ); - + mStyleMonitor.StyleChangeSignal().Connect(this, &StyleManager::StyleMonitorChange); mDefaultFontSize = mStyleMonitor.GetDefaultFontSize(); } + // Set the full path for the default style theme. + const std::string styleDirPath = AssetManager::GetDaliStylePath(); + mDefaultThemeFilePath = styleDirPath + DEFAULT_THEME_FILE_NAME; + // Sound & haptic style mFeedbackStyle = new FeedbackStyle(); + // Initialize BrokenImages + mBrokenImageUrls.assign(COUNT_BROKEN_IMAGE_MAX, ""); } StyleManager::~StyleManager() @@ -124,51 +137,30 @@ StyleManager::~StyleManager() delete mFeedbackStyle; } -void StyleManager::SetOrientationValue( int orientation ) +void StyleManager::ApplyTheme(const std::string& themeFile) { - if( orientation != mOrientationDegrees ) - { - mOrientationDegrees = orientation; - // TODO: if orientation changed, apply the new style to all controls - // dont want to really do the whole load from file again if the bundle contains both portrait & landscape - SetTheme(); - } + SetTheme(themeFile); } -int StyleManager::GetOrientationValue() +void StyleManager::ApplyDefaultTheme() { - return mOrientationDegrees; -} - -void StyleManager::SetOrientation( Orientation orientation ) -{ - if( mOrientation ) - { - mOrientation.ChangedSignal().Disconnect( this, &StyleManager::OnOrientationChanged ); - } - - OnOrientationChanged( orientation ); - - if( mOrientation ) - { - mOrientation.ChangedSignal().Connect( this, &StyleManager::OnOrientationChanged ); - } + SetTheme(mDefaultThemeFilePath); } -Orientation StyleManager::GetOrientation() +const std::string& StyleManager::GetDefaultFontFamily() const { - return mOrientation; + return mDefaultFontFamily; } -void StyleManager::SetStyleConstant( const std::string& key, const Property::Value& value ) +void StyleManager::SetStyleConstant(const std::string& key, const Property::Value& value) { - mStyleBuilderConstants[ key ] = value; + mStyleBuilderConstants[key] = value; } -bool StyleManager::GetStyleConstant( const std::string& key, Property::Value& valueOut ) +bool StyleManager::GetStyleConstant(const std::string& key, Property::Value& valueOut) { - Property::Value* value = mStyleBuilderConstants.Find( key ); - if( value ) + Property::Value* value = mStyleBuilderConstants.Find(key); + if(value) { valueOut = *value; return true; @@ -177,228 +169,336 @@ bool StyleManager::GetStyleConstant( const std::string& key, Property::Value& va return false; } -void StyleManager::OnOrientationChanged( Orientation orientation ) +void StyleManager::ApplyThemeStyle(Toolkit::Control control) { - mOrientation = orientation; - // TODO: if orientation changed, apply the new style to all controls - // dont want to really do the whole load from file again if the bundle contains both portrait & landscape - SetTheme(); + if(!mThemeBuilder) + { + ApplyDefaultTheme(); + } + + if(mThemeBuilder) + { + ApplyStyle(mThemeBuilder, control); + } } -Toolkit::Builder StyleManager::CreateBuilder( const Property::Map& constants ) +void StyleManager::ApplyThemeStyleAtInit(Toolkit::Control control) { - Toolkit::Builder builder = Toolkit::Builder::New(); - builder.AddConstants( constants ); + ApplyThemeStyle(control); - return builder; + if(mFeedbackStyle) + { + mFeedbackStyle->ObjectCreated(control); + } } -bool StyleManager::LoadJSON( Toolkit::Builder builder, const std::string& jsonFilePath ) +void StyleManager::ApplyStyle(Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName) { - std::string fileString; - if( LoadFile( jsonFilePath, fileString ) ) + bool builderReady = false; + + // First look in the cache + Toolkit::Builder builder = FindCachedBuilder(jsonFileName); + if(builder) { - builder.LoadFromString( fileString ); - return true; + builderReady = true; } else { - DALI_LOG_WARNING("Error loading file '%s'\n", jsonFilePath.c_str()); - return false; - } -} + // Merge theme and style constants + Property::Map constants(mThemeBuilderConstants); + constants.Merge(mStyleBuilderConstants); -void StyleManager::CollectQualifiers( StringList& qualifiersOut ) -{ - // Append the relevant qualifier for orientation - int orientation = mOrientationDegrees; + // Create it + builder = CreateBuilder(constants); - if( mOrientation ) - { - orientation = mOrientation.GetDegrees(); + if(LoadJSON(builder, jsonFileName)) + { + CacheBuilder(builder, jsonFileName); + builderReady = true; + } } - switch( orientation ) + // Apply the style to the control + if(builderReady) { - case 90: - case 270: - { - qualifiersOut.push_back( std::string( LANDSCAPE_QUALIFIER ) ); - break; - } - case 180: - case 0: // fall through - default: - { - qualifiersOut.push_back( std::string( PORTRAIT_QUALIFIER ) ); - break; - } + builder.ApplyStyle(styleName, control); } } -void StyleManager::BuildQualifiedStyleName( const std::string& styleName, const StringList& qualifiers, std::string& qualifiedStyleOut ) +Toolkit::StyleManager::StyleChangedSignalType& StyleManager::StyleChangedSignal() { - qualifiedStyleOut.append( styleName ); + return mStyleChangedSignal; +} - for( StringList::const_iterator it = qualifiers.begin(), itEnd = qualifiers.end(); it != itEnd; ++it ) - { - const std::string& str = *it; +Toolkit::StyleManager::StyleChangedSignalType& StyleManager::ControlStyleChangeSignal() +{ + return mControlStyleChangeSignal; +} - qualifiedStyleOut.append( "-" ); - qualifiedStyleOut.append( str ); - } +Toolkit::DevelStyleManager::BrokenImageChangedSignalType& StyleManager::BrokenImageChangedSignal() +{ + return mBrokenImageChangedSignal; } -void StyleManager::ApplyStyle( Toolkit::Builder builder, Toolkit::Control control ) +void StyleManager::SetTheme(const std::string& themeFile) { - std::string styleName = control.GetStyleName(); + bool themeLoaded = false; + bool loading = false; - if( styleName.empty() ) + // If we haven't loaded a theme, or the stored theme file is empty, or + // the previously loaded theme is different to the requested theme, + // first reset the builder and load the default theme. + if(!mThemeBuilder || mThemeFile.empty() || mThemeFile.compare(themeFile) != 0) { - // Convert control name to lower case - styleName = control.GetTypeName(); - std::transform( styleName.begin(), styleName.end(), styleName.begin(), ::tolower ); + loading = true; + mThemeBuilder = CreateBuilder(mThemeBuilderConstants); + themeLoaded = LoadJSON(mThemeBuilder, mDefaultThemeFilePath); // Sets themeLoaded to true if theme exists } - // Apply the style after choosing the correct actual style (e.g. landscape or portrait) - StringList qualifiers; - CollectQualifiers( qualifiers ); + if(themeFile.compare(mDefaultThemeFilePath) != 0) + { + // The theme is different to the default: Merge it + loading = true; + themeLoaded |= LoadJSON(mThemeBuilder, themeFile); + } - while( true ) + if(loading) { - std::string qualifiedStyleName; - BuildQualifiedStyleName( styleName, qualifiers, qualifiedStyleName ); + mThemeFile = themeFile; - // Break if style found or we have tried the root style name (qualifiers is empty) - if( builder.ApplyStyle( qualifiedStyleName, control ) || qualifiers.size() == 0 ) + if(themeLoaded) { - break; - } - - // Remove the last qualifier in an attempt to find a style that is valid - qualifiers.pop_back(); - } + // We've successfully loaded the theme file + if(mFeedbackStyle) + { + mFeedbackStyle->StyleChanged(mThemeFile, StyleChange::THEME_CHANGE); + } - if( mDefaultFontSize >= 0 ) - { - // Apply the style for logical font size - std::stringstream fontSizeQualifier; - fontSizeQualifier << styleName << "-" << FONT_SIZE_QUALIFIER << mDefaultFontSize; - builder.ApplyStyle( fontSizeQualifier.str(), control ); + EmitStyleChangeSignals(StyleChange::THEME_CHANGE); + } + else + { + // We tried to load a theme, but it failed. Ensure the builder is reset + mThemeBuilder.Reset(); + mThemeFile.clear(); + } } } -void StyleManager::ApplyThemeStyle( Toolkit::Control control ) +const Property::Map& StyleManager::GetConfigurations() { - if( !mThemeBuilder ) - { - RequestDefaultTheme(); - } + DALI_LOG_STREAM(gLogFilter, Debug::Concise, "GetConfigurations()\n On entry, mThemeBuilder: " << (bool(mThemeBuilder) ? "Created" : "Empty") << " mThemeFile: " << mThemeFile); - if( mThemeBuilder ) + if(!mThemeBuilder) { - ApplyStyle( mThemeBuilder, control ); + DALI_LOG_STREAM(gLogFilter, Debug::Concise, "GetConfigurations() Loading default theme"); + + mThemeBuilder = CreateBuilder(mThemeBuilderConstants); + + // Load default theme because this is first try to load stylesheet. +#if defined(DEBUG_ENABLED) + bool themeLoaded = LoadJSON(mThemeBuilder, mDefaultThemeFilePath); + DALI_LOG_STREAM(gLogFilter, Debug::Concise, " themeLoaded" << (themeLoaded ? "success" : "failure")); +#else + LoadJSON(mThemeBuilder, mDefaultThemeFilePath); +#endif + + mThemeFile = mDefaultThemeFilePath; } + +#if defined(DEBUG_ENABLED) + Property::Map result = mThemeBuilder.GetConfigurations(); + DALI_LOG_STREAM(gLogFilter, Debug::Concise, "GetConfigurations()\n On exit, result Count: " << (result.Count() != 0)); + DALI_LOG_STREAM(gLogFilter, Debug::Verbose, " result: " << result); +#endif + + return mThemeBuilder.GetConfigurations(); } -void StyleManager::ApplyThemeStyleAtInit( Toolkit::Control control ) +void StyleManager::SetBrokenImageUrl(DevelStyleManager::BrokenImageType brokenImageType, const std::string& brokenImageUrl) { - ApplyThemeStyle( control ); - - if(mFeedbackStyle) - { - mFeedbackStyle->ObjectCreated( control ); - } + int brokenType = static_cast(brokenImageType); + mBrokenImageUrls[brokenType] = brokenImageUrl; + Toolkit::StyleManager styleManager = StyleManager::Get(); + mBrokenImageChangedSignal.Emit(styleManager); } -void StyleManager::ApplyStyle( Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName ) +std::string StyleManager::GetBrokenImageUrl(DevelStyleManager::BrokenImageType brokenImageType) { - bool builderReady = false; + int brokenType = static_cast(brokenImageType); + return mBrokenImageUrls[brokenType]; +} - // First look in the cache - Toolkit::Builder builder = FindCachedBuilder( jsonFileName ); - if( builder ) - { - builderReady = true; - } - else +std::vector StyleManager::GetBrokenImageUrlList() +{ + // create a list for brokenImage + std::vector brokenImageUrlList; + for(int i = 0; i < COUNT_BROKEN_IMAGE_MAX; i++) { - // Merge theme and style constants - Property::Map constants( mThemeBuilderConstants ); - constants.Merge( mStyleBuilderConstants ); - - // Create it - builder = CreateBuilder( constants ); - - if( LoadJSON( builder, jsonFileName ) ) + if(!mBrokenImageUrls[i].empty()) { - CacheBuilder( builder, jsonFileName ); - builderReady = true; + brokenImageUrlList.push_back(mBrokenImageUrls[i]); } } - - // Apply the style to the control - if( builderReady ) - { - builder.ApplyStyle( styleName, control ); - } + return brokenImageUrlList; } -bool StyleManager::LoadFile( const std::string& filename, std::string& stringOut ) +bool StyleManager::LoadFile(const std::string& filename, std::string& stringOut) { - DALI_ASSERT_DEBUG( 0 != filename.length()); + DALI_ASSERT_DEBUG(0 != filename.length()); // as toolkit is platform agnostic, it cannot load files from filesystem // ask style monitor to load the style sheet - if( mStyleMonitor ) + if(mStyleMonitor) { - return mStyleMonitor.LoadThemeFile( filename, stringOut ); + return mStyleMonitor.LoadThemeFile(filename, stringOut); } return false; } -Toolkit::StyleManager::StyleChangeSignalType& StyleManager::StyleChangeSignal() +Toolkit::Builder StyleManager::CreateBuilder(const Property::Map& constants) { - return mStyleChangeSignal; + Toolkit::Builder builder = Toolkit::Builder::New(); + builder.AddConstants(constants); + + return builder; } -void StyleManager::RequestThemeChange( const std::string& themeFile ) +bool StyleManager::LoadJSON(Toolkit::Builder builder, const std::string& jsonFilePath) { - mThemeFile = themeFile; + std::string fileString; + if(LoadFile(jsonFilePath, fileString)) + { + builder.LoadFromString(fileString); + return true; + } + else + { + DALI_LOG_WARNING("Error loading file '%s'\n", jsonFilePath.c_str()); + return false; + } +} - // need to do style change synchronously as app might create a UI control on the next line - SetTheme(); +static void CollectQualifiers(std::vector& qualifiersOut) +{ + // Append the relevant qualifier for orientation + // int orientation = 0; // Get the orientation from the system + /* + //// To Do ///// + Getting orientation from the system, and determine Qualifie LANDSCAPE or PORTRAIT + orientation 0, 180 : PORTRAIT_QUALIFIER (default) + orientation 90, 270 : LANDSCAPE_QUALIFIER + */ + + qualifiersOut.push_back(std::string(PORTRAIT_QUALIFIER)); } -void StyleManager::RequestDefaultTheme() +/** + * @brief Construct a qualified style name out of qualifiers + * + * A qualifed style name will be in the format: style-qualifier0-qualifier1-qualifierN + * + * @param[in] styleName The root name of the style + * @param[in] qualifiers List of qualifier names + * @param[out] qualifiedStyleOut The qualified style name + */ +static void BuildQualifiedStyleName( + const std::string& styleName, + const std::vector& qualifiers, + std::string& qualifiedStyleOut) { - RequestThemeChange( DEFAULT_THEME ); + qualifiedStyleOut.append(styleName); + + for(std::vector::const_iterator it = qualifiers.begin(), + itEnd = qualifiers.end(); + it != itEnd; + ++it) + { + const std::string& str = *it; + + qualifiedStyleOut.append("-"); + qualifiedStyleOut.append(str); + } } -void StyleManager::SetTheme() +static bool GetStyleNameForControl(Toolkit::Builder builder, Toolkit::Control control, std::string& styleName) { - mThemeBuilder = CreateBuilder( mThemeBuilderConstants ); + styleName = control.GetStyleName(); + + if(styleName.empty()) + { + styleName = control.GetTypeName(); + } + + // Apply the style after choosing the correct actual style (e.g. landscape or portrait) + std::vector qualifiers; + CollectQualifiers(qualifiers); - if( LoadJSON( mThemeBuilder, mThemeFile ) ) + bool found = 0; + std::string qualifiedStyleName; + do { - if(mFeedbackStyle) + qualifiedStyleName.clear(); + BuildQualifiedStyleName(styleName, qualifiers, qualifiedStyleName); + + // Break if style found or we have tried the root style name (qualifiers is empty) + if(GetImpl(builder).LookupStyleName(qualifiedStyleName)) { - mFeedbackStyle->StyleChanged( mThemeFile, StyleChange::THEME_CHANGE ); + found = true; + break; } + if(qualifiers.size() == 0) + { + break; + } + // Remove the last qualifier in an attempt to find a style that is valid + qualifiers.pop_back(); + } while(!found); - mStyleChangeSignal.Emit( Toolkit::StyleManager::Get(), StyleChange::THEME_CHANGE ); + if(found) + { + styleName = qualifiedStyleName; } - else + return found; +} + +void StyleManager::ApplyStyle(Toolkit::Builder builder, Toolkit::Control control) +{ + std::string styleName = control.GetStyleName(); + if(GetStyleNameForControl(builder, control, styleName)) { - mThemeBuilder.Reset(); + builder.ApplyStyle(styleName, control); } + + if(mDefaultFontSize >= 0) + { + // Apply the style for logical font size + std::stringstream fontSizeQualifier; + fontSizeQualifier << styleName << FONT_SIZE_QUALIFIER << mDefaultFontSize; + builder.ApplyStyle(fontSizeQualifier.str(), control); + } +} + +const StylePtr StyleManager::GetRecordedStyle(Toolkit::Control control) +{ + if(mThemeBuilder) + { + std::string styleName = control.GetStyleName(); + + if(GetStyleNameForControl(mThemeBuilder, control, styleName)) + { + const StylePtr style = GetImpl(mThemeBuilder).GetStyle(styleName); + return style; + } + } + return StylePtr(NULL); } -Toolkit::Builder StyleManager::FindCachedBuilder( const std::string& key ) +Toolkit::Builder StyleManager::FindCachedBuilder(const std::string& key) { - BuilderMap::iterator builderIt = mBuilderCache.find( key ); - if( builderIt != mBuilderCache.end() ) + BuilderMap::iterator builderIt = mBuilderCache.find(key); + if(builderIt != mBuilderCache.end()) { return builderIt->second; } @@ -406,17 +506,18 @@ Toolkit::Builder StyleManager::FindCachedBuilder( const std::string& key ) return Toolkit::Builder(); } -void StyleManager::CacheBuilder( Toolkit::Builder builder, const std::string& key ) +void StyleManager::CacheBuilder(Toolkit::Builder builder, const std::string& key) { - mBuilderCache[ key ] = builder; + mBuilderCache[key] = builder; } -void StyleManager::StyleMonitorChange( StyleMonitor styleMonitor, StyleChange::Type styleChange ) +void StyleManager::StyleMonitorChange(StyleMonitor styleMonitor, StyleChange::Type styleChange) { - switch ( styleChange ) + switch(styleChange) { case StyleChange::DEFAULT_FONT_CHANGE: { + mDefaultFontFamily = styleMonitor.GetDefaultFontFamily(); break; } @@ -428,22 +529,22 @@ void StyleManager::StyleMonitorChange( StyleMonitor styleMonitor, StyleChange::T case StyleChange::THEME_CHANGE: { - const std::string& newTheme = styleMonitor.GetTheme(); - if( ! newTheme.empty() ) - { - mThemeFile = newTheme; - } - else - { - mThemeFile = DEFAULT_THEME; - } - - SetTheme(); + SetTheme(styleMonitor.GetTheme()); break; } } + EmitStyleChangeSignals(styleChange); +} + +void StyleManager::EmitStyleChangeSignals(StyleChange::Type styleChange) +{ + Toolkit::StyleManager styleManager = StyleManager::Get(); + + // Update Controls first + mControlStyleChangeSignal.Emit(styleManager, styleChange); - mStyleChangeSignal.Emit( Toolkit::StyleManager::Get(), styleChange ); + // Inform application last + mStyleChangedSignal.Emit(styleManager, styleChange); } } // namespace Internal