diff options
Diffstat (limited to 'library/lua/gui/dialogs.lua')
| -rw-r--r-- | library/lua/gui/dialogs.lua | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua new file mode 100644 index 00000000..b1a96a55 --- /dev/null +++ b/library/lua/gui/dialogs.lua @@ -0,0 +1,268 @@ +-- 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 x,y = self.frame_rect.x1+1, self.frame_rect.y2+1 + dscreen.paintString({fg=COLOR_LIGHTGREEN},x,y,'ESC') + dscreen.paintString({fg=COLOR_GREY},x+3,y,'/') + dscreen.paintString({fg=COLOR_LIGHTGREEN},x+4,y,'y') + 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.selection<self.page_top and self.selection >0 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 |
