TextInput PopUp supports scrolling if buttons do not fit in visible area.
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-input / text-input-impl.cpp
index 615903c..d615942 100644 (file)
@@ -27,9 +27,6 @@
 #include <math.h>
 #include <sstream>
 #include <algorithm>
 #include <math.h>
 #include <sstream>
 #include <algorithm>
-#include <libintl.h>
-
-#define GET_LOCALE_TEXT(string) dgettext("sys_string", string)
 
 using namespace std;
 using namespace Dali;
 
 using namespace std;
 using namespace Dali;
@@ -47,7 +44,7 @@ const std::size_t DEFAULT_NUMBER_OF_LINES_LIMIT( std::numeric_limits<std::size_t
 const Vector3 DEFAULT_SELECTION_HANDLE_SIZE( 51.0f, 79.0f, 0.0f );  // Selection cursor image size
 const Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
 const Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
 const Vector3 DEFAULT_SELECTION_HANDLE_SIZE( 51.0f, 79.0f, 0.0f );  // Selection cursor image size
 const Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
 const Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
-const Vector4 LIGHTBLUE( 10.0f/255.0f, 140.0f/255.0f, 210.0f/255.0f, 1.0f );    // Used for Selection highlight
+const Vector4 LIGHTBLUE( 0.07f, 0.41f, 0.59f, 1.0f );    // Used for Selection highlight
 
 const char* DEFAULT_GRAB_HANDLE( DALI_IMAGE_DIR "insertpoint-icon.png" );
 const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
 
 const char* DEFAULT_GRAB_HANDLE( DALI_IMAGE_DIR "insertpoint-icon.png" );
 const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
@@ -56,22 +53,8 @@ const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-sel
 const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
 const char* DEFAULT_CURSOR( DALI_IMAGE_DIR "cursor.png" );
 
 const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
 const char* DEFAULT_CURSOR( DALI_IMAGE_DIR "cursor.png" );
 
-const char* DEFAULT_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" );
-const char* DEFAULT_ICON_COPY( DALI_IMAGE_DIR "copy_paste_icon_copy.png" );
-const char* DEFAULT_ICON_CUT( DALI_IMAGE_DIR "copy_paste_icon_cut.png" );
-const char* DEFAULT_ICON_PASTE( DALI_IMAGE_DIR "copy_paste_icon_paste.png" );
-const char* DEFAULT_ICON_SELECT( DALI_IMAGE_DIR "copy_paste_icon_select.png" );
-const char* DEFAULT_ICON_SELECT_ALL( DALI_IMAGE_DIR "copy_paste_icon_select_all.png" );
-
 const Vector4 DEFAULT_CURSOR_IMAGE_9_BORDER( 2.0f, 2.0f, 2.0f, 2.0f );
 
 const Vector4 DEFAULT_CURSOR_IMAGE_9_BORDER( 2.0f, 2.0f, 2.0f, 2.0f );
 
-const std::string OPTION_SELECT_WORD("select_word");                        ///< "Select Word" popup option.
-const std::string OPTION_SELECT_ALL("select_all");                          ///< "Select All" popup option.
-const std::string OPTION_CUT("cut");                                        ///< "Cut" popup option.
-const std::string OPTION_COPY("copy");                                      ///< "Copy" popup option.
-const std::string OPTION_PASTE("paste");                                    ///< "Paste" popup option.
-const std::string OPTION_CLIPBOARD("clipboard");                            ///< "Clipboard" popup option.
-
 const std::size_t CURSOR_BLINK_INTERVAL = 500;                              ///< Cursor blink interval
 const float CHARACTER_THRESHOLD( 2.5f );                                    ///< the threshold of a line.
 const float DISPLAYED_HIGHLIGHT_Z_OFFSET( 0.0f );                           ///< 1. Highlight rendered (z-offset).
 const std::size_t CURSOR_BLINK_INTERVAL = 500;                              ///< Cursor blink interval
 const float CHARACTER_THRESHOLD( 2.5f );                                    ///< the threshold of a line.
 const float DISPLAYED_HIGHLIGHT_Z_OFFSET( 0.0f );                           ///< 1. Highlight rendered (z-offset).
@@ -95,6 +78,16 @@ const float SCROLL_THRESHOLD = 10.f;
 const float SCROLL_SPEED = 15.f;
 
 /**
 const float SCROLL_SPEED = 15.f;
 
 /**
+ * Selection state enumeration (FSM)
+ */
+enum SelectionState
+{
+  SelectionNone,                            ///< Currently not encountered selected section.
+  SelectionStarted,                         ///< Encountered selected section
+  SelectionFinished                         ///< Finished selected section
+};
+
+/**
  * Whether the given style is the default style or not.
  * @param[in] style The given style.
  * @return \e true if the given style is the default. Otherwise it returns \e false.
  * Whether the given style is the default style or not.
  * @param[in] style The given style.
  * @return \e true if the given style is the default. Otherwise it returns \e false.
@@ -124,16 +117,6 @@ bool IsTextDefaultStyle( const Toolkit::MarkupProcessor::StyledTextArray& textAr
   return true;
 }
 
   return true;
 }
 
-/**
- * Selection state enumeration (FSM)
- */
-enum SelectionState
-{
-  SelectionNone,                            ///< Currently not encountered selected section.
-  SelectionStarted,                         ///< Encountered selected section
-  SelectionFinished                         ///< Finished selected section
-};
-
 std::size_t FindVisibleCharacterLeft( std::size_t cursorPosition, const Toolkit::TextView::CharacterLayoutInfoContainer& characterLayoutInfoTable )
 {
   for( Toolkit::TextView::CharacterLayoutInfoContainer::const_reverse_iterator it = characterLayoutInfoTable.rbegin() + characterLayoutInfoTable.size() - cursorPosition, endIt = characterLayoutInfoTable.rend();
 std::size_t FindVisibleCharacterLeft( std::size_t cursorPosition, const Toolkit::TextView::CharacterLayoutInfoContainer& characterLayoutInfoTable )
 {
   for( Toolkit::TextView::CharacterLayoutInfoContainer::const_reverse_iterator it = characterLayoutInfoTable.rbegin() + characterLayoutInfoTable.size() - cursorPosition, endIt = characterLayoutInfoTable.rend();
@@ -213,6 +196,17 @@ namespace Dali
 
 namespace Toolkit
 {
 
 namespace Toolkit
 {
+// Properties
+const Property::Index TextInput::HIGHLIGHT_COLOR_PROPERTY                     = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX;
+const Property::Index TextInput::CUT_AND_PASTE_COLOR_PROPERTY                 = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+1;
+const Property::Index TextInput::CUT_AND_PASTE_PRESSED_COLOR_PROPERTY         = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+2;
+
+const Property::Index TextInput::CUT_BUTTON_POSITION_PRIORITY_PROPERTY        = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+3;
+const Property::Index TextInput::COPY_BUTTON_POSITION_PRIORITY_PROPERTY       = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+4;
+const Property::Index TextInput::PASTE_BUTTON_POSITION_PRIORITY_PROPERTY      = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+5;
+const Property::Index TextInput::SELECT_BUTTON_POSITION_PRIORITY_PROPERTY     = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+6;
+const Property::Index TextInput::SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+7;
+const Property::Index TextInput::CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY  = Internal::TextInput::TEXTINPUT_PROPERTY_START_INDEX+8;
 
 namespace Internal
 {
 
 namespace Internal
 {
@@ -236,6 +230,17 @@ SignalConnectorType signalConnector6( typeRegistration, Toolkit::TextInput::SIGN
 
 }
 
 
 }
 
+PropertyRegistration property1( typeRegistration, "highlight-color",  Toolkit::TextInput::HIGHLIGHT_COLOR_PROPERTY, Property::VECTOR4, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property2( typeRegistration, "cut-and-paste-bg-color",  Toolkit::TextInput::CUT_AND_PASTE_COLOR_PROPERTY, Property::VECTOR4, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property3( typeRegistration, "cut-and-paste-pressed-color",  Toolkit::TextInput::CUT_AND_PASTE_PRESSED_COLOR_PROPERTY, Property::VECTOR4, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property4( typeRegistration, "cut-button-position-priority",  Toolkit::TextInput::CUT_BUTTON_POSITION_PRIORITY_PROPERTY, Property::UNSIGNED_INTEGER, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property5( typeRegistration, "copy-button-position-priority",  Toolkit::TextInput::COPY_BUTTON_POSITION_PRIORITY_PROPERTY, Property::UNSIGNED_INTEGER, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property6( typeRegistration, "paste-button-position-priority",  Toolkit::TextInput::PASTE_BUTTON_POSITION_PRIORITY_PROPERTY, Property::UNSIGNED_INTEGER, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property7( typeRegistration, "select-button-position-priority",  Toolkit::TextInput::SELECT_BUTTON_POSITION_PRIORITY_PROPERTY, Property::UNSIGNED_INTEGER, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property8( typeRegistration, "select-all-button-position-priority",  Toolkit::TextInput::SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY, Property::UNSIGNED_INTEGER, &TextInput::SetProperty, &TextInput::GetProperty );
+PropertyRegistration property9( typeRegistration, "clipboard-button-position-priority",  Toolkit::TextInput::CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY, Property::UNSIGNED_INTEGER, &TextInput::SetProperty, &TextInput::GetProperty );
+
+
 // [TextInput::HighlightInfo] /////////////////////////////////////////////////
 
 void TextInput::HighlightInfo::AddQuad( float x1, float y1, float x2, float y2 )
 // [TextInput::HighlightInfo] /////////////////////////////////////////////////
 
 void TextInput::HighlightInfo::AddQuad( float x1, float y1, float x2, float y2 )
@@ -270,7 +275,7 @@ Dali::Toolkit::TextInput TextInput::New()
 }
 
 TextInput::TextInput()
 }
 
 TextInput::TextInput()
-:ControlImpl( true ),
+:Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
  mState( StateEdit ),
  mStyledText(),
  mInputStyle(),
  mState( StateEdit ),
  mStyledText(),
  mInputStyle(),
@@ -296,6 +301,7 @@ TextInput::TextInput()
  mTouchStartTime( 0 ),
  mTextLayoutInfo(),
  mCurrentCopySelecton(),
  mTouchStartTime( 0 ),
  mTextLayoutInfo(),
  mCurrentCopySelecton(),
+ mPopUpPanel(),
  mScrollTimer(),
  mScrollDisplacement(),
  mCurrentHandlePosition(),
  mScrollTimer(),
  mScrollDisplacement(),
  mCurrentHandlePosition(),
@@ -305,6 +311,7 @@ TextInput::TextInput()
  mSelectionHandleFlipMargin( 0.0f, 0.0f, 0.0f, 0.0f ),
  mBoundingRectangleWorldCoordinates( 0.0f, 0.0f, 0.0f, 0.0f ),
  mClipboard(),
  mSelectionHandleFlipMargin( 0.0f, 0.0f, 0.0f, 0.0f ),
  mBoundingRectangleWorldCoordinates( 0.0f, 0.0f, 0.0f, 0.0f ),
  mClipboard(),
+ mMaterialColor( LIGHTBLUE ),
  mOverrideAutomaticAlignment( false ),
  mCursorRTLEnabled( false ),
  mClosestCursorPositionEOL ( false ),
  mOverrideAutomaticAlignment( false ),
  mCursorRTLEnabled( false ),
  mClosestCursorPositionEOL ( false ),
@@ -328,7 +335,7 @@ TextInput::TextInput()
  mUnderlinedPriorToPreEdit ( false ),
  mCommitByKeyInput( false ),
  mPlaceHolderSet( false ),
  mUnderlinedPriorToPreEdit ( false ),
  mCommitByKeyInput( false ),
  mPlaceHolderSet( false ),
- mMarkUpEnabled( true )
+ mMarkUpEnabled( false )
 {
   // Updates the line height accordingly with the input style.
   UpdateLineHeight();
 {
   // Updates the line height accordingly with the input style.
   UpdateLineHeight();
@@ -444,6 +451,8 @@ void TextInput::SetText(const std::string& initialText)
   RemoveHighlight();
 
   DrawCursor();
   RemoveHighlight();
 
   DrawCursor();
+
+  EmitTextModified();
 }
 
 void TextInput::SetText( const MarkupProcessor::StyledTextArray& styleText )
 }
 
 void TextInput::SetText( const MarkupProcessor::StyledTextArray& styleText )
@@ -489,6 +498,8 @@ void TextInput::SetText( const MarkupProcessor::StyledTextArray& styleText )
                                              Toolkit::Alignment::VerticalTop ) );
     mDisplayedTextView.SetLineJustification( leftToRight ? Toolkit::TextView::Left : Toolkit::TextView::Right);
   }
                                              Toolkit::Alignment::VerticalTop ) );
     mDisplayedTextView.SetLineJustification( leftToRight ? Toolkit::TextView::Left : Toolkit::TextView::Right);
   }
+
+  EmitTextModified();
 }
 
 void TextInput::SetMaxCharacterLength(std::size_t maxChars)
 }
 
 void TextInput::SetMaxCharacterLength(std::size_t maxChars)
@@ -516,6 +527,24 @@ std::size_t TextInput::GetNumberOfCharacters() const
   return mStyledText.size();
 }
 
   return mStyledText.size();
 }
 
+// Styling
+void TextInput::SetMaterialDiffuseColor( const Vector4& color )
+{
+  mMaterialColor = color;
+  if ( mCustomMaterial )
+  {
+    mCustomMaterial.SetDiffuseColor( mMaterialColor );
+    mMeshData.SetMaterial( mCustomMaterial );
+  }
+}
+
+const Vector4& TextInput::GetMaterialDiffuseColor() const
+{
+  return mMaterialColor;
+}
+
+// Signals
+
 Toolkit::TextInput::InputSignalV2& TextInput::InputStartedSignal()
 {
   return mInputStartedSignalV2;
 Toolkit::TextInput::InputSignalV2& TextInput::InputStartedSignal()
 {
   return mInputStartedSignalV2;
@@ -536,6 +565,11 @@ Toolkit::TextInput::StyleChangedSignalV2& TextInput::StyleChangedSignal()
   return mStyleChangedSignalV2;
 }
 
   return mStyleChangedSignalV2;
 }
 
+Toolkit::TextInput::TextModifiedSignalType& TextInput::TextModifiedSignal()
+{
+  return mTextModifiedSignal;
+}
+
 Toolkit::TextInput::MaxInputCharactersReachedSignalV2& TextInput::MaxInputCharactersReachedSignal()
 {
   return mMaxInputCharactersReachedSignalV2;
 Toolkit::TextInput::MaxInputCharactersReachedSignalV2& TextInput::MaxInputCharactersReachedSignal()
 {
   return mMaxInputCharactersReachedSignalV2;
@@ -748,6 +782,9 @@ void TextInput::SetBoundingRectangle( const Rect<float>& boundingRectangle )
                           originY + boundingRectangle.height );
 
   mBoundingRectangleWorldCoordinates = boundary;
                           originY + boundingRectangle.height );
 
   mBoundingRectangleWorldCoordinates = boundary;
+
+  // Set Boundary for Popup so it keeps the Pop-up within the area also.
+  mPopUpPanel.SetPopupBoundary( boundingRectangle );
 }
 
 const Rect<float> TextInput::GetBoundingRectangle() const
 }
 
 const Rect<float> TextInput::GetBoundingRectangle() const
@@ -1045,6 +1082,7 @@ void TextInput::OnKeyInputFocusLost()
     RemovePreEditStyle();
     const std::size_t numberOfCharactersDeleted = DeletePreEdit();
     InsertAt( mPreEditString, mPreEditStartPosition, numberOfCharactersDeleted );
     RemovePreEditStyle();
     const std::size_t numberOfCharactersDeleted = DeletePreEdit();
     InsertAt( mPreEditString, mPreEditStartPosition, numberOfCharactersDeleted );
+    EmitTextModified();
   }
 
   ImfManager imfManager = ImfManager::Get();
   }
 
   ImfManager imfManager = ImfManager::Get();
