Added Tooltip functionality to Control 43/103143/10
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 7 Dec 2016 10:45:58 +0000 (10:45 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 22 Dec 2016 18:32:09 +0000 (18:32 +0000)
Change-Id: I49fbb96bd31d3cf3cb06f959a8e4e380ba4b7120

21 files changed:
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp
automated-tests/src/dali-toolkit/utc-Dali-Tooltip.cpp [new file with mode: 0644]
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/devel-api/controls/control-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h [new file with mode: 0644]
dali-toolkit/devel-api/file.list
dali-toolkit/internal/controls/tooltip/tooltip.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/tooltip/tooltip.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/control.h
dali-toolkit/styles/1920x1080/dali-toolkit-default-theme.json
dali-toolkit/styles/480x800/dali-toolkit-default-theme.json
dali-toolkit/styles/images-common/tooltip-tail-above.png [new file with mode: 0644]
dali-toolkit/styles/images-common/tooltip-tail-below.png [new file with mode: 0644]
dali-toolkit/styles/images-common/tooltip.9.png [new file with mode: 0644]

index 681d677..4e59f15 100644 (file)
@@ -33,6 +33,7 @@ SET(TC_SOURCES
    utc-Dali-TextLabel.cpp
    utc-Dali-TextSelectionPopup.cpp
    utc-Dali-ToolBar.cpp
+   utc-Dali-Tooltip.cpp
    utc-Dali-TransitionData.cpp
    utc-Dali-Button.cpp
    utc-Dali-Control.cpp
index 2f1ce14..f46dacd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * 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.
@@ -35,6 +35,7 @@ class Timer;
 typedef IntrusivePtr<Timer> TimerPtr;
 
 Dali::Timer::TimerSignalType gTickSignal;
+int gTimerCount = 0;
 
 /**
  * Implementation of the timer
@@ -98,10 +99,12 @@ TimerPtr Timer::New( unsigned int milliSec )
 Timer::Timer( unsigned int milliSec )
 : mInterval( milliSec )
 {
+  ++gTimerCount;
 }
 
 Timer::~Timer()
 {
+  --gTimerCount;
 }
 
 void Timer::Start()
@@ -141,7 +144,11 @@ Dali::Timer::TimerSignalType& Timer::TickSignal()
 
 void Timer::MockEmitSignal()
 {
-  gTickSignal.Emit();
+  if( gTimerCount > 1 )
+  {
+    // Only emit the signal if we have more than just the timer created in the test function
+    gTickSignal.Emit();
+  }
 }
 
 
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Tooltip.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Tooltip.cpp
new file mode 100644 (file)
index 0000000..42f5d1c
--- /dev/null
@@ -0,0 +1,1182 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-timer.h>
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/popup/popup.h>
+#include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
+#include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void utc_dali_toolkit_tooltip_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_tooltip_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+
+Integration::HoverEvent GenerateSingleHover( TouchPoint::State state, const Vector2& screenPosition )
+{
+  Integration::HoverEvent hoverEvent;
+  Integration::Point point;
+  point.SetState( static_cast< PointState::Type >( state ) );
+  point.SetScreenPosition( screenPosition );
+  hoverEvent.points.push_back( point );
+  return hoverEvent;
+}
+
+} // unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliTooltipGetWithoutSetting(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map is empty" );
+  DALI_TEST_EQUALS( true, map->Empty(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithString(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Hello Test" );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the text item" );
+  Property::Value* textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( "Hello Test", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent valid text, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithTextVisualMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Visual::Property::TYPE, DevelVisual::TEXT )
+                                                           .Add( TextVisual::Property::TEXT, "Hello TextVisual Test" ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the text item" );
+  Property::Value* textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( "Hello TextVisual Test", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent a text visual with TEXT property set, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithTextVisualMapWithoutString(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Visual::Property::TYPE, DevelVisual::TEXT )
+                                                           .Add( TextVisual::Property::POINT_SIZE, 20 ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the point-size item" );
+  Property::Value* pointSizeValue = contentMap->Find( TextVisual::Property::POINT_SIZE );
+  DALI_TEST_CHECK( pointSizeValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( 20, pointSizeValue->Get< int >(), TEST_LOCATION );
+
+  tet_infoline( "We sent a text visual without a TEXT property set, so ensure the hover signal has NOT been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithImageVisualMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Visual::Property::TYPE, Visual::IMAGE )
+                                                           .Add( ImageVisual::Property::URL, "dummy-url.png" ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the url item" );
+  Property::Value* urlValue = contentMap->Find( ImageVisual::Property::URL );
+  DALI_TEST_CHECK( urlValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( "dummy-url.png", urlValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent an ImageVisual, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithArray(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Array().Add( Property::Map().Add( Visual::Property::TYPE, Visual::IMAGE )
+                                                             .Add( ImageVisual::Property::URL, "dummy-url.png" ) )
+                                        .Add( Property::Map().Add( Visual::Property::TYPE, DevelVisual::TEXT )
+                                                             .Add( TextVisual::Property::TEXT, "Hello Array Test" ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property array" );
+  Property::Array* contentArray = contentValue->GetArray();
+  DALI_TEST_CHECK( contentArray );
+
+  tet_infoline( "Ensure the array contains two items" );
+  DALI_TEST_EQUALS( 2u, contentArray->Count(), TEST_LOCATION );
+
+  tet_infoline( "Ensure first value is a map and contains the right item" );
+  const Property::Value mapValue1 = contentArray->GetElementAt( 0 );
+  Property::Map* map1 = mapValue1.GetMap();
+  DALI_TEST_CHECK( map1 );
+  Property::Value* urlValue = map1->Find( ImageVisual::Property::URL );
+  DALI_TEST_CHECK( urlValue );
+  DALI_TEST_EQUALS( "dummy-url.png", urlValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "Ensure second value is a map and contains the right item" );
+  const Property::Value mapValue2 = contentArray->GetElementAt( 1 );
+  Property::Map* map2 = mapValue2.GetMap();
+  DALI_TEST_CHECK( map2 );
+  Property::Value* textValue = map2->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textValue );
+  DALI_TEST_EQUALS( "Hello Array Test", textValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent an array, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithFullMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Visual::Property::TYPE, DevelVisual::TEXT )
+                                                           .Add( TextVisual::Property::TEXT, "Hello TextVisual Test" ) )
+                                      .Add( Tooltip::Property::LAYOUT, Vector2( 1.0f, 2.0f ) )
+                                      .Add( Tooltip::Property::WAIT_TIME, 2.5f )
+                                      .Add( Tooltip::Property::BACKGROUND, "tooltip-background.png" )
+                                      .Add( Tooltip::Property::TAIL, true )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::HOVER_POINT )
+                                      .Add( Tooltip::Property::HOVER_POINT_OFFSET, Vector2( 100.0f, 50.f ) )
+                                      .Add( Tooltip::Property::MOVEMENT_THRESHOLD, 50 )
+                                      .Add( Tooltip::Property::DISAPPEAR_ON_MOVEMENT, true )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check layout" );
+  Property::Value* layoutValue = map->Find( Tooltip::Property::LAYOUT );
+  DALI_TEST_CHECK( layoutValue );
+  DALI_TEST_EQUALS( layoutValue->Get< Vector2 >(), Vector2( 1.0f, 2.0f ), TEST_LOCATION );
+
+  tet_infoline( "Check wait time" );
+  Property::Value* waitTimeValue = map->Find( Tooltip::Property::WAIT_TIME );
+  DALI_TEST_CHECK( waitTimeValue );
+  DALI_TEST_EQUALS( waitTimeValue->Get< float >(), 2.5f, TEST_LOCATION );
+
+  tet_infoline( "Check background" );
+  Property::Value* backgroundMapValue = map->Find( Tooltip::Property::BACKGROUND );
+  DALI_TEST_CHECK( backgroundMapValue );
+  Property::Map* backgroundMap = backgroundMapValue->GetMap();
+  DALI_TEST_CHECK( backgroundMap );
+  Property::Value* backgroundStringValue = backgroundMap->Find( Tooltip::Background::Property::VISUAL );
+  DALI_TEST_CHECK( backgroundStringValue );
+  DALI_TEST_EQUALS( backgroundStringValue->Get< std::string >(), "tooltip-background.png", TEST_LOCATION );
+
+  tet_infoline( "Check Tail" );
+  Property::Value* tailMapValue = map->Find( Tooltip::Property::TAIL );
+  DALI_TEST_CHECK( tailMapValue );
+  Property::Map* tailMap = tailMapValue->GetMap();
+  DALI_TEST_CHECK( tailMap );
+  Property::Value* tailVisibilityValue = tailMap->Find( Tooltip::Tail::Property::VISIBILITY );
+  DALI_TEST_CHECK( tailVisibilityValue );
+  DALI_TEST_EQUALS( tailVisibilityValue->Get< bool >(), true, TEST_LOCATION );
+
+  tet_infoline( "Check position" );
+  Property::Value* positionValue = map->Find( Tooltip::Property::POSITION );
+  DALI_TEST_CHECK( positionValue );
+  DALI_TEST_EQUALS( positionValue->Get< int >(), static_cast< int >( Tooltip::Position::HOVER_POINT ), TEST_LOCATION );
+
+  tet_infoline( "Check hover point offset" );
+  Property::Value* hoverPointOffsetValue = map->Find( Tooltip::Property::HOVER_POINT_OFFSET );
+  DALI_TEST_CHECK( hoverPointOffsetValue );
+  DALI_TEST_EQUALS( hoverPointOffsetValue->Get< Vector2 >(), Vector2( 100.0f, 50.f ), TEST_LOCATION );
+
+  tet_infoline( "Check movement threshold" );
+  Property::Value* movementThresholdValue = map->Find( Tooltip::Property::MOVEMENT_THRESHOLD );
+  DALI_TEST_CHECK( movementThresholdValue );
+  DALI_TEST_EQUALS( movementThresholdValue->Get< int >(), 50, TEST_LOCATION );
+
+  tet_infoline( "Check disappear on movement" );
+  Property::Value* disappearOnMovementValue = map->Find( Tooltip::Property::DISAPPEAR_ON_MOVEMENT );
+  DALI_TEST_CHECK( disappearOnMovementValue );
+  DALI_TEST_EQUALS( disappearOnMovementValue->Get< bool >(), true, TEST_LOCATION );
+
+  tet_infoline( "We sent a text visual with TEXT property set, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithBackgroundMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Hello TextVisual Test" )
+                                      .Add( Tooltip::Property::BACKGROUND,
+                                            Property::Map().Add( Tooltip::Background::Property::VISUAL, "tooltip-background.png" )
+                                                           .Add( Tooltip::Background::Property::BORDER, Rect< int >( 10, 20, 30, 40 ) ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check background map" );
+  Property::Value* backgroundMapValue = map->Find( Tooltip::Property::BACKGROUND );
+  DALI_TEST_CHECK( backgroundMapValue );
+  Property::Map* backgroundMap = backgroundMapValue->GetMap();
+  DALI_TEST_CHECK( backgroundMap );
+
+  tet_infoline( "Check visual" );
+  Property::Value* backgroundStringValue = backgroundMap->Find( Tooltip::Background::Property::VISUAL );
+  DALI_TEST_CHECK( backgroundStringValue );
+  DALI_TEST_EQUALS( backgroundStringValue->Get< std::string >(), "tooltip-background.png", TEST_LOCATION );
+
+  tet_infoline( "Check border" );
+  Property::Value* borderValue = backgroundMap->Find( Tooltip::Background::Property::BORDER );
+  DALI_TEST_CHECK( borderValue );
+  DALI_TEST_EQUALS( borderValue->Get< Rect< int > >(), Rect< int >( 10, 20, 30, 40 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithBackgroundMapVector4(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Hello TextVisual Test" )
+                                      .Add( Tooltip::Property::BACKGROUND,
+                                            Property::Map().Add( Tooltip::Background::Property::VISUAL, "tooltip-background.png" )
+                                                           .Add( Tooltip::Background::Property::BORDER, Vector4( 40.0f, 30.0f, 20.0f, 10.0f ) ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check background map" );
+  Property::Value* backgroundMapValue = map->Find( Tooltip::Property::BACKGROUND );
+  DALI_TEST_CHECK( backgroundMapValue );
+  Property::Map* backgroundMap = backgroundMapValue->GetMap();
+  DALI_TEST_CHECK( backgroundMap );
+
+  tet_infoline( "Check visual" );
+  Property::Value* backgroundStringValue = backgroundMap->Find( Tooltip::Background::Property::VISUAL );
+  DALI_TEST_CHECK( backgroundStringValue );
+  DALI_TEST_EQUALS( backgroundStringValue->Get< std::string >(), "tooltip-background.png", TEST_LOCATION );
+
+  tet_infoline( "Check border" );
+  Property::Value* borderValue = backgroundMap->Find( Tooltip::Background::Property::BORDER );
+  DALI_TEST_CHECK( borderValue );
+  DALI_TEST_EQUALS( borderValue->Get< Rect< int > >(), Rect< int >( 40, 30, 20, 10 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithTailMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Hello TextVisual Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ))
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check Tail" );
+  Property::Value* tailMapValue = map->Find( Tooltip::Property::TAIL );
+  DALI_TEST_CHECK( tailMapValue );
+  Property::Map* tailMap = tailMapValue->GetMap();
+  DALI_TEST_CHECK( tailMap );
+
+  tet_infoline( "Check visibility" );
+  Property::Value* tailVisibilityValue = tailMap->Find( Tooltip::Tail::Property::VISIBILITY );
+  DALI_TEST_CHECK( tailVisibilityValue );
+  DALI_TEST_EQUALS( tailVisibilityValue->Get< bool >(), true, TEST_LOCATION );
+
+  tet_infoline( "Check above visual" );
+  Property::Value* aboveVisualValue = tailMap->Find( Tooltip::Tail::Property::ABOVE_VISUAL );
+  DALI_TEST_CHECK( aboveVisualValue );
+  DALI_TEST_EQUALS( aboveVisualValue->Get< std::string >(), "above-visual.png", TEST_LOCATION );
+
+  tet_infoline( "Check below visual" );
+  Property::Value* belowVisualValue = tailMap->Find( Tooltip::Tail::Property::BELOW_VISUAL );
+  DALI_TEST_CHECK( belowVisualValue );
+  DALI_TEST_EQUALS( belowVisualValue->Get< std::string >(), "below-visual.png", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplay(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Stationary, centerPoint ) ); // Emit for code coverage, will have no effect
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayWithTail(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ))
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayWithContentArray(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Array().Add( Property::Map().Add( Visual::Property::TYPE, Visual::IMAGE )
+                                                                                  .Add( ImageVisual::Property::URL, "dummy-url.png" ) )
+                                                             .Add( Property::Map().Add( Visual::Property::TYPE, DevelVisual::TEXT )
+                                                                                  .Add( TextVisual::Property::TEXT, "Hello Array Test" ) ))
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ))
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayBelow(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+
+  tet_infoline( "Ensure tooltip is below control" );
+  DALI_TEST_CHECK( ( control.GetCurrentWorldPosition().y + 50.0f /* Half Size */) < tooltip.GetCurrentWorldPosition().y );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayAbove(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::ABOVE )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+
+  tet_infoline( "Ensure tooltip is above control" );
+  DALI_TEST_CHECK( ( control.GetCurrentWorldPosition().y - 50.0f /* Half Size */) >= ( tooltip.GetCurrentWorldPosition().y + 0.5f * tooltip.GetCurrentSize().height ) );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayAtHoverPoint(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::HOVER_POINT )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  const Vector2 stageSize = Stage::GetCurrent().GetSize();
+  Vector2 hoverPoint = stageSize * 0.5f;
+  hoverPoint.x -= 10.0f;
+  hoverPoint.y -= 10.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+
+  tet_infoline( "Ensure tooltip is below and to the right of control" );
+  DALI_TEST_CHECK( ( hoverPoint.y - stageSize.height * 0.5f ) < tooltip.GetCurrentWorldPosition().y );
+  DALI_TEST_CHECK( ( hoverPoint.x - stageSize.width  * 0.5f ) < tooltip.GetCurrentWorldPosition().x );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipExceedThreshold(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::MOVEMENT_THRESHOLD, 5 )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  tet_infoline( "Start hover" );
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit a value which exceeds threshold, timer should start again" );
+  hoverPoint.x += 10.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit Timer signal - timeout at new point which is still within bounds" );
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipGoOutOfBounds(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  tet_infoline( "Start hover" );
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit a value which goes out of bounds" );
+  hoverPoint.x += 100.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit Timer signal - nothing should happen" );
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should be the same as before" );
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipHideTooltipWhenOutOfBounds(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  hoverPoint.x += 100.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should be back to what was there before the tooltip was shown" );
+  --rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipHideTooltipWhenSetToDisapperOnMovement(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::DISAPPEAR_ON_MOVEMENT, true )
+                                      .Add( Tooltip::Property::MOVEMENT_THRESHOLD, 5 )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  hoverPoint.x += 10.0f; // Stay within bounds but exceed threshold
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should be back to what was there before the tooltip was shown" );
+  --rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipChangeContent(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  tet_infoline( "Change content while timer is running and ensure it matches the new value" );
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Second Value" );
+
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+  Property::Value* textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+  DALI_TEST_EQUALS( "Second Value", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "Emit signal, nothing should happen as everything has been reset" );
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, there should NOT be any new actors" );
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  tet_infoline( "More movement at same point, and emit signal, we should get the tooltip" );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, centerPoint ) );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  tet_infoline( "Change content while tooltip is showing, current one should be removed from the stage and ensure it matches new value" );
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Third Value" );
+
+  value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+  map = value.GetMap();
+  DALI_TEST_CHECK( map );
+  contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+  contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+  textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+  DALI_TEST_EQUALS( "Third Value", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "Emit signal, nothing should happen as everything has been reset" );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, there should be one less actor on the stage" );
+  --rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage1(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  tet_infoline( "Create a control and place it at the bottom of the screen, setting the tooltip to appear below" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+  control.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = stageSize * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().y + tooltip.GetCurrentSize().height * 0.5f ) <= centerPoint.height );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage2(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  tet_infoline( "Create a control and place it at the top of the screen, setting the tooltip to appear above" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+  control.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::ABOVE )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = stageSize * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().y - tooltip.GetCurrentSize().height * 0.5f ) >= -centerPoint.height );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage3(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  Vector2 centerPoint = stageSize * 0.5f;
+
+  tet_infoline( "Create a control and adjust it's position so that the tooltip will attempt to appear to the left of the screen" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+  control.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+  control.SetX( -centerPoint.x );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 hoverPoint( centerPoint );
+  hoverPoint.x = 1.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().x - tooltip.GetCurrentSize().width * 0.5f ) >= -centerPoint.width );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage4(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  Vector2 centerPoint = stageSize * 0.5f;
+
+  tet_infoline( "Create a control and adjust it's position so that the tooltip will attempt to appear to the right of the screen" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+  control.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+  control.SetX( centerPoint.x );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 hoverPoint( centerPoint );
+  hoverPoint.x = 1.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().x + tooltip.GetCurrentSize().width * 0.5f ) <= centerPoint.width );
+
+  END_TEST;
+}
index 2b80acf..67b723c 100644 (file)
@@ -118,6 +118,7 @@ develapiscriptingdir =          $(develapidir)/scripting
 develapishadereffectsdir =      $(develapidir)/shader-effects
 develapitransitioneffectsdir =  $(develapidir)/transition-effects
 develapitoolbardir =            $(develapicontrolsdir)/tool-bar
