Move FontDefaults Declaration/Definition as it's needed by the TextInput.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
index 3981ce1..591dbaf 100644 (file)
@@ -70,6 +70,31 @@ namespace Toolkit
 namespace Text
 {
 
+struct Controller::FontDefaults
+{
+  FontDefaults()
+  : mDefaultPointSize(0.0f),
+    mFontId(0u)
+  {
+  }
+
+  FontId GetFontId( TextAbstraction::FontClient& fontClient )
+  {
+    if( !mFontId )
+    {
+      Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
+      mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
+    }
+
+    return mFontId;
+  }
+
+  std::string mDefaultFontFamily;
+  std::string mDefaultFontStyle;
+  float mDefaultPointSize;
+  FontId mFontId;
+};
+
 struct Controller::TextInput
 {
   // Used to queue input events until DoRelayout()
@@ -109,7 +134,8 @@ struct Controller::TextInput
   {
     INACTIVE,
     SELECTING,
-    EDITING
+    EDITING,
+    EDITING_WITH_POPUP
   };
 
   TextInput( LogicalModelPtr logicalModel,
@@ -123,9 +149,9 @@ struct Controller::TextInput
     mSecondaryCursorPosition( 0u ),
     mDecoratorUpdated( false ),
     mCursorBlinkEnabled( true ),
-    mGrabHandleEnabled( false ),
-    mGrabHandlePopupEnabled( false ),
-    mSelectionEnabled( false ),
+    mGrabHandleEnabled( true ),
+    mGrabHandlePopupEnabled( true ),
+    mSelectionEnabled( true ),
     mHorizontalScrollingEnabled( true ),
     mVerticalScrollingEnabled( false ),
     mUpdateCursorPosition( false )
@@ -244,7 +270,7 @@ struct Controller::TextInput
       float yPosition = event.p3.mFloat - alignmentOffset.y;
       float height(0.0f);
       GetClosestCursorPosition( mPrimaryCursorPosition, xPosition, yPosition, height );
-      mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
+      mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height, height ); // TODO: To be fixed in the next patch.
       mUpdateCursorPosition = false;
 
       mDecoratorUpdated = true;
@@ -253,6 +279,8 @@ struct Controller::TextInput
              2u == tapCount )
     {
       ChangeState( SELECTING );
+
+      RepositionSelectionHandles( event.p2.mFloat, event.p3.mFloat );
     }
   }
 
@@ -322,14 +350,48 @@ struct Controller::TextInput
 
       GetClosestCursorPosition( mPrimaryCursorPosition, xPosition, yPosition, height );
 
-      mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
-      mDecorator->HidePopup();
+      mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height, height ); // TODO: To be fixed in the next patch.
+
+      //mDecorator->HidePopup();
+      ChangeState ( EDITING );
       mDecoratorUpdated = true;
     }
     else if ( mGrabHandlePopupEnabled &&
               GRAB_HANDLE_RELEASED == state )
     {
-      mDecorator->ShowPopup();
+      //mDecorator->ShowPopup();
+      ChangeState ( EDITING_WITH_POPUP );
+      mDecoratorUpdated = true;
+    }
+  }
+
+  void RepositionSelectionHandles( float visualX, float visualY )
+  {
+    // TODO - Find which word was selected
+
+    const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
+    const Vector<Vector2>::SizeType glyphCount = glyphs.Count();
+
+    const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
+    const Vector<Vector2>::SizeType positionCount = positions.Count();
+
+    // Guard against glyphs which did not fit inside the layout
+    const Vector<Vector2>::SizeType count = (positionCount < glyphCount) ? positionCount : glyphCount;
+
+    if( count )
+    {
+      float primaryX   = positions[0].x;
+      float secondaryX = positions[count-1].x + glyphs[count-1].width;
+
+      // TODO - multi-line selection
+      const Vector<LineRun>& lines = mVisualModel->mLines;
+      float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
+
+      mDecorator->SetPosition( PRIMARY_SELECTION_HANDLE,   primaryX,   0.0f, height );
+      mDecorator->SetPosition( SECONDARY_SELECTION_HANDLE, secondaryX, 0.0f, height );
+
+      mDecorator->ClearHighlights();
+      mDecorator->AddHighlight( primaryX, 0.0f, secondaryX, height );
     }
   }
 