@@ -1351,7 +1389,7 @@ void TextInput::OnDoubleTap(Dali::Actor actor, Dali::TapGesture tap)
      SelectText( start, end );
    }
    // if no text but clipboard has content then show paste option
      SelectText( start, end );
    }
    // if no text but clipboard has content then show paste option
-   if ( mClipboard.NumberOfItems() || !mStyledText.empty() )
+   if ( ( mClipboard && mClipboard.NumberOfItems() ) || !mStyledText.empty() )
    {
      ShowPopupCutCopyPaste();
    }
    {
      ShowPopupCutCopyPaste();
    }
@@ -1541,7 +1579,7 @@ void TextInput::OnLongPress(Dali::Actor actor, Dali::LongPressGesture longPress)
     }
 
     // if no text but clipboard has content then show paste option, if no text and clipboard empty then do nothing
     }
 
     // if no text but clipboard has content then show paste option, if no text and clipboard empty then do nothing
-    if ( mClipboard.NumberOfItems() || !mStyledText.empty() )
+    if ( ( mClipboard && mClipboard.NumberOfItems() ) || !mStyledText.empty() )
     {
       ShowPopupCutCopyPaste();
     }
     {
       ShowPopupCutCopyPaste();
     }
@@ -1568,7 +1606,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button )
 
   const std::string& name = button.GetName();
 
 
   const std::string& name = button.GetName();
 