+develapitooltipdir =            $(develapicontrolsdir)/tooltip
 develapitextselectionpopupdir = $(develapicontrolsdir)/text-controls
 develapivisualfactorydir =      $(develapidir)/visual-factory
 develapivisualsdir =            $(develapidir)/visuals
@@ -146,6 +147,7 @@ develapishadowview_HEADERS =        $(devel_api_shadow_view_header_files)
 develapishadereffects_HEADERS =     $(devel_api_shader_effects_header_files)
 develapisuperblurview_HEADERS =     $(devel_api_super_blur_view_header_files)
 develapitoolbar_HEADERS =           $(devel_api_tool_bar_header_files)
+develapitooltip_HEADERS =           $(devel_api_tooltip_header_files)
 develapitransitioneffects_HEADERS = $(devel_api_transition_effects_header_files)
 develapitextselectionpopup_HEADERS = $(devel_api_text_controls_header_files)
 
diff --git a/dali-toolkit/devel-api/controls/control-devel.h b/dali-toolkit/devel-api/controls/control-devel.h
new file mode 100644 (file)
index 0000000..71071db
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_TOOLKIT_CONTROL_DEVEL_H
+#define DALI_TOOLKIT_CONTROL_DEVEL_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 <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelControl
+{
+
+namespace Property
+{
+
+enum
+{
+  STYLE_NAME        = Control::Property::STYLE_NAME,
+  BACKGROUND_COLOR  = Control::Property::BACKGROUND_COLOR,
+  BACKGROUND_IMAGE  = Control::Property::BACKGROUND_IMAGE,
+  KEY_INPUT_FOCUS   = Control::Property::KEY_INPUT_FOCUS,
+  BACKGROUND        = Control::Property::BACKGROUND,
+
+  /**
+   * @brief Displays a tooltip when the control is hovered over.
+   * @details Name "tooltip", type Property::STRING, Property::ARRAY or Property::MAP.
+   *          If Property::STRING, then the style specified in the stylesheet is used.
+   *          If Property::ARRAY of Visuals then all are displayed in one row.
+   *          If Property::MAP, then it should be a map of Tooltip properties.
+   * @note The tooltip is only activated if display content is received, i.e. a string (text) or visual to show.
+   *       The rest is used to just build up the style of the tooltip (i.e. background, text color/point-size etc.)
+   * @note When retrieved, a Property::MAP is returned.
+   * @see Toolkit::Tooltip
+   */
+  TOOLTIP = BACKGROUND + 1,
+};
+
+} // namespace Property
+
+} // namespace DevelControl
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_DEVEL_H
diff --git a/dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h b/dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h
new file mode 100644 (file)
index 0000000..d473cec
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef DALI_TOOLKIT_TOOLTIP_PROPERTIES_H
+#define DALI_TOOLKIT_TOOLTIP_PROPERTIES_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Tooltip
+{
+
+/**
+ * @brief The properties used for a Tooltip.
+ */
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief The content to display.
+   * @details Name "content", type Property::STRING, Property::MAP or Property::ARRAY.
+   *          If Property::STRING is used, then the string is shown as a text and the default font style for a Tooltip will be used.
+   *          This can be overridden by passing in a Property::MAP of TextVisual properties. For text styling purposes, a Property::MAP excluding the TEXT property can be sent.
+   *          If a different Visual is required, then a Property::MAP defining that visual can be set.
+   *          If more than one visual is required, then a Property::ARRAY can be used. The contents are added to the layout as per their order in the array. Text has to be styled in the visual passed in (default toolkit style will not be used).
+   * @note Mandatory.
+   * @note If set using Property::STRING, then when retrieved, a Property::MAP is returned.
+   *       If set using a Property::MAP or Property::ARRAY, then the appropriate type is returned.
+   * @see Toolkit::TextVisual
+   */
+  CONTENT = CORE_PROPERTY_MAX_INDEX + 1,
+
+  /**
+   * @brief The layout of the content.
+   * @details Name "layout", type Property::VECTOR2.
+   *          The number of rows and columns expected.
+   *          ( 1, 2 ) means 1 row, 2 columns so the content will have two items placed on one row.
+   *          ( 2, 2 ) means 2 rows, 2 columns so the content will have 4 items with two items placed on each row.
+   * @note Optional.
+   * @note If not provided, the default is to put all items in the same row.
+   */
+  LAYOUT,
+
+  /**
+   * @brief Time to wait in seconds before a tooltip is shown while the is movement is within the allowed threshold.
+   * @details Name "waitTime", type Property::FLOAT.
+   * @note Optional.
+   * @note If not provided, the default is 0.5 seconds.
+   */
+  WAIT_TIME,
+
+  /**
+   * @brief The background of the tooltip.
+   * @details Name "background", type Property::STRING or Property::MAP.
+   *          If Property::STRING, then the path to the image is required and it's assumed that there are no borders.
+   * @note Optional.
+   * @note If not provided, the default is taken from the stylesheet.
+   * @note When retrieved, a Property::MAP is returned.
+   * @see Tooltip::Background
+   */
+  BACKGROUND,
+
+  /**
+   * @brief The tail used by the tooltip.
+   * @details Name "tail", type Property::BOOLEAN or Property::MAP.
+   *          If Property::BOOLEAN and true, then the default visuals are used for the tail.
+   *          A Property::MAP can be used to override the visuals for the tail.
+   * @note Optional.
+   * @note The default is false, i.e. to not show a tail.
+   * @note When retrieved, a Property::MAP is returned.
+   * @note If the popup has to be moved because it goes out of bounds, then the tail is not shown regardless of whether it is set or not.
+   * @see Tooltip::Tail
+   */
+  TAIL,
+
+  /**
+   * @brief The position of the tooltip in relation to the control.
+   * @details Name "position", type Tooltip::Position::Type (Property::INTEGER) or Property::STRING.
+   * @note Optional.
+   * @note If not provided, the default is Tooltip::Position::BELOW.
+   * @note When retrieved, a Tooltip::Position::Type (Property::INTEGER) is returned.
+   */
+  POSITION,
+
+  /**
+   * @brief If Tooltip::Position::HOVER_POINT is used for the POSITION, then this is the offset the tooltip is displayed at from the hover point.
+   * @details Name "hoverPointOffset", type Property::VECTOR2.
+   * @note Optional.
+   * @note If not provided, the default is Vector2( 10.0f, 10.0f ).
+   */
+  HOVER_POINT_OFFSET,
+
+  /**
+   * @brief The movement threshold allowed before showing (or hiding a popup).
+   * @details Name "movementThreshold", type Property::INTEGER.
+   *          This value is used as the threshold to hide the popup as well if DISAPPEAR_ON_MOVEMENT is set to true.
+   * @note Optional.
+   * @note If not provided, the default is 5.
+   */
+  MOVEMENT_THRESHOLD,
+
+  /**
+   * @brief If true, the tooltip will disappear after hover movement beyond a certain distance.
+   * @details Name "disappearOnMovement", type Property::BOOLEAN.
+   * @note Optional.
+   * @note If not provided, the default is to disappear only when moving out of bounds of the control.
+   */
+  DISAPPEAR_ON_MOVEMENT,
+};
+
+} // namespace Property
+
+namespace Background
+{
+
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief The image to use as the background.
+   * @details Name "visual", type Property::STRING.
+   */
+  VISUAL,
+
+  /**
+   * @brief The size of the borders in the order: left, right, bottom, top.
+   * @details Name "border", type Property::RECTANGLE.
+   *          This is different from the nPatch border as the it will place the content within the bounds specified.
+   *          For example, there could be some round corners in the image used and we may not want the content going over the rounded corners.
+   * @note Optional.
+   * @note If not provided, then then it is assumed that the image does not have a border.
+   */
+  BORDER
+};
+
+} // namespace Property
+
+} // namespace Background
+
+/**
+ * @brief The tail used by the tooltip.
+ */
+namespace Tail
+{
+
+/**
+ * @brief The properties of the tail used by the tooltip.
+ */
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief Whether to show the tail or not.
+   * @details Name "visibility", type Property::BOOLEAN.
+   * @note Optional.
+   * @note If the popup has to be moved because it goes out of bounds, then the tail is not shown regardless of whether it is set or not.
+   */
+  VISIBILITY,
+
+  /**
+   * @brief The image used for the tail if it is above the tooltip.
+   * @details Name "aboveVisual", type Property::STRING.
+   */
+  ABOVE_VISUAL,
+
+  /**
+   * @brief The image used for the tail if it is below the tooltip.
+   * @details Name "belowVisual", type Property::STRING.
+   */
+  BELOW_VISUAL
+};
+
+} // namespace Property
+
+} // namespace Tail
+
+namespace Position
+{
+
+/**
+ * @brief The position of the tooltip in relation to the control.
+ */
+enum Type
+{
+  ABOVE, ///< The tooltip will appear above the control.
+  BELOW, ///< The tooltip will appear below the control.
+  HOVER_POINT ///< The tooltip will appear near the hover point.
+};
+
+} // namespace Position
+
+} // namespace Tooltip
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TOOLTIP_PROPERTIES_H
index 48cc2aa..a67e25b 100644 (file)
@@ -42,6 +42,7 @@ devel_api_header_files = \
 
 devel_api_controls_header_files = \
   $(devel_api_src_dir)/controls/control-depth-index-ranges.h \
