-- Some simple dialog screens local _ENV = mkmodule('gui.dialogs') local gui = require('gui') local utils = require('utils') local dscreen = dfhack.screen MessageBox = defclass(MessageBox, gui.FramedScreen) MessageBox.focus_path = 'MessageBox' MessageBox.ATTRS{ frame_style = gui.GREY_LINE_FRAME, -- new attrs text = {}, on_accept = DEFAULT_NIL, on_cancel = DEFAULT_NIL, on_close = DEFAULT_NIL, text_pen = DEFAULT_NIL, } function MessageBox:preinit(info) if type(info.text) == 'string' then info.text = utils.split_string(info.text, "\n") end end function MessageBox:getWantedFrameSize() local text = self.text local w = #(self.frame_title or '') + 4 w = math.max(w, 20) w = math.max(self.frame_width or w, w) for _, l in ipairs(text) do w = math.max(w, #l) end local h = #text+1 if h > 1 then h = h+1 end return w+2, #text+2 end function MessageBox:onRenderBody(dc) if #self.text > 0 then dc:newline(1):pen(self.text_pen or COLOR_GREY) for _, l in ipairs(self.text or {}) do dc:string(l):newline(1) end end if self.on_accept then local fr = self.frame_rect local dc2 = gui.Painter.new_xy(fr.x1+1,fr.y2+1,fr.x2-8,fr.y2+1) dc2:key('LEAVESCREEN'):string('/'):key('MENU_CONFIRM') end end function MessageBox:onDestroy() if self.on_close then self.on_close() end end function MessageBox:onInput(keys) if keys.MENU_CONFIRM then self:dismiss() if self.on_accept then self.on_accept() end elseif keys.LEAVESCREEN or (keys.SELECT and not self.on_accept) then self:dismiss() if self.on_cancel then self.on_cancel() end end end function showMessage(title, text, tcolor, on_close) MessageBox{ frame_title = title, text = text, text_pen = tcolor, on_close = on_close }:show() end function showYesNoPrompt(title, text, tcolor, on_accept, on_cancel) MessageBox{ frame_title = title, text = text, text_pen = tcolor, on_accept = on_accept, on_cancel = on_cancel, }:show() end InputBox = defclass(InputBox, MessageBox) InputBox.focus_path = 'InputBox' InputBox.ATTRS{ input = '', input_pen = DEFAULT_NIL, on_input = DEFAULT_NIL, } function InputBox:preinit(info) info.on_accept = nil end function InputBox:getWantedFrameSize() local mw, mh = InputBox.super.getWantedFrameSize(self) return mw, mh+2 end function InputBox:onRenderBody(dc) InputBox.super.onRenderBody(self, dc) dc:newline(1) dc:pen(self.input_pen or COLOR_LIGHTCYAN) dc:fill(1,dc:localY(),dc.width-2,dc:localY()) local cursor = '_' if math.floor(dfhack.getTickCount()/300) % 2 == 0 then cursor = ' ' end local txt = self.input .. cursor if #txt > dc.width-2 then txt = string.char(27)..string.sub(txt, #txt-dc.width+4) end dc:string(txt) end function InputBox:onInput(keys) if keys.SELECT then self:dismiss() if self.on_input then self.on_input(self.input) end elseif keys.LEAVESCREEN then self:dismiss() if self.on_cancel then self.on_cancel() end elseif keys._STRING then if keys._STRING == 0 then self.input = string.sub(self.input, 1, #self.input-1) else self.input = self.input .. string.char(keys._STRING) end end end function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width) InputBox{ frame_title = title, text = text, text_pen = tcolor, input = input, on_input = on_input, on_cancel = on_cancel, frame_width = min_width, }:show() end ListBox = defclass(ListBox, MessageBox) ListBox.focus_path = 'ListBox' ListBox.ATTRS{ selection = 0, choices = {}, select_pen = DEFAULT_NIL, on_input = DEFAULT_NIL } function InputBox:preinit(info) info.on_accept = nil end function ListBox:init(info) self.page_top = 0 end function ListBox:getWantedFrameSize() local mw, mh = ListBox.super.getWantedFrameSize(self) return mw, mh+#self.choices end function ListBox:onRenderBody(dc) ListBox.super.onRenderBody(self, dc) dc:newline(1) if self.selection>dc.height-3 then self.page_top=self.selection-(dc.height-3) elseif self.selection0 then self.page_top=self.selection-1 end for i,entry in ipairs(self.choices) do if type(entry)=="table" then entry=entry[1] end if i>self.page_top then if i == self.selection then dc:pen(self.select_pen or COLOR_LIGHTCYAN) else dc:pen(self.text_pen or COLOR_GREY) end dc:string(entry) dc:newline(1) end end end function ListBox:moveCursor(delta) local newsel=self.selection+delta if #self.choices ~=0 then if newsel<1 or newsel>#self.choices then newsel=newsel % #self.choices end end self.selection=newsel end function ListBox:onInput(keys) if keys.SELECT then self:dismiss() local choice=self.choices[self.selection] if self.on_input then self.on_input(self.selection,choice) end if choice and choice[2] then choice[2](choice,self.selection) -- maybe reverse the arguments? end elseif keys.LEAVESCREEN then self:dismiss() if self.on_cancel then self.on_cancel() end elseif keys.CURSOR_UP then self:moveCursor(-1) elseif keys.CURSOR_DOWN then self:moveCursor(1) elseif keys.CURSOR_UP_FAST then self:moveCursor(-10) elseif keys.CURSOR_DOWN_FAST then self:moveCursor(10) end end function showListPrompt(title, text, tcolor, choices, on_input, on_cancel, min_width) ListBox{ frame_title = title, text = text, text_pen = tcolor, choices = choices, on_input = on_input, on_cancel = on_cancel, frame_width = min_width, }:show() end return _ENV