-  if(name == OPTION_SELECT_WORD)
+  if(name == TextInputPopup::OPTION_SELECT_WORD)
   {
     std::size_t start = 0;
     std::size_t end = 0;
   {
     std::size_t start = 0;
     std::size_t end = 0;
@@ -1576,7 +1614,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button )
 
     SelectText( start, end );
   }
 
     SelectText( start, end );
   }
-  else if(name == OPTION_SELECT_ALL)
+  else if(name == TextInputPopup::OPTION_SELECT_ALL)
   {
     SetCursorVisibility(false);
     StopCursorBlinkTimer();
   {
     SetCursorVisibility(false);
     StopCursorBlinkTimer();
@@ -1586,7 +1624,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button )
 
     SelectText( start, end );
   }
 
     SelectText( start, end );
   }
-  else if(name == OPTION_CUT)
+  else if(name == TextInputPopup::OPTION_CUT)
   {
     bool ret = CopySelectedTextToClipboard();
 
   {
     bool ret = CopySelectedTextToClipboard();
 
@@ -1601,7 +1639,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button )
 
     HidePopup();
   }
 
     HidePopup();
   }
-  else if(name == OPTION_COPY)
+  else if(name == TextInputPopup::OPTION_COPY)
   {
     CopySelectedTextToClipboard();
 
   {
     CopySelectedTextToClipboard();
 
@@ -1612,7 +1650,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button )
 
     HidePopup();
   }
 
     HidePopup();
   }
