Dali 3D User Interface Engine
utc-Dali-TextEditor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #include <iostream>
19 #include <stdlib.h>
27 
28 using namespace Dali;
29 using namespace Toolkit;
30 
32 {
34 }
35 
37 {
39 }
40 
41 namespace
42 {
43 
44 const char* const PROPERTY_NAME_RENDERING_BACKEND = "renderingBackend";
45 const char* const PROPERTY_NAME_TEXT = "text";
46 const char* const PROPERTY_NAME_TEXT_COLOR = "textColor";
47 const char* const PROPERTY_NAME_FONT_FAMILY = "fontFamily";
48 const char* const PROPERTY_NAME_FONT_STYLE = "fontStyle";
49 const char* const PROPERTY_NAME_POINT_SIZE = "pointSize";
50 const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT = "horizontalAlignment";
51 const char* const PROPERTY_NAME_SCROLL_THRESHOLD = "scrollThreshold";
52 const char* const PROPERTY_NAME_SCROLL_SPEED = "scrollSpeed";
53 const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR = "primaryCursorColor";
54 const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR = "secondaryCursorColor";
55 const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK = "enableCursorBlink";
56 const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL = "cursorBlinkInterval";
57 const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION = "cursorBlinkDuration";
58 const char* const PROPERTY_NAME_CURSOR_WIDTH = "cursorWidth";
59 const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE = "grabHandleImage";
60 const char* const PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE = "grabHandlePressedImage";
61 const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT = "selectionHandleImageLeft";
62 const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT = "selectionHandleImageRight";
63 const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT = "selectionHandlePressedImageLeft";
64 const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT = "selectionHandlePressedImageRight";
65 const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_LEFT = "selectionHandleMarkerImageLeft";
66 const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_RIGHT = "selectionHandleMarkerImageRight";
67 const char* const PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR = "selectionHighlightColor";
68 const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX = "decorationBoundingBox";
69 const char* const PROPERTY_NAME_ENABLE_MARKUP = "enableMarkup";
70 const char* const PROPERTY_NAME_INPUT_COLOR = "inputColor";
71 const char* const PROPERTY_NAME_INPUT_FONT_FAMILY = "inputFontFamily";
72 const char* const PROPERTY_NAME_INPUT_FONT_STYLE = "inputFontStyle";
73 const char* const PROPERTY_NAME_INPUT_POINT_SIZE = "inputPointSize";
74 
76 
77 const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color.
78 
79 const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval
80 const float TO_MILLISECONDS = 1000.f;
81 const float TO_SECONDS = 1.f / TO_MILLISECONDS;
82 
83 const float SCROLL_THRESHOLD = 10.f;
84 const float SCROLL_SPEED = 300.f;
85 
87 
88 static void TestTextChangedCallback( TextEditor control )
89 {
90  tet_infoline(" TestTextChangedCallback");
91 
92  gTextChangedCallBackCalled = true;
93 }
94 
95 // Generate a TapGestureEvent to send to Core.
96 Integration::TapGestureEvent GenerateTap(
97  Gesture::State state,
98  unsigned int numberOfTaps,
99  unsigned int numberOfTouches,
100  Vector2 point)
101 {
102  Integration::TapGestureEvent tap( state );
103 
104  tap.numberOfTaps = numberOfTaps;
105  tap.numberOfTouches = numberOfTouches;
106  tap.point = point;
107 
108  return tap;
109 }
110 
111 // Generate a KeyEvent to send to Core.
112 Integration::KeyEvent GenerateKey( const std::string& keyName,
113  const std::string& keyString,
114  int keyCode,
115  int keyModifier,
116  unsigned long timeStamp,
117  const Integration::KeyEvent::State& keyState )
118 {
119  return Integration::KeyEvent( keyName,
120  keyString,
121  keyCode,
122  keyModifier,
123  timeStamp,
124  keyState );
125 }
126 
127 } // namespace
128 
130 {
131  ToolkitTestApplication application;
132  tet_infoline(" UtcDaliToolkitTextEditorConstructorP");
133  TextEditor textEditor;
134  DALI_TEST_CHECK( !textEditor );
135  END_TEST;
136 }
137 
139 {
140  ToolkitTestApplication application;
141  tet_infoline(" UtcDaliToolkitTextEditorNewP");
142  TextEditor textEditor = TextEditor::New();
143  DALI_TEST_CHECK( textEditor );
144  END_TEST;
145 }
146 
148 {
149  ToolkitTestApplication application;
150  tet_infoline(" UtcDaliToolkitTextEditorDownCastP");
151  TextEditor textEditor1 = TextEditor::New();
152  BaseHandle object( textEditor1 );
153 
154  TextEditor textEditor2 = TextEditor::DownCast( object );
155  DALI_TEST_CHECK( textEditor2 );
156 
157  TextEditor textEditor3 = DownCast< TextEditor >( object );
158  DALI_TEST_CHECK( textEditor3 );
159  END_TEST;
160 }
161 
163 {
164  ToolkitTestApplication application;
165  tet_infoline(" UtcDaliToolkitTextEditorDownCastN");
166  BaseHandle uninitializedObject;
167  TextEditor textEditor1 = TextEditor::DownCast( uninitializedObject );
168  DALI_TEST_CHECK( !textEditor1 );
169 
170  TextEditor textEditor2 = DownCast< TextEditor >( uninitializedObject );
171  DALI_TEST_CHECK( !textEditor2 );
172  END_TEST;
173 }
174 
176 {
177  ToolkitTestApplication application;
178  tet_infoline(" UtcDaliToolkitTextEditorCopyConstructorP");
179  TextEditor textEditor = TextEditor::New();
180  textEditor.SetProperty( TextEditor::Property::TEXT, "Test" );
181 
182  TextEditor copy( textEditor );
183  DALI_TEST_CHECK( copy );
184  DALI_TEST_CHECK( copy.GetProperty<std::string>( TextLabel::Property::TEXT ) == textEditor.GetProperty<std::string>( TextLabel::Property::TEXT ) );
185  END_TEST;
186 }
187 
189 {
190  ToolkitTestApplication application;
191  tet_infoline(" UtcDaliToolkitTextEditorAssignmentOperatorP");
192  TextEditor textEditor = TextEditor::New();
193  textEditor.SetProperty( TextEditor::Property::TEXT, "Test" );
194 
195  TextEditor copy = textEditor;
196  DALI_TEST_CHECK( copy );
197  DALI_TEST_CHECK( copy.GetProperty<std::string>( TextEditor::Property::TEXT ) == textEditor.GetProperty<std::string>( TextEditor::Property::TEXT ) );
198  END_TEST;
199 }
200 
202 {
203  ToolkitTestApplication application;
204  tet_infoline(" UtcDaliToolkitTextEditorNewP");
205  TextEditor textEditor = TextEditor::New();
206  DALI_TEST_CHECK( textEditor );
207  END_TEST;
208 }
209 
210 // Positive test case for a method
212 {
213  ToolkitTestApplication application;
214  tet_infoline(" UtcDaliToolkitTextEditorGetPropertyP");
215  TextEditor editor = TextEditor::New();
216  DALI_TEST_CHECK( editor );
217 
218  // Check Property Indices are correct
249  END_TEST;
250 }
251 
252 bool SetPropertyMapRetrieved( TextEditor& editor, const Property::Index property, const std::string mapKey, const std::string mapValue )
253 {
254  bool result = false;
255  Property::Map imageMap;
256  imageMap[mapKey] =mapValue;
257 
258  editor.SetProperty( property , imageMap );
259  Property::Value propValue = editor.GetProperty( property );
260  Property::Map* resultMap = propValue.GetMap();
261 
262  if ( resultMap->Find( mapKey )->Get< std::string>() == mapValue )
263  {
264  result = true;
265  }
266 
267  return result;
268 }
269 
270 // Positive test case for a method
272 {
273  ToolkitTestApplication application;
274  tet_infoline(" UtcDaliToolkitTextEditorSetPropertyP");
275  TextEditor editor = TextEditor::New();
276  DALI_TEST_CHECK( editor );
277  Stage::GetCurrent().Add( editor );
278 
279  // Note - we can't check the defaults since the stylesheets are platform-specific
280 
281  // Check the render backend property.
284 
285  // Check text property.
286  editor.SetProperty( TextEditor::Property::TEXT, "Setting Text" );
287  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("Setting Text"), TEST_LOCATION );
288 
289  // Check text's color property
292 
293  // Check font properties.
294  editor.SetProperty( TextEditor::Property::FONT_FAMILY, "Setting font family" );
295  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::FONT_FAMILY ), std::string("Setting font family"), TEST_LOCATION );
296  editor.SetProperty( TextEditor::Property::FONT_STYLE, "Setting font style" );
297  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::FONT_STYLE ), std::string("Setting font style"), TEST_LOCATION );
300 
301  // Check that the Alignment properties can be correctly set
304 
305  // Check scroll properties.
310 
311  // Check cursor properties
316 
325 
326  // Check handle images
332 
333  // Check handle images
340 
341  // Check the highlight color
344 
345  // Decoration bounding box
348 
349  // Check the enable markup property.
353 
354  // Check input color property.
357 
358  // Check input font properties.
359  editor.SetProperty( TextEditor::Property::INPUT_FONT_FAMILY, "Setting input font family" );
360  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::INPUT_FONT_FAMILY ), "Setting input font family", TEST_LOCATION );
361  editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, "Setting input font style" );
362  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::INPUT_FONT_STYLE ), "Setting input font style", TEST_LOCATION );
365 
366  END_TEST;
367 }
368 
369 // Positive Atlas Text Renderer test
371 {
372  ToolkitTestApplication application;
373  tet_infoline(" UtcDaliToolkitTextEditorAtlasRenderP");
374  StyleManager styleManager = StyleManager::Get();
375  styleManager.RequestDefaultTheme();
376  TextEditor editor = TextEditor::New();
377  DALI_TEST_CHECK( editor );
378 
380 
382 
383  Stage::GetCurrent().Add( editor );
384 
385  try
386  {
387  // Render some text with the shared atlas backend
389  application.SendNotification();
390  application.Render();
391  }
392  catch( ... )
393  {
395  }
396  END_TEST;
397 }
398 
399 // Positive test for the textChanged signal.
401 {
402  ToolkitTestApplication application;
403  tet_infoline(" utcDaliTextEditorTextChangedP");
404  TextEditor editor = TextEditor::New();
405  DALI_TEST_CHECK( editor );
406 
407  Stage::GetCurrent().Add( editor );
408 
409  editor.TextChangedSignal().Connect(&TestTextChangedCallback);
410 
412  editor.SetProperty( TextEditor::Property::TEXT, "ABC" );
414 
415  application.SendNotification();
416 
417  editor.SetKeyInputFocus();
418 
420  application.ProcessEvent( GenerateKey( "D", "D", 0, 0, 0, Integration::KeyEvent::Down ) );
422 
423  END_TEST;
424 }
425 
427 {
428  ToolkitTestApplication application;
429  tet_infoline(" utcDaliTextEditorEvent01");
430 
431  // Creates a tap event. After creating a tap event the text editor should
432  // have the focus and add text with key events should be possible.
433 
434  TextEditor editor = TextEditor::New();
435  DALI_TEST_CHECK( editor );
436 
437  Stage::GetCurrent().Add( editor );
438 
439  editor.SetSize( 300.f, 50.f );
442 
443  // Avoid a crash when core load gl resources.
445 
446  // Render and notify
447  application.SendNotification();
448  application.Render();
449 
450  // Add a key event but as the text editor has not the focus it should do nothing.
451  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
452 
453  // Render and notify
454  application.SendNotification();
455  application.Render();
456 
457  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string(""), TEST_LOCATION );
458 
459  // Create a tap event to touch the text editor.
460  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
461  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
462 
463  // Render and notify
464  application.SendNotification();
465  application.Render();
466 
467  // Now the text editor has the focus, so it can handle the key events.
468  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
469  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
470 
471  // Render and notify
472  application.SendNotification();
473  application.Render();
474 
475  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("aa"), TEST_LOCATION );
476 
477  // Create a second text editor and send key events to it.
478  TextEditor editor2 = TextEditor::New();
479 
482  editor2.SetSize( 100.f, 100.f );
483  editor2.SetPosition( 100.f, 100.f );
484 
485  Stage::GetCurrent().Add( editor2 );
486 
487  // Render and notify
488  application.SendNotification();
489  application.Render();
490 
491  // Create a tap event on the second text editor.
492  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 125.0f ) ) );
493  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 125.0f ) ) );
494 
495  // Render and notify
496  application.SendNotification();
497  application.Render();
498 
499  // The second text editor has the focus. It should handle the key events.
500  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
501  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
502 
503  // Render and notify
504  application.SendNotification();
505  application.Render();
506 
507  // Check the text has been added to the second text editor.
508  DALI_TEST_EQUALS( editor2.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("aa"), TEST_LOCATION );
509 
510  END_TEST;
511 }
512 
514 {
515  ToolkitTestApplication application;
516  tet_infoline(" utcDaliTextEditorEvent02");
517 
518  // Checks if the right number of actors are created.
519 
520  TextEditor editor = TextEditor::New();
522  DALI_TEST_CHECK( editor );
523 
524  Stage::GetCurrent().Add( editor );
525 
526  editor.SetSize( 300.f, 50.f );
529 
530  // Avoid a crash when core load gl resources.
532 
533  // Render and notify
534  application.SendNotification();
535  application.Render();
536 
537  // Check there are the expected number of children ( active layer, offscreen root actor, and the offscreen image actor
539 
540  Actor layer = editor.GetChildAt( 0u );
541  DALI_TEST_CHECK( layer.IsLayer() );
542 
543  Actor offscreenRoot = editor.GetChildAt( 1u );
544  DALI_TEST_CHECK( offscreenRoot.IsLayer() );
545  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor.
546 
547  Actor offscreenImage = editor.GetChildAt( 2u );
548  ImageActor imageActor = ImageActor::DownCast( offscreenImage );
549  DALI_TEST_CHECK( imageActor );
550 
551  // Create a tap event to touch the text editor.
552  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
553  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
554 
555  // Render and notify
556  application.SendNotification();
557  application.Render();
558 
559  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
560  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor.
561 
562  // Now the text editor has the focus, so it can handle the key events.
563  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
564  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
565 
566  // Render and notify
567  application.SendNotification();
568  application.Render();
569 
570  // Checks the cursor and the renderer have been created.
571  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
572  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 2u, TEST_LOCATION ); // The camera actor and the renderer
573 
574  Control cursor = Control::DownCast( layer.GetChildAt( 0u ) );
575  DALI_TEST_CHECK( cursor );
576 
577  CameraActor camera = CameraActor::DownCast( offscreenRoot.GetChildAt( 0u ) );
578  DALI_TEST_CHECK( camera );
579 
580  Renderer renderer = offscreenRoot.GetChildAt( 1u ).GetRendererAt( 0u );
581  DALI_TEST_CHECK( renderer );
582 
583  // Move the cursor and check the position changes.
584  Vector3 position1 = cursor.GetCurrentPosition();
585 
588 
589  // Render and notify
590  application.SendNotification();
591  application.Render();
592 
593  Vector3 position2 = cursor.GetCurrentPosition();
594 
595  DALI_TEST_CHECK( position2.x < position1.x );
596 
599 
600  // Render and notify
601  application.SendNotification();
602  application.Render();
603 
604  Vector3 position3 = cursor.GetCurrentPosition();
605 
606  DALI_TEST_EQUALS( position1, position3, TEST_LOCATION ); // Should be in the same position1.
607 
608  // Send some taps and check the cursor positions.
609 
610  // Try to tap at the beginning.
611  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 1.f, 25.0f ) ) );
612  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 1.f, 25.0f ) ) );
613 
614  // Render and notify
615  application.SendNotification();
616  application.Render();
617 
618  // Cursor position should be the same than position1.
619  Vector3 position4 = cursor.GetCurrentPosition();
620 
621  DALI_TEST_EQUALS( position2, position4, TEST_LOCATION ); // Should be in the same position2.
622 
623  // Tap away from the start position.
624  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 16.f, 25.0f ) ) );
625  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 16.0f, 25.0f ) ) );
626 
627  // Render and notify
628  application.SendNotification();
629  application.Render();
630 
631  Vector3 position5 = cursor.GetCurrentPosition();
632 
633  DALI_TEST_CHECK( position5.x > position4.x );
634 
635  // Remove all the text.
639 
640  // Render and notify
641  application.SendNotification();
642  application.Render();
643 
644  // Cursor position should be the same than position2.
645  Vector3 position6 = cursor.GetCurrentPosition();
646 
647  DALI_TEST_EQUALS( position2, position6, TEST_LOCATION );// Should be in the same position2.
648 
649  // Should not be a renderer.
650  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor only.
651 
652  END_TEST;
653 }
654 
656 {
657  ToolkitTestApplication application;
658  tet_infoline(" utcDaliTextEditorEvent03");
659 
660  // Checks if the highlight actor is created.
661 
662  TextEditor editor = TextEditor::New();
663  DALI_TEST_CHECK( editor );
664 
665  Stage::GetCurrent().Add( editor );
666 
667  editor.SetProperty( TextEditor::Property::TEXT, "This is a long text for the size of the text-editor." );
669  editor.SetSize( 30.f, 50.f );
672 
673  // Avoid a crash when core load gl resources.
675 
676  // Render and notify
677  application.SendNotification();
678  application.Render();
679 
680  // Tap first to get the focus.
681  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
682  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
683 
684  // Render and notify
685  application.SendNotification();
686  application.Render();
687 
688  // Double tap to select a word.
689  application.ProcessEvent( GenerateTap( Gesture::Possible, 2u, 1u, Vector2( 3.f, 25.0f ) ) );
690  application.ProcessEvent( GenerateTap( Gesture::Started, 2u, 1u, Vector2( 3.f, 25.0f ) ) );
691 
692  // Render and notify
693  application.SendNotification();
694  application.Render();
695 
696  // The offscreen root actor should have three actors: the camera, a renderer and the highlight actor.
697  Actor offscreenRoot = editor.GetChildAt( 1u );
698  DALI_TEST_CHECK( offscreenRoot.IsLayer() );
699 
700  CameraActor camera = CameraActor::DownCast( offscreenRoot.GetChildAt( 0u ) );
701  DALI_TEST_CHECK( camera );
702 
703  Renderer renderer = offscreenRoot.GetChildAt( 1u ).GetRendererAt( 0u );
704  DALI_TEST_CHECK( renderer );
705 
706  Renderer highlight = offscreenRoot.GetChildAt( 2u ).GetRendererAt( 0u );
707  DALI_TEST_CHECK( highlight );
708 
709  END_TEST;
710 }
Dali Docs Home
Read more about Dali