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