From 094ca4278df850c7870382c3896476a1bd1c9b7b Mon Sep 17 00:00:00 2001 From: abdullah Date: Mon, 26 Jul 2021 09:42:30 +0300 Subject: [PATCH] Support line spacing & min line size in texteditor support texteditor to have properties like textlabel. line spacing set the space between lines. min line size set the total line size (we internally take the max between line size vs font line size) Change-Id: I2cccc910406db181561ff5e7274b997b60b44737 --- .../src/dali-toolkit/utc-Dali-TextEditor.cpp | 55 +++++++++++++++++++ .../text-controls/text-editor-devel.h | 7 +++ .../devel-api/text/text-utils-devel.cpp | 4 +- .../text-controls/text-editor-impl.cpp | 42 ++++++++------ .../internal/text/cursor-helper-functions.cpp | 16 ++---- .../internal/text/layouts/layout-engine.cpp | 14 +++-- dali-toolkit/internal/text/line-run.h | 7 +++ .../text-controller-impl-event-handler.cpp | 4 +- .../internal/text/text-controller.cpp | 21 +++++++ dali-toolkit/internal/text/text-controller.h | 5 ++ .../text/text-selection-handle-controller.cpp | 8 +-- dali-toolkit/internal/text/text-view.cpp | 4 +- 12 files changed, 142 insertions(+), 45 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp index 9b1d0ff1a5..5003beae0c 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp @@ -1005,6 +1005,11 @@ int UtcDaliTextEditorSetPropertyP(void) application.SendNotification(); application.Render(); + // Check the line size property + DALI_TEST_EQUALS( editor.GetProperty( DevelTextEditor::Property::MIN_LINE_SIZE ), 0.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + editor.SetProperty( DevelTextEditor::Property::MIN_LINE_SIZE, 50.f ); + DALI_TEST_EQUALS( editor.GetProperty( DevelTextEditor::Property::MIN_LINE_SIZE ), 50.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + END_TEST; } @@ -3974,5 +3979,55 @@ int UtcDaliToolkitTextEditorEllipsisPositionProperty(void) textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, "end"); DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION ); + END_TEST; +} + +int UtcDaliTextEditorLineSpacing(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextEditorLineSpacing "); + + TextEditor textEditor = TextEditor::New(); + textEditor.SetProperty( Actor::Property::SIZE, Vector2( 400.0f, 400.f ) ); + application.GetScene().Add( textEditor ); + application.SendNotification(); + application.Render(); + + textEditor.SetProperty( TextEditor::Property::TEXT, "Line #1\nLine #2\nLine #3" ); + textEditor.SetProperty( DevelTextEditor::Property::LINE_SPACING, 0 ); + + Vector3 sizeBefore = textEditor.GetNaturalSize(); + + textEditor.SetProperty( DevelTextEditor::Property::LINE_SPACING, 20 ); + + //add 20 for each line 20 * 3 + DALI_TEST_EQUALS(sizeBefore.height + 60.0f, textEditor.GetNaturalSize().height, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliTextEditorMinLineSize(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextEditorMinLineSize "); + + TextEditor textEditor = TextEditor::New(); + textEditor.SetProperty( Actor::Property::SIZE, Vector2( 400.0f, 400.f ) ); + application.GetScene().Add( textEditor ); + application.SendNotification(); + application.Render(); + + textEditor.SetProperty( TextEditor::Property::TEXT, "Line #1\nLine #2\nLine #3" ); + textEditor.SetProperty( DevelTextEditor::Property::MIN_LINE_SIZE, 0 ); + + Vector3 sizeBefore = textEditor.GetNaturalSize(); + + textEditor.SetProperty( DevelTextEditor::Property::MIN_LINE_SIZE, 60 ); + + DALI_TEST_NOT_EQUALS( sizeBefore, textEditor.GetNaturalSize(), 0.0f, TEST_LOCATION); + + //60 * 3 lines + DALI_TEST_EQUALS(180.0f, textEditor.GetNaturalSize().height, TEST_LOCATION); + END_TEST; } \ No newline at end of file diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h index 2d145428ad..7a6442ac83 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h +++ b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h @@ -267,6 +267,13 @@ enum Type * @see DevelText::EllipsisPosition */ ELLIPSIS_POSITION, + + /** + * @brief Sets the height of the line in points. + * @details Name "minLineSize", type Property::FLOAT. + * @note If the font size is larger than the line size, it works with the font size. + */ + MIN_LINE_SIZE, }; } // namespace Property diff --git a/dali-toolkit/devel-api/text/text-utils-devel.cpp b/dali-toolkit/devel-api/text/text-utils-devel.cpp index 9609a3b214..41d7126d4f 100644 --- a/dali-toolkit/devel-api/text/text-utils-devel.cpp +++ b/dali-toolkit/devel-api/text/text-utils-devel.cpp @@ -828,7 +828,7 @@ void Ellipsis(const RendererParameters& textParameters, TextAbstraction::TextRen { Length finalNumberOfGlyphs = 0u; - if((line.ascender - line.descender) > textLayoutArea.height) + if((GetLineHeight(line)) > textLayoutArea.height) { // The height of the line is bigger than the height of the text area. // Show the ellipsis glyph even if it doesn't fit in the text area. @@ -1524,7 +1524,7 @@ Dali::Property::Array RenderForLastIndex(RendererParameters& textParameters) const LineRun& line = *(lines.Begin() + index); numberOfCharacters += line.characterRun.numberOfCharacters; - lineOffset = lineSize > 0.f ? lineSize : (line.ascender + -line.descender); + lineOffset = lineSize > 0.f ? lineSize : GetLineHeight(line); penY += lineOffset; if((penY + lineOffset) > boundingBox) { diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp index dd67a85a89..8dee30e3c4 100644 --- a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp @@ -151,6 +151,7 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "inputMethodSett DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "inputFilter", MAP, INPUT_FILTER ) DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "ellipsis", BOOLEAN, ELLIPSIS ) DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "ellipsisPosition", INTEGER, ELLIPSIS_POSITION ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "minLineSize", FLOAT, MIN_LINE_SIZE ) DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED ) DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED) @@ -491,13 +492,8 @@ void TextEditor::SetProperty(BaseObject* object, Property::Index index, const Pr } case Toolkit::TextEditor::Property::LINE_SPACING: { - // The line spacing isn't supported by the TextEditor. Since it's supported - // by the TextLabel for now it must be ignored. The property is being shadowed - // locally so its value isn't affected. const float lineSpacing = value.Get(); - impl.mLineSpacing = lineSpacing; - // set it to 0.0 due to missing implementation - impl.mController->SetDefaultLineSpacing(0.0f); + impl.mController->SetDefaultLineSpacing(lineSpacing); impl.mRenderer.Reset(); break; } @@ -832,6 +828,15 @@ void TextEditor::SetProperty(BaseObject* object, Property::Index index, const Pr } break; } + case Toolkit::DevelTextEditor::Property::MIN_LINE_SIZE: + { + const float minLineSize = value.Get(); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p MIN_LINE_SIZE %f\n", impl.mController.Get(), minLineSize); + + impl.mController->SetDefaultLineSize(minLineSize); + impl.mRenderer.Reset(); + break; + } } // switch } // texteditor } @@ -1011,9 +1016,7 @@ Property::Value TextEditor::GetProperty(BaseObject* object, Property::Index inde } case Toolkit::TextEditor::Property::LINE_SPACING: { - // LINE_SPACING isn't implemented for the TextEditor. Returning - // only shadowed value, not the real one. - value = impl.mLineSpacing; + value = impl.mController->GetDefaultLineSpacing(); break; } case Toolkit::TextEditor::Property::INPUT_LINE_SPACING: @@ -1222,6 +1225,11 @@ Property::Value TextEditor::GetProperty(BaseObject* object, Property::Index inde value = impl.mController->GetEllipsisPosition(); break; } + case Toolkit::DevelTextEditor::Property::MIN_LINE_SIZE: + { + value = impl.mController->GetDefaultLineSize(); + break; + } } //switch } @@ -2291,10 +2299,10 @@ bool TextEditor::AccessibleImpl::SetCursorOffset(size_t offset) return true; } -Dali::Accessibility::Range TextEditor::AccessibleImpl::GetTextAtOffset( size_t offset, Dali::Accessibility::TextBoundary boundary) +Dali::Accessibility::Range TextEditor::AccessibleImpl::GetTextAtOffset(size_t offset, Dali::Accessibility::TextBoundary boundary) { - auto self = Toolkit::TextEditor::DownCast(Self()); - auto text = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get(); + auto self = Toolkit::TextEditor::DownCast(Self()); + auto text = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get(); auto textSize = text.size(); auto range = Dali::Accessibility::Range{}; @@ -2315,7 +2323,7 @@ Dali::Accessibility::Range TextEditor::AccessibleImpl::GetTextAtOffset( size_t o case Dali::Accessibility::TextBoundary::LINE: { auto textString = text.c_str(); - auto breaks = std::vector(textSize, 0); + auto breaks = std::vector(textSize, 0); if(boundary == Dali::Accessibility::TextBoundary::WORD) { @@ -2390,8 +2398,8 @@ Dali::Accessibility::Range TextEditor::AccessibleImpl::GetRangeOfSelection(size_ return {}; } - auto self = Toolkit::TextEditor::DownCast(Self()); - auto controller = Dali::Toolkit::GetImpl(self).GetTextController(); + auto self = Toolkit::TextEditor::DownCast(Self()); + auto controller = Dali::Toolkit::GetImpl(self).GetTextController(); std::string value{}; controller->RetrieveSelection(value); auto indices = controller->GetSelectionIndexes(); @@ -2474,7 +2482,7 @@ Dali::Accessibility::States TextEditor::AccessibleImpl::CalculateStates() { using namespace Dali::Accessibility; - auto states = DevelControl::AccessibleImpl::CalculateStates(); + auto states = DevelControl::AccessibleImpl::CalculateStates(); states[State::EDITABLE] = true; states[State::FOCUSABLE] = true; @@ -2489,7 +2497,7 @@ Dali::Accessibility::States TextEditor::AccessibleImpl::CalculateStates() bool TextEditor::AccessibleImpl::InsertText(size_t startPosition, std::string text) { - auto self = Toolkit::TextEditor::DownCast(Self()); + auto self = Toolkit::TextEditor::DownCast(Self()); auto insertedText = self.GetProperty(Toolkit::TextEditor::Property::TEXT).Get(); insertedText.insert(startPosition, text); diff --git a/dali-toolkit/internal/text/cursor-helper-functions.cpp b/dali-toolkit/internal/text/cursor-helper-functions.cpp index 1df142c7c3..c2d35d9be5 100644 --- a/dali-toolkit/internal/text/cursor-helper-functions.cpp +++ b/dali-toolkit/internal/text/cursor-helper-functions.cpp @@ -155,9 +155,7 @@ LineIndex GetClosestLine(VisualModelPtr visualModel, { const LineRun& lineRun = *it; - // The line height is the addition of the line ascender and the line descender. - // However, the line descender has a negative value, hence the subtraction. - totalHeight += lineRun.ascender - lineRun.descender; + totalHeight += GetLineHeight(lineRun); if(visualY < totalHeight) { @@ -186,9 +184,7 @@ float CalculateLineOffset(const Vector& lines, { const LineRun& lineRun = *it; - // The line height is the addition of the line ascender and the line descender. - // However, the line descender has a negative value, hence the subtraction. - offset += lineRun.ascender - lineRun.descender; + offset += GetLineHeight(lineRun); } return offset; @@ -495,9 +491,7 @@ void GetCursorPosition(GetCursorPositionParameters& parameters, cursorInfo.lineOffset = CalculateLineOffset(parameters.visualModel->mLines, newLineIndex); - // The line height is the addition of the line ascender and the line descender. - // However, the line descender has a negative value, hence the subtraction. - cursorInfo.lineHeight = newLine.ascender - newLine.descender; + cursorInfo.lineHeight = GetLineHeight(newLine); // Set the primary cursor's height. cursorInfo.primaryCursorHeight = cursorInfo.lineHeight; @@ -543,9 +537,7 @@ void GetCursorPosition(GetCursorPositionParameters& parameters, cursorInfo.lineOffset = CalculateLineOffset(parameters.visualModel->mLines, lineIndex); - // The line height is the addition of the line ascender and the line descender. - // However, the line descender has a negative value, hence the subtraction. - cursorInfo.lineHeight = line.ascender - line.descender; + cursorInfo.lineHeight = GetLineHeight(line); // Calculate the primary cursor. diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index b27f6349ca..695d950a69 100644 --- a/dali-toolkit/internal/text/layouts/layout-engine.cpp +++ b/dali-toolkit/internal/text/layouts/layout-engine.cpp @@ -36,6 +36,12 @@ namespace Toolkit { namespace Text { +float GetLineHeight(const LineRun lineRun) +{ + // The line height is the addition of the line ascender, the line descender and the line spacing. + // However, the line descender has a negative value, hence the subtraction. + return lineRun.ascender - lineRun.descender + lineRun.lineSpacing; +} namespace Layout { namespace @@ -1275,7 +1281,7 @@ struct Engine::Impl layoutSize.width = layoutParameters.boundingBox.width; if(layoutSize.height < Math::MACHINE_EPSILON_1000) { - layoutSize.height += (lineRun->ascender + -lineRun->descender) + lineRun->lineSpacing; + layoutSize.height += GetLineHeight(*lineRun); } const Vector& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo; @@ -1382,7 +1388,7 @@ struct Engine::Impl layoutSize.width = lineRun.width; } - layoutSize.height += (lineRun.ascender + -lineRun.descender) + lineRun.lineSpacing; + layoutSize.height += GetLineHeight(lineRun); } /** @@ -1433,7 +1439,7 @@ struct Engine::Impl lineRun.lineSpacing += mDefaultLineSpacing; - layoutSize.height += (lineRun.ascender + -lineRun.descender) + lineRun.lineSpacing; + layoutSize.height += GetLineHeight(lineRun); } /** @@ -1457,7 +1463,7 @@ struct Engine::Impl layoutSize.width = line.width; } - layoutSize.height += (line.ascender + -line.descender) + line.lineSpacing; + layoutSize.height += GetLineHeight(line); } } diff --git a/dali-toolkit/internal/text/line-run.h b/dali-toolkit/internal/text/line-run.h index ff826e64c7..52c47a13e8 100644 --- a/dali-toolkit/internal/text/line-run.h +++ b/dali-toolkit/internal/text/line-run.h @@ -48,6 +48,13 @@ struct LineRun CharacterRun characterRunForSecondHalfLine; ///< The initial character index and the number of characters of the run for the second half of line. }; +/** + * @brief Get the line height for the specified line run. + * + * @param[in] lineRun The line runs to get the height for. + */ +float GetLineHeight(const LineRun lineRun); + } // namespace Text } // namespace Toolkit diff --git a/dali-toolkit/internal/text/text-controller-impl-event-handler.cpp b/dali-toolkit/internal/text/text-controller-impl-event-handler.cpp index 2aafff7b19..f8aa7a59ed 100644 --- a/dali-toolkit/internal/text/text-controller-impl-event-handler.cpp +++ b/dali-toolkit/internal/text/text-controller-impl-event-handler.cpp @@ -338,7 +338,7 @@ void ControllerImplEventHandler::OnCursorKeyEvent(Controller::Impl& impl, const const LineRun& line = *(visualModel->mLines.Begin() + previousLineIndex); // Get the next hit 'y' point. - const float hitPointY = cursorInfo.lineOffset - 0.5f * (line.ascender - line.descender); + const float hitPointY = cursorInfo.lineOffset - 0.5f * GetLineHeight(line); // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index. bool matchedCharacter = false; @@ -374,7 +374,7 @@ void ControllerImplEventHandler::OnCursorKeyEvent(Controller::Impl& impl, const const LineRun& line = *(visualModel->mLines.Begin() + lineIndex + 1u); // Get the next hit 'y' point. - const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * (line.ascender - line.descender); + const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * GetLineHeight(line); // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index. bool matchedCharacter = false; diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index dce67ff237..b058e2696b 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -1219,12 +1219,31 @@ const std::string& Controller::GetDefaultOutlineProperties() const return EMPTY_STRING; } +void Controller::RelayoutForNewLineSize() +{ + // relayout all characters + mImpl->mTextUpdateInfo.mCharacterIndex = 0; + mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); + mImpl->mOperationsPending = static_cast(mImpl->mOperationsPending | LAYOUT); + + //remove selection + if((mImpl->mEventData != nullptr) && (mImpl->mEventData->mState == EventData::SELECTING)) + { + mImpl->ChangeState(EventData::EDITING); + } + + mImpl->RequestRelayout(); +} + bool Controller::SetDefaultLineSpacing(float lineSpacing) { if(std::fabs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000) { mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing); mImpl->mRecalculateNaturalSize = true; + + RelayoutForNewLineSize(); return true; } return false; @@ -1241,6 +1260,8 @@ bool Controller::SetDefaultLineSize(float lineSize) { mImpl->mLayoutEngine.SetDefaultLineSize(lineSize); mImpl->mRecalculateNaturalSize = true; + + RelayoutForNewLineSize(); return true; } return false; diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 8c388b93d2..109be1ab27 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -1874,6 +1874,11 @@ private: // Helpers. */ void ResetScrollPosition(); + /** + * @brief fill needed relayout parameters when line size is changed & request relayout. + */ + void RelayoutForNewLineSize(); + private: // Private contructors & copy operator. /** * @brief Private constructor. diff --git a/dali-toolkit/internal/text/text-selection-handle-controller.cpp b/dali-toolkit/internal/text/text-selection-handle-controller.cpp index 06017501e4..b0825108fb 100644 --- a/dali-toolkit/internal/text/text-selection-handle-controller.cpp +++ b/dali-toolkit/internal/text/text-selection-handle-controller.cpp @@ -144,9 +144,7 @@ void SelectionHandleController::Reposition(Controller::Impl& impl) lineRun += firstLineIndex; - // The line height is the addition of the line ascender and the line descender. - // However, the line descender has a negative value, hence the subtraction. - selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender; + selectionBoxInfo->lineHeight = GetLineHeight(*lineRun); GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u; @@ -275,9 +273,7 @@ void SelectionHandleController::Reposition(Controller::Impl& impl) // Update the line's vertical offset. selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight; - // The line height is the addition of the line ascender and the line descender. - // However, the line descender has a negative value, hence the subtraction. - selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender; + selectionBoxInfo->lineHeight = GetLineHeight(*lineRun); } } } diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp index f8a2722ac9..a5a6b3b2c4 100644 --- a/dali-toolkit/internal/text/text-view.cpp +++ b/dali-toolkit/internal/text/text-view.cpp @@ -225,7 +225,7 @@ Length View::GetGlyphs(GlyphInfo* glyphs, lastGlyphIndexOfLine = (line->isSplitToTwoHalves ? line->glyphRunSecondHalf.glyphIndex + line->glyphRunSecondHalf.numberOfGlyphs : line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs) - 1u; - penY += line->ascender; + penY += line->ascender + line->lineSpacing; } } } @@ -265,7 +265,7 @@ Length View::GetGlyphs(GlyphInfo* glyphs, const LineRun& elidedLine = *ellipsisLine; if((1u == numberOfLines) && - (elidedLine.ascender - elidedLine.descender > mImpl->mVisualModel->mControlSize.height)) + (GetLineHeight(elidedLine) > mImpl->mVisualModel->mControlSize.height)) { // Replace the first glyph with ellipsis glyph auto indexOfFirstGlyph = (ellipsisPosition == DevelText::EllipsisPosition::START) ? startIndexOfEllipsis : 0u; -- 2.34.1