Merge "Add a TextEditor property to limit input to maximum characters" into devel...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / arc / arc-visual.cpp
1 /*
2  * Copyright (c) 2020 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 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/arc/arc-visual.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 //INTERNAL INCLUDES
25 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
26 #include <dali-toolkit/devel-api/visuals/arc-visual-actions-devel.h>
27 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
28 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
29 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
30 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
31
32 namespace Dali
33 {
34
35 namespace Toolkit
36 {
37
38 namespace Internal
39 {
40
41 namespace
42 {
43
44 // cap
45 DALI_ENUM_TO_STRING_TABLE_BEGIN( CAP )
46 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelArcVisual::Cap, BUTT )
47 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelArcVisual::Cap, ROUND )
48 DALI_ENUM_TO_STRING_TABLE_END( CAP )
49
50 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
51   attribute mediump vec2 aPosition;\n
52   uniform highp   mat4 uMvpMatrix;\n
53   uniform mediump vec3 uSize;\n
54   \n
55   varying mediump vec2 vPosition;\n
56   \n
57   //Visual size and offset
58   uniform mediump vec2 offset;\n
59   uniform mediump vec2 size;\n
60   uniform mediump vec4 offsetSizeMode;\n
61   uniform mediump vec2 origin;\n
62   uniform mediump vec2 anchorPoint;\n
63
64   vec4 ComputeVertexPosition()\n
65   {\n
66     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
67     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
68     vPosition = aPosition* visualSize;\n
69     return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
70   }\n
71
72   void main()\n
73   {\n
74     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
75   }\n
76 );
77
78 const char* FRAGMENT_SHADER_BUTT_CAP = DALI_COMPOSE_SHADER(
79   varying mediump vec2 vPosition;\n
80   uniform lowp vec4 uColor;\n
81   uniform lowp vec3 mixColor;\n
82   uniform mediump float thickness;\n
83   uniform mediump float radius;\n
84   uniform mediump float startAngle;\n
85   uniform mediump float sweepAngle;\n
86   \n
87   const mediump float M_PI_OVER_2 = 1.57079632679;\n
88   const mediump float M_PI = 3.14159265359;\n
89   const mediump float M_PI_2 = 6.28318530718;\n
90   \n
91   mediump float GetOpacity()\n
92   {\n
93       mediump float start = radians( mod( startAngle, 360.0 ) );\n
94       mediump float angle = mod( atan( vPosition.y, vPosition.x ) + M_PI_OVER_2 - start, M_PI_2 );\n
95       mediump float dist = length( vPosition );\n
96       if( angle <= radians( sweepAngle ) )\n
97       {\n
98         return smoothstep( -1.0, 1.0, thickness / 2.0 - ( abs( dist - radius ) ) );\n
99       }\n
100       mediump float end = radians( mod( startAngle + sweepAngle, 360.0 ) );\n
101       mediump vec2 q0 = vec2( dist * cos( start - M_PI_OVER_2 ), dist * sin( start - M_PI_OVER_2 ) );\n
102       mediump vec2 q1 = vec2( dist * cos( end - M_PI_OVER_2 ), dist * sin( end - M_PI_OVER_2 ) );\n
103       mediump float opacity = 1.0 - smoothstep( 0.0, 2.0, min( length( vPosition - q0 ), length( vPosition - q1 ) ) );\n
104       opacity *= step( 0.0, thickness / 2.0 - abs( dist - radius ) );\n
105       return opacity;\n
106   }\n
107   void main()\n
108   {\n
109     gl_FragColor = vec4( mixColor, 1.0 ) * uColor;\n
110     gl_FragColor.a *= GetOpacity();\n
111   }\n
112 );
113
114 const char* FRAGMENT_SHADER_ROUND_CAP = DALI_COMPOSE_SHADER(
115   varying mediump vec2 vPosition;\n
116   uniform lowp vec4 uColor;\n
117   uniform lowp vec3 mixColor;\n
118   uniform mediump float thickness;\n
119   uniform mediump float radius;\n
120   uniform mediump float startAngle;\n
121   uniform mediump float sweepAngle;\n
122   \n
123   const mediump float M_PI_OVER_2 = 1.57079632679;\n
124   const mediump float M_PI_2 = 6.28318530718;\n
125   \n
126   mediump float GetOpacity()\n
127   {\n
128       mediump float start = radians( mod( startAngle, 360.0 ) );\n
129       mediump float angle = mod( atan( vPosition.y, vPosition.x ) + M_PI_OVER_2 - start, M_PI_2 );\n
130       mediump float dist = length( vPosition );\n
131       if( angle <= radians( sweepAngle ) )\n
132       {\n
133         return smoothstep( -1.0, 1.0, thickness / 2.0 - ( abs( dist - radius ) ) );\n
134       }\n
135       mediump float end = radians( mod( startAngle + sweepAngle, 360.0 ) );\n
136       mediump vec2 q0 = vec2( radius * cos( start - M_PI_OVER_2 ), radius * sin( start - M_PI_OVER_2 ) );\n
137       mediump vec2 q1 = vec2( radius * cos( end - M_PI_OVER_2 ), radius * sin( end - M_PI_OVER_2 ) );\n
138       return smoothstep( -1.0, 1.0, thickness / 2.0 - min( length( vPosition - q0 ), length( vPosition - q1 ) ) );\n
139   }\n
140   void main()\n
141   {\n
142     gl_FragColor = vec4( mixColor, 1.0 ) * uColor;\n
143     gl_FragColor.a *= GetOpacity();\n
144   }\n
145 );
146
147 }
148
149 ArcVisualPtr ArcVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
150 {
151   ArcVisualPtr arcVisualPtr( new ArcVisual( factoryCache ) );
152   arcVisualPtr->SetProperties( properties );
153   return arcVisualPtr;
154 }
155
156 ArcVisual::ArcVisual( VisualFactoryCache& factoryCache )
157 : Visual::Base( factoryCache, Visual::FittingMode::FILL, static_cast<Toolkit::Visual::Type>( Toolkit::DevelVisual::ARC ) ),
158   mThickness( 0.0f ),
159   mRadius( 0.0f ),
160   mStartAngle( 0.0f ),
161   mSweepAngle( 360.0f ),
162   mRadiusIndex( Property::INVALID_INDEX ),
163   mThicknessIndex( Property::INVALID_INDEX ),
164   mStartAngleIndex( Property::INVALID_INDEX ),
165   mSweepAngleIndex( Property::INVALID_INDEX ),
166   mCapType( DevelArcVisual::Cap::BUTT )
167 {
168 }
169
170 ArcVisual::~ArcVisual()
171 {
172 }
173
174 void ArcVisual::DoSetProperties( const Property::Map& propertyMap )
175 {
176   Property::Value* thicknessValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::THICKNESS, THICKNESS_NAME );
177   if( thicknessValue )
178   {
179     if( !thicknessValue->Get( mThickness ) )
180     {
181       DALI_LOG_ERROR( "ArcVisual:DoSetProperties:: THICKNESS property has incorrect type: %d\n", thicknessValue->GetType() );
182     }
183     else
184     {
185       if( mImpl->mRenderer )
186       {
187         mImpl->mRenderer.SetProperty( mThicknessIndex, mThickness );
188
189         // Need to calculate radius again
190         OnSetTransform();
191       }
192     }
193   }
194
195   Property::Value* startAngleValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::START_ANGLE, START_ANGLE_NAME );
196   if( startAngleValue )
197   {
198     if( !startAngleValue->Get( mStartAngle ) )
199     {
200       DALI_LOG_ERROR( "ArcVisual:DoSetProperties:: START_ANGLE property has incorrect type: %d\n", startAngleValue->GetType() );
201     }
202     else
203     {
204       if( mImpl->mRenderer )
205       {
206         mImpl->mRenderer.SetProperty( mStartAngleIndex, mStartAngle );
207       }
208     }
209   }
210
211   Property::Value* sweepAngleValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::SWEEP_ANGLE, SWEEP_ANGLE_NAME );
212   if( sweepAngleValue )
213   {
214     if( !sweepAngleValue->Get( mSweepAngle ) )
215     {
216       DALI_LOG_ERROR( "ArcVisual:DoSetProperties:: SWEEP_ANGLE property has incorrect type: %d\n", sweepAngleValue->GetType() );
217     }
218     else
219     {
220       if( mImpl->mRenderer )
221       {
222         mImpl->mRenderer.SetProperty( mSweepAngleIndex, mSweepAngle );
223       }
224     }
225   }
226
227   Property::Value* capValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::CAP, CAP_NAME );
228   if( capValue )
229   {
230     int capType = 0;
231     Scripting::GetEnumerationProperty( *capValue, CAP_TABLE, CAP_TABLE_COUNT, capType );
232     mCapType = Toolkit::DevelArcVisual::Cap::Type( capType );
233   }
234 }
235
236 void ArcVisual::DoSetOnScene( Actor& actor )
237 {
238   InitializeRenderer();
239
240   actor.AddRenderer( mImpl->mRenderer );
241
242   // Arc Visual generated and ready to display
243   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
244 }
245
246 void ArcVisual::DoCreatePropertyMap( Property::Map& map ) const
247 {
248   map.Clear();
249   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ARC );
250   map.Insert( Toolkit::DevelArcVisual::Property::THICKNESS, mThickness );
251   map.Insert( Toolkit::DevelArcVisual::Property::START_ANGLE, mStartAngle );
252   map.Insert( Toolkit::DevelArcVisual::Property::SWEEP_ANGLE, mSweepAngle );
253   map.Insert( Toolkit::DevelArcVisual::Property::CAP, mCapType );
254 }
255
256 void ArcVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
257 {
258   // Do nothing
259 }
260
261 void ArcVisual::OnSetTransform()
262 {
263   Vector2 visualSize = mImpl->mTransform.GetVisualSize( mImpl->mControlSize );
264   mRadius = ( std::min( visualSize.width, visualSize.height ) - mThickness ) / 2.0f;
265
266   if( mImpl->mRenderer )
267   {
268     mImpl->mRenderer.SetProperty( mRadiusIndex, mRadius );
269   }
270 }
271
272 void ArcVisual::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
273 {
274   // Check if action is valid for this visual type and perform action if possible
275   switch( actionId )
276   {
277     case DevelArcVisual::Action::UPDATE_PROPERTY:
278     {
279       Property::Map* map = attributes.GetMap();
280       if( map )
281       {
282         DoSetProperties( *map );
283       }
284       break;
285     }
286   }
287 }
288
289 void ArcVisual::InitializeRenderer()
290 {
291   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
292
293   Shader shader;
294   if( mCapType == DevelArcVisual::Cap::BUTT )
295   {
296     shader = mFactoryCache.GetShader( VisualFactoryCache::ARC_BUTT_CAP_SHADER );
297     if( !shader )
298     {
299       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_BUTT_CAP );
300       mFactoryCache.SaveShader( VisualFactoryCache::ARC_BUTT_CAP_SHADER, shader );
301     }
302   }
303   else
304   {
305     shader = mFactoryCache.GetShader( VisualFactoryCache::ARC_ROUND_CAP_SHADER );
306     if( !shader )
307     {
308       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ROUND_CAP );
309       mFactoryCache.SaveShader( VisualFactoryCache::ARC_ROUND_CAP_SHADER, shader );
310     }
311   }
312
313   mImpl->mRenderer = Renderer::New( geometry, shader );
314
315   mThicknessIndex = mImpl->mRenderer.RegisterProperty( THICKNESS_NAME, mThickness );
316   mStartAngleIndex = mImpl->mRenderer.RegisterProperty( START_ANGLE_NAME, mStartAngle );
317   mSweepAngleIndex = mImpl->mRenderer.RegisterProperty( SWEEP_ANGLE_NAME, mSweepAngle );
318
319   mRadiusIndex = mImpl->mRenderer.RegisterProperty( RADIUS_NAME, mRadius );
320
321   mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
322
323   // Register transform properties
324   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
325 }
326
327 } // namespace Internal
328
329 } // namespace Toolkit
330
331 } // namespace Dali