Merge "Completely remove use of Adaptor class" into tizen
[platform/core/uifw/dali-toolkit.git] / optional / dali-toolkit / internal / controls / magnifier / magnifier-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dali-toolkit/internal/controls/magnifier/magnifier-impl.h>
19
20 using namespace Dali;
21
22 namespace // unnamed namespace
23 {
24
25 const char* DEFAULT_FRAME_IMAGE_PATH = DALI_IMAGE_DIR "magnifier-image-frame.png";
26
27 const float IMAGE_BORDER_INDENT = 14.0f;            ///< Indent of border in pixels.
28
29 /**
30  * ImageBorderSizeConstraint
31  */
32 struct ImageBorderSizeConstraint
33 {
34   ImageBorderSizeConstraint()
35   : mSizeOffset(Vector3(IMAGE_BORDER_INDENT - 1, IMAGE_BORDER_INDENT - 1, 0.0f) * 2.0f)
36   {
37   }
38
39   Vector3 operator()(const Vector3&    current,
40                      const PropertyInput& referenceSizeProperty)
41   {
42     const Vector3& referenceSize = referenceSizeProperty.GetVector3();
43
44     return referenceSize + mSizeOffset;
45   }
46
47   Vector3 mSizeOffset;                        ///< The amount to offset the size from referenceSize
48 };
49
50 struct CameraActorPositionConstraint
51 {
52   CameraActorPositionConstraint(const Vector2& stageSize, float defaultCameraDistance = 0.0f)
53   : mStageSize(stageSize),
54     mDefaultCameraDistance(defaultCameraDistance)
55   {
56   }
57
58   Vector3 operator()(const Vector3& current,
59                      const PropertyInput& sourcePositionProperty)
60   {
61     const Vector3& sourcePosition = sourcePositionProperty.GetVector3();
62
63     return Vector3( sourcePosition.x + mStageSize.x * 0.5f,
64                     sourcePosition.y + mStageSize.y * 0.5f,
65                     sourcePosition.z + mDefaultCameraDistance);
66   }
67
68   Vector2 mStageSize;
69   float mDefaultCameraDistance;
70
71 };
72
73 struct RenderTaskViewportPositionConstraint
74 {
75   RenderTaskViewportPositionConstraint(const Vector2& stageSize)
76   : mStageSize(stageSize)
77   {
78   }
79
80   Vector2 operator()(const Vector2& current,
81                      const PropertyInput& positionProperty,
82                      const PropertyInput& magnifierSizeProperty,
83                      const PropertyInput& magnifierScaleProperty)
84   {
85     Vector2 position(positionProperty.GetVector3()); // World position?
86
87     //position -= mStageSize * 0.5f;
88
89     // should be updated when:
90     // Magnifier's world position/size/scale/parentorigin/anchorpoint changes.
91     // or Magnifier camera's world position changes.
92     Vector3 size = magnifierSizeProperty.GetVector3() * magnifierScaleProperty.GetVector3();
93
94     // Reposition, and resize viewport to reflect the world bounds of this Magnifier actor.
95     position.x += (mStageSize.width - size.width) * 0.5f;
96     position.y += (mStageSize.height - size.height) * 0.5f;
97
98     return position;
99   }
100
101   Vector2 mStageSize;
102 };
103
104 struct RenderTaskViewportSizeConstraint
105 {
106   RenderTaskViewportSizeConstraint()
107   {
108   }
109
110   Vector2 operator()(const Vector2& current,
111                      const PropertyInput& magnifierSizeProperty,
112                      const PropertyInput& magnifierScaleProperty)
113   {
114     return Vector2(magnifierSizeProperty.GetVector3() * magnifierScaleProperty.GetVector3());
115   }
116 };
117
118 }
119
120 namespace Dali
121 {
122
123 namespace Toolkit
124 {
125
126 namespace Internal
127 {
128
129 ///////////////////////////////////////////////////////////////////////////////////////////////////
130 // Magnifier
131 ///////////////////////////////////////////////////////////////////////////////////////////////////
132
133 Dali::Toolkit::Magnifier Magnifier::New()
134 {
135   // Create the implementation
136   MagnifierPtr magnifier(new Magnifier());
137
138   // Pass ownership to CustomActor via derived handle
139   Dali::Toolkit::Magnifier handle(*magnifier);
140
141   // Second-phase init of the implementation
142   // This can only be done after the CustomActor connection has been made...
143   magnifier->Initialize();
144
145   return handle;
146 }
147
148 Magnifier::Magnifier()
149 : Control( REQUIRES_TOUCH_EVENTS ),
150   mPropertySourcePosition(Property::INVALID_INDEX),
151   mActorSize(Vector3::ZERO),
152   mMagnificationFactor(1.0f)
153 {
154 }
155
156 void Magnifier::SetSourceActor(Actor actor)
157 {
158   mTask.SetSourceActor( actor );
159 }
160
161 void Magnifier::SetSourcePosition(const Vector3& position)
162 {
163   Self().SetProperty(mPropertySourcePosition, position);
164 }
165
166 void Magnifier::Initialize()
167 {
168   Actor self = Self();
169   mPropertySourcePosition = self.RegisterProperty( Toolkit::Magnifier::SOURCE_POSITION_PROPERTY_NAME, Vector3::ZERO );
170   Vector2 stageSize(Stage::GetCurrent().GetSize());
171
172   Layer dummyLayer = Layer::New();
173   Stage().GetCurrent().Add(dummyLayer);
174   dummyLayer.SetParentOrigin(ParentOrigin::CENTER);
175
176   // NOTE:
177   // sourceActor is a dummy delegate actor that takes the source property position,
178   // and generates a WORLD_POSITION, which is 1 frame behind the source property.
179   // This way the constraints for determining the camera position (source) and those
180   // for determining viewport position use the same 1 frame old values.
181   // A simple i) CameraPos = f(B), ii) B = f(A) set of constraints wont suffice as
182   // although CameraPos will use B, which is A's previous value. The constraint will
183   // not realise that B is still dirty as far as constraint (i) is concerned.
184   // Perhaps this is a bug in the way the constraint system factors into what is dirty
185   // and what is not.
186   mSourceActor = Actor::New();
187   dummyLayer.Add(mSourceActor);
188   mSourceActor.SetParentOrigin(ParentOrigin::CENTER);
189   Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
190                                                     Source( self, mPropertySourcePosition ),
191                                                     EqualToConstraint() );
192   mSourceActor.ApplyConstraint(constraint);
193
194   // create the render task this will render content on top of everything
195   // based on camera source position.
196   InitializeRenderTask();
197
198   // set up some constraints to:
199   // i) reposition (dest) frame actor based on magnifier actor's world position (this is 1 frame delayed)
200   // ii) reposition and resize (dest) the render task's viewport based on magnifier actor's world position (1 frame delayed) & size.
201   // iii) reposition (source) camera actor based on magnifier source actor's world position (this is 1 frame delayed)
202
203   // Apply constraint to camera's position
204   // Position our camera at the same distance from its target as the default camera is.
205   // The camera position doesn't affect how we render, just what we render (due to near and far clip planes)
206   // NOTE: We can't interrogate the default camera's position as it is not known initially (takes 1 frame
207   // for value to update).
208   // But we can determine the initial position using the same formula:
209   // distance = stage.height * 0.5 / tan(FOV * 0.5)
210
211   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
212   RenderTask renderTask = taskList.GetTask(0u);
213   float fov = renderTask.GetCameraActor().GetFieldOfView();
214   mDefaultCameraDistance = (stageSize.height * 0.5f) / tanf(fov * 0.5f);
215
216   // Use a 1 frame delayed source position to determine the camera actor's position.
217   // This is necessary as the viewport is determined by the Magnifier's Actor's World position (which is computed
218   // at the end of the update cycle i.e. after constraints have been applied.)
219   //Property::Index propertySourcePositionDelayed = mCameraActor.RegisterProperty("delayed-source-position", Vector3::ZERO);
220
221   constraint = Constraint::New<Vector3>( Actor::POSITION,
222                                                     Source( mSourceActor, Actor::WORLD_POSITION ),
223                                                     CameraActorPositionConstraint(stageSize, mDefaultCameraDistance) );
224   mCameraActor.ApplyConstraint(constraint);
225
226   // Apply constraint to render-task viewport position
227   constraint = Constraint::New<Vector2>( RenderTask::VIEWPORT_POSITION,
228                                          Source( self, Actor::WORLD_POSITION ),//mPropertySourcePosition ),
229                                          Source( self, Actor::SIZE ),
230                                          Source( self, Actor::WORLD_SCALE),
231                                          RenderTaskViewportPositionConstraint(stageSize) );
232   mTask.ApplyConstraint(constraint);
233
234   // Apply constraint to render-task viewport position
235   constraint = Constraint::New<Vector2>( RenderTask::VIEWPORT_SIZE,
236                                          Source( self, Actor::SIZE ),
237                                          Source( self, Actor::WORLD_SCALE),
238                                          RenderTaskViewportSizeConstraint() );
239   mTask.ApplyConstraint(constraint);
240 }
241
242 Magnifier::~Magnifier()
243 {
244
245 }
246
247 void Magnifier::InitializeRenderTask()
248 {
249   Stage stage = Stage::GetCurrent();
250
251   RenderTaskList taskList = stage.GetRenderTaskList();
252
253   mTask = taskList.CreateTask();
254   mTask.SetInputEnabled(false);
255   mTask.SetClearColor(Vector4(0.5f, 0.5f, 0.5f, 1.0f));
256   mTask.SetClearEnabled(true);
257
258   mCameraActor = CameraActor::New();
259   mCameraActor.SetType(Camera::FREE_LOOK);
260   mCameraActor.SetRotation(Quaternion(M_PI, Vector3::YAXIS)); // Look at stage
261
262   stage.Add(mCameraActor);
263   mTask.SetCameraActor( mCameraActor );
264
265   SetFrameVisibility(true);
266 }
267
268 bool Magnifier::GetFrameVisibility() const
269 {
270   return mFrameLayer;
271 }
272
273 void Magnifier::SetFrameVisibility(bool visible)
274 {
275   if(visible && !mFrameLayer)
276   {
277     Actor self(Self());
278
279     Layer mFrameLayer = Layer::New();
280     mFrameLayer.SetParentOrigin( ParentOrigin::CENTER );
281     Stage::GetCurrent().Add(mFrameLayer);
282
283     Image image = Image::New( DEFAULT_FRAME_IMAGE_PATH );
284     ImageActor frame = ImageActor::New( image );
285     frame.SetDrawMode(DrawMode::OVERLAY);
286     frame.SetStyle( ImageActor::STYLE_NINE_PATCH );
287
288     frame.SetNinePatchBorder( Vector4::ONE * IMAGE_BORDER_INDENT );
289     mFrameLayer.Add(frame);
290
291     // Apply position constraint to the frame
292     Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
293                                                       Source( self, Actor::WORLD_POSITION ),
294                                                       EqualToConstraint() );
295     frame.ApplyConstraint(constraint);
296
297     // Apply scale constraint to the frame
298     constraint = Constraint::New<Vector3>( Actor::SCALE,
299                                            Source( self, Actor::SCALE ),
300                                            EqualToConstraint() );
301     frame.ApplyConstraint(constraint);
302
303     Source(self, Actor::SCALE),
304
305     // Apply size constraint to the the frame
306     constraint = Constraint::New<Vector3>(Actor::SIZE,
307                                           Source(self, Actor::SIZE),
308                                           ImageBorderSizeConstraint());
309     frame.ApplyConstraint(constraint);
310   }
311   else if(!visible && mFrameLayer)
312   {
313     Stage::GetCurrent().Remove(mFrameLayer);
314     mFrameLayer.Reset();
315   }
316 }
317
318 void Magnifier::OnControlSizeSet(const Vector3& targetSize)
319 {
320   // TODO: Once Camera/CameraActor properties function as proper animatable properties
321   // this code can disappear.
322   // whenever the size of the magnifier changes, the field of view needs to change
323   // to compensate for the new size of the viewport. this cannot be done within
324   // a constraint yet as Camera/CameraActor properties are not animatable/constrainable.
325   mActorSize = targetSize;
326   Update();
327 }
328
329 float Magnifier::GetMagnificationFactor() const
330 {
331   return mMagnificationFactor;
332 }
333
334 void Magnifier::SetMagnificationFactor(float value)
335 {
336   mMagnificationFactor = value;
337   Update();
338 }
339
340 void Magnifier::Update()
341 {
342   // TODO: Make Camera settings (fieldofview/aspectratio) as animatable constraints.
343
344   // should be updated when:
345   // Magnifier's world size/scale changes.
346   Actor self(Self());
347   Vector3 worldSize = mActorSize * self.GetCurrentWorldScale();
348
349   // Adjust field of view to scale content
350
351   // size.height / 2
352   // |------/
353   // |d    /
354   // |i   /
355   // |s  /
356   // |t /
357   // |./
358   // |/ <--- fov/2 radians.
359   //
360   const float fov = atanf( 0.5f * worldSize.height / mDefaultCameraDistance / mMagnificationFactor) * 2.0f;
361   mCameraActor.SetFieldOfView( fov );
362
363   // Adjust aspect ratio to compensate for rectangular viewports.
364   mCameraActor.SetAspectRatio( worldSize.width / worldSize.height );
365 }
366
367 } // namespace Internal
368
369 } // namespace Toolkit
370
371 } // namespace Dali