+  $(devel_api_src_dir)/controls/control-devel.h \
   $(devel_api_src_dir)/controls/control-wrapper.h \
   $(devel_api_src_dir)/controls/control-wrapper-impl.h
 
@@ -126,6 +127,9 @@ devel_api_text_controls_header_files = \
 devel_api_tool_bar_header_files = \
   $(devel_api_src_dir)/controls/tool-bar/tool-bar.h
 
+devel_api_tooltip_header_files = \
+  $(devel_api_src_dir)/controls/tooltip/tooltip-properties.h
+
 devel_api_transition_effects_header_files = \
   $(devel_api_src_dir)/transition-effects/cube-transition-effect.h \
   $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.h \
diff --git a/dali-toolkit/internal/controls/tooltip/tooltip.cpp b/dali-toolkit/internal/controls/tooltip/tooltip.cpp
new file mode 100644 (file)
index 0000000..be1017f
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * 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 <dali-toolkit/internal/controls/tooltip/tooltip.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/hover-event.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
+#include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/controls/popup/popup-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( TOOLTIP_POSITION )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Tooltip::Position, ABOVE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Tooltip::Position, BELOW )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Tooltip::Position, HOVER_POINT )
+DALI_ENUM_TO_STRING_TABLE_END( TOOLTIP_POSITION )
+
+const float MILLISECONDS_PER_SECOND = 1000.0f;
+
+const char * const PROPERTY_CONTENT_NAME              = "content";
+const char * const PROPERTY_LAYOUT_NAME               = "layout";
+const char * const PROPERTY_WAIT_TIME_NAME            = "waitTime";
+const char * const PROPERTY_BACKGROUND_NAME           = "background";
+const char * const PROPERTY_TAIL_NAME                 = "tail";
+const char * const PROPERTY_POSITION_NAME             = "position";
+const char * const PROPERTY_HOVER_POINT_OFFSET_NAME   = "hoverPointOffset";
+const char * const PROPERTY_MOVEMENT_THRESHOLD        = "movementThreshold";
+const char * const PROPERTY_DISAPPEAR_ON_MOVEMENT     = "disappearOnMovement";
+
+const char * const PROPERTY_BACKGROUND_VISUAL         = "visual";
+const char * const PROPERTY_BACKGROUND_BORDER         = "border";
+
+const char * const PROPERTY_TAIL_VISIBILITY           = "visibility";
+const char * const PROPERTY_TAIL_ABOVE_VISUAL         = "aboveVisual";
+const char * const PROPERTY_TAIL_BELOW_VISUAL         = "belowVisual";
+
+} // unnamed namespace
+
+TooltipPtr Tooltip::New( Toolkit::Control control )
+{
+  return new Tooltip( control );
+}
+
+void Tooltip::SetProperties( const Property::Value& value )
+{
+  Toolkit::Control control = mControl.GetHandle();
+  if( control )
+  {
+    Property::Map* properties = value.GetMap();
+    if( properties )
+    {
+      const Property::Map::SizeType count = properties->Count();
+      for( Property::Map::SizeType position = 0; position < count; ++position )
+      {
+        KeyValuePair keyValue = properties->GetKeyValue( position );
+        Property::Key& key = keyValue.first;
+        Property::Value& value = keyValue.second;
+
+        if( key == Toolkit::Tooltip::Property::CONTENT || key == PROPERTY_CONTENT_NAME )
+        {
+          SetContent( control, value );
+        }
+        else if( key == Toolkit::Tooltip::Property::LAYOUT || key == PROPERTY_LAYOUT_NAME )
+        {
+          value.Get( mLayout );
+        }
+        else if( key == Toolkit::Tooltip::Property::WAIT_TIME || key == PROPERTY_WAIT_TIME_NAME )
+        {
+          float waitTime = 0.0f;
+          if( value.Get( waitTime ) )
+          {
+            mWaitTime = waitTime * MILLISECONDS_PER_SECOND;
+          }
+        }
+        else if( key == Toolkit::Tooltip::Property::BACKGROUND || key == PROPERTY_BACKGROUND_NAME )
+        {
+          SetBackground( value );
+        }
+        else if( key == Toolkit::Tooltip::Property::TAIL || key == PROPERTY_TAIL_NAME )
+        {
+          SetTail( value );
+        }
+        else if( key == Toolkit::Tooltip::Property::POSITION || key == PROPERTY_POSITION_NAME )
+        {
+          Scripting::GetEnumerationProperty< Toolkit::Tooltip::Position::Type >( value, TOOLTIP_POSITION_TABLE, TOOLTIP_POSITION_TABLE_COUNT, mPositionType );
+        }
+        else if( key == Toolkit::Tooltip::Property::HOVER_POINT_OFFSET || key == PROPERTY_HOVER_POINT_OFFSET_NAME )
+        {
+          value.Get( mHoverPointOffset );
+        }
+        else if( key == Toolkit::Tooltip::Property::MOVEMENT_THRESHOLD || key == PROPERTY_MOVEMENT_THRESHOLD )
+        {
+          value.Get( mMovementThreshold );
+        }
+        else if( key == Toolkit::Tooltip::Property::DISAPPEAR_ON_MOVEMENT || key == PROPERTY_DISAPPEAR_ON_MOVEMENT )
+        {
+          value.Get( mDisappearOnMovement );
+        }
+      }
+    }
+    else
+    {
+      Property::Type type = value.GetType();
+      if( ( value.GetType() == Property::STRING ) || ( type == Property::ARRAY ) )
+      {
+        SetContent( control, value );
+      }
+    }
+  }
+}
+
+void Tooltip::CreatePropertyMap( Property::Map& map ) const
+{
+  if( ! mContentTextVisual.Empty() )
+  {
+    Property::Map content = mContentTextVisual; // Need this copy as there's no Value constructor which takes in a 'const Property::Map&'.
+    map.Insert( Toolkit::Tooltip::Property::CONTENT, content );
+  }
+  else if( ! mContentArray.Empty() )
+  {
+    Property::Array content = mContentArray; // Need this copy as there's no Value constructor which takes in a 'const Property::Array&'.
+    map.Insert( Toolkit::Tooltip::Property::CONTENT, content );
+  }
+
+  map.Insert( Toolkit::Tooltip::Property::LAYOUT, mLayout );
+  map.Insert( Toolkit::Tooltip::Property::WAIT_TIME, static_cast<float>( mWaitTime ) / MILLISECONDS_PER_SECOND );
+  map.Insert( Toolkit::Tooltip::Property::BACKGROUND,
+              Property::Map().Add( Toolkit::Tooltip::Background::Property::VISUAL, mBackgroundImage )
+                             .Add( Toolkit::Tooltip::Background::Property::BORDER, mBackgroundBorder ) );
+  map.Insert( Toolkit::Tooltip::Property::TAIL,
+              Property::Map().Add( Toolkit::Tooltip::Tail::Property::VISIBILITY, mTailVisibility )
+                             .Add( Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL, mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ])
+                             .Add( Toolkit::Tooltip::Tail::Property::BELOW_VISUAL, mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ]) );
+  map.Insert( Toolkit::Tooltip::Property::POSITION, mPositionType );
+  map.Insert( Toolkit::Tooltip::Property::HOVER_POINT_OFFSET, mHoverPointOffset );
+  map.Insert( Toolkit::Tooltip::Property::MOVEMENT_THRESHOLD, mMovementThreshold );
+  map.Insert( Toolkit::Tooltip::Property::DISAPPEAR_ON_MOVEMENT, mDisappearOnMovement );
+}
+
+Tooltip::Tooltip( Toolkit::Control control )
+: mPopup(),
+  mTooltipTimer(),
+  mControl( control ),
+  mContentTextVisual(),
+  mTailImages(),
+  mContentArray(),
+  mBackgroundBorder( 0, 0, 0, 0 ),
+  mLayout( 1, 1 ),
+  mHoverPoint(),
+  mHoverPointOffset( 10.0f, 10.0f ),
+  mBackgroundImage(),
+  mMovementThreshold( 5.0f ),
+  mWaitTime( 500 ),
+  mPositionType( Toolkit::Tooltip::Position::ABOVE ),
+  mTailVisibility( false ),
+  mDisappearOnMovement( false ),
+  mSignalsConnected( false )
+{
+  mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ] = "";
+  mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ] = "";
+}
+
+Tooltip::~Tooltip()
+{
+  if( mPopup )
+  {
+    mPopup.Unparent();
+    mPopup.Reset();
+  }
+}
+
+void Tooltip::SetContent( Toolkit::Control& control, const Property::Value& value )
+{
+  // Delete popup & timer
+
+  if( mTooltipTimer )
+  {
+    mTooltipTimer.Stop();
+    mTooltipTimer.Reset();
+  }
+
+  if( mPopup )
+  {
+    mPopup.Unparent();
+    mPopup.Reset();
+  }
+
+  bool connectSignals = false;
+
+  Property::Type type = value.GetType();
+  if( type == Property::MAP )
+  {
+    Property::Map* map = value.GetMap();
+    if( map )
+    {
+      mContentTextVisual.Merge( *map );
+
+      Property::Value* typeValue = map->Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE );
+      if( typeValue )
+      {
+        // Set to an invalid value so it definitely changes if set in Scripting::GetEnumerationProperty
+        Toolkit::DevelVisual::Type visualType = static_cast< Toolkit::DevelVisual::Type >( -1 );
+
+        if( Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, visualType ) )
+        {
+          if( visualType == Toolkit::DevelVisual::TEXT )
+          {
+            // Visual Type is text, ensure we have a the TEXT property set before we connect to the signals.
+
+            if( map->Find( Toolkit::TextVisual::Property::TEXT, TEXT_PROPERTY ) )
+            {
+              mContentArray.Clear();
+              connectSignals = true;
+            }
+          }
+          else
+          {
+            // Visual Type is not text, so connect to the signals as we're displaying a non text visual.
+
+            mContentArray.Clear();
+            connectSignals = true;
+          }
+        }
+      }
+    }
+  }
+  else if( type == Property::ARRAY )
+  {
+    if( value.Get( mContentArray ) )
+    {
+      mContentTextVisual.Clear();
+      connectSignals = true;
+    }
+  }
+  else if( type == Property::STRING )
+  {
+    std::string text;
+    if( value.Get( text ) )
+    {
+      mContentTextVisual[ Toolkit::TextVisual::Property::TEXT ] = text;
+      mContentTextVisual[ Toolkit::Visual::Property::TYPE ] = DevelVisual::TEXT;
+      mContentArray.Clear();
+      connectSignals = true;
+    }
+  }
+
+  if( connectSignals && ! mSignalsConnected )
+  {
+    control.HoveredSignal().Connect( this, &Tooltip::OnHovered );
+    control.SetLeaveRequired( true );
+    mSignalsConnected = true;
+  }
+}
+
+void Tooltip::SetBackground( const Property::Value& value )
+{
+  Property::Type type = value.GetType();
+
+  if( type == Property::STRING )
+  {
+    value.Get( mBackgroundImage );
+    mBackgroundBorder.Set( 0, 0, 0, 0 );
+  }
+  else if( type == Property::MAP )
+  {
+    Property::Map* map = value.GetMap();
+    if( map )
+    {
+      const Property::Map::SizeType count = map->Count();
+      for( Property::Map::SizeType position = 0; position < count; ++position )
+      {
+        KeyValuePair keyValue = map->GetKeyValue( position );
+        Property::Key& key = keyValue.first;
+        Property::Value& value = keyValue.second;
+
+        if( key == Toolkit::Tooltip::Background::Property::VISUAL || key == PROPERTY_BACKGROUND_VISUAL )
+        {
+          value.Get( mBackgroundImage );
+        }
+        else if( key == Toolkit::Tooltip::Background::Property::BORDER || key == PROPERTY_BACKGROUND_BORDER )
+        {
+          if( ! value.Get( mBackgroundBorder ) )
+          {
+            // If not a Property::RECTANGLE, then check if it's a Vector4 and set it accordingly
+            Vector4 valueVector4;
+            if( value.Get( valueVector4 ) )
+            {
+              mBackgroundBorder.left   = valueVector4.x;
+              mBackgroundBorder.right  = valueVector4.y;
+              mBackgroundBorder.bottom = valueVector4.z;
+              mBackgroundBorder.top    = valueVector4.w;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+void Tooltip::SetTail( const Property::Value& value )
+{
+  Property::Type type = value.GetType();
+
+  if( type == Property::BOOLEAN )
+  {
+    value.Get( mTailVisibility );
+  }
+  else if( type == Property::MAP )
+  {
+    Property::Map map;
+    if( value.Get( map ) )
+    {
+      const Property::Map::SizeType count = map.Count();
+      for( Property::Map::SizeType position = 0; position < count; ++position )
+      {
+        KeyValuePair keyValue = map.GetKeyValue( position );
+        Property::Key& key = keyValue.first;
+        Property::Value& value = keyValue.second;
+
+        // Set the values manually rather than merging so that we only have to deal with Property indices when creating the actual tooltip.
+
+        if( key == Toolkit::Tooltip::Tail::Property::VISIBILITY || key == PROPERTY_TAIL_VISIBILITY )
+        {
+          value.Get( mTailVisibility );
+        }
+        else if( key == Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL || key == PROPERTY_TAIL_ABOVE_VISUAL )
+        {
+          std::string path;
+          if( value.Get( path ) )
+          {
+            mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ] = path;
+          }
+        }
+        else if( key == Toolkit::Tooltip::Tail::Property::BELOW_VISUAL || key == PROPERTY_TAIL_BELOW_VISUAL )
+        {
+          std::string path;
+          if( value.Get( path ) )
+          {
+            mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ] = path;
+          }
+        }
+      }
+    }
+  }
+}
+
+bool Tooltip::OnHovered( Actor /* actor */, const HoverEvent& hover )
+{
+  const TouchPoint::State state = hover.points[0].state;
+  switch( state )
+  {
+    case TouchPoint::Started:
+    case TouchPoint::Motion:
+    {
+      if( ! mPopup )
+      {
+        if( ! mTooltipTimer )
+        {
+          mHoverPoint = hover.points[ 0 ].screen;
+          mTooltipTimer = Timer::New( mWaitTime );
+          mTooltipTimer.TickSignal().Connect( this, &Tooltip::OnTimeout );
+          mTooltipTimer.Start();
+        }
+        else
+        {
+          Vector2 movement = mHoverPoint - hover.points[ 0 ].screen;
+          if( std::abs( movement.Length() ) > mMovementThreshold )
+          {
+            mTooltipTimer.Stop();
+            mTooltipTimer.Reset();
+
+            mHoverPoint = hover.points[ 0 ].screen;
+            mTooltipTimer = Timer::New( mWaitTime );
+            mTooltipTimer.TickSignal().Connect( this, &Tooltip::OnTimeout );
+            mTooltipTimer.Start();
+          }
+        }
+      }
+      else if( mDisappearOnMovement )
+      {
+        // Popup is showing, and we're set to disappear on excessive movement so make sure we're still within the threshold.
+
+        Vector2 movement = mHoverPoint - hover.points[ 0 ].screen;
+        if( std::abs( movement.Length() ) > mMovementThreshold )
+        {
+          // Exceeding the threshold, hide the popup.
+
+          if( mTooltipTimer )
+          {
+            mTooltipTimer.Stop();
+            mTooltipTimer.Reset();
+          }
+          if( mPopup )
+          {
+            mPopup.Unparent();
+            mPopup.Reset();
+          }
+        }
+      }
+      break;
+    }
+    case TouchPoint::Finished:
+    case TouchPoint::Leave:
+    case TouchPoint::Interrupted:
+    {
+      if( mTooltipTimer )
+      {
+        mTooltipTimer.Stop();
+        mTooltipTimer.Reset();
+      }
+      if( mPopup )
+      {
+        mPopup.Unparent();
+        mPopup.Reset();
+      }
+      break;
+    }
+
+    case TouchPoint::Stationary:
+    case TouchPoint::Last:
+    {
+      break;
+    }
+  }
+
+  return true;
+}
+
+bool Tooltip::OnTimeout()
+{
+  Toolkit::Control control = mControl.GetHandle();
+  if( ! mPopup && control )
+  {
+    mPopup = Toolkit::Popup::New();
+
+    // General set up of popup
+    mPopup.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+    mPopup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, "NON_CONTEXTUAL" );
+    mPopup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, "NONE" );
+    mPopup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false ); // Disable the dimmed backing.
+    mPopup.SetProperty( Toolkit::Popup::Property::TOUCH_TRANSPARENT, true ); // Let events pass through the popup
+    mPopup.SetParentOrigin( ParentOrigin::TOP_LEFT );
+    mPopup.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+    // Background
+    mPopup.SetProperty( Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE, mBackgroundImage );
+    mPopup.SetProperty( Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER, mBackgroundBorder );
+
+    // Tail
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_VISIBILITY, mTailVisibility );
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_UP_IMAGE,   mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ] );
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_DOWN_IMAGE, mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ] );
+
+    Vector3 tailPosition;
+    switch( mPositionType )
+    {
+      case Toolkit::Tooltip::Position::HOVER_POINT:
+      case Toolkit::Tooltip::Position::BELOW:
+      {
+        tailPosition = Vector3( 0.5f, 0.0f, 0.0 );
+        break;
+      }
+
+      case Toolkit::Tooltip::Position::ABOVE:
+      {
+        tailPosition = Vector3( 0.5f, 1.0f, 0.0 );
+        break;
+      }
+    }
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_POSITION, tailPosition );
+
+    // Content
+    Actor content;
+    if( ! mContentTextVisual.Empty() )
+    {
+      content = Toolkit::Control::New();
+      content.SetProperty( Toolkit::Control::Property::BACKGROUND, mContentTextVisual );
+    }
+    else if( ! mContentArray.Empty() )
+    {
+      const unsigned int visuals = mContentArray.Size();
+      unsigned int rows = mLayout.x;
+      unsigned int columns = mLayout.y;
+      if( Equals( mLayout.x, 1.0f, Math::MACHINE_EPSILON_1 ) &&
+          Equals( mLayout.y, 1.0f, Math::MACHINE_EPSILON_1 ) &&
+          visuals > 1 )
+      {
+        rows = mLayout.x;
+        columns = visuals;
+      }
+
+      Toolkit::TableView tableView = Toolkit::TableView::New( rows, columns );
+      tableView.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+      for( unsigned int currentContent = 0, currentRow = 0; currentRow < rows && currentContent < visuals; ++currentRow )
+      {
+        tableView.SetFitHeight( currentRow );
+        for( unsigned int currentColumn = 0; currentColumn < columns && currentContent < visuals; ++currentColumn )
+        {
+          Actor child = Toolkit::Control::New();
+          child.SetProperty( Toolkit::Control::Property::BACKGROUND, mContentArray[ currentContent ] );
+
+          Toolkit::TableView::CellPosition cellPosition( currentRow, currentColumn );
+          tableView.AddChild( child, cellPosition );
+          tableView.SetCellAlignment( cellPosition, HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
+          tableView.SetFitWidth( currentColumn );
+
+          ++currentContent;
+        }
+      }
+      content = tableView;
+    }
+    mPopup.SetContent( content );
+
+    // Connect to the relayout signal of the background of the popup as at that point we have the full size
+    Actor popupBackground = GetImpl( mPopup ).GetPopupBackgroundImage();
+    if( popupBackground )
+    {
+      popupBackground.OnRelayoutSignal().Connect( this, &Tooltip::OnRelayout );
+    }
+
+    mPopup.SetDisplayState( Toolkit::Popup::SHOWN );
+
+    Stage::GetCurrent().Add( mPopup );
+  }
+
+  return false;
+}
+
+void Tooltip::OnRelayout( Actor actor )
+{
+  if( mPopup && actor )
+  {
+    float popupWidth = actor.GetRelayoutSize( Dimension::WIDTH );
+    float popupHeight = actor.GetRelayoutSize( Dimension::HEIGHT );
+    float tailHeight = 0.0f;
+    Actor tail;
+
+    if( mTailVisibility )
+    {
+      // Popup's background has the tail, we want to know the tail size as well.
+      if( actor.GetChildCount() )
+      {
+        tail = actor.GetChildAt( 0 );
+        if( tail )
+        {
+          tailHeight = tail.GetRelayoutSize( Dimension::HEIGHT );
+        }
+      }
+    }
+
+    Vector2 stageSize = Stage::GetCurrent().GetSize();
+    Vector3 position;
+
+    switch( mPositionType )
+    {
+      case Toolkit::Tooltip::Position::HOVER_POINT:
+      {
+        position = mHoverPoint + mHoverPointOffset;
+        position.y += tailHeight;
+        break;
+      }
+
+      case Toolkit::Tooltip::Position::ABOVE:
+      {
+        Toolkit::Control control = mControl.GetHandle();
+        if( control )
+        {
+          Vector3 worldPos = control.GetCurrentWorldPosition();
+          float height = control.GetRelayoutSize( Dimension::HEIGHT );
+
+          position.x = stageSize.width * 0.5f + worldPos.x - popupWidth * 0.5f;
+          position.y = stageSize.height * 0.5f + worldPos.y - height * 0.5f - popupHeight * 1.0f - tailHeight;
+        }
+        break;
+      }
+
+      case Toolkit::Tooltip::Position::BELOW:
+      {
+        Toolkit::Control control = mControl.GetHandle();
+        if( control )
+        {
+          Vector3 worldPos = control.GetCurrentWorldPosition();
+          float height = control.GetRelayoutSize( Dimension::HEIGHT );
+
+          position.x = stageSize.width * 0.5f + worldPos.x - popupWidth * 0.5f;
+          position.y = stageSize.height * 0.5f + worldPos.y + height * 0.5f + tailHeight;
+        }
+        break;
+      }
+    }
+
+    // Ensure the Popup is still on the screen
+
+    if( position.x < 0.0f )
+    {
+      position.x = 0.0f;
+    }
+    else if( ( position.x + popupWidth ) > stageSize.width )
+    {
+      position.x -= position.x + popupWidth - stageSize.width;
+    }
+
+    bool yPosChanged = false;
+    if( position.y < 0.0f )
+    {
+      yPosChanged = true;
+      position.y = 0.0f;
+    }
+    else if( ( position.y + popupHeight ) > stageSize.height )
+    {
+      yPosChanged = true;
+      position.y -= position.y + popupHeight - stageSize.height;
+    }
+
+    if( yPosChanged && tail )
+    {
+      // If we change the y position, then the tail may be shown pointing to the wrong control so just hide it.
+      tail.SetVisible( false );
+    }
+
+    mPopup.SetPosition( position );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/tooltip/tooltip.h b/dali-toolkit/internal/controls/tooltip/tooltip.h
new file mode 100644 (file)
index 0000000..7dae92a
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef DALI_INTERNAL_TOOLTIP_H
+#define DALI_INTERNAL_TOOLTIP_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/devel-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/controls/popup/popup.h>
+#include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class Tooltip;
+typedef IntrusivePtr< Tooltip > TooltipPtr;
+
+/**
+ * @brief Handles all the required tooltip related functionality for a control.
+ *
+ * Connects to the Hovered signal of the control.
+ * Styling is achieved by merging the properties set so that new properties override previous but existing properties are still kept.
+ */
+class Tooltip : public RefObject, public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Creates an instance of the Tooltip class.
+   * @param[in]  control  The control the tooltip should be shown on.
+   */
+  static TooltipPtr New( Toolkit::Control control );
+
+  /**
+   * @brief Sets the properties of the Tooltip.
+   * @details The properties are merged over the currently stored properties.
+   *          If a Property::STRING is passed, then the style set previously by the stylesheet is used.
+   *          If a Property::MAP then the map is merged.
+   *          If a Property::ARRAY of Visuals then all are displayed in one row.
+   * @param[in]  value  This can either be a Property::STRING, Property::MAP or Property::ARRAY.
+   */
+  void SetProperties( const Property::Value& value );
+
+  /**
+   * @brief Creates a property map of the tooltip properties.
+   * @param[out]  map  Filled with all the properties of the tooltip.
+   * @note map should be empty.
+   */
+  void CreatePropertyMap( Property::Map& map ) const;
+
+private:
+
+  /**
+   * @brief Private constructor.
+   */
+  Tooltip( Toolkit::Control control );
+
+  /**
+   * @brief Private destructor.
+   */
+  ~Tooltip();
+
+  Tooltip( const Tooltip& ); ///< Undefined
+  Tooltip& operator=( const Tooltip& ); ///< ///< Undefined
+
+  /**
+   * @brief Sets the content of the tooltip.
+   * @details Connects to the signals if there is real content to display.
+   * @param[in]  control  Is used to connect to this control's signals.
+   * @param[in]  value    The content property value.
+   */
+  void SetContent( Toolkit::Control& control, const Property::Value& value );
+
+  /**
+   * @brief Sets the background properties of the tooltip.
+   * @param[in]  value  The background property value.
+   */
+  void SetBackground( const Property::Value& value );
+
+  /**
+   * @brief Sets the tail properties of the tooltip.
+   * @param[in]  value  The tail property value.
+   */
+  void SetTail( const Property::Value& value );
+
+  /**
+   * @brief Method used to connect to the control's Hovered signal.
+   * @param[in]  hover  The hover event.
+   */
+  bool OnHovered( Actor /* actor */, const HoverEvent& hover );
+
+  /**
+   * @brief Method used to connect to the internal timer used by Tooltip.
+   * @return Always return false as we're only interested in one timeout.
+   */
+  bool OnTimeout();
+
+  /**
+   * @brief Used to know when the we're laying out the actor used to display the tooltip.
+   * @details This is required so we can appropriately position it.
+   * @param[in]  actor  The actor being laid out.
+   */
+  void OnRelayout( Actor actor );
+
+  // Data
+
+  Toolkit::Popup mPopup; ///< The Popup class is used to display the actual tooltip.
+  Timer mTooltipTimer; ///< Timer used to wait a certain length of time before we display the tooltip.
+
+  WeakHandle< Toolkit::Control > mControl; ///< A weak handle to the control we are setting the tooltip on.
+
+  Property::Map mContentTextVisual; ///< If using just one visual, then this is set.
+  Property::Map mTailImages; ///< The different images used by the tail.
+  Property::Array mContentArray; ///< If using an array of visuals, then this is used.
+
+  Rect< int > mBackgroundBorder; ///< The size of the background border in the order: left, right, bottom, top. @see Toolkit::Tooltip::Border::Property::BORDER
+
+  Vector2 mLayout; ///< The layout of the content if using an array.
+  Vector2 mHoverPoint; ///< The first point where hover starts.
+  Vector2 mHoverPointOffset; ///< The tooltip is displayed with this offset from hover point if using Toolkit::Tooltip::Position::HOVER_POINT.
+
+  std::string mBackgroundImage; ///< The path to the background image used for the tooltip.
+
+  float mMovementThreshold; ///< This is the allowable movement of the hover before the tooltip processing is cancelled.
+
+  int mWaitTime; ///< Time in milliseconds to wait before we display the tooltip.
+
+  Toolkit::Tooltip::Position::Type mPositionType; ///< The position of the tooltip.
+  bool mTailVisibility; ///< Whether we are showing a tail or not.
+  bool mDisappearOnMovement; ///< Whether the tooltip is set to disappear on movement or when we go out of the bounds of mControl.
+  bool mSignalsConnected; ///< Whether any signals required for Tooltip functionality have been connected.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TOOLTIP_H
index a4f49d9..f003ce2 100644 (file)
@@ -79,6 +79,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/controls/text-controls/text-selection-popup-impl.cpp \
    $(toolkit_src_dir)/controls/text-controls/text-selection-toolbar-impl.cpp \
    $(toolkit_src_dir)/controls/tool-bar/tool-bar-impl.cpp \
+   $(toolkit_src_dir)/controls/tooltip/tooltip.cpp \
    $(toolkit_src_dir)/controls/video-view/video-view-impl.cpp \
    $(toolkit_src_dir)/accessibility-manager/accessibility-manager-impl.cpp \
    \
index 4145bf7..2b40d32 100644 (file)
@@ -40,8 +40,7 @@ namespace Internal
 namespace
 {
 
-// Property names.
-const char * const TEXT_PROPERTY( "text" );
+// Property names - common properties defined in visual-string-constants.h/cpp
 const char * const FONT_FAMILY_PROPERTY( "fontFamily" );
 const char * const FONT_STYLE_PROPERTY( "fontStyle" );
 const char * const POINT_SIZE_PROPERTY( "pointSize" );
index 239f5c4..e829889 100644 (file)
@@ -23,7 +23,6 @@
 #include <dali/public-api/object/property-array.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
-#include <dali/devel-api/scripting/enum-helper.h>
 #include <dali/devel-api/scripting/scripting.h>
 
 // INTERNAL INCLUDES
@@ -58,18 +57,6 @@ namespace Internal
 namespace
 {
 
-DALI_ENUM_TO_STRING_TABLE_BEGIN( VISUAL_TYPE )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, BORDER )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, COLOR )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, GRADIENT )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, IMAGE )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, MESH )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, PRIMITIVE )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelVisual, TEXT )
-DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, WIREFRAME )
-DALI_ENUM_TO_STRING_TABLE_END( VISUAL_TYPE )
-
-const char * const VISUAL_TYPE( "visualType" );
 const char * const BATCHING_ENABLED( "batchingEnabled" );
 BaseHandle Create()
 {
index a854aba..9126fce 100644 (file)
 // CLASS HEADER
 #include "visual-string-constants.h"
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+
 namespace Dali
 {
 
@@ -27,6 +31,20 @@ namespace Toolkit
 namespace Internal
 {
 
+DALI_ENUM_TO_STRING_TABLE_BEGIN( VISUAL_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, BORDER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, GRADIENT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, IMAGE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, MESH )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, PRIMITIVE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelVisual, TEXT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, WIREFRAME )
+DALI_ENUM_TO_STRING_TABLE_END( VISUAL_TYPE )
+
+// Visual Type
+const char * const VISUAL_TYPE( "visualType" );
+
 // Custom shader
 const char * const CUSTOM_SHADER( "shader" );
 const char * const CUSTOM_VERTEX_SHADER( "vertexShader" );
@@ -50,6 +68,9 @@ extern const char * const PREMULTIPLIED_ALPHA( "premultipliedAlpha" );
 const char * const IMAGE_URL_NAME( "url" );
 const char * const ATLAS_RECT_UNIFORM_NAME ( "uAtlasRect" );
 
+// Text visual
+const char * const TEXT_PROPERTY( "text" );
+
 } // namespace Internal
 
 } // namespace Toolkit
