|
|
|
@ -1,7 +1,17 @@
|
|
|
|
|
-- Interface powered item editor.
|
|
|
|
|
local gui = require 'gui'
|
|
|
|
|
local dialog = require 'gui.dialogs'
|
|
|
|
|
local widgets =require 'gui.widgets'
|
|
|
|
|
local args={...}
|
|
|
|
|
|
|
|
|
|
local keybindings={
|
|
|
|
|
offset={key="CUSTOM_ALT_O",desc="Show current items offset"},
|
|
|
|
|
find={key="CUSTOM_F",desc="Find a value by entering a predicate"},
|
|
|
|
|
lua_set={key="CUSTOM_ALT_S",desc="Set by using a lua function"},
|
|
|
|
|
insert={key="CUSTOM_ALT_I",desc="Insert a new value to the vector"},
|
|
|
|
|
delete={key="CUSTOM_ALT_D",desc="Delete selected entry"},
|
|
|
|
|
help={key="HELP",desc="Show this help"},
|
|
|
|
|
}
|
|
|
|
|
function getTargetFromScreens()
|
|
|
|
|
local my_trg
|
|
|
|
|
if dfhack.gui.getCurFocus() == 'item' then
|
|
|
|
@ -28,46 +38,94 @@ function getTargetFromScreens()
|
|
|
|
|
return my_trg
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local MODE_BROWSE=0
|
|
|
|
|
local MODE_EDIT=1
|
|
|
|
|
GmEditorUi = defclass(GmEditorUi, gui.FramedScreen)
|
|
|
|
|
GmEditorUi.ATTRS={
|
|
|
|
|
frame_style = gui.GREY_LINE_FRAME,
|
|
|
|
|
frame_title = "GameMaster's editor",
|
|
|
|
|
}
|
|
|
|
|
function GmEditorUi:onHelp()
|
|
|
|
|
self.subviews.pages:setSelected(2)
|
|
|
|
|
end
|
|
|
|
|
function burning_red(input) -- todo does not work! bug angavrilov that so that he would add this, very important!!
|
|
|
|
|
local col=COLOR_LIGHTRED
|
|
|
|
|
return {text=input,pen=dfhack.pen.parse{fg=COLOR_LIGHTRED,bg=0}}
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:init(args)
|
|
|
|
|
self.stack={}
|
|
|
|
|
self.item_count=0
|
|
|
|
|
self.mode=MODE_BROWSE
|
|
|
|
|
self.keys={}
|
|
|
|
|
self:pushTarget(args.target)
|
|
|
|
|
local helptext={{text="Help"},NEWLINE,NEWLINE}
|
|
|
|
|
for k,v in pairs(keybindings) do
|
|
|
|
|
table.insert(helptext,{text=v.desc,key=v.key,key_sep=':'})
|
|
|
|
|
table.insert(helptext,NEWLINE)
|
|
|
|
|
end
|
|
|
|
|
table.insert(helptext,NEWLINE)
|
|
|
|
|
table.insert(helptext,{text="DISCLAIMER:",pen=dfhack.pen.parse{fg=COLOR_RED,bg=0}})
|
|
|
|
|
table.insert(helptext,NEWLINE)
|
|
|
|
|
table.insert(helptext,"Association Of ")
|
|
|
|
|
table.insert(helptext,{text="Psychic ",pen=dfhack.pen.parse{fg=COLOR_YELLOW,bg=0}})
|
|
|
|
|
table.insert(helptext,"Dwarves (AOPD) is not responsible for all the damage")
|
|
|
|
|
table.insert(helptext,NEWLINE)
|
|
|
|
|
table.insert(helptext,"that this tool can (and will) cause to you and your loved dwarves")
|
|
|
|
|
table.insert(helptext,NEWLINE)
|
|
|
|
|
table.insert(helptext,"and/or saves.Please use with caution.")
|
|
|
|
|
table.insert(helptext,NEWLINE)
|
|
|
|
|
table.insert(helptext,{text="Magma not included.",pen=dfhack.pen.parse{fg=COLOR_LIGHTRED,bg=0}})
|
|
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
local helpPage=widgets.Panel{
|
|
|
|
|
subviews={widgets.Label{text=helptext,frame = {l=1,t=1,yalign=0}}}}
|
|
|
|
|
local mainList=widgets.List{view_id="list_main",choices={},frame = {l=1,t=3,yalign=0},on_submit=self:callback("editSelected"),
|
|
|
|
|
text_pen=dfhack.pen.parse{fg=COLOR_DARKGRAY,bg=0},cursor_pen=dfhack.pen.parse{fg=COLOR_YELLOW,bg=0}}
|
|
|
|
|
local mainPage=widgets.Panel{
|
|
|
|
|
subviews={
|
|
|
|
|
mainList,
|
|
|
|
|
widgets.Label{text={{text="<no item>",id="name",minw=50},{gap=1,text="Help",key="HELP",key_sep = '()'}}, view_id = 'lbl_current_item',frame = {l=1,t=1,yalign=0}},
|
|
|
|
|
--widgets.Label{text="BLAH2"}
|
|
|
|
|
}
|
|
|
|
|
,view_id='page_main'}
|
|
|
|
|
|
|
|
|
|
local pages=widgets.Pages{subviews={mainPage,helpPage},view_id="pages"}
|
|
|
|
|
self:addviews{
|
|
|
|
|
pages
|
|
|
|
|
}
|
|
|
|
|
self:pushTarget(args.target)
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:find(test)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
|
|
|
|
|
if test== nil then
|
|
|
|
|
dialog.showInputPrompt("Test function","Input function that tests(k,v as argument):",COLOR_WHITE,"",dfhack.curry(self.find,self))
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local e,what=load("return function(k,v) return "..test.." end")
|
|
|
|
|
if e==nil then
|
|
|
|
|
dialog.showMessage("Error!","function failed to compile\n"..what,COLOR_RED)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if trg.target and trg.target._kind and trg.target._kind=="container" then
|
|
|
|
|
if test== nil then
|
|
|
|
|
dialog.showInputPrompt("Test function","Input function that tests(k,v as argument):",COLOR_WHITE,"",dfhack.curry(self.find,self))
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local e,what=load("return function(k,v) return "..test.." end")
|
|
|
|
|
if e==nil then
|
|
|
|
|
dialog.showMessage("Error!","function failed to compile\n"..what,COLOR_RED)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
for k,v in pairs(trg.target) do
|
|
|
|
|
if e()(k,v)==true then
|
|
|
|
|
self:pushTarget(v)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
local i=1
|
|
|
|
|
for k,v in pairs(trg.target) do
|
|
|
|
|
if e()(k,v)==true then
|
|
|
|
|
self.subviews.list_main:setSelected(i)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
i=i+1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:insertNew(typename)
|
|
|
|
|
local tp=typename
|
|
|
|
|
if typename== nil then
|
|
|
|
|
dialog.showInputPrompt("Class type","Input class type:",COLOR_WHITE,"",dfhack.curry(self.insertNew,self))
|
|
|
|
|
dialog.showInputPrompt("Class type","Input class type:",COLOR_WHITE,"",self:callback("insertNew"))
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local ntype=df[tp]
|
|
|
|
@ -79,152 +137,124 @@ function GmEditorUi:insertNew(typename)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
if trg.target and trg.target._kind and trg.target._kind=="container" then
|
|
|
|
|
local thing=ntype:new()
|
|
|
|
|
dfhack.call_with_finalizer(1,false,df.delete,thing,trg.target.insert,trg.target,'#',thing)
|
|
|
|
|
dfhack.call_with_finalizer(1,false,df.delete,thing,function (tscreen,target,to_insert)
|
|
|
|
|
target:insert("#",to_insert); tscreen:updateTarget(true,true);end,self,trg.target,thing)
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:deleteSelected()
|
|
|
|
|
function GmEditorUi:deleteSelected(key)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
if trg.target and trg.target._kind and trg.target._kind=="container" then
|
|
|
|
|
trg.target:erase(trg.keys[trg.selected])
|
|
|
|
|
trg.target:erase(key)
|
|
|
|
|
self:updateTarget(true,true)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:getSelectedKey()
|
|
|
|
|
return self:currentTarget().keys[self.subviews.list_main:getSelected()]
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:currentTarget()
|
|
|
|
|
return self.stack[#self.stack]
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:changeSelected(delta)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
if trg.item_count <= 1 then return end
|
|
|
|
|
trg.selected = 1 + (trg.selected + delta - 1) % trg.item_count
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:editSelected()
|
|
|
|
|
function GmEditorUi:editSelected(index,choice)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
local trg_key=trg.keys[index]
|
|
|
|
|
if trg.target and trg.target._kind and trg.target._kind=="bitfield" then
|
|
|
|
|
trg.target[trg.keys[trg.selected]]= not trg.target[trg.keys[trg.selected]]
|
|
|
|
|
trg.target[trg_key]= not trg.target[trg_key]
|
|
|
|
|
self:updateTarget(true)
|
|
|
|
|
else
|
|
|
|
|
--print(type(trg.target[trg.keys[trg.selected]]),trg.target[trg.keys[trg.selected]]._kind or "")
|
|
|
|
|
local trg_type=type(trg.target[trg.keys[trg.selected]])
|
|
|
|
|
local trg_type=type(trg.target[trg_key])
|
|
|
|
|
if trg_type=='number' or trg_type=='string' then --ugly TODO: add metatable get selected
|
|
|
|
|
self.mode=MODE_EDIT
|
|
|
|
|
self.input=tostring(trg.target[trg.keys[trg.selected]])
|
|
|
|
|
dialog.showInputPrompt(trg_key,"Enter new value:",COLOR_WHITE,
|
|
|
|
|
tostring(trg.target[trg_key]),self:callback("commitEdit",trg_key))
|
|
|
|
|
|
|
|
|
|
elseif trg_type=='boolean' then
|
|
|
|
|
trg.target[trg.keys[trg.selected]]= not trg.target[trg.keys[trg.selected]]
|
|
|
|
|
trg.target[trg_key]= not trg.target[trg_key]
|
|
|
|
|
self:updateTarget(true)
|
|
|
|
|
elseif trg_type=='userdata' then
|
|
|
|
|
self:pushTarget(trg.target[trg.keys[trg.selected]])
|
|
|
|
|
--local screen = mkinstance(gui.FramedScreen,GmEditorUi):init(trg.target[trg.keys[trg.selected]]) -- does not work
|
|
|
|
|
--screen:show()
|
|
|
|
|
self:pushTarget(trg.target[trg_key])
|
|
|
|
|
else
|
|
|
|
|
print("Unknow type:"..trg_type)
|
|
|
|
|
print("Subtype:"..tostring(trg.target[trg.keys[trg.selected]]._kind))
|
|
|
|
|
print("Subtype:"..tostring(trg.target[trg_key]._kind))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:cancelEdit()
|
|
|
|
|
self.mode=MODE_BROWSE
|
|
|
|
|
self.input=""
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:commitEdit()
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
self.mode=MODE_BROWSE
|
|
|
|
|
if type(trg.target[trg.keys[trg.selected]])=='number' then
|
|
|
|
|
trg.target[trg.keys[trg.selected]]=tonumber(self.input)
|
|
|
|
|
elseif type(trg.target[trg.keys[trg.selected]])=='string' then
|
|
|
|
|
trg.target[trg.keys[trg.selected]]=self.input
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:onRenderBody( dc)
|
|
|
|
|
|
|
|
|
|
function GmEditorUi:commitEdit(key,value)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
dc:seek(2,1):string(tostring(trg.target), COLOR_RED)
|
|
|
|
|
local offset=2
|
|
|
|
|
local page_offset=0
|
|
|
|
|
local current_item=1
|
|
|
|
|
local t_col
|
|
|
|
|
local width,height=self:getWindowSize()
|
|
|
|
|
local window_height=height-offset-2
|
|
|
|
|
local cursor_window=math.floor(trg.selected / window_height)
|
|
|
|
|
if cursor_window>0 then
|
|
|
|
|
page_offset=cursor_window*window_height-1
|
|
|
|
|
end
|
|
|
|
|
for k,v in pairs(trg.target) do
|
|
|
|
|
|
|
|
|
|
if current_item==trg.selected then
|
|
|
|
|
t_col=COLOR_LIGHTGREEN
|
|
|
|
|
else
|
|
|
|
|
t_col=COLOR_GRAY
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if current_item-page_offset > 0 then
|
|
|
|
|
local y_pos=current_item-page_offset+offset
|
|
|
|
|
dc:seek(2,y_pos):string(tostring(k),t_col)
|
|
|
|
|
|
|
|
|
|
if self.mode==MODE_EDIT and current_item==trg.selected then
|
|
|
|
|
dc:seek(20,y_pos):string(self.input..'_',COLOR_GREEN)
|
|
|
|
|
else
|
|
|
|
|
dc:seek(20,y_pos):string(tostring(v),t_col)
|
|
|
|
|
end
|
|
|
|
|
if y_pos+3>height then
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
current_item=current_item+1
|
|
|
|
|
|
|
|
|
|
if type(trg.target[key])=='number' then
|
|
|
|
|
trg.target[key]=tonumber(value)
|
|
|
|
|
elseif type(trg.target[key])=='string' then
|
|
|
|
|
trg.target[key]=value
|
|
|
|
|
end
|
|
|
|
|
self:updateTarget(true)
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:set(input)
|
|
|
|
|
|
|
|
|
|
function GmEditorUi:set(key,input)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
|
|
|
|
|
if input== nil then
|
|
|
|
|
dialog.showInputPrompt("Set to what?","Lua code to set to (v cur target):",COLOR_WHITE,"",dfhack.curry(self.set,self))
|
|
|
|
|
dialog.showInputPrompt("Set to what?","Lua code to set to (v cur target):",COLOR_WHITE,"",self:callback("set",key))
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local e,what=load("return function(v) return "..input.." end")
|
|
|
|
|
if e==nil then
|
|
|
|
|
dialog.showMessage("Error!","function failed to compile\n"..what,COLOR_RED)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
trg.target[trg.keys[trg.selected]]=e()(trg)
|
|
|
|
|
trg.target[key]=e()(trg)
|
|
|
|
|
self:updateTarget(true)
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:onInput(keys)
|
|
|
|
|
if self.mode==MODE_BROWSE then
|
|
|
|
|
if keys.LEAVESCREEN then
|
|
|
|
|
function GmEditorUi:onInput(keys)
|
|
|
|
|
|
|
|
|
|
if keys.LEAVESCREEN then
|
|
|
|
|
if self.subviews.pages:getSelected()==2 then
|
|
|
|
|
self.subviews.pages:setSelected(1)
|
|
|
|
|
else
|
|
|
|
|
self:popTarget()
|
|
|
|
|
elseif keys.CURSOR_UP then
|
|
|
|
|
self:changeSelected(-1)
|
|
|
|
|
elseif keys.CURSOR_DOWN then
|
|
|
|
|
self:changeSelected(1)
|
|
|
|
|
elseif keys.CURSOR_UP_FAST then
|
|
|
|
|
self:changeSelected(-10)
|
|
|
|
|
elseif keys.CURSOR_DOWN_FAST then
|
|
|
|
|
self:changeSelected(10)
|
|
|
|
|
elseif keys.SELECT then
|
|
|
|
|
self:editSelected()
|
|
|
|
|
elseif keys.CUSTOM_ALT_O then
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
local size,off=df.sizeof(trg.target:_field(trg.keys[trg.selected]))
|
|
|
|
|
dialog.showMessage("Offset",string.format("Size hex=%x,%x dec=%d,%d",size,off,size,off),COLOR_WHITE)
|
|
|
|
|
elseif keys.CUSTOM_ALT_F then
|
|
|
|
|
self:find()
|
|
|
|
|
elseif keys.CUSTOM_ALT_S then
|
|
|
|
|
self:set()
|
|
|
|
|
elseif keys.CUSTOM_ALT_E then
|
|
|
|
|
--self:specialEditor()
|
|
|
|
|
elseif keys.CUSTOM_ALT_I then --insert
|
|
|
|
|
self:insertNew()
|
|
|
|
|
elseif keys.CUSTOM_ALT_D then --delete
|
|
|
|
|
self:deleteSelected()
|
|
|
|
|
end
|
|
|
|
|
elseif self.mode==MODE_EDIT then
|
|
|
|
|
if keys.LEAVESCREEN then
|
|
|
|
|
self:cancelEdit()
|
|
|
|
|
elseif keys.SELECT then
|
|
|
|
|
self:commitEdit()
|
|
|
|
|
elseif keys._STRING then
|
|
|
|
|
if keys._STRING==0 then
|
|
|
|
|
self.input=string.sub(self.input,1,-2)
|
|
|
|
|
else
|
|
|
|
|
self.input=self.input.. string.char(keys._STRING)
|
|
|
|
|
end
|
|
|
|
|
elseif keys[keybindings.offset.key] then
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
local size,off=df.sizeof(trg.target:_field(trg.keys[trg.selected]))
|
|
|
|
|
dialog.showMessage("Offset",string.format("Size hex=%x,%x dec=%d,%d",size,off,size,off),COLOR_WHITE)
|
|
|
|
|
--elseif keys.CUSTOM_ALT_F then --filter?
|
|
|
|
|
elseif keys[keybindings.find.key] then
|
|
|
|
|
self:find()
|
|
|
|
|
elseif keys[keybindings.lua_set.key] then
|
|
|
|
|
self:set(self:getSelectedKey())
|
|
|
|
|
--elseif keys.CUSTOM_I then
|
|
|
|
|
-- self:insertSimple()
|
|
|
|
|
elseif keys[keybindings.insert.key] then --insert
|
|
|
|
|
self:insertNew()
|
|
|
|
|
elseif keys[keybindings.delete.key] then --delete
|
|
|
|
|
self:deleteSelected(self:getSelectedKey())
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
self.super.onInput(self,keys)
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:updateTarget(preserve_pos,reindex)
|
|
|
|
|
local trg=self:currentTarget()
|
|
|
|
|
if reindex then
|
|
|
|
|
trg.keys={}
|
|
|
|
|
for k,v in pairs(trg.target) do
|
|
|
|
|
table.insert(trg.keys,k)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
self.subviews.lbl_current_item:itemById('name').text=tostring(trg.target)
|
|
|
|
|
local t={}
|
|
|
|
|
for k,v in pairs(trg.keys) do
|
|
|
|
|
table.insert(t,{text={{text=tostring(v),minw=25},{gap=1,text=tostring(trg.target[v]),}}})
|
|
|
|
|
end
|
|
|
|
|
local last_pos
|
|
|
|
|
if preserve_pos then
|
|
|
|
|
last_pos=self.subviews.list_main:getSelected()
|
|
|
|
|
end
|
|
|
|
|
self.subviews.list_main:setChoices(t)
|
|
|
|
|
if last_pos then
|
|
|
|
|
self.subviews.list_main:setSelected(last_pos)
|
|
|
|
|
else
|
|
|
|
|
self.subviews.list_main:setSelected(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:pushTarget(target_to_push)
|
|
|
|
|
local new_tbl={}
|
|
|
|
@ -236,12 +266,16 @@ function GmEditorUi:pushTarget(target_to_push)
|
|
|
|
|
end
|
|
|
|
|
new_tbl.item_count=#new_tbl.keys
|
|
|
|
|
table.insert(self.stack,new_tbl)
|
|
|
|
|
|
|
|
|
|
self:updateTarget()
|
|
|
|
|
end
|
|
|
|
|
function GmEditorUi:popTarget()
|
|
|
|
|
table.remove(self.stack) --removes last element
|
|
|
|
|
if #self.stack==0 then
|
|
|
|
|
self:dismiss()
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
self:updateTarget()
|
|
|
|
|
end
|
|
|
|
|
function show_editor(trg)
|
|
|
|
|
local screen = GmEditorUi{target=trg}
|
|
|
|
|