Merge "Updates needed after encapsulation and harmonizing operators for LayoutLength...
[platform/core/uifw/dali-demo.git] / examples / pre-render-callback / pre-render-callback-example.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <dali-toolkit/dali-toolkit.h>
18 #include <dali/integration-api/adaptors/adaptor.h>
19 #include <dali/devel-api/adaptor-framework/application-devel.h>
20 #include <dali-toolkit/devel-api/layouting/linear-layout.h>
21 #include <dali-toolkit/devel-api/controls/control-devel.h>
22
23 using namespace Dali::Toolkit;
24
25 namespace Dali
26 {
27 const char* SCENE_IMAGE_1( DEMO_IMAGE_DIR "gallery-small-10.jpg");
28 const char* SCENE_IMAGE_2( DEMO_IMAGE_DIR "gallery-small-42.jpg");
29 const char* SCENE_IMAGE_3( DEMO_IMAGE_DIR "gallery-small-48.jpg");
30 const char* ROTATE_TEXT("-\\|/");
31
32 void AddText( Control textContainer, std::string text )
33 {
34   auto label = TextLabel::New(text);
35   label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
36   textContainer.Add(label);
37 }
38
39 class PreRenderCallbackController : public ConnectionTracker
40 {
41 public:
42
43   /**
44    * @brief Constructor.
45    * @param[in]  application  The application.
46    */
47   PreRenderCallbackController ( Application& application )
48   : mApplication( application ),
49     mStage(),
50     mTapDetector(),
51     mKeepPreRender(false),
52     mRotateTextCharacter(0),
53     mLastRTC(-1),
54     mImageActor1(),
55     mImageActor2(),
56     mImageActor3(),
57     mAngle1Index( Property::INVALID_INDEX ),
58     mAngle3Index( Property::INVALID_INDEX ),
59     mSceneActor(),
60     mSceneAnimation(),
61     mSpinner()
62   {
63     // Connect to the Application's Init signal
64     mApplication.InitSignal().Connect( this, &PreRenderCallbackController::Create );
65   }
66
67 private:
68   struct RotationConstraint
69   {
70     RotationConstraint(float sign)
71     : mSign(sign)
72     {
73     }
74
75     void operator()( Quaternion& current, const PropertyInputContainer& inputs )
76     {
77       Radian angle( inputs[0]->GetFloat() );
78       current = Quaternion( angle * mSign, Vector3::YAXIS );
79     }
80
81     float mSign;
82   };
83
84   /**
85    * @brief Creates the scene.
86    */
87   void Create( Application& application )
88   {
89     mStage = Stage::GetCurrent();
90     mStage.SetBackgroundColor( Color::WHITE );
91     mStage.KeyEventSignal().Connect( this, &PreRenderCallbackController::OnKeyEvent );
92
93     // Hide the indicator bar.
94     mApplication.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
95
96     // Detect taps on the root layer.
97     mTapDetector = TapGestureDetector::New();
98     mTapDetector.Attach( mStage.GetRootLayer() );
99     mTapDetector.DetectedSignal().Connect( this, &PreRenderCallbackController::OnTap );
100
101     CreateAnimatingScene();
102
103     auto vbox = LinearLayout::New();
104     vbox.SetOrientation(LinearLayout::Orientation::VERTICAL);
105     vbox.SetAlignment( LinearLayout::Alignment::TOP | LinearLayout::Alignment::CENTER_HORIZONTAL );
106     auto textContainer = Control::New();
107     textContainer.SetAnchorPoint(AnchorPoint::TOP_LEFT);
108     DevelControl::SetLayout( textContainer, vbox );
109     AddText(textContainer, "Click to add callback");
110     AddText(textContainer, "Press 1 to add callback");
111     AddText(textContainer, "Press 2 to clear callback");
112     AddText(textContainer, "Press 3 to toggle keep alive");
113
114     auto vbox2 = LinearLayout::New();
115     vbox2.SetOrientation(LinearLayout::Orientation::VERTICAL);
116     vbox2.SetAlignment( LinearLayout::Alignment::BOTTOM | LinearLayout::Alignment::CENTER_HORIZONTAL );
117     auto textContainer2 = Control::New();
118     textContainer2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
119     DevelControl::SetLayout( textContainer2, vbox2 );
120     mSpinner = TextLabel::New("");
121     mSpinner.SetAnchorPoint( AnchorPoint::TOP_LEFT );
122     textContainer2.Add(mSpinner);
123
124     mStage.Add(textContainer);
125     mStage.Add(textContainer2);
126
127     DevelApplication::AddIdleWithReturnValue( application, MakeCallback( this, &PreRenderCallbackController::OnIdle ) );
128   }
129
130   void CreateAnimatingScene()
131   {
132     mSceneActor = Layer::New();
133     mSceneActor.SetBehavior( Layer::LAYER_3D );
134     mSceneActor.SetParentOrigin(ParentOrigin::CENTER);
135
136     // Create and add images to the scene actor:
137     mImageActor1 = ImageView::New( SCENE_IMAGE_1 );
138     mImageActor2 = ImageView::New( SCENE_IMAGE_2 );
139     mImageActor3 = ImageView::New( SCENE_IMAGE_3 );
140
141     mImageActor1.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
142     mImageActor2.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
143     mImageActor3.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
144
145     mImageActor2.SetParentOrigin(ParentOrigin::CENTER);
146
147     mImageActor1.SetParentOrigin(ParentOrigin::CENTER_LEFT);
148     mImageActor1.SetAnchorPoint(AnchorPoint::CENTER_RIGHT);
149
150     mImageActor3.SetParentOrigin(ParentOrigin::CENTER_RIGHT);
151     mImageActor3.SetAnchorPoint(AnchorPoint::CENTER_LEFT);
152
153     mSceneActor.Add(mImageActor2);
154     mImageActor2.Add(mImageActor1);
155     mImageActor2.Add(mImageActor3);
156
157     Property::Index angleIndex = mImageActor2.RegisterProperty("angle", Property::Value( Dali::ANGLE_30 ) );
158     Source angleSrc( mImageActor2, angleIndex );
159
160     Constraint constraint = Constraint::New<Quaternion>( mImageActor1, Actor::Property::ORIENTATION, RotationConstraint(-1.0f) );
161     constraint.AddSource( angleSrc );
162     constraint.Apply();
163
164     constraint = Constraint::New<Quaternion>( mImageActor3, Actor::Property::ORIENTATION, RotationConstraint(+1.0f) );
165     constraint.AddSource( angleSrc );
166     constraint.Apply();
167
168     mSceneAnimation = Animation::New(2.5f);
169
170     // Want to animate angle from 30 => -30 and back again smoothly.
171     mSceneAnimation.AnimateTo( Property( mImageActor2, angleIndex ), Property::Value(-Dali::ANGLE_30), AlphaFunction::SIN );
172
173     mSceneAnimation.SetLooping(true);
174     mSceneAnimation.Play();
175
176     mSceneActor.SetSize(250.0f, 250.0f);
177     mSceneActor.SetPosition(0.0f, 0.0f, 130.0f);
178     Quaternion p( Degree( -6.0f ), Vector3::XAXIS );
179     Quaternion q( Degree( 20.0f ), Vector3::YAXIS );
180     mSceneActor.SetOrientation( p * q );
181
182     mStage.Add( mSceneActor );
183   }
184
185   void OnTap( Actor /* actor */, const TapGesture& /* tap */ )
186   {
187     Adaptor::Get().SetPreRenderCallback( MakeCallback( this, &PreRenderCallbackController::OnPreRender ) );
188   }
189
190   /**
191    * @brief Called when any key event is received
192    *
193    * Will use this to quit the application if Back or the Escape key is received
194    * @param[in] event The key event information
195    */
196   void OnKeyEvent( const KeyEvent& event )
197   {
198     if( event.state == KeyEvent::Down )
199     {
200       if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
201       {
202         mApplication.Quit();
203       }
204       else if( event.keyPressedName.compare("1") == 0)
205       {
206         Adaptor::Get().SetPreRenderCallback( MakeCallback( this, &PreRenderCallbackController::OnPreRender ) );
207       }
208       else if( event.keyPressedName.compare("2") == 0)
209       {
210         Adaptor::Get().SetPreRenderCallback( NULL );
211       }
212       else if( event.keyPressedName.compare("3") == 0)
213       {
214         mKeepPreRender = !mKeepPreRender;
215       }
216     }
217   }
218
219   bool OnPreRender()
220   {
221     // Called from Update/Render thread
222     printf("Pre-render callback\n");
223     ++mRotateTextCharacter;
224     return mKeepPreRender;
225   }
226
227   bool OnIdle()
228   {
229     // Called from Event thread on main loop
230     int rotation = mRotateTextCharacter;
231     if( rotation != mLastRTC )
232     {
233       mLastRTC = rotation;
234       mSpinner.SetProperty(TextLabel::Property::TEXT, std::string(1, ROTATE_TEXT[rotation%4]));
235     }
236     return true;
237   }
238
239
240 private:
241   Application& mApplication;
242   Stage mStage;
243   TapGestureDetector  mTapDetector;          ///< Tap detector to enable the PreRenderCallback
244   bool mKeepPreRender;
245   int mRotateTextCharacter;
246   int mLastRTC;
247
248   // Scene objects:
249   ImageView                 mImageActor1;
250   ImageView                 mImageActor2;
251   ImageView                 mImageActor3;
252   Property::Index           mAngle1Index;
253   Property::Index           mAngle3Index;
254   Layer                     mSceneActor;
255   Animation                 mSceneAnimation;
256   TextLabel                 mSpinner;
257 };
258
259 } // namespace Dali
260
261 int main( int argc, char **argv )
262 {
263   Dali::Application application = Dali::Application::New( &argc, &argv );
264   Dali::PreRenderCallbackController controller( application );
265   application.MainLoop();
266   return 0;
267 }