index 655a9a2..c6692c0 100644 (file)
@@ -18,6 +18,9 @@
  *
  */
 
+// EXTERNAL INCLUDES
+#include <dali/devel-api/scripting/enum-helper.h>
+
 namespace Dali
 {
 
@@ -27,6 +30,11 @@ namespace Toolkit
 namespace Internal
 {
 
+// Visual type
+extern const char * const VISUAL_TYPE;
+extern const Dali::Scripting::StringEnum VISUAL_TYPE_TABLE[];
+extern const unsigned int VISUAL_TYPE_TABLE_COUNT;
+
 // Custom shader
 extern const char * const CUSTOM_SHADER;
 extern const char * const CUSTOM_VERTEX_SHADER;
@@ -50,6 +58,9 @@ extern const char * const PREMULTIPLIED_ALPHA;
 extern const char * const IMAGE_URL_NAME;
 extern const char * const ATLAS_RECT_UNIFORM_NAME;
 
+// Text visual
+extern const char * const TEXT_PROPERTY;
+
 } // namespace Internal
 
 } // namespace Toolkit
index 39128d0..5103060 100644 (file)
@@ -40,6 +40,7 @@
 #include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
@@ -47,6 +48,7 @@
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
 #include <dali-toolkit/internal/visuals/transition-data-impl.h>
 #include <dali-toolkit/devel-api/align-enums.h>
