Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / text-label / text-label-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 /**
19  * @file text-label-example.cpp
20  * @brief Usage of TextLabel control with style application.
21  */
22
23 // EXTERNAL INCLUDES
24 #include <dali-toolkit/dali-toolkit.h>
25 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
26 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
27 #include <dali/devel-api/actors/actor-devel.h>
28 #include <dali/devel-api/object/handle-devel.h>
29 #include <iostream>
30
31 // INTERNAL INCLUDES
32 #include "expanding-buttons.h"
33 #include "shared/multi-language-strings.h"
34 #include "shared/view.h"
35
36 using namespace Dali;
37 using namespace Dali::Toolkit;
38 using namespace MultiLanguageStrings;
39
40 namespace
41 {
42 const char* const BACKGROUND_IMAGE     = DEMO_IMAGE_DIR "grab-handle.png";
43 const char* const STYLE_SELECTED_IMAGE = DEMO_IMAGE_DIR "FontStyleButton_OK_03.png";
44
45 const char* BUTTON_IMAGES[] =
46   {
47     DEMO_IMAGE_DIR "FontStyleButton_Colour.png",
48     DEMO_IMAGE_DIR "FontStyleButton_Outline.png",
49     DEMO_IMAGE_DIR "FontStyleButton_Shadow.png",
50     DEMO_IMAGE_DIR "FontStyleButton_Background.png"};
51
52 const unsigned int KEY_ZERO  = 10;
53 const unsigned int KEY_ONE   = 11;
54 const unsigned int KEY_A     = 38;
55 const unsigned int KEY_F     = 41;
56 const unsigned int KEY_H     = 43;
57 const unsigned int KEY_U     = 30;
58 const unsigned int KEY_V     = 55;
59 const unsigned int KEY_M     = 58;
60 const unsigned int KEY_L     = 46;
61 const unsigned int KEY_S     = 39;
62 const unsigned int KEY_PLUS  = 21;
63 const unsigned int KEY_MINUS = 20;
64
65 const char* H_ALIGNMENT_STRING_TABLE[] =
66   {
67     "BEGIN",
68     "CENTER",
69     "END"};
70
71 const unsigned int H_ALIGNMENT_STRING_COUNT = sizeof(H_ALIGNMENT_STRING_TABLE) / sizeof(H_ALIGNMENT_STRING_TABLE[0u]);
72
73 const char* V_ALIGNMENT_STRING_TABLE[] =
74   {
75     "TOP",
76     "CENTER",
77     "BOTTOM"};
78
79 const unsigned int V_ALIGNMENT_STRING_COUNT = sizeof(V_ALIGNMENT_STRING_TABLE) / sizeof(V_ALIGNMENT_STRING_TABLE[0u]);
80
81 enum StyleType
82 {
83   TEXT_COLOR = 0,
84   OUTLINE,
85   SHADOW,
86   BACKGROUND,
87   NUMBER_OF_STYLES
88 };
89
90 const Vector4 AVAILABLE_COLORS[] =
91   {
92     Color::GREEN,
93     Color::BLUE,
94     Color::RED,
95     Color::CYAN,
96     Color::WHITE // Used as clear
97 };
98
99 const unsigned int NUMBER_OF_COLORS = sizeof(AVAILABLE_COLORS) / sizeof(AVAILABLE_COLORS[0u]);
100
101 int ConvertToEven(int value)
102 {
103   return (value % 2 == 0) ? value : (value + 1);
104 }
105
106 struct HSVColorConstraint
107 {
108   HSVColorConstraint(float hue, float saturation, float value)
109   : hue(hue),
110     saturation(saturation),
111     value(value)
112   {
113   }
114
115   void operator()(Vector3& current, const PropertyInputContainer& inputs)
116   {
117     current = hsv2rgb(Vector3(inputs[0]->GetFloat(), saturation, value));
118   }
119
120   Vector3 hsv2rgb(Vector3 colorHSV)
121   {
122     float r = colorHSV.z * (1 + colorHSV.y * (cos(colorHSV.x) - 1));
123     float g = colorHSV.z * (1 + colorHSV.y * (cos(colorHSV.x - 2.09439) - 1));
124     float b = colorHSV.z * (1 + colorHSV.y * (cos(colorHSV.x + 2.09439) - 1));
125     return Vector3(r, g, b);
126   }
127   float hue;
128   float saturation;
129   float value;
130 };
131
132 const float   STYLE_BUTTON_POSTION_RELATIVE_TO_WINDOW = 0.9f;
133 const float   BUTTON_SIZE_RATIO_TO_WINDOW             = 0.1f;
134 const float   OUTLINE_WIDTH                           = 2.0f;
135 const Vector2 SHADOW_OFFSET                           = Vector2(2.0f, 2.0f);
136 const int     GAP_BETWEEN_BUTTONS                     = 3;
137
138 } // anonymous namespace
139
140 /**
141  * @brief The main class of the demo.
142  */
143 class TextLabelExample : public ConnectionTracker
144 {
145 public:
146   TextLabelExample(Application& application)
147   : mApplication(application),
148     mLabel(),
149     mSelectedColor(AVAILABLE_COLORS[0]),
150     mStyleActivatedForColor(NUMBER_OF_STYLES),
151     mContainer(),
152     mGrabCorner(),
153     mBorder(),
154     mPanGestureDetector(),
155     mLayoutSize(),
156     mLanguageId(0u),
157     mAlignment(0u),
158     mHueAngleIndex(Property::INVALID_INDEX),
159     mOverrideMixColorIndex(Property::INVALID_INDEX),
160     mColorButtonsHidden(true),
161     mCollapseColorsAndStyles(false)
162   {
163     // Connect to the Application's Init signal
164     mApplication.InitSignal().Connect(this, &TextLabelExample::Create);
165
166     // Set Style flags to inactive
167     for(unsigned int i = TEXT_COLOR; i < NUMBER_OF_STYLES; i++)
168     {
169       mStyleActiveState[i]  = false;
170       mCurrentStyleColor[i] = AVAILABLE_COLORS[NUMBER_OF_COLORS - 1];
171     }
172   }
173
174   ~TextLabelExample()
175   {
176     // Nothing to do here.
177   }
178
179   // Clicking the expanding button shows the registered style buttons.
180   void SetUpExpandingStyleButtons(Vector2 position)
181   {
182     mExpandingButtons = Demo::ExpandingButtons::New();
183     mExpandingButtons.SetProperty(Actor::Property::POSITION, Vector2(mButtonSize.width, mWindowSize.height * STYLE_BUTTON_POSTION_RELATIVE_TO_WINDOW));
184     mExpandingButtons.CollapsingSignal().Connect(this, &TextLabelExample::OnExpandingButtonCollapsing);
185     mExpandingButtons.SetProperty(Actor::Property::SIZE, mButtonSize);
186     // Creates the buttons to be expanded
187     CreateStyleButtons();
188
189     // Register the created buttons with the ExpandingButtons.
190     for(unsigned int index = 0; index < NUMBER_OF_STYLES; index++)
191     {
192       mExpandingButtons.RegisterButton(mStyleButtons[index]);
193     }
194   }
195
196   /**
197    * One-time setup in response to Application InitSignal.
198    */
199   void Create(Application& application)
200   {
201     Window window = application.GetWindow();
202
203     window.KeyEventSignal().Connect(this, &TextLabelExample::OnKeyEvent);
204     mWindowSize = window.GetSize();
205     mButtonSize = Size(mWindowSize.height * 0.1, mWindowSize.height * 0.1); // Button size 1/10 of window height
206
207     mContainer = Control::New();
208     mContainer.SetProperty(Dali::Actor::Property::NAME, "Container");
209     mContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
210     mLayoutSize = Vector2(mWindowSize.width * 0.6f, mWindowSize.width * 0.6f);
211     mContainer.SetProperty(Actor::Property::SIZE, mLayoutSize);
212     window.Add(mContainer);
213
214     // Resize the center layout when the corner is grabbed
215     mGrabCorner = ImageView::New(BACKGROUND_IMAGE);
216     mGrabCorner.SetProperty(Dali::Actor::Property::NAME, "GrabCorner");
217     mGrabCorner.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
218     mGrabCorner.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_RIGHT);
219     mGrabCorner.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
220     mContainer.Add(mGrabCorner);
221
222     mPanGestureDetector = PanGestureDetector::New();
223     mPanGestureDetector.Attach(mGrabCorner);
224     mPanGestureDetector.DetectedSignal().Connect(this, &TextLabelExample::OnPan);
225
226     mLabel = TextLabel::New("\xF0\x9F\x98\x89 A Quick Brown Fox Jumps Over The Lazy Dog");
227
228     mLabel.SetProperty(Dali::Actor::Property::NAME, "TextLabel");
229     mLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
230     mLabel.SetProperty(Actor::Property::SIZE, mLayoutSize);
231     mLabel.SetProperty(TextLabel::Property::MULTI_LINE, true);
232     mLabel.SetProperty(TextLabel::Property::TEXT_COLOR, Color::GREEN);
233     mLabel.SetBackgroundColor(Color::WHITE);
234     mContainer.Add(mLabel);
235
236     // Clicking ExpandingButton shows the Registered Style buttons, clicking again hides them.
237     Vector2 expandingButtonPosition(mButtonSize.width, mWindowSize.height * STYLE_BUTTON_POSTION_RELATIVE_TO_WINDOW);
238     SetUpExpandingStyleButtons(expandingButtonPosition);
239     window.Add(mExpandingButtons);
240
241     // Add a border for the container so you can see the container is being resized while grabbing the handle.
242     mBorder = Control::New();
243     mBorder.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
244     mBorder.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
245     mBorder.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT);
246
247     Dali::Property::Map border;
248     border.Insert(Toolkit::Visual::Property::TYPE, Visual::BORDER);
249     border.Insert(BorderVisual::Property::COLOR, Color::WHITE);
250     border.Insert(BorderVisual::Property::SIZE, 3.f);
251     mBorder.SetProperty(Control::Property::BACKGROUND, border);
252     mContainer.Add(mBorder);
253     mBorder.SetProperty(Actor::Property::VISIBLE, false);
254     mGrabCorner.RaiseToTop();
255
256     mHueAngleIndex         = mLabel.RegisterProperty("hue", 0.0f);
257     Renderer bgRenderer    = mLabel.GetRendererAt(0);
258     mOverrideMixColorIndex = bgRenderer.GetPropertyIndex(ColorVisual::Property::MIX_COLOR);
259
260     Constraint constraint = Constraint::New<Vector3>(bgRenderer, mOverrideMixColorIndex, HSVColorConstraint(0.0f, 0.5f, 0.8f));
261     constraint.AddSource(Source(mLabel, mHueAngleIndex));
262     constraint.SetRemoveAction(Constraint::DISCARD);
263     constraint.Apply();
264
265     Animation anim = Animation::New(50.0f);
266     anim.AnimateTo(Property(mLabel, mHueAngleIndex), 6.28318f);
267     anim.SetLooping(true);
268     anim.Play();
269
270     mContainer.RaiseToTop();
271     mGrabCorner.RaiseToTop();
272
273     Property::Value labelText = mLabel.GetProperty(TextLabel::Property::TEXT);
274     std::cout << "Displaying text: \"" << labelText.Get<std::string>() << "\"" << std::endl;
275   }
276
277   // If the styling buttons should colapse (hide) then the color buttons should also hide.
278   bool OnExpandingButtonCollapsing(Demo::ExpandingButtons button)
279   {
280     mCollapseColorsAndStyles = true;
281     HideColorButtons();
282     return true;
283   }
284
285   // Get the style type from the given button
286   StyleType GetStyleTypeFromButton(Toolkit::Button button)
287   {
288     StyleType style = StyleType::TEXT_COLOR;
289
290     if(button == mStyleButtons[StyleType::OUTLINE])
291     {
292       style = StyleType::OUTLINE;
293     }
294     else if(button == mStyleButtons[StyleType::SHADOW])
295     {
296       style = StyleType::SHADOW;
297     }
298     else if(button == mStyleButtons[StyleType::BACKGROUND])
299     {
300       style = StyleType::BACKGROUND;
301     }
302     return style;
303   }
304
305   // Style selected, show color buttons
306   bool OnStyleButtonClicked(Toolkit::Button button)
307   {
308     StyleType selectedStyle = GetStyleTypeFromButton(button);
309     if(mStyleActivatedForColor == selectedStyle)
310     {
311       HideColorButtons();
312     }
313     else
314     {
315       ResetColorButtons(mColorButtons, NUMBER_OF_COLORS);
316       ShowColorButtons(selectedStyle);
317     }
318     return true;
319   }
320
321   // Set style to selected color
322   bool OnColorSelected(Toolkit::Button button)
323   {
324     for(unsigned int index = 0; index < NUMBER_OF_COLORS; index++)
325     {
326       if(mColorButtons[index] == button)
327       {
328         mSelectedColor = AVAILABLE_COLORS[index];
329       }
330     }
331
332     switch(mStyleActivatedForColor)
333     {
334       case TEXT_COLOR:
335       {
336         Animation animation = Animation::New(1.f);
337         animation.AnimateTo(Property(mLabel, TextLabel::Property::TEXT_COLOR), mSelectedColor, AlphaFunction::LINEAR);
338         mCurrentStyleColor[TEXT_COLOR] = mSelectedColor;
339         animation.Play();
340         break;
341       }
342       case OUTLINE:
343       {
344         Property::Map outlineMap;
345         float         outlineWidth = OUTLINE_WIDTH;
346
347         if(mStyleActiveState[OUTLINE])
348         {
349           outlineWidth = (Color::WHITE == mSelectedColor) ? 0.0f : OUTLINE_WIDTH; // toggles outline on/off
350         }
351         mStyleActiveState[OUTLINE] = (outlineWidth > 0.0f) ? true : false;
352
353         outlineMap["color"]         = mSelectedColor;
354         outlineMap["width"]         = outlineWidth;
355         mCurrentStyleColor[OUTLINE] = mSelectedColor;
356         mLabel.SetProperty(TextLabel::Property::OUTLINE, outlineMap);
357         break;
358       }
359       case SHADOW:
360       {
361         Vector2         shadowOffset(SHADOW_OFFSET); // Will be set to zeros if color already set
362         Property::Value value = mLabel.GetProperty(TextLabel::Property::SHADOW);
363         Vector4         currentShadowColor;
364         value.Get(currentShadowColor);
365
366         if(mStyleActiveState[SHADOW])
367         {
368           // toggle shadow off ( zero offset ) if color is already set
369           shadowOffset = (Color::WHITE == mSelectedColor) ? Vector2::ZERO : Vector2(SHADOW_OFFSET);
370         }
371
372         mStyleActiveState[SHADOW]  = (shadowOffset == Vector2::ZERO) ? false : true;
373         mCurrentStyleColor[SHADOW] = mSelectedColor;
374
375         Property::Map shadowMap;
376         shadowMap.Insert("offset", shadowOffset);
377         shadowMap.Insert("color", mSelectedColor);
378         mLabel.SetProperty(TextLabel::Property::SHADOW, shadowMap);
379
380         break;
381       }
382       case BACKGROUND:
383       {
384         Property::Map backgroundMap;
385         auto          backgroundEnabled(true);
386
387         if(mStyleActiveState[BACKGROUND])
388         {
389           backgroundEnabled = (Color::WHITE != mSelectedColor); // toggles background on/off
390         }
391         mStyleActiveState[BACKGROUND] = backgroundEnabled;
392
393         backgroundMap["color"]         = mSelectedColor;
394         backgroundMap["enable"]        = backgroundEnabled;
395         mCurrentStyleColor[BACKGROUND] = mSelectedColor;
396         mLabel.SetProperty(DevelTextLabel::Property::BACKGROUND, backgroundMap);
397
398         break;
399       }
400       default:
401         break;
402     }
403
404     return true;
405   }
406
407   // Set the inital color button that should be be selected.
408   // If the style already has a color set then that should be used
409   void SetInitialSelectedColorButton(StyleType styleButtonIndex)
410   {
411     Vector4 selectedColor = mCurrentStyleColor[styleButtonIndex];
412
413     for(unsigned int i = 0; i < NUMBER_OF_COLORS; i++)
414     {
415       if(AVAILABLE_COLORS[i] == selectedColor)
416       {
417         if(mColorButtons[i])
418         {
419           mColorButtons[i].SetProperty(Toolkit::Button::Property::SELECTED, true);
420         }
421         break;
422       }
423     }
424   }
425
426   // Create a bar of color buttons that the user can select.
427   void ShowColorButtons(StyleType styleButtonIndex)
428   {
429     mCollapseColorsAndStyles = false; // Request to show colors so reset flag
430     mStyleActivatedForColor  = styleButtonIndex;
431
432     for(unsigned int index = 0; index < NUMBER_OF_COLORS; index++)
433     {
434       if(!mColorButtonsAnimation)
435       {
436         mColorButtonsAnimation = Animation::New(0.15f);
437         mColorButtonsAnimation.FinishedSignal().Connect(this, &TextLabelExample::OnColorButtonAnimationFinished);
438       }
439
440       // Create a color button
441       if(!mColorButtons[index])
442       {
443         mColorButtons[index] = RadioButton::New();
444         mColorButtons[index].SetProperty(Actor::Property::SIZE, mButtonSize);
445         mColorButtons[index].ClickedSignal().Connect(this, &TextLabelExample::OnColorSelected);
446         mColorButtons[index].SetProperty(Button::Property::TOGGLABLE, true);
447         Property::Map propertyMap;
448         propertyMap.Insert(Visual::Property::TYPE, Visual::COLOR);
449         propertyMap.Insert(ColorVisual::Property::MIX_COLOR, AVAILABLE_COLORS[index]);
450         mColorButtons[index].SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, propertyMap);
451         mColorButtons[index].SetProperty(Toolkit::Button::Property::UNSELECTED_VISUAL, propertyMap);
452         mColorButtons[index].SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
453         mColorButtons[index].SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
454
455         propertyMap.Insert(Visual::Property::TYPE, Visual::COLOR);
456         propertyMap.Insert(ColorVisual::Property::MIX_COLOR, AVAILABLE_COLORS[index]);
457         mColorButtons[index].SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, propertyMap);
458
459         mColorButtons[index].SetProperty(Toolkit::Button::Property::SELECTED_VISUAL,
460                                          Property::Map().Add(Visual::Property::TYPE, Visual::BORDER).Add(BorderVisual::Property::COLOR, Color::WHITE).Add(BorderVisual::Property::SIZE, 4.0f).Add(BorderVisual::Property::ANTI_ALIASING, true));
461
462         // Use a white button with 50% transparency as a clear color button
463         if(Color::WHITE == AVAILABLE_COLORS[index] && styleButtonIndex != StyleType::TEXT_COLOR)
464         {
465           mColorButtons[index].SetProperty(Actor::Property::OPACITY, 0.5f);
466
467           mColorButtons[index].SetProperty(Toolkit::Button::Property::LABEL,
468                                            Property::Map().Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT).Add(Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT, HorizontalAlignment::CENTER).Add(Toolkit::TextVisual::Property::TEXT, "off"));
469         }
470       }
471
472       SetInitialSelectedColorButton(mStyleActivatedForColor);
473
474       mColorButtons[index].Unparent();
475
476       mStyleButtons[styleButtonIndex].Add(mColorButtons[index]);
477       mColorButtons[index].Lower();
478
479       // Position button using nice animation
480       mColorButtons[index].SetProperty(Actor::Property::POSITION_Y, -GAP_BETWEEN_BUTTONS);
481       float         desiredPosition      = -(mButtonSize.height + GAP_BETWEEN_BUTTONS) * (index);
482       AlphaFunction focusedAlphaFunction = AlphaFunction(Vector2(0.32f, 0.08f), Vector2(0.38f, 1.72f));
483       mColorButtonsAnimation.AnimateBy(Property(mColorButtons[index], Actor::Property::POSITION_Y), desiredPosition, focusedAlphaFunction);
484     }
485
486     mColorButtonsHidden = false;
487     mColorButtonsAnimation.Play();
488   }
489
490   // Remove the color buttons when not being shown.
491   void ResetColorButtons(Button buttons[], unsigned int numberOfButtons)
492   {
493     for(unsigned int index = 0; index < numberOfButtons; index++)
494     {
495       UnparentAndReset(buttons[index]);
496     }
497   }
498
499   void OnColorButtonAnimationFinished(Animation& animation)
500   {
501     animation.Clear();
502     if(mColorButtonsHidden)
503     {
504       ResetColorButtons(mColorButtons, NUMBER_OF_COLORS);
505       animation.Reset(); // Handle reset
506       if(mCollapseColorsAndStyles)
507       {
508         mExpandingButtons.Collapse();
509       }
510     }
511   }
512
513   // Create the style buttons that will expand from the expanding button.
514   void CreateStyleButtons()
515   {
516     for(unsigned int index = 0; index < NUMBER_OF_STYLES; index++)
517     {
518       if(!mStyleButtons[index])
519       {
520         mStyleButtons[index] = PushButton::New();
521         mStyleButtons[index].SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, BUTTON_IMAGES[index]);
522         mStyleButtons[index].SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, STYLE_SELECTED_IMAGE);
523         mStyleButtons[index].SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
524         mStyleButtons[index].SetProperty(Actor::Property::SIZE, mButtonSize);
525         mStyleButtons[index].ClickedSignal().Connect(this, &TextLabelExample::OnStyleButtonClicked);
526       }
527     }
528   }
529
530   // Animate away the color bar.
531   void HideColorButtons()
532   {
533     if(!mColorButtonsHidden)
534     {
535       for(unsigned int index = 0; index < NUMBER_OF_COLORS; index++)
536       {
537         mColorButtonsAnimation.AnimateTo(Property(mColorButtons[index], Actor::Property::POSITION_Y), 0.0f);
538       }
539       mColorButtonsHidden = true;
540       mColorButtonsAnimation.Play();
541     }
542     mStyleActivatedForColor = NUMBER_OF_STYLES;
543   }
544
545   //  Request the expanding button to collapse.
546   void HideStyleAndColorButtons()
547   {
548     mCollapseColorsAndStyles = true;
549     if(mColorButtonsHidden)
550     {
551       mExpandingButtons.Collapse();
552     }
553     else
554     {
555       HideColorButtons();
556     }
557   }
558
559   // Resize the text-label with pan gesture
560   void OnPan(Actor actor, const PanGesture& gesture)
561   {
562     // Reset mLayoutSize when the pan starts
563     GestureState state = gesture.GetState();
564     if(state == GestureState::STARTED)
565     {
566       if(mLayoutSize.x < 2.0f)
567       {
568         mLayoutSize.x = 2.0f;
569       }
570
571       if(mLayoutSize.y < 2.0f)
572       {
573         mLayoutSize.y = 2.0f;
574       }
575
576       // Only show the border during the panning
577       mBorder.SetProperty(Actor::Property::VISIBLE, true);
578
579       HideStyleAndColorButtons();
580     }
581
582     const Vector2& displacement = gesture.GetDisplacement();
583     mLayoutSize.x += displacement.x * 2.0f;
584     mLayoutSize.y += displacement.y * 2.0f;
585
586     if(mLayoutSize.x >= 2.0f ||
587        mLayoutSize.y >= 2.0f)
588     {
589       mLayoutSize.x = std::min(mLayoutSize.x, mWindowSize.width);
590       mLayoutSize.y = std::min(mLayoutSize.y, mWindowSize.height * .9f);
591
592       // Avoid pixel mis-alignment issue
593       Vector2 clampedSize = Vector2(std::max(ConvertToEven(static_cast<int>(mLayoutSize.x)), 2),
594                                     std::max(ConvertToEven(static_cast<int>(mLayoutSize.y)), 2));
595
596       mContainer.SetProperty(Actor::Property::SIZE, clampedSize);
597     }
598
599     if(state == GestureState::CANCELLED || state == GestureState::FINISHED)
600     {
601       // Resize the text label to match the container size when panning is finished
602       mLabel.SetProperty(Actor::Property::SIZE, mLayoutSize);
603       mBorder.SetProperty(Actor::Property::VISIBLE, false);
604     }
605   }
606
607   /**
608    * Main key event handler
609    */
610   void OnKeyEvent(const KeyEvent& event)
611   {
612     if(event.GetState() == KeyEvent::DOWN)
613     {
614       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
615       {
616         mApplication.Quit();
617       }
618       else if(event.IsCtrlModifier())
619       {
620         switch(event.GetKeyCode())
621         {
622           // Select rendering back-end
623           case KEY_ZERO: // fall through
624           case KEY_ONE:
625           {
626             mLabel.SetProperty(DevelTextLabel::Property::RENDERING_BACKEND, event.GetKeyCode() - 10);
627             break;
628           }
629           case KEY_A: // Animate text colour
630           {
631             Animation animation = Animation::New(2.f);
632             animation.AnimateTo(Property(mLabel, TextLabel::Property::TEXT_COLOR), Color::RED, AlphaFunction::SIN);
633             animation.SetLoopCount(3);
634             animation.Play();
635             break;
636           }
637           case KEY_F: // Fill vertically
638           {
639             if(ResizePolicy::DIMENSION_DEPENDENCY == mLabel.GetResizePolicy(Dimension::HEIGHT))
640             {
641               mLabel.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT);
642             }
643             else
644             {
645               mLabel.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT);
646             }
647             break;
648           }
649           case KEY_H: // Horizontal alignment
650           {
651             if(++mAlignment >= H_ALIGNMENT_STRING_COUNT)
652             {
653               mAlignment = 0u;
654             }
655
656             mLabel.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, H_ALIGNMENT_STRING_TABLE[mAlignment]);
657             break;
658           }
659           case KEY_V: // Vertical alignment
660           {
661             if(++mAlignment >= V_ALIGNMENT_STRING_COUNT)
662             {
663               mAlignment = 0u;
664             }
665
666             mLabel.SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, V_ALIGNMENT_STRING_TABLE[mAlignment]);
667             break;
668           }
669           case KEY_M: // Multi-line
670           {
671             bool multiLine = mLabel.GetProperty<bool>(TextLabel::Property::MULTI_LINE);
672             mLabel.SetProperty(TextLabel::Property::MULTI_LINE, !multiLine);
673             break;
674           }
675           case KEY_L: // Language
676           {
677             const Language& language = LANGUAGES[mLanguageId];
678
679             mLabel.SetProperty(TextLabel::Property::TEXT, language.text);
680
681             if(++mLanguageId >= NUMBER_OF_LANGUAGES)
682             {
683               mLanguageId = 0u;
684             }
685             break;
686           }
687           case KEY_S: // Shadow color
688           {
689             Property::Value value = mLabel.GetProperty(TextLabel::Property::SHADOW);
690             Vector4         shadowColor;
691             value.Get(shadowColor);
692             Property::Map shadowMap;
693             if(Color::BLACK == shadowColor)
694             {
695               shadowMap.Insert("color", Color::RED);
696               mLabel.SetProperty(TextLabel::Property::SHADOW, shadowMap);
697             }
698             else
699             {
700               shadowMap.Insert("color", Color::BLACK);
701               mLabel.SetProperty(TextLabel::Property::SHADOW, shadowMap);
702             }
703             break;
704           }
705           case KEY_U: // Markup
706           {
707             mLabel.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
708             mLabel.SetProperty(TextLabel::Property::TEXT, "<font family='DejaVuSerif' size='18'>H<color value='blue'>ello</color> <font weight='bold'>world</font> demo</font>");
709             break;
710           }
711           case KEY_PLUS: // Increase shadow offset
712           {
713             Property::Value value = mLabel.GetProperty(TextLabel::Property::SHADOW);
714             Vector2         shadowOffset;
715             value.Get(shadowOffset);
716             shadowOffset += Vector2(1.0f, 1.0f);
717
718             Property::Map shadowMap;
719             shadowMap.Insert("offset", shadowOffset);
720             mLabel.SetProperty(TextLabel::Property::SHADOW, shadowMap);
721             break;
722           }
723           case KEY_MINUS: // Decrease shadow offset
724           {
725             Property::Value value = mLabel.GetProperty(TextLabel::Property::SHADOW);
726             Vector2         shadowOffset;
727             value.Get(shadowOffset);
728             shadowOffset -= Vector2(1.0f, 1.0f);
729
730             Property::Map shadowMap;
731             shadowMap.Insert("offset", shadowOffset);
732             mLabel.SetProperty(TextLabel::Property::SHADOW, shadowMap);
733             break;
734           }
735         }
736       }
737     }
738   }
739
740 private:
741   Application& mApplication;
742
743   TextLabel mLabel;
744
745   Demo::ExpandingButtons mExpandingButtons;
746   PushButton             mStyleButtons[NUMBER_OF_STYLES];
747   bool                   mStyleActiveState[NUMBER_OF_STYLES];
748
749   Vector4 mCurrentStyleColor[NUMBER_OF_STYLES];
750
751   Vector4 mSelectedColor;
752
753   Button mColorButtons[NUMBER_OF_COLORS];
754
755   StyleType mStyleActivatedForColor; // The style that the color bar is connected to
756
757   Control mContainer;
758   Control mGrabCorner;
759   Control mBorder;
760
761   PanGestureDetector mPanGestureDetector;
762
763   Vector2 mLayoutSize;
764
765   Animation mColorButtonsAnimation;
766
767   Size mWindowSize;
768   Size mButtonSize;
769
770   unsigned int    mLanguageId;
771   unsigned int    mAlignment;
772   Property::Index mHueAngleIndex;
773   Property::Index mOverrideMixColorIndex;
774
775   bool mColorButtonsHidden;
776   bool mCollapseColorsAndStyles;
777 };
778
779 int DALI_EXPORT_API main(int argc, char** argv)
780 {
781   Application      application = Application::New(&argc, &argv, DEMO_THEME_PATH);
782   TextLabelExample test(application);
783   application.MainLoop();
784   return 0;
785 }