// 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, "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_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_SIGNAL_REGISTRATION(Toolkit, TextField, "cursorPositionChanged", SIGNAL_CURSOR_POSITION_CHANGED)
+DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "selectionChanged", SIGNAL_SELECTION_CHANGED )
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:
{
uint32_t position = static_cast<uint32_t>(value.Get<int>());
DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p PRIMARY_CURSOR_POSITION %d\n", impl.mController.Get(), position);
- if(impl.mController->SetPrimaryCursorPosition(position))
+ if(impl.mController->SetPrimaryCursorPosition(position, impl.HasKeyInputFocus()))
{
impl.SetKeyInputFocus();
}
}
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 = map;
break;
}
+ case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
+ {
+ value = impl.mController->GetEllipsisPosition();
+ break;
+ }
} //switch
}
}
}
+void TextField::SelectText(const uint32_t start, const uint32_t end)
+{
+ if(mController && mController->IsShowingRealText())
+ {
+ mController->SelectText(start, end);
+ SetKeyInputFocus();
+ }
+}
+
string TextField::GetSelectedText() const
{
string selectedText = "";
return range;
}
+string TextField::CopyText()
+{
+ string copiedText = "";
+ if(mController && mController->IsShowingRealText())
+ {
+ copiedText = mController->CopyText();
+ }
+ return copiedText;
+}
+
+string TextField::CutText()
+{
+ string cutText = "";
+ if(mController && mController->IsShowingRealText())
+ {
+ cutText = mController->CutText();
+ }
+ return cutText;
+}
+
+void TextField::PasteText()
+{
+ if(mController)
+ {
+ SetKeyInputFocus(); //Giving focus to the field that was passed to the PasteText in case the passed field (current field) doesn't have focus.
+ mController->PasteText();
+ }
+}
+
InputMethodContext TextField::GetInputMethodContext()
{
return mInputMethodContext;
fieldImpl.AnchorClickedSignal().Connect(tracker, functor);
}
}
+ else if(0 == strcmp(signalName.c_str(), SIGNAL_CURSOR_POSITION_CHANGED))
+ {
+ if(field)
+ {
+ Internal::TextField& fieldImpl(GetImpl(field));
+ fieldImpl.CursorPositionChangedSignal().Connect(tracker, functor);
+ }
+ }
else if(0 == strcmp(signalName.c_str(), SIGNAL_INPUT_FILTERED))
{
if(field)
fieldImpl.InputFilteredSignal().Connect(tracker, functor);
}
}
+ else if(0 == strcmp(signalName.c_str(), SIGNAL_SELECTION_CHANGED))
+ {
+ if(field)
+ {
+ Internal::TextField& fieldImpl(GetImpl(field));
+ fieldImpl.SelectionChangedSignal().Connect(tracker, functor);
+ }
+ }
else
{
// signalName does not match any signal
return mAnchorClickedSignal;
}
+DevelTextField::CursorPositionChangedSignalType& TextField::CursorPositionChangedSignal()
+{
+ return mCursorPositionChangedSignal;
+}
+
DevelTextField::InputFilteredSignalType& TextField::InputFilteredSignal()
{
return mInputFilteredSignal;
}
+DevelTextField::SelectionChangedSignalType& TextField::SelectionChangedSignal()
+{
+ return mSelectionChangedSignal;
+}
+
void TextField::OnInitialize()
{
Actor self = Self();
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);
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);
RenderText(updateTextType);
}
+ if(mCursorPositionChanged)
+ {
+ EmitCursorPositionChangedSignal();
+ }
+
+ if(mSelectionChanged)
+ {
+ EmitSelectionChangedSignal();
+ }
+
// The text-field emits signals when the input style changes. These changes of style are
// detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
// can't be emitted during the size negotiation as the callbacks may update the UI.
}
}
-void TextField::CursorMoved(unsigned int position)
+void TextField::CursorPositionChanged(unsigned int oldPosition, unsigned int newPosition)
{
if(Accessibility::IsUp())
{
- Control::Impl::GetAccessibilityObject(Self())->EmitTextCursorMoved(position);
+ Control::Impl::GetAccessibilityObject(Self())->EmitTextCursorMoved(newPosition);
+ }
+
+ if((oldPosition != newPosition) && !mCursorPositionChanged)
+ {
+ mCursorPositionChanged = true;
+ mOldPosition = oldPosition;
}
}
mAnchorClickedSignal.Emit(handle, href.c_str(), href.length());
}
+void TextField::EmitCursorPositionChangedSignal()
+{
+ Dali::Toolkit::TextField handle(GetOwner());
+ mCursorPositionChangedSignal.Emit(handle, mOldPosition);
+ mCursorPositionChanged = false;
+}
+
void TextField::InputFiltered(Toolkit::InputFilter::Property::Type type)
{
Dali::Toolkit::TextField handle(GetOwner());
mInputFilteredSignal.Emit(handle, type);
}
+void TextField::EmitSelectionChangedSignal()
+{
+ Dali::Toolkit::TextField handle(GetOwner());
+ mSelectionChangedSignal.Emit(handle, mOldSelectionStart, mOldSelectionEnd);
+ mSelectionChanged = false;
+}
+
+void TextField::SelectionChanged(uint32_t oldStart, uint32_t oldEnd, uint32_t newStart, uint32_t newEnd)
+{
+ if(((oldStart != newStart) || (oldEnd != newEnd)) && !mSelectionChanged)
+ {
+ mSelectionChanged = true;
+ mOldSelectionStart = oldStart;
+ mOldSelectionEnd = oldEnd;
+
+ if(mOldSelectionStart > mOldSelectionEnd)
+ {
+ //swap
+ uint32_t temp = mOldSelectionStart;
+ mOldSelectionStart = mOldSelectionEnd;
+ mOldSelectionEnd = temp;
+ }
+ }
+}
+
void TextField::AddDecoration(Actor& actor, bool needsClipping)
{
if(actor)
return false;
}
+void TextField::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type)
+{
+ mController->ChangedLayoutDirection();
+}
+
void TextField::OnIdleSignal()
{
// Emits the change of input style signals.
mRenderingBackend(DEFAULT_RENDERING_BACKEND),
mExceedPolicy(Dali::Toolkit::TextField::EXCEED_POLICY_CLIP),
mHasBeenStaged(false),
- mTextChanged(false)
+ mTextChanged(false),
+ mCursorPositionChanged(false),
+ mSelectionChanged(false)
{
}
Dali::Accessibility::Range TextField::AccessibleImpl::GetTextAtOffset(
size_t offset, Dali::Accessibility::TextBoundary boundary)
{
- auto self = Toolkit::TextField::DownCast(Self());
- auto text = self.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>();
auto textSize = text.size();
auto range = Dali::Accessibility::Range{};
case Dali::Accessibility::TextBoundary::LINE:
{
auto textString = text.c_str();
- auto breaks = std::vector<char>(textSize, 0);
+ auto breaks = std::vector<char>(textSize, 0);
if(boundary == Dali::Accessibility::TextBoundary::WORD)
{
return {};
}
- auto self = Toolkit::TextField::DownCast(Self());
- auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
+ auto self = Toolkit::TextField::DownCast(Self());
+ auto controller = Dali::Toolkit::GetImpl(self).GetTextController();
std::string value{};
controller->RetrieveSelection(value);
auto indices = controller->GetSelectionIndexes();
bool TextField::AccessibleImpl::InsertText(size_t startPosition, std::string text)
{
- auto self = Toolkit::TextField::DownCast(Self());
+ auto self = Toolkit::TextField::DownCast(Self());
auto insertedText = self.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
insertedText.insert(startPosition, text);