+#include <dali-toolkit/internal/controls/tooltip/tooltip.h>
 
 namespace Dali
 {
@@ -412,6 +414,16 @@ public:
           }
           break;
         }
+
+        case Toolkit::DevelControl::Property::TOOLTIP:
+        {
+          TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
+          if( ! tooltipPtr )
+          {
+            tooltipPtr = Tooltip::New( control );
+          }
+          tooltipPtr->SetProperties( value );
+        }
       }
     }
   }
@@ -479,6 +491,17 @@ public:
           break;
         }
 
+        case Toolkit::DevelControl::Property::TOOLTIP:
+        {
+          Property::Map map;
+          if( controlImpl.mImpl->mTooltip )
+          {
+            controlImpl.mImpl->mTooltip->CreatePropertyMap( map );
+          }
+          value = map;
+          break;
+        }
+
       }
     }
 
@@ -502,16 +525,20 @@ public:
   TapGestureDetector mTapGestureDetector;
   LongPressGestureDetector mLongPressGestureDetector;
 
+  // Tooltip
+  TooltipPtr mTooltip;
+
   ControlBehaviour mFlags : CONTROL_BEHAVIOUR_FLAG_COUNT;    ///< Flags passed in from constructor.
   bool mIsKeyboardNavigationSupported :1;  ///< Stores whether keyboard navigation is supported by the control.
   bool mIsKeyboardFocusGroup :1;           ///< Stores whether the control is a focus group.
 
