From bf1b09699543fa11113e834ec4f796e115cf5adb Mon Sep 17 00:00:00 2001 From: DarkGod <darkgod@net-core.org> Date: Mon, 4 Nov 2013 00:47:22 +0100 Subject: [PATCH] Long chat dialogs will scroll --- game/engines/default/engine/dialogs/Chat.lua | 2 +- .../default/engine/ui/VariableList.lua | 85 ++++++++++++++++--- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/game/engines/default/engine/dialogs/Chat.lua b/game/engines/default/engine/dialogs/Chat.lua index 8282601052..cb50438a1e 100644 --- a/game/engines/default/engine/dialogs/Chat.lua +++ b/game/engines/default/engine/dialogs/Chat.lua @@ -43,7 +43,7 @@ function _M:init(chat, id) self:generateList() self.c_desc = Textzone.new{width=self.iw - 10 - xoff, height=1, auto_height=true, text=self.text.."\n"} - self.c_list = VariableList.new{width=self.iw - 10 - xoff, list=self.list, fct=function(item) self:use(item) end, select=function(item) self:select(item) end} + self.c_list = VariableList.new{width=self.iw - 10 - xoff, max_height=game.h * 0.70 - self.c_desc.h, list=self.list, fct=function(item) self:use(item) end, select=function(item) self:select(item) end} local uis = { {left=0, top=0, ui=self.c_desc}, diff --git a/game/engines/default/engine/ui/VariableList.lua b/game/engines/default/engine/ui/VariableList.lua index 4615864784..e9fb954910 100644 --- a/game/engines/default/engine/ui/VariableList.lua +++ b/game/engines/default/engine/ui/VariableList.lua @@ -20,6 +20,7 @@ require "engine.class" local Base = require "engine.ui.Base" local Focusable = require "engine.ui.Focusable" +local Slider = require "engine.ui.Slider" --- A generic UI list module(..., package.seeall, class.inherit(Base, Focusable)) @@ -27,8 +28,11 @@ module(..., package.seeall, class.inherit(Base, Focusable)) function _M:init(t) self.list = assert(t.list, "no list list") self.w = assert(t.width, "no list width") + self.max_h = t.max_height self.fct = t.fct self.select = t.select + self.scrollbar = t.scrollbar + self.min_items_shown = t.min_items_shown or 3 self.display_prop = t.display_prop or "name" Base.init(self, t) @@ -39,6 +43,7 @@ function _M:generate() self.key:reset() self.sel = 1 + self.scroll = 1 self.max = #self.list local fw, fh = self.w, self.font_h @@ -49,7 +54,8 @@ function _M:generate() self.frame_usel = self:makeFrame("ui/selector", fw, fh) -- Draw the list items - self.h = 0 + local sh = 0 + local minh = 0 for i, item in ipairs(self.list) do local color = item.color or {255,255,255} local text = item[self.display_prop]:splitLines(fw - self.frame_sel.b4.w - self.frame_sel.b6.w, self.font) @@ -62,18 +68,38 @@ function _M:generate() color_r, color_g, color_b = s:drawColorStringBlended(self.font, text[z], self.frame_sel.b4.w, self.frame_sel.b8.w / 3 + self.font_h * (z-1), color_r, color_g, color_b, true) end + item.start_h = sh item.fh = fh item._tex = {s:glTexture()} - self.mouse:registerZone(0, self.h, self.w, fh, function(button, x, y, xrel, yrel, bx, by, event) - if self.sel and self.list[self.sel] then self.list[self.sel].focus_decay = self.focus_decay_max end - self.sel = i - self:onSelect() - if button == "left" and event == "button" then self:onUse() end - end) - - self.h = self.h + fh + sh = sh + fh + if i <= self.min_items_shown then minh = sh end end + self.h = math.max(minh, math.min(self.max_h or 1000000, sh)) + if sh > self.h then self.scrollbar = true end + + self.scroll_inertia = 0 + self.scroll = 0 + if self.scrollbar then self.scrollbar = Slider.new{size=self.h, max=sh} end + + self.mouse:registerZone(0, 0, self.w, self.h, function(button, x, y, xrel, yrel, bx, by, event) + self.last_input_was_keyboard = false + + if event == "button" and button == "wheelup" then if self.scrollbar then self.scroll_inertia = math.min(self.scroll_inertia, 0) - 5 end + elseif event == "button" and button == "wheeldown" then if self.scrollbar then self.scroll_inertia = math.max(self.scroll_inertia, 0) + 5 end + end + + for i = 1, #self.list do + local item = self.list[i] + if by + self.scroll >= item.start_h and by + self.scroll < item.start_h + item.fh then + if self.sel and self.list[self.sel] then self.list[self.sel].focus_decay = self.focus_decay_max end + self.sel = i + self:onSelect() + if button == "left" and event == "button" then self:onUse() end + break + end + end + end) -- Add UI controls self.key:addBinds{ @@ -101,10 +127,41 @@ function _M:onSelect() local item = self.list[self.sel] if not item then return end + if self.scrollbar then + local pos = 0 + for i = 1, #self.list do + local itm = self.list[i] + pos = pos + itm.fh + -- we've reached selected row + if self.sel == i then + -- check if it was visible if not go scroll over there + if pos - itm.fh < self.scrollbar.pos then self.scrollbar.pos = util.minBound(pos - itm.fh, 0, self.scrollbar.max) + elseif pos > self.scrollbar.pos + self.h then self.scrollbar.pos = util.minBound(pos - self.h, 0, self.scrollbar.max) + end + break + end + end + end + if rawget(self, "select") then self.select(item, self.sel) end end -function _M:display(x, y, nb_keyframes) +function _M:display(x, y, nb_keyframes, screen_x, screen_y) + local by = y + core.display.glScissor(true, screen_x, screen_y, self.w, self.h) + + if self.scrollbar then + local tmp_pos = self.scrollbar.pos + self.scrollbar.pos = util.minBound(self.scrollbar.pos + self.scroll_inertia, 0, self.scrollbar.max) + if self.scroll_inertia > 0 then self.scroll_inertia = math.max(self.scroll_inertia - 1, 0) + elseif self.scroll_inertia < 0 then self.scroll_inertia = math.min(self.scroll_inertia + 1, 0) + end + if self.scrollbar.pos == 0 or self.scrollbar.pos == self.scrollbar.max then self.scroll_inertia = 0 end + + y = y + (self.scrollbar and -self.scrollbar.pos or 0) + self.scroll = self.scrollbar.pos + end + for i = 1, self.max do local item = self.list[i] if not item then break end @@ -129,4 +186,12 @@ function _M:display(x, y, nb_keyframes) item._tex[1]:toScreenFull(x + self.frame_sel.b4.w, y, self.fw, item.fh, item._tex[2], item._tex[3]) y = y + item.fh end + + core.display.glScissor(false) + + if self.focused and self.scrollbar then + self.scrollbar:display(x + self.w - self.scrollbar.w, by) + + self.last_scroll = self.scrollbar.pos + end end -- GitLab