[dali_1.0.5] Merge branch 'tizen'
[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) { 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
200     PropertyValueMap defaultDirs;
201     defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ]  = DALI_IMAGE_DIR;
202     defaultDirs[ TOKEN_STRING(DALI_MODEL_DIR) ]  = DALI_MODEL_DIR;
203     defaultDirs[ TOKEN_STRING(DALI_SCRIPT_DIR) ] = DALI_SCRIPT_DIR;
204
205     builder.AddConstants( defaultDirs );
206
207     if(!layer)
208     {
209       layer = Layer::New();
210       layer.SetParentOrigin(ParentOrigin::CENTER);
211       layer.SetAnchorPoint(AnchorPoint::CENTER);
212       layer.SetSize( stage.GetRootLayer().GetCurrentSize() );
213       stage.GetRootLayer().Add(layer);
214
215       // render tasks may have been setup last load so remove them
216       RenderTaskList taskList = stage.GetRenderTaskList();
217       if( taskList.GetTaskCount() > 1 )
218       {
219         typedef std::vector<RenderTask> Collection;
220         typedef Collection::iterator ColIter;
221         Collection tasks;
222
223         for(unsigned int i = 1; i < taskList.GetTaskCount(); ++i)
224         {
225           tasks.push_back( taskList.GetTask(i) );
226         }
227
228         for(ColIter iter = tasks.begin(); iter != tasks.end(); ++iter)
229         {
230           taskList.RemoveTask(*iter);
231         }
232
233         RenderTask defaultTask = taskList.GetTask(0);
234         defaultTask.SetSourceActor( stage.GetRootLayer() );
235         defaultTask.SetTargetFrameBuffer( FrameBufferImage() );
236       }
237     }
238
239     unsigned int numChildren = layer.GetChildCount();
240
241     for(unsigned int i=0; i<numChildren; ++i)
242     {
243       layer.Remove( layer.GetChildAt(0) );
244     }
245
246     std::string data(fw.GetFileContents());
247
248     try
249     {
250       builder.LoadFromString(data);
251     }
252     catch(...)
253     {
254       builder.LoadFromString(ReplaceQuotes(JSON_BROKEN));
255     }
256
257     builder.AddActors( layer );
258
259   }
260
261
262   bool OnTimer(void)
263   {
264     if(fw.FileHasChanged())
265     {
266       ReloadJsonFile( mBuilder, mRootLayer );
267     }
268
269     return true;
270   }
271
272   // Process Key events to Quit on back-key
273   void OnKeyEvent( const KeyEvent& event )
274   {
275     if( event.state == KeyEvent::Down )
276     {
277       if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
278       {
279         Application::Get().Quit();
280       }
281     }
282   }
283
284   Builder mBuilder;
285 };
286
287 //------------------------------------------------------------------------------
288 //
289 //
290 //
291 //------------------------------------------------------------------------------
292 int main(int argc, char **argv)
293 {
294   Application dali_app = Application::New(&argc, &argv);
295
296   ExampleApp app(dali_app);
297
298
299   if(argc > 1)
300   {
301     std::cout << "Loading file:" << argc << " " << argv[1] << std::endl;
302     app.SetJSONFilename(argv[1]);
303   }
304   else
305   {
306     DALI_ASSERT_ALWAYS(!"Specify JSON file on command line\n");
307   }
308
309   dali_app.MainLoop();
310
311   return 0;
312 }