-  else if(name == OPTION_PASTE)
+  else if(name == TextInputPopup::OPTION_PASTE)
   {
     const Text retrievedString( mClipboard.GetItem( 0 ) );  // currently can only get first item in clip board, index 0;
 
   {
     const Text retrievedString( mClipboard.GetItem( 0 ) );  // currently can only get first item in clip board, index 0;
 
@@ -1623,10 +1661,9 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button )
 
     ShowGrabHandleAndSetVisibility( false );
 
 
     ShowGrabHandleAndSetVisibility( false );
 
-
     HidePopup();
   }
     HidePopup();
   }
-  else if(name == OPTION_CLIPBOARD)
+  else if(name == TextInputPopup::OPTION_CLIPBOARD)
   {
     // In the case of clipboard being shown we do not want to show updated pop-up after hide animation completes
     // Hence pass the false parameter for signalFinished.
   {
     // In the case of clipboard being shown we do not want to show updated pop-up after hide animation completes
     // Hence pass the false parameter for signalFinished.
@@ -1715,7 +1752,7 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event)
         mPreEditFlag = true;
         mIgnoreCommitFlag = false;
       }
         mPreEditFlag = true;
         mIgnoreCommitFlag = false;
       }
-
+      EmitTextModified();
       update = true;
     }
     else
       update = true;
     }
     else
@@ -1740,7 +1777,7 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event)
     {
       mCommitByKeyInput = true;
     }
     {
       mCommitByKeyInput = true;
     }
-
+    EmitTextModified();
     update = true;
   } // space
   else if (keyName == "BackSpace")
     update = true;
   } // space
   else if (keyName == "BackSpace")
