diff --git a/scripts/gui/gm-editor.lua b/scripts/gui/gm-editor.lua index d95cb652b..44345b3e8 100644 --- a/scripts/gui/gm-editor.lua +++ b/scripts/gui/gm-editor.lua @@ -1,5 +1,4 @@ -- Interface powered item editor. --- TODO use this: MechanismList = defclass(MechanismList, guidm.MenuOverlay) local gui = require 'gui' local dialog = require 'gui.dialogs' @@ -40,177 +39,181 @@ end local MODE_BROWSE=0 local MODE_EDIT=1 -local item_screen={ +GmEditorUi = defclass(GmEditorUi, gui.FramedScreen) +GmEditorUi.ATTRS={ frame_style = gui.GREY_LINE_FRAME, frame_title = "GameMaster's editor", - stack={}, - item_count=0, - mode=MODE_BROWSE, - - keys={}, - - insertNew=function(self,typename) - local tp=typename - if typename== nil then - dialog.showInputPrompt("Class type","Input class type\n:",COLOR_WHITE,"",dfhack.curry(self.insertNew,self)) - return - end - local ntype=df[tp] - if ntype== nil then - dialog.showMessage("Error!","Type '"..tp.." not found",COLOR_RED) - return - end - - 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) - - end - end, - deleteSelected=function(self) - local trg=self:currentTarget() - if trg.target and trg.target._kind and trg.target._kind=="container" then - trg.target:erase(trg.keys[trg.selected]) - end - end, - currentTarget=function(self) - return self.stack[#self.stack] - end, - changeSelected = function (self,delta) - local trg=self:currentTarget() - if trg.item_count <= 1 then return end - trg.selected = 1 + (trg.selected + delta - 1) % trg.item_count - end, - editSelected = function(self) - local trg=self:currentTarget() - 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]] - 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]]) - 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]]) - elseif trg_type=='boolean' then - trg.target[trg.keys[trg.selected]]= not trg.target[trg.keys[trg.selected]] - elseif trg_type=='userdata' then - self:pushTarget(trg.target[trg.keys[trg.selected]]) - --local screen = mkinstance(gui.FramedScreen,item_screen):init(trg.target[trg.keys[trg.selected]]) -- does not work - --screen:show() - else - print("Unknow type:"..trg_type) - print("Subtype:"..tostring(trg.target[trg.keys[trg.selected]]._kind)) - end - end - end, - cancelEdit = function(self) - self.mode=MODE_BROWSE - self.input="" - end, - commitEdit = function(self) - 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, - onRenderBody = function(self, dc) - 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 - if math.floor(trg.selected / (self.frame_height-offset-2)) >0 then - page_offset=math.floor(trg.selected / (self.frame_height-offset-2))*(self.frame_height-offset-2)-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 - end - current_item=current_item+1 - end - end, - - onInput = function(self,keys) - if self.mode==MODE_BROWSE then - if keys.LEAVESCREEN then - 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_E then - --self:specialEditor() - local screen = mkinstance(TextInputDialog):init("Input new coordinates") - screen:show() - 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 - end - end - end, - pushTarget=function(self,target_to_push) - local new_tbl={} - new_tbl.target=target_to_push - new_tbl.keys={} - new_tbl.selected=1 - for k,v in pairs(target_to_push) do - table.insert(new_tbl.keys,k) - end - new_tbl.item_count=#new_tbl.keys - table.insert(self.stack,new_tbl) - end, - popTarget=function(self) - table.remove(self.stack) --removes last element - if #self.stack==0 then - self:dismiss() - end - end, - init = function(self,item_to_edit) - self:pushTarget(item_to_edit) - self.frame_width,self.frame_height=dfhack.screen.getWindowSize() - return self - end } +function GmEditorUi:init(args) + self.stack={} + self.item_count=0 + self.mode=MODE_BROWSE + self.keys={} + self:pushTarget(args.target) + + return self +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)) + return + end + local ntype=df[tp] + if ntype== nil then + dialog.showMessage("Error!","Type '"..tp.." not found",COLOR_RED) + return + end + + 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) + + end +end +function GmEditorUi:deleteSelected() + local trg=self:currentTarget() + if trg.target and trg.target._kind and trg.target._kind=="container" then + trg.target:erase(trg.keys[trg.selected]) + end +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() + local trg=self:currentTarget() + 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]] + 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]]) + 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]]) + elseif trg_type=='boolean' then + trg.target[trg.keys[trg.selected]]= not trg.target[trg.keys[trg.selected]] + 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() + else + print("Unknow type:"..trg_type) + print("Subtype:"..tostring(trg.target[trg.keys[trg.selected]]._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) + 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 + + end +end + function GmEditorUi:onInput(keys) + if self.mode==MODE_BROWSE then + if keys.LEAVESCREEN then + 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_E then + --self:specialEditor() + local screen = mkinstance(TextInputDialog):init("Input new coordinates") + screen:show() + 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 + end + end +end +function GmEditorUi:pushTarget(target_to_push) + local new_tbl={} + new_tbl.target=target_to_push + new_tbl.keys={} + new_tbl.selected=1 + for k,v in pairs(target_to_push) do + table.insert(new_tbl.keys,k) + end + new_tbl.item_count=#new_tbl.keys + table.insert(self.stack,new_tbl) +end +function GmEditorUi:popTarget() + table.remove(self.stack) --removes last element + if #self.stack==0 then + self:dismiss() + end +end +local screen = GmEditorUi{target=my_trg} - -local screen = mkinstance(gui.FramedScreen,item_screen):init(my_trg) screen:show() \ No newline at end of file