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