/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
#include <dali/public-api/adaptor-framework/key.h>
#include <dali/public-api/common/stage.h>
#include <dali/public-api/images/resource-image.h>
-#include <dali/devel-api/adaptor-framework/virtual-keyboard.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/devel-api/actors/actor-devel.h>
#include <dali/public-api/object/type-registry-helper.h>
#include <dali/integration-api/adaptors/adaptor.h>
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/text/rendering-backend.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.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/devel-api/controls/text-controls/text-field-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
#include <dali-toolkit/internal/text/rendering/text-backend.h>
#include <dali-toolkit/internal/text/text-effects-style.h>
#include <dali-toolkit/internal/text/text-font-style.h>
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputEmboss", MAP, INPUT_EMBOSS )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "outline", MAP, OUTLINE )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputOutline", MAP, INPUT_OUTLINE )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "hiddenInputSettings", MAP, HIDDEN_INPUT_SETTINGS )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "pixelSize", FLOAT, PIXEL_SIZE )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "enableSelection", BOOLEAN, ENABLE_SELECTION )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholder", MAP, PLACEHOLDER )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "ellipsis", BOOLEAN, ELLIPSIS )
DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "maxLengthReached", SIGNAL_MAX_LENGTH_REACHED )
const float pointSize = value.Get< float >();
DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p POINT_SIZE %f\n", impl.mController.Get(), pointSize );
- if( !Equals( impl.mController->GetDefaultPointSize(), pointSize ) )
+ if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
{
- impl.mController->SetDefaultPointSize( pointSize );
+ impl.mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
}
}
break;
}
case Toolkit::TextField::Property::EXCEED_POLICY:
{
- // TODO
+ impl.mExceedPolicy = value.Get<int>();
+
+ if( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == impl.mExceedPolicy )
+ {
+ impl.EnableClipping();
+ }
+ else
+ {
+ UnparentAndReset( impl.mStencil );
+ }
+ impl.RequestTextRelayout();
break;
}
case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
}
case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
{
- const Property::Map map = value.Get<Property::Map>();
- VirtualKeyboard::ApplySettings( map );
+ const Property::Map* map = value.GetMap();
+ if (map)
+ {
+ impl.mInputMethodOptions.ApplyProperty( *map );
+ }
+ impl.mController->SetInputModePassword( impl.mInputMethodOptions.IsPassword() );
+
+ Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
+ if (control == textField)
+ {
+ impl.mImfManager.ApplyOptions( impl.mInputMethodOptions );
+ }
break;
}
case Toolkit::TextField::Property::INPUT_COLOR:
}
break;
}
+ case Toolkit::DevelTextField::Property::HIDDEN_INPUT_SETTINGS:
+ {
+ const Property::Map* map = value.GetMap();
+ if (map)
+ {
+ impl.mController->SetHiddenInputOption(*map);
+ }
+ break;
+ }
+ case Toolkit::DevelTextField::Property::PIXEL_SIZE:
+ {
+ if( impl.mController )
+ {
+ const float pixelSize = value.Get< float >();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize );
+
+ if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
+ {
+ impl.mController->SetDefaultFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
+ }
+ }
+ break;
+ }
+ case Toolkit::DevelTextField::Property::ENABLE_SELECTION:
+ {
+ if( impl.mController )
+ {
+ const bool enableSelection = value.Get< bool >();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ENABLE_SELECTION %d\n", impl.mController.Get(), enableSelection );
+ impl.mController->SetSelectionEnabled( enableSelection );
+ }
+ break;
+ }
+ case Toolkit::DevelTextField::Property::PLACEHOLDER:
+ {
+ const Property::Map* map = value.GetMap();
+ if( map )
+ {
+ impl.mController->SetPlaceholderProperty( *map );
+ }
+ break;
+ }
+ case Toolkit::DevelTextField::Property::ELLIPSIS:
+ {
+ if( impl.mController )
+ {
+ const bool ellipsis = value.Get<bool>();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis );
+
+ impl.mController->SetTextElideEnabled( ellipsis );
+ }
+ break;
+ }
} // switch
} // textfield
}
{
if( impl.mController )
{
- value = impl.mController->GetDefaultPointSize();
+ value = impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE );
}
break;
}
}
case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
{
- if( impl.mController )
+ if( impl.mController )
{
const char* name = Scripting::GetEnumerationName< Toolkit::Text::Layout::VerticalAlignment >( impl.mController->GetVerticalAlignment(),
VERTICAL_ALIGNMENT_STRING_TABLE,
}
case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
{
+ Property::Map map;
+ impl.mInputMethodOptions.RetrieveProperty( map );
+ value = map;
break;
}
case Toolkit::TextField::Property::INPUT_COLOR:
GetOutlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
break;
}
+ case Toolkit::DevelTextField::Property::HIDDEN_INPUT_SETTINGS:
+ {
+ Property::Map map;
+ impl.mController->GetHiddenInputOption(map);
+ value = map;
+ break;
+ }
+ case Toolkit::DevelTextField::Property::PIXEL_SIZE:
+ {
+ if( impl.mController )
+ {
+ value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE );
+ }
+ break;
+ }
+ case Toolkit::DevelTextField::Property::ENABLE_SELECTION:
+ {
+ if( impl.mController )
+ {
+ value = impl.mController->IsSelectionEnabled();
+ }
+ break;
+ }
+ case Toolkit::DevelTextField::Property::PLACEHOLDER:
+ {
+ Property::Map map;
+ impl.mController->GetPlaceholderProperty( map );
+ value = map;
+ break;
+ }
+ case Toolkit::DevelTextField::Property::ELLIPSIS:
+ {
+ if( impl.mController )
+ {
+ value = impl.mController->IsTextElideEnabled();
+ }
+ break;
+ }
} //switch
}
// Disable the smooth handle panning.
mController->SetSmoothHandlePanEnabled( false );
+ mController->SetNoTextDoubleTapAction( Controller::NoTextTap::HIGHLIGHT );
+ mController->SetNoTextLongPressAction( Controller::NoTextTap::HIGHLIGHT );
+
// Forward input events to controller
EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan | Gesture::LongPress ) );
GetTapGestureDetector().SetMaximumTapsRequired( 2 );
+ mImfManager = ImfManager::Get();
+
self.TouchSignal().Connect( this, &TextField::OnTouched );
// Set BoundingBox to stage size if not already set.
self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
self.OnStageSignal().Connect( this, &TextField::OnStageConnect );
+
+ if( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy )
+ {
+ EnableClipping();
+ }
}
void TextField::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
// Property system did not set the font so should update it.
mController->UpdateAfterFontChange( newFont );
+ RelayoutRequest();
break;
}
case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
{
GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+ RelayoutRequest();
break;
}
case StyleChange::THEME_CHANGE:
{
- GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+ // Nothing to do, let control base class handle this
break;
}
}
+
+ // Up call to Control
+ Control::OnStyleChange( styleManager, change );
}
Vector3 TextField::GetNaturalSize()
float TextField::GetHeightForWidth( float width )
{
- return mController->GetHeightForWidth( width );
+ Padding padding;
+ Self().GetPadding( padding );
+ return mController->GetHeightForWidth( width ) + padding.top + padding.bottom;
}
void TextField::OnRelayout( const Vector2& size, RelayoutContainer& container )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField OnRelayout\n");
- const Text::Controller::UpdateTextType updateTextType = mController->Relayout( size );
+ Actor self = Self();
+ Padding padding;
+
+ self.GetPadding( padding );
+ Vector2 contentSize( size.x - ( padding.left + padding.right ), size.y - ( padding.top + padding.bottom ) );
+
+ if( mStencil )
+ {
+ mStencil.SetPosition( padding.left , padding.top );
+ }
+ if( mActiveLayer )
+ {
+ mActiveLayer.SetPosition( padding.left , padding.top );
+ }
+
+ const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize );
if( ( Text::Controller::NONE_UPDATED != updateTextType ) ||
!mRenderer )
mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
}
- EnableClipping( size );
RenderText( updateTextType );
+
}
// The text-field emits signals when the input style changes. These changes of style are
void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
{
- Actor self = Self();
Actor renderableActor;
if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) )
{
if( mRenderer )
{
- renderableActor = mRenderer->Render( mController->GetView(), DepthIndex::TEXT );
+ Dali::Toolkit::TextField handle = Dali::Toolkit::TextField( GetOwner() );
+
+ renderableActor = mRenderer->Render( mController->GetView(),
+ handle,
+ Property::INVALID_INDEX, // Animatable property not supported
+ mAlignmentOffset,
+ DepthIndex::CONTENT );
}
if( renderableActor != mRenderableActor )
{
const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
- mRenderableActor.SetPosition( scrollOffset.x, scrollOffset.y );
-
- Actor clipRootActor;
- if( mClipper )
+ if( mStencil )
{
- clipRootActor = mClipper->GetRootActor();
+ mRenderableActor.SetPosition( scrollOffset.x + mAlignmentOffset, scrollOffset.y );
}
+ else
+ {
+ Padding padding;
+ Self().GetPadding( padding );
+ mRenderableActor.SetPosition( scrollOffset.x + mAlignmentOffset + padding.left, scrollOffset.y + padding.top );
+ }
+
+
+ // Make sure the actors are parented correctly with/without clipping
+ Actor self = mStencil ? mStencil : Self();
for( std::vector<Actor>::const_iterator it = mClippingDecorationActors.begin(),
endIt = mClippingDecorationActors.end();
it != endIt;
++it )
{
- Actor actor = *it;
-
- if( clipRootActor )
- {
- clipRootActor.Add( actor );
- }
- else
- {
- self.Add( actor );
- }
+ self.Add( *it );
+ DevelActor::LowerToBottom(*it);
}
mClippingDecorationActors.clear();
- // Make sure the actor is parented correctly with/without clipping
- if( clipRootActor )
- {
- clipRootActor.Add( mRenderableActor );
- }
- else
- {
- self.Add( mRenderableActor );
- }
+ self.Add( mRenderableActor );
}
}
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyInputFocusGained %p\n", mController.Get() );
- VirtualKeyboard::StatusChangedSignal().Connect( this, &TextField::KeyboardStatusChanged );
+ mImfManager.ApplyOptions( mInputMethodOptions );
- ImfManager imfManager = ImfManager::Get();
+ mImfManager.StatusChangedSignal().Connect( this, &TextField::KeyboardStatusChanged );
- if ( imfManager )
- {
- imfManager.EventReceivedSignal().Connect( this, &TextField::OnImfEvent );
+ mImfManager.EventReceivedSignal().Connect( this, &TextField::OnImfEvent );
- // Notify that the text editing start.
- imfManager.Activate();
+ // Notify that the text editing start.
+ mImfManager.Activate();
- // When window gain lost focus, the imf manager is deactivated. Thus when window gain focus again, the imf manager must be activated.
- imfManager.SetRestoreAfterFocusLost( true );
- }
+ // When window gain lost focus, the imf manager is deactivated. Thus when window gain focus again, the imf manager must be activated.
+ mImfManager.SetRestoreAfterFocusLost( true );
ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField:OnKeyInputFocusLost %p\n", mController.Get() );
- VirtualKeyboard::StatusChangedSignal().Disconnect( this, &TextField::KeyboardStatusChanged );
+ mImfManager.StatusChangedSignal().Disconnect( this, &TextField::KeyboardStatusChanged );
+ // The text editing is finished. Therefore the imf manager don't have restore activation.
+ mImfManager.SetRestoreAfterFocusLost( false );
- ImfManager imfManager = ImfManager::Get();
- if ( imfManager )
- {
- // The text editing is finished. Therefore the imf manager don't have restore activation.
- imfManager.SetRestoreAfterFocusLost( false );
-
- // Notify that the text editing finish.
- imfManager.Deactivate();
+ // Notify that the text editing finish.
+ mImfManager.Deactivate();
- imfManager.EventReceivedSignal().Disconnect( this, &TextField::OnImfEvent );
- }
+ mImfManager.EventReceivedSignal().Disconnect( this, &TextField::OnImfEvent );
ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnTap %p\n", mController.Get() );
- // Show the keyboard if it was hidden.
- if (!VirtualKeyboard::IsVisible())
- {
- VirtualKeyboard::Show();
- }
+ mImfManager.Activate();
// Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures
- mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x, gesture.localPoint.y );
+ Padding padding;
+ Self().GetPadding( padding );
+ mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x - padding.left, gesture.localPoint.y - padding.top );
SetKeyInputFocus();
}
void TextField::OnLongPress( const LongPressGesture& gesture )
{
- // Show the keyboard if it was hidden.
- if (!VirtualKeyboard::IsVisible())
- {
- VirtualKeyboard::Show();
- }
+ mImfManager.Activate();
- mController->LongPressEvent( gesture.state, gesture.localPoint.x, gesture.localPoint.y );
+ Padding padding;
+ Self().GetPadding( padding );
+ mController->LongPressEvent( gesture.state, gesture.localPoint.x - padding.left, gesture.localPoint.y - padding.top );
SetKeyInputFocus();
}
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyEvent %p keyCode %d\n", mController.Get(), event.keyCode );
- if( Dali::DALI_KEY_ESCAPE == event.keyCode ||
- "Return" == event.keyPressedName ) // Make a Dali key code for this
+ if( Dali::DALI_KEY_ESCAPE == event.keyCode && mController->ShouldClearFocusOnEscape() )
{
- ClearKeyInputFocus();
+ // Make sure ClearKeyInputFocus when only key is up
+ if( event.state == KeyEvent::Up )
+ {
+ ClearKeyInputFocus();
+ }
+
return true;
}
}
else
{
+ actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+ actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
Self().Add( actor );
+ mActiveLayer = actor;
}
}
}
}
}
-void TextField::EnableClipping( const Vector2& size )
+void TextField::EnableClipping()
{
- if( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy )
+ if( !mStencil )
{
- // Not worth to created clip actor if width or height is equal to zero.
- if( size.width > Math::MACHINE_EPSILON_1000 && size.height > Math::MACHINE_EPSILON_1000 )
- {
- if( !mClipper )
- {
- Actor self = Self();
+ // Creates an extra control to be used as stencil buffer.
+ mStencil = Control::New();
+ mStencil.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+ mStencil.SetParentOrigin( ParentOrigin::TOP_LEFT );
- mClipper = Clipper::New( size );
- self.Add( mClipper->GetRootActor() );
- self.Add( mClipper->GetImageView() );
- }
- else if ( mClipper )
- {
- mClipper->Refresh( size );
- }
- }
- }
- else
- {
- // Note - this will automatically remove the root actor & the image view
- mClipper.Reset();
+ // Creates a background visual. Even if the color is transparent it updates the stencil.
+ mStencil.SetProperty( Toolkit::Control::Property::BACKGROUND,
+ Property::Map().Add( Toolkit::Visual::Property::TYPE, DevelVisual::COLOR ).
+ Add( ColorVisual::Property::MIX_COLOR, Color::TRANSPARENT ) );
+
+ // Enable the clipping property.
+ mStencil.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+ mStencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+ Self().Add( mStencil );
}
}
void TextField::OnStageConnection( int depth )
{
- // Call the Control::OnStageConnection() to set the depth of the background.
- Control::OnStageConnection( depth );
-
// Sets the depth to the visuals inside the text's decorator.
mDecorator->SetTextDepth( depth );
// The depth of the text renderer is set in the RenderText() called from OnRelayout().
+
+ // Call the Control::OnStageConnection() to set the depth of the background.
+ Control::OnStageConnection( depth );
}
bool TextField::OnTouched( Actor actor, const TouchData& touch )
TextField::TextField()
: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
mIdleCallback( NULL ),
+ mAlignmentOffset( 0.f ),
mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
mExceedPolicy( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP ),
mHasBeenStaged( false )
TextField::~TextField()
{
- mClipper.Reset();
+ UnparentAndReset( mStencil );
if( ( NULL != mIdleCallback ) && Adaptor::IsAvailable() )
{