DALI_TEST_EQUALS( backgroundColorIndicesBuffer[7], 2u, TEST_LOCATION);
END_TEST;
+}
+
+int UtcDaliTextEditorTextWithSpan(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliTextEditorTextWithSpan\n");
+
+ TextEditor editor = TextEditor::New();
+ DALI_TEST_CHECK( editor );
+
+ editor.SetProperty( TextEditor ::Property::ENABLE_MARKUP, true );
+ editor.SetProperty( TextEditor::Property::TEXT, "Hello Span" );
+ application.GetScene().Add( editor );
+
+ application.SendNotification();
+ application.Render();
+
+ Vector3 originalSize = editor.GetNaturalSize();
+ editor.SetProperty( TextEditor::Property::TEXT, "H<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red'>ello</span> Span" );
+
+ application.SendNotification();
+ application.Render();
+
+ Vector3 spanSize = editor.GetNaturalSize();
+
+ DALI_TEST_GREATER(spanSize.width, originalSize.width, TEST_LOCATION);
+
+ Toolkit::Internal::TextEditor& editorImpl = GetImpl( editor );
+ const ColorIndex* const colorIndicesBuffer1 = editorImpl.getController()->GetTextModel()->GetColorIndices();
+
+ DALI_TEST_CHECK( colorIndicesBuffer1 );
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[0], 0u, TEST_LOCATION);
+
+ //span color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[1], 1u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[6], 0u, TEST_LOCATION);
+
+
+ editor.SetProperty( TextEditor::Property::TEXT, "<span font-size='45'>H</span>ello <span text-color='red'>S</span>pan" );
+
+ application.SendNotification();
+ application.Render();
+
+ const ColorIndex* const colorIndicesBuffer2 = editorImpl.getController()->GetTextModel()->GetColorIndices();
+
+ DALI_TEST_CHECK( colorIndicesBuffer2 );
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[0], 0u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[1], 0u, TEST_LOCATION);
+
+ //span color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[6], 1u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[7], 0u, TEST_LOCATION);
+
+ END_TEST;
}
\ No newline at end of file
DALI_TEST_EQUALS( backgroundColorIndicesBuffer[7], 2u, TEST_LOCATION);
END_TEST;
+}
+
+int UtcDaliTextFieldTextWithSpan(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliTextFieldTextWithSpan\n");
+
+ TextField field = TextField::New();
+ DALI_TEST_CHECK( field );
+
+ field.SetProperty( TextField ::Property::ENABLE_MARKUP, true );
+ field.SetProperty( TextField::Property::TEXT, "Hello Span" );
+ application.GetScene().Add( field );
+
+ application.SendNotification();
+ application.Render();
+
+ Vector3 originalSize = field.GetNaturalSize();
+ field.SetProperty( TextField::Property::TEXT, "H<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red'>ello</span> Span" );
+
+ application.SendNotification();
+ application.Render();
+
+ Vector3 spanSize = field.GetNaturalSize();
+
+ DALI_TEST_GREATER(spanSize.width, originalSize.width, TEST_LOCATION);
+
+ Toolkit::Internal::TextField& fieldImpl = GetImpl( field );
+ const ColorIndex* const colorIndicesBuffer1 = fieldImpl.getController()->GetTextModel()->GetColorIndices();
+
+ DALI_TEST_CHECK( colorIndicesBuffer1 );
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[0], 0u, TEST_LOCATION);
+
+ //span color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[1], 1u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[6], 0u, TEST_LOCATION);
+
+
+ field.SetProperty( TextField::Property::TEXT, "<span font-size='45'>H</span>ello <span text-color='red'>S</span>pan" );
+
+ application.SendNotification();
+ application.Render();
+
+ const ColorIndex* const colorIndicesBuffer2 = fieldImpl.getController()->GetTextModel()->GetColorIndices();
+
+ DALI_TEST_CHECK( colorIndicesBuffer2 );
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[0], 0u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[1], 0u, TEST_LOCATION);
+
+ //span color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[6], 1u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[7], 0u, TEST_LOCATION);
+
+ END_TEST;
}
\ No newline at end of file
DALI_TEST_EQUALS( backgroundColorIndicesBuffer[7], 2u, TEST_LOCATION);
END_TEST;
+}
+
+int UtcDaliTextLabelTextWithSpan(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliTextLabelTextWithSpan\n");
+
+ TextLabel label = TextLabel::New();
+ DALI_TEST_CHECK( label );
+
+ label.SetProperty( TextLabel ::Property::ENABLE_MARKUP, true );
+ label.SetProperty( TextLabel::Property::TEXT, "Hello Span" );
+ application.GetScene().Add( label );
+
+ application.SendNotification();
+ application.Render();
+
+ Vector3 originalSize = label.GetNaturalSize();
+ label.SetProperty( TextLabel::Property::TEXT, "H<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red'>ello</span> Span" );
+
+ application.SendNotification();
+ application.Render();
+
+ Vector3 spanSize = label.GetNaturalSize();
+
+ DALI_TEST_GREATER(spanSize.width, originalSize.width, TEST_LOCATION);
+
+ Toolkit::Internal::TextLabel& labelImpl = GetImpl( label );
+ const ColorIndex* const colorIndicesBuffer1 = labelImpl.getController()->GetTextModel()->GetColorIndices();
+
+ DALI_TEST_CHECK( colorIndicesBuffer1 );
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[0], 0u, TEST_LOCATION);
+
+ //span color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[1], 1u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer1[6], 0u, TEST_LOCATION);
+
+
+ label.SetProperty( TextLabel::Property::TEXT, "<span font-size='45'>H</span>ello <span text-color='red'>S</span>pan" );
+
+ application.SendNotification();
+ application.Render();
+
+ const ColorIndex* const colorIndicesBuffer2 = labelImpl.getController()->GetTextModel()->GetColorIndices();
+
+ DALI_TEST_CHECK( colorIndicesBuffer2 );
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[0], 0u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[1], 0u, TEST_LOCATION);
+
+ //span color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[6], 1u, TEST_LOCATION);
+
+ //default color
+ DALI_TEST_EQUALS( colorIndicesBuffer2[7], 0u, TEST_LOCATION);
+
+ END_TEST;
}
\ No newline at end of file
mDelayTime(0),
mDroppedFrames(0),
mFrameRate( 60.0f ),
+ mTestFrameDrop(false),
mNeedDroppedFrames(false),
mEventThreadCallback( new EventThreadCallback( MakeCallback( this, &VectorAnimationRenderer::OnTriggered ) ) )
{
bool Load(const std::string& url)
{
mUrl = url;
- if(mUrl == "invalid.json" || mUrl == "invalid.riv")
+ if(mUrl == "invalid.json")
{
return false;
}
{
// Change total frame number for test
mTotalFrameNumber = 200;
+ mTestFrameDrop = true;
}
return true;
}
bool Render( uint32_t frameNumber )
{
- if(mDelayTime != 0)
+ if(mTestFrameDrop)
{
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int32_t>(mDelayTime)));
- mDelayTime = 0;
+ mTestFrameDrop = false;
mNeedDroppedFrames = true;
}
else if(mNeedDroppedFrames)
uint32_t mDelayTime;
uint32_t mDroppedFrames;
float mFrameRate;
+ bool mTestFrameDrop;
bool mNeedDroppedFrames;
Dali::VectorAnimationRenderer::UploadCompletedSignalType mUploadCompletedSignal;
std::unique_ptr< EventThreadCallback > mEventThreadCallback;
const char* TEST_VECTOR_IMAGE_FILE_NAME_FRAME_DROP = "framedrop.json";
const char* TEST_VECTOR_IMAGE_INVALID_FILE_NAME = "invalid.json";
-const char* TEST_VECTOR_IMAGE_RIVE_FILE_NAME = TEST_RESOURCE_DIR "/shape.riv";
-const char* TEST_VECTOR_IMAGE_INVALID_RIVE_FILE_NAME = "invalid.riv";
-
bool gAnimationFinishedSignalFired = false;
void VisualEventSignal( Control control, Dali::Property::Index visualIndex, Dali::Property::Index signalId )
Property::Map attributes;
DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
+ // Make delay to drop frames
+ Test::VectorAnimationRenderer::DelayRendering(170); // longer than 16.6 * 10frames
+
application.SendNotification();
application.Render();
// Trigger count is 1 - render the first frame
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- // Make delay to drop frames
- Test::VectorAnimationRenderer::DelayRendering(170); // longer than 16.6 * 10frames
-
- // Check dropped frame
+ // Wait for calculating frame drops
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+ // Check dropped frame
uint32_t frames = Test::VectorAnimationRenderer::GetDroppedFrames();
DALI_TEST_CHECK(frames >= 9);
END_TEST;
}
-
-int UtcDaliAnimatedVectorImageVisualLoadRiveFileP(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliAnimatedVectorImageVisualLoadRiveFile: Request animated vector image visual with a rive url" );
-
- VisualFactory factory = VisualFactory::Get();
- Visual::Base visual = factory.CreateVisual( TEST_VECTOR_IMAGE_RIVE_FILE_NAME, ImageDimensions() );
- DALI_TEST_CHECK( visual );
-
- DummyControl actor = DummyControl::New( true );
- DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
- dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
- actor.SetProperty( Actor::Property::SIZE, Vector2( 200.0f, 200.0f ) );
- application.GetScene().Add( actor );
-
- application.SendNotification();
- application.Render();
-
- // renderer is added to actor
- DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
- Renderer renderer = actor.GetRendererAt( 0u );
- DALI_TEST_CHECK( renderer );
-
- // Test SetOffScene().
- actor.Unparent();
- DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
-
- END_TEST;
-}
-
-int UtcDaliAnimatedVectorImageVisualLoadRiveFileN(void)
-{
- ToolkitTestApplication application;
- tet_infoline("Request loading with invalid rive file - should draw broken image");
-
- TestGlAbstraction& gl = application.GetGlAbstraction();
- TraceCallStack& textureTrace = gl.GetTextureTrace();
- textureTrace.Enable(true);
-
- Property::Map propertyMap;
- propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
- .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_INVALID_RIVE_FILE_NAME);
-
- Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
- DALI_TEST_CHECK(visual);
-
- DummyControl actor = DummyControl::New(true);
- DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >(actor.GetImplementation());
- dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
-
- actor.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
-
- application.GetScene().Add(actor);
-
- application.SendNotification();
- application.Render();
-
- // Check resource status
- Visual::ResourceStatus status = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL);
- DALI_TEST_EQUALS(status, Visual::ResourceStatus::FAILED, TEST_LOCATION);
-
- // The broken image should be shown.
- DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
- DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
-
- END_TEST;
-}
-
-int UtcDaliAnimatedVectorImageVisualPlaybackRiveFile(void)
-{
- ToolkitTestApplication application;
-
- tet_infoline( "UtcDaliAnimatedVectorImageVisualPlaybackRiveFile" );
-
- {
- // request AnimatedVectorImageVisual for Rive with a property map
- VisualFactory factory = VisualFactory::Get();
- Visual::Base visual = factory.CreateVisual(
- Property::Map()
- .Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
- .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_RIVE_FILE_NAME ) );
-
- DummyControl dummyControl = DummyControl::New( true );
- Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummyControl.GetImplementation() );
- dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
- dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
-
- Property::Map attributes;
- tet_infoline( "Test Play action" );
- DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
-
- application.GetScene().Add( dummyControl );
- application.SendNotification();
- application.Render( 16 );
-
- Property::Map map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- Property::Value* value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
-
- tet_infoline( "Test Pause action" );
- DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, attributes );
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PAUSED );
-
- tet_infoline( "Test Play action" );
- DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
-
- tet_infoline( "Test Stop action" );
- DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
-
- tet_infoline( "Test Stop action again" );
- DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
-
- tet_infoline( "Test Play action" );
- DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
-
- tet_infoline( "Off stage" );
- dummyControl.Unparent();
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
-
- tet_infoline( "On stage again" );
- application.GetScene().Add( dummyControl );
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
-
- tet_infoline( "Test Play action" );
- DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
-
- application.SendNotification();
- application.Render(16);
-
- map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::PLAY_STATE );
- DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
-
- // Change Size
- Vector3 newSize( 100.0f, 100.0f, 0.0f );
- dummyControl.SetProperty( Actor::Property::SIZE, newSize );
-
- application.SendNotification();
- application.Render(16);
-
- // Size should be changed
- Vector3 naturalSize = dummyControl.GetNaturalSize();
- DALI_TEST_CHECK( naturalSize == newSize );
-
- dummyControl.Unparent();
- }
-
- END_TEST;
-}
const char* const PROPERTY_NAME_GRAB_HANDLE_COLOR = "grabHandleColor";
const char* const PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP = "enableGrabHandlePopup";
const char* const PROPERTY_NAME_INPUT_METHOD_SETTINGS = "inputMethodSettings";
+const char* const PROPERTY_NAME_INPUT_FILTER = "inputFilter";
const Vector4 PLACEHOLDER_TEXT_COLOR( 0.8f, 0.8f, 0.8f, 0.8f );
const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color.
static bool gAnchorClickedCallBackCalled;
static bool gAnchorClickedCallBackNotCalled;
static bool gTextChangedCallBackCalled;
+static bool gInputFilteredAcceptedCallbackCalled;
+static bool gInputFilteredRejectedCallbackCalled;
static bool gInputStyleChangedCallbackCalled;
static bool gMaxCharactersCallBackCalled;
static Dali::Toolkit::TextEditor::InputStyle::Mask gInputStyleMask;
gMaxCharactersCallBackCalled = true;
}
+static void TestInputFilteredCallback(TextEditor control, Toolkit::InputFilter::Property::Type type)
+{
+ tet_infoline(" TestInputFilteredCallback");
+
+ if(type == Toolkit::InputFilter::Property::ACCEPTED)
+ {
+ gInputFilteredAcceptedCallbackCalled = true;
+ }
+ else if(type == Toolkit::InputFilter::Property::REJECTED)
+ {
+ gInputFilteredRejectedCallbackCalled = true;
+ }
+}
+
// Generate a KeyEvent to send to Core.
Integration::KeyEvent GenerateKey( const std::string& keyName,
const std::string& logicalKey,
DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_COLOR ) == DevelTextEditor::Property::GRAB_HANDLE_COLOR );
DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP ) == DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP );
DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_METHOD_SETTINGS ) == DevelTextEditor::Property::INPUT_METHOD_SETTINGS );
+ DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_FILTER ) == DevelTextEditor::Property::INPUT_FILTER );
END_TEST;
}
DALI_TEST_CHECK( map[ "VARIATION" ].Get( variation ) );
DALI_TEST_EQUALS( inputVariation, variation, TEST_LOCATION );
+ // Check the input filter property
+ Property::Map inputFilterMapSet;
+ Property::Map inputFilterMapGet;
+ inputFilterMapSet[InputFilter::Property::ACCEPTED] = "[\\w]";
+ inputFilterMapSet[InputFilter::Property::REJECTED] = "[\\d]";
+
+ editor.SetProperty(DevelTextEditor::Property::INPUT_FILTER, inputFilterMapSet);
+
+ inputFilterMapGet = editor.GetProperty<Property::Map>(DevelTextEditor::Property::INPUT_FILTER);
+ DALI_TEST_EQUALS(inputFilterMapGet.Count(), inputFilterMapSet.Count(), TEST_LOCATION);
+
+ // Clear
+ inputFilterMapSet.Clear();
+ editor.SetProperty(DevelTextEditor::Property::INPUT_FILTER, inputFilterMapSet);
+
application.SendNotification();
application.Render();
END_TEST;
}
+int utcDaliTextEditorInputFiltered(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextEditorInputFiltered");
+ TextEditor editor = TextEditor::New();
+ DALI_TEST_CHECK(editor);
+
+ application.GetScene().Add(editor);
+
+ Property::Map inputFilter;
+
+ // Only digit is accepted.
+ inputFilter[InputFilter::Property::ACCEPTED] = "[\\d]";
+
+ // Set input filter to TextEditor.
+ editor.SetProperty(DevelTextEditor::Property::INPUT_FILTER, inputFilter);
+
+ editor.SetKeyInputFocus();
+
+ // connect to the input filtered signal.
+ ConnectionTracker* testTracker = new ConnectionTracker();
+ DevelTextEditor::InputFilteredSignal(editor).Connect(&TestInputFilteredCallback);
+ bool inputFilteredSignal = false;
+ editor.ConnectSignal(testTracker, "inputFiltered", CallbackFunctor(&inputFilteredSignal));
+
+ gInputFilteredAcceptedCallbackCalled = false;
+
+ application.ProcessEvent(GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::DOWN, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ));
+
+ DALI_TEST_CHECK(gInputFilteredAcceptedCallbackCalled);
+ DALI_TEST_CHECK(inputFilteredSignal);
+
+ // Word is rejected.
+ inputFilter[InputFilter::Property::ACCEPTED] = "";
+ inputFilter[InputFilter::Property::REJECTED] = "[\\w]";
+
+ // Set input filter to TextEditor.
+ editor.SetProperty(DevelTextEditor::Property::INPUT_FILTER, inputFilter);
+
+ editor.SetKeyInputFocus();
+
+ inputFilteredSignal = false;
+ gInputFilteredRejectedCallbackCalled = false;
+
+ application.ProcessEvent(GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::DOWN, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ DALI_TEST_CHECK(gInputFilteredAcceptedCallbackCalled);
+ DALI_TEST_CHECK(inputFilteredSignal);
+
+ END_TEST;
+}
+
int UtcDaliTextEditorSelectWholeText(void)
{
ToolkitTestApplication application;
const char* const PROPERTY_NAME_BACKGROUND = "textBackground";
const char* const PROPERTY_NAME_FONT_SIZE_SCALE = "fontSizeScale";
const char* const PROPERTY_NAME_GRAB_HANDLE_COLOR = "grabHandleColor";
+const char* const PROPERTY_NAME_INPUT_FILTER = "inputFilter";
const Vector4 PLACEHOLDER_TEXT_COLOR( 0.8f, 0.8f, 0.8f, 0.8f );
const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color.
static bool gAnchorClickedCallBackNotCalled;
static bool gTextChangedCallBackCalled;
static bool gMaxCharactersCallBackCalled;
+static bool gInputFilteredAcceptedCallbackCalled;
+static bool gInputFilteredRejectedCallbackCalled;
static bool gInputStyleChangedCallbackCalled;
static Dali::Toolkit::TextField::InputStyle::Mask gInputStyleMask;
gMaxCharactersCallBackCalled = true;
}
+static void TestInputFilteredCallback(TextField control, Toolkit::InputFilter::Property::Type type)
+{
+ tet_infoline(" TestInputFilteredCallback");
+
+ if(type == Toolkit::InputFilter::Property::ACCEPTED)
+ {
+ gInputFilteredAcceptedCallbackCalled = true;
+ }
+ else if(type == Toolkit::InputFilter::Property::REJECTED)
+ {
+ gInputFilteredRejectedCallbackCalled = true;
+ }
+}
+
static void TestInputStyleChangedCallback( TextField control, TextField::InputStyle::Mask mask )
{
tet_infoline(" TestInputStyleChangedCallback");
DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP ) == DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP );
DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_BACKGROUND ) == DevelTextField::Property::BACKGROUND );
DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_COLOR ) == DevelTextField::Property::GRAB_HANDLE_COLOR );
+ DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_FILTER ) == DevelTextField::Property::INPUT_FILTER );
END_TEST;
}
field.SetProperty( DevelTextField::Property::GRAB_HANDLE_COLOR, Color::GREEN );
DALI_TEST_EQUALS( field.GetProperty<Vector4>( DevelTextField::Property::GRAB_HANDLE_COLOR ), Color::GREEN, TEST_LOCATION );
+ // Check the input filter property
+ Property::Map inputFilterMapSet;
+ Property::Map inputFilterMapGet;
+ inputFilterMapSet[InputFilter::Property::ACCEPTED] = "[\\w]";
+ inputFilterMapSet[InputFilter::Property::REJECTED] = "[\\d]";
+
+ field.SetProperty(DevelTextField::Property::INPUT_FILTER, inputFilterMapSet);
+
+ inputFilterMapGet = field.GetProperty<Property::Map>(DevelTextField::Property::INPUT_FILTER);
+ DALI_TEST_EQUALS(inputFilterMapGet.Count(), inputFilterMapSet.Count(), TEST_LOCATION);
+
+ // Clear
+ inputFilterMapSet.Clear();
+ field.SetProperty(DevelTextField::Property::INPUT_FILTER, inputFilterMapSet);
+
application.SendNotification();
application.Render();
END_TEST;
}
+// Positive test for Input Filtered signal.
+int utcDaliTextFieldInputFilteredP(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextFieldInputFilteredP");
+ TextField field = TextField::New();
+ DALI_TEST_CHECK(field);
+
+ application.GetScene().Add(field);
+
+ Property::Map inputFilter;
+
+ // Only digit is accepted.
+ inputFilter[InputFilter::Property::ACCEPTED] = "[\\d]";
+
+ // Set input filter to TextField.
+ field.SetProperty(DevelTextField::Property::INPUT_FILTER, inputFilter);
+
+ field.SetKeyInputFocus();
+
+ // connect to the input filtered signal.
+ ConnectionTracker* testTracker = new ConnectionTracker();
+ DevelTextField::InputFilteredSignal(field).Connect(&TestInputFilteredCallback);
+ bool inputFilteredSignal = false;
+ field.ConnectSignal(testTracker, "inputFiltered", CallbackFunctor(&inputFilteredSignal));
+
+ gInputFilteredAcceptedCallbackCalled = false;
+
+ application.ProcessEvent(GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::DOWN, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ));
+
+ DALI_TEST_CHECK(gInputFilteredAcceptedCallbackCalled);
+ DALI_TEST_CHECK(inputFilteredSignal);
+
+ // Word is rejected.
+ inputFilter[InputFilter::Property::ACCEPTED] = "";
+ inputFilter[InputFilter::Property::REJECTED] = "[\\w]";
+
+ // Set input filter to TextField.
+ field.SetProperty(DevelTextField::Property::INPUT_FILTER, inputFilter);
+
+ field.SetKeyInputFocus();
+
+ inputFilteredSignal = false;
+ gInputFilteredRejectedCallbackCalled = false;
+
+ application.ProcessEvent(GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::DOWN, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ DALI_TEST_CHECK(gInputFilteredAcceptedCallbackCalled);
+ DALI_TEST_CHECK(inputFilteredSignal);
+
+ END_TEST;
+}
+
+// Negative test for Input Filtered signal.
+int utcDaliTextFieldInputFilteredN(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextFieldInputFilteredP");
+ TextField field = TextField::New();
+ DALI_TEST_CHECK(field);
+
+ application.GetScene().Add(field);
+
+ Property::Map inputFilter;
+
+ // Only word is accepted.
+ inputFilter[InputFilter::Property::ACCEPTED] = "[\\w]";
+
+ // Set input filter to TextField.
+ field.SetProperty(DevelTextField::Property::INPUT_FILTER, inputFilter);
+
+ field.SetKeyInputFocus();
+
+ // connect to the input filtered signal.
+ ConnectionTracker* testTracker = new ConnectionTracker();
+ DevelTextField::InputFilteredSignal(field).Connect(&TestInputFilteredCallback);
+ bool inputFilteredSignal = false;
+ field.ConnectSignal(testTracker, "inputFiltered", CallbackFunctor(&inputFilteredSignal));
+
+ gInputFilteredAcceptedCallbackCalled = false;
+
+ // Key a, d should not be filtered.
+ application.ProcessEvent(GenerateKey("a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::DOWN, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey("a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::UP, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey("d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey("d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::UP, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ // Backspace, Delete should not be filtered.
+ application.ProcessEvent(GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey( "Delete", "", "Delete", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::DOWN, "Delete", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(!gInputFilteredAcceptedCallbackCalled);
+ DALI_TEST_CHECK(!inputFilteredSignal);
+
+ // Digit is rejected.
+ inputFilter[InputFilter::Property::ACCEPTED] = "";
+ inputFilter[InputFilter::Property::REJECTED] = "[\\d]";
+
+ field.SetProperty(DevelTextField::Property::INPUT_FILTER, inputFilter);
+
+ field.SetKeyInputFocus();
+
+ inputFilteredSignal = false;
+ gInputFilteredRejectedCallbackCalled = false;
+
+ // Key a, d should not be filtered.
+ application.ProcessEvent(GenerateKey("a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::DOWN, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey("a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::UP, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey("d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey("d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::UP, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ // Backspace, Delete should not be filtered.
+ application.ProcessEvent(GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+ application.ProcessEvent(GenerateKey( "Delete", "", "Delete", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::DOWN, "Delete", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK(!gInputFilteredAcceptedCallbackCalled);
+ DALI_TEST_CHECK(!inputFilteredSignal);
+
+ END_TEST;
+}
+
int utcDaliTextFieldInputStyleChanged01(void)
{
// The text-field emits signals when the input style changes. These changes of style are
#include <dali-toolkit/public-api/controls/scrollable/scrollable.h>
#include <dali-toolkit/public-api/controls/slider/slider.h>
#include <dali-toolkit/public-api/controls/text-controls/hidden-input-properties.h>
+#include <dali-toolkit/public-api/controls/text-controls/input-filter-properties.h>
#include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
#include "accessible-impl.h"
// EXTERNAL INCLUDES
+#ifdef DGETTEXT_ENABLED
+#include <libintl.h>
+#endif
+
#include <dali/devel-api/actors/actor-devel.h>
// INTERNAL INCLUDES
namespace Dali::Toolkit::DevelControl {
+static std::string GetLocaleText(std::string string, const char *domain = "dali-toolkit")
+{
+#ifdef DGETTEXT_ENABLED
+ /*TODO: currently non-localized string is used as a key for translation lookup. In case the lookup key formatting is forced
+ consider calling utility function for converting non-localized string into well-formatted key before lookup. */
+ return dgettext(domain, string.c_str());
+#else
+ return string;
+#endif
+}
+
AccessibleImpl::AccessibleImpl(Dali::Actor self, Dali::Accessibility::Role role, bool modal)
: self(self),
modal(modal)
Internal::Control& internalControl = Toolkit::Internal::GetImplementation(control);
Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get(internalControl);
+ std::string name;
if(!controlImpl.mAccessibilityGetNameSignal.Empty())
{
- std::string ret;
- controlImpl.mAccessibilityGetNameSignal.Emit(ret);
- return ret;
+ controlImpl.mAccessibilityGetNameSignal.Emit(name);
+ }
+ else if(controlImpl.mAccessibilityNameSet)
+ {
+ name = controlImpl.mAccessibilityName;
+ }
+ else if(auto raw = GetNameRaw(); !raw.empty())
+ {
+ name = raw;
+ }
+ else
+ {
+ name = Self().GetProperty<std::string>(Actor::Property::NAME);
}
- if(controlImpl.mAccessibilityNameSet)
- return controlImpl.mAccessibilityName;
-
- if(auto raw = GetNameRaw(); !raw.empty())
- return raw;
+ if(controlImpl.mAccessibilityTranslationDomainSet)
+ {
+ return GetLocaleText(name, controlImpl.mAccessibilityTranslationDomain.c_str());
+ }
- return Self().GetProperty<std::string>(Actor::Property::NAME);
+ return GetLocaleText(name);
}
std::string AccessibleImpl::GetNameRaw()
Internal::Control& internalControl = Toolkit::Internal::GetImplementation(control);
Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get(internalControl);
+ std::string description;
if(!controlImpl.mAccessibilityGetDescriptionSignal.Empty())
{
- std::string ret;
- controlImpl.mAccessibilityGetDescriptionSignal.Emit(ret);
- return ret;
+ controlImpl.mAccessibilityGetDescriptionSignal.Emit(description);
+ }
+ else if(controlImpl.mAccessibilityDescriptionSet)
+ {
+ description = controlImpl.mAccessibilityDescription;
+ }
+ else
+ {
+ description = GetDescriptionRaw();
+ }
+ if(controlImpl.mAccessibilityTranslationDomainSet)
+ {
+ return GetLocaleText(description, controlImpl.mAccessibilityTranslationDomain.c_str());
}
- if(controlImpl.mAccessibilityDescriptionSet)
- return controlImpl.mAccessibilityDescription;
-
- return GetDescriptionRaw();
+ return GetLocaleText(description);
}
std::string AccessibleImpl::GetDescriptionRaw()
{
- return "";
+ return {};
}
Dali::Accessibility::Accessible* AccessibleImpl::GetParent()
return Self().GetProperty<Dali::Accessibility::Role>(Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE);
}
+std::string AccessibleImpl::GetLocalizedRoleName()
+{
+ return GetLocaleText(GetRoleName());
+}
+
Dali::Accessibility::States AccessibleImpl::CalculateStates()
{
Dali::Actor self = Self();
// keyboard focusable actors
auto actor = Toolkit::ImageView::New(focusBorderImagePath);
actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
- DevelControl::AppendAccessibilityAttribute(actor, "highlight", "");
+ DevelControl::AppendAccessibilityAttribute(actor, "highlight", std::string());
actor.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false);
return actor;
std::string AccessibleImpl::GetActionName(size_t index)
{
- if(index >= GetActionCount()) return "";
+ if(index >= GetActionCount()) return {};
Dali::TypeInfo type;
Self().GetTypeInfo(type);
DALI_ASSERT_ALWAYS(type && "no TypeInfo object");
std::string AccessibleImpl::GetLocalizedActionName(size_t index)
{
- // TODO: add localization
- return GetActionName(index);
+ return GetLocaleText(GetActionName(index));
}
std::string AccessibleImpl::GetActionDescription(size_t index)
{
- return "";
+ return {};
}
size_t AccessibleImpl::GetActionCount()
std::string AccessibleImpl::GetActionKeyBinding(size_t index)
{
- return "";
+ return {};
}
bool AccessibleImpl::DoAction(size_t index)
Dali::Accessibility::Role GetRole() override;
/**
+ * @copydoc Dali::Accessibility::Accessible::GetLocalizedRoleName()
+ */
+ std::string GetLocalizedRoleName() override;
+
+ /**
* @copydoc Dali::Accessibility::Accessible::GetStates()
*/
Dali::Accessibility::States GetStates() override;
return GetImpl(textEditor).AnchorClickedSignal();
}
+InputFilteredSignalType& InputFilteredSignal(TextEditor textEditor)
+{
+ return GetImpl(textEditor).InputFilteredSignal();
+}
+
void SelectWholeText(TextEditor textEditor)
{
GetImpl(textEditor).SelectWholeText();
#include <dali/devel-api/adaptor-framework/input-method-context.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/input-filter-properties.h>
#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
namespace Dali
* @endcode
*/
INPUT_METHOD_SETTINGS,
+
+ /**
+ * @brief The input filter
+ * @details Name "inputFilter", type Property::MAP.
+ *
+ * The inputFilter map contains the following keys:
+ *
+ * | %Property Name | Type | Required | Description |
+ * |----------------------|----------|----------|---------------------------------------------------------------------------------------------------------------------|
+ * | accepted | STRING | No | A regular expression in the set of characters to be accepted by the inputFilter (the default value is empty string) |
+ * | rejected | STRING | No | A regular expression in the set of characters to be rejected by the inputFilter (the default value is empty string) |
+ *
+ * @note Optional.
+ * The character set must follow the regular expression rules.
+ * Behaviour can not be guaranteed for incorrect grammars.
+ * Refer the link below for detailed rules.
+ * The functions in std::regex library use the ECMAScript grammar:
+ * http://cplusplus.com/reference/regex/ECMAScript/
+ *
+ * You can use enums instead of "accepted" and "rejected" strings.
+ * @see Dali::Toolkit::InputFilter::Property::Type
+ *
+ * Example Usage:
+ * @code
+ * Property::Map filter;
+ * filter[InputFilter::Property::ACCEPTED] = "[\\d]"; // accept whole digits
+ * filter[InputFilter::Property::REJECTED] = "[0-5]"; // reject 0, 1, 2, 3, 4, 5
+ *
+ * editor.SetProperty(DevelTextEditor::Property::INPUT_FILTER, filter); // acceptable inputs are 6, 7, 8, 9
+ * @endcode
+ */
+ INPUT_FILTER,
};
} // namespace Property
DALI_TOOLKIT_API AnchorClickedSignalType& AnchorClickedSignal(TextEditor textEditor);
/**
+ * @brief Input filtered signal type.
+ */
+using InputFilteredSignalType = Signal<void(TextEditor, Toolkit::InputFilter::Property::Type)>;
+
+/**
+ * @brief This signal is emitted when the character to be inserted is filtered by the input filter.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ * void YourCallbackName(TextEditor textEditor, Toolkit::InputFilter::Property::Type type);
+ *
+ * DevelTextEditor::InputFilteredSignal(textEditor).Connect(this, &OnInputFiltered);
+ *
+ * void OnInputFiltered(TextEditor textEditor, InputFilter::Property::Type type)
+ * {
+ * if (type == InputFilter::Property::ACCEPTED)
+ * {
+ * // If the input has been filtered with an accepted filter, the type is ACCEPTED.
+ * }
+ * else if (type == InputFilter::Property::REJECTED)
+ * {
+ * // If the input has been filtered with an rejected filter, the type is REJECTED.
+ * }
+ * }
+ * @endcode
+ * @param[in] textEditor The instance of TextEditor.
+ * @return The signal to connect to.
+ */
+DALI_TOOLKIT_API InputFilteredSignalType& InputFilteredSignal(TextEditor textEditor);
+
+/**
* @brief Select the whole text of TextEditor.
*
* @param[in] textEditor The instance of TextEditor.
return GetImpl(textField).AnchorClickedSignal();
}
+InputFilteredSignalType& InputFilteredSignal(TextField textField)
+{
+ return GetImpl(textField).InputFilteredSignal();
+}
+
void SelectWholeText(TextField textField)
{
GetImpl(textField).SelectWholeText();
#include <dali/devel-api/adaptor-framework/input-method-context.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/input-filter-properties.h>
#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
namespace Dali
* @details Name "grabHandleColor", type Property::VECTOR4.
*/
GRAB_HANDLE_COLOR,
+
+ /**
+ * @brief The input filter
+ * @details Name "inputFilter", type Property::MAP.
+ *
+ * The inputFilter map contains the following keys:
+ *
+ * | %Property Name | Type | Required | Description |
+ * |----------------------|----------|----------|---------------------------------------------------------------------------------------------------------------------|
+ * | accepted | STRING | No | A regular expression in the set of characters to be accepted by the inputFilter (the default value is empty string) |
+ * | rejected | STRING | No | A regular expression in the set of characters to be rejected by the inputFilter (the default value is empty string) |
+ *
+ * @note Optional.
+ * The character set must follow the regular expression rules.
+ * Behaviour can not be guaranteed for incorrect grammars.
+ * Refer the link below for detailed rules.
+ * The functions in std::regex library use the ECMAScript grammar:
+ * http://cplusplus.com/reference/regex/ECMAScript/
+ *
+ * You can use enums instead of "accepted" and "rejected" strings.
+ * @see Dali::Toolkit::InputFilter::Property::Type
+ *
+ * Example Usage:
+ * @code
+ * Property::Map filter;
+ * filter[InputFilter::Property::ACCEPTED] = "[\\d]"; // accept whole digits
+ * filter[InputFilter::Property::REJECTED] = "[0-5]"; // reject 0, 1, 2, 3, 4, 5
+ *
+ * field.SetProperty(DevelTextField::Property::INPUT_FILTER, filter); // acceptable inputs are 6, 7, 8, 9
+ * @endcode
+ */
+ INPUT_FILTER,
};
} // namespace Property
DALI_TOOLKIT_API AnchorClickedSignalType& AnchorClickedSignal(TextField textField);
/**
+ * @brief Input filtered signal type.
+ */
+using InputFilteredSignalType = Signal<void(TextField, Toolkit::InputFilter::Property::Type)>;
+
+/**
+ * @brief This signal is emitted when the character to be inserted is filtered by the input filter.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ * void YourCallbackName(TextField textField, Toolkit::InputFilter::Property::Type type);
+ *
+ * DevelTextField::InputFilteredSignal(textField).Connect(this, &OnInputFiltered);
+ *
+ * void OnInputFiltered(TextField textField, InputFilter::Property::Type type)
+ * {
+ * if (type == InputFilter::Property::ACCEPTED)
+ * {
+ * // If the input has been filtered with an accepted filter, the type is ACCEPTED.
+ * }
+ * else if (type == InputFilter::Property::REJECTED)
+ * {
+ * // If the input has been filtered with an rejected filter, the type is REJECTED.
+ * }
+ * }
+ * @endcode
+ * @param[in] textField The instance of TextField.
+ * @return The signal to connect to.
+ */
+DALI_TOOLKIT_API InputFilteredSignalType& InputFilteredSignal(TextField textField);
+
+/**
* @brief Select the whole text of TextField.
*
* @param[in] textField The instance of TextField.
return std::unique_ptr<Dali::Accessibility::Accessible>(
new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::IMAGE));
});
-
- //Enable highightability
- Self().SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
}
void ImageView::SetImage(const Property::Map& map)
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "grabHandleColor", VECTOR4, GRAB_HANDLE_COLOR )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "enableGrabHandlePopup", BOOLEAN, ENABLE_GRAB_HANDLE_POPUP )
DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "inputMethodSettings", MAP, INPUT_METHOD_SETTINGS )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextEditor, "inputFilter", MAP, INPUT_FILTER )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged", SIGNAL_INPUT_STYLE_CHANGED)
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "maxLengthReached", SIGNAL_MAX_LENGTH_REACHED )
DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "anchorClicked", SIGNAL_ANCHOR_CLICKED )
+DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputFiltered", SIGNAL_INPUT_FILTERED )
+
DALI_TYPE_REGISTRATION_END()
// clang-format on
}
break;
}
+ case Toolkit::DevelTextEditor::Property::INPUT_FILTER:
+ {
+ const Property::Map* map = value.GetMap();
+ if(map)
+ {
+ impl.mController->SetInputFilterOption(*map);
+ }
+ break;
+ }
} // switch
} // texteditor
}
value = map;
break;
}
+ case Toolkit::DevelTextEditor::Property::INPUT_FILTER:
+ {
+ Property::Map map;
+ impl.mController->GetInputFilterOption(map);
+ value = map;
+ break;
+ }
} //switch
}
return mAnchorClickedSignal;
}
+DevelTextEditor::InputFilteredSignalType& TextEditor::InputFilteredSignal()
+{
+ return mInputFilteredSignal;
+}
+
Text::ControllerPtr TextEditor::getController()
{
return mController;
editorImpl.AnchorClickedSignal().Connect(tracker, functor);
}
}
+ else if(0 == strcmp(signalName.c_str(), SIGNAL_INPUT_FILTERED))
+ {
+ if(editor)
+ {
+ Internal::TextEditor& editorImpl(GetImpl(editor));
+ editorImpl.InputFilteredSignal().Connect(tracker, functor);
+ }
+ }
else
{
// signalName does not match any signal
mAnchorClickedSignal.Emit(handle, href.c_str(), href.length());
}
+void TextEditor::InputFiltered(Toolkit::InputFilter::Property::Type type)
+{
+ Dali::Toolkit::TextEditor handle(GetOwner());
+ mInputFilteredSignal.Emit(handle, type);
+}
+
void TextEditor::AddDecoration(Actor& actor, bool needsClipping)
{
if(actor)
DevelTextEditor::AnchorClickedSignalType& AnchorClickedSignal();
/**
+ * @copydoc Dali::Toollkit::TextEditor::InputFilteredSignal()
+ */
+ DevelTextEditor::InputFilteredSignalType& InputFilteredSignal();
+
+ /**
* Connects a callback function with the object's signals.
* @param[in] object The object providing the signal.
* @param[in] tracker Used to disconnect the signal.
*/
void AddDecoration(Actor& actor, bool needsClipping) override;
+ /**
+ * @copydoc Text::EditableControlInterface::InputFiltered()
+ */
+ void InputFiltered(Toolkit::InputFilter::Property::Type type) override;
+
// From SelectableControlInterface
public:
/**
Toolkit::TextEditor::ScrollStateChangedSignalType mScrollStateChangedSignal;
Toolkit::DevelTextEditor::MaxLengthReachedSignalType mMaxLengthReachedSignal;
Toolkit::DevelTextEditor::AnchorClickedSignalType mAnchorClickedSignal;
+ Toolkit::DevelTextEditor::InputFilteredSignalType mInputFilteredSignal;
InputMethodContext mInputMethodContext;
Text::ControllerPtr mController;
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_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
impl.RequestTextRelayout();
break;
}
+ case Toolkit::DevelTextField::Property::INPUT_FILTER:
+ {
+ const Property::Map* map = value.GetMap();
+ if(map)
+ {
+ impl.mController->SetInputFilterOption(*map);
+ }
+ break;
+ }
} // switch
} // textfield
}
value = impl.mDecorator->GetHandleColor();
break;
}
+ case Toolkit::DevelTextField::Property::INPUT_FILTER:
+ {
+ Property::Map map;
+ impl.mController->GetInputFilterOption(map);
+ value = map;
+ break;
+ }
} //switch
}
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 mAnchorClickedSignal;
}
+DevelTextField::InputFilteredSignalType& TextField::InputFilteredSignal()
+{
+ return mInputFilteredSignal;
+}
+
void TextField::OnInitialize()
{
Actor self = Self();
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)
*/
DevelTextField::AnchorClickedSignalType& AnchorClickedSignal();
+ /**
+ * @copydoc TextField::InputFilteredSignal()
+ */
+ DevelTextField::InputFilteredSignalType& InputFilteredSignal();
+
Text::ControllerPtr getController();
private: // From Control
*/
void AddDecoration(Actor& actor, bool needsClipping) override;
+ /**
+ * @copydoc Text::EditableControlInterface::InputFiltered()
+ */
+ void InputFiltered(Toolkit::InputFilter::Property::Type type) override;
+
// From SelectableControlInterface
public:
/**
Toolkit::TextField::MaxLengthReachedSignalType mMaxLengthReachedSignal;
Toolkit::TextField::InputStyleChangedSignalType mInputStyleChangedSignal;
Toolkit::DevelTextField::AnchorClickedSignalType mAnchorClickedSignal;
+ Toolkit::DevelTextField::InputFilteredSignalType mInputFilteredSignal;
InputMethodContext mInputMethodContext;
Text::ControllerPtr mController;
${toolkit_src_dir}/text/markup-processor-anchor.cpp
${toolkit_src_dir}/text/markup-processor-font.cpp
${toolkit_src_dir}/text/markup-processor-background.cpp
+ ${toolkit_src_dir}/text/markup-processor-span.cpp
${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
${toolkit_src_dir}/text/multi-language-support.cpp
${toolkit_src_dir}/text/hidden-text.cpp
+ ${toolkit_src_dir}/text/input-filter.cpp
${toolkit_src_dir}/text/property-string-parser.cpp
${toolkit_src_dir}/text/segmentation.cpp
${toolkit_src_dir}/text/shaper.cpp
--- /dev/null
+/*
+ * Copyright (c) 2021 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/hidden-text.h>
+#include <dali-toolkit/internal/text/input-filter.h>
+
+// INTERNAL INCLUDES
+
+using namespace Dali::Toolkit;
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+const char* const PROPERTY_ACCEPTED = "accepted";
+const char* const PROPERTY_REJECTED = "rejected";
+
+InputFilter::InputFilter()
+: mAccepted(""),
+ mRejected("")
+{
+}
+
+void InputFilter::SetProperties(const Property::Map& map)
+{
+ const Property::Map::SizeType count = map.Count();
+
+ for(Property::Map::SizeType position = 0; position < count; ++position)
+ {
+ KeyValuePair keyValue = map.GetKeyValue(position);
+ Property::Key& key = keyValue.first;
+ Property::Value& value = keyValue.second;
+
+ if(key == Toolkit::InputFilter::Property::ACCEPTED || key == PROPERTY_ACCEPTED)
+ {
+ value.Get(mAccepted);
+ }
+ else if(key == Toolkit::InputFilter::Property::REJECTED || key == PROPERTY_REJECTED)
+ {
+ value.Get(mRejected);
+ }
+ }
+}
+
+void InputFilter::GetProperties(Property::Map& map)
+{
+ map[Toolkit::InputFilter::Property::ACCEPTED] = mAccepted.c_str();
+ map[Toolkit::InputFilter::Property::REJECTED] = mRejected.c_str();
+}
+
+bool InputFilter::Contains(Toolkit::InputFilter::Property::Type type, std::string source)
+{
+ bool match = false;
+ std::regex pattern;
+
+ if(type == Toolkit::InputFilter::Property::ACCEPTED)
+ {
+ if(mAccepted.empty())
+ {
+ return true;
+ }
+ pattern = mAccepted;
+ }
+ else if(type == Toolkit::InputFilter::Property::REJECTED)
+ {
+ if(mRejected.empty())
+ {
+ return false;
+ }
+ pattern = mRejected;
+ }
+
+ match = std::regex_match(source, pattern);
+
+ return match;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INPUT_FILTER_H
+#define DALI_INPUT_FILTER_H
+
+/*
+ * Copyright (c) 2021 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/input-filter-properties.h>
+#include <regex>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * Class to handle the input text filtering
+ */
+class InputFilter : public ConnectionTracker
+{
+public:
+ /**
+ * @brief Constructor
+ */
+ InputFilter();
+
+public: // Intended for internal use
+ /**
+ * @brief Used to set options of input filter.
+ * @param[in] map The property map describing the option.
+ */
+ void SetProperties(const Property::Map& map);
+
+ /**
+ * @brief Retrieve property map of input filter options.
+ * @param[out] map The input filter option.
+ */
+ void GetProperties(Property::Map& map);
+
+ /**
+ * @brief Check if the source is contained in regex.
+ * @param[in] type ACCEPTED or REJECTED
+ * @param[in] source The original text.
+ * @return @e true if the source is contained in regex, otherwise returns @e false.
+ */
+ bool Contains(Toolkit::InputFilter::Property::Type type, std::string source);
+
+private:
+ std::string mAccepted;
+ std::string mRejected;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_INPUT_FILTER_H
const std::string XHTML_VALUE_ATTRIBUTE("value");
}
+void ProcessColor(const Attribute& attribute, ColorRun& colorRun)
+{
+ ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
+}
+
void ProcessColorTag(const Tag& tag, ColorRun& colorRun)
{
for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
const Attribute& attribute(*it);
if(TokenComparison(XHTML_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
{
- ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
+ ProcessColor(attribute, colorRun);
}
}
}
namespace Text
{
struct Tag;
+struct Attribute;
struct ColorRun;
/**
* @brief Retrieves the color value from the tag and sets it to the color run.
*
+ * @param[in] attribute the color attribute.
+ * @param[in,out] colorRun The color run.
+ */
+void ProcessColor(const Attribute& attribute, ColorRun& colorRun);
+
+/**
+ * @brief Retrieves the color value from the tag and sets it to the color run.
+ *
* @param[in] tag The color tag and its attributes.
* @param[in,out] colorRun The color run.
*/
const std::string XHTML_WIDTH_ATTRIBUTE("width");
const std::string XHTML_SLANT_ATTRIBUTE("slant");
-const unsigned int MAX_FONT_ATTRIBUTE_SIZE = 15u; ///< The maximum length of any of the possible 'weight', 'width' or 'slant' values.
+const std::string FONT_PREFIX("font-");
+const unsigned int FONT_PREFIX_LENGTH = 5u;
+const unsigned int MIN_FONT_ATTRIBUTE_SIZE = 4u; ///< The minimum length of any of the possible 'weight', 'width' , 'slant' or 'size' values.
+const unsigned int MAX_FONT_ATTRIBUTE_SIZE = 15u; ///< The maximum length of any of the possible 'weight', 'width' or 'slant' values.
+const float PIXEL_FORMAT_64_FACTOR = 64.f; ///< 64.f is used to convert from point size to 26.6 pixel format.
} // namespace
+void processFontAttributeValue(char value[], const Attribute& attribute)
+{
+ // The StringToWeight() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
+ const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
+ memcpy(value, attribute.valueBuffer, length);
+ value[length] = 0;
+}
+
+void ProcessFontFamily(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ fontRun.familyDefined = true;
+ fontRun.familyLength = attribute.valueLength;
+ fontRun.familyName = new char[fontRun.familyLength];
+ memcpy(fontRun.familyName, attribute.valueBuffer, fontRun.familyLength);
+ // The memory is freed when the font run is removed from the logical model.
+}
+
+void ProcessFontSize(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ // 64.f is used to convert from point size to 26.6 pixel format.
+ fontRun.size = static_cast<PointSize26Dot6>(StringToFloat(attribute.valueBuffer) * PIXEL_FORMAT_64_FACTOR);
+ fontRun.sizeDefined = true;
+}
+
+void ProcessFontWeight(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
+ processFontAttributeValue(value, attribute);
+
+ fontRun.weight = StringToWeight(value);
+ fontRun.weightDefined = true;
+}
+
+void ProcessFontWidth(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
+ processFontAttributeValue(value, attribute);
+
+ fontRun.width = StringToWidth(value);
+ fontRun.widthDefined = true;
+}
+
+void ProcessFontSlant(const Attribute& attribute, FontDescriptionRun& fontRun)
+{
+ char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
+ processFontAttributeValue(value, attribute);
+
+ fontRun.slant = StringToSlant(value);
+ fontRun.slantDefined = true;
+}
+
void ProcessFontTag(const Tag& tag, FontDescriptionRun& fontRun)
{
for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
++it)
{
const Attribute& attribute(*it);
+
if(TokenComparison(XHTML_FAMILY_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
{
- fontRun.familyDefined = true;
- fontRun.familyLength = attribute.valueLength;
- fontRun.familyName = new char[fontRun.familyLength];
- memcpy(fontRun.familyName, attribute.valueBuffer, fontRun.familyLength);
- // The memory is freed when the font run is removed from the logical model.
+ ProcessFontFamily(attribute, fontRun);
}
else if(TokenComparison(XHTML_SIZE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
{
- // 64.f is used to convert from point size to 26.6 pixel format.
- fontRun.size = static_cast<PointSize26Dot6>(StringToFloat(attribute.valueBuffer) * 64.f);
- fontRun.sizeDefined = true;
+ ProcessFontSize(attribute, fontRun);
}
else if(TokenComparison(XHTML_WEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
{
- // The StringToWeight() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
- char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
- const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
- memcpy(value, attribute.valueBuffer, length);
- value[length] = 0;
-
- fontRun.weight = StringToWeight(value);
- fontRun.weightDefined = true;
+ ProcessFontWeight(attribute, fontRun);
}
else if(TokenComparison(XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
{
- // The StringToWidth() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
- char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
- const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
- memcpy(value, attribute.valueBuffer, length);
- value[length] = 0;
-
- fontRun.width = StringToWidth(value);
- fontRun.widthDefined = true;
+ ProcessFontWidth(attribute, fontRun);
}
else if(TokenComparison(XHTML_SLANT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
{
- // The StringToSlant() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
- char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
- const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
- memcpy(value, attribute.valueBuffer, length);
- value[length] = 0;
-
- fontRun.slant = StringToSlant(value);
- fontRun.slantDefined = true;
+ ProcessFontSlant(attribute, fontRun);
}
}
}
namespace Text
{
struct Tag;
+struct Attribute;
struct FontDescriptionRun;
/**
*/
void ProcessFontTag(const Tag& tag, FontDescriptionRun& fontRun);
+/**
+ * @brief Fill the font run with the font slant attribute value.
+ *
+ * @param[in] attribute the font slant attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontSlant(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font width attribute value.
+ *
+ * @param[in] attribute the font width attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontWidth(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font weight attribute value.
+ *
+ * @param[in] attribute the font weight attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontWeight(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font size attribute value.
+ *
+ * @param[in] attribute the font size attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontSize(const Attribute& attribute, FontDescriptionRun& fontRun);
+
+/**
+ * @brief Fill the font run with the font family attribute value.
+ *
+ * @param[in] attribute the font family attribute.
+ * @param[out] fontRun The font description run.
+ */
+void ProcessFontFamily(const Attribute& attribute, FontDescriptionRun& fontRun);
+
} // namespace Text
} // namespace Toolkit
--- /dev/null
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-color.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/markup-processor-font.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const std::string XHTML_FAMILY_ATTRIBUTE("font-family");
+const std::string XHTML_SIZE_ATTRIBUTE("font-size");
+const std::string XHTML_WEIGHT_ATTRIBUTE("font-weight");
+const std::string XHTML_WIDTH_ATTRIBUTE("font-width");
+const std::string XHTML_SLANT_ATTRIBUTE("font-slant");
+
+const std::string XHTML_COLOR_ATTRIBUTE("text-color");
+} // namespace
+
+void ProcessSpanTag(const Tag& tag, ColorRun& colorRun, FontDescriptionRun& fontRun, bool& isColorDefined, bool& isFontDefined)
+{
+ for(Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+ endIt = tag.attributes.End();
+ it != endIt;
+ ++it)
+ {
+ const Attribute& attribute(*it);
+
+ if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isColorDefined = true;
+ ProcessColor(attribute, colorRun);
+ }
+ else if(TokenComparison(XHTML_FAMILY_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontFamily(attribute, fontRun);
+ }
+ else if(TokenComparison(XHTML_SIZE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontSize(attribute, fontRun);
+ }
+ else if(TokenComparison(XHTML_WEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontWeight(attribute, fontRun);
+ }
+ else if(TokenComparison(XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontWidth(attribute, fontRun);
+ }
+ else if(TokenComparison(XHTML_SLANT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+ {
+ isFontDefined = true;
+ ProcessFontSlant(attribute, fontRun);
+ }
+ }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_H
+
+/*
+ * Copyright (c) 2021 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Tag;
+struct MarkupProcessData;
+
+/**
+ * @brief process the span from the tag and process all styles in it.
+ *
+ * @param[in] tag The span tag and its attributes.
+ * @param[out] colorRun the color run to be filled.
+ * @param[out] fontRun the font run to be filled.
+ * @param[out] isColorDefined if the span has color defined.
+ * @param[out] isFontDefined if the span has font defined.
+ */
+void ProcessSpanTag(const Tag& tag, ColorRun& colorRun, FontDescriptionRun& fontRun, bool& isColorDefined, bool& isFontDefined);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_H
#include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
#include <dali-toolkit/internal/text/markup-processor-font.h>
#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor-span.h>
#include <dali-toolkit/internal/text/xhtml-entities.h>
namespace Dali
const std::string XHTML_ITEM_TAG("item");
const std::string XHTML_ANCHOR_TAG("a");
const std::string XHTML_BACKGROUND_TAG("background");
+const std::string XHTML_SPAN_TAG("span");
const char LESS_THAN = '<';
const char GREATER_THAN = '>';
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_MARKUP_PROCESSOR");
#endif
+typedef VectorBase::SizeType RunIndex;
+
/**
* @brief Struct used to retrieve the style runs from the mark-up string.
*/
+template<typename StyleStackType>
struct StyleStack
{
- typedef VectorBase::SizeType RunIndex;
-
- Vector<RunIndex> stack; ///< Use a vector as a style stack. Stores the indices pointing where the run is stored inside the logical model.
- unsigned int topIndex; ///< Points the top of the stack.
+ Vector<StyleStackType> stack; ///< Use a vector as a style stack.
+ unsigned int topIndex; ///< Points the top of the stack.
StyleStack()
: stack(),
stack.Resize(DEFAULT_VECTOR_SIZE);
}
- void Push(RunIndex index)
+ void Push(StyleStackType item)
{
// Check if there is space inside the style stack.
const VectorBase::SizeType size = stack.Count();
stack.Resize(2u * size);
}
- // Set the run index in the top of the stack.
- *(stack.Begin() + topIndex) = index;
+ // Set the item in the top of the stack.
+ *(stack.Begin() + topIndex) = item;
// Reposition the pointer to the top of the stack.
++topIndex;
}
- RunIndex Pop()
+ StyleStackType Pop()
{
// Pop the top of the stack.
--topIndex;
};
/**
+ * @brief Struct used to retrieve spans from the mark-up string.
+ */
+struct Span
+{
+ RunIndex colorRunIndex;
+ RunIndex fontRunIndex;
+ bool isColorDefined;
+ bool isFontDefined;
+};
+
+/**
* @brief Initializes a font run description to its defaults.
*
* @param[in,out] fontRun The font description run to initialize.
}
/**
+ * @brief Initializes a span to its defaults.
+ *
+ * @param[in,out] span The span to be initialized.
+ */
+void Initialize(Span& span)
+{
+ span.colorRunIndex = 0u;
+ span.isColorDefined = false;
+ span.fontRunIndex = 0u;
+ span.isFontDefined = false;
+}
+
+/**
* @brief Splits the tag string into the tag name and its attributes.
*
* The attributes are stored in a vector in the tag.
template<typename RunType>
void ProcessTagForRun(
Vector<RunType>& runsContainer,
- StyleStack& styleStack,
+ StyleStack<RunIndex>& styleStack,
const Tag& tag,
const CharacterIndex characterIndex,
- StyleStack::RunIndex& runIndex,
+ RunIndex& runIndex,
int& tagReference,
std::function<void(const Tag&, RunType&)> parameterSettingFunction)
{
}
/**
+ * @brief Processes span tag for the color-run & font-run.
+ *
+ * @param[in] spanTag The tag we are currently processing
+ * @param[in/out] spanStack The spans stack
+ * @param[int/out] colorRuns The container containing all the color runs
+ * @param[int/out] fontRuns The container containing all the font description runs
+ * @param[in/out] colorRunIndex The color run index
+ * @param[in/out] fontRunIndex The font run index
+ * @param[in] characterIndex The current character index
+ * @param[in] tagReference The tagReference we should increment/decrement
+ */
+void ProcessSpanForRun(
+ const Tag& spanTag,
+ StyleStack<Span>& spanStack,
+ Vector<ColorRun>& colorRuns,
+ Vector<FontDescriptionRun>& fontRuns,
+ RunIndex& colorRunIndex,
+ RunIndex& fontRunIndex,
+ const CharacterIndex characterIndex,
+ int& tagReference)
+{
+ if(!spanTag.isEndTag)
+ {
+ // Create a new run.
+ ColorRun colorRun;
+ Initialize(colorRun);
+
+ FontDescriptionRun fontRun;
+ Initialize(fontRun);
+
+ Span span;
+ Initialize(span);
+
+ // Fill the run with the parameters.
+ colorRun.characterRun.characterIndex = characterIndex;
+ fontRun.characterRun.characterIndex = characterIndex;
+
+ span.colorRunIndex = colorRunIndex;
+ span.fontRunIndex = fontRunIndex;
+
+ ProcessSpanTag(spanTag, colorRun, fontRun, span.isColorDefined, span.isFontDefined);
+
+ // Push the span into the stack.
+ spanStack.Push(span);
+
+ // Point the next free run.
+ if(span.isColorDefined)
+ {
+ // Push the run in the logical model.
+ colorRuns.PushBack(colorRun);
+ ++colorRunIndex;
+ }
+
+ if(span.isFontDefined)
+ {
+ // Push the run in the logical model.
+ fontRuns.PushBack(fontRun);
+ ++fontRunIndex;
+ }
+
+ // Increase reference
+ ++tagReference;
+ }
+ else
+ {
+ if(tagReference > 0)
+ {
+ // Pop the top of the stack and set the number of characters of the run.
+ Span span = spanStack.Pop();
+
+ if(span.isColorDefined)
+ {
+ ColorRun& colorRun = *(colorRuns.Begin() + span.colorRunIndex);
+ colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
+ }
+
+ if(span.isFontDefined)
+ {
+ FontDescriptionRun& fontRun = *(fontRuns.Begin() + span.fontRunIndex);
+ fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
+ }
+
+ --tagReference;
+ }
+ }
+}
+
+/**
* @brief Resizes the model's vectors
*
* @param[in/out] markupProcessData The markup process data
* @param[in] underlinedCharacterRunIndex The underlined character run index
* @param[in] backgroundRunIndex The background run index
*/
-void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex, const StyleStack::RunIndex underlinedCharacterRunIndex, const StyleStack::RunIndex backgroundRunIndex)
+void ResizeModelVectors(MarkupProcessData& markupProcessData, const RunIndex fontRunIndex, const RunIndex colorRunIndex, const RunIndex underlinedCharacterRunIndex, const RunIndex backgroundRunIndex)
{
markupProcessData.fontRuns.Resize(fontRunIndex);
markupProcessData.colorRuns.Resize(colorRunIndex);
markupProcessData.markupProcessedText.reserve(markupStringSize);
// Stores a struct with the index to the first character of the run, the type of run and its parameters.
- StyleStack styleStack;
+ StyleStack<RunIndex> styleStack;
+
+ // Stores a struct with the index to the first character of the color run & color font for the span.
+ StyleStack<Span> spanStack;
// Points the next free position in the vector of runs.
- StyleStack::RunIndex colorRunIndex = 0u;
- StyleStack::RunIndex fontRunIndex = 0u;
- StyleStack::RunIndex underlinedCharacterRunIndex = 0u;
- StyleStack::RunIndex backgroundRunIndex = 0u;
+ RunIndex colorRunIndex = 0u;
+ RunIndex fontRunIndex = 0u;
+ RunIndex underlinedCharacterRunIndex = 0u;
+ RunIndex backgroundRunIndex = 0u;
// check tag reference
int colorTagReference = 0u;
int bTagReference = 0u;
int uTagReference = 0u;
int backgroundTagReference = 0u;
+ int spanTagReference = 0u;
// Give an initial default value to the model's vectors.
markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
ProcessTagForRun<ColorRun>(
markupProcessData.backgroundColorRuns, styleStack, tag, characterIndex, backgroundRunIndex, backgroundTagReference, [](const Tag& tag, ColorRun& run) { ProcessBackground(tag, run); });
}
+ else if(TokenComparison(XHTML_SPAN_TAG, tag.buffer, tag.length))
+ {
+ ProcessSpanForRun(tag, spanStack, markupProcessData.colorRuns, markupProcessData.fontRuns, colorRunIndex, fontRunIndex, characterIndex, spanTagReference);
+ }
} // end if( IsTag() )
else if(markupStringBuffer < markupStringEndBuffer)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", &controller, keyString.c_str());
if(!controller.IsEditable()) return false;
- if(!keyString.empty())
+ std::string refinedKey = keyString;
+ if(controller.mImpl->mInputFilter != NULL && !refinedKey.empty())
+ {
+ bool accepted = false;
+ bool rejected = false;
+ accepted = controller.mImpl->mInputFilter->Contains(Toolkit::InputFilter::Property::ACCEPTED, keyString);
+ rejected = controller.mImpl->mInputFilter->Contains(Toolkit::InputFilter::Property::REJECTED, keyString);
+
+ if(!accepted)
+ {
+ // The filtered key is set to empty.
+ refinedKey = "";
+ // Signal emits when the character to be inserted is filtered by the accepted filter.
+ controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::ACCEPTED);
+ }
+ if(rejected)
+ {
+ // The filtered key is set to empty.
+ refinedKey = "";
+ // Signal emits when the character to be inserted is filtered by the rejected filter.
+ controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::REJECTED);
+ }
+ }
+
+ if(!refinedKey.empty())
{
// InputMethodContext is no longer handling key-events
controller.mImpl->ClearPreEditFlag();
- controller.InsertText(keyString, COMMIT);
+ controller.InsertText(refinedKey, COMMIT);
textChanged = true;
mOperationsPending(NO_OPERATION),
mMaximumNumberOfCharacters(50u),
mHiddenInput(NULL),
+ mInputFilter(nullptr),
mRecalculateNaturalSize(true),
mMarkupProcessorEnabled(false),
mClipboardHideEnabled(true),
~Impl()
{
delete mHiddenInput;
-
delete mFontDefaults;
delete mUnderlineDefaults;
delete mShadowDefaults;
void CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns);
public:
- ControlInterface* mControlInterface; ///< Reference to the text controller.
- EditableControlInterface* mEditableControlInterface; ///< Reference to the editable text controller.
- SelectableControlInterface* mSelectableControlInterface; ///< Reference to the selectable text controller.
- AnchorControlInterface* mAnchorControlInterface; ///< Reference to the anchor controller.
- ModelPtr mModel; ///< Pointer to the text's model.
- FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
- UnderlineDefaults* mUnderlineDefaults; ///< Avoid allocating this when the user does not specify underline parameters.
- ShadowDefaults* mShadowDefaults; ///< Avoid allocating this when the user does not specify shadow parameters.
- EmbossDefaults* mEmbossDefaults; ///< Avoid allocating this when the user does not specify emboss parameters.
- OutlineDefaults* mOutlineDefaults; ///< Avoid allocating this when the user does not specify outline parameters.
- EventData* mEventData; ///< Avoid allocating everything for text input until EnableTextInput().
- TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
- Clipboard mClipboard; ///< Handle to the system clipboard
- View mView; ///< The view interface to the rendering back-end.
- MetricsPtr mMetrics; ///< A wrapper around FontClient used to get metrics & potentially down-scaled Emoji metrics.
- Layout::Engine mLayoutEngine; ///< The layout engine.
- Vector<ModifyEvent> mModifyEvents; ///< Temporary stores the text set until the next relayout.
- Vector4 mTextColor; ///< The regular text color
- TextUpdateInfo mTextUpdateInfo; ///< Info of the characters updated.
- OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
- Length mMaximumNumberOfCharacters; ///< Maximum number of characters that can be inserted.
- HiddenText* mHiddenInput; ///< Avoid allocating this when the user does not specify hidden input mode.
- Vector2 mTextFitContentSize; ///< Size of Text fit content
+ ControlInterface* mControlInterface; ///< Reference to the text controller.
+ EditableControlInterface* mEditableControlInterface; ///< Reference to the editable text controller.
+ SelectableControlInterface* mSelectableControlInterface; ///< Reference to the selectable text controller.
+ AnchorControlInterface* mAnchorControlInterface; ///< Reference to the anchor controller.
+ ModelPtr mModel; ///< Pointer to the text's model.
+ FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
+ UnderlineDefaults* mUnderlineDefaults; ///< Avoid allocating this when the user does not specify underline parameters.
+ ShadowDefaults* mShadowDefaults; ///< Avoid allocating this when the user does not specify shadow parameters.
+ EmbossDefaults* mEmbossDefaults; ///< Avoid allocating this when the user does not specify emboss parameters.
+ OutlineDefaults* mOutlineDefaults; ///< Avoid allocating this when the user does not specify outline parameters.
+ EventData* mEventData; ///< Avoid allocating everything for text input until EnableTextInput().
+ TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
+ Clipboard mClipboard; ///< Handle to the system clipboard
+ View mView; ///< The view interface to the rendering back-end.
+ MetricsPtr mMetrics; ///< A wrapper around FontClient used to get metrics & potentially down-scaled Emoji metrics.
+ Layout::Engine mLayoutEngine; ///< The layout engine.
+ Vector<ModifyEvent> mModifyEvents; ///< Temporary stores the text set until the next relayout.
+ Vector4 mTextColor; ///< The regular text color
+ TextUpdateInfo mTextUpdateInfo; ///< Info of the characters updated.
+ OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
+ Length mMaximumNumberOfCharacters; ///< Maximum number of characters that can be inserted.
+ HiddenText* mHiddenInput; ///< Avoid allocating this when the user does not specify hidden input mode.
+ std::unique_ptr<InputFilter> mInputFilter; ///< Avoid allocating this when the user does not specify input filter mode.
+ Vector2 mTextFitContentSize; ///< Size of Text fit content
bool mRecalculateNaturalSize : 1; ///< Whether the natural size needs to be recalculated.
bool mMarkupProcessorEnabled : 1; ///< Whether the mark-up procesor is enabled.
{
namespace Text
{
-
Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask, bool restoreLinesAndGlyphPositions)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->CalculateLayoutSizeOnRequiredControllerSize\n");
// The number of lines and glyph-positions inside visualModel have been changed by calling DoRelayout with requestedControllerSize.
// Store the mLines and mGlyphPositions from visualModel so that they can be restored later on with no modifications made on them.
//TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel, and then blah, blah, etc.
- Vector<LineRun> linesBackup = visualModel->mLines;
+ Vector<LineRun> linesBackup = visualModel->mLines;
Vector<Vector2> glyphPositionsBackup = visualModel->mGlyphPositions;
// Operations that can be done only once until the text changes.
const Size actualControlSize = visualModel->mControlSize;
DoRelayout(controller,
- requestedControllerSize,
- static_cast<OperationsMask>(onlyOnceOperations |
- requestedOperationsMask),
- calculatedLayoutSize);
-
+ requestedControllerSize,
+ static_cast<OperationsMask>(onlyOnceOperations |
+ requestedOperationsMask),
+ calculatedLayoutSize);
// Clear the update info. This info will be set the next time the text is updated.
textUpdateInfo.Clear();
// Restore the previously backed-up mLines and mGlyphPositions from visualModel.
if(restoreLinesAndGlyphPositions)
{
- visualModel->mLines = linesBackup;
+ visualModel->mLines = linesBackup;
visualModel->mGlyphPositions = glyphPositionsBackup;
}
return calculatedLayoutSize;
}
-
Vector3 Controller::Relayouter::GetNaturalSize(Controller& controller)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
// Make sure the model is up-to-date before layouting
controller.ProcessModifyEvents();
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- VisualModelPtr& visualModel = model->mVisualModel;
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
if(impl.mRecalculateNaturalSize)
{
Size naturalSize;
// Layout the text for the new width.
- OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT | REORDER);
- Size sizeMaxWidthAndMaxHeight = Size(MAX_FLOAT, MAX_FLOAT);
+ OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT | REORDER);
+ Size sizeMaxWidthAndMaxHeight = Size(MAX_FLOAT, MAX_FLOAT);
naturalSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeMaxWidthAndMaxHeight, requestedOperationsMask, true);
textUpdateInfo.mFullRelayoutNeeded ||
textUpdateInfo.mClearAll)
{
-
// Layout the text for the new width.
- OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT);
- Size sizeRequestedWidthAndMaxHeight = Size(width, MAX_FLOAT);
+ OperationsMask requestedOperationsMask = static_cast<OperationsMask>(LAYOUT);
+ Size sizeRequestedWidthAndMaxHeight = Size(width, MAX_FLOAT);
// Skip restore, because if GetHeightForWidth called before rendering and layouting then visualModel->mControlSize will be zero which will make LineCount zero.
// The implementation of Get LineCount property depends on calling GetHeightForWidth then read mLines.Count() from visualModel direct.
// So we will not restore the previously backed-up mLines and mGlyphPositions from visualModel in such case.
// Another case to skip restore is when the requested width equals the Control's width which means the caller need to update the old values.
// For example, when the text is changed.
- bool restoreLinesAndGlyphPositions = (visualModel->mControlSize.width>0 && visualModel->mControlSize.height>0)
- && (visualModel->mControlSize.width != width);
+ bool restoreLinesAndGlyphPositions = (visualModel->mControlSize.width > 0 && visualModel->mControlSize.height > 0) && (visualModel->mControlSize.width != width);
layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask, restoreLinesAndGlyphPositions);
void Controller::Relayouter::CalculateVerticalOffset(Controller& controller, const Size& controlSize)
{
- Controller::Impl& impl = *controller.mImpl;
- ModelPtr& model = impl.mModel;
- VisualModelPtr& visualModel = model->mVisualModel;
- Size layoutSize = model->mVisualModel->GetLayoutSize();
- Size oldLayoutSize = layoutSize;
- float offsetY = 0.f;
- bool needRecalc = false;
+ Controller::Impl& impl = *controller.mImpl;
+ ModelPtr& model = impl.mModel;
+ VisualModelPtr& visualModel = model->mVisualModel;
+ Size layoutSize = model->mVisualModel->GetLayoutSize();
+ Size oldLayoutSize = layoutSize;
+ float offsetY = 0.f;
+ bool needRecalc = false;
float defaultFontLineHeight = impl.GetDefaultFontLineHeight();
if(fabsf(layoutSize.height) < Math::MACHINE_EPSILON_1000)
// Whether the text control is editable
const bool isEditable = NULL != impl.mEventData;
- if (isEditable && layoutSize.height != defaultFontLineHeight)
+ if(isEditable && layoutSize.height != defaultFontLineHeight && impl.IsShowingPlaceholderText())
{
// This code prevents the wrong positioning of cursor when the layout size is bigger/smaller than defaultFontLineHeight.
// This situation occurs when the size of placeholder text is different from the default text.
layoutSize.height = defaultFontLineHeight;
- needRecalc = true;
+ needRecalc = true;
}
switch(model->mVerticalAlignment)
case VerticalAlignment::TOP:
{
model->mScrollPosition.y = 0.f;
- offsetY = 0.f;
+ offsetY = 0.f;
break;
}
case VerticalAlignment::CENTER:
{
model->mScrollPosition.y = floorf(0.5f * (controlSize.height - layoutSize.height)); // try to avoid pixel alignment.
- if (needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
+ if(needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
break;
}
case VerticalAlignment::BOTTOM:
{
model->mScrollPosition.y = controlSize.height - layoutSize.height;
- if (needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
+ if(needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
break;
}
}
- if (needRecalc)
+ if(needRecalc)
{
// Update glyphPositions according to recalculation.
- const Length positionCount = visualModel->mGlyphPositions.Count();
+ const Length positionCount = visualModel->mGlyphPositions.Count();
Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
for(Length index = 0u; index < positionCount; index++)
{
glyphPositions[index].y += offsetY;
}
}
-
}
} // namespace Text
}
}
+void Controller::SetInputFilterOption(const Property::Map& options)
+{
+ if(!mImpl->mInputFilter)
+ {
+ mImpl->mInputFilter = std::unique_ptr<InputFilter>(new InputFilter());
+ }
+ mImpl->mInputFilter->SetProperties(options);
+}
+
+void Controller::GetInputFilterOption(Property::Map& options)
+{
+ if(NULL != mImpl->mInputFilter)
+ {
+ mImpl->mInputFilter->GetProperties(options);
+ }
+}
+
void Controller::SetPlaceholderProperty(const Property::Map& map)
{
PlaceholderHandler::SetPlaceholderProperty(*this, map);
#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
#include <dali-toolkit/internal/text/decorator/text-decorator.h>
#include <dali-toolkit/internal/text/hidden-text.h>
+#include <dali-toolkit/internal/text/input-filter.h>
#include <dali-toolkit/internal/text/layouts/layout-engine.h>
#include <dali-toolkit/internal/text/text-anchor-control-interface.h>
#include <dali-toolkit/internal/text/text-model-interface.h>
void GetHiddenInputOption(Property::Map& options);
/**
+ * @brief Used to set the input filter option
+ */
+ void SetInputFilterOption(const Property::Map& options);
+
+ /**
+ * @brief Used to get the input filter option
+ */
+ void GetInputFilterOption(Property::Map& options);
+
+ /**
* @brief Sets the Placeholder Properties.
*
* @param[in] map The placeholder property map
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/input-style.h>
+#include <dali-toolkit/public-api/controls/text-controls/input-filter-properties.h>
namespace Dali
{
virtual void InputStyleChanged(InputStyle::Mask inputStyleMask) = 0;
/**
+ * @brief Called when the character to be inserted is filtered by the input filter.
+ *
+ * @param[in] type The filter type is ACCEPTED or REJECTED.
+ */
+ virtual void InputFiltered(Toolkit::InputFilter::Property::Type type) = 0;
+
+ /**
* @brief Add a decoration.
*
* @param[in] decoration The actor displaying a decoration.
Property::Map startPropertyMap;
Property::Map finishPropertyMap;
+ float targetOpacity = GetWorldColor(targetControl).a;
+ targetControl[Dali::Actor::Property::COLOR_MODE] = Dali::ColorMode::USE_OWN_COLOR;
+
if(IsAppearingTransition())
{
initialPropertyMap.Insert(Dali::Actor::Property::OPACITY, 0.0f);
- startPropertyMap.Insert(Dali::Actor::Property::OPACITY, mOpacity);
- finishPropertyMap.Insert(Dali::Actor::Property::OPACITY, targetControl[Dali::Actor::Property::OPACITY]);
+ startPropertyMap.Insert(Dali::Actor::Property::OPACITY, mOpacity * targetOpacity);
+ finishPropertyMap.Insert(Dali::Actor::Property::OPACITY, targetOpacity);
}
else
{
- initialPropertyMap.Insert(Dali::Actor::Property::OPACITY, targetControl[Dali::Actor::Property::OPACITY]);
- startPropertyMap.Insert(Dali::Actor::Property::OPACITY, targetControl[Dali::Actor::Property::OPACITY]);
- finishPropertyMap.Insert(Dali::Actor::Property::OPACITY, mOpacity);
+ initialPropertyMap.Insert(Dali::Actor::Property::OPACITY, targetOpacity);
+ startPropertyMap.Insert(Dali::Actor::Property::OPACITY, targetOpacity);
+ finishPropertyMap.Insert(Dali::Actor::Property::OPACITY, mOpacity * targetOpacity);
}
SetInitialPropertyMap(initialPropertyMap);
{
namespace Internal
{
+std::unique_ptr<TransitionLifecycleController> TransitionLifecycleController::mInstance = nullptr;
+std::once_flag TransitionLifecycleController::mOnceFlag;
+
+TransitionLifecycleController& TransitionLifecycleController::GetInstance()
+{
+ std::call_once(mOnceFlag, []()
+ { mInstance.reset(new TransitionLifecycleController); });
+ return *(mInstance.get());
+}
+
void TransitionLifecycleController::AddTransitions(Dali::Toolkit::TransitionSet transitions)
{
mTransitionList.push_back(transitions);
transitions.FinishedSignal().Connect(this, &TransitionLifecycleController::RemoveTransitions);
}
-void TransitionLifecycleController::RemoveTransitions(Dali::Toolkit::TransitionSet &transitions)
+void TransitionLifecycleController::RemoveTransitions(Dali::Toolkit::TransitionSet& transitions)
{
mTransitionList.erase(std::remove(mTransitionList.begin(), mTransitionList.end(), transitions));
}
{
namespace Internal
{
-class TransitionLifecycleController;
-
-namespace
-{
-std::unique_ptr<TransitionLifecycleController> instance = nullptr;
-std::once_flag onceFlag;
-} // namespace
class TransitionLifecycleController : public ConnectionTracker
{
public:
- static TransitionLifecycleController& GetInstance()
- {
- std::call_once(onceFlag, []() {
- instance.reset(new TransitionLifecycleController);
- });
- return *(instance.get());
- }
+ static TransitionLifecycleController& GetInstance();
void AddTransitions(Dali::Toolkit::TransitionSet transitions);
TransitionLifecycleController& operator=(const TransitionLifecycleController& rhs) = delete;
private:
- std::vector<Dali::Toolkit::TransitionSet> mTransitionList;
+ std::vector<Dali::Toolkit::TransitionSet> mTransitionList;
+ static std::unique_ptr<TransitionLifecycleController> mInstance;
+ static std::once_flag mOnceFlag;
};
} // namespace Internal
break;
}
case VisualUrl::JSON:
- case VisualUrl::RIVE:
{
visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
break;
break;
}
case VisualUrl::JSON:
- case VisualUrl::RIVE:
{
visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl);
break;
char GIF[4] = {'f', 'i', 'g', '.'};
char WEBP[5] = {'p', 'b', 'e', 'w', '.'};
char JSON[5] = {'n', 'o', 's', 'j', '.'};
- char RIVE[4] = {'v', 'i', 'r', '.'};
unsigned int svgScore = 0;
unsigned int gifScore = 0;
unsigned int webpScore = 0;
unsigned int jsonScore = 0;
- unsigned int riveScore = 0;
int index = count;
while(--index >= 0)
{
return VisualUrl::JSON;
}
}
- if((offsetFromEnd < sizeof(RIVE)) && (currentChar == RIVE[offsetFromEnd]))
- {
- // early out if RIVE as can't be used in N patch for now
- if(++riveScore == sizeof(RIVE))
- {
- return VisualUrl::RIVE;
- }
- }
switch(state)
{
case SUFFIX:
SVG,
GIF,
WEBP,
- JSON,
- RIVE
+ JSON
};
enum ProtocolType
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "الحافظة"
+msgid "slider"
+msgstr ""
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Mübadilə buferi"
+msgid "icon"
+msgstr "Piktoqram"
+
+msgid "slider"
+msgstr "Sürüngəc"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Системен буфер"
+msgid "icon"
+msgstr "Икона"
+
+msgid "slider"
+msgstr "Плъзгач"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "ক্লিপবোর্ড"
+msgid "icon"
+msgstr "Icon"
+
+msgid "slider"
+msgstr "স্লাইডার"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Porta-retalls"
+msgid "slider"
+msgstr "control lliscant"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Schránka"
+msgid "slider"
+msgstr "šoupátko"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Udklipsholder"
+msgid "icon"
+msgstr "Ikon"
+
+msgid "slider"
+msgstr "skyder"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Zwischenablage"
+msgid "slider"
+msgstr ""
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Πρόχειρο"
+msgid "icon"
+msgstr "Εικονίδιο"
+
+msgid "slider"
+msgstr "Ρυθμιστικό"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Clipboard"
+msgid "icon"
+msgstr "Icon"
+
+msgid "slider"
+msgstr "Slider"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Clipboard"
+msgid "icon"
+msgstr "Icon"
+
+msgid "slider"
+msgstr "Slider"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Portapapeles"
+msgid "icon"
+msgstr "Icono"
+
+msgid "slider"
+msgstr "Controlador deslizante"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Portapapeles"
+msgid "icon"
+msgstr "Icono"
+
+msgid "slider"
+msgstr "Controlador deslizante"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Lõikelaud"
+msgid "icon"
+msgstr "Ikoon"
+
+msgid "slider"
+msgstr "Liugur"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Arbela"
+msgid "icon"
+msgstr "Ikonoa"
+
+msgid "slider"
+msgstr "Irristagailua"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "کلیپ بورد"
+msgid "slider"
+msgstr ""
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Leikepöytä"
+msgid "slider"
+msgstr "liukusäädin"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Presse-papier"
+msgid "slider"
+msgstr "curseur"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Presse-papier"
+msgid "icon"
+msgstr "Icône"
+
+msgid "slider"
+msgstr "Curseur"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Portapapeis"
+msgid "slider"
+msgstr "Barra de desprazamento"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Međuspremnik"
+msgid "icon"
+msgstr "Ikona"
+
+msgid "slider"
+msgstr "Klizač"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Vágólap"
+msgid "slider"
+msgstr "csúszka"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Գզրոց"
+msgid "icon"
+msgstr "Պատկերակ"
+
+msgid "slider"
+msgstr "Սողանիկ"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Klippiborð"
+msgid "icon"
+msgstr "Tákn"
+
+msgid "slider"
+msgstr "Skyggna"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Appunti"
+msgid "icon"
+msgstr "Icona"
+
+msgid "slider"
+msgstr "Dispositivo di scorrimento"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "ბუფერული მეხს."
+msgid "icon"
+msgstr "ნიშანი"
+
+msgid "slider"
+msgstr "სლაიდერი"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Буфер"
+msgid "icon"
+msgstr "Белгіше"
+
+msgid "slider"
+msgstr "Сырғытпа"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "클립보드"
+msgid "slider"
+msgstr "슬라이더"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Iškarpinė"
+msgid "slider"
+msgstr "šliaužiklis"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Starpliktuve"
+msgid "icon"
+msgstr "Ikona"
+
+msgid "slider"
+msgstr "Slīdnis"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Түр санах ой"
+msgid "icon"
+msgstr "Дүрс"
+
+msgid "slider"
+msgstr "Slider"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Utklippstavle"
+msgid "icon"
+msgstr "Ikon"
+
+msgid "slider"
+msgstr "Glidebryter"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Klembord"
+msgid "slider"
+msgstr ""
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Schowek"
+msgid "slider"
+msgstr "slajder"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Área de transferência"
+msgid "icon"
+msgstr "Ícone"
+
+msgid "slider"
+msgstr "Controle deslizante"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Área transferência"
+msgid "icon"
+msgstr "Ícone"
+
+msgid "slider"
+msgstr "Cursor de deslocamento"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Clipboard"
+msgid "icon"
+msgstr "Pictogr."
+
+msgid "slider"
+msgstr "Cursor"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Буфер обмена"
+msgid "icon"
+msgstr "Значок"
+
+msgid "slider"
+msgstr "Ползунок"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Schránka"
+msgid "icon"
+msgstr "Ikona"
+
+msgid "slider"
+msgstr "Posuvný ovládač"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Odložišče"
+msgid "slider"
+msgstr "drsnik"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Privremena memorija"
+msgid "slider"
+msgstr "клизач"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Urklipp"
+msgid "icon"
+msgstr "Ikon"
+
+msgid "slider"
+msgstr "Slider"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Pano"
+msgid "icon"
+msgstr "Simge"
+
+msgid "slider"
+msgstr "Kaydırıcı"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Буфер обміну"
+msgid "icon"
+msgstr "Значок"
+
+msgid "slider"
+msgstr "Слайдер"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "کلپ بورڈ"
+msgid "slider"
+msgstr ""
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Bufer"
+msgid "icon"
+msgstr "Ikoncha"
+
+msgid "slider"
+msgstr "Slider"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "Bộ nhớ tạm"
+msgid "slider"
+msgstr "Thanh Trượt"
msgid "IDS_COM_BODY_CLIPBOARD"
msgstr "剪贴板"
+msgid "slider"
+msgstr "滑块"
--- /dev/null
+#ifndef DALI_INPUT_FILTER_PROPERTIES_H
+#define DALI_INPUT_FILTER_PROPERTIES_H
+
+/*
+ * Copyright (c) 2021 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+namespace InputFilter
+{
+/**
+ * @brief InputFilter Property.
+ * @SINCE_2_0.33
+ */
+namespace Property
+{
+/**
+ * @brief Enumeration for the type of InputFilter.
+ *
+ * An enum that determines the input filter type of the InputFilter map.
+ * Users can set the ACCEPTED or REJECTED character set, or both.
+ * If both are used, REJECTED has higher priority.
+ * The character set must follow the regular expression rules.
+ * Behaviour can not be guaranteed for incorrect grammars.
+ *
+ * Useful Meta characters:
+ *
+ * | %Meta characters | Description
+ * |-------------------|------------------------------------------------------------------------------------------------------------|
+ * | \\w | Matches an alphanumeric character, including "_"; same as [A-Za-z0-9_]. |
+ * | \\W | Matches a non-alphanumeric character, excluding "_"; same as [^A-Za-z0-9_]. |
+ * | \\s | Matches a whitespace character, which in ASCII are tab, line feed, form feed, carriage return, and space. |
+ * | \\S | Matches anything but a whitespace. |
+ * | \\d | Matches a digit; same as [0-9]. |
+ * | \\D | Matches a non-digit; same as [^0-9]. |
+ *
+ * Example Usage:
+ * @code
+ * Property::Map filter;
+ * filter[InputFilter::Property::ACCEPTED] = "[\\d]"; // accept whole digits
+ * filter[InputFilter::Property::REJECTED] = "[0-5]"; // reject 0, 1, 2, 3, 4, 5
+ *
+ * field.SetProperty(DevelTextField::Property::INPUT_FILTER, filter); // acceptable inputs are 6, 7, 8, 9
+ * @endcode
+ * @SINCE_2_0.33
+ */
+enum Type
+{
+ /**
+ * @brief The set of characters to be accepted.
+ * @details Name "accepted", type Property::STRING.
+ * @SINCE_2_0.33
+ * @note Available on regex string.
+ */
+ ACCEPTED,
+
+ /**
+ * @brief The set of characters to be rejected.
+ * @details Name "rejected", type Property::STRING.
+ * @SINCE_2_0.33
+ * @note Available on regex string.
+ */
+ REJECTED
+};
+
+} // namespace Property
+
+} // namespace InputFilter
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_INPUT_FILTER_PROPERTIES_H
{
const unsigned int TOOLKIT_MAJOR_VERSION = 2;
const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 32;
+const unsigned int TOOLKIT_MICRO_VERSION = 33;
const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
SET( public_api_text_controls_header_files
${public_api_src_dir}/controls/text-controls/hidden-input-properties.h
+ ${public_api_src_dir}/controls/text-controls/input-filter-properties.h
${public_api_src_dir}/controls/text-controls/placeholder-properties.h
${public_api_src_dir}/controls/text-controls/text-editor.h
${public_api_src_dir}/controls/text-controls/text-label.h
Name: dali2-toolkit
Summary: Dali 3D engine Toolkit
-Version: 2.0.32
+Version: 2.0.33
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT