From: Victor Cebollada Date: Mon, 11 Jan 2016 09:00:21 +0000 (+0000) Subject: Multiline - Create a text-editor control. X-Git-Tag: dali_1.1.18~13 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=07f42751dbdbf750111752a824ec989fc25f64fe Multiline - Create a text-editor control. Change-Id: If2d26ec599b30fcb121d0ff720f67fc9f6b0263b Signed-off-by: Victor Cebollada --- diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 5951546..e338ad4 100644 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ SET(TC_SOURCES utc-Dali-ShadowView.cpp utc-Dali-Slider.cpp utc-Dali-TableView.cpp + utc-Dali-TextEditor.cpp utc-Dali-TextField.cpp utc-Dali-TextLabel.cpp utc-Dali-TextSelectionPopup.cpp diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp new file mode 100644 index 0000000..fc49de9 --- /dev/null +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2016 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include ///< @todo to be removed when text-editor is added to the dali-toolkit.h +#include + +using namespace Dali; +using namespace Toolkit; + +void dali_texteditor_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void dali_texteditor_cleanup(void) +{ + test_return_value = TET_PASS; +} + +namespace +{ + +const char* const PROPERTY_NAME_RENDERING_BACKEND = "renderingBackend"; +const char* const PROPERTY_NAME_TEXT = "text"; +const char* const PROPERTY_NAME_TEXT_COLOR = "textColor"; +const char* const PROPERTY_NAME_FONT_FAMILY = "fontFamily"; +const char* const PROPERTY_NAME_FONT_STYLE = "fontStyle"; +const char* const PROPERTY_NAME_POINT_SIZE = "pointSize"; +const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT = "horizontalAlignment"; +const char* const PROPERTY_NAME_SCROLL_THRESHOLD = "scrollThreshold"; +const char* const PROPERTY_NAME_SCROLL_SPEED = "scrollSpeed"; +const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR = "primaryCursorColor"; +const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR = "secondaryCursorColor"; +const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK = "enableCursorBlink"; +const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL = "cursorBlinkInterval"; +const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION = "cursorBlinkDuration"; +const char* const PROPERTY_NAME_CURSOR_WIDTH = "cursorWidth"; +const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE = "grabHandleImage"; +const char* const PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE = "grabHandlePressedImage"; +const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT = "selectionHandleImageLeft"; +const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT = "selectionHandleImageRight"; +const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT = "selectionHandlePressedImageLeft"; +const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT = "selectionHandlePressedImageRight"; +const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_LEFT = "selectionHandleMarkerImageLeft"; +const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_RIGHT = "selectionHandleMarkerImageRight"; +const char* const PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR = "selectionHighlightColor"; +const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX = "decorationBoundingBox"; +const char* const PROPERTY_NAME_ENABLE_MARKUP = "enableMarkup"; +const char* const PROPERTY_NAME_INPUT_COLOR = "inputColor"; +const char* const PROPERTY_NAME_INPUT_FONT_FAMILY = "inputFontFamily"; +const char* const PROPERTY_NAME_INPUT_FONT_STYLE = "inputFontStyle"; +const char* const PROPERTY_NAME_INPUT_POINT_SIZE = "inputPointSize"; + +const int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND; + +const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color. + +const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval +const float TO_MILLISECONDS = 1000.f; +const float TO_SECONDS = 1.f / TO_MILLISECONDS; + +const float SCROLL_THRESHOLD = 10.f; +const float SCROLL_SPEED = 300.f; + +static bool gTextChangedCallBackCalled; + +static void TestTextChangedCallback( TextEditor control ) +{ + tet_infoline(" TestTextChangedCallback"); + + gTextChangedCallBackCalled = true; +} + +// Generate a TapGestureEvent to send to Core. +Integration::TapGestureEvent GenerateTap( + Gesture::State state, + unsigned int numberOfTaps, + unsigned int numberOfTouches, + Vector2 point) +{ + Integration::TapGestureEvent tap( state ); + + tap.numberOfTaps = numberOfTaps; + tap.numberOfTouches = numberOfTouches; + tap.point = point; + + return tap; +} + +// Generate a KeyEvent to send to Core. +Integration::KeyEvent GenerateKey( const std::string& keyName, + const std::string& keyString, + int keyCode, + int keyModifier, + unsigned long timeStamp, + const Integration::KeyEvent::State& keyState ) +{ + return Integration::KeyEvent( keyName, + keyString, + keyCode, + keyModifier, + timeStamp, + keyState ); +} + +} // namespace + +int UtcDaliToolkitTextEditorConstructorP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorConstructorP"); + TextEditor textEditor; + DALI_TEST_CHECK( !textEditor ); + END_TEST; +} + +int UtcDaliToolkitTextEditorNewP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorNewP"); + TextEditor textEditor = TextEditor::New(); + DALI_TEST_CHECK( textEditor ); + END_TEST; +} + +int UtcDaliToolkitTextEditorDownCastP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorDownCastP"); + TextEditor textEditor1 = TextEditor::New(); + BaseHandle object( textEditor1 ); + + TextEditor textEditor2 = TextEditor::DownCast( object ); + DALI_TEST_CHECK( textEditor2 ); + + TextEditor textEditor3 = DownCast< TextEditor >( object ); + DALI_TEST_CHECK( textEditor3 ); + END_TEST; +} + +int UtcDaliToolkitTextEditorDownCastN(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorDownCastN"); + BaseHandle uninitializedObject; + TextEditor textEditor1 = TextEditor::DownCast( uninitializedObject ); + DALI_TEST_CHECK( !textEditor1 ); + + TextEditor textEditor2 = DownCast< TextEditor >( uninitializedObject ); + DALI_TEST_CHECK( !textEditor2 ); + END_TEST; +} + +int UtcDaliToolkitTextEditorCopyConstructorP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorCopyConstructorP"); + TextEditor textEditor = TextEditor::New(); + textEditor.SetProperty( TextEditor::Property::TEXT, "Test" ); + + TextEditor copy( textEditor ); + DALI_TEST_CHECK( copy ); + DALI_TEST_CHECK( copy.GetProperty( TextLabel::Property::TEXT ) == textEditor.GetProperty( TextLabel::Property::TEXT ) ); + END_TEST; +} + +int UtcDaliToolkitTextEditorAssignmentOperatorP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorAssignmentOperatorP"); + TextEditor textEditor = TextEditor::New(); + textEditor.SetProperty( TextEditor::Property::TEXT, "Test" ); + + TextEditor copy = textEditor; + DALI_TEST_CHECK( copy ); + DALI_TEST_CHECK( copy.GetProperty( TextEditor::Property::TEXT ) == textEditor.GetProperty( TextEditor::Property::TEXT ) ); + END_TEST; +} + +int UtcDaliTextEditorNewP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorNewP"); + TextEditor textEditor = TextEditor::New(); + DALI_TEST_CHECK( textEditor ); + END_TEST; +} + +// Positive test case for a method +int UtcDaliTextEditorGetPropertyP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorGetPropertyP"); + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + + // Check Property Indices are correct + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_RENDERING_BACKEND ) == TextEditor::Property::RENDERING_BACKEND ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_TEXT ) == TextEditor::Property::TEXT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_TEXT_COLOR ) == TextEditor::Property::TEXT_COLOR ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_FONT_FAMILY ) == TextEditor::Property::FONT_FAMILY ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_FONT_STYLE ) == TextEditor::Property::FONT_STYLE ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_POINT_SIZE ) == TextEditor::Property::POINT_SIZE ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_HORIZONTAL_ALIGNMENT ) == TextEditor::Property::HORIZONTAL_ALIGNMENT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SCROLL_THRESHOLD ) == TextEditor::Property::SCROLL_THRESHOLD ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SCROLL_SPEED ) == TextEditor::Property::SCROLL_SPEED ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PRIMARY_CURSOR_COLOR ) == TextEditor::Property::PRIMARY_CURSOR_COLOR ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SECONDARY_CURSOR_COLOR ) == TextEditor::Property::SECONDARY_CURSOR_COLOR ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_CURSOR_BLINK ) == TextEditor::Property::ENABLE_CURSOR_BLINK ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_INTERVAL ) == TextEditor::Property::CURSOR_BLINK_INTERVAL ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_DURATION ) == TextEditor::Property::CURSOR_BLINK_DURATION ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_CURSOR_WIDTH ) == TextEditor::Property::CURSOR_WIDTH ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_IMAGE ) == TextEditor::Property::GRAB_HANDLE_IMAGE ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE ) == TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT ) == TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT ) == TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT ) == TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT ) == TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_LEFT ) == TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_RIGHT ) == TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR ) == TextEditor::Property::SELECTION_HIGHLIGHT_COLOR ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_DECORATION_BOUNDING_BOX ) == TextEditor::Property::DECORATION_BOUNDING_BOX ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_MARKUP ) == TextEditor::Property::ENABLE_MARKUP ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_COLOR ) == TextEditor::Property::INPUT_COLOR ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_FONT_FAMILY ) == TextEditor::Property::INPUT_FONT_FAMILY ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_FONT_STYLE ) == TextEditor::Property::INPUT_FONT_STYLE ); + DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_POINT_SIZE ) == TextEditor::Property::INPUT_POINT_SIZE ); + END_TEST; +} + +bool SetPropertyMapRetrieved( TextEditor& editor, const Property::Index property, const std::string mapKey, const std::string mapValue ) +{ + bool result = false; + Property::Map imageMap; + imageMap[mapKey] =mapValue; + + editor.SetProperty( property , imageMap ); + Property::Value propValue = editor.GetProperty( property ); + Property::Map* resultMap = propValue.GetMap(); + + if ( resultMap->Find( mapKey )->Get< std::string>() == mapValue ) + { + result = true; + } + + return result; +} + +// Positive test case for a method +int UtcDaliTextEditorSetPropertyP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorSetPropertyP"); + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + Stage::GetCurrent().Add( editor ); + + // Note - we can't check the defaults since the stylesheets are platform-specific + + // Check the render backend property. + editor.SetProperty( TextEditor::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS ); + DALI_TEST_EQUALS( (Text::RenderingType)editor.GetProperty( TextEditor::Property::RENDERING_BACKEND ), Text::RENDERING_SHARED_ATLAS, TEST_LOCATION ); + + // Check text property. + editor.SetProperty( TextEditor::Property::TEXT, "Setting Text" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::TEXT ), std::string("Setting Text"), TEST_LOCATION ); + + // Check text's color property + editor.SetProperty( TextEditor::Property::TEXT_COLOR, Color::WHITE ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::TEXT_COLOR ), Color::WHITE, TEST_LOCATION ); + + // Check font properties. + editor.SetProperty( TextEditor::Property::FONT_FAMILY, "Setting font family" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::FONT_FAMILY ), std::string("Setting font family"), TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::FONT_STYLE, "Setting font style" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::FONT_STYLE ), std::string("Setting font style"), TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::POINT_SIZE ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + + // Check that the Alignment properties can be correctly set + editor.SetProperty( TextEditor::Property::HORIZONTAL_ALIGNMENT, "END" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::HORIZONTAL_ALIGNMENT ), "END", TEST_LOCATION ); + + // Check scroll properties. + editor.SetProperty( TextEditor::Property::SCROLL_THRESHOLD, 1.f ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::SCROLL_THRESHOLD ), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::SCROLL_SPEED, 100.f ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::SCROLL_SPEED ), 100.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + + // Check cursor properties + editor.SetProperty( TextEditor::Property::PRIMARY_CURSOR_COLOR, Color::RED ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::PRIMARY_CURSOR_COLOR ), Color::RED, TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::SECONDARY_CURSOR_COLOR, Color::BLUE ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::SECONDARY_CURSOR_COLOR ), Color::BLUE, TEST_LOCATION ); + + editor.SetProperty( TextEditor::Property::ENABLE_CURSOR_BLINK, false ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::ENABLE_CURSOR_BLINK ), false, TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::CURSOR_BLINK_INTERVAL, 1.f ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::CURSOR_BLINK_INTERVAL ), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::CURSOR_BLINK_DURATION, 10.f ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::CURSOR_BLINK_DURATION ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::CURSOR_WIDTH, 1 ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::CURSOR_WIDTH ), 1, TEST_LOCATION ); + + // Check handle images + editor.SetProperty( TextEditor::Property::GRAB_HANDLE_IMAGE, "image1" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::GRAB_HANDLE_IMAGE ), "image1", TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE, "image2" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE ), "image2", TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT, "image3" ); + + // Check handle images + DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT, "filename", "leftHandleImage" ) ); + DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT, "filename", "rightHandleImage" ) ); + DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT, "filename", "leftHandleImagePressed" ) ); + DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, "filename", "rightHandleImagePressed" ) ); + DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT, "filename", "leftHandleMarkerImage" ) ); + DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT, "filename", "rightHandleMarkerImage" ) ); + + // Check the highlight color + editor.SetProperty( TextEditor::Property::SELECTION_HIGHLIGHT_COLOR, Color::GREEN ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::SELECTION_HIGHLIGHT_COLOR ), Color::GREEN, TEST_LOCATION ); + + // Decoration bounding box + editor.SetProperty( TextEditor::Property::DECORATION_BOUNDING_BOX, Rect( 0, 0, 1, 1 ) ); + DALI_TEST_EQUALS( editor.GetProperty >( TextEditor::Property::DECORATION_BOUNDING_BOX ), Rect( 0, 0, 1, 1 ), TEST_LOCATION ); + + // Check the enable markup property. + DALI_TEST_CHECK( !editor.GetProperty( TextEditor::Property::ENABLE_MARKUP ) ); + editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true ); + DALI_TEST_CHECK( editor.GetProperty( TextEditor::Property::ENABLE_MARKUP ) ); + + // Check input color property. + editor.SetProperty( TextEditor::Property::INPUT_COLOR, Color::YELLOW ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::INPUT_COLOR ), Color::YELLOW, TEST_LOCATION ); + + // Check input font properties. + editor.SetProperty( TextEditor::Property::INPUT_FONT_FAMILY, "Setting input font family" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::INPUT_FONT_FAMILY ), "Setting input font family", TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, "Setting input font style" ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::INPUT_FONT_STYLE ), "Setting input font style", TEST_LOCATION ); + editor.SetProperty( TextEditor::Property::INPUT_POINT_SIZE, 12.f ); + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::INPUT_POINT_SIZE ), 12.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + + END_TEST; +} + +// Positive Atlas Text Renderer test +int utcDaliTextEditorAtlasRenderP(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextEditorAtlasRenderP"); + StyleManager styleManager = StyleManager::Get(); + styleManager.RequestDefaultTheme(); + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + + editor.SetProperty( TextEditor::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); + + application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE ); + + Stage::GetCurrent().Add( editor ); + + try + { + // Render some text with the shared atlas backend + editor.SetProperty( TextEditor::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS ); + application.SendNotification(); + application.Render(); + } + catch( ... ) + { + tet_result(TET_FAIL); + } + END_TEST; +} + +// Positive test for the textChanged signal. +int utcDaliTextEditorTextChangedP(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextEditorTextChangedP"); + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + + Stage::GetCurrent().Add( editor ); + + editor.TextChangedSignal().Connect(&TestTextChangedCallback); + + gTextChangedCallBackCalled = false; + editor.SetProperty( TextEditor::Property::TEXT, "ABC" ); + DALI_TEST_CHECK( gTextChangedCallBackCalled ); + + application.SendNotification(); + + editor.SetKeyInputFocus(); + + gTextChangedCallBackCalled = false; + application.ProcessEvent( GenerateKey( "D", "D", 0, 0, 0, Integration::KeyEvent::Down ) ); + DALI_TEST_CHECK( gTextChangedCallBackCalled ); + + END_TEST; +} + +int utcDaliTextEditorEvent01(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextEditorEvent01"); + + // Creates a tap event. After creating a tap event the text editor should + // have the focus and add text with key events should be possible. + + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + + Stage::GetCurrent().Add( editor ); + + editor.SetSize( 300.f, 50.f ); + editor.SetParentOrigin( ParentOrigin::TOP_LEFT ); + editor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + // Avoid a crash when core load gl resources. + application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Add a key event but as the text editor has not the focus it should do nothing. + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::TEXT ), std::string(""), TEST_LOCATION ); + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 25.0f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 25.0f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Now the text editor has the focus, so it can handle the key events. + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( editor.GetProperty( TextEditor::Property::TEXT ), std::string("aa"), TEST_LOCATION ); + + // Create a second text editor and send key events to it. + TextEditor editor2 = TextEditor::New(); + + editor2.SetParentOrigin( ParentOrigin::TOP_LEFT ); + editor2.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + editor2.SetSize( 100.f, 100.f ); + editor2.SetPosition( 100.f, 100.f ); + + Stage::GetCurrent().Add( editor2 ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Create a tap event on the second text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 125.0f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 125.0f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // The second text editor has the focus. It should handle the key events. + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Check the text has been added to the second text editor. + DALI_TEST_EQUALS( editor2.GetProperty( TextEditor::Property::TEXT ), std::string("aa"), TEST_LOCATION ); + + END_TEST; +} + +int utcDaliTextEditorEvent02(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextEditorEvent02"); + + // Checks if the right number of actors are created. + + TextEditor editor = TextEditor::New(); + editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f ); + DALI_TEST_CHECK( editor ); + + Stage::GetCurrent().Add( editor ); + + editor.SetSize( 300.f, 50.f ); + editor.SetParentOrigin( ParentOrigin::TOP_LEFT ); + editor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + // Avoid a crash when core load gl resources. + application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Check there are the expected number of children ( active layer, offscreen root actor, and the offscreen image actor + DALI_TEST_EQUALS( editor.GetChildCount(), 3u, TEST_LOCATION ); + + Actor layer = editor.GetChildAt( 0u ); + DALI_TEST_CHECK( layer.IsLayer() ); + + Actor offscreenRoot = editor.GetChildAt( 1u ); + DALI_TEST_CHECK( offscreenRoot.IsLayer() ); + DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor. + + Actor offscreenImage = editor.GetChildAt( 2u ); + ImageActor imageActor = ImageActor::DownCast( offscreenImage ); + DALI_TEST_CHECK( imageActor ); + + // Create a tap event to touch the text editor. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 25.0f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 25.0f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor. + DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor. + + // Now the text editor has the focus, so it can handle the key events. + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Checks the cursor and the renderer have been created. + DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor. + DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 2u, TEST_LOCATION ); // The camera actor and the renderer + + Control cursor = Control::DownCast( layer.GetChildAt( 0u ) ); + DALI_TEST_CHECK( cursor ); + + CameraActor camera = CameraActor::DownCast( offscreenRoot.GetChildAt( 0u ) ); + DALI_TEST_CHECK( camera ); + + Renderer renderer = offscreenRoot.GetChildAt( 1u ).GetRendererAt( 0u ); + DALI_TEST_CHECK( renderer ); + + // Move the cursor and check the position changes. + Vector3 position1 = cursor.GetCurrentPosition(); + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down ) ); + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + Vector3 position2 = cursor.GetCurrentPosition(); + + DALI_TEST_CHECK( position2.x < position1.x ); + + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down ) ); + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + Vector3 position3 = cursor.GetCurrentPosition(); + + DALI_TEST_EQUALS( position1, position3, TEST_LOCATION ); // Should be in the same position1. + + // Send some taps and check the cursor positions. + + // Try to tap at the beginning. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 1.f, 25.0f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 1.f, 25.0f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Cursor position should be the same than position1. + Vector3 position4 = cursor.GetCurrentPosition(); + + DALI_TEST_EQUALS( position2, position4, TEST_LOCATION ); // Should be in the same position2. + + // Tap away from the start position. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 16.f, 25.0f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 16.0f, 25.0f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + Vector3 position5 = cursor.GetCurrentPosition(); + + DALI_TEST_CHECK( position5.x > position4.x ); + + // Remove all the text. + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) ); + editor.SetProperty( TextEditor::Property::TEXT, "" ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Cursor position should be the same than position2. + Vector3 position6 = cursor.GetCurrentPosition(); + + DALI_TEST_EQUALS( position2, position6, TEST_LOCATION );// Should be in the same position2. + + // Should not be a renderer. + DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor only. + + END_TEST; +} + +int utcDaliTextEditorEvent03(void) +{ + ToolkitTestApplication application; + tet_infoline(" utcDaliTextEditorEvent03"); + + // Checks if the highlight actor is created. + + TextEditor editor = TextEditor::New(); + DALI_TEST_CHECK( editor ); + + Stage::GetCurrent().Add( editor ); + + editor.SetProperty( TextEditor::Property::TEXT, "This is a long text for the size of the text-editor." ); + editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f ); + editor.SetSize( 30.f, 50.f ); + editor.SetParentOrigin( ParentOrigin::TOP_LEFT ); + editor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + // Avoid a crash when core load gl resources. + application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Tap first to get the focus. + application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 3.f, 25.0f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 3.f, 25.0f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // Double tap to select a word. + application.ProcessEvent( GenerateTap( Gesture::Possible, 2u, 1u, Vector2( 3.f, 25.0f ) ) ); + application.ProcessEvent( GenerateTap( Gesture::Started, 2u, 1u, Vector2( 3.f, 25.0f ) ) ); + + // Render and notify + application.SendNotification(); + application.Render(); + + // The offscreen root actor should have three actors: the camera, a renderer and the highlight actor. + Actor offscreenRoot = editor.GetChildAt( 1u ); + DALI_TEST_CHECK( offscreenRoot.IsLayer() ); + + CameraActor camera = CameraActor::DownCast( offscreenRoot.GetChildAt( 0u ) ); + DALI_TEST_CHECK( camera ); + + Renderer renderer = offscreenRoot.GetChildAt( 1u ).GetRendererAt( 0u ); + DALI_TEST_CHECK( renderer ); + + Renderer highlight = offscreenRoot.GetChildAt( 2u ).GetRendererAt( 0u ); + DALI_TEST_CHECK( highlight ); + + END_TEST; +} diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor.cpp b/dali-toolkit/devel-api/controls/text-controls/text-editor.cpp new file mode 100644 index 0000000..70dc1f4 --- /dev/null +++ b/dali-toolkit/devel-api/controls/text-controls/text-editor.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016 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 + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +TextEditor TextEditor::New() +{ + return Internal::TextEditor::New(); +} + +TextEditor::TextEditor() +{ +} + +TextEditor::TextEditor( const TextEditor& handle ) +: Control( handle ) +{ +} + +TextEditor& TextEditor::operator=( const TextEditor& handle ) +{ + if( &handle != this ) + { + Control::operator=( handle ); + } + return *this; +} + +TextEditor::~TextEditor() +{ +} + +TextEditor TextEditor::DownCast( BaseHandle handle ) +{ + return Control::DownCast( handle ); +} + +TextEditor::TextChangedSignalType& TextEditor::TextChangedSignal() +{ + return Dali::Toolkit::GetImpl( *this ).TextChangedSignal(); +} + +TextEditor::TextEditor( Internal::TextEditor& implementation ) +: Control( implementation ) +{ +} + +TextEditor::TextEditor( Dali::Internal::CustomActor* internal ) +: Control( internal ) +{ + VerifyCustomActorPointer( internal ); +} + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor.h b/dali-toolkit/devel-api/controls/text-controls/text-editor.h new file mode 100644 index 0000000..0e1f9bb --- /dev/null +++ b/dali-toolkit/devel-api/controls/text-controls/text-editor.h @@ -0,0 +1,187 @@ +#ifndef __DALI_TOOLKIT_TEXT_EDITOR_H__ +#define __DALI_TOOLKIT_TEXT_EDITOR_H__ + +/* + * Copyright (c) 2016 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. + * + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal DALI_INTERNAL +{ +class TextEditor; +} +/** + * @addtogroup dali_toolkit_controls_text_controls + * @{ + */ + +/** + * @brief A control which provides a multi-line editable text editor. + * + * * Signals + * | %Signal Name | Method | + * |----------------------|-----------------------------------------------------| + * | textChanged | @ref TextChangedSignal() | + * + */ +class DALI_IMPORT_API TextEditor : public Control +{ +public: + + /** + * @brief The start and end property ranges for this control. + */ + enum PropertyRange + { + PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000 ///< Reserve property indices + }; + + /** + * @brief An enumeration of properties belonging to the TextEditor class. + */ + struct Property + { + enum + { + RENDERING_BACKEND = PROPERTY_START_INDEX, ///< name "renderingBackend", The type or rendering e.g. bitmap-based, type INT + TEXT, ///< name "text", The text to display in UTF-8 format, type STRING + TEXT_COLOR, ///< name "textColor", The text color, type VECTOR4 + FONT_FAMILY, ///< name "fontFamily", The requested font family, type STRING + FONT_STYLE, ///< name "fontStyle", The requested font style, type STRING + POINT_SIZE, ///< name "pointSize", The size of font in points, type FLOAT + HORIZONTAL_ALIGNMENT, ///< name "horizontalAlignment", The text horizontal alignment, type STRING, values "BEGIN", "CENTER", "END" + SCROLL_THRESHOLD, ///< name "scrollThreshold" Vertical scrolling will occur if the cursor is this close to the control border, type FLOAT + SCROLL_SPEED, ///< name "scrollSpeed" The scroll speed in pixels per second, type FLOAT + PRIMARY_CURSOR_COLOR, ///< name "primaryCursorColor", The color to apply to the primary cursor, type VECTOR4 + SECONDARY_CURSOR_COLOR, ///< name "secondaryCursorColor", The color to apply to the secondary cursor, type VECTOR4 + ENABLE_CURSOR_BLINK, ///< name "enableCursorBlink", Whether the cursor should blink or not, type BOOLEAN + CURSOR_BLINK_INTERVAL, ///< name "cursorBlinkInterval", The time interval in seconds between cursor on/off states, type FLOAT + CURSOR_BLINK_DURATION, ///< name "cursorBlinkDuration", The cursor will stop blinking after this number of seconds (if non-zero), type FLOAT + CURSOR_WIDTH, ///< name "cursorWidth", The cursor width, type INTEGER + GRAB_HANDLE_IMAGE, ///< name "grabHandleImage", The image to display for the grab handle, type STRING + GRAB_HANDLE_PRESSED_IMAGE, ///< name "grabHandlePressedImage", The image to display when the grab handle is pressed, type STRING + SELECTION_HANDLE_IMAGE_LEFT, ///< name "selectionHandleImageLeft", The image to display for the left selection handle, type MAP + SELECTION_HANDLE_IMAGE_RIGHT, ///< name "selectionHandleImageRight", The image to display for the right selection handle, type MAP + SELECTION_HANDLE_PRESSED_IMAGE_LEFT, ///< name "selectionHandlePressedImageLeft", The image to display when the left selection handle is pressed, type MAP + SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, ///< name "selectionHandlePressedImageRight", The image to display when the right selection handle is pressed, type MAP + SELECTION_HANDLE_MARKER_IMAGE_LEFT, ///< name "selectionHandleMarkerImageLeft", The image to display for the left selection handle marker, type MAP + SELECTION_HANDLE_MARKER_IMAGE_RIGHT, ///< name "selectionHandleMarkerImageRight", The image to display for the right selection handle marker, type MAP + SELECTION_HIGHLIGHT_COLOR, ///< name "selectionHighlightColor", The color of the selection highlight, type VECTOR4 + DECORATION_BOUNDING_BOX, ///< name "decorationBoundingBox", The decorations (handles etc) will positioned within this area on-screen, type RECTANGLE + ENABLE_MARKUP, ///< name "enableMarkup", Whether the mark-up processing is enabled. type BOOLEAN + INPUT_COLOR, ///< name "inputColor", The color of the new input text, type VECTOR4 + INPUT_FONT_FAMILY, ///< name "inputFontFamily", The font's family of the new input text, type STRING + INPUT_FONT_STYLE, ///< name "inputFontStyle", The font's style of the new input text, type STRING + INPUT_POINT_SIZE ///< name "inputPointSize", The font's size of the new input text in points, type FLOAT + }; + }; + + // Type Defs + + /// @brief Text changed signal type. + typedef Signal TextChangedSignalType; + + /** + * @brief Create the TextEditor control. + * @return A handle to the TextEditor control. + */ + static TextEditor New(); + + /** + * @brief Creates an empty handle. + */ + TextEditor(); + + /** + * @brief Copy constructor. + * + * @param[in] handle The handle to copy from. + */ + TextEditor( const TextEditor& handle ); + + /** + * @brief Assignment operator. + * + * @param[in] handle The handle to copy from. + * @return A reference to this. + */ + TextEditor& operator=( const TextEditor& handle ); + + /** + * @brief Destructor. + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~TextEditor(); + + /** + * @brief Downcast a handle to TextEditor. + * + * If the BaseHandle points is a TextEditor the downcast returns a valid handle. + * If not the returned handle is left empty. + * + * @param[in] handle Handle to an object. + * @return handle to a TextEditor or an empty handle. + */ + static TextEditor DownCast( BaseHandle handle ); + + // Signals + + /** + * @brief This signal is emitted when the text changes. + * + * A callback of the following type may be connected: + * @code + * void YourCallbackName( TextEditor textEditor ); + * @endcode + * @return The signal to connect to. + */ + TextChangedSignalType& TextChangedSignal(); + +public: // Not intended for application developers + + /** + * @brief Creates a handle using the Toolkit::Internal implementation. + * + * @param[in] implementation The Control implementation. + */ + DALI_INTERNAL TextEditor( Internal::TextEditor& implementation ); + + /** + * @brief Allows the creation of this Control from an Internal::CustomActor pointer. + * + * @param[in] internal A pointer to the internal CustomActor. + */ + explicit DALI_INTERNAL TextEditor( Dali::Internal::CustomActor* internal ); +}; + +/** + * @} + */ +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_EDITOR_H__ diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list index 953c478..ff91aa7 100755 --- a/dali-toolkit/devel-api/file.list +++ b/dali-toolkit/devel-api/file.list @@ -15,6 +15,7 @@ devel_api_src_files = \ $(devel_api_src_dir)/controls/shadow-view/shadow-view.cpp \ $(devel_api_src_dir)/controls/slider/slider.cpp \ $(devel_api_src_dir)/controls/super-blur-view/super-blur-view.cpp \ + $(devel_api_src_dir)/controls/text-controls/text-editor.cpp \ $(devel_api_src_dir)/controls/text-controls/text-selection-popup.cpp \ $(devel_api_src_dir)/controls/text-controls/text-selection-toolbar.cpp \ $(devel_api_src_dir)/controls/tool-bar/tool-bar.cpp \ @@ -103,6 +104,7 @@ devel_api_super_blur_view_header_files = \ $(devel_api_src_dir)/controls/super-blur-view/super-blur-view.h devel_api_text_controls_header_files = \ + $(devel_api_src_dir)/controls/text-controls/text-editor.h \ $(devel_api_src_dir)/controls/text-controls/text-selection-popup.h \ $(devel_api_src_dir)/controls/text-controls/text-selection-toolbar.h diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp new file mode 100644 index 0000000..a029c83 --- /dev/null +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp @@ -0,0 +1,1178 @@ +/* + * Copyright (c) 2016 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 + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include + +using namespace Dali::Toolkit::Text; + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace // unnamed namespace +{ + +#if defined(DEBUG_ENABLED) + Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS"); +#endif + + const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND; +} // unnamed namespace + +namespace +{ + +const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] = +{ + { "BEGIN", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_BEGIN }, + { "CENTER", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_CENTER }, + { "END", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_END }, +}; +const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] ); + +// Type registration +BaseHandle Create() +{ + return Toolkit::TextEditor::New(); +} + +// Setup properties, signals and actions using the type-registry. +DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextEditor, Toolkit::Control, Create ); + +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "renderingBackend", INTEGER, RENDERING_BACKEND ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "text", STRING, TEXT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "textColor", VECTOR4, TEXT_COLOR ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "fontFamily", STRING, FONT_FAMILY ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "fontStyle", STRING, FONT_STYLE ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "pointSize", FLOAT, POINT_SIZE ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "horizontalAlignment", STRING, HORIZONTAL_ALIGNMENT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "scrollThreshold", FLOAT, SCROLL_THRESHOLD ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "scrollSpeed", FLOAT, SCROLL_SPEED ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "primaryCursorColor", VECTOR4, PRIMARY_CURSOR_COLOR ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "secondaryCursorColor", VECTOR4, SECONDARY_CURSOR_COLOR ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableCursorBlink", BOOLEAN, ENABLE_CURSOR_BLINK ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "cursorBlinkInterval", FLOAT, CURSOR_BLINK_INTERVAL ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "cursorBlinkDuration", FLOAT, CURSOR_BLINK_DURATION ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "cursorWidth", INTEGER, CURSOR_WIDTH ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "grabHandleImage", STRING, GRAB_HANDLE_IMAGE ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "grabHandlePressedImage", STRING, GRAB_HANDLE_PRESSED_IMAGE ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleImageLeft", MAP, SELECTION_HANDLE_IMAGE_LEFT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleImageRight", MAP, SELECTION_HANDLE_IMAGE_RIGHT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandlePressedImageLeft", MAP, SELECTION_HANDLE_PRESSED_IMAGE_LEFT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandlePressedImageRight", MAP, SELECTION_HANDLE_PRESSED_IMAGE_RIGHT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleMarkerImageLeft", MAP, SELECTION_HANDLE_MARKER_IMAGE_LEFT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleMarkerImageRight", MAP, SELECTION_HANDLE_MARKER_IMAGE_RIGHT ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHighlightColor", VECTOR4, SELECTION_HIGHLIGHT_COLOR ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "decorationBoundingBox", RECTANGLE, DECORATION_BOUNDING_BOX ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableMarkup", BOOLEAN, ENABLE_MARKUP ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputColor", VECTOR4, INPUT_COLOR ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputFontFamily", STRING, INPUT_FONT_FAMILY ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputFontStyle", STRING, INPUT_FONT_STYLE ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputPointSize", FLOAT, INPUT_POINT_SIZE ) + +DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "textChanged", SIGNAL_TEXT_CHANGED ) + +DALI_TYPE_REGISTRATION_END() + +} // namespace + +Toolkit::TextEditor TextEditor::New() +{ + // Create the implementation, temporarily owned by this handle on stack + IntrusivePtr< TextEditor > impl = new TextEditor(); + + // Pass ownership to CustomActor handle + Toolkit::TextEditor handle( *impl ); + + // Second-phase init of the implementation + // This can only be done after the CustomActor connection has been made... + impl->Initialize(); + + return handle; +} + +void TextEditor::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) +{ + Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast( Dali::BaseHandle( object ) ); + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor SetProperty\n"); + + + if( textEditor ) + { + TextEditor& impl( GetImpl( textEditor ) ); + + switch( index ) + { + case Toolkit::TextEditor::Property::RENDERING_BACKEND: + { + int backend = value.Get< int >(); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend ); + + if( impl.mRenderingBackend != backend ) + { + impl.mRenderingBackend = backend; + impl.mRenderer.Reset(); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::TEXT: + { + if( impl.mController ) + { + const std::string text = value.Get< std::string >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p TEXT %s\n", impl.mController.Get(), text.c_str() ); + + impl.mController->SetText( text ); + } + break; + } + case Toolkit::TextEditor::Property::TEXT_COLOR: + { + if( impl.mController ) + { + const Vector4 textColor = value.Get< Vector4 >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a ); + + if( impl.mController->GetTextColor() != textColor ) + { + impl.mController->SetTextColor( textColor ); + impl.mController->SetInputColor( textColor ); + impl.mRenderer.Reset(); + } + } + break; + } + case Toolkit::TextEditor::Property::FONT_FAMILY: + { + if( impl.mController ) + { + const std::string fontFamily = value.Get< std::string >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() ); + impl.mController->SetDefaultFontFamily( fontFamily ); + } + break; + } + case Toolkit::TextEditor::Property::FONT_STYLE: + { + SetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT ); + break; + } + case Toolkit::TextEditor::Property::POINT_SIZE: + { + if( impl.mController ) + { + const float pointSize = value.Get< float >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p POINT_SIZE %f\n", impl.mController.Get(), pointSize ); + + if( !Equals( impl.mController->GetDefaultPointSize(), pointSize ) ) + { + impl.mController->SetDefaultPointSize( pointSize ); + } + } + break; + } + case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT: + { + if( impl.mController ) + { + const std::string alignStr = value.Get< std::string >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p HORIZONTAL_ALIGNMENT %s\n", impl.mController.Get(), alignStr.c_str() ); + + LayoutEngine::HorizontalAlignment alignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN ); + if( Scripting::GetEnumeration< LayoutEngine::HorizontalAlignment >( alignStr.c_str(), + HORIZONTAL_ALIGNMENT_STRING_TABLE, + HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT, + alignment ) ) + { + impl.mController->SetHorizontalAlignment( alignment ); + } + } + break; + } + case Toolkit::TextEditor::Property::SCROLL_THRESHOLD: + { + const float threshold = value.Get< float >(); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold ); + + if( impl.mDecorator ) + { + impl.mDecorator->SetScrollThreshold( threshold ); + } + break; + } + case Toolkit::TextEditor::Property::SCROLL_SPEED: + { + const float speed = value.Get< float >(); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p SCROLL_SPEED %f\n", impl.mController.Get(), speed ); + + if( impl.mDecorator ) + { + impl.mDecorator->SetScrollSpeed( speed ); + } + break; + } + case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR: + { + if( impl.mDecorator ) + { + const Vector4 color = value.Get< Vector4 >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p PRIMARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a ); + + impl.mDecorator->SetCursorColor( PRIMARY_CURSOR, color ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR: + { + if( impl.mDecorator ) + { + const Vector4 color = value.Get< Vector4 >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SECONDARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a ); + + impl.mDecorator->SetCursorColor( SECONDARY_CURSOR, color ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK: + { + if( impl.mController ) + { + const bool enable = value.Get< bool >(); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable ); + + impl.mController->SetEnableCursorBlink( enable ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL: + { + if( impl.mDecorator ) + { + const float interval = value.Get< float >(); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval ); + + impl.mDecorator->SetCursorBlinkInterval( interval ); + } + break; + } + case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION: + { + if( impl.mDecorator ) + { + const float duration = value.Get< float >(); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_DURATION %f\n", impl.mController.Get(), duration ); + + impl.mDecorator->SetCursorBlinkDuration( duration ); + } + break; + } + case Toolkit::TextEditor::Property::CURSOR_WIDTH: + { + if( impl.mDecorator ) + { + const int width = value.Get< int >(); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_WIDTH %d\n", impl.mController.Get(), width ); + + impl.mDecorator->SetCursorWidth( width ); + impl.mController->GetLayoutEngine().SetCursorWidth( width ); + } + break; + } + case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE: + { + const ResourceImage image = ResourceImage::New( value.Get< std::string >() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() ); + + if( impl.mDecorator ) + { + impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE: + { + const ResourceImage image = ResourceImage::New( value.Get< std::string >() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() ); + + if( impl.mDecorator ) + { + impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT: + { + const Image image = Scripting::NewImage( value ); + + if( impl.mDecorator && image ) + { + impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT: + { + const Image image = Scripting::NewImage( value ); + + if( impl.mDecorator && image ) + { + impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT: + { + const Image image = Scripting::NewImage( value ); + + if( impl.mDecorator && image ) + { + impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT: + { + const Image image = Scripting::NewImage( value ); + + if( impl.mDecorator && image ) + { + impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT: + { + const Image image = Scripting::NewImage( value ); + + if( impl.mDecorator && image ) + { + impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT: + { + const Image image = Scripting::NewImage( value ); + + if( impl.mDecorator && image ) + { + impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, image ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR: + { + const Vector4 color = value.Get< Vector4 >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTION_HIGHLIGHT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a ); + + if( impl.mDecorator ) + { + impl.mDecorator->SetHighlightColor( color ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX: + { + if( impl.mDecorator ) + { + const Rect box = value.Get< Rect >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height ); + + impl.mDecorator->SetBoundingBox( box ); + impl.RequestTextRelayout(); + } + break; + } + case Toolkit::TextEditor::Property::ENABLE_MARKUP: + { + if( impl.mController ) + { + const bool enableMarkup = value.Get(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup ); + + impl.mController->SetMarkupProcessorEnabled( enableMarkup ); + } + break; + } + case Toolkit::TextEditor::Property::INPUT_COLOR: + { + if( impl.mController ) + { + const Vector4 inputColor = value.Get< Vector4 >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a ); + + impl.mController->SetInputColor( inputColor ); + } + break; + } + case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY: + { + if( impl.mController ) + { + const std::string fontFamily = value.Get< std::string >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p INPUT_FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() ); + impl.mController->SetInputFontFamily( fontFamily ); + } + break; + } + case Toolkit::TextEditor::Property::INPUT_FONT_STYLE: + { + SetFontStyleProperty( impl.mController, value, Text::FontStyle::INPUT ); + break; + } + case Toolkit::TextEditor::Property::INPUT_POINT_SIZE: + { + if( impl.mController ) + { + const float pointSize = value.Get< float >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p INPUT_POINT_SIZE %f\n", impl.mController.Get(), pointSize ); + impl.mController->SetInputFontPointSize( pointSize ); + } + break; + } + } // switch + } // texteditor +} + +Property::Value TextEditor::GetProperty( BaseObject* object, Property::Index index ) +{ + Property::Value value; + + Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast( Dali::BaseHandle( object ) ); + + if( textEditor ) + { + TextEditor& impl( GetImpl( textEditor ) ); + + switch( index ) + { + case Toolkit::TextEditor::Property::RENDERING_BACKEND: + { + value = impl.mRenderingBackend; + break; + } + case Toolkit::TextEditor::Property::TEXT: + { + if( impl.mController ) + { + std::string text; + impl.mController->GetText( text ); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p returning text: %s\n", impl.mController.Get(), text.c_str() ); + value = text; + } + break; + } + case Toolkit::TextEditor::Property::TEXT_COLOR: + { + if ( impl.mController ) + { + value = impl.mController->GetTextColor(); + } + break; + } + case Toolkit::TextEditor::Property::FONT_FAMILY: + { + if( impl.mController ) + { + value = impl.mController->GetDefaultFontFamily(); + } + break; + } + case Toolkit::TextEditor::Property::FONT_STYLE: + { + GetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT ); + break; + } + case Toolkit::TextEditor::Property::POINT_SIZE: + { + if( impl.mController ) + { + value = impl.mController->GetDefaultPointSize(); + } + break; + } + case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT: + { + if( impl.mController ) + { + const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetLayoutEngine().GetHorizontalAlignment(), + HORIZONTAL_ALIGNMENT_STRING_TABLE, + HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT ); + if( name ) + { + value = std::string( name ); + } + } + break; + } + case Toolkit::TextEditor::Property::SCROLL_THRESHOLD: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetScrollThreshold(); + } + break; + } + case Toolkit::TextEditor::Property::SCROLL_SPEED: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetScrollSpeed(); + } + break; + } + case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetColor( PRIMARY_CURSOR ); + } + break; + } + case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetColor( SECONDARY_CURSOR ); + } + break; + } + case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK: + { + value = impl.mController->GetEnableCursorBlink(); + break; + } + case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetCursorBlinkInterval(); + } + break; + } + case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetCursorBlinkDuration(); + } + break; + } + case Toolkit::TextEditor::Property::CURSOR_WIDTH: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetCursorWidth(); + } + break; + } + case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE: + { + if( impl.mDecorator ) + { + ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED ) ); + if( image ) + { + value = image.GetUrl(); + } + } + break; + } + case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE: + { + if( impl.mDecorator ) + { + ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED ) ); + if( image ) + { + value = image.GetUrl(); + } + } + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT: + { + impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ); + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT: + { + impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) ; + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT: + { + impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ); + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT: + { + impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ); + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT: + { + impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED ); + break; + } + case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT: + { + impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED ); + break; + } + case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR: + { + if( impl.mDecorator ) + { + value = impl.mDecorator->GetHighlightColor(); + } + break; + } + case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX: + { + if( impl.mDecorator ) + { + Rect boundingBox; + impl.mDecorator->GetBoundingBox( boundingBox ); + value = boundingBox; + } + break; + } + case Toolkit::TextEditor::Property::ENABLE_MARKUP: + { + if( impl.mController ) + { + value = impl.mController->IsMarkupProcessorEnabled(); + } + break; + } + case Toolkit::TextEditor::Property::INPUT_COLOR: + { + if( impl.mController ) + { + value = impl.mController->GetInputColor(); + } + break; + } + case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY: + { + if( impl.mController ) + { + value = impl.mController->GetInputFontFamily(); + } + break; + } + case Toolkit::TextEditor::Property::INPUT_FONT_STYLE: + { + GetFontStyleProperty( impl.mController, value, Text::FontStyle::INPUT ); + break; + } + case Toolkit::TextEditor::Property::INPUT_POINT_SIZE: + { + if( impl.mController ) + { + value = impl.mController->GetInputFontPointSize(); + } + break; + } + } //switch + } + + return value; +} + +bool TextEditor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) +{ + Dali::BaseHandle handle( object ); + + bool connected( true ); + Toolkit::TextEditor editor = Toolkit::TextEditor::DownCast( handle ); + + if( 0 == strcmp( signalName.c_str(), SIGNAL_TEXT_CHANGED ) ) + { + editor.TextChangedSignal().Connect( tracker, functor ); + } + else + { + // signalName does not match any signal + connected = false; + } + + return connected; +} + +Toolkit::TextEditor::TextChangedSignalType& TextEditor::TextChangedSignal() +{ + return mTextChangedSignal; +} + +void TextEditor::OnInitialize() +{ + Actor self = Self(); + + mController = Text::Controller::New( *this ); + + mDecorator = Text::Decorator::New( *mController, + *mController ); + + mController->GetLayoutEngine().SetLayout( LayoutEngine::MULTI_LINE_BOX ); + + mController->EnableTextInput( mDecorator ); + + mController->SetMaximumNumberOfCharacters( std::numeric_limits::max() ); + + // Forward input events to controller + EnableGestureDetection( static_cast( Gesture::Tap | Gesture::Pan | Gesture::LongPress ) ); + GetTapGestureDetector().SetMaximumTapsRequired( 2 ); + + self.TouchedSignal().Connect( this, &TextEditor::OnTouched ); + + // Set BoundingBox to stage size if not already set. + Rect boundingBox; + mDecorator->GetBoundingBox( boundingBox ); + + if( boundingBox.IsEmpty() ) + { + Vector2 stageSize = Dali::Stage::GetCurrent().GetSize(); + mDecorator->SetBoundingBox( Rect( 0.0f, 0.0f, stageSize.width, stageSize.height ) ); + } + + // Flip vertically the 'left' selection handle + mDecorator->FlipHandleVertically( LEFT_SELECTION_HANDLE, true ); + + // Fill-parent area by default + self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); + self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT ); + self.OnStageSignal().Connect( this, &TextEditor::OnStageConnect ); +} + +void TextEditor::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnStyleChange\n"); + + switch ( change ) + { + case StyleChange::DEFAULT_FONT_CHANGE: + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnStyleChange DEFAULT_FONT_CHANGE\n"); + std::string newFont = styleManager.GetDefaultFontFamily(); + // Property system did not set the font so should update it. + mController->UpdateAfterFontChange( newFont ); + break; + } + + case StyleChange::DEFAULT_FONT_SIZE_CHANGE: + { + DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor::OnStyleChange StyleChange::DEFAULT_FONT_SIZE_CHANGE (%f)\n", mController->GetDefaultPointSize() ); + + if ( (mController->GetDefaultPointSize() <= 0.0f) ) // If DefaultPointSize not set by Property system it will be 0.0f + { + // Property system did not set the PointSize so should update it. + // todo instruct text-controller to update model + } + break; + } + case StyleChange::THEME_CHANGE: + { + GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) ); + break; + } + } +} + +Vector3 TextEditor::GetNaturalSize() +{ + return mController->GetNaturalSize(); +} + +float TextEditor::GetHeightForWidth( float width ) +{ + return mController->GetHeightForWidth( width ); +} + +void TextEditor::OnRelayout( const Vector2& size, RelayoutContainer& container ) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor OnRelayout\n"); + + if( mController->Relayout( size ) || + !mRenderer ) + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnRelayout %p Displaying new contents\n", mController.Get() ); + + if( mDecorator ) + { + mDecorator->Relayout( size ); + } + + if( !mRenderer ) + { + mRenderer = Backend::Get().NewRenderer( mRenderingBackend ); + } + + EnableClipping( true, size ); + RenderText(); + } +} + +void TextEditor::RenderText() +{ + Actor self = Self(); + Actor renderableActor; + if( mRenderer ) + { + renderableActor = mRenderer->Render( mController->GetView(), DepthIndex::TEXT ); + } + + if( renderableActor != mRenderableActor ) + { + UnparentAndReset( mRenderableActor ); + mRenderableActor = renderableActor; + } + + if( mRenderableActor ) + { + const Vector2 offset = mController->GetScrollPosition() + mController->GetAlignmentOffset(); + + mRenderableActor.SetPosition( offset.x, offset.y ); + + Actor clipRootActor; + if( mClipper ) + { + clipRootActor = mClipper->GetRootActor(); + } + + for( std::vector::const_iterator it = mClippingDecorationActors.begin(), + endIt = mClippingDecorationActors.end(); + it != endIt; + ++it ) + { + Actor actor = *it; + + if( clipRootActor ) + { + clipRootActor.Add( actor ); + } + else + { + self.Add( actor ); + } + } + mClippingDecorationActors.clear(); + + // Make sure the actor is parented correctly with/without clipping + if( clipRootActor ) + { + clipRootActor.Add( mRenderableActor ); + } + else + { + self.Add( mRenderableActor ); + } + } +} + +void TextEditor::OnKeyInputFocusGained() +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnKeyInputFocusGained %p\n", mController.Get() ); + + VirtualKeyboard::StatusChangedSignal().Connect( this, &TextEditor::KeyboardStatusChanged ); + + ImfManager imfManager = ImfManager::Get(); + + if ( imfManager ) + { + imfManager.EventReceivedSignal().Connect( this, &TextEditor::OnImfEvent ); + + // Notify that the text editing start. + imfManager.Activate(); + + // When window gain lost focus, the imf manager is deactivated. Thus when window gain focus again, the imf manager must be activated. + imfManager.SetRestoreAfterFocusLost( true ); + } + + ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); + + if ( notifier ) + { + notifier.ContentSelectedSignal().Connect( this, &TextEditor::OnClipboardTextSelected ); + } + + mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event + + EmitKeyInputFocusSignal( true ); // Calls back into the Control hence done last. +} + +void TextEditor::OnKeyInputFocusLost() +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor:OnKeyInputFocusLost %p\n", mController.Get() ); + + VirtualKeyboard::StatusChangedSignal().Disconnect( this, &TextEditor::KeyboardStatusChanged ); + + ImfManager imfManager = ImfManager::Get(); + if ( imfManager ) + { + // The text editing is finished. Therefore the imf manager don't have restore activation. + imfManager.SetRestoreAfterFocusLost( false ); + + // Notify that the text editing finish. + imfManager.Deactivate(); + + imfManager.EventReceivedSignal().Disconnect( this, &TextEditor::OnImfEvent ); + } + + ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); + + if ( notifier ) + { + notifier.ContentSelectedSignal().Disconnect( this, &TextEditor::OnClipboardTextSelected ); + } + + mController->KeyboardFocusLostEvent(); + + EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last. +} + +void TextEditor::OnTap( const TapGesture& gesture ) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnTap %p\n", mController.Get() ); + + // Show the keyboard if it was hidden. + if (!VirtualKeyboard::IsVisible()) + { + VirtualKeyboard::Show(); + } + + // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures + mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x, gesture.localPoint.y ); + + SetKeyInputFocus(); +} + +void TextEditor::OnPan( const PanGesture& gesture ) +{ + mController->PanEvent( gesture.state, gesture.displacement ); +} + +void TextEditor::OnLongPress( const LongPressGesture& gesture ) +{ + // Show the keyboard if it was hidden. + if (!VirtualKeyboard::IsVisible()) + { + VirtualKeyboard::Show(); + } + + mController->LongPressEvent( gesture.state, gesture.localPoint.x, gesture.localPoint.y ); + + SetKeyInputFocus(); +} + +bool TextEditor::OnKeyEvent( const KeyEvent& event ) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnKeyEvent %p keyCode %d\n", mController.Get(), event.keyCode ); + + if( Dali::DALI_KEY_ESCAPE == event.keyCode ) // Make a Dali key code for this + { + ClearKeyInputFocus(); + return true; + } + + return mController->KeyEvent( event ); +} + +void TextEditor::AddDecoration( Actor& actor, bool needsClipping ) +{ + if( actor ) + { + if( needsClipping ) + { + mClippingDecorationActors.push_back( actor ); + } + else + { + Self().Add( actor ); + } + } +} + +void TextEditor::RequestTextRelayout() +{ + RelayoutRequest(); +} + +void TextEditor::TextChanged() +{ + Dali::Toolkit::TextEditor handle( GetOwner() ); + mTextChangedSignal.Emit( handle ); +} + +void TextEditor::MaxLengthReached() +{ + // Nothing to do as TextEditor doesn't emit a max length reached signal. +} + +void TextEditor::OnStageConnect( Dali::Actor actor ) +{ + if ( mHasBeenStaged ) + { + RenderText(); + } + else + { + mHasBeenStaged = true; + } +} + +ImfManager::ImfCallbackData TextEditor::OnImfEvent( Dali::ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent ) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnImfEvent %p eventName %d\n", mController.Get(), imfEvent.eventName ); + return mController->OnImfEvent( imfManager, imfEvent ); +} + +void TextEditor::GetHandleImagePropertyValue( Property::Value& value, Text::HandleType handleType, Text::HandleImageType handleImageType ) +{ + if( mDecorator ) + { + ResourceImage image = ResourceImage::DownCast( mDecorator->GetHandleImage( handleType, handleImageType ) ); + + if ( image ) + { + Property::Map map; + Scripting::CreatePropertyMap( image, map ); + value = map; + } + } +} + +void TextEditor::EnableClipping( bool clipping, const Vector2& size ) +{ + if( clipping ) + { + // Not worth to created clip actor if width or height is equal to zero. + if( size.width > Math::MACHINE_EPSILON_1000 && size.height > Math::MACHINE_EPSILON_1000 ) + { + if( !mClipper ) + { + Actor self = Self(); + + mClipper = Clipper::New( size ); + self.Add( mClipper->GetRootActor() ); + self.Add( mClipper->GetImageActor() ); + } + else if ( mClipper ) + { + mClipper->Refresh( size ); + } + } + } + else + { + // Note - this will automatically remove the root & image actors + mClipper.Reset(); + } +} + +void TextEditor::OnClipboardTextSelected( ClipboardEventNotifier& clipboard ) +{ + mController->PasteClipboardItemEvent(); +} + +void TextEditor::KeyboardStatusChanged(bool keyboardShown) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown ); + + // Just hide the grab handle when keyboard is hidden. + if (!keyboardShown ) + { + mController->KeyboardFocusLostEvent(); + } + else + { + mController->KeyboardFocusGainEvent(); // Initially called by OnKeyInputFocusGained + } +} + +void TextEditor::OnStageConnection( int depth ) +{ + // Call the Control::OnStageConnection() to set the depth of the background. + Control::OnStageConnection( depth ); + + // Sets the depth to the renderers inside the text's decorator. + mDecorator->SetTextDepth( depth ); + + // The depth of the text renderer is set in the RenderText() called from OnRelayout(). +} + +bool TextEditor::OnTouched( Actor actor, const TouchEvent& event ) +{ + return true; +} + +TextEditor::TextEditor() +: Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ), + mRenderingBackend( DEFAULT_RENDERING_BACKEND ), + mHasBeenStaged( false ) +{ +} + +TextEditor::~TextEditor() +{ + mClipper.Reset(); +} + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.h b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h new file mode 100644 index 0000000..b10b78b --- /dev/null +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h @@ -0,0 +1,283 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_H__ +#define __DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_H__ + +/* + * Copyright (c) 2016 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. + * + */ + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +/** + * @brief A control which renders a long text string with styles. + */ +class TextEditor : public Control, public Text::ControlInterface +{ +public: + + /** + * @copydoc Dali::Toollkit::TextEditor::New() + */ + static Toolkit::TextEditor New(); + + // Properties + + /** + * @brief Called when a property of an object of this type is set. + * + * @param[in] object The object whose property is set. + * @param[in] index The property index. + * @param[in] value The new property value. + */ + static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ); + + /** + * @brief Called to retrieve a property of an object of this type. + * + * @param[in] object The object whose property is to be retrieved. + * @param[in] index The property index. + * @return The current value of the property. + */ + static Property::Value GetProperty( BaseObject* object, Property::Index index ); + + /** + * 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. + * @param[in] signalName The signal to connect to. + * @param[in] functor A newly allocated FunctorDelegate. + * @return True if the signal was connected. + * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor. + */ + static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ); + + /** + * @copydoc TextEditor::TextChangedSignal() + */ + Toolkit::TextEditor::TextChangedSignalType& TextChangedSignal(); + +private: // From Control + + /** + * @copydoc Control::OnInitialize() + */ + virtual void OnInitialize(); + + /** + * @copydoc Control::OnStyleChange() + */ + virtual void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ); + + /** + * @copydoc Control::GetNaturalSize() + */ + virtual Vector3 GetNaturalSize(); + + /** + * @copydoc Control::GetHeightForWidth() + */ + virtual float GetHeightForWidth( float width ); + + /** + * @copydoc Control::OnInitialize() + */ + virtual void OnRelayout( const Vector2& size, RelayoutContainer& container ); + + /** + * @copydoc Control::OnKeyInputFocusGained() + */ + virtual void OnKeyInputFocusGained(); + + /** + * @copydoc Control::OnKeyInputFocusLost() + */ + virtual void OnKeyInputFocusLost(); + + /** + * @copydoc Control::OnTap() + */ + virtual void OnTap( const TapGesture& tap ); + + /** + * @copydoc Control::OnPan() + */ + virtual void OnPan( const PanGesture& gesture ); + + /** + * @copydoc Control::OnLongPress() + */ + virtual void OnLongPress( const LongPressGesture& gesture ); + + /** + * @copydoc Control::OnStageConnection() + */ + virtual void OnStageConnection( int depth ); + + /** + * @copydoc Dali::CustomActorImpl::OnKeyEvent(const KeyEvent&) + */ + virtual bool OnKeyEvent(const KeyEvent& event); + +// From ControlInterface + + /** + * @copydoc Text::ControlInterface::AddDecoration() + */ + virtual void AddDecoration( Actor& actor, bool needsClipping ); + + /** + * @copydoc Text::ControlInterface::RequestTextRelayout() + */ + virtual void RequestTextRelayout(); + + /** + * @copydoc Text::ControlInterface::TextChanged() + */ + virtual void TextChanged(); + + /** + * @copydoc Text::ControlInterface::MaxLengthReached() + */ + virtual void MaxLengthReached(); + +private: // Implementation + + /** + * @copydoc Dali::Toolkit::Text::Controller::(ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent) + */ + ImfManager::ImfCallbackData OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent ); + + /** + * @brief Callback when Clipboard signals an item should be pasted + * @param[in] clipboard handle to Clipboard Event Notifier + */ + void OnClipboardTextSelected( ClipboardEventNotifier& clipboard ); + + /** + * @brief Get a Property Map for the image used for the required Handle Image + * @param[out] value the returned image property + * @param[in] handleType the type of handle + * @param[in] handleImageType the type of image for the given handleType + */ + void GetHandleImagePropertyValue( Property::Value& value, Text::HandleType handleType, Text::HandleImageType handleImageType ); + + /** + * @brief Enable or disable clipping. + * + * @param[in] clipping True if clipping should be enabled. + * @param[in] size The area to clip within. + */ + void EnableClipping( bool clipping, const Vector2& size ); + + /** + * @brief Callback when keyboard is shown/hidden. + * + * @param[in] keyboardShown True if keyboard is shown. + */ + void KeyboardStatusChanged( bool keyboardShown ); + + /** + * @brief Callback when TextEditor is touched + * + * @param[in] actor TextEditor touched + * @param[in] event TouchEvent information + */ + bool OnTouched( Actor actor, const TouchEvent& event ); + + /** + * Construct a new TextEditor. + */ + TextEditor(); + + /** + * A reference counted object may only be deleted by calling Unreference() + */ + virtual ~TextEditor(); + + // Undefined copy constructor and assignment operators + TextEditor(const TextEditor&); + TextEditor& operator=(const TextEditor& rhs); + + /** + * @brief Render view, create and attach actor(s) to this text editor. + */ + void RenderText(); + + // Connection needed to re-render text, when a text editor returns to the stage. + void OnStageConnect( Dali::Actor actor ); + +private: // Data + + // Signals + Toolkit::TextEditor::TextChangedSignalType mTextChangedSignal; + + Text::ControllerPtr mController; + Text::RendererPtr mRenderer; + Text::DecoratorPtr mDecorator; + Text::ClipperPtr mClipper; + std::vector mClippingDecorationActors; ///< Decoration actors which need clipping. + + Actor mRenderableActor; + + int mRenderingBackend; + bool mHasBeenStaged:1; +}; + +} // namespace Internal + +// Helpers for public-api forwarding methods + +inline Toolkit::Internal::TextEditor& GetImpl( Toolkit::TextEditor& textEditor ) +{ + DALI_ASSERT_ALWAYS(textEditor); + + Dali::RefObject& handle = textEditor.GetImplementation(); + + return static_cast(handle); +} + +inline const Toolkit::Internal::TextEditor& GetImpl( const Toolkit::TextEditor& textEditor ) +{ + DALI_ASSERT_ALWAYS(textEditor); + + const Dali::RefObject& handle = textEditor.GetImplementation(); + + return static_cast(handle); +} + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_H__ diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.h b/dali-toolkit/internal/controls/text-controls/text-field-impl.h index 8a59577..91d757b 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.h @@ -154,6 +154,8 @@ private: // From Control */ virtual bool OnKeyEvent(const KeyEvent& event); +// From ControlInterface + /** * @copydoc Text::ControlInterface::AddDecoration() */ @@ -174,6 +176,8 @@ private: // From Control */ virtual void MaxLengthReached(); +private: // Implementation + /** * @copydoc Dali::Toolkit::Text::Controller::(ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent) */ @@ -185,8 +189,6 @@ private: // From Control */ void OnClipboardTextSelected( ClipboardEventNotifier& clipboard ); -private: // Implementation - /** * @brief Get a Property Map for the image used for the required Handle Image * @param[out] value the returned image property @@ -211,7 +213,7 @@ private: // Implementation void KeyboardStatusChanged( bool keyboardShown ); /** - * @brief Callback when Textfield is touched + * @brief Callback when TextField is touched * * @param[in] actor TextField touched * @param[in] event TouchEvent information diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 345c107..96501dd 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -60,6 +60,7 @@ toolkit_src_files = \ $(toolkit_src_dir)/controls/slider/slider-impl.cpp \ $(toolkit_src_dir)/controls/super-blur-view/super-blur-view-impl.cpp \ $(toolkit_src_dir)/controls/table-view/table-view-impl.cpp \ + $(toolkit_src_dir)/controls/text-controls/text-editor-impl.cpp \ $(toolkit_src_dir)/controls/text-controls/text-field-impl.cpp \ $(toolkit_src_dir)/controls/text-controls/text-label-impl.cpp \ $(toolkit_src_dir)/controls/text-controls/text-selection-popup-impl.cpp \ diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 3143603..8a500f7 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -282,12 +282,9 @@ void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) c } } -void Controller::SetMaximumNumberOfCharacters( int maxCharacters ) +void Controller::SetMaximumNumberOfCharacters( Length maxCharacters ) { - if( maxCharacters >= 0 ) - { - mImpl->mMaximumNumberOfCharacters = maxCharacters; - } + mImpl->mMaximumNumberOfCharacters = maxCharacters; } int Controller::GetMaximumNumberOfCharacters() diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index a9cc0df..d239d13 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -184,7 +184,7 @@ public: * * @param[in] maxCharacters maximum number of characters to be accepted */ - void SetMaximumNumberOfCharacters( int maxCharacters ); + void SetMaximumNumberOfCharacters( Length maxCharacters ); /** * @brief Sets the maximum number of characters that can be inserted into the TextModel diff --git a/dali-toolkit/public-api/controls/text-controls/text-field.h b/dali-toolkit/public-api/controls/text-controls/text-field.h index f2205f5..1ada2cd 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-field.h +++ b/dali-toolkit/public-api/controls/text-controls/text-field.h @@ -60,51 +60,51 @@ public: }; /** - * @brief An enumeration of properties belonging to the TextLabel class. + * @brief An enumeration of properties belonging to the TextField class. */ struct Property { enum { - RENDERING_BACKEND = PROPERTY_START_INDEX, ///< name "renderingBackend", The type or rendering e.g. bitmap-based, type INT - TEXT, ///< name "text", The text to display in UTF-8 format, type STRING - PLACEHOLDER_TEXT, ///< name "placeholderText", The text to display when the TextField is empty and inactive, type STRING - PLACEHOLDER_TEXT_FOCUSED, ///< name "placeholderTextFocused", The text to display when the TextField is empty with key-input focus, type STRING - FONT_FAMILY, ///< name "fontFamily", The requested font family, type STRING - FONT_STYLE, ///< name "fontStyle", The requested font style, type STRING - POINT_SIZE, ///< name "pointSize", The size of font in points, type FLOAT - MAX_LENGTH, ///< name "maxLength" The maximum number of characters that can be inserted, type INTEGER - EXCEED_POLICY, ///< name "exceedPolicy" Specifies how the text is truncated when it does not fit, type INTEGER - HORIZONTAL_ALIGNMENT, ///< name "horizontalAlignment", The line horizontal alignment, type STRING, values "BEGIN", "CENTER", "END" - VERTICAL_ALIGNMENT, ///< name "verticalAlignment", The line vertical alignment, type STRING, values "TOP", "CENTER", "BOTTOM" - TEXT_COLOR, ///< name "textColor", The text color, type VECTOR4 - PLACEHOLDER_TEXT_COLOR, ///< name "placeholderTextColor", The placeholder-text color, type VECTOR4 - SHADOW_OFFSET, ///< name "shadowOffset", The drop shadow offset 0 indicates no shadow, type VECTOR2 - SHADOW_COLOR, ///< name "shadowColor", The color of a drop shadow, type VECTOR4 - PRIMARY_CURSOR_COLOR, ///< name "primaryCursorColor", The color to apply to the primary cursor, type VECTOR4 - SECONDARY_CURSOR_COLOR, ///< name "secondaryCursorColor", The color to apply to the secondary cursor, type VECTOR4 - ENABLE_CURSOR_BLINK, ///< name "enableCursorBlink", Whether the cursor should blink or not, type BOOLEAN - CURSOR_BLINK_INTERVAL, ///< name "cursorBlinkInterval", The time interval in seconds between cursor on/off states, type FLOAT - CURSOR_BLINK_DURATION, ///< name "cursorBlinkDuration", The cursor will stop blinking after this number of seconds (if non-zero), type FLOAT - CURSOR_WIDTH, ///< name "cursorWidth", The cursor width, type INTEGER - GRAB_HANDLE_IMAGE, ///< name "grabHandleImage", The image to display for the grab handle, type STRING - GRAB_HANDLE_PRESSED_IMAGE, ///< name "grabHandlePressedImage", The image to display when the grab handle is pressed, type STRING - SCROLL_THRESHOLD, ///< name "scrollThreshold" Scrolling will occur if the cursor is this close to the control border, type FLOAT - SCROLL_SPEED, ///< name "scrollSpeed" The scroll speed in pixels per second, type FLOAT - SELECTION_HANDLE_IMAGE_LEFT, ///< name "selectionHandleImageLeft", The image to display for the left selection handle, type MAP - SELECTION_HANDLE_IMAGE_RIGHT, ///< name "selectionHandleImageRight", The image to display for the right selection handle, type MAP - SELECTION_HANDLE_PRESSED_IMAGE_LEFT, ///< name "selectionHandlePressedImageLeft", The image to display when the left selection handle is pressed, type MAP - SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, ///< name "selectionHandlePressedImageRight", The image to display when the right selection handle is pressed, type MAP - SELECTION_HANDLE_MARKER_IMAGE_LEFT, ///< name "selectionHandleMarkerImageLeft", The image to display for the left selection handle marker, type MAP - SELECTION_HANDLE_MARKER_IMAGE_RIGHT, ///< name "selectionHandleMarkerImageRight", The image to display for the right selection handle marker, type MAP - SELECTION_HIGHLIGHT_COLOR, ///< name "selectionHighlightColor", The color of the selection highlight, type VECTOR4 - DECORATION_BOUNDING_BOX, ///< name "decorationBoundingBox", The decorations (handles etc) will positioned within this area on-screen, type RECTANGLE - INPUT_METHOD_SETTINGS, ///< name "inputMethodSettings", The settings to relating to the System's Input Method, Key and Value type MAP - INPUT_COLOR, ///< name "inputColor", The color of the new input text, type VECTOR4 - ENABLE_MARKUP, ///< name "enableMarkup", Whether the mark-up processing is enabled. type BOOLEAN - INPUT_FONT_FAMILY, ///< name "inputFontFamily", The font's family of the new input text, type STRING - INPUT_FONT_STYLE, ///< name "inputFontStyle", The font's style of the new input text, type STRING - INPUT_POINT_SIZE ///< name "inputPointSize", The font's size of the new input text in points, type FLOAT + RENDERING_BACKEND = PROPERTY_START_INDEX, ///< name "renderingBackend", The type or rendering e.g. bitmap-based, type INT + TEXT, ///< name "text", The text to display in UTF-8 format, type STRING + PLACEHOLDER_TEXT, ///< name "placeholderText", The text to display when the TextField is empty and inactive, type STRING + PLACEHOLDER_TEXT_FOCUSED, ///< name "placeholderTextFocused", The text to display when the TextField is empty with key-input focus, type STRING + FONT_FAMILY, ///< name "fontFamily", The requested font family, type STRING + FONT_STYLE, ///< name "fontStyle", The requested font style, type STRING + POINT_SIZE, ///< name "pointSize", The size of font in points, type FLOAT + MAX_LENGTH, ///< name "maxLength" The maximum number of characters that can be inserted, type INTEGER + EXCEED_POLICY, ///< name "exceedPolicy" Specifies how the text is truncated when it does not fit, type INTEGER + HORIZONTAL_ALIGNMENT, ///< name "horizontalAlignment", The line horizontal alignment, type STRING, values "BEGIN", "CENTER", "END" + VERTICAL_ALIGNMENT, ///< name "verticalAlignment", The line vertical alignment, type STRING, values "TOP", "CENTER", "BOTTOM" + TEXT_COLOR, ///< name "textColor", The text color, type VECTOR4 + PLACEHOLDER_TEXT_COLOR, ///< name "placeholderTextColor", The placeholder-text color, type VECTOR4 + SHADOW_OFFSET, ///< name "shadowOffset", The drop shadow offset 0 indicates no shadow, type VECTOR2 + SHADOW_COLOR, ///< name "shadowColor", The color of a drop shadow, type VECTOR4 + PRIMARY_CURSOR_COLOR, ///< name "primaryCursorColor", The color to apply to the primary cursor, type VECTOR4 + SECONDARY_CURSOR_COLOR, ///< name "secondaryCursorColor", The color to apply to the secondary cursor, type VECTOR4 + ENABLE_CURSOR_BLINK, ///< name "enableCursorBlink", Whether the cursor should blink or not, type BOOLEAN + CURSOR_BLINK_INTERVAL, ///< name "cursorBlinkInterval", The time interval in seconds between cursor on/off states, type FLOAT + CURSOR_BLINK_DURATION, ///< name "cursorBlinkDuration", The cursor will stop blinking after this number of seconds (if non-zero), type FLOAT + CURSOR_WIDTH, ///< name "cursorWidth", The cursor width, type INTEGER + GRAB_HANDLE_IMAGE, ///< name "grabHandleImage", The image to display for the grab handle, type STRING + GRAB_HANDLE_PRESSED_IMAGE, ///< name "grabHandlePressedImage", The image to display when the grab handle is pressed, type STRING + SCROLL_THRESHOLD, ///< name "scrollThreshold" Horizontal scrolling will occur if the cursor is this close to the control border, type FLOAT + SCROLL_SPEED, ///< name "scrollSpeed" The scroll speed in pixels per second, type FLOAT + SELECTION_HANDLE_IMAGE_LEFT, ///< name "selectionHandleImageLeft", The image to display for the left selection handle, type MAP + SELECTION_HANDLE_IMAGE_RIGHT, ///< name "selectionHandleImageRight", The image to display for the right selection handle, type MAP + SELECTION_HANDLE_PRESSED_IMAGE_LEFT, ///< name "selectionHandlePressedImageLeft", The image to display when the left selection handle is pressed, type MAP + SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, ///< name "selectionHandlePressedImageRight", The image to display when the right selection handle is pressed, type MAP + SELECTION_HANDLE_MARKER_IMAGE_LEFT, ///< name "selectionHandleMarkerImageLeft", The image to display for the left selection handle marker, type MAP + SELECTION_HANDLE_MARKER_IMAGE_RIGHT, ///< name "selectionHandleMarkerImageRight", The image to display for the right selection handle marker, type MAP + SELECTION_HIGHLIGHT_COLOR, ///< name "selectionHighlightColor", The color of the selection highlight, type VECTOR4 + DECORATION_BOUNDING_BOX, ///< name "decorationBoundingBox", The decorations (handles etc) will positioned within this area on-screen, type RECTANGLE + INPUT_METHOD_SETTINGS, ///< name "inputMethodSettings", The settings to relating to the System's Input Method, Key and Value type MAP + INPUT_COLOR, ///< name "inputColor", The color of the new input text, type VECTOR4 + ENABLE_MARKUP, ///< name "enableMarkup", Whether the mark-up processing is enabled. type BOOLEAN + INPUT_FONT_FAMILY, ///< name "inputFontFamily", The font's family of the new input text, type STRING + INPUT_FONT_STYLE, ///< name "inputFontStyle", The font's style of the new input text, type STRING + INPUT_POINT_SIZE ///< name "inputPointSize", The font's size of the new input text in points, type FLOAT }; }; @@ -121,12 +121,13 @@ public: // Type Defs - /// @brief Max Characters Exceed signal type; + /// @brief Text changed signal type. typedef Signal TextChangedSignalType; + /// @brief Max Characters Exceed signal type. typedef Signal MaxLengthReachedSignalType; /** - * Create the TextField control. + * @brief Create the TextField control. * @return A handle to the TextField control. */ static TextField New(); @@ -152,7 +153,7 @@ public: TextField& operator=( const TextField& handle ); /** - * @brief Destructor + * @brief Destructor. * * This is non-virtual since derived Handle types must not contain data or virtual methods. */ @@ -164,8 +165,8 @@ public: * If the BaseHandle points is a TextField the downcast returns a valid handle. * If not the returned handle is left empty. * - * @param[in] handle Handle to an object - * @return handle to a TextField or an empty handle + * @param[in] handle Handle to an object. + * @return handle to a TextField or an empty handle. */ static TextField DownCast( BaseHandle handle ); diff --git a/dali-toolkit/styles/480x800/dali-toolkit-default-theme.json b/dali-toolkit/styles/480x800/dali-toolkit-default-theme.json index 7b4b130..3717470 100644 --- a/dali-toolkit/styles/480x800/dali-toolkit-default-theme.json +++ b/dali-toolkit/styles/480x800/dali-toolkit-default-theme.json @@ -131,6 +131,17 @@ distributing this software or its derivatives. "overshootEffectColor":"B018", "overshootAnimationSpeed":120.0, "overshootSize":[480.0,42.0] + }, + "texteditor": + { + "pointSize":18, + "primaryCursorColor":[0.0,0.72,0.9,1.0], + "secondaryCursorColor":[0.0,0.72,0.9,1.0], + "cursorWidth":1, + "selectionHighlightColor":[0.75,0.96,1.0,1.0], + "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png", + "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" }, + "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" } } } } diff --git a/dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json b/dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json index 525857b..30325c6 100644 --- a/dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json +++ b/dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json @@ -131,6 +131,17 @@ distributing this software or its derivatives. "overshootEffectColor":"B018", "overshootAnimationSpeed":360.0, "overshootSize":[720.0,130.0] + }, + "texteditor": + { + "pointSize":18, + "primaryCursorColor":[0.0,0.72,0.9,1.0], + "secondaryCursorColor":[0.0,0.72,0.9,1.0], + "cursorWidth":3, + "selectionHighlightColor":[0.75,0.96,1.0,1.0], + "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png", + "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" }, + "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" } } } } diff --git a/docs/content/main.md b/docs/content/main.md index 7bd9936..1f6091a 100644 --- a/docs/content/main.md +++ b/docs/content/main.md @@ -58,6 +58,7 @@ + [Popup](@ref popup) + [Scroll View](@ref scroll-view) + TableView + + [Text Editor](@ref text-editor) + [Text Field](@ref text-field) + [Text Label](@ref text-label) diff --git a/docs/content/shared-javascript-and-cpp-documentation/copy-and-paste.md b/docs/content/shared-javascript-and-cpp-documentation/copy-and-paste.md new file mode 100644 index 0000000..759de31 --- /dev/null +++ b/docs/content/shared-javascript-and-cpp-documentation/copy-and-paste.md @@ -0,0 +1,27 @@ + + +# Copy and Paste (Selection) {#copy-n-paste} + +Text can be selected by a long press or double tapping it. Depending on certain conditions a popup could be shown giving options including [CUT][COPY][PASTE], [SELECT ALL] or [CLIPBOARD]. Below these conditions will be explained. + +[CUT] or [COPY] send the selected text to the clipboard ready to be pasted directly or via the clipboard UI. Pressing [PASTE] will paste the top item from the clipboard (what has just been copied, possibly from another application). If the system supports a clipboard UI this can be displayed by pressing the [CLIPBOARD] button. + +Empty text means the user has not inputted any text, a text-control containing special characters or purely whitespace is not empty. + +Below shows how the popup will look depending on the state of the text-control. + +| | | +|--|--| +| Condition: Long press/double tap when empty text but clipboard has content | Condition: Long press/double tap when text-control contains text | +|[PASTE][CLIPBOARD] buttons shown| [CUT][COPY], [SELECT ALL] unless all text selected and [PASTE][CLIPBOARD] if content to paste. | +| ![ ](../assets/img/text-controls/EmptyTextClipboardHasContent.png) ![ ](./EmptyTextClipboardHasContent.png) | ![ ](../assets/img/text-controls/SelectingText.png) ![ ](./SelectingText.png) | +| Condition: Long press/double tap popup when text-control contains just whitespace | Condition: Empty text & clipboard empty | +| Whitespace treated as regular text, [CUT][COPY] shown and [PASTE][CLIPBOARD] if content to paste. As all text is selected there is no need for [SELECT ALL] | No popup shown after longpress/double tap| +| ![ ](../assets/img/text-controls/SelectAllWhitespace.png) ![ ](./SelectAllWhitespace.png) | ![ ](../assets/img/text-controls/EmptyTextAndNoContentToPaste.png) ![ ](./EmptyTextAndNoContentToPaste.png)| +| Condition: Longpress/(double tap) on whitespace which is following text | Condition: Tapping text or panning grab handle | +| [PASTE][CLIPBOARD] shown if something to paste. [SELECT ALL] as more text to select | If content in clipboard [PASTE][CLIPBOARD] popup will be shown. | +| ![ ](../assets/img/text-controls/SelectWhitespaceAfterText.png) ![ ](./SelectWhitespaceAfterText.png) | ![ ](../assets/img/text-controls/TapAfterCopyingText.png) ![ ](./TapAfterCopyingText.png) | + + +*/ diff --git a/docs/content/shared-javascript-and-cpp-documentation/input-style.md b/docs/content/shared-javascript-and-cpp-documentation/input-style.md new file mode 100644 index 0000000..f37f126 --- /dev/null +++ b/docs/content/shared-javascript-and-cpp-documentation/input-style.md @@ -0,0 +1,17 @@ + + +# Input Style {#input-style} + +The input style can be changed through the control properties. All subsequent characters added will be rendered with the new input style. + +Note the input style may change if the cursor is updated by tapping in a new position. + +Current supported input style properties are: + +- *INPUT_COLOR* Sets the input color. The property expects a Vector4 with the red, green, blue and alpha values clamped between 0 and 1. +- *INPUT_FONT_FAMILY* Sets the input font's family name. The property expects the name of the font. If the new text is not supported by the given font a suitable one will be set. +- *INPUT_FONT_STYLE* Sets the input font's style. The property expects a json formatted string with the font's style. See the [Font Selection](@ref font-selection) section for more details. +- *INPUT_POINT_SIZE* Sets the input font's size. The property expects a float with the font's size in points. See the [Font Selection](@ref font-selection) section for more details. + +*/ diff --git a/docs/content/shared-javascript-and-cpp-documentation/text-editor.md b/docs/content/shared-javascript-and-cpp-documentation/text-editor.md new file mode 100644 index 0000000..0da1f43 --- /dev/null +++ b/docs/content/shared-javascript-and-cpp-documentation/text-editor.md @@ -0,0 +1,134 @@ + + +# Text Editor {#text-editor} + +## Overview + +The Dali::Toolkit::TextEditor is a control which provides a multi-line editable text. + +### Basic usage + +Add the text-editor to the stage. + +~~~{.cpp} +// C++ + +TextEditor editor = TextEditor::New(); + +Stage::GetCurrent().Add( editor ); +~~~ + +~~~{.js} +// JavaScript + +var editor = new dali.TextEditor(); + +dali.stage.add( editor ); +~~~ + +When the TextEditor is tapped, it will automatically gain the keyboard focus. Key events will then result in text being inserted. +After text has been entered, it can be retrieved from the TEXT property. + +~~~{.cpp} +// C++ + +Property::Value editorText = editor.GetProperty( TextEditor::Property::TEXT ); +std::cout << "Received text: " << editorText.Get< std::string >() << std::endl; +~~~ + +~~~{.js} +// JavaScript + +console.log( editor.text ); +~~~ + +### Font Selection + +By default TextEditor will automatically select a suitable font from the platform. However, a different font could be selected. See the [Font Selection](@ref font-selection) section for more details. + +### Mark-up Style + +Mark-up tags can be used to change the style of the text. See the [Mark-up Style](@ref markup-style) section for more details. + +### Input Style + +The input style can be changed through the control properties.See the [Input Style](@ref input-style) section for more details. + +### Text Alignment + +TextEditor displays a multi-line of text, which will scroll if there is not enough room for the text displayed. +If there is enough room, then the text can be aligned horizontally to the beginning, end, or center of the available area: + +~~~{.cpp} +// C++ + +editor.SetProperty( TextEditor::Property::HORIZONTAL_ALIGNMENT, "BEGIN" ); // "CENTER" or "END" +~~~ + +~~~{.js} +// JavaScript + +editor.HorizontalAlignment = "BEGIN"; // "CENTER" or "END" +~~~ + +### Copy and Paste (Selection) + +Text can be selected by a long press or double tapping it. See the [Copy and Paste](@ref copy-n-paste) section for more details. + +### TextEditor Decorations + +#### Color + +To change the color of the text, the recommended way is to use the TEXT_COLOR property. + +~~~{.cpp} +// C++ +editor.SetProperty( TextEditor::Property::TEXT_COLOR, Color::CYAN ); +~~~ + +~~~{.js} +// JavaScript + +editor.textColor = dali.COLOR_CYAN; +~~~ + +### TextEditor Properties + + Name (JavaScript) | Name (C++) | Type | Writable | Animatable +-----------------------------------|--------------------------------------|--------------|--------------|----------- + renderingBackend | RENDERING_BACKEND | INTEGER | O | X + text | TEXT | STRING | O | X + textColor | TEXT_COLOR | VECTOR4 | O | X + fontFamily | FONT_FAMILY | STRING | O | X + fontStyle | FONT_STYLE | STRING | O | X + pointSize | POINT_SIZE | FLOAT | O | X + horizontalAlignment | HORIZONTAL_ALIGNMENT | STRING | O | X + verticalAlignment | VERTICAL_ALIGNMENT | STRING | O | X + scrollThreshold | SCROLL_THRESHOLD | FLOAT | O | X + scrollSpeed | SCROLL_SPEED | FLOAT | O | X + primaryCursorColor | PRIMARY_CURSOR_COLOR | VECTOR4 | O | X + secondaryCursorColor | SECONDARY_CURSOR_COLOR | VECTOR4 | O | X + enableCursorBlink | ENABLE_CURSOR_BLINK | BOOLEAN | O | X + cursorBlinkInterval | CURSOR_BLINK_INTERVAL | FLOAT | O | X + cursorBlinkDuration | CURSOR_BLINK_DURATION | FLOAT | O | X + cursorWidth | CURSOR_WIDTH | INTEGER | O | X + grabHandleImage | GRAB_HANDLE_IMAGE | STRING | O | X + grabHandlePressedImage | GRAB_HANDLE_PRESSED_IMAGE | STRING | O | X + selectionHandleImageLeft | SELECTION_HANDLE_IMAGE_LEFT | STRING | O | X + selectionHandleImageRight | SELECTION_HANDLE_IMAGE_RIGHT | STRING | O | X + selectionHandlePressedImageLeft | SELECTION_HANDLE_PRESSED_IMAGE_LEFT | STRING | O | X + selectionHandlePressedImageRight | SELECTION_HANDLE_PRESSED_IMAGE_RIGHT | STRING | O | X + selectionHandleMarkerImageLeft | SELECTION_HANDLE_MARKER_IMAGE_LEFT | MAP | O | X + selectionHandleMarkerImageRight | SELECTION_HANDLE_MARKER_IMAGE_RIGHT | MAP | O | X + selectionHighlightColor | SELECTION_HIGHLIGHT_COLOR | VECTOR4 | O | X + decorationBoundingBox | DECORATION_BOUNDING_BOX | RECTANGLE | O | X + enableMarkup | ENABLE_MARKUP | BOOLEAN | O | X + inputColor | INPUT_COLOR | VECTOR4 | O | X + inputFontFamily | INPUT_FONT_FAMILY | STRING | O | X + inputFontStyle | INPUT_FONT_STYLE | STRING | O | X + inputPointSize | INPUT_POINT_SIZE | FLOAT | O | X + +@class TextEditor + +*/ diff --git a/docs/content/shared-javascript-and-cpp-documentation/text-field.md b/docs/content/shared-javascript-and-cpp-documentation/text-field.md index 76cea4c..f6c8ecc 100644 --- a/docs/content/shared-javascript-and-cpp-documentation/text-field.md +++ b/docs/content/shared-javascript-and-cpp-documentation/text-field.md @@ -61,16 +61,7 @@ Mark-up tags can be used to change the style of the text. See the [Mark-up Style ### Input Style -The input style can be changed through the control properties. All subsequent characters added will be rendered with the new input style. - -Note the input style may change if the cursor is updated by tapping in a new position. - -Current supported input style properties are: - -- *INPUT_COLOR* Sets the input color. The property expects a Vector4 with the red, green, blue and alpha values clamped between 0 and 1. -- *INPUT_FONT_FAMILY* Sets the input font's family name. The property expects the name of the font. If the new text is not supported by the given font a suitable one will be set. -- *INPUT_FONT_STYLE* Sets the input font's style. The property expects a json formatted string with the font's style. See the [Font Selection](@ref font-selection) section for more details. -- *INPUT_POINT_SIZE* Sets the input font's size. The property expects a float with the font's size in points. See the [Font Selection](@ref font-selection) section for more details. +The input style can be changed through the control properties. See the [Input Style](@ref input-style) section for more details. ### Text Alignment @@ -91,25 +82,7 @@ field.HorizontalAlignment = "BEGIN"; // "CENTER" or "END" ### Copy and Paste (Selection) -Text can be selected by a long press or double tapping it. Depending on certain conditions a popup could be shown giving options including [CUT][COPY][PASTE], [SELECT ALL] or [CLIPBOARD]. Below these conditions will be explained. - -[CUT] or [COPY] send the selected text to the clipboard ready to be pasted directly or via the clipboard UI. Pressing [PASTE] will paste the top item from the clipboard (what has just been copied, possibly from another application). If the system supports a clipboard UI this can be displayed by pressing the [CLIPBOARD] button. - -Empty text means the user has not inputted any text, a TextField containing special characters or purely whitespace is not empty. - -Below shows how the popup will look depending on the state of the TextField - -| | | -|--|--| -| Condition: Long press/double tap when empty text but clipboard has content | Condition: Long press/double tap when TextField contains text | -|[PASTE][CLIPBOARD] buttons shown| [CUT][COPY], [SELECT ALL] unless all text selected and [PASTE][CLIPBOARD] if content to paste. | -| ![ ](../assets/img/text-controls/EmptyTextClipboardHasContent.png) ![ ](./EmptyTextClipboardHasContent.png) | ![ ](../assets/img/text-controls/SelectingText.png) ![ ](./SelectingText.png) | -| Condition: Long press/double tap popup when TextField contains just whitespace | Condition: Empty text & clipboard empty | -| Whitespace treated as regular text, [CUT][COPY] shown and [PASTE][CLIPBOARD] if content to paste. As all text is selected there is no need for [SELECT ALL] | No popup shown after longpress/double tap| -| ![ ](../assets/img/text-controls/SelectAllWhitespace.png) ![ ](./SelectAllWhitespace.png) | ![ ](../assets/img/text-controls/EmptyTextAndNoContentToPaste.png) ![ ](./EmptyTextAndNoContentToPaste.png)| -| Condition: Longpress/(double tap) on whitespace which is following text | Condition: Tapping text or panning grab handle | -| [PASTE][CLIPBOARD] shown if something to paste. [SELECT ALL] as more text to select | If content in clipboard [PASTE][CLIPBOARD] popup will be shown. | -| ![ ](../assets/img/text-controls/SelectWhitespaceAfterText.png) ![ ](./SelectWhitespaceAfterText.png) | ![ ](../assets/img/text-controls/TapAfterCopyingText.png) ![ ](./TapAfterCopyingText.png) | +Text can be selected by a long press or double tapping it. See the [Copy and Paste](@ref copy-n-paste) section for more details. ### TextField Decorations