Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / primitive-shapes / primitive-shapes-example.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali-toolkit/devel-api/controls/table-view/table-view.h>
20
21 using namespace Dali;
22 using namespace Dali::Toolkit;
23
24 namespace
25 {
26 //Button image urls
27 const char* BUTTON_IMAGE_URL[] =
28   {
29     DEMO_IMAGE_DIR "sphere-button.png",
30     DEMO_IMAGE_DIR "cone-button.png",
31     DEMO_IMAGE_DIR "conical-frustum-button.png",
32     DEMO_IMAGE_DIR "cylinder-button.png",
33     DEMO_IMAGE_DIR "cube-button.png",
34     DEMO_IMAGE_DIR "bevelled-cube-button.png",
35     DEMO_IMAGE_DIR "octahedron-button.png"};
36
37 //Prefix of all shape titles.
38 const std::string SHAPE_TITLE_PREFIX = "Current Shape: ";
39
40 //Shape property defaults
41 const int   DEFAULT_SLICES              = 32;
42 const int   DEFAULT_STACKS              = 32;
43 const float DEFAULT_SCALE_HEIGHT        = 16.0f;
44 const float DEFAULT_SCALE_BOTTOM_RADIUS = 8.0f;
45 const float DEFAULT_SCALE_TOP_RADIUS    = 4.0f;
46 const float DEFAULT_SCALE_RADIUS        = 8.0f;
47 const float DEFAULT_BEVEL_PERCENTAGE    = 0.3f;
48 const float DEFAULT_BEVEL_SMOOTHNESS    = 0.0f;
49
50 //Shape property limits
51 const int SLICES_LOWER_BOUND = 3;
52 const int SLICES_UPPER_BOUND = 16;
53 const int STACKS_LOWER_BOUND = 2;
54 const int STACKS_UPPER_BOUND = 16;
55
56 //Used to the control rate of rotation when panning an object.
57 const float X_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
58 const float Y_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
59
60 const int NUM_MODELS     = 7; //Total number of possible base shapes.
61 const int MAX_PROPERTIES = 3; //Maximum number of properties a shape may require. (For displaying sliders.)
62
63 } //End namespace
64
65 class PrimitiveShapesController : public ConnectionTracker
66 {
67 public:
68   PrimitiveShapesController(Application& application)
69   : mApplication(application),
70     mColor(Vector4(0.3f, 0.7f, 1.0f, 1.0f)),
71     mRotation(Vector2::ZERO)
72   {
73     // Connect to the Application's Init signal
74     mApplication.InitSignal().Connect(this, &PrimitiveShapesController::Create);
75   }
76
77   ~PrimitiveShapesController()
78   {
79   }
80
81   // The Init signal is received once (only) during the Application lifetime
82   void Create(Application& application)
83   {
84     // Get a handle to the window
85     Window window = application.GetWindow();
86     window.SetBackgroundColor(Color::WHITE);
87
88     //Set up layer to place UI on.
89     Layer layer = Layer::New();
90     layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
91     layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
92     layer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
93     layer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_UI); //We use a 2D layer as this is closer to UI work than full 3D scene creation.
94     layer.SetProperty(Layer::Property::DEPTH_TEST, true);          //Enable depth testing, as otherwise the 2D layer would not do so.
95     window.Add(layer);
96
97     //Set up model selection buttons.
98     SetupButtons(layer);
99
100     //Set up model parameter sliders.
101     SetupSliders(layer);
102
103     //Set up 3D model.
104     SetupModel(layer);
105
106     //Allow for exiting of the application via key presses.
107     window.KeyEventSignal().Connect(this, &PrimitiveShapesController::OnKeyEvent);
108   }
109
110   //Place buttons on the top of the screen, which allow for selection of the shape to be displayed.
111   //A title above indicates the currently selected shape.
112   //The buttons are laid out like so:
113   //
114   //      ^    +--------------------------------+
115   //      |    | Current Shape: ~~~~~           |
116   //      |    |                                |
117   //      |    | +----+ +----+ +----+ +----+    |
118   //      |    | |    | |    | |    | |    |    |
119   //  30% |    | +----+ +----+ +----+ +----+    |
120   //      |    |                                |
121   //      |    | +----+ +----+ +----+           |
122   //      |    | |    | |    | |    |           |
123   //      v    | +----+ +----+ +----+           |
124   //           |                                |
125   //           |                                |
126   //           |                                |
127   //           |                                |
128   //           |                                |
129   //           |                                |
130   //           |                                |
131   //           |                                |
132   //           |                                |
133   //           |                                |
134   //           |                                |
135   //           |                                |
136   //           |                                |
137   //           |                                |
138   //           |                                |
139   //           |                                |
140   //           |                                |
141   //           |                                |
142   //           +--------------------------------+
143   //
144   void SetupButtons(Layer layer)
145   {
146     float containerPadding = 10.0f;
147     float elementPadding   = 5.0f;
148
149     //Used to layout the title and the buttons below it.
150     Control topAlignment = Control::New();
151     topAlignment.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
152     topAlignment.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
153     topAlignment.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
154     topAlignment.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT);
155     layer.Add(topAlignment);
156
157     //Add a title to indicate the currently selected shape.
158     mShapeTitle = TextLabel::New("DEFAULT");
159     mShapeTitle.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
160     mShapeTitle.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
161     mShapeTitle.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
162     mShapeTitle.SetProperty(Actor::Property::PADDING, Padding(elementPadding, elementPadding, elementPadding, elementPadding));
163     topAlignment.Add(mShapeTitle);
164
165     //Create a variable-length container that can wrap buttons around as more are added.
166     FlexContainer buttonContainer = FlexContainer::New();
167     buttonContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
168     buttonContainer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
169     buttonContainer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
170     buttonContainer.SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
171     buttonContainer.SetProperty(Actor::Property::PADDING, Padding(containerPadding, containerPadding, containerPadding, containerPadding));
172     buttonContainer.SetProperty(FlexContainer::Property::FLEX_DIRECTION, FlexContainer::ROW);
173     buttonContainer.SetProperty(FlexContainer::Property::FLEX_WRAP, FlexContainer::WRAP);
174     topAlignment.Add(buttonContainer);
175
176     //Create buttons and place them in the container.
177     for(int modelNumber = 0; modelNumber < NUM_MODELS; modelNumber++)
178     {
179       PushButton button = Toolkit::PushButton::New();
180       button.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
181       button.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
182       button.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
183       button.SetProperty(Actor::Property::PADDING, Padding(elementPadding, elementPadding, elementPadding, elementPadding));
184       button.SetProperty(Button::Property::UNSELECTED_BACKGROUND_VISUAL, BUTTON_IMAGE_URL[modelNumber]);
185       button.SetProperty(Button::Property::SELECTED_BACKGROUND_VISUAL, BUTTON_IMAGE_URL[modelNumber]);
186       button.RegisterProperty("modelNumber", Property::Value(modelNumber));
187       button.ClickedSignal().Connect(this, &PrimitiveShapesController::OnChangeShapeClicked);
188
189       buttonContainer.Add(button);
190     }
191   }
192
193   //Add sliders to the bottom of the screen, which allow for control of shape properties such as radius.
194   //Each slider is placed next to a label that states the property it affects.
195   //The sliders are laid out like so:
196   //
197   //           +--------------------------------+
198   //           |                                |
199   //           |                                |
200   //           |                                |
201   //           |                                |
202   //           |                                |
203   //           |                                |
204   //           |                                |
205   //           |                                |
206   //           |                                |
207   //           |                                |
208   //           |                                |
209   //           |                                |
210   //           |                                |
211   //           |                                |
212   //           |                                |
213   //           |                                |
214   //           |                                |
215   //           |                                |
216   //           |                                |
217   //      ^    | Label +----------O-----------+ |
218   //      |    |                                |
219   //      |    |                                |
220   //      |    | Label +--O-------------------+ |
221   //  30% |    |                                |
222   //      |    |                                |
223   //      |    | Label +----------------------O |
224   //      |    |                                |
225   //      v    +--------------------------------+
226   //
227   void SetupSliders(Layer layer)
228   {
229     //Create table to hold sliders and their corresponding labels.
230     mSliderTable = Toolkit::TableView::New(MAX_PROPERTIES, 2);
231     mSliderTable.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
232     mSliderTable.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
233     mSliderTable.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
234     mSliderTable.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(0.9, 0.3, 0.0)); //90% of width, 30% of height.
235     mSliderTable.SetFitWidth(0);                                                         //Label column should fit to natural size of label.
236     mSliderTable.SetRelativeWidth(1, 1.0f);                                              //Slider column should fill remaining space.
237     mSliderTable.SetCellPadding(Vector2(10.0f, 0.0f));                                   //Leave a gap between the slider and its label.
238     layer.Add(mSliderTable);
239
240     //Set up sliders, and place labels next to them.
241     for(int i = 0; i < MAX_PROPERTIES; i++)
242     {
243       //Create slider
244       Slider slider = Slider::New();
245       slider.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
246       slider.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
247       slider.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
248       slider.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
249       slider.ValueChangedSignal().Connect(this, &PrimitiveShapesController::OnSliderValueChanged);
250       mSliders.push_back(slider);
251
252       //Setup slider cell properties
253       mSliderTable.AddChild(slider, TableView::CellPosition(i, 1));
254       mSliderTable.SetCellAlignment(TableView::CellPosition(i, 1), HorizontalAlignment::CENTER, VerticalAlignment::CENTER);
255
256       //Create slider label
257       TextLabel sliderLabel = TextLabel::New();
258       sliderLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
259       sliderLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
260       sliderLabel.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
261       mSliderLabels.push_back(sliderLabel);
262
263       //Setup slider-label cell properties
264       mSliderTable.AddChild(sliderLabel, TableView::CellPosition(i, 0));
265       mSliderTable.SetCellAlignment(TableView::CellPosition(i, 0), HorizontalAlignment::LEFT, VerticalAlignment::CENTER);
266     }
267   }
268
269   //Adds a control to the centre of the window to display the 3D shapes.
270   //The model is placed in the center of the screen, like so:
271   //
272   //           +--------------------------------+
273   //           |                                |
274   //           |                                |
275   //           |                                |
276   //           |                                |
277   //           |                                |
278   //           |                                |
279   //           |                                |
280   //           |                                |
281   //           |                                |
282   //       ^   |           ----------           |
283   //       |   |          /          \          |
284   //       |   |         /            \         |
285   //       |   |        |              |        |
286   //   30% |   |        |              |        |
287   //       |   |        |              |        |
288   //       |   |         \            /         |
289   //       |   |          \          /          |
290   //       v   |           ----------           |
291   //           |                                |
292   //           |                                |
293   //           |                                |
294   //           |                                |
295   //           |                                |
296   //           |                                |
297   //           |                                |
298   //           |                                |
299   //           |                                |
300   //           +--------------------------------+
301   //
302   void SetupModel(Layer layer)
303   {
304     //Create a container to house the visual-holding actor, to provide a constant hitbox.
305     Actor container = Actor::New();
306     container.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
307     container.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(0.9, 0.3, 0.0)); //90% of width, 30% of height.
308     container.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
309     container.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
310     layer.Add(container);
311
312     //Create control to display the 3D primitive.
313     mModel = Control::New();
314     mModel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
315     mModel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
316     mModel.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
317     container.Add(mModel);
318
319     //Load default shape.
320     LoadCube();
321
322     //Make model spin to demonstrate 3D.
323     mRotationAnimation = Animation::New(15.0f);
324     mRotationAnimation.AnimateBy(Property(mModel, Actor::Property::ORIENTATION),
325                                  Quaternion(Degree(0.0f), Degree(360.0f), Degree(0.0f)));
326     mRotationAnimation.SetLooping(true);
327     mRotationAnimation.Play();
328
329     //Attach gesture detector to pan models when rotated.
330     mPanGestureDetector = PanGestureDetector::New();
331     mPanGestureDetector.Attach(container);
332     mPanGestureDetector.DetectedSignal().Connect(this, &PrimitiveShapesController::OnPan);
333   }
334
335   //Clears all sliders and resets the primitive visual property map.
336   void InitialiseSlidersAndModel()
337   {
338     //Sliders
339     for(unsigned i = 0; i < mSliders.size(); i++)
340     {
341       mSliders.at(i).SetProperty(Slider::Property::MARKS, Property::Value(0)); //Remove marks
342       mSliders.at(i).SetProperty(Actor::Property::VISIBLE, false);
343       mSliderLabels.at(i).SetProperty(TextLabel::Property::TEXT, Property::Value("Default"));
344       mSliderLabels.at(i).SetProperty(Actor::Property::VISIBLE, false);
345     }
346
347     //Visual map for model
348     mVisualMap.Clear();
349     mVisualMap[Toolkit::Visual::Property::TYPE]      = Visual::PRIMITIVE;
350     mVisualMap[PrimitiveVisual::Property::MIX_COLOR] = mColor;
351     mVisualMap[Visual::Property::TRANSFORM] =
352       Property::Map().Add(Visual::Transform::Property::ORIGIN, Align::CENTER).Add(Visual::Transform::Property::ANCHOR_POINT, Align::CENTER);
353   }
354
355   //Sets the 3D model to a sphere and modifies the sliders appropriately.
356   void LoadSphere()
357   {
358     InitialiseSlidersAndModel();
359
360     //Set up specific visual properties.
361     mVisualMap[PrimitiveVisual::Property::SHAPE]  = PrimitiveVisual::Shape::SPHERE;
362     mVisualMap[PrimitiveVisual::Property::SLICES] = DEFAULT_SLICES;
363     mVisualMap[PrimitiveVisual::Property::STACKS] = DEFAULT_STACKS;
364
365     //Set up sliders.
366     SetupSlider(0, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND, DEFAULT_STACKS, PrimitiveVisual::Property::SLICES, "slices");
367     SetupMarks(0, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND);
368     mSliders.at(0).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(0));
369
370     SetupSlider(1, STACKS_LOWER_BOUND, STACKS_UPPER_BOUND, DEFAULT_STACKS, PrimitiveVisual::Property::STACKS, "stacks");
371     SetupMarks(1, STACKS_LOWER_BOUND, STACKS_UPPER_BOUND);
372     mSliders.at(1).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(0));
373
374     //Set model in control.
375     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
376
377     //Update title.
378     mShapeTitle.SetProperty(TextLabel::Property::TEXT, SHAPE_TITLE_PREFIX + "Sphere");
379   }
380
381   //Sets the 3D model to a cone and modifies the sliders appropriately.
382   void LoadCone()
383   {
384     InitialiseSlidersAndModel();
385
386     //Set up specific visual properties.
387     mVisualMap[PrimitiveVisual::Property::SHAPE]               = PrimitiveVisual::Shape::CONE;
388     mVisualMap[PrimitiveVisual::Property::SCALE_HEIGHT]        = DEFAULT_SCALE_HEIGHT;
389     mVisualMap[PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS] = DEFAULT_SCALE_BOTTOM_RADIUS;
390     mVisualMap[PrimitiveVisual::Property::SLICES]              = DEFAULT_SLICES;
391
392     //Set up sliders.
393     SetupSlider(0, 1.0f, 32.0f, DEFAULT_SCALE_HEIGHT, PrimitiveVisual::Property::SCALE_HEIGHT, "scaleHeight");
394     mSliders.at(0).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(1));
395
396     SetupSlider(1, 1.0f, 32.0f, DEFAULT_SCALE_BOTTOM_RADIUS, PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, "scaleBottomRadius");
397     mSliders.at(1).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(1));
398
399     SetupSlider(2, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND, DEFAULT_STACKS, PrimitiveVisual::Property::SLICES, "slices");
400     SetupMarks(2, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND);
401     mSliders.at(2).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(0));
402
403     //Set model in control.
404     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
405
406     //Update title.
407     mShapeTitle.SetProperty(TextLabel::Property::TEXT, SHAPE_TITLE_PREFIX + "Cone");
408   }
409
410   //Sets the 3D model to a conical frustum and modifies the sliders appropriately.
411   void LoadConicalFrustum()
412   {
413     InitialiseSlidersAndModel();
414
415     //Set up specific visual properties.
416     mVisualMap[PrimitiveVisual::Property::SHAPE]               = PrimitiveVisual::Shape::CONICAL_FRUSTUM;
417     mVisualMap[PrimitiveVisual::Property::SCALE_TOP_RADIUS]    = DEFAULT_SCALE_TOP_RADIUS;
418     mVisualMap[PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS] = DEFAULT_SCALE_BOTTOM_RADIUS;
419     mVisualMap[PrimitiveVisual::Property::SCALE_HEIGHT]        = DEFAULT_SCALE_HEIGHT;
420     mVisualMap[PrimitiveVisual::Property::SLICES]              = DEFAULT_SLICES;
421
422     //Set up used sliders.
423     SetupSlider(0, 1.0f, 32.0f, DEFAULT_SCALE_HEIGHT, PrimitiveVisual::Property::SCALE_HEIGHT, "scaleHeight");
424     mSliders.at(0).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(1));
425
426     SetupSlider(1, 0.0f, 32.0f, DEFAULT_SCALE_BOTTOM_RADIUS, PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, "scaleBottomRadius");
427     mSliders.at(1).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(1));
428
429     SetupSlider(2, 0.0f, 32.0f, DEFAULT_SCALE_TOP_RADIUS, PrimitiveVisual::Property::SCALE_TOP_RADIUS, "scaleTopRadius");
430     mSliders.at(2).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(1));
431
432     //Set model in control.
433     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
434
435     //Update title.
436     mShapeTitle.SetProperty(TextLabel::Property::TEXT, SHAPE_TITLE_PREFIX + "Conical Frustum");
437   }
438
439   //Sets the 3D model to a cylinder and modifies the sliders appropriately.
440   void LoadCylinder()
441   {
442     InitialiseSlidersAndModel();
443
444     //Set up specific visual properties.
445     mVisualMap[PrimitiveVisual::Property::SHAPE]        = PrimitiveVisual::Shape::CYLINDER;
446     mVisualMap[PrimitiveVisual::Property::SCALE_HEIGHT] = DEFAULT_SCALE_HEIGHT;
447     mVisualMap[PrimitiveVisual::Property::SCALE_RADIUS] = DEFAULT_SCALE_RADIUS;
448     mVisualMap[PrimitiveVisual::Property::SLICES]       = DEFAULT_SLICES;
449
450     //Set up used sliders.
451     SetupSlider(0, 1.0f, 32.0f, DEFAULT_SCALE_HEIGHT, PrimitiveVisual::Property::SCALE_HEIGHT, "scaleHeight");
452     mSliders.at(0).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(1));
453
454     SetupSlider(1, 1.0f, 32.0f, DEFAULT_SCALE_RADIUS, PrimitiveVisual::Property::SCALE_RADIUS, "scaleRadius");
455     mSliders.at(1).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(1));
456
457     SetupSlider(2, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND, DEFAULT_STACKS, PrimitiveVisual::Property::SLICES, "slices");
458     SetupMarks(2, SLICES_LOWER_BOUND, SLICES_UPPER_BOUND);
459     mSliders.at(2).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(0));
460
461     //Set model in control.
462     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
463
464     //Update title.
465     mShapeTitle.SetProperty(TextLabel::Property::TEXT, SHAPE_TITLE_PREFIX + "Cylinder");
466   }
467
468   //Sets the 3D model to a cube and modifies the sliders appropriately.
469   void LoadCube()
470   {
471     InitialiseSlidersAndModel();
472
473     //Set up specific visual properties.
474     mVisualMap[PrimitiveVisual::Property::SHAPE] = PrimitiveVisual::Shape::CUBE;
475
476     //Set model in control.
477     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
478
479     //Update title.
480     mShapeTitle.SetProperty(TextLabel::Property::TEXT, SHAPE_TITLE_PREFIX + "Cube");
481   }
482
483   //Sets the 3D model to a bevelled cube and modifies the sliders appropriately.
484   void LoadBevelledCube()
485   {
486     InitialiseSlidersAndModel();
487
488     //Set up specific visual properties.
489     mVisualMap[PrimitiveVisual::Property::SHAPE]            = PrimitiveVisual::Shape::BEVELLED_CUBE;
490     mVisualMap[PrimitiveVisual::Property::BEVEL_PERCENTAGE] = DEFAULT_BEVEL_PERCENTAGE;
491     mVisualMap[PrimitiveVisual::Property::BEVEL_SMOOTHNESS] = DEFAULT_BEVEL_SMOOTHNESS;
492
493     //Set up used sliders.
494     SetupSlider(0, 0.0f, 1.0f, DEFAULT_BEVEL_PERCENTAGE, PrimitiveVisual::Property::BEVEL_PERCENTAGE, "bevelPercentage");
495     mSliders.at(0).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(2));
496
497     SetupSlider(1, 0.0f, 1.0f, DEFAULT_BEVEL_SMOOTHNESS, PrimitiveVisual::Property::BEVEL_SMOOTHNESS, "bevelSmoothness");
498     mSliders.at(1).SetProperty(Slider::Property::VALUE_PRECISION, Property::Value(2));
499
500     //Set model in control.
501     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
502
503     //Update title.
504     mShapeTitle.SetProperty(TextLabel::Property::TEXT, SHAPE_TITLE_PREFIX + "Bevelled Cube");
505   }
506
507   //Sets the 3D model to an octahedron and modifies the sliders appropriately.
508   void LoadOctahedron()
509   {
510     InitialiseSlidersAndModel();
511
512     //Set up specific visual properties.
513     mVisualMap[PrimitiveVisual::Property::SHAPE] = PrimitiveVisual::Shape::OCTAHEDRON;
514
515     //Set model in control.
516     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
517
518     //Update title.
519     mShapeTitle.SetProperty(TextLabel::Property::TEXT, SHAPE_TITLE_PREFIX + "Octahedron");
520   }
521
522   //Sets up the slider at the given index for the supplied property, and labels it appropriately.
523   // visualProperty is the property that will be set by this slider.
524   void SetupSlider(int sliderIndex, float lowerBound, float upperBound, float startPoint, Property::Index visualProperty, std::string visualPropertyLabel)
525   {
526     //Set up the slider itself.
527     mSliders.at(sliderIndex).RegisterProperty("visualProperty", Property::Value(visualProperty), Property::READ_WRITE);
528     mSliders.at(sliderIndex).SetProperty(Slider::Property::LOWER_BOUND, Property::Value(lowerBound));
529     mSliders.at(sliderIndex).SetProperty(Slider::Property::UPPER_BOUND, Property::Value(upperBound));
530     mSliders.at(sliderIndex).SetProperty(Slider::Property::VALUE, Property::Value(startPoint));
531     mSliders.at(sliderIndex).SetProperty(Actor::Property::VISIBLE, true);
532
533     //Label the slider with the property.
534     //We reset the TextLabel to force a relayout of the table.
535     mSliderTable.RemoveChildAt(TableView::CellPosition(sliderIndex, 0));
536
537     TextLabel sliderLabel = TextLabel::New(visualPropertyLabel);
538     sliderLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
539     sliderLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
540     sliderLabel.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
541
542     mSliderTable.AddChild(sliderLabel, TableView::CellPosition(sliderIndex, 0));
543     mSliderTable.SetCellAlignment(TableView::CellPosition(sliderIndex, 0), HorizontalAlignment::LEFT, VerticalAlignment::CENTER);
544
545     mSliderLabels.at(sliderIndex).SetProperty(Actor::Property::VISIBLE, true);
546     mSliderLabels.at(sliderIndex) = sliderLabel;
547   }
548
549   //Setup snapping to integer values between the two given values.
550   void SetupMarks(int sliderIndex, int lower, int upper)
551   {
552     Property::Array marks;
553
554     for(int mark = lower; mark <= upper; mark++)
555     {
556       marks.PushBack(Property::Value(mark));
557     }
558
559     mSliders.at(sliderIndex).SetProperty(Slider::Property::MARKS, Property::Value(marks));
560     mSliders.at(sliderIndex).SetProperty(Slider::Property::SNAP_TO_MARKS, Property::Value(true));
561   }
562
563   //When a shape button is tapped, switch to the corresponding shape.
564   bool OnChangeShapeClicked(Button button)
565   {
566     //Get the model number from the button.
567     int modelNumber;
568     button.GetProperty(button.GetPropertyIndex("modelNumber")).Get(modelNumber);
569
570     //Switch to the shape that corresponds to the model number.
571     switch(modelNumber)
572     {
573       case 0:
574       {
575         LoadSphere();
576         break;
577       }
578       case 1:
579       {
580         LoadCone();
581         break;
582       }
583       case 2:
584       {
585         LoadConicalFrustum();
586         break;
587       }
588       case 3:
589       {
590         LoadCylinder();
591         break;
592       }
593       case 4:
594       {
595         LoadCube();
596         break;
597       }
598       case 5:
599       {
600         LoadBevelledCube();
601         break;
602       }
603       case 6:
604       {
605         LoadOctahedron();
606         break;
607       }
608     }
609
610     return true;
611   }
612
613   //When the slider is adjusted, change the corresponding shape property accordingly.
614   bool OnSliderValueChanged(Slider slider, float value)
615   {
616     //Update property map to reflect the change to the specific visual property.
617     int visualProperty;
618     slider.GetProperty(slider.GetPropertyIndex("visualProperty")).Get(visualProperty);
619     mVisualMap[visualProperty] = value;
620
621     //Reload the model to display the change.
622     mModel.SetProperty(Control::Property::BACKGROUND, Property::Value(mVisualMap));
623
624     return true;
625   }
626
627   //Panning around the shape rotates it.
628   void OnPan(Actor actor, const PanGesture& gesture)
629   {
630     switch(gesture.GetState())
631     {
632       case GestureState::STARTED:
633       {
634         //Pause animation, as the gesture will be used to manually rotate the model
635         mRotationAnimation.Pause();
636
637         break;
638       }
639       case GestureState::CONTINUING:
640       {
641         //Rotate based off the gesture.
642         const Vector2& displacement = gesture.GetDisplacement();
643         mRotation.x -= displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
644         mRotation.y += displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
645         Quaternion rotation = Quaternion(Radian(mRotation.x), Vector3::XAXIS) *
646                               Quaternion(Radian(mRotation.y), Vector3::YAXIS);
647
648         mModel.SetProperty(Actor::Property::ORIENTATION, rotation);
649
650         break;
651       }
652       case GestureState::FINISHED:
653       {
654         //Return to automatic animation
655         mRotationAnimation.Play();
656
657         break;
658       }
659       case GestureState::CANCELLED:
660       {
661         //Return to automatic animation
662         mRotationAnimation.Play();
663
664         break;
665       }
666       default:
667       {
668         break;
669       }
670     }
671   }
672
673   //If escape or the back button is pressed, quit the application (and return to the launcher)
674   void OnKeyEvent(const KeyEvent& event)
675   {
676     if(event.GetState() == KeyEvent::DOWN)
677     {
678       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
679       {
680         mApplication.Quit();
681       }
682     }
683   }
684
685 private:
686   Application& mApplication;
687
688   std::vector<Slider>    mSliders;      ///< Holds the sliders on screen that each shape accesses.
689   std::vector<TextLabel> mSliderLabels; ///< Holds the labels to each slider.
690   TableView              mSliderTable;  ///< A table to layout the sliders next to their labels.
691
692   Property::Map mVisualMap;  ///< Property map to create a primitive visual.
693   Control       mModel;      ///< Control to house the primitive visual.
694   TextLabel     mShapeTitle; ///< Indicates what the currently selected shape is.
695
696   PanGestureDetector mPanGestureDetector; ///< Detects pan gestures for rotation of the model.
697   Animation          mRotationAnimation;  ///< Automatically rotates the model, unless it is being panned.
698
699   Vector4 mColor;    ///< Color to set all shapes.
700   Vector2 mRotation; ///< Keeps track of model rotation.
701 };
702
703 int DALI_EXPORT_API main(int argc, char** argv)
704 {
705   Application               application = Application::New(&argc, &argv);
706   PrimitiveShapesController test(application);
707   application.MainLoop();
708   return 0;
709 }