void Controller::SetText( const std::string& text )
{
- // Cancel previously queued inserts etc.
- mImpl->mModifyEvents.clear();
-
// Remove the previously set text
ResetText();
- if( ! text.empty() )
+ CharacterIndex lastCursorIndex = 0u;
+
+ if( !text.empty() )
{
// Convert text into UTF-32
Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
DALI_ASSERT_DEBUG( text.size() >= characterCount && "Invalid UTF32 conversion length" );
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, text.size(), mImpl->mLogicalModel->mText.Count() );
- // Reset the cursor position
- if( mImpl->mEventData )
- {
- mImpl->mEventData->mPrimaryCursorPosition = characterCount;
- }
+ // To reset the cursor position
+ lastCursorIndex = characterCount;
// Update the rest of the model during size negotiation
mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
+
+ // The natural size needs to be re-calculated.
+ mImpl->mRecalculateNaturalSize = true;
+
+ // Apply modifications to the model
+ mImpl->mOperationsPending = ALL_OPERATIONS;
}
else
{
ShowPlaceholderText();
}
+ // Resets the cursor position.
+ ResetCursorPosition( lastCursorIndex );
+
+ // Scrolls the text to make the cursor visible.
+ ResetScrollPosition();
+
+ mImpl->RequestRelayout();
+
if( mImpl->mEventData )
{
// Cancel previously queued events
// Reset keyboard as text changed
mImpl->ResetImfManager();
+
+ // Do this last since it provides callbacks into application code
+ mImpl->mControlInterface.TextChanged();
}
void Controller::GetText( std::string& text ) const
mImpl->mEventData->mPlaceholderTextActive = text;
}
- ShowPlaceholderText();
+ // Update placeholder if there is no text
+ if( mImpl->IsShowingPlaceholderText() ||
+ 0u == mImpl->mLogicalModel->mText.Count() )
+ {
+ ShowPlaceholderText();
+ }
}
}
{
mImpl->mTextColor = textColor;
- if( ! mImpl->IsShowingPlaceholderText() )
+ if( !mImpl->IsShowingPlaceholderText() )
{
mImpl->mVisualModel->SetTextColor( textColor );
+
+ mImpl->RequestRelayout();
}
}
if( mImpl->IsShowingPlaceholderText() )
{
mImpl->mVisualModel->SetTextColor( textColor );
+ mImpl->RequestRelayout();
}
}
void Controller::SetShadowOffset( const Vector2& shadowOffset )
{
mImpl->mVisualModel->SetShadowOffset( shadowOffset );
+
+ mImpl->RequestRelayout();
}
const Vector2& Controller::GetShadowOffset() const
void Controller::SetShadowColor( const Vector4& shadowColor )
{
mImpl->mVisualModel->SetShadowColor( shadowColor );
+
+ mImpl->RequestRelayout();
}
const Vector4& Controller::GetShadowColor() const
void Controller::SetUnderlineColor( const Vector4& color )
{
mImpl->mVisualModel->SetUnderlineColor( color );
+
+ mImpl->RequestRelayout();
}
const Vector4& Controller::GetUnderlineColor() const
void Controller::SetUnderlineEnabled( bool enabled )
{
mImpl->mVisualModel->SetUnderlineEnabled( enabled );
+
+ mImpl->RequestRelayout();
}
bool Controller::IsUnderlineEnabled() const
void Controller::SetUnderlineHeight( float height )
{
mImpl->mVisualModel->SetUnderlineHeight( height );
+
+ mImpl->RequestRelayout();
}
float Controller::GetUnderlineHeight() const
mImpl->mLogicalModel->mText.Clear();
ClearModelData();
- // Reset the cursor position
- if( mImpl->mEventData )
- {
- mImpl->mEventData->mPrimaryCursorPosition = 0;
- }
-
// We have cleared everything including the placeholder-text
mImpl->PlaceholderCleared();
mImpl->mOperationsPending = ALL_OPERATIONS;
}
+void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
+{
+ // Reset the cursor position
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
+
+ // Update the cursor if it's in editing mode.
+ if( ( EventData::EDITING == mImpl->mEventData->mState ) ||
+ ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) )
+ {
+ mImpl->mEventData->mUpdateCursorPosition = true;
+ }
+ }
+}
+
+void Controller::ResetScrollPosition()
+{
+ if( NULL != mImpl->mEventData )
+ {
+ // Reset the scroll position.
+ mImpl->mEventData->mScrollPosition = Vector2::ZERO;
+ mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
+ }
+}
+
void Controller::TextReplacedEvent()
{
// Reset buffers.
REORDER );
// Queue a cursor reposition event; this must wait until after DoRelayout()
- mImpl->mEventData->mUpdateCursorPosition = true;
- mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
+ mImpl->mEventData->mScrollAfterDelete = true;
}
bool Controller::DoRelayout( const Size& size,
}
} // REORDER
- if( ALIGN & operations )
- {
- mImpl->mLayoutEngine.Align( layoutParameters,
- layoutSize,
- lines,
- glyphPositions );
- }
-
// Sets the actual size.
if( UPDATE_ACTUAL_SIZE & operations )
{
layoutSize = mImpl->mVisualModel->GetActualSize();
}
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
+ if( ALIGN & operations )
+ {
+ // The laid-out lines.
+ Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
+
+ mImpl->mLayoutEngine.Align( layoutSize,
+ lines );
+
+ viewUpdated = true;
+ }
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
return viewUpdated;
}
+void Controller::SetMultiLineEnabled( bool enable )
+{
+ const LayoutEngine::Layout layout = enable ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
+
+ if( layout != mImpl->mLayoutEngine.GetLayout() )
+ {
+ // Set the layout type.
+ mImpl->mLayoutEngine.SetLayout( layout );
+
+ // Set the flags to redo the layout operations
+ const OperationsMask layoutOperations = static_cast<OperationsMask>( LAYOUT |
+ UPDATE_ACTUAL_SIZE |
+ ALIGN |
+ REORDER );
+
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
+
+ mImpl->RequestRelayout();
+ }
+}
+
+bool Controller::IsMultiLineEnabled() const
+{
+ return LayoutEngine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
+}
+
+void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment alignment )
+{
+ if( alignment != mImpl->mLayoutEngine.GetHorizontalAlignment() )
+ {
+ // Set the alignment.
+ mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
+
+ // Set the flag to redo the alignment operation.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
+
+ mImpl->RequestRelayout();
+ }
+}
+
+LayoutEngine::HorizontalAlignment Controller::GetHorizontalAlignment() const
+{
+ return mImpl->mLayoutEngine.GetHorizontalAlignment();
+}
+
+void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment )
+{
+ if( alignment != mImpl->mLayoutEngine.GetVerticalAlignment() )
+ {
+ // Set the alignment.
+ mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
+
+ // Set the flag to redo the alignment operation.
+ // TODO : Is not needed re-layout and reorder again but with the current implementation it is.
+ // Im working on a different patch to fix an issue with the alignment. When that patch
+ // is in, this issue can be fixed.
+ const OperationsMask layoutOperations = static_cast<OperationsMask>( LAYOUT |
+ UPDATE_ACTUAL_SIZE |
+ ALIGN |
+ REORDER );
+
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
+
+ mImpl->RequestRelayout();
+ }
+}
+
+LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
+{
+ return mImpl->mLayoutEngine.GetVerticalAlignment();
+}
+
void Controller::CalculateTextAlignment( const Size& size )
{
// Get the direction of the first character.
{
DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
+ bool textChanged( false );
+
if( mImpl->mEventData &&
keyEvent.state == KeyEvent::Down )
{
int keyCode = keyEvent.keyCode;
const std::string& keyString = keyEvent.keyPressed;
+ // Hide the grab handle.
+ mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+
// Pre-process to separate modifying events from non-modifying input events.
if( Dali::DALI_KEY_ESCAPE == keyCode )
{
if( removed )
{
- if( 0u == mImpl->mLogicalModel->mText.Count() )
+ if( 0u != mImpl->mLogicalModel->mText.Count() ||
+ !mImpl->IsPlaceholderAvailable() )
{
- ShowPlaceholderText();
- mImpl->mEventData->mUpdateCursorPosition = true;
+ mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
}
else
{
- mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
+ ShowPlaceholderText();
+ mImpl->mEventData->mUpdateCursorPosition = true;
}
+
+ textChanged = true;
}
}
else
mImpl->ClearPreEditFlag();
InsertText( keyString, COMMIT );
+
+ textChanged = true;
}
mImpl->ChangeState( EventData::EDITING ); // todo Confirm this is the best place to change the state of
mImpl->RequestRelayout();
}
+ if( textChanged )
+ {
+ // Do this last since it provides callbacks into application code
+ mImpl->mControlInterface.TextChanged();
+ }
+
return false;
}
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
- mImpl->mControlInterface.MaxLengthReached();
-
mImpl->ResetImfManager();
+
+ // Do this last since it provides callbacks into application code
+ mImpl->mControlInterface.MaxLengthReached();
}
}
}
}
-void Controller::HandleEvent( HandleType handleType, HandleState state, float x, float y )
+void Controller::GetTargetSize( Vector2& targetSize )
{
- DALI_ASSERT_DEBUG( mImpl->mEventData && "Controller::HandleEvent. Unexpected HandleEvent" );
+ targetSize = mImpl->mControlSize;
+}
+
+void Controller::AddDecoration( Actor& actor )
+{
+ mImpl->mControlInterface.AddDecoration( actor );
+}
+
+void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
+{
+ DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
if( mImpl->mEventData )
{
}
}
+ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
+{
+ bool update( false );
+ bool requestRelayout = false;
+
+ std::string text;
+ unsigned int cursorPosition( 0 );
+
+ switch ( imfEvent.eventName )
+ {
+ case ImfManager::COMMIT:
+ {
+ InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
+ requestRelayout = true;
+ break;
+ }
+ case ImfManager::PREEDIT:
+ {
+ InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
+ update = true;
+ requestRelayout = true;
+ break;
+ }
+ case ImfManager::DELETESURROUNDING:
+ {
+ RemoveText( imfEvent.cursorOffset, imfEvent.numberOfChars );
+ requestRelayout = true;
+ break;
+ }
+ case ImfManager::GETSURROUNDING:
+ {
+ GetText( text );
+ cursorPosition = GetLogicalCursorPosition();
+
+ imfManager.SetSurroundingText( text );
+ imfManager.SetCursorPosition( cursorPosition );
+ break;
+ }
+ case ImfManager::VOID:
+ {
+ // do nothing
+ break;
+ }
+ } // end switch
+
+ if( ImfManager::GETSURROUNDING != imfEvent.eventName )
+ {
+ GetText( text );
+ cursorPosition = GetLogicalCursorPosition();
+ }
+
+ if( requestRelayout )
+ {
+ mImpl->mOperationsPending = ALL_OPERATIONS;
+ mImpl->RequestRelayout();
+
+ // Do this last since it provides callbacks into application code
+ mImpl->mControlInterface.TextChanged();
+ }
+
+ ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
+
+ return callbackData;
+}
+
+
Controller::~Controller()
{
delete mImpl;
mImpl->mEventData->mIsShowingPlaceholderText = true;
- // Cancel previously queued inserts etc.
- mImpl->mModifyEvents.clear();
-
// Disable handles when showing place-holder text
mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
// Apply modifications to the model
mImpl->mOperationsPending = ALL_OPERATIONS;
+
+ // Update the rest of the model during size negotiation
mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
}
}