@@ -1759,6 +1796,7 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event)
         update = true;
       }
     }
         update = true;
       }
     }
+    EmitTextModified();
   } // BackSpace
   else if (keyName == "Right")
   {
   } // BackSpace
   else if (keyName == "Right")
   {
@@ -1785,6 +1823,7 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event)
       // Received key String
       mCursorPosition = mCursorPosition + InsertAt( Text( keyString ), mCursorPosition, 0 );
       update = true;
       // Received key String
       mCursorPosition = mCursorPosition + InsertAt( Text( keyString ), mCursorPosition, 0 );
       update = true;
+      EmitTextModified();
     }
   }
 
     }
   }
 
@@ -2038,7 +2077,7 @@ void TextInput::CreateTextViewActor()
   mDisplayedTextView.SetLineJustification( Toolkit::TextView::Left );
   mDisplayedTextView.SetTextAlignment( static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalLeft | Toolkit::Alignment::VerticalTop ) );
   mDisplayedTextView.SetPosition( Vector3( 0.0f, 0.0f, DISPLAYED_TEXT_VIEW_Z_OFFSET ) );
   mDisplayedTextView.SetLineJustification( Toolkit::TextView::Left );
   mDisplayedTextView.SetTextAlignment( static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalLeft | Toolkit::Alignment::VerticalTop ) );
   mDisplayedTextView.SetPosition( Vector3( 0.0f, 0.0f, DISPLAYED_TEXT_VIEW_Z_OFFSET ) );
-  mDisplayedTextView.SetSizePolicy( Control::Fixed, Control::Fixed );
+  mDisplayedTextView.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
 
   mDisplayedTextView.ScrolledSignal().Connect( this, &TextInput::OnTextViewScrolled );
 
 
   mDisplayedTextView.ScrolledSignal().Connect( this, &TextInput::OnTextViewScrolled );
 
@@ -2100,7 +2139,7 @@ void TextInput::ApplyPreEditStyle( std::size_t preEditStartPosition, std::size_t
 {
   if ( mPreEditFlag && ( preEditStringLength > 0 ) )
   {
 {
   if ( mPreEditFlag && ( preEditStringLength > 0 ) )
   {
-    mUnderlinedPriorToPreEdit = mInputStyle.GetUnderline();
+    mUnderlinedPriorToPreEdit = mInputStyle.IsUnderlineEnabled();
     TextStyle style;
     style.SetUnderline( true );
     ApplyStyleToRange( style, TextStyle::UNDERLINE , preEditStartPosition, preEditStartPosition + preEditStringLength -1 );
     TextStyle style;
     style.SetUnderline( true );
     ApplyStyleToRange( style, TextStyle::UNDERLINE , preEditStartPosition, preEditStartPosition + preEditStringLength -1 );
@@ -2235,6 +2274,8 @@ ImfManager::ImfCallbackData TextInput::ImfEventReceived( Dali::ImfManager& imfMa
       mCursorPosition = toDelete;
       mNumberOfSurroundingCharactersDeleted = numberOfCharacters;
 
       mCursorPosition = toDelete;
       mNumberOfSurroundingCharactersDeleted = numberOfCharacters;
 
+      EmitTextModified();
+
       DALI_LOG_INFO( gLogFilter, Debug::General, "ImfEventReceived - deleteSurrounding post-delete range mCursorPosition[%u] \n", mCursorPosition);
       break;
     }
       DALI_LOG_INFO( gLogFilter, Debug::General, "ImfEventReceived - deleteSurrounding post-delete range mCursorPosition[%u] \n", mCursorPosition);
       break;
     }
@@ -2326,6 +2367,7 @@ bool TextInput::PreEditReceived(const std::string& keyString, std::size_t cursor
           mDisplayedTextView.RemoveTextFrom( mPreEditStartPosition, numberOfCharactersToReplace );
         }
         GetTextLayoutInfo();
           mDisplayedTextView.RemoveTextFrom( mPreEditStartPosition, numberOfCharactersToReplace );
         }
         GetTextLayoutInfo();
+        EmitTextModified();
       }
       else
       {
       }
       else
       {
@@ -2335,6 +2377,7 @@ bool TextInput::PreEditReceived(const std::string& keyString, std::size_t cursor
         mCursorPosition = mPreEditStartPosition + std::min( cursorOffset, mPreEditLength );
         ApplyPreEditStyle( mPreEditStartPosition, mPreEditLength );
         DALI_LOG_INFO(gLogFilter, Debug::General, "PreEditReceived mCursorPosition[%u] \n", mCursorPosition);
         mCursorPosition = mPreEditStartPosition + std::min( cursorOffset, mPreEditLength );
         ApplyPreEditStyle( mPreEditStartPosition, mPreEditLength );
         DALI_LOG_INFO(gLogFilter, Debug::General, "PreEditReceived mCursorPosition[%u] \n", mCursorPosition);
+        EmitTextModified();
       }
       // cursor update to keyboard is not done here as the keyboard knows the cursor position and provides the 'cursorOffset'.
       DrawCursor();
       }
       // cursor update to keyboard is not done here as the keyboard knows the cursor position and provides the 'cursorOffset'.
       DrawCursor();
@@ -2354,9 +2397,9 @@ bool TextInput::PreEditReceived(const std::string& keyString, std::size_t cursor
       mCursorPosition = mPreEditStartPosition + std::min( cursorOffset, mPreEditLength );
       ApplyPreEditStyle( mPreEditStartPosition, mPreEditLength );
       DALI_LOG_INFO(gLogFilter, Debug::General, "PreEditReceived mCursorPosition[%u] mPreEditStartPosition[%u]\n", mCursorPosition, mPreEditStartPosition);
       mCursorPosition = mPreEditStartPosition + std::min( cursorOffset, mPreEditLength );
       ApplyPreEditStyle( mPreEditStartPosition, mPreEditLength );
       DALI_LOG_INFO(gLogFilter, Debug::General, "PreEditReceived mCursorPosition[%u] mPreEditStartPosition[%u]\n", mCursorPosition, mPreEditStartPosition);
-
       // cursor update to keyboard is not done here as the keyboard knows the cursor position and provides the 'cursorOffset'.
       DrawCursor();
       // cursor update to keyboard is not done here as the keyboard knows the cursor position and provides the 'cursorOffset'.
       DrawCursor();
+      EmitTextModified();
     }
     else
     {
     }
     else
     {
@@ -2417,6 +2460,8 @@ bool TextInput::CommitReceived(const std::string& keyString )
         }
       }
 
         }
       }
 
