From: Tom Robinson Date: Mon, 27 Jul 2015 16:15:45 +0000 (+0100) Subject: New Popup implementation X-Git-Tag: dali_1.0.52~1^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=91b8f5bbaa7d68f5ca8fc94287b8c181a10ba894 New Popup implementation Change-Id: Id57b2824d26aa863454e428f5cc67a6128e1cfc1 --- diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 2b1858e..8f40f82 100644 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -12,6 +12,7 @@ SET(TC_SOURCES utc-Dali-BubbleEmitter.cpp utc-Dali-Builder.cpp utc-Dali-CheckBoxButton.cpp + utc-Dali-ConfirmationPopup.cpp utc-Dali-CubeTransitionEffect.cpp utc-Dali-EffectsView.cpp utc-Dali-GaussianBlurView.cpp diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp index 864e41e..2f1ce14 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,12 +34,17 @@ class Timer; typedef IntrusivePtr TimerPtr; +Dali::Timer::TimerSignalType gTickSignal; + /** * Implementation of the timer */ class Timer : public BaseObject { public: + void MockEmitSignal(); + +public: static TimerPtr New( unsigned int milliSec ); Timer( unsigned int milliSec ); virtual ~Timer(); @@ -63,7 +68,6 @@ private: // Implementation private: // Data - Dali::Timer::TimerSignalType mTickSignal; unsigned int mInterval; }; @@ -87,7 +91,7 @@ inline const Timer& GetImplementation(const Dali::Timer& timer) TimerPtr Timer::New( unsigned int milliSec ) { - TimerPtr timerImpl = new Timer(10); + TimerPtr timerImpl = new Timer( milliSec ); return timerImpl; } @@ -130,9 +134,17 @@ bool Timer::Tick() Dali::Timer::TimerSignalType& Timer::TickSignal() { - return mTickSignal; + return gTickSignal; +} + +// Mock setup functions: + +void Timer::MockEmitSignal() +{ + gTickSignal.Emit(); } + } // namespace Adaptor } // namespace Internal @@ -206,5 +218,12 @@ Timer::Timer(Internal::Adaptor::Timer* timer) { } +// Mock setup functions: + +void Timer::MockEmitSignal() +{ + Internal::Adaptor::GetImplementation( *this ).MockEmitSignal(); +} + } // namespace Dali diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h index a7397e6..e0c886c 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_TOOLKIT_TIMER_H__ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,9 @@ class Timer; class Timer : public BaseHandle { public: + void MockEmitSignal(); + +public: typedef Signal< bool () > TimerSignalType; Timer(); static Timer New( unsigned int milliSec ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp index 990be9c..f290cb2 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp @@ -346,7 +346,6 @@ int UtcDaliButtonSetUnselectedImageP(void) application.Render(); Vector3 size = pushButton.GetCurrentSize(); - tet_printf( "todor: size: %f,%f", size.width, size.height ); DALI_TEST_EQUALS( size.width, 20.f, TEST_LOCATION ); DALI_TEST_EQUALS( size.height, 20.f, TEST_LOCATION ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ConfirmationPopup.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ConfirmationPopup.cpp new file mode 100644 index 0000000..0d3dec9 --- /dev/null +++ b/automated-tests/src/dali-toolkit/utc-Dali-ConfirmationPopup.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +// Need to override adaptor classes for toolkit test harness, so include +// test harness headers before dali headers. +#include +#include +#include + +using namespace Dali; +using namespace Toolkit; + +void utc_dali_toolkit_confirmation_popup_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void utc_dali_toolkit_confirmation_popup_cleanup(void) +{ + test_return_value = TET_PASS; +} + +namespace +{ + +static bool gObjectCreatedCallBackCalled; + +static void TestCallback(BaseHandle handle) +{ + gObjectCreatedCallBackCalled = true; +} + +static bool gSignalReceivedOK; +static bool gSignalReceivedCancel; + +/** + * A connection tracker is required when connecting to a signal with a functor. + */ +class TestConnectionTrackerObject : public ConnectionTracker +{ +}; + +/** + * This functor is used to test the confirmation popup's OK signal connection. + */ +struct ConfirmationPopupOKTestFunctor +{ + ConfirmationPopupOKTestFunctor() + { + } + + void operator()() + { + gSignalReceivedOK = true; + } +}; + +/** + * This functor is used to test the confirmation popup's Cancel signal connection. + */ +struct ConfirmationPopupCancelTestFunctor +{ + ConfirmationPopupCancelTestFunctor() + { + } + + void operator()() + { + gSignalReceivedCancel = true; + } +}; + +} // unnamed namespace. + + +int UtcDaliConfirmationPopupNewP( void ) +{ + ToolkitTestApplication application; + tet_infoline( " UtcDaliConfirmationPopupNewP" ); + + // Create the ConfirmationPopup. + ConfirmationPopup popup; + + DALI_TEST_CHECK( !popup ); + + popup = ConfirmationPopup::New(); + + DALI_TEST_CHECK( popup ); + + ConfirmationPopup popup2( popup ); + + DALI_TEST_CHECK( popup2 == popup ); + + // Additional check to ensure object is created by checking if it's registered. + ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry(); + DALI_TEST_CHECK( registry ); + + gObjectCreatedCallBackCalled = false; + registry.ObjectCreatedSignal().Connect( &TestCallback ); + { + ConfirmationPopup popup = ConfirmationPopup::New(); + } + DALI_TEST_CHECK( gObjectCreatedCallBackCalled ); + END_TEST; +} + +int UtcDaliConfirmationPopupDestructorP( void ) +{ + ToolkitTestApplication application; + tet_infoline( " UtcDaliConfirmationPopupDestructorP" ); + + ConfirmationPopup* popup = new ConfirmationPopup(); + delete popup; + + DALI_TEST_CHECK( true ); + END_TEST; +} + +int UtcDaliConfirmationPopupDownCastP(void) +{ + ToolkitTestApplication application; + tet_infoline( " UtcDaliConfirmationPopupDownCastP" ); + + Handle handle = ConfirmationPopup::New(); + + ConfirmationPopup popup = ConfirmationPopup::DownCast( handle ); + + DALI_TEST_CHECK( popup == handle ); + END_TEST; +} + +int UtcDaliConfirmationPopupDynamicSignalGenerationP(void) +{ + ToolkitTestApplication application; + tet_infoline( " UtcDaliConfirmationPopupDynamicSignalGenerationP" ); + + ConfirmationPopup popup = ConfirmationPopup::New(); + + TextLabel titleActor = TextLabel::New( "Title" ); + popup.SetTitle( titleActor ); + + TextLabel contentActor = TextLabel::New( "Content" ); + popup.SetContent( contentActor ); + + Actor footerActor = Actor::New(); + + // The confirmation popup can use any control type for the ok or cancel buttons. + // It requires that the name is "control-ok" to provide the "control-signal-ok" signal. + PushButton buttonOK = PushButton::New(); + buttonOK.SetName( "control-ok" ); + footerActor.Add( buttonOK ); + + PushButton buttonCancel = PushButton::New(); + buttonCancel.SetName( "control-cancel" ); + footerActor.Add( buttonCancel ); + + popup.SetFooter( footerActor ); + + // Tell the confirmation popup to connect to the signal in our button called "on-stage". + popup.SetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED, "on-stage" ); + + // Connect to the confirmation popup's OK signal. This signal is dynamically created upon connection. + gSignalReceivedOK = false; + gSignalReceivedCancel = false; + TestConnectionTrackerObject* testTracker = new TestConnectionTrackerObject(); + popup.ConnectSignal( testTracker, "control-signal-ok", ConfirmationPopupOKTestFunctor() ); + + // Check no signal has occurred yet. + DALI_TEST_CHECK( !gSignalReceivedOK ); + DALI_TEST_CHECK( !gSignalReceivedCancel ); + + // Provoke the signal. + Stage::GetCurrent().Add( popup ); + + // Check the signal has occurred. + DALI_TEST_CHECK( gSignalReceivedOK ); + DALI_TEST_CHECK( !gSignalReceivedCancel ); + + // Remove the popup from the stage, and connect the cancel signal. + popup.Unparent(); + popup.SetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED, "on-stage" ); + popup.ConnectSignal( testTracker, "control-signal-cancel", ConfirmationPopupCancelTestFunctor() ); + + // Check the cancel signal has not occurred yet. + DALI_TEST_CHECK( gSignalReceivedOK ); + DALI_TEST_CHECK( !gSignalReceivedCancel ); + + // Provoke the signal. + Stage::GetCurrent().Add( popup ); + + // Check the cancel signal has occurred. + DALI_TEST_CHECK( gSignalReceivedOK ); + DALI_TEST_CHECK( gSignalReceivedCancel ); + + END_TEST; +} + +int UtcDaliConfirmationPopupDynamicSignalGenerationN(void) +{ + ToolkitTestApplication application; + tet_infoline( " UtcDaliConfirmationPopupDynamicSignalGenerationN" ); + + ConfirmationPopup popup = ConfirmationPopup::New(); + + TextLabel titleActor = TextLabel::New( "Title" ); + popup.SetTitle( titleActor ); + + TextLabel contentActor = TextLabel::New( "Content" ); + popup.SetContent( contentActor ); + + Actor footerActor = Actor::New(); + + PushButton buttonOK = PushButton::New(); + buttonOK.SetName( "control-ok-misnamed" ); + popup.SetFooter( buttonOK ); + + // Tell the confirmation popup to connect to the signal in our button called "on-stage". + popup.SetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED, "on-stage" ); + + // Connect to the confirmation popup's OK signal. + gSignalReceivedOK = false; + + // The connection will fail at this point as no actor with the name "control-ok" will be located. + TestConnectionTrackerObject* testTracker = new TestConnectionTrackerObject(); + popup.ConnectSignal( testTracker, "control-signal-ok", ConfirmationPopupOKTestFunctor() ); + + // Check no signal has occurred yet. + DALI_TEST_CHECK( !gSignalReceivedOK ); + + // Provoke the signal. + Stage::GetCurrent().Add( popup ); + + // Check the signal has still not occurred, as our button was incorrectly named. + DALI_TEST_CHECK( !gSignalReceivedOK ); + + END_TEST; +} + + + diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp index 294bec2..990c20a 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,15 +15,16 @@ * */ -#include #include // Need to override adaptor classes for toolkit test harness, so include // test harness headers before dali headers. #include +#include "dali-toolkit-test-utils/toolkit-timer.h" #include #include +#include #include #include @@ -50,18 +51,18 @@ static void TestCallback(BaseHandle handle) } const int RENDER_FRAME_INTERVAL = 10; ///< Duration of each frame in ms. -const int RENDER_ANIMATION_TEST_DURATION_MS = 1000; ///< 1000ms to test animation +const int RENDER_ANIMATION_TEST_DURATION_MS = 2000; ///< 2000ms to test animation. const int RENDER_ANIMATION_TEST_DURATION_FRAMES = RENDER_ANIMATION_TEST_DURATION_MS / RENDER_FRAME_INTERVAL; ///< equivalent frames. const Vector3 DEFAULT_BUTTON_SIZE(100.0f, 50.0f, 0.0f); const Dali::TouchPoint pointDownOutside( 0, TouchPoint::Down, 10.0f, 10.0f ); const Dali::TouchPoint pointUpOutside( 0, TouchPoint::Up, 10.0f, 10.0f ); /** - * Counts how many descendents root Actor has, including + * Counts how many descendants root Actor has, including * itself. * * @param[in] root The root actor to count from. - * @return The number of descendents including root actor itself. + * @return The number of descendants including root actor itself. */ int DescendentCount(const Actor& root) { @@ -87,30 +88,65 @@ bool HasAncestor(Actor child, Actor ancestor) return (child == ancestor); } +static Toolkit::Popup::DisplayState gPopupState = Toolkit::Popup::HIDDEN; +static bool gTouchedOutside; -static bool gHidden = false; +// Signal callbacks -static void OnPopupHidden() +static void OnPopupTouchedOutside() { - gHidden = true; + gTouchedOutside = true; } -static bool gTouchedOutside; +static void OnPopupShowing() +{ + gPopupState = Toolkit::Popup::SHOWING; +} -static void OnPopupTouchedOutside() +static void OnPopupShown() { - gTouchedOutside = true; + gPopupState = Toolkit::Popup::SHOWN; +} + +static void OnPopupHiding() +{ + gPopupState = Toolkit::Popup::HIDING; +} + +static void OnPopupHidden() +{ + gPopupState = Toolkit::Popup::HIDDEN; } +void ConnectStateSignals( Toolkit::Popup popup ) +{ + popup.ShowingSignal().Connect( &OnPopupShowing ); + popup.ShownSignal().Connect( &OnPopupShown ); + popup.HidingSignal().Connect( &OnPopupHiding ); + popup.HiddenSignal().Connect( &OnPopupHidden ); +} + +void WaitAnimation( ToolkitTestApplication& application ) +{ + // Wait for a while (allow animation to complete), and then check state. + for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ ) + { + application.SendNotification(); + application.Render( RENDER_FRAME_INTERVAL ); + } +} -} // anon namespace +} // Anonymous namespace -int UtcDaliPopupNew(void) +/* + * This test checks popup creation. + */ +int UtcDaliPopupNewP( void ) { ToolkitTestApplication application; - tet_infoline(" UtcDaliPopupNew"); + tet_infoline( " UtcDaliPopupNewP" ); - // Create the Popup actor + // Create the Popup actor. Popup popup; DALI_TEST_CHECK( !popup ); @@ -119,11 +155,11 @@ int UtcDaliPopupNew(void) DALI_TEST_CHECK( popup ); - Popup popup2(popup); + Popup popup2( popup ); DALI_TEST_CHECK( popup2 == popup ); - //Additional check to ensure object is created by checking if it's registered + // Additional check to ensure object is created by checking if it's registered. ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry(); DALI_TEST_CHECK( registry ); @@ -136,9 +172,13 @@ int UtcDaliPopupNew(void) END_TEST; } -int UtcDaliPopupDestructor(void) +/* + * This test checks popup destruction. + */ +int UtcDaliPopupDestructorP( void ) { ToolkitTestApplication application; + tet_infoline( " UtcDaliPopupDestructorP" ); Popup* popup = new Popup(); delete popup; @@ -147,9 +187,10 @@ int UtcDaliPopupDestructor(void) END_TEST; } -int UtcDaliPopupDownCast(void) +int UtcDaliPopupDownCastP(void) { ToolkitTestApplication application; + tet_infoline( " UtcDaliPopupDownCastP" ); Handle handle = Popup::New(); @@ -159,132 +200,292 @@ int UtcDaliPopupDownCast(void) END_TEST; } -int UtcDaliPopoupSetProperty(void) +int UtcDaliPopupSetPropertyP(void) { - tet_infoline("UtcDaliPopoupSetProperty: "); ToolkitTestApplication application; + tet_infoline( " UtcDaliPopupSetProperty" ); Popup popup = Popup::New(); //Test properties std::string testString = "Hello World"; - popup.SetProperty(popup.GetPropertyIndex("title"), testString); - DALI_TEST_EQUALS( testString, popup.GetTitle(), TEST_LOCATION ); + + TextLabel textActorIn = TextLabel::New( testString ); + Property::Map map; + Scripting::CreatePropertyMap( textActorIn, map ); + popup.SetProperty( popup.GetPropertyIndex( "title" ), map ); + TextLabel textActorOut = TextLabel::DownCast( popup.GetTitle() ); + std::string resultText; + DALI_TEST_CHECK( textActorOut.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get( resultText ) ); + DALI_TEST_EQUALS( testString, resultText, TEST_LOCATION ); + END_TEST; } +int UtcDaliPopupSetTitleP(void) +{ + ToolkitTestApplication application; // Exceptions require ToolkitTestApplication + tet_infoline( " UtcDaliPopupSetTitleP" ); + + // Create the Popup actor + Popup popup = Popup::New(); + + // Put in show state so it's layer is connected to popup (for ancestor check). + popup.SetDisplayState( Popup::SHOWN ); + + TextLabel titleActor = TextLabel::New(); + titleActor.SetProperty( Toolkit::TextLabel::Property::TEXT, "title" ); + + DALI_TEST_CHECK( !popup.GetTitle() ); + popup.SetTitle( titleActor ); + TextLabel textActor = TextLabel::DownCast( popup.GetTitle() ); + DALI_TEST_CHECK( textActor == titleActor ); + + std::string resultText; + DALI_TEST_CHECK( textActor.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get( resultText ) ); + + DALI_TEST_CHECK( ( popup.GetTitle() ) && ( resultText == "title" ) ); + // verify titleActor is actually inside popup, and not elsewhere on stage, or off even. + DALI_TEST_CHECK( HasAncestor( titleActor, popup ) ); -int UtcDaliPopupSetBackgroundImage(void) + TextLabel titleActor2 = TextLabel::New(); + titleActor2.SetProperty( Toolkit::TextLabel::Property::TEXT, "anothertitle" ); + popup.SetTitle( titleActor2 ); + DALI_TEST_CHECK( popup.GetTitle() != titleActor ); + DALI_TEST_CHECK( popup.GetTitle() == titleActor2 ); + DALI_TEST_CHECK( TextLabel::DownCast( popup.GetTitle() ).GetProperty( Toolkit::TextLabel::Property::TEXT ).Get( resultText ) ); + + DALI_TEST_CHECK( ( popup.GetTitle() ) && ( resultText == "anothertitle" ) ); + + // verify titleActor is actually inside popup, and not elsewhere on stage, or off even. + DALI_TEST_CHECK( HasAncestor( titleActor2, popup ) ); + END_TEST; +} + +int UtcDaliPopupSetTitleN(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication - tet_infoline(" UtcDaliPopupSetBackgroundImage"); + tet_infoline( " UtcDaliPopupSetTitleN" ); // Create the Popup actor Popup popup = Popup::New(); - Stage::GetCurrent().Add( popup ); - ImageActor image = CreateSolidColorActor( Color::RED ); - DALI_TEST_CHECK( !image.GetParent() ); - popup.SetBackgroundImage(image); - DALI_TEST_CHECK( image.GetParent() ); + TextLabel titleActor = TextLabel::New( "text" ); + popup.SetTitle( titleActor ); + + DALI_TEST_CHECK( popup.GetTitle() ); + + // Set a bad title value. + // Confirm this has disabled the title. + Actor badActor; + popup.SetTitle( badActor ); + + DALI_TEST_CHECK( !popup.GetTitle() ); + END_TEST; } -int UtcDaliPopupSetTitle(void) +int UtcDaliPopupSetContentP(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication - tet_infoline(" UtcDaliPopupSetTitle"); + tet_infoline( " UtcDaliPopupSetContentP" ); // Create the Popup actor Popup popup = Popup::New(); Stage::GetCurrent().Add( popup ); + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f ); + // Put in show state so it's layer is connected to popup (for ancestor check). - popup.SetState(Popup::POPUP_SHOW, 0.0f); + popup.SetDisplayState( Popup::SHOWN ); + + PushButton button = PushButton::New(); + DALI_TEST_CHECK( !HasAncestor( button, popup ) ); + popup.SetFooter( button ); + // Hide and then re-show popup to cause button to be rearranged and added to popup. + popup.SetDisplayState( Popup::HIDDEN ); + popup.SetDisplayState( Popup::SHOWN ); + DALI_TEST_CHECK( HasAncestor( button, popup ) ); + END_TEST; +} + +int UtcDaliPopupSetContentN(void) +{ + ToolkitTestApplication application; // Exceptions require ToolkitTestApplication + tet_infoline( " UtcDaliPopupSetContentN" ); + + // Create the Popup actor + Popup popup = Popup::New(); - popup.SetTitle("title"); + TextLabel content = TextLabel::New( "text" ); + popup.SetContent( content ); - DALI_TEST_CHECK( popup.GetTitle() == "title" ); + DALI_TEST_CHECK( popup.GetContent() ); + + // Set a bad title value. + Actor badActor; + popup.SetContent( badActor ); + + DALI_TEST_CHECK( !popup.GetContent() ); END_TEST; } -int UtcDaliPopupAddButton(void) +int UtcDaliPopupSetFooterP(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication - tet_infoline(" UtcDaliPopupAddButton"); + tet_infoline(" UtcDaliPopupSetFooterP"); // Create the Popup actor Popup popup = Popup::New(); Stage::GetCurrent().Add( popup ); + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f ); // Put in show state so it's layer is connected to popup (for ancestor check). - popup.SetState(Popup::POPUP_SHOW, 0.0f); + popup.SetDisplayState( Popup::SHOWN ); PushButton button = PushButton::New(); DALI_TEST_CHECK( !HasAncestor(button, popup) ); - popup.AddButton(button); + popup.SetFooter( button ); + // Hide and then re-show popup to cause button to be rearranged and added to popup. + popup.SetDisplayState( Popup::HIDDEN ); + popup.SetDisplayState( Popup::SHOWN ); + DALI_TEST_CHECK( HasAncestor( button, popup ) ); + END_TEST; +} + +int UtcDaliPopupSetFooterN(void) +{ + ToolkitTestApplication application; // Exceptions require ToolkitTestApplication + tet_infoline(" UtcDaliPopupSetFooterN"); + + // Create the Popup actor + Popup popup = Popup::New(); + + PushButton button = PushButton::New(); + popup.SetFooter( button ); + + DALI_TEST_CHECK( popup.GetFooter() ); + + // Set a bad title value. + Actor badActor; + popup.SetFooter( badActor ); + + DALI_TEST_CHECK( !popup.GetFooter() ); + + END_TEST; +} + +int UtcDaliPopupSetControlFooterMultiple(void) +{ + ToolkitTestApplication application; // Exceptions require ToolkitTestApplication + tet_infoline(" UtcDaliPopupSetControlFooterMultiple"); + + // Create the Popup actor + Popup popup = Popup::New(); + Stage::GetCurrent().Add( popup ); + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f ); + // Put in show state so it's layer is connected to popup (for ancestor check). + popup.SetDisplayState( Popup::SHOWN ); + + Actor container = Actor::New(); + PushButton button1 = PushButton::New(); + PushButton button2 = PushButton::New(); + DALI_TEST_CHECK( !HasAncestor( button1, popup ) ); + DALI_TEST_CHECK( !HasAncestor( button2, popup ) ); + container.Add( button1 ); + container.Add( button2 ); + popup.SetFooter( container ); + // Hide and then re-show popup to cause button to be rearranged and added to popup. - popup.SetState( Popup::POPUP_HIDE, 0.0f ); - popup.SetState( Popup::POPUP_SHOW, 0.0f ); - DALI_TEST_CHECK( HasAncestor(button, popup) ); + popup.SetDisplayState( Popup::HIDDEN ); + popup.SetDisplayState( Popup::SHOWN ); + DALI_TEST_CHECK( HasAncestor( button1, popup ) ); + DALI_TEST_CHECK( HasAncestor( button2, popup ) ); + END_TEST; +} + +int UtcDaliPopupSetStateP(void) +{ + ToolkitTestApplication application; // Exceptions require ToolkitTestApplication + tet_infoline(" UtcDaliPopupSetStateP"); + + // Create the Popup actor + Popup popup = Popup::New(); + + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f ); + + DALI_TEST_EQUALS( popup.GetDisplayState(), Popup::HIDDEN, TEST_LOCATION ); + + popup.SetDisplayState( Popup::SHOWN ); + DALI_TEST_EQUALS( Popup::SHOWN, popup.GetDisplayState(), TEST_LOCATION ); + + popup.SetDisplayState( Popup::HIDDEN ); + DALI_TEST_EQUALS( Popup::HIDDEN, popup.GetDisplayState(), TEST_LOCATION ); END_TEST; } -int UtcDaliPopupSetState(void) +int UtcDaliPopupSetStateN(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication - tet_infoline(" UtcDaliPopupSetState"); + tet_infoline(" UtcDaliPopupSetStateN"); // Create the Popup actor Popup popup = Popup::New(); - ImageActor backgroundImage = CreateSolidColorActor( Color::RED ); - popup.SetBackgroundImage(backgroundImage); - - // Showing/Hiding popup, results in all child Actors being - // connected/disconnected from the stage. - DALI_TEST_CHECK( !backgroundImage.OnStage() ); - popup.SetState(Popup::POPUP_SHOW, 0.0f); - DALI_TEST_CHECK( backgroundImage.OnStage() ); - DALI_TEST_EQUALS( Popup::POPUP_SHOW, popup.GetState(), TEST_LOCATION ); - popup.SetState(Popup::POPUP_HIDE, 0.0f); - DALI_TEST_CHECK( !backgroundImage.OnStage() ); - DALI_TEST_EQUALS( Popup::POPUP_HIDE, popup.GetState(), TEST_LOCATION ); + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 1.0f ); + + DALI_TEST_EQUALS( popup.GetDisplayState(), Popup::HIDDEN, TEST_LOCATION ); + + popup.SetDisplayState( Popup::SHOWN ); + DALI_TEST_EQUALS( Popup::SHOWING, popup.GetDisplayState(), TEST_LOCATION ); + + // Test cancelling a show before it has finished. + popup.SetDisplayState( Popup::HIDDEN ); + DALI_TEST_EQUALS( Popup::HIDING, popup.GetDisplayState(), TEST_LOCATION ); END_TEST; } -int UtcDaliPopupSetStateSlow(void) +int UtcDaliPopupDisplayStateSignal(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication - tet_infoline(" UtcDaliPopupSetStateSlow"); + tet_infoline( " UtcDaliPopupDisplayStateSignal" ); // Create the Popup actor Popup popup = Popup::New(); + ConnectStateSignals( popup ); - ImageActor backgroundImage = CreateSolidColorActor( Color::RED ); - popup.SetBackgroundImage(backgroundImage); + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 1.0f ); + popup.SetDisplayState( Popup::SHOWN ); + DALI_TEST_EQUALS( Popup::SHOWING, popup.GetDisplayState(), TEST_LOCATION ); + DALI_TEST_EQUALS( gPopupState, Popup::SHOWING, TEST_LOCATION ); - // Showing/Hiding popup, results in all child Actors being - // connected/disconnected from the stage. - DALI_TEST_CHECK( !backgroundImage.OnStage() ); - popup.SetState(Popup::POPUP_SHOW, 0.0f); - DALI_TEST_CHECK( backgroundImage.OnStage() ); + // Wait for a while (allow animation to complete), and then check state. + for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++) + { + application.SendNotification(); + application.Render( RENDER_FRAME_INTERVAL ); + } + + DALI_TEST_EQUALS( Popup::SHOWN, popup.GetDisplayState(), TEST_LOCATION ); + DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION ); // Hide slowly - popup.SetState(Popup::POPUP_HIDE); + popup.SetDisplayState( Popup::HIDDEN ); + DALI_TEST_EQUALS( Popup::HIDING, popup.GetDisplayState(), TEST_LOCATION ); + DALI_TEST_EQUALS( gPopupState, Popup::HIDING, TEST_LOCATION ); // Wait for a while (allow animation to complete), and then check state. - for(int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++) + for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++) { application.SendNotification(); - application.Render(RENDER_FRAME_INTERVAL); + application.Render( RENDER_FRAME_INTERVAL ); } - DALI_TEST_CHECK( !backgroundImage.OnStage() ); + DALI_TEST_EQUALS( Popup::HIDDEN, popup.GetDisplayState(), TEST_LOCATION ); + DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION ); + END_TEST; } - - int UtcDaliPopupShowHide(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication @@ -292,40 +493,32 @@ int UtcDaliPopupShowHide(void) // Create the Popup actor Popup popup = Popup::New(); - popup.HiddenSignal().Connect( &OnPopupHidden ); - - ImageActor backgroundImage = CreateSolidColorActor( Color::RED ); - popup.SetBackgroundImage(backgroundImage); + ConnectStateSignals( popup ); + Actor container = Actor::New(); PushButton button1 = PushButton::New(); PushButton button2 = PushButton::New(); - button1.SetSize(DEFAULT_BUTTON_SIZE.GetVectorXY()); - popup.AddButton(button1); - button2.SetSize(DEFAULT_BUTTON_SIZE.GetVectorXY()); - popup.AddButton(button2); - - // Showing/Hiding popup, results in all child Actors being - // connected/disconnected from the stage. - DALI_TEST_CHECK( !backgroundImage.OnStage() ); + button1.SetSize( DEFAULT_BUTTON_SIZE.GetVectorXY() ); + button2.SetSize( DEFAULT_BUTTON_SIZE.GetVectorXY() ); + container.Add( button1 ); + container.Add( button2 ); + popup.SetFooter( container ); // Show // Note: in most popup animation implementations show would result in // popup being onstage immediately following Show(). However we can't // assume for all. e.g. If one creates a animation with a delay. - popup.Show(); + popup.SetDisplayState( Popup::SHOWN ); // Wait for a while (allow animation to complete), and then check state. for(int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++) { application.SendNotification(); - application.Render(RENDER_FRAME_INTERVAL); + application.Render( RENDER_FRAME_INTERVAL ); } - DALI_TEST_CHECK( backgroundImage.OnStage() ); - // Hide - gHidden = false; - popup.Hide(); + popup.SetDisplayState( Popup::HIDDEN ); // Wait for a while (allow animation to complete), and then check state. for(int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++) @@ -334,12 +527,11 @@ int UtcDaliPopupShowHide(void) application.Render(RENDER_FRAME_INTERVAL); } - DALI_TEST_CHECK( !backgroundImage.OnStage() ); - DALI_TEST_CHECK( gHidden ); + DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION ); END_TEST; } -int UtcDaliPopupShowHideTail(void) +int UtcDaliPopupPropertyTailVisibility(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication tet_infoline(" UtcDaliPopupShowHideTail"); @@ -347,37 +539,48 @@ int UtcDaliPopupShowHideTail(void) // Create the Popup actor Popup popup = Popup::New(); Stage::GetCurrent().Add( popup ); - popup.SetState(Popup::POPUP_SHOW, 0.0f); - popup.HideTail(); - int withoutTailCount = DescendentCount(popup); + popup.SetProperty( Popup::Property::TAIL_VISIBILITY, false ); + popup.SetDisplayState( Popup::SHOWN ); + + int withoutTailCount = DescendentCount( popup ); + + popup.SetDisplayState( Popup::HIDDEN ); - popup.ShowTail(ParentOrigin::BOTTOM_CENTER); - int withTailCount = DescendentCount(popup); + popup.SetProperty( Popup::Property::TAIL_POSITION, "BOTTOM_CENTER" ); + popup.SetProperty( Popup::Property::TAIL_VISIBILITY, true ); + popup.SetDisplayState( Popup::SHOWN ); + + int withTailCount = DescendentCount( popup ); // There should be more actors if the Tail has been added. DALI_TEST_CHECK( withTailCount > withoutTailCount ); // Hide again - popup.HideTail(); + popup.SetDisplayState( Popup::HIDDEN ); + popup.SetProperty( Popup::Property::TAIL_VISIBILITY, false ); + popup.SetDisplayState( Popup::SHOWN ); int withoutTailCount2 = DescendentCount(popup); DALI_TEST_CHECK( withTailCount > withoutTailCount2 ); END_TEST; } -int UtcDaliPopupOnTouchedOutside(void) +int UtcDaliPopupOnTouchedOutsideSignal(void) { ToolkitTestApplication application; // Exceptions require ToolkitTestApplication tet_infoline(" UtcDaliPopupOnTouchedOutside"); // Create the Popup actor Popup popup = Popup::New(); + popup.SetParentOrigin( ParentOrigin::CENTER ); + popup.SetAnchorPoint( ParentOrigin::CENTER ); + popup.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + popup.SetSize( 50.0f, 50.0f ); + popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f ); Stage::GetCurrent().Add( popup ); - popup.SetParentOrigin(ParentOrigin::CENTER); - popup.SetAnchorPoint(ParentOrigin::CENTER); - popup.SetState(Popup::POPUP_SHOW, 0.0f); popup.OutsideTouchedSignal().Connect( &OnPopupTouchedOutside ); + popup.SetDisplayState( Popup::SHOWN ); application.SendNotification(); application.Render(); @@ -399,6 +602,113 @@ int UtcDaliPopupOnTouchedOutside(void) application.SendNotification(); application.Render(); - DALI_TEST_CHECK(gTouchedOutside); + DALI_TEST_CHECK( gTouchedOutside ); END_TEST; } + +int UtcDaliPopupPropertyAutoHide(void) +{ + ToolkitTestApplication application; // Exceptions require ToolkitTestApplication + tet_infoline( " UtcDaliPopupPropertyAutoHide" ); + + // Create the Popup actor + Popup popup = Popup::New(); + ConnectStateSignals( popup ); + + Actor container = Actor::New(); + PushButton button1 = PushButton::New(); + button1.SetSize( DEFAULT_BUTTON_SIZE.GetVectorXY() ); + container.Add( button1 ); + popup.SetFooter( container ); + + popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f ); + popup.SetProperty( Popup::Property::AUTO_HIDE_DELAY, 200 ); + + Stage::GetCurrent().Add( popup ); + + DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION ); + + // Show + // Note: in most popup animation implementations show would result in + // popup being onstage immediately following Show(). However we can't + // assume for all. e.g. If one creates a animation with a delay. + popup.SetDisplayState( Popup::SHOWN ); + + DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION ); + + for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ ) + { + application.SendNotification(); + application.Render( RENDER_FRAME_INTERVAL ); + } + + // Force the timer used by the popup to expire, + // this will cause the popup to hide automatically. + Dali::Timer timer = Timer::New( 0 ); + timer.MockEmitSignal(); + + DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION ); + + END_TEST; +} + +/* + * This test checks all animation modes to confirm they all trigger all display states at the expected times. + */ +int UtcDaliPopupPropertyAnimationMode(void) +{ + ToolkitTestApplication application; // Exceptions require ToolkitTestApplication + tet_infoline( " UtcDaliPopupPropertyAnimationMode" ); + + // Create the Popup actor + Popup popup = Popup::New(); + ConnectStateSignals( popup ); + popup.SetTitle( TextLabel::New( "Title" ) ); + Stage::GetCurrent().Add( popup ); + + std::string animationModes[] = { "NONE", "ZOOM", "FADE", "CUSTOM" }; + + // Try both default and zero animation duration, as zero has a special case for some animation types. + for( int j = 0; j <= 1; j++ ) + { + // On the second loop, set duration to zero. + if( j == 1 ) + { + popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f ); + } + + // Loop through 4 animation modes. + for( int i = 0; i < 4; i++ ) + { + popup.SetProperty( Popup::Property::ANIMATION_MODE, animationModes[i] ); + + std::string checkMode; + DALI_TEST_CHECK( popup.GetProperty( Popup::Property::ANIMATION_MODE ).Get( checkMode ) ) + + DALI_TEST_EQUALS( checkMode, animationModes[i], TEST_LOCATION ); + + popup.SetDisplayState( Popup::SHOWN ); + + // Only wait for animation if it isn't instant. + if( j == 0 ) + { + DALI_TEST_EQUALS( gPopupState, Popup::SHOWING, TEST_LOCATION ); + WaitAnimation( application ); + } + + DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION ); + popup.SetDisplayState( Popup::HIDDEN ); + + if( j == 0 ) + { + DALI_TEST_EQUALS( gPopupState, Popup::HIDING, TEST_LOCATION ); + WaitAnimation( application ); + } + + DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION ); + } + } + + END_TEST; +} + diff --git a/dali-toolkit/devel-api/controls/popup/confirmation-popup.cpp b/dali-toolkit/devel-api/controls/popup/confirmation-popup.cpp new file mode 100644 index 0000000..de7e116 --- /dev/null +++ b/dali-toolkit/devel-api/controls/popup/confirmation-popup.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER + +#include + +// INTERNAL INCLUDES + +#include +#include + +using namespace Dali; + +namespace Dali +{ + +namespace Toolkit +{ + + +ConfirmationPopup::ConfirmationPopup() +: Popup() +{ +} + +ConfirmationPopup::ConfirmationPopup( Internal::ConfirmationPopup& implementation ) +: Popup( implementation ) +{ +} + +ConfirmationPopup::ConfirmationPopup( const ConfirmationPopup& confirmationPopup ) +: Popup( confirmationPopup ) +{ +} + +ConfirmationPopup& ConfirmationPopup::operator=( const ConfirmationPopup& confirmationPopup ) +{ + if( &confirmationPopup != this ) + { + Popup::operator=( confirmationPopup ); + } + return *this; +} + +ConfirmationPopup::ConfirmationPopup( Dali::Internal::CustomActor* internal ) +: Popup( internal ) +{ + VerifyCustomActorPointer( internal ); +} + +ConfirmationPopup::~ConfirmationPopup() +{ +} + +ConfirmationPopup ConfirmationPopup::New() +{ + return Internal::ConfirmationPopup::New(); +} + +ConfirmationPopup ConfirmationPopup::DownCast( BaseHandle handle ) +{ + return Control::DownCast( handle ); +} + + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/devel-api/controls/popup/confirmation-popup.h b/dali-toolkit/devel-api/controls/popup/confirmation-popup.h new file mode 100644 index 0000000..621eaec --- /dev/null +++ b/dali-toolkit/devel-api/controls/popup/confirmation-popup.h @@ -0,0 +1,148 @@ +#ifndef __DALI_TOOLKIT_CONFIRMATION_POPUP_H__ +#define __DALI_TOOLKIT_CONFIRMATION_POPUP_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include "popup.h" + +namespace Dali +{ + +namespace Toolkit +{ + +// Forward declarations +namespace Internal DALI_INTERNAL +{ +class ConfirmationPopup; +} + +/** + * @brief The ConfirmationPopup widget provides a simple interface to the Popup widget in which to + * create common use-case popups. + * + * ConfirmationPopup will automatically provide signals for 1 or 2 buttons. + * These signals are dynamically created. The controls (typically PushButtons) must be named as per the example below. + * + * Please see the programming guide for a detailed description of the ConfirmationPopup including examples. + * + * Signals (these are dynamically created upon connect). + * | %Signal Name | Actor name to connect to | Property to set signal type (eg clicked) | + * |-----------------------|--------------------------|------------------------------------------| + * | control-signal-ok | control-ok | connect-signal-ok-selected | + * | control-signal-cancel | control-cancel | connect-signal-cancel-selected | + */ +class DALI_IMPORT_API ConfirmationPopup : public Popup +{ +public: + + /** + * @brief The start and end property ranges for this control. + */ + enum PropertyRange + { + PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1 + DEFAULT_PROPERTY_MAX_COUNT_PER_DERIVATION + 1, + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000 ///< Reserve property indices + }; + + /** + * @brief An enumeration of properties belonging to the ConfirmationPopup class. + */ + struct Property + { + enum + { + CONNECT_SIGNAL_OK_SELECTED = PROPERTY_START_INDEX, ///< name "connect-signal-ok-selected", type std::string + CONNECT_SIGNAL_CANCEL_SELECTED ///< name "connect-signal-cancel-selected", type std::string + }; + }; + + /** + * @brief An enumeration to use as indices to reference buttons. + */ + enum ControlIndex + { + CONTROL_OK = 0, ///< Index of control 1 + CONTROL_CANCEL, ///< Index of control 2 + }; + + /** + * @brief Create an uninitialized ConfirmationPopup; this can be initialized with ConfirmationPopup::New(). + * + * Calling member functions with an uninitialized Dali::Object is not allowed. + */ + ConfirmationPopup(); + + /** + * @brief Copy constructor. + */ + ConfirmationPopup( const ConfirmationPopup& confirmationPopup ); + + /** + * @brief Assignment operator. + */ + ConfirmationPopup& operator=( const ConfirmationPopup& confirmationPopup ); + + /** + * @brief Destructor. + * + * This is non-virtual since derived types must not contain data or virtual methods. + */ + ~ConfirmationPopup(); + + /** + * @brief Create an initialized ConfirmationPopup. + * + * @return A handle to a newly allocated Dali resource. + */ + static ConfirmationPopup New(); + + /** + * @brief Downcast an Object handle to ConfirmationPopup. + * + * If handle points to a ConfirmationPopup the downcast produces valid + * handle. If not the returned handle is left uninitialized. + * + * @param[in] handle Handle to an object + * @return handle to a ConfirmationPopup or an uninitialized handle + */ + static ConfirmationPopup DownCast( BaseHandle handle ); + +public: // Not intended for application developers + + /** + * @brief Creates a handle using the Toolkit::Internal implementation. + * + * @param[in] implementation The Control implementation. + */ + DALI_INTERNAL ConfirmationPopup( Internal::ConfirmationPopup& implementation ); + + /** + * @brief Allows the creation of this Control from an Internal::CustomActor pointer. + * + * @param[in] internal A pointer to the internal CustomActor. + */ + DALI_INTERNAL ConfirmationPopup( Dali::Internal::CustomActor* internal ); +}; + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_CONFIRMATION_POPUP_H__ diff --git a/dali-toolkit/devel-api/controls/popup/popup.cpp b/dali-toolkit/devel-api/controls/popup/popup.cpp index 9b74a3d..f3669fa 100644 --- a/dali-toolkit/devel-api/controls/popup/popup.cpp +++ b/dali-toolkit/devel-api/controls/popup/popup.cpp @@ -20,7 +20,6 @@ // INTERNAL INCLUDES #include -#include using namespace Dali; @@ -77,69 +76,73 @@ Popup Popup::DownCast( BaseHandle handle ) return Control::DownCast(handle); } -void Popup::SetBackgroundImage( Actor image ) +// Properties: + +void Popup::SetTitle( Actor titleActor ) { - GetImpl(*this).SetBackgroundImage( image ); + GetImpl( *this ).SetTitle( titleActor ); } -void Popup::SetTitle( const std::string& text ) +Actor Popup::GetTitle() const { - GetImpl(*this).SetTitle( text ); + return GetImpl( *this ).GetTitle(); } -std::string Popup::GetTitle() const +void Popup::SetContent( Actor content ) { - return GetImpl(*this).GetTitle(); + GetImpl( *this ).SetContent( content ); } -void Popup::AddButton( Button button ) +Actor Popup::GetContent() const { - GetImpl(*this).AddButton( button ); + return GetImpl( *this ).GetContent(); } -void Popup::SetState( PopupState state ) +void Popup::SetFooter( Actor footer ) { - GetImpl(*this).SetState( state ); + GetImpl( *this ).SetFooter( footer ); } -void Popup::SetState( PopupState state, float duration ) +Actor Popup::GetFooter() const { - GetImpl(*this).SetState( state, duration ); + return GetImpl( *this ).GetFooter(); } -Popup::PopupState Popup::GetState() const +void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState ) { - return GetImpl(*this).GetState(); + GetImpl( *this ).SetDisplayState( displayState ); } -void Popup::Show() +Toolkit::Popup::DisplayState Popup::GetDisplayState() const { - GetImpl(*this).SetState( POPUP_SHOW ); + return GetImpl( *this ).GetDisplayState(); } -void Popup::Hide() +// Signals: + +Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal() { - GetImpl(*this).SetState( POPUP_HIDE ); + return GetImpl( *this ).OutsideTouchedSignal(); } -void Popup::ShowTail(const Vector3& position) +Popup::DisplayStateChangeSignalType& Popup::ShowingSignal() { - GetImpl(*this).ShowTail( position ); + return GetImpl( *this ).ShowingSignal(); } -void Popup::HideTail() +Popup::DisplayStateChangeSignalType& Popup::ShownSignal() { - GetImpl(*this).HideTail(); + return GetImpl( *this ).ShownSignal(); } -Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal() +Popup::DisplayStateChangeSignalType& Popup::HidingSignal() { - return GetImpl(*this).OutsideTouchedSignal(); + return GetImpl( *this ).HidingSignal(); } -Popup::HiddenSignalType& Popup::HiddenSignal() +Popup::DisplayStateChangeSignalType& Popup::HiddenSignal() { - return GetImpl(*this).HiddenSignal(); + return GetImpl( *this ).HiddenSignal(); } } // namespace Toolkit diff --git a/dali-toolkit/devel-api/controls/popup/popup.h b/dali-toolkit/devel-api/controls/popup/popup.h index 32322e2..40b4df3 100644 --- a/dali-toolkit/devel-api/controls/popup/popup.h +++ b/dali-toolkit/devel-api/controls/popup/popup.h @@ -32,40 +32,24 @@ namespace Internal DALI_INTERNAL class Popup; } -class Button; - /** - * @brief Popup contains content that can come into focus when activated, and out of focus when deactivated. - * - * Content: - * - * The content within a popup consists of: - * - * 1. Title - * 2. Buttons - * 3. Background/Frame (i.e. Scale-9 image) - * 4. Custom Content (Actors) - * - * All of which are optional. + * @brief The Popup widget provides a configurable pop-up dialog with built-in layout of three main fields. * - * States: + * Fields: + * - Background Image + * - Title + * - Content + * - Footer * - * A popup can be in a number of states: - * - * 1. HIDE (invisible) - * 2. SHOW (visible at normal size) - * 3. SHOW_MAXIMIZED (visible occupying full parent size) - * 4. Or custom defined. - * - * Transition Effects: - * - * A popup can use various custom transition effects, e.g. - * Alpha fade, Scaling transition, position/rotation, shader effects. + * Please see the programming guide for a detailed description of the Popup including examples. * * Signals * | %Signal Name | Method | * |-------------------|------------------------------| * | touched-outside | @ref OutsideTouchedSignal() | + * | showing | @ref ShowingSignal() | + * | shown | @ref ShownSignal() | + * | hiding | @ref HidingSignal() | * | hidden | @ref HiddenSignal() | */ class DALI_IMPORT_API Popup : public Control @@ -74,27 +58,80 @@ class DALI_IMPORT_API Popup : public Control public: /** - * @brief Current popup state. + * @brief The start and end property ranges for this control. */ - enum PopupState + enum PropertyRange { - POPUP_NONE, ///< Init status - POPUP_HIDE, ///< Hidden (not visible) - POPUP_SHOW, ///< Shown (visible in default size) + PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000 ///< Reserve property indices }; - typedef Signal< void () > TouchedOutsideSignalType; ///< Touched outside signal type. - typedef Signal< void () > HiddenSignalType; ///< Hidden signal type. + /** + * @brief An enumeration of properties belonging to the Popup class. + */ + struct Property + { + enum + { + TITLE = PROPERTY_START_INDEX, ///< name "title", type Property::Map + CONTENT, ///< name "content", type Property::Map + FOOTER, ///< name "footer", type Property::Map + DISPLAY_STATE, ///< name "display-state", type std::string + TOUCH_TRANSPARENT, ///< name "touch-transparent", type bool + TAIL_VISIBILITY, ///< name "tail-visibility", type bool + TAIL_POSITION, ///< name "tail-position", type Vector3 + CONTEXTUAL_MODE, ///< name "contextual-mode", type std::string + ANIMATION_DURATION, ///< name "animation-duration", type float + ANIMATION_MODE, ///< name "animation-mode", type std::string + ENTRY_ANIMATION, ///< name "entry-animation", type Property::Map + EXIT_ANIMATION, ///< name "exit-animation", type Property::Map + AUTO_HIDE_DELAY, ///< name "auto-hide-delay", type int + BACKING_ENABLED, ///< name "backing-enabled", type bool + BACKING_COLOR, ///< name "backing-color", type Vector4 + POPUP_BACKGROUND_IMAGE, ///< name "popup-background-image", type std::string + TAIL_UP_IMAGE, ///< name "tail-up-image", type std::string + TAIL_DOWN_IMAGE, ///< name "tail-down-image", type std::string + TAIL_LEFT_IMAGE, ///< name "tail-left-image", type std::string + TAIL_RIGHT_IMAGE, ///< name "tail-right-image", type std::string + }; + }; /** - * @brief Signal emitted when user has touched outside of the Dialog. + * The display states of the Popup. */ - TouchedOutsideSignalType& OutsideTouchedSignal(); + enum DisplayState + { + SHOWING, ///< The popup is transitioning in + SHOWN, ///< The popup is fully shown + HIDING, ///< The popup is transitioning out + HIDDEN ///< The popup is fully hidden + }; /** - * @brief Signal emitted when popup has been hidden. + * The animation mode within popup. + * Choose from a predefined mode or "CUSTOM" to use the ANIMATION_IN and ANIMATION_OUT properties. */ - HiddenSignalType& HiddenSignal(); + enum AnimationMode + { + NONE, ///< No animation. + ZOOM, ///< Popup zooms in and out animating the scale property. + FADE, ///< Popup fades in and out. + CUSTOM ///< Use the EntryAnimation and ExitAnimation animation properties. + }; + + /** + * Types of contextual layout. + * The Popup is positioned adjacent to it's parent in the direction specified by this mode. + * NON_CONTEXTUAL disables any contextual positioning. + */ + enum ContextualMode + { + NON_CONTEXTUAL, + ABOVE, + RIGHT, + BELOW, + LEFT + }; public: @@ -104,6 +141,20 @@ public: Popup(); /** + * @brief Create the Popup control. + * + * @return A handle to the Popup control. + */ + static Popup New(); + + /** + * @brief Destructor + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~Popup(); + + /** * @brief Copy constructor. * * Creates another handle that points to the same real object @@ -121,20 +172,6 @@ public: Popup& operator=( const Popup& handle ); /** - * @brief Destructor - * - * This is non-virtual since derived Handle types must not contain data or virtual methods. - */ - ~Popup(); - - /** - * @brief Create the Poup control. - * - * @return A handle to the Popup control. - */ - static Popup New(); - - /** * @brief Downcast an Object handle to Popup. * * If handle points to a Popup the @@ -147,102 +184,108 @@ public: public: /** - * @brief Sets the background image for this Popup. - * - * The background is resized (stretched according to scale settings), - * to the size of the Popup. + * @brief Sets a title for this Popup. * - * @param[in] image The Background ImageActor to cover background + * @param[in] titleActor Any actor can be specified when using this method. */ - void SetBackgroundImage( Actor image ); + void SetTitle( Actor titleActor ); /** - * @brief Sets a title for this Popup. + * @brief Gets the title actor for this Popup. * - * By default a TextView is created with following settings: black color, split-by-word multi-line policy and split exceed policy. - * - * @param[in] text The text to appear as the heading for this Popup + * @return The actor representing the title is returned. */ - void SetTitle( const std::string& text ); + Actor GetTitle() const; /** - * @brief Gets the text (TextView) for this Popup. + * @brief Sets the content actor. + * This can any actor type or heirarchy of actors. * - * @return The text to appear as the heading for this Popup + * @param[in] content The actor to use. */ - std::string GetTitle() const; + void SetContent( Actor content ); /** - * @brief Adds a button to this Popup. + * @brief Gets the actor currently used for the content. * - * Buttons are added to the bottom of the Popup and Centered. + * @return The content actor. + */ + Actor GetContent() const; + + /** + * @brief Sets the actor to use for a footer in this Popup. * - * By default the first button added will have the focus, and the focus will - * shift to other buttons based on the sequence in which they are added to the popup. + * @param[in] control The footer actor to be added to this Popup + */ + void SetFooter( Actor footer ); + + /** + * @brief Gets the footer actor. * - * @param[in] button The button to be added to this Popup + * @return The footer actor. */ - void AddButton( Button button ); + Actor GetFooter() const; /** - * @brief Sets state of Popup, such as HIDE, and SHOW. + * @brief Sets the display state of Popup. + * + * There are 4 total display states. + * Only 2 can be set, but all four can be read for better inspection of the current popup state. + * + * The other two states are getable, but not setable and are there for consistency. * - * The Popup will instantaneously jump to this state. + * | Value | Setting the state | Getting the state | + * |----------|--------------------------------|--------------------------------| + * | SHOWN | Show the popup | The popup is fully shown | + * | HIDDEN | Hide the popup | The popup is fully hidden | + * | SHOWING | | The popup is transitioning in | + * | HIDING | | The popup is transitioning out | * - * @param[in] state The state of the popup + * All 4 state changes cause notifications via 4 respective signals that can be connected to. + * @see GetDisplayState() + * + * @param[in] displayState The desired display state to change to. */ - void SetState( PopupState state ); + void SetDisplayState( Toolkit::Popup::DisplayState displayState ); /** - * @brief Sets state of Popup, such as HIDE, and SHOW. + * @brief Gets the current state of the popup. * - * The Popup will smoothly animate to this state. + * This will also show if the popup is in the process of showing or hiding. * - * @param[in] state The state of the popup - * @param[in] duration The time to animate to this new state. + * @return The current state of the popup. */ - void SetState( PopupState state, float duration ); + Toolkit::Popup::DisplayState GetDisplayState() const; + +public: + + typedef Signal< void () > TouchedOutsideSignalType; ///< Touched outside signal type. + typedef Signal< void () > DisplayStateChangeSignalType; ///< Used for signals emitted when the displayed state changes. /** - * @brief Gets the state of the popup. - * - * @return The state of the popup. + * @brief Signal emitted when user has touched outside of the Dialog. */ - PopupState GetState() const; + TouchedOutsideSignalType& OutsideTouchedSignal(); /** - * @brief Shows the popup. - * - * The Popup will animate to the SHOW state + * @brief Signal emitted when the Popup is starting to be shown. */ - void Show(); + DisplayStateChangeSignalType& ShowingSignal(); /** - * @brief Hides the popup. - * - * The Popup will animate to the HIDE state + * @brief Signal emitted when the Popup has been fully displayed. */ - void Hide(); + DisplayStateChangeSignalType& ShownSignal(); /** - * @brief Shows the tail. - * - * The tail position is specified relative to it's Parent. - * To display at top center for instace, pass: - * - * ParentOrigin::TOP_CENTER - * - * @note The tail images are defined inside PopupStyle as - * tailUpImage, tailDownImage, tailLeftImage, and tailRightImage - * - * @param[in] position A position around the perimeter of the Parent. + * @brief Signal emitted when the Popup is starting to be hidden. */ - void ShowTail(const Vector3& position); + DisplayStateChangeSignalType& HidingSignal(); /** - * @brief Hides the tail. + * @brief Signal emitted when the Popup has been completely hidden. */ - void HideTail(); + DisplayStateChangeSignalType& HiddenSignal(); public: // Not intended for application developers @@ -251,7 +294,7 @@ public: // Not intended for application developers * * @param[in] implementation The Control implementation. */ - DALI_INTERNAL Popup(Internal::Popup& implementation); + DALI_INTERNAL Popup( Internal::Popup& implementation ); /** * @brief Allows the creation of this Control from an Internal::CustomActor pointer. diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list index 71202e2..c5187c3 100755 --- a/dali-toolkit/devel-api/file.list +++ b/dali-toolkit/devel-api/file.list @@ -12,6 +12,7 @@ devel_api_src_files = \ $(devel_api_src_dir)/controls/page-turn-view/page-turn-landscape-view.cpp \ $(devel_api_src_dir)/controls/page-turn-view/page-turn-portrait-view.cpp \ $(devel_api_src_dir)/controls/page-turn-view/page-turn-view.cpp \ + $(devel_api_src_dir)/controls/popup/confirmation-popup.cpp \ $(devel_api_src_dir)/controls/popup/popup.cpp \ $(devel_api_src_dir)/controls/shadow-view/shadow-view.cpp \ $(devel_api_src_dir)/controls/slider/slider.cpp \ @@ -53,6 +54,7 @@ devel_api_page_turn_view_header_files = \ $(devel_api_src_dir)/controls/page-turn-view/page-turn-view.h devel_api_popup_header_files = \ + $(devel_api_src_dir)/controls/popup/confirmation-popup.h \ $(devel_api_src_dir)/controls/popup/popup.h devel_api_shadow_view_header_files = \ diff --git a/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp new file mode 100644 index 0000000..cb0c9e9 --- /dev/null +++ b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "confirmation-popup-impl.h" + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace +{ + +/* + * This struct is used to define all details required about a dynamically created signal. + */ +struct ControlDetailType +{ + const char* signalName; + const char* controlName; + const char* connectSignalPropertyName; +}; + +/* A table of all control details. These details are kept in one place for maintainability. + * Name of the signal | Name of the control | Name of the property which lets the + * the app-developer | which will provide | app developer choose which signal + * can connect to. | the signal. | within the control to connect to. */ +const ControlDetailType ControlDetails[] = { + { "control-signal-ok", "control-ok", "connect-signal-ok-selected" }, + { "control-signal-cancel", "control-cancel", "connect-signal-cancel-selected" }, +}; +const unsigned int ControlDetailsCount = sizeof( ControlDetails ) / sizeof( ControlDetails[0] ); + +// To give sensible default behaviour to save the connect signal properties being set. +const char* const DEFAULT_CONNECT_SIGNAL_NAME = "clicked"; + +BaseHandle Create() +{ + return Toolkit::ConfirmationPopup::New(); +} + +DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ConfirmationPopup, Toolkit::Popup, Create ) + +DALI_PROPERTY_REGISTRATION( Toolkit, ConfirmationPopup, ControlDetails[0].connectSignalPropertyName, STRING, CONNECT_SIGNAL_OK_SELECTED ) +DALI_PROPERTY_REGISTRATION( Toolkit, ConfirmationPopup, ControlDetails[1].connectSignalPropertyName, STRING, CONNECT_SIGNAL_CANCEL_SELECTED ) + +// Note: We do not use the macros for signal registration as we do not want to redefine the signal name strings. +// We have predefined them for optimal signal name to control name lookup. +SignalConnectorType signalConnector1( typeRegistration, ControlDetails[0].signalName, &Toolkit::Internal::ConfirmationPopup::DoConnectSignal ); +SignalConnectorType signalConnector2( typeRegistration, ControlDetails[1].signalName, &Toolkit::Internal::ConfirmationPopup::DoConnectSignal ); + +DALI_TYPE_REGISTRATION_END() + +} // Unnamed namespace + +Dali::Toolkit::ConfirmationPopup ConfirmationPopup::New() +{ + // Create the implementation, temporarily owned on stack. + IntrusivePtr< ConfirmationPopup > internalConfirmationPopup = new ConfirmationPopup(); + + // Pass ownership to CustomActor + Dali::Toolkit::ConfirmationPopup confirmationPopup( *internalConfirmationPopup ); + + // Second-phase initialisation of the implementation. + // This can only be done after the CustomActor connection has been made... + internalConfirmationPopup->Initialize(); + + return confirmationPopup; +} + +ConfirmationPopup::ConfirmationPopup() +: Toolkit::Internal::Popup() +{ + mControlSignals.reserve( MAXIMUM_NUMBER_OF_CONTROLS ); + mControlSignalNames[ Toolkit::ConfirmationPopup::CONTROL_OK ] = DEFAULT_CONNECT_SIGNAL_NAME; + mControlSignalNames[ Toolkit::ConfirmationPopup::CONTROL_CANCEL ] = DEFAULT_CONNECT_SIGNAL_NAME; +} + +ConfirmationPopup::~ConfirmationPopup() +{ + for( SignalContainerType::iterator i = mControlSignals.begin(); i != mControlSignals.end(); ++i ) + { + delete ( i->second ); + } + mControlSignals.clear(); +} + +void ConfirmationPopup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value ) +{ + Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( Dali::BaseHandle( object ) ); + + if ( popup ) + { + ConfirmationPopup& popupImpl( GetDerivedImplementation( popup ) ); + + switch ( propertyIndex ) + { + case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED: + { + popupImpl.SetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_OK, value.Get< std::string >() ); + break; + } + case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED: + { + popupImpl.SetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_CANCEL, value.Get< std::string >() ); + break; + } + } + } +} + +Property::Value ConfirmationPopup::GetProperty( BaseObject* object, Property::Index propertyIndex ) +{ + Property::Value value; + + Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( Dali::BaseHandle( object ) ); + + if ( popup ) + { + ConfirmationPopup& popupImpl( GetDerivedImplementation( popup ) ); + + switch ( propertyIndex ) + { + case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED: + { + value = popupImpl.GetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_OK ); + break; + } + case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED: + { + value = popupImpl.GetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_CANCEL ); + break; + } + } + } + + return value; +} + +void ConfirmationPopup::SetControlSignalName( const unsigned int controlNumber, const std::string& signalName ) +{ + if( controlNumber < ControlDetailsCount ) + { + mControlSignalNames[ controlNumber ] = signalName; + } +} + +std::string ConfirmationPopup::GetControlSignalName( unsigned int controlNumber ) const +{ + if( controlNumber < ControlDetailsCount ) + { + return mControlSignalNames[ controlNumber ]; + } + + return ""; +} + +bool ConfirmationPopup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) +{ + Dali::BaseHandle handle( object ); + Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( handle ); + + // Look up the requested signal, attempting to create it dynamically if it doesn't exist. + SignalDelegate* signalDelegate = Dali::Toolkit::GetDerivedImplementation( popup ).GetControlSignal( signalName ); + if( signalDelegate ) + { + // The signal delegate was created successfully, attempt to connect it to a callback if specified. + // If none is specified, the creation is still successful as the signal delegate can connect at a later time. + if( functor ) + { + signalDelegate->Connect( tracker, functor ); + } + return true; + } + + // The signal could not be created. + return false; +} + +SignalDelegate* ConfirmationPopup::GetControlSignal( const std::string& signalName ) +{ + // Check if the specified signal name already exists. + SignalContainerType::iterator end = mControlSignals.end(); + for( SignalContainerType::iterator iter = mControlSignals.begin(); iter != end; ++iter ) + { + // Find the first non-connected signal by matching signal name. + if( ( signalName == iter->first ) && ( !iter->second->IsConnected() ) ) + { + // The requested signal (delegate) already exists, just return it. + return iter->second; + } + } + + // The signal doesn't exist, or it does but it's already connected to something else. + // To make a new connection to an existing signal, we need a new delegate, + // as delegates house a signal connection functor each. + // Check the signal name is valid and if so create the signal dynamically. + for( unsigned int i = 0; i < ControlDetailsCount; ++i ) + { + if( 0 == strcmp( signalName.c_str(), ControlDetails[ i ].signalName ) ) + { + // The signal name is valid, check the respective actor to connect to exists. + Actor connectActor = Self().FindChildByName( ControlDetails[ i ].controlName ); + if( connectActor ) + { + // The actor exists, set up a signal delegate that will allow the application developer + // to connect the actor signal directly to their callback. + // Note: We don't use the GetControlSignalName() here for speedup, as we know the array bound is capped. + SignalDelegate* signalDelegate = new SignalDelegate( connectActor, mControlSignalNames[ i ] ); + + // Store the delegate with the signal name so we know what signals have been dynamically created so far. + mControlSignals.push_back( std::make_pair( signalName, signalDelegate ) ); + + // Return the delegate to allow connection to the newly created signal. + return signalDelegate; + } + + // Signal name valid but could not connect to the control, + return NULL; + } + } + + // Signal name was not found (invalid). + return NULL; +} + + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/controls/popup/confirmation-popup-impl.h b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.h new file mode 100644 index 0000000..45f23a9 --- /dev/null +++ b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.h @@ -0,0 +1,180 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_CONFIRMATION_POPUP_H__ +#define __DALI_TOOLKIT_INTERNAL_CONFIRMATION_POPUP_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include "popup-impl.h" +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace +{ + +#define MAXIMUM_NUMBER_OF_CONTROLS 2 + +} + +/** + * ConfirmationPopup implementation class. + * + * \sa Dali::Toolkit::ConfirmationPopup + */ +class ConfirmationPopup : public Dali::Toolkit::Internal::Popup +{ +public: + + /** + * Create a new ConfirmationPopup. + * @return A smart-pointer to the newly allocated ConfirmationPopup. + */ + static Dali::Toolkit::ConfirmationPopup New(); + +protected: + + /** + * Construct a new ConfirmationPopup. + */ + ConfirmationPopup(); + + /** + * A reference counted object may only be deleted by calling Unreference() + */ + virtual ~ConfirmationPopup(); + +public: + + /** + * Called when a property of an object of this type is set. + * @param[in] object The object whose property is set. + * @param[in] propertyIndex The property index. + * @param[in] value The new property value. + */ + static void SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value ); + + /** + * Called to retrieve a property of an object of this type. + * @param[in] object The object whose property is to be retrieved. + * @param[in] propertyIndex The property index. + * @return The current value of the property. + */ + static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex ); + + /** + * Connects a callback function with the object's signals. + * @param[in] object The object providing the signal. + * @param[in] tracker Used to disconnect the signal. + * @param[in] signalName The signal to connect to. + * @param[in] functor A newly allocated FunctorDelegate. + * @return True if the signal was connected. + * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor. + */ + static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ); + +private: + + /** + * This type houses a list of dynamically created signals. + */ + typedef std::vector< std::pair< std::string, SignalDelegate* > > SignalContainerType; + +private: + + /** + * Sets the name of the signal to connect to within the specified actor. + * + * @param[in] controlNumber The index of the control. + * @param[in] signalName The name of the signal to connect to. + */ + void SetControlSignalName( const unsigned int controlNumber, const std::string& signalName ); + + /** + * Gets the name of the signal to connect to within the specified actor. + * + * @param[in] controlNumber The index of the control. + * @return The name of the signal to connect to. + */ + std::string GetControlSignalName( unsigned int controlNumber ) const; + + /** + * @copydoc Control::GetControlSignal() + */ + SignalDelegate* GetControlSignal( const std::string& signalName ); + +private: + + // Undefined + ConfirmationPopup( const ConfirmationPopup& ); + + // Undefined + ConfirmationPopup& operator=( const ConfirmationPopup& ); + +private: + + // Properties: + + std::string mControlSignalNames[ MAXIMUM_NUMBER_OF_CONTROLS ]; ///< Stores the names of the signals to connect to per control. + + // Internal variables: + + SignalContainerType mControlSignals; ///< Stores the dynamically created signals. + +}; + +} // namespace Internal + + +// Helpers for public-api forwarding methods + +inline Toolkit::Internal::ConfirmationPopup& GetDerivedImplementation( Toolkit::ConfirmationPopup& popup ) +{ + DALI_ASSERT_ALWAYS( popup ); + + Dali::RefObject& handle = popup.GetImplementation(); + + return static_cast( handle ); +} + +inline const Toolkit::Internal::ConfirmationPopup& GetDerivedImplementation( const Toolkit::ConfirmationPopup& popup ) +{ + DALI_ASSERT_ALWAYS( popup ); + + const Dali::RefObject& handle = popup.GetImplementation(); + + return static_cast( handle ); +} + + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_CONFIRMATION_POPUP_H__ diff --git a/dali-toolkit/internal/controls/popup/popup-impl.cpp b/dali-toolkit/internal/controls/popup/popup-impl.cpp index d4fcc43..cc7ae5d 100755 --- a/dali-toolkit/internal/controls/popup/popup-impl.cpp +++ b/dali-toolkit/internal/controls/popup/popup-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,26 +20,25 @@ // EXTERNAL INCLUDES #include // for strcmp -#include #include +#include +#include +#include #include #include #include #include #include #include -#include +#include #include -#include // INTERNAL INCLUDES -#include +#include #include -#include #include #include #include -#include using namespace Dali; @@ -55,524 +54,1332 @@ namespace Internal namespace { +/** + * Creation function for main Popup type. + * @return Handle to the new popup object. + */ BaseHandle Create() { return Toolkit::Popup::New(); } -// Setup properties, signals and actions using the type-registry. -DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Popup, Toolkit::Control, Create ) +// Toast style defaults. +const int DEFAULT_TOAST_AUTO_HIDE_DELAY = 3000; ///< Toast will auto-hide after 3000ms (3 seconds) +const float DEFAULT_TOAST_TRANSITION_TIME = 0.65f; ///< Default time the toast Popup will take to show and hide. +const Vector3 DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN( 0.5f, 0.94f, 0.5f ); ///< This is similar to BOTTOM_CENTER, but vertically higher up, as a ratio of parent height. +const Vector3 DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO( 0.75f, 0.75f, 0.75f ); ///< Amount of the stage's width that the toast popup will take up. -DALI_SIGNAL_REGISTRATION( Toolkit, Popup, "touched-outside", SIGNAL_TOUCHED_OUTSIDE ) -DALI_SIGNAL_REGISTRATION( Toolkit, Popup, "hidden", SIGNAL_HIDDEN ) +/** + * Creation function for named type "popup-toast". + * @return Handle to the new toast popup object. + */ +BaseHandle CreateToast() +{ + Toolkit::Popup popup = Toolkit::Popup::New(); -DALI_TYPE_REGISTRATION_END() + // Setup for Toast Popup type. + popup.SetSizeModeFactor( DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO ); + popup.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH ); + popup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT ); + popup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, Toolkit::Popup::NON_CONTEXTUAL ); + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, DEFAULT_TOAST_TRANSITION_TIME ); + popup.SetProperty( Toolkit::Popup::Property::TAIL_VISIBILITY, false ); -// Properties -const char* const PROPERTY_TITLE = "title"; -const char* const PROPERTY_STATE = "state"; + // Disable the dimmed backing. + popup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false ); -const float POPUP_ANIMATION_DURATION = 0.45f; ///< Duration of hide/show animations + // The toast popup should fade in (not zoom). + popup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, Toolkit::Popup::FADE ); -const float POPUP_WIDTH = 720.0f; ///< Width of Popup -const float POPUP_OUT_MARGIN_WIDTH = 16.f; ///< Space between the screen edge and the popup edge in the horizontal dimension. -const float POPUP_OUT_MARGIN_HEIGHT = 36.f; ///< Space between the screen edge and the popup edge in the vertical dimension. -const float POPUP_TITLE_WIDTH = 648.0f; /// DEFAULT_TITLE_PADDING( 20.0f, 20.0f, 20.0f, 20.0f ); ///< Title padding used on popups with content and/or controls (from Tizen GUI UX). +const Rect DEFAULT_TITLE_ONLY_PADDING( 8.0f, 8.0f, 8.0f, 8.0f ); ///< Title padding used on popups with a title only (like toast popups). +const Vector3 FOOTER_SIZE( 620.0f, 96.0f,0.0f ); ///< Default size of the bottom control area. +const float DEFAULT_RELATIVE_PARENT_WIDTH = 0.75f; ///< If width is not fixed, relative size to parent is used by default. + +} // Unnamed namespace + +/* + * Implementation. + */ Dali::Toolkit::Popup Popup::New() { - PopupStylePtr style = PopupStyleDefault::New(); - // Create the implementation - PopupPtr popup(new Popup(*style)); + PopupPtr popup( new Popup() ); - // Pass ownership to CustomActor via derived handle - Dali::Toolkit::Popup handle(*popup); + // Pass ownership to CustomActor via derived handle. + Dali::Toolkit::Popup handle( *popup ); - // Second-phase init of the implementation - // This can only be done after the CustomActor connection has been made... + // Second-phase initialisation of the implementation. + // This can only be done after the CustomActor connection has been made. popup->Initialize(); return handle; } -Popup::Popup(PopupStyle& style) +Popup::Popup() : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ), - mShowing(false), - mState(Toolkit::Popup::POPUP_NONE), // Initially, the popup state should not be set, it's set in OnInitialize - mAlterAddedChild(false), - mPopupStyle(PopupStylePtr(&style)), - mPropertyTitle(Property::INVALID_INDEX), - mPropertyState(Property::INVALID_INDEX) + // Main variables: + mAlterAddedChild( false ), + mLayoutDirty( true ), + mTouchTransparent( false ), + + // Property variables: + mDisplayState( Toolkit::Popup::HIDDEN ), // Hidden until shown with SetDisplayState() + mTailVisible( false ), + mTailPosition( DEFAULT_TAIL_POSITION ), + mContextualMode( Toolkit::Popup::NON_CONTEXTUAL ), + mAnimationDuration( DEFAULT_POPUP_ANIMATION_DURATION ), + mAnimationMode( Toolkit::Popup::FADE ), + mAutoHideDelay( 0 ), + mBackingEnabled( true ), + mBackingColor( DEFAULT_BACKING_COLOR ), + mTailUpImage( DEFAULT_TAIL_UP_IMAGE_PATH ), + mTailDownImage( DEFAULT_TAIL_DOWN_IMAGE_PATH ), + mTailLeftImage( DEFAULT_TAIL_LEFT_IMAGE_PATH ), + mTailRightImage( DEFAULT_TAIL_RIGHT_IMAGE_PATH ) { SetKeyboardNavigationSupport( true ); } void Popup::OnInitialize() { - Dali::Stage stage = Dali::Stage::GetCurrent(); - Actor self = Self(); - self.SetSensitive(false); - // Reisize to fit the height of children - self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT ); + self.SetName( "popup" ); - // Create Layer + // Apply some default resizing rules. + self.SetParentOrigin( ParentOrigin::CENTER ); + self.SetAnchorPoint( AnchorPoint::CENTER ); + + self.SetSizeModeFactor( DEFAULT_POPUP_PARENT_RELATIVE_SIZE ); + self.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH ); + self.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT ); + + // Create a new layer so all Popup components can appear above all other actors. mLayer = Layer::New(); - mLayer.SetName( "POPUP_LAYER" ); - mLayer.SetDepthTestDisabled( true ); - mLayer.SetParentOrigin(ParentOrigin::CENTER); - mLayer.SetAnchorPoint(AnchorPoint::CENTER); + mLayer.SetName( "popup-layer" ); + + mLayer.SetParentOrigin( ParentOrigin::CENTER ); + mLayer.SetAnchorPoint( AnchorPoint::CENTER ); mLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - // Any content after this point which is added to Self() will be reparented to - // mContent. - mAlterAddedChild = true; - // Add Backing (Dim effect) - CreateBacking(); - mAlterAddedChild = false; + // Important to set as invisible as otherwise, if the popup is parented, + // but not shown yet it will appear statically on the screen. + mLayer.SetVisible( false ); + + // Add the layer to the hierarchy. + self.Add( mLayer ); - // Add Dialog ( background image, title, content container, button container and tail ) - CreateDialog(); + // Add Backing (Dimmed effect). + mLayer.Add( CreateBacking() ); - mLayer.Add( self ); + mPopupContainer = Actor::New(); + mPopupContainer.SetName( "popup-container" ); + mPopupContainer.SetParentOrigin( ParentOrigin::CENTER ); + mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER ); + mPopupContainer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS ); + mLayer.Add( mPopupContainer ); + // Create the Popup layout to contain all main content. mPopupLayout = Toolkit::TableView::New( 3, 1 ); - mPopupLayout.SetName( "POPUP_LAYOUT_TABLE" ); - mPopupLayout.SetParentOrigin(ParentOrigin::CENTER); - mPopupLayout.SetAnchorPoint(AnchorPoint::CENTER); - mPopupLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); + + // Adds the default background image. + SetPopupBackgroundImage( ImageActor::New( ResourceImage::New( DEFAULT_BACKGROUND_IMAGE_PATH ) ) ); + + mPopupLayout.SetName( "popup-layout-table" ); + mPopupLayout.SetParentOrigin( ParentOrigin::CENTER ); + mPopupLayout.SetAnchorPoint( AnchorPoint::CENTER ); + + mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH ); mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT ); - mPopupLayout.SetFitHeight( 0 ); // Set row to fit - mPopupLayout.SetFitHeight( 1 ); // Set row to fit - self.Add( mPopupLayout ); + mPopupLayout.SetSize( Stage::GetCurrent().GetSize().x * DEFAULT_RELATIVE_PARENT_WIDTH, 0.0f ); + + mPopupLayout.SetFitHeight( 0 ); // Set row to fit. + mPopupLayout.SetFitHeight( 1 ); // Set row to fit. - // Any content after this point which is added to Self() will be reparented to - // mContent. + mPopupLayout.TouchedSignal().Connect( this, &Popup::OnDialogTouched ); + + mPopupContainer.Add( mPopupLayout ); + + // Any content after this point which is added to Self() will be re-parented to mContent. mAlterAddedChild = true; - // Default content. -// ShowTail(ParentOrigin::BOTTOM_CENTER); + // Make self keyboard focusable and a focus group. + self.SetKeyboardFocusable( true ); + SetAsKeyboardFocusGroup( true ); +} + +Popup::~Popup() +{ + mEntryAnimationData.Clear(); + mExitAnimationData.Clear(); +} - // Hide content by default. - SetState( Toolkit::Popup::POPUP_HIDE, 0.0f ); +void Popup::LayoutAnimation() +{ + // Perform setup based on the currently selected animation. + switch( mAnimationMode ) + { + case Toolkit::Popup::ZOOM: + { + // Zoom animations start fully zoomed out. + mPopupContainer.SetScale( Vector3::ZERO ); + break; + } - mPropertyTitle = self.RegisterProperty( PROPERTY_TITLE, "", Property::READ_WRITE ); - mPropertyState = self.RegisterProperty( PROPERTY_STATE, "POPUP_HIDE", Property::READ_WRITE ); + case Toolkit::Popup::FADE: + { + // Fade animations start transparent. + mPopupContainer.SetOpacity( 0.0f ); + break; + } - // Make self as keyboard focusable and focus group - self.SetKeyboardFocusable(true); - SetAsKeyboardFocusGroup(true); + case Toolkit::Popup::CUSTOM: + { + // Initialise the custom animation by playing to the end of it's exit animation instantly. + // EG. If it was zooming in, then we zoom out fully instantly so the zoom in works. + StartTransitionAnimation( false, true ); + break; + } + + case Toolkit::Popup::NONE: + { + break; + } + } } -void Popup::OnPropertySet( Property::Index index, Property::Value propertyValue ) +void Popup::StartTransitionAnimation( bool transitionIn, bool instantaneous /* false */ ) { - if( index == mPropertyTitle ) + // Stop and recreate animation. + if ( mAnimation ) { - SetTitle(propertyValue.Get()); + mAnimation.Stop(); + mAnimation.Clear(); + mAnimation.Reset(); } - else if ( index == mPropertyState ) + float duration = GetAnimationDuration(); + + // Setup variables ready to start the animations. + // If we are performing the animation instantaneously, we do not want to emit a signal. + if( !instantaneous ) { - std::string value( propertyValue.Get() ); - if(value == "POPUP_SHOW") + if( transitionIn ) { - SetState( Toolkit::Popup::POPUP_SHOW, 0.0f ); + // Setup variables and signal that we are starting the transition. + // Note: We signal even if the transition is instant so signal order is consistent. + mShowingSignal.Emit(); } - else if( value == "POPUP_HIDE") + else { - SetState( Toolkit::Popup::POPUP_HIDE, 0.0f ); + mHidingSignal.Emit(); } } -} -Popup::~Popup() -{ - mLayer.Unparent(); + // Perform chosen animation for the Popup. + switch( mAnimationMode ) + { + case Toolkit::Popup::NONE: + { + mAnimation = Animation::New( 0.0f ); + break; + } + + case Toolkit::Popup::ZOOM: + { + mAnimation = Animation::New( duration ); + if( duration > Math::MACHINE_EPSILON_0 ) + { + if( transitionIn ) + { + mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT, TimePeriod( duration * 0.25f, duration * 0.75f ) ); + } + else + { + // Zoom out animation is twice the speed. Modify the duration variable so the backing animation speed is modified also. + duration /= 2.0f; + mAnimation.SetDuration( duration ); + mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ZERO, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration ) ); + } + } + else + { + mPopupContainer.SetScale( transitionIn ? Vector3::ONE : Vector3::ZERO ); + } + break; + } + + case Toolkit::Popup::FADE: + { + mAnimation = Animation::New( duration ); + if( duration > Math::MACHINE_EPSILON_0 ) + { + if( transitionIn ) + { + mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) ); + } + else + { + mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) ); + } + } + else + { + mPopupContainer.SetOpacity( transitionIn ? 1.0f : 0.0f ); + } + break; + } + + case Toolkit::Popup::CUSTOM: + { + // Use a user specified animation for in and out. + // Read the correct animation depending on entry or exit. + // Attempt to use animation data defined from script data. + Dali::AnimationData* animationData = transitionIn ? &mEntryAnimationData : &mExitAnimationData; + + // Create a new animation from the pre-defined data in the AnimationData class. + // If there is no data, mAnimation is invalidated. + mAnimation = animationData->CreateAnimation( mPopupContainer, duration ); + + // If we don't have a valid animation, provide a blank one so play() can still function generically. + if( !mAnimation ) + { + // No animation was configured (even though custom mode was specified). Create a dummy animation to avoid an exception. + mAnimation = Animation::New( 0.0f ); + } + + break; + } + } + + // Animate the backing, if enabled. + // This is set up last so that different animation modes can have an effect on the backing animation speed. + if( mBackingEnabled ) + { + if( duration > Math::MACHINE_EPSILON_0 ) + { + if( transitionIn ) + { + mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) ); + } + else + { + mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) ); + } + } + else + { + mBacking.SetOpacity( transitionIn ? 1.0f : 0.0f ); + } + } + + // If we are performing the animation instantaneously, jump to the position directly and do not signal. + if( instantaneous ) + { + mAnimation.SetCurrentProgress( 1.0f ); + mAnimation.Play(); + } + else if( duration > Math::MACHINE_EPSILON_0 ) + { + // Run the animation. + mAnimation.FinishedSignal().Connect( this, &Popup::OnDisplayChangeAnimationFinished ); + mAnimation.Play(); + } + else + { + // We did not use an animation to achive the transition. + // Trigger the state change directly. + DisplayStateChangeComplete(); + } } -size_t Popup::GetButtonCount() const +void Popup::OnDisplayChangeAnimationFinished( Animation& source ) { - return mButtons.size(); + DisplayStateChangeComplete(); } -void Popup::SetBackgroundImage( Actor image ) +void Popup::DisplayStateChangeComplete() { - // Removes any previous background. - if( mBackgroundImage && mPopupLayout ) + // Remove contents from stage if completely hidden. + if( mDisplayState == Toolkit::Popup::HIDING ) { - mPopupLayout.Remove( mBackgroundImage ); - } + mDisplayState = Toolkit::Popup::HIDDEN; - // Adds new background to the dialog. - mBackgroundImage = image; + mLayer.SetVisible( false ); + mPopupLayout.SetSensitive( false ); - mBackgroundImage.SetName( "POPUP_BACKGROUND_IMAGE" ); + // Guard against destruction during signal emission. + Toolkit::Popup handle( GetOwner() ); + mHiddenSignal.Emit(); + } + else if( mDisplayState == Toolkit::Popup::SHOWING ) + { + mDisplayState = Toolkit::Popup::SHOWN; + Toolkit::Popup handle( GetOwner() ); + mShownSignal.Emit(); + + // Start a timer to auto-hide if enabled. + if( mAutoHideDelay > 0u ) + { + mAutoHideTimer = Timer::New( mAutoHideDelay ); + mAutoHideTimer.TickSignal().Connect( this, &Popup::OnAutoHideTimeReached ); + mAutoHideTimer.Start(); + } + } +} - // OnDialogTouched only consume the event. It prevents the touch event to be caught by the backing. - mBackgroundImage.TouchedSignal().Connect( this, &Popup::OnDialogTouched ); +bool Popup::OnAutoHideTimeReached() +{ + // Display timer has expired, auto hide the popup exactly as if the user had clicked outside. + SetDisplayState( Toolkit::Popup::HIDDEN ); - mBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS ); - mBackgroundImage.SetAnchorPoint( AnchorPoint::CENTER ); - mBackgroundImage.SetParentOrigin( ParentOrigin::CENTER ); + if( mAutoHideTimer ) + { + mAutoHideTimer.Stop(); + mAutoHideTimer.TickSignal().Disconnect( this, &Popup::OnAutoHideTimeReached ); + mAutoHideTimer.Reset(); + } + return true; +} - if ( ImageActor imageActor = DownCast< ImageActor >( image ) ) +void Popup::SetPopupBackgroundImage( Actor image ) +{ + // Removes any previous background. + if( mPopupBackgroundImage ) { - imageActor.SetSortModifier( BACKGROUND_DEPTH_INDEX ); + mPopupContainer.Remove( mPopupBackgroundImage ); } - Vector3 border( mPopupStyle->backgroundOuterBorder.x, mPopupStyle->backgroundOuterBorder.z, 0.0f ); - mBackgroundImage.SetSizeModeFactor( border ); + // Adds new background to the dialog. + mPopupBackgroundImage = image; + mPopupBackgroundImage.SetName( "popup-background-image" ); + mPopupBackgroundImage.SetAnchorPoint( AnchorPoint::CENTER ); + mPopupBackgroundImage.SetParentOrigin( ParentOrigin::CENTER ); + + // OnDialogTouched only consumes the event. It prevents the touch event to be caught by the backing. + mPopupBackgroundImage.TouchedSignal().Connect( this, &Popup::OnDialogTouched ); + + // Set the popup border to be slightly larger than the layout contents. + mPopupBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS ); + mPopupBackgroundImage.SetSizeModeFactor( BACKGROUND_OUTER_BORDER ); const bool prevAlter = mAlterAddedChild; mAlterAddedChild = false; - Self().Add( mBackgroundImage ); + mPopupContainer.Add( mPopupBackgroundImage ); mAlterAddedChild = prevAlter; + + mLayoutDirty = true; +} + +Actor Popup::GetPopupBackgroundImage() const +{ + return mPopupBackgroundImage; } -void Popup::SetButtonAreaImage( Actor image ) +void Popup::SetTitle( Actor titleActor ) { - // Removes any previous area image. - if( mButtonAreaImage && mPopupLayout ) + // Replaces the current title actor. + if( !mPopupLayout ) { - mPopupLayout.Remove( mButtonAreaImage ); + return; } - // Adds new area image to the dialog. - mButtonAreaImage = image; - - if ( ImageActor imageActor = DownCast< ImageActor >( image ) ) + if( mTitle ) { - imageActor.SetSortModifier( BACKGROUND_DEPTH_INDEX + 1 ); + mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 0, 0) ); } + mTitle = titleActor; - // OnDialogTouched only consume the event. It prevents the touch event to be caught by the backing. - mButtonAreaImage.TouchedSignal().Connect( this, &Popup::OnDialogTouched ); - - mButtonAreaImage.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - mButtonAreaImage.SetAnchorPoint( AnchorPoint::CENTER ); - mButtonAreaImage.SetParentOrigin( ParentOrigin::CENTER ); - - if( GetButtonCount() > 0 ) + if( mTitle ) { - mBottomBg.Add( mButtonAreaImage ); + // Set up padding to give sensible default behaviour + // (an application developer can later override this if they wish). + mTitle.SetPadding( DEFAULT_TITLE_PADDING ); + + mPopupLayout.AddChild( mTitle, Toolkit::TableView::CellPosition( 0, 0 ) ); } + + mLayoutDirty = true; + RelayoutRequest(); } -void Popup::SetTitle( const std::string& text ) +Actor Popup::GetTitle() const { - // Replaces the current title actor. + return mTitle; +} + +void Popup::SetContent( Actor content ) +{ + // Remove previous content actor. if( mPopupLayout ) { - mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 0, 0 ) ); + mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 1, 0 ) ); } + // Keep a handle to the new content. + mContent = content; - mTitle = Toolkit::TextLabel::New( text ); - mTitle.SetName( "POPUP_TITLE" ); - mTitle.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true ); - mTitle.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); - - if( mPopupLayout ) + if( mContent ) { - mTitle.SetPadding( Padding( 0.0f, 0.0f, mPopupStyle->margin, mPopupStyle->margin ) ); - mTitle.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); - mTitle.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT ); - mPopupLayout.AddChild( mTitle, Toolkit::TableView::CellPosition( 0, 0 ) ); + mContent.SetName( "popup-content" ); + + mPopupLayout.AddChild( mContent, Toolkit::TableView::CellPosition( 1, 0 ) ); } + mLayoutDirty = true; RelayoutRequest(); } -std::string Popup::GetTitle() const +Actor Popup::GetContent() const { - if( mTitle ) + return mContent; +} + +void Popup::SetFooter( Actor footer ) +{ + // Remove previous content actor. + if( mPopupLayout ) { - return mTitle.GetProperty( Toolkit::TextLabel::Property::TEXT ); + mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 2, 0 ) ); } - return std::string(); -} + // Keep a handle to the new content. + mFooter = footer; -void Popup::CreateFooter() -{ - if( !mBottomBg ) + if( mFooter ) { - // Adds bottom background - mBottomBg = Actor::New(); - mBottomBg.SetName( "POPUP_BOTTOM_BG" ); - mBottomBg.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + mFooter.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); - mPopupLayout.SetFixedHeight( 2, mPopupStyle->bottomSize.height ); // Buttons - mPopupLayout.AddChild( mBottomBg, Toolkit::TableView::CellPosition( 2, 0 ) ); + // The control container has a fixed height. + mPopupLayout.SetFitHeight( 2u ); + mPopupLayout.AddChild( footer, Toolkit::TableView::CellPosition( 2, 0 ) ); } + + mLayoutDirty = true; + RelayoutRequest(); } -void Popup::AddButton( Toolkit::Button button ) +Actor Popup::GetFooter() const { - mButtons.push_back( button ); - button.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::ALL_DIMENSIONS ); // Size will be assigned to it + return mFooter; +} + +void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState ) +{ + // Convert the 4-way state to a bool, true for show, false for hide. + bool display = ( displayState == Toolkit::Popup::SHOWING ) || ( displayState == Toolkit::Popup::SHOWN ); + + // Ignore if we are already at the target display state. + if( display == ( ( mDisplayState == Toolkit::Popup::SHOWING ) || ( mDisplayState == Toolkit::Popup::SHOWN ) ) ) + { + return; + } + + // Convert the bool state to the actual display state to use. + mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING; - // If this is the first button added - if( mButtons.size() == 1 ) + if ( display ) { - CreateFooter(); + // Update the state to indicate the current intent. + mDisplayState = Toolkit::Popup::SHOWING; - if( mButtonAreaImage ) + // We are displaying so bring the popup layer to the front, and set it visible so it is rendered. + mLayer.RaiseToTop(); + mLayer.SetVisible( true ); + + // Set up the layout if this is the first display or the layout has become dirty. + if( mLayoutDirty ) { - mBottomBg.Add( mButtonAreaImage ); + // Bake-in any style and layout options to create the Popup layout. + LayoutPopup(); + } + + // Allow the popup to catch events. + mPopupLayout.SetSensitive( true ); + SetKeyInputFocus(); + + // Handle the keyboard focus when popup is shown. + Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get(); + if( keyboardFocusManager ) + { + mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor(); + + if( mContent && mContent.IsKeyboardFocusable() ) + { + // If content is focusable, move the focus to content. + keyboardFocusManager.SetCurrentFocusActor( mContent ); + } + else + { + DALI_LOG_WARNING( "There is no focusable in popup\n" ); + } } } + else // Not visible. + { + mDisplayState = Toolkit::Popup::HIDING; + ClearKeyInputFocus(); - mBottomBg.Add( button ); + // Restore the keyboard focus when popup is hidden. + if( mPreviousFocusedActor && mPreviousFocusedActor.IsKeyboardFocusable() ) + { + Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get(); + if( keyboardFocusManager ) + { + keyboardFocusManager.SetCurrentFocusActor( mPreviousFocusedActor ); + } + } + } - RelayoutRequest(); + // Perform animation. + StartTransitionAnimation( display ); } -void Popup::SetState( Toolkit::Popup::PopupState state ) +Toolkit::Popup::DisplayState Popup::GetDisplayState() const { - SetState( state, POPUP_ANIMATION_DURATION ); + return mDisplayState; } -void Popup::SetState( Toolkit::Popup::PopupState state, float duration ) +void Popup::LayoutPopup() { - // default animation behaviour. - HandleStateChange(state, duration); -} + mLayoutDirty = false; + + /* When animating in, we want to respect the origin applied to Self(). + * For example, if zooming, not only will the final result be anchored to the + * selected point, but the zoom will originate from this point also. + * + * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT : + * + * -------- -------- + * |X| |XXX| + * |`` Animates |XXX| + * | to: |XXX| + * | |```` + * | | + */ + mPopupContainer.SetParentOrigin( Self().GetCurrentParentOrigin() ); + mPopupContainer.SetAnchorPoint( Self().GetCurrentAnchorPoint() ); + + // If there is only a title, use less padding. + if( mTitle ) + { + if( !mContent && !mFooter ) + { + mTitle.SetPadding( DEFAULT_TITLE_ONLY_PADDING ); + } + else + { + mTitle.SetPadding( DEFAULT_TITLE_PADDING ); + } + } -Toolkit::Popup::PopupState Popup::GetState() const -{ - return mState; + // Allow derived classes to perform any layout they may need to do. + OnLayoutSetup(); + + // Update background visibility. + mPopupContainer.SetVisible( !( !mFooter && mPopupLayout.GetChildCount() == 0 ) ); + + // Create / destroy / position the tail as needed. + LayoutTail(); + + // Setup any layout and initialisation required for the selected animation. + LayoutAnimation(); + + RelayoutRequest(); } -void Popup::ShowTail(const Vector3& position) +void Popup::LayoutTail() { - // Replaces the tail actor. - if(mTailImage && mTailImage.GetParent()) + // Removes the tail actor. + if( mTailImage && mTailImage.GetParent() ) { mTailImage.GetParent().Remove( mTailImage ); mTailImage.Reset(); } - std::string image = ""; + if( !mTailVisible ) + { + return; + } + + const Vector3& position = GetTailPosition(); + std::string image; // depending on position of tail around ParentOrigin, a different tail image is used... - if(position.y < Math::MACHINE_EPSILON_1) + if( position.y < Math::MACHINE_EPSILON_1 ) { - image = mPopupStyle->tailUpImage; + image = mTailUpImage; } - else if(position.y > 1.0f - Math::MACHINE_EPSILON_1) + else if( position.y > 1.0f - Math::MACHINE_EPSILON_1 ) { - image = mPopupStyle->tailDownImage; + image = mTailDownImage; } - else if(position.x < Math::MACHINE_EPSILON_1) + else if( position.x < Math::MACHINE_EPSILON_1 ) { - image = mPopupStyle->tailLeftImage; + image = mTailLeftImage; } - else if(position.x > 1.0f - Math::MACHINE_EPSILON_1) + else if( position.x > 1.0f - Math::MACHINE_EPSILON_1 ) { - image = mPopupStyle->tailRightImage; + image = mTailRightImage; } - if(image != "") + if( !image.empty() ) { + // Adds the tail actor. Image tail = ResourceImage::New( image ); - mTailImage = ImageActor::New(tail); + mTailImage = ImageActor::New( tail ); + mTailImage.SetName( "tail-image" ); const Vector3 anchorPoint = AnchorPoint::BOTTOM_RIGHT - position; + mTailImage.SetParentOrigin( position ); + mTailImage.SetAnchorPoint( anchorPoint ); - mTailImage.SetParentOrigin(position); - mTailImage.SetAnchorPoint(anchorPoint); + mLayer.Add( mTailImage ); + } +} - CreateFooter(); +void Popup::SetContextualMode( Toolkit::Popup::ContextualMode mode ) +{ + mContextualMode = mode; + mLayoutDirty = true; +} - mBottomBg.Add(mTailImage); - } +Toolkit::Popup::ContextualMode Popup::GetContextualMode() const +{ + return mContextualMode; +} + +ImageActor Popup::CreateBacking() +{ + mBacking = Dali::Toolkit::CreateSolidColorActor( mBackingColor ); + mBacking.SetName( "popup-backing" ); + + // Must always be positioned top-left of stage, regardless of parent. + mBacking.SetPositionInheritanceMode( DONT_INHERIT_POSITION ); + mBacking.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + + // Always the full size of the stage. + mBacking.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS ); + mBacking.SetSize( Stage::GetCurrent().GetSize() ); + + // Catch events. + mBacking.SetSensitive( true ); + + // Default to being transparent. + mBacking.SetOpacity( 0.0f ); + mBacking.TouchedSignal().Connect( this, &Popup::OnBackingTouched ); + mBacking.WheelEventSignal().Connect( this, &Popup::OnBackingWheelEvent ); + return mBacking; } -void Popup::HideTail() +Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal() { - ShowTail(ParentOrigin::CENTER); + return mTouchedOutsideSignal; } -void Popup::SetStyle(PopupStyle& style) +Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal() { - mPopupStyle = PopupStylePtr(&style); - // update // + return mShowingSignal; } -PopupStylePtr Popup::GetStyle() const +Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal() { - return mPopupStyle; + return mShownSignal; } -void Popup::SetDefaultBackgroundImage() +Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal() { - Image buttonBg = ResourceImage::New( mPopupStyle->buttonAreaImage ); - ImageActor buttonBgImage = ImageActor::New( buttonBg ); - buttonBgImage.SetStyle( ImageActor::STYLE_NINE_PATCH ); - buttonBgImage.SetNinePatchBorder( mPopupStyle->buttonArea9PatchBorder ); + return mHidingSignal; +} - SetBackgroundImage( ImageActor::New( ResourceImage::New( mPopupStyle->backgroundImage ) ) ); - SetButtonAreaImage( buttonBgImage ); +Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal() +{ + return mHiddenSignal; } -void Popup::CreateBacking() +void Popup::SetTailVisibility( bool visible ) { - mBacking = Dali::Toolkit::CreateSolidColorActor( mPopupStyle->backingColor ); - mBacking.SetName( "POPUP_BACKING" ); - mBacking.SetSortModifier( BACKGROUND_DEPTH_INDEX - 1 ); - mBacking.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - mBacking.SetSensitive(true); + mTailVisible = visible; + mLayoutDirty = true; +} - mLayer.Add( mBacking ); - mBacking.SetOpacity(0.0f); - mBacking.TouchedSignal().Connect( this, &Popup::OnBackingTouched ); - mBacking.WheelEventSignal().Connect(this, &Popup::OnBackingWheelEvent); +const bool Popup::IsTailVisible() const +{ + return mTailVisible; } -void Popup::CreateDialog() +void Popup::SetTailPosition( Vector3 position ) { - // Adds default background image. - SetDefaultBackgroundImage(); + mTailPosition = position; + mLayoutDirty = true; } -void Popup::HandleStateChange( Toolkit::Popup::PopupState state, float duration ) +const Vector3& Popup::GetTailPosition() const { - Vector3 targetSize; - float targetBackingAlpha; + return mTailPosition; +} - if(mState == state) - { - return; - } - mState = state; - switch(state) +void Popup::SetAnimationDuration( float duration ) +{ + mAnimationDuration = duration; + mLayoutDirty = true; +} + +float Popup::GetAnimationDuration() const +{ + return mAnimationDuration; +} + +void Popup::SetAnimationMode( Toolkit::Popup::AnimationMode animationMode ) +{ + mAnimationMode = animationMode; + mLayoutDirty = true; +} + +Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const +{ + return mAnimationMode; +} + +void Popup::SetEntryAnimationData( const Property::Map& map ) +{ + mEntryAnimationData.Clear(); + Scripting::NewAnimation( map, mEntryAnimationData ); +} + +void Popup::SetExitAnimationData( const Property::Map& map ) +{ + mExitAnimationData.Clear(); + Scripting::NewAnimation( map, mExitAnimationData ); +} + +void Popup::SetAutoHideDelay( int delay ) +{ + mAutoHideDelay = delay; +} + +int Popup::GetAutoHideDelay() const +{ + return mAutoHideDelay; +} + +void Popup::SetBackingEnabled( bool enabled ) +{ + mBackingEnabled = enabled; + mLayoutDirty = true; +} + +const bool Popup::IsBackingEnabled() const +{ + return mBackingEnabled; +} + +void Popup::SetBackingColor( Vector4 color ) +{ + mBackingColor = color; + mLayoutDirty = true; +} + +const Vector4& Popup::GetBackingColor() const +{ + return mBackingColor; +} + +void Popup::SetTailUpImage( std::string image ) +{ + mTailUpImage = image; + mLayoutDirty = true; +} + +const std::string& Popup::GetTailUpImage() const +{ + return mTailUpImage; +} + +void Popup::SetTailDownImage( std::string image ) +{ + mTailDownImage = image; + mLayoutDirty = true; +} + +const std::string& Popup::GetTailDownImage() const +{ + return mTailDownImage; +} + +void Popup::SetTailLeftImage( std::string image ) +{ + mTailLeftImage = image; + mLayoutDirty = true; +} + +const std::string& Popup::GetTailLeftImage() const +{ + return mTailLeftImage; +} + +void Popup::SetTailRightImage( std::string image ) +{ + mTailRightImage = image; + mLayoutDirty = true; +} + +const std::string& Popup::GetTailRightImage() const +{ + return mTailRightImage; +} + +void Popup::SetTouchTransparent( bool enabled ) +{ + mTouchTransparent = enabled; +} + +const bool Popup::IsTouchTransparent() const +{ + return mTouchTransparent; +} + +void Popup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value ) +{ + Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) ); + + if ( popup ) { - case Toolkit::Popup::POPUP_HIDE: - { - targetSize = Vector3(0.0f, 0.0f, 1.0f); - targetBackingAlpha = 0.0f; - mShowing = false; - ClearKeyInputFocus(); + Popup& popupImpl( GetImpl( popup ) ); - // Retore the keyboard focus when popup is hidden - if(mPreviousFocusedActor && mPreviousFocusedActor.IsKeyboardFocusable() ) + switch ( propertyIndex ) + { + case Toolkit::Popup::Property::TITLE: { - Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get(); - if( keyboardFocusManager ) + Property::Map valueMap; + if( value.Get( valueMap ) ) { - keyboardFocusManager.SetCurrentFocusActor(mPreviousFocusedActor); + popupImpl.SetTitle( Scripting::NewActor( valueMap ) ); } + break; } - - break; - } - - case Toolkit::Popup::POPUP_SHOW: - default: - { - targetSize = Vector3(1.0f, 1.0f, 1.0f); - targetBackingAlpha = 1.0f; - mShowing = true; - - // Add contents to stage for showing. - if( !mLayer.GetParent() ) + case Toolkit::Popup::Property::CONTENT: + { + Property::Map valueMap; + if( value.Get( valueMap ) ) + { + popupImpl.SetContent( Scripting::NewActor( valueMap ) ); + } + break; + } + case Toolkit::Popup::Property::FOOTER: + { + Property::Map valueMap; + if( value.Get( valueMap ) ) + { + popupImpl.SetFooter( Scripting::NewActor( valueMap ) ); + } + break; + } + case Toolkit::Popup::Property::DISPLAY_STATE: + { + std::string valueString; + if( value.Get( valueString ) ) + { + Toolkit::Popup::DisplayState displayState( Toolkit::Popup::HIDDEN ); + if( Scripting::GetEnumeration< Toolkit::Popup::DisplayState >( valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState ) ) + { + popupImpl.SetDisplayState( displayState ); + } + } + break; + } + case Toolkit::Popup::Property::TOUCH_TRANSPARENT: + { + bool valueBool; + if( value.Get( valueBool ) ) + { + popupImpl.SetTouchTransparent( valueBool ); + } + break; + } + case Toolkit::Popup::Property::TAIL_VISIBILITY: + { + bool valueBool; + if( value.Get( valueBool ) ) + { + popupImpl.SetTailVisibility( valueBool ); + } + break; + } + case Toolkit::Popup::Property::TAIL_POSITION: + { + Vector3 valueVector3; + if( value.Get( valueVector3 ) ) + { + popupImpl.SetTailPosition( valueVector3 ); + } + break; + } + case Toolkit::Popup::Property::CONTEXTUAL_MODE: + { + std::string valueString; + if( value.Get( valueString ) ) + { + Toolkit::Popup::ContextualMode contextualMode( Toolkit::Popup::BELOW ); + if( Scripting::GetEnumeration< Toolkit::Popup::ContextualMode >( valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode ) ) + { + popupImpl.SetContextualMode( contextualMode ); + } + } + break; + } + case Toolkit::Popup::Property::ANIMATION_DURATION: + { + float valueFloat; + if( value.Get( valueFloat ) ) + { + popupImpl.SetAnimationDuration( valueFloat ); + } + break; + } + case Toolkit::Popup::Property::ANIMATION_MODE: + { + std::string valueString; + if( value.Get( valueString ) ) + { + Toolkit::Popup::AnimationMode animationMode( Toolkit::Popup::FADE ); + if( Scripting::GetEnumeration< Toolkit::Popup::AnimationMode >( valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode ) ) + { + popupImpl.SetAnimationMode( animationMode ); + } + } + break; + } + case Toolkit::Popup::Property::ENTRY_ANIMATION: + { + Property::Map valueMap; + if( value.Get( valueMap ) ) + { + popupImpl.SetEntryAnimationData( valueMap ); + } + break; + } + case Toolkit::Popup::Property::EXIT_ANIMATION: + { + Property::Map valueMap; + if( value.Get( valueMap ) ) + { + popupImpl.SetExitAnimationData( valueMap ); + } + break; + } + case Toolkit::Popup::Property::AUTO_HIDE_DELAY: + { + int valueInt; + if( value.Get( valueInt ) ) + { + popupImpl.SetAutoHideDelay( valueInt ); + } + break; + } + case Toolkit::Popup::Property::BACKING_ENABLED: + { + bool valueBool; + if( value.Get( valueBool ) ) + { + popupImpl.SetBackingEnabled( valueBool ); + } + break; + } + case Toolkit::Popup::Property::BACKING_COLOR: + { + Vector4 valueVector4; + if( value.Get( valueVector4 ) ) + { + popupImpl.SetBackingColor( valueVector4 ); + } + break; + } + case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE: + { + std::string valueString; + if( value.Get( valueString ) ) + { + Image image = ResourceImage::New( valueString ); + if( image ) + { + ImageActor actor = ImageActor::New( image ); + popupImpl.SetPopupBackgroundImage( actor ); + } + } + break; + } + case Toolkit::Popup::Property::TAIL_UP_IMAGE: { - Dali::Stage stage = Dali::Stage::GetCurrent(); - stage.Add( mLayer ); - mLayer.RaiseToTop(); + std::string valueString; + if( value.Get( valueString ) ) + { + popupImpl.SetTailUpImage( valueString ); + } + break; } - - Self().SetSensitive(true); - SetKeyInputFocus(); - - // Handle the keyboard focus when popup is shown - Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get(); - if( keyboardFocusManager ) + case Toolkit::Popup::Property::TAIL_DOWN_IMAGE: { - mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor(); - - if( mContent && mContent.IsKeyboardFocusable() ) + std::string valueString; + if( value.Get( valueString ) ) { - // If content is focusable, move the focus to content - keyboardFocusManager.SetCurrentFocusActor(mContent); + popupImpl.SetTailDownImage( valueString ); } - else if( !mButtons.empty() ) + break; + } + case Toolkit::Popup::Property::TAIL_LEFT_IMAGE: + { + std::string valueString; + if( value.Get( valueString ) ) { - // Otherwise, movethe focus to the first button - keyboardFocusManager.SetCurrentFocusActor(mButtons[0]); + popupImpl.SetTailLeftImage( valueString ); } - else + break; + } + case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE: + { + std::string valueString; + if( value.Get( valueString ) ) { - DALI_LOG_WARNING("There is no focusable in popup\n"); + popupImpl.SetTailRightImage( valueString ); } + break; } - break; - } - } - - Actor self = Self(); - if(duration > Math::MACHINE_EPSILON_1) - { - if ( mAnimation ) - { - mAnimation.Stop(); - mAnimation.Clear(); - mAnimation.Reset(); - } - mAnimation = Animation::New(duration); - - if(mShowing) - { - mAnimation.AnimateTo( Property(mBacking, Actor::Property::COLOR_ALPHA), targetBackingAlpha, AlphaFunction::EASE_IN_OUT, TimePeriod(0.0f, duration * 0.5f) ); - mAnimation.AnimateTo( Property(self, Actor::Property::SCALE), targetSize, AlphaFunction::EASE_IN_OUT, TimePeriod(duration * 0.5f, duration * 0.5f) ); - } - else - { - mAnimation.AnimateTo( Property(mBacking, Actor::Property::COLOR_ALPHA), targetBackingAlpha, AlphaFunction::EASE_IN_OUT, TimePeriod(0.0f, duration * 0.5f) ); - mAnimation.AnimateTo( Property(self, Actor::Property::SCALE), targetSize, AlphaFunction::EASE_IN_OUT, TimePeriod(0.0f, duration * 0.5f) ); } - mAnimation.Play(); - mAnimation.FinishedSignal().Connect(this, &Popup::OnStateAnimationFinished); - } - else - { - mBacking.SetOpacity( targetBackingAlpha ); - self.SetScale( targetSize ); - - HandleStateChangeComplete(); } } -void Popup::HandleStateChangeComplete() +Property::Value Popup::GetProperty( BaseObject* object, Property::Index propertyIndex ) { - // Remove contents from stage if completely hidden. - if( ( mState == Toolkit::Popup::POPUP_HIDE ) && mLayer.GetParent() ) + Property::Value value; + + Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) ); + + if ( popup ) { - mLayer.Unparent(); - Self().SetSensitive( false ); + Popup& popupImpl( GetImpl( popup ) ); - // Guard against destruction during signal emission - Toolkit::Popup handle( GetOwner() ); - mHiddenSignal.Emit(); + switch ( propertyIndex ) + { + case Toolkit::Popup::Property::TITLE: + { + Property::Map map; + Scripting::CreatePropertyMap( popupImpl.GetTitle(), map ); + value = map; + break; + } + case Toolkit::Popup::Property::CONTENT: + { + Property::Map map; + Scripting::CreatePropertyMap( popupImpl.GetContent(), map ); + value = map; + break; + } + case Toolkit::Popup::Property::FOOTER: + { + Property::Map map; + Scripting::CreatePropertyMap( popupImpl.GetFooter(), map ); + value = map; + break; + } + case Toolkit::Popup::Property::DISPLAY_STATE: + { + value = Scripting::GetLinearEnumerationName< Toolkit::Popup::DisplayState >( popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount ); + break; + } + case Toolkit::Popup::Property::TOUCH_TRANSPARENT: + { + value = popupImpl.IsTouchTransparent(); + break; + } + case Toolkit::Popup::Property::TAIL_VISIBILITY: + { + value = popupImpl.IsTailVisible(); + break; + } + case Toolkit::Popup::Property::TAIL_POSITION: + { + value = popupImpl.GetTailPosition(); + break; + } + case Toolkit::Popup::Property::CONTEXTUAL_MODE: + { + value = Scripting::GetLinearEnumerationName< Toolkit::Popup::ContextualMode >( popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount ); + break; + } + case Toolkit::Popup::Property::ANIMATION_DURATION: + { + value = popupImpl.GetAnimationDuration(); + break; + } + case Toolkit::Popup::Property::ANIMATION_MODE: + { + value = Scripting::GetLinearEnumerationName< Toolkit::Popup::AnimationMode >( popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount ); + break; + } + case Toolkit::Popup::Property::ENTRY_ANIMATION: + { + // Note: Cannot retrieve property map from animation. + Property::Map map; + value = map; + break; + } + case Toolkit::Popup::Property::EXIT_ANIMATION: + { + // Note: Cannot retrieve property map from animation. + Property::Map map; + value = map; + break; + } + case Toolkit::Popup::Property::AUTO_HIDE_DELAY: + { + value = popupImpl.GetAutoHideDelay(); + break; + } + case Toolkit::Popup::Property::BACKING_ENABLED: + { + value = popupImpl.IsBackingEnabled(); + break; + } + case Toolkit::Popup::Property::BACKING_COLOR: + { + value = popupImpl.GetBackingColor(); + break; + } + case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE: + { + ResourceImage image = ResourceImage::DownCast( popupImpl.GetPopupBackgroundImage() ); + if( image ) + { + value = image.GetUrl(); + } + break; + } + case Toolkit::Popup::Property::TAIL_UP_IMAGE: + { + value = popupImpl.GetTailUpImage(); + break; + } + case Toolkit::Popup::Property::TAIL_DOWN_IMAGE: + { + value = popupImpl.GetTailDownImage(); + break; + } + case Toolkit::Popup::Property::TAIL_LEFT_IMAGE: + { + value = popupImpl.GetTailLeftImage(); + break; + } + case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE: + { + value = popupImpl.GetTailRightImage(); + break; + } + } } -} - -Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal() -{ - return mTouchedOutsideSignal; -} -Toolkit::Popup::HiddenSignalType& Popup::HiddenSignal() -{ - return mHiddenSignal; + return value; } bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) @@ -586,6 +1393,18 @@ bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tra { popup.OutsideTouchedSignal().Connect( tracker, functor ); } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWING ) ) + { + popup.ShowingSignal().Connect( tracker, functor ); + } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWN ) ) + { + popup.ShownSignal().Connect( tracker, functor ); + } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDING ) ) + { + popup.HidingSignal().Connect( tracker, functor ); + } else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDDEN ) ) { popup.HiddenSignal().Connect( tracker, functor ); @@ -599,235 +1418,302 @@ bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tra return connected; } -void Popup::OnStateAnimationFinished( Animation& source ) +bool Popup::OnBackingTouched( Actor actor, const TouchEvent& event ) { - HandleStateChangeComplete(); -} + // Allow events to pass through if touch transparency is enabled. + if( mTouchTransparent ) + { + return false; + } -bool Popup::OnBackingTouched(Actor actor, const TouchEvent& event) -{ - if(event.GetPointCount()>0) + if( event.GetPointCount() > 0 ) { - const TouchPoint& point = event.GetPoint(0); + const TouchPoint& point = event.GetPoint( 0 ); - if(point.state == TouchPoint::Down) + if( point.state == TouchPoint::Down ) { - // Guard against destruction during signal emission + // Guard against destruction during signal emission. Toolkit::Popup handle( GetOwner() ); mTouchedOutsideSignal.Emit(); } } + // Block anything behind backing becoming touched. + mLayer.SetTouchConsumed( true ); return true; } -bool Popup::OnBackingWheelEvent(Actor actor, const WheelEvent& event) +bool Popup::OnBackingWheelEvent( Actor actor, const WheelEvent& event ) { - // consume wheel event in dimmed backing actor + // Allow events to pass through if touch transparency is enabled. + if( mTouchTransparent ) + { + return false; + } + + // Consume wheel event in dimmed backing actor. + mLayer.SetTouchConsumed( true ); return true; } bool Popup::OnDialogTouched(Actor actor, const TouchEvent& event) { - // consume event (stops backing actor receiving touch events) + // Allow events to pass through if touch transparency is enabled. + if( mTouchTransparent ) + { + return false; + } + + // Consume event (stops backing actor receiving touch events) + mLayer.SetTouchConsumed( true ); return true; } +void Popup::OnControlStageConnection() +{ + mLayoutDirty = true; + RelayoutRequest(); +} + void Popup::OnControlChildAdd( Actor& child ) { - // reparent any children added by user to the body layer. + // Re-parent any children added by user to the body layer. if( mAlterAddedChild ) { - // Removes previously added content. - if( mContent ) - { - mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 1, 0 ) ); - } - - // keep a handle to the new content. - mContent = child; - - mPopupLayout.AddChild( mContent, Toolkit::TableView::CellPosition( 1, 0 ) ); + SetContent( child ); + } + else + { + mLayoutDirty = true; + RelayoutRequest(); } } -void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container ) +void Popup::LayoutContext( const Vector2& size ) { - // Hide the background image - mBackgroundImage.SetVisible( !( mButtons.empty() && mPopupLayout.GetChildCount() == 0 ) ); - - // Relayout All buttons - if( !mButtons.empty() ) + // Do nothing if not in a contextual mode (or there is no parent context). + Actor self = Self(); + Actor parent = self.GetParent(); + if( ( mContextualMode == Toolkit::Popup::NON_CONTEXTUAL ) || !parent ) { - // All buttons should be the same size and fill the button area. The button spacing needs to be accounted for as well. - Vector2 buttonSize( ( ( size.width - mPopupStyle->buttonSpacing * ( mButtons.size() + 1 ) ) / mButtons.size() ), - mPopupStyle->bottomSize.height - mPopupStyle->margin ); - - Vector3 buttonPosition( mPopupStyle->buttonSpacing, 0.0f, 0.0f ); - - for( std::vector< Actor >::iterator iter = mButtons.begin(), endIter = mButtons.end(); - iter != endIter; - ++iter, buttonPosition.x += mPopupStyle->buttonSpacing + buttonSize.width ) - { - Actor button = *iter; - - // If there is only one button, it needs to be laid out on center. - if ( mButtons.size() == 1 ) - { - buttonPosition.x = 0.0f; - button.SetAnchorPoint( AnchorPoint::CENTER ); - button.SetParentOrigin( ParentOrigin::CENTER ); - } - else - { - button.SetAnchorPoint( AnchorPoint::CENTER_LEFT ); - button.SetParentOrigin( ParentOrigin::CENTER_LEFT ); - } + return; + } - button.SetPosition( buttonPosition ); + mPopupContainer.SetParentOrigin( ParentOrigin::CENTER ); + // We always anchor to the CENTER, rather than a different anchor point for each contextual + // mode to allow code-reuse of the bound checking code (for maintainability). + mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER ); - //Todo: Use the size negotiation pass instead of SetSize directly - button.SetSize( buttonSize ); - } - } -} + // Setup with some pre-calculations for speed. + Vector3 halfStageSize( Stage().GetCurrent().GetSize() / 2.0f ); + Vector3 parentPosition( parent.GetCurrentPosition() ); + Vector2 halfSize( size / 2.0f ); + Vector2 halfParentSize( parent.GetRelayoutSize( Dimension::WIDTH ) / 2.0f, parent.GetRelayoutSize( Dimension::HEIGHT ) / 2.0f ); + Vector3 newPosition( Vector3::ZERO ); -void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension ) -{ - if( mPopupLayout ) + // Perform different positioning based on the specified contextual layout mode. + switch( mContextualMode ) { - if( policy == ResizePolicy::FIT_TO_CHILDREN ) + case Toolkit::Popup::BELOW: { - mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, dimension ); - if( dimension & Dimension::HEIGHT ) - { - mPopupLayout.SetFitHeight( 1 ); - } + newPosition.x += halfSize.x - halfParentSize.x; + newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y; + break; } - else + case Toolkit::Popup::ABOVE: { - mPopupLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, dimension ); - // Make the content cell fill the whole of the available space - if( dimension & Dimension::HEIGHT ) - { - mPopupLayout.SetRelativeHeight( 1, 1.0f ); - } + newPosition.x += halfSize.x - halfParentSize.x; + newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y; + break; + } + case Toolkit::Popup::RIGHT: + { + newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x; + newPosition.y += halfSize.y - halfParentSize.y; + break; + } + case Toolkit::Popup::LEFT: + { + newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x; + newPosition.y += halfSize.y - halfParentSize.y; + break; + } + case Toolkit::Popup::NON_CONTEXTUAL: + { + // Code won't reach here (caught earlier). + break; } } -} - -bool Popup::OnKeyEvent(const KeyEvent& event) -{ - bool consumed = false; - if(event.state == KeyEvent::Down) + // On-screen position checking. + // Check new position is not too far right. If so, correct it. + // Note: Check for right rather than left first, so if popup is too wide, the left check overrides + // the right check and we at least see the left portion of the popup (as this is more useful). + if( newPosition.x >= ( halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x ) ) { - if (event.keyCode == Dali::DALI_KEY_ESCAPE || event.keyCode == Dali::DALI_KEY_BACK) - { - SetState(Toolkit::Popup::POPUP_HIDE); - consumed = true; - } + newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x; + } + // Check new position is not too far left. If so, correct it. + if( newPosition.x < halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x ) + { + newPosition.x = halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x;// - parentSize.x; + } + // Check new position is not too far down. If so, correct it. + if( newPosition.y >= ( halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y ) ) + { + newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y; + } + // Check new position is not too far up. If so, correct it. + if( newPosition.y < halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y ) + { + newPosition.y = halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y; } - return consumed; + // Set the final position. + mPopupContainer.SetPosition( newPosition ); } -Vector3 Popup::GetNaturalSize() +void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container ) { - float margin = 2.0f * ( POPUP_OUT_MARGIN_WIDTH + mPopupStyle->margin ); - const float maxWidth = Stage::GetCurrent().GetSize().width - margin; + Vector2 useSize( size ); + + // Use the Popup layouts size, unless requested to use a fixed size. + // In which case take the size set for the Popup itself. + ResizePolicy::Type widthPolicy = Self().GetResizePolicy( Dimension::WIDTH ); + ResizePolicy::Type heightPolicy = Self().GetResizePolicy( Dimension::HEIGHT ); - Vector3 naturalSize( 0.0f, 0.0f, 0.0f ); + // Width calculations: + if( widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN ) + { + // If we using a child-based policy, take the size from the popup layout. + mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH ); + useSize.width = mPopupLayout.GetRelayoutSize( Dimension::WIDTH ); - if ( mTitle ) + mPopupLayout.SetFitWidth( 0u ); + } + else { - Vector3 titleNaturalSize = mTitle.GetImplementation().GetNaturalSize(); - // Buffer to avoid errors. The width of the popup could potentially be the width of the title text. - // It was observed in this case that text wrapping was then inconsistent when seen on device - const float titleBuffer = 0.5f; - titleNaturalSize.width += titleBuffer; + // If we using a parent-based policy, take the size from the popup object itself (self). + mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH ); + + mPopupLayout.SetFixedWidth( 0u, useSize.width ); + } + + // Height calculations: + // Title: Let the title be as high as it needs to be. + mPopupLayout.SetFitHeight( 0u ); - // As TextLabel GetNaturalSize does not take wrapping into account, limit the width - // to that of the stage - if( titleNaturalSize.width >= maxWidth) + // Footer: Convert the footer's resize policy to a TableView row policy. + if( mFooter ) + { + ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy( Dimension::HEIGHT ); + if( ( footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE ) || + ( footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN ) ) + { + mPopupLayout.SetFitHeight( 2u ); + } + else if( footerHeightPolicy == ResizePolicy::FIXED ) { - naturalSize.width = maxWidth; - naturalSize.height = mTitle.GetImplementation().GetHeightForWidth( naturalSize.width ); + mPopupLayout.SetFixedHeight( 2u, mFooter.GetRelayoutSize( Dimension::HEIGHT) ); } else { - naturalSize += titleNaturalSize; + mPopupLayout.SetRelativeHeight( 2u, 1.0f ); } + } + else + { + mPopupLayout.SetFixedHeight( 2u, 0.0f ); + } + + // Popup contents: Adjust the tableview's policies based on the popup's policies. + if( heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN ) + { + mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT ); + + // Let both the contents expand as necessary. + mPopupLayout.SetFitHeight( 1u ); + useSize.height = mPopupLayout.GetRelayoutSize( Dimension::HEIGHT ); + } + else + { + mPopupLayout.SetResizePolicy( heightPolicy, Dimension::HEIGHT ); - naturalSize.height += mPopupStyle->margin; + // Let the content expand to fill the remaining space. + mPopupLayout.SetRelativeHeight( 1u, 1.0f ); + mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT ); } + // Relayout the popup-layout to give it it's new size this frame. + container.Add( mPopupLayout, useSize ); + if( mContent ) { - Vector3 contentSize = mContent.GetNaturalSize(); - // Choose the biggest width - naturalSize.width = std::max( naturalSize.width, contentSize.width ); - if( naturalSize.width > maxWidth ) - { - naturalSize.width = maxWidth; - contentSize.height = mContent.GetHeightForWidth( maxWidth ); - } - naturalSize.height += contentSize.height + mPopupStyle->margin; + container.Add( mContent, Vector2( mContent.GetRelayoutSize( Dimension::WIDTH ), mContent.GetRelayoutSize( Dimension::HEIGHT ) ) ); } - if( !mButtons.empty() ) + // Perform contextual layout setup if required. + // This is done each time in case the parent moves. + // This will have no effect if no contextual mode is selected. + LayoutContext( useSize ); +} + +void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension ) +{ + // To get the popup to emulate fit-to-children, we need to actually set use-natural-size. + if( ( dimension & Dimension::HEIGHT ) && ( policy == ResizePolicy::FIT_TO_CHILDREN ) ) { - naturalSize.height += mPopupStyle->bottomSize.height; + Self().SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT ); } - // Add the margins - naturalSize.width += margin; - naturalSize.height += margin; + mLayoutDirty = true; + return; +} - return naturalSize; +Vector3 Popup::GetNaturalSize() +{ + return mPopupLayout.GetNaturalSize(); } float Popup::GetHeightForWidth( float width ) { - float height( 0.0f ); - float popupWidth( width - 2.f * ( POPUP_OUT_MARGIN_WIDTH + mPopupStyle->margin ) ); + return mPopupLayout.GetHeightForWidth( width ); +} - if ( mTitle ) - { - height += mTitle.GetImplementation().GetHeightForWidth( popupWidth ); - height += mPopupStyle->margin; - } +float Popup::GetWidthForHeight( float height ) +{ + return mPopupLayout.GetWidthForHeight( height ); +} - if( mContent ) +bool Popup::OnKeyEvent( const KeyEvent& event ) +{ + // Allow events to pass through if touch transparency is enabled. + if( mTouchTransparent ) { - height += mContent.GetHeightForWidth( popupWidth ) + mPopupStyle->margin; + return false; } - if( !mButtons.empty() ) + bool consumed = false; + + if( event.state == KeyEvent::Down ) { - height += mPopupStyle->bottomSize.height; + if (event.keyCode == Dali::DALI_KEY_ESCAPE || event.keyCode == Dali::DALI_KEY_BACK) + { + SetDisplayState( Toolkit::Popup::HIDDEN ); + consumed = true; + } } - // Add the margins - float margin( 2.0f * ( POPUP_OUT_MARGIN_WIDTH + mPopupStyle->margin ) ); - height += margin; - - return height; -} - -float Popup::GetWidthForHeight( float height ) -{ - return GetNaturalSize().width; + return consumed; } -Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled) +Actor Popup::GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled ) { Actor nextFocusableActor( currentFocusedActor ); // TODO: Needs to be optimised - - if ( !currentFocusedActor || ( currentFocusedActor && KeyboardFocusManager::Get().GetFocusGroup(currentFocusedActor) != Self() ) ) + if( !currentFocusedActor || ( currentFocusedActor && KeyboardFocusManager::Get().GetFocusGroup( currentFocusedActor ) != Self() ) ) { // The current focused actor is not within popup if( mContent && mContent.IsKeyboardFocusable() ) @@ -835,38 +1721,25 @@ Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::C // If content is focusable, move the focus to content nextFocusableActor = mContent; } - else if( !mButtons.empty() ) - { - // Otherwise, movethe focus to the first button - nextFocusableActor = mButtons[0]; - } } else { - // Rebuild the focus chain because button or content can be added or removed dynamically + // Rebuild the focus chain because controls or content can be added or removed dynamically std::vector< Actor > focusableActors; if( mContent && mContent.IsKeyboardFocusable() ) { - focusableActors.push_back(mContent); - } - - for(unsigned int i = 0; i < mButtons.size(); i++) - { - if( mButtons[i] && mButtons[i].IsKeyboardFocusable() ) - { - focusableActors.push_back(mButtons[i]); - } + focusableActors.push_back( mContent ); } for( std::vector< Actor >::iterator iter = focusableActors.begin(), end = focusableActors.end(); iter != end; ++iter ) { - if ( currentFocusedActor == *iter ) + if( currentFocusedActor == *iter ) { - switch ( direction ) + switch( direction ) { case Toolkit::Control::KeyboardFocus::LEFT: { - if ( iter == focusableActors.begin() ) + if( iter == focusableActors.begin() ) { nextFocusableActor = *( focusableActors.end() - 1 ); } @@ -878,7 +1751,7 @@ Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::C } case Toolkit::Control::KeyboardFocus::RIGHT: { - if ( iter == focusableActors.end() - 1 ) + if( iter == focusableActors.end() - 1 ) { nextFocusableActor = *( focusableActors.begin() ); } @@ -891,13 +1764,13 @@ Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::C case Toolkit::Control::KeyboardFocus::UP: { - if ( *iter == mContent ) + if( mContent && *iter == mContent ) { nextFocusableActor = *( focusableActors.end() - 1 ); } else { - if ( mContent && mContent.IsKeyboardFocusable() ) + if( mContent && mContent.IsKeyboardFocusable() ) { nextFocusableActor = mContent; } @@ -918,13 +1791,13 @@ Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::C case Toolkit::Control::KeyboardFocus::DOWN: { - if ( mContent && mContent.IsKeyboardFocusable() ) + if( mContent && mContent.IsKeyboardFocusable() ) { nextFocusableActor = mContent; } else { - if ( iter == focusableActors.end() - 1 ) + if( iter == focusableActors.end() - 1 ) { nextFocusableActor = *( focusableActors.begin() ); } @@ -933,18 +1806,13 @@ Actor Popup::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::C nextFocusableActor = *( iter + 1 ); } } - - if ( *iter == mContent && !mButtons.empty() ) - { - nextFocusableActor = mButtons[0]; - } break; } } - if(!nextFocusableActor) + if( !nextFocusableActor ) { - DALI_LOG_WARNING("Can not decide next focusable actor\n"); + DALI_LOG_WARNING( "Can not decide next focusable actor\n" ); } break; diff --git a/dali-toolkit/internal/controls/popup/popup-impl.h b/dali-toolkit/internal/controls/popup/popup-impl.h index 099e5e6..c40811c 100755 --- a/dali-toolkit/internal/controls/popup/popup-impl.h +++ b/dali-toolkit/internal/controls/popup/popup-impl.h @@ -2,7 +2,7 @@ #define __DALI_TOOLKIT_INTERNAL_POPUP_H__ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,14 @@ // EXTERNAL INCLUDES #include #include +#include #include +#include // INTERNAL INCLUDES #include #include -#include #include -#include namespace Dali { @@ -36,16 +36,12 @@ namespace Dali namespace Toolkit { -class Button; - namespace Internal { class Popup; -class PopupStyle; -typedef IntrusivePtr PopupPtr; -typedef IntrusivePtr PopupStylePtr; +typedef IntrusivePtr< Popup > PopupPtr; /** * @copydoc Toolkit::Popup @@ -63,81 +59,197 @@ public: public: /** - * Returns number of buttons added to Popup - * - * @return Number of buttons + * @copydoc Toolkit::Popup::SetPopupBackgroundImage */ - size_t GetButtonCount() const; + void SetPopupBackgroundImage( Actor image ); /** - * @copydoc Toolkit::Popup::SetBackgroundImage + * @copydoc Toolkit::Popup::GetPopupBackgroundImage */ - void SetBackgroundImage( Actor image ); + Actor GetPopupBackgroundImage() const; /** - * @copydoc Toolkit::Popup::SetButtonAreaImage + * @copydoc Toolkit::Popup::SetTitle( Actor titleActor ) */ - void SetButtonAreaImage( Actor image ); + void SetTitle( Actor titleActor ); /** - * @copydoc Toolkit::Popup::SetTitle( const std::string& text ); + * @copydoc Toolkit::Popup::GetTitle */ - void SetTitle( const std::string& text ); + Actor GetTitle() const; /** - * @copydoc Toolkit::Popup::GetTitle + * @copydoc Toolkit::Popup::SetContent + */ + void SetContent( Actor content ); + + /** + * @copydoc Toolkit::Popup::GetContent + */ + Actor GetContent() const; + + /** + * @copydoc Toolkit::Popup::SetFooter + */ + void SetFooter( Actor control ); + + /** + * @copydoc Toolkit::Popup::GetFooter + */ + Actor GetFooter() const; + + /** + * @copydoc Toolkit::Popup::SetDisplayState + */ + void SetDisplayState( Toolkit::Popup::DisplayState displayState ); + + /** + * @copydoc Toolkit::Popup::GetDisplayState + */ + Toolkit::Popup::DisplayState GetDisplayState() const; + + /** + * @copydoc Toolkit::Popup::SetTailVisibility + */ + void SetTailVisibility( bool visible ); + + /** + * @copydoc Toolkit::Popup::IsTailVisible + */ + const bool IsTailVisible() const; + + /** + * @copydoc Toolkit::Popup::SetTailPosition + */ + void SetTailPosition( Vector3 position ); + + /** + * @copydoc Toolkit::Popup::GetTailPosition + */ + const Vector3& GetTailPosition() const; + + /** + * @copydoc Toolkit::Popup::SetContextualMode + */ + void SetContextualMode( Toolkit::Popup::ContextualMode mode ); + + /** + * @copydoc Toolkit::Popup::GetContextualMode + */ + Toolkit::Popup::ContextualMode GetContextualMode() const; + + /** + * @copydoc Toolkit::Popup::SetAnimationDuration + */ + void SetAnimationDuration( float duration ); + + /** + * @copydoc Toolkit::Popup::GetAnimationDuration + */ + float GetAnimationDuration() const; + + /** + * @copydoc Toolkit::Popup::SetAnimationMode + */ + void SetAnimationMode( Toolkit::Popup::AnimationMode animationMode ); + + /** + * @copydoc Toolkit::Popup::GetAnimationMode + */ + Toolkit::Popup::AnimationMode GetAnimationMode() const; + + /** + * @copydoc Toolkit::Popup::SetAutoHideDelay + */ + void SetAutoHideDelay( int delay ); + + /** + * @copydoc Toolkit::Popup::GetAutoHideDelay + */ + int GetAutoHideDelay() const; + + /** + * @copydoc Toolkit::Popup::SetBackingEnabled + */ + void SetBackingEnabled( bool enabled ); + + /** + * @copydoc Toolkit::Popup::IsBackingEnabled + */ + const bool IsBackingEnabled() const; + + /** + * @copydoc Toolkit::Popup::SetBackingColor + */ + void SetBackingColor( Vector4 color ); + + /** + * @copydoc Toolkit::Popup::GetBackingColor */ - std::string GetTitle() const; + const Vector4& GetBackingColor() const; /** - * @copydoc Toolkit::Popup::AddButton + * @copydoc Toolkit::Popup::SetTailUpImage */ - void AddButton( Toolkit::Button button ); + void SetTailUpImage( std::string image ); /** - * @copydoc Toolkit::Popup::SetState( PopupState state ) + * @copydoc Toolkit::Popup::GetTailUpImage */ - void SetState( Toolkit::Popup::PopupState state ); + const std::string& GetTailUpImage() const; /** - * @copydoc Toolkit::Popup::SetState( PopupState state, float duration ) + * @copydoc Toolkit::Popup::SetTailDownImage */ - void SetState( Toolkit::Popup::PopupState state, float duration ); + void SetTailDownImage( std::string image ); /** - * @copydoc Toolkit::Popup::GetState( ) + * @copydoc Toolkit::Popup::GetTailDownImage */ - Toolkit::Popup::PopupState GetState() const; + const std::string& GetTailDownImage() const; /** - * @copydoc Toolkit::Popup::ShowTail + * @copydoc Toolkit::Popup::SetTailLeftImage */ - void ShowTail(const Vector3& position); + void SetTailLeftImage( std::string image ); /** - * @copydoc Toolkit::Popup::HideTail + * @copydoc Toolkit::Popup::GetTailLeftImage */ - void HideTail(); + const std::string& GetTailLeftImage() const; /** - * Sets the style of the popup - * @param[in] style The style of the popup + * @copydoc Toolkit::Popup::SetTailRightImage */ - void SetStyle(PopupStyle& style); + void SetTailRightImage( std::string image ); /** - * Gets the style of the popup - * @return style of the popup + * @copydoc Toolkit::Popup::GetTailRightImage */ - PopupStylePtr GetStyle() const; + const std::string& GetTailRightImage() const; + + /** + * Called when a property of an object of this type is set. + * @param[in] object The object whose property is set. + * @param[in] propertyIndex The property index. + * @param[in] value The new property value. + */ + static void SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value ); + + /** + * Called to retrieve a property of an object of this type. + * @param[in] object The object whose property is to be retrieved. + * @param[in] propertyIndex The property index. + * @return The current value of the property. + */ + static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex ); protected: /** * Construct a new Popup. - * @param[in] style of the popup */ - Popup(PopupStyle& style); + Popup(); /** * A reference counted object may only be deleted by calling Unreference() @@ -147,33 +259,94 @@ protected: private: /** - * Creates and applies the default background image. + * @brief Creates the layout of the popup, to be done just before showing for the first time. + * Also calls OnLayoutSetup() to allow derived classes to perform layout at this stage. + */ + void LayoutPopup(); + + /** + * @brief Creates or destroys the popup tail based on the current TAIL_DISPLAYED property. + * Also uses the TAIL_POSITION property to position it. */ - void SetDefaultBackgroundImage(); + void LayoutTail(); /** - * Create Dim Backing - * (covers all content behind the dialog) + * @brief Performs any relative positioning required based on the current contextual mode, if set. + * If contextual mode is not enabled, this method has no effect. + * @param[in] size The Popups current size (can be accessed from within the OnRelayout() method). + */ + void LayoutContext( const Vector2& size ); + + /** + * @brief All transition-in animation setup and layout is done here. + * Different types of animation mode require different layouts to work, + * this function encapsulates anything animation-mode specific. + * This is called once for multiple displays/hides of the pops. + * It is only re-called when the layout becomes dirty. + */ + void LayoutAnimation(); + + /** + * @brief Initiates a transition-in or transition-out animation based + * on the current animation settings. + * @param[in] transitionIn True to perform a transition-in, false for transition out. + * @param[in] instantaneous Optional - If set to true will override the duration to provide an instant animation. + */ + void StartTransitionAnimation( bool transitionIn, bool instantaneous = false ); + + /** + * @brief Invoked once a display state change has completed. + */ + void DisplayStateChangeComplete(); + + /** + * @brief This is called when the auto-hide timer finishes. + * It performs a display-state change to HIDDEN. + * @return True as signal is consumed. + */ + bool OnAutoHideTimeReached(); + + /** + * @brief Create Dimmed Backing (covers all content behind the dialog). + * + * @return The backing actor. + */ + ImageActor CreateBacking(); + + /** + * @brief Creates the lower area within the popup. + */ + void CreateFooter(); + + /** + * @brief Sets if the popup allows touch events to pass through or not. + * + * @param[in] enabled Set to true to make the popup touch-transparent. */ - void CreateBacking(); + void SetTouchTransparent( bool enabled ); /** - * Create Dialog - * (dialog content resides inside this - buttons, title etc.) + * @brief Returns if the popup allows touch events to pass through or not. + * + * @return True if the popup is touch-transparent. */ - void CreateDialog(); + const bool IsTouchTransparent() const; /** - * Animate Popup by scaling uniformally from 0 to 100% and vice versa (default behaviour) - * @param[in] state The desired state to change into. - * @param[in] duration The time for this animation to take. + * @brief Allows the popup entry animation to be setup from a Property::Map that could + * originate, for example, from a JSON file. + * + * @param[in] map A Property::Map containing a description of an animation */ - void HandleStateChange( Toolkit::Popup::PopupState state, float duration ); + void SetEntryAnimationData( const Property::Map& map ); /** - * Invoked once StateChange has completed. + * @brief Allows the popup exit animation to be setup from a Property::Map that could + * originate, for example, from a JSON file. + * + * @param[in] map A Property::Map containing a description of an animation */ - void HandleStateChangeComplete(); + void SetExitAnimationData( const Property::Map& map ); public: // Signals @@ -183,9 +356,24 @@ public: // Signals Toolkit::Popup::TouchedOutsideSignalType& OutsideTouchedSignal(); /** + * @copydoc Dali::Toolkit::Popup::ShowingSignal() + */ + Toolkit::Popup::DisplayStateChangeSignalType& ShowingSignal(); + + /** + * @copydoc Dali::Toolkit::Popup::ShownSignal() + */ + Toolkit::Popup::DisplayStateChangeSignalType& ShownSignal(); + + /** + * @copydoc Dali::Toolkit::Popup::HidingSignal() + */ + Toolkit::Popup::DisplayStateChangeSignalType& HidingSignal(); + + /** * @copydoc Dali::Toolkit::Popup::HiddenSignal() */ - Toolkit::Popup::HiddenSignalType& HiddenSignal(); + Toolkit::Popup::DisplayStateChangeSignalType& HiddenSignal(); /** * Connects a callback function with the object's signals. @@ -201,10 +389,10 @@ public: // Signals private: /** - * Signal occurs when the State animation (transition from hide<->show) finishes + * Signal occurs when the State animation (transition from hide <-> show) finishes. * @param[in] source The animation that just finished. */ - void OnStateAnimationFinished( Animation& source ); + void OnDisplayChangeAnimationFinished( Animation& source ); /** * Signal occurs when the dimmed backing for the Popup is touched. @@ -215,8 +403,8 @@ private: bool OnBackingTouched(Actor actor, const TouchEvent& event); /** - * Signal occurs when the wheel event is occured on dimmed backing for the Popup. - * @param[in] actor The Actor got wheel + * Signal occurs when a mouse wheel event occurs on the dimmed backing. + * @param[in] actor The Actor that got the wheel event. * @param[in] event The Wheel Event. * @return Whether to consume event or not. */ @@ -236,9 +424,16 @@ private: virtual void OnInitialize(); /** - * @copydoc Dali::CustomActorImpl::OnPropertySet() + * Called whenever the popup layout is re-set up. + * Normally due to a change in contents. + * Note: This is only done when the popup is shown. + */ + virtual void OnLayoutSetup() {} + + /** + * Called when the popup is directly or indirectly parented to the stage. */ - virtual void OnPropertySet( Property::Index index, Property::Value propertyValue ); + virtual void OnControlStageConnection(); /** * From Control; called after a child has been added to the owning actor. @@ -257,11 +452,6 @@ private: virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension ); /** - * @copydoc Control::OnKeyEvent() - */ - virtual bool OnKeyEvent(const KeyEvent& event); - - /** * @copydoc Control::GetNaturalSize() */ virtual Vector3 GetNaturalSize(); @@ -269,93 +459,99 @@ private: /** * @copydoc Control::GetHeightForWidth() */ - float GetHeightForWidth( float width ); + virtual float GetHeightForWidth( float width ); /** * @copydoc Control::GetWidthForHeight() */ - float GetWidthForHeight( float height ); + virtual float GetWidthForHeight( float height ); /** - * @copydoc Control::GetNextKeyboardFocusableActor() + * @copydoc Control::OnKeyEvent() */ - Actor GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled); + virtual bool OnKeyEvent( const KeyEvent& event ); /** - * Create the root actor for the footer + * @copydoc Control::GetNextKeyboardFocusableActor() */ - void CreateFooter(); + Actor GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled ); private: - // Undefined + // Undefined. Popup(const Popup&); - // Undefined + // Undefined. Popup& operator=(const Popup& rhs); private: - struct LayoutInfo - { - Vector3 mTitleSize; - Vector3 mContentSize; - Vector3 mButtonBgSize; - std::vector mButtonSize; - }; - -private: - - bool mShowing; ///< Popup is showing or not - - Layer mLayer; ///< Popup Layer (i.e. Dim backing and PopupBg reside in this) - Toolkit::TableView mPopupLayout; ///< Popup layout (i.e. dialog reside in this) - ImageActor mBacking; ///< Backing actor (dim effect) - - Actor mPreviousFocusedActor; ///< Store the previous focused actor to restore the focus when popup hide - - Actor mBackgroundImage; ///< Stores the background image. - Actor mButtonAreaImage; ///< Stores the button background image. - Toolkit::TextLabel mTitle; ///< Stores the text title. - Actor mContent; ///< Stores popup's content. - Actor mBottomBg; ///< bottom button bar background. ImageActor is replaced with Actor due to hidden image. - Actor mTailImage; ///< Stores the tail image - - std::vector< Actor > mButtons; ///< Keeps track of the buttons added to this popup. - Toolkit::Popup::PopupState mState; ///< Popup current state. - Animation mAnimation; ///< The animation instance managing state changing. - bool mAlterAddedChild; ///< Flag used to control whether children are reparented or not. - PopupStylePtr mPopupStyle; ///< The style to be used for this popup. - - LayoutInfo mLayoutInfo; ///< Stores sizes of all popup components. - - Toolkit::Popup::TouchedOutsideSignalType mTouchedOutsideSignal; - Toolkit::Popup::HiddenSignalType mHiddenSignal; - - Property::Index mPropertyTitle; ///< Property index for Title. - Property::Index mPropertyState; ///< Property index for popup state. + Toolkit::Popup::TouchedOutsideSignalType mTouchedOutsideSignal; + Toolkit::Popup::DisplayStateChangeSignalType mShowingSignal; + Toolkit::Popup::DisplayStateChangeSignalType mShownSignal; + Toolkit::Popup::DisplayStateChangeSignalType mHidingSignal; + Toolkit::Popup::DisplayStateChangeSignalType mHiddenSignal; + + Layer mLayer; ///< Popup Layer (i.e. Dim backing and PopupBg reside in this). + Toolkit::TableView mPopupLayout; ///< Popup Background (i.e. dialog reside in this). + ImageActor mBacking; ///< Backing actor (dim effect). + Actor mPreviousFocusedActor; ///< Store the previous focused actor to restore the focus when popup hide. + Actor mTailImage; ///< Stores the tail image. + Actor mPopupContainer; ///< This actor is used to house the background image and the main popup layout. + Animation mAnimation; ///< The current animation in use used to manage display state changing. + bool mAlterAddedChild; ///< Flag used to control whether children are reparented or not. + bool mLayoutDirty; ///< Set to true whenever any property that would require a layout update is modified. + Timer mAutoHideTimer; ///< Used to perform an auto-hide of the popup if desired. + bool mTouchTransparent; ///< Allows all events to pass through the popup. + + // Main Content related properties: + Actor mTitle; ///< Stores the text title. + Actor mContent; ///< Stores the unselected content. + Actor mFooter; ///< Stores the footer content (typically controls). + + // Display related properties. + Toolkit::Popup::DisplayState mDisplayState; ///< The current display state of the popup. + bool mTailVisible; ///< True if the popup tail should be visible. + Vector3 mTailPosition; ///< The position of the tail. + Toolkit::Popup::ContextualMode mContextualMode; ///< Allows the popup to be layed out adjacent to its parent in different directions. + float mAnimationDuration; ///< The duration of the transition in and out animations. + Toolkit::Popup::AnimationMode mAnimationMode; ///< The animation to use to transition in and out. + Dali::AnimationData mEntryAnimationData; ///< Stores description data that can be used for generating a custom entry animation. + Dali::AnimationData mExitAnimationData; ///< Stores description data that can be used for generating a custom exit animation. + unsigned int mAutoHideDelay; ///< If set, will auto-hide the popup after a specified amount of time. + + // Style related properties: + bool mBackingEnabled; ///< True if a dimmed backing will be used. + Vector4 mBackingColor; ///< The color of the backing. + Actor mPopupBackgroundImage; ///< Stores the background image. + Vector4 mBackgroundOuterBorder; ///< Background external border margin size + float mMargin; ///< Internal margin for popup contents. + std::string mTailUpImage; ///< Image used for the tail for the up direction. + std::string mTailDownImage; ///< Image used for the tail for the down direction. + std::string mTailLeftImage; ///< Image used for the tail for the left direction. + std::string mTailRightImage; ///< Image used for the tail for the right direction. }; } // namespace Internal // Helpers for public-api forwarding methods -inline Toolkit::Internal::Popup& GetImpl(Toolkit::Popup& pub) +inline Toolkit::Internal::Popup& GetImpl( Toolkit::Popup& publicObject ) { - DALI_ASSERT_ALWAYS(pub); + DALI_ASSERT_ALWAYS( publicObject ); - Dali::RefObject& handle = pub.GetImplementation(); + Dali::RefObject& handle = publicObject.GetImplementation(); - return static_cast(handle); + return static_cast( handle ); } -inline const Toolkit::Internal::Popup& GetImpl(const Toolkit::Popup& pub) +inline const Toolkit::Internal::Popup& GetImpl( const Toolkit::Popup& publicObject ) { - DALI_ASSERT_ALWAYS(pub); + DALI_ASSERT_ALWAYS( publicObject ); - const Dali::RefObject& handle = pub.GetImplementation(); + const Dali::RefObject& handle = publicObject.GetImplementation(); - return static_cast(handle); + return static_cast( handle ); } } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/popup/popup-style-impl.cpp b/dali-toolkit/internal/controls/popup/popup-style-impl.cpp deleted file mode 100644 index 4dba00b..0000000 --- a/dali-toolkit/internal/controls/popup/popup-style-impl.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2014 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 - -using namespace Dali; -using namespace Dali::Toolkit; - -namespace // unnamed namespace -{ -// Popup style default -const Vector4 DEFAULT_BACKING_COLOR = Vector4(0.0f, 0.0f, 0.0f, 0.5f); -const float DEFAULT_MARGIN = 20.0f; //From Tizen GUI UX -const float DEFAULT_BUTTON_SPACING = 10.0f; //From Tizen GUI UX -const Vector3 DEFAULT_BUTTON_SIZE(275.0f, 74.0f, 0.0f); -const char* DEFAULT_BACKGROUND_IMAGE_PATH = DALI_IMAGE_DIR "00_popup_bg.9.png"; -const char* DEFAULT_BUTTON_AREA_IMAGE_PATH = DALI_IMAGE_DIR "00_popup_button_bg.png"; -const char* DEFAULT_TAIL_UP_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_up.png"; -const char* DEFAULT_TAIL_DOWN_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_down.png"; -const char* DEFAULT_TAIL_LEFT_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_left.png"; -const char* DEFAULT_TAIL_RIGHT_IMAGE_PATH = DALI_IMAGE_DIR "popup_tail_right.png"; -const Vector3 DEFAULT_BOTTOM_SIZE(620.0f,96.0f,0.0f); -const Vector2 DEFAULT_BACKGROUND_SIZE(620.0f, 236.0f); -const Vector4 DEFAULT_BACKGROUND_STYLE_9_BORDER( 25.0f, 25.0f, 26.0f, 50.0f ); -const Vector4 DEFAULT_BACKGROUND_OUTER_BORDER( 40.0f, 0.0f, 30.0f, 0.0f ); -const Vector4 DEFAULT_BUTTON_AREA_9_PATCH_BORDER( 13.0f, 8.0f, 13.0f, 8.0f ); -} - -namespace Dali -{ - -namespace Toolkit -{ - -namespace Internal -{ - -/////////////////////////////////////////////////////////////////////////////// -// Popup Style (base class) -/////////////////////////////////////////////////////////////////////////////// - -PopupStyle::PopupStyle() -: backingColor(), - backgroundImage(), - buttonAreaImage(), - backgroundSize(), - backgroundScale9Border(), - backgroundOuterBorder(), - buttonArea9PatchBorder(), - margin(0.0f), - buttonSpacing(0.0f), - buttonSize(), - tailUpImage(), - tailDownImage(), - tailLeftImage(), - tailRightImage() -{ -} - -PopupStyle::~PopupStyle() -{ -} - -/////////////////////////////////////////////////////////////////////////////// -// Popup style: Default -/////////////////////////////////////////////////////////////////////////////// - -PopupStyleDefault::PopupStyleDefault() -{ - backingColor = DEFAULT_BACKING_COLOR; - backgroundImage = DEFAULT_BACKGROUND_IMAGE_PATH; - buttonAreaImage = DEFAULT_BUTTON_AREA_IMAGE_PATH; - margin = DEFAULT_MARGIN; - buttonSpacing = DEFAULT_BUTTON_SPACING; - buttonSize = DEFAULT_BUTTON_SIZE; - tailUpImage = DEFAULT_TAIL_UP_IMAGE_PATH; - tailDownImage = DEFAULT_TAIL_DOWN_IMAGE_PATH; - tailLeftImage = DEFAULT_TAIL_LEFT_IMAGE_PATH; - tailRightImage = DEFAULT_TAIL_RIGHT_IMAGE_PATH; - backgroundSize = DEFAULT_BACKGROUND_SIZE; - backgroundScale9Border = DEFAULT_BACKGROUND_STYLE_9_BORDER; - backgroundOuterBorder = DEFAULT_BACKGROUND_OUTER_BORDER; - buttonArea9PatchBorder = DEFAULT_BUTTON_AREA_9_PATCH_BORDER; - bottomSize = DEFAULT_BOTTOM_SIZE; -} - -PopupStyleDefaultPtr PopupStyleDefault::New() -{ - return PopupStyleDefaultPtr(new PopupStyleDefault()); -} - -PopupStyleDefault::~PopupStyleDefault() -{ -} - -} // namespace Internal - -} // namespace Toolkit - -} // namespace Dali diff --git a/dali-toolkit/internal/controls/popup/popup-style-impl.h b/dali-toolkit/internal/controls/popup/popup-style-impl.h deleted file mode 100644 index 34d051a..0000000 --- a/dali-toolkit/internal/controls/popup/popup-style-impl.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef __DALI_TOOLKIT_INTERNAL_POPUP_STYLE_H__ -#define __DALI_TOOLKIT_INTERNAL_POPUP_STYLE_H__ - -/* - * Copyright (c) 2014 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 -#include -#include -#include -#include - -#include - -namespace Dali -{ - -namespace Toolkit -{ - -namespace Internal -{ - -class PopupStyle; - -typedef IntrusivePtr PopupStylePtr; - -/** - * A PopupStyle describes the images, positions, sizes, and various other metrics - * which define how the popup should look. - */ -class PopupStyle : public RefObject -{ -public: - - /** - * Virtual destructor. - */ - virtual ~PopupStyle(); - -public: - - Vector4 backingColor; ///< Color of backing layer (covers entire screen) - std::string backgroundImage; ///< Background image path - std::string buttonAreaImage; ///< This image is for the back ground area common for all the buttons in the popup - Vector2 backgroundSize; ///< Background image size. - Vector4 backgroundScale9Border; ///< Background scale-9 border settings. - Vector4 backgroundOuterBorder; ///< Background outer border settings. - Vector4 buttonArea9PatchBorder; ///< 9 patch border constants for buttonAreaImage - float margin; ///< Margin for all contents (body, title, button) - float buttonSpacing; ///< Horizontal spacing for buttons. - Vector3 buttonSize; ///< Size of Buttons. - Vector3 bottomSize; ///< size of bottom button bar. - std::string bottomBackgroundImage; ///< bottom background image path. - std::string tailUpImage; ///< Tail Up-side image path. - std::string tailDownImage; ///< Tail Down-side image path. - std::string tailLeftImage; ///< Tail Left-side image path. - std::string tailRightImage; ///< Tail Right-side image path. - -protected: - - /** - * Create a new PopupStyle; Only derived versions are instantiable. - */ - PopupStyle(); -}; - -class PopupStyleDefault; - -typedef IntrusivePtr PopupStyleDefaultPtr; - -/** - * This is the default popup style. - */ -class PopupStyleDefault : public PopupStyle -{ -public: - - /** - * Create a new PopupStyle - */ - static PopupStyleDefaultPtr New(); - - /** - * Virtual destructor. - */ - virtual ~PopupStyleDefault(); - -private: - -protected: - - /** - * Protected constructor; see also PopupStyleDefault::New() - */ - PopupStyleDefault(); -}; - -} // namespace Internal - -} // namespace Toolkit - -} // namespace Dali - -#endif // __DALI_TOOLKIT_INTERNAL_POPUP_STYLE_H__ diff --git a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp index ae35484..f482fdd 100644 --- a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp +++ b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp @@ -798,6 +798,14 @@ void TableView::OnLayoutNegotiated( float size, Dimension::Type dimension ) } } +void TableView::OnSizeSet( const Vector3& size ) +{ + // If this table view is size negotiated by another actor or control, then the + // rows and columns must be recalculated or the new size will not take effect. + mRowDirty = mColumnDirty = true; + RelayoutRequest(); +} + void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container ) { // Go through the layout data diff --git a/dali-toolkit/internal/controls/table-view/table-view-impl.h b/dali-toolkit/internal/controls/table-view/table-view-impl.h index 2543b5e..d6ccf4b 100644 --- a/dali-toolkit/internal/controls/table-view/table-view-impl.h +++ b/dali-toolkit/internal/controls/table-view/table-view-impl.h @@ -261,6 +261,11 @@ private: // From Control */ virtual void OnLayoutNegotiated( float size, Dimension::Type dimension ); + /** + * @copydoc CustomActorImpl::OnSizeSet( const Vector3& size ) + */ + virtual void OnSizeSet( const Vector3& size ); + private: // Implementation /** diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index a93f983..3b04cf6 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -24,8 +24,8 @@ toolkit_src_files = \ $(toolkit_src_dir)/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp \ $(toolkit_src_dir)/controls/image-view/image-view-impl.cpp \ $(toolkit_src_dir)/controls/magnifier/magnifier-impl.cpp \ + $(toolkit_src_dir)/controls/popup/confirmation-popup-impl.cpp \ $(toolkit_src_dir)/controls/popup/popup-impl.cpp \ - $(toolkit_src_dir)/controls/popup/popup-style-impl.cpp \ $(toolkit_src_dir)/controls/page-turn-view/page-turn-portrait-view-impl.cpp \ $(toolkit_src_dir)/controls/page-turn-view/page-turn-effect.cpp \ $(toolkit_src_dir)/controls/page-turn-view/page-turn-landscape-view-impl.cpp \ diff --git a/docs/content/images/popup/popup-example.png b/docs/content/images/popup/popup-example.png new file mode 100644 index 0000000..352a2e0 Binary files /dev/null and b/docs/content/images/popup/popup-example.png differ diff --git a/docs/content/images/popup/popup-fields.png b/docs/content/images/popup/popup-fields.png new file mode 100644 index 0000000..8555dcf Binary files /dev/null and b/docs/content/images/popup/popup-fields.png differ diff --git a/docs/content/images/popup/popup-image-content.png b/docs/content/images/popup/popup-image-content.png new file mode 100644 index 0000000..7876811 Binary files /dev/null and b/docs/content/images/popup/popup-image-content.png differ diff --git a/docs/content/images/popup/popup-toast.png b/docs/content/images/popup/popup-toast.png new file mode 100644 index 0000000..25e07b1 Binary files /dev/null and b/docs/content/images/popup/popup-toast.png differ diff --git a/docs/content/main.md b/docs/content/main.md index cf99aeb..fefb8a3 100644 --- a/docs/content/main.md +++ b/docs/content/main.md @@ -51,12 +51,13 @@ + [Accessibility](@ref accessibility) ### UI Components - + [Text Label](@ref text-label) - + [Text Field](@ref text-field) + Buttons - + TableView - + [Scroll View](@ref scroll-view) + [ItemView](@ref item-view) + + [Popup](@ref popup) + + [Scroll View](@ref scroll-view) + + TableView + + [Text Field](@ref text-field) + + [Text Label](@ref text-label) ### RenderTasks diff --git a/docs/content/shared-javascript-and-cpp-documentation/popup.md b/docs/content/shared-javascript-and-cpp-documentation/popup.md new file mode 100644 index 0000000..c302f82 --- /dev/null +++ b/docs/content/shared-javascript-and-cpp-documentation/popup.md @@ -0,0 +1,392 @@ + + +[TOC] + +# Popup {#popup} + +![ ](../assets/img/popup/popup-example.png) ![ ](./popup-example.png) + +## Description {#popupdescription} + +The Popup control provides a generic way of displaying modal content. + +The content is displayed until it is dismissed by hiding the Popup. + +While the Popup is visible, it is displayed within a layer that is placed above any other actors. + +Content behind the Popup is dimmed by default, although this is configurable. + + +## Contents {#popupcontents} + + +The Popup is designed to be generic, but provide the necessary layout functionality to achieve this. + +The Popup window is broken down into the following areas: + +PopupBackgroundImage: This is the frame that appears around the edge of the Popup. + +Within the Popup there are three main fields: + +- Title +- Content +- Footer + +![ ](../assets/img/popup/popup-fields.png) ![ ](./popup-fields.png) + +Each field can contain any Actor. + +Note: All actor properties are optional, allowing any combination of content areas. +Example: Image only popup (using the content field): +![ ](../assets/img/popup/popup-image-content.png) ![ ](./popup-image-content.png) + +### Example content: {#popupfieldexample} + +- Title: TextLabel +- Content: ImageActor or TextLabel +- Footer: PushButton or Actor containing two PushButtons + +## Setting and getting the display state {#popupdisplaystate} + +The popup will not be shown immediately upon parenting it / adding it to the stage. First the display state must be set. +The display state is represented by the property DISPLAY_STATE. It can be set with SHOWN and HIDDEN to show or hide the Popup. +However, when getting the state, you will also be told if the Popup is in the process of SHOWING or HIDING. + + | Value | Setting the state | Getting the state | + |----------|--------------------------------|--------------------------------| + | SHOWN | Show the popup | The popup is fully shown | + | HIDDEN | Hide the popup | The popup is fully hidden | + | SHOWING | | The popup is transitioning in | + | HIDING | | The popup is transitioning out | + + +## Signals {#popupsignals} + +### Display State Signals {#popupdisplaystatesignals} + +All four state changes cause notifications via four respective signals that can be connected to. + +### OutsideTouched Signal {#popupoutsidetouched} + +This signal is emitted whenever a touch is received outside of the popups area. +This is typically used to hide / dismiss the popup, but can be ignored if it is desired to force the user to make a selection using the controls within the Popup. + + +## Transition effects {#popuptransitioneffects} + +The Popup object has built-in transitional animation effects. +These can be user-defined by setting ANIMATION_MODE to CUSTOM, and setting the ENTRY_ANIMATION and +EXIT_ANIMATION properties accordingly. + +The default to fading in and out. + + +## Types of Popup {#popuptypes} + +The Popup can be configured to a preset type by using named types within the type-registry. + +These types are modifications / specialisations of a Popup. They provide the library user with a shortcut way of creating a specific type of Popup. + + +The Popup control features a "Toast" popup type. This is a Popup that appears at the bottom of the screen, typically with some text. They are normally for informational purposes only. + + +### Key differences of the Toast popup {#popuptoastdifferences} + +- The Popup will auto-hide itself after a few seconds. +- It is touch-transparent. This means touch events go through the Popup to Actors below, giving it non-modal behaviour. +- The backing is not dimmed. This allows the user to continue their actions without distraction. + +Note: All the above features can be set or unset manually on the Popup control if desired. + +Popup types can be created with the TypeRegistry (as they are not separate classes). + + +### Example: {#popuptoastexample} + +![ ](../assets/img/popup/popup-toast.png) ![ ](./popup-toast.png) + +Here is the code to produce the above example: + +C++ +~~~{.cpp} +TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( "popup-toast" ); +if( typeInfo ) +{ + BaseHandle baseHandle = typeInfo.CreateInstance(); + if( baseHandle ) + { + Toolkit::Popup popup = Toolkit::Popup::DownCast( baseHandle ); + popup.SetTitle( Toolkit::TextLabel::New( "This is a Toast Popup.\nIt will auto-hide itself" ) ); + Stage::GetCurrent().Add( popup ); + popup.SetDisplayState( Toolkit::Popup::SHOWN ); + } +} +~~~ + + +## Contextual Mode {#popupcontextualmode} + +Contextual Mode allows the popup can appear adjacent to it's parent in screen space. + +If disabled, the Popup will ignore it's parent and appear centered on the stage (user positioning can override this). + +If enabled, the contextual mode can be set to four directions. The Popup will be made adjacent on the selected axis. + +EG: +~~~{.cpp} +myPopup.SetProperty( Toolkit::Popup::Properties::CONTEXTUAL_MODE, "BELOW" ); +~~~ + +Will make the top of the Popup appear just below the bottom of the parent object (plus a margin). + +The default is: NON_CONTEXTUAL which means no layout or positioning is performed. + +| ContextualMode | Layout | +|-------------------|---------------------------------------------------------| +| NON_CONTEXTUAL | No contextual layout is performed | +| ABOVE | Popup is above vertically, centered horizontally | +| RIGHT | Popup is to the right horizontally, centered vertically | +| BELOW | Popup is below vertically, centered horizontally | +| LEFT | Popup is to the left horizontally, centered vertically | + + +## Properties {#popupproperties} + +Various properties provide more configuration on the Popup's styling. + +This is a breakdown of remaining properties not described in detail above. + + +| Property | Type | Description | +|------------------------|---------|--------------------------------------------------------------------------| +| TOUCH_TRANSPARENT | bool | If true, allow touch events to travel through the popup. | +| TAIL_VISIBILITY | bool | If true, display a tail image on one of the edges of the popup. | +| TAIL_POSITION | Vector3 | Describes the position of the tail image. Orientation is inferred. | +| ANIMATION_DURATION | float | Duration used for entry and exit transition animations. | +| AUTO_HIDE_DELAY | int | If non-zero, the number of milliseconds before the popup will auto-hide. | +| BACKING_ENABLED | bool | True if backing (dimmed background) is enabled. | +| BACKING_COLOR | Vector4 | The color of the dimmed background. | +| TAIL_UP_IMAGE | string | The image to use for the tail if above the popup. | +| TAIL_DOWN_IMAGE | string | The image to use for the tail if below the popup. | +| TAIL_LEFT_IMAGE | string | The image to use for the tail if to the left of the popup. | +| TAIL_RIGHT_IMAGE | string | The image to use for the tail if to the right of the popup. | + + +# ConfirmationPopup Control {#popupconfirmation} + +The ConfirmationPopup control provides a simple interface for providing automatic connection to control signals for common-use Popup use-cases. + +ConfirmationPopup will automatically provide signals for 1 or 2 controls. +Note: The controls do not need to be PushButtons. +These signals are dynamically created. The controls (typically PushButtons) must be specifially named so the ConfirmationPopup can locate them. + +## Step 1 {#popupconfirmationstep1} +Name your controls. + +- Name your first control, or OK control: "control-ok" +- Name your second control, or Cancel control: "control-cancel" + +## Step 2 {#popupconfirmationstep2} +Tell the ConfirmationPopup the names of the signals to connect to for each control. +For example, if we are using PushButtons as controls, the signal name would be "clicked". +This allows us to use different control types. + +- Set property "connect-signal-ok-selected" with the name of the signal to connect to within the first control. +- Set property "connect-signal-cancel-selected" with the name of the signal to connect to within the second control. + +## Step 3 {#popupconfirmationstep3} +Connect to the following respective signals within ConfirmationPopup: + +- Connect to signal "control-signal-ok" to be signalled for the first control. +- Connect to signal "control-signal-cancel" to be signalled for the second control. + +The ConfirmationPopup will dynamically make the connection between the signalling control, and your signal handler. + +This allows connection of signals within both C++, JSON and Javascript APIs. +If more manual control or customisable layout is needed, then it is recommended to use the Popup widget directly for full control. + +The JSON code example at the bottom of this document uses the ConfirmationPopup to allow signal connection from within the JSON description. + + +# C++ example of a Popup with two buttons {#popupexamplec} + +This example creates a Popup with: + +- Title: TextLabel +- Content: TextLabel +- Footer: ImageActor (an image border around the buttons) + - PushButton (OK control) + - PushButton (Cancel control) + +The example connects signals to the two buttons, and to the OutsideTouched signal. + +~~~{.cpp} +Toolkit::Popup popup = Toolkit::Popup::New(); + +Toolkit::TextLabel titleActor = Toolkit::TextLabel::New( "Title" ); +titleActor.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::WHITE ); +titleActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); +popup.SetTitle( titleActor ); + +Toolkit::TextLabel contentActor = Toolkit::TextLabel::New( "Content text" ); +contentActor.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::WHITE ); +contentActor.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true ); +contentActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); +popup.SetContent( contentActor ); + +// Create the footer: Two buttons surrounded by an image. +ImageActor footer = ImageActor::New( ResourceImage::New( DEFAULT_CONTROL_AREA_IMAGE_PATH ) ); +footer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); +footer.SetResizePolicy( ResizePolicy::FIXED, Dimension::HEIGHT ); +footer.SetSize( 0.0f, 80.0f ); +footer.SetAnchorPoint( AnchorPoint::CENTER ); +footer.SetParentOrigin( ParentOrigin::CENTER ); + +Toolkit::PushButton okButton = Toolkit::PushButton::New(); +okButton.SetLabelText( "OK" ); +okButton.SetParentOrigin( ParentOrigin::CENTER ); +okButton.SetAnchorPoint( AnchorPoint::CENTER ); +okButton.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS ); +okButton.SetSizeModeFactor( Vector3( -20.0f, -20.0f, 0.0 ) ); +okButton.ClickedSignal().Connect( this, &MyExample::OnOKButtonClicked ); + +Toolkit::PushButton cancelButton = Toolkit::PushButton::New(); +cancelButton.SetLabelText( "Cancel" ); +cancelButton.SetParentOrigin( ParentOrigin::CENTER ); +cancelButton.SetAnchorPoint( AnchorPoint::CENTER ); +cancelButton.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS ); +cancelButton.SetSizeModeFactor( Vector3( -20.0f, -20.0f, 0.0 ) ); +cancelButton.ClickedSignal().Connect( this, &MyExample::OnCancelButtonClicked ); + +// Set up the footer's layout. +Toolkit::TableView controlLayout = Toolkit::TableView::New( 1, 2 ); +controlLayout.SetParentOrigin( ParentOrigin::CENTER ); +controlLayout.SetAnchorPoint( AnchorPoint::CENTER ); +controlLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); +controlLayout.SetCellPadding( Size( 10.0f, 10.0f ) ); +controlLayout.SetRelativeWidth( 0, 0.5f ); +controlLayout.SetRelativeWidth( 1, 0.5f ); +controlLayout.SetCellAlignment( Toolkit::TableView::CellPosition( 0, 0 ), HorizontalAlignment::CENTER, VerticalAlignment::CENTER ); +controlLayout.SetCellAlignment( Toolkit::TableView::CellPosition( 0, 1 ), HorizontalAlignment::CENTER, VerticalAlignment::CENTER ); +controlLayout.AddChild( okButton, Toolkit::TableView::CellPosition( 0, 0 ) ); +controlLayout.AddChild( cancelButton, Toolkit::TableView::CellPosition( 0, 1 ) ); +footer.Add( controlLayout ); +popup.SetFooter( footer ); + +popup.OutsideTouchedSignal().Connect( this, &MyExample::OnPopupOutsideTouched ); + +// Add to stage (the popup is still invisible at this point). +Stage::GetCurrent().Add( popup ); + +// Display the popup. +mPopup.SetDisplayState( Toolkit::Popup::SHOWN ); +~~~ + + +# JSON example of a Popup with two buttons {#popupexamplejson} + +This example creates a Popup with: + +- Title: TextLabel +- Content: TextLabel +- Footer: Control + - PushButton (OK control) + - PushButton (Cancel control) + +The example connects signals to the two buttons, and to the OutsideTouched signal. +This time without an image around the buttons. This could be added in the same way as the C++ example however. + + +~~~{.json} +{ + "constants": { + "CONFIG_SCRIPT_LOG_LEVEL": "Verbose" + }, + "stage": [ + { + "type": "ConfirmationPopup", + "name": "confirmation-popup", + "parent-origin": [0.5, 0.55, 0.5], + "anchor-point": "CENTER", + "width-resize-policy": "SIZE_RELATIVE_TO_PARENT", + "height-resize-policy": "USE_NATURAL_SIZE", + "size-mode-factor": [0.65, 1.0, 1.0], + "tail-visibility": false, + "display-change-animation-duration": 1.0, + "contextual-mode": "NON_CONTEXTUAL", + "animation-mode": "ZOOM", + "connect-signal-ok-selected": "clicked", + "connect-signal-cancel-selected": "clicked", + "title": { + "type": "TextLabel", + "text": "Title text", + "text-color": [1, 1, 1, 1] + }, + "content": { + "type": "TextLabel", + "text": "Content text", + "padding": [20, 20, 20, 0], + "text-color": [1, 1, 1, 1] + }, + "footer": { + "type": "Control", + "size": [0, 80, 0], + "width-resize-policy": "FILL_TO_PARENT", + "height-resize-policy": "FIXED", + "parent-origin": "CENTER", + "anchor-point": "CENTER", + "actors": [ + { + "type": "PushButton", + "name": "control-ok", + "parent-origin": "CENTER_LEFT", + "anchor-point": "CENTER_LEFT", + "position": [20, 0, 0], + "size": [0, 0, 0], + "label-text": "OK" + }, + { + "type": "PushButton", + "name": "control-cancel", + "parent-origin": "CENTER_RIGHT", + "anchor-point": "CENTER_RIGHT", + "position": [-20, 0, 0], + "size": [0, 0, 0], + "label-text": "Cancel" + } + ] + }, + "signals": [ + { + "name": "control-signal-ok", + "action": "set", + "actor": "confirmation-popup", + "property": "display-state", + "value": "HIDDEN" + }, + { + "name": "control-signal-cancel", + "action": "set", + "actor": "confirmation-popup", + "property": "display-state", + "value": "HIDDEN" + }, + { + "name": "touched-outside", + "action": "set", + "actor": "confirmation-popup", + "property": "display-state", + "value": "HIDDEN" + } + ] + } + ] +} +~~~ + + +@class _Guide_Popup +*/ +