TextSelectionPopup follows Handles and button change with state and other improvements 75/41875/7
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Thu, 18 Jun 2015 13:28:48 +0000 (14:28 +0100)
committerAgnelo Vaz <agnelo.vaz@samsung.com>
Thu, 18 Jun 2015 18:10:28 +0000 (11:10 -0700)
Pixel align positioning of Popup and padding
Show Copy and Cut when in Selecting State

Change-Id: I5e8a02fae89cf096f3e6319eb8f500aaf0ea6741
Signed-off-by: Agnelo Vaz <agnelo.vaz@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp
dali-toolkit/devel-api/controls/text-controls/text-selection-popup.cpp
dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h
dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp
dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h
dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp

index b248e01..84046fd 100644 (file)
@@ -41,7 +41,7 @@ int UtcDaliToolkitTextSelectionPopupNewP(void)
 
   DALI_TEST_CHECK( !textSelectionPopup );
 
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY );
 
   DALI_TEST_CHECK( textSelectionPopup );
   END_TEST;
@@ -61,7 +61,7 @@ int UtcDaliToolkitTextSelectionPopupCopyConstructorP(void)
   ToolkitTestApplication application;
   TextSelectionPopup textSelectionPopup;
 
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY );
   TextSelectionPopup copy( textSelectionPopup );
 
   DALI_TEST_CHECK( copy == textSelectionPopup );
@@ -85,7 +85,7 @@ int UtcDaliToolkitTextSelectionPopupAssignmentOperatorP(void)
 {
   ToolkitTestApplication application;
   TextSelectionPopup textSelectionPopup;
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY );
   TextSelectionPopup copy;
   copy = textSelectionPopup;
 
@@ -97,7 +97,7 @@ int UtcDaliToolkitTextSelectionPopupDownCastP(void)
 {
   ToolkitTestApplication application;
   TextSelectionPopup textSelectionPopup;
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY );
 
   TextSelectionPopup cast = TextSelectionPopup::DownCast( textSelectionPopup );
 
