Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / builder / dali-builder.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 //
19 // Run a json script layout file
20 //
21 //  - watches an named file and reloads actor tree if the file changes
22 //    ie run
23 //       builder-run layout.json
24 //
25 //       and edit layout.json in a text editor saving to trigger the reload
26 //
27 //------------------------------------------------------------------------------
28
29 #include <dali-toolkit/dali-toolkit.h>
30 #include <dali-toolkit/devel-api/builder/builder.h>
31 #include <dali-toolkit/devel-api/builder/tree-node.h>
32 #include <dali/dali.h>
33 #include <dali/devel-api/adaptor-framework/file-loader.h>
34 #include <fstream>
35 #include <iostream>
36 #include <map>
37 #include <streambuf>
38 #include <string>
39
40 #include <ctime>
41 #include "sys/stat.h"
42
43 #include <dali/integration-api/debug.h>
44
45 #define TOKEN_STRING(x) #x
46
47 using namespace Dali;
48 using namespace Dali::Toolkit;
49
50 namespace
51 {
52 std::string JSON_BROKEN(
53   "                                      \
54 {                                                              \
55   'stage':                                                     \
56   [                                                            \
57     {                                                          \
58       'type':'TextActor',                                      \
59       'size': [50,50,1],                                       \
60       'parentOrigin': 'CENTER',                                \
61       'text':'COULD NOT LOAD JSON FILE'                        \
62     }                                                          \
63   ]                                                            \
64 }                                                              \
65 ");
66
67 std::string ReplaceQuotes(const std::string& single_quoted)
68 {
69   std::string s(single_quoted);
70
71   // wrong as no embedded quote but had regex link problems
72   std::replace(s.begin(), s.end(), '\'', '"');
73
74   return s;
75 }
76
77 } // namespace
78
79 //------------------------------------------------------------------------------
80 //
81 //
82 //
83 //------------------------------------------------------------------------------
84 class FileWatcher
85 {
86 public:
87   FileWatcher(void);
88   ~FileWatcher(void);
89   explicit FileWatcher(const std::string& fn)
90   : mLastTime(0)
91   {
92     SetFilename(fn);
93   };
94
95   void        SetFilename(const std::string& fn);
96   std::string GetFilename();
97
98   bool        FileHasChanged(void);
99   std::string GetFileContents(void)
100   {
101     return GetFileContents(mstringPath);
102   };
103
104 private:
105   // compiler does
106   // FileWatcher(const FileWatcher&);
107   // FileWatcher &operator=(const FileWatcher &);
108
109   std::time_t mLastTime;
110   std::string mstringPath;
111
112   std::string GetFileContents(const std::string& filename)
113   {
114     std::streampos     bufferSize = 0;
115     Dali::Vector<char> fileBuffer;
116     if(!Dali::FileLoader::ReadFile(filename, bufferSize, fileBuffer, FileLoader::FileType::BINARY))
117     {
118       return std::string();
119     }
120
121     return std::string(&fileBuffer[0], bufferSize);
122   };
123 };
124
125 FileWatcher::FileWatcher(void)
126 : mLastTime(0)
127 {
128 }
129
130 bool FileWatcher::FileHasChanged(void)
131 {
132   struct stat buf;
133
134   if(0 != stat(mstringPath.c_str(), &buf))
135   {
136     DALI_LOG_WARNING("File does not exist '%s'\n", mstringPath.c_str());
137     return false;
138   }
139   else
140   {
141     if(buf.st_mtime > mLastTime)
142     {
143       mLastTime = buf.st_mtime;
144       return true;
145     }
146     else
147     {
148       mLastTime = buf.st_mtime;
149       return false;
150     }
151   }
152
153   return false;
154 }
155
156 FileWatcher::~FileWatcher()
157 {
158 }
159
160 void FileWatcher::SetFilename(const std::string& fn)
161 {
162   mstringPath = fn;
163 }
164
165 std::string FileWatcher::GetFilename(void)
166 {
167   return mstringPath;
168 }
169
170 //------------------------------------------------------------------------------
171 //
172 //
173 //
174 //------------------------------------------------------------------------------
175 class ExampleApp : public ConnectionTracker
176 {
177 public:
178   ExampleApp(Application& app)
179   : mApp(app)
180   {
181     app.InitSignal().Connect(this, &ExampleApp::Create);
182   }
183
184   ~ExampleApp()
185   {
186   }
187
188 public:
189   void SetJSONFilename(std::string const& fn)
190   {
191     fw.SetFilename(fn);
192   };
193
194   void Create(Application& app)
195   {
196     mTimer = Timer::New(500); // ms
197     mTimer.TickSignal().Connect(this, &ExampleApp::OnTimer);
198     mTimer.Start();
199
200     // Connect to key events in order to exit
201     app.GetWindow().KeyEventSignal().Connect(this, &ExampleApp::OnKeyEvent);
202   }
203
204 private:
205   Application& mApp;
206   Layer        mRootLayer;
207
208   FileWatcher fw;
209   Timer       mTimer;
210
211   void ReloadJsonFile(Builder& builder, Layer& layer)
212   {
213     Window window = mApp.GetWindow();
214     window.SetBackgroundColor(Color::WHITE);
215
216     builder = Builder::New();
217     builder.QuitSignal().Connect(this, &ExampleApp::OnBuilderQuit);
218
219     Property::Map defaultDirs;
220     defaultDirs[TOKEN_STRING(DEMO_IMAGE_DIR)]  = DEMO_IMAGE_DIR;
221     defaultDirs[TOKEN_STRING(DEMO_MODEL_DIR)]  = DEMO_MODEL_DIR;
222     defaultDirs[TOKEN_STRING(DEMO_SCRIPT_DIR)] = DEMO_SCRIPT_DIR;
223
224     builder.AddConstants(defaultDirs);
225
226     if(!layer)
227     {
228       layer = Layer::New();
229       layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
230       layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
231       layer.SetProperty(Actor::Property::SIZE, window.GetRootLayer().GetCurrentProperty<Vector3>(Actor::Property::SIZE));
232       window.GetRootLayer().Add(layer);
233
234       // render tasks may have been setup last load so remove them
235       RenderTaskList taskList = window.GetRenderTaskList();
236       if(taskList.GetTaskCount() > 1)
237       {
238         typedef std::vector<RenderTask> Collection;
239         typedef Collection::iterator    ColIter;
240         Collection                      tasks;
241
242         for(unsigned int i = 1; i < taskList.GetTaskCount(); ++i)
243         {
244           tasks.push_back(taskList.GetTask(i));
245         }
246
247         for(ColIter iter = tasks.begin(); iter != tasks.end(); ++iter)
248         {
249           taskList.RemoveTask(*iter);
250         }
251
252         RenderTask defaultTask = taskList.GetTask(0);
253         defaultTask.SetSourceActor(window.GetRootLayer());
254         defaultTask.SetFrameBuffer(FrameBuffer());
255       }
256     }
257
258     unsigned int numChildren = layer.GetChildCount();
259
260     for(unsigned int i = 0; i < numChildren; ++i)
261     {
262       layer.Remove(layer.GetChildAt(0));
263     }
264
265     std::string data(fw.GetFileContents());
266
267     try
268     {
269       builder.LoadFromString(data);
270     }
271     catch(...)
272     {
273       builder.LoadFromString(ReplaceQuotes(JSON_BROKEN));
274     }
275
276     builder.AddActors(layer);
277   }
278
279   bool OnTimer(void)
280   {
281     if(fw.FileHasChanged())
282     {
283       ReloadJsonFile(mBuilder, mRootLayer);
284     }
285
286     return true;
287   }
288
289   // Process Key events to Quit on back-key
290   void OnKeyEvent(const KeyEvent& event)
291   {
292     if(event.GetState() == KeyEvent::DOWN)
293     {
294       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
295       {
296         mApp.Quit();
297       }
298     }
299   }
300
301   void OnBuilderQuit()
302   {
303     mApp.Quit();
304   }
305
306   Builder mBuilder;
307 };
308
309 //------------------------------------------------------------------------------
310 //
311 //
312 //
313 //------------------------------------------------------------------------------
314 int DALI_EXPORT_API main(int argc, char** argv)
315 {
316   Application dali_app = Application::New(&argc, &argv, DEMO_THEME_PATH);
317   ExampleApp  app(dali_app);
318
319   if(argc > 1)
320   {
321     std::cout << "Loading file:" << argc << " " << argv[1] << std::endl;
322     app.SetJSONFilename(argv[1]);
323   }
324   else
325   {
326     DALI_ASSERT_ALWAYS(!"Specify JSON file on command line\n");
327   }
328
329   dali_app.MainLoop();
330
331   return 0;
332 }