/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali-toolkit/internal/text/text-controller-background-actor.h>
#include <dali-toolkit/internal/text/text-controller-event-handler.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
#include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
#include <dali-toolkit/internal/text/text-controller-relayouter.h>
#include <dali-toolkit/internal/text/text-controller-text-updater.h>
#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-geometry.h>
namespace
{
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
#endif
-constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
-
const std::string EMPTY_STRING("");
template<typename Type>
namespace Dali::Toolkit::Text
{
-
void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
{
if(!decorator)
Dali::LayoutDirection::Type Controller::GetLayoutDirection(Dali::Actor& actor) const
{
- if(mImpl->mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE ||
- (mImpl->mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mImpl->mIsLayoutDirectionChanged))
- {
- return static_cast<Dali::LayoutDirection::Type>(DevelWindow::Get(actor).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
- }
- else
- {
- return static_cast<Dali::LayoutDirection::Type>(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
- }
+ return mImpl->GetLayoutDirection(actor);
}
bool Controller::IsShowingRealText() const
void Controller::GetText(std::string& text) const
{
- if(!mImpl->IsShowingPlaceholderText())
- {
- // Retrieves the text string.
- mImpl->GetText(0u, text);
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this);
- }
+ mImpl->GetText(text);
}
void Controller::SetPlaceholderText(PlaceholderType type, const std::string& text)
{
mImpl->mFontSizeScale = scale;
+ // No relayout is required
+ if(!mImpl->mFontSizeScaleEnabled) return;
+
// Update the cursor position if it's in editing mode
UpdateCursorPosition(mImpl->mEventData);
return mImpl->mFontDefaults ? mImpl->mFontSizeScale : 1.0f;
}
+void Controller::SetFontSizeScaleEnabled(bool enabled)
+{
+ mImpl->mFontSizeScaleEnabled = enabled;
+
+ // Update the cursor position if it's in editing mode
+ UpdateCursorPosition(mImpl->mEventData);
+
+ // Clear the font-specific data
+ mImpl->ClearFontData();
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsFontSizeScaleEnabled() const
+{
+ return mImpl->mFontSizeScaleEnabled;
+}
+
void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
{
EnsureCreated(mImpl->mFontDefaults);
return mImpl->mModel->mVisualModel->GetUnderlineHeight();
}
+void Controller::SetUnderlineType(Text::Underline::Type type)
+{
+ mImpl->mModel->mVisualModel->SetUnderlineType(type);
+
+ mImpl->RequestRelayout();
+}
+
+Text::Underline::Type Controller::GetUnderlineType() const
+{
+ return mImpl->mModel->mVisualModel->GetUnderlineType();
+}
+
+void Controller::SetDashedUnderlineWidth(float width)
+{
+ mImpl->mModel->mVisualModel->SetDashedUnderlineWidth(width);
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetDashedUnderlineWidth() const
+{
+ return mImpl->mModel->mVisualModel->GetDashedUnderlineWidth();
+}
+
+void Controller::SetDashedUnderlineGap(float gap)
+{
+ mImpl->mModel->mVisualModel->SetDashedUnderlineGap(gap);
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetDashedUnderlineGap() const
+{
+ return mImpl->mModel->mVisualModel->GetDashedUnderlineGap();
+}
+
void Controller::SetOutlineColor(const Vector4& color)
{
mImpl->mModel->mVisualModel->SetOutlineColor(color);
return mImpl->mLayoutEngine.GetDefaultLineSize();
}
+bool Controller::SetRelativeLineSize(float relativeLineSize)
+{
+ return mImpl->SetRelativeLineSize(relativeLineSize);
+}
+
+float Controller::GetRelativeLineSize() const
+{
+ return mImpl->GetRelativeLineSize();
+}
+
void Controller::SetInputColor(const Vector4& color)
{
InputProperties::SetInputColor(*this, color);
mImpl->mFontStyleSetByString = setByString;
}
+void Controller::SetStrikethroughHeight(float height)
+{
+ mImpl->mModel->mVisualModel->SetStrikethroughHeight(height);
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetStrikethroughHeight() const
+{
+ return mImpl->mModel->mVisualModel->GetStrikethroughHeight();
+}
+
+void Controller::SetStrikethroughColor(const Vector4& color)
+{
+ mImpl->mModel->mVisualModel->SetStrikethroughColor(color);
+
+ mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetStrikethroughColor() const
+{
+ return mImpl->mModel->mVisualModel->GetStrikethroughColor();
+}
+
+void Controller::SetStrikethroughEnabled(bool enabled)
+{
+ mImpl->mModel->mVisualModel->SetStrikethroughEnabled(enabled);
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsStrikethroughEnabled() const
+{
+ return mImpl->mModel->mVisualModel->IsStrikethroughEnabled();
+}
+
+void Controller::SetInputStrikethroughProperties(const std::string& strikethroughProperties)
+{
+ if(NULL != mImpl->mEventData)
+ {
+ mImpl->mEventData->mInputStyle.strikethroughProperties = strikethroughProperties;
+ }
+}
+
+const std::string& Controller::GetInputStrikethroughProperties() const
+{
+ return (NULL != mImpl->mEventData) ? mImpl->mEventData->mInputStyle.strikethroughProperties : EMPTY_STRING;
+}
+
+bool Controller::IsStrikethroughSetByString()
+{
+ return mImpl->mStrikethroughSetByString;
+}
+
+void Controller::StrikethroughSetByString(bool setByString)
+{
+ mImpl->mStrikethroughSetByString = setByString;
+}
+
Layout::Engine& Controller::GetLayoutEngine()
{
return mImpl->mLayoutEngine;
Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
{
// Make sure the model is up-to-date before layouting
- ProcessModifyEvents();
-
- if(mImpl->mUpdateTextDirection)
- {
- // 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);
-
- // Set the update info to relayout the whole text.
- 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);
-
- Vector3 naturalSize;
- DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
- static_cast<OperationsMask>(onlyOnceOperations |
- LAYOUT | REORDER | UPDATE_DIRECTION),
- naturalSize.GetVectorXY());
-
- // Do not do again the only once operations.
- mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
-
- // 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;
- }
+ EventHandler::ProcessModifyEvents(*this);
- return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
+ return mImpl->GetTextDirection();
}
Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
mImpl->mModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
}
+void Controller::SetCharacterSpacing(float characterSpacing)
+{
+ mImpl->mModel->mVisualModel->SetCharacterSpacing(characterSpacing);
+
+ mImpl->RelayoutAllCharacters();
+ mImpl->RequestRelayout();
+}
+
+const float Controller::GetCharacterSpacing() const
+{
+ return mImpl->mModel->mVisualModel->GetCharacterSpacing();
+}
+
Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
{
return Relayouter::Relayout(*this, size, layoutDirection);
mImpl->RequestRelayout();
}
+Vector<Vector2> Controller::GetTextSize(CharacterIndex startIndex, CharacterIndex endIndex)
+{
+ Vector<Vector2> sizesList;
+ Vector<Vector2> positionsList;
+
+ GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizesList, positionsList);
+ return sizesList;
+}
+
+Vector<Vector2> Controller::GetTextPosition(CharacterIndex startIndex, CharacterIndex endIndex)
+{
+ Vector<Vector2> sizesList;
+ Vector<Vector2> positionsList;
+
+ GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizesList, positionsList);
+ return positionsList;
+}
+
+Rect<> Controller::GetTextBoundingRectangle(CharacterIndex startIndex, CharacterIndex endIndex)
+{
+ Vector<Vector2> sizeList;
+ Vector<Vector2> positionList;
+
+ GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizeList, positionList);
+
+ if(sizeList.Empty() || sizeList.Size() != positionList.Size())
+ {
+ return {0, 0, 0, 0};
+ }
+
+ auto minX = positionList[0].x;
+ auto minY = positionList[0].y;
+ auto maxRight = positionList[0].x + sizeList[0].x;
+ auto maxBottom = positionList[0].y + sizeList[0].y;
+
+ for(unsigned int i = 1; i < sizeList.Size(); i++)
+ {
+ minX = std::min(minX, positionList[i].x);
+ minY = std::min(minY, positionList[i].y);
+ maxRight = std::max(maxRight, positionList[i].x + sizeList[i].x);
+ maxBottom = std::max(maxBottom, positionList[i].y + sizeList[i].y);
+ }
+
+ return {minX, minY, maxRight - minX, maxBottom - minY};
+}
+
bool Controller::IsInputStyleChangedSignalsQueueEmpty()
{
return mImpl->IsInputStyleChangedSignalsQueueEmpty();
EventHandler::SelectEvent(*this, x, y, selectType);
}
-void Controller::SelectEvent(const uint32_t start, const uint32_t end, SelectionType selectType)
-{
- EventHandler::SelectEvent(*this, start, end, selectType);
-}
-
void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
{
if(mImpl->mEventData)
mImpl->mEventData->mIsRightHandleSelected = true;
mImpl->SetTextSelectionRange(start, end);
mImpl->RequestRelayout();
- KeyboardFocusGainEvent();
+ EventHandler::KeyboardFocusGainEvent(*this);
}
}
mImpl->mEventData->mCheckScrollAmount = true;
if(mImpl->SetPrimaryCursorPosition(index, focused) && focused)
{
- KeyboardFocusGainEvent();
+ EventHandler::KeyboardFocusGainEvent(*this);
return true;
}
}
void Controller::SelectWholeText()
{
- SelectEvent(0.f, 0.f, SelectionType::ALL);
+ EventHandler::SelectEvent(*this, 0.f, 0.f, SelectionType::ALL);
}
void Controller::SelectNone()
{
- SelectEvent(0.f, 0.f, SelectionType::NONE);
+ EventHandler::SelectEvent(*this, 0.f, 0.f, SelectionType::NONE);
}
void Controller::SelectText(const uint32_t start, const uint32_t end)
{
- SelectEvent(start, end, SelectionType::RANGE);
+ EventHandler::SelectEvent(*this, start, end, SelectionType::RANGE);
}
string Controller::GetSelectedText() const
{
- string text;
- if(EventData::SELECTING == mImpl->mEventData->mState)
- {
- mImpl->RetrieveSelection(text, false);
- }
- return text;
+ return mImpl->GetSelectedText();
}
string Controller::CopyText()
{
- string text;
- mImpl->RetrieveSelection(text, false);
- mImpl->SendSelectionToClipboard(false); // Text not modified
-
- mImpl->mEventData->mUpdateCursorPosition = true;
-
- mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
-
- return text;
+ return mImpl->CopyText();
}
string Controller::CutText()
{
- string text;
- mImpl->RetrieveSelection(text, false);
-
- if(!IsEditable())
- {
- return EMPTY_STRING;
- }
-
- mImpl->SendSelectionToClipboard(true); // Synchronous call to modify text
- mImpl->mOperationsPending = ALL_OPERATIONS;
-
- if((0u != mImpl->mModel->mLogicalModel->mText.Count()) ||
- !mImpl->IsPlaceholderAvailable())
- {
- mImpl->QueueModifyEvent(ModifyEvent::TEXT_DELETED);
- }
- else
- {
- ShowPlaceholderText();
- }
-
- mImpl->mEventData->mUpdateCursorPosition = true;
- mImpl->mEventData->mScrollAfterDelete = true;
-
- mImpl->RequestRelayout();
-
- if(nullptr != mImpl->mEditableControlInterface)
- {
- mImpl->mEditableControlInterface->TextChanged(true);
- }
- return text;
+ return mImpl->CutText();
}
void Controller::PasteText()
targetSize = mImpl->mModel->mVisualModel->mControlSize;
}
-void Controller::AddDecoration(Actor& actor, bool needsClipping)
+void Controller::AddDecoration(Actor& actor, DecorationType type, bool needsClipping)
{
if(mImpl->mEditableControlInterface)
{
- mImpl->mEditableControlInterface->AddDecoration(actor, needsClipping);
+ mImpl->mEditableControlInterface->AddDecoration(actor, type, needsClipping);
}
}
mImpl->RequestRelayout();
}
-void Controller::InsertText(const std::string& text, Controller::InsertType type)
-{
- TextUpdater::InsertText(*this, text, type);
-}
-
-void Controller::PasteText(const std::string& stringToPaste)
-{
- TextUpdater::PasteText(*this, stringToPaste);
-}
-
-bool Controller::RemoveText(int cursorOffset, int numberOfCharacters, UpdateInputStyleType type)
-{
- return TextUpdater::RemoveText(*this, cursorOffset, numberOfCharacters, type);
-}
-
-bool Controller::RemoveSelectedText()
-{
- return TextUpdater::RemoveSelectedText(*this);
-}
-
-void Controller::InsertTextAnchor(int numberOfCharacters, CharacterIndex previousCursorIndex)
-{
- TextUpdater::InsertTextAnchor(*this, numberOfCharacters, previousCursorIndex);
-}
-
-void Controller::RemoveTextAnchor(int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex)
-{
- TextUpdater::RemoveTextAnchor(*this, cursorOffset, numberOfCharacters, previousCursorIndex);
-}
-
-bool Controller::DoRelayout(const Size& size, OperationsMask operationsRequired, Size& layoutSize)
-{
- return Relayouter::DoRelayout(*this, size, operationsRequired, layoutSize);
-}
-
-void Controller::CalculateVerticalOffset(const Size& controlSize)
-{
- Relayouter::CalculateVerticalOffset(*this, controlSize);
-}
-
-void Controller::ProcessModifyEvents()
-{
- EventHandler::ProcessModifyEvents(*this);
-}
-
-void Controller::TextReplacedEvent()
-{
- EventHandler::TextReplacedEvent(*this);
-}
-
-void Controller::TextInsertedEvent()
-{
- EventHandler::TextInsertedEvent(*this);
-}
-
-void Controller::TextDeletedEvent()
-{
- EventHandler::TextDeletedEvent(*this);
-}
-
-bool Controller::DeleteEvent(int keyCode)
-{
- return EventHandler::DeleteEvent(*this, keyCode);
-}
-
-// private : Helpers.
-
-void Controller::ResetText()
-{
- TextUpdater::ResetText(*this);
-}
-
-void Controller::ShowPlaceholderText()
-{
- PlaceholderHandler::ShowPlaceholderText(*this);
-}
-
void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
{
// Reset the cursor position
Actor Controller::CreateBackgroundActor()
{
- return mImpl->CreateBackgroundActor();
+ return CreateControllerBackgroundActor(mImpl->mView, mImpl->mModel->mVisualModel, mImpl->mModel->mLogicalModel, mImpl->mShaderBackground);
+}
+
+void Controller::GetAnchorActors(std::vector<Toolkit::TextAnchor>& anchorActors)
+{
+ mImpl->GetAnchorActors(anchorActors);
+}
+
+int Controller::GetAnchorIndex(size_t characterOffset)
+{
+ return mImpl->GetAnchorIndex(characterOffset);
}
Controller::Controller(ControlInterface* controlInterface,