296 lines
6.8 KiB
Lua
296 lines
6.8 KiB
Lua
-- 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:cursorY(),dc.width-2,dc:cursorY())
|
|
|
|
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 = 1,
|
|
choices = {},
|
|
select_pen = DEFAULT_NIL,
|
|
on_select = DEFAULT_NIL
|
|
}
|
|
|
|
function InputBox:preinit(info)
|
|
info.on_accept = nil
|
|
end
|
|
|
|
function ListBox:init(info)
|
|
self.page_top = 1
|
|
end
|
|
|
|
local function choice_text(entry)
|
|
if type(entry)=="table" then
|
|
return entry.caption or entry[1]
|
|
else
|
|
return entry
|
|
end
|
|
end
|
|
|
|
function ListBox:getWantedFrameSize()
|
|
local mw, mh = ListBox.super.getWantedFrameSize(self)
|
|
for _,v in ipairs(self.choices) do
|
|
local text = choice_text(v)
|
|
mw = math.max(mw, #text+2)
|
|
end
|
|
return mw, mh+#self.choices+1
|
|
end
|
|
|
|
function ListBox:postUpdateLayout()
|
|
self.page_size = self.frame_rect.height - #self.text - 3
|
|
self:moveCursor(0)
|
|
end
|
|
|
|
function ListBox:moveCursor(delta)
|
|
local page = math.max(1, self.page_size)
|
|
local cnt = #self.choices
|
|
local off = self.selection+delta-1
|
|
local ds = math.abs(delta)
|
|
|
|
if ds > 1 then
|
|
if off >= cnt+ds-1 then
|
|
off = 0
|
|
else
|
|
off = math.min(cnt-1, off)
|
|
end
|
|
if off <= -ds then
|
|
off = cnt-1
|
|
else
|
|
off = math.max(0, off)
|
|
end
|
|
end
|
|
|
|
self.selection = 1 + off % cnt
|
|
self.page_top = 1 + page * math.floor((self.selection-1) / page)
|
|
end
|
|
|
|
function ListBox:onRenderBody(dc)
|
|
ListBox.super.onRenderBody(self, dc)
|
|
|
|
dc:newline(1):pen(self.select_pen or COLOR_CYAN)
|
|
|
|
local choices = self.choices
|
|
local iend = math.min(#choices, self.page_top+self.page_size-1)
|
|
|
|
for i = self.page_top,iend do
|
|
local text = choice_text(choices[i])
|
|
if text then
|
|
dc.cur_pen.bold = (i == self.selection);
|
|
dc:string(text)
|
|
else
|
|
dc:string('?ERROR?', COLOR_LIGHTRED)
|
|
end
|
|
dc:newline(1)
|
|
end
|
|
end
|
|
|
|
function ListBox:onInput(keys)
|
|
if keys.SELECT then
|
|
self:dismiss()
|
|
|
|
local choice=self.choices[self.selection]
|
|
if self.on_select then
|
|
self.on_select(self.selection, choice)
|
|
end
|
|
|
|
if choice then
|
|
local callback = choice.on_select or choice[2]
|
|
if callback then
|
|
callback(choice, self.selection)
|
|
end
|
|
end
|
|
elseif keys.LEAVESCREEN then
|
|
self:dismiss()
|
|
if self.on_cancel then
|
|
self.on_cancel()
|
|
end
|
|
elseif keys.STANDARDSCROLL_UP then
|
|
self:moveCursor(-1)
|
|
elseif keys.STANDARDSCROLL_DOWN then
|
|
self:moveCursor(1)
|
|
elseif keys.STANDARDSCROLL_PAGEUP then
|
|
self:moveCursor(-self.page_size)
|
|
elseif keys.STANDARDSCROLL_PAGEDOWN then
|
|
self:moveCursor(self.page_size)
|
|
end
|
|
end
|
|
|
|
function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width)
|
|
ListBox{
|
|
frame_title = title,
|
|
text = text,
|
|
text_pen = tcolor,
|
|
choices = choices,
|
|
on_select = on_select,
|
|
on_cancel = on_cancel,
|
|
frame_width = min_width,
|
|
}:show()
|
|
end
|
|
|
|
return _ENV
|