// EXTERNAL INCLUDES
#include <dali/devel-api/actors/actor-devel.h>
#include <dali/devel-api/adaptor-framework/key-devel.h>
-#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/devel-api/common/stage.h>
#include <dali/devel-api/object/property-helper-devel.h>
#include <dali/integration-api/debug.h>
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "enableEditing", BOOLEAN, ENABLE_EDITING )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "fontSizeScale", FLOAT, FONT_SIZE_SCALE )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "primaryCursorPosition", INTEGER, PRIMARY_CURSOR_POSITION )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "grabHandleColor", VECTOR4, GRAB_HANDLE_COLOR )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "inputFilter", MAP, INPUT_FILTER )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextField, "ellipsisPosition", INTEGER, ELLIPSIS_POSITION )
DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "maxLengthReached", SIGNAL_MAX_LENGTH_REACHED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED)
+DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "anchorClicked", SIGNAL_ANCHOR_CLICKED )
+DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "inputFiltered", SIGNAL_INPUT_FILTERED )
DALI_TYPE_REGISTRATION_END()
// clang-format on
}
case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
{
- impl.mController->SetMatchSystemLanguageDirection(value.Get<bool>());
+ impl.mController->SetMatchLayoutDirection(value.Get<bool>() ? DevelText::MatchLayoutDirection::LOCALE : DevelText::MatchLayoutDirection::CONTENTS);
break;
}
case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
}
break;
}
+ case Toolkit::DevelTextField::Property::GRAB_HANDLE_COLOR:
+ {
+ const Vector4 color = value.Get<Vector4>();
+ DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p GRAB_HANDLE_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+ impl.mDecorator->SetHandleColor(color);
+ impl.RequestTextRelayout();
+ break;
+ }
+ case Toolkit::DevelTextField::Property::INPUT_FILTER:
+ {
+ const Property::Map* map = value.GetMap();
+ if(map)
+ {
+ impl.mController->SetInputFilterOption(*map);
+ }
+ break;
+ }
+ case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
+ {
+ DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+ if(GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
+ impl.mController->SetEllipsisPosition(ellipsisPositionType);
+ }
+ break;
+ }
} // switch
} // textfield
}
}
case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
{
- value = impl.mController->IsMatchSystemLanguageDirection();
+ value = impl.mController->GetMatchLayoutDirection() != DevelText::MatchLayoutDirection::CONTENTS;
break;
}
case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
value = static_cast<int>(impl.mController->GetPrimaryCursorPosition());
break;
}
+ case Toolkit::DevelTextField::Property::GRAB_HANDLE_COLOR:
+ {
+ value = impl.mDecorator->GetHandleColor();
+ break;
+ }
+ case Toolkit::DevelTextField::Property::INPUT_FILTER:
+ {
+ Property::Map map;
+ impl.mController->GetInputFilterOption(map);
+ value = map;
+ break;
+ }
+ case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
+ {
+ value = impl.mController->GetEllipsisPosition();
+ break;
+ }
} //switch
}
{
field.InputStyleChangedSignal().Connect(tracker, functor);
}
+ else if(0 == strcmp(signalName.c_str(), SIGNAL_ANCHOR_CLICKED))
+ {
+ if(field)
+ {
+ Internal::TextField& fieldImpl(GetImpl(field));
+ fieldImpl.AnchorClickedSignal().Connect(tracker, functor);
+ }
+ }
+ else if(0 == strcmp(signalName.c_str(), SIGNAL_INPUT_FILTERED))
+ {
+ if(field)
+ {
+ Internal::TextField& fieldImpl(GetImpl(field));
+ fieldImpl.InputFilteredSignal().Connect(tracker, functor);
+ }
+ }
else
{
// signalName does not match any signal
return mInputStyleChangedSignal;
}
+DevelTextField::AnchorClickedSignalType& TextField::AnchorClickedSignal()
+{
+ return mAnchorClickedSignal;
+}
+
+DevelTextField::InputFilteredSignalType& TextField::InputFilteredSignal()
+{
+ return mInputFilteredSignal;
+}
+
void TextField::OnInitialize()
{
Actor self = Self();
- mController = Text::Controller::New(this, this, this);
+ mController = Text::Controller::New(this, this, this, this);
// When using the vector-based rendering, the size of the GLyphs are different
TextAbstraction::GlyphType glyphType = (DevelText::RENDERING_VECTOR_BASED == mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(stage.GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
mController->SetLayoutDirection(layoutDirection);
+ self.LayoutDirectionChangedSignal().Connect(this, &TextField::OnLayoutDirectionChanged);
+
// Forward input events to controller
EnableGestureDetection(static_cast<GestureType::Value>(GestureType::TAP | GestureType::PAN | GestureType::LONG_PRESS));
GetTapGestureDetector().SetMaximumTapsRequired(2);
void TextField::ResizeActor(Actor& actor, const Vector2& size)
{
- if (actor.GetProperty<Vector3>(Dali::Actor::Property::SIZE).GetVectorXY() != size)
+ if(actor.GetProperty<Vector3>(Dali::Actor::Property::SIZE).GetVectorXY() != size)
{
actor.SetProperty(Actor::Property::SIZE, size);
}
Vector2 contentSize(size.x - (padding.start + padding.end), size.y - (padding.top + padding.bottom));
// Support Right-To-Left of padding
- Dali::LayoutDirection::Type layoutDirection;
- if(mController->IsMatchSystemLanguageDirection())
- {
- layoutDirection = static_cast<Dali::LayoutDirection::Type>(DevelWindow::Get(self).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
- }
- else
- {
- layoutDirection = static_cast<Dali::LayoutDirection::Type>(self.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
- }
+ Dali::LayoutDirection::Type layoutDirection = mController->GetLayoutDirection(self);
+
if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
{
std::swap(padding.start, padding.end);
ResizeActor(mActiveLayer, contentSize);
}
+ // If there is text changed, callback is called.
+ if(mTextChanged)
+ {
+ EmitTextChangedSignal();
+ }
+
const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
if((Text::Controller::NONE_UPDATED != updateTextType) ||
}
}
-Text::ControllerPtr TextField::getController()
+Text::ControllerPtr TextField::GetTextController()
{
return mController;
}
padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
const Vector2& localPoint = gesture.GetLocalPoint();
mController->TapEvent(gesture.GetNumberOfTaps(), localPoint.x - padding.start, localPoint.y - padding.top);
+ mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top);
SetKeyInputFocus();
}
}
}
-void TextField::CaretMoved(unsigned int position)
+void TextField::CursorMoved(unsigned int position)
{
if(Accessibility::IsUp())
{
- Control::Impl::GetAccessibilityObject(Self())->EmitTextCaretMoved(position);
+ Control::Impl::GetAccessibilityObject(Self())->EmitTextCursorMoved(position);
+ }
+}
+
+void TextField::TextChanged(bool immediate)
+{
+ if(immediate) // Emits TextChangedSignal immediately
+ {
+ EmitTextChangedSignal();
+ }
+ else
+ {
+ mTextChanged = true;
}
}
-void TextField::TextChanged()
+void TextField::EmitTextChangedSignal()
{
Dali::Toolkit::TextField handle(GetOwner());
mTextChangedSignal.Emit(handle);
+ mTextChanged = false;
}
void TextField::MaxLengthReached()
mInputStyleChangedSignal.Emit(handle, fieldInputStyleMask);
}
+void TextField::AnchorClicked(const std::string& href)
+{
+ Dali::Toolkit::TextField handle(GetOwner());
+ mAnchorClickedSignal.Emit(handle, href.c_str(), href.length());
+}
+
+void TextField::InputFiltered(Toolkit::InputFilter::Property::Type type)
+{
+ Dali::Toolkit::TextField handle(GetOwner());
+ mInputFilteredSignal.Emit(handle, type);
+}
+
void TextField::AddDecoration(Actor& actor, bool needsClipping)
{
if(actor)
}
}
+void TextField::GetControlBackgroundColor(Vector4& color) const
+{
+ Property::Value propValue = Self().GetProperty(Toolkit::Control::Property::BACKGROUND);
+ Property::Map* resultMap = propValue.GetMap();
+
+ Property::Value* colorValue = nullptr;
+ if(resultMap && (colorValue = resultMap->Find(ColorVisual::Property::MIX_COLOR)))
+ {
+ colorValue->Get(color);
+ }
+}
+
void TextField::OnSceneConnect(Dali::Actor actor)
{
if(mHasBeenStaged)
return false;
}
+void TextField::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type)
+{
+ mController->ChangedLayoutDirection();
+}
+
void TextField::OnIdleSignal()
{
// Emits the change of input style signals.
mAlignmentOffset(0.f),
mRenderingBackend(DEFAULT_RENDERING_BACKEND),
mExceedPolicy(Dali::Toolkit::TextField::EXCEED_POLICY_CLIP),
- mHasBeenStaged(false)
+ mHasBeenStaged(false),
+ mTextChanged(false)
{
}
std::string TextField::AccessibleImpl::GetName()
{
- auto slf = Toolkit::TextField::DownCast(self);
- return slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+ auto self = Toolkit::TextField::DownCast(Self());
+ return self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
}
-std::string TextField::AccessibleImpl::GetText(size_t startOffset,
- size_t endOffset)
+std::string TextField::AccessibleImpl::GetText(size_t startOffset, size_t endOffset)
{
if(endOffset <= startOffset)
+ {
return {};
+ }
- auto slf = Toolkit::TextField::DownCast(self);
- auto txt =
- slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
- if(startOffset > txt.size() || endOffset > txt.size())
+ if(startOffset > text.size() || endOffset > text.size())
+ {
return {};
+ }
- return txt.substr(startOffset, endOffset - startOffset);
+ return text.substr(startOffset, endOffset - startOffset);
}
size_t TextField::AccessibleImpl::GetCharacterCount()
{
- auto slf = Toolkit::TextField::DownCast(self);
- auto txt =
- slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
- return txt.size();
+ return text.size();
}
-size_t TextField::AccessibleImpl::GetCaretOffset()
+size_t TextField::AccessibleImpl::GetCursorOffset()
{
- auto slf = Toolkit::TextField::DownCast(self);
- return Dali::Toolkit::GetImpl(slf).getController()->GetCursorPosition();
+ auto self = Toolkit::TextField::DownCast(Self());
+ return Dali::Toolkit::GetImpl(self).GetTextController()->GetCursorPosition();
}
-bool TextField::AccessibleImpl::SetCaretOffset(size_t offset)
+bool TextField::AccessibleImpl::SetCursorOffset(size_t offset)
{
- auto slf = Toolkit::TextField::DownCast(self);
- auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
- if(offset > txt.size())
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+ if(offset > text.size())
+ {
return false;
+ }
+
+ auto& selfImpl = Dali::Toolkit::GetImpl(self);
+ selfImpl.GetTextController()->ResetCursorPosition(offset);
+ selfImpl.RequestTextRelayout();
- auto& slfImpl = Dali::Toolkit::GetImpl(slf);
- slfImpl.getController()->ResetCursorPosition(offset);
- slfImpl.RequestTextRelayout();
return true;
}
Dali::Accessibility::Range TextField::AccessibleImpl::GetTextAtOffset(
size_t offset, Dali::Accessibility::TextBoundary boundary)
{
- auto slf = Toolkit::TextField::DownCast(self);
- auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
- auto txt_size = txt.size();
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+ auto textSize = text.size();
auto range = Dali::Accessibility::Range{};
{
case Dali::Accessibility::TextBoundary::CHARACTER:
{
- if(offset < txt_size)
+ if(offset < textSize)
{
- range.content = txt[offset];
+ range.content = text[offset];
range.startOffset = offset;
range.endOffset = offset + 1;
}
+ break;
}
- break;
case Dali::Accessibility::TextBoundary::WORD:
case Dali::Accessibility::TextBoundary::LINE:
{
- auto txt_c_string = txt.c_str();
- auto breaks = std::vector<char>(txt_size, 0);
+ auto textString = text.c_str();
+ auto breaks = std::vector<char>(textSize, 0);
+
if(boundary == Dali::Accessibility::TextBoundary::WORD)
- Accessibility::Accessible::FindWordSeparationsUtf8((const utf8_t*)txt_c_string, txt_size, "", breaks.data());
+ {
+ Accessibility::Accessible::FindWordSeparationsUtf8(reinterpret_cast<const utf8_t*>(textString), textSize, "", breaks.data());
+ }
else
- Accessibility::Accessible::FindLineSeparationsUtf8((const utf8_t*)txt_c_string, txt_size, "", breaks.data());
+ {
+ Accessibility::Accessible::FindLineSeparationsUtf8(reinterpret_cast<const utf8_t*>(textString), textSize, "", breaks.data());
+ }
+
auto index = 0u;
auto counter = 0u;
- while(index < txt_size && counter <= offset)
+ while(index < textSize && counter <= offset)
{
auto start = index;
if(breaks[index])
{
while(breaks[index])
+ {
index++;
+ }
counter++;
}
else
{
if(boundary == Dali::Accessibility::TextBoundary::WORD)
+ {
index++;
+ }
if(boundary == Dali::Accessibility::TextBoundary::LINE)
+ {
counter++;
+ }
}
+
if((counter > 0) && ((counter - 1) == offset))
{
- range.content = txt.substr(start, index - start + 1);
+ range.content = text.substr(start, index - start + 1);
range.startOffset = start;
range.endOffset = index + 1;
}
+
if(boundary == Dali::Accessibility::TextBoundary::LINE)
+ {
index++;
+ }
}
+ break;
}
- break;
case Dali::Accessibility::TextBoundary::SENTENCE:
{
- /* not supported by efl */
+ /* not supported by default */
+ break;
}
- break;
case Dali::Accessibility::TextBoundary::PARAGRAPH:
{
/* Paragraph is not supported by libunibreak library */
+ break;
}
- break;
default:
break;
}
return range;
}
-Dali::Accessibility::Range
-TextField::AccessibleImpl::GetSelection(size_t selectionNum)
+Dali::Accessibility::Range TextField::AccessibleImpl::GetRangeOfSelection(size_t selectionIndex)
{
// Since DALi supports only one selection indexes higher than 0 are ignored
- if(selectionNum > 0)
+ if(selectionIndex > 0)
+ {
return {};
+ }
- auto slf = Toolkit::TextField::DownCast(self);
- auto ctrl = Dali::Toolkit::GetImpl(slf).getController();
- std::string ret;
- ctrl->RetrieveSelection(ret);
- auto r = ctrl->GetSelectionIndexes();
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
+ std::string value{};
+ controller->RetrieveSelection(value);
+ auto indices = controller->GetSelectionIndexes();
- return {static_cast<size_t>(r.first), static_cast<size_t>(r.second), ret};
+ return {static_cast<size_t>(indices.first), static_cast<size_t>(indices.second), value};
}
-bool TextField::AccessibleImpl::RemoveSelection(size_t selectionNum)
+bool TextField::AccessibleImpl::RemoveSelection(size_t selectionIndex)
{
// Since DALi supports only one selection indexes higher than 0 are ignored
- if(selectionNum > 0)
+ if(selectionIndex > 0)
+ {
return false;
+ }
- auto slf = Toolkit::TextField::DownCast(self);
- Dali::Toolkit::GetImpl(slf).getController()->SetSelection(0, 0);
+ auto self = Toolkit::TextField::DownCast(Self());
+ Dali::Toolkit::GetImpl(self).GetTextController()->SetSelection(0, 0);
return true;
}
-bool TextField::AccessibleImpl::SetSelection(size_t selectionNum,
- size_t startOffset,
- size_t endOffset)
+bool TextField::AccessibleImpl::SetRangeOfSelection(size_t selectionIndex, size_t startOffset, size_t endOffset)
{
// Since DALi supports only one selection indexes higher than 0 are ignored
- if(selectionNum > 0)
+ if(selectionIndex > 0)
+ {
+ return false;
+ }
+
+ auto self = Toolkit::TextField::DownCast(Self());
+ Dali::Toolkit::GetImpl(self).GetTextController()->SetSelection(startOffset, endOffset);
+ return true;
+}
+
+bool TextField::AccessibleImpl::CopyText(size_t startPosition, size_t endPosition)
+{
+ if(endPosition <= startPosition)
+ {
return false;
+ }
+
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+ Dali::Toolkit::GetImpl(self).GetTextController()->CopyStringToClipboard(text.substr(startPosition, endPosition - startPosition));
- auto slf = Toolkit::TextField::DownCast(self);
- Dali::Toolkit::GetImpl(slf).getController()->SetSelection(startOffset,
- endOffset);
return true;
}
-bool TextField::AccessibleImpl::CopyText(size_t startPosition,
- size_t endPosition)
+bool TextField::AccessibleImpl::CutText(size_t startPosition, size_t endPosition)
{
if(endPosition <= startPosition)
+ {
return false;
+ }
- auto slf = Toolkit::TextField::DownCast(self);
- auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
- Dali::Toolkit::GetImpl(slf).getController()->CopyStringToClipboard(txt.substr(startPosition, endPosition - startPosition));
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+ Dali::Toolkit::GetImpl(self).GetTextController()->CopyStringToClipboard(text.substr(startPosition, endPosition - startPosition));
+
+ self.SetProperty(Toolkit::TextField::Property::TEXT, text.substr(0, startPosition) + text.substr(endPosition));
return true;
}
-bool TextField::AccessibleImpl::CutText(size_t startPosition,
- size_t endPosition)
+bool TextField::AccessibleImpl::DeleteText(size_t startPosition, size_t endPosition)
{
if(endPosition <= startPosition)
+ {
return false;
+ }
- auto slf = Toolkit::TextField::DownCast(self);
- auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
- Dali::Toolkit::GetImpl(slf).getController()->CopyStringToClipboard(txt.substr(startPosition, endPosition - startPosition));
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto text = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
- slf.SetProperty(Toolkit::TextField::Property::TEXT,
- txt.substr(0, startPosition) + txt.substr(endPosition - startPosition, txt.size()));
+ self.SetProperty(Toolkit::TextField::Property::TEXT, text.substr(0, startPosition) + text.substr(endPosition));
return true;
}
states[State::FOCUSABLE] = true;
Toolkit::Control focusControl = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
- if(self == focusControl)
+ if(mSelf == focusControl)
{
states[State::FOCUSED] = true;
}
return states;
}
+bool TextField::AccessibleImpl::InsertText(size_t startPosition, std::string text)
+{
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto insertedText = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+
+ insertedText.insert(startPosition, text);
+
+ self.SetProperty(Toolkit::TextField::Property::TEXT, std::move(insertedText));
+
+ return true;
+}
+
+bool TextField::AccessibleImpl::SetTextContents(std::string newContents)
+{
+ auto self = Toolkit::TextField::DownCast(Self());
+ self.SetProperty(Toolkit::TextField::Property::TEXT, std::move(newContents));
+ return true;
+}
+
} // namespace Internal
} // namespace Toolkit