Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / homescreen-benchmark / homescreen-benchmark.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // EXTERNAL INCLUDES
19 #include <dali-toolkit/dali-toolkit.h>
20 #include <dali/devel-api/actors/actor-devel.h>
21 #include <iostream>
22 #include <sstream>
23
24 #include <dali-toolkit/devel-api/controls/table-view/table-view.h>
25 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
26
27 using namespace Dali;
28 using Dali::Toolkit::TextLabel;
29
30 namespace
31 {
32 enum IconType
33 {
34   IMAGEVIEW,
35   CHECKBOX
36 };
37
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);
41
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
46
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);
54
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);
58
59 /**
60  * Random words used as unique application names.
61  * The number matches the value of TOTAL_ICON_DEFINITIONS.
62  */
63 const char* DEMO_APPS_NAMES[] =
64   {
65     "Achdyer", "Aughm", "Cerl", "Daril", "Emgha", "Ghatan", "Issum", "Lertan", "Mosorrad", "Achtortor", "Aughtheryer", "Certin", "Darpban", "Emiton", "Gibanis", "Itenthbel", "Liadem", "Mosraye", "Ackirlor", "Awitad", "Checerper", "Dasrad", "Emworeng", "Hatdyn", "K'ackves", "Liathar", "Mosth", "Ackptin", "Banengon", "Chegit", "Deeqskel", "Endnys", "Heesban", "Kagdra", "Liephden", "Neabar", "Aighte", "Banhinat", "Cheirat", "Delurnther", "Enessray", "Hesub", "Kalbankim", "Likellor", "Neerdem", "Akala", "Belrisash", "Che'rak", "Denalda", "Engyer", "Hinkelenth", "Kal'enda", "Loightmos", "Nichqua", "Alealdny", "Bilorm", "Cheves", "Derynkel", "En'rady", "Hirryer", "Kimest", "Loromum", "Nudraough", "Angash", "Bleustcer", "Chiperath", "Deurnos", "Enthount", "Ideinta", "Kimundeng", "Lorr", "Nuyim", "Anglor", "Bliagelor", "Chralerack", "Doyaryke", "Enundem", "Im'eld", "Koachlor", "Lortas", "Nycha", "Anveraugh", "Blorynton", "Chram", "Draithon", "Essina", "Ina'ir", "Kuren", "Lyerr", "Nyia", "Ardangas", "Booten", "Clyimen", "Drantess", "Faughald", "Ing'moro", "Kygver", "Maustbur", "Nyjac", "Ardug", "Bripolqua", "Coqueang", "Druardny", "Fiummos", "Ingormess", "Kyning", "Menvor", "Nystondar", "Ardworu", "Bryray", "Craennther", "Dynsaytor", "Garash", "Ingshy", "Laiyach", "Meusten", "Okine", "Ascerald", "Burust", "Cykage", "Dytinris", "Garight", "Issath", "Lasuzu", "Mirodskel", "Oldit", "Ash'ach", "Cataikel", "Dalek", "Eeni", "Garrynath", "Issendris", "Lekew", "Morhatrod", "Om'mose", "Athiund", "Cerilwar", "Darhkel", "Elmryn", "Ghalora", "Issey", "Lerengom", "Moserbel", "Onye", "Ososrak", "Pecertin", "Perrd"};
66
67 // This code comes from command-line-options.cpp. the reason it's here is to
68 // keep consistent the extra-help formatting when '--help' used.
69 void PrintHelp(const char* const opt, const char* const optDescription)
70 {
71   const std::ios_base::fmtflags flags = std::cout.flags();
72   std::cout << std::left << "  -";
73   std::cout.width(18);
74   std::cout << opt;
75   std::cout << optDescription;
76   std::cout << std::endl;
77   std::cout.flags(flags);
78 }
79
80 } // namespace
81
82 /**
83  * @brief This example is a benchmark that mimics the paged applications list of the homescreen application.
84  */
85 class HomescreenBenchmark : public ConnectionTracker
86 {
87 public:
88   // Config structure passed to the constructor. It makes easier to increase number
89   // of setup parameters if needed.
90   struct Config
91   {
92     Config()
93     : mRows(DEFAULT_OPT_ROW_COUNT),
94       mCols(DEFAULT_OPT_COL_COUNT),
95       mPageCount(DEFAULT_OPT_PAGE_COUNT),
96       mTableViewEnabled(DEFAULT_OPT_USE_TABLEVIEW),
97       mIconLabelsEnabled(DEFAULT_OPT_ICON_LABELS),
98       mIconType(DEFAULT_OPT_ICON_TYPE),
99       mUseTextLabel(DEFAULT_OPT_USE_TEXT_LABEL)
100     {
101     }
102
103     int      mRows;
104     int      mCols;
105     int      mPageCount;
106     bool     mTableViewEnabled;
107     bool     mIconLabelsEnabled;
108     IconType mIconType;
109     bool     mUseTextLabel;
110   };
111
112   // animation script data
113   struct ScriptData
114   {
115     ScriptData(int pages, float duration, bool flick)
116     : mPages(pages),
117       mDuration(duration),
118       mFlick(flick)
119     {
120     }
121
122     int   mPages;    ///< Number of pages to scroll
123     float mDuration; ///< Duration
124     bool  mFlick;    ///< Use flick or 'one-by-one' scroll
125   };
126
127   HomescreenBenchmark(Application& application, const Config& config)
128   : mApplication(application),
129     mConfig(config),
130     mScriptFrame(0),
131     mCurrentPage(0)
132   {
133     // Connect to the Application's Init signal.
134     mApplication.InitSignal().Connect(this, &HomescreenBenchmark::Create);
135   }
136
137   ~HomescreenBenchmark()
138   {
139   }
140
141   // The Init signal is received once (only) during the Application lifetime.
142   void Create(Application& application)
143   {
144     // Create benchmark script
145     CreateScript();
146
147     // Get a handle to the window
148     Window window = application.GetWindow();
149
150     mScrollParent = Actor::New();
151     mScrollParent.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
152     mScrollParent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
153     mScrollParent.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
154
155     // create background
156     Toolkit::ImageView background = Toolkit::ImageView::New(BACKGROUND_IMAGE);
157     window.Add(background);
158     background.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
159     background.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
160     background.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
161
162     PopulatePages();
163
164     window.Add(mScrollParent);
165
166     // Respond to a click anywhere on the window.
167     window.GetRootLayer().TouchedSignal().Connect(this, &HomescreenBenchmark::OnTouch);
168
169     // Respond to key events
170     window.KeyEventSignal().Connect(this, &HomescreenBenchmark::OnKeyEvent);
171   }
172
173   bool OnTouch(Actor actor, const TouchEvent& touch)
174   {
175     // Quit the application.
176     mApplication.Quit();
177     return true;
178   }
179
180   Actor AddPage()
181   {
182     // Create root page actor.
183     Toolkit::Control pageActor;
184
185     if(mConfig.mTableViewEnabled)
186     {
187       pageActor = Toolkit::TableView::New(mConfig.mRows, mConfig.mCols);
188     }
189     else
190     {
191       pageActor = Toolkit::Control::New();
192     }
193
194     pageActor.SetBackgroundColor(Vector4(0.0f, 0.0f, 0.0f, 0.5f));
195     pageActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
196     pageActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
197     pageActor.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
198     pageActor.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(PAGE_SCALE_FACTOR_X, PAGE_SCALE_FACTOR_Y, 1.0f));
199     return pageActor;
200   }
201
202   Toolkit::ImageView CreateImageView(const unsigned int currentIconIndex)
203   {
204     // Create empty image to avoid early renderer creation
205     Toolkit::ImageView imageView = Toolkit::ImageView::New();
206
207     // Auto-generate the Icons image URL.
208     Property::Map     map;
209     std::stringstream imagePath;
210     imagePath << IMAGE_PATH_PREFIX << currentIconIndex << IMAGE_PATH_POSTFIX;
211     map[Dali::Toolkit::ImageVisual::Property::URL] = imagePath.str();
212
213     imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, map);
214     imageView.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
215     imageView.SetProperty(Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO);
216     imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
217     imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
218     imageView.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(IMAGE_AREA, IMAGE_AREA, 1.0f));
219
220     return imageView;
221   }
222
223   Toolkit::Button CreateButton(const unsigned int currentIconIndex)
224   {
225     Toolkit::CheckBoxButton button = Toolkit::CheckBoxButton::New();
226     button.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
227     button.SetProperty(Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO);
228     button.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
229     button.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
230     button.SetProperty(Toolkit::Button::Property::SELECTED, (currentIconIndex % 2 == 0)); // Select half the button
231
232     return button;
233   }
234
235   void AddIconsToPage(Actor page, bool useTextLabel)
236   {
237     Window window = mApplication.GetWindow();
238
239     Size        windowSize(window.GetSize());
240     const float scaledHeight = windowSize.y * PAGE_SCALE_FACTOR_Y;
241     const float scaledWidth  = windowSize.x * PAGE_SCALE_FACTOR_X;
242     const float PADDING      = windowSize.y / 64.0f;
243     const float ROW_HEIGHT   = (scaledHeight - (PADDING * 2.0f)) / static_cast<float>(mConfig.mRows);
244     const float COL_WIDTH    = (scaledWidth - (PADDING * 2.0f)) / static_cast<float>(mConfig.mCols);
245
246     Vector2 dpi = window.GetDpi();
247
248     static int currentIconIndex = 0;
249
250     for(int y = 0; y < mConfig.mRows; ++y)
251     {
252       for(int x = 0; x < mConfig.mCols; ++x)
253       {
254         // Create parent icon view
255         Toolkit::Control iconView = Toolkit::Control::New();
256         iconView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
257         iconView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
258
259         if(!mConfig.mTableViewEnabled)
260         {
261           float rowX = x * COL_WIDTH + PADDING;
262           float rowY = y * ROW_HEIGHT + PADDING;
263           iconView.SetProperty(Actor::Property::SIZE, Vector3(COL_WIDTH, ROW_HEIGHT, 1.0f));
264           iconView.SetProperty(Actor::Property::POSITION, Vector3(rowX, rowY, 0.0f));
265         }
266         else
267         {
268           iconView.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
269           iconView.SetProperty(Actor::Property::SIZE_SCALE_POLICY, SizeScalePolicy::FIT_WITH_ASPECT_RATIO);
270         }
271
272         Actor icon;
273
274         switch(mConfig.mIconType)
275         {
276           case CHECKBOX:
277           {
278             icon = CreateButton(currentIconIndex);
279             break;
280           }
281           case IMAGEVIEW:
282           {
283             icon = CreateImageView(currentIconIndex);
284             break;
285           }
286         }
287
288         if(mConfig.mIconLabelsEnabled)
289         {
290           // create label
291           if(useTextLabel)
292           {
293             Toolkit::TextLabel textLabel = Toolkit::TextLabel::New(DEMO_APPS_NAMES[currentIconIndex]);
294             textLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
295             textLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
296             textLabel.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
297             textLabel.SetProperty(Toolkit::TextLabel::Property::TEXT_COLOR, Vector4(1.0f, 1.0f, 1.0f, 1.0f)); // White.
298             textLabel.SetProperty(Toolkit::TextLabel::Property::POINT_SIZE, ((static_cast<float>(ROW_HEIGHT * LABEL_AREA) * 72.0f) / dpi.y) * 0.25f);
299             textLabel.SetProperty(Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
300             textLabel.SetProperty(Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "TOP");
301             icon.Add(textLabel);
302           }
303           else
304           {
305             Property::Map map;
306             map.Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT).Add(Toolkit::TextVisual::Property::TEXT, DEMO_APPS_NAMES[currentIconIndex]).Add(Toolkit::TextVisual::Property::TEXT_COLOR, Color::WHITE).Add(Toolkit::TextVisual::Property::POINT_SIZE, ((static_cast<float>(ROW_HEIGHT * LABEL_AREA) * 72.0f) / dpi.y) * 0.25f).Add(Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT, "CENTER").Add(Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT, "TOP");
307
308             Toolkit::Control control = Toolkit::Control::New();
309             control.SetProperty(Toolkit::Control::Property::BACKGROUND, map);
310             control.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
311             control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
312             icon.Add(control);
313           }
314         }
315
316         iconView.Add(icon);
317         page.Add(iconView);
318
319         // We only have images and names for a certain number of icons.
320         // Wrap around if we have used them all.
321         if(++currentIconIndex == TOTAL_ICON_DEFINITIONS)
322         {
323           currentIconIndex = 0;
324         }
325       }
326     }
327   }
328
329   void CreateScript()
330   {
331     const int lastPage = mConfig.mPageCount - 1;
332     const int halfA    = lastPage / 2;
333     const int halfB    = lastPage / 2 + lastPage % 2;
334     mScriptFrameData.push_back(ScriptData(lastPage, 1.5f, true));
335     mScriptFrameData.push_back(ScriptData(-lastPage, 1.5f, true));
336     mScriptFrameData.push_back(ScriptData(halfA, 1.0f, true));
337     mScriptFrameData.push_back(ScriptData(halfB, 1.0f, true));
338     mScriptFrameData.push_back(ScriptData(-lastPage, 0.5f, false));
339     mScriptFrameData.push_back(ScriptData(halfA, 0.5f, false));
340     mScriptFrameData.push_back(ScriptData(halfB, 1.0f, true));
341     mScriptFrameData.push_back(ScriptData(-halfA, 1.0f, true));
342     mScriptFrameData.push_back(ScriptData(1, 0.1f, true));
343     mScriptFrameData.push_back(ScriptData(-1, 0.1f, true));
344     mScriptFrameData.push_back(ScriptData(1, 0.1f, true));
345     mScriptFrameData.push_back(ScriptData(-1, 0.1f, true));
346     mScriptFrameData.push_back(ScriptData(1, 0.1f, true));
347     mScriptFrameData.push_back(ScriptData(-1, 0.1f, true));
348     mScriptFrameData.push_back(ScriptData(halfA, 1.0f, true));
349   }
350
351   void PopulatePages()
352   {
353     Vector3 windowSize(mApplication.GetWindow().GetSize());
354
355     for(int i = 0; i < mConfig.mPageCount; ++i)
356     {
357       // Create page.
358       Actor page = AddPage();
359
360       // Populate icons.
361       AddIconsToPage(page, mConfig.mUseTextLabel);
362
363       // Move page 'a little bit up'.
364       page.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
365       page.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
366       page.SetProperty(Actor::Property::POSITION, Vector3(windowSize.x * i, 0.0f, 0.0f));
367       mScrollParent.Add(page);
368     }
369
370     mScrollParent.SetProperty(Actor::Property::OPACITY, 1.0f);
371     mScrollParent.SetProperty(Actor::Property::SCALE, Vector3::ONE);
372
373     // Fade in.
374     ShowAnimation();
375   }
376
377   void ShowAnimation()
378   {
379     mShowAnimation = Animation::New(1.0f);
380     mShowAnimation.AnimateTo(Property(mScrollParent, Actor::Property::COLOR_ALPHA), 1.0f, AlphaFunction::EASE_IN_OUT);
381     mShowAnimation.AnimateTo(Property(mScrollParent, Actor::Property::SCALE), Vector3::ONE, AlphaFunction::EASE_IN_OUT);
382     mShowAnimation.FinishedSignal().Connect(this, &HomescreenBenchmark::OnAnimationEnd);
383     mShowAnimation.Play();
384   }
385
386   void ScrollPages(int pages, float duration, bool flick)
387   {
388     duration *= PAGE_DURATION_SCALE_FACTOR;
389     Vector3 windowSize(mApplication.GetWindow().GetSize());
390     mScrollAnimation = Animation::New(duration);
391     if(flick)
392     {
393       mScrollAnimation.AnimateBy(Property(mScrollParent, Actor::Property::POSITION), Vector3(-windowSize.x * pages, 0.0f, 0.0f), AlphaFunction::EASE_IN_OUT);
394     }
395     else
396     {
397       int totalPages = abs(pages);
398       for(int i = 0; i < totalPages; ++i)
399       {
400         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));
401       }
402     }
403     mScrollAnimation.FinishedSignal().Connect(this, &HomescreenBenchmark::OnAnimationEnd);
404     mScrollAnimation.Play();
405     mCurrentPage += pages;
406   }
407
408   void OnAnimationEnd(Animation& source)
409   {
410     if(mScriptFrame < mScriptFrameData.size())
411     {
412       ScriptData& frame = mScriptFrameData[mScriptFrame];
413       ScrollPages(frame.mPages, frame.mDuration, frame.mFlick);
414       ++mScriptFrame;
415     }
416     else
417     {
418       mApplication.Quit();
419     }
420   }
421
422   void OnKeyEvent(const KeyEvent& event)
423   {
424     if(event.GetState() == KeyEvent::DOWN)
425     {
426       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
427       {
428         mApplication.Quit();
429       }
430     }
431   }
432
433 private:
434   Application&            mApplication;
435   Actor                   mScrollParent;
436   Animation               mShowAnimation;
437   Animation               mScrollAnimation;
438   Config                  mConfig;
439   std::vector<ScriptData> mScriptFrameData;
440   size_t                  mScriptFrame;
441   int                     mCurrentPage;
442 };
443
444 int DALI_EXPORT_API main(int argc, char** argv)
445 {
446   // Default settings.
447   HomescreenBenchmark::Config config;
448
449   bool printHelpAndExit = false;
450
451   for(int i = 1; i < argc; ++i)
452   {
453     std::string arg(argv[i]);
454     if(arg.compare(0, 2, "-r") == 0)
455     {
456       config.mRows = atoi(arg.substr(2).c_str());
457     }
458     else if(arg.compare(0, 2, "-c") == 0)
459     {
460       config.mCols = atoi(arg.substr(2).c_str());
461     }
462     else if(arg.compare(0, 2, "-p") == 0)
463     {
464       config.mPageCount = atoi(arg.substr(2).c_str());
465     }
466     else if(arg.compare("--disable-tableview") == 0)
467     {
468       config.mTableViewEnabled = false;
469     }
470     else if(arg.compare("--disable-icon-labels") == 0)
471     {
472       config.mIconLabelsEnabled = false;
473     }
474     else if(arg.compare("--use-checkbox") == 0)
475     {
476       config.mIconType = CHECKBOX;
477     }
478     else if(arg.compare("--use-text-label") == 0)
479     {
480       config.mUseTextLabel = true;
481     }
482     else if(arg.compare("--help") == 0)
483     {
484       printHelpAndExit = true;
485     }
486   }
487
488   Application         application = Application::New(&argc, &argv);
489   HomescreenBenchmark test(application, config);
490
491   if(printHelpAndExit)
492   {
493     PrintHelp("c<num>", " Number of columns");
494     PrintHelp("r<num>", " Number of rows");
495     PrintHelp("p<num>", " Number of pages ( must be greater than 1 )");
496     PrintHelp("-disable-tableview", " Disables the use of TableView for layouting");
497     PrintHelp("-disable-icon-labels", " Disables labels for each icon");
498     PrintHelp("-use-checkbox", " Uses checkboxes for icons");
499     PrintHelp("-use-text-label", " Uses TextLabel instead of a TextVisual");
500     return 0;
501   }
502
503   application.MainLoop();
504
505   return 0;
506 }