nagview: support vscroll when message is too long

Also some other minor changes:
* fix transition when nagview is closed
* do not draw or update when not visible
* do not process events when not visible
* cleaned a bit the logic on next and show
* fixes #848
This commit is contained in:
jgmdev 2022-03-10 04:27:04 -04:00
parent e08353ea08
commit 0aa53a0e7f
1 changed files with 82 additions and 39 deletions

View File

@ -19,6 +19,9 @@ function NagView:new()
self.show_height = 0 self.show_height = 0
self.force_focus = false self.force_focus = false
self.queue = {} self.queue = {}
self.scrollable = true
self.target_height = 0
self.on_mouse_pressed_root = nil
end end
function NagView:get_title() function NagView:get_title()
@ -47,15 +50,15 @@ function NagView:get_target_height()
return self.target_height + 2 * style.padding.y return self.target_height + 2 * style.padding.y
end end
function NagView:update() function NagView:get_scrollable_size()
NagView.super.update(self) local w, h = system.get_window_size()
if self.visible and self:get_target_height() > h then
if core.active_view == self and self.title then self.size.y = h
self:move_towards(self, "show_height", self:get_target_height()) return self:get_target_height()
self:move_towards(self, "underline_progress", 1)
else else
self:move_towards(self, "show_height", 0) self.size.y = 0
end end
return 0
end end
function NagView:dim_window_content() function NagView:dim_window_content()
@ -95,6 +98,8 @@ function NagView:each_option()
end end
function NagView:on_mouse_moved(mx, my, ...) function NagView:on_mouse_moved(mx, my, ...)
if not self.visible then return end
core.set_active_view(self)
NagView.super.on_mouse_moved(self, mx, my, ...) NagView.super.on_mouse_moved(self, mx, my, ...)
for i, _, x,y,w,h in self:each_option() do for i, _, x,y,w,h in self:each_option() do
if mx >= x and my >= y and mx < x + w and my < y + h then if mx >= x and my >= y and mx < x + w and my < y + h then
@ -104,43 +109,55 @@ function NagView:on_mouse_moved(mx, my, ...)
end end
end end
-- Used to store saved value for RootView.on_view_mouse_pressed local function register_mouse_pressed(self)
local on_view_mouse_pressed if self.on_mouse_pressed_root then return end
local function capture_mouse_pressed(nag_view)
-- RootView is loaded locally to avoid NagView and RootView being -- RootView is loaded locally to avoid NagView and RootView being
-- mutually recursive -- mutually recursive
local RootView = require "core.rootview" local RootView = require "core.rootview"
on_view_mouse_pressed = RootView.on_view_mouse_pressed self.on_mouse_pressed_root = RootView.on_mouse_pressed
RootView.on_view_mouse_pressed = function(button, x, y, clicks) local this = self
local handled = NagView.on_mouse_pressed(nag_view, button, x, y, clicks) function RootView:on_mouse_pressed(button, x, y, clicks)
return handled or on_view_mouse_pressed(button, x, y, clicks) if
not this:on_mouse_pressed(button, x, y, clicks)
then
return this.on_mouse_pressed_root(self, button, x, y, clicks)
else
return true
end end
end end
self.new_on_mouse_pressed_root = RootView.on_mouse_pressed
end
local function unregister_mouse_pressed(self)
local function release_mouse_pressed()
local RootView = require "core.rootview" local RootView = require "core.rootview"
if on_view_mouse_pressed then if
RootView.on_view_mouse_pressed = on_view_mouse_pressed self.on_mouse_pressed_root
on_view_mouse_pressed = nil and
-- just in case prevent overwriting what something else may
-- have overwrote after us, but after testing with various
-- plugins this doesn't seems to happen, but just in case
self.new_on_mouse_pressed_root == RootView.on_mouse_pressed
then
RootView.on_mouse_pressed = self.on_mouse_pressed_root
self.on_mouse_pressed_root = nil
self.new_on_mouse_pressed_root = nil
end end
end end
function NagView:on_mouse_pressed(button, mx, my, clicks) function NagView:on_mouse_pressed(button, mx, my, clicks)
if not self.visible then return false end
if NagView.super.on_mouse_pressed(self, button, mx, my, clicks) then return true end if NagView.super.on_mouse_pressed(self, button, mx, my, clicks) then return true end
for i, _, x,y,w,h in self:each_option() do for i, _, x,y,w,h in self:each_option() do
if mx >= x and my >= y and mx < x + w and my < y + h then if mx >= x and my >= y and mx < x + w and my < y + h then
self:change_hovered(i) self:change_hovered(i)
command.perform "dialog:select" command.perform "dialog:select"
end
end
return true return true
end end
end
end
function NagView:on_text_input(text) function NagView:on_text_input(text)
if not self.visible then return end
if text:lower() == "y" then if text:lower() == "y" then
command.perform "dialog:select-yes" command.perform "dialog:select-yes"
elseif text:lower() == "n" then elseif text:lower() == "n" then
@ -148,10 +165,25 @@ function NagView:on_text_input(text)
end end
end end
function NagView:update()
if not self.visible and self.show_height <= 0 then return end
NagView.super.update(self)
if self.visible and core.active_view == self and self.title then
self:move_towards(self, "show_height", self:get_target_height())
self:move_towards(self, "underline_progress", 1)
else
self:move_towards(self, "show_height", 0)
if self.show_height <= 0 then
self.title = nil
self.message = nil
self.options = nil
self.on_selected = nil
end
end
end
local function draw_nagview_message(self) local function draw_nagview_message(self)
if self.show_height <= 0 or not self.title then return end
self:dim_window_content() self:dim_window_content()
-- draw message's background -- draw message's background
@ -160,6 +192,8 @@ local function draw_nagview_message(self)
ox = ox + style.padding.x ox = ox + style.padding.x
core.push_clip_rect(ox, oy, self.size.x, self.show_height)
-- if there are other items, show it -- if there are other items, show it
if #self.queue > 0 then if #self.queue > 0 then
local str = string.format("[%d]", #self.queue) local str = string.format("[%d]", #self.queue)
@ -196,9 +230,16 @@ local function draw_nagview_message(self)
common.draw_text(opt.font, style.nagbar_text, opt.text, "center", fx,fy,fw,fh) common.draw_text(opt.font, style.nagbar_text, opt.text, "center", fx,fy,fw,fh)
end end
self:draw_scrollbar()
core.pop_clip_rect()
end end
function NagView:draw() function NagView:draw()
if (not self.visible and self.show_height <= 0) or not self.title then
return
end
core.root_view:defer_draw(draw_nagview_message, self) core.root_view:defer_draw(draw_nagview_message, self)
end end
@ -210,28 +251,30 @@ function NagView:get_message_height()
return h return h
end end
function NagView:next() function NagView:next()
local opts = table.remove(self.queue, 1) or {} local opts = table.remove(self.queue, 1) or {}
if opts.title and opts.message and opts.options then
self.visible = true
self.title = opts.title self.title = opts.title
self.message = opts.message and opts.message .. "\n" self.message = opts.message and opts.message .. "\n"
self.options = opts.options self.options = opts.options
self.on_selected = opts.on_selected self.on_selected = opts.on_selected
if self.message and self.options then
local message_height = self:get_message_height() local message_height = self:get_message_height()
-- self.target_height is the nagview height needed to display the message and -- self.target_height is the nagview height needed to display the message and
-- the buttons, excluding the top and bottom padding space. -- the buttons, excluding the top and bottom padding space.
self.target_height = math.max(message_height, self:get_buttons_height()) self.target_height = math.max(message_height, self:get_buttons_height())
self:change_hovered(common.find_index(self.options, "default_yes")) self:change_hovered(common.find_index(self.options, "default_yes"))
end
self.force_focus = self.message ~= nil self.force_focus = true
core.set_active_view(self.message ~= nil and self or core.set_active_view(self)
core.next_active_view or core.last_active_view)
if self.message ~= nil and self then
-- We add a hook to manage all the mouse_pressed events. -- We add a hook to manage all the mouse_pressed events.
capture_mouse_pressed(self) register_mouse_pressed(self)
else else
release_mouse_pressed() self.force_focus = false
core.set_active_view(core.next_active_view or core.last_active_view)
self.visible = false
unregister_mouse_pressed(self)
end end
end end
@ -242,7 +285,7 @@ function NagView:show(title, message, options, on_select)
opts.options = assert(options, "No options") opts.options = assert(options, "No options")
opts.on_selected = on_select or noop opts.on_selected = on_select or noop
table.insert(self.queue, opts) table.insert(self.queue, opts)
if #self.queue > 0 and not self.title then self:next() end self:next()
end end
return NagView return NagView