From d875cacd691538e371c1b3f575b85675be922d6b Mon Sep 17 00:00:00 2001 From: "dongsug.song" Date: Tue, 15 Nov 2016 14:08:11 +0900 Subject: [PATCH] Revert "[3.0] Added bubble effect back in dali-demo (+visual changes)" This reverts commit b4aed990f90ddd8f69a765effbb911b6c800c30f. Change-Id: I278fb1f3db6b81eaf9424004fa248f546856eef0 --- demo/dali-table-view.cpp | 462 ++++++--------------------- demo/dali-table-view.h | 99 +----- resources/images/demo-tile-texture.9.png | Bin 22266 -> 0 bytes resources/images/item-background-alpha.9.png | Bin 0 -> 254 bytes resources/images/item-background.9.png | Bin 672 -> 489 bytes 5 files changed, 100 insertions(+), 461 deletions(-) delete mode 100644 resources/images/demo-tile-texture.9.png create mode 100644 resources/images/item-background-alpha.9.png diff --git a/demo/dali-table-view.cpp b/demo/dali-table-view.cpp index 827b665..6d23833 100644 --- a/demo/dali-table-view.cpp +++ b/demo/dali-table-view.cpp @@ -25,12 +25,9 @@ #include #include #include -#include -#include // INTERNAL INCLUDES #include "shared/view.h" -#include "shared/utility.h" using namespace Dali; using namespace Dali::Toolkit; @@ -41,11 +38,14 @@ namespace { const std::string LOGO_PATH( DEMO_IMAGE_DIR "Logo-for-demo.png" ); +const std::string DEFAULT_TOOLBAR_IMAGE_PATH( DEMO_IMAGE_DIR "top-bar.png" ); const std::string TILE_BACKGROUND(DEMO_IMAGE_DIR "item-background.9.png"); -const std::string TILE_BACKGROUND_ALPHA( DEMO_IMAGE_DIR "demo-tile-texture.9.png" ); +const std::string TILE_BACKGROUND_ALPHA(DEMO_IMAGE_DIR "item-background-alpha.9.png"); -const float TILE_LABEL_PADDING = 8.0f; ///< Border between edge of tile and the example text -const float BUTTON_PRESS_ANIMATION_TIME = 0.35f; ///< Time to perform button scale effect. +const char * const DEFAULT_TOOLBAR_TEXT( "TOUCH TO LAUNCH EXAMPLE" ); + +const Vector4 TILE_COLOR( 0.5f, 0.6f, 0.8f, 0.23f ); ///< Color (including alpha) of tile contents. +const float BUTTON_PRESS_ANIMATION_TIME = 0.25f; ///< Time to perform button scale effect. const float ROTATE_ANIMATION_TIME = 0.5f; ///< Time to perform rotate effect. const int MAX_PAGES = 256; ///< Maximum pages (arbitrary safety limit) const int EXAMPLES_PER_ROW = 3; @@ -53,62 +53,8 @@ const int ROWS_PER_PAGE = 3; const int EXAMPLES_PER_PAGE = EXAMPLES_PER_ROW * ROWS_PER_PAGE; const float LOGO_MARGIN_RATIO = 0.1f / 0.3f; const float BOTTOM_PADDING_RATIO = 0.4f / 0.9f; -const Vector3 SCROLLVIEW_RELATIVE_SIZE(0.9f, 1.0f, 0.8f ); ///< ScrollView's relative size to its parent +const Vector3 SCROLLVIEW_RELATIVE_SIZE(0.9f, 1.0f, 0.8f ); ///< ScrollView's relative size to its parent const Vector3 TABLE_RELATIVE_SIZE(0.95f, 0.9f, 0.8f ); ///< TableView's relative size to the entire stage. The Y value means sum of the logo and table relative heights. -const float STENCIL_RELATIVE_SIZE = 1.0f; - -const float EFFECT_SNAP_DURATION = 0.66f; ///< Scroll Snap Duration for Effects -const float EFFECT_FLICK_DURATION = 0.5f; ///< Scroll Flick Duration for Effects -const Vector3 ANGLE_CUBE_PAGE_ROTATE(Math::PI * 0.5f, Math::PI * 0.5f, 0.0f); -const Vector4 TILE_COLOR( 0.4f, 0.6f, 0.9f, 0.6f ); - -const Vector4 BUBBLE_COLOR[] = -{ - Vector4( 0.3255f, 0.3412f, 0.6353f, 0.32f ), - Vector4( 0.3647f, 0.7569f, 0.8157f, 0.32f ), - Vector4( 0.3804f, 0.7412f, 0.6510f, 0.32f ), - Vector4( 1.f, 1.f, 1.f, 0.13f ) -}; -const int NUMBER_OF_BUBBLE_COLOR( sizeof(BUBBLE_COLOR) / sizeof(BUBBLE_COLOR[0]) ); - -const int NUM_BACKGROUND_IMAGES = 18; -const float BACKGROUND_SWIPE_SCALE = 0.025f; -const float BACKGROUND_SPREAD_SCALE = 1.5f; -const float SCALE_MOD = 1000.0f * Math::PI * 2.0f; -const float SCALE_SPEED = 10.0f; -const float SCALE_SPEED_SIN = 0.1f; - -const unsigned int BACKGROUND_ANIMATION_DURATION = 15000; // 15 secs - -const Vector4 BACKGROUND_COLOR( 0.3569f, 0.5451f, 0.7294f, 1.0f ); - -const float BUBBLE_MIN_Z = -1.0; -const float BUBBLE_MAX_Z = 0.0f; - -// This shader takes a texture. -// An alpha discard is performed. -// The shader uses the tiles position within the scroll-view page and the scroll-views rotation position to create a parallax effect. -const char* FRAGMENT_SHADER_TEXTURED = DALI_COMPOSE_SHADER( - varying mediump vec2 vTexCoord; - varying mediump vec3 vIllumination; - uniform lowp vec4 uColor; - uniform sampler2D sTexture; - uniform mediump vec3 uCustomPosition; - - void main() - { - if( texture2D( sTexture, vTexCoord ).a <= 0.0001 ) - { - discard; - } - - mediump vec2 wrapTexCoord = vec2( ( vTexCoord.x / 4.0 ) + ( uCustomPosition.x / 4.0 ) + ( uCustomPosition.z / 2.0 ), vTexCoord.y / 4.0 ); - mediump vec4 color = texture2D( sTexture, wrapTexCoord ); - mediump float positionWeight = ( uCustomPosition.y + 0.3 ) * color.r * 2.0; - - gl_FragColor = vec4( positionWeight, positionWeight, positionWeight, 0.9 ) * uColor + vec4( uColor.xyz, 0.0 ); - } -); /** * Creates the background image @@ -117,81 +63,15 @@ Control CreateBackground( std::string stylename ) { Control background = Control::New(); Stage::GetCurrent().Add( background ); - background.SetStyleName( stylename ); + background.SetProperty( Control::Property::STYLE_NAME,stylename); background.SetName( "BACKGROUND" ); background.SetAnchorPoint( AnchorPoint::CENTER ); background.SetParentOrigin( ParentOrigin::CENTER ); background.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + return background; } -/** - * Constraint to return a position for a bubble based on the scroll value and vertical wrapping - */ -struct AnimateBubbleConstraint -{ -public: - AnimateBubbleConstraint( const Vector3& initialPos, float scale ) - : mInitialX( initialPos.x ), - mScale( scale ) - { - } - - void operator()( Vector3& position, const PropertyInputContainer& inputs ) - { - const Vector3& parentSize = inputs[1]->GetVector3(); - const Vector3& childSize = inputs[2]->GetVector3(); - - // Wrap bubbles vertically. - float range = parentSize.y + childSize.y; - // This performs a float mod (we don't use fmod as we want the arithmetic modulus as opposed to the remainder). - position.y -= range * ( floor( position.y / range ) + 0.5f ); - - // Bubbles X position moves parallax to horizontal - // panning by a scale factor unique to each bubble. - position.x = mInitialX + ( inputs[0]->GetVector2().x * mScale ); - } - -private: - float mInitialX; - float mScale; -}; - -/** - * Constraint to precalculate values from the scroll-view - * and tile positions to pass to the tile shader. - */ -struct TileShaderPositionConstraint -{ - TileShaderPositionConstraint( float pageWidth, float tileXOffset ) - : mPageWidth( pageWidth ), - mTileXOffset( tileXOffset ) - { - } - - void operator()( Vector3& position, const PropertyInputContainer& inputs ) - { - // Set up position.x as the tiles X offset (0.0 -> 1.0). - position.x = mTileXOffset; - // Set up position.z as the linear scroll-view X offset (0.0 -> 1.0). - position.z = 1.0f * ( -fmod( inputs[0]->GetVector2().x, mPageWidth ) / mPageWidth ); - // Set up position.y as a rectified version of the scroll-views X offset. - // IE. instead of 0.0 -> 1.0, it moves between 0.0 -> 0.5 -> 0.0 within the same span. - if( position.z > 0.5f ) - { - position.y = 1.0f - position.z; - } - else - { - position.y = position.z; - } - } - -private: - float mPageWidth; - float mTileXOffset; -}; - bool CompareByTitle( const Example& lhs, const Example& rhs ) { return lhs.title < rhs.title; @@ -201,24 +81,23 @@ bool CompareByTitle( const Example& lhs, const Example& rhs ) DaliTableView::DaliTableView( Application& application ) : mApplication( application ), + mBackgroundLayer(), mRootActor(), mRotateAnimation(), mPressedAnimation(), + mScrollViewLayer(), mScrollView(), mScrollViewEffect(), mScrollRulerX(), mScrollRulerY(), mPressedActor(), - mAnimationTimer(), mLogoTapDetector(), mVersionPopup(), mPages(), - mBackgroundAnimations(), mExampleList(), mTotalPages(), mScrolling( false ), - mSortAlphabetically( false ), - mBackgroundAnimsPlaying( false ) + mSortAlphabetically( false ) { application.InitSignal().Connect( this, &DaliTableView::Initialize ); } @@ -240,32 +119,60 @@ void DaliTableView::SortAlphabetically( bool sortAlphabetically ) void DaliTableView::Initialize( Application& application ) { Stage::GetCurrent().KeyEventSignal().Connect( this, &DaliTableView::OnKeyEvent ); + const Vector2 stageSize = Stage::GetCurrent().GetSize(); // Background - mRootActor = CreateBackground( "LauncherBackground" ); + Control background = CreateBackground( "launcherbackground" ); + Stage::GetCurrent().Add( background ); + + // Add root actor + mRootActor = TableView::New( 4, 1 ); + mRootActor.SetAnchorPoint( AnchorPoint::CENTER ); + mRootActor.SetParentOrigin( ParentOrigin::CENTER ); + mRootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); Stage::GetCurrent().Add( mRootActor ); + // Toolbar at top + Dali::Toolkit::ToolBar toolbar; + Dali::Layer toolBarLayer = DemoHelper::CreateToolbar(toolbar, + DEFAULT_TOOLBAR_IMAGE_PATH, + DEFAULT_TOOLBAR_TEXT, + DemoHelper::DEFAULT_VIEW_STYLE); + + mRootActor.AddChild( toolBarLayer, TableView::CellPosition( 0, 0 ) ); + mRootActor.SetFitHeight( 0 ); + // Add logo ImageView logo = CreateLogo( LOGO_PATH ); logo.SetName( "LOGO_IMAGE" ); - logo.SetAnchorPoint( AnchorPoint::TOP_CENTER ); - logo.SetParentOrigin( Vector3( 0.5f, 0.1f, 0.5f ) ); logo.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS ); + const float paddingHeight = ( ( 1.f-TABLE_RELATIVE_SIZE.y ) * stageSize.y ); + const float logoMargin = paddingHeight * LOGO_MARGIN_RATIO; // Show version in a popup when log is tapped mLogoTapDetector = TapGestureDetector::New(); mLogoTapDetector.Attach( logo ); mLogoTapDetector.DetectedSignal().Connect( this, &DaliTableView::OnLogoTapped ); - // Scrollview occupying the majority of the screen + const float bottomMargin = paddingHeight * BOTTOM_PADDING_RATIO; + + Alignment alignment = Alignment::New(); + alignment.SetName( "LOGO_ALIGNMENT" ); + alignment.Add( logo ); + alignment.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); + alignment.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT ); + Actor alignmentActor = alignment; + alignmentActor.SetPadding( Padding( 0.0f, 0.0f, logoMargin, logoMargin )); + mRootActor.AddChild( alignment, TableView::CellPosition( 1, 0 ) ); + mRootActor.SetFitHeight( 1 ); + + // scrollview occupying the majority of the screen mScrollView = ScrollView::New(); - mScrollView.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER ); - mScrollView.SetParentOrigin( Vector3( 0.5f, 1.0f - 0.05f, 0.5f ) ); - mScrollView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); - mScrollView.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::HEIGHT ); - mScrollView.SetSizeModeFactor( Vector3( 0.0f, 0.6f, 0.0f ) ); + mScrollView.SetAnchorPoint( AnchorPoint::CENTER ); + mScrollView.SetParentOrigin( ParentOrigin::CENTER ); + mScrollView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); const float buttonsPageMargin = ( 1.0f - TABLE_RELATIVE_SIZE.x ) * 0.5f * stageSize.width; mScrollView.SetPadding( Padding( buttonsPageMargin, buttonsPageMargin, 0.0f, 0.0f ) ); @@ -274,20 +181,23 @@ void DaliTableView::Initialize( Application& application ) mScrollView.ScrollStartedSignal().Connect( this, &DaliTableView::OnScrollStart ); mScrollView.TouchSignal().Connect( this, &DaliTableView::OnScrollTouched ); - mPageWidth = stageSize.width * TABLE_RELATIVE_SIZE.x * 0.5f; + mScrollViewLayer = Layer::New(); - // Populate background and bubbles - needs to be scrollViewLayer so scroll ends show - Actor bubbleContainer = Actor::New(); - bubbleContainer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - bubbleContainer.SetAnchorPoint( AnchorPoint::CENTER ); - bubbleContainer.SetParentOrigin( ParentOrigin::CENTER ); - SetupBackground( bubbleContainer ); + // Disable the depth test for performance + mScrollViewLayer.SetDepthTestDisabled( true ); + mScrollViewLayer.SetAnchorPoint( AnchorPoint::CENTER ); + mScrollViewLayer.SetParentOrigin( ParentOrigin::CENTER ); + mScrollViewLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - mRootActor.Add( logo ); - // We use depth index to bring the logo above the bubbles (as an alternative to creating actors). - logo.GetRendererAt( 0 ).SetProperty( Renderer::Property::DEPTH_INDEX, 30000 ); - mRootActor.Add( bubbleContainer ); - mRootActor.Add( mScrollView ); + Alignment buttonsAlignment = Alignment::New(); + buttonsAlignment.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + buttonsAlignment.Add( mScrollViewLayer ); + + mScrollViewLayer.Add( mScrollView ); + + mRootActor.AddChild( buttonsAlignment, TableView::CellPosition( 2, 0 ) ); + + mRootActor.SetFixedHeight( 3, bottomMargin ); // Add scroll view effect and setup constraints on pages ApplyScrollViewEffect(); @@ -310,12 +220,6 @@ void DaliTableView::Initialize( Application& application ) winHandle.ShowIndicator( Dali::Window::INVISIBLE ); - // Background animation - mAnimationTimer = Timer::New( BACKGROUND_ANIMATION_DURATION ); - mAnimationTimer.TickSignal().Connect( this, &DaliTableView::PauseBackgroundAnimation ); - mAnimationTimer.Start(); - mBackgroundAnimsPlaying = true; - KeyboardFocusManager::Get().PreFocusChangeSignal().Connect( this, &DaliTableView::OnKeyboardPreFocusChange ); KeyboardFocusManager::Get().FocusedActorEnterKeySignal().Connect( this, &DaliTableView::OnFocusedActorActivated ); AccessibilityManager::Get().FocusedActorActivatedSignal().Connect( this, &DaliTableView::OnFocusedActorActivated ); @@ -372,9 +276,7 @@ void DaliTableView::Populate() { const Example& example = ( *iter ); - // Calculate the tiles relative position on the page (between 0 & 1 in each dimension). - Vector2 position( static_cast( column ) / ( EXAMPLES_PER_ROW - 1.0f ), static_cast( row ) / ( EXAMPLES_PER_ROW - 1.0f ) ); - Actor tile = CreateTile( example.name, example.title, Vector3( tileParentMultiplier, tileParentMultiplier, 1.0f ), position ); + Actor tile = CreateTile( example.name, example.title, Vector3( tileParentMultiplier, tileParentMultiplier, 1.0f ), TILE_COLOR ); AccessibilityManager accessibilityManager = AccessibilityManager::Get(); accessibilityManager.SetFocusOrder( tile, ++exampleCount ); accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_LABEL, @@ -384,6 +286,7 @@ void DaliTableView::Populate() "You can run this example" ); tile.SetPadding( Padding( margin, margin, margin, margin ) ); + page.AddChild( tile, TableView::CellPosition( row, column ) ); iter++; @@ -414,7 +317,7 @@ void DaliTableView::Populate() } // Update Ruler info. - mScrollRulerX = new FixedRuler( mPageWidth ); + mScrollRulerX = new FixedRuler( stageSize.width * TABLE_RELATIVE_SIZE.x * 0.5f ); mScrollRulerY = new DefaultRuler(); mScrollRulerX->SetDomain( RulerDomain( 0.0f, (mTotalPages+1) * stageSize.width * TABLE_RELATIVE_SIZE.x * 0.5f, true ) ); mScrollRulerY->Disable(); @@ -445,7 +348,7 @@ void DaliTableView::Rotate( unsigned int degrees ) mRotateAnimation.Play(); } -Actor DaliTableView::CreateTile( const std::string& name, const std::string& title, const Dali::Vector3& sizeMultiplier, Vector2& position ) +Actor DaliTableView::CreateTile( const std::string& name, const std::string& title, const Dali::Vector3& sizeMultiplier, const Dali::Vector4& color ) { Actor content = Actor::New(); content.SetName( name ); @@ -454,53 +357,33 @@ Actor DaliTableView::CreateTile( const std::string& name, const std::string& tit content.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS ); content.SetSizeModeFactor( sizeMultiplier ); - Toolkit::ImageView tileContent = ImageView::New(); - tileContent.SetParentOrigin( ParentOrigin::CENTER ); - tileContent.SetAnchorPoint( AnchorPoint::CENTER ); - tileContent.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - - // Add the image via the property first. - tileContent.SetProperty( Toolkit::ImageView::Property::IMAGE, TILE_BACKGROUND_ALPHA ); - // Register a property with the ImageView. This allows us to inject the scroll-view position into the shader. - Property::Value value = Vector3( 0.0f, 0.0f, 0.0f ); - Property::Index propertyIndex = tileContent.RegisterProperty( "uCustomPosition", value ); - - // Add a shader to the image (details in shader source). - Property::Map map; - Property::Map customShader; - customShader[ Visual::Shader::Property::FRAGMENT_SHADER ] = FRAGMENT_SHADER_TEXTURED; - map[ Visual::Property::SHADER ] = customShader; - tileContent.SetProperty( Toolkit::ImageView::Property::IMAGE, map ); - tileContent.SetColor( TILE_COLOR ); - - // We create a constraint to perform a precalculation on the scroll-view X offset - // and pass it to the shader uniform, along with the tile's position. - Constraint shaderPosition = Constraint::New < Vector3 > ( tileContent, propertyIndex, TileShaderPositionConstraint( mPageWidth, position.x ) ); - shaderPosition.AddSource( Source( mScrollView, ScrollView::Property::SCROLL_POSITION ) ); - shaderPosition.SetRemoveAction( Constraint::Discard ); - shaderPosition.Apply(); - content.Add( tileContent ); - - // Create an ImageView for the 9-patch border around the tile. + // Create background image. ImageView image = ImageView::New( TILE_BACKGROUND ); image.SetAnchorPoint( AnchorPoint::CENTER ); image.SetParentOrigin( ParentOrigin::CENTER ); + // Make the image 100% of tile. image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - image.SetOpacity( 0.8f ); - tileContent.Add( image ); - + content.Add( image ); + + // Create the tile background. + Actor tileBackground = ImageView::New( TILE_BACKGROUND_ALPHA ); + tileBackground.SetParentOrigin( ParentOrigin::CENTER ); + tileBackground.SetAnchorPoint( AnchorPoint::CENTER ); + tileBackground.SetProperty( Actor::Property::COLOR, color ); + Property::Map shaderEffect = CreateAlphaDiscardEffect(); + tileBackground.SetProperty( Toolkit::ImageView::Property::IMAGE, shaderEffect ); + tileBackground.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + image.Add( tileBackground ); + + // Create the tile label. TextLabel label = TextLabel::New(); - label.SetAnchorPoint( AnchorPoint::CENTER ); - label.SetParentOrigin( ParentOrigin::CENTER ); - label.SetStyleName( "LauncherLabel" ); + label.SetAnchorPoint( AnchorPoint::TOP_LEFT ); + label.SetProperty( Control::Property::STYLE_NAME, "launcherlabel" ); label.SetProperty( TextLabel::Property::MULTI_LINE, true ); label.SetProperty( TextLabel::Property::TEXT, title ); label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); label.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" ); label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT ); - - // Pad around the label as its size is the same as the 9-patch border. It will overlap it without padding. - label.SetPadding( Padding( TILE_LABEL_PADDING, TILE_LABEL_PADDING, TILE_LABEL_PADDING, TILE_LABEL_PADDING ) ); content.Add( label ); // Set the tile to be keyboard focusable @@ -556,14 +439,10 @@ bool DaliTableView::DoTilePress( Actor actor, PointState::Type pointState ) // scale the content actor within the Tile, as to not affect the placement within the Table. Actor content = actor.GetChildAt(0); - mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3( 0.7f, 0.7f, 1.0f ), AlphaFunction::EASE_IN_OUT, + mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3( 0.9f, 0.9f, 1.0f ), AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) ); mPressedAnimation.AnimateTo( Property( content, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT, TimePeriod( BUTTON_PRESS_ANIMATION_TIME * 0.5f, BUTTON_PRESS_ANIMATION_TIME * 0.5f ) ); - - // Rotate button on the Y axis when pressed. - mPressedAnimation.AnimateBy( Property( content, Actor::Property::ORIENTATION ), Quaternion( Degree( 0.0f ), Degree( 180.0f ), Degree( 0.0f ) ) ); - mPressedAnimation.Play(); mPressedAnimation.FinishedSignal().Connect( this, &DaliTableView::OnPressedAnimationFinished ); } @@ -593,8 +472,6 @@ void DaliTableView::OnPressedAnimationFinished( Dali::Animation& source ) void DaliTableView::OnScrollStart( const Dali::Vector2& position ) { mScrolling = true; - - PlayAnimation(); } void DaliTableView::OnScrollComplete( const Dali::Vector2& position ) @@ -678,128 +555,6 @@ void DaliTableView::OnKeyEvent( const KeyEvent& event ) } } -void DaliTableView::SetupBackground( Actor bubbleContainer ) -{ - // Create distance field shapes. - BufferImage distanceFields[2]; - Size imageSize( 512, 512 ); - - CreateShapeImage( CIRCLE, imageSize, distanceFields[0] ); - CreateShapeImage( BUBBLE, imageSize, distanceFields[1] ); - - // Add bubbles to the bubbleContainer. - // Note: The bubbleContainer is parented externally to this function. - AddBackgroundActors( bubbleContainer, NUM_BACKGROUND_IMAGES, distanceFields ); -} - -void DaliTableView::InitialiseBackgroundActors( Actor actor ) -{ - // Delete current animations - mBackgroundAnimations.clear(); - - // Create new animations - const Vector3 size = actor.GetTargetSize(); - - for( unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i ) - { - Actor child = actor.GetChildAt( i ); - - // Calculate a random position - Vector3 childPos( Random::Range( -size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.85f * BACKGROUND_SPREAD_SCALE ), - Random::Range( -size.y, size.y ), - Random::Range( BUBBLE_MIN_Z, BUBBLE_MAX_Z ) ); - - child.SetPosition( childPos ); - - // Define bubble horizontal parallax and vertical wrapping - Constraint animConstraint = Constraint::New < Vector3 > ( child, Actor::Property::POSITION, AnimateBubbleConstraint( childPos, Random::Range( -0.85f, 0.25f ) ) ); - animConstraint.AddSource( Source( mScrollView, ScrollView::Property::SCROLL_POSITION ) ); - animConstraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) ); - animConstraint.AddSource( Dali::LocalSource( Dali::Actor::Property::SIZE ) ); - animConstraint.SetRemoveAction( Constraint::Discard ); - animConstraint.Apply(); - - // Kickoff animation - Animation animation = Animation::New( Random::Range( 30.0f, 160.0f ) ); - animation.AnimateBy( Property( child, Actor::Property::POSITION ), Vector3( 0.0f, -2000.0f, 0.0f ), AlphaFunction::LINEAR ); - animation.SetLooping( true ); - animation.Play(); - mBackgroundAnimations.push_back( animation ); - } -} - -void DaliTableView::AddBackgroundActors( Actor layer, int count, BufferImage* distanceField ) -{ - for( int i = 0; i < count; ++i ) - { - float randSize = Random::Range( 10.0f, 400.0f ); - int distanceFieldType = static_cast( Random::Range( 0.0f, 1.0f ) + 0.5f ); - ImageView dfActor = ImageView::New( distanceField[ distanceFieldType ] ); - dfActor.SetSize( Vector2( randSize, randSize ) ); - dfActor.SetParentOrigin( ParentOrigin::CENTER ); - - Dali::Property::Map effect = Toolkit::CreateDistanceFieldEffect(); - dfActor.SetProperty( Toolkit::ImageView::Property::IMAGE, effect ); - dfActor.SetColor( BUBBLE_COLOR[ i%NUMBER_OF_BUBBLE_COLOR ] ); - - layer.Add( dfActor ); - } - - // Positioning will occur when the layer is relaid out - layer.OnRelayoutSignal().Connect( this, &DaliTableView::InitialiseBackgroundActors ); -} - -void DaliTableView::CreateShapeImage( ShapeType shapeType, const Size& size, BufferImage& distanceFieldOut ) -{ - // this bitmap will hold the alpha map for the distance field shader - distanceFieldOut = BufferImage::New( size.width, size.height, Pixel::A8 ); - - // Generate bit pattern - std::vector< unsigned char > imageDataA8; - imageDataA8.reserve( size.width * size.height ); // A8 - - switch( shapeType ) - { - case CIRCLE: - GenerateCircle( size, imageDataA8 ); - break; - case BUBBLE: - GenerateCircle( size, imageDataA8, true ); - break; - default: - break; - } - - PixelBuffer* buffer = distanceFieldOut.GetBuffer(); - if( buffer ) - { - GenerateDistanceFieldMap( &imageDataA8[ 0 ], size, buffer, size, 8.0f, size ); - distanceFieldOut.Update(); - } -} - -void DaliTableView::GenerateCircle( const Size& size, std::vector< unsigned char >& distanceFieldOut, bool hollow ) -{ - const float radius = size.width * 0.5f * size.width * 0.5f; - Vector2 center( size.width / 2, size.height / 2 ); - - for( int h = 0; h < size.height; ++h ) - { - for( int w = 0; w < size.width; ++w ) - { - Vector2 pos( w, h ); - Vector2 dist = pos - center; - - float distance = ( dist.x * dist.x ) + ( dist.y * dist.y ); - - // If hollow, check the distance against a min & max value, otherwise just use the max value. - unsigned char fillByte = ( hollow ? ( ( distance <= radius ) && ( distance > ( radius * 0.7f ) ) ) : ( distance <= radius ) ) ? 0xFF : 0x00; - - distanceFieldOut.push_back( fillByte ); - } - } -} - ImageView DaliTableView::CreateLogo( std::string imagePath ) { ImageView logo = ImageView::New( imagePath ); @@ -810,55 +565,16 @@ ImageView DaliTableView::CreateLogo( std::string imagePath ) return logo; } -bool DaliTableView::PauseBackgroundAnimation() -{ - PauseAnimation(); - - return false; -} - -void DaliTableView::PauseAnimation() -{ - if( mBackgroundAnimsPlaying ) - { - for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter ) - { - Animation anim = *animIter; - - anim.Stop(); - } - - mBackgroundAnimsPlaying = false; - } -} - -void DaliTableView::PlayAnimation() -{ - if ( !mBackgroundAnimsPlaying ) - { - for( AnimationListIter animIter = mBackgroundAnimations.begin(); animIter != mBackgroundAnimations.end(); ++animIter ) - { - Animation anim = *animIter; - - anim.Play(); - } - - mBackgroundAnimsPlaying = true; - } - - mAnimationTimer.SetInterval( BACKGROUND_ANIMATION_DURATION ); -} - Dali::Actor DaliTableView::OnKeyboardPreFocusChange( Dali::Actor current, Dali::Actor proposed, Dali::Toolkit::Control::KeyboardFocus::Direction direction ) { Actor nextFocusActor = proposed; - if( !current && !proposed ) + if ( !current && !proposed ) { // Set the initial focus to the first tile in the current page should be focused. nextFocusActor = mPages[mScrollView.GetCurrentPage()].GetChildAt(0); } - else if( !proposed ) + else if( !proposed || (proposed && proposed == mScrollViewLayer) ) { // ScrollView is being focused but nothing in the current page can be focused further // in the given direction. We should work out which page to scroll to next. @@ -942,11 +658,13 @@ void DaliTableView::OnLogoTapped( Dali::Actor actor, const Dali::TapGesture& tap Toolkit::TextLabel titleActor = Toolkit::TextLabel::New( "Version information" ); titleActor.SetName( "titleActor" ); titleActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); + titleActor.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::WHITE ); Toolkit::TextLabel contentActor = Toolkit::TextLabel::New( stream.str() ); contentActor.SetName( "contentActor" ); contentActor.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true ); contentActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); + contentActor.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::WHITE ); contentActor.SetPadding( Padding( 0.0f, 0.0f, 20.0f, 0.0f ) ); mVersionPopup.SetTitle( titleActor ); diff --git a/demo/dali-table-view.h b/demo/dali-table-view.h index f7785d5..c712a5b 100644 --- a/demo/dali-table-view.h +++ b/demo/dali-table-view.h @@ -1,8 +1,8 @@ -#ifndef __DALI_DEMO_H__ -#define __DALI_DEMO_H__ +#ifndef DALI_DEMO_H +#define DALI_DEMO_H /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -98,15 +98,6 @@ public: private: // Application callbacks & implementation /** - * Shape enum for create function - */ - enum ShapeType - { - CIRCLE, - BUBBLE - }; - - /** * Initialize application. * * @param[in] app Application instance @@ -135,16 +126,16 @@ private: // Application callbacks & implementation void Rotate( unsigned int degrees ); /** - * Creates a tile for the main menu. + * Creates a tile for the main menu and toolbar. * * @param[in] name The unique name for this Tile * @param[in] title The text caption that appears on the Tile * @param[in] parentSize Tile's parent size. - * @param[in] position The tiles relative position within a page + * @param[in] color The color (including alpha) of the tiles contents. * * @return The Actor for the created tile. */ - Dali::Actor CreateTile( const std::string& name, const std::string& title, const Dali::Vector3& sizeMultiplier, Dali::Vector2& position ); + Dali::Actor CreateTile( const std::string& name, const std::string& title, const Dali::Vector3& sizeMultiplier, const Dali::Vector4& color ); // Signal handlers @@ -250,50 +241,6 @@ private: // Application callbacks & implementation void OnKeyEvent( const Dali::KeyEvent& event ); /** - * Create a depth field background - * - * @param[in] bubbleLayer Add the graphics to this layer - */ - void SetupBackground( Dali::Actor bubbleLayer ); - - /** - * Create background actors for the given layer - * - * @param[in] layer The layer to add the actors to - * @param[in] count The number of actors to generate - * @param[in] distanceField A array (pointer) to 2 distance field types to use - */ - void AddBackgroundActors( Dali::Actor layer, int count, Dali::BufferImage* distanceField ); - - /** - * Create a bitmap with the specified shape and also output a distance field - * - * @param[in] shapeType The shape to generate - * @param[in] size The size of the bitmap to create - * @param[out] distanceFieldOut The return depth field alpha map - */ - void CreateShapeImage( ShapeType shapeType, const Dali::Size& size, Dali::BufferImage& distanceFieldOut ); - - /** - * Generate a square bit pattern and depth field - * - * @param[in] size The size of the bitmap to create - * @param[out] imageOut The return bitmap - * @param[out] distanceFieldOut The return depth field alpha map - */ - void GenerateSquare( const Dali::Size& size, std::vector& distanceFieldOut ); - - /** - * Generate a circle bit pattern and depth field - * - * @param[in] size The size of the bitmap to create - * @param[out] imageOut The return bitmap - * @param[out] distanceFieldOut The return depth field alpha map - * @param[in] hollow Optional - Set to true for a thick circle outline without fill - */ - void GenerateCircle( const Dali::Size& size, std::vector& distanceFieldOut, bool hollow = false ); - - /** * Creates the logo. * * @param[in] imagePath The path to the image file to load @@ -303,23 +250,6 @@ private: // Application callbacks & implementation Dali::Toolkit::ImageView CreateLogo( std::string imagePath ); /** - * Timer handler for ending background animation - * - * @return Return value for timer handler - */ - bool PauseBackgroundAnimation(); - - /** - * Pause all animations - */ - void PauseAnimation(); - - /** - * Resume all animations - */ - void PlayAnimation(); - - /** * Callback when the keyboard focus is going to be changed. * * @param[in] current The current focused actor @@ -356,39 +286,30 @@ private: // Application callbacks & implementation */ void OnButtonsPageRelayout( const Dali::Actor& actor ); - /** - * @brief Callback called to set up background actors - * - * @param[in] actor The actor raising the callback - */ - void InitialiseBackgroundActors( Dali::Actor actor ); - private: Dali::Application& mApplication; ///< Application instance. - Dali::Toolkit::Control mRootActor; ///< All content (excluding background is anchored to this Actor) + Dali::Layer mBackgroundLayer; ///< Background resides on a separate layer. + Dali::Toolkit::TableView mRootActor; ///< All content (excluding background is anchored to this Actor) Dali::Animation mRotateAnimation; ///< Animation to rotate and resize mRootActor. Dali::Animation mPressedAnimation; ///< Button press scaling animation. + Dali::Layer mScrollViewLayer; ///< ScrollView resides on a separate layer. Dali::Toolkit::ScrollView mScrollView; ///< ScrollView container (for all Examples) Dali::Toolkit::ScrollViewEffect mScrollViewEffect; ///< Effect to be applied to the scroll view Dali::Toolkit::RulerPtr mScrollRulerX; ///< ScrollView X (horizontal) ruler Dali::Toolkit::RulerPtr mScrollRulerY; ///< ScrollView Y (vertical) ruler Dali::Actor mPressedActor; ///< The currently pressed actor. - Dali::Timer mAnimationTimer; ///< Timer used to turn off animation after a specific time period Dali::TapGestureDetector mLogoTapDetector; ///< To detect taps on the logo Dali::Toolkit::Popup mVersionPopup; ///< Displays DALi library version information std::vector< Dali::Actor > mPages; ///< List of pages. - AnimationList mBackgroundAnimations; ///< List of background bubble animations ExampleList mExampleList; ///< List of examples. - float mPageWidth; ///< The width of a page within the scroll-view, used to calculate the domain int mTotalPages; ///< Total pages within scrollview. bool mScrolling:1; ///< Flag indicating whether view is currently being scrolled bool mSortAlphabetically:1; ///< Sort examples alphabetically. - bool mBackgroundAnimsPlaying:1; ///< Are background animations playing }; -#endif // __DALI_DEMO_H__ +#endif // DALI_DEMO_H diff --git a/resources/images/demo-tile-texture.9.png b/resources/images/demo-tile-texture.9.png deleted file mode 100644 index e7a6a4d1ee83dbca0c6bfc30aa6951cbb1741df4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22266 zcmb@uRa9Kvx~^NeyGw8lF2OZ;2<{TxAvnR^-Q9v~fdd}_K>^g}U zB8(o&Y7lA5OV1HT32xZo9e*)`{##BM`Qr29umwqpIVvVf4RulK$L!E>=pVp^1U_=S zwoKB%v^`AK6__G>R$l9SM!M7lRpco|`mdl@Zz;6f3LyYufO3MYB{%E49Hpu60mx{& zOoiNS??;_!V1lrWV}tn-hr?`<2m8scoDM3f=);#Xz0_{OyFs# zZ+IeT!L;w?ceWB{ma%Kq5ZiO;=4Wm;#V;Y@SCoRm<1o)ikSPeQJ!^f>V|Y}R9?|jp zn)t7Y{lfl*H{pof-uf`p(OrEa3w|8|P@1>SMH7m_&y^nhJ~c^-j0L(+$w(D>+@ zMCij;;JPX)C%gO&=DBd5(=K3OUBd9lx*8C0`jD0l(Wy4KNJCnvBR%+_DdsivBaiqz z-(*ydA$uEvU-5&Wcs!$W05yTb6+9rAIikYsgJH+^9s!`V4(&xi&KU%;->u6J>O=$g z-4~*Ci4my(u*Tn(lE%i4L#`zdAYyN`EU~LiQHcWtfVWmsI1ul$st-vVMy0%b^=vIz z;Za60IDUyha%m+7_&0R~Lf{~W0}ys334T^7ilnWwSf=9BZswcVf~~YX%(-iZ0c?9J zhA_({Ro5b24rM`IaL%|n6>(V97|0j1oqFPsFXJOj&*2*dPso8ICa4$Ee#sBGEPQQ) z6gs^45;!prNlhTuZG|Qx`niKD>Ug5nVV1*mQ9$@7EAIMP=zg!CmVPA57aQ)1g$uQ{ zM6*6p*(YRhWv;l?yFPuEO5)(0fv&Gt{1)j);;;C)>MSi3&Bgm;>v=l9&!-tZl(D#hjqE>u)~MA7WcU`ev;NybvYJzb?u_1R<~ z4UVT%<0f1&g+JROb`?7wQ!+iJ&JTG`SBBm+^QC8E3#td9Dzyu;rtU=6z2(ST@^hUaSb5qm0mG036gmu8npi?=ZWqcVDx7d#-HRzgC#|DVl}rKg z6RFfg-VvB##Z8!Q@qt$Ie4I+$=aCXDj`w;Xb~%82&>u3y(}iW8?TQ4R59W9S_O5k5 zm?H(PJ+&49tu1Y61q$<->wY+7>w@VhGC87PF`o;uAi}gkoJ`w9!?)wQgb_{XGz;gShi*y<-Iu{7cqshksrDVeaFur1LW(fRW0-R-5IzgZ6%Xae-Z zasZk}QY7q=iS2NUsz32~FMvCL!m^_NVu(YPR+-gOod2M3RaV)scvdJBF#gG?3gKOZ z|8n@%%f{}EXCgEJER#jl3y@@JRxIOA@N}kV6pYyuQ(RFbeG#+xn)-@$FB4EGNcx!Y z{cK2~NyG~7jQkZWz4bPwP)$6I3nKL5^bzclN^E@7VnP_q31@;Jj}b;euoR|o&%fKE zFS6Sah6i%RFy_g8bXU!1>rZ8#T&j3)m8^ta$!P=<4b4V1)Pz%)`$FdTgHEb)hVPLp z9)k3$5(L3Sk_a`5c^yluOLb{(W67o!-E}c%L3cALT5&_(M`qE#R9E0z(*K>NwVFMU zK|%?!)_PPZ5Lb#m&UVEJpjV|X8i$n@N8dvS(P}O z%ek6ZU0B$&-#cbMAxSxoO&xvDF^PT7W>qOh`=T(LZ*t{syI+nryC}ZJ@O{4B;RiZ{ z2-f$}qqFEwZkk6{#8H~`{Htaxi81)lSB?ltOoUrT*+2#B!iam=%$>!SiU^%za*|Zd z%gYScDhMkDF2+TF(P?at*CavZ^V^lgES-iCmS+M_e%kQ`bY-+A<~D) z7$Pr-9=|x|&_pgF^jBNQ0K33XFP(6HcIR$HXrH_T-Pg?T?p)M&Uoc>P!m|G?iiJ^a zVUoi78U={0en(_U8h!tH#UzJTmg{R*>Q(Ym>q6ol09q`9fKO2?^9Jd_$LX5-+n`(i+&^ zX!eAKiu5-%0`IxdY_5A`bxnD|izEvN8egUSa;4u^Z8(&OD=_66DieAM!&noc_mQR( z!QKW%zD03K%fhS(HxaQ4h<#vdw+xsL?NUzt_@3-~EfPBz=@rQRdT!b}du!l?RG1TZ zF<|^S>l6fZJS_dCWMw9WqGn6Z9Lv;?*`7+9r-EoLC(us(sx}q05QPYFJA)(YottHfEWp=R4#Pu!%HFCCTQkDD!?_ybpt!pLLp!N2pC{l!w;i(1sZ+m z<17zzSt8Kt-dhCBH|{7{_t-4H+pu5CAS3moR6(b;V{ugCOYaaUHYyD0srE=akyWQW zJjQx9#(^9GL?+maE30=gm4gjTDdU@0#N=U7d}x@$KTUH_Pw!6o2u#!q-P=>f%%iu# z^kuFm0fN63_+CDj0b8_e74aNAg0=^JSlC`QC%xnMx%sHD0zyh=_AD$&LUEvvN1q>pZ=7YC@>;yat zT^4B{gv(jm07?TucS)X5mZqPREryMCSoec!bF)OWUn{fejWm}9(?9v1r2Tj-u5<%I z^udQ=RzzTeUS52Y+U$9XXCJw>mllvMPV++n?p28bWyfxVMi%q!_x9YeqmzM&o5hrf z-j0X*n4=Ho)m7#gTyh_|Hw);iA5p*SVBNWbAjRNAWKh6ml>xF|van{TQnfO7E*|4M z#hx#OlY5C3cS%{xSr-Vyo;~^>gzO!{>5Et42)v^o@sGN_m(tWee^xW4z1@PF%T2}S z=+T$@E+tz`r%HYK@$%#LX=T}AcihS@93-7d6zDLJ`c!UUVT z4G)TSP^mt0qf2@RtorrbQolJibD8Y6v4H;o2Q(;B%8fIb$LHe<(Z*rqUh9t=f{U%N zflp>KQ;WL_hOq1a*I=4=bG>asV)SE_nidfAd)C0|s%;2gZXz{oO3L!8=1fzye)N=Kv1IHqp6ipqS>mkWs;Qbl?VU;fWZDOUXqRe;H#;2)35QH3j;R@(@ zVrJ9-?pYK0a`IC>BbuQF=F5;8|D<{ySD{er&3AtF1n<_S^McoussNxXL--D39?lqo!O9!N0{>ZQoW=~$Frm7eI$Cn4N1i<5;;k* zJEEkwiInf_N$Us3SiXYQ7=@qtrdXYr{|s9XNhs3UrD@mUvor4Vv!0p;3vObG7JOm%|I0^H&$Tk;l5456KiBN4cA z_|&5Qfy%cQ#k{~r7OXQWXK8YK(*V>S+>@-~G) zYV8F6WE#b8u=?wJ)Cr_Kg{GBT8WlfdXf+$h3~5& zzF5nuNU43WT=d>}`$wlTN4;h>Mt5%sL$CCHOW0z!5~o@q5JS-1O=Z=!39yWCS+El_ zfg}y>Oe&F(5&Ymqd>xN%Te!7cyJYoMR+*Q1CjAe^r#}H^%)iTsss_enQFG)$$n_bq zqy^N|IOf#r0w@(^E3z`4_-k z;N*xCU;d%GgFq$B6-1X-br-0MAKI>d!2I?b4j7DHV}*G

