Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / item-view / item-view-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 <sstream>
19 #include "shared/view.h"
20
21 #include <dali-toolkit/dali-toolkit.h>
22 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
23 #include <dali/dali.h>
24
25 using namespace Dali;
26 using namespace Dali::Toolkit;
27
28 namespace
29 {
30 enum AllImagesLayouts
31 {
32   SPIRAL_LAYOUT,
33   DEPTH_LAYOUT,
34   GRID_LAYOUT,
35
36   NUMBER_OF_LAYOUTS
37 };
38
39 const char* IMAGE_PATHS[] = {
40   DEMO_IMAGE_DIR "gallery-medium-1.jpg",
41   DEMO_IMAGE_DIR "gallery-medium-2.jpg",
42   DEMO_IMAGE_DIR "gallery-medium-3.jpg",
43   DEMO_IMAGE_DIR "gallery-medium-4.jpg",
44   DEMO_IMAGE_DIR "gallery-medium-5.jpg",
45   DEMO_IMAGE_DIR "gallery-medium-6.jpg",
46   DEMO_IMAGE_DIR "gallery-medium-7.jpg",
47   DEMO_IMAGE_DIR "gallery-medium-8.jpg",
48   DEMO_IMAGE_DIR "gallery-medium-9.jpg",
49   DEMO_IMAGE_DIR "gallery-medium-10.jpg",
50   DEMO_IMAGE_DIR "gallery-medium-11.jpg",
51   DEMO_IMAGE_DIR "gallery-medium-12.jpg",
52   DEMO_IMAGE_DIR "gallery-medium-13.jpg",
53   DEMO_IMAGE_DIR "gallery-medium-14.jpg",
54   DEMO_IMAGE_DIR "gallery-medium-15.jpg",
55   DEMO_IMAGE_DIR "gallery-medium-16.jpg",
56   DEMO_IMAGE_DIR "gallery-medium-17.jpg",
57   DEMO_IMAGE_DIR "gallery-medium-18.jpg",
58   DEMO_IMAGE_DIR "gallery-medium-19.jpg",
59   DEMO_IMAGE_DIR "gallery-medium-20.jpg",
60   DEMO_IMAGE_DIR "gallery-medium-21.jpg",
61   DEMO_IMAGE_DIR "gallery-medium-22.jpg",
62   DEMO_IMAGE_DIR "gallery-medium-23.jpg",
63   DEMO_IMAGE_DIR "gallery-medium-24.jpg",
64   DEMO_IMAGE_DIR "gallery-medium-25.jpg",
65   DEMO_IMAGE_DIR "gallery-medium-26.jpg",
66   DEMO_IMAGE_DIR "gallery-medium-27.jpg",
67   DEMO_IMAGE_DIR "gallery-medium-28.jpg",
68   DEMO_IMAGE_DIR "gallery-medium-29.jpg",
69   DEMO_IMAGE_DIR "gallery-medium-30.jpg",
70   DEMO_IMAGE_DIR "gallery-medium-31.jpg",
71   DEMO_IMAGE_DIR "gallery-medium-32.jpg",
72   DEMO_IMAGE_DIR "gallery-medium-33.jpg",
73   DEMO_IMAGE_DIR "gallery-medium-34.jpg",
74   DEMO_IMAGE_DIR "gallery-medium-35.jpg",
75   DEMO_IMAGE_DIR "gallery-medium-36.jpg",
76   DEMO_IMAGE_DIR "gallery-medium-37.jpg",
77   DEMO_IMAGE_DIR "gallery-medium-38.jpg",
78   DEMO_IMAGE_DIR "gallery-medium-39.jpg",
79   DEMO_IMAGE_DIR "gallery-medium-40.jpg",
80   DEMO_IMAGE_DIR "gallery-medium-41.jpg",
81   DEMO_IMAGE_DIR "gallery-medium-42.jpg",
82   DEMO_IMAGE_DIR "gallery-medium-43.jpg",
83   DEMO_IMAGE_DIR "gallery-medium-44.jpg",
84   DEMO_IMAGE_DIR "gallery-medium-45.jpg",
85   DEMO_IMAGE_DIR "gallery-medium-46.jpg",
86   DEMO_IMAGE_DIR "gallery-medium-47.jpg",
87   DEMO_IMAGE_DIR "gallery-medium-48.jpg",
88   DEMO_IMAGE_DIR "gallery-medium-49.jpg",
89   DEMO_IMAGE_DIR "gallery-medium-50.jpg",
90   DEMO_IMAGE_DIR "gallery-medium-51.jpg",
91   DEMO_IMAGE_DIR "gallery-medium-52.jpg",
92   DEMO_IMAGE_DIR "gallery-medium-53.jpg",
93 };
94
95 const unsigned int NUM_IMAGES = sizeof(IMAGE_PATHS) / sizeof(char*);
96
97 const char* BACKGROUND_IMAGE("");
98 const char* TOOLBAR_IMAGE(DEMO_IMAGE_DIR "top-bar.png");
99 const char* EDIT_IMAGE(DEMO_IMAGE_DIR "icon-edit.png");
100 const char* EDIT_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-edit-selected.png");
101 const char* SPIRAL_LAYOUT_IMAGE(DEMO_IMAGE_DIR "icon-item-view-layout-spiral.png");
102 const char* SPIRAL_LAYOUT_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-item-view-layout-spiral-selected.png");
103 const char* GRID_LAYOUT_IMAGE(DEMO_IMAGE_DIR "icon-item-view-layout-grid.png");
104 const char* GRID_LAYOUT_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-item-view-layout-grid-selected.png");
105 const char* DEPTH_LAYOUT_IMAGE(DEMO_IMAGE_DIR "icon-item-view-layout-depth.png");
106 const char* DEPTH_LAYOUT_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-item-view-layout-depth-selected.png");
107 const char* DELETE_IMAGE(DEMO_IMAGE_DIR "icon-delete.png");
108 const char* DELETE_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-delete-selected.png");
109 const char* REPLACE_IMAGE(DEMO_IMAGE_DIR "icon-replace.png");
110 const char* REPLACE_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-replace-selected.png");
111 const char* INSERT_IMAGE(DEMO_IMAGE_DIR "icon-insert.png");
112 const char* INSERT_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-insert-selected.png");
113 const char* SELECTED_IMAGE(DEMO_IMAGE_DIR "item-select-check.png");
114 const char* APPLICATION_TITLE("ItemView");
115
116 const char* SPIRAL_LABEL("Spiral");
117 const char* GRID_LABEL("Grid");
118 const char* DEPTH_LABEL("Depth");
119
120 const float ITEM_BORDER_SIZE = 2.0f;
121
122 const float DEPTH_LAYOUT_ITEM_SIZE_FACTOR_PORTRAIT  = 1.0f;
123 const float DEPTH_LAYOUT_ITEM_SIZE_FACTOR_LANDSCAPE = 0.8f;
124 const float DEPTH_LAYOUT_COLUMNS                    = 3.0f;
125
126 const float MIN_SWIPE_DISTANCE = 15.0f;
127 const float MIN_SWIPE_SPEED    = 5.0f;
128
129 const float SELECTION_BORDER_WIDTH = 3.0f;
130 const float BUTTON_BORDER          = -10.0f;
131 const float MENU_OPTION_HEIGHT(140.0f);
132 const float LABEL_TEXT_SIZE_Y = 20.0f;
133
134 const Vector3 INITIAL_OFFSCREEN_POSITION(1000.0f, 0, -1000.0f);
135
136 const float SCROLL_TO_ITEM_ANIMATION_TIME = 5.f;
137
138 static Vector3 DepthLayoutItemSizeFunctionPortrait(float layoutWidth)
139 {
140   float width = (layoutWidth / (DEPTH_LAYOUT_COLUMNS + 1.0f)) * DEPTH_LAYOUT_ITEM_SIZE_FACTOR_PORTRAIT;
141
142   // 1x1 aspect ratio
143   return Vector3(width, width, width);
144 }
145
146 static Vector3 DepthLayoutItemSizeFunctionLandscape(float layoutWidth)
147 {
148   float width = (layoutWidth / (DEPTH_LAYOUT_COLUMNS + 1.0f)) * DEPTH_LAYOUT_ITEM_SIZE_FACTOR_LANDSCAPE;
149
150   // 1x1 aspect ratio
151   return Vector3(width, width, width);
152 }
153
154 } // unnamed namespace
155
156 /**
157  * This example shows how to use ItemView UI control.
158  * There are three layouts created for ItemView, i.e., Spiral, Depth and Grid.
159  * There is one button in the upper-left corner for quitting the application and
160  * another button in the upper-right corner for switching between different layouts.
161  */
162 class ItemViewExample : public ConnectionTracker, public ItemFactory
163 {
164 public:
165   enum Mode
166   {
167     MODE_NORMAL,
168     MODE_REMOVE,
169     MODE_REMOVE_MANY,
170     MODE_INSERT,
171     MODE_INSERT_MANY,
172     MODE_REPLACE,
173     MODE_REPLACE_MANY,
174     MODE_LAST
175   };
176
177   /**
178    * Constructor
179    * @param application class, stored as reference
180    */
181   ItemViewExample(Application& application)
182   : mApplication(application),
183     mMode(MODE_NORMAL),
184     mOrientation(0),
185     mCurrentLayout(SPIRAL_LAYOUT),
186     mDurationSeconds(0.25f)
187   {
188     // Connect to the Application's Init signal
189     mApplication.InitSignal().Connect(this, &ItemViewExample::OnInit);
190   }
191
192   /**
193    * This method gets called once the main loop of application is up and running
194    */
195   void OnInit(Application& app)
196   {
197     Window window = app.GetWindow();
198     window.KeyEventSignal().Connect(this, &ItemViewExample::OnKeyEvent);
199     window.GetRootLayer().SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
200
201     Vector2 windowSize = window.GetSize();
202
203     // Creates a default view with a default tool bar.
204     // The view is added to the window.
205
206     Layer contents = DemoHelper::CreateView(mApplication,
207                                             mView,
208                                             mToolBar,
209                                             BACKGROUND_IMAGE,
210                                             TOOLBAR_IMAGE,
211                                             "");
212
213     // Create an edit mode button. (left of toolbar)
214     Toolkit::PushButton editButton = Toolkit::PushButton::New();
215     editButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, EDIT_IMAGE);
216     editButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, EDIT_IMAGE_SELECTED);
217     editButton.ClickedSignal().Connect(this, &ItemViewExample::OnModeButtonClicked);
218     editButton.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
219     mToolBar.AddControl(editButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_LEFT, DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
220
221     // Create a layout toggle button. (right of toolbar)
222     mLayoutButton = Toolkit::PushButton::New();
223     mLayoutButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, SPIRAL_LAYOUT_IMAGE);
224     mLayoutButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, SPIRAL_LAYOUT_IMAGE_SELECTED);
225     mLayoutButton.ClickedSignal().Connect(this, &ItemViewExample::OnLayoutButtonClicked);
226     mLayoutButton.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
227     mToolBar.AddControl(mLayoutButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_RIGHT, DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
228
229     // Create a delete button (bottom right of screen)
230     mDeleteButton = Toolkit::PushButton::New();
231     mDeleteButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_RIGHT);
232     mDeleteButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_RIGHT);
233     mDeleteButton.SetProperty(Actor::Property::POSITION, Vector2(BUTTON_BORDER, BUTTON_BORDER));
234     mDeleteButton.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
235     mDeleteButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, DELETE_IMAGE);
236     mDeleteButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, DELETE_IMAGE_SELECTED);
237     mDeleteButton.SetProperty(Toolkit::Control::Property::BACKGROUND, TOOLBAR_IMAGE);
238     mDeleteButton.SetProperty(Actor::Property::SIZE, Vector2(windowSize.width * 0.15f, windowSize.width * 0.15f));
239     mDeleteButton.ClickedSignal().Connect(this, &ItemViewExample::OnDeleteButtonClicked);
240     mDeleteButton.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
241     mDeleteButton.SetProperty(Actor::Property::VISIBLE, false);
242     window.Add(mDeleteButton);
243
244     // Create an insert button (bottom right of screen)
245     mInsertButton = Toolkit::PushButton::New();
246     mInsertButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_RIGHT);
247     mInsertButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_RIGHT);
248     mInsertButton.SetProperty(Actor::Property::POSITION, Vector2(BUTTON_BORDER, BUTTON_BORDER));
249     mInsertButton.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
250     mInsertButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, INSERT_IMAGE);
251     mInsertButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, INSERT_IMAGE_SELECTED);
252     mInsertButton.SetProperty(Toolkit::Control::Property::BACKGROUND, TOOLBAR_IMAGE);
253     mInsertButton.SetProperty(Actor::Property::SIZE, Vector2(windowSize.width * 0.15f, windowSize.width * 0.15f));
254     mInsertButton.ClickedSignal().Connect(this, &ItemViewExample::OnInsertButtonClicked);
255     mInsertButton.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
256     mInsertButton.SetProperty(Actor::Property::VISIBLE, false);
257     window.Add(mInsertButton);
258
259     // Create an replace button (bottom right of screen)
260     mReplaceButton = Toolkit::PushButton::New();
261     mReplaceButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_RIGHT);
262     mReplaceButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_RIGHT);
263     mReplaceButton.SetProperty(Actor::Property::POSITION, Vector2(BUTTON_BORDER, BUTTON_BORDER));
264     mReplaceButton.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
265     mReplaceButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, REPLACE_IMAGE);
266     mReplaceButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, REPLACE_IMAGE_SELECTED);
267     mReplaceButton.SetProperty(Toolkit::Control::Property::BACKGROUND, TOOLBAR_IMAGE);
268     mReplaceButton.SetProperty(Actor::Property::SIZE, Vector2(windowSize.width * 0.15f, windowSize.width * 0.15f));
269     mReplaceButton.ClickedSignal().Connect(this, &ItemViewExample::OnReplaceButtonClicked);
270     mReplaceButton.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
271     mReplaceButton.SetProperty(Actor::Property::VISIBLE, false);
272     window.Add(mReplaceButton);
273
274     // Create the item view actor
275     mItemView = ItemView::New(*this);
276     mItemView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
277     mItemView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
278
279     // Display item view on the window
280     window.Add(mItemView);
281     window.GetRootLayer().SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
282
283     // Create the layouts
284     mSpiralLayout = DefaultItemLayout::New(DefaultItemLayout::SPIRAL);
285     mDepthLayout  = DefaultItemLayout::New(DefaultItemLayout::DEPTH);
286     mGridLayout   = DefaultItemLayout::New(DefaultItemLayout::GRID);
287
288     // Add the layouts to item view
289     mItemView.AddLayout(*mSpiralLayout);
290     mItemView.AddLayout(*mDepthLayout);
291     mItemView.AddLayout(*mGridLayout);
292
293     mItemView.SetMinimumSwipeDistance(MIN_SWIPE_DISTANCE);
294     mItemView.SetMinimumSwipeSpeed(MIN_SWIPE_SPEED);
295
296     // Activate the spiral layout
297     SetLayout(mCurrentLayout);
298     mItemView.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
299     KeyboardFocusManager::Get().PreFocusChangeSignal().Connect(this, &ItemViewExample::OnKeyboardPreFocusChange);
300
301     // Set the title and icon to the current layout
302     SetLayoutTitle();
303     SetLayoutImage();
304
305     mLongPressDetector = LongPressGestureDetector::New();
306     mLongPressDetector.Attach(mItemView);
307     mLongPressDetector.DetectedSignal().Connect(this, &ItemViewExample::OnLongPress);
308   }
309
310   Actor OnKeyboardPreFocusChange(Actor current, Actor proposed, Control::KeyboardFocus::Direction direction)
311   {
312     if(!current && !proposed)
313     {
314       return mItemView;
315     }
316
317     return proposed;
318   }
319
320   /**
321    * Animate to a different layout
322    */
323   void ChangeLayout()
324   {
325     Animation animation = Animation::New(mDurationSeconds);
326     animation.FinishedSignal().Connect(this, &ItemViewExample::AnimationFinished);
327     animation.AnimateTo(Property(mItemView, Actor::Property::COLOR_ALPHA), 0.0f);
328     animation.Play();
329   }
330
331   void AnimationFinished(Animation&)
332   {
333     SetLayout(mCurrentLayout);
334
335     Animation animation = Animation::New(mDurationSeconds);
336     animation.AnimateTo(Property(mItemView, Actor::Property::COLOR_ALPHA), 1.0f);
337     animation.Play();
338   }
339
340   /**
341    * Switch to a different item view layout
342    */
343   void SetLayout(int layoutId)
344   {
345     Window window = mApplication.GetWindow();
346     switch(mCurrentLayout)
347     {
348       case SPIRAL_LAYOUT:
349       case DEPTH_LAYOUT:
350       {
351         window.GetRootLayer().SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
352         break;
353       }
354       case GRID_LAYOUT:
355       {
356         window.GetRootLayer().SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_UI);
357         break;
358       }
359     }
360
361     // Set the new orientation to the layout
362     mItemView.GetLayout(layoutId)->SetOrientation(static_cast<ControlOrientation::Type>(mOrientation / 90));
363
364     Vector2 windowSize = window.GetSize();
365
366     if(layoutId == DEPTH_LAYOUT)
367     {
368       // Set up the depth layout according to the new orientation
369       if(Toolkit::IsVertical(mDepthLayout->GetOrientation()))
370       {
371         mDepthLayout->SetItemSize(DepthLayoutItemSizeFunctionPortrait(windowSize.width));
372       }
373       else
374       {
375         mDepthLayout->SetItemSize(DepthLayoutItemSizeFunctionLandscape(windowSize.height));
376       }
377     }
378
379     // Enable anchoring for depth layout only
380     mItemView.SetAnchoring(layoutId == DEPTH_LAYOUT);
381
382     // Activate the layout
383     mItemView.ActivateLayout(layoutId, Vector3(windowSize.x, windowSize.y, windowSize.x), 0.0f);
384   }
385
386   bool OnLayoutButtonClicked(Toolkit::Button button)
387   {
388     // Switch to the next layout
389     mCurrentLayout = (mCurrentLayout + 1) % mItemView.GetLayoutCount();
390
391     ChangeLayout();
392
393     SetLayoutTitle();
394     SetLayoutImage();
395
396     return true;
397   }
398
399   bool OnModeButtonClicked(Toolkit::Button button)
400   {
401     SwitchToNextMode();
402
403     return true;
404   }
405
406   void SwitchToNextMode()
407   {
408     switch(mMode)
409     {
410       case MODE_REMOVE:
411       {
412         ExitRemoveMode();
413         mMode = MODE_REMOVE_MANY;
414         EnterRemoveManyMode();
415         break;
416       }
417
418       case MODE_REMOVE_MANY:
419       {
420         ExitRemoveManyMode();
421         mMode = MODE_INSERT;
422         EnterInsertMode();
423         break;
424       }
425
426       case MODE_INSERT:
427       {
428         ExitInsertMode();
429         mMode = MODE_INSERT_MANY;
430         EnterInsertManyMode();
431         break;
432       }
433
434       case MODE_INSERT_MANY:
435       {
436         ExitInsertManyMode();
437         mMode = MODE_REPLACE;
438         EnterReplaceMode();
439         break;
440       }
441
442       case MODE_REPLACE:
443       {
444         ExitReplaceMode();
445         mMode = MODE_REPLACE_MANY;
446         EnterReplaceManyMode();
447         break;
448       }
449
450       case MODE_REPLACE_MANY:
451       {
452         ExitReplaceManyMode();
453         mMode = MODE_NORMAL;
454         SetLayoutTitle();
455         break;
456       }
457
458       case MODE_NORMAL:
459       default:
460       {
461         mMode = MODE_REMOVE;
462         EnterRemoveMode();
463         break;
464       }
465     }
466   }
467
468   void EnterRemoveMode()
469   {
470     SetTitle("Edit: Remove");
471
472     mTapDetector = TapGestureDetector::New();
473
474     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
475     {
476       mTapDetector.Attach(mItemView.GetChildAt(i));
477     }
478
479     mTapDetector.DetectedSignal().Connect(this, &ItemViewExample::RemoveOnTap);
480   }
481
482   void ExitRemoveMode()
483   {
484     mTapDetector.Reset();
485   }
486
487   void RemoveOnTap(Actor actor, const TapGesture& tap)
488   {
489     mItemView.RemoveItem(mItemView.GetItemId(actor), 0.5f);
490   }
491
492   void EnterRemoveManyMode()
493   {
494     SetTitle("Edit: Remove Many");
495
496     mDeleteButton.SetProperty(Actor::Property::VISIBLE, true);
497
498     mTapDetector = TapGestureDetector::New();
499
500     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
501     {
502       Actor child = mItemView.GetChildAt(i);
503       Actor box   = child.FindChildByName("CheckBox");
504
505       if(box)
506       {
507         mTapDetector.Attach(child);
508         box.SetProperty(Actor::Property::VISIBLE, true);
509       }
510     }
511
512     mTapDetector.DetectedSignal().Connect(this, &ItemViewExample::SelectOnTap);
513   }
514
515   void ExitRemoveManyMode()
516   {
517     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
518     {
519       Actor child = mItemView.GetChildAt(i);
520       Actor box   = child.FindChildByName("CheckBox");
521
522       if(box)
523       {
524         box.SetProperty(Actor::Property::VISIBLE, false);
525
526         Actor tick = box.FindChildByName("Tick");
527         if(tick)
528         {
529           tick.SetProperty(Actor::Property::VISIBLE, false);
530         }
531       }
532     }
533
534     mTapDetector.Reset();
535
536     mDeleteButton.SetProperty(Actor::Property::VISIBLE, false);
537   }
538
539   void SelectOnTap(Actor actor, const TapGesture& tap)
540   {
541     Actor tick = actor.FindChildByName("Tick");
542     if(tick)
543     {
544       tick.SetProperty(Actor::Property::VISIBLE, !tick.GetCurrentProperty<bool>(Actor::Property::VISIBLE));
545     }
546   }
547
548   void OnLongPress(Actor actor, const LongPressGesture& gesture)
549   {
550     switch(gesture.GetState())
551     {
552       case GestureState::STARTED:
553       {
554         const Size& size = mApplication.GetWindow().GetSize();
555
556         ItemRange range(0u, 0u);
557         mItemView.GetItemsRange(range);
558
559         const unsigned int item = (gesture.GetScreenPoint().y < 0.5f * size.height) ? range.begin : range.end;
560         mItemView.ScrollToItem(item, SCROLL_TO_ITEM_ANIMATION_TIME);
561
562         break;
563       }
564       case GestureState::FINISHED:
565       {
566         Property::Map attributes;
567         mItemView.DoAction("stopScrolling", attributes);
568         break;
569       }
570       default:
571       {
572         break;
573       }
574     }
575   }
576
577   bool OnDeleteButtonClicked(Toolkit::Button button)
578   {
579     ItemIdContainer removeList;
580
581     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
582     {
583       Actor child = mItemView.GetChildAt(i);
584       Actor tick  = child.FindChildByName("Tick");
585
586       if(tick && tick.GetCurrentProperty<bool>(Actor::Property::VISIBLE))
587       {
588         removeList.push_back(mItemView.GetItemId(child));
589       }
590     }
591
592     if(!removeList.empty())
593     {
594       mItemView.RemoveItems(removeList, 0.5f);
595     }
596
597     return true;
598   }
599
600   void EnterInsertMode()
601   {
602     SetTitle("Edit: Insert");
603
604     mTapDetector = TapGestureDetector::New();
605
606     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
607     {
608       mTapDetector.Attach(mItemView.GetChildAt(i));
609     }
610
611     mTapDetector.DetectedSignal().Connect(this, &ItemViewExample::InsertOnTap);
612   }
613
614   void ExitInsertMode()
615   {
616     mTapDetector.Reset();
617   }
618
619   void InsertOnTap(Actor actor, const TapGesture& tap)
620   {
621     ItemId id = mItemView.GetItemId(actor);
622
623     Actor newActor = NewItem(rand());
624
625     mItemView.InsertItem(Item(id, newActor), 0.5f);
626   }
627
628   void EnterInsertManyMode()
629   {
630     SetTitle("Edit: Insert Many");
631
632     mInsertButton.SetProperty(Actor::Property::VISIBLE, true);
633
634     mTapDetector = TapGestureDetector::New();
635
636     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
637     {
638       Actor child = mItemView.GetChildAt(i);
639       Actor box   = child.FindChildByName("CheckBox");
640
641       if(box)
642       {
643         mTapDetector.Attach(child);
644         box.SetProperty(Actor::Property::VISIBLE, true);
645       }
646     }
647
648     mTapDetector.DetectedSignal().Connect(this, &ItemViewExample::SelectOnTap);
649   }
650
651   void ExitInsertManyMode()
652   {
653     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
654     {
655       Actor child = mItemView.GetChildAt(i);
656       Actor box   = child.FindChildByName("CheckBox");
657
658       if(box)
659       {
660         box.SetProperty(Actor::Property::VISIBLE, false);
661
662         Actor tick = box.FindChildByName("Tick");
663         if(tick)
664         {
665           tick.SetProperty(Actor::Property::VISIBLE, false);
666         }
667       }
668     }
669
670     mTapDetector.Reset();
671
672     mInsertButton.SetProperty(Actor::Property::VISIBLE, false);
673   }
674
675   bool OnInsertButtonClicked(Toolkit::Button button)
676   {
677     ItemContainer insertList;
678
679     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
680     {
681       Actor child = mItemView.GetChildAt(i);
682       Actor tick  = child.FindChildByName("Tick");
683
684       if(tick && tick.GetCurrentProperty<bool>(Actor::Property::VISIBLE))
685       {
686         insertList.push_back(Item(mItemView.GetItemId(child), NewItem(rand())));
687       }
688     }
689
690     if(!insertList.empty())
691     {
692       mItemView.InsertItems(insertList, 0.5f);
693     }
694
695     return true;
696   }
697
698   void EnterReplaceMode()
699   {
700     SetTitle("Edit: Replace");
701
702     mTapDetector = TapGestureDetector::New();
703
704     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
705     {
706       mTapDetector.Attach(mItemView.GetChildAt(i));
707     }
708
709     mTapDetector.DetectedSignal().Connect(this, &ItemViewExample::ReplaceOnTap);
710   }
711
712   void ReplaceOnTap(Actor actor, const TapGesture& tap)
713   {
714     mItemView.ReplaceItem(Item(mItemView.GetItemId(actor), NewItem(rand())), 0.5f);
715   }
716
717   void ExitReplaceMode()
718   {
719     mTapDetector.Reset();
720   }
721
722   void EnterReplaceManyMode()
723   {
724     SetTitle("Edit: Replace Many");
725
726     mReplaceButton.SetProperty(Actor::Property::VISIBLE, true);
727
728     mTapDetector = TapGestureDetector::New();
729
730     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
731     {
732       Actor child = mItemView.GetChildAt(i);
733       Actor box   = child.FindChildByName("CheckBox");
734
735       if(box)
736       {
737         mTapDetector.Attach(child);
738         box.SetProperty(Actor::Property::VISIBLE, true);
739       }
740     }
741
742     mTapDetector.DetectedSignal().Connect(this, &ItemViewExample::SelectOnTap);
743   }
744
745   void ExitReplaceManyMode()
746   {
747     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
748     {
749       Actor child = mItemView.GetChildAt(i);
750       Actor box   = child.FindChildByName("CheckBox");
751
752       if(box)
753       {
754         box.SetProperty(Actor::Property::VISIBLE, false);
755
756         Actor tick = box.FindChildByName("Tick");
757         if(tick)
758         {
759           tick.SetProperty(Actor::Property::VISIBLE, false);
760         }
761       }
762     }
763
764     mTapDetector.Reset();
765
766     mReplaceButton.SetProperty(Actor::Property::VISIBLE, false);
767   }
768
769   bool OnReplaceButtonClicked(Toolkit::Button button)
770   {
771     ItemContainer replaceList;
772
773     for(unsigned int i = 0u; i < mItemView.GetChildCount(); ++i)
774     {
775       Actor child = mItemView.GetChildAt(i);
776       Actor tick  = child.FindChildByName("Tick");
777
778       if(tick && tick.GetCurrentProperty<bool>(Actor::Property::VISIBLE))
779       {
780         replaceList.push_back(Item(mItemView.GetItemId(child), NewItem(rand())));
781       }
782     }
783
784     if(!replaceList.empty())
785     {
786       mItemView.ReplaceItems(replaceList, 0.5f);
787     }
788
789     return true;
790   }
791
792   void SetLayoutTitle()
793   {
794     if(MODE_NORMAL == mMode)
795     {
796       std::stringstream ss(APPLICATION_TITLE);
797       switch(mCurrentLayout)
798       {
799         case SPIRAL_LAYOUT:
800           ss << APPLICATION_TITLE << ": " << SPIRAL_LABEL;
801           break;
802         case GRID_LAYOUT:
803           ss << APPLICATION_TITLE << ": " << GRID_LABEL;
804           break;
805         case DEPTH_LAYOUT:
806           ss << APPLICATION_TITLE << ": " << DEPTH_LABEL;
807           break;
808         default:
809           break;
810       }
811       SetTitle(ss.str());
812     }
813   }
814
815   void SetLayoutImage()
816   {
817     if(mLayoutButton)
818     {
819       switch(mCurrentLayout)
820       {
821         case SPIRAL_LAYOUT:
822         {
823           mLayoutButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, SPIRAL_LAYOUT_IMAGE);
824           mLayoutButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, SPIRAL_LAYOUT_IMAGE_SELECTED);
825           break;
826         }
827
828         case GRID_LAYOUT:
829         {
830           mLayoutButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, GRID_LAYOUT_IMAGE);
831           mLayoutButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, GRID_LAYOUT_IMAGE_SELECTED);
832           break;
833         }
834
835         case DEPTH_LAYOUT:
836         {
837           mLayoutButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, DEPTH_LAYOUT_IMAGE);
838           mLayoutButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, DEPTH_LAYOUT_IMAGE_SELECTED);
839           break;
840         }
841
842         default:
843           break;
844       }
845     }
846   }
847
848 public: // From ItemFactory
849   /**
850    * Query the number of items available from the factory.
851    * The maximum available item has an ID of GetNumberOfItems() - 1.
852    */
853   virtual unsigned int GetNumberOfItems()
854   {
855     return NUM_IMAGES * 10;
856   }
857
858   /**
859    * Create an Actor to represent a visible item.
860    * @param itemId
861    * @return the created actor.
862    */
863   virtual Actor NewItem(unsigned int itemId)
864   {
865     // Create an image view for this item
866     Property::Map propertyMap;
867     propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
868     propertyMap.Insert(ImageVisual::Property::URL, IMAGE_PATHS[itemId % NUM_IMAGES]);
869     propertyMap.Insert(DevelVisual::Property::VISUAL_FITTING_MODE, DevelVisual::FILL);
870     ImageView actor = ImageView::New();
871     actor.SetProperty(Toolkit::ImageView::Property::IMAGE, propertyMap);
872     actor.SetProperty(Actor::Property::POSITION_Z, 0.0f);
873     actor.SetProperty(Actor::Property::POSITION, INITIAL_OFFSCREEN_POSITION);
874
875     // Add a border image child actor
876     ImageView borderActor = ImageView::New();
877     borderActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
878     borderActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
879     borderActor.SetResizePolicy(ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS);
880     borderActor.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(2.0f * ITEM_BORDER_SIZE, 2.0f * ITEM_BORDER_SIZE, 0.0f));
881     borderActor.SetProperty(Actor::Property::COLOR_MODE, USE_PARENT_COLOR);
882
883     Property::Map borderProperty;
884     borderProperty.Insert(Toolkit::Visual::Property::TYPE, Visual::BORDER);
885     borderProperty.Insert(BorderVisual::Property::COLOR, Color::WHITE);
886     borderProperty.Insert(BorderVisual::Property::SIZE, ITEM_BORDER_SIZE);
887     borderProperty.Insert(BorderVisual::Property::ANTI_ALIASING, true);
888     borderActor.SetProperty(ImageView::Property::IMAGE, borderProperty);
889
890     actor.Add(borderActor);
891
892     actor.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
893
894     Vector3 spiralItemSize;
895     Vector2 windowSize = mApplication.GetWindow().GetSize();
896     static_cast<ItemLayout&>(*mSpiralLayout).GetItemSize(0u, Vector3(windowSize), spiralItemSize);
897
898     // Add a checkbox child actor; invisible until edit-mode is enabled
899     ImageView checkbox = ImageView::New();
900     checkbox.SetProperty(Dali::Actor::Property::NAME, "CheckBox");
901     checkbox.SetProperty(Actor::Property::COLOR_MODE, USE_PARENT_COLOR);
902     checkbox.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_RIGHT);
903     checkbox.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_RIGHT);
904     checkbox.SetProperty(Actor::Property::SIZE, Vector2(spiralItemSize.width * 0.2f, spiralItemSize.width * 0.2f));
905     checkbox.SetProperty(Actor::Property::POSITION, Vector2(-SELECTION_BORDER_WIDTH, SELECTION_BORDER_WIDTH));
906     checkbox.SetProperty(Actor::Property::POSITION_Z, 0.1f);
907
908     Property::Map solidColorProperty;
909     solidColorProperty.Insert(Toolkit::Visual::Property::TYPE, Visual::COLOR);
910     solidColorProperty.Insert(ColorVisual::Property::MIX_COLOR, Vector4(0.f, 0.f, 0.f, 0.6f));
911     checkbox.SetProperty(ImageView::Property::IMAGE, solidColorProperty);
912
913     if(MODE_REMOVE_MANY != mMode &&
914        MODE_INSERT_MANY != mMode &&
915        MODE_REPLACE_MANY != mMode)
916     {
917       checkbox.SetProperty(Actor::Property::VISIBLE, false);
918     }
919     borderActor.Add(checkbox);
920
921     ImageView tick = ImageView::New(SELECTED_IMAGE);
922     tick.SetProperty(Dali::Actor::Property::NAME, "Tick");
923     tick.SetProperty(Actor::Property::COLOR_MODE, USE_PARENT_COLOR);
924     tick.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_RIGHT);
925     tick.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_RIGHT);
926     tick.SetProperty(Actor::Property::SIZE, Vector2(spiralItemSize.width * 0.2f, spiralItemSize.width * 0.2f));
927     tick.SetProperty(Actor::Property::POSITION_Z, 0.2f);
928     tick.SetProperty(Actor::Property::VISIBLE, false);
929     checkbox.Add(tick);
930
931     // Connect new items for various editing modes
932     if(mTapDetector)
933     {
934       mTapDetector.Attach(actor);
935     }
936
937     return actor;
938   }
939
940 private:
941   /**
942    * Sets/Updates the title of the View
943    * @param[in] title The new title for the view.
944    */
945   void SetTitle(const std::string& title)
946   {
947     if(!mTitleActor)
948     {
949       mTitleActor = DemoHelper::CreateToolBarLabel("");
950       // Add title to the tool bar.
951       mToolBar.AddControl(mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HORIZONTAL_CENTER);
952     }
953
954     mTitleActor.SetProperty(TextLabel::Property::TEXT, title);
955   }
956
957   /**
958    * Main key event handler
959    */
960   void OnKeyEvent(const KeyEvent& event)
961   {
962     if(event.GetState() == KeyEvent::DOWN)
963     {
964       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
965       {
966         mApplication.Quit();
967       }
968     }
969   }
970
971 private:
972   Application& mApplication;
973   Mode         mMode;
974
975   Toolkit::Control mView;
976   unsigned int     mOrientation;
977
978   Toolkit::ToolBar mToolBar;
979   TextLabel        mTitleActor; ///< The Toolbar's Title.
980
981   ItemView     mItemView;
982   unsigned int mCurrentLayout;
983   float        mDurationSeconds;
984
985   ItemLayoutPtr mSpiralLayout;
986   ItemLayoutPtr mDepthLayout;
987   ItemLayoutPtr mGridLayout;
988
989   TapGestureDetector  mTapDetector;
990   Toolkit::PushButton mLayoutButton;
991   Toolkit::PushButton mDeleteButton;
992   Toolkit::PushButton mInsertButton;
993   Toolkit::PushButton mReplaceButton;
994
995   LongPressGestureDetector mLongPressDetector;
996 };
997
998 int DALI_EXPORT_API main(int argc, char** argv)
999 {
1000   Application     app = Application::New(&argc, &argv, DEMO_THEME_PATH);
1001   ItemViewExample test(app);
1002   app.MainLoop();
1003   return 0;
1004 }