/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// EXTERNAL INCLUDES
#include <limits>
+#include <cmath>
#include <memory.h>
#include <dali/public-api/adaptor-framework/key.h>
#include <dali/integration-api/debug.h>
const std::string KEY_C_NAME = "c";
const std::string KEY_V_NAME = "v";
const std::string KEY_X_NAME = "x";
+const std::string KEY_A_NAME = "a";
+const std::string KEY_INSERT_NAME = "Insert";
const char * const PLACEHOLDER_TEXT = "text";
const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
-const unsigned int MAX_TEXT_LENGTH = 1024u * 32u;
float ConvertToEven( float value )
{
return static_cast<float>( intValue + ( intValue & 1 ) );
}
+int ConvertPixelToPint( float pixel )
+{
+ unsigned int horizontalDpi = 0u;
+ unsigned int verticalDpi = 0u;
+ Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+ fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+ return ( pixel * 72.f ) / static_cast< float >( horizontalDpi );
+}
+
} // namespace
namespace Dali
}
ControllerPtr Controller::New( ControlInterface* controlInterface,
- EditableControlInterface* editableControlInterface )
+ EditableControlInterface* editableControlInterface,
+ SelectableControlInterface* selectableControlInterface )
{
return ControllerPtr( new Controller( controlInterface,
- editableControlInterface ) );
+ editableControlInterface,
+ selectableControlInterface ) );
}
// public : Configure the text controller.
void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
{
- mImpl->mMaximumNumberOfCharacters = std::min( maxCharacters, MAX_TEXT_LENGTH );
+ mImpl->mMaximumNumberOfCharacters = maxCharacters;
}
int Controller::GetMaximumNumberOfCharacters()
// Set the flag to redo the alignment operation.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
+ if( mImpl->mEventData )
+ {
+ mImpl->mEventData->mUpdateAlignment = true;
+
+ // Update the cursor if it's in editing mode
+ if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+ {
+ mImpl->ChangeState( EventData::EDITING );
+ mImpl->mEventData->mUpdateCursorPosition = true;
+ }
+ }
+
mImpl->RequestRelayout();
}
}
return mImpl->mModel->mElideEnabled;
}
+void Controller::SetTextFitEnabled(bool enabled)
+{
+ mImpl->mTextFitEnabled = enabled;
+}
+
+bool Controller::IsTextFitEnabled() const
+{
+ return mImpl->mTextFitEnabled;
+}
+
+void Controller::SetTextFitMinSize( float minSize, FontSizeType type )
+{
+ switch( type )
+ {
+ case POINT_SIZE:
+ {
+ mImpl->mTextFitMinSize = minSize;
+ break;
+ }
+ case PIXEL_SIZE:
+ {
+ mImpl->mTextFitMinSize = ConvertPixelToPint( minSize );
+ break;
+ }
+ }
+}
+
+float Controller::GetTextFitMinSize() const
+{
+ return mImpl->mTextFitMinSize;
+}
+
+void Controller::SetTextFitMaxSize( float maxSize, FontSizeType type )
+{
+ switch( type )
+ {
+ case POINT_SIZE:
+ {
+ mImpl->mTextFitMaxSize = maxSize;
+ break;
+ }
+ case PIXEL_SIZE:
+ {
+ mImpl->mTextFitMaxSize = ConvertPixelToPint( maxSize );
+ break;
+ }
+ }
+}
+
+float Controller::GetTextFitMaxSize() const
+{
+ return mImpl->mTextFitMaxSize;
+}
+
+void Controller::SetTextFitStepSize( float step, FontSizeType type )
+{
+ switch( type )
+ {
+ case POINT_SIZE:
+ {
+ mImpl->mTextFitStepSize = step;
+ break;
+ }
+ case PIXEL_SIZE:
+ {
+ mImpl->mTextFitStepSize = ConvertPixelToPint( step );
+ break;
+ }
+ }
+}
+
+float Controller::GetTextFitStepSize() const
+{
+ return mImpl->mTextFitStepSize;
+}
+
+void Controller::SetTextFitContentSize(Vector2 size)
+{
+ mImpl->mTextFitContentSize = size;
+}
+
+Vector2 Controller::GetTextFitContentSize() const
+{
+ return mImpl->mTextFitContentSize;
+}
+
void Controller::SetPlaceholderTextElideEnabled( bool enabled )
{
mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
}
- // Limit the text size. If the text size is too large, crash or deadlock will occur.
- if( textSize > MAX_TEXT_LENGTH )
- {
- DALI_LOG_WARNING( "The text size is too large(%d), limit the length to 32,768u\n", textSize );
- textSize = MAX_TEXT_LENGTH;
- }
-
// Convert text into UTF-32
Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
utf32Characters.Resize( textSize );
DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
+ if( mImpl->mEventData )
+ {
+ // Update the cursor position if it's in editing mode
+ if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+ {
+ mImpl->mEventData->mDecoratorUpdated = true;
+ mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font family is updated.
+ }
+ }
+
// Clear the font-specific data
ClearFontData();
mImpl->mFontDefaults->mFontDescription.weight = weight;
mImpl->mFontDefaults->weightDefined = true;
+ if( mImpl->mEventData )
+ {
+ // Update the cursor position if it's in editing mode
+ if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+ {
+ mImpl->mEventData->mDecoratorUpdated = true;
+ mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font weight is updated.
+ }
+ }
+
// Clear the font-specific data
ClearFontData();
mImpl->mFontDefaults->mFontDescription.width = width;
mImpl->mFontDefaults->widthDefined = true;
+ if( mImpl->mEventData )
+ {
+ // Update the cursor position if it's in editing mode
+ if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+ {
+ mImpl->mEventData->mDecoratorUpdated = true;
+ mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font width is updated.
+ }
+ }
+
// Clear the font-specific data
ClearFontData();
mImpl->mFontDefaults->mFontDescription.slant = slant;
mImpl->mFontDefaults->slantDefined = true;
+ if( mImpl->mEventData )
+ {
+ // Update the cursor position if it's in editing mode
+ if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+ {
+ mImpl->mEventData->mDecoratorUpdated = true;
+ mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font slant is updated.
+ }
+ }
+
// Clear the font-specific data
ClearFontData();
}
}
+ if( mImpl->mEventData )
+ {
+ // Update the cursor position if it's in editing mode
+ if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+ {
+ mImpl->mEventData->mDecoratorUpdated = true;
+ mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
+ }
+ }
+
// Clear the font-specific data
ClearFontData();
{
mImpl->mModel->mVisualModel->SetTextColor( color );
+ mImpl->mModel->mLogicalModel->mColorRuns.Clear();
+
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
+
mImpl->RequestRelayout();
}
}
bool Controller::SetDefaultLineSpacing( float lineSpacing )
{
- if( std::abs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000 )
+ if( std::fabs( lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing() ) > Math::MACHINE_EPSILON_1000 )
{
mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
mImpl->mRecalculateNaturalSize = true;
return mImpl->mLayoutEngine.GetDefaultLineSpacing();
}
+bool Controller::SetDefaultLineSize( float lineSize )
+{
+ if( std::fabs( lineSize - mImpl->mLayoutEngine.GetDefaultLineSize() ) > Math::MACHINE_EPSILON_1000 )
+ {
+ mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
+ mImpl->mRecalculateNaturalSize = true;
+ return true;
+ }
+ return false;
+}
+
+float Controller::GetDefaultLineSize() const
+{
+ return mImpl->mLayoutEngine.GetDefaultLineSize();
+}
+
void Controller::SetInputColor( const Vector4& color )
{
if( NULL != mImpl->mEventData )
{
CharacterIndex startOfSelectedText = 0u;
Length lengthOfSelectedText = 0u;
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
- mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText );
- fontDescriptionRun.familyLength = fontFamily.size();
- fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
- memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
- fontDescriptionRun.familyDefined = true;
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.familyLength = fontFamily.size();
+ fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+ memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+ fontDescriptionRun.familyDefined = true;
+
+ // The memory allocated for the font family name is freed when the font description is removed from the logical model.
- // The memory allocated for the font family name is freed when the font description is removed from the logical model.
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+ }
// Request to relayout.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
mImpl->mRecalculateNaturalSize = true;
mImpl->RequestRelayout();
- mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
-
// As the font changes, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
{
CharacterIndex startOfSelectedText = 0u;
Length lengthOfSelectedText = 0u;
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
- mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText );
- fontDescriptionRun.weight = weight;
- fontDescriptionRun.weightDefined = true;
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.weight = weight;
+ fontDescriptionRun.weightDefined = true;
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+ }
// Request to relayout.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
mImpl->mRecalculateNaturalSize = true;
mImpl->RequestRelayout();
- mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
-
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
{
CharacterIndex startOfSelectedText = 0u;
Length lengthOfSelectedText = 0u;
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
- mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText );
- fontDescriptionRun.width = width;
- fontDescriptionRun.widthDefined = true;
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.width = width;
+ fontDescriptionRun.widthDefined = true;
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+ }
// Request to relayout.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
mImpl->mRecalculateNaturalSize = true;
mImpl->RequestRelayout();
- mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
-
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
{
CharacterIndex startOfSelectedText = 0u;
Length lengthOfSelectedText = 0u;
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
- mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText );
- fontDescriptionRun.slant = slant;
- fontDescriptionRun.slantDefined = true;
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.slant = slant;
+ fontDescriptionRun.slantDefined = true;
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+ }
// Request to relayout.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
mImpl->mRecalculateNaturalSize = true;
mImpl->RequestRelayout();
- mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
-
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
{
CharacterIndex startOfSelectedText = 0u;
Length lengthOfSelectedText = 0u;
- FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
- mImpl->mModel->mLogicalModel,
- startOfSelectedText,
- lengthOfSelectedText );
- fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
- fontDescriptionRun.sizeDefined = true;
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ // Update a font description run for the selecting state.
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mModel->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
+ fontDescriptionRun.sizeDefined = true;
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ else
+ {
+ mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+ }
// Request to relayout.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
mImpl->mRecalculateNaturalSize = true;
mImpl->RequestRelayout();
- mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
- mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
-
// As the font might change, recalculate the handle positions is needed.
mImpl->mEventData->mUpdateLeftSelectionPosition = true;
mImpl->mEventData->mUpdateRightSelectionPosition = true;
GET_SCRIPTS |
VALIDATE_FONTS |
GET_LINE_BREAKS |
- GET_WORD_BREAKS |
BIDI_INFO |
SHAPE_TEXT |
GET_GLYPH_METRICS );
return naturalSize;
}
+bool Controller::CheckForTextFit( float pointSize, Size& layoutSize )
+{
+ Size textSize;
+ mImpl->mFontDefaults->mFitPointSize = pointSize;
+ mImpl->mFontDefaults->sizeDefined = true;
+ ClearFontData();
+
+ // Operations that can be done only once until the text changes.
+ const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
+ GET_SCRIPTS |
+ VALIDATE_FONTS |
+ GET_LINE_BREAKS |
+ BIDI_INFO |
+ SHAPE_TEXT|
+ GET_GLYPH_METRICS );
+
+ mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+ mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+
+ // Make sure the model is up-to-date before layouting
+ mImpl->UpdateModel( onlyOnceOperations );
+
+ DoRelayout( Size( layoutSize.width, MAX_FLOAT ),
+ static_cast<OperationsMask>( onlyOnceOperations | LAYOUT),
+ textSize);
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ mImpl->mTextUpdateInfo.Clear();
+ mImpl->mTextUpdateInfo.mClearAll = true;
+
+ if( textSize.width > layoutSize.width || textSize.height > layoutSize.height )
+ {
+ return false;
+ }
+ return true;
+}
+
+void Controller::FitPointSizeforLayout( Size layoutSize )
+{
+ const OperationsMask operations = mImpl->mOperationsPending;
+ if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) || mImpl->mTextFitContentSize != layoutSize )
+ {
+ bool actualellipsis = mImpl->mModel->mElideEnabled;
+ float minPointSize = mImpl->mTextFitMinSize;
+ float maxPointSize = mImpl->mTextFitMaxSize;
+ float pointInterval = mImpl->mTextFitStepSize;
+
+ mImpl->mModel->mElideEnabled = false;
+ Vector<float> pointSizeArray;
+
+ // check zero value
+ if( pointInterval < 1.f )
+ {
+ mImpl->mTextFitStepSize = pointInterval = 1.0f;
+ }
+
+ pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) );
+
+ for( float i = minPointSize; i < maxPointSize; i += pointInterval )
+ {
+ pointSizeArray.PushBack( i );
+ }
+
+ pointSizeArray.PushBack( maxPointSize );
+
+ int bestSizeIndex = 0;
+ int min = bestSizeIndex + 1;
+ int max = pointSizeArray.Size() - 1;
+ while( min <= max )
+ {
+ int destI = ( min + max ) / 2;
+
+ if( CheckForTextFit( pointSizeArray[destI], layoutSize ) )
+ {
+ bestSizeIndex = min;
+ min = destI + 1;
+ }
+ else
+ {
+ max = destI - 1;
+ bestSizeIndex = max;
+ }
+ }
+
+ mImpl->mModel->mElideEnabled = actualellipsis;
+ mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
+ mImpl->mFontDefaults->sizeDefined = true;
+ ClearFontData();
+ }
+}
+
float Controller::GetHeightForWidth( float width )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
GET_SCRIPTS |
VALIDATE_FONTS |
GET_LINE_BREAKS |
- GET_WORD_BREAKS |
BIDI_INFO |
SHAPE_TEXT |
GET_GLYPH_METRICS );
GET_SCRIPTS |
VALIDATE_FONTS |
GET_LINE_BREAKS |
- GET_WORD_BREAKS |
BIDI_INFO |
SHAPE_TEXT |
GET_GLYPH_METRICS );
// Clear the update info. This info will be set the next time the text is updated.
mImpl->mTextUpdateInfo.Clear();
+ // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+ mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+
mImpl->mUpdateTextDirection = false;
}
bool relayoutNeeded = false;
if( ( NULL != mImpl->mEventData ) &&
- ( keyEvent.state == KeyEvent::Down ) )
+ ( keyEvent.GetState() == KeyEvent::DOWN ) )
{
- int keyCode = keyEvent.keyCode;
- const std::string& keyString = keyEvent.keyPressed;
- const std::string keyName = keyEvent.keyPressedName;
+ int keyCode = keyEvent.GetKeyCode();
+ const std::string& keyString = keyEvent.GetKeyString();
+ const std::string keyName = keyEvent.GetKeyName();
const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
// Do nothing
return false;
}
- else if ( keyEvent.IsCtrlModifier() )
+ else if ( keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier())
{
bool consumed = false;
- if (keyName == KEY_C_NAME)
+ if (keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME)
{
- // Ctrl-C to copy the selected text
+ // Ctrl-C or Ctrl+Insert to copy the selected text
TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY );
consumed = true;
}
TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
consumed = true;
}
+ else if (keyName == KEY_A_NAME)
+ {
+ // Ctrl-A to select All the text
+ TextPopupButtonTouched( Toolkit::TextSelectionPopup::SELECT_ALL );
+ consumed = true;
+ }
return consumed;
}
else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
else
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
+ if (!IsEditable()) return false;
if( !keyString.empty() )
{
mImpl->ResetInputMethodContext();
}
-void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
+void Controller::PanEvent( GestureState state, const Vector2& displacement )
{
DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
if( NULL != mImpl->mEventData )
{
Event event( Event::PAN_EVENT );
- event.p1.mInt = state;
+ event.p1.mInt = static_cast<int>( state );
event.p2.mFloat = displacement.x;
event.p3.mFloat = displacement.y;
mImpl->mEventData->mEventQueue.push_back( event );
}
}
-void Controller::LongPressEvent( Gesture::State state, float x, float y )
+void Controller::LongPressEvent( GestureState state, float x, float y )
{
DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
- if( ( state == Gesture::Started ) &&
+ if( ( state == GestureState::STARTED ) &&
( NULL != mImpl->mEventData ) )
{
// The 1st long-press on inactive text-field is treated as tap
else if( !mImpl->IsShowingRealText() )
{
Event event( Event::LONG_PRESS_EVENT );
- event.p1.mInt = state;
+ event.p1.mInt = static_cast<int>( state );
event.p2.mFloat = x;
event.p3.mFloat = y;
mImpl->mEventData->mEventQueue.push_back( event );
mImpl->ResetInputMethodContext();
Event event( Event::LONG_PRESS_EVENT );
- event.p1.mInt = state;
+ event.p1.mInt = static_cast<int>( state );
event.p2.mFloat = x;
event.p3.mFloat = y;
mImpl->mEventData->mEventQueue.push_back( event );
}
}
-void Controller::SelectEvent( float x, float y, bool selectAll )
+void Controller::SelectEvent( float x, float y, SelectionType selectType )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
if( NULL != mImpl->mEventData )
{
- if( selectAll )
+ if( selectType == SelectionType::ALL )
{
Event event( Event::SELECT_ALL );
mImpl->mEventData->mEventQueue.push_back( event );
}
+ else if( selectType == SelectionType::NONE )
+ {
+ Event event( Event::SELECT_NONE );
+ mImpl->mEventData->mEventQueue.push_back( event );
+ }
else
{
Event event( Event::SELECT );
}
}
+void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end)
+{
+ if( mImpl->mEventData )
+ {
+ mImpl->mEventData->mCheckScrollAmount = true;
+ mImpl->mEventData->mIsLeftHandleSelected = true;
+ mImpl->mEventData->mIsRightHandleSelected = true;
+ mImpl->SetTextSelectionRange(start, end);
+ mImpl->RequestRelayout();
+ KeyboardFocusGainEvent();
+ }
+}
+
+Uint32Pair Controller::GetTextSelectionRange() const
+{
+ return mImpl->GetTextSelectionRange();
+}
+
+void Controller::SelectWholeText()
+{
+ SelectEvent( 0.f, 0.f, SelectionType::ALL );
+}
+
+void Controller::SelectNone()
+{
+ SelectEvent( 0.f, 0.f, SelectionType::NONE );
+}
+
+string Controller::GetSelectedText() const
+{
+ string text;
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ mImpl->RetrieveSelection( text, false );
+ }
+ return text;
+}
+
InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
{
// Whether the text needs to be relaid-out.
}
}
+bool Controller::IsEditable() const
+{
+ return mImpl->IsEditable();
+}
+
+void Controller::SetEditable( bool editable )
+{
+ mImpl->SetEditable( editable );
+ if(mImpl->mEventData && mImpl->mEventData->mDecorator)
+ {
+ mImpl->mEventData->mDecorator->SetEditable( editable );
+ }
+}
+
void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
{
DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
{
case Toolkit::TextSelectionPopup::CUT:
{
+ if (!IsEditable()) return;
mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
mImpl->mOperationsPending = ALL_OPERATIONS;
if( mImpl->mEventData->mSelectionEnabled )
{
// Creates a SELECT event.
- SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
+ SelectEvent( currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE );
}
break;
}
case Toolkit::TextSelectionPopup::SELECT_ALL:
{
// Creates a SELECT_ALL event
- SelectEvent( 0.f, 0.f, true );
+ SelectEvent( 0.f, 0.f, SelectionType::ALL );
break;
}
case Toolkit::TextSelectionPopup::CLIPBOARD:
}
}
+ // If the number of current text and the number of characters to be deleted are same,
+ // it means all texts should be removed and all Preedit variables should be initialized.
+ if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) )
+ {
+ mImpl->ClearPreEditFlag();
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
+ }
+
// Updates the text style runs by removing characters. Runs with no characters are removed.
mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
mImpl->mEventData->mScrollAfterDelete = true;
+ if( EventData::INACTIVE == mImpl->mEventData->mState )
+ {
+ mImpl->ChangeState( EventData::EDITING );
+ }
+
DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
removed = true;
}
// Make sure the index is not out of bound
if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
requestedNumberOfCharacters > charactersToGlyph.Count() ||
- ( lastIndex >= charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
+ ( lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
{
std::string currentText;
GetText( currentText );
return true;
}
- const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
- const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
- const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
- const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
- const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
- const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
- const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
- const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
-
// Set the layout parameters.
Layout::Parameters layoutParameters( size,
- textBuffer,
- lineBreakInfo.Begin(),
- wordBreakInfo.Begin(),
- ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
- glyphs.Begin(),
- glyphsToCharactersMap.Begin(),
- charactersPerGlyph.Begin(),
- charactersToGlyphBuffer,
- glyphsPerCharacterBuffer,
- totalNumberOfGlyphs,
- mImpl->mModel->mHorizontalAlignment,
- mImpl->mModel->mLineWrapMode,
- outlineWidth,
- mImpl->mModel->mIgnoreSpacesAfterText,
- mImpl->mModel->mMatchSystemLanguageDirection );
+ mImpl->mModel);
// Resize the vector of positions to have the same size than the vector of glyphs.
Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
glyphPositions.Resize( totalNumberOfGlyphs );
// Whether the last character is a new paragraph character.
+ const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
Size newLayoutSize;
viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
- glyphPositions,
- mImpl->mModel->mVisualModel->mLines,
newLayoutSize,
elideTextEnabled,
isAutoScrollEnabled );
mImpl->mIsTextDirectionRTL = false;
}
- // Reorder the lines
- if( NO_OPERATION != ( REORDER & operations ) )
+ if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && !mImpl->mModel->mVisualModel->mLines.Empty() )
{
- Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
- Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
-
- // Check first if there are paragraphs with bidirectional info.
- if( 0u != bidirectionalInfo.Count() )
- {
- // Get the lines
- const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
-
- // Reorder the lines.
- bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
- ReorderLines( bidirectionalInfo,
- startIndex,
- requestedNumberOfCharacters,
- mImpl->mModel->mVisualModel->mLines,
- bidirectionalLineInfo );
-
- // Set the bidirectional info per line into the layout parameters.
- layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
- layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
-
- // Re-layout the text. Reorder those lines with right to left characters.
- mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
- startIndex,
- requestedNumberOfCharacters,
- glyphPositions );
-
- if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
- {
- const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
- if ( firstline )
- {
- mImpl->mIsTextDirectionRTL = firstline->direction;
- }
- }
- }
- } // REORDER
+ mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
+ }
// Sets the layout size.
if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
// The laid-out lines.
Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
+ CharacterIndex alignStartIndex = startIndex;
+ Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
+
+ // the whole text needs to be full aligned.
+ // If you do not do a full aligned, only the last line of the multiline input is aligned.
+ if( mImpl->mEventData && mImpl->mEventData->mUpdateAlignment )
+ {
+ alignStartIndex = 0u;
+ alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+ mImpl->mEventData->mUpdateAlignment = false;
+ }
+
// Need to align with the control's size as the text may contain lines
// starting either with left to right text or right to left.
mImpl->mLayoutEngine.Align( size,
- startIndex,
- requestedNumberOfCharacters,
+ alignStartIndex,
+ alignRequestedNumberOfCharacters,
mImpl->mModel->mHorizontalAlignment,
lines,
mImpl->mModel->mAlignmentOffset,
mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
}
- // Discard temporary text
+ // DISCARD temporary text
events.Clear();
}
return;
}
+ if (!IsEditable()) return;
+
mImpl->mEventData->mCheckScrollAmount = true;
// The natural size needs to be re-calculated.
return removed;
}
+ if (!IsEditable()) return false;
+
// InputMethodContext is no longer handling key-events
mImpl->ClearPreEditFlag();
return mImpl->mShouldClearFocusOnEscape;
}
+Actor Controller::CreateBackgroundActor()
+{
+ return mImpl->CreateBackgroundActor();
+}
+
// private : Private contructors & copy operator.
Controller::Controller()
: mImpl( NULL )
{
- mImpl = new Controller::Impl( NULL, NULL );
+ mImpl = new Controller::Impl( nullptr, nullptr, nullptr );
}
Controller::Controller( ControlInterface* controlInterface )
{
- mImpl = new Controller::Impl( controlInterface, NULL );
+ mImpl = new Controller::Impl( controlInterface, NULL, NULL );
}
Controller::Controller( ControlInterface* controlInterface,
- EditableControlInterface* editableControlInterface )
+ EditableControlInterface* editableControlInterface,
+ SelectableControlInterface* selectableControlInterface )
{
mImpl = new Controller::Impl( controlInterface,
- editableControlInterface );
+ editableControlInterface,
+ selectableControlInterface );
}
// The copy constructor and operator are left unimplemented.