summaryrefslogtreecommitdiff
path: root/library/lua/gui/dialogs.lua
diff options
context:
space:
mode:
Diffstat (limited to 'library/lua/gui/dialogs.lua')
-rw-r--r--library/lua/gui/dialogs.lua268
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