From abf503fcdca4dd6c07171f93e4c4bc3ed85759d2 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 2 Oct 2012 16:45:17 +0400 Subject: [PATCH] Fix the ListBox dialog to behave in a more consistent way. --- library/lua/gui.lua | 3 +- library/lua/gui/dialogs.lua | 112 +++++++++++++++++++++------------- library/lua/gui/dwarfmode.lua | 5 +- 3 files changed, 74 insertions(+), 46 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 22066c077..a5e4f7503 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -310,6 +310,7 @@ function Screen:onResize(w,h) end function Screen:updateLayout() + self:invoke_after('postUpdateLayout') end ------------------------ @@ -399,7 +400,7 @@ function FramedScreen:updateFrameSize() self.frame_opaque = (gw == 0 and gh == 0) end -function FramedScreen:updateLayout() +function FramedScreen:postUpdateLayout() self:updateFrameSize() end diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 707b36d52..553bb3a4b 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -170,10 +170,10 @@ ListBox = defclass(ListBox, MessageBox) ListBox.focus_path = 'ListBox' ListBox.ATTRS{ - selection = 0, + selection = 1, choices = {}, select_pen = DEFAULT_NIL, - on_input = DEFAULT_NIL + on_select = DEFAULT_NIL } function InputBox:preinit(info) @@ -181,84 +181,112 @@ function InputBox:preinit(info) end function ListBox:init(info) - self.page_top = 0 + 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) - return mw, mh+#self.choices + 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:onRenderBody(dc) - ListBox.super.onRenderBody(self, dc) - - dc:newline(1) +function ListBox:postUpdateLayout() + self.page_size = self.frame_rect.height - #self.text - 3 + self:moveCursor(0) +end - 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] +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 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) + 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:moveCursor(delta) - local newsel=self.selection+delta - if #self.choices ~=0 then - if newsel<1 or newsel>#self.choices then - newsel=newsel % #self.choices +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 - 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) + if self.on_select then + self.on_select(self.selection, choice) end - if choice and choice[2] then - choice[2](choice,self.selection) -- maybe reverse the arguments? + 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.CURSOR_UP then + elseif keys.STANDARDSCROLL_UP then self:moveCursor(-1) - elseif keys.CURSOR_DOWN then + elseif keys.STANDARDSCROLL_DOWN then self:moveCursor(1) - elseif keys.CURSOR_UP_FAST then - self:moveCursor(-10) - elseif keys.CURSOR_DOWN_FAST then - self:moveCursor(10) + 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_input, on_cancel, min_width) +function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width) ListBox{ frame_title = title, text = text, text_pen = tcolor, choices = choices, - on_input = on_input, + on_select = on_select, on_cancel = on_cancel, frame_width = min_width, }:show() diff --git a/library/lua/gui/dwarfmode.lua b/library/lua/gui/dwarfmode.lua index ba3cfbe6c..125e71220 100644 --- a/library/lua/gui/dwarfmode.lua +++ b/library/lua/gui/dwarfmode.lua @@ -253,7 +253,7 @@ end DwarfOverlay = defclass(DwarfOverlay, gui.Screen) -function DwarfOverlay:updateLayout() +function DwarfOverlay:postUpdateLayout() self.df_layout = getPanelLayout() end @@ -352,8 +352,7 @@ end MenuOverlay = defclass(MenuOverlay, DwarfOverlay) -function MenuOverlay:updateLayout() - MenuOverlay.super.updateLayout(self) +function MenuOverlay:postUpdateLayout() self.frame_rect = self.df_layout.menu end