Implementation
TODO
editor/controller/save.lua
editor/parts/controller/properties/save.lua
implementation Details
the following functions in editor.controller.index class are mainly used for CRUD of json/lua files in select, save, delete etc. See editor.controller.save.
separate controllers for the audio, group, timer and variable components are implemented i.e
- useClassEditorProps
- setValue
- render
- save
- read
select (read)
See editor.parts.controller directory. selectXXX lua reads json and displays a UI table. The data is passed by nanostore such as bookStore:set, pageStore:set.
nanostore is used as an experimental usage
selectApp.lua
local appFolder = params.appFolder or system.pathForFile( "App", system.ResourceDirectory ) if params.useTinyfiledialogs then appFolder = tfd.selectFolderDialog({ title = "select App folder", default_path = path }) -- print("", appFolder) end if success then local books = {} for file in lfs.dir( appFolder ) do if util.isDir(file) then -- print("", "Found file: " .. file ) -- set them to nanostores if file:len() > 3 and file ~="kwikEditor" then table.insert(books, {name = file, path= util.PATH(appFolder.."/"..file)}) end end end if #books > 0 then UI.editor.bookStore:set(books) end
selectBook.lua
local path =system.pathForFile( "App/"..bookName.."/models", system.ResourceDirectory) UI.editor.currentBook = bookName local success = lfs.chdir( path ) -- isDir works with current dir if success then local pages = {} for file in lfs.dir( path ) do if util.isDir(file) then -- set them to nanostores if file:len() > 3 and file ~='assets' then table.insert(pages, {name = file, path= util.PATH(path.."/"..file)}) end end end if #pages > 0 then UI.editor.pageStore:set(pages) end end
selectPage.lua
if params.page:len() > 0 and UI.page ~= params.page then local app = App.get() app:showView("components." .. params.page .. ".index", {effect = "slideDown"}) end
selectLayer.lua
local path = system.pathForFile( "App/"..UI.editor.currentBook.."/models/"..UI.page .."/"..params.path..getFileName(layerName, className)..".json", system.ResourceDirectory) ... propsTable:setValue(decoded) ...
instead of nanostore, a traditional set/get functions are used here
selectTool.lua
this loads class’s properties of a layer
if params.layer then -- this measn user clicks one of class, anim, button, drag ... UI.editor.currentLayer = params.layer end tool.controller:read(UI.editor.currentBook, UI.page, UI.editor.currentLayer, params.isNew, params.class)
if params.isNew then it loads default values to propsTable
edtior.controller.index
function M:read(book, page, layer, isNew, class) print("read", page, layer, isNew, class) -- the values are used in useClassEdtiorProps() self.page = page self.layer = layer self.isNew = isNew self.class = class if isNew then local path = "editor.template.components.pageX."..self.layerTool..".defaults."..class local template = require(path) self:reset() self:setValue(template, nil, true) self:redraw() elseif layer then -- this comes from clicking layerTable.class local layerName = layer or "index" --local path = page .."/"..layerName.."_"..self.layerTool..".json" local path = system.pathForFile( "App/"..book.."/models/"..page .."/"..layerName.."_"..self.layerTool..".json", system.ResourceDirectory) if self.lastSelection ~= path then self.lastSelection = path local decoded, pos, msg = json.decodeFile( path ) if not decoded then print( "Decode failed at "..tostring(pos)..": "..tostring(msg) ) else print( "File successfully decoded!" ) end self:reset() self:setValue(decoded, 1) self:redraw() else self.view.isNew = true toolbar:toogleToolMap() end end end
For layer’s class, the json is retrived by tool.controller:read above and the read function calls setValue(decoded) inside to display the data to controlProps table.
editor.controller.index
function M:setValue(decoded, index, template) if decoded == nil then return end if not template then print(json.encode(decoded[index])) self.selectbox:setValue(decoded, index) -- "linear 1", "rotation 1" ... self.controlProps:setValue(decoded[index].controls) self.onCompletebox:setValue(decoded[index].actionName) else self.selectbox:setTemplate(decoded) -- "linear 1", "rotation 1" ... self.controlProps:setValue(decoded.controls) self.onCompletebox:setValue(decoded.actionName) end end
generic setValue is implemented in edtior.controller.index, and components can have own setValue for their UI table. for instance,
- editor/animation/controller.lua
- editor/replacement/controller/index.lua
editor.controller.index
the command() reads json with util.decode() from params.
function M:command() local instance = require("commands.kwik.baseCommand").new( function (params) local UI = params.UI local name = params[params.class] or "" local decoded = util.decode(params) -- this reads models/xx.json -- print("From selectors") self.controlProps:didHide(UI) self.controlProps:destroy(UI) self.controlProps:init(UI) self.controlProps:setValue(decoded) self.controlProps.isNew = params.isNew -- self.controlProps:create(UI) self.controlProps:didShow(UI) -- -- self:show() self.controlProps:show() self.onCompletebox:show() self.buttons:show() ...
- util.decode
function M.decode(params) local UI = params.UI if params.isNew then local path = "editor.template.components.pageX."..params.class..".defaults."..params.class return require(path) elseif params.isDelete then print(params.class, "delete") return {} else local name = params[params.class] or "" if params.subclass then name = params.subclass.."/"..name end local path = system.pathForFile( "App/"..UI.editor.currentBook.."/models/"..UI.page .."/"..params.class.."s/"..name..".json", system.ResourceDirectory) decoded, pos, msg = json.decodeFile( path ) if not decoded then print( "Decode failed at "..tostring(pos)..": "..tostring(msg), path ) decoded = {} end return decoded or {} end end
selectAudio.lua
require(“editor.audio.index”).controller:command()
selectTimer.lua
require(“editor.timer.index”).controller:command()
selectVariable.lua
require(“editor.variable.index”).controller:command()
selectGroup.lua
require(“editor.group.controller.selectGroup”)
selectGroup returns a command() for Group
local command = function (params) local UI = params.UI local name = params.group or "" print (params.class) print("selectGroup", name, path, params.show) --print(debug.traceback()) local tableData if params.isNew then local boxData = util.read( UI.editor.currentBook, UI.page) -- tableData = { name = "(new-group)", layers = {}, children = {}, alpha = nil, xScale = nil, yScale = nil, rotation = nil, isLuaTable = nll } UI.editor.groupLayersStore:set(tableData) -- layersTable UI.editor.layerJsonStore:set(boxData.layers) -- layersbox elseif params.isDelete then elseif name:len() > 0 then -- -- layersTable -- local path = system.pathForFile( "App/"..UI.editor.currentBook.."/models/"..UI.page .."/groups/"..name..".json", system.ResourceDirectory) tableData, pos, msg = json.decodeFile( path ) if not tableData then print( "Decode failed at "..tostring(pos)..": "..tostring(msg), path ) tableData = {} end -- -- layersbox -- local boxData = util.read( UI.editor.currentBook, UI.page, function(parent, name) -- let's remove entries of tableData from boxData -- layers = ["GroupA.Ellipse", "GroupA.SubA.Triangle"] for i=1, #tableData.layers do local _name = tableData.layers[i] if parent then if parent .."."..name == _name then return true end elseif name == _name then return true end end return false end) UI.editor.layerJsonStore:set(boxData.layers) -- layersbox UI.editor.groupLayersStore:set(tableData) -- layersTable end -- editor:show()
selectPageIcons.lua
local command = function (params) ... local path = system.pathForFile( "App/"..UI.editor.currentBook.."/models/settings.json", system.ResourceDirectory) ... settingsTable:setValue(decoded) ...
create a new component from toolbar
- selectToolbar.lua
UI.scene.model
UI.scene.model is set when selectPage is called
local scene = require('controller.scene').new(sceneName, {
name = "page1",
components = {
layers = {
{ bg={
} },
{ gotoBtn={ --class={"animation"}
} },
{ title={ class={"linear"} } },
},
audios = {},
groups = {},
timers = {},
variables = {},
page = { }
},
commands = { "eventOne", "eventTwo", "act01" },
onInit = function(scene) print("onInit") end
})
util.read() function parses “App/”..book.."/models/"..page .."/index.json"
...
ret.layers = parser(decoded)
...
setFiles(ret.audios, "/audios/short")
setFiles(ret.audios, "/audios/long")
setFiles(ret.groups, "/groups")
setFiles(ret.commands, "/commands")
return ret
{
layers = {
{name = "layerOne", parent="", children = {
{name="childOne}, parent="layerOne", children = {}}
}
},
{name = "layerTwo", parent="", children = {}},
},
audios = {}
}
save (write)
CRUD operations on json/lua files are mainly for commands and components in a selected page
the editor does not support to create a new entry of App, Book, Page. The properties can be modified for App, Book, Page.
- create/update a layer class
- get props
- render App/booxX/components/pageX/layers/XXX.lua
- save it as a json file
- util.createIndexModel returns the updated scene model if a classname for a layer is newly added
layer names must be unique in a scene model.
```lua
util.createIndexModel(UI.scene.model, UI.editor.currentLayer, classname)
```
```lua
scene = {
name = "canvas",
components = {
layers = {
{ back={
} },
{ butBlue={ class={"button"}, {A={}}, {B={}}
} },
{ butWhite={
} },
},
audios = { },
groups = { },
timers = { },
variables = { },
others = { }
},
}
```
- render App.booxX.components.pageX.index.lua
- save json
- editor.controller.save
local name = ...
local parent, root = parent_root(name)
local util = require("editor.util")
local json = require("json")
--
-- save command performs on one entry.
-- If user switch to another entry without saving, the previous change will be lost.
--
local instance =
require("commands.kwik.baseCommand").new(
function(params)
local UI = params.UI
local props = params.props
local tool = UI.editor:getTool(props.class) -- each tool.contoller can overide render/save. So page tools of audio, group, timer should use own render/save
if tool then
local files = {}
local toolName = UI.editor:getToolName(props.class)
local filename = props.name
local classname = props.class:lower()
-------------
-- save lua
files[#files+1] = tool.controller:render(UI.editor.currentBook, UI.page, UI.editor.currentLayer, toolName, classname, props)
-----------
--- save json
local decoded = params.decoded or {}
decoded[props.index] = props
--
files[#files+1] = tool.controller:save(UI.editor.currentBook, UI.page, UI.editor.currentLayer,toolName, decoded)
-----------
--- Update components/pageX/index.lua model/pageX/index.json
local updatedModel = util.createIndexModel(UI.scene.model, UI.editor.currentLayer, classname)
files[#files+1] = tool.controller:renderIndex(UI.editor.currentBook, UI.page, updatedModel)
files[#files+1] = tool.controller:saveIndex(UI.editor.currentBook, UI.page, UI.editor.currentLayer,classname, updatedModel)
----------
-- publish
util.executePubish(files)
else
print("tool not found for", props.class)
end
end
)
--
return instance
assets
media files of audio, layer replacements(video, spritesheet, particle, syncText, web) in App/bookX/assets folder are indexed with linked layers in assets.json
So tool.controller:save() also performs a write operation on assets.json