Further Setter/Getter public API removal from Dali::Actor
[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/devel-api/adaptor-framework/file-loader.h>
31 #include <dali-toolkit/dali-toolkit.h>
32 #include <dali-toolkit/devel-api/builder/builder.h>
33 #include <dali-toolkit/devel-api/builder/tree-node.h>
34 #include <iostream>
35 #include <map>
36 #include <string>
37 #include <fstream>
38 #include <streambuf>
39
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       '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 } // 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 &filename)
107   {
108     std::streampos bufferSize = 0;
109     Dali::Vector<char> fileBuffer;
110     if( !Dali::FileLoader::ReadFile( filename, bufferSize, fileBuffer, FileLoader::FileType::BINARY ) )
111     {
112       return std::string();
113     }
114
115     return std::string( &fileBuffer[0], bufferSize );
116   };
117 };
118
119 FileWatcher::FileWatcher(void) : mLastTime(0)
120 {
121 }
122
123 bool FileWatcher::FileHasChanged(void)
124 {
125   struct stat buf;
126
127   if(0 != stat(mstringPath.c_str(), &buf))
128   {
129     DALI_LOG_WARNING("File does not exist '%s'\n", mstringPath.c_str());
130     return false;
131   }
132   else
133   {
134     if(buf.st_mtime > mLastTime)
135     {
136       mLastTime = buf.st_mtime;
137       return true;
138     }
139     else
140     {
141       mLastTime = buf.st_mtime;
142       return false;
143     }
144   }
145
146   return false;
147 }
148
149 FileWatcher::~FileWatcher()
150 {
151 }
152
153 void FileWatcher::SetFilename(const std::string &fn)
154 {
155   mstringPath = fn;
156 }
157
158 std::string FileWatcher::GetFilename(void)
159 {
160   return mstringPath;
161 }
162
163
164 //------------------------------------------------------------------------------
165 //
166 //
167 //
168 //------------------------------------------------------------------------------
169 class ExampleApp : public ConnectionTracker
170 {
171 public:
172   ExampleApp(Application &app) : mApp(app)
173   {
174     app.InitSignal().Connect(this, &ExampleApp::Create);
175
176   }
177
178   ~ExampleApp() {}
179
180 public:
181   void SetJSONFilename(std::string const &fn) { fw.SetFilename(fn) ; };
182
183   void Create(Application& app)
184   {
185     mTimer = Timer::New( 500 ); // ms
186     mTimer.TickSignal().Connect( this, &ExampleApp::OnTimer);
187     mTimer.Start();
188
189     // Connect to key events in order to exit
190     Stage::GetCurrent().KeyEventSignal().Connect(this, &ExampleApp::OnKeyEvent);
191   }
192
193 private:
194   Application& mApp;
195   Layer mRootLayer;
196
197   FileWatcher fw;
198   Timer mTimer;
199
200   void ReloadJsonFile(Builder& builder, Layer& layer)
201   {
202     Stage stage = Stage::GetCurrent();
203     stage.SetBackgroundColor( Color::WHITE );
204
205     builder = Builder::New();
206     builder.QuitSignal().Connect( this, &ExampleApp::OnBuilderQuit );
207
208     Property::Map defaultDirs;
209     defaultDirs[ TOKEN_STRING(DEMO_IMAGE_DIR) ]  = DEMO_IMAGE_DIR;
210     defaultDirs[ TOKEN_STRING(DEMO_MODEL_DIR) ]  = DEMO_MODEL_DIR;
211     defaultDirs[ TOKEN_STRING(DEMO_SCRIPT_DIR) ] = DEMO_SCRIPT_DIR;
212
213     builder.AddConstants( defaultDirs );
214
215     if(!layer)
216     {
217       layer = Layer::New();
218       layer.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
219       layer.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::CENTER);
220       layer.SetProperty( Actor::Property::SIZE, stage.GetRootLayer().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) );
221       stage.GetRootLayer().Add(layer);
222
223       // render tasks may have been setup last load so remove them
224       RenderTaskList taskList = stage.GetRenderTaskList();
225       if( taskList.GetTaskCount() > 1 )
226       {
227         typedef std::vector<RenderTask> Collection;
228         typedef Collection::iterator ColIter;
229         Collection tasks;
230
231         for(unsigned int i = 1; i < taskList.GetTaskCount(); ++i)
232         {
233           tasks.push_back( taskList.GetTask(i) );
234         }
235
236         for(ColIter iter = tasks.begin(); iter != tasks.end(); ++iter)
237         {
238           taskList.RemoveTask(*iter);
239         }
240
241         RenderTask defaultTask = taskList.GetTask(0);
242         defaultTask.SetSourceActor( stage.GetRootLayer() );
243         defaultTask.SetTargetFrameBuffer( FrameBufferImage() );
244       }
245     }
246
247     unsigned int numChildren = layer.GetChildCount();
248
249     for(unsigned int i=0; i<numChildren; ++i)
250     {
251       layer.Remove( layer.GetChildAt(0) );
252     }
253
254     std::string data(fw.GetFileContents());
255
256     try
257     {
258       builder.LoadFromString(data);
259     }
260     catch(...)
261     {
262       builder.LoadFromString(ReplaceQuotes(JSON_BROKEN));
263     }
264
265     builder.AddActors( layer );
266
267   }
268
269
270   bool OnTimer(void)
271   {
272     if(fw.FileHasChanged())
273     {
274       ReloadJsonFile( mBuilder, mRootLayer );
275     }
276
277     return true;
278   }
279
280   // Process Key events to Quit on back-key
281   void OnKeyEvent( const KeyEvent& event )
282   {
283     if( event.state == KeyEvent::Down )
284     {
285       if( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
286       {
287         mApp.Quit();
288       }
289     }
290   }
291
292   void OnBuilderQuit()
293   {
294     mApp.Quit();
295   }
296
297   Builder mBuilder;
298 };
299
300 //------------------------------------------------------------------------------
301 //
302 //
303 //
304 //------------------------------------------------------------------------------
305 int DALI_EXPORT_API main(int argc, char **argv)
306 {
307
308   Application dali_app = Application::New(&argc, &argv, DEMO_THEME_PATH);
309   ExampleApp app(dali_app);
310
311   if(argc > 1)
312   {
313     std::cout << "Loading file:" << argc << " " << argv[1] << std::endl;
314     app.SetJSONFilename(argv[1]);
315   }
316   else
317   {
318     DALI_ASSERT_ALWAYS(!"Specify JSON file on command line\n");
319   }
320
321   dali_app.MainLoop();
322
323   return 0;
324 }