YR&5(h($KDaoj5MbzG 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 Qpv)GeqNo9>mNyOg7t9brn*aa+ diff --git a/resources/images/item-background-alpha.9.png b/resources/images/item-background-alpha.9.png new file mode 100644 index 0000000000000000000000000000000000000000..64579dddcbbb6984b0932e4a31b46fa5971188c9 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^5&lbA^_0NL6N_G*~(@VA=Jkz2dB<^|X%##^@6(>(|94=O<6yjpo#5zt0xi&l*v>F3aCXXO#T1GcdZeT{om?Vb%P7)8DX_^L%*D_Hz4+OWyk~Db&t7 uXUC(zbjn^f{zBffCW-xlr)GTTJI>BM@6QYU<~<x&S_at(l!#3AlS7m;)1FE5cmM zi3CSle_NPY-dMohC%|j)^XW!(Gi_vHW-qk@0r}X>4o&jx?g_90ax0#oFlb<5;PGVq$vmDFoL+Q<=Y~ccXr0)JzDl)JD=E`4N@>s`2Rua$|v<5a0IBKIKdwpvjtmLS1 z)85dAHfpY6c;rNXbm3GEI5w$?X2>USx+bri$*D$RU!!xU@C&V_atlCaX4|&6ic~$4 mB8c?TH#xAYB5sSj??vD2Iio^wNR77u0000%_JzTO`FsMcQg0n9PXX-o$pF_1Le9ktQ* zDins{2~e3uzG{s52GHyEXfzr~I+pZI(x#*b<=QO29XA>cdc7V1Q4|e<)qe^^QPctG zbUIY4RV3}*;(yS4)oPVarvrfR`zO~{g<<#-U^E(0tJRRyy2CGP)oL|HqY(hE>mFRG zNRlK1Xf~Tj+MmN0`^{z(fH;oFf9-gl_Y|Pp?ILL)X?YHTWl4i>w+p~vFnB%f1K^1y z9UUD>(xIeu4uMqCVacJDm6gYTdOiTC*Xu~y*8JG6*MI91+h&ulC(E(|pi-$IX=4F_ zjY_35X~1c$P!t6KmSr(3K4wLaWmy0eMS&zNNh*p$lC-wACQ0iH2&|VJQ%+0LQktfr zBsq>FNm~mDY?T}`#^h5MB}wu_l6H1>Bx!d6f!&frNs|1Mv?NKoxVU(6-+j>U_uu`` zPR_6Fx__>Fa9>$891cHTTjl%y$)ag`d3o8taUPVJKG!@5f*?FSJ$*QHq6IrD^c%fvY9}6$B=i6P002ovPDHLkU;%;|jW7uS -- 2.7.4