-  // Properties - these need to be members of Internal::Control::Impl as they need to function within this class.
+  // Properties - these need to be members of Internal::Control::Impl as they access private methods/data of Internal::Control and Internal::Control::Impl.
   static const PropertyRegistration PROPERTY_1;
   static const PropertyRegistration PROPERTY_2;
   static const PropertyRegistration PROPERTY_3;
   static const PropertyRegistration PROPERTY_4;
   static const PropertyRegistration PROPERTY_5;
+  static const PropertyRegistration PROPERTY_6;
 };
 
 // Properties registered without macro to use specific member variables.
@@ -520,6 +547,7 @@ const PropertyRegistration Control::Impl::PROPERTY_2( typeRegistration, "backgro
 const PropertyRegistration Control::Impl::PROPERTY_3( typeRegistration, "backgroundImage", Toolkit::Control::Property::BACKGROUND_IMAGE, Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
 const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus",   Toolkit::Control::Property::KEY_INPUT_FOCUS,  Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
 const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background",      Toolkit::Control::Property::BACKGROUND,       Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "tooltip",         Toolkit::DevelControl::Property::TOOLTIP,     Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
 
 Toolkit::Control Control::New()
 {
index 9ede92d..c6e3b1d 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_TOOLKIT_CONTROL_H__
 
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * 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.
index ea73d40..8c5661b 100644 (file)
 {
   "styles":
   {
+    "Tooltip":
+    {
+      "tooltip":
+      {
+        "content":
+        {
+          "pointSize":84
+        },
+        "waitTime":0.5,
+        "background":
+        {
+          "visual":"{DALI_IMAGE_DIR}tooltip.9.png",
+          "border":[1,5,5,1]
+        },
+        "tail":
+        {
+          "visibility":false,
+          "aboveVisual":"{DALI_IMAGE_DIR}tooltip-tail-above.png",
+          "belowVisual":"{DALI_IMAGE_DIR}tooltip-tail-below.png"
+        },
+        "position":"BELOW",
+        "hoverPointOffset":[10,10],
+        "movementThreshold":5,
+        "disappearOnMovement":false
+      }
+    },
     "TextLabel":
     {
       "pointSize":108,
     },
     "Button":
     {
+      "styles":["Tooltip"],
       "initialAutoRepeatingDelay":2.0,
       "nextAutoRepeatingDelay":0.9
       // Note: Visuals added to Button will be used in all derived buttons unless overridden.
index 431f73c..b188dab 100644 (file)
 {
   "styles":
   {
+    "Tooltip":
+    {
+      "tooltip":
+      {
+        "content":
+        {
+          "pointSize":12
+        },
+        "waitTime":0.5,
+        "background":
+        {
+          "visual":"{DALI_IMAGE_DIR}tooltip.9.png",
+          "border":[1,5,5,1]
+        },
+        "tail":
+        {
+          "visibility":false,
+          "aboveVisual":"{DALI_IMAGE_DIR}tooltip-tail-above.png",
+          "belowVisual":"{DALI_IMAGE_DIR}tooltip-tail-below.png"
+        },
+        "position":"BELOW",
+        "hoverPointOffset":[10,10],
+        "movementThreshold":5,
+        "disappearOnMovement":false
+      }
+    },
     "TextLabel":
     {
       "pointSize":18,
     },
     "Button":
     {
+      "styles":["Tooltip"],
       "initialAutoRepeatingDelay":2.0,
       "nextAutoRepeatingDelay":0.9
       // Note: Visuals added to Button will be used in all derived buttons unless overridden.
diff --git a/dali-toolkit/styles/images-common/tooltip-tail-above.png b/dali-toolkit/styles/images-common/tooltip-tail-above.png
new file mode 100644 (file)
index 0000000..9695929
Binary files /dev/null and b/dali-toolkit/styles/images-common/tooltip-tail-above.png differ
diff --git a/dali-toolkit/styles/images-common/tooltip-tail-below.png b/dali-toolkit/styles/images-common/tooltip-tail-below.png
new file mode 100644 (file)
index 0000000..3b4a0f9
Binary files /dev/null and b/dali-toolkit/styles/images-common/tooltip-tail-below.png differ
diff --git a/dali-toolkit/styles/images-common/tooltip.9.png b/dali-toolkit/styles/images-common/tooltip.9.png
new file mode 100644 (file)
index 0000000..bd4b6e8
Binary files /dev/null and b/dali-toolkit/styles/images-common/tooltip.9.png differ