-/*
+ /*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
#include <test-button.h>
#include <test-animation-data.h>
#include <toolkit-style-monitor.h>
+#include <dummy-control.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
using namespace Dali;
using namespace Dali::Toolkit;
" \"grabHandleImage\" : \"{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png\",\n"
" \"selectionHandleImageLeft\" : {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png\" },\n"
" \"selectionHandleImageRight\": {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png\" }\n"
+" },\n"
+" \"ComplexControl\":\n"
+" {\n"
+" \"states\":\n"
+" {\n"
+" \"NORMAL\":\n"
+" {\n"
+" \"states\":\n"
+" {\n"
+" \"SELECTED\":\n"
+" {\n"
+" \"visuals\":\n"
+" {\n"
+" \"foregroundVisual\":\n"
+" {\n"
+" \"visualType\":\"GRADIENT\",\n"
+" \"startPosition\": [-1, -1],\n"
+" \"endPosition\": [1, 1],\n"
+" \"spreadMethod\": \"REPEAT\",\n"
+" \"stopOffset\": [0.2, 0.8],\n"
+" \"stopColor\": [ [ 1,0,0,1], [0,1,0,1] ]\n"
+" }\n"
+" }\n"
+" },\n"
+" \"UNSELECTED\":\n"
+" {\n"
+" \"visuals\":\n"
+" {\n"
+" \"foregroundVisual\":\n"
+" {\n"
+" \"visualType\":\"COLOR\",\n"
+" \"mixColor\": [ 1,0,0,1]\n"
+" }\n"
+" }\n"
+" }\n"
+" },\n"
+" \"transitions\":\n"
+" {\n"
+" \"visualName\":\"*\",\n"
+" \"effect\":\"CROSSFADE\",\n"
+" \"animator\":\n"
+" {\n"
+" \"alphaFunction\":\"EASE_IN_OUT\",\n"
+" \"duration\":0.3\n"
+" }\n"
+" }\n"
+" },\n"
+" \"FOCUSED\":\n"
+" {\n"
+" \"visuals\":\n"
+" {\n"
+" \"foregroundVisual\":\n"
+" {\n"
+" \"visualType\":\"GRADIENT\",\n"
+" \"startPosition\": [-1, -1],\n"
+" \"endPosition\": [1, 1],\n"
+" \"spreadMethod\": \"REPEAT\",\n"
+" \"stopOffset\": [0.3, 0.9],\n"
+" \"stopColor\": [ [ 0,0,1,1], [0,1,1,1] ]\n"
+" },\n"
+" \"focusVisual\":\n"
+" {\n"
+" \"visualType\":\"IMAGE\",\n"
+" \"url\": \"focus.png\"\n"
+" }\n"
+" },\n"
+" \"entryTransition\":\n"
+" {\n"
+" \"target\":\"focusVisual\",\n"
+" \"property\":\"mixColor\",\n"
+" \"initialValue\":[0,0,0,0],\n"
+" \"targetValue\":[1,1,1,1],\n"
+" \"animator\":\n"
+" {\n"
+" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n"
+" \"timePeriod\": \n"
+" {\n"
+" \"duration\":0.5,\n"
+" \"delay\":0\n"
+" }\n"
+" }\n"
+" },\n"
+" \"exitTransition\":\n"
+" {\n"
+" \"target\":\"focusVisual\",\n"
+" \"property\":\"mixColor\",\n"
+" \"initialValue\":[1,1,1,1],\n"
+" \"targetValue\":[0,0,0,0],\n"
+" \"animator\":\n"
+" {\n"
+" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n"
+" \"timePeriod\": \n"
+" {\n"
+" \"duration\":0.5,\n"
+" \"delay\":0\n"
+" }\n"
+" }\n"
+" }\n"
+" },\n"
+" \"DISABLED\":\n"
+" {\n"
+" \"visuals\":\n"
+" {\n"
+" \"foregroundVisual\":\n"
+" {\n"
+" \"visualType\":\"COLOR\",\n"
+" \"mixColor\": [1,0,0,1]\n"
+" }\n"
+" }\n"
+" }\n"
+" },\n"
+" \"transitions\":\n"
+" [\n"
+" {\n"
+" \"effect\":\"CROSSFADE\",\n"
+" \"animator\":\n"
+" {\n"
+" \"alphaFunction\":\"EASE_IN_OUT\",\n"
+" \"duration\":0.3\n"
+" }\n"
+" }\n"
+" ]\n"
+" },\n"
+" \"BasicControl\":\n"
+" {\n"
+" \"states\":\n"
+" {\n"
+" \"NORMAL\":\n"
+" {\n"
+" \"visuals\":\n"
+" {\n"
+" \"foregroundVisual\":\n"
+" {\n"
+" \"visualType\":\"GRADIENT\",\n"
+" \"startPosition\": [-1, -1],\n"
+" \"endPosition\": [1, 1],\n"
+" \"spreadMethod\": \"REPEAT\",\n"
+" \"stopOffset\": [0.2, 0.8],\n"
+" \"stopColor\": [ [ 1,0,0,1], [0,1,0,1] ]\n"
+" }\n"
+" }\n"
+" },\n"
+" \"FOCUSED\":\n"
+" {\n"
+" \"visuals\":\n"
+" {\n"
+" \"foregroundVisual\":\n"
+" {\n"
+" \"visualType\":\"GRADIENT\",\n"
+" \"startPosition\": [-1, -1],\n"
+" \"endPosition\": [1, 1],\n"
+" \"spreadMethod\": \"REPEAT\",\n"
+" \"stopOffset\": [0.3, 0.9],\n"
+" \"stopColor\": [ [ 0,0,1,1], [0,1,1,1] ]\n"
+" },\n"
+" \"focusVisual\":\n"
+" {\n"
+" \"visualType\":\"IMAGE\",\n"
+" \"url\": \"focus.png\"\n"
+" }\n"
+" },\n"
+" \"entryTransition\":\n"
+" {\n"
+" \"target\":\"focusVisual\",\n"
+" \"property\":\"mixColor\",\n"
+" \"initialValue\":[0,0,0,0],\n"
+" \"targetValue\":[1,1,1,1],\n"
+" \"animator\":\n"
+" {\n"
+" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n"
+" \"timePeriod\": \n"
+" {\n"
+" \"duration\":0.5,\n"
+" \"delay\":0\n"
+" }\n"
+" }\n"
+" },\n"
+" \"exitTransition\":\n"
+" {\n"
+" \"target\":\"focusVisual\",\n"
+" \"property\":\"mixColor\",\n"
+" \"initialValue\":[1,1,1,1],\n"
+" \"targetValue\":[0,0,0,0],\n"
+" \"animator\":\n"
+" {\n"
+" \"alphaFunction\":\"EASE_IN_OUT_SINE\",\n"
+" \"timePeriod\": \n"
+" {\n"
+" \"duration\":0.5,\n"
+" \"delay\":0\n"
+" }\n"
+" }\n"
+" }\n"
+" },\n"
+" \"DISABLED\":\n"
+" {\n"
+" \"visuals\":\n"
+" {\n"
+" \"foregroundVisual\":\n"
+" {\n"
+" \"visualType\":\"COLOR\",\n"
+" \"mixColor\": [1,0,0,1]\n"
+" }\n"
+" }\n"
+" }\n"
+" },\n"
+" \"transitions\":\n"
+" [\n"
+" {\n"
+" \"effect\":\"CROSSFADE\",\n"
+" \"animator\":\n"
+" {\n"
+" \"alphaFunction\":\"EASE_IN_OUT\",\n"
+" \"duration\":0.3\n"
+" }\n"
+" }\n"
+" ]\n"
" }\n"
" }\n"
"}\n";
+
void dali_style_manager_startup(void)
{
test_return_value = TET_UNDEF;
END_TEST;
}
+
+
+int UtcDaliStyleManagerVisualTransitionParsing(void)
+{
+ tet_infoline("Instantiate dummy control and test state/visual/transition capture" );
+ Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+ defaultTheme );
+
+ ToolkitTestApplication application;
+
+ StyleChangedSignalChecker styleChangedSignalHandler;
+ Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+ StyleManager styleManager = StyleManager::Get();
+
+ DummyControl actor = DummyControl::New(true);
+ actor.SetStyleName("BasicControl");
+ Stage::GetCurrent().Add(actor);
+
+ Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+
+ DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+ Visual::Base visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+
+ actor.SetProperty( DevelControl::Property::STATE, DevelControl::FOCUSED );
+
+ DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), true, TEST_LOCATION);
+
+ Visual::Base visual2 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+ DALI_TEST_CHECK( visual1 != visual2 );
+
+ actor.SetProperty( DevelControl::Property::STATE, DevelControl::DISABLED );
+
+ DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+
+ Visual::Base visual3 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+ Visual::Base focusVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+ DALI_TEST_CHECK( !focusVisual );
+ DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), false, TEST_LOCATION);
+
+ DALI_TEST_CHECK( visual1 != visual3 );
+ DALI_TEST_CHECK( visual2 != visual3 );
+
+ END_TEST;
+}
+
+
+int UtcDaliStyleManagerVisualTransitionParsing02(void)
+{
+ tet_infoline("Instantiate dummy control and test state/visual/transition capture" );
+ Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+ defaultTheme );
+
+ ToolkitTestApplication application;
+
+ StyleChangedSignalChecker styleChangedSignalHandler;
+ Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+ StyleManager styleManager = StyleManager::Get();
+
+ DummyControl actor = DummyControl::New(true);
+ actor.SetProperty(DevelControl::Property::STATE, "FOCUSED");
+
+ actor.SetStyleName("ComplexControl");
+ Stage::GetCurrent().Add(actor);
+
+ Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+
+ DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+ Visual::Base visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+ DALI_TEST_CHECK( visual1 );
+ Property::Map map;
+ visual1.CreatePropertyMap( map );
+ Property::Value* value = map.Find( Visual::Property::TYPE );
+ DALI_TEST_CHECK( value );
+
+ int visualType;
+ value->Get( visualType );
+
+ DALI_TEST_EQUALS( visualType, (int)Toolkit::Visual::GRADIENT, TEST_LOCATION );
+
+ END_TEST;
+}
Dali::PropertyRegistration dummyControlVisualProperty02(
typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+Dali::PropertyRegistration dummyControlVisualProperty03(
+ typeRegistration, "foregroundVisual", Dali::Toolkit::DummyControl::Property::FOREGROUND_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
+Dali::PropertyRegistration dummyControlVisualProperty04(
+ typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
}
DummyControl DummyControlImpl::New()
void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value )
{
+ Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) );
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
+
+ switch(index)
+ {
+ case Toolkit::DummyControl::Property::TEST_VISUAL:
+ case Toolkit::DummyControl::Property::TEST_VISUAL2:
+ case Toolkit::DummyControl::Property::FOREGROUND_VISUAL:
+ case Toolkit::DummyControl::Property::FOCUS_VISUAL:
+ {
+ Property::Map* map = value.GetMap();
+ if( map != NULL )
+ {
+ VisualFactory visualFactory = VisualFactory::Get();
+ Visual::Base visual = visualFactory.CreateVisual(*map);
+ dummyImpl.RegisterVisual(index, visual);
+ }
+ break;
+ }
+ }
}
Property::Value DummyControlImpl::GetProperty( BaseObject* object, Dali::Property::Index propertyIndex )
enum Type
{
TEST_VISUAL = PROPERTY_START_INDEX,
- TEST_VISUAL2
+ TEST_VISUAL2,
+ FOREGROUND_VISUAL,
+ FOCUS_VISUAL
};
};
void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled );
void UnregisterVisual( Property::Index index );
void EnableVisual( Property::Index index, bool enabled );
- bool IsVisualEnabled( Property::Index indepx );
+ bool IsVisualEnabled( Property::Index index );
Toolkit::Visual::Base GetVisual( Property::Index index );
Animation CreateTransition( const Toolkit::TransitionData& transition );
" \"name\": \"greeting\","
" \"type\": \"TextLabel\","
" \"text\": \"Touch me\","
- " \"styles\": [\"basicText\"],"
+ " \"inherit\": [\"basicText\"],"
" \"position\": [0, -120, 0],"
" \"size\": [200, 200, 1],"
" \"orientation\": [0, 0, 30],"
" \"name\": \"greeting\","
" \"type\": \"TextLabel\","
" \"text\": \"Touch me\","
- " \"styles\": [\"basicText\"],"
+ " \"inherit\": [\"basicText\"],"
" \"position\": [0, -120, 0],"
" \"size\": [200, 200, 1],"
" \"orientation\": [0, 0, 30],"
#include "dali-toolkit/devel-api/builder/tree-node.h"
#include "dali-toolkit/internal/builder/tree-node-manipulator.h"
-namespace
+
+namespace Dali
{
bool CaseInsensitiveCharacterCompare( unsigned char a, unsigned char b )
return result;
}
-} // anonymous namespace
-
-
-namespace Dali
-{
-
namespace Toolkit
{
namespace DevelControl
{
+enum State
+{
+ NORMAL,
+ FOCUSED,
+ DISABLED
+};
+
namespace Property
{
* @see Toolkit::Tooltip
*/
TOOLTIP = BACKGROUND + 1,
+
+ /**
+ * @brief The current state of the control.
+ * @details Name "state", type DevelControl::State ( Property::INTEGER ) or Property::STRING
+ *
+ * @see DevelControl::State
+ */
+ STATE = BACKGROUND + 2,
+
+ /**
+ * @brief The current sub state of the control.
+ * @details Name "subState", type Property::INTEGER or Property::STRING. The enumeration used is dependent on the derived control.
+ *
+ * @see DevelControl::State
+ */
+ SUB_STATE = BACKGROUND + 3
};
} // namespace Property
#define TOKEN_STRING(x) #x
const std::string KEYNAME_ACTORS = "actors";
+const std::string KEYNAME_ENTRY_TRANSITION = "entryTransition";
+const std::string KEYNAME_EXIT_TRANSITION = "exitTransition";
const std::string KEYNAME_INCLUDES = "includes";
+const std::string KEYNAME_INHERIT = "inherit";
const std::string KEYNAME_MAPPINGS = "mappings";
const std::string KEYNAME_NAME = "name";
const std::string KEYNAME_SIGNALS = "signals";
+const std::string KEYNAME_STATES = "states";
const std::string KEYNAME_STYLES = "styles";
const std::string KEYNAME_TEMPLATES = "templates";
+const std::string KEYNAME_TRANSITIONS = "transitions";
const std::string KEYNAME_TYPE = "type";
+const std::string KEYNAME_VISUALS = "visuals";
const std::string PROPERTIES = "properties";
const std::string ANIMATABLE_PROPERTIES = "animatableProperties";
{
styleList.push_back( &(*node) );
- if( OptionalChild subStyle = IsChild( *node, KEYNAME_STYLES ) )
+ OptionalChild subStyle = IsChild( *node, KEYNAME_INHERIT );
+ if( ! subStyle )
+ {
+ subStyle = IsChild( *node, KEYNAME_STYLES );
+ }
+ if( subStyle )
{
CollectAllStyles( stylesCollection, *subStyle, styleList );
}
return ApplyStyle( styleName, handle, replacer );
}
+bool Builder::LookupStyleName( const std::string& styleName )
+{
+ DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+ OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES );
+ OptionalChild style = IsChildIgnoreCase( *styles, styleName );
+
+ if( styles && style )
+ {
+ return true;
+ }
+ return false;
+}
+
+const StylePtr Builder::GetStyle( const std::string& styleName )
+{
+ const StylePtr* style = mStyles.FindCaseInsensitiveC( styleName );
+
+ if( style==NULL )
+ {
+ return StylePtr(NULL);
+ }
+ else
+ {
+ return *style;
+ }
+}
+
void Builder::AddActors( Actor toActor )
{
// 'stage' is the default/by convention section to add from
SetProperties( node, task, constant );
}
-
bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement )
{
DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node,
Dali::Handle& handle, const Replacement& constant )
{
- OptionalChild styles = IsChild(root, KEYNAME_STYLES);
- OptionalChild style = IsChild(node, KEYNAME_STYLES);
+ const char* styleName = node.GetName();
- if( styles && style )
+ StylePtr style = Style::New();
+
+ StylePtr* matchedStyle = NULL;
+ if( styleName )
{
- TreeNodeList additionalStyles;
+ matchedStyle = mStyles.FindCaseInsensitive( styleName );
+ if( ! matchedStyle )
+ {
+ OptionalChild styleNodes = IsChild(root, KEYNAME_STYLES);
+ OptionalChild inheritFromNode = IsChild(node, KEYNAME_INHERIT);
+ if( !inheritFromNode )
+ {
+ inheritFromNode = IsChild( node, KEYNAME_STYLES );
+ }
+
+ if( styleNodes )
+ {
+ if( inheritFromNode )
+ {
+ TreeNodeList additionalStyleNodes;
- CollectAllStyles( *styles, *style, additionalStyles );
+ CollectAllStyles( *styleNodes, *inheritFromNode, additionalStyleNodes );
#if defined(DEBUG_ENABLED)
- for(TreeNode::ConstIterator iter = (*style).CBegin(); iter != (*style).CEnd(); ++iter)
+ for(TreeNode::ConstIterator iter = (*inheritFromNode).CBegin(); iter != (*inheritFromNode).CEnd(); ++iter)
+ {
+ if( OptionalString styleName = IsString( (*iter).second ) )
+ {
+ DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str());
+ }
+ }
+#endif
+
+ // a style may have other styles, which has other styles etc so we apply in reverse by convention.
+ for(TreeNodeList::reverse_iterator iter = additionalStyleNodes.rbegin(); iter != additionalStyleNodes.rend(); ++iter)
+ {
+ RecordStyle( style, *(*iter), handle, constant );
+ ApplySignals( root, *(*iter), handle );
+ ApplyStylesByActor( root, *(*iter), handle, constant );
+ }
+ }
+
+ RecordStyle( style, node, handle, constant );
+ mStyles.Add( styleName, style ); // shallow copy
+ matchedStyle = &style;
+ }
+ }
+ }
+
+ if( matchedStyle )
+ {
+ StylePtr style( *matchedStyle );
+ style->ApplyVisualsAndPropertiesRecursively( handle ); // (recurses through states)
+ }
+ else // If there were no styles, instead set properties
+ {
+ SetProperties( node, handle, constant );
+ }
+ ApplySignals( root, node, handle );
+ ApplyStylesByActor( root, node, handle, constant );
+}
+
+void Builder::RecordStyle( StylePtr style,
+ const TreeNode& node,
+ Dali::Handle& handle,
+ const Replacement& replacements )
+{
+ // With repeated calls, accumulate inherited states, visuals and properties
+ // but override any with same name
+
+ for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
+ {
+ const TreeNode::KeyNodePair& keyValue = *iter;
+ std::string key( keyValue.first );
+ if( key == KEYNAME_STATES )
{
- if( OptionalString styleName = IsString( (*iter).second ) )
+ const TreeNode& states = keyValue.second;
+ if( states.GetType() != TreeNode::OBJECT )
{
- DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str());
+ DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", key.c_str() );
+ continue;
}
- }
-#endif
- // a style may have other styles, which has other styles etc so we apply in reverse by convention.
- for(TreeNodeList::reverse_iterator iter = additionalStyles.rbegin(); iter != additionalStyles.rend(); ++iter)
+ for( TreeNode::ConstIterator iter = states.CBegin(); iter != states.CEnd(); ++iter )
+ {
+ const TreeNode& stateNode = (*iter).second;
+ const char* stateName = stateNode.GetName();
+ if( stateNode.GetType() != TreeNode::OBJECT )
+ {
+ DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", stateName );
+ continue;
+ }
+
+ StylePtr* stylePtr = style->subStates.FindCaseInsensitive( stateName );
+ if( stylePtr )
+ {
+ StylePtr style(*stylePtr);
+ RecordStyle( style, stateNode, handle, replacements );
+ }
+ else
+ {
+ StylePtr subState = Style::New();
+ RecordStyle( subState, stateNode, handle, replacements );
+ style->subStates.Add( stateName, subState );
+ }
+ }
+ }
+ else if( key == KEYNAME_VISUALS )
{
- ApplyProperties( root, *(*iter), handle, constant );
- ApplyStylesByActor( root, *(*iter), handle, constant );
+ for( TreeNode::ConstIterator iter = keyValue.second.CBegin(); iter != keyValue.second.CEnd(); ++iter )
+ {
+ // Each key in this table should be a property name matching a visual.
+ const TreeNode::KeyNodePair& visual = *iter;
+ Dali::Property::Value property(Property::MAP);
+ if( DeterminePropertyFromNode( visual.second, Property::MAP, property, replacements ) )
+ {
+ Property::Map* mapPtr = style->visuals.FindCaseInsensitive( visual.first );
+ if( mapPtr )
+ {
+ // Override existing visuals
+ mapPtr->Clear();
+ mapPtr->Merge(*property.GetMap());
+ }
+ else
+ {
+ style->visuals.Add(visual.first, *property.GetMap());
+ }
+ }
+ }
+ }
+ else if( key == KEYNAME_ENTRY_TRANSITION )
+ {
+ Dali::Property::Value property(Property::MAP);
+ if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) )
+ {
+ style->entryTransition = Toolkit::TransitionData::New( *property.GetMap() );
+ }
+ }
+ else if( key == KEYNAME_EXIT_TRANSITION )
+ {
+ Dali::Property::Value property(Property::MAP);
+ if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) )
+ {
+ style->exitTransition = Toolkit::TransitionData::New( *property.GetMap() );
+ }
+ }
+ else if( key == KEYNAME_TRANSITIONS )
+ {
+ //@todo add new transitions to style.transitions
+ // override existing transitions. A transition matches on target & property name
+ const TreeNode& node = keyValue.second;
+ if( node.GetType() == TreeNode::ARRAY )
+ {
+ Dali::Property::Value property(Property::ARRAY);
+ if( DeterminePropertyFromNode( node, Property::ARRAY, property, replacements ) )
+ {
+ style->transitions = *property.GetArray();
+ }
+ }
+ else if( node.GetType() == TreeNode::OBJECT )
+ {
+ Dali::Property::Value property(Property::MAP);
+ if( DeterminePropertyFromNode( node, Property::MAP, property, replacements ) )
+ {
+ Property::Array propertyArray;
+ propertyArray.Add( property );
+ style->transitions = propertyArray;
+ }
+ }
+ else
+ {
+ DALI_LOG_WARNING( "RecordState() Node \"%s\" is not a JSON array or object\n", key.c_str() );
+ }
+ }
+ else if( key == KEYNAME_TYPE ||
+ key == KEYNAME_ACTORS ||
+ key == KEYNAME_SIGNALS ||
+ key == KEYNAME_STYLES ||
+ key == KEYNAME_MAPPINGS ||
+ key == KEYNAME_INHERIT )
+ {
+ continue;
+ }
+ else // It's a property
+ {
+ Property::Index index;
+ Property::Value value;
+ if( MapToTargetProperty( handle, key, keyValue.second, replacements, index, value ) )
+ {
+ Property::Value* existingValuePtr = style->properties.Find( index );
+ if( existingValuePtr != NULL )
+ {
+ *existingValuePtr = value; // Overwrite existing property.
+ }
+ else
+ {
+ style->properties.Add( index, value );
+ }
+ }
}
}
-
- // applying given node last
- ApplyProperties( root, node, handle, constant );
- ApplyStylesByActor( root, node, handle, constant );
}
// Set properties from node on handle.
void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node,
Dali::Handle& handle, const Replacement& constant )
{
- if( Actor actor = Actor::DownCast(handle) )
- {
- SetProperties( node, actor, constant );
+ SetProperties( node, handle, constant );
+ ApplySignals( root, node, handle );
+}
- if( actor )
- {
- // add signals
- SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
- SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
- }
- }
- else
+void Builder::ApplySignals(const TreeNode& root, const TreeNode& node, Dali::Handle& handle )
+{
+ Actor actor = Actor::DownCast(handle);
+ if( actor )
{
- SetProperties( node, handle, constant );
+ // add signals
+ SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
+ SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
}
}
+
// Appling by style helper
// use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node
void Builder::ApplyStylesByActor( const TreeNode& root, const TreeNode& node,
if( !foundActor )
{
- // debug log cannot find searched for actor
-#if defined(DEBUG_ENABLED)
DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first);
-#endif
}
else
{
-#if defined(DEBUG_ENABLED)
DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first);
-#endif
ApplyProperties( root, (*iter).second, foundActor, constant );
}
}
std::string key( keyChild.first );
// ignore special fields;
- if( key == KEYNAME_TYPE || key == KEYNAME_ACTORS || key == KEYNAME_SIGNALS || key == KEYNAME_STYLES || key == KEYNAME_MAPPINGS )
+ if( key == KEYNAME_TYPE ||
+ key == KEYNAME_ACTORS ||
+ key == KEYNAME_SIGNALS ||
+ key == KEYNAME_STYLES ||
+ key == KEYNAME_MAPPINGS ||
+ key == KEYNAME_INHERIT ||
+ key == KEYNAME_STATES ||
+ key == KEYNAME_VISUALS ||
+ key == KEYNAME_ENTRY_TRANSITION ||
+ key == KEYNAME_EXIT_TRANSITION ||
+ key == KEYNAME_TRANSITIONS )
{
continue;
}
- Handle propertyObject( handle );
-
- Dali::Property::Index index = propertyObject.GetPropertyIndex( key );
+ Property::Index index;
+ Property::Value value;
- if( Property::INVALID_INDEX != index )
+ bool mapped = MapToTargetProperty( handle, key, keyChild.second, constant, index, value );
+ if( mapped )
{
- Property::Type type = propertyObject.GetPropertyType(index);
- Property::Value value;
- bool mapped = false;
+ DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() );
- // if node.value is a mapping, get the property value from the "mappings" table
- if( keyChild.second.GetType() == TreeNode::STRING )
- {
- std::string mappingKey;
- if( GetMappingKey(keyChild.second.GetString(), mappingKey) )
- {
- OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS );
- mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value );
- }
- }
- if( ! mapped )
- {
- mapped = DeterminePropertyFromNode( keyChild.second, type, value, constant );
- if( ! mapped )
- {
- // Just determine the property from the node and if it's valid, let the property object handle it
- DeterminePropertyFromNode( keyChild.second, value, constant );
- mapped = ( value.GetType() != Property::NONE );
- }
- }
- if( mapped )
- {
- DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() );
-
- propertyObject.SetProperty( index, value );
- }
- }
- else
- {
- DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str());
+ handle.SetProperty( index, value );
}
// Add custom properties
}
}
+bool Builder::MapToTargetProperty(
+ Handle& propertyObject,
+ const std::string& key,
+ const TreeNode& node,
+ const Replacement& constant,
+ Property::Index& index,
+ Property::Value& value )
+{
+ bool mapped = false;
+
+ index = propertyObject.GetPropertyIndex( key );
+ if( Property::INVALID_INDEX != index )
+ {
+ Property::Type type = propertyObject.GetPropertyType(index);
+
+ // if node.value is a mapping, get the property value from the "mappings" table
+ if( node.GetType() == TreeNode::STRING )
+ {
+ std::string mappingKey;
+ if( GetMappingKey( node.GetString(), mappingKey) )
+ {
+ OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS );
+ mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value );
+ }
+ }
+ if( ! mapped )
+ {
+ mapped = DeterminePropertyFromNode( node, type, value, constant );
+ if( ! mapped )
+ {
+ // Just determine the property from the node and if it's valid, let the property object handle it
+ DeterminePropertyFromNode( node, value, constant );
+ mapped = ( value.GetType() != Property::NONE );
+ }
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str());
+ }
+ return mapped;
+}
+
bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value )
{
KeyStack keyStack;
{
const TreeNode::KeyNodePair& keyChild = *iter;
std::string key( keyChild.first );
-
Property::Value value;
DeterminePropertyFromNode( keyChild.second, value, constant );
}
}
+
} // namespace Internal
} // namespace Toolkit
#include <dali/public-api/object/base-object.h>
#include <dali/public-api/object/property-map.h>
#include <dali/public-api/render-tasks/render-task.h>
-#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/builder/json-parser.h>
#include <dali-toolkit/devel-api/builder/builder.h>
#include <dali-toolkit/internal/builder/builder-declarations.h>
+#include <dali-toolkit/internal/builder/style.h>
// Warning messages usually displayed
#define DALI_SCRIPT_WARNING(format, args...) \
bool ApplyStyle( const std::string& styleName, Handle& handle );
/**
+ * Lookup the stylename in builder. If it's found in the parse tree,
+ * then return true.
+ * @param[in] styleName The style name to search for
+ * @return true if the stylename exists
+ */
+ bool LookupStyleName( const std::string& styleName );
+
+ /**
+ * Lookup the stylename in the recorded Styles - if it exists,
+ * performs a shallow copy to the passed in style and returns true.
+ * Otherwise it returns false.
+
+ * @param[in] styleName The stylename to search for
+ * @return A const pointer to the style object
+ */
+ const StylePtr GetStyle( const std::string& styleName );
+
+ /**
* @copydoc Toolkit::Builder::AddActors
*/
void AddActors( Actor toActor );
*/
void EmitQuitSignal();
+
protected:
virtual ~Builder();
Dali::Handle& handle,
const Replacement& constant );
+ void RecordStyles( const char* styleName,
+ const TreeNode& node,
+ Dali::Handle& handle,
+ const Replacement& replacements );
+
+ void RecordStyle( StylePtr style,
+ const TreeNode& node,
+ Dali::Handle& handle,
+ const Replacement& replacements );
+
void ApplyProperties( const TreeNode& root,
const TreeNode& node,
Dali::Handle& handle,
const Replacement& constant );
+ void ApplySignals( const TreeNode& root,
+ const TreeNode& node,
+ Dali::Handle& handle );
+
void ApplyStylesByActor( const TreeNode& root,
const TreeNode& node,
Dali::Handle& handle,
Handle& handle,
const Replacement& constant );
+ bool MapToTargetProperty( Handle& propertyObject,
+ const std::string& key,
+ const TreeNode& node,
+ const Replacement& constant,
+ Property::Index& index,
+ Property::Value& value );
+
/**
* Find the key in the mapping table, if it's present, then generate
* a property value for it (of the given type if available),
SlotDelegate<Builder> mSlotDelegate;
Property::Map mReplacementMap;
MappingsLut mCompleteMappings;
+ Dictionary<StylePtr> mStyles; // State based styles
Toolkit::Builder::BuilderSignalType mQuitSignal;
};
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H
+
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <algorithm>
+
+namespace Dali
+{
+extern bool CaseInsensitiveStringCompare( const std::string& a, const std::string& b );
+
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * The Dictionary template class enables a means of storing key-value
+ * pairs where the keys are strings and the value can be a complex
+ * type.
+ *
+ * It enables lookup of keys via case-insensitive match.
+ */
+template<typename EntryType>
+class Dictionary
+{
+private:
+ /**
+ * Element is a key-value pair
+ */
+ struct Element
+ {
+ std::string key;
+ EntryType entry;
+ Element( const std::string&name, EntryType entry )
+ : key( name ),
+ entry( entry )
+ {
+ }
+ };
+ typedef std::vector<Element> Elements;
+ Elements container;
+
+public:
+ /**
+ * Only allow const iteration over the dictionary
+ */
+ typedef typename Elements::const_iterator iterator;
+
+
+ /**
+ * Constructor
+ */
+ Dictionary<EntryType>()
+ {
+ }
+
+ /**
+ * Add a key value pair to the dictionary.
+ * If the entry does not already exist, add it to the dictionary
+ * using a shallow copy
+ */
+ bool Add( const std::string& name, const EntryType& entry )
+ {
+ for( typename Elements::iterator iter = container.begin(); iter != container.end(); ++iter )
+ {
+ if( iter->key == name )
+ {
+ return false;
+ }
+ }
+ container.push_back( Element(name, entry) );
+ return true;
+ }
+
+ /**
+ * Add a key-value pair to the dictionary
+ * If the entry does not already exist, add it to the dictionary
+ * (shallow copy)
+ */
+ bool Add( const char* name, const EntryType& entry )
+ {
+ bool result=false;
+ if( name != NULL )
+ {
+ std::string theName(name);
+ result=Add(theName, entry);
+ }
+ return result;
+ }
+
+ /**
+ * Find the element in the dictionary pointed at by key, and
+ * return a pointer to it, or NULL.
+ */
+ EntryType* Find( const std::string& key ) const
+ {
+ EntryType* result=NULL;
+
+ if( ! key.empty() )
+ {
+ for( typename Elements::iterator iter = container.begin(); iter != container.end(); ++iter )
+ {
+ if( iter->key == key )
+ {
+ result = &(iter->entry);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Find the element in the dictionary pointed at by key, and
+ * return a pointer to it, or NULL
+ */
+ EntryType* Find( const char* key ) const
+ {
+ if( key != NULL )
+ {
+ std::string theKey(key);
+ return Find(theKey);
+ }
+ return NULL;
+ }
+
+ /**
+ * Find the element in the dictionary pointed at by key using a case
+ * insensitive search, and return a const pointer to it, or NULL
+ */
+ const EntryType* FindCaseInsensitiveC( const std::string& key ) const
+ {
+ if( ! key.empty() )
+ {
+ for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter )
+ {
+ if( Dali::CaseInsensitiveStringCompare(iter->key, key ))
+ {
+ const EntryType* result = &(iter->entry);
+ return result;
+ }
+ }
+ }
+ return NULL;
+ }
+
+ /**
+ * Find the element in the dictionary pointed at by key using a case
+ * insensitive search, and return a non-const pointer to it, or NULL
+ */
+ EntryType* FindCaseInsensitive( const std::string& key ) const
+ {
+ EntryType* result = NULL;
+ if( ! key.empty() )
+ {
+ for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter )
+ {
+ if( Dali::CaseInsensitiveStringCompare(iter->key, key ))
+ {
+ // Const cast because of const_iterator. const_iterator because, STL.
+ result = const_cast<EntryType*>(&(iter->entry));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Find the element in the dictionary pointed at by key using a case
+ * insensitive search, and return a const pointer to it, or NULL
+ */
+ const EntryType* FindCaseInsensitiveC( const char* key ) const
+ {
+ if( key != NULL )
+ {
+ std::string theKey(key);
+ return FindCaseInsensitiveC( theKey );
+ }
+ return NULL;
+ }
+
+ /**
+ * Find the element in the dictionary pointed at by key using a case
+ * insensitive search, and return a non-const pointer to it, or NULL
+ */
+ EntryType* FindCaseInsensitive( const char* key ) const
+ {
+ if( key != NULL )
+ {
+ std::string theKey(key);
+ return FindCaseInsensitive( theKey );
+ }
+ return NULL;
+ }
+
+ /**
+ * Return an iterator pointing at the first entry in the dictionary
+ */
+ typename Elements::const_iterator Begin() const
+ {
+ return container.begin();
+ }
+
+ /**
+ * Return an iterator pointing past the last entry in the dictionary
+ */
+ typename Elements::const_iterator End() const
+ {
+ return container.end();
+ }
+};
+
+
+
+}//Internal
+}//Toolkit
+}//Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/object/handle.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/builder/style.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+StylePtr Style::New()
+{
+ StylePtr stylePtr( new Style() );
+ return stylePtr;
+}
+
+void Style::ApplyVisualsAndPropertiesRecursively( Handle handle ) const
+{
+ ApplyVisuals( handle );
+ ApplyProperties( handle );
+
+ Toolkit::Control control = Toolkit::Control::DownCast(handle);
+ if( control )
+ {
+ Property::Value value = control.GetProperty(DevelControl::Property::STATE);
+ std::string stateName;
+ if( value.Get( stateName ) )
+ {
+ // Look up state in states table:
+ const StylePtr* stylePtr = subStates.FindCaseInsensitiveC( stateName );
+ if( stylePtr )
+ {
+ const StylePtr statePtr(*stylePtr);
+
+ // We have a state match.
+ statePtr->ApplyVisuals( handle );
+ statePtr->ApplyProperties( handle );
+
+ // Apply substate visuals
+ Property::Value value = control.GetProperty(DevelControl::Property::SUB_STATE);
+ std::string subStateName;
+ if( value.Get( subStateName ) && ! subStateName.empty() )
+ {
+ const StylePtr* stylePtr = statePtr->subStates.FindCaseInsensitiveC( subStateName );
+ if( stylePtr )
+ {
+ const StylePtr subStatePtr(*stylePtr);
+ // We have a sub-state match.
+ subStatePtr->ApplyVisuals( handle );
+ subStatePtr->ApplyProperties( handle );
+ }
+ }
+ }
+ }
+ }
+}
+
+void Style::ApplyVisuals( Handle handle ) const
+{
+ for( Dictionary<Property::Map>::iterator iter = visuals.Begin(); iter != visuals.End() ; ++iter )
+ {
+ const std::string& visualName = (*iter).key;
+ const Property::Map& map = (*iter).entry;
+ Dali::Property::Index index = handle.GetPropertyIndex( visualName );
+ if( index != Property::INVALID_INDEX )
+ {
+ const Property::Value value(const_cast<Property::Map&>(map));
+ handle.SetProperty( index, value );
+ }
+ }
+}
+
+void Style::ApplyProperties( Handle handle ) const
+{
+ for( Property::Map::SizeType i=0; i<properties.Count(); ++i )
+ {
+ KeyValuePair keyValue = properties.GetKeyValue( i );
+ if( keyValue.first.type == Property::Key::INDEX )
+ {
+ handle.SetProperty( keyValue.first.indexKey, keyValue.second );
+ }
+ }
+}
+
+Style::Style()
+{
+}
+
+Style::~Style()
+{
+}
+
+
+} // Internal
+} // Toolkit
+} // Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_STYLE_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_STYLE_H
+
+/*
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/object/ref-object.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/internal/builder/dictionary.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class Style;
+typedef IntrusivePtr<Style> StylePtr;
+
+/**
+ * This class encapsulates the style information for a given styled
+ * control. It is generated only when a control instance looks up
+ * it's style information for the first time, and then stored by
+ * Builder.
+ *
+ * It contains the visual, property and transition definitions for the
+ * main control and for each state and sub-state within the control.
+ *
+ * It has methods to enable the base control to apply visuals and
+ * properties per state.
+ */
+class Style : public RefObject
+{
+public:
+ static StylePtr New();
+
+public:
+ /**
+ * Apply the visuals and properties for the current state/substate
+ * of the handle to the control pointed at by handle. Recurses
+ * through sub-states.
+ *
+ * @param[in] handle The handle to apply the visuals to
+ */
+ void ApplyVisualsAndPropertiesRecursively( Handle handle ) const;
+
+
+private:
+ /**
+ * Apply the visuals of the style to the control pointed at by
+ * handle.
+ *
+ * @param[in] handle The handle to apply the visuals to
+ */
+ void ApplyVisuals( Handle handle ) const;
+
+ /**
+ * Apply the properties of the style to the control pointed at by
+ * handle.
+ *
+ * @param[in] handle The handle to apply the properties to
+ */
+ void ApplyProperties( Handle handle ) const;
+
+protected:
+ /**
+ * @brief Default constructor.
+ */
+ Style();
+
+ /**
+ * @brief virtual destructor.
+ */
+ virtual ~Style();
+
+private:
+ // Not implemented
+ DALI_INTERNAL Style( const Style& rhs );
+
+ // Not implemented
+ DALI_INTERNAL Style& operator=(const Style& rhs);
+
+public:
+ // Everything must be shallow-copiable.
+ Dictionary<StylePtr> subStates; // Each named style maps to a state.
+ Dictionary<Property::Map> visuals;
+ Property::Map properties;
+ Property::Array transitions;
+ Toolkit::TransitionData entryTransition;
+ Toolkit::TransitionData exitTransition;
+};
+
+} // Internal
+} // Toolkit
+} // Dali
+
+
+#endif //DALI_TOOLKIT_INTERNAL_BUILDER_STYLE_H
$(toolkit_src_dir)/builder/builder-signals.cpp \
$(toolkit_src_dir)/builder/json-parser-state.cpp \
$(toolkit_src_dir)/builder/json-parser-impl.cpp \
+ $(toolkit_src_dir)/builder/style.cpp \
$(toolkit_src_dir)/builder/tree-node-manipulator.cpp \
$(toolkit_src_dir)/builder/replacement.cpp \
$(toolkit_src_dir)/visuals/visual-base-impl.cpp \
#include <dali/public-api/adaptor-framework/application.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/builder-impl.h>
#include <dali-toolkit/public-api/controls/control.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/public-api/styling/style-manager.h>
}
}
-void StyleManager::CollectQualifiers( StringList& qualifiersOut )
+static void CollectQualifiers( std::vector<std::string>& qualifiersOut )
{
// Append the relevant qualifier for orientation
int orientation = 0; // Get the orientation from the system
}
}
-void StyleManager::BuildQualifiedStyleName( const std::string& styleName, const StringList& qualifiers, std::string& qualifiedStyleOut )
+/**
+ * @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<std::string>& qualifiers,
+ std::string& qualifiedStyleOut )
{
qualifiedStyleOut.append( styleName );
- for( StringList::const_iterator it = qualifiers.begin(), itEnd = qualifiers.end(); it != itEnd; ++it )
+ for( std::vector<std::string>::const_iterator it = qualifiers.begin(),
+ itEnd = qualifiers.end(); it != itEnd; ++it )
{
const std::string& str = *it;
}
}
-void StyleManager::ApplyStyle( Toolkit::Builder builder, Toolkit::Control control )
+static bool GetStyleNameForControl( Toolkit::Builder builder, Toolkit::Control control, std::string& styleName)
{
- std::string styleName = control.GetStyleName();
+ styleName = control.GetStyleName();
if( styleName.empty() )
{
}
// Apply the style after choosing the correct actual style (e.g. landscape or portrait)
- StringList qualifiers;
+ std::vector<std::string> qualifiers;
CollectQualifiers( qualifiers );
- while( true )
+ bool found = 0;
+ std::string qualifiedStyleName;
+ do
{
- std::string qualifiedStyleName;
+ qualifiedStyleName.clear();
BuildQualifiedStyleName( styleName, qualifiers, qualifiedStyleName );
// Break if style found or we have tried the root style name (qualifiers is empty)
- if( builder.ApplyStyle( qualifiedStyleName, control ) || qualifiers.size() == 0 )
+ if( GetImpl(builder).LookupStyleName( qualifiedStyleName ) )
+ {
+ 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);
+
+ if(found)
+ {
+ styleName = qualifiedStyleName;
+ }
+ return found;
+}
+
+void StyleManager::ApplyStyle( Toolkit::Builder builder, Toolkit::Control control )
+{
+ std::string styleName = control.GetStyleName();
+ if( GetStyleNameForControl( builder, control, styleName ) )
+ {
+ builder.ApplyStyle( styleName, control );
}
if( mDefaultFontSize >= 0 )
}
}
+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 )
{
BuilderMap::iterator builderIt = mBuilderCache.find( key );
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/styling/style-manager.h>
#include <dali-toolkit/devel-api/builder/builder.h>
+#include <dali-toolkit/internal/builder/style.h>
namespace Dali
{
public: // Public API
-/**
+ /**
* @copydoc Toolkit::StyleManager::ApplyTheme
*/
void ApplyTheme( const std::string& themeFile );
*/
void ApplyStyle( Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName );
+ /**
+ * Get the state/style information for the given control
+ * @param[in] control The control to get state information for
+ * @return The style information (or empty ptr if not found)
+ */
+ const StylePtr GetRecordedStyle( Toolkit::Control control );
+
public:
// SIGNALS
bool LoadJSON( Toolkit::Builder builder, const std::string& jsonFileName );
/**
- * @brief Collect qualifiers (e.g. Landscape, portrait etc) for a given style
- *
- * @param[in,out] qualifiersOut The list to populate with qualifiers
- */
- void CollectQualifiers( StringList& qualifiersOut );
-
- /**
- * @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
- */
- void BuildQualifiedStyleName( const std::string& styleName, const StringList& qualifiers, std::string& qualifiedStyleOut );
-
- /**
* @brief Apply a style to the control using the given builder
*
* @param[in] builder The builder to apply the style from
return connected;
}
+const Scripting::StringEnum ControlStateTable[] = {
+ { "NORMAL", Toolkit::DevelControl::NORMAL },
+ { "FOCUSED", Toolkit::DevelControl::FOCUSED },
+ { "DISABLED", Toolkit::DevelControl::DISABLED },
+}; const unsigned int ControlStateTableCount = sizeof( ControlStateTable ) / sizeof( ControlStateTable[0] );
+
// Setup signals and actions using the type-registry.
DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create );
// Construction & Destruction
Impl(Control& controlImpl)
: mControlImpl( controlImpl ),
+ mState( Toolkit::DevelControl::NORMAL ),
+ mSubState(""),
mStyleName(""),
mBackgroundColor(Color::TRANSPARENT),
mStartingPinchScale( NULL ),
break;
}
+ case Toolkit::DevelControl::Property::STATE:
+ {
+ Toolkit::DevelControl::State state( DevelControl::NORMAL );
+
+ if( Scripting::GetEnumerationProperty< Toolkit::DevelControl::State >( value, ControlStateTable, ControlStateTableCount, state ) )
+ {
+ controlImpl.mImpl->SetState( state );
+ }
+ }
+ break;
+
+ case Toolkit::DevelControl::Property::SUB_STATE:
+ {
+ std::string subState;
+ if( value.Get( subState ) )
+ {
+ controlImpl.mImpl->SetSubState( subState );
+ }
+ }
+ break;
+
case Toolkit::Control::Property::BACKGROUND_COLOR:
{
DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
break;
}
+ case Toolkit::DevelControl::Property::STATE:
+ {
+ value = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( controlImpl.mImpl->mState, ControlStateTable, ControlStateTableCount );
+ break;
+ }
+
case Toolkit::Control::Property::BACKGROUND_COLOR:
{
DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
return value;
}
+ void SetState( DevelControl::State state )
+ {
+ if( mState != state )
+ {
+ mState = state;
+
+ // Trigger state change and transitions
+ // Apply new style, if stylemanager is available
+ Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+ if( styleManager )
+ {
+ const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
+ if( stylePtr )
+ {
+ for( int i=mVisuals.Count()-1; i >= 0; i-- )
+ {
+ mControlImpl.UnregisterVisual( mVisuals[i]->index );
+ }
+
+ Dali::CustomActor handle( mControlImpl.GetOwner() );
+ stylePtr->ApplyVisualsAndPropertiesRecursively( handle );
+ }
+ }
+ }
+ }
+
+ void SetSubState( const std::string& state )
+ {
+ if( mSubState != state )
+ {
+ mSubState = state;
+ // Trigger transitions
+
+ }
+ }
+
// Data
Control& mControlImpl;
+ DevelControl::State mState;
+ std::string mSubState;
+
RegisteredVisualContainer mVisuals; // Stores visuals needed by the control, non trivial type so std::vector used.
std::string mStyleName;
Vector4 mBackgroundColor; ///< The color of the background visual
static const PropertyRegistration PROPERTY_4;
static const PropertyRegistration PROPERTY_5;
static const PropertyRegistration PROPERTY_6;
+ static const PropertyRegistration PROPERTY_7;
+ static const PropertyRegistration PROPERTY_8;
};
// Properties registered without macro to use specific member variables.
const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus", Toolkit::Control::Property::KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background", Toolkit::Control::Property::BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "tooltip", Toolkit::DevelControl::Property::TOOLTIP, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_7( typeRegistration, "state", Toolkit::DevelControl::Property::STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_8( typeRegistration, "subState", Toolkit::DevelControl::Property::SUB_STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
Toolkit::Control Control::New()
{