Merge "Add a TextEditor property to limit input to maximum characters" into devel...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / color / color-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 "color-visual.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/devel-api/object/handle-devel.h>
24
25 //INTERNAL INCLUDES
26 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
27 #include <dali-toolkit/public-api/visuals/visual-properties.h>
28 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
29 #include <dali-toolkit/devel-api/visuals/color-visual-actions-devel.h>
30 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
31 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
32 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
33 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
34
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace
45 {
46
47 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
48   attribute mediump vec2 aPosition;\n
49   uniform highp   mat4 uMvpMatrix;\n
50   uniform mediump vec3 uSize;\n
51   \n
52
53   //Visual size and offset
54   uniform mediump vec2 offset;\n
55   uniform mediump vec2 size;\n
56   uniform mediump vec4 offsetSizeMode;\n
57   uniform mediump vec2 origin;\n
58   uniform mediump vec2 anchorPoint;\n
59   uniform mediump vec2 extraSize;\n
60
61   vec4 ComputeVertexPosition()\n
62   {\n
63     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
64     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
65     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
66   }\n
67
68   void main()\n
69   {\n
70     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
71   }\n
72 );
73
74 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
75   uniform lowp vec4 uColor;\n
76   uniform lowp vec3 mixColor;\n
77   \n
78   void main()\n
79   {\n
80     gl_FragColor = vec4(mixColor, 1.0)*uColor;\n
81   }\n
82 );
83
84 const char* VERTEX_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
85   attribute mediump vec2 aPosition;\n
86   uniform highp   mat4 uMvpMatrix;\n
87   uniform mediump vec3 uSize;\n
88   varying mediump vec2 vPosition;\n
89   varying mediump vec2 vRectSize;\n
90   varying mediump float vCornerRadius;\n
91   \n
92   //Visual size and offset
93   uniform mediump vec2 offset;\n
94   uniform mediump vec2 size;\n
95   uniform mediump vec2 extraSize;\n
96   uniform mediump vec4 offsetSizeMode;\n
97   uniform mediump vec2 origin;\n
98   uniform mediump vec2 anchorPoint;\n
99   uniform mediump float cornerRadius;\n
100   uniform mediump float cornerRadiusPolicy;\n
101   \n
102   vec4 ComputeVertexPosition()\n
103   {\n
104     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
105     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
106     mediump float minSize = min( visualSize.x, visualSize.y );\n
107     vCornerRadius = mix( cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);\n
108     vCornerRadius = min( vCornerRadius, minSize * 0.5 );\n
109     vRectSize = visualSize / 2.0 - vCornerRadius;\n
110     vPosition = aPosition* visualSize;\n
111     return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
112   }\n
113   \n
114   void main()\n
115   {\n
116     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
117   }\n
118 );
119
120 //float distance = length( max( abs( position - center ), size ) - size ) - radius;
121 const char* FRAGMENT_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
122   varying mediump vec2 vPosition;\n
123   varying mediump vec2 vRectSize;\n
124   varying mediump float vCornerRadius;\n
125   uniform lowp vec4 uColor;\n
126   uniform lowp vec3 mixColor;\n
127   \n
128   void main()\n
129   {\n
130       mediump float dist = length( max( abs( vPosition ), vRectSize ) - vRectSize ) - vCornerRadius;\n
131       gl_FragColor = uColor * vec4( mixColor, 1.0 );\n
132       gl_FragColor.a *= 1.0 - smoothstep( -1.0, 1.0, dist );\n
133   }\n
134 );
135
136 const char* VERTEX_SHADER_BLUR_EDGE = DALI_COMPOSE_SHADER(
137   attribute mediump vec2 aPosition;\n
138   uniform highp   mat4 uMvpMatrix;\n
139   uniform mediump vec3 uSize;\n
140   varying mediump vec2 vPosition;\n
141   varying mediump vec2 vRectSize;\n
142   \n
143   //Visual size and offset
144   uniform mediump vec2 offset;\n
145   uniform mediump vec2 size;\n
146   uniform mediump vec2 extraSize;\n
147   uniform mediump vec4 offsetSizeMode;\n
148   uniform mediump vec2 origin;\n
149   uniform mediump vec2 anchorPoint;\n
150   uniform mediump float blurRadius;\n
151   \n
152   vec4 ComputeVertexPosition()\n
153   {\n
154     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize + blurRadius * 2.0;\n
155     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
156     vRectSize = visualSize / 2.0;\n
157     vPosition = aPosition* visualSize;\n
158     return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
159   }\n
160   \n
161   void main()\n
162   {\n
163     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
164   }\n
165 );
166
167 const char* FRAGMENT_SHADER_BLUR_EDGE = DALI_COMPOSE_SHADER(
168   varying mediump vec2 vPosition;\n
169   varying mediump vec2 vRectSize;\n
170   uniform lowp vec4 uColor;\n
171   uniform lowp vec3 mixColor;\n
172   uniform mediump float blurRadius;\n
173   \n
174   void main()\n
175   {\n
176       mediump vec2 blur = 1.0 - smoothstep( vRectSize - blurRadius * 2.0, vRectSize, abs( vPosition ) );\n
177       gl_FragColor = uColor * vec4( mixColor, 1.0 );\n
178       gl_FragColor.a *= blur.x * blur.y;\n
179   }\n
180 );
181
182 }
183
184 ColorVisualPtr ColorVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
185 {
186   ColorVisualPtr colorVisualPtr( new ColorVisual( factoryCache ) );
187   colorVisualPtr->SetProperties( properties );
188   return colorVisualPtr;
189 }
190
191 ColorVisual::ColorVisual( VisualFactoryCache& factoryCache )
192 : Visual::Base( factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::COLOR ),
193   mBlurRadius( 0.0f ),
194   mRenderIfTransparent( false )
195 {
196 }
197
198 ColorVisual::~ColorVisual()
199 {
200 }
201
202 void ColorVisual::DoSetProperties( const Property::Map& propertyMap )
203 {
204   // By virtue of DoSetProperties being called last, this will override
205   // anything set by Toolkit::Visual::Property::MIX_COLOR
206   Property::Value* colorValue = propertyMap.Find( Toolkit::ColorVisual::Property::MIX_COLOR, MIX_COLOR );
207   if( colorValue )
208   {
209     Vector4 color;
210     if( colorValue->Get( color ) )
211     {
212       Property::Type type = colorValue->GetType();
213       if( type == Property::VECTOR4 )
214       {
215         SetMixColor( color );
216       }
217       else if( type == Property::VECTOR3 )
218       {
219         Vector3 color3(color);
220         SetMixColor( color3 );
221       }
222     }
223     else
224     {
225       DALI_LOG_ERROR("ColorVisual: mixColor property has incorrect type\n");
226     }
227   }
228
229   Property::Value* renderIfTransparentValue = propertyMap.Find( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, RENDER_IF_TRANSPARENT_NAME );
230   if( renderIfTransparentValue )
231   {
232     if( ! renderIfTransparentValue->Get( mRenderIfTransparent ) )
233     {
234       DALI_LOG_ERROR( "ColorVisual: renderIfTransparent property has incorrect type: %d\n", renderIfTransparentValue->GetType() );
235     }
236   }
237
238   Property::Value* blurRadiusValue = propertyMap.Find( Toolkit::DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME );
239   if( blurRadiusValue )
240   {
241     if( !blurRadiusValue->Get( mBlurRadius ) )
242     {
243       DALI_LOG_ERROR( "ColorVisual:DoSetProperties:: BLUR_RADIUS property has incorrect type: %d\n", blurRadiusValue->GetType() );
244     }
245   }
246 }
247
248 void ColorVisual::DoSetOnScene( Actor& actor )
249 {
250   InitializeRenderer();
251
252   // Only add the renderer if it's not fully transparent
253   // We cannot avoid creating a renderer as it's used in the base class
254   if( mRenderIfTransparent || mImpl->mMixColor.a > 0.0f )
255   {
256     actor.AddRenderer( mImpl->mRenderer );
257   }
258
259   // Color Visual generated and ready to display
260   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
261 }
262
263 void ColorVisual::DoCreatePropertyMap( Property::Map& map ) const
264 {
265   map.Clear();
266   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR );
267   map.Insert( Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor );
268   map.Insert( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, mRenderIfTransparent );
269   map.Insert( Toolkit::DevelColorVisual::Property::BLUR_RADIUS, mBlurRadius );
270 }
271
272 void ColorVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
273 {
274   // Do nothing
275 }
276
277
278 void ColorVisual::OnSetTransform()
279 {
280   if( mImpl->mRenderer )
281   {
282     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
283   }
284 }
285
286 void ColorVisual::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
287 {
288   // Check if action is valid for this visual type and perform action if possible
289   switch( actionId )
290   {
291     case DevelColorVisual::Action::UPDATE_PROPERTY:
292     {
293       Property::Map* map = attributes.GetMap();
294       if( map )
295       {
296         DoSetProperties( *map );
297       }
298       break;
299     }
300   }
301 }
302
303 void ColorVisual::InitializeRenderer()
304 {
305   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
306
307   Shader shader;
308   if( !EqualsZero( mBlurRadius ) )
309   {
310     shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER_BLUR_EDGE );
311     if( !shader )
312     {
313       shader = Shader::New( VERTEX_SHADER_BLUR_EDGE, FRAGMENT_SHADER_BLUR_EDGE );
314       mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER_BLUR_EDGE, shader );
315     }
316   }
317   else if( !IsRoundedCornerRequired() )
318   {
319     shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER );
320     if( !shader )
321     {
322       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
323       mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER, shader );
324     }
325   }
326   else
327   {
328     shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER );
329     if( !shader )
330     {
331       shader = Shader::New( VERTEX_SHADER_ROUNDED_CORNER, FRAGMENT_SHADER_ROUNDED_CORNER );
332       mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER, shader );
333     }
334   }
335
336   mImpl->mRenderer = Renderer::New( geometry, shader );
337
338   // ColorVisual has it's own index key for mix color - use this instead
339   // of using the new base index to avoid changing existing applications
340   // String keys will get to this property.
341   mImpl->mMixColorIndex = DevelHandle::RegisterProperty( mImpl->mRenderer, Toolkit::ColorVisual::Property::MIX_COLOR, MIX_COLOR, Vector3(mImpl->mMixColor) );
342
343   mImpl->mRenderer.RegisterProperty( BLUR_RADIUS_NAME, mBlurRadius );
344
345   if( mImpl->mMixColor.a < 1.f || !EqualsZero( mBlurRadius ) )
346   {
347     mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
348   }
349
350   // Register transform properties
351   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
352 }
353
354 } // namespace Internal
355
356 } // namespace Toolkit
357
358 } // namespace Dali