From bf2e33bdeb3e28c8d207a9b193d48443d73559b8 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Mon, 9 Mar 2015 16:22:51 +0000 Subject: [PATCH] Updated programming guide for Properties Change-Id: Ie96b72c4f4f2f22edaca653fe435de1dd937dcbb --- build/tizen/docs/dali.doxy.in | 8 +- docs/content/example-code/property-example.cpp | 144 ++++++++++++++ docs/content/programming-guide/properties.h | 252 ++++++++++++++++++++++++- 3 files changed, 394 insertions(+), 10 deletions(-) create mode 100644 docs/content/example-code/property-example.cpp diff --git a/build/tizen/docs/dali.doxy.in b/build/tizen/docs/dali.doxy.in index 92ff833..e072023 100644 --- a/build/tizen/docs/dali.doxy.in +++ b/build/tizen/docs/dali.doxy.in @@ -231,6 +231,10 @@ TAB_SIZE = 2 # newlines. ALIASES = +# Clip alias inserts the specified file between two text markers. +# EG: @clip{"button.h",public,private} +# Shows all lines between public and private *inclusive*. +ALIASES += clip{3}="\dontinclude \1 \n \skip \2 \n \until \3" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" @@ -859,7 +863,7 @@ EXCLUDE_SYMBOLS = DaliInternal \ # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = @DOXYGEN_DOCS_DIR@/../ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -953,7 +957,7 @@ INLINE_SOURCES = NO # Fortran comments will always remain visible. # The default value is: YES. -STRIP_CODE_COMMENTS = YES +STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. diff --git a/docs/content/example-code/property-example.cpp b/docs/content/example-code/property-example.cpp new file mode 100644 index 0000000..35e7869 --- /dev/null +++ b/docs/content/example-code/property-example.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2014 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 +#include +#include + +using namespace Dali; + +namespace +{ + +// The name we will use to register our custom property by. +const char* const TAG_PROPERTY_NAME = "tag-identifier"; + +const char* const PUSHBUTTON_PRESS_IMAGE = DALI_IMAGE_DIR "button-down.9.png"; +const char* const PUSHBUTTON_BUTTON_IMAGE = DALI_IMAGE_DIR "button-up.9.png"; + +// Define the grid geometry. +#define BUTTON_ROWS 9.0f +#define BUTTON_COLUMNS 7.0f +#define BUTTON_GAP 10.0f + +} // namespace + +/** + * This example shows how to register and look-up custom properties. + * A button grid is created, each with a new "tag" property which is set to a unique value. + * When pressed, the "tag" property is looked up to retrieve the unique value and display it. + */ +class PropertyButtonsController: public ConnectionTracker +{ + public: + + PropertyButtonsController( Application& application ) + { + // Connect to the Application's Init signal + application.InitSignal().Connect( this, &PropertyButtonsController::Create ); + } + + ~PropertyButtonsController() + { + } + + void Create( Application& application ) + { + // Setup precalculations for button size and start positions. + Toolkit::PushButton button; + int index = 0; + Vector2 stageSize = Stage::GetCurrent().GetSize(); + float buttonSize = ( stageSize.x - ( BUTTON_GAP * ( BUTTON_COLUMNS + 1 ) ) ) / BUTTON_COLUMNS; + float yStart = ( stageSize.y - ( ( buttonSize * BUTTON_ROWS ) + ( BUTTON_GAP * ( BUTTON_ROWS - 1 ) ) ) ) / 2.0f; + + // Create a grid of buttons. + for( int y = 0; y < BUTTON_ROWS; ++y ) + { + for( int x = 0; x < BUTTON_COLUMNS; ++x ) + { + // Create a button and position it. + button = Toolkit::PushButton::New(); + button.SetParentOrigin( ParentOrigin::TOP_LEFT ); + button.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + button.SetPosition( Vector3( BUTTON_GAP + ( x * ( buttonSize + BUTTON_GAP ) ), yStart + ( y * ( buttonSize + BUTTON_GAP ) ), 0.0f ) ); + button.SetSize( Vector3( buttonSize, buttonSize, 0) ); + button.SetSelectedImage( Dali::ResourceImage::New( PUSHBUTTON_PRESS_IMAGE ) ); + button.SetButtonImage( Dali::ResourceImage::New( PUSHBUTTON_BUTTON_IMAGE ) ); + + // Label the button with a unique value. + std::stringstream label; + label << index; + button.SetLabel( label.str() ); + + // Register our custom property, and use it to store a unique number. + // Store the index to the property so we can look it up later. + // Note: This is much faster than looking the property up by name and should always be used if possible. + // As all our control types are the same (PushButtons) the indecies to our unique property is the same for each one. + Property::Value tag = ( float )index; + mTagPropertyIndex = button.RegisterProperty( TAG_PROPERTY_NAME, tag ); + + // Hook a callback when the button is clicked. + button.ClickedSignal().Connect( this, &PropertyButtonsController::OnButtonClicked ); + + // Add the button to the stage. + Stage::GetCurrent().Add( button ); + index++; + } + } + + // Create the last selected button text view. + mTagText = Toolkit::TextView::New( "None selected" ); + mTagText.SetParentOrigin( ParentOrigin::BOTTOM_CENTER ); + mTagText.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER ); + mTagText.SetPosition( Vector3( 0.0f, -30.0f, 0.0f ) ); + Stage::GetCurrent().Add( mTagText ); + } + + /** + * Called when any button within the grid is clicked. + * param[in] The clicked button control + * return Set to true if the signal was consumed correctly + */ + bool OnButtonClicked( Toolkit::Button button ) + { + std::stringstream valueText; + // Look up the tag property by the cached property index. + // Note: If the property belongs to a control in another library, or we do not know the index, we can look the index up first with: + // Property::Index index = button.GetPropertyIndex( TAG_PROPERTY_NAME ); + valueText << "Selected: " << button.GetProperty< float >( mTagPropertyIndex ); + + mTagText.SetText( valueText.str() ); + + return true; + } + + private: + + Toolkit::TextView mTagText; ///< A text label used to show the last button pressed. + Property::Index mTagPropertyIndex; ///< A cached property index of our custom tag property. +}; + +// Entry point for applications. +int main( int argc, char **argv ) +{ + Application application = Application::New( &argc, &argv ); + + PropertyButtonsController test( application ); + application.MainLoop(); + + return 0; +} diff --git a/docs/content/programming-guide/properties.h b/docs/content/programming-guide/properties.h index 4c124cb..8838e78 100644 --- a/docs/content/programming-guide/properties.h +++ b/docs/content/programming-guide/properties.h @@ -1,20 +1,256 @@ /*! \page properties Properties * +@section what-is-a-property What is a property? + +A property is a value used by an object that can be modified or read externally to that object. +This could be from within Dali or externally by an application. + +