@@ -345,7 +407,7 @@ struct Controller::TextInput
         mDecorator->StopCursorBlink();
         mDecorator->SetGrabHandleActive( false );
         mDecorator->SetSelectionActive( false );
-        mDecorator->HidePopup();
+        mDecorator->SetPopupActive( false );
         mDecoratorUpdated = true;
       }
       else if ( SELECTING == mState )
@@ -367,6 +429,28 @@ struct Controller::TextInput
         {
           mDecorator->SetGrabHandleActive( true );
         }
+        if( mGrabHandlePopupEnabled )
+        {
+          mDecorator->SetPopupActive( false );
+        }
+        mDecorator->SetSelectionActive( false );
+        mDecoratorUpdated = true;
+      }
+      else if( EDITING_WITH_POPUP == mState )
+      {
+        mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mCursorBlinkEnabled )
+        {
+          mDecorator->StartCursorBlink();
+        }
+        if( mGrabHandleEnabled )
+        {
+          mDecorator->SetGrabHandleActive( true );
+        }
+        if( mGrabHandlePopupEnabled )
+        {
+          mDecorator->SetPopupActive( true );
+        }
         mDecorator->SetSelectionActive( false );
         mDecoratorUpdated = true;
       }
@@ -380,14 +464,15 @@ struct Controller::TextInput
     const Vector<LineRun>& lines = mVisualModel->mLines;
     for( float totalHeight = 0; lineIndex < lines.Count(); ++lineIndex )
     {
-      totalHeight += lines[lineIndex].lineSize.height;
+      const LineRun& lineRun = lines[lineIndex];
+      totalHeight += lineRun.ascender + -lineRun.descender;
       if( y < totalHeight )
       {
-        break;
+        return lineIndex;
       }
     }
 
-    return lineIndex;
+    return lineIndex-1;
   }
 
   void GetClosestCursorPosition( CharacterIndex& logical, float& visualX, float& visualY, float& height )
@@ -457,7 +542,7 @@ struct Controller::TextInput
     }
     visualY = 0.0f;
 
-    height = line.lineSize.height;
+    height = line.ascender + -line.descender;
   }
 
   void UpdateCursorPosition()
@@ -483,7 +568,7 @@ struct Controller::TextInput
 
     float visualX( 0.0f );
     float visualY( 0.0f );
-    LineIndex lineIndex( 0u );
+    float height( 0.0f );
     const Vector<LineRun>& lineRuns = mVisualModel->mLines;
 
     if( cursorGlyph > 0 )
@@ -495,17 +580,20 @@ struct Controller::TextInput
         visualX += mVisualModel->mGlyphs[ cursorGlyph ].width;
 
       // Find the line height
-      for( GlyphIndex lastGlyph = 0; lineIndex < lineRuns.Count(); ++lineIndex )
+      GlyphIndex lastGlyph( 0 );
+      for( LineIndex lineIndex = 0u; lineIndex < lineRuns.Count(); ++lineIndex )
       {
         lastGlyph = (lineRuns[lineIndex].glyphIndex + lineRuns[lineIndex].numberOfGlyphs);
         if( cursorGlyph < lastGlyph )
         {
+          const LineRun& lineRun = lineRuns[lineIndex];
+          height = lineRun.ascender + -lineRun.descender;
           break;
         }
       }
     }
 
-    mDecorator->SetPosition( PRIMARY_CURSOR, visualX, visualY, lineRuns[lineIndex].lineSize.height );
+    mDecorator->SetPosition( PRIMARY_CURSOR, visualX, visualY, height, height ); // TODO: To be fixed in the next patch.
     mDecoratorUpdated = true;
   }
 
