From 15198eb77727b4277d5b5d80fb3ae4b25b3c8ef8 Mon Sep 17 00:00:00 2001 From: David Vazgenovich Shakaryan Date: Wed, 21 Jan 2026 12:52:15 -0800 Subject: move mouse state to osd; add scrollbar hover --- osd.lua | 160 +++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 114 insertions(+), 46 deletions(-) (limited to 'osd.lua') diff --git a/osd.lua b/osd.lua index 35115a1..981d824 100644 --- a/osd.lua +++ b/osd.lua @@ -43,7 +43,7 @@ function osd.new(init) local t = setmetatable({ fg = mp.create_osd_overlay('ass-events'), bg = mp.create_osd_overlay('ass-events'), - menu_button = mp.create_osd_overlay('ass-events'), + menu_btn = mp.create_osd_overlay('ass-events'), width = 0, height = 0, scale = 1, @@ -51,8 +51,8 @@ function osd.new(init) padding = math.floor((720 - (lines * config.font_size)) / 2), }, mt) t.bg.z = -1 - t.menu_button.z = 1 - t.menu_button.hidden = true + t.menu_btn.z = 1 + t.menu_btn.hidden = true for k, v in pairs(init or {}) do t[k] = v @@ -93,15 +93,15 @@ function mt:resize(w, h) } coords.x2 = coords.x1 + sz coords.y2 = coords.y1 + sz - self.menu_button_coords = coords - self.menu_button.data = + self.menu_btn_coords = coords + self.menu_btn.data = '{\\pos(' .. coords.x1 .. ',' .. coords.y1 .. ')}' .. - colours.menu_button_bg .. draw_rect(0, 0, sz, sz) .. '\n' .. + colours.menu_btn_bg .. draw_rect(0, 0, sz, sz) .. '\n' .. '{\\q2\\fs' .. sz .. '\\bord0\\an5\\pos(' .. coords.x1 + sz/2 .. ',' .. coords.y1 + sz/2 ..')}' .. - colours.menu_button_fg .. '≡' - self.menu_button:update() + colours.menu_btn_fg .. '≡' + self.menu_btn:update() end function mt:set_status(msg, level, no_dirty) @@ -414,12 +414,11 @@ function mt:set_img(path, menu_res) return true, true end -function mt:draw_scrollbar(state) +function mt:calc_scrollbar(state) local menu = state:menu() local opts = #menu.options local lines = self:menu_lines(state) if opts <= lines then - self.scrollbar_coords = nil return end @@ -428,20 +427,45 @@ function mt:draw_scrollbar(state) local w = self.padding - 4 local hh = math.max(config.font_size / 2, h * lines / opts) local pos = (h - hh) * (menu.view_top - 1) / (opts - lines) - self.scrollbar_coords = { + + return { x1 = 2, y1 = top, x2 = 2 + w, y2 = top + h, + w = w, + h = h, + pos = pos, + hh = hh, } - return ( - -- bg - colours.scrollbar_bg .. - '{\\pos(2,' .. top .. ')}' .. draw_rect(0, 0, w, h) .. '\n' .. - -- fg - colours.scrollbar_fg .. '{\\bord0}' .. - '{\\pos(2,' .. top + pos .. ')}' .. draw_rect(0, 0, w, hh)) +end + +function mt:render_bg() + self.bg.data = + '{\\pos(0,0)\\alpha&H' .. config.bg_alpha .. '&\\c&H&}' .. + draw_rect(0, 0, 7680, 720) + + local sb = self.out.scrollbar + if sb then + local hover = self.mstate and self.mstate.target == 'scrollbar' + local fg = hover and colours.scrollbar_fg_hover or + colours.scrollbar_fg + local bg = hover and colours.scrollbar_bg_hover or + colours.scrollbar_bg + + self.bg.data = self.bg.data .. '\n' .. + -- bg + bg .. + '{\\pos(2,' .. sb.y1 .. ')}' .. + draw_rect(0, 0, sb.w, sb.h) .. '\n' .. + -- fg + fg .. '{\\bord0}' .. + '{\\pos(2,' .. sb.y1 + sb.pos .. ')}' .. + draw_rect(0, 0, sb.w, sb.hh) + end + + self.bg:update() end -- this takes the data generated by redraw() and related functions, prepares it @@ -486,7 +510,7 @@ function mt:render() -- need it when update() is called to toggle visibility of the last -- rendered data. self.fg.compute_bounds = false - self.bg:update() + self:render_bg() if self.out.img_path then local upd, new = self:set_img(self.out.img_path, res) if upd then @@ -565,18 +589,9 @@ function mt:redraw(state) titles = out_titles, options = out_options, max = out_max, + scrollbar = self:calc_scrollbar(state), } - -- we can draw this directly from here since any changes handled by - -- render() will not modify this. - self.bg.data = - '{\\pos(0,0)\\alpha&H' .. config.bg_alpha .. '&\\c&H&}' .. - draw_rect(0, 0, 7680, 720) - local sb = self:draw_scrollbar(state) - if sb then - self.bg.data = self.bg.data .. '\n' .. sb - end - if img and self.img_path_func then self.out.img_path = self.img_path_func(img, function(path) -- these are set by render(), which we always call @@ -587,6 +602,9 @@ function mt:redraw(state) end) end + -- menu changes could result in hover changes + self:update_mstate() + self:render() self.is_dirty = false end @@ -628,7 +646,7 @@ end function mt:mouse_scrollbar_ratio(mpos) local x = mpos.x / self.scale local y = mpos.y / self.scale - local coords = self.scrollbar_coords + local coords = self.out.scrollbar if not coords or x < coords.x1 or x > coords.x2 or y < coords.y1 or y > coords.y2 then @@ -639,39 +657,89 @@ function mt:mouse_scrollbar_ratio(mpos) return math.max(0, math.min(1, ratio)) end -function mt:mouse_over_button_area(mpos) - if not mpos.hover then - return false - end - +function mt:mouse_over_btn_area(mpos) local y = mpos.y / self.scale return y < self.padding + (2 * config.font_size) end -function mt:mouse_over_menu_button(mpos) - if not mpos.hover then - return false - end - +function mt:mouse_over_menu_btn(mpos) local x = mpos.x / self.scale local y = mpos.y / self.scale - local coords = self.menu_button_coords + local coords = self.menu_btn_coords return coords and x > coords.x1 and x < coords.x2 and y > coords.y1 and y < coords.y2 end -function mt:show_menu_button(bool) - if self.menu_button.hidden ~= bool then +function mt:update_mstate() + local t = {} + local val + + if not self.mpos or not self.mpos.hover then + goto update + end + + val = self:mouse_over_menu_btn(self.mpos) + if val then + t.target = 'menu_btn' + goto common + end + + val = self:mouse_scrollbar_ratio(self.mpos) + if val then + t.target = 'scrollbar' + t.ratio = val + goto common + end + + val = self:mouse_menu_line(self.mpos) + if val then + t.target = 'menu' + t.line = val + t.option_line = val - #self.out.titles - 1 + goto common + end + + ::common:: + + t.over_btn_area = self:mouse_over_btn_area(self.mpos) + + ::update:: + + local ms = self.mstate or {} + self.mstate = t + + if (t.target == 'scrollbar') ~= (ms.target == 'scrollbar') then + self:render_bg() + end + + return t +end + +function mt:set_mpos(mpos) + -- mpv sends (0, 0) on startup if the mouse hasn't moved yet. don't + -- trigger display of the button until the mouse has actually moved. + if not self.mpos and mpos and mpos.x == 0 and mpos.y == 0 then + return + end + + self.mpos = mpos + self.mpos_time = mp.get_time() + + return self:update_mstate() +end + +function mt:show_menu_btn(bool) + if not self.menu_btn.hidden ~= not bool then return end - self.menu_button.hidden = not bool - self.menu_button:update() + self.menu_btn.hidden = not bool + self.menu_btn:update() end function mt:measure_width(str) - local e = self.menu_button + local e = self.menu_btn local data = e.data local hidden = e.hidden e.hidden = true -- cgit v1.2.3-70-g09d2