What is a property used for?

+ +Properties can be set externally by an application, allowing that application to change the configuration or behaviour of an actor. +This could include the physical geometry of the actor, or how it is drawn or moves. + +Properties can also be read. This feature can be used in conjunction with constraints to allow changes to a property within one actor to cause changes to the property of another actor. For example, an actor following the movement of another separate actor (that it is not a child of). + +Properties can be used to expose any useful information or behaviour of an actor. +Other actor variables that are used to implement this bevahiour, or do not make useful sense from an application developers point of view should not be exposed. + +

How to implement a property within Dali-core:

+ +There are two stages: + +- Define the properties as an enum in the public-api header file. +- Define the property details using the pre-defined macros to build up a table of property information. + +There are some pre-defined macros designed to help with and standardise the definition of the propery details table per class. + +These macros generate an array of property details which allow efficient lookup of flags like "animatable" or "constraint input". + +Example: ImageActor + +Within the public-api header file; image-actor.h: + +@code +/** + * @brief An enumeration of properties belonging to the ImageActor class. + * Properties additional to RenderableActor. + */ +struct Property +{ + enum + { + PIXEL_AREA = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX, ///< name "pixel-area", type Rect + STYLE, ///< name "style", type std::string + BORDER, ///< name "border", type Vector4 + IMAGE, ///< name "image", type Map {"filename":"", "load-policy":...} + }; +}; +@endcode +From @ref Dali::ImageActor::Property + +Notes: + +- The properties are enumerated within a named struct to give them a namespace. +- The properties are then refered to as <OBJECT>::%Property::<PROPERTY_NAME>. + +Within the internal implementation; image-actor-impl.cpp: + +@code +namespace // Unnamed namespace +{ + +// Properties + +// Name Type writable animatable constraint-input enum for index-checking +DALI_PROPERTY_TABLE_BEGIN +DALI_PROPERTY( "pixel-area", RECTANGLE, true, false, true, Dali::ImageActor::Property::PIXEL_AREA ) +DALI_PROPERTY( "style", STRING, true, false, true, Dali::ImageActor::Property::STYLE ) +DALI_PROPERTY( "border", VECTOR4, true, false, true, Dali::ImageActor::Property::BORDER ) +DALI_PROPERTY( "image", MAP, true, false, false, Dali::ImageActor::Property::IMAGE ) +DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX ) +@endcode + +Notes: + +- The table lays within an unnamed namespace. +- The table should be in the same order as the enum. +- The table should be the only place where the text names of the properties are defined. +- The information in the table should be used within the classes IsDefaultPropertyWritable / Animatable / ConstraintInput methods for quick lookup. +- The last entry in the table is optionally used in debug builds for index checking. +- The parameter to DALI_PROPERTY_TABLE_END should match the start index of the property enumeration. + +
+

How to implement a property within Dali-toolkit:

+ +Note that toolkit properties have extra limitations in that they cannot be animated or used as a constraint input. For this reason there is no requirement for a table of property details. +Macros are still used to define properties, but for the following reasons: + +To standardise the way properties are defined. +To handle type-registering for properties, signals and actions in one place. +To facilitate the posibility of running the code with the type-registry disabled. + +There are two stages: + +- Define the properties as an enum in the public-api header file, along with a definition of the property ranges. +- Define the property details using the pre-defined macros to perform the type-registering of the properties. This is done for signals and actions also. + +Example: Button + +Source file: button.h: +Note that the “PropertyRange” contents “PROPERTY_START_INDEX” is also used by the macro for order checking. + +@code + /** + * @brief The start and end property ranges for this control. + */ + enum PropertyRange + { + PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000 ///< Reserve property indices + }; + + /** + * @brief An enumeration of properties belonging to the Button class. + */ + struct Property + { + enum + { + DISABLED = PROPERTY_START_INDEX, ///< name "disabled", @see SetDisabled(), type bool + AUTO_REPEATING, ///< name "auto-repeating", @see SetAutoRepeating(), type bool + INITIAL_AUTO_REPEATING_DELAY, ///< name "initial-auto-repeating-delay", @see SetInitialAutoRepeatingDelay(), type float + NEXT_AUTO_REPEATING_DELAY, ///< name "next-auto-repeating-delay", @see SetNextAutoRepeatingDelay(), type float + TOGGLABLE, ///< name "togglable", @see SetTogglableButton(), type bool + SELECTED, ///< name "selected", @see SetSelected(), type bool + NORMAL_STATE_ACTOR, ///< name "normal-state-actor", @see SetButtonImage(), type Map + SELECTED_STATE_ACTOR, ///< name "selected-state-actor", @see SetSelectedImage(), type Map + DISABLED_STATE_ACTOR, ///< name "disabled-state-actor", @see SetDisabledImage(), type Map + LABEL_ACTOR, ///< name "label-actor", @see SetLabel(), type Map + }; + }; +@endcode + +Source file: button-impl.cpp, within an unnamed namespace: + +@clip{"button-impl.cpp",DALI_TYPE_REGISTRATION_BEGIN,DALI_TYPE_REGISTRATION_END} + +Notes: + +- The “Create” parameter to the begin macro is the function pointer to the creation function. +- Properties should be in the same order as in the enum. +- Signals and actions are registered likewise in that order. +- Properties type-registered using these macros will have their order checked at compile time. If you get an indexing compile error, check the order matches the enum order. + + +
+
@section property-indices Property Indices +The properties are enumerated to give them a unique index. This index can be used to access them. +The indecies must be unique per flattened derivation heirachy. +EG: +- CameraActor derives from Actor. No property indicies in either CameraActor or Actor should collide with each other. +- ActiveConstraintBase derives from Object. It CAN have property indices that match Actor or CameraActor. + +There are some predefined start indecies and ranges that should be used for common cases, these are defined below: + + DALi has a property system and provides several different kinds of properties. The following table shows the index range of the different properties in place. - - - - - - + + + + + +
Kind Description Range
Default Properties defined within DALi Core, e.g. Dali::Actor, Dali::ShaderEffect default properties etc. 0 to 9999999
Registered Properties registered using Dali::PropertyRegistration 10000000 to 19999999
Control Property range reserved by Dali::Toolkit::Control 10000000 to 10001000
- \link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX CONTROL_PROPERTY_START_INDEX\endlink - to \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX CONTROL_PROPERTY_END_INDEX\endlink
Derived Control Property range for control deriving directly from Dali::Toolkit::Control 10001001 to 19999999
Custom Custom properties added to instance using Dali::Handle::RegisterProperty 50000000 onwards
Kind Description Start IndexEnd Index
Default Properties defined within DALi Core, e.g. Dali::Actor, Dali::ShaderEffect default properties etc. \link Dali::DEFAULT_OBJECT_PROPERTY_START_INDEX DEFAULT_OBJECT_PROPERTY_START_INDEX\endlink (0)9999999
Registered Properties registered using Dali::PropertyRegistration \link Dali::PROPERTY_REGISTRATION_START_INDEX PROPERTY_REGISTRATION_START_INDEX\endlink (10000000)\link Dali::PROPERTY_REGISTRATION_MAX_INDEX PROPERTY_REGISTRATION_MAX_INDEX\endlink (19999999)
Control Property range reserved by Dali::Toolkit::Control \link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX CONTROL_PROPERTY_START_INDEX\endlink (10000000) + \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX CONTROL_PROPERTY_END_INDEX\endlink (10001000)
Derived Control Property range for control deriving directly from Dali::Toolkit::Control 10001001\link Dali::PROPERTY_REGISTRATION_MAX_INDEX PROPERTY_REGISTRATION_MAX_INDEX\endlink (19999999)
Custom Custom properties added to instance using Dali::Handle::RegisterProperty \link Dali::PROPERTY_CUSTOM_START_INDEX PROPERTY_CUSTOM_START_INDEX\endlink (50000000)Onwards...
+ +
+
+@section property-use-example-cpp Property use example C++ + +Common uses for properties are constraints and animations. + +An application developer can use an existing property, or, if necessary, register their own. + +Here is a code example. + +This example shows how to register and look-up custom properties. +A grid of buttons is created, each with a new "tag" property which is set to a unique value. The index to this property is cached for later use. +When pressed, the property is looked up by index (as this is much faster than a text lookup of the property name). + +Property lookup via index should always be used unless the indecies cannot be known. If the property reader was completely decoupled from the creation, EG. A custom control with a custom property being used by external application code, then it may be necessary. In this case the application writer should aim to perform the text lookup once at start-up, and cache the property index locally. + +@clip{"property-example.cpp", void Create, return true;} + +Once run, a grid of buttons will appear. When a button is pressed, the unique number stored in the property (in this case the index) is displayed at the bottom of the screen. + +
+
+@section property-use-example-js Property use in JavaScript + +Note that constraints cannot be used within JavaScript, so below is a simple example that sets one of the default properties; scale: + +@code +var image = new dali.ResourceImage( {url:"background.png"} ); +var imageActor = new dali.ImageActor( image ); + +// by default an actor is anchored to the top-left of it's parent actor +// change it to the middle +imageActor.parentOrigin = dali.CENTER; + +// scale it up by 2 times in x,y +imageActor.scale = [ 2, 2, 1 ]; + +// add to the stage +dali.stage.add( imageActor ); +@endcode + +For a more detailed example see the ShaderEffect example in the JavaScript documentation. + +
+
+@section property-use-example-json Property use in JSON + +This is a basic example of a button defined in JSON by setting the default properties. + +@code +{ + "constants": { + "CONFIG_SCRIPT_LOG_LEVEL": "Verbose" + }, + "stage": [ + // First Button + { + "type": "PushButton", + "parent-origin": "TOP_CENTER", + "anchor-point": "TOP_CENTER", + "position": [0, 0, 0], + "size": [0, 200, 0], + "normal-state-actor": { + "type": "ImageActor", + "image": { + "filename": "{DALI_IMAGE_DIR}blocks-brick-1.png" + } + }, + "selected-state-actor": { + "type": "ImageActor", + "image": { + "filename": "{DALI_IMAGE_DIR}blocks-brick-2.png" + } + }, + "label-actor": { + "type": "TextView", + "text": "Normal" + } + } + ] +} +@endcode + * */ -- 2.7.4