+      EmitTextModified();
+
       if ( mSelectTextOnCommit )
       {
         SelectText(mRequestedSelection.mStartOfSelection, mRequestedSelection.mEndOfSelection );
       if ( mSelectTextOnCommit )
       {
         SelectText(mRequestedSelection.mStartOfSelection, mRequestedSelection.mEndOfSelection );
@@ -2438,6 +2483,7 @@ bool TextInput::CommitReceived(const std::string& keyString )
         mCursorPosition = mCursorPosition + InsertAt( Text( keyString ), mCursorPosition, mNumberOfSurroundingCharactersDeleted );
         update = true;
         mNumberOfSurroundingCharactersDeleted = 0;
         mCursorPosition = mCursorPosition + InsertAt( Text( keyString ), mCursorPosition, mNumberOfSurroundingCharactersDeleted );
         update = true;
         mNumberOfSurroundingCharactersDeleted = 0;
+        EmitTextModified();
       }
       else
       {
       }
       else
       {
@@ -2855,7 +2901,7 @@ void TextInput::DrawCursor(const std::size_t nthChar)
   mCursor.SetSize(size);
 
   // If the character is italic then the cursor also tilts.
   mCursor.SetSize(size);
 
   // If the character is italic then the cursor also tilts.
-  mCursor.SetRotation( mInputStyle.GetItalics() ? Degree( mInputStyle.GetItalicsAngle() - CURSOR_ANGLE_OFFSET ) : Degree( 0.f ), Vector3::ZAXIS );
+  mCursor.SetRotation( mInputStyle.IsItalicsEnabled() ? Degree( mInputStyle.GetItalicsAngle() - CURSOR_ANGLE_OFFSET ) : Degree( 0.f ), Vector3::ZAXIS );
 
   DALI_ASSERT_DEBUG( mCursorPosition <= mTextLayoutInfo.mCharacterLayoutInfoTable.size() );
 
 
   DALI_ASSERT_DEBUG( mCursorPosition <= mTextLayoutInfo.mCharacterLayoutInfoTable.size() );
 
@@ -3649,9 +3695,9 @@ void TextInput::ClearPopup()
   mPopUpPanel.Clear();
 }
 
   mPopUpPanel.Clear();
 }
 
-void TextInput::AddPopupOption(const std::string& name, const std::string& caption, const Image icon, bool finalOption)
+void TextInput::AddPopupOptions()
 {
 {
-  mPopUpPanel.AddOption(name, caption, icon, finalOption);
+  mPopUpPanel.AddPopupOptions();
 }
 
 void TextInput::SetPopupPosition(const Vector3& position)
 }
 
 void TextInput::SetPopupPosition(const Vector3& position)
@@ -3699,7 +3745,7 @@ void TextInput::ShowPopup(bool animate)
     Vector3 bottomHandle;
     bottomHandle.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y );
     bottomHandle.y += GetSelectionHandleSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET;
     Vector3 bottomHandle;
     bottomHandle.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y );
     bottomHandle.y += GetSelectionHandleSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET;
