2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/dali-toolkit.h>
20 #include <dali/devel-api/actors/actor-devel.h>
24 #include <dali-toolkit/devel-api/controls/table-view/table-view.h>
25 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
28 using Dali::Toolkit::TextLabel;
38 const char* IMAGE_PATH_PREFIX ( DEMO_IMAGE_DIR "application-icon-" );
39 const char* IMAGE_PATH_POSTFIX ( ".png" );
40 const int TOTAL_ICON_DEFINITIONS ( 147 );
42 const char* BACKGROUND_IMAGE ( DEMO_IMAGE_DIR "background-3.jpg" );
43 const float PAGE_SCALE_FACTOR_X ( 0.95f );
44 const float PAGE_SCALE_FACTOR_Y ( 0.95f );
45 const float PAGE_DURATION_SCALE_FACTOR ( 10.0f ); ///< Time-scale factor, larger = animation is slower
47 const float DEFAULT_OPT_ROW_COUNT ( 5 );
48 const float DEFAULT_OPT_COL_COUNT ( 4 );
49 const float DEFAULT_OPT_PAGE_COUNT ( 10 );
50 const bool DEFAULT_OPT_USE_TABLEVIEW ( true );
51 const bool DEFAULT_OPT_ICON_LABELS ( true );
52 const IconType DEFAULT_OPT_ICON_TYPE ( IMAGEVIEW );
53 const bool DEFAULT_OPT_USE_TEXT_LABEL ( false );
55 // The image/label area tries to make sure the positioning will be relative to previous sibling
56 const float IMAGE_AREA ( 0.60f );
57 const float LABEL_AREA ( 0.50f );
62 * Random words used as unique application names.
63 * The number matches the value of TOTAL_ICON_DEFINITIONS.
65 const char* DEMO_APPS_NAMES[] =
67 "Achdyer", "Aughm", "Cerl", "Daril", "Emgha", "Ghatan", "Issum", "Lertan", "Mosorrad",
68 "Achtortor", "Aughtheryer", "Certin", "Darpban", "Emiton", "Gibanis", "Itenthbel", "Liadem", "Mosraye",
69 "Ackirlor", "Awitad", "Checerper", "Dasrad", "Emworeng", "Hatdyn", "K'ackves", "Liathar", "Mosth",
70 "Ackptin", "Banengon", "Chegit", "Deeqskel", "Endnys", "Heesban", "Kagdra", "Liephden", "Neabar",
71 "Aighte", "Banhinat", "Cheirat", "Delurnther", "Enessray", "Hesub", "Kalbankim", "Likellor", "Neerdem",
72 "Akala", "Belrisash", "Che'rak", "Denalda", "Engyer", "Hinkelenth", "Kal'enda", "Loightmos", "Nichqua",
73 "Alealdny", "Bilorm", "Cheves", "Derynkel", "En'rady", "Hirryer", "Kimest", "Loromum", "Nudraough",
74 "Angash", "Bleustcer", "Chiperath", "Deurnos", "Enthount", "Ideinta", "Kimundeng", "Lorr", "Nuyim",
75 "Anglor", "Bliagelor", "Chralerack", "Doyaryke", "Enundem", "Im'eld", "Koachlor", "Lortas", "Nycha",
76 "Anveraugh", "Blorynton", "Chram", "Draithon", "Essina", "Ina'ir", "Kuren", "Lyerr", "Nyia",
77 "Ardangas", "Booten", "Clyimen", "Drantess", "Faughald", "Ing'moro", "Kygver", "Maustbur", "Nyjac",
78 "Ardug", "Bripolqua", "Coqueang", "Druardny", "Fiummos", "Ingormess", "Kyning", "Menvor", "Nystondar",
79 "Ardworu", "Bryray", "Craennther", "Dynsaytor", "Garash", "Ingshy", "Laiyach", "Meusten", "Okine",
80 "Ascerald", "Burust", "Cykage", "Dytinris", "Garight", "Issath", "Lasuzu", "Mirodskel", "Oldit",
81 "Ash'ach", "Cataikel", "Dalek", "Eeni", "Garrynath", "Issendris", "Lekew", "Morhatrod", "Om'mose",
82 "Athiund", "Cerilwar", "Darhkel", "Elmryn", "Ghalora", "Issey", "Lerengom", "Moserbel", "Onye",
83 "Ososrak", "Pecertin", "Perrd"
86 // This code comes from command-line-options.cpp. the reason it's here is to
87 // keep consistent the extra-help formatting when '--help' used.
88 void PrintHelp( const char * const opt, const char * const optDescription)
90 const std::ios_base::fmtflags flags = std::cout.flags();
91 std::cout << std::left << " -";
92 std::cout.width( 18 );
94 std::cout << optDescription;
95 std::cout << std::endl;
96 std::cout.flags( flags );
102 * @brief This example is a benchmark that mimics the paged applications list of the homescreen application.
104 class HomescreenBenchmark : public ConnectionTracker
108 // Config structure passed to the constructor. It makes easier to increase number
109 // of setup parameters if needed.
113 mRows( DEFAULT_OPT_ROW_COUNT ),
114 mCols( DEFAULT_OPT_COL_COUNT ),
115 mPageCount( DEFAULT_OPT_PAGE_COUNT ),
116 mTableViewEnabled( DEFAULT_OPT_USE_TABLEVIEW ),
117 mIconLabelsEnabled( DEFAULT_OPT_ICON_LABELS ),
118 mIconType( DEFAULT_OPT_ICON_TYPE ),
119 mUseTextLabel( DEFAULT_OPT_USE_TEXT_LABEL )
126 bool mTableViewEnabled;
127 bool mIconLabelsEnabled;
132 // animation script data
135 ScriptData( int pages, float duration, bool flick )
137 mDuration( duration ),
142 int mPages; ///< Number of pages to scroll
143 float mDuration; ///< Duration
144 bool mFlick; ///< Use flick or 'one-by-one' scroll
147 HomescreenBenchmark( Application& application, const Config& config )
148 : mApplication( application ),
153 // Connect to the Application's Init signal.
154 mApplication.InitSignal().Connect( this, &HomescreenBenchmark::Create );
157 ~HomescreenBenchmark()
161 // The Init signal is received once (only) during the Application lifetime.
162 void Create( Application& application )
164 // Create benchmark script
167 // Get a handle to the window
168 Window window = application.GetWindow();
170 mScrollParent = Actor::New();
171 mScrollParent.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
172 mScrollParent.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
173 mScrollParent.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
176 Toolkit::ImageView background = Toolkit::ImageView::New( BACKGROUND_IMAGE );
177 window.Add( background );
178 background.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
179 background.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
180 background.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
184 window.Add( mScrollParent );
186 // Respond to a click anywhere on the window.
187 window.GetRootLayer().TouchSignal().Connect( this, &HomescreenBenchmark::OnTouch );
189 // Respond to key events
190 window.KeyEventSignal().Connect( this, &HomescreenBenchmark::OnKeyEvent );
193 bool OnTouch( Actor actor, const TouchEvent& touch )
195 // Quit the application.
202 // Create root page actor.
203 Toolkit::Control pageActor;
205 if( mConfig.mTableViewEnabled )
207 pageActor = Toolkit::TableView::New( mConfig.mRows, mConfig.mCols );
211 pageActor = Toolkit::Control::New();
214 pageActor.SetBackgroundColor( Vector4( 0.0f, 0.0f, 0.0f, 0.5f ) );
215 pageActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
216 pageActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
217 pageActor.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
218 pageActor.SetProperty( Actor::Property::SIZE_MODE_FACTOR, Vector3( PAGE_SCALE_FACTOR_X, PAGE_SCALE_FACTOR_Y, 1.0f ) );
222 Toolkit::ImageView CreateImageView( const unsigned int currentIconIndex )
224 // Create empty image to avoid early renderer creation
225 Toolkit::ImageView imageView = Toolkit::ImageView::New();
227 // Auto-generate the Icons image URL.
229 std::stringstream imagePath;
230 imagePath << IMAGE_PATH_PREFIX << currentIconIndex << IMAGE_PATH_POSTFIX;
231 map[ Dali::Toolkit::ImageVisual::Property::URL ] = imagePath.str();
233 imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, map );
234 imageView.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
235 imageView.SetProperty( Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
236 imageView.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
237 imageView.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
238 imageView.SetProperty( Actor::Property::SIZE_MODE_FACTOR, Vector3( IMAGE_AREA, IMAGE_AREA, 1.0f ) );
243 Toolkit::Button CreateButton( const unsigned int currentIconIndex )
245 Toolkit::CheckBoxButton button = Toolkit::CheckBoxButton::New();
246 button.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
247 button.SetProperty( Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
248 button.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
249 button.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
250 button.SetProperty( Toolkit::Button::Property::SELECTED, ( currentIconIndex % 2 == 0 ) ); // Select half the button
255 void AddIconsToPage( Actor page, bool useTextLabel )
257 Window window = mApplication.GetWindow();
259 Size windowSize( window.GetSize() );
260 const float scaledHeight = windowSize.y * PAGE_SCALE_FACTOR_Y;
261 const float scaledWidth = windowSize.x * PAGE_SCALE_FACTOR_X;
262 const float PADDING = windowSize.y / 64.0f;
263 const float ROW_HEIGHT = ( scaledHeight - (PADDING*2.0f) ) / static_cast<float>( mConfig.mRows );
264 const float COL_WIDTH = ( scaledWidth - (PADDING*2.0f) ) / static_cast<float>( mConfig.mCols );
266 Vector2 dpi = window.GetDpi();
268 static int currentIconIndex = 0;
270 for( int y = 0; y < mConfig.mRows; ++y )
272 for( int x = 0; x < mConfig.mCols; ++x )
274 // Create parent icon view
275 Toolkit::Control iconView = Toolkit::Control::New();
276 iconView.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
277 iconView.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
279 if( !mConfig.mTableViewEnabled )
281 float rowX = x * COL_WIDTH + PADDING;
282 float rowY = y * ROW_HEIGHT + PADDING;
283 iconView.SetProperty( Actor::Property::SIZE, Vector3( COL_WIDTH, ROW_HEIGHT, 1.0f ) );
284 iconView.SetProperty( Actor::Property::POSITION, Vector3( rowX, rowY, 0.0f ) );
288 iconView.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
289 iconView.SetProperty( Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
294 switch( mConfig.mIconType )
298 icon = CreateButton( currentIconIndex );
303 icon = CreateImageView( currentIconIndex );
308 if( mConfig.mIconLabelsEnabled )
313 Toolkit::TextLabel textLabel = Toolkit::TextLabel::New( DEMO_APPS_NAMES[currentIconIndex] );
314 textLabel.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
315 textLabel.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER );
316 textLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
317 textLabel.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); // White.
318 textLabel.SetProperty( Toolkit::TextLabel::Property::POINT_SIZE, ( ( static_cast<float>( ROW_HEIGHT * LABEL_AREA ) * 72.0f ) / dpi.y ) * 0.25f );
319 textLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
320 textLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "TOP" );
321 icon.Add( textLabel );
326 map.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT ).
327 Add( Toolkit::TextVisual::Property::TEXT, DEMO_APPS_NAMES[currentIconIndex] ).
328 Add( Toolkit::TextVisual::Property::TEXT_COLOR, Color::WHITE ).
329 Add( Toolkit::TextVisual::Property::POINT_SIZE, ( ( static_cast<float>( ROW_HEIGHT * LABEL_AREA ) * 72.0f ) / dpi.y ) * 0.25f ).
330 Add( Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT, "CENTER" ).
331 Add( Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT, "TOP" );
333 Toolkit::Control control = Toolkit::Control::New();
334 control.SetProperty( Toolkit::Control::Property::BACKGROUND, map );
335 control.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
336 control.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER );
341 iconView.Add( icon );
342 page.Add( iconView );
344 // We only have images and names for a certain number of icons.
345 // Wrap around if we have used them all.
346 if( ++currentIconIndex == TOTAL_ICON_DEFINITIONS )
348 currentIconIndex = 0;
356 const int lastPage = mConfig.mPageCount - 1;
357 const int halfA = lastPage / 2;
358 const int halfB = lastPage / 2 + lastPage % 2;
359 mScriptFrameData.push_back( ScriptData( lastPage, 1.5f, true ) );
360 mScriptFrameData.push_back( ScriptData( -lastPage, 1.5f, true ) );
361 mScriptFrameData.push_back( ScriptData( halfA, 1.0f, true ) );
362 mScriptFrameData.push_back( ScriptData( halfB, 1.0f, true ) );
363 mScriptFrameData.push_back( ScriptData( -lastPage, 0.5f, false ) );
364 mScriptFrameData.push_back( ScriptData( halfA, 0.5f, false ) );
365 mScriptFrameData.push_back( ScriptData( halfB, 1.0f, true ) );
366 mScriptFrameData.push_back( ScriptData( -halfA, 1.0f, true ) );
367 mScriptFrameData.push_back( ScriptData( 1, 0.1f, true ) );
368 mScriptFrameData.push_back( ScriptData( -1, 0.1f, true ) );
369 mScriptFrameData.push_back( ScriptData( 1, 0.1f, true ) );
370 mScriptFrameData.push_back( ScriptData( -1, 0.1f, true ) );
371 mScriptFrameData.push_back( ScriptData( 1, 0.1f, true ) );
372 mScriptFrameData.push_back( ScriptData( -1, 0.1f, true ) );
373 mScriptFrameData.push_back( ScriptData( halfA, 1.0f, true ) );
378 Vector3 windowSize( mApplication.GetWindow().GetSize() );
380 for( int i = 0; i < mConfig.mPageCount; ++i )
383 Actor page = AddPage();
386 AddIconsToPage( page, mConfig.mUseTextLabel );
388 // Move page 'a little bit up'.
389 page.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
390 page.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
391 page.SetProperty( Actor::Property::POSITION, Vector3( windowSize.x * i, 0.0f, 0.0f ) );
392 mScrollParent.Add( page );
395 mScrollParent.SetProperty( Actor::Property::OPACITY, 1.0f );
396 mScrollParent.SetProperty( Actor::Property::SCALE, Vector3::ONE );
404 mShowAnimation = Animation::New( 1.0f );
405 mShowAnimation.AnimateTo( Property( mScrollParent, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN_OUT );
406 mShowAnimation.AnimateTo( Property( mScrollParent, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT );
407 mShowAnimation.FinishedSignal().Connect( this, &HomescreenBenchmark::OnAnimationEnd );
408 mShowAnimation.Play();
411 void ScrollPages(int pages, float duration, bool flick)
413 duration *= PAGE_DURATION_SCALE_FACTOR;
414 Vector3 windowSize( mApplication.GetWindow().GetSize() );
415 mScrollAnimation = Animation::New( duration );
418 mScrollAnimation.AnimateBy( Property( mScrollParent, Actor::Property::POSITION ), Vector3( -windowSize.x * pages, 0.0f, 0.0f ), AlphaFunction::EASE_IN_OUT );
422 int totalPages = abs( pages );
423 for( int i = 0; i < totalPages; ++i )
425 mScrollAnimation.AnimateBy( Property( mScrollParent, Actor::Property::POSITION ), Vector3( pages < 0 ? windowSize.x : -windowSize.x, 0.0f, 0.0f ), AlphaFunction::EASE_IN_OUT, TimePeriod( duration * i, duration ) );
428 mScrollAnimation.FinishedSignal().Connect( this, &HomescreenBenchmark::OnAnimationEnd );
429 mScrollAnimation.Play();
430 mCurrentPage += pages;
433 void OnAnimationEnd( Animation& source )
435 if( mScriptFrame < mScriptFrameData.size() )
437 ScriptData& frame = mScriptFrameData[mScriptFrame];
438 ScrollPages( frame.mPages, frame.mDuration, frame.mFlick );
447 void OnKeyEvent( const KeyEvent& event )
449 if( event.GetState() == KeyEvent::Down )
451 if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
460 Application& mApplication;
462 Animation mShowAnimation;
463 Animation mScrollAnimation;
465 std::vector<ScriptData> mScriptFrameData;
470 int DALI_EXPORT_API main( int argc, char **argv )
473 HomescreenBenchmark::Config config;
475 bool printHelpAndExit = false;
477 for( int i = 1 ; i < argc; ++i )
479 std::string arg( argv[i] );
480 if( arg.compare( 0, 2, "-r" ) == 0 )
482 config.mRows = atoi( arg.substr( 2 ).c_str() );
484 else if( arg.compare( 0, 2, "-c" ) == 0 )
486 config.mCols = atoi( arg.substr( 2 ).c_str() );
488 else if( arg.compare( 0, 2, "-p" ) == 0 )
490 config.mPageCount = atoi( arg.substr( 2 ).c_str() );
492 else if( arg.compare( "--disable-tableview" ) == 0 )
494 config.mTableViewEnabled = false;
496 else if( arg.compare( "--disable-icon-labels" ) == 0 )
498 config.mIconLabelsEnabled = false;
500 else if( arg.compare( "--use-checkbox" ) == 0 )
502 config.mIconType = CHECKBOX;
504 else if( arg.compare("--use-text-label" ) == 0)
506 config.mUseTextLabel = true;
508 else if( arg.compare( "--help" ) == 0 )
510 printHelpAndExit = true;
514 Application application = Application::New( &argc, &argv );
515 HomescreenBenchmark test( application, config );
517 if( printHelpAndExit )
519 PrintHelp( "c<num>", " Number of columns" );
520 PrintHelp( "r<num>", " Number of rows" );
521 PrintHelp( "p<num>", " Number of pages ( must be greater than 1 )" );
522 PrintHelp( "-disable-tableview", " Disables the use of TableView for layouting" );
523 PrintHelp( "-disable-icon-labels", " Disables labels for each icon" );
524 PrintHelp( "-use-checkbox", " Uses checkboxes for icons" );
525 PrintHelp( "-use-text-label", " Uses TextLabel instead of a TextVisual" );
529 application.MainLoop();