2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 //------------------------------------------------------------------------------
19 // Run a json script layout file
21 // - watches an named file and reloads actor tree if the file changes
23 // builder-run layout.json
25 // and edit layout.json in a text editor saving to trigger the reload
27 //------------------------------------------------------------------------------
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>
43 #include <dali/integration-api/debug.h>
45 #define TOKEN_STRING(x) #x
48 using namespace Dali::Toolkit;
52 std::string JSON_BROKEN(
60 'parentOrigin': 'CENTER', \
61 'text':'COULD NOT LOAD JSON FILE' \
67 std::string ReplaceQuotes(const std::string& single_quoted)
69 std::string s(single_quoted);
71 // wrong as no embedded quote but had regex link problems
72 std::replace(s.begin(), s.end(), '\'', '"');
79 //------------------------------------------------------------------------------
83 //------------------------------------------------------------------------------
89 explicit FileWatcher(const std::string& fn)
95 void SetFilename(const std::string& fn);
96 std::string GetFilename();
98 bool FileHasChanged(void);
99 std::string GetFileContents(void)
101 return GetFileContents(mstringPath);
106 // FileWatcher(const FileWatcher&);
107 // FileWatcher &operator=(const FileWatcher &);
109 std::time_t mLastTime;
110 std::string mstringPath;
112 std::string GetFileContents(const std::string& filename)
114 std::streampos bufferSize = 0;
115 Dali::Vector<char> fileBuffer;
116 if(!Dali::FileLoader::ReadFile(filename, bufferSize, fileBuffer, FileLoader::FileType::BINARY))
118 return std::string();
121 return std::string(&fileBuffer[0], bufferSize);
125 FileWatcher::FileWatcher(void)
130 bool FileWatcher::FileHasChanged(void)
134 if(0 != stat(mstringPath.c_str(), &buf))
136 DALI_LOG_WARNING("File does not exist '%s'\n", mstringPath.c_str());
141 if(buf.st_mtime > mLastTime)
143 mLastTime = buf.st_mtime;
148 mLastTime = buf.st_mtime;
156 FileWatcher::~FileWatcher()
160 void FileWatcher::SetFilename(const std::string& fn)
165 std::string FileWatcher::GetFilename(void)
170 //------------------------------------------------------------------------------
174 //------------------------------------------------------------------------------
175 class ExampleApp : public ConnectionTracker
178 ExampleApp(Application& app)
181 app.InitSignal().Connect(this, &ExampleApp::Create);
189 void SetJSONFilename(std::string const& fn)
194 void Create(Application& app)
196 mTimer = Timer::New(500); // ms
197 mTimer.TickSignal().Connect(this, &ExampleApp::OnTimer);
200 // Connect to key events in order to exit
201 app.GetWindow().KeyEventSignal().Connect(this, &ExampleApp::OnKeyEvent);
211 void ReloadJsonFile(Builder& builder, Layer& layer)
213 Window window = mApp.GetWindow();
214 window.SetBackgroundColor(Color::WHITE);
216 builder = Builder::New();
217 builder.QuitSignal().Connect(this, &ExampleApp::OnBuilderQuit);
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;
224 builder.AddConstants(defaultDirs);
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);
234 // render tasks may have been setup last load so remove them
235 RenderTaskList taskList = window.GetRenderTaskList();
236 if(taskList.GetTaskCount() > 1)
238 typedef std::vector<RenderTask> Collection;
239 typedef Collection::iterator ColIter;
242 for(unsigned int i = 1; i < taskList.GetTaskCount(); ++i)
244 tasks.push_back(taskList.GetTask(i));
247 for(ColIter iter = tasks.begin(); iter != tasks.end(); ++iter)
249 taskList.RemoveTask(*iter);
252 RenderTask defaultTask = taskList.GetTask(0);
253 defaultTask.SetSourceActor(window.GetRootLayer());
254 defaultTask.SetFrameBuffer(FrameBuffer());
258 unsigned int numChildren = layer.GetChildCount();
260 for(unsigned int i = 0; i < numChildren; ++i)
262 layer.Remove(layer.GetChildAt(0));
265 std::string data(fw.GetFileContents());
269 builder.LoadFromString(data);
273 builder.LoadFromString(ReplaceQuotes(JSON_BROKEN));
276 builder.AddActors(layer);
281 if(fw.FileHasChanged())
283 ReloadJsonFile(mBuilder, mRootLayer);
289 // Process Key events to Quit on back-key
290 void OnKeyEvent(const KeyEvent& event)
292 if(event.GetState() == KeyEvent::DOWN)
294 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
309 //------------------------------------------------------------------------------
313 //------------------------------------------------------------------------------
314 int DALI_EXPORT_API main(int argc, char** argv)
316 Application dali_app = Application::New(&argc, &argv, DEMO_THEME_PATH);
317 ExampleApp app(dali_app);
321 std::cout << "Loading file:" << argc << " " << argv[1] << std::endl;
322 app.SetJSONFilename(argv[1]);
326 DALI_ASSERT_ALWAYS(!"Specify JSON file on command line\n");