#include <dali-toolkit/devel-api/text/rendering-backend.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
#include <dali-toolkit/public-api/visuals/visual-properties.h>
#include <dali-toolkit/internal/text/text-enumerations-impl.h>
#include <dali-toolkit/internal/text/rendering/text-backend.h>
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "maxLength", INTEGER, MAX_LENGTH )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectedTextStart", INTEGER, SELECTED_TEXT_START )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectedTextEnd", INTEGER, SELECTED_TEXT_END )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "horizontalScrollPosition", FLOAT, HORIZONTAL_SCROLL_POSITION )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "verticalScrollPosition", INTEGER, VERTICAL_SCROLL_POSITION )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableEditing", BOOLEAN, ENABLE_EDITING )
+DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextEditor, "selectedText", STRING, SELECTED_TEXT )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "fontSizeScale", FLOAT, FONT_SIZE_SCALE )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "primaryCursorPosition", INTEGER, PRIMARY_CURSOR_POSITION )
DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED )
}
case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START:
{
- if( impl.mController )
+ uint32_t start = static_cast<uint32_t>(value.Get< int >());
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start );
+ impl.SetTextSelectionRange( &start, nullptr );
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_END:
+ {
+ uint32_t end = static_cast<uint32_t>(value.Get< int >());
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end );
+ impl.SetTextSelectionRange( nullptr, &end );
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::ENABLE_EDITING:
+ {
+ const bool editable = value.Get< bool >();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p ENABLE_EDITING %d\n", impl.mController.Get(), editable );
+ impl.SetEditable( editable );
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::HORIZONTAL_SCROLL_POSITION:
+ {
+ float horizontalScroll = value.Get< float >();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p HORIZONTAL_SCROLL_POSITION %d\n", impl.mController.Get(), horizontalScroll );
+ if (horizontalScroll >= 0.0f)
{
- uint32_t start = static_cast<uint32_t>(value.Get< int >());
- DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start );
- impl.SetTextSelectionRange( &start, nullptr );
+ impl.ScrollBy( Vector2(horizontalScroll - impl.GetHorizontalScrollPosition(), 0 ));
}
break;
}
- case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_END:
+ case Toolkit::DevelTextEditor::Property::VERTICAL_SCROLL_POSITION:
+ {
+ float verticalScroll = value.Get< float >();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p VERTICAL_SCROLL_POSITION %d\n", impl.mController.Get(), verticalScroll );
+ if (verticalScroll >= 0.0f)
+ {
+ impl.ScrollBy( Vector2(0, verticalScroll - impl.GetVerticalScrollPosition() ));
+ }
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::FONT_SIZE_SCALE:
+ {
+ const float scale = value.Get< float >();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p FONT_SIZE_SCALE %f\n", impl.mController.Get(), scale );
+
+ if( !Equals( impl.mController->GetFontSizeScale(), scale ) )
+ {
+ impl.mController->SetFontSizeScale( scale );
+ }
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::PRIMARY_CURSOR_POSITION:
{
- if( impl.mController )
+ uint32_t position = static_cast<uint32_t>(value.Get< int >());
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p PRIMARY_CURSOR_POSITION %d\n", impl.mController.Get(), position );
+ if (impl.mController->SetPrimaryCursorPosition( position ))
{
- uint32_t end = static_cast<uint32_t>(value.Get< int >());
- DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end );
- impl.SetTextSelectionRange( nullptr, &end );
+ impl.SetKeyInputFocus();
}
break;
}
value = impl.mController->GetMaximumNumberOfCharacters();
break;
}
+ case Toolkit::DevelTextEditor::Property::SELECTED_TEXT:
+ {
+ value = impl.mController->GetSelectedText( );
+ break;
+ }
case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START:
{
Uint32Pair range = impl.GetTextSelectionRange();
value = static_cast<int>(range.second);
break;
}
+ case Toolkit::DevelTextEditor::Property::ENABLE_EDITING:
+ {
+ value = impl.IsEditable();
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::HORIZONTAL_SCROLL_POSITION:
+ {
+ value = impl.GetHorizontalScrollPosition();
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::VERTICAL_SCROLL_POSITION:
+ {
+ value = impl.GetVerticalScrollPosition();
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::FONT_SIZE_SCALE:
+ {
+ value = impl.mController->GetFontSizeScale();
+ break;
+ }
+ case Toolkit::DevelTextEditor::Property::PRIMARY_CURSOR_POSITION:
+ {
+ value = static_cast<int>(impl.mController->GetPrimaryCursorPosition());
+ break;
+ }
} //switch
}
return value;
}
+void TextEditor::SelectWholeText()
+{
+ if( mController && mController->IsShowingRealText() )
+ {
+ mController->SelectWholeText();
+ SetKeyInputFocus();
+ }
+}
+
+void TextEditor::SelectNone()
+{
+ if( mController && mController->IsShowingRealText() )
+ {
+ mController->SelectNone();
+ }
+}
+
+void TextEditor::ScrollBy(Vector2 scroll)
+{
+ if( mController && mController->IsShowingRealText() )
+ {
+ mController->ScrollBy(scroll);
+ }
+}
+
+float TextEditor::GetHorizontalScrollPosition()
+{
+ if( mController && mController->IsShowingRealText() )
+ {
+ return mController->GetHorizontalScrollPosition();
+ }
+ return 0;
+}
+
+float TextEditor::GetVerticalScrollPosition()
+{
+ if( mController && mController->IsShowingRealText() )
+ {
+ return mController->GetVerticalScrollPosition();
+ }
+ return 0;
+}
+
+string TextEditor::GetSelectedText() const
+{
+ string selectedText = "";
+ if( mController && mController->IsShowingRealText() )
+ {
+ selectedText = mController->GetSelectedText( );
+ }
+ return selectedText;
+}
+
InputMethodContext TextEditor::GetInputMethodContext()
{
return mInputMethodContext;
return mMaxLengthReachedSignal;
}
+Text::ControllerPtr TextEditor::getController()
+{
+ return mController;
+}
+
bool TextEditor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
{
Dali::BaseHandle handle( object );
self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
self.OnSceneSignal().Connect( this, &TextEditor::OnSceneConnect );
+ //Enable highightability
+ self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true );
+
DevelControl::SetInputMethodContext( *this, mInputMethodContext );
// Creates an extra control to be used as stencil buffer.
mStencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
self.Add( mStencil );
+
+ DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) {
+ return std::unique_ptr< Dali::Accessibility::Accessible >(
+ new AccessibleImpl( actor, Dali::Accessibility::Role::ENTRY ) );
+ } );
}
void TextEditor::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
void TextEditor::OnKeyInputFocusGained()
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnKeyInputFocusGained %p\n", mController.Get() );
- if ( mInputMethodContext )
+ if ( mInputMethodContext && IsEditable() )
{
mInputMethodContext.StatusChangedSignal().Connect( this, &TextEditor::KeyboardStatusChanged );
EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last.
}
+bool TextEditor::OnAccessibilityActivated()
+{
+ SetKeyInputFocus();
+ return true;
+}
+
void TextEditor::OnTap( const TapGesture& gesture )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnTap %p\n", mController.Get() );
- if ( mInputMethodContext )
+ if ( mInputMethodContext && IsEditable() )
{
mInputMethodContext.Activate();
}
void TextEditor::OnLongPress( const LongPressGesture& gesture )
{
- if ( mInputMethodContext )
+ if ( mInputMethodContext && IsEditable() )
{
mInputMethodContext.Activate();
}
RelayoutRequest();
}
+void TextEditor::TextInserted( unsigned int position, unsigned int length, const std::string &content )
+{
+ if( Accessibility::IsUp() )
+ {
+ Control::Impl::GetAccessibilityObject( Self() )->EmitTextInserted( position, length, content );
+ }
+}
+
+void TextEditor::TextDeleted( unsigned int position, unsigned int length, const std::string &content )
+{
+ if( Accessibility::IsUp() )
+ {
+ Control::Impl::GetAccessibilityObject( Self() )->EmitTextDeleted( position, length, content );
+ }
+}
+
+void TextEditor::CaretMoved( unsigned int position )
+{
+ if( Accessibility::IsUp() )
+ {
+ Control::Impl::GetAccessibilityObject( Self() )->EmitTextCaretMoved( position );
+ }
+}
+
void TextEditor::TextChanged()
{
Dali::Toolkit::TextEditor handle( GetOwner() );
}
}
+bool TextEditor::IsEditable() const
+{
+ return mController->IsEditable();
+}
+
+void TextEditor::SetEditable( bool editable )
+{
+ mController->SetEditable(editable);
+ if ( mInputMethodContext && !editable )
+ {
+ mInputMethodContext.Deactivate();
+ }
+}
+
TextEditor::TextEditor()
: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
mAnimationPeriod( 0.0f, 0.0f ),
}
}
+std::string TextEditor::AccessibleImpl::GetName()
+{
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ return slf.GetProperty( Toolkit::TextEditor::Property::TEXT )
+ .Get< std::string >();
+}
+
+std::string TextEditor::AccessibleImpl::GetText( size_t startOffset,
+ size_t endOffset )
+{
+ if( endOffset <= startOffset )
+ return {};
+
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ auto txt =
+ slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >();
+
+ if( startOffset > txt.size() || endOffset > txt.size() )
+ return {};
+
+ return txt.substr( startOffset, endOffset - startOffset );
+}
+
+size_t TextEditor::AccessibleImpl::GetCharacterCount()
+{
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ auto txt =
+ slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >();
+
+ return txt.size();
+}
+
+size_t TextEditor::AccessibleImpl::GetCaretOffset()
+{
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ return Dali::Toolkit::GetImpl( slf ).getController()->GetCursorPosition();
+}
+
+bool TextEditor::AccessibleImpl::SetCaretOffset(size_t offset)
+{
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >();
+ if (offset > txt.size())
+ return false;
+
+ auto& slfImpl = Dali::Toolkit::GetImpl( slf );
+ slfImpl.getController()->ResetCursorPosition( offset );
+ slfImpl.RequestTextRelayout();
+ return true;
+}
+
+Dali::Accessibility::Range TextEditor::AccessibleImpl::GetTextAtOffset(
+ size_t offset, Dali::Accessibility::TextBoundary boundary )
+{
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >();
+ auto txt_size = txt.size();
+
+ auto range = Dali::Accessibility::Range{};
+
+ switch(boundary)
+ {
+ case Dali::Accessibility::TextBoundary::CHARACTER:
+ {
+ if (offset < txt_size)
+ {
+ range.content = txt[offset];
+ range.startOffset = offset;
+ range.endOffset = offset + 1;
+ }
+ }
+ 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 );
+ if(boundary == Dali::Accessibility::TextBoundary::WORD)
+ Accessibility::Accessible::FindWordSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data());
+ else
+ Accessibility::Accessible::FindLineSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data());
+ auto index = 0u;
+ auto counter = 0u;
+ while( index < txt_size && 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.startOffset = start;
+ range.endOffset = index + 1;
+ }
+ if (boundary == Dali::Accessibility::TextBoundary::LINE)
+ index++;
+ }
+ }
+ break;
+ case Dali::Accessibility::TextBoundary::SENTENCE:
+ {
+ /* not supported by efl */
+ }
+ break;
+ case Dali::Accessibility::TextBoundary::PARAGRAPH:
+ {
+ /* Paragraph is not supported by libunibreak library */
+ }
+ break;
+ default:
+ break;
+ }
+
+ return range;
+}
+
+Dali::Accessibility::Range
+TextEditor::AccessibleImpl::GetSelection( size_t selectionNum )
+{
+ // Since DALi supports only one selection indexes higher than 0 are ignored
+ if( selectionNum > 0 )
+ return {};
+
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ auto ctrl = Dali::Toolkit::GetImpl( slf ).getController();
+ std::string ret;
+ ctrl->RetrieveSelection( ret );
+ auto r = ctrl->GetSelectionIndexes();
+
+ return { static_cast<size_t>(r.first), static_cast<size_t>(r.second), ret };
+}
+
+bool TextEditor::AccessibleImpl::RemoveSelection( size_t selectionNum )
+{
+ // Since DALi supports only one selection indexes higher than 0 are ignored
+ if( selectionNum > 0 )
+ return false;
+
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( 0, 0 );
+ return true;
+}
+
+bool TextEditor::AccessibleImpl::SetSelection( size_t selectionNum,
+ size_t startOffset,
+ size_t endOffset )
+{
+ // Since DALi supports only one selection indexes higher than 0 are ignored
+ if( selectionNum > 0 )
+ return false;
+
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( startOffset,
+ endOffset );
+ return true;
+}
+
+bool TextEditor::AccessibleImpl::CopyText( size_t startPosition,
+ size_t endPosition )
+{
+ if( endPosition <= startPosition )
+ return false;
+
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get<std::string>();
+ Dali::Toolkit::GetImpl( slf ).getController()->CopyStringToClipboard( txt.substr(startPosition, endPosition - startPosition) );
+
+ return true;
+}
+
+bool TextEditor::AccessibleImpl::CutText( size_t startPosition,
+ size_t endPosition )
+{
+ if( endPosition <= startPosition )
+ return false;
+
+ auto slf = Toolkit::TextEditor::DownCast( self );
+ auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get<std::string>();
+ Dali::Toolkit::GetImpl( slf ).getController()->CopyStringToClipboard( txt.substr(startPosition, endPosition - startPosition) );
+
+ slf.SetProperty( Toolkit::TextEditor::Property::TEXT,
+ txt.substr( 0, startPosition ) + txt.substr( endPosition - startPosition, txt.size()));
+
+ return true;
+}
+
+Dali::Accessibility::States TextEditor::AccessibleImpl::CalculateStates()
+{
+ using namespace Dali::Accessibility;
+
+ auto states = Control::Impl::AccessibleImpl::CalculateStates();
+ states[State::EDITABLE] = true;
+ states[State::FOCUSABLE] = true;
+
+ Toolkit::Control focusControl = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
+ if (self == focusControl)
+ {
+ states[State::FOCUSED] = true;
+ }
+
+ return states;
+}
+
} // namespace Internal
} // namespace Toolkit