Updated programming guide for Properties 37/36537/10
authorTom Robinson <tom.robinson@samsung.com>
Mon, 9 Mar 2015 16:22:51 +0000 (16:22 +0000)
committerTom Robinson <tom.robinson@samsung.com>
Fri, 13 Mar 2015 11:44:39 +0000 (11:44 +0000)
Change-Id: Ie96b72c4f4f2f22edaca653fe435de1dd937dcbb

build/tizen/docs/dali.doxy.in
docs/content/example-code/property-example.cpp [new file with mode: 0644]
docs/content/programming-guide/properties.h

index 92ff833..e072023 100644 (file)
@@ -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 (file)
index 0000000..35e7869
--- /dev/null
@@ -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 <dali/dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <sstream>
+
+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;
+}
index 4c124cb..8838e78 100644 (file)
 /*! \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.
+
+<h2 class="pg">What is a property used for?</h2>
+
+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.
+
+<h2 class="pg">How to implement a property within Dali-core:</h2>
+
+<b>There are two stages:</b>
+
+- 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".
+
+<b>Example: ImageActor</b>
+
+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<int>
+    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
+
+<b>Notes:</b>
+
+- The properties are enumerated within a named struct to give them a namespace.
+- The properties are then refered to as &lt;OBJECT&gt;::%Property::&lt;PROPERTY_NAME&gt;.
+
+Within the internal implementation; <b>image-actor-impl.cpp</b>:
+
+@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
+
+<b>Notes:</b>
+
+- 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.
+
+<br>
+<h2 class="pg">How to implement a property within Dali-toolkit:</h2>
+
+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.
+
+<b>There are two stages:</b>
+
+- 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.
+
+<b>Example: Button</b>
+
+Source file: <b>button.h</b>:
+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: <b>button-impl.cpp</b>, within an unnamed namespace:
+
+@clip{"button-impl.cpp",DALI_TYPE_REGISTRATION_BEGIN,DALI_TYPE_REGISTRATION_END}
+
+<b>Notes:</b>
+
+- 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.
+
+
+<br>
+<hr>
 @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.
 
 <table>
-  <tr> <td><b>Kind</b></td>     <td><b>Description</b></td>                                                                                <td style="text-align:center;"><b>Range</b></td>         </tr>
-  <tr> <td>Default</td>         <td>Properties defined within DALi Core, e.g. Dali::Actor, Dali::ShaderEffect default properties etc.</td> <td style="text-align:center;">0 to 9999999</td>         </tr>
-  <tr> <td>Registered</td>      <td>Properties registered using Dali::PropertyRegistration</td>                                            <td style="text-align:center;">10000000 to 19999999</td> </tr>
-  <tr> <td>Control</td>         <td>Property range reserved by Dali::Toolkit::Control</td>                                                 <td style="text-align:center;">10000000 to 10001000<br>
-                                                                                      \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</td> </tr>
-  <tr> <td>Derived Control</td> <td>Property range for control deriving directly from Dali::Toolkit::Control</td>                          <td style="text-align:center;">10001001 to 19999999</td> </tr>
-  <tr> <td>Custom</td>          <td>Custom properties added to instance using Dali::Handle::RegisterProperty</td>                          <td style="text-align:center;">50000000 onwards</td>     </tr>
+  <tr> <td><b>Kind</b></td>     <td><b>Description</b></td>                                                                                <td style="text-align:center;"><b>Start Index</b></td><td><b>End Index</b></td>         </tr>
+  <tr> <td>Default</td>         <td>Properties defined within DALi Core, e.g. Dali::Actor, Dali::ShaderEffect default properties etc.</td> <td style="text-align:center;">\link Dali::DEFAULT_OBJECT_PROPERTY_START_INDEX DEFAULT_OBJECT_PROPERTY_START_INDEX\endlink (0)</td><td>9999999</td>         </tr>
+  <tr> <td>Registered</td>      <td>Properties registered using Dali::PropertyRegistration</td>                                            <td style="text-align:center;">\link Dali::PROPERTY_REGISTRATION_START_INDEX PROPERTY_REGISTRATION_START_INDEX\endlink (10000000)</td><td>\link Dali::PROPERTY_REGISTRATION_MAX_INDEX PROPERTY_REGISTRATION_MAX_INDEX\endlink (19999999)</td> </tr>
+  <tr> <td>Control</td>         <td>Property range reserved by Dali::Toolkit::Control</td>                                                 <td style="text-align:center;">\link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX CONTROL_PROPERTY_START_INDEX\endlink (10000000)</td><td>
+  \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX CONTROL_PROPERTY_END_INDEX\endlink (10001000)</td></tr>
+  <tr> <td>Derived Control</td> <td>Property range for control deriving directly from Dali::Toolkit::Control</td>                          <td style="text-align:center;">10001001</td><td>\link Dali::PROPERTY_REGISTRATION_MAX_INDEX PROPERTY_REGISTRATION_MAX_INDEX\endlink (19999999)</td> </tr>
+  <tr> <td>Custom</td>          <td>Custom properties added to instance using Dali::Handle::RegisterProperty</td>                          <td style="text-align:center;">\link Dali::PROPERTY_CUSTOM_START_INDEX PROPERTY_CUSTOM_START_INDEX\endlink (50000000)</td><td>Onwards...</td>     </tr>
 </table>
 
+
+<br>
+<hr>
+@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.
+
+<br>
+<hr>
+@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.
+
+<br>
+<hr>
+@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
+
 *
 */