9c97fecf5858e982ed7a63bd1ef01e26f129ea33
[platform/core/uifw/dali-demo.git] / examples / builder / dali-builder.cpp
1 /*
2  * Copyright (c) 2014 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/public-api/builder/builder.h>
32 #include <dali-toolkit/public-api/builder/tree-node.h>
33 #include <map>
34 #include <string>
35 #include <fstream>
36 #include <streambuf>
37 #include <boost/scoped_ptr.hpp>
38
39 //#include <boost/regex.hpp>
40 #include "sys/stat.h"
41 #include <ctime>
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
53 std::string JSON_BROKEN("                                      \
54 {                                                              \
55   'stage':                                                     \
56   [                                                            \
57     {                                                          \
58       'type':'TextActor',                                      \
59       'size': [50,50,1],                                       \
60       'parent-origin': '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 } // anon namespace
78
79
80 //------------------------------------------------------------------------------
81 //
82 //
83 //
84 //------------------------------------------------------------------------------
85 class FileWatcher
86 {
87 public:
88   FileWatcher(void);
89   ~FileWatcher(void);
90   explicit FileWatcher(const std::string &fn): mLastTime(0) { SetFilename(fn) ; };
91
92   void SetFilename(const std::string &fn);
93   std::string GetFilename();
94
95   bool FileHasChanged(void);
96   std::string GetFileContents(void) { return GetFileContents(mstringPath) ; };
97
98 private:
99   // compiler does
100   // FileWatcher(const FileWatcher&);
101   // FileWatcher &operator=(const FileWatcher &);
102
103   std::time_t mLastTime;
104   std::string mstringPath;
105
106   std::string GetFileContents(const std::string &fn)
107   {
108     std::ifstream t(fn.c_str());
109     return std::string((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
110   };
111 };
112
113 FileWatcher::FileWatcher(void) : mLastTime(0)
114 {
115 }
116
117 bool FileWatcher::FileHasChanged(void)
118 {
119   struct stat buf;
120
121   if(0 != stat(mstringPath.c_str(), &buf))
122   {
123     DALI_LOG_WARNING("File does not exist '%s'\n", mstringPath.c_str());
124     return false;
125   }
126   else
127   {
128     if(buf.st_mtime > mLastTime)
129     {
130       mLastTime = buf.st_mtime;
131       return true;
132     }
133     else
134     {
135       mLastTime = buf.st_mtime;
136       return false;
137     }
138   }
139
140   return false;
141 }
142
143 FileWatcher::~FileWatcher()
144 {
145 }
146
147 void FileWatcher::SetFilename(const std::string &fn)
148 {
149   mstringPath = fn;
150 }
151
152 std::string FileWatcher::GetFilename(void)
153 {
154   return mstringPath;
155 }
156
157
158 //------------------------------------------------------------------------------
159 //
160 //
161 //
162 //------------------------------------------------------------------------------
163 class ExampleApp : public ConnectionTracker
164 {
165 public:
166   ExampleApp(Application &app) : mApp(app)
167   {
168     app.InitSignal().Connect(this, &ExampleApp::Create);
169
170   }
171
172   ~ExampleApp() {}
173
174 public:
175   void SetJSONFilename(std::string const &fn) { fw.SetFilename(fn) ; };
176
177   void Create(Application& app)
178   {
179     mTimer = Timer::New( 500 ); // ms
180     mTimer.TickSignal().Connect( this, &ExampleApp::OnTimer);
181     mTimer.Start();
182
183     // Connect to key events in order to exit
184     Stage::GetCurrent().KeyEventSignal().Connect(this, &ExampleApp::OnKeyEvent);
185   }
186
187 private:
188   Application& mApp;
189   Layer mRootLayer;
190
191   FileWatcher fw;
192   Timer mTimer;
193
194   void ReloadJsonFile(Builder& builder, Layer& layer)
195   {
196     Stage stage = Stage::GetCurrent();
197
198     builder = Builder::New();
199     builder.QuitSignal().Connect( this, &ExampleApp::OnBuilderQuit );
200
201     Property::Map defaultDirs;
202     defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ]  = DALI_IMAGE_DIR;
203     defaultDirs[ TOKEN_STRING(DALI_MODEL_DIR) ]  = DALI_MODEL_DIR;
204     defaultDirs[ TOKEN_STRING(DALI_SCRIPT_DIR) ] = DALI_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 main(int argc, char **argv)
299 {
300   Application dali_app = Application::New(&argc, &argv);
301
302   ExampleApp app(dali_app);
303
304
305   if(argc > 1)
306   {
307     std::cout << "Loading file:" << argc << " " << argv[1] << std::endl;
308     app.SetJSONFilename(argv[1]);
309   }
310   else
311   {
312     DALI_ASSERT_ALWAYS(!"Specify JSON file on command line\n");
313   }
314
315   dali_app.MainLoop();
316
317   return 0;
318 }