X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Fdecorator%2Ftext-decorator.cpp;h=4cff45440da2f31d1ff000461d67b9188dceb8e3;hb=5a984a1705bf94f17a8ef6a05ce170d1a47e49b1;hp=5b5ba836448e85aaed020e6d8de732e06bc8bdc1;hpb=830f03638ec6ecd3b12ba3d9eb6419fdb3a3db09;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/text/decorator/text-decorator.cpp b/dali-toolkit/internal/text/decorator/text-decorator.cpp index 5b5ba83..4cff454 100644 --- a/dali-toolkit/internal/text/decorator/text-decorator.cpp +++ b/dali-toolkit/internal/text/decorator/text-decorator.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -32,16 +31,25 @@ #include #include #include +#include #include +#include // INTERNAL INCLUDES #include #include +#include +#include +#include +#include #ifdef DEBUG_ENABLED #define DECORATOR_DEBUG #endif +// todo Move this to adaptor?? +#define GET_LOCALE_TEXT(string) dgettext("elementary", string) + // Local Data namespace { @@ -51,7 +59,6 @@ const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-h const char* DEFAULT_SELECTION_HANDLE_TWO( DALI_IMAGE_DIR "text-input-selection-handle-right.png" ); //const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-left-press.png" ); //const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" ); -const char* DEFAULT_CURSOR_IMAGE( DALI_IMAGE_DIR "decorator-cursor.png"); const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f ); const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f ); @@ -59,6 +66,100 @@ const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f ); const std::size_t CURSOR_BLINK_INTERVAL = 500; // Cursor blink interval const std::size_t MILLISECONDS = 1000; +const std::string POPUP_BACKGROUND( DALI_IMAGE_DIR "popup_bubble_bg.#.png" ); +const std::string POPUP_BACKGROUND_EFFECT( DALI_IMAGE_DIR "popup_bubble_bg_ef.#.png" ); +const std::string POPUP_BACKGROUND_LINE( DALI_IMAGE_DIR "popup_bubble_bg_line.#.png" ); + +const Dali::Vector4 DEFAULT_POPUP_BACKGROUND( Dali::Vector4( .20f, 0.29f, 0.44f, 1.0f ) ); +const Dali::Vector4 DEFAULT_POPUP_BACKGROUND_PRESSED( Dali::Vector4( 0.07f, 0.10f, 0.17f, 1.0f ) ); +const Dali::Vector4 DEFAULT_POPUP_LINE_COLOR( Dali::Vector4( 0.36f, 0.45f, 0.59f, 1.0f ) ); +const Dali::Vector4 DEFAULT_OPTION_ICON( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); +const Dali::Vector4 DEFAULT_OPTION_ICON_PRESSED( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); +const Dali::Vector4 DEFAULT_OPTION_TEXT( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); +const Dali::Vector4 DEFAULT_OPTION_TEXT_PRESSED( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); + +const std::string OPTION_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" ); +const std::string OPTION_ICON_COPY( DALI_IMAGE_DIR "copy_paste_icon_copy.png" ); +const std::string OPTION_ICON_CUT( DALI_IMAGE_DIR "copy_paste_icon_cut.png" ); +const std::string OPTION_ICON_PASTE( DALI_IMAGE_DIR "copy_paste_icon_paste.png" ); +const std::string OPTION_ICON_SELECT( DALI_IMAGE_DIR "copy_paste_icon_select.png" ); +const std::string OPTION_ICON_SELECT_ALL( DALI_IMAGE_DIR "copy_paste_icon_select_all.png" ); + +const Dali::Vector2 DEFAULT_POPUP_MAX_SIZE( 470.0f, 120.0f ); ///< The maximum size of the popup. + +const float OPTION_TEXT_LINE_HEIGHT( 32.0f ); ///< The line height of the text. +const Dali::Vector2 OPTION_ICON_SIZE( 0.f, 0.f ); ///< The size of the icon. +const float OPTION_GAP_ICON_TEXT( 6.f ); ///< The gap between the icon and the text +const float OPTION_MARGIN_WIDTH( 10.f ); ///< The margin between the right or lefts edge and the text or icon. +const float OPTION_MAX_WIDTH( DEFAULT_POPUP_MAX_SIZE.width / 6 ); ///< The maximum width of the option (currently set to the max) +const float OPTION_MIN_WIDTH( 86.0f ); ///< The minimum width of the option. + +const float POPUP_DIVIDER_WIDTH( 1.f ); ///< The size of the divider. + +const Dali::Vector2 POPUP_TAIL_SIZE( 20.0f, 16.0f ); ///< The size of the tail. +const float POPUP_TAIL_Y_OFFSET( 5.f ); ///< The y offset of the tail (when its position is on the bottom). +const float POPUP_TAIL_TOP_Y_OFFSET( 3.f ); ///< The y offset of the tail (when its position is on the top). + +const float HIDE_POPUP_ANIMATION_DURATION( 0.2f ); ///< Duration of popup hide animation in seconds. +const float SHOW_POPUP_ANIMATION_DURATION( 0.2f ); ///< Duration of popup show animation in seconds. + +const char* const OPTION_SELECT_WORD = "option-select_word"; // "Select Word" popup option. +const char* const OPTION_SELECT_ALL("option-select_all"); // "Select All" popup option. +const char* const OPTION_CUT("option-cut"); // "Cut" popup option. +const char* const OPTION_COPY("option-copy"); // "Copy" popup option. +const char* const OPTION_PASTE("option-paste"); // "Paste" popup option. +const char* const OPTION_CLIPBOARD("option-clipboard"); // "Clipboard" popup option. + +enum Buttons +{ + ButtonsCut, + ButtonsCopy, + ButtonsPaste, + ButtonsSelect, + ButtonsSelectAll, + ButtonsClipboard, + ButtonsEnumEnd +}; + +struct ButtonRequirement +{ + ButtonRequirement() + : id( ButtonsEnumEnd ), + priority( 0u ), + name(), + caption(), + icon(), + enabled( false ) + {} + + ButtonRequirement( Buttons buttonId, + std::size_t buttonPriority, + const std::string& buttonName, + const std::string& buttonCaption, + Dali::ResourceImage buttonIcon, + bool buttonEnabled ) + : id( buttonId ), + priority( buttonPriority ), + name( buttonName ), + caption( buttonCaption ), + icon( buttonIcon ), + enabled( buttonEnabled ) + {} + + Buttons id; + std::size_t priority; + std::string name; + std::string caption; + Dali::ResourceImage icon; + bool enabled; +}; + +// Comparison function for ButtonRequirement Priority +bool PriorityCompare( ButtonRequirement const& a, ButtonRequirement const& b) +{ + return a.priority < b.priority; +} + } // end of namespace namespace Dali @@ -111,12 +212,68 @@ struct Decorator::Impl : public ConnectionTracker Image releasedImage; }; + struct PopupImpl + { + PopupImpl() + : mVisiblePopUpSize( Vector2( 100.0f, 100.0f ) ), + mRequiredPopUpSize( Vector2( 100.0f, 100.0f ) ), + mMaxWidth( DEFAULT_POPUP_MAX_SIZE.width ), + mBackgroundColor( DEFAULT_POPUP_BACKGROUND ), + mBackgroundPressedColor( DEFAULT_POPUP_BACKGROUND_PRESSED ), + mLineColor( DEFAULT_POPUP_LINE_COLOR ), + mIconColor( DEFAULT_OPTION_ICON ), + mIconPressedColor( DEFAULT_OPTION_ICON_PRESSED ), + mTextColor( DEFAULT_OPTION_TEXT ), + mTextPressedColor( DEFAULT_OPTION_TEXT_PRESSED ) + { + } + + Actor mRoot; // The actor which all popup content is added to (i.e. panel and buttons) + Actor mButtons; // Actor which holds all the buttons, sensitivity can be set oActor buttons via this actor + Layer mStencilLayer; // Layer to enable clipping when buttons exceed popup + ImageActor mBackground; // The background popup panel + ImageActor mTail; // The tail for the popup + ImageActor mTailEffect; // the tail effect + ImageActor mTailLine; // The border/outline around the tail + + Size mVisiblePopUpSize; // Visible Size of popup excluding content that needs scrolling. + Size mRequiredPopUpSize; // Total size of popup including any invisible margin + float mMaxWidth; // Max width of the Popup + + Vector4 mNinePatchMargins; // Margins between the edge of the cropped image and the nine patch rect (left, right, top, bottom). + + Size mContentSize; // Size of Content (i.e. Buttons) + //Animation mAnimation; // Popup Hide/Show animation. + + std::vector mOrderListOfButtons; // List of buttons in the order to be displayed and a flag to indicate if needed. + + Vector4 mBackgroundColor; // Color of the background of the text input popup + Vector4 mBackgroundPressedColor; // Color of the option background. + Vector4 mLineColor; // Color of the line around the text input popup + Vector4 mIconColor; // Color of the popup icon. + Vector4 mIconPressedColor; // Color of the popup icon when pressed. + Vector4 mTextColor; // Color of the popup text. + Vector4 mTextPressedColor; // Color of the popup text when pressed. + + // Priority of Options/Buttons in the Cut and Paste pop-up, higher priority buttons are displayed first, left to right. + std::size_t mSelectOptionPriority; // Position of Select Button + std::size_t mSelectAllOptionPriority; // Position of Select All button + std::size_t mCutOptionPriority; // Position of Cut button + std::size_t mCopyOptionPriority; // Position of Copy button + std::size_t mPasteOptionPriority; // Position of Paste button + std::size_t mClipboardOptionPriority; // Position of Clipboard button + + bool mShowIcons; // Flag to show icons + }; + + Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer ) - : mParent(parent), + : mTextControlParent(parent), mObserver(observer), mActiveCursor(ACTIVE_CURSOR_NONE), mActiveGrabHandle(false), mActiveSelection( false ), + mActiveCopyPastePopup( false ), mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ), mCursorBlinkDuration( 0.0f ), mCursorBlinkStatus( true ), @@ -130,19 +287,35 @@ struct Decorator::Impl : public ConnectionTracker * Relayout of the decorations owned by the decorator. * @param[in] size The Size of the UI control the decorater is adding it's decorations to. */ - void Relayout( const Vector2& size ) + void Relayout( const Vector2& size, const Vector2& scrollPosition ) { - SetCursors(); + // TODO - Remove this if nothing is active + CreateActiveLayer(); + + // Show or hide the cursors + CreateCursors(); + if( mPrimaryCursor ) + { + mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x, + mCursor[PRIMARY_CURSOR].y + scrollPosition.y ); + mPrimaryCursor.SetSize( 1.0f, mCursor[PRIMARY_CURSOR].height ); + } + if( mSecondaryCursor ) + { + mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].x + scrollPosition.x, + mCursor[SECONDARY_CURSOR].y + scrollPosition.y ); + mSecondaryCursor.SetSize( 1.0f, mCursor[SECONDARY_CURSOR].height ); + } // Show or hide the grab handle if( mActiveGrabHandle ) { SetupTouchEvents(); - CreateActiveLayer(); CreateGrabHandle(); - mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].x, mCursor[PRIMARY_CURSOR].y + mCursor[PRIMARY_CURSOR].height ); + mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].x + scrollPosition.x, + mCursor[PRIMARY_CURSOR].y + scrollPosition.y + mCursor[PRIMARY_CURSOR].height ); } else if( mGrabHandle ) { @@ -154,14 +327,15 @@ struct Decorator::Impl : public ConnectionTracker { SetupTouchEvents(); - CreateActiveLayer(); CreateSelectionHandles(); SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ]; - primary.actor.SetPosition( primary.x, primary.y + primary.cursorHeight ); + primary.actor.SetPosition( primary.x + scrollPosition.x, + primary.y + scrollPosition.y + primary.cursorHeight ); SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ]; - secondary.actor.SetPosition( secondary.x, secondary.y + secondary.cursorHeight ); + secondary.actor.SetPosition( secondary.x + scrollPosition.x, + secondary.y + scrollPosition.y + secondary.cursorHeight ); //CreateHighlight(); TODO } @@ -170,63 +344,59 @@ struct Decorator::Impl : public ConnectionTracker UnparentAndReset( mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].actor ); UnparentAndReset( mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].actor ); } + + if ( mActiveCopyPastePopup ) + { + CreatePopup(); + mCopyPastePopup.mRoot.SetPosition( Vector3( 180.0f, -100.0f, 0.0f ) ); //todo grabhandle or selection handle postions to be used + } + else + { + DestroyPopup(); + } } - /** - * Creates a cursor - */ void CreateCursor( ImageActor& cursor ) { - if ( !mCursorImage ) - { - mCursorImage = ResourceImage::New( DEFAULT_CURSOR_IMAGE ); - } - cursor = ImageActor::New( mCursorImage ); + cursor = CreateSolidColorActor( Color::WHITE ); + cursor.SetParentOrigin( ParentOrigin::TOP_LEFT ); cursor.SetAnchorPoint( AnchorPoint::TOP_CENTER ); } - /** - * Add / Remove cursor(s) from parent - */ - void SetCursors() + // Add or Remove cursor(s) from parent + void CreateCursors() { - Actor parent = mParent.Self(); - /* Create Primary and or Secondary Cursor(s) if active and add to parent */ - if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY ) + if( mActiveCursor == ACTIVE_CURSOR_NONE ) { - if ( !mPrimaryCursor ) - { - CreateCursor( mPrimaryCursor ); -#ifdef DECORATOR_DEBUG - mPrimaryCursor.SetName( "PrimaryCursorActor" ); -#endif - parent.Add( mPrimaryCursor); - } - - mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x, mCursor[PRIMARY_CURSOR].y ); + UnparentAndReset( mPrimaryCursor ); + UnparentAndReset( mSecondaryCursor ); } - else if ( mActiveCursor == ACTIVE_CURSOR_BOTH ) + else { - if ( !mSecondaryCursor ) + /* Create Primary and or Secondary Cursor(s) if active and add to parent */ + if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY || + mActiveCursor == ACTIVE_CURSOR_BOTH ) { - CreateCursor( mSecondaryCursor ); + if ( !mPrimaryCursor ) + { + CreateCursor( mPrimaryCursor ); #ifdef DECORATOR_DEBUG - mSecondaryCursor.SetName( "SecondaryCursorActor" ); + mPrimaryCursor.SetName( "PrimaryCursorActor" ); #endif - parent.Add( mSecondaryCursor); - } - } - else - { - /* ACTIVE_CURSOR_NONE so unparent cursors*/ - if ( mPrimaryCursor ) - { - UnparentAndReset( mPrimaryCursor ); + mActiveLayer.Add( mPrimaryCursor); + } } - if ( mSecondaryCursor ) + if ( mActiveCursor == ACTIVE_CURSOR_BOTH ) { - UnparentAndReset( mSecondaryCursor ); + if ( !mSecondaryCursor ) + { + CreateCursor( mSecondaryCursor ); +#ifdef DECORATOR_DEBUG + mSecondaryCursor.SetName( "SecondaryCursorActor" ); +#endif + mActiveLayer.Add( mSecondaryCursor); + } } } } @@ -234,13 +404,12 @@ struct Decorator::Impl : public ConnectionTracker bool OnCursorBlinkTimerTick() { // Cursor blinking - if ( ACTIVE_CURSOR_PRIMARY ) + if ( mPrimaryCursor ) { mPrimaryCursor.SetVisible( mCursorBlinkStatus ); } - else if ( ACTIVE_CURSOR_BOTH ) + if ( mSecondaryCursor ) { - mPrimaryCursor.SetVisible( mCursorBlinkStatus ); mSecondaryCursor.SetVisible( mCursorBlinkStatus ); } @@ -268,7 +437,7 @@ struct Decorator::Impl : public ConnectionTracker { if( !mActiveLayer ) { - Actor parent = mParent.Self(); + Actor parent = mTextControlParent.Self(); mActiveLayer = Layer::New(); #ifdef DECORATOR_DEBUG @@ -438,7 +607,292 @@ struct Decorator::Impl : public ConnectionTracker return false; } - Internal::Control& mParent; + /** + * Popup + */ + + void CreateOrderedListOfPopupOptions() + { + mCopyPastePopup.mOrderListOfButtons.clear(); + + // Create button for each possible option using Option priority + ResourceImage cutIcon = ResourceImage::New( OPTION_ICON_CUT ); + mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsCut, mCopyPastePopup.mCutOptionPriority, OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), cutIcon, true ) ); + + ResourceImage copyIcon = ResourceImage::New( OPTION_ICON_COPY ); + mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsCopy, mCopyPastePopup.mCopyOptionPriority, OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), copyIcon, true ) ); + + ResourceImage pasteIcon = ResourceImage::New( OPTION_ICON_PASTE ); + mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsPaste, mCopyPastePopup.mPasteOptionPriority, OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon, true ) ); + + ResourceImage selectIcon = ResourceImage::New( OPTION_ICON_SELECT ); + mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsSelect, mCopyPastePopup.mSelectOptionPriority, OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), selectIcon, true ) ); + + ResourceImage selectAllIcon = ResourceImage::New( OPTION_ICON_SELECT_ALL ); + mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsSelectAll, mCopyPastePopup.mSelectAllOptionPriority, OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon, true ) ); + + ResourceImage clipboardIcon = ResourceImage::New( OPTION_ICON_CLIPBOARD ); + mCopyPastePopup.mOrderListOfButtons.push_back( ButtonRequirement( ButtonsClipboard, mCopyPastePopup.mClipboardOptionPriority, OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, true ) ); + + // Sort the buttons according their priorities. + std::sort( mCopyPastePopup.mOrderListOfButtons.begin(), mCopyPastePopup.mOrderListOfButtons.end(), PriorityCompare ); + } + + void CreateBackground( PopupImpl& popup ) + { + // Create background-panel if not already created (required if we have at least one option) + if ( !popup.mBackground ) + { + ResourceImage bgImg = ResourceImage::New( POPUP_BACKGROUND ); + popup.mBackground = ImageActor::New( bgImg ); + popup.mBackground.SetColor( popup.mBackgroundColor ); + popup.mBackground.SetParentOrigin( ParentOrigin::CENTER ); + + NinePatchImage backgroundImageNinePatch = NinePatchImage::DownCast( bgImg ); + if( backgroundImageNinePatch ) + { + const Size ninePatchImageSize = Size( static_cast( bgImg.GetWidth() ), static_cast( bgImg.GetHeight() ) ); + Rect childRect = backgroundImageNinePatch.GetChildRectangle(); + + // -1u because of the cropping. + popup.mNinePatchMargins.x = childRect.x - 1u; + popup.mNinePatchMargins.y = ninePatchImageSize.width - ( childRect.x + childRect.width ) - 1u; + popup.mNinePatchMargins.z = childRect.y - 1u; + popup.mNinePatchMargins.w = ninePatchImageSize.height - ( childRect.y + childRect.height ) - 1u; + } + + ResourceImage::Image bgEffectImg = ResourceImage::New( POPUP_BACKGROUND_EFFECT ); + ImageActor backgroundEffect = ImageActor::New( bgEffectImg ); + backgroundEffect.SetParentOrigin( ParentOrigin::CENTER ); + + ResourceImage::Image bgLine = ResourceImage::New( POPUP_BACKGROUND_LINE ); + ImageActor backgroundLine = ImageActor::New( bgLine ); + backgroundLine.SetParentOrigin( ParentOrigin::CENTER ); + backgroundLine.SetColor( popup.mLineColor ); + + popup.mBackground.Add( backgroundEffect ); + popup.mBackground.Add( backgroundLine ); + } + } + + void AddOption( Actor& parent, const std::string& name, const std::string& caption, const Image iconImage, bool finalOption, bool showIcons ) + { + // 1. Create the backgrounds for the popup option both normal and pressed. + // Both containers will be added to a button. + Actor optionContainer = Actor::New(); + optionContainer.SetDrawMode( DrawMode::OVERLAY ); + //optionContainer.SetParentOrigin( ParentOrigin::CENTER ); + optionContainer.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + ImageActor optionPressedContainer = Toolkit::CreateSolidColorActor( mCopyPastePopup.mBackgroundPressedColor ); + optionPressedContainer.SetDrawMode( DrawMode::OVERLAY ); + //optionPressedContainer.SetParentOrigin( ParentOrigin::CENTER ); + optionPressedContainer.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + // 2. Add text. + Toolkit::TextLabel captionTextLabel = Toolkit::TextLabel::New(); + captionTextLabel.SetProperty( TextLabel::Property::TEXT, caption ); + optionContainer.Add( captionTextLabel ); + + Toolkit::TextLabel pressedCaptionTextLabel = Toolkit::TextLabel::New(); + pressedCaptionTextLabel.SetProperty( TextLabel::Property::TEXT, caption ); + optionPressedContainer.Add( pressedCaptionTextLabel ); + + // Calculates the icon/text position. + float iconTextOffsetY = 0.0f; + + if ( showIcons ) + { + // 3. Create the icons + ImageActor pressedIcon = ImageActor::New( iconImage ); + ImageActor icon = ImageActor::New( iconImage ); + + optionContainer.Add( icon ); + optionPressedContainer.Add( pressedIcon ); + + iconTextOffsetY = 0.5f * ( ( DEFAULT_POPUP_MAX_SIZE.height - mCopyPastePopup.mNinePatchMargins.z - mCopyPastePopup.mNinePatchMargins.w ) - ( OPTION_ICON_SIZE.height + OPTION_GAP_ICON_TEXT + OPTION_TEXT_LINE_HEIGHT ) ); + + icon.SetParentOrigin( ParentOrigin::TOP_CENTER ); + icon.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + icon.SetY( iconTextOffsetY ); + + pressedIcon.SetParentOrigin( ParentOrigin::TOP_CENTER ); + pressedIcon.SetAnchorPoint( AnchorPoint::TOP_CENTER ); + pressedIcon.SetY( iconTextOffsetY ); + + // Layout icon + gap + text + captionTextLabel.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER ); + pressedCaptionTextLabel.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER ); + pressedCaptionTextLabel.SetParentOrigin( ParentOrigin::BOTTOM_CENTER ); + captionTextLabel.SetParentOrigin( ParentOrigin::BOTTOM_CENTER ); + pressedCaptionTextLabel.SetY( -iconTextOffsetY ); + captionTextLabel.SetY( -iconTextOffsetY ); + } + else + { + // Centre option text + captionTextLabel.SetAnchorPoint( AnchorPoint::CENTER ); + captionTextLabel.SetParentOrigin( ParentOrigin::CENTER ); + pressedCaptionTextLabel.SetAnchorPoint( AnchorPoint::CENTER ); + pressedCaptionTextLabel.SetParentOrigin( ParentOrigin::CENTER ); + } + + // Calculate the size of the text. + Vector3 textSize = captionTextLabel.GetNaturalSize(); + textSize.width = std::min( textSize.width, OPTION_MAX_WIDTH - 2.f * OPTION_MARGIN_WIDTH ); + + // Set the size to the text. Text will be ellipsized if exceeds the max width. + captionTextLabel.SetSize( textSize ); + pressedCaptionTextLabel.SetSize( textSize ); + + // 4. Calculate the size of option. + + // The width is the max size of the text or the icon plus the margins clamped between the option min and max size. + // The height is the whole popup height minus the ninepatch margins. + const Vector2 optionSize( std::min( OPTION_MAX_WIDTH, std::max( OPTION_MIN_WIDTH, std::max( textSize.width, OPTION_ICON_SIZE.width ) + 2.f * OPTION_MARGIN_WIDTH ) ), + DEFAULT_POPUP_MAX_SIZE.height - mCopyPastePopup.mNinePatchMargins.z - mCopyPastePopup.mNinePatchMargins.w ); + + optionContainer.SetSize( optionSize ); + optionPressedContainer.SetSize( optionSize ); + + // 5. Create a option. + Toolkit::PushButton option = Toolkit::PushButton::New(); + option.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed ); + option.SetSize( optionSize ); + option.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + option.SetX( mCopyPastePopup.mContentSize.width ); + option.SetName( name ); + option.SetAnimationTime( 0.0f ); + //option.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed ); + + parent.Add( option ); + + // 6. Set the normal option image. + option.SetButtonImage( optionContainer ); + + // 7. Set the pressed option image + option.SetSelectedImage( optionPressedContainer ); + + // 8. Update the content size. + mCopyPastePopup.mContentSize.width += optionSize.width; + mCopyPastePopup.mContentSize.height = std::max ( optionSize.height, mCopyPastePopup.mContentSize.height ); + + // 9. Add the divider + if( !finalOption ) + { + const Size size( POPUP_DIVIDER_WIDTH, mCopyPastePopup.mContentSize.height ); + + ImageActor divider = Toolkit::CreateSolidColorActor( Color::WHITE ); + divider.SetSize (size); + divider.SetParentOrigin( ParentOrigin::TOP_LEFT ); + divider.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + divider.SetPosition( mCopyPastePopup.mContentSize.width - POPUP_DIVIDER_WIDTH, 0.0f ); + parent.Add( divider ); + } + } + + void SetUpPopup( Actor& popupRootActor, Size& size ) + { + // Create Layer and Stencil. + popupRootActor = Actor::New(); + mCopyPastePopup.mStencilLayer = Layer::New(); + ImageActor stencil = CreateSolidColorActor( Color::RED ); + stencil.SetDrawMode( DrawMode::STENCIL ); + stencil.SetVisible( true ); + Actor scrollview = Actor::New(); + + //todo Use Size negotiation + mCopyPastePopup.mStencilLayer.SetSize( size ); // matches stencil size + popupRootActor.SetSize( size ); // matches stencil size + stencil.SetSize( size ); + scrollview.SetSize( size ); + mCopyPastePopup.mButtons.SetSize( size ); + + mCopyPastePopup.mStencilLayer.SetAnchorPoint(AnchorPoint::TOP_LEFT); + scrollview.SetAnchorPoint(AnchorPoint::TOP_LEFT); + mCopyPastePopup.mButtons.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + mActiveLayer.Add( mCopyPastePopup.mRoot ); + popupRootActor.Add( mCopyPastePopup.mBackground ); + popupRootActor.Add( mCopyPastePopup.mStencilLayer ); + mCopyPastePopup.mStencilLayer.Add( stencil ); + mCopyPastePopup.mStencilLayer.Add( scrollview ); + scrollview.Add( mCopyPastePopup.mButtons ); + } + + void AddPopupOptions( bool createTail, bool showIcons ) + { + mCopyPastePopup.mShowIcons = showIcons; + + mCopyPastePopup.mContentSize = Vector2::ZERO; + + mCopyPastePopup.mButtons = Actor::New(); + + // Add the options into the buttons container. + + // 1. Determine how many buttons are active and should be added to container. + std::size_t numberOfOptions = 0u; + for( std::vector::const_iterator it = mCopyPastePopup.mOrderListOfButtons.begin(), endIt = mCopyPastePopup.mOrderListOfButtons.end(); ( it != endIt ); ++it ) + { + const ButtonRequirement& button( *it ); + if( button.enabled ) + { + ++numberOfOptions; + } + } + + // 2. Iterate list of buttons and add active ones. + std::size_t optionsAdded = 0u; + for( std::vector::const_iterator it = mCopyPastePopup.mOrderListOfButtons.begin(), endIt = mCopyPastePopup.mOrderListOfButtons.end(); ( it != endIt ); ++it ) + { + const ButtonRequirement& button( *it ); + if ( button.enabled ) + { + ++optionsAdded; + AddOption( mCopyPastePopup.mButtons, button.name, button.caption, button.icon, optionsAdded == numberOfOptions, mCopyPastePopup.mShowIcons ); + } + } + + // Calculate the size of the whole popup which may not be all visible. + mCopyPastePopup.mRequiredPopUpSize = Size( std::min( mCopyPastePopup.mMaxWidth, mCopyPastePopup.mContentSize.width + mCopyPastePopup.mNinePatchMargins.x + mCopyPastePopup.mNinePatchMargins.y ), DEFAULT_POPUP_MAX_SIZE. height ); + + // Set the size of the background, background line and background effect. + mCopyPastePopup.mBackground.SetSize( mCopyPastePopup.mRequiredPopUpSize); + for( std::size_t index = 0u, childCount = mCopyPastePopup.mBackground.GetChildCount(); index < childCount; ++index ) + { + mCopyPastePopup.mBackground.GetChildAt( index ).SetSize( mCopyPastePopup.mRequiredPopUpSize ); + } + + // Size of the contents within the popup + mCopyPastePopup.mVisiblePopUpSize = Size( mCopyPastePopup.mRequiredPopUpSize.width - mCopyPastePopup.mNinePatchMargins.x - mCopyPastePopup.mNinePatchMargins.y, mCopyPastePopup.mRequiredPopUpSize.height - mCopyPastePopup.mNinePatchMargins.z - mCopyPastePopup.mNinePatchMargins.w ); + + } + + void CreatePopup() + { + if ( !mCopyPastePopup.mRoot ) + { + mActiveCopyPastePopup = true; + CreateOrderedListOfPopupOptions(); //todo Currently causes all options to be shown + CreateBackground( mCopyPastePopup ); + AddPopupOptions( true, true ); + SetUpPopup( mCopyPastePopup.mRoot, mCopyPastePopup.mVisiblePopUpSize ); + } + + mCopyPastePopup.mStencilLayer.RaiseToTop(); + } + + void DestroyPopup() + { + if ( mCopyPastePopup.mRoot ) + { + mActiveCopyPastePopup = false; + UnparentAndReset( mCopyPastePopup.mButtons ); + UnparentAndReset( mCopyPastePopup.mRoot ); + } + } + + Internal::Control& mTextControlParent; Observer& mObserver; Layer mActiveLayer; // Layer for active handles and alike that ensures they are above all else. @@ -446,6 +900,7 @@ struct Decorator::Impl : public ConnectionTracker unsigned int mActiveCursor; bool mActiveGrabHandle; bool mActiveSelection; + bool mActiveCopyPastePopup; CursorImpl mCursor[CURSOR_COUNT]; @@ -464,6 +919,8 @@ struct Decorator::Impl : public ConnectionTracker SelectionHandleImpl mSelectionHandle[SELECTION_HANDLE_COUNT]; + PopupImpl mCopyPastePopup; + Image mCursorImage; Image mGrabHandleImage; @@ -488,9 +945,9 @@ const Rect& Decorator::GetBoundingBox() const return mImpl->mBoundingBox; } -void Decorator::Relayout( const Vector2& size ) +void Decorator::Relayout( const Vector2& size, const Vector2& scrollPosition ) { - mImpl->Relayout( size ); + mImpl->Relayout( size, scrollPosition ); } /** Cursor **/ @@ -523,16 +980,6 @@ void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& height ) height = mImpl->mCursor[cursor].height; } -void Decorator::SetCursorImage( Dali::Image image ) -{ - mImpl->mCursorImage = image; -} - -Dali::Image Decorator::GetCursorImage() const -{ - return mImpl->mCursorImage; -} - void Decorator::SetColor( Cursor cursor, const Dali::Vector4& color ) { mImpl->mCursor[cursor].color = color; @@ -655,6 +1102,22 @@ Dali::Image Decorator::GetImage( SelectionHandle handle, SelectionHandleState st return mImpl->mSelectionHandle[handle].releasedImage; } +void Decorator::ShowPopup() +{ + if ( !mImpl->mCopyPastePopup.mRoot ) + { + mImpl->CreatePopup(); + } +} + +void Decorator::HidePopup() +{ + if ( mImpl->mCopyPastePopup.mRoot ) + { + mImpl->DestroyPopup(); + } +} + Decorator::~Decorator() { delete mImpl;