END_TEST;
}
+int UtcDaliToolkitTextlabelTextFitArray(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliToolkitTextlabelTextFitArray");
+ TextLabel label = TextLabel::New();
+ Vector2 size(300.0f, 80.0f);
+ label.SetProperty(Actor::Property::SIZE, size);
+ label.SetProperty(TextLabel::Property::TEXT, "A Quick Brown Fox Jumps Over The Lazy Dog");
+ label.SetProperty(DevelTextLabel::Property::MIN_LINE_SIZE, 80.f);
+ label.SetProperty(TextLabel::Property::POINT_SIZE, 10.f);
+ application.GetScene().Add(label);
+
+ // make sorted options.
+ std::vector<DevelTextLabel::FitOption> fitOptions;
+ fitOptions.push_back(DevelTextLabel::FitOption(10, 12));
+ fitOptions.push_back(DevelTextLabel::FitOption(8, 10));
+ fitOptions.push_back(DevelTextLabel::FitOption(6, 8));
+ fitOptions.push_back(DevelTextLabel::FitOption(4, 6));
+ fitOptions.push_back(DevelTextLabel::FitOption(20, 22));
+ fitOptions.push_back(DevelTextLabel::FitOption(22, 24));
+ fitOptions.push_back(DevelTextLabel::FitOption(12, 14));
+
+ DevelTextLabel::SetTextFitArray(label, true, fitOptions);
+
+ application.SendNotification();
+ application.Render();
+
+ bool enable = Dali::Toolkit::DevelTextLabel::IsTextFitArrayEnabled(label);
+ DALI_TEST_EQUALS(true, enable, TEST_LOCATION);
+
+ std::vector<Dali::Toolkit::DevelTextLabel::FitOption> getFitOptions = Dali::Toolkit::DevelTextLabel::GetTextFitArray(label);
+ size_t numberOfFitOptions = getFitOptions.size();
+ DALI_TEST_EQUALS(7u, numberOfFitOptions, TEST_LOCATION);
+
+ const Vector3 EXPECTED_NATURAL_SIZE(276.0f, 16.0f, 0.0f);
+ DALI_TEST_EQUALS(EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION);
+
+ std::vector<DevelTextLabel::FitOption> emptyFitOptions;
+ DevelTextLabel::SetTextFitArray(label, false, emptyFitOptions);
+
+ application.SendNotification();
+ application.Render();
+
+ enable = Dali::Toolkit::DevelTextLabel::IsTextFitArrayEnabled(label);
+ DALI_TEST_EQUALS(false, enable, TEST_LOCATION);
+
+ const Vector3 EXPECTED_NATURAL_SIZE_DISABLE(690.0f, 80.0f, 0.0f);
+ DALI_TEST_EQUALS(EXPECTED_NATURAL_SIZE_DISABLE, label.GetNaturalSize(), TEST_LOCATION);
+
+ // make unsorted options.
+ std::vector<DevelTextLabel::FitOption> unorderedFitOptions;
+ unorderedFitOptions.push_back(DevelTextLabel::FitOption(4, 6));
+ unorderedFitOptions.push_back(DevelTextLabel::FitOption(6, 8));
+ unorderedFitOptions.push_back(DevelTextLabel::FitOption(8, 10));
+ unorderedFitOptions.push_back(DevelTextLabel::FitOption(10, 8));
+
+ DevelTextLabel::SetTextFitArray(label, true, unorderedFitOptions);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliToolkitTextlabelMaxTextureSet(void)
{
ToolkitTestApplication application;
return GetImpl(textLabel).GetTextBoundingRectangle(startIndex, endIndex);
}
+void SetTextFitArray(TextLabel textLabel, const bool enable, std::vector<FitOption>& fitOptions)
+{
+ GetImpl(textLabel).SetTextFitArray(enable, fitOptions);
+}
+
+std::vector<FitOption>& GetTextFitArray(TextLabel textLabel)
+{
+ return GetImpl(textLabel).GetTextFitArray();
+}
+
+bool IsTextFitArrayEnabled(TextLabel textLabel)
+{
+ return GetImpl(textLabel).IsTextFitArrayEnabled();
+}
+
} // namespace DevelTextLabel
} // namespace Toolkit
} // namespace Property
+struct FitOption
+{
+ FitOption(float pointSize = 0.0f, float minLineSize = 0.0f)
+ : mPointSize(pointSize), mMinLineSize(minLineSize) {}
+
+ float GetPointSize() const
+ {
+ return mPointSize;
+ }
+ float GetMinLineSize() const
+ {
+ return mMinLineSize;
+ }
+ void SetPointSize(float pointSize)
+ {
+ mPointSize = pointSize;
+ }
+ void SetMinLineSize(float minLineSize)
+ {
+ mMinLineSize = minLineSize;
+ }
+
+private:
+ float mPointSize = 0.0f;
+ float mMinLineSize = 0.0f;
+};
+
/**
* @brief Get the rendered size of a specific text range.
* if the requested text is at multilines, multiple sizes will be returned for each text located in a separate line.
DALI_TOOLKIT_API Rect<> GetTextBoundingRectangle(TextLabel textLabel, uint32_t startIndex, uint32_t endIndex);
/**
+ * @brief Set text fit array to text label.
+ *
+ * @param[in] textLabel The instance of TextLabel.
+ * @param[in] enable Whether the text fit array is enabled or not.
+ * @param[in] fitOptions list of the fit options.
+ */
+DALI_TOOLKIT_API void SetTextFitArray(TextLabel textLabel, const bool enable, std::vector<FitOption>& fitOptions);
+
+/**
+ * @brief Get the text fit array of text label.
+ *
+ * @param[in] textLabel The instance of TextLabel.
+ * @return list of the fit options.
+ */
+DALI_TOOLKIT_API std::vector<FitOption>& GetTextFitArray(TextLabel textLabel);
+
+/**
+ * @brief Whether the text fit array is enabled or not.
+ *
+ * @return True if the text fit array is enabled.
+ */
+DALI_TOOLKIT_API bool IsTextFitArrayEnabled(TextLabel textLabel);
+
+/**
* @brief Anchor clicked signal type.
*
* @note Signal
}
case Toolkit::DevelTextLabel::Property::TEXT_FIT:
{
+ // If TextFitArray is enabled, this should be disabled.
+ if(impl.mController->IsTextFitArrayEnabled())
+ {
+ impl.mController->SetDefaultLineSize(impl.mController->GetCurrentLineSize());
+ impl.mController->SetTextFitArrayEnabled(false);
+ }
+
ParseTextFitProperty(impl.mController, value.GetMap());
impl.mController->SetTextFitChanged(true);
break;
}
case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
{
- const float lineSize = value.Get<float>();
- impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize(lineSize) || impl.mTextUpdateNeeded;
+ const float lineSize = value.Get<float>();
+ // If TextFitArray is enabled, do not update the default line size.
+ if(!impl.mController->IsTextFitArrayEnabled())
+ {
+ impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize(lineSize) || impl.mTextUpdateNeeded;
+ }
+ impl.mController->SetCurrentLineSize(lineSize);
break;
}
case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE:
}
case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
{
- value = impl.mController->GetDefaultLineSize();
+ // If TextFitArray is enabled, the stored value (MIN_LINE_SIZE set by the user) is retrun.
+ value = impl.mController->IsTextFitArrayEnabled() ? impl.mController->GetCurrentLineSize() : impl.mController->GetDefaultLineSize();
break;
}
case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE:
Vector2 contentSize(size.x - (padding.start + padding.end), size.y - (padding.top + padding.bottom));
- if(mController->IsTextFitEnabled())
+ if(mController->IsTextFitArrayEnabled())
+ {
+ mController->FitArrayPointSizeforLayout(contentSize);
+ mController->SetTextFitContentSize(contentSize);
+ }
+ else if(mController->IsTextFitEnabled())
{
mController->FitPointSizeforLayout(contentSize);
mController->SetTextFitContentSize(contentSize);
mController->SetSpannedText(spannedText);
}
+void TextLabel::SetTextFitArray(const bool enable, std::vector<Toolkit::DevelTextLabel::FitOption>& fitOptions)
+{
+ if(!enable)
+ {
+ // If TextFitArray is disabled, MinLineSize shoud be restored to its original size.
+ mController->SetDefaultLineSize(mController->GetCurrentLineSize());
+ }
+ mController->SetTextFitArrayEnabled(enable);
+ mController->SetTextFitArray(fitOptions);
+}
+
+std::vector<Toolkit::DevelTextLabel::FitOption>& TextLabel::GetTextFitArray()
+{
+ return mController->GetTextFitArray();
+}
+
+bool TextLabel::IsTextFitArrayEnabled() const
+{
+ return mController->IsTextFitArrayEnabled();
+}
+
std::string TextLabel::TextLabelAccessible::GetNameRaw() const
{
return GetWholeText();
*/
void SetSpannedText(const Text::Spanned& spannedText);
+ /**
+ * @brief Set text fit array to text label.
+ *
+ * @param[in] enable Whether the text fit array is enabled or not.
+ * @param[in] fitOptions list of the fit options.
+ */
+ void SetTextFitArray(const bool enable, std::vector<Toolkit::DevelTextLabel::FitOption>& fitOptions);
+
+ /**
+ * @brief Get the text fit array of text label.
+ *
+ * @return list of the fit options.
+ */
+ std::vector<Toolkit::DevelTextLabel::FitOption>& GetTextFitArray();
+
+ /**
+ * @brief Whether the text fit array is enabled or not.
+ *
+ * @return True if the text fit array is enabled.
+ */
+ bool IsTextFitArrayEnabled() const;
+
private: // From Control
/**
* @copydoc Control::OnInitialize()
// Set the normal font and the placeholder font.
defaultFontDescription = impl.mFontDefaults->mFontDescription;
- if(impl.mTextFitEnabled)
+ if(impl.mTextFitEnabled || impl.mTextFitArrayEnabled)
{
defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
}
mMaximumNumberOfCharacters(50u),
mHiddenInput(NULL),
mInputFilter(nullptr),
+ mTextFitContentSize(),
+ mTextFitArray(),
mRecalculateNaturalSize(true),
mMarkupProcessorEnabled(false),
mClipboardHideEnabled(true),
mStrikethroughSetByString(false),
mShouldClearFocusOnEscape(true),
mLayoutDirection(LayoutDirection::LEFT_TO_RIGHT),
+ mCurrentLineSize(0.f),
mTextFitMinSize(DEFAULT_TEXTFIT_MIN),
mTextFitMaxSize(DEFAULT_TEXTFIT_MAX),
mTextFitStepSize(DEFAULT_TEXTFIT_STEP),
mFontSizeScaleEnabled(true),
mTextFitEnabled(false),
mTextFitChanged(false),
+ mTextFitArrayEnabled(false),
mIsLayoutDirectionChanged(false),
mIsUserInteractionEnabled(true)
{
std::unique_ptr<InputFilter> mInputFilter; ///< Avoid allocating this when the user does not specify input filter mode.
Vector2 mTextFitContentSize; ///< Size of Text fit content
+ std::vector<Toolkit::DevelTextLabel::FitOption> mTextFitArray; ///< List of FitOption for TextFitArray operation.
+
bool mRecalculateNaturalSize : 1; ///< Whether the natural size needs to be recalculated.
bool mMarkupProcessorEnabled : 1; ///< Whether the mark-up procesor is enabled.
bool mClipboardHideEnabled : 1; ///< Whether the ClipboardHide function work or not
Shader mShaderBackground; ///< The shader for text background.
+ float mCurrentLineSize; ///< Used to store the MinLineSize set by user when TextFitArray is enabled.
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 mFontSizeScaleEnabled : 1; ///< Whether the font size scale is enabled.
bool mTextFitEnabled : 1; ///< Whether the text's fit is enabled.
bool mTextFitChanged : 1; ///< Whether the text fit property has changed.
+ bool mTextFitArrayEnabled : 1; ///< Whether the text's fit array is enabled.
bool mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed.
bool mIsUserInteractionEnabled : 1; ///< Whether the user interaction is enabled.
return true;
}
+void Controller::Relayouter::FitArrayPointSizeforLayout(Controller& controller, const Size& layoutSize)
+{
+ Controller::Impl& impl = *controller.mImpl;
+
+ const OperationsMask operations = impl.mOperationsPending;
+ if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations) || impl.mTextFitContentSize != layoutSize)
+ {
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_FIT_ARRAY_LAYOUT");
+ std::vector<Toolkit::DevelTextLabel::FitOption> fitOptions = impl.mTextFitArray;
+ int numberOfFitOptions = static_cast<int>(fitOptions.size());
+ if(numberOfFitOptions == 0)
+ {
+ DALI_LOG_ERROR("fitOptions is empty\n");
+ return;
+ }
+
+ ModelPtr& model = impl.mModel;
+ bool actualellipsis = model->mElideEnabled;
+ model->mElideEnabled = false;
+
+ // Sort in ascending order by PointSize.
+ std::sort(fitOptions.begin(), fitOptions.end(), compareByPointSize);
+
+ // Decide whether to use binary search.
+ // If MinLineSize is not sorted in ascending order,
+ // binary search cannot guarantee that it will always find the best value.
+ bool binarySearch = true;
+ float prevMinLineSize = 0.0f;
+ for(Toolkit::DevelTextLabel::FitOption& option : fitOptions)
+ {
+ float optionMinLineSize = option.GetMinLineSize();
+ if(prevMinLineSize > optionMinLineSize)
+ {
+ binarySearch = false;
+ break;
+ }
+ prevMinLineSize = optionMinLineSize;
+ }
+
+ // Set the first FitOption(Minimum PointSize) to the best value.
+ // If the search does not find an optimal value, the minimum PointSize will be used to text fit.
+ Toolkit::DevelTextLabel::FitOption firstOption = fitOptions.front();
+ bool bestSizeUpdatedLatest = false;
+ float bestPointSize = firstOption.GetPointSize();
+ float bestMinLineSize = firstOption.GetMinLineSize();
+
+ if(binarySearch)
+ {
+ int left = 0u;
+ int right = numberOfFitOptions - 1;
+
+ while (left <= right)
+ {
+ int mid = left + (right - left) / 2;
+ Toolkit::DevelTextLabel::FitOption option = fitOptions[mid];
+ float testPointSize = option.GetPointSize();
+ float testMinLineSize = option.GetMinLineSize();
+ impl.SetDefaultLineSize(testMinLineSize);
+
+ if(CheckForTextFit(controller, testPointSize, layoutSize))
+ {
+ bestSizeUpdatedLatest = true;
+ bestPointSize = testPointSize;
+ bestMinLineSize = testMinLineSize;
+ left = mid + 1;
+ }
+ else
+ {
+ bestSizeUpdatedLatest = false;
+ right = mid - 1;
+ }
+ }
+ }
+ else
+ {
+ // If binary search is not possible, search sequentially starting from the largest PointSize.
+ for(auto it = fitOptions.rbegin(); it != fitOptions.rend(); ++it)
+ {
+ Toolkit::DevelTextLabel::FitOption option = *it;
+ float testPointSize = option.GetPointSize();
+ float testMinLineSize = option.GetMinLineSize();
+ impl.SetDefaultLineSize(testMinLineSize);
+
+ if(CheckForTextFit(controller, testPointSize, layoutSize))
+ {
+ bestSizeUpdatedLatest = true;
+ bestPointSize = testPointSize;
+ bestMinLineSize = testMinLineSize;
+ break;
+ }
+ else
+ {
+ bestSizeUpdatedLatest = false;
+ }
+ }
+ }
+
+ // Best point size was not updated. re-run so the TextFit should be fitted really.
+ if(!bestSizeUpdatedLatest)
+ {
+ impl.SetDefaultLineSize(bestMinLineSize);
+ CheckForTextFit(controller, bestPointSize, layoutSize);
+ }
+
+ model->mElideEnabled = actualellipsis;
+ impl.mFontDefaults->mFitPointSize = bestPointSize;
+ impl.mFontDefaults->sizeDefined = true;
+ impl.ClearFontData();
+ }
+}
+
void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const Size& layoutSize)
{
Controller::Impl& impl = *controller.mImpl;
static void FitPointSizeforLayout(Controller& controller, const Size& layoutSize);
/**
+ * @brief Calculates the point size for text for given layout() using text fit array.
+ *
+ * @param[in] controller A reference to the controller class
+ * @param[in] layoutSize The layout size
+ */
+ static void FitArrayPointSizeforLayout(Controller& controller, const Size& layoutSize);
+
+ /**
* @brief Called by the Controller to get the height for a particular width.
*
* @param[in] controller A reference to the controller class
static void DoRelayoutHorizontalAlignment(Controller::Impl& impl, const Size& size, const CharacterIndex startIndex, const Length requestedNumberOfCharacters);
};
+inline bool compareByPointSize(Toolkit::DevelTextLabel::FitOption& lhs, Toolkit::DevelTextLabel::FitOption& rhs)
+{
+ return lhs.GetPointSize() < rhs.GetPointSize();
+}
+
} // namespace Text
} // namespace Toolkit
return mImpl->mTextFitChanged;
}
+void Controller::SetCurrentLineSize(float lineSize)
+{
+ mImpl->mCurrentLineSize = lineSize;
+}
+
+float Controller::GetCurrentLineSize() const
+{
+ return mImpl->mCurrentLineSize;
+}
+
void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
{
mImpl->mTextFitMinSize = (type == POINT_SIZE) ? minSize : ConvertPixelToPoint(minSize);
mImpl->mTextFitLineSize = lineSize;
}
+void Controller::SetTextFitArrayEnabled(bool enabled)
+{
+ mImpl->mTextFitArrayEnabled = enabled;
+ mImpl->ClearFontData();
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsTextFitArrayEnabled() const
+{
+ return mImpl->mTextFitArrayEnabled;
+}
+
+void Controller::SetTextFitArray(std::vector<Toolkit::DevelTextLabel::FitOption>& fitOptions)
+{
+ mImpl->mTextFitArray = fitOptions;
+}
+
+std::vector<Toolkit::DevelTextLabel::FitOption>& Controller::GetTextFitArray()
+{
+ return mImpl->mTextFitArray;
+}
+
void Controller::SetPlaceholderTextElideEnabled(bool enabled)
{
PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
Relayouter::FitPointSizeforLayout(*this, layoutSize);
}
+void Controller::FitArrayPointSizeforLayout(Size layoutSize)
+{
+ Relayouter::FitArrayPointSizeforLayout(*this, layoutSize);
+}
+
float Controller::GetHeightForWidth(float width)
{
return Relayouter::GetHeightForWidth(*this, width);
bool IsTextFitEnabled() const;
/**
+ * @brief Sets current line size.
+ *
+ * @param[in] lineSize line size value to store the MinLineSize set by user when TextFitArray is enabled.
+ */
+ void SetCurrentLineSize(float lineSize);
+
+ /**
+ * @brief Retrieves the current line size.
+ *
+ * @return The current line size
+ */
+ float GetCurrentLineSize() const;
+
+ /**
* @brief Sets minimum size valid for text fit.
*
* @param[in] minimum size value.
void SetTextFitLineSize(float lineSize);
/**
+ * @brief Enable or disable the text fit array.
+ *
+ * @param[in] enabled Whether to enable the text fit array.
+ */
+ void SetTextFitArrayEnabled(bool enabled);
+
+ /**
+ * @brief Whether the text fit array is enabled or not.
+ *
+ * @return True if the text fit array is enabled.
+ */
+ bool IsTextFitArrayEnabled() const;
+
+ /**
+ * @brief Sets the text fit array.
+ *
+ * @param[in] fitOptions The list of text fit options.
+ */
+ void SetTextFitArray(std::vector<Toolkit::DevelTextLabel::FitOption>& fitOptions);
+
+ /**
+ * @brief Retrieve the text fit array.
+ *
+ * @return The list of text fit options.
+ */
+ std::vector<Toolkit::DevelTextLabel::FitOption>& GetTextFitArray();
+
+ /**
* @brief Sets disabled color opacity.
*
* @param[in] opacity The color opacity value in disabled state.
void FitPointSizeforLayout(Size layoutSize);
/**
+ * @brief Calculates the point size for text for given layout() using fit array.
+ */
+ void FitArrayPointSizeforLayout(Size layoutSize);
+
+ /**
* @brief Checks if the point size fits within the layout size.
*
* @return Whether the point size fits within the layout size.