TextInput Popup scrolling fixed after GUI changes. GUI settings changed.
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-input / text-input-popup-impl.cpp
1 /*
2  * Copyright (c) 2014 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/integration-api/debug.h>
19
20 #include <dali-toolkit/internal/controls/text-input/text-input-popup-impl.h>
21 #include <dali-toolkit/public-api/controls/buttons/push-button.h>
22 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
23
24 #include <libintl.h>
25
26 using namespace std;
27 using namespace Dali;
28
29 #define GET_LOCALE_TEXT(string) dgettext("sys_string", string)
30
31 namespace
32 {
33 const Vector2 DEFAULT_POPUP_INDICATOR_OFFSET(0.0f, 60.0f);
34
35 // 1. For selection: should be above top of highlighted selection, or below bottom of highlighted selection + end handle.
36 // 2. For cursor: should be above top of cursor, or below bottom of cursor + grab handle.
37
38 /**
39  * Image resource paths
40  */
41 const std::string POPUP_BACKGROUND( DALI_IMAGE_DIR "popup_bubble_bg.#.png" );
42 const std::string POPUP_BACKGROUND_EFFECT( DALI_IMAGE_DIR "popup_bubble_bg_ef.#.png" );
43 const std::string POPUP_BACKGROUND_LINE( DALI_IMAGE_DIR "popup_bubble_bg_line.#.png" );
44
45 const std::string POPUP_TAIL_BOTTOM( DALI_IMAGE_DIR "popup_bubble_tail_bottom.png" );
46 const std::string POPUP_TAIL_BOTTOM_EFFECT( DALI_IMAGE_DIR "popup_bubble_tail_bottom_ef.png" );
47 const std::string POPUP_TAIL_BOTTOM_LINE( DALI_IMAGE_DIR "popup_bubble_tail_bottom_line.png" );
48 const std::string POPUP_TAIL_TOP( DALI_IMAGE_DIR "popup_bubble_tail_top.png" );
49 const std::string POPUP_TAIL_TOP_EFFECT( DALI_IMAGE_DIR "popup_bubble_tail_top_ef.png" );
50 const std::string POPUP_TAIL_TOP_LINE( DALI_IMAGE_DIR "popup_bubble_tail_top_line.png" );
51
52 const std::string OPTION_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" );
53 const std::string OPTION_ICON_COPY( DALI_IMAGE_DIR "copy_paste_icon_copy.png" );
54 const std::string OPTION_ICON_CUT( DALI_IMAGE_DIR "copy_paste_icon_cut.png" );
55 const std::string OPTION_ICON_PASTE( DALI_IMAGE_DIR "copy_paste_icon_paste.png" );
56 const std::string OPTION_ICON_SELECT( DALI_IMAGE_DIR "copy_paste_icon_select.png" );
57 const std::string OPTION_ICON_SELECT_ALL( DALI_IMAGE_DIR "copy_paste_icon_select_all.png" );
58
59 /**
60  * Constant values for building the GUI
61  */
62 const Vector4 POPUP_MARGIN( 14.0f, 14.0f, 14.0f, 14.0f );  ///< Margin around the popup visible background Image.
63 const Vector4 POPUP_BORDER( 2.0f, 2.0f, 2.0f, 2.0f );  ///< The Border of the popup.
64 const Vector2 POPUP_MIN_SIZE( 0.0f, 126.0f );  ///< The minimum size of the popup.
65 const Vector2 POPUP_MAX_SIZE( 720.0f, 126.0f );  ///< The maximum size of the popup.
66 const float POPUP_TAIL_Y_OFFSET( -2.25f );  ///< The y offset of the tail.
67 const Vector2 POPUP_TAIL_SIZE( 36.0f, 36.0f );  ///< The size of the tail.
68 const Vector2 POPUP_DIVIDER_SIZE( 1.0f, 126.0f );  ///< The size of the divider.
69
70 const Vector4 OPTION_PADDING( 16.0f, 16.0f, 24.0f, 19.0f );  ///< The padding within the option to position icon and text away from the border. The order is left, right, top and bottom
71 const Vector2 OPTION_MAX_SIZE( 220.0f, 126.0f );  ///< The maximum size of the option.
72 const Vector2 OPTION_MIN_SIZE( 128.0f, 126.0f );  ///< The minimum size of the option.
73 const Vector2 OPTION_ICON_SIZE( 45.0f, 45.0f );  ///< The size of the icon.
74 const Vector2 OPTION_TEXT_MIN_SIZE( 128.0f, 30.0f );  ///< The minimum size of the text.
75 const float OPTION_GAP_ICON_TEXT( 8.0f );  ///< The gap between the icon and the text
76
77 const float HIDE_POPUP_ANIMATION_DURATION( 0.2f );                            ///< Duration of popup hide animation in seconds.
78 const float SHOW_POPUP_ANIMATION_DURATION( 0.2f );                            ///< Duration of popup show animation in seconds.
79
80 /**
81  * Default Colors
82  */
83 const Vector4 DEFAULT_POPUP_BACKGROUND( Vector4( .20f, 0.29f, 0.44f, 1.0f ) );
84 const Vector4 DEFAULT_POPUP_BACKGROUND_PRESSED( Vector4( 0.07f, 0.10f, 0.17f, 1.0f ) );
85 const Vector4 DEFAULT_POPUP_LINE_COLOR( Vector4( 0.36f, 0.45f, 0.59f, 1.0f ) );
86 const Vector4 DEFAULT_OPTION_ICON( Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
87 const Vector4 DEFAULT_OPTION_ICON_PRESSED( Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
88 const Vector4 DEFAULT_OPTION_TEXT( Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
89 const Vector4 DEFAULT_OPTION_TEXT_PRESSED( Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
90
91 } // unnamed namespace
92
93 namespace Dali
94 {
95
96 namespace Toolkit
97 {
98
99 namespace Internal
100 {
101
102 const char* const TextInputPopup::SIGNAL_PRESSED = "pressed";
103 const char* const TextInputPopup::SIGNAL_HIDE_FINISHED = "hide-finished";
104 const char* const TextInputPopup::SIGNAL_SHOW_FINISHED = "show-finished";
105
106 const char* const TextInputPopup::OPTION_SELECT_WORD = "option-select_word";                       // "Select Word" popup option.
107 const char* const TextInputPopup::OPTION_SELECT_ALL("option-select_all");                          // "Select All" popup option.
108 const char* const TextInputPopup::OPTION_CUT("option-cut");                                        // "Cut" popup option.
109 const char* const TextInputPopup::OPTION_COPY("option-copy");                                      // "Copy" popup option.
110 const char* const TextInputPopup::OPTION_PASTE("option-paste");                                    // "Paste" popup option.
111 const char* const TextInputPopup::OPTION_CLIPBOARD("option-clipboard");                            // "Clipboard" popup option.
112
113 TextInputPopup::TextInputPopup()
114 : mState(StateHidden),
115   mRoot( Layer::New() ),
116   mButtons(),
117   mVisiblePopUpSize(),
118   mPopupTailXPosition( 0.0f ),
119   mContentSize(),
120   mBackgroundColor( DEFAULT_POPUP_BACKGROUND ),
121   mBackgroundPressedColor( DEFAULT_POPUP_BACKGROUND_PRESSED ),
122   mLineColor( DEFAULT_POPUP_LINE_COLOR ),
123   mIconColor( DEFAULT_OPTION_ICON ),
124   mIconPressedColor( DEFAULT_OPTION_ICON_PRESSED ),
125   mTextColor( DEFAULT_OPTION_TEXT ),
126   mTextPressedColor( DEFAULT_OPTION_TEXT_PRESSED ),
127   mSelectOptionPriority(1),
128   mSelectAllOptionPriority(2),
129   mCutOptionPriority(3),
130   mCopyOptionPriority(4),
131   mPasteOptionPriority(5),
132   mClipboardOptionPriority(6),
133   mPressedSignal(),
134   mHideFinishedSignal(),
135   mShowFinishedSignal()
136 {
137   mRoot.SetParentOrigin( ParentOrigin::TOP_LEFT );
138   mRoot.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
139 }
140
141 void TextInputPopup::AddToParent( Actor parent )
142 {
143   Actor existingParent = mRoot.GetParent();
144
145   if ( !existingParent )
146   {
147     parent.Add( mRoot );
148   }
149 }
150
151 void TextInputPopup::RemoveFromParent()
152 {
153   Actor parent = mRoot.GetParent();
154
155   if ( parent )
156   {
157     parent.Remove( mRoot );
158   }
159 }
160
161 void TextInputPopup::CreateLayer( const Vector2& size )
162 {
163   mLayer = Layer::New();
164   mLayer.SetParentOrigin(ParentOrigin::CENTER);
165   mLayer.SetAnchorPoint(AnchorPoint::CENTER);
166   mLayer.SetSize( size ); // matches stencil size
167   mLayer.SetName("popup-mLayer");
168 }
169
170 void TextInputPopup::CreateStencil( const Vector2& size )
171 {
172   mStencil = CreateSolidColorActor( Color::BLUE );
173   mStencil.SetParentOrigin( ParentOrigin::CENTER );
174   mStencil.SetAnchorPoint( AnchorPoint::CENTER );
175   mStencil.SetDrawMode( DrawMode::STENCIL );
176   mStencil.SetVisible( true );
177   mStencil.SetName( "popup-stencil" );
178   mStencil.SetSize( size );
179 }
180
181 void TextInputPopup::OnScrollStarted( const Vector3& position )
182 {
183   mButtons.SetSensitive( false );
184 }
185
186 void TextInputPopup::OnScrollCompleted( const Vector3& position )
187 {
188   mButtons.SetSensitive( true );
189 }
190
191 void TextInputPopup::CreateScrollView()
192 {
193   mScrollView = Toolkit::ScrollView::New();
194   mScrollView.SetName("popup-scroll-view");
195   mScrollView.SetAnchorPoint( AnchorPoint::CENTER );
196   mScrollView.SetParentOrigin( ParentOrigin::CENTER );
197   mScrollView.SetScrollingDirection( PanGestureDetector::DIRECTION_HORIZONTAL, Degree( 40.0f ) );
198   mScrollView.SetAxisAutoLock( true );
199   mScrollView.ScrollStartedSignal().Connect( this, &TextInputPopup::OnScrollStarted );
200   mScrollView.ScrollCompletedSignal().Connect( this, &TextInputPopup::OnScrollCompleted );
201 }
202
203 void TextInputPopup::UpdateScrollViewRulerAndSize( const Vector2& visibleSize )
204 {
205   mScrollView.SetSize( visibleSize.x, visibleSize.y );
206
207   RulerPtr rulerX = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
208   RulerPtr rulerY = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
209   rulerY->Disable();
210   rulerX->SetDomain( RulerDomain( 0, mContentSize.width, true ) );
211   mScrollView.SetRulerX(rulerX);
212   mScrollView.SetRulerY(rulerY);
213 }
214
215
216 void TextInputPopup::Clear()
217 {
218   if ( mBackground )
219   {
220     UnparentAndReset( mTail );
221     UnparentAndReset( mStencil );
222     UnparentAndReset( mBackground );
223     UnparentAndReset( mButtons );
224     UnparentAndReset( mScrollView );
225     mDividerContainer.clear();
226     RemoveFromParent();
227     mState = StateHidden;
228   }
229 }
230
231 ImageActor TextInputPopup::CreateOptionIcon( Image iconImage, const Vector4& color )
232 {
233   ImageActor icon = ImageActor::New( iconImage );
234   icon.SetSize( OPTION_ICON_SIZE );
235   icon.SetParentOrigin( ParentOrigin::TOP_CENTER );
236   icon.SetAnchorPoint( AnchorPoint::TOP_CENTER );
237   icon.SetColor( color );
238   icon.SetY( OPTION_PADDING.z - POPUP_BORDER.y );
239   return icon;
240 }
241
242 Toolkit::TextView TextInputPopup::CreateOptionCaption( const std::string& caption, const Vector4& color )
243 {
244   TextStyle style;
245   style.SetTextColor( color );
246
247   PointSize pointSize( Font::PixelsToPoints( OPTION_TEXT_MIN_SIZE.y ) );
248   style.SetFontPointSize( pointSize );
249
250   MarkupProcessor::StyledTextArray styledCaption;
251   styledCaption.push_back( MarkupProcessor::StyledText( Text( caption ), style ) );
252
253   Toolkit::TextView textView = Toolkit::TextView::New( styledCaption );
254   textView.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
255   textView.SetWidthExceedPolicy( Toolkit::TextView::EllipsizeEnd );
256   textView.SetHeightExceedPolicy( Toolkit::TextView::EllipsizeEnd );
257   textView.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
258   textView.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
259   textView.SetY( -OPTION_PADDING.w + POPUP_BORDER.w );
260
261   MarkupProcessor::StyledTextArray styledCaptionEllipsize;
262   MarkupProcessor::SetTextStyle( Text("..."), styledCaptionEllipsize, style );
263   textView.SetEllipsizeText( styledCaptionEllipsize );
264
265   const float textWidth = textView.GetWidthForHeight( OPTION_TEXT_MIN_SIZE.y );
266   textView.SetSize( textWidth, OPTION_TEXT_MIN_SIZE.y );
267
268   return textView;
269 }
270
271 void TextInputPopup::CreateBackground()
272 {
273   // Create background-panel if not already created (required if we have at least one option)
274   if ( !mBackground )
275   {
276     Image bgImg = Image::New( POPUP_BACKGROUND );
277     mBackground = ImageActor::New( bgImg );
278     mBackground.SetAnchorPoint( AnchorPoint::CENTER );
279     mBackground.SetParentOrigin( ParentOrigin::CENTER );
280     mBackground.SetName( "text-input-popup-background" );
281     mBackground.SetColor( mBackgroundColor );
282
283     Image bgEffectImg = Image::New( POPUP_BACKGROUND_EFFECT );
284     mBackgroundEffect = ImageActor::New( bgEffectImg );
285     mBackgroundEffect.SetAnchorPoint( AnchorPoint::CENTER );
286     mBackgroundEffect.SetParentOrigin( ParentOrigin::CENTER );
287     mBackgroundEffect.SetName( "text-input-popup-background-effect" );
288     mBackgroundEffect.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
289     mBackgroundEffect.SetZ( 1.0f );
290     mBackground.Add( mBackgroundEffect );
291
292     Image bgLine = Image::New( POPUP_BACKGROUND_LINE );
293     mBackgroundLine = ImageActor::New( bgLine );
294     mBackgroundLine.SetAnchorPoint( AnchorPoint::CENTER);
295     mBackgroundLine.SetParentOrigin( ParentOrigin::CENTER );
296     mBackgroundLine.SetName( "text-input-popup-background-effect" );
297     mBackgroundLine.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
298     mBackgroundLine.SetColor( mLineColor );
299     mBackgroundLine.SetZ( 0.1f );
300     mBackgroundEffect.Add( mBackgroundLine );
301
302     Hide(false);
303   }
304 }
305
306 void TextInputPopup::CreateTail()
307 {
308   if ( !mTail )
309   {
310     Image tail = Image::New( POPUP_TAIL_BOTTOM );
311     mTail = ImageActor::New( tail );
312     mTail.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
313     mTail.SetAnchorPoint( AnchorPoint::TOP_CENTER );
314     mTail.SetName( "text-input-popup-tail" );
315     mTail.SetPosition( 0.0f, POPUP_TAIL_Y_OFFSET - POPUP_BORDER.w, 1.2f );
316     mTail.SetColor( mBackgroundColor );
317
318     Image tailEffect = Image::New( POPUP_TAIL_BOTTOM_EFFECT );
319     mTailEffect = ImageActor::New( tailEffect );
320     mTailEffect.SetParentOrigin( ParentOrigin::CENTER );
321     mTailEffect.SetAnchorPoint( AnchorPoint::CENTER );
322     mTailEffect.SetName( "text-input-popup-tail-effect" );
323     mTailEffect.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
324     mTailEffect.SetZ( 0.1f );
325     mTail.Add( mTailEffect );
326
327     Image tailLine = Image::New( POPUP_TAIL_BOTTOM_LINE );
328     mTailLine = ImageActor::New( tailLine );
329     mTailLine.SetParentOrigin( ParentOrigin::CENTER );
330     mTailLine.SetAnchorPoint( AnchorPoint::CENTER );
331     mTailLine.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
332     mTailLine.SetName( "text-input-popup-tail-line" );
333     mTailLine.SetColor( mLineColor );
334     mTailLine.SetZ( 0.1f );
335     mTailEffect.Add( mTailLine );
336   }
337 }
338
339 ImageActor TextInputPopup::CreateDivider()
340 {
341   ImageActor divider = Toolkit::CreateSolidColorActor( mLineColor );
342   divider.SetParentOrigin( ParentOrigin::TOP_LEFT );
343   divider.SetAnchorPoint( AnchorPoint::TOP_LEFT );
344   divider.SetSize( POPUP_DIVIDER_SIZE.width , mContentSize.height );
345   divider.SetPosition( mContentSize.width - POPUP_DIVIDER_SIZE.width, 0.0f );
346
347   // Keep track of all the dividers. As their height's need to be updated to the max of all
348   // buttons currently added.
349   mDividerContainer.push_back( divider );
350
351   return divider;
352 }
353
354 ImageActor TextInputPopup::CreatePressedBackground( const Vector2& requiredSize )
355 {
356   ImageActor pressedBg = Toolkit::CreateSolidColorActor( mBackgroundPressedColor );
357   pressedBg.SetDrawMode( DrawMode::OVERLAY );
358   pressedBg.SetParentOrigin( ParentOrigin::CENTER );
359   pressedBg.SetAnchorPoint( AnchorPoint::CENTER );
360   pressedBg.SetSize( requiredSize );
361   return pressedBg;
362 }
363
364 TextInputPopup::ButtonRequirement TextInputPopup::CreateRequiredButton( TextInputPopup::Buttons buttonId, std::size_t orderOfPriority,
365                                                                         const std::string& name, const std::string& caption, Image iconImage, bool enabled )
366 {
367   TextInputPopup::ButtonRequirement currentButton;
368   currentButton.buttonId = buttonId;
369   currentButton.orderOfPriority = orderOfPriority;
370   currentButton.name = name;
371   currentButton.caption = caption;
372   currentButton.iconImage = iconImage;
373   currentButton.enabled = enabled;
374
375   return currentButton;
376 }
377
378 void TextInputPopup::CreateOrderedListOfOptions()
379 {
380   mOrderListOfButtons.clear();
381
382   for ( std::size_t index= 0; index < ButtonsEnumEnd; index++ )
383   {
384     TextInputPopup::ButtonRequirement currentButton;
385
386     // Create button for each possible option using Option priority
387     switch ( index )
388     {
389       case ButtonsCut:
390       {
391         Image cutIcon = Image::New( OPTION_ICON_CUT );
392         currentButton = CreateRequiredButton( ButtonsCut, mCutOptionPriority, OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), cutIcon, false );
393         break;
394       }
395       case ButtonsCopy:
396       {
397         Image copyIcon = Image::New( OPTION_ICON_COPY );
398         currentButton = CreateRequiredButton( ButtonsCopy, mCopyOptionPriority, OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), copyIcon, false );
399         break;
400       }
401       case ButtonsPaste:
402       {
403         Image pasteIcon = Image::New( OPTION_ICON_PASTE );
404         currentButton = CreateRequiredButton( ButtonsPaste, mPasteOptionPriority, OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon, false );
405         break;
406       }
407       case ButtonsSelect:
408       {
409         Image selectIcon = Image::New( OPTION_ICON_SELECT );
410         currentButton = CreateRequiredButton( ButtonsSelect, mSelectOptionPriority, OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), selectIcon, false );
411         break;
412       }
413       case ButtonsSelectAll:
414       {
415         Image selectAllIcon = Image::New( OPTION_ICON_SELECT_ALL );
416         currentButton = CreateRequiredButton( ButtonsSelectAll, mSelectAllOptionPriority, OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon, false );
417         break;
418       }
419       case ButtonsClipboard:
420       {
421         Image clipboardIcon = Image::New( OPTION_ICON_CLIPBOARD );
422         currentButton = CreateRequiredButton( ButtonsClipboard, mClipboardOptionPriority, OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, false );
423         break;
424       }
425       case ButtonsEnumEnd:
426       {
427         DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
428         currentButton.orderOfPriority = 0;
429         break;
430       }
431     }
432
433     bool match = false;
434
435     // Insert button in list of buttons in order of priority setting.
436     for( std::vector<ButtonRequirement>::iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt && !match ); ++it )
437     {
438       const ButtonRequirement& button( *it );
439       if ( currentButton.orderOfPriority < button.orderOfPriority )
440       {
441         if ( currentButton.orderOfPriority != 0 ) // If order priority 0 then do not add button as not required.
442         {
443           mOrderListOfButtons.insert( it, currentButton );
444         }
445         match = true;
446       }
447     }
448
449     if ( !match )
450     {
451       mOrderListOfButtons.push_back( currentButton );
452     }
453   }
454 }
455
456 Vector2 TextInputPopup::GetConstrainedTextSize( const Vector2& textSize )
457 {
458   return  Vector2( std::min( textSize.width, OPTION_MAX_SIZE.width - OPTION_PADDING.x - OPTION_PADDING.y ), textSize.height );
459 }
460
461 void TextInputPopup::AddOption(const std::string& name, const std::string& caption, const Image iconImage, bool finalOption)
462 {
463   // 1. Create container for text and icon when not pressed.
464   Actor optionContainer = Actor::New();
465   optionContainer.SetParentOrigin( ParentOrigin::TOP_LEFT );
466   optionContainer.SetAnchorPoint( AnchorPoint::TOP_LEFT );
467
468   // 2. Add text.
469   Toolkit::TextView captionTextView = CreateOptionCaption( caption, mTextColor );
470   optionContainer.Add( captionTextView );
471
472   // 3. Add icon.
473   ImageActor icon = CreateOptionIcon( iconImage, mIconColor );
474   optionContainer.Add( icon );
475
476   // 4. Calculate the size of option.
477   const Vector2 textSize = Vector2( captionTextView.GetNaturalSize() );
478   captionTextView.SetSize( GetConstrainedTextSize( textSize ) );
479
480
481   const Vector2 optionSize( std::max( textSize.x, OPTION_ICON_SIZE.x ) +  OPTION_PADDING.x + OPTION_PADDING.z,
482                             OPTION_PADDING.z + OPTION_ICON_SIZE.y + OPTION_GAP_ICON_TEXT + textSize.y + OPTION_MAX_SIZE.y );
483
484
485   Vector2 constrainedOptionSize = Min( Max( optionSize, OPTION_MIN_SIZE ), OPTION_MAX_SIZE );
486
487   constrainedOptionSize.height = constrainedOptionSize.height - POPUP_BORDER.y - POPUP_BORDER.z;
488
489   // 5. Create a option.
490   Toolkit::PushButton option = Toolkit::PushButton::New();
491   option.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
492   option.SetParentOrigin( ParentOrigin::TOP_LEFT );
493   option.SetAnchorPoint( AnchorPoint::TOP_LEFT );
494   option.SetSize( constrainedOptionSize );
495   option.SetX( mContentSize.x );
496   option.SetName( name );
497   option.SetAnimationTime( 0.0f );
498   option.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
499   mButtons.Add( option );
500
501   // 6. Set the normal option image.
502   option.SetButtonImage( optionContainer );
503
504   // 7. Update the content size.
505   mContentSize.x += constrainedOptionSize.x;
506   mContentSize.y = std::max ( constrainedOptionSize.y, mContentSize.y );
507
508   // 8. Create the pressed container.
509   Actor optionPressedContainer = Actor::New();
510
511   // 9. Add option pressed background.
512   Vector2 optionPressedBackgroundSize( constrainedOptionSize.x - POPUP_BORDER.x, mContentSize.y - POPUP_BORDER.y - POPUP_BORDER.w );
513   ImageActor optionPressedBackground = CreatePressedBackground( optionPressedBackgroundSize );
514   optionPressedContainer.Add( optionPressedBackground );
515
516   // 10. Add pressed text
517   Toolkit::TextView pressedCaptionTextView = CreateOptionCaption( caption, mTextPressedColor );
518   pressedCaptionTextView.SetSize( GetConstrainedTextSize( Vector2( pressedCaptionTextView.GetNaturalSize() ) ) );
519   optionPressedBackground.Add( pressedCaptionTextView );
520
521   // 11. Add pressed icon
522   ImageActor pressedIcon = CreateOptionIcon( iconImage, mIconPressedColor );
523   optionPressedBackground.Add( pressedIcon );
524
525   // 12. Set the pressed option image
526   option.SetPressedImage( optionPressedContainer );
527
528   // 13. Add the divider
529   if ( !finalOption )
530   {
531     ImageActor divider = CreateDivider();
532     mButtons.Add( divider );
533   }
534 }
535
536 void TextInputPopup::Hide(bool animate)
537 {
538   if( mRoot )
539   {
540     if(mAnimation)
541     {
542       mAnimation.Clear();
543       mAnimation.Reset();
544     }
545
546     if(animate)
547     {
548       mAnimation = Animation::New( HIDE_POPUP_ANIMATION_DURATION );
549       mAnimation.AnimateTo( Property(mRoot, Actor::SCALE), Vector3::ZERO, AlphaFunctions::EaseOut );
550       mAnimation.AnimateTo( Property(mRoot, Actor::COLOR_ALPHA), 0.0f, AlphaFunctions::EaseOut );
551       mAnimation.Play();
552
553       mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnHideFinished );
554       mState = StateHiding;
555     }
556     else
557     {
558       mRoot.SetProperty(Actor::SCALE, Vector3::ZERO);
559       mRoot.SetProperty(Actor::COLOR_ALPHA, 0.0f);
560       mState = StateHidden;
561     }
562   }
563 }
564
565 void TextInputPopup::Show( Actor target, bool animate )
566 {
567   if( mRoot )
568   {
569     mRoot.SetSensitive( true );
570
571     if(mAnimation)
572     {
573       mAnimation.Clear();
574       mAnimation.Reset();
575     }
576
577     if ( target )
578     {
579       AddToParent( target );
580     }
581
582     if(animate)
583     {
584       mAnimation = Animation::New( SHOW_POPUP_ANIMATION_DURATION );
585       mAnimation.AnimateTo( Property(mRoot, Actor::SCALE), Vector3::ONE, AlphaFunctions::EaseOut );
586       mAnimation.AnimateTo( Property(mRoot, Actor::COLOR_ALPHA), 1.0f, AlphaFunctions::EaseOut );
587       mAnimation.Play();
588
589       mAnimation.FinishedSignal().Connect( this, &TextInputPopup::OnShowFinished );
590       mState = StateShowing;
591     }
592     else
593     {
594       mRoot.SetProperty(Actor::SCALE, Vector3::ONE);
595       mRoot.SetProperty(Actor::COLOR_ALPHA, 1.0f);
596       mState = StateShown;
597     }
598   }
599 }
600
601 TextInputPopup::State TextInputPopup::GetState(void) const
602 {
603   return mState;
604 }
605
606 Actor TextInputPopup::GetRootActor() const
607 {
608   return mRoot;
609 }
610
611 // Styling
612
613 void TextInputPopup::SetCutPastePopupColor( const Vector4& color )
614 {
615   mBackgroundColor = color;
616 }
617
618 const Vector4& TextInputPopup::GetCutPastePopupColor() const
619 {
620   return mBackgroundColor;
621 }
622
623 void TextInputPopup::SetCutPastePopupPressedColor( const Vector4& color )
624 {
625   mBackgroundPressedColor = color;
626 }
627
628 const Vector4& TextInputPopup::GetCutPastePopupPressedColor() const
629 {
630   return mBackgroundPressedColor;
631 }
632
633 void TextInputPopup::SetCutPastePopupBorderColor( const Vector4& color )
634 {
635   mLineColor = color;
636 }
637
638 const Vector4& TextInputPopup::GetCutPastePopupBorderColor() const
639 {
640   return mLineColor;
641 }
642
643 void TextInputPopup::SetCutPastePopupIconColor( const Vector4& color )
644 {
645   mIconColor = color;
646 }
647
648 const Vector4& TextInputPopup::GetCutPastePopupIconColor() const
649 {
650   return mIconColor;
651 }
652
653 void TextInputPopup::SetCutPastePopupIconPressedColor( const Vector4& color )
654 {
655   mIconPressedColor = color;
656 }
657
658 const Vector4& TextInputPopup::GetCutPastePopupIconPressedColor()
659 {
660   return mIconPressedColor;
661 }
662
663 void TextInputPopup::SetCutPastePopupTextColor( const Vector4& color )
664 {
665   mTextColor = color;
666 }
667
668 const Vector4& TextInputPopup::GetCutPastePopupTextColor()
669 {
670   return mTextColor;
671 }
672
673 void TextInputPopup::SetCutPastePopupTextPressedColor( const Vector4& color )
674 {
675   mTextPressedColor = color;
676 }
677
678 const Vector4& TextInputPopup::GetCutPastePopupTextPressedColor()
679 {
680   return mTextPressedColor;
681 }
682
683 void TextInputPopup::TogglePopupButtonOnOff( TextInputPopup::Buttons requiredButton, bool enable )
684 {
685   bool match ( false );
686   for( std::vector<ButtonRequirement>::iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt && !match ); ++it )
687    {
688      ButtonRequirement& button( *it );
689      if ( requiredButton == button.buttonId )
690      {
691        button.enabled = enable;
692        match = true;
693      }
694    }
695 }
696
697 void TextInputPopup::SetButtonPriorityPosition( TextInputPopup::Buttons button, unsigned int priority )
698 {
699   switch ( button )
700   {
701     case ButtonsCut:
702     {
703       mCutOptionPriority = priority;
704       break;
705     }
706     case ButtonsCopy:
707     {
708       mCopyOptionPriority = priority;
709       break;
710     }
711     case ButtonsPaste:
712     {
713       mPasteOptionPriority = priority;
714       break;
715     }
716     case ButtonsSelect:
717     {
718       mSelectOptionPriority = priority;
719       break;
720     }
721     case ButtonsSelectAll:
722     {
723       mSelectAllOptionPriority = priority;
724       break;
725     }
726     case ButtonsClipboard:
727     {
728       mClipboardOptionPriority = priority;
729       break;
730     }
731     case ButtonsEnumEnd:
732     {
733       DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
734       break;
735     }
736   }
737   CreateOrderedListOfOptions(); // Update list of options as priority changed.
738 }
739
740 unsigned int TextInputPopup::GetButtonPriorityPosition( TextInputPopup::Buttons button ) const
741 {
742   unsigned int priority = 0;
743
744   switch ( button )
745   {
746     case ButtonsCut:
747     {
748       priority = mCutOptionPriority;
749       break;
750     }
751     case ButtonsCopy:
752     {
753       priority = mCopyOptionPriority;
754       break;
755     }
756     case ButtonsPaste:
757     {
758       priority = mPasteOptionPriority;
759       break;
760     }
761     case ButtonsSelect:
762     {
763       priority = mSelectOptionPriority;
764       break;
765     }
766     case ButtonsSelectAll:
767     {
768       priority = mSelectAllOptionPriority;
769       break;
770     }
771     case ButtonsClipboard:
772     {
773       priority = mClipboardOptionPriority;
774       break;
775     }
776     case ButtonsEnumEnd:
777     {
778       DALI_ASSERT_DEBUG( "ButtonsEnumEnd used but an invalid choice");
779       break;
780     }
781   }
782
783   return priority;
784 }
785
786 void TextInputPopup::AddPopupOptions()
787 {
788   mContentSize = Vector2( POPUP_MIN_SIZE.width, ( POPUP_BORDER.y + POPUP_BORDER.z ) );
789
790   // 1. Create the background.
791   CreateBackground();
792
793   // 2. Create the tail.
794   CreateTail();
795
796   // 3. Create the scroll view and Actor to hold buttons.
797   CreateScrollView();
798
799   // Clear previous buttons
800   if ( mButtons )
801   {
802     UnparentAndReset( mButtons );
803   }
804
805   mButtons = Actor::New();
806   mButtons.SetParentOrigin( ParentOrigin::CENTER );
807   mButtons.SetAnchorPoint( AnchorPoint::CENTER );
808
809   // 4. Create the options and add into the scroll view.
810   for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
811   {
812     const ButtonRequirement& button( *it );
813     if ( button.enabled )
814     {
815       AddOption( button.name, button.caption, button.iconImage, it != ( endIt - 1 ) ? false : true );
816     }
817   }
818
819   // 5. Calculate size of content and of popup including borders
820   const Vector2 popupSize = Vector2( std::min ( ( POPUP_BORDER.x + mContentSize.width + POPUP_BORDER.z ), POPUP_MAX_SIZE.width ) ,  POPUP_BORDER.y + mContentSize.height + POPUP_BORDER.w );
821
822   mVisiblePopUpSize = Vector3( popupSize.width - POPUP_BORDER.x - POPUP_BORDER.z , mContentSize.height, 1.0f);
823
824   mBackground.SetSize( popupSize.x + 28 - POPUP_BORDER.x - POPUP_BORDER.z, popupSize.y + 28 - POPUP_BORDER.y - POPUP_BORDER.w );
825   mButtons.SetSize( mVisiblePopUpSize.GetVectorXY() );
826
827   // 6. Set the scroll view ruler.
828   UpdateScrollViewRulerAndSize( mVisiblePopUpSize.GetVectorXY() );
829
830   // 7. Create stencil
831   const Vector2 stencilSize = Vector2( mVisiblePopUpSize.GetVectorXY() );
832
833   CreateLayer( stencilSize );
834   CreateStencil( stencilSize );
835
836   mScrollView.Add ( mButtons );
837   mLayer.Add( mScrollView);
838   mLayer.Add( mStencil);
839   mRoot.Add( mTail );
840   mRoot.Add( mBackground );
841   mRoot.Add( mLayer );
842
843   // 8. Set the root size.
844   mRoot.SetSize( popupSize );   // Make Root Actor reflect the size of its content
845 }
846
847 const Vector3& TextInputPopup::GetVisibileSize() const
848 {
849   return mVisiblePopUpSize;
850 }
851
852 void TextInputPopup::SetTailPosition( const Vector3& position, bool yAxisFlip )
853 {
854   mPopupTailXPosition = std::max(  position.x, POPUP_TAIL_SIZE.width*0.5f - mVisiblePopUpSize.width*0.5f + POPUP_BORDER.x );
855
856   std::min( mPopupTailXPosition, mVisiblePopUpSize.width*0.5f - POPUP_BORDER.x - POPUP_TAIL_SIZE.width*0.5f );
857
858   mTail.SetX( mPopupTailXPosition );
859
860   if ( yAxisFlip )
861   {
862     Image tail = Image::New( POPUP_TAIL_TOP );
863     Image tailEffect = Image::New( POPUP_TAIL_TOP_EFFECT );
864     Image tailLine = Image::New( POPUP_TAIL_TOP_LINE );
865
866     mTail.SetImage( tail );
867     mTailEffect.SetImage( tailEffect );
868     mTailLine.SetImage( tailLine );
869
870     mTail.SetParentOrigin( ParentOrigin::TOP_CENTER );
871     mTail.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
872     mTail.SetY( POPUP_BORDER.y - POPUP_TAIL_Y_OFFSET );
873   }
874 }
875
876 bool TextInputPopup::OnButtonPressed( Toolkit::Button button )
877 {
878   mPressedSignal.Emit( button );
879   return false;
880 }
881
882 void TextInputPopup::OnHideFinished(Animation& source)
883 {
884   source.FinishedSignal().Disconnect( this, &TextInputPopup::OnHideFinished );
885   Clear();
886   mState = StateHidden;
887   mHideFinishedSignal.Emit( *this );
888 }
889
890 void TextInputPopup::OnShowFinished(Animation& source)
891 {
892   source.FinishedSignal().Disconnect( this, &TextInputPopup::OnShowFinished );
893   mState = StateShown;
894   mShowFinishedSignal.Emit( *this );
895 }
896
897 TextInputPopup::PressedSignalV2& TextInputPopup::PressedSignal()
898 {
899   return mPressedSignal;
900 }
901
902 TextInputPopup::HideFinishedSignalV2& TextInputPopup::HideFinishedSignal()
903 {
904   return mHideFinishedSignal;
905 }
906
907 TextInputPopup::ShowFinishedSignalV2& TextInputPopup::ShowFinishedSignal()
908 {
909   return mShowFinishedSignal;
910 }
911
912 } // namespace Internal
913
914 } // namespace Toolkit
915
916 } // namespace Dali
917