index 7cf97da..a1237f2 100644 (file)
@@ -29,11 +29,6 @@ namespace Dali
 namespace Toolkit
 {
 
-TextSelectionPopup TextSelectionPopup::New()
-{
-  return Internal::TextSelectionPopup::New();
-}
-
 TextSelectionPopup TextSelectionPopup::New( Buttons enabledButtons )
 {
   return Internal::TextSelectionPopup::New( enabledButtons );
index 292d5c5..c2ad190 100644 (file)
@@ -88,12 +88,6 @@ public:
   };
 
   /**
-   * Create the TextSelectionPopup control.
-   * @return A handle to the TextSelectionPopup control.
-   */
-  static TextSelectionPopup New();
-
-  /**
    * Create the TextSelectionPopup control with the given set of buttons.
    * @param[in] enabledButtons The given set of buttons to enable
    * @return A handle to the TextSelectionPopup control.
index 28a3d18..ee0d950 100644 (file)
@@ -47,7 +47,7 @@ namespace
 
 const Dali::Vector4 DEFAULT_POPUP_LINE_COLOR( Dali::Vector4( 0.69f, 0.93f, 0.93f, 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( 0.5f, 1.0f, 1.0f, 1.0f ) );
+const Dali::Vector4 DEFAULT_OPTION_ICON_PRESSED( Dali::Vector4( 0.12f, 0.56f, 1.0f, 1.0f ) );
 
 const std::string DEFAULT_POPUP_BACKGROUND_IMAGE( DALI_IMAGE_DIR "selection-popup-bg#.png" );
 const std::string OPTION_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" );
@@ -88,7 +88,7 @@ const char* const OPTION_CLIPBOARD("option-clipboard");
 
 BaseHandle Create()
 {
-  return Toolkit::TextSelectionPopup::New();
+  return Toolkit::TextSelectionPopup::New( Toolkit::TextSelectionPopup::NONE );
 }
 
 // Setup properties, signals and actions using the type-registry.
@@ -111,20 +111,6 @@ DALI_TYPE_REGISTRATION_END()
 
 } // namespace
 
-Dali::Toolkit::TextSelectionPopup TextSelectionPopup::New()
-{
-  // Create the implementation, temporarily owned by this handle on stack
-  IntrusivePtr< TextSelectionPopup > impl = new TextSelectionPopup();
-
-  // Pass ownership to CustomActor handle
-  Dali::Toolkit::TextSelectionPopup handle( *impl );
-
-  // Second-phase init of the implementation
-  // This can only be done after the CustomActor connection has been made...
-  impl->Initialize();
-
-  return handle;
-}
 
 Dali::Toolkit::TextSelectionPopup TextSelectionPopup::New( Toolkit::TextSelectionPopup::Buttons buttonsToEnable )
 {
@@ -535,7 +521,7 @@ Dali::Image TextSelectionPopup::GetButtonImage( Toolkit::TextSelectionPopup::But
    optionPressedContainer.SetDrawMode( DrawMode::OVERLAY );
    optionPressedContainer.SetFitHeight( 0 );
    optionPressedContainer.SetFitWidth( 0 );
-   optionPressedContainer.SetBackgroundColor(Color::RED); //todo member variable
+   optionPressedContainer.SetBackgroundColor( mPressedColor );
 
 #ifdef DECORATOR_DEBUG
    optionContainer.SetName("optionContainer");
@@ -556,7 +542,7 @@ Dali::Image TextSelectionPopup::GetButtonImage( Toolkit::TextSelectionPopup::But
      Padding padding;
      padding.left = 24.0f;
      padding.right = 24.0f;
-     padding.top = 13.0f;
+     padding.top = 14.0f;
      padding.bottom = 14.0f;
      captionTextLabel.SetPadding( padding );
      pressedCaptionTextLabel.SetPadding( padding );
@@ -574,7 +560,6 @@ Dali::Image TextSelectionPopup::GetButtonImage( Toolkit::TextSelectionPopup::But
      icon.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
      pressedIcon.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
      icon.SetColor( mIconColor );
-     pressedIcon.SetColor( mIconPressedColor );
 
      if ( showCaption & showIcons )
      {
@@ -677,7 +662,7 @@ TextSelectionPopup::TextSelectionPopup()
   mEnabledButtons( Toolkit::TextSelectionPopup::NONE ),
   mLineColor( DEFAULT_POPUP_LINE_COLOR ),
   mIconColor( DEFAULT_OPTION_ICON ),
-  mIconPressedColor( DEFAULT_OPTION_ICON_PRESSED ),
+  mPressedColor( DEFAULT_OPTION_ICON_PRESSED ),
   mSelectOptionPriority( 1 ),
   mSelectAllOptionPriority ( 2 ),
   mCutOptionPriority ( 3 ),
index 3650977..8d75848 100644 (file)
@@ -97,11 +97,6 @@ public:
   };
 
   /**
-   * @copydoc Dali::Toollkit::TextSelectionPopup::New()
-   */
-  static Toolkit::TextSelectionPopup New();
-
-  /**
    * @brief New constructor with provided buttons to enable.
    * @param[in] buttonsToEnable bit mask of buttons to enable
    * @return A handle to the TextSelectionPopup control.
@@ -228,7 +223,7 @@ private: // Data
 
   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 mPressedColor;                // Color of the popup option 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
index 4b25f77..3ff40b3 100644 (file)
@@ -43,8 +43,6 @@ namespace
 {
 const Dali::Vector2 DEFAULT_MAX_SIZE( 400.0f, 65.0f ); ///< The maximum size of the Toolbar.
 
-} // namespace
-
 BaseHandle Create()
 {
   return Toolkit::TextSelectionToolbar::New();
@@ -58,6 +56,8 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "max-size", VECTOR2,
 
 DALI_TYPE_REGISTRATION_END()
 
+} // namespace
+
 Dali::Toolkit::TextSelectionToolbar TextSelectionToolbar::New()
 {
   // Create the implementation, temporarily owned by this handle on stack
index ef6a54f..392fde1 100644 (file)
@@ -80,6 +80,8 @@ const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-sel
 const char* DEFAULT_SELECTION_HANDLE_TWO_RELEASED( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
 const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
 
+const int DEFAULT_POPUP_OFFSET( -100.0f ); // Vertical offset of Popup from cursor or handles position.
+
 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 );
 
@@ -213,6 +215,19 @@ struct Decorator::Impl : public ConnectionTracker
     bool flipped : 1;
   };
 
+  struct PopupImpl
+  {
+    PopupImpl()
+    : position(),
+      offset( DEFAULT_POPUP_OFFSET )
+    {
+    }
+
+    TextSelectionPopup actor;
+    Vector3 position;
+    int offset;
+  };
+
   Impl( ControllerInterface& controller )
   : mController( controller ),
     mEnabledPopupButtons( TextSelectionPopup::NONE ),
@@ -386,22 +401,24 @@ struct Decorator::Impl : public ConnectionTracker
 
     if ( mActiveCopyPastePopup )
     {
-      if ( !mCopyPastePopup )
+      // todo Swap UnparentAndReset for DeterminePositionPopup() if mCopyPastePopup.actor valid Once the issue with the labels disappearing is fixed.
+      UnparentAndReset( mCopyPastePopup.actor );
+      if ( !mCopyPastePopup.actor )
       {
-        mCopyPastePopup = TextSelectionPopup::New( mEnabledPopupButtons );
+        mCopyPastePopup.actor = TextSelectionPopup::New( mEnabledPopupButtons );
 #ifdef DECORATOR_DEBUG
-        mCopyPastePopup.SetName("mCopyPastePopup");
+        mCopyPastePopup.actor.SetName("mCopyPastePopup");
 #endif
-        mCopyPastePopup.SetAnchorPoint( AnchorPoint::CENTER );
-        mCopyPastePopup.OnRelayoutSignal().Connect( this,  &Decorator::Impl::PopUpRelayoutComplete  ); // Position popup after size negotiation
-        mActiveLayer.Add ( mCopyPastePopup );
+        mCopyPastePopup.actor.SetAnchorPoint( AnchorPoint::CENTER );
+        mCopyPastePopup.actor.OnRelayoutSignal().Connect( this,  &Decorator::Impl::PopupRelayoutComplete  ); // Position popup after size negotiation
+        mActiveLayer.Add ( mCopyPastePopup.actor );
       }
     }
     else
     {
-     if ( mCopyPastePopup )
+     if ( mCopyPastePopup.actor )
      {
-       UnparentAndReset( mCopyPastePopup );
+       UnparentAndReset( mCopyPastePopup.actor );
      }
     }
   }
@@ -416,21 +433,43 @@ struct Decorator::Impl : public ConnectionTracker
     mHighlightPosition += scrollOffset;
   }
 
-  void PopUpRelayoutComplete( Actor actor )
+  void DeterminePositionPopup()
   {
-    // Size negotiation for CopyPastePopup complete so can get the size and constrain position within bounding box.
+    if ( !mActiveCopyPastePopup )
+    {
+      return;
+    }
 
-    mCopyPastePopup.OnRelayoutSignal().Disconnect( this, &Decorator::Impl::PopUpRelayoutComplete  );
+    if ( mHandle[LEFT_SELECTION_HANDLE].active || mHandle[RIGHT_SELECTION_HANDLE].active )
+    {
+      float minHandleXPosition = std::min (  mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
+      float maxHandleXPosition = std::max (  mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
 
-    Vector3 popupPosition( mCursor[PRIMARY_CURSOR].position.x, mCursor[PRIMARY_CURSOR].position.y -100.0f , 0.0f); //todo 100 to be an offset Property
+      float minHandleYPosition = std::min (  mHandle[LEFT_SELECTION_HANDLE].position.y, mHandle[RIGHT_SELECTION_HANDLE].position.y );
 
-    Vector3 popupSize = Vector3( mCopyPastePopup.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
+      mCopyPastePopup.position.x = minHandleXPosition + ( ( maxHandleXPosition - minHandleXPosition ) *0.5f );
+      mCopyPastePopup.position.y = minHandleYPosition + mCopyPastePopup.offset;
+    }
+    else
+    {
+      mCopyPastePopup.position = Vector3( mCursor[PRIMARY_CURSOR].position.x, mCursor[PRIMARY_CURSOR].position.y -100.0f , 0.0f ); //todo 100 to be an offset Property
+    }
+
+    Vector3 popupSize = Vector3( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
+
+    GetConstrainedPopupPosition( mCopyPastePopup.position, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
+
+    SetUpPopupPositionNotifications();
 
-    GetConstrainedPopupPosition( popupPosition, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
+    mCopyPastePopup.actor.SetPosition( mCopyPastePopup.position );
+  }
 
-    SetUpPopUpPositionNotifications();
+  void PopupRelayoutComplete( Actor actor )
+  {
+    // Size negotiation for CopyPastePopup complete so can get the size and constrain position within bounding box.
+    mCopyPastePopup.actor.OnRelayoutSignal().Disconnect( this, &Decorator::Impl::PopupRelayoutComplete  );
 
-    mCopyPastePopup.SetPosition( popupPosition ); //todo grabhandle(cursor) or selection handle positions to be used
+    DeterminePositionPopup();
   }
 
   void CreateCursor( ImageActor& cursor, const Vector4& color )
@@ -1007,11 +1046,11 @@ struct Decorator::Impl : public ConnectionTracker
     // if can't be positioned above, then position below row.
     alternativeYPosition = AlternatePopUpPositionRelativeToCursor();
 
-    mCopyPastePopup.SetY( alternativeYPosition );
+    mCopyPastePopup.actor.SetY( alternativeYPosition );
   }
 
 
-  void SetUpPopUpPositionNotifications( )
+  void SetUpPopupPositionNotifications( )
   {
     // Note Property notifications ignore any set anchor point so conditions must allow for this.  Default is Top Left.
 
@@ -1020,11 +1059,11 @@ struct Decorator::Impl : public ConnectionTracker
     Vector4 worldCoordinatesBoundingBox;
     LocalToWorldCoordinatesBoundingBox( mBoundingBox, worldCoordinatesBoundingBox );
 
-    float popupHeight = mCopyPastePopup.GetRelayoutSize( Dimension::HEIGHT);
+    float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT);
 
-    PropertyNotification verticalExceedNotification = mCopyPastePopup.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
-                                                      OutsideCondition( worldCoordinatesBoundingBox.y + popupHeight/2,
-                                                                        worldCoordinatesBoundingBox.w - popupHeight/2 ) );
+    PropertyNotification verticalExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                      OutsideCondition( worldCoordinatesBoundingBox.y + popupHeight * 0.5f,
+                                                                        worldCoordinatesBoundingBox.w - popupHeight * 0.5f ) );
 
     verticalExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesVerticalBoundary );
   }
@@ -1061,6 +1100,11 @@ struct Decorator::Impl : public ConnectionTracker
     }
 
     requiredPopupPosition.x = requiredPopupPosition.x + xOffSetToKeepWithinBounds;
+
+    // Prevent pixel mis-alignment by rounding down.
+    requiredPopupPosition.x = static_cast<int>( requiredPopupPosition.x );
+    requiredPopupPosition.y = static_cast<int>( requiredPopupPosition.y );
+
   }
 
   void FlipSelectionHandleImages()
@@ -1166,7 +1210,8 @@ struct Decorator::Impl : public ConnectionTracker
   ImageActor          mPrimaryCursor;
   ImageActor          mSecondaryCursor;
   MeshActor           mHighlightMeshActor;        ///< Mesh Actor to display highlight
-  TextSelectionPopup  mCopyPastePopup;
+
+  PopupImpl           mCopyPastePopup;
   TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
 
   Image               mHandleImages[HANDLE_TYPE_COUNT][HANDLE_IMAGE_TYPE_COUNT];
index fb2bf2b..24e38c2 100644 (file)
@@ -847,7 +847,17 @@ void Controller::Impl::ChangeState( EventData::State newState )
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
       if( mEventData->mGrabHandlePopupEnabled )
       {
-        TextSelectionPopup::Buttons selectedButtons = TextSelectionPopup::Buttons( TextSelectionPopup::COPY );
+        TextSelectionPopup::Buttons selectedButtons = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+        mEventData->mDecorator->SetEnabledPopupButtons( selectedButtons );
+        mEventData->mDecorator->SetPopupActive( true );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if ( EventData::SELECTION_CHANGED  == mEventData->mState )
+    {
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        TextSelectionPopup::Buttons selectedButtons = TextSelectionPopup::Buttons( TextSelectionPopup::CUT | TextSelectionPopup::COPY );
         mEventData->mDecorator->SetEnabledPopupButtons( selectedButtons );
         mEventData->mDecorator->SetPopupActive( true );
       }
index 81125da..326770d 100644 (file)
@@ -99,6 +99,7 @@ struct EventData
   {
     INACTIVE,
     SELECTING,
+    SELECTION_CHANGED,
     EDITING,
     EDITING_WITH_POPUP,
     GRAB_HANDLE_PANNING,
index 3b36ed3..f63944a 100644 (file)
@@ -47,6 +47,12 @@ const float MAX_FLOAT = std::numeric_limits<float>::max();
 
 const std::string EMPTY_STRING("");
 
+float ConvertToEven( float value )
+{
+  int intValue(static_cast<int>( value ));
+  return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
+}
+
 } // namespace
 
 namespace Dali
@@ -533,6 +539,9 @@ Vector3 Controller::GetNaturalSize()
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
   }
 
+  naturalSize.x = ConvertToEven( naturalSize.x );
+  naturalSize.y = ConvertToEven( naturalSize.y );
+
   return naturalSize;
 }
 
@@ -1312,11 +1321,7 @@ void Controller::TapEvent( unsigned int tapCount, float x, float y )
 
       if( !isShowingPlaceholderText && tapDuringEditMode )
       {
-        // Grab handle is not shown until a tap is received whilst EDITING
-        if( tapDuringEditMode )
-        {
-          mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
-        }
+        mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
         mImpl->mEventData->mDecorator->SetPopupActive( false );
       }
 
@@ -1326,7 +1331,14 @@ void Controller::TapEvent( unsigned int tapCount, float x, float y )
              mImpl->mEventData->mSelectionEnabled &&
              ( 2u == tapCount ) )
     {
-      mImpl->ChangeState( EventData::SELECTING );
+      if ( mImpl->mEventData->mState == EventData::SELECTING )
+      {
+        mImpl->ChangeState( EventData::SELECTION_CHANGED );
+      }
+      else
+      {
+        mImpl->ChangeState( EventData::SELECTING );
+      }
     }
   }