1 #include <dali-toolkit/dali-toolkit.h>
2 #include <dali/public-api/object/property-map.h>
3 #include <dali-toolkit/public-api/controls/slider/slider.h>
6 using namespace Dali::Toolkit;
11 const char* BUTTON_IMAGE_URL[] =
13 DEMO_IMAGE_DIR "sphere-button.png",
14 DEMO_IMAGE_DIR "cone-button.png",
15 DEMO_IMAGE_DIR "conical-frustrum-button.png",
16 DEMO_IMAGE_DIR "cylinder-button.png",
17 DEMO_IMAGE_DIR "cube-button.png",
18 DEMO_IMAGE_DIR "bevelled-cube-button.png",
19 DEMO_IMAGE_DIR "octahedron-button.png"
23 const char * const SHAPE_SPHERE = "SPHERE";
24 const char * const SHAPE_CONE = "CONE";
25 const char * const SHAPE_CONICAL_FRUSTRUM = "CONICAL_FRUSTRUM";
26 const char * const SHAPE_CYLINDER = "CYLINDER";
27 const char * const SHAPE_CUBE = "CUBE";
28 const char * const SHAPE_BEVELLED_CUBE = "BEVELLED_CUBE";
29 const char * const SHAPE_OCTAHEDRON = "OCTAHEDRON";
31 //Shape property defaults
32 const int DEFAULT_SLICES = 32;
33 const int DEFAULT_STACKS = 32;
34 const float DEFAULT_SCALE_HEIGHT = 16.0f;
35 const float DEFAULT_SCALE_BOTTOM_RADIUS = 8.0f;
36 const float DEFAULT_SCALE_TOP_RADIUS = 4.0f;
37 const float DEFAULT_SCALE_RADIUS = 8.0f;
38 const float DEFAULT_BEVEL_PERCENTAGE = 0.3f;
39 const float DEFAULT_BEVEL_SMOOTHNESS = 0.0f;
41 //Shape property limits
42 const int SLICES_LOWER_BOUND = 3;
43 const int SLICES_UPPER_BOUND = 16;
44 const int STACKS_LOWER_BOUND = 2;
45 const int STACKS_UPPER_BOUND = 16;
47 //Used to the control rate of rotation when panning an object.
48 const float X_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
49 const float Y_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
51 const int NUM_MODELS = 7; //Total number of possible base shapes.
52 const int MAX_PROPERTIES = 3; //Maximum number of properties a shape may require. (For displaying sliders.)
56 class PrimitiveShapesController : public ConnectionTracker
60 PrimitiveShapesController( Application& application )
61 : mApplication( application ),
62 mColor( Vector4( 0.3f, 0.7f, 1.0f, 1.0f ) ),
63 mRotation( Vector2::ZERO )
65 // Connect to the Application's Init signal
66 mApplication.InitSignal().Connect( this, &PrimitiveShapesController::Create );
69 ~PrimitiveShapesController()
73 // The Init signal is received once (only) during the Application lifetime
74 void Create( Application& application )
76 // Get a handle to the stage
77 Stage stage = Stage::GetCurrent();
78 stage.SetBackgroundColor( Color::WHITE );
80 //Set up layer to place UI on.
81 Layer layer = Layer::New();
82 layer.SetParentOrigin( ParentOrigin::CENTER );
83 layer.SetAnchorPoint( AnchorPoint::CENTER );
84 layer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
85 layer.SetBehavior( Layer::LAYER_2D ); //We use a 2D layer as this is closer to UI work than full 3D scene creation.
86 layer.SetDepthTestDisabled( false ); //Enable depth testing, as otherwise the 2D layer would not do so.
89 //Set up model selection buttons.
90 SetupButtons( layer );
92 //Set up model parameter sliders.
93 SetupSliders( layer );
98 //Allow for exiting of the application via key presses.
99 stage.KeyEventSignal().Connect( this, &PrimitiveShapesController::OnKeyEvent );
102 //Place buttons on the top of the screen, which allow for selection of the shape to be displayed.
103 //The buttons are laid out like so:
105 // ^ +--------------------------------+
107 // | | +----+ +----+ +----+ +----+ |
108 // | | | | | | | | | | |
109 // 30% | | +----+ +----+ +----+ +----+ |
111 // | | +----+ +----+ +----+ |
113 // v | +----+ +----+ +----+ |
133 // +--------------------------------+
135 void SetupButtons( Layer layer )
137 float containerPadding = 10.0f;
138 float buttonPadding = 5.0f;
140 //Create a variable-length container that can wrap buttons around as more are added.
141 FlexContainer buttonContainer = FlexContainer::New();
142 buttonContainer.SetParentOrigin( ParentOrigin::TOP_CENTER );
143 buttonContainer.SetAnchorPoint( AnchorPoint::TOP_CENTER );
144 buttonContainer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
145 buttonContainer.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::HEIGHT );
146 buttonContainer.SetSizeModeFactor( Vector3( 0.0, 0.3, 0.0 ) ); //30% of height.
147 buttonContainer.SetPadding( Padding( containerPadding, containerPadding, containerPadding, containerPadding ) );
148 buttonContainer.SetProperty( FlexContainer::Property::FLEX_DIRECTION, FlexContainer::ROW );
149 buttonContainer.SetProperty( FlexContainer::Property::FLEX_WRAP, FlexContainer::WRAP );
151 layer.Add( buttonContainer );
153 //Create buttons and place them in the container.
154 for( int modelNumber = 0; modelNumber < NUM_MODELS; modelNumber++ )
156 PushButton button = Toolkit::PushButton::New();
157 button.SetParentOrigin( ParentOrigin::CENTER );
158 button.SetAnchorPoint( AnchorPoint::CENTER );
159 button.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
160 button.SetPadding( Padding( buttonPadding, buttonPadding, buttonPadding, buttonPadding ) );
161 button.SetProperty( Button::Property::UNSELECTED_STATE_IMAGE, Property::Value( BUTTON_IMAGE_URL[modelNumber] ) );
162 button.SetProperty( Button::Property::SELECTED_STATE_IMAGE, Property::Value( BUTTON_IMAGE_URL[modelNumber] ) );
163 button.RegisterProperty( "modelNumber", Property::Value( modelNumber ) );
164 button.ClickedSignal().Connect( this, &PrimitiveShapesController::OnChangeShapeClicked );
166 buttonContainer.Add( button );
170 //Add sliders to the bottom of the screen, which allow for control of shape properties such as radius.
171 //Each slider is placed next to a label that states the property it affects.
172 //The sliders are laid out like so:
174 // +--------------------------------+
194 // ^ | Label +----------O-----------+ |
197 // | | Label +--O-------------------+ |
200 // | | Label +----------------------O |
202 // v +--------------------------------+
204 void SetupSliders( Layer layer )
206 //Create table to hold sliders and their corresponding labels.
207 mSliderTable = Toolkit::TableView::New( MAX_PROPERTIES, 2 );
208 mSliderTable.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
209 mSliderTable.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
210 mSliderTable.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
211 mSliderTable.SetSizeModeFactor( Vector3( 0.9, 0.3, 0.0 ) ); //90% of width, 30% of height.
212 mSliderTable.SetFitWidth( 0 ); //Label column should fit to natural size of label.
213 mSliderTable.SetRelativeWidth( 1, 1.0f ); //Slider column should fill remaining space.
214 mSliderTable.SetCellPadding( Vector2( 10.0f, 0.0f ) ); //Leave a gap between the slider and its label.
215 layer.Add( mSliderTable );
217 //Set up sliders, and place labels next to them.
218 for( int i = 0; i < MAX_PROPERTIES; i++ )
221 Slider slider = Slider::New();
222 slider.SetParentOrigin( ParentOrigin::CENTER );
223 slider.SetAnchorPoint( AnchorPoint::CENTER );
224 slider.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
225 slider.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
226 slider.ValueChangedSignal().Connect( this, &PrimitiveShapesController::OnSliderValueChanged );
227 mSliders.push_back( slider );
229 //Setup slider cell properties
230 mSliderTable.AddChild( slider, TableView::CellPosition( i, 1 ) );
231 mSliderTable.SetCellAlignment( TableView::CellPosition( i, 1 ), HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
233 //Create slider label
234 TextLabel sliderLabel = TextLabel::New();
235 sliderLabel.SetParentOrigin( ParentOrigin::CENTER );
236 sliderLabel.SetAnchorPoint( AnchorPoint::CENTER );
237 sliderLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
238 mSliderLabels.push_back( sliderLabel );
240 //Setup slider-label cell properties
241 mSliderTable.AddChild( sliderLabel, TableView::CellPosition( i, 0 ) );
242 mSliderTable.SetCellAlignment( TableView::CellPosition( i, 0 ), HorizontalAlignment::LEFT, VerticalAlignment::CENTER );
246 //Adds a control to the centre of the stage to display the 3D shapes.
247 //The model is placed in the center of the screen, like so:
249 // +--------------------------------+
277 // +--------------------------------+
279 void SetupModel( Layer layer )
281 //Create a container to house the renderer-holding actor, to provide a constant hitbox.
282 Actor container = Actor::New();
283 container.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
284 container.SetSizeModeFactor( Vector3( 0.9, 0.3, 0.0 ) ); //90% of width, 30% of height.
285 container.SetParentOrigin( ParentOrigin::CENTER );
286 container.SetAnchorPoint( AnchorPoint::CENTER );
287 layer.Add( container );
289 //Create control to display the 3D primitive.
290 mModel = Control::New();
291 mModel.SetParentOrigin( ParentOrigin::CENTER );
292 mModel.SetAnchorPoint( AnchorPoint::CENTER);
293 mModel.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
294 container.Add( mModel );
296 //Load default shape.
299 //Make model spin to demonstrate 3D.
300 mRotationAnimation = Animation::New(15.0f);
301 mRotationAnimation.AnimateBy( Property( mModel, Actor::Property::ORIENTATION ),
302 Quaternion( Degree( 0.0f ), Degree( 360.0f ), Degree( 0.0f ) ) );
303 mRotationAnimation.SetLooping(true);
304 mRotationAnimation.Play();
306 //Attach gesture detector to pan models when rotated.
307 mPanGestureDetector = PanGestureDetector::New();
308 mPanGestureDetector.Attach( container );
309 mPanGestureDetector.DetectedSignal().Connect( this, &PrimitiveShapesController::OnPan );
312 //Clears all sliders and resets the primitive renderer property map.
313 void InitialiseSlidersAndModel()
316 for( unsigned i = 0; i < mSliders.size(); i++ )
318 mSliders.at( i ).SetProperty( Slider::Property::MARKS, Property::Value( 0 ) ); //Remove marks
319 mSliders.at( i ).SetVisible( false );
320 mSliderLabels.at( i ).SetProperty( TextLabel::Property::TEXT, Property::Value( "Default" ) );
321 mSliderLabels.at( i ).SetVisible( false );
324 //Renderer map for model
325 mRendererMap.Clear();
326 mRendererMap[ "rendererType" ] = "PRIMITIVE";
327 mRendererMap[ "color" ] = mColor;
330 //Sets the 3D model to a sphere and modifies the sliders appropriately.
333 InitialiseSlidersAndModel();
335 //Set up specific renderer properties.
336 mRendererMap[ "shape" ] = SHAPE_SPHERE;
337 mRendererMap[ "slices" ] = DEFAULT_SLICES;
338 mRendererMap[ "stacks" ] = DEFAULT_STACKS;
341 SetupSlider( 0, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND, DEFAULT_STACKS, "slices" );
342 SetupMarks( mSliders.at( 0 ), SLICES_LOWER_BOUND, SLICES_UPPER_BOUND );
343 SetupSlider( 1, STACKS_LOWER_BOUND, STACKS_UPPER_BOUND, DEFAULT_STACKS, "stacks" );
344 SetupMarks( mSliders.at( 1 ), STACKS_LOWER_BOUND, STACKS_UPPER_BOUND );
346 //Set model in control.
347 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
350 //Sets the 3D model to a cone and modifies the sliders appropriately.
353 InitialiseSlidersAndModel();
355 //Set up specific renderer properties.
356 mRendererMap[ "shape" ] = SHAPE_CONE;
357 mRendererMap[ "scaleHeight" ] = DEFAULT_SCALE_HEIGHT;
358 mRendererMap[ "scaleBottomRadius" ] = DEFAULT_SCALE_BOTTOM_RADIUS;
359 mRendererMap[ "slices" ] = DEFAULT_SLICES;
362 SetupSlider( 0, 1.0f, 32.0f, DEFAULT_SCALE_HEIGHT, "scaleHeight" );
363 SetupSlider( 1, 1.0f, 32.0f, DEFAULT_SCALE_BOTTOM_RADIUS, "scaleBottomRadius" );
364 SetupSlider( 2, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND, DEFAULT_STACKS, "slices" );
365 SetupMarks( mSliders.at( 2 ), SLICES_LOWER_BOUND, SLICES_UPPER_BOUND );
367 //Set model in control.
368 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
371 //Sets the 3D model to a conical frustrum and modifies the sliders appropriately.
372 void LoadConicalFrustrum()
374 InitialiseSlidersAndModel();
376 //Set up specific renderer properties.
377 mRendererMap[ "shape" ] = SHAPE_CONICAL_FRUSTRUM;
378 mRendererMap[ "scaleTopRadius" ] = DEFAULT_SCALE_TOP_RADIUS;
379 mRendererMap[ "scaleBottomRadius" ] = DEFAULT_SCALE_BOTTOM_RADIUS;
380 mRendererMap[ "scaleHeight" ] = DEFAULT_SCALE_HEIGHT;
381 mRendererMap[ "slices" ] = DEFAULT_SLICES;
383 //Set up used sliders.
384 SetupSlider( 0, 1.0f, 32.0f, DEFAULT_SCALE_HEIGHT, "scaleHeight" );
385 SetupSlider( 1, 0.0f, 32.0f, DEFAULT_SCALE_BOTTOM_RADIUS, "scaleBottomRadius" );
386 SetupSlider( 2, 0.0f, 32.0f, DEFAULT_SCALE_TOP_RADIUS, "scaleTopRadius" );
388 //Set model in control.
389 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
392 //Sets the 3D model to a cylinder and modifies the sliders appropriately.
395 InitialiseSlidersAndModel();
397 //Set up specific renderer properties.
398 mRendererMap[ "shape" ] = SHAPE_CYLINDER;
399 mRendererMap[ "scaleHeight" ] = DEFAULT_SCALE_HEIGHT;
400 mRendererMap[ "scaleRadius" ] = DEFAULT_SCALE_RADIUS;
401 mRendererMap[ "slices" ] = DEFAULT_SLICES;
403 //Set up used sliders.
404 SetupSlider( 0, 1.0f, 32.0f, DEFAULT_SCALE_HEIGHT, "scaleHeight" );
405 SetupSlider( 1, 1.0f, 32.0f, DEFAULT_SCALE_RADIUS, "scaleRadius" );
406 SetupSlider( 2, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND, DEFAULT_STACKS, "slices" );
407 SetupMarks( mSliders.at( 2 ), SLICES_LOWER_BOUND, SLICES_UPPER_BOUND );
409 //Set model in control.
410 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
413 //Sets the 3D model to a cube and modifies the sliders appropriately.
416 InitialiseSlidersAndModel();
418 //Set up specific renderer properties.
419 mRendererMap[ "shape" ] = SHAPE_CUBE;
421 //Set model in control.
422 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
425 //Sets the 3D model to a bevelled cube and modifies the sliders appropriately.
426 void LoadBevelledCube()
428 InitialiseSlidersAndModel();
430 //Set up specific renderer properties.
431 mRendererMap[ "shape" ] = SHAPE_BEVELLED_CUBE;
432 mRendererMap[ "bevelPercentage" ] = DEFAULT_BEVEL_PERCENTAGE;
433 mRendererMap[ "bevelSmoothness" ] = DEFAULT_BEVEL_SMOOTHNESS;
435 //Set up used sliders.
436 SetupSlider( 0, 0.0f, 1.0f, DEFAULT_BEVEL_PERCENTAGE, "bevelPercentage" );
437 SetupSlider( 1, 0.0f, 1.0f, DEFAULT_BEVEL_SMOOTHNESS, "bevelSmoothness" );
439 //Set model in control.
440 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
443 //Sets the 3D model to an octahedron and modifies the sliders appropriately.
444 void LoadOctahedron()
446 InitialiseSlidersAndModel();
448 //Set up specific renderer properties.
449 mRendererMap[ "shape" ] = SHAPE_OCTAHEDRON;
451 //Set model in control.
452 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
455 //Sets up the slider at the given index for the supplied property, and labels it appropriately.
456 // rendererPropertyLabel is the property that will be set by this slider.
457 void SetupSlider( int sliderIndex, float lowerBound, float upperBound, float startPoint,
458 std::string rendererPropertyLabel )
460 //Set up the slider itself.
461 mSliders.at( sliderIndex ).RegisterProperty( "rendererProperty", Property::Value( rendererPropertyLabel ), Property::READ_WRITE );
462 mSliders.at( sliderIndex ).SetProperty( Slider::Property::LOWER_BOUND, Property::Value( lowerBound ) );
463 mSliders.at( sliderIndex ).SetProperty( Slider::Property::UPPER_BOUND, Property::Value( upperBound ) );
464 mSliders.at( sliderIndex ).SetProperty( Slider::Property::VALUE, Property::Value( startPoint ) );
465 mSliders.at( sliderIndex ).SetVisible( true );
467 //Label the slider with the property.
468 //We reset the TextLabel to force a relayout of the table.
469 mSliderTable.RemoveChildAt( TableView::CellPosition(sliderIndex, 0) );
471 TextLabel sliderLabel = TextLabel::New( rendererPropertyLabel );
472 sliderLabel.SetParentOrigin( ParentOrigin::CENTER );
473 sliderLabel.SetAnchorPoint( AnchorPoint::CENTER );
474 sliderLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
476 mSliderTable.AddChild( sliderLabel, TableView::CellPosition( sliderIndex, 0 ) );
477 mSliderTable.SetCellAlignment( TableView::CellPosition( sliderIndex, 0 ), HorizontalAlignment::LEFT, VerticalAlignment::CENTER );
479 mSliderLabels.at( sliderIndex ).SetVisible( true );
480 mSliderLabels.at( sliderIndex) = sliderLabel;
483 //Setup snapping to integer values between the two given values.
484 void SetupMarks( Slider& slider, int lower, int upper )
486 Property::Array marks;
488 for( int mark = lower; mark <= upper; mark++ )
490 marks.PushBack( Property::Value( mark ) );
493 slider.SetProperty( Slider::Property::MARKS, Property::Value( marks ) );
494 slider.SetProperty( Slider::Property::SNAP_TO_MARKS, Property::Value( true ) );
497 //When a shape button is tapped, switch to the corresponding shape.
498 bool OnChangeShapeClicked( Button button )
500 //Get the model number from the button.
502 button.GetProperty( button.GetPropertyIndex( "modelNumber" ) ).Get( modelNumber );
504 //Switch to the shape that corresponds to the model number.
505 switch( modelNumber )
519 LoadConicalFrustrum();
547 //When the slider is adjusted, change the corresponding shape property accordingly.
548 bool OnSliderValueChanged( Slider slider, float value )
550 //Update property map to reflect the change to the specific renderer property.
551 std::string rendererPropertyLabel;
552 slider.GetProperty( slider.GetPropertyIndex( "rendererProperty" ) ).Get( rendererPropertyLabel );
553 mRendererMap[ rendererPropertyLabel ] = value;
555 //Reload the model to display the change.
556 mModel.SetProperty( Control::Property::BACKGROUND, Property::Value( mRendererMap ) );
561 //Panning around the shape rotates it.
562 void OnPan( Actor actor, const PanGesture& gesture )
564 switch( gesture.state )
566 case Gesture::Started:
568 //Pause animation, as the gesture will be used to manually rotate the model
569 mRotationAnimation.Pause();
573 case Gesture::Continuing:
575 //Rotate based off the gesture.
576 mRotation.x -= gesture.displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
577 mRotation.y += gesture.displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
578 Quaternion rotation = Quaternion( Radian( mRotation.x ), Vector3::XAXIS) *
579 Quaternion( Radian( mRotation.y ), Vector3::YAXIS);
581 mModel.SetOrientation( rotation );
585 case Gesture::Finished:
587 //Return to automatic animation
588 mRotationAnimation.Play();
592 case Gesture::Cancelled:
594 //Return to automatic animation
595 mRotationAnimation.Play();
606 //If escape or the back button is pressed, quit the application (and return to the launcher)
607 void OnKeyEvent( const KeyEvent& event )
609 if( event.state == KeyEvent::Down )
611 if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
619 Application& mApplication;
621 std::vector<Slider> mSliders; ///< Holds the sliders on screen that each shape accesses.
622 std::vector<TextLabel> mSliderLabels; ///< Holds the labels to each slider.
623 TableView mSliderTable; ///< A table to layout the sliders next to their labels.
625 Property::Map mRendererMap; ///< Property map to create a primitive renderer.
626 Control mModel; ///< Control to house the primitive renderer.
628 PanGestureDetector mPanGestureDetector; ///< Detects pan gestures for rotation of the model.
629 Animation mRotationAnimation; ///< Automatically rotates the model, unless it is being panned.
631 Vector4 mColor; ///< Color to set all shapes.
632 Vector2 mRotation; ///< Keeps track of model rotation.
635 void RunTest( Application& application )
637 PrimitiveShapesController test( application );
639 application.MainLoop();
642 // Entry point for Linux & Tizen applications
644 int main( int argc, char **argv )
646 Application application = Application::New( &argc, &argv );
648 RunTest( application );