-    mPopUpPanel.SetAlternativeOffset(Vector2(0.0f, bottomHandle.y - topHandle.y));
+    mPopUpPanel.SetAlternativeOffset(Vector2( mBoundingRectangleWorldCoordinates.x, bottomHandle.y - topHandle.y));
   }
   else
   {
   }
   else
   {
@@ -3708,11 +3754,11 @@ void TextInput::ShowPopup(bool animate)
     const Size rowSize = GetRowRectFromCharacterPosition( mCursorPosition );
     position.y -= rowSize.height;
     // if can't be positioned above, then position below row.
     const Size rowSize = GetRowRectFromCharacterPosition( mCursorPosition );
     position.y -= rowSize.height;
     // if can't be positioned above, then position below row.
-    Vector2 alternativePopUpPosition( 0.0f, position.y ); // default if no grab handle
+    Vector2 alternativePopUpPosition( mBoundingRectangleWorldCoordinates.x, position.y ); // default if no grab handle
     if ( mGrabHandle )
     {
     if ( mGrabHandle )
     {
-      alternativePopUpPosition.y = rowSize.height + ( mGrabHandle.GetCurrentSize().height * DEFAULT_GRAB_HANDLE_RELATIVE_SIZE.y ) ;
       // If grab handle enabled then position pop-up below the grab handle.
       // If grab handle enabled then position pop-up below the grab handle.
+      alternativePopUpPosition.y = rowSize.height + mGrabHandle.GetCurrentSize().height + BOTTOM_HANDLE_BOTTOM_OFFSET ;
     }
     mPopUpPanel.SetAlternativeOffset( alternativePopUpPosition );
   }
     }
     mPopUpPanel.SetAlternativeOffset( alternativePopUpPosition );
   }
@@ -3720,7 +3766,7 @@ void TextInput::ShowPopup(bool animate)
   // reposition popup above the desired cursor posiiton.
   Vector3 textViewSize = mDisplayedTextView.GetCurrentSize();
   textViewSize.z = 0.0f;
   // reposition popup above the desired cursor posiiton.
   Vector3 textViewSize = mDisplayedTextView.GetCurrentSize();
   textViewSize.z = 0.0f;
-  // World position = world position of ParentOrigin of cursor (i.e. top-left corner of TextView) + cursor position;
+  // World position = world position of local position i.e. top-left corner of TextView
   Vector3 worldPosition = mDisplayedTextView.GetCurrentWorldPosition() - (textViewSize * 0.5f) + position;
 
   SetPopupPosition( worldPosition );
   Vector3 worldPosition = mDisplayedTextView.GetCurrentWorldPosition() - (textViewSize * 0.5f) + position;
 
   SetPopupPosition( worldPosition );
@@ -3735,29 +3781,29 @@ void TextInput::ShowPopup(bool animate)
 void TextInput::ShowPopupCutCopyPaste()
 {
   ClearPopup();
 void TextInput::ShowPopupCutCopyPaste()
 {
   ClearPopup();
+
+  mPopUpPanel.CreateOrderedListOfOptions(); // todo Move this so only run when order has changed
   // Check the selected text is whole text or not.
   if( IsTextSelected() && ( mStyledText.size() != GetSelectedText().size() ) )
   {
   // Check the selected text is whole text or not.
   if( IsTextSelected() && ( mStyledText.size() != GetSelectedText().size() ) )
   {
-    Image selectAllIcon = Image::New( DEFAULT_ICON_SELECT_ALL );
-    AddPopupOption( OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsSelectAll, true );
   }
 
   if ( !mStyledText.empty() )
   {
   }
 
   if ( !mStyledText.empty() )
   {
-    Image cutIcon = Image::New( DEFAULT_ICON_CUT );
-    Image copyIcon = Image::New( DEFAULT_ICON_COPY );
-    AddPopupOption( OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), cutIcon );
-    AddPopupOption( OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), copyIcon, true );
+
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsCopy, true );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsCut, true );
   }
 
   }
 
-  if(mClipboard.NumberOfItems())
+  if( mClipboard && mClipboard.NumberOfItems() )
   {
   {
-    Image pasteIcon = Image::New( DEFAULT_ICON_PASTE );
-    Image clipboardIcon = Image::New( DEFAULT_ICON_CLIPBOARD );
-    AddPopupOption( OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon );
-    AddPopupOption( OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, true );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsPaste, true );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsClipboard, true );
   }
 
   }
 
+  AddPopupOptions();
+
   mPopUpPanel.Hide(false);
   ShowPopup();
 }
   mPopUpPanel.Hide(false);
   ShowPopup();
 }
@@ -3765,24 +3811,23 @@ void TextInput::ShowPopupCutCopyPaste()
 void TextInput::SetUpPopUpSelection()
 {
   ClearPopup();
 void TextInput::SetUpPopUpSelection()
 {
   ClearPopup();
-
+  mPopUpPanel.CreateOrderedListOfOptions(); // todo Move this so only run when order has changed
   // If no text exists then don't offer to select
   if ( !mStyledText.empty() )
   {
   // If no text exists then don't offer to select
   if ( !mStyledText.empty() )
   {
-    Image selectIcon = Image::New( DEFAULT_ICON_SELECT );
-    Image selectAllIcon = Image::New( DEFAULT_ICON_SELECT_ALL );
-    AddPopupOption( OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), selectIcon );
-    AddPopupOption( OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsSelectAll, true );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsSelect, true );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsCut, true );
   }
   // if clipboard has valid contents then offer paste option
   }
   // if clipboard has valid contents then offer paste option
-  if( mClipboard.NumberOfItems() )
+  if( mClipboard && mClipboard.NumberOfItems() )
   {
   {
-    Image pasteIcon = Image::New( DEFAULT_ICON_PASTE );
-    Image clipboardIcon = Image::New( DEFAULT_ICON_CLIPBOARD );
-    AddPopupOption( OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon, true );
-    AddPopupOption( OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, true );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsPaste, true );
+    mPopUpPanel.TogglePopUpButtonOnOff( TextInputPopup::ButtonsClipboard, true );
   }
 
   }
 
+  AddPopupOptions();
+
   mPopUpPanel.Hide(false);
 }
 
   mPopUpPanel.Hide(false);
 }
 
@@ -4653,7 +4698,7 @@ void TextInput::CreateHighlight()
     mMeshData.SetHasNormals( true );
 
     mCustomMaterial = Material::New("CustomMaterial");
     mMeshData.SetHasNormals( true );
 
     mCustomMaterial = Material::New("CustomMaterial");
-    mCustomMaterial.SetDiffuseColor( LIGHTBLUE );
+    mCustomMaterial.SetDiffuseColor( mMaterialColor );
 
     mMeshData.SetMaterial( mCustomMaterial );
 
 
     mMeshData.SetMaterial( mCustomMaterial );
 
@@ -5090,14 +5135,142 @@ void TextInput::GetTextLayoutInfo()
   }
 }
 
   }
 }
 
+void TextInput::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::TextInput textInput = Toolkit::TextInput::DownCast( Dali::BaseHandle( object ) );
+
+  if ( textInput )
+  {
+    TextInput& textInputImpl( GetImpl( textInput ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::TextInput::HIGHLIGHT_COLOR_PROPERTY:
+      {
+        textInputImpl.SetMaterialDiffuseColor( value.Get< Vector4 >() );
+        break;
+      }
+      case Toolkit::TextInput::CUT_AND_PASTE_COLOR_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetCutPastePopUpColor( value.Get< Vector4 >() );
+        break;
+      }
+      case Toolkit::TextInput::CUT_AND_PASTE_PRESSED_COLOR_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetCutPastePopUpPressedColor( value.Get< Vector4 >() );
+        break;
+      }
+      case Toolkit::TextInput::CUT_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsCut, value.Get<unsigned int>() );
+        break;
+      }
+      case Toolkit::TextInput::COPY_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsCopy, value.Get<unsigned int>() );
+        break;
+      }
+      case Toolkit::TextInput::PASTE_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsPaste, value.Get<unsigned int>() );
+        break;
+      }
+      case Toolkit::TextInput::SELECT_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsSelect, value.Get<unsigned int>() );
+        break;
+      }
+      case Toolkit::TextInput::SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsSelectAll, value.Get<unsigned int>() );
+        break;
+      }
+      case Toolkit::TextInput::CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        textInputImpl.mPopUpPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsClipboard, value.Get<unsigned int>() );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value TextInput::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::TextInput textInput = Toolkit::TextInput::DownCast( Dali::BaseHandle( object ) );
+
+  if ( textInput )
+  {
+    TextInput& textInputImpl( GetImpl( textInput ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::TextInput::HIGHLIGHT_COLOR_PROPERTY:
+      {
+        value = textInputImpl.GetMaterialDiffuseColor();
+        break;
+      }
+      case Toolkit::TextInput::CUT_AND_PASTE_COLOR_PROPERTY:
+      {
+        value = textInputImpl.mPopUpPanel.GetCutPastePopUpColor();
+        break;
+      }
+      case Toolkit::TextInput::CUT_AND_PASTE_PRESSED_COLOR_PROPERTY:
+      {
+        value = textInputImpl.mPopUpPanel.GetCutPastePopUpPressedColor();
+        break;
+      }
+      case Toolkit::TextInput::CUT_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        value = textInputImpl.mPopUpPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsCut );
+        break;
+      }
+      case Toolkit::TextInput::COPY_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        value =  textInputImpl.mPopUpPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsCopy );
+        break;
+      }
+      case Toolkit::TextInput::PASTE_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        value = textInputImpl.mPopUpPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsPaste );
+        break;
+      }
+      case Toolkit::TextInput::SELECT_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        value = textInputImpl.mPopUpPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsSelect );
+        break;
+      }
+      case Toolkit::TextInput::SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        value = textInputImpl.mPopUpPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsSelectAll );
+        break;
+      }
+      case Toolkit::TextInput::CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY:
+      {
+        value = textInputImpl.mPopUpPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsClipboard );
+        break;
+      }
+    }
+  }
+  return value;
+}
+
 void TextInput::EmitStyleChangedSignal()
 {
   // emit signal if input style changes.
 void TextInput::EmitStyleChangedSignal()
 {
   // emit signal if input style changes.
-
   Toolkit::TextInput handle( GetOwner() );
   mStyleChangedSignalV2.Emit( handle, mInputStyle );
 }
 
   Toolkit::TextInput handle( GetOwner() );
   mStyleChangedSignalV2.Emit( handle, mInputStyle );
 }
 
+void TextInput::EmitTextModified()
+{
+  // emit signal when text changes.
+  Toolkit::TextInput handle( GetOwner() );
+  mTextModifiedSignal.Emit( handle );
+}
+
+
 void TextInput::EmitMaxInputCharactersReachedSignal()
 {
   // emit signal if max characters is reached during text input.
 void TextInput::EmitMaxInputCharactersReachedSignal()
 {
   // emit signal if max characters is reached during text input.