// Send some taps and check the cursor positions.
// Try to tap at the beginning.
- application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
- application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
+ application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 1.f, 25.0f ) ) );
+ application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 1.f, 25.0f ) ) );
// Render and notify
application.SendNotification();
DALI_TEST_EQUALS( position2, position4, TEST_LOCATION ); // Should be in the same position2.
// Tap away from the start position.
- application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 13.f, 25.0f ) ) );
- application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 13.0f, 25.0f ) ) );
+ application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 16.f, 25.0f ) ) );
+ application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 16.0f, 25.0f ) ) );
// Render and notify
application.SendNotification();
application.SendNotification();
application.Render();
- // Should not be renderer.
+ // Cursor position should be the same than position2.
+ Vector3 position6 = cursor.GetCurrentPosition();
+
+ DALI_TEST_EQUALS( position2, position6, TEST_LOCATION );// Should be in the same position2.
+
+ // Should not be a renderer.
DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor only.
END_TEST;
# Build the Dali Toolkit library
-toolkit_images_dir = ../../../dali-toolkit/images
+toolkit_images_dir = ../../../dali-toolkit/images-common
toolkit_sounds_dir = ../../../dali-toolkit/sounds
toolkit_src_dir = ../../../dali-toolkit/internal
public_api_src_dir = ../../../dali-toolkit/public-api
devel_api_src_dir = ../../../dali-toolkit/devel-api
toolkit_styles_dir = $(STYLE_DIR)
+toolkit_style_images_dir = $(STYLE_DIR)/images
-include ../../../dali-toolkit/images/file.list
+include ../../../dali-toolkit/images-common/file.list
include ../../../dali-toolkit/sounds/file.list
include ../../../dali-toolkit/styles/file.list
include ../../../dali-toolkit/internal/file.list
dalistyledir = ${dataReadOnlyDir}/toolkit/styles/
dalistyle_DATA = ${dali_toolkit_style_files}
+dalistyleimagesdir = ${dataReadOnlyDir}/toolkit/styles/images/
+dalistyleimages_DATA = ${dali_toolkit_style_images}
+
libdali_toolkit_la_DEPENDENCIES =
libdali_toolkit_la_CXXFLAGS = -DDALI_COMPILATION \
-DDALI_IMAGE_DIR="\"${daliimagedir}\"" \
-DDALI_SOUND_DIR="\"${dalisounddir}\"" \
-DDALI_STYLE_DIR="\"${dalistyledir}\"" \
+ -DDALI_STYLE_IMAGE_DIR="\"${dalistyleimagesdir}\"" \
-DDALI_DATA_READ_ONLY_DIR="\"${dataReadOnlyDir}\"" \
-Werror -Wall \
-I../../../ \
* This function should be called when the control put on stage.
*
* @param[in] actor The actor applying this renderer.
+ * @post SetOffStage should be called with the same actor when the control is put off stage otherwise memory will be leaked
*/
void SetOnStage( Actor& actor );
defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ] = DALI_IMAGE_DIR;
defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ] = DALI_SOUND_DIR;
defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR;
+ defaultDirs[ TOKEN_STRING(DALI_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR;
AddConstants( defaultDirs );
}
}
}
+void ImageView::OnStageDisconnection()
+{
+ if( mRenderer )
+ {
+ CustomActor self = Self();
+ mRenderer.SetOffStage( self );
+ }
+}
+
+
///////////////////////////////////////////////////////////
//
// Properties
virtual void OnStageConnection( int depth );
/**
+ * @copydoc Toolkit::Control::OnStageDisconnection()
+ */
+ virtual void OnStageDisconnection();
+
+ /**
* @copydoc Toolkit::Control::GetNaturalSize
*/
virtual Vector3 GetNaturalSize();
);
}
-BorderRenderer::BorderRenderer()
-: ControlRenderer(),
+BorderRenderer::BorderRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
mBorderColor( Color::TRANSPARENT ),
mBorderSize( 0.f ),
mBorderColorIndex( Property::INVALID_INDEX ),
{
}
-void BorderRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void BorderRenderer::DoInitialize( const Property::Map& propertyMap )
{
- Initialize( factoryCache );
-
Property::Value* color = propertyMap.Find( COLOR_NAME );
if( !( color && color->Get(mBorderColor) ) )
{
map.Insert( SIZE_NAME, mBorderSize );
}
-void BorderRenderer::Initialize( RendererFactoryCache& factoryCache)
+void BorderRenderer::InitializeRenderer( Renderer& renderer )
{
- mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::BORDER_GEOMETRY );
- if( !(mImpl->mGeometry) )
+ Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::BORDER_GEOMETRY );
+ if( !geometry )
+ {
+ geometry = CreateBorderGeometry();
+ mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
+ }
+
+ Shader shader = mFactoryCache.GetShader( RendererFactoryCache::BORDER_SHADER );
+ if( !shader )
{
- mImpl->mGeometry = CreateBorderGeometry();
- factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ mFactoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, shader );
}
- mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::BORDER_SHADER );
- if( !(mImpl->mShader) )
+ if( !renderer )
{
- mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
- factoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, mImpl->mShader );
+ Material material = Material::New( shader );
+ renderer = Renderer::New( geometry, material );
+ }
+ else
+ {
+ mImpl->mRenderer.SetGeometry( geometry );
+ Material material = mImpl->mRenderer.GetMaterial();
+ if( material )
+ {
+ material.SetShader( shader );
+ }
}
}
* | /| /| /|
* |/ |/ |/ |
* 4--5--6--7
- * | /| | /|
- * |/ | |/ |
+ * |\ | |\ |
+ * | \| | \|
* 8--9--10-11
- * | /| /| /|
- * |/ |/ |/ |
+ * | /| /|\ |
+ * |/ |/ | \|
* 12-13-14-15
*/
Geometry BorderRenderer::CreateBorderGeometry()
borderVertices.SetData(borderVertexData);
// Create indices
- unsigned int indexData[48] = { 0, 4, 1, 1, 4, 5, 1, 5, 2, 2, 5, 6, 2, 6,3, 3, 6, 7,
- 4, 8, 5, 5, 8, 9, 6, 10, 7, 7, 10, 11,
- 8, 12, 9, 9, 12, 13, 9, 13, 10, 10, 13, 14, 10, 11, 14, 11, 14, 15};
-
+ unsigned int indexData[24] = { 0,4,1,5,2,6,3,7,7,6,11,10,15,14,14,10,13,9,12,8,8,9,4,5 };
Property::Map indexFormat;
indexFormat[INDEX_NAME] = Property::INTEGER;
- PropertyBuffer indices = PropertyBuffer::New( indexFormat, 48 );
+ PropertyBuffer indices = PropertyBuffer::New( indexFormat, 24 );
indices.SetData(indexData);
// Create the geometry object
Geometry geometry = Geometry::New();
geometry.AddVertexBuffer( borderVertices );
geometry.SetIndexBuffer( indices );
+ geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
return geometry;
}
/**
* @brief Constructor.
+ *
+ * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
*/
- BorderRenderer();
+ BorderRenderer( RendererFactoryCache& factoryCache );
/**
* @brief A reference counted object may only be deleted by calling Unreference().
public: // from ControlRenderer
/**
+ * @copydoc ControlRenderer::SetClipRect
+ */
+ virtual void SetClipRect( const Rect<int>& clipRect );
+
+protected:
+
+ /**
* @copydoc ControlRenderer::DoInitialize
*/
- virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+ virtual void DoInitialize( const Property::Map& propertyMap );
/**
- * @copydoc ControlRenderer::SetClipRect
+ * @copydoc ControlRenderer::InitializeRenderer
*/
- virtual void SetClipRect( const Rect<int>& clipRect );
+ virtual void InitializeRenderer( Renderer& renderer );
-protected:
/**
* @copydoc ControlRenderer::DoSetOnStage
*/
public:
/**
- * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
- *
- * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
- */
- void Initialize( RendererFactoryCache& factoryCache );
-
- /**
* Set the color of the border.
* @param[in] color The border color.
*/
);
}
-ColorRenderer::ColorRenderer()
-: ControlRenderer(),
+ColorRenderer::ColorRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
mBlendColorIndex( Property::INVALID_INDEX )
{
}
{
}
-void ColorRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ColorRenderer::DoInitialize( const Property::Map& propertyMap )
{
- Initialize( factoryCache );
-
Property::Value* color = propertyMap.Find( COLOR_NAME );
if( !( color && color->Get(mBlendColor) ) )
{
map.Insert( COLOR_NAME, mBlendColor );
}
-void ColorRenderer::DoSetOnStage( Actor& actor )
+void ColorRenderer::InitializeRenderer( Renderer& renderer )
{
- mBlendColorIndex = (mImpl->mRenderer).RegisterProperty( COLOR_UNIFORM_NAME, mBlendColor );
- if( mBlendColor.a < 1.f )
+ Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
+ if( !geometry )
{
- (mImpl->mRenderer).GetMaterial().SetBlendMode( BlendingMode::ON );
+ geometry = RendererFactoryCache::CreateQuadGeometry();
+ mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
}
-}
-void ColorRenderer::Initialize( RendererFactoryCache& factoryCache)
-{
- mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
- if( !(mImpl->mGeometry) )
+ Shader shader = mFactoryCache.GetShader( RendererFactoryCache::COLOR_SHADER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ mFactoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, shader );
+ }
+
+ if( !renderer )
+ {
+ Material material = Material::New( shader );
+ renderer = Renderer::New( geometry, material );
+ }
+ else
{
- mImpl->mGeometry = RendererFactoryCache::CreateQuadGeometry();
- factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
+ mImpl->mRenderer.SetGeometry( geometry );
+ Material material = mImpl->mRenderer.GetMaterial();
+ if( material )
+ {
+ material.SetShader( shader );
+ }
}
- mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::COLOR_SHADER );
- if( !(mImpl->mShader) )
+ mBlendColorIndex = renderer.RegisterProperty( COLOR_UNIFORM_NAME, mBlendColor );
+ if( mBlendColor.a < 1.f )
{
- mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
- factoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, mImpl->mShader );
+ renderer.GetMaterial().SetBlendMode( BlendingMode::ON );
}
}
/**
* @brief Constructor.
+ *
+ * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
*/
- ColorRenderer();
+ ColorRenderer( RendererFactoryCache& factoryCache );
/**
* @brief A reference counted object may only be deleted by calling Unreference().
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::DoInitialize
- */
- virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
- /**
* @copydoc ControlRenderer::SetSize
*/
virtual void SetSize( const Vector2& size );
virtual void DoCreatePropertyMap( Property::Map& map ) const;
protected:
+
/**
- * @copydoc ControlRenderer::DoSetOnStage
+ * @copydoc ControlRenderer::DoInitialize
*/
- virtual void DoSetOnStage( Actor& actor );
-
-public:
+ virtual void DoInitialize( const Property::Map& propertyMap );
/**
- * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
- *
- * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
+ * @copydoc ControlRenderer::InitializeRenderer
*/
- void Initialize( RendererFactoryCache& factoryCache );
+ virtual void InitializeRenderer( Renderer& renderer );
+
+public:
/**
* Set the color for rendering.
void CreatePropertyMap( Property::Map& map ) const;
};
- Geometry mGeometry;
- Shader mShader;
+ std::string mCachedRendererKey; ///< The key to use for caching of the renderer. If it is empty then no caching will occur
+ RendererFactoryCache::CachedRendererPtr mCachedRenderer; ///< The current cached renderer from the Factory Cache. mCachedRenderer == null whilst this control render is offstage
Renderer mRenderer;
CustomShader* mCustomShader;
namespace Internal
{
-ControlRenderer::ControlRenderer()
-: mImpl( new Impl() )
+ControlRenderer::ControlRenderer( RendererFactoryCache& factoryCache )
+: mImpl( new Impl() ),
+ mFactoryCache( factoryCache )
{
}
delete mImpl;
}
-void ControlRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ControlRenderer::Initialize( const Property::Map& propertyMap )
{
if( mImpl->mCustomShader )
{
}
}
}
- DoInitialize( factoryCache, propertyMap );
+ DoInitialize( propertyMap );
+
+ if( mImpl->mIsOnStage )
+ {
+ InitializeRenderer( mImpl->mRenderer );
+ }
}
void ControlRenderer::SetSize( const Vector2& size )
return mImpl->mDepthIndex;
}
+void ControlRenderer::SetCachedRendererKey( const std::string& cachedRendererKey )
+{
+ if( mImpl->mCachedRendererKey == cachedRendererKey )
+ {
+ return;
+ }
+ if( !mImpl->mIsOnStage )
+ {
+ mImpl->mCachedRendererKey = cachedRendererKey;
+ }
+ else
+ {
+ //remove the cached renderer from the cache if we and the cache are the only things that hold a reference to it
+ if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->ReferenceCount() == 2 )
+ {
+ mFactoryCache.RemoveRenderer( mImpl->mCachedRenderer->mKey );
+ }
+ mImpl->mCachedRenderer.Reset();
+
+ //add the new renderer
+ mImpl->mCachedRendererKey = cachedRendererKey;
+ if( !mImpl->mCachedRendererKey.empty() && !mImpl->mCustomShader )
+ {
+ DALI_ASSERT_DEBUG( mImpl->mRenderer && "The control render is on stage but it doesn't have a valid renderer.");
+ mImpl->mCachedRenderer = mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
+ }
+ }
+}
+
void ControlRenderer::SetOnStage( Actor& actor )
{
- Material material = Material::New( mImpl->mShader );
- mImpl->mRenderer = Renderer::New( mImpl->mGeometry, material );
+ if( !mImpl->mCachedRendererKey.empty() && !mImpl->mCustomShader )
+ {
+ mImpl->mCachedRenderer = mFactoryCache.GetRenderer( mImpl->mCachedRendererKey );
+ if( !mImpl->mCachedRenderer || !mImpl->mCachedRenderer->mRenderer )
+ {
+ InitializeRenderer( mImpl->mRenderer );
+ mImpl->mCachedRenderer = mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
+ }
+
+ if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->mRenderer )
+ {
+ mImpl->mRenderer = mImpl->mCachedRenderer->mRenderer;
+ }
+ }
+
+ if( !mImpl->mRenderer )
+ {
+ InitializeRenderer( mImpl->mRenderer );
+ }
+
mImpl->mRenderer.SetDepthIndex( mImpl->mDepthIndex );
actor.AddRenderer( mImpl->mRenderer );
mImpl->mIsOnStage = true;
{
DoSetOffStage( actor );
+ //remove the cached renderer from the cache if we and the cache are the only things that hold a reference to it
+ if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->ReferenceCount() == 2 )
+ {
+ mFactoryCache.RemoveRenderer( mImpl->mCachedRenderer->mKey );
+ }
+ mImpl->mCachedRenderer.Reset();
+
actor.RemoveRenderer( mImpl->mRenderer );
mImpl->mRenderer.Reset();
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h>
#include <dali-toolkit/devel-api/controls/renderer-factory/control-renderer.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
namespace Dali
{
namespace Internal
{
-class RendererFactoryCache;
-
/**
* Base class for all Control rendering logic. A control may have multiple control renderers.
*
* request the geometry and shader from the cache, if not available, create and save to the cache for sharing;
* record the property values.
*
- * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
* @param[in] propertyMap The properties for the requested ControlRenderer object.
*/
- void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+ void Initialize( const Property::Map& propertyMap );
/**
* @copydoc Toolkit::ControlRenderer::SetSize
/**
* @brief Constructor.
+ *
+ * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
*/
- ControlRenderer();
+ ControlRenderer( RendererFactoryCache& factoryCache );
/**
* @brief A reference counted object may only be deleted by calling Unreference().
* @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
* @param[in] propertyMap The properties for the requested ControlRenderer object.
*/
- virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap ) = 0;
+ virtual void DoInitialize( const Property::Map& propertyMap ) = 0;
+
+ /**
+ * @brief Initialises a renderer ready to be put on stage.
+ *
+ * @param[inout] renderer The Renderer to initialise. If the renderer is not empty then re-initialise the renderer
+ */
+ virtual void InitializeRenderer( Renderer& renderer ) = 0;
protected:
*/
virtual void DoSetOffStage( Actor& actor );
+protected:
+
+ /**
+ * @brief Sets the key to use for caching the renderer. If this is empty then no caching will occur
+ *
+ * @param[in] cachedRendererKey The key to use for caching the renderer.
+ */
+ void SetCachedRendererKey( const std::string& cachedRendererKey );
+
private:
// Undefined
protected:
struct Impl;
Impl* mImpl;
+ RendererFactoryCache& mFactoryCache;
};
} // namespace Internal
const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
const char * const UNIFORM_TEXTULRE_NAME("sTexture");
+RendererFactoryCache::ShaderType GetShaderType( GradientRenderer::Type type, Gradient::GradientUnits units)
+{
+ if( type==GradientRenderer::LINEAR )
+ {
+ if( units == Gradient::USER_SPACE_ON_USE )
+ {
+ return RendererFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
+ }
+ return RendererFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
+ }
+ else if( units == Gradient::USER_SPACE_ON_USE )
+ {
+ return RendererFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
+ }
-const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+ return RendererFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
+}
+
+const char* VERTEX_SHADER[] =
+{
+// vertex shader for gradient units as USER_SPACE_ON_USE
+DALI_COMPOSE_SHADER(
attribute mediump vec2 aPosition;\n
uniform mediump mat4 uMvpMatrix;\n
uniform mediump vec3 uSize;\n
\n
vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
}\n
-);
+),
-const char* FRAGMENT_SHADER_LINEAR = DALI_COMPOSE_SHADER(
+// vertex shader for gradient units as OBJECT_BOUNDING_BOX
+ DALI_COMPOSE_SHADER(
+ attribute mediump vec2 aPosition;\n
+ uniform mediump mat4 uMvpMatrix;\n
+ uniform mediump vec3 uSize;\n
+ uniform mediump mat3 uAlignmentMatrix;\n
+ varying mediump vec2 vTexCoord;\n
+ \n
+ void main()\n
+ {\n
+ mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+ vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
+ \n
+ vertexPosition.xyz *= uSize;\n
+ gl_Position = uMvpMatrix * vertexPosition;\n
+ }\n
+)
+};
+
+const char* FRAGMENT_SHADER[] =
+{
+// fragment shader for linear gradient
+DALI_COMPOSE_SHADER(
uniform sampler2D sTexture;\n // sampler1D?
uniform lowp vec4 uColor;\n
varying mediump vec2 vTexCoord;\n
{\n
gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
}\n
-);
+),
-const char* FRAGMENT_SHADER_RADIAL = DALI_COMPOSE_SHADER(
+// fragment shader for radial gradient
+DALI_COMPOSE_SHADER(
uniform sampler2D sTexture;\n // sampler1D?
uniform lowp vec4 uColor;\n
varying mediump vec2 vTexCoord;\n
{\n
gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
}\n
-);
+)
+};
Sampler::WrapMode GetWrapMode( Gradient::SpreadMethod spread )
{
}
-GradientRenderer::GradientRenderer()
-:mGradientTransformIndex( Property::INVALID_INDEX )
+GradientRenderer::GradientRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
+ mGradientType( LINEAR )
{
}
{
}
-void GradientRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void GradientRenderer::DoInitialize( const Property::Map& propertyMap )
{
- mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
- if( !(mImpl->mGeometry) )
+ Gradient::GradientUnits gradientUnits = Gradient::OBJECT_BOUNDING_BOX;
+ Property::Value* unitsValue = propertyMap.Find( GRADIENT_UNITS_NAME );
+ std::string units;
+ // The default unit is OBJECT_BOUNDING_BOX.
+ // Only need to set new units if 'user-space'
+ if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
{
- mImpl->mGeometry = RendererFactoryCache::CreateQuadGeometry();
- factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
+ gradientUnits = Gradient::USER_SPACE_ON_USE;
}
- Type gradientType;
+ mGradientType = LINEAR;
if( propertyMap.Find( GRADIENT_RADIUS_NAME ))
{
- mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL );
- if( !(mImpl->mShader) )
- {
- mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RADIAL );
- factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL, mImpl->mShader );
- }
- gradientType = RADIAL;
- }
- else
- {
- mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR );
- if( !(mImpl->mShader) )
- {
- mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_LINEAR );
- factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR, mImpl->mShader );
- }
- gradientType = LINEAR;
+ mGradientType = RADIAL;
}
- if( NewGradient(gradientType, propertyMap) )
+ if( NewGradient( mGradientType, propertyMap ) )
{
+ mGradient->SetGradientUnits( gradientUnits );
mGradientTransform = mGradient->GetAlignmentTransform();
}
else
void GradientRenderer::SetSize( const Vector2& size )
{
ControlRenderer::SetSize( size );
-
- if( mGradient->GetGradientUnits() == Gradient::OBJECT_BOUNDING_BOX )
- {
- // Apply scaling
- Matrix3 scaling( 1.f/(size.x+Math::MACHINE_EPSILON_100), 0.f, 0.f,
- 0.f, 1.f/(size.y+Math::MACHINE_EPSILON_100), 0.f, 0.5f, 0.5f, 1.f );
- Matrix3::Multiply( mGradientTransform, scaling, mGradient->GetAlignmentTransform() );
-
- if( mImpl->mRenderer )
- {
- (mImpl->mRenderer).SetProperty( mGradientTransformIndex, mGradientTransform );
- }
- }
}
void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
}
}
-void GradientRenderer::DoSetOnStage( Actor& actor )
+void GradientRenderer::InitializeRenderer( Dali::Renderer& renderer )
{
- mGradientTransformIndex = (mImpl->mRenderer).RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
+ Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
+ if( !geometry )
+ {
+ geometry = RendererFactoryCache::CreateQuadGeometry();
+ mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
+ }
+
+ Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
+ RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
+ Shader shader = mFactoryCache.GetShader( shaderType );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
+ mFactoryCache.SaveShader( shaderType, shader );
+ }
+
+ Material material;
+ if( !renderer )
+ {
+ material = Material::New( shader );
+ renderer = Renderer::New( geometry, material );
+ }
+ else
+ {
+ mImpl->mRenderer.SetGeometry( geometry );
+ material = mImpl->mRenderer.GetMaterial();
+ if( material )
+ {
+ material.SetShader( shader );
+ }
+ }
Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
Sampler sampler = Sampler::New( lookupTexture, UNIFORM_TEXTULRE_NAME );
Sampler::WrapMode wrap = GetWrapMode( mGradient->GetSpreadMethod() );
sampler.SetWrapMode( wrap, wrap );
- Material material = (mImpl->mRenderer).GetMaterial();
- if( material )
- {
- material.AddSampler( sampler );
- }
+ material.AddSampler( sampler );
+
+ renderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
}
bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
return false;
}
- Property::Value* unitsValue = propertyMap.Find( GRADIENT_UNITS_NAME );
- std::string units;
- // The default unit is OBJECT_BOUNDING_BOX.
- // Only need to set new units if 'user-space'
- if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
- {
- mGradient->SetGradientUnits( Gradient::USER_SPACE_ON_USE );
- }
-
Property::Value* spread = propertyMap.Find( GRADIENT_SPREAD_METHOD_NAME );
std::string stringValue ;
// The default spread method is PAD.
public:
/**
+ * Types of the gradient
+ */
+ enum Type
+ {
+ LINEAR,
+ RADIAL
+ };
+
+ /**
* @brief Constructor.
+ *
+ * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
*/
- GradientRenderer();
+ GradientRenderer( RendererFactoryCache& factoryCache );
/**
* @brief A reference counted object may only be deleted by calling Unreference().
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::DoInitialize
- */
- virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
- /**
* @copydoc ControlRenderer::SetSize
*/
virtual void SetSize( const Vector2& size );
protected:
/**
- * @copydoc ControlRenderer::DoSetOnStage
+ * @copydoc ControlRenderer::DoInitialize
*/
- virtual void DoSetOnStage( Actor& actor );
-
-private:
+ virtual void DoInitialize( const Property::Map& propertyMap );
/**
- * Types of the gradient
+ * @copydoc ControlRenderer::InitializeRenderer
*/
- enum Type
- {
- LINEAR,
- RADIAL
- };
+ virtual void InitializeRenderer( Renderer& renderer );
+
+private:
/**
* New a gradient object with the given property map.
private:
Matrix3 mGradientTransform;
- Property::Index mGradientTransformIndex;
IntrusivePtr<Gradient> mGradient;
+ Type mGradientType;
};
} // namespace Internal
}\n
);
-void AddQuadIndices( Vector< unsigned int >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
-{
- indices.PushBack( rowIdx );
- indices.PushBack( nextRowIdx + 1 );
- indices.PushBack( rowIdx + 1 );
-
- indices.PushBack( rowIdx );
- indices.PushBack( nextRowIdx );
- indices.PushBack( nextRowIdx + 1 );
-}
-
Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned int >& indices )
{
Property::Map vertexFormat;
Geometry geometry = Geometry::New();
geometry.AddVertexBuffer( vertexPropertyBuffer );
geometry.SetIndexBuffer( indexPropertyBuffer );
+ geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
return geometry;
}
// Create indices
Vector< unsigned int > indices;
- indices.Reserve( gridWidth * gridHeight * 6 );
+ indices.Reserve( (gridWidth+2)*gridHeight*2 - 2);
- unsigned int rowIdx = 0;
- unsigned int nextRowIdx = gridWidth + 1;
- for( int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx )
+ for( unsigned int row = 0u; row < gridHeight; ++row )
{
- for( int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx )
+ unsigned int rowStartIndex = row*(gridWidth+1u);
+ unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
+
+ if( row != 0u ) // degenerate index on non-first row
{
- AddQuadIndices( indices, rowIdx, nextRowIdx );
+ indices.PushBack( rowStartIndex );
+ }
+
+ for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
+ {
+ indices.PushBack( rowStartIndex + column);
+ indices.PushBack( nextRowStartIndex + column);
+ }
+
+ if( row != gridHeight-1u ) // degenerate index on non-last row
+ {
+ indices.PushBack( nextRowStartIndex + gridWidth );
}
}
} //unnamed namespace
-ImageRenderer::ImageRenderer()
-: ControlRenderer(),
+ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
mDesiredSize(),
mFittingMode( FittingMode::DEFAULT ),
mSamplingMode( SamplingMode::DEFAULT )
{
}
-void ImageRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ImageRenderer::DoInitialize( const Property::Map& propertyMap )
{
- Initialize(factoryCache);
-
Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
if( imageURLValue )
{
imageURLValue->Get( mImageUrl );
if( !mImageUrl.empty() )
{
+ SetCachedRendererKey( mImageUrl );
mImage.Reset();
}
{
}
+void ImageRenderer::InitializeRenderer( Renderer& renderer )
+{
+ Geometry geometry;
+ Shader shader;
+ if( !mImpl->mCustomShader )
+ {
+ geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
+
+ shader = mFactoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ mFactoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
+ }
+ }
+ else
+ {
+ geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
+
+ if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
+ {
+ shader = mFactoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ mFactoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
+ }
+ }
+ else
+ {
+ shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
+ mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
+ mImpl->mCustomShader->mHints );
+ }
+ }
+
+ if( !renderer )
+ {
+ Material material = Material::New( shader );
+ renderer = Renderer::New( geometry, material );
+ }
+ else
+ {
+ renderer.SetGeometry( geometry );
+ Material material = renderer.GetMaterial();
+ if( material )
+ {
+ material.SetShader( shader );
+ }
+ }
+}
+
void ImageRenderer::DoSetOnStage( Actor& actor )
{
if( !mImageUrl.empty() && !mImage )
}
}
-void ImageRenderer::Initialize( RendererFactoryCache& factoryCache )
-{
- if( !mImpl->mCustomShader )
- {
- mImpl->mGeometry = CreateGeometry( factoryCache, ImageDimensions( 1, 1 ) );
-
- mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
-
- if( !mImpl->mShader )
- {
- mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
- factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
- }
- }
- else
- {
- mImpl->mGeometry = CreateGeometry( factoryCache, mImpl->mCustomShader->mGridSize );
-
- if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
- {
- mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
-
- if( !mImpl->mShader )
- {
- mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
- factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
- }
- }
- else
- {
- mImpl->mShader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
- mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
- mImpl->mCustomShader->mHints );
- }
- }
-
- if( mImpl->mRenderer )
- {
- mImpl->mRenderer.SetGeometry( mImpl->mGeometry );
- Material material = mImpl->mRenderer.GetMaterial();
- if( material )
- {
- material.SetShader( mImpl->mShader );
- }
- }
-}
-
void ImageRenderer::SetImage( const std::string& imageUrl )
{
SetImage( imageUrl, 0, 0, Dali::FittingMode::DEFAULT, Dali::SamplingMode::DEFAULT );
if( mImageUrl != imageUrl )
{
mImageUrl = imageUrl;
+ SetCachedRendererKey( mImageUrl );
mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
mFittingMode = fittingMode;
mSamplingMode = samplingMode;
/**
* @brief Constructor.
+ *
+ * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
*/
- ImageRenderer();
+ ImageRenderer( RendererFactoryCache& factoryCache );
/**
* @brief A reference counted object may only be deleted by calling Unreference().
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::DoInitialize
- */
- virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
- /**
* @copydoc ControlRenderer::SetSize
*/
virtual void SetSize( const Vector2& size );
protected:
/**
+ * @copydoc ControlRenderer::DoInitialize
+ */
+ virtual void DoInitialize( const Property::Map& propertyMap );
+
+ /**
* @copydoc ControlRenderer::DoSetOnStage
*/
virtual void DoSetOnStage( Actor& actor );
*/
virtual void DoSetOffStage( Actor& actor );
-public:
-
/**
- * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
- *
- * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
+ * @copydoc ControlRenderer::InitializeRenderer
*/
- void Initialize( RendererFactoryCache& factoryCache );
+ virtual void InitializeRenderer( Renderer& renderer );
+
+public:
/**
* @brief Sets the image of this renderer to the resource at imageUrl
/////////////////NPatchRenderer////////////////
-NPatchRenderer::NPatchRenderer()
-: ControlRenderer(),
+NPatchRenderer::NPatchRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
mBorderOnly( false )
{
}
{
}
-void NPatchRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void NPatchRenderer::DoInitialize( const Property::Map& propertyMap )
{
- Initialize(factoryCache);
-
Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
if( imageURLValue )
{
//ToDo: renderer applies the offset
}
+void NPatchRenderer::InitializeRenderer( Renderer& renderer )
+{
+ Geometry geometry;
+ if( !mBorderOnly )
+ {
+ geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY );
+ if( !geometry )
+ {
+ geometry = CreateGeometry( Uint16Pair( 3, 3 ) );
+ mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, geometry );
+ }
+ }
+ else
+ {
+ geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY );
+ if( !geometry )
+ {
+ geometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) );
+ mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, geometry );
+ }
+ }
+
+ Shader shader = mFactoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
+ mFactoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, shader );
+ }
+
+ if( !renderer )
+ {
+ Material material = Material::New( shader );
+ renderer = Renderer::New( geometry, material );
+ }
+ else
+ {
+ mImpl->mRenderer.SetGeometry( geometry );
+ Material material = mImpl->mRenderer.GetMaterial();
+ if( material )
+ {
+ material.SetShader( shader );
+ }
+ }
+}
+
void NPatchRenderer::DoSetOnStage( Actor& actor )
{
if( !mCroppedImage )
map.Insert( BORDER_ONLY, mBorderOnly );
}
-void NPatchRenderer::Initialize( RendererFactoryCache& factoryCache )
-{
- mNinePatchGeometry = factoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY );
- if( !(mNinePatchGeometry) )
- {
- mNinePatchGeometry = CreateGeometry( Uint16Pair( 3, 3 ) );
- factoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, mNinePatchGeometry );
- }
-
- mNinePatchBorderGeometry = factoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY );
- if( !(mNinePatchBorderGeometry) )
- {
- mNinePatchBorderGeometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) );
- factoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, mNinePatchBorderGeometry );
- }
-
- mNinePatchShader = factoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
- if( !mNinePatchShader )
- {
- mNinePatchShader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
- factoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, mNinePatchShader );
- }
-
- mImpl->mGeometry = mNinePatchGeometry;
- mImpl->mShader = mNinePatchShader;
-
- mImageUrl.clear();
-}
-
void NPatchRenderer::SetImage( const std::string& imageUrl, bool borderOnly )
{
mBorderOnly = borderOnly;
mStretchPixelsX = nPatch.GetStretchPixelsX();
mStretchPixelsY = nPatch.GetStretchPixelsY();
-
- if( mStretchPixelsX.Size() > 0 && mStretchPixelsY.Size() > 0 )
- {
- //only 9 patch supported for now
- mImpl->mGeometry = !mBorderOnly ? mNinePatchGeometry : mNinePatchBorderGeometry;
- mImpl->mShader = mNinePatchShader;
- }
}
void NPatchRenderer::CreateErrorImage()
mStretchPixelsX.PushBack( Uint16Pair( 0, mImageSize.GetWidth() ) );
mStretchPixelsY.Clear();
mStretchPixelsY.PushBack( Uint16Pair( 0, mImageSize.GetHeight() ) );
-
- mImpl->mGeometry = mNinePatchGeometry;
- mImpl->mShader = mNinePatchShader;
}
void NPatchRenderer::ApplyImageToSampler()
/**
* @brief Constructor.
+ *
+ * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
*/
- NPatchRenderer();
+ NPatchRenderer( RendererFactoryCache& factoryCache );
/**
* @brief A reference counted object may only be deleted by calling Unreference().
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::DoInitialize
- */
- virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
- /**
* @copydoc ControlRenderer::GetNaturalSize
*/
virtual void GetNaturalSize( Vector2& naturalSize ) const;
virtual void DoCreatePropertyMap( Property::Map& map ) const;
protected:
+
+ /**
+ * @copydoc ControlRenderer::DoInitialize
+ */
+ virtual void DoInitialize( const Property::Map& propertyMap );
+
+ /**
+ * @copydoc ControlRenderer::InitializeRenderer
+ */
+ virtual void InitializeRenderer( Renderer& renderer );
+
/**
* @copydoc ControlRenderer::DoSetOnStage
*/
public:
/**
- * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
- *
- * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
- */
- void Initialize( RendererFactoryCache& factoryCache );
-
- /**
* @brief Sets the 9 patch image of this renderer to the resource at imageUrl
* The renderer will load the image synchronously when the associated actor is put on stage, and destroy the image when it is off stage
*
Image mCroppedImage;
Geometry mNinePatchGeometry;
Geometry mNinePatchBorderGeometry;
- Shader mNinePatchShader;
std::string mImageUrl; ///< The url to the image resource to render if the renderer was set from an image resource url, empty otherwise
NinePatchImage::StretchRanges mStretchPixelsX;
// CLASS HEADER
#include "renderer-factory-cache.h"
-// Internal HEADER
+// EXTERNAL HEADER
+#include <dali/devel-api/common/hash.h>
+
+// INTERNAL HEADER
#include <dali-toolkit/internal/controls/renderers/color/color-renderer.h>
namespace Dali
RendererFactoryCache::~RendererFactoryCache()
{
- for( int i=0; i<= SHADER_TYPE_MAX; i++)
- {
- if(mShader[i])
- {
- mShader[i].Reset();
- }
- }
-
- for( int i=0; i<= GEOMETRY_TYPE_MAX; i++)
- {
- if(mGeometry[i])
- {
- mGeometry[i].Reset();
- }
- }
}
-
Geometry RendererFactoryCache::GetGeometry( GeometryType type )
{
return mGeometry[type];
mShader[type] = shader;
}
+int RendererFactoryCache::FindRenderer( const std::string& key ) const
+{
+ int hash = Dali::CalculateHash( key );
+
+ HashVector::Iterator startIt = mRendererHashes.Begin();
+ HashVector::Iterator it;
+
+ for(;;)
+ {
+ it = std::find( startIt, mRendererHashes.End(), hash );
+ if( it != mRendererHashes.End() )
+ {
+ int index = it - mRendererHashes.Begin();
+ const CachedRendererPtr& cachedRenderer = mRenderers[ index ];
+
+ if( cachedRenderer && cachedRenderer->mKey == key )
+ {
+ return index;
+ }
+ }
+ else
+ {
+ break;
+ }
+ startIt = it + 1;
+ }
+
+ return -1;
+}
+
+RendererFactoryCache::CachedRendererPtr RendererFactoryCache::GetRenderer( const std::string& key ) const
+{
+ int index = FindRenderer( key );
+ if( index != -1 )
+ {
+ return mRenderers[ index ];
+ }
+ else
+ {
+ return CachedRendererPtr();
+ }
+}
+
+RendererFactoryCache::CachedRendererPtr RendererFactoryCache::SaveRenderer( const std::string& key, Renderer& renderer )
+{
+ int hash = Dali::CalculateHash( key );
+ CachedRendererPtr newCachedRenderer = new CachedRenderer( key, renderer );
+
+ CachedRenderers::iterator it = std::find(mRenderers.begin(), mRenderers.end(), CachedRendererPtr() );
+ if( it != mRenderers.end() )
+ {
+ *it = newCachedRenderer;
+ int index = it - mRenderers.begin();
+ mRendererHashes[ index ] = hash;
+ }
+ else
+ {
+ mRendererHashes.PushBack( hash );
+ mRenderers.push_back( newCachedRenderer );
+ }
+
+ return newCachedRenderer;
+}
+
+void RendererFactoryCache::RemoveRenderer( const std::string& key )
+{
+ int index = FindRenderer( key );
+ if( index != -1 )
+ {
+ mRendererHashes[ index ] = Dali::CalculateHash( "" );
+ mRenderers[ index ].Reset();
+ }
+}
+
Geometry RendererFactoryCache::CreateQuadGeometry()
{
const float halfWidth = 0.5f;
PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat, 4 );
quadVertices.SetData(quadVertexData);
- // Create indices
- //TODO: replace with triangle strip when Geometry supports it
- unsigned int indexData[6] = { 0, 3, 1, 0, 2, 3 };
- Property::Map indexFormat;
- indexFormat["indices"] = Property::INTEGER;
- PropertyBuffer indices = PropertyBuffer::New( indexFormat, 6 );
- indices.SetData(indexData);
-
// Create the geometry object
Geometry geometry = Geometry::New();
geometry.AddVertexBuffer( quadVertices );
- geometry.SetIndexBuffer( indices );
+ geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
return geometry;
}
* limitations under the License.
*/
+#include <map>
+
// EXTERNAL INCLUDES
#include <dali/public-api/object/ref-object.h>
#include <dali/devel-api/rendering/geometry.h>
#include <dali/devel-api/rendering/shader.h>
+#include <dali/devel-api/rendering/renderer.h>
namespace Dali
{
{
COLOR_SHADER,
BORDER_SHADER,
- GRADIENT_SHADER_LINEAR,
- GRADIENT_SHADER_RADIAL,
+ GRADIENT_SHADER_LINEAR_USER_SPACE,
+ GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
+ GRADIENT_SHADER_RADIAL_USER_SPACE,
+ GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
IMAGE_SHADER,
NINE_PATCH_SHADER,
SVG_SHADER,
*/
static Geometry CreateQuadGeometry();
+public:
+ struct CachedRenderer : RefObject
+ {
+ std::string mKey;
+ Renderer mRenderer;
+
+ CachedRenderer( const std::string& key, const Renderer& renderer )
+ : mKey( key ),
+ mRenderer( renderer )
+ {}
+ };
+
+ typedef IntrusivePtr< CachedRenderer > CachedRendererPtr;
+
+ /**
+ * @brief Request renderer from the url
+ *
+ * @return The cached renderer if exist in the cache. Otherwise null is returned.
+ */
+ CachedRendererPtr GetRenderer( const std::string& key ) const;
+
+ /**
+ * @brief Cache the renderer based on the given key.
+ *
+ * If the key already exists in the cache, then the cache will save an additional renderer to the cache.
+ * RemoveRenderer will then need to be called twice to remove both items from the cache.
+ *
+ * @param[in] key The key to use for caching
+ * @param[in] renderer The Renderer to be cached
+ *
+ * @return The cached renderer stored in the cache
+ */
+ CachedRendererPtr SaveRenderer( const std::string& key, Renderer& renderer );
+
+ /**
+ * @brief Removes the renderer from the cache based on the given key
+ *
+ * @param[in] key The key used for caching
+ */
+ void RemoveRenderer( const std::string& key );
+
protected:
/**
RendererFactoryCache& operator=(const RendererFactoryCache& rhs);
private:
+ typedef Dali::Vector< std::size_t > HashVector;
+ typedef std::vector< CachedRendererPtr > CachedRenderers;
+ /**
+ * @brief Finds the first index into the cached renderers from the url
+ *
+ * @return Returns the first index into the cached renderer from the url if it exists in the cache, otherwise returns -1
+ */
+ int FindRenderer( const std::string& key ) const;
+
+private:
// ToDo: test whether using the WeakHandle could improve the performance
// With WeakHandle, the resource would be released automatically when no control is using it
Geometry mGeometry[GEOMETRY_TYPE_MAX+1];
Shader mShader[SHADER_TYPE_MAX+1];
+
+ HashVector mRendererHashes;
+ CachedRenderers mRenderers;
};
} // namespace Internal
std::string typeValue ;
if( type && type->Get( typeValue ))
{
+ if( !mFactoryCache )
+ {
+ mFactoryCache = new RendererFactoryCache();
+ }
+
if( typeValue == COLOR_RENDERER )
{
- rendererPtr = new ColorRenderer();
+ rendererPtr = new ColorRenderer( *( mFactoryCache.Get() ) );
}
else if( typeValue == GRADIENT_RENDERER )
{
- rendererPtr = new GradientRenderer();
+ rendererPtr = new GradientRenderer( *( mFactoryCache.Get() ) );
}
else if( typeValue == IMAGE_RENDERER )
{
- rendererPtr = new ImageRenderer();
+ rendererPtr = new ImageRenderer( *( mFactoryCache.Get() ) );
}
else if( typeValue == N_PATCH_RENDERER )
{
- rendererPtr = new NPatchRenderer();
+ rendererPtr = new NPatchRenderer( *( mFactoryCache.Get() ) );
}
else if( typeValue == BORDER_RENDERER )
{
- rendererPtr = new BorderRenderer();
+ rendererPtr = new BorderRenderer( *( mFactoryCache.Get() ) );
}
}
if( rendererPtr )
{
- if( !mFactoryCache )
- {
- mFactoryCache = new RendererFactoryCache();
- }
- rendererPtr->Initialize( *( mFactoryCache.Get() ), propertyMap );
+ rendererPtr->Initialize( propertyMap );
}
else
{
Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Vector4& color )
{
- ColorRenderer* rendererPtr = new ColorRenderer();
-
if( !mFactoryCache )
{
mFactoryCache = new RendererFactoryCache();
}
- rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+ ColorRenderer* rendererPtr = new ColorRenderer( *( mFactoryCache.Get() ) );
rendererPtr->SetColor( color );
return Toolkit::ControlRenderer( rendererPtr );
Toolkit::ControlRenderer RendererFactory::GetControlRenderer( float borderSize, const Vector4& borderColor )
{
- BorderRenderer* rendererPtr = new BorderRenderer();
+ if( !mFactoryCache )
+ {
+ mFactoryCache = new RendererFactoryCache();
+ }
+ BorderRenderer* rendererPtr = new BorderRenderer( *mFactoryCache.Get() );
if( !mFactoryCache )
{
mFactoryCache = new RendererFactoryCache();
}
- rendererPtr->Initialize( *( mFactoryCache.Get() ) );
rendererPtr->SetBorderSize( borderSize );
rendererPtr->SetBorderColor( borderColor );
NinePatchImage npatchImage = NinePatchImage::DownCast( image );
if( npatchImage )
{
- NPatchRenderer* rendererPtr = new NPatchRenderer();
- rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+ NPatchRenderer* rendererPtr = new NPatchRenderer( *( mFactoryCache.Get() ) );
rendererPtr->SetImage( npatchImage );
return Toolkit::ControlRenderer( rendererPtr );
}
else
{
- ImageRenderer* rendererPtr = new ImageRenderer();
- rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+ ImageRenderer* rendererPtr = new ImageRenderer( *( mFactoryCache.Get() ) );
rendererPtr->SetImage( image );
return Toolkit::ControlRenderer( rendererPtr );
Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const std::string& url )
{
+ if( !mFactoryCache )
+ {
+ mFactoryCache = new RendererFactoryCache();
+ }
+
if( NinePatchImage::IsNinePatchUrl( url ) )
{
- NPatchRenderer* rendererPtr = new NPatchRenderer();
- if( !mFactoryCache )
- {
- mFactoryCache = new RendererFactoryCache();
- }
- rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+ NPatchRenderer* rendererPtr = new NPatchRenderer( *( mFactoryCache.Get() ) );
rendererPtr->SetImage( url );
return Toolkit::ControlRenderer( rendererPtr );
}
else
{
- ImageRenderer* rendererPtr = new ImageRenderer();
- if( !mFactoryCache )
- {
- mFactoryCache = new RendererFactoryCache();
- }
- rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+ ImageRenderer* rendererPtr = new ImageRenderer( *( mFactoryCache.Get() ) );
rendererPtr->SetImage( url );
return Toolkit::ControlRenderer( rendererPtr );
}
}
- if( !mFactoryCache )
- {
- mFactoryCache = new RendererFactoryCache();
- }
- GetImplementation( renderer ).Initialize( *( mFactoryCache.Get() ), propertyMap );
+ GetImplementation( renderer ).Initialize( propertyMap );
return false;
}
mController->EnableTextInput( mDecorator );
// Forward input events to controller
- EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan |Gesture::LongPress ) );
+ EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan | Gesture::LongPress ) );
GetTapGestureDetector().SetMaximumTapsRequired( 2 );
self.TouchedSignal().Connect( this, &TextField::OnTouched );
mDecorator->SetBoundingBox( Rect<int>( 0.0f, 0.0f, stageSize.width, stageSize.height ) );
}
+ // Flip vertically the 'left' selection handle
+ mDecorator->FlipHandleVertically( LEFT_SELECTION_HANDLE, true );
+
// Fill-parent area by default
self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
// Enable the text ellipsis.
LayoutEngine& engine = mController->GetLayoutEngine();
+
engine.SetTextEllipsisEnabled( true );
+ engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
+
self.OnStageSignal().Connect( this, &TextLabel::OnStageConnect );
}
// Local Data
namespace
{
-
-const char* DEFAULT_GRAB_HANDLE_IMAGE_RELEASED( DALI_IMAGE_DIR "cursor_handler_center.png" );
-
const int DEFAULT_POPUP_OFFSET( -100.0f ); // Vertical offset of Popup from cursor or handles position.
const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
active( false ),
visible( false ),
pressed( false ),
+ verticallyFlippedPreferred( false ),
horizontallyFlipped( false ),
verticallyFlipped( false )
{
bool active : 1;
bool visible : 1;
bool pressed : 1;
- bool horizontallyFlipped : 1; ///< Whether the handle has been horizontally flipped.
- bool verticallyFlipped : 1; ///< Whether the handle has been vertically flipped.
+ bool verticallyFlippedPreferred : 1; ///< Whether the handle is preferred to be vertically flipped.
+ bool horizontallyFlipped : 1; ///< Whether the handle has been horizontally flipped.
+ bool verticallyFlipped : 1; ///< Whether the handle has been vertically flipped.
};
struct PopupImpl
if( mPrimaryCursor )
{
const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
- mPrimaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f );
+ mPrimaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
if( mPrimaryCursorVisible )
{
- const Vector2& position = cursor.position;
-
- mPrimaryCursor.SetPosition( position.x,
- position.y );
+ mPrimaryCursor.SetPosition( cursor.position.x,
+ cursor.position.y );
mPrimaryCursor.SetSize( Size( mCursorWidth, cursor.cursorHeight ) );
}
mPrimaryCursor.SetVisible( mPrimaryCursorVisible && mCursorBlinkStatus );
if( mSecondaryCursor )
{
const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
- mSecondaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f );
+ mSecondaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
if( mSecondaryCursorVisible )
{
mSecondaryCursor.SetPosition( cursor.position.x,
HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
if( grabHandle.active )
{
- const Vector2& position = grabHandle.position;
-
- const bool isVisible = ( position.x <= size.width ) && ( position.x >= 0.f );
+ const bool isVisible = ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= size.width ) && ( grabHandle.position.x >= 0.f );
if( isVisible )
{
// Sets the grab handle image according if it's pressed, flipped, etc.
SetHandleImage( GRAB_HANDLE );
}
- grabHandle.actor.SetVisible( isVisible );
+
+ if( grabHandle.actor )
+ {
+ grabHandle.actor.SetVisible( isVisible );
+ }
}
else if( grabHandle.actor )
{
HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
if( primary.active || secondary.active )
{
- const Vector2& primaryPosition = primary.position;
- const Vector2& secondaryPosition = secondary.position;
-
- const bool isPrimaryVisible = ( primaryPosition.x <= size.width ) && ( primaryPosition.x >= 0.f );
- const bool isSecondaryVisible = ( secondaryPosition.x <= size.width ) && ( secondaryPosition.x >= 0.f );
+ const bool isPrimaryVisible = ( primary.position.x <= size.width ) && ( primary.position.x >= 0.f );
+ const bool isSecondaryVisible = ( secondary.position.x <= size.width ) && ( secondary.position.x >= 0.f );
if( isPrimaryVisible || isSecondaryVisible )
{
SetSelectionHandleMarkerSize( secondary );
}
}
- primary.actor.SetVisible( isPrimaryVisible );
- secondary.actor.SetVisible( isSecondaryVisible );
+
+ if( primary.actor )
+ {
+ primary.actor.SetVisible( isPrimaryVisible );
+ }
+ if( secondary.actor )
+ {
+ secondary.actor.SetVisible( isSecondaryVisible );
+ }
CreateHighlight();
UpdateHighlight();
void SetSelectionHandleMarkerSize( HandleImpl& handle )
{
- if ( handle.markerActor )
+ if( handle.markerActor )
{
handle.markerActor.SetSize( 0, handle.lineHeight );
}
HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
if( !grabHandle.actor )
{
- if( !mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
- {
- SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_RELEASED ) );
- }
-
grabHandle.actor = ImageActor::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
grabHandle.actor.SetSortModifier( DECORATION_DEPTH_INDEX );
grabHandle.actor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
void CreateHandleMarker( HandleImpl& handle, Image& image, HandleType handleType )
{
- if ( image )
+ if( image )
{
handle.markerActor = ImageActor::New( image );
handle.markerActor.SetColor( mHandleColor );
handle.markerActor.SetResizePolicy ( ResizePolicy::FIXED, Dimension::HEIGHT );
- if ( LEFT_SELECTION_HANDLE == handleType )
+ if( LEFT_SELECTION_HANDLE == handleType )
{
handle.markerActor.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
handle.markerActor.SetParentOrigin( ParentOrigin::TOP_RIGHT );
}
- else if ( RIGHT_SELECTION_HANDLE == handleType )
+ else if( RIGHT_SELECTION_HANDLE == handleType )
{
handle.markerActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
handle.markerActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
// Check if the grab handle exceeds the boundaries of the decoration box.
// At the moment only the height is checked for the grab handle.
- grabHandle.verticallyFlipped = ( grabHandleWorldPosition.y + grabHandle.size.height > mBoundingBox.w );
+
+ grabHandle.verticallyFlipped = ( grabHandle.verticallyFlippedPreferred &&
+ ( ( grabHandleWorldPosition.y - grabHandle.lineHeight - grabHandle.size.height ) > mBoundingBox.y ) ) ||
+ ( grabHandleWorldPosition.y + grabHandle.size.height > mBoundingBox.w );
// The grab handle 'y' position in local coords.
// If the grab handle exceeds the bottom of the decoration box,
// The SetGrabHandleImage() method will change the orientation.
const float yLocalPosition = grabHandle.verticallyFlipped ? grabHandle.position.y : grabHandle.position.y + grabHandle.lineHeight;
- grabHandle.actor.SetPosition( grabHandle.position.x - floor( 0.5f * mCursorWidth ),
+ grabHandle.actor.SetPosition( grabHandle.position.x + floor( 0.5f * mCursorWidth ),
yLocalPosition ); // TODO : Fix for multiline.
}
Vector2 handleWorldPosition;
CalculateHandleWorldCoordinates( handle, handleWorldPosition );
- // Whether to flip the handle.
+ // Whether to flip the handle (horizontally).
bool flipHandle = isPrimaryHandle ? mFlipLeftSelectionHandleDirection : mFlipRightSelectionHandleDirection;
// Whether to flip the handles if they are crossed.
// Does not flip if both conditions are true (double flip)
flipHandle = flipHandle != ( crossFlip || mHandlePreviousCrossed );
+ // Will flip the handles vertically if the user prefers it.
+ bool verticallyFlippedPreferred = handle.verticallyFlippedPreferred;
+
+ if( crossFlip || mHandlePreviousCrossed )
+ {
+ if( isPrimaryHandle )
+ {
+ verticallyFlippedPreferred = mHandle[RIGHT_SELECTION_HANDLE].verticallyFlippedPreferred;
+ }
+ else
+ {
+ verticallyFlippedPreferred = mHandle[LEFT_SELECTION_HANDLE].verticallyFlippedPreferred;
+ }
+ }
+
// Check if the selection handle exceeds the boundaries of the decoration box.
const bool exceedsLeftEdge = ( isPrimaryHandle ? !flipHandle : flipHandle ) && ( handleWorldPosition.x - handle.size.width < mBoundingBox.x );
}
// Whether to flip the handle vertically.
- handle.verticallyFlipped = ( handleWorldPosition.y + handle.size.height > mBoundingBox.w );
+ handle.verticallyFlipped = ( verticallyFlippedPreferred &&
+ ( ( handleWorldPosition.y - handle.lineHeight - handle.size.height ) > mBoundingBox.y ) ) ||
+ ( handleWorldPosition.y + handle.size.height > mBoundingBox.w );
// The primary selection handle 'y' position in local coords.
// If the handle exceeds the bottom of the decoration box,
}
// Chooses between the released or pressed image. It checks whether the pressed image exists.
- const HandleImageType imageType = ( handle.pressed ? ( mHandleImages[type][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
+ if( handle.actor )
+ {
+ const HandleImageType imageType = ( handle.pressed ? ( mHandleImages[type][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
- handle.actor.SetImage( mHandleImages[type][imageType] );
+ handle.actor.SetImage( mHandleImages[type][imageType] );
+ }
if( HANDLE_TYPE_COUNT != markerType )
{
- const HandleImageType markerImageType = ( handle.pressed ? ( mHandleImages[markerType][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
- handle.markerActor.SetImage( mHandleImages[markerType][markerImageType] );
+ if( handle.markerActor )
+ {
+ const HandleImageType markerImageType = ( handle.pressed ? ( mHandleImages[markerType][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
+ handle.markerActor.SetImage( mHandleImages[markerType][markerImageType] );
+ }
}
// Whether to flip the handle vertically.
- handle.actor.SetOrientation( handle.verticallyFlipped ? ANGLE_180 : ANGLE_0, Vector3::XAXIS );
+ if( handle.actor )
+ {
+ handle.actor.SetOrientation( handle.verticallyFlipped ? ANGLE_180 : ANGLE_0, Vector3::XAXIS );
+ }
}
void CreateHighlight()
float AlternatePopUpPositionRelativeToCursor()
{
+ const float popupHeight = 120.0f; // todo Set as a MaxSize Property in Control or retrieve from CopyPastePopup class.
+ const float BOTTOM_HANDLE_BOTTOM_OFFSET = 1.5; //todo Should be a property
+
float alternativePosition=0.0f;;
- if ( mPrimaryCursor ) // Secondary cursor not used for paste
+ if( mPrimaryCursor ) // Secondary cursor not used for paste
{
- Cursor cursor = PRIMARY_CURSOR;
- alternativePosition = mCursor[cursor].position.y;
+ alternativePosition = mCursor[PRIMARY_CURSOR].position.y + popupHeight;
}
- const float popupHeight = 120.0f; // todo Set as a MaxSize Property in Control or retrieve from CopyPastePopup class.
+ const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+ const HandleImpl& selectionPrimaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+ const HandleImpl& selectionSecondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
- if( mHandle[GRAB_HANDLE].active )
+ if( grabHandle.active )
{
// If grab handle enabled then position pop-up below the grab handle.
- const Vector2 grabHandleSize( 59.0f, 56.0f ); // todo
- const float BOTTOM_HANDLE_BOTTOM_OFFSET = 1.5; //todo Should be a property
- alternativePosition += grabHandleSize.height + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET ;
+ alternativePosition = grabHandle.position.y + grabHandle.size.height + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET;
+
}
- else
+ else if( selectionPrimaryHandle.active || selectionSecondaryHandle.active )
{
- alternativePosition += popupHeight;
+ const float maxHeight = std::max( selectionPrimaryHandle.size.height,
+ selectionSecondaryHandle.size.height );
+ const float maxY = std::max( selectionPrimaryHandle.position.y,
+ selectionSecondaryHandle.position.y );
+
+ alternativePosition = maxY + maxHeight + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET;
}
return alternativePosition;
mCopyPastePopup.actor.SetY( alternativeYPosition );
}
-
void SetUpPopupPositionNotifications( )
{
// Note Property notifications ignore any set anchor point so conditions must allow for this. Default is Top Left.
return mImpl->mHandle[handleType].position;
}
+void Decorator::FlipHandleVertically( HandleType handleType, bool flip )
+{
+ mImpl->mHandle[handleType].verticallyFlippedPreferred = flip;
+}
+
+bool Decorator::IsHandleVerticallyFlipped( HandleType handleType ) const
+{
+ return mImpl->mHandle[handleType].verticallyFlippedPreferred;
+}
+
void Decorator::FlipSelectionHandlesOnCrossEnabled( bool enable )
{
mImpl->mFlipSelectionHandlesOnCross = enable;
const Vector2& GetPosition( HandleType handleType ) const;
/**
+ * @brief Whether to flip vertically a handle.
+ *
+ * @param[in] handleType The handle to flip vertically.
+ * @param[in] flip Whether to flip vertically.
+ */
+ void FlipHandleVertically( HandleType handleType, bool flip );
+
+ /**
+ * @brief Retrieves whether the handle is vertically flipped.
+ *
+ * @param[in] handleType The handle to query.
+ *
+ * @return @e ture if the handle is vertically flipped.
+ */
+ bool IsHandleVerticallyFlipped( HandleType handleType ) const;
+
+ /**
* @brief Whether to flip the selection handles as soon as they are crossed.
*
* By default they flip when the handle is released.
const GlyphInfo& glyph = *glyphsBuffer;
float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing : 0.f;
- penX += mCursorWidth; // Added to give some space to the cursor.
for( GlyphIndex i = 0u; i < numberOfGlyphs; ++i )
{
const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing : 0.f;
- penX += mCursorWidth; // Added to give some space to the cursor.
Vector2* glyphPositionsBuffer = glyphPositions.Begin();
if( mEventData->mUpdateCursorPosition )
{
// Updates the cursor position and scrolls the text to make it visible.
-
- UpdateCursorPosition();
+ CursorInfo cursorInfo;
+ GetCursorPosition( mEventData->mPrimaryCursorPosition,
+ cursorInfo );
if( mEventData->mScrollAfterUpdatePosition )
{
- const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
-
- ScrollToMakePositionVisible( primaryCursorPosition );
+ ScrollToMakePositionVisible( cursorInfo.primaryPosition );
mEventData->mScrollAfterUpdatePosition = false;
}
+ else if( mEventData->mScrollAfterDelete )
+ {
+ ScrollTextToMatchCursor( cursorInfo );
+ mEventData->mScrollAfterDelete = false;
+ }
+
+ UpdateCursorPosition( cursorInfo );
mEventData->mDecoratorUpdated = true;
mEventData->mUpdateCursorPosition = false;
}
- else if( mEventData->mScrollAfterDelete )
- {
- ScrollTextToMatchCursor();
- mEventData->mDecoratorUpdated = true;
- mEventData->mScrollAfterDelete = false;
- }
else
{
bool leftScroll = false;
bool rightScroll = false;
+ CursorInfo leftHandleInfo;
+ CursorInfo rightHandleInfo;
+
if( mEventData->mUpdateLeftSelectionPosition )
{
- UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
+ GetCursorPosition( mEventData->mLeftSelectionPosition,
+ leftHandleInfo );
if( mEventData->mScrollAfterUpdatePosition )
{
- const Vector2& leftHandlePosition = mEventData->mDecorator->GetPosition( LEFT_SELECTION_HANDLE );
-
- ScrollToMakePositionVisible( leftHandlePosition );
+ ScrollToMakePositionVisible( leftHandleInfo.primaryPosition );
leftScroll = true;
}
-
- SetPopupButtons();
- mEventData->mDecoratorUpdated = true;
- mEventData->mUpdateLeftSelectionPosition = false;
}
if( mEventData->mUpdateRightSelectionPosition )
{
- UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+ GetCursorPosition( mEventData->mRightSelectionPosition,
+ rightHandleInfo );
if( mEventData->mScrollAfterUpdatePosition )
{
- const Vector2& rightHandlePosition = mEventData->mDecorator->GetPosition( RIGHT_SELECTION_HANDLE );
-
- ScrollToMakePositionVisible( rightHandlePosition );
+ ScrollToMakePositionVisible( rightHandleInfo.primaryPosition );
rightScroll = true;
}
+ }
+
+ if( mEventData->mUpdateLeftSelectionPosition )
+ {
+ UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
+ leftHandleInfo );
SetPopupButtons();
mEventData->mDecoratorUpdated = true;
+ }
+
+ if( mEventData->mUpdateRightSelectionPosition )
+ {
+ UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
+ rightHandleInfo );
+
+ SetPopupButtons();
+ mEventData->mDecoratorUpdated = true;
+ }
+
+ if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+ {
+ RepositionSelectionHandles();
+
+ mEventData->mUpdateLeftSelectionPosition = false;
mEventData->mUpdateRightSelectionPosition = false;
}
{
mEventData->mLeftSelectionPosition = handleNewPosition;
- RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
- mEventData->mRightSelectionPosition );
-
mEventData->mUpdateLeftSelectionPosition = true;
}
}
{
mEventData->mRightSelectionPosition = handleNewPosition;
- RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
- mEventData->mRightSelectionPosition );
-
mEventData->mUpdateRightSelectionPosition = true;
}
}
if( mEventData->mUpdateLeftSelectionPosition )
{
mEventData->mLeftSelectionPosition = handlePosition;
-
- RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
- mEventData->mRightSelectionPosition );
}
}
}
if( mEventData->mUpdateRightSelectionPosition )
{
mEventData->mRightSelectionPosition = handlePosition;
- RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
- mEventData->mRightSelectionPosition );
}
}
}
if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
{
- RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
- mEventData->mRightSelectionPosition );
+ RepositionSelectionHandles();
mEventData->mScrollAfterUpdatePosition = true;
}
const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
- const CharacterIndex leftPosition = mEventData->mLeftSelectionPosition;
- const CharacterIndex rightPosition = mEventData->mRightSelectionPosition;
-
+ // Calculates the logical position from the x,y coords.
RepositionSelectionHandles( xPosition,
yPosition );
- mEventData->mUpdateLeftSelectionPosition = leftPosition != mEventData->mLeftSelectionPosition;
- mEventData->mUpdateRightSelectionPosition = rightPosition != mEventData->mRightSelectionPosition;
+ mEventData->mUpdateLeftSelectionPosition = true;
+ mEventData->mUpdateRightSelectionPosition = true;
- mEventData->mScrollAfterUpdatePosition = ( ( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition ) &&
- ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ) );
+ mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
}
}
if( mEventData->mSelectionEnabled )
{
- RepositionSelectionHandles( 0u,
- mLogicalModel->mText.Count() );
+ mEventData->mLeftSelectionPosition = 0u;
+ mEventData->mRightSelectionPosition = mLogicalModel->mText.Count();
mEventData->mScrollAfterUpdatePosition = true;
mEventData->mUpdateLeftSelectionPosition = true;
Vector<Character>::Iterator first = currentText.Begin() + startOfSelectedText;
Vector<Character>::Iterator last = first + lengthOfSelectedText;
currentText.Erase( first, last );
+
+ // Scroll after delete.
+ mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+ mEventData->mScrollAfterDelete = true;
}
- mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
- mEventData->mScrollAfterDelete = true;
+ // Udpade the cursor position and the decorator.
+ // Scroll after the position is updated if is not scrolling after delete.
+ mEventData->mUpdateCursorPosition = true;
+ mEventData->mScrollAfterUpdatePosition = !mEventData->mScrollAfterDelete;
mEventData->mDecoratorUpdated = true;
}
}
}
}
-void Controller::Impl::RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd )
+void Controller::Impl::RepositionSelectionHandles()
{
+ CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
+ CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
+
if( selectionStart == selectionEnd )
{
// Nothing to select if handles are in the same place.
mEventData->mDecorator->ClearHighlights();
- mEventData->mLeftSelectionPosition = selectionStart;
- mEventData->mRightSelectionPosition = selectionEnd;
-
const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
const GlyphInfo* const glyphsBuffer = mVisualModel->mGlyphs.Begin();
return;
}
- RepositionSelectionHandles( selectionStart, selectionEnd );
+ mEventData->mLeftSelectionPosition = selectionStart;
+ mEventData->mRightSelectionPosition = selectionEnd;
}
void Controller::Impl::SetPopupButtons()
TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
- if ( ( EventData::SELECTING == mEventData->mState ) || ( EventData::SELECTION_CHANGED == mEventData->mState ) )
+ if( EventData::SELECTING == mEventData->mState )
{
buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::CUT | TextSelectionPopup::COPY );
}
mEventData->mDecoratorUpdated = true;
}
- else if ( EventData::SELECTION_CHANGED == mEventData->mState )
- {
- if( mEventData->mGrabHandlePopupEnabled )
- {
- SetPopupButtons();
- mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
- mEventData->mDecorator->SetPopupActive( true );
- }
- mEventData->mDecoratorUpdated = true;
- }
else if( EventData::EDITING == mEventData->mState )
{
mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
{
// TODO: Check for multiline with \n, etc...
- // Check if the logical position is the first or the last one of the text.
- const bool isFirstPosition = 0u == logical;
- const bool isLastPosition = mLogicalModel->mText.Count() == logical;
-
- if( isFirstPosition && isLastPosition )
+ const Length numberOfCharacters = mLogicalModel->mText.Count();
+ if( !IsShowingRealText() )
{
- // There is zero characters. Get the default font's line height.
+ // Do not want to use the place-holder text to set the cursor position.
+
+ // Use the line's height of the font's family set to set the cursor's size.
+ // If there is no font's family set, use the default font.
+ // Use the current alignment to place the cursor at the beginning, center or end of the box.
+
cursorInfo.lineHeight = GetDefaultFontLineHeight();
cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
- cursorInfo.primaryPosition.x = 0.f;
- cursorInfo.primaryPosition.y = 0.f;
+ switch( mLayoutEngine.GetHorizontalAlignment() )
+ {
+ case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
+ {
+ cursorInfo.primaryPosition.x = 0.f;
+ break;
+ }
+ case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
+ {
+ cursorInfo.primaryPosition.x = floorf( 0.5f * mVisualModel->mControlSize.width );
+ break;
+ }
+ case LayoutEngine::HORIZONTAL_ALIGN_END:
+ {
+ cursorInfo.primaryPosition.x = mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+ break;
+ }
+ }
+
+ switch( mLayoutEngine.GetVerticalAlignment() )
+ {
+ case LayoutEngine::VERTICAL_ALIGN_TOP:
+ {
+ cursorInfo.primaryPosition.y = 0.f;
+ break;
+ }
+ case LayoutEngine::VERTICAL_ALIGN_CENTER:
+ {
+ cursorInfo.primaryPosition.y = floorf( 0.5f * ( mVisualModel->mControlSize.height - cursorInfo.lineHeight ) );
+ break;
+ }
+ case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
+ {
+ cursorInfo.primaryPosition.y = mVisualModel->mControlSize.height - cursorInfo.lineHeight;
+ break;
+ }
+ }
// Nothing else to do.
return;
}
+ // Check if the logical position is the first or the last one of the text.
+ const bool isFirstPosition = 0u == logical;
+ const bool isLastPosition = numberOfCharacters == logical;
+
// 'logical' is the logical 'cursor' index.
// Get the next and current logical 'character' index.
const CharacterIndex nextCharacterIndex = logical;
return cursorIndex;
}
-void Controller::Impl::UpdateCursorPosition()
+void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
if( NULL == mEventData )
return;
}
- if( IsShowingPlaceholderText() || ( 0u == mLogicalModel->mText.Count() ) )
- {
- // Do not want to use the place-holder text to set the cursor position.
-
- // Use the line's height of the font's family set to set the cursor's size.
- // If there is no font's family set, use the default font.
- // Use the current alignment to place the cursor at the beginning, center or end of the box.
-
- float lineHeight = 0.f;
-
- FontId defaultFontId = 0u;
- if( NULL == mFontDefaults )
- {
- TextAbstraction::FontDescription fontDescription;
- defaultFontId = mFontClient.GetFontId( fontDescription );
- }
- else
- {
- defaultFontId = mFontDefaults->GetFontId( mFontClient );
- }
-
- Text::FontMetrics fontMetrics;
- mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
-
- lineHeight = fontMetrics.ascender - fontMetrics.descender;
-
-
- Vector2 cursorPosition;
+ const Vector2 offset = mEventData->mScrollPosition + ( IsShowingRealText() ? mAlignmentOffset : Vector2::ZERO );
+ const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
- switch( mLayoutEngine.GetHorizontalAlignment() )
- {
- case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
- {
- cursorPosition.x = 0.f;
- break;
- }
- case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
- {
- cursorPosition.x = floor( 0.5f * mVisualModel->mControlSize.width );
- break;
- }
- case LayoutEngine::HORIZONTAL_ALIGN_END:
- {
- cursorPosition.x = mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
- break;
- }
- }
+ // Sets the cursor position.
+ mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+ cursorPosition.x,
+ cursorPosition.y,
+ cursorInfo.primaryCursorHeight,
+ cursorInfo.lineHeight );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
- switch( mLayoutEngine.GetVerticalAlignment() )
- {
- case LayoutEngine::VERTICAL_ALIGN_TOP:
- {
- cursorPosition.y = 0.f;
- break;
- }
- case LayoutEngine::VERTICAL_ALIGN_CENTER:
- {
- cursorPosition.y = floorf( 0.5f * ( mVisualModel->mControlSize.height - lineHeight ) );
- break;
- }
- case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
- {
- cursorPosition.y = mVisualModel->mControlSize.height - lineHeight;
- break;
- }
- }
+ // Sets the grab handle position.
+ mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+ cursorPosition.x,
+ cursorPosition.y,
+ cursorInfo.lineHeight );
- mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
- cursorPosition.x,
- cursorPosition.y,
- lineHeight,
- lineHeight );
- }
- else
+ if( cursorInfo.isSecondaryCursor )
{
- CursorInfo cursorInfo;
- GetCursorPosition( mEventData->mPrimaryCursorPosition,
- cursorInfo );
-
- const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
- const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
-
- // Sets the cursor position.
- mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
- cursorPosition.x,
- cursorPosition.y,
- cursorInfo.primaryCursorHeight,
- cursorInfo.lineHeight );
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
-
- // Sets the grab handle position.
- mEventData->mDecorator->SetPosition( GRAB_HANDLE,
- cursorPosition.x,
- cursorPosition.y,
+ mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+ cursorInfo.secondaryPosition.x + offset.x,
+ cursorInfo.secondaryPosition.y + offset.y,
+ cursorInfo.secondaryCursorHeight,
cursorInfo.lineHeight );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
+ }
+ // Set which cursors are active according the state.
+ if( ( EventData::EDITING == mEventData->mState ) ||
+ ( EventData::EDITING_WITH_POPUP == mEventData->mState ) ||
+ ( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState ) ||
+ ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
+ {
if( cursorInfo.isSecondaryCursor )
{
mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
- mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
- cursorInfo.secondaryPosition.x + offset.x,
- cursorInfo.secondaryPosition.y + offset.y,
- cursorInfo.secondaryCursorHeight,
- cursorInfo.lineHeight );
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
}
else
{
mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
}
}
+ else
+ {
+ mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+ }
+
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
}
-void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
+void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
+ const CursorInfo& cursorInfo )
{
if( ( LEFT_SELECTION_HANDLE != handleType ) &&
( RIGHT_SELECTION_HANDLE != handleType ) )
return;
}
- const bool leftSelectionHandle = LEFT_SELECTION_HANDLE == handleType;
- const CharacterIndex index = leftSelectionHandle ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
-
- CursorInfo cursorInfo;
- GetCursorPosition( index,
- cursorInfo );
-
- const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
- const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+ const Vector2 cursorPosition = cursorInfo.primaryPosition + mEventData->mScrollPosition + mAlignmentOffset;
// Sets the grab handle position.
mEventData->mDecorator->SetPosition( handleType,
void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
{
// Clamp between -space & 0 (and the text alignment).
+
if( actualSize.width > mVisualModel->mControlSize.width )
{
const float space = ( actualSize.width - mVisualModel->mControlSize.width ) + mAlignmentOffset.x;
void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position )
{
- Vector2 offset;
- bool updateDecorator = false;
- if( position.x < 0.f )
- {
- offset.x = -position.x;
- mEventData->mScrollPosition.x += offset.x;
- updateDecorator = true;
- }
- else if( position.x > mVisualModel->mControlSize.width )
+ // position is in actor's coords.
+ const float positionEnd = position.x + ( mEventData->mDecorator ? mEventData->mDecorator->GetCursorWidth() : 0.f );
+
+ // Transform the position to decorator coords.
+ const float offset = mEventData->mScrollPosition.x + mAlignmentOffset.x;
+ const float decoratorPositionBegin = position.x + offset;
+ const float decoratorPositionEnd = positionEnd + offset;
+
+ if( decoratorPositionBegin < 0.f )
{
- offset.x = mVisualModel->mControlSize.width - position.x;
- mEventData->mScrollPosition.x += offset.x;
- updateDecorator = true;
+ mEventData->mScrollPosition.x = -position.x - mAlignmentOffset.x;
}
-
- if( updateDecorator && mEventData->mDecorator )
+ else if( decoratorPositionEnd > mVisualModel->mControlSize.width )
{
- mEventData->mDecorator->UpdatePositions( offset );
+ mEventData->mScrollPosition.x = mVisualModel->mControlSize.width - positionEnd - mAlignmentOffset.x;
}
-
- // TODO : calculate the vertical scroll.
}
-void Controller::Impl::ScrollTextToMatchCursor()
+void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
{
// Get the current cursor position in decorator coords.
const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
- // Calculate the new cursor position.
- CursorInfo cursorInfo;
- GetCursorPosition( mEventData->mPrimaryCursorPosition,
- cursorInfo );
-
// Calculate the offset to match the cursor position before the character was deleted.
mEventData->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x - mAlignmentOffset.x;
ClampHorizontalScroll( mVisualModel->GetActualSize() );
-
- const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
- const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
-
- // Sets the cursor position.
- mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
- cursorPosition.x,
- cursorPosition.y,
- cursorInfo.primaryCursorHeight,
- cursorInfo.lineHeight );
-
- // Sets the grab handle position.
- mEventData->mDecorator->SetPosition( GRAB_HANDLE,
- cursorPosition.x,
- cursorPosition.y,
- cursorInfo.lineHeight );
-
- if( cursorInfo.isSecondaryCursor )
- {
- mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
- cursorInfo.secondaryPosition.x + offset.x,
- cursorInfo.secondaryPosition.y + offset.y,
- cursorInfo.secondaryCursorHeight,
- cursorInfo.lineHeight );
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
- }
-
- // Set which cursors are active according the state.
- if( ( EventData::EDITING == mEventData->mState ) ||
- ( EventData::EDITING_WITH_POPUP == mEventData->mState ) ||
- ( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState ) ||
- ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
- {
- if( cursorInfo.isSecondaryCursor )
- {
- mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
- }
- else
- {
- mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
- }
- }
- else
- {
- mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
- }
}
void Controller::Impl::RequestRelayout()
INACTIVE,
INTERRUPTED,
SELECTING,
- SELECTION_CHANGED,
EDITING,
EDITING_WITH_POPUP,
EDITING_WITH_GRAB_HANDLE,
void GetTextFromClipboard( unsigned int itemIndex, std::string& retreivedString );
- void RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd );
+ void RepositionSelectionHandles();
void RepositionSelectionHandles( float visualX, float visualY );
void SetPopupButtons();
/**
* @brief Updates the cursor position.
*
- * Retrieves the x,y position of the cursor logical position and sets it into the decorator.
+ * Sets the cursor's position into the decorator. It transforms the cursor's position into decorator's coords.
* It sets the position of the secondary cursor if it's a valid one.
* Sets which cursors are active.
+ *
+ * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
+ *
*/
- void UpdateCursorPosition();
+ void UpdateCursorPosition( const CursorInfo& cursorInfo );
/**
- * @brief Updates the position of the given selection handle.
+ * @brief Updates the position of the given selection handle. It transforms the handle's position into decorator's coords.
*
* @param[in] handleType One of the selection handles.
+ * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
*/
- void UpdateSelectionHandle( HandleType handleType );
+ void UpdateSelectionHandle( HandleType handleType,
+ const CursorInfo& cursorInfo );
/**
* @biref Clamps the horizontal scrolling to get the control always filled with text.
*
* This method is called after deleting text.
*/
- void ScrollTextToMatchCursor();
+ void ScrollTextToMatchCursor( const CursorInfo& cursorInfo);
ControlInterface& mControlInterface; ///< Reference to the text controller.
LogicalModelPtr mLogicalModel; ///< Pointer to the logical model.
{
// If popup shown then hide it by switching to Editing state
if( ( EventData::SELECTING == mImpl->mEventData->mState ) ||
- ( EventData::SELECTION_CHANGED == mImpl->mEventData->mState ) ||
( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
{
return glyphsRemoved;
}
- if( size != mImpl->mVisualModel->mControlSize )
+ const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
+
+ if( newSize )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
// Do not re-do any operation until something changes.
mImpl->mOperationsPending = NO_OPERATION;
- // Keep the current offset and alignment as it will be used to update the decorator's positions.
+ // Keep the current offset and alignment as it will be used to update the decorator's positions (if the size changes).
Vector2 offset;
- if( mImpl->mEventData )
+ if( newSize && mImpl->mEventData )
{
offset = mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition;
}
if( mImpl->mEventData )
{
- // If there is a nex size, the scroll position needs to be clamped.
- mImpl->ClampHorizontalScroll( layoutSize );
+ if( newSize )
+ {
+ // If there is a new size, the scroll position needs to be clamped.
+ mImpl->ClampHorizontalScroll( layoutSize );
- // Update the decorator's positions.
- mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
+ // Update the decorator's positions is needed if there is a new size.
+ mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
+ }
// Move the cursor, grab handle etc.
updated = mImpl->ProcessInputEvents() || updated;
REORDER );
// Queue a cursor reposition event; this must wait until after DoRelayout()
- if( 0u == mImpl->mLogicalModel->mText.Count() )
- {
- mImpl->mEventData->mUpdateCursorPosition = true;
- }
- else
+ mImpl->mEventData->mUpdateCursorPosition = true;
+ if( 0u != mImpl->mLogicalModel->mText.Count() )
{
mImpl->mEventData->mScrollAfterDelete = true;
}
}
case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
{
- const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
- mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
+ mImpl->mAlignmentOffset.x = floorf( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
break;
}
case LayoutEngine::HORIZONTAL_ALIGN_END:
}
case LayoutEngine::VERTICAL_ALIGN_CENTER:
{
- const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
- mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
+ mImpl->mAlignmentOffset.y = floorf( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
break;
}
case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
{
bool textRemoved( false );
- if ( EventData::SELECTING == mImpl->mEventData->mState ||
- EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
+ if( EventData::SELECTING == mImpl->mEventData->mState )
{
std::string removedString;
mImpl->RetrieveSelection( removedString, true );
{
if( mImpl->mEventData )
{
- if ( mImpl->mEventData->mState == EventData::SELECTING )
- {
- mImpl->ChangeState( EventData::SELECTION_CHANGED );
- }
- else
- {
- mImpl->ChangeState( EventData::SELECTING );
- }
+ mImpl->ChangeState( EventData::SELECTING );
if( selectAll )
{
bool removed( false );
- if ( EventData::SELECTING == mImpl->mEventData->mState ||
- EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
+ if( EventData::SELECTING == mImpl->mEventData->mState )
{
removed = RemoveSelectedText();
}
const unsigned int TOOLKIT_MAJOR_VERSION = 1;
const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 5;
+const unsigned int TOOLKIT_MICRO_VERSION = 6;
const char * const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
"secondary-cursor-color":[0.0,0.72,0.9,1.0],
"cursor-width":1,
"selection-highlight-color":[0.75,0.96,1.0,1.0],
- "grab-handle-image": { "filename":"{DALI_IMAGE_DIR}cursor_handler_center.png" },
- "selection-handle-image-left" : {"filename":"{DALI_IMAGE_DIR}selection_handle_left.png" },
- "selection-handle-image-right": {"filename":"{DALI_IMAGE_DIR}selection_handle_right.png" },
- "selection-handle-marker-image-left":{ "filename":"{DALI_IMAGE_DIR}selection_marker_left.png" },
- "selection-handle-marker-image-right":{ "filename":"{DALI_IMAGE_DIR}selection_marker_right.png" }
+ "grab-handle-image" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+ "selection-handle-image-left" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+ "selection-handle-image-right": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
},
"textfield-font-size-0":
"secondary-cursor-color":[0.0,0.72,0.9,1.0],
"cursor-width":3,
"selection-highlight-color":[0.75,0.96,1.0,1.0],
- "grab-handle-image": { "filename":"{DALI_IMAGE_DIR}cursor_handler_center.png" },
- "selection-handle-image-left" : {"filename":"{DALI_IMAGE_DIR}selection_handle_left.png" },
- "selection-handle-image-right": {"filename":"{DALI_IMAGE_DIR}selection_handle_right.png" },
- "selection-handle-marker-image-left":{ "filename":"{DALI_IMAGE_DIR}selection_marker_left.png" },
- "selection-handle-marker-image-right":{ "filename":"{DALI_IMAGE_DIR}selection_marker_right.png" }
+ "grab-handle-image" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+ "selection-handle-image-left" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+ "selection-handle-image-right": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
},
"textfield-font-size-0":
dali_toolkit_style_files =\
$(toolkit_styles_dir)/*.json
+
+dali_toolkit_style_images =\
+ $(toolkit_style_images_dir)/*.png
+ [Relative To Constraint](@ref constraints-relative-to)
+ [Multi-threading Notes](@ref animation-multi-threading-notes)
+ [Shader Animation](@ref animation-shader)
+ + [Styling](@ref styling)
### Resources
+ [Resource Image](@ref resource-image)
--- /dev/null
+/*! \page styling Styling
+ *
+@section styling-controls Styling Controls
+
+DALi Controls can be styled to look and behaviour differently.
+
+There are 2 ways to style a control, 1 is recommended.
+
+1) json markup in one of the style files.
+
+~~~
+ ...
+ "control":
+ {
+ "filename":"{IMAGES}file_name.png"
+ },
+ ...
+~~~
+
+or 2) via code using SetProperty
+
+@code
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+control.SetProperty( Control::BACKGROUND, "file_name.png" );
+@endcode
+
+By setting the properties in the json file and not in code it prevents the need to edit code and recompile if changes required.
+
+In the example above, if the png file needs to be changed, method 1 only requires the json file to be changed and no actual code change.
+
+@section choosing-style-at-build Choosing Style files at build time
+
+When building for a target, a style selector should be specified.
+
+The selectors are resolution biased e.g; 720 and 480.
+
+Below can be added to configure to select a style
+
+@code
+./configure --with-style=480
+@endcode
+
+@code
+./configure --with-style=720
+@endcode
+
+
+or for gbs the below define added to the build command
+
+@code
+--define "dali_style 480x800"
+@endcode
+
+@section resources-for-styling Style specific resources
+
+Each style selector can have resource folders associated with it.
+
+Images for that style should be in their own folder named images.
+
+Common images not specific for a particular style will be in the dali-toolkit common images folder.
+*
+*/
Name: dali-toolkit
Summary: The OpenGLES Canvas Core Library Toolkit
-Version: 1.1.5
+Version: 1.1.6
Release: 1
Group: System/Libraries
License: Apache-2.0, BSD-2.0, MIT