@@ -542,31 +630,6 @@ struct Controller::TextInput
   bool mUpdateCursorPosition       : 1; ///< True if the visual position of the cursor must be recalculated
 };
 
-struct Controller::FontDefaults
-{
-  FontDefaults()
-  : mDefaultPointSize(0.0f),
-    mFontId(0u)
-  {
-  }
-
-  FontId GetFontId( TextAbstraction::FontClient& fontClient )
-  {
-    if( !mFontId )
-    {
-      Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
-      mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
-    }
-
-    return mFontId;
-  }
-
-  std::string mDefaultFontFamily;
-  std::string mDefaultFontStyle;
-  float mDefaultPointSize;
-  FontId mFontId;
-};
-
 struct Controller::Impl
 {
   Impl( ControlInterface& controlInterface )
@@ -590,6 +653,12 @@ struct Controller::Impl
     mFontClient = TextAbstraction::FontClient::Get();
 
     mView.SetVisualModel( mVisualModel );
+
+    // Set the text properties to default
+    mVisualModel->SetTextColor( Color::WHITE );
+    mVisualModel->SetShadowOffset( Vector2::ZERO );
+    mVisualModel->SetShadowColor( Vector4::ZERO );
+    mVisualModel->SetUnderlineEnabled( false );
   }
 
   ~Impl()
@@ -677,6 +746,18 @@ void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
+
+  // Clear the font-specific data
+  mImpl->mLogicalModel->mFontRuns.Clear();
+  mImpl->mVisualModel->mGlyphs.Clear();
+  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+  mImpl->mVisualModel->mCharactersToGlyph.Clear();
+  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+  mImpl->mVisualModel->mGlyphPositions.Clear();
+  mImpl->mVisualModel->mLines.Clear();
+
+  RequestRelayout();
 }
 
 const std::string& Controller::GetDefaultFontFamily() const
@@ -700,6 +781,18 @@ void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
+
+  // Clear the font-specific data
+  mImpl->mLogicalModel->mFontRuns.Clear();
+  mImpl->mVisualModel->mGlyphs.Clear();
+  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+  mImpl->mVisualModel->mCharactersToGlyph.Clear();
+  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+  mImpl->mVisualModel->mGlyphPositions.Clear();
+  mImpl->mVisualModel->mLines.Clear();
+
+  RequestRelayout();
 }
 
 const std::string& Controller::GetDefaultFontStyle() const
@@ -723,6 +816,18 @@ void Controller::SetDefaultPointSize( float pointSize )
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
+
+  // Clear the font-specific data
+  mImpl->mLogicalModel->mFontRuns.Clear();
+  mImpl->mVisualModel->mGlyphs.Clear();
+  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+  mImpl->mVisualModel->mCharactersToGlyph.Clear();
+  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+  mImpl->mVisualModel->mGlyphPositions.Clear();
+  mImpl->mVisualModel->mLines.Clear();
+
+  RequestRelayout();
 }
 
 float Controller::GetDefaultPointSize() const
@@ -749,6 +854,56 @@ void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharact
   }
 }
 
+const Vector4& Controller::GetTextColor() const
+{
+  return mImpl->mVisualModel->GetTextColor();
+}
+
+const Vector2& Controller::GetShadowOffset() const
+{
+  return mImpl->mVisualModel->GetShadowOffset();
+}
+
+const Vector4& Controller::GetShadowColor() const
+{
+  return mImpl->mVisualModel->GetShadowColor();
+}
+
+const Vector4& Controller::GetUnderlineColor() const
+{
+  return mImpl->mVisualModel->GetUnderlineColor();
+}
+
+bool Controller::IsUnderlineEnabled() const
+{
+  return mImpl->mVisualModel->IsUnderlineEnabled();
+}
+
+void Controller::SetTextColor( const Vector4& textColor )
+{
+  mImpl->mVisualModel->SetTextColor( textColor );
+}
+
+void Controller::SetShadowOffset( const Vector2& shadowOffset )
+{
+  mImpl->mVisualModel->SetShadowOffset( shadowOffset );
+}
+
+void Controller::SetShadowColor( const Vector4& shadowColor )
+{
+  mImpl->mVisualModel->SetShadowColor( shadowColor );
+}
+
+void Controller::SetUnderlineColor( const Vector4& color )
+{
+  mImpl->mVisualModel->SetUnderlineColor( color );
+}
+
+void Controller::SetUnderlineEnabled( bool enabled )
+{
+  mImpl->mVisualModel->SetUnderlineEnabled( enabled );
+}
+
 void Controller::EnableTextInput( DecoratorPtr decorator )
 {
   if( !mImpl->mTextInput )
@@ -1270,6 +1425,10 @@ void Controller::UpdateModel( OperationsMask operationsRequired )
                glyphs,
                glyphsToCharactersMap,
                charactersPerGlyph );
+
+    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+    mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
+    mImpl->mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
   }
 
   const Length numberOfGlyphs = glyphs.Count();
@@ -1278,13 +1437,6 @@ void Controller::UpdateModel( OperationsMask operationsRequired )
   {
     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
   }
-
-  if( 0u != numberOfGlyphs )
-  {
-    // Create the glyph to character conversion table and the 'number of glyphs' per character.
-    mImpl->mVisualModel->CreateCharacterToGlyphTable(numberOfCharacters );
-    mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
-  }
 }
 
 bool Controller::DoRelayout( const Size& size,
@@ -1419,49 +1571,66 @@ bool Controller::DoRelayout( const Size& size,
 
 void Controller::CalculateTextAlignment( const Size& size )
 {
-  // TODO : Calculate the vertical offset.
-
   // Get the direction of the first character.
   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
 
   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
 
   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
-  LayoutEngine::Alignment alignment = mImpl->mLayoutEngine.GetAlignment();
+  LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
   if( firstParagraphDirection &&
-      ( LayoutEngine::ALIGN_CENTER != alignment ) )
+      ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
   {
-    if( LayoutEngine::ALIGN_BEGIN == alignment )
+    if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
     {
-      alignment = LayoutEngine::ALIGN_END;
+      horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
     }
     else
     {
-      alignment = LayoutEngine::ALIGN_BEGIN;
+      horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
     }
   }
 
-  switch( alignment )
+  switch( horizontalAlignment )
   {
-    case LayoutEngine::ALIGN_BEGIN:
+    case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
     {
-      mImpl->mAlignmentOffset = Vector2::ZERO;
+      mImpl->mAlignmentOffset.x = 0.f;
       break;
     }
-    case LayoutEngine::ALIGN_CENTER:
+    case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
     {
-      mImpl->mAlignmentOffset.y = 0.f;
       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
       break;
     }
-    case LayoutEngine::ALIGN_END:
+    case LayoutEngine::HORIZONTAL_ALIGN_END:
     {
-      mImpl->mAlignmentOffset.y = 0.f;
       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
       break;
     }
   }
+
+  const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
+  switch( verticalAlignment )
+  {
+    case LayoutEngine::VERTICAL_ALIGN_TOP:
+    {
+      mImpl->mAlignmentOffset.y = 0.f;
+      break;
+    }
+    case LayoutEngine::VERTICAL_ALIGN_CENTER:
+    {
+      const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
+      mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
+      break;
+    }
+    case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
+    {
+      mImpl->mAlignmentOffset.y = size.height - actualSize.height;
+      break;
+    }
+  }
 }
 
 View& Controller::GetView()
@@ -1546,6 +1715,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       mImpl->mModifyEvents.push_back( event );
     }
 
+    mImpl->mTextInput->ChangeState( TextInput::EDITING ); // todo Confirm this is the best place to change the state of
+
     RequestRelayout();
   }