- Adjust the text point size to match the size of the TextLabel.
sample) If TEXT_FIT is set to true,
the size of the text will increase to match the size of SetSize()
Property::Map backgroundMap;
backgroundMap["color"] = Color::RED;
backgroundMap["enable"] = true;
Property::Map textFitMap;
textFitMap["enable"] = true;
textFitMap["minSize"] = 10.f;
textFitMap["maxSize"] = 100.f;
textFitMap["stepSize"] = 1.f;
textFitMap["fontSizeType"] = "pointSize";
TextLabel textFit = TextLabel::New( "This is a sample text " );
textFit.SetSize( 450, 100 );
textFit.SetParentOrigin(ParentOrigin::TOP_LEFT);
textFit.SetAnchorPoint(AnchorPoint::TOP_LEFT);
textFit.SetPosition( 100.f, 100.f);
textFit.SetProperty( Toolkit::DevelTextLabel::Property::TEXT_FIT, textFitMap );
textFit.SetProperty( Toolkit::DevelTextLabel::Property::BACKGROUND, backgroundMap );
stage.Add( textFit );
Change-Id: I50fea94547bc8147dd211f597520b27a35c8eb85
END_TEST;
}
+
+int ConvertPointToPixel( float point )
+{
+ unsigned int horizontalDpi = 0u;
+ unsigned int verticalDpi = 0u;
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+ return ( point * 72.f ) / static_cast< float >( horizontalDpi );
+}
+
+int UtcDaliToolkitTextlabelTextFit(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliToolkitTextlabelTextFit");
+ TextLabel label = TextLabel::New();
+ Vector2 size( 460.0f, 100.0f );
+ label.SetSize( size );
+ label.SetProperty( TextLabel::Property::TEXT, "Hello world" );
+
+ // check point size
+ Property::Map textFitMapSet;
+ textFitMapSet["enable"] = true;
+ textFitMapSet["minSize"] = 10.f;
+ textFitMapSet["maxSize"] = 100.f;
+ textFitMapSet["stepSize"] = -1.f;
+ textFitMapSet["fontSizeType"] = "pointSize";
+
+ label.SetProperty( Toolkit::DevelTextLabel::Property::TEXT_FIT, textFitMapSet );
+ label.SetProperty( TextLabel::Property::POINT_SIZE, 120.f);
+
+ Stage::GetCurrent().Add( label );
+
+ application.SendNotification();
+ application.Render();
+
+ const Vector3 EXPECTED_NATURAL_SIZE( 460.0f, 98.0f, 0.0f );
+ DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION );
+
+ // check pixel size
+ textFitMapSet.Clear();
+ textFitMapSet["enable"] = true;
+ textFitMapSet["minSize"] = ConvertPointToPixel( 10.f );
+ textFitMapSet["maxSize"] = ConvertPointToPixel( 100.f );
+ textFitMapSet["stepSize"] = ConvertPointToPixel ( 1.f );
+ textFitMapSet["fontSizeType"] = "pixelSize";
+
+ label.SetProperty( Toolkit::DevelTextLabel::Property::TEXT_FIT, textFitMapSet );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION );
+
+ END_TEST;
+}
*
*/
MATCH_SYSTEM_LANGUAGE_DIRECTION,
+
+ /**
+ * @brief The text fit parameters.
+ * @details Name "textFit", type Property::MAP.
+ * @note The default value is false
+ *
+ * The textFit map contains the following keys:
+ *
+ * | %Property Name | Type | Required | Description |
+ * |----------------------|----------|----------|--------------------------------------------------------------------------------------------------------------------|
+ * | enable | BOOLEAN | No | True to enable the text fit or false to disable (the default value is false) |
+ * | minSize | FLOAT | No | Minimum Size for text fit (the default value is 10.f) |
+ * | maxSize | FLOAT | No | Maximum Size for text fit (the default value is 100.f) |
+ * | stepSize | FLOAT | No | Step Size for font increase (the default value is 1.f) |
+ * | fontSizeType | STRING | No | The size type of font, You can choose between "pointSize" or "pixelSize". (the default value is "pointSize") |
+ */
+ TEXT_FIT,
+
};
} // namespace Property
0.5f, // VerticalAlignment::CENTER
1.0f // VerticalAlignment::BOTTOM
};
+
+ const std::string TEXT_FIT_ENABLE_KEY( "enable" );
+ const std::string TEXT_FIT_MIN_SIZE_KEY( "minSize" );
+ const std::string TEXT_FIT_MAX_SIZE_KEY( "maxSize" );
+ const std::string TEXT_FIT_STEP_SIZE_KEY( "stepSize" );
+ const std::string TEXT_FIT_FONT_SIZE_TYPE_KEY( "fontSizeType" );
}
namespace
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textBackground", MAP, BACKGROUND )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "ignoreSpacesAfterText", BOOLEAN, IGNORE_SPACES_AFTER_TEXT )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "matchSystemLanguageDirection", BOOLEAN, MATCH_SYSTEM_LANGUAGE_DIRECTION )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textFit", MAP, TEXT_FIT )
DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColor", Color::BLACK, TEXT_COLOR )
DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorRed", TEXT_COLOR_RED, TEXT_COLOR, 0 )
DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1 )
impl.mController->SetMatchSystemLanguageDirection(value.Get< bool >());
break;
}
+ case Toolkit::DevelTextLabel::Property::TEXT_FIT:
+ {
+ const Property::Map& propertiesMap = value.Get<Property::Map>();
+
+ bool enabled = false;
+ float minSize = 0.f;
+ float maxSize = 0.f;
+ float stepSize = 0.f;
+ bool isMinSizeSet = false, isMaxSizeSet = false, isStepSizeSet = false;
+ Controller::FontSizeType type = Controller::FontSizeType::POINT_SIZE;
+
+ if ( !propertiesMap.Empty() )
+ {
+ const unsigned int numberOfItems = propertiesMap.Count();
+
+ // Parses and applies
+ for( unsigned int index = 0u; index < numberOfItems; ++index )
+ {
+ const KeyValuePair& valueGet = propertiesMap.GetKeyValue( index );
+
+ if( ( Controller::TextFitInfo::Property::TEXT_FIT_ENABLE == valueGet.first.indexKey ) || ( TEXT_FIT_ENABLE_KEY == valueGet.first.stringKey ) )
+ {
+ /// Enable key.
+ enabled = valueGet.second.Get< bool >();
+ }
+ else if( ( Controller::TextFitInfo::Property::TEXT_FIT_MIN_SIZE == valueGet.first.indexKey ) || ( TEXT_FIT_MIN_SIZE_KEY == valueGet.first.stringKey ) )
+ {
+ /// min size.
+ minSize = valueGet.second.Get< float >();
+ isMinSizeSet = true;
+ }
+ else if( ( Controller::TextFitInfo::Property::TEXT_FIT_MAX_SIZE == valueGet.first.indexKey ) || ( TEXT_FIT_MAX_SIZE_KEY == valueGet.first.stringKey ) )
+ {
+ /// max size.
+ maxSize = valueGet.second.Get< float >();
+ isMaxSizeSet = true;
+ }
+ else if( ( Controller::TextFitInfo::Property::TEXT_FIT_STEP_SIZE == valueGet.first.indexKey ) || ( TEXT_FIT_STEP_SIZE_KEY == valueGet.first.stringKey ) )
+ {
+ /// step size.
+ stepSize = valueGet.second.Get< float >();
+ isStepSizeSet = true;
+ }
+ else if( ( Controller::TextFitInfo::Property::TEXT_FIT_FONT_SIZE_TYPE == valueGet.first.indexKey ) || ( TEXT_FIT_FONT_SIZE_TYPE_KEY == valueGet.first.stringKey ) )
+ {
+ if( "pixelSize" == valueGet.second.Get< std::string >() )
+ {
+ type = Controller::FontSizeType::PIXEL_SIZE;
+ }
+ }
+ }
+
+ impl.mController->SetTextFitEnabled( enabled );
+ if( isMinSizeSet )
+ {
+ impl.mController->SetTextFitMinSize( minSize, type );
+ }
+ if( isMaxSizeSet )
+ {
+ impl.mController->SetTextFitMaxSize( maxSize, type );
+ }
+ if( isStepSizeSet )
+ {
+ impl.mController->SetTextFitStepSize( stepSize, type );
+ }
+ }
+ break;
+ }
}
// Request relayout when text update is needed. It's necessary to call it
impl.RequestTextRelayout();
}
}
-
-
-
-
}
Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
value = impl.mController->IsMatchSystemLanguageDirection();
break;
}
+ case Toolkit::DevelTextLabel::Property::TEXT_FIT:
+ {
+ const bool enabled = impl.mController->IsTextFitEnabled();
+ const float minSize = impl.mController->GetTextFitMinSize();
+ const float maxSize = impl.mController->GetTextFitMaxSize();
+ const float stepSize = impl.mController->GetTextFitStepSize();
+
+ Property::Map map;
+ map.Insert( TEXT_FIT_ENABLE_KEY, enabled );
+ map.Insert( TEXT_FIT_MIN_SIZE_KEY, minSize );
+ map.Insert( TEXT_FIT_MAX_SIZE_KEY, maxSize );
+ map.Insert( TEXT_FIT_STEP_SIZE_KEY, stepSize );
+ map.Insert( TEXT_FIT_FONT_SIZE_TYPE_KEY, "pointSize" );
+
+ value = map;
+ break;
+ }
}
}
Vector2 contentSize( size.x - ( padding.start + padding.end ), size.y - ( padding.top + padding.bottom ) );
+ // If the same text comes for relayouting for same layout size we don't need to calculate point size again.
+ // Like for color change.
+ if (mController->IsTextFitEnabled() && (mController->GetTextFitContentSize() != contentSize ) )
+ {
+ mController->FitPointSizeforLayout(contentSize);
+ mController->SetTextFitContentSize(contentSize);
+ }
+
// Support Right-To-Left
Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
{
// Set the normal font and the placeholder font.
defaultFontDescription = mFontDefaults->mFontDescription;
- defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
+
+ if( mTextFitEnabled )
+ {
+ defaultPointSize = mFontDefaults->mFitPointSize * 64u;
+ }
+ else
+ {
+ defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
+ }
}
// Validates the fonts. If there is a character with no assigned font it sets a default one.
namespace Text
{
+const float DEFAULT_TEXTFIT_MIN = 10.f;
+const float DEFAULT_TEXTFIT_MAX = 100.f;
+const float DEFAULT_TEXTFIT_STEP = 1.f;
+
//Forward declarations
struct CursorInfo;
struct FontDefaults;
FontDefaults()
: mFontDescription(),
mDefaultPointSize( 0.f ),
+ mFitPointSize( 0.f ),
mFontId( 0u ),
familyDefined( false ),
weightDefined( false ),
TextAbstraction::FontDescription mFontDescription; ///< The default font's description.
float mDefaultPointSize; ///< The default font's point size.
+ float mFitPointSize; ///< The fit font's point size.
FontId mFontId; ///< The font's id of the default font.
bool familyDefined:1; ///< Whether the default font's family name is defined.
bool weightDefined:1; ///< Whether the default font's weight is defined.
mOutlineSetByString( false ),
mFontStyleSetByString( false ),
mShouldClearFocusOnEscape( true ),
- mLayoutDirection( LayoutDirection::LEFT_TO_RIGHT )
+ mLayoutDirection( LayoutDirection::LEFT_TO_RIGHT ),
+ mTextFitMinSize( DEFAULT_TEXTFIT_MIN ),
+ mTextFitMaxSize( DEFAULT_TEXTFIT_MAX ),
+ mTextFitStepSize( DEFAULT_TEXTFIT_STEP ),
+ mTextFitEnabled( false )
{
mModel = Model::New();
OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
Length mMaximumNumberOfCharacters; ///< Maximum number of characters that can be inserted.
HiddenText* mHiddenInput; ///< Avoid allocating this when the user does not specify hidden input mode.
+ Vector2 mTextFitContentSize; ///< Size of Text fit content
bool mRecalculateNaturalSize:1; ///< Whether the natural size needs to be recalculated.
bool mMarkupProcessorEnabled:1; ///< Whether the mark-up procesor is enabled.
bool mFontStyleSetByString:1; ///< Set when font style is set by string (legacy) instead of map
bool mShouldClearFocusOnEscape:1; ///< Whether text control should clear key input focus
LayoutDirection::Type mLayoutDirection; ///< Current system language direction
+
+ float mTextFitMinSize; ///< Minimum Font Size for text fit. Default 10
+ float mTextFitMaxSize; ///< Maximum Font Size for text fit. Default 100
+ float mTextFitStepSize; ///< Step Size for font intervalse. Default 1
+ bool mTextFitEnabled : 1; ///< Whether the text's fit is enabled.
};
} // namespace Text
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
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;
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 |
+ GET_WORD_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 )
+{
+ 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 );
};
};
+ struct TextFitInfo
+ {
+ enum Property
+ {
+ TEXT_FIT_ENABLE,
+ TEXT_FIT_MIN_SIZE,
+ TEXT_FIT_MAX_SIZE,
+ TEXT_FIT_STEP_SIZE,
+ TEXT_FIT_FONT_SIZE_TYPE
+ };
+ };
+
public: // Constructor.
/**
*/
bool IsTextElideEnabled() const;
+ /**
+ * @brief Enable or disable the text fit.
+ *
+ * @param[in] enabled Whether to enable the text fit.
+ */
+ void SetTextFitEnabled(bool enabled);
+
+ /**
+ * @brief Whether the text fit is enabled or not.
+ *
+ * @return True if the text fit is enabled
+ */
+ bool IsTextFitEnabled() const;
+
+ /**
+ * @brief Sets minimum size valid for text fit.
+ *
+ * @param[in] minimum size value.
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetTextFitMinSize( float pointSize, FontSizeType type );
+
+ /**
+ * @brief Retrieves the minimum point size valid for text fit.
+ *
+ * @return The minimum point size valid for text fit
+ */
+ float GetTextFitMinSize() const;
+
+ /**
+ * @brief Sets maximum size valid for text fit.
+ *
+ * @param[in] maximum size value.
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetTextFitMaxSize( float pointSize, FontSizeType type );
+
+ /**
+ * @brief Retrieves the maximum point size valid for text fit.
+ *
+ * @return The maximum point size valid for text fit
+ */
+ float GetTextFitMaxSize() const;
+
+ /**
+ * @brief Sets step size for font increase valid for text fit.
+ *
+ * @param[in] step size value.
+ * @param[in] type The font size type is point size or pixel size
+ */
+ void SetTextFitStepSize( float step, FontSizeType type );
+
+ /**
+ * @brief Retrieves the step point size valid for text fit.
+ *
+ * @return The step point size valid for text fit
+ */
+ float GetTextFitStepSize() const;
+
+ /**
+ * @brief Sets content size valid for text fit.
+ *
+ * @param[in] Content size value.
+ */
+ void SetTextFitContentSize(Vector2 size);
+
+ /**
+ * @brief Retrieves the content size valid for text fit.
+ *
+ * @return The content size valid for text fit
+ */
+ Vector2 GetTextFitContentSize() const;
+
/**
* @brief Enable or disable the placeholder text elide.
* @param enabled Whether to enable the placeholder text elide.
*/
float GetHeightForWidth( float width );
+ /**
+ * @brief Calculates the point size for text for given layout()
+ */
+ void FitPointSizeforLayout( Size layoutSize );
+
+ /**
+ * @brief Checks if the point size fits within the layout size.
+ *
+ * @return Whether the point size fits within the layout size.
+ */
+ bool CheckForTextFit( float pointSize, Size& layoutSize );
+
/**
* @brief Retrieves the text's number of lines for a given width.
* @param[in] width The width of the text's area.