From 6b754eb62880188d3c4939db95557fd236c3d4bd Mon Sep 17 00:00:00 2001 From: Guldoman Date: Sun, 16 Oct 2022 02:12:15 +0200 Subject: [PATCH] Refactor scrollbar into its own file (#1124) * Move scrollbar to its own file * Don't call `Scrollbar` functions if `View` is not scrollable * Allow horizontal scrolling in `Scrollbar` * Add horizontal scrollbar to `View` * Add `root:horizontal-scroll` command with `shift+wheel` keymap * Prioritize vertical scrollbar hover * Don't send mouse movement to vertical scrollbar when dragging horizontal one * Fix clicking on horizontal scrollbar track * Implement `start` scrollbar alignment * Add documentation to `Scrollbar` * Make `DocView` infinitely scrollable horizontally * Handle horizontal scroll SDL event --- data/core/commands/root.lua | 8 + data/core/commandview.lua | 4 + data/core/docview.lua | 6 +- data/core/keymap-macos.lua | 3 +- data/core/keymap.lua | 31 +++- data/core/scrollbar.lua | 294 ++++++++++++++++++++++++++++++++++ data/core/statusview.lua | 8 +- data/core/view.lua | 207 ++++++++++-------------- data/plugins/linewrapping.lua | 2 +- data/plugins/treeview.lua | 4 +- src/api/system.c | 9 +- 11 files changed, 442 insertions(+), 134 deletions(-) create mode 100644 data/core/scrollbar.lua diff --git a/data/core/commands/root.lua b/data/core/commands/root.lua index deea858e..61e3890b 100644 --- a/data/core/commands/root.lua +++ b/data/core/commands/root.lua @@ -123,5 +123,13 @@ command.add(nil, { return true end return false + end, + ["root:horizontal-scroll"] = function(delta) + local view = (core.root_view.overlapping_node and core.root_view.overlapping_node.active_view) or core.active_view + if view and view.scrollable then + view.scroll.to.x = view.scroll.to.x + delta * -config.mouse_wheel_scroll + return true + end + return false end }) diff --git a/data/core/commandview.lua b/data/core/commandview.lua index a77db961..e0af6c21 100644 --- a/data/core/commandview.lua +++ b/data/core/commandview.lua @@ -88,6 +88,10 @@ function CommandView:get_scrollable_size() return 0 end +function CommandView:get_h_scrollable_size() + return 0 +end + function CommandView:scroll_to_make_visible() -- no-op function to disable this functionality diff --git a/data/core/docview.lua b/data/core/docview.lua index cc8ad7ee..693684a1 100644 --- a/data/core/docview.lua +++ b/data/core/docview.lua @@ -113,6 +113,10 @@ function DocView:get_scrollable_size() return self:get_line_height() * (#self.doc.lines - 1) + self.size.y end +function DocView:get_h_scrollable_size() + return math.huge +end + function DocView:get_font() return style[self.font] @@ -241,7 +245,7 @@ end function DocView:on_mouse_moved(x, y, ...) DocView.super.on_mouse_moved(self, x, y, ...) - if self.hovered_scrollbar_track or self.dragging_scrollbar then + if self:scrollbar_hovering() or self:scrollbar_dragging() then self.cursor = "arrow" else self.cursor = "ibeam" diff --git a/data/core/keymap-macos.lua b/data/core/keymap-macos.lua index edbd53ef..28457fe8 100644 --- a/data/core/keymap-macos.lua +++ b/data/core/keymap-macos.lua @@ -34,7 +34,8 @@ local function keymap_macos(keymap) ["cmd+8"] = "root:switch-to-tab-8", ["cmd+9"] = "root:switch-to-tab-9", ["wheel"] = "root:scroll", - + ["shift+wheel"] = "root:horizontal-scroll", + ["cmd+f"] = "find-replace:find", ["cmd+r"] = "find-replace:replace", ["f3"] = "find-replace:repeat-find", diff --git a/data/core/keymap.lua b/data/core/keymap.lua index c392c546..88bad277 100644 --- a/data/core/keymap.lua +++ b/data/core/keymap.lua @@ -212,9 +212,32 @@ function keymap.on_key_pressed(k, ...) return false end -function keymap.on_mouse_wheel(delta, ...) - return not (keymap.on_key_pressed("wheel" .. (delta > 0 and "up" or "down"), delta, ...) - or keymap.on_key_pressed("wheel", delta, ...)) +function keymap.on_mouse_wheel(delta_y, delta_x, ...) + local y_direction = delta_y > 0 and "up" or "down" + local x_direction = delta_x > 0 and "left" or "right" + -- Try sending a "cumulative" event for both scroll directions + if delta_y ~= 0 and delta_x ~= 0 then + local result = keymap.on_key_pressed("wheel" .. y_direction .. x_direction, delta_y, delta_x, ...) + if not result then + result = keymap.on_key_pressed("wheelyx", delta_y, delta_x, ...) + end + if result then return true end + end + -- Otherwise send each direction as its own separate event + local y_result, x_result + if delta_y ~= 0 then + y_result = keymap.on_key_pressed("wheel" .. y_direction, delta_y, ...) + if not y_result then + y_result = keymap.on_key_pressed("wheel", delta_y, ...) + end + end + if delta_x ~= 0 then + x_result = keymap.on_key_pressed("wheel" .. x_direction, delta_x, ...) + if not x_result then + x_result = keymap.on_key_pressed("hwheel", delta_x, ...) + end + end + return y_result or x_result end function keymap.on_mouse_pressed(button, x, y, clicks) @@ -277,6 +300,8 @@ keymap.add_direct { ["alt+8"] = "root:switch-to-tab-8", ["alt+9"] = "root:switch-to-tab-9", ["wheel"] = "root:scroll", + ["hwheel"] = "root:horizontal-scroll", + ["shift+wheel"] = "root:horizontal-scroll", ["ctrl+f"] = "find-replace:find", ["ctrl+r"] = "find-replace:replace", diff --git a/data/core/scrollbar.lua b/data/core/scrollbar.lua new file mode 100644 index 00000000..77cefeeb --- /dev/null +++ b/data/core/scrollbar.lua @@ -0,0 +1,294 @@ +local core = require "core" +local common = require "core.common" +local config = require "core.config" +local style = require "core.style" +local Object = require "core.object" + +---Scrollbar +---Use Scrollbar:set_size to set the bounding box of the view the scrollbar belongs to. +---Use Scrollbar:update to update the scrollbar animations. +---Use Scrollbar:draw to draw the scrollbar. +---Use Scrollbar:on_mouse_pressed, Scrollbar:on_mouse_released, +---Scrollbar:on_mouse_moved and Scrollbar:on_mouse_left to react to mouse movements; +---the scrollbar won't update automatically. +---Use Scrollbar:set_percent to set the scrollbar location externally. +--- +---To manage all the orientations, the scrollbar changes the coordinates system +---accordingly. The "normal" coordinate system adapts the scrollbar coordinates +---as if it's always a vertical scrollbar, positioned at the end of the bounding box. +---@class core.scrollbar : core.object +local Scrollbar = Object:extend() + +---@param direction "v" | "h" @Vertical or Horizontal +---@param alignment "s" | "e" @Start or End (left to right, top to bottom) +function Scrollbar:new(direction, alignment) + ---Position information of the owner + self.rect = { + x = 0, y = 0, w = 0, h = 0, + ---Scrollable size + scrollable = 0 + } + self.normal_rect = { + across = 0, + along = 0, + across_size = 0, + along_size = 0, + scrollable = 0 + } + ---@type integer @Position in percent [0-1] + self.percent = 0 + ---@type boolean @Scrollbar dragging status + self.dragging = false + ---@type integer @Private. Used to offset the start of the drag from the top of the thumb + self.drag_start_offset = 0 + ---What is currently being hovered. `thumb` implies` track` + self.hovering = { track = false, thumb = false } + ---@type "v" | "h"@Vertical or Horizontal + self.direction = direction or "v" + ---@type "s" | "e" @Start or End (left to right, top to bottom) + self.alignment = alignment or "e" + ---@type number @Private. Used to keep track of animations + self.expand_percent = 0 +end + + +function Scrollbar:real_to_normal(x, y, w, h) + x, y, w, h = x or 0, y or 0, w or 0, h or 0 + if self.direction == "v" then + if self.alignment == "s" then + x = (self.rect.x + self.rect.w) - x - w + end + return x, y, w, h + else + if self.alignment == "s" then + y = (self.rect.y + self.rect.h) - y - h + end + return y, x, h, w + end +end + + +function Scrollbar:normal_to_real(x, y, w, h) + x, y, w, h = x or 0, y or 0, w or 0, h or 0 + if self.direction == "v" then + if self.alignment == "s" then + x = (self.rect.x + self.rect.w) - x - w + end + return x, y, w, h + else + if self.alignment == "s" then + x = (self.rect.y + self.rect.h) - x - w + end + return y, x, h, w + end +end + + +function Scrollbar:_get_thumb_rect_normal() + local nr = self.normal_rect + local sz = nr.scrollable + if sz == math.huge or sz <= nr.along_size + then + return 0, 0, 0, 0 + end + local along_size = math.max(20, nr.along_size * nr.along_size / sz) + local across_size = style.scrollbar_size + across_size = across_size + (style.expanded_scrollbar_size - style.scrollbar_size) * self.expand_percent + return + nr.across + nr.across_size - across_size, + nr.along + self.percent * nr.scrollable * (nr.along_size - along_size) / (sz - nr.along_size), + across_size, + along_size +end + +---Get the thumb rect (the part of the scrollbar that can be dragged) +---@return integer,integer,integer,integer @x, y, w, h +function Scrollbar:get_thumb_rect() + return self:normal_to_real(self:_get_thumb_rect_normal()) +end + + +function Scrollbar:_get_track_rect_normal() + local nr = self.normal_rect + local sz = nr.scrollable + if sz <= nr.along_size or sz == math.huge then + return 0, 0, 0, 0 + end + local across_size = style.scrollbar_size + across_size = across_size + (style.expanded_scrollbar_size - style.scrollbar_size) * self.expand_percent + return + nr.across + nr.across_size - across_size, + nr.along, + across_size, + nr.along_size +end + +---Get the track rect (the "background" of the scrollbar) +---@return number,number,number,number @x, y, w, h +function Scrollbar:get_track_rect() + return self:normal_to_real(self:_get_track_rect_normal()) +end + + +function Scrollbar:_overlaps_normal(x, y) + local sx, sy, sw, sh = self:_get_thumb_rect_normal() + local result + if x >= sx - style.scrollbar_size * 3 and x <= sx + sw and y >= sy and y <= sy + sh then + result = "thumb" + else + sx, sy, sw, sh = self:_get_track_rect_normal() + if x >= sx - style.scrollbar_size * 3 and x <= sx + sw and y >= sy and y <= sy + sh then + result = "track" + end + end + return result +end + +---Get what part of the scrollbar the coordinates overlap +---@return "thumb"|"track"|nil +function Scrollbar:overlaps(x, y) + x, y = self:real_to_normal(x, y) + return self:_overlaps_normal(x, y) +end + + +function Scrollbar:_on_mouse_pressed_normal(button, x, y, clicks) + local overlaps = self:_overlaps_normal(x, y) + if overlaps then + local _, along, _, along_size = self:_get_thumb_rect_normal() + self.dragging = true + if overlaps == "thumb" then + self.drag_start_offset = along - y + return true + elseif overlaps == "track" then + self.drag_start_offset = - along_size / 2 + return (y - self.normal_rect.along - along_size / 2) / self.normal_rect.along_size + end + end +end + +---Updates the scrollbar with mouse pressed info. +---Won't update the scrollbar position automatically. +---Use Scrollbar:set_percent to update it. +--- +---This sets the dragging status if needed. +--- +---Returns a falsy value if the event happened outside the scrollbar. +---Returns `true` if the thumb was pressed. +---If the track was pressed this returns a value between 0 and 1 +---representing the percent of the position. +---@return boolean|number +function Scrollbar:on_mouse_pressed(button, x, y, clicks) + x, y = self:real_to_normal(x, y) + return self:_on_mouse_pressed_normal(button, x, y, clicks) +end + +---Updates the scrollbar dragging status +function Scrollbar:on_mouse_released(button, x, y) + self.dragging = false +end + + +function Scrollbar:_on_mouse_moved_normal(x, y, dx, dy) + if self.dragging then + local nr = self.normal_rect + return common.clamp((y - nr.along + self.drag_start_offset) / nr.along_size, 0, 1) + end + local overlaps = self:_overlaps_normal(x, y) + self.hovering.thumb = overlaps == "thumb" + self.hovering.track = self.hovering.thumb or overlaps == "track" + return self.hovering.track or self.hovering.thumb +end + +---Updates the scrollbar with mouse moved info. +---Won't update the scrollbar position automatically. +---Use Scrollbar:set_percent to update it. +--- +---This updates the hovering status. +--- +---Returns a falsy value if the event happened outside the scrollbar. +---Returns `true` if the scrollbar is hovered. +---If the scrollbar was being dragged, this returns a value between 0 and 1 +---representing the percent of the position. +---@return boolean|number +function Scrollbar:on_mouse_moved(x, y, dx, dy) + x, y = self:real_to_normal(x, y) + dx, dy = self:real_to_normal(dx, dy) -- TODO: do we need this? (is this even correct?) + return self:_on_mouse_moved_normal(x, y, dx, dy) +end + +---Updates the scrollbar hovering status +function Scrollbar:on_mouse_left() + self.hovering.track, self.hovering.thumb = false, false +end + +---Updates the bounding box of the view the scrollbar belongs to. +---@param x number +---@param y number +---@param w number +---@param h number +---@param scrollable number @size of the scrollable area +function Scrollbar:set_size(x, y, w, h, scrollable) + self.rect.x, self.rect.y, self.rect.w, self.rect.h = x, y, w, h + self.rect.scrollable = scrollable + + local nr = self.normal_rect + nr.across, nr.along, nr.across_size, nr.along_size = self:real_to_normal(x, y, w, h) + nr.scrollable = scrollable +end + +---Updates the scrollbar location +---@param percent number @number between 0 and 1 representing the position of the middle part of the thumb +function Scrollbar:set_percent(percent) + self.percent = percent +end + +---Updates the scrollbar animations +function Scrollbar:update() + -- TODO: move the animation code to its own class + local dest = (self.hovering.track or self.dragging) and 1 or 0 + local diff = math.abs(self.expand_percent - dest) + if not config.transitions or diff < 0.05 or config.disabled_transitions["scroll"] then + self.expand_percent = dest + else + local rate = 0.3 + if config.fps ~= 60 or config.animation_rate ~= 1 then + local dt = 60 / config.fps + rate = 1 - common.clamp(1 - rate, 1e-8, 1 - 1e-8)^(config.animation_rate * dt) + end + self.expand_percent = common.lerp(self.expand_percent, dest, rate) + end + if diff > 1e-8 then + core.redraw = true + end +end + + +---Draw the scrollbar track +function Scrollbar:draw_track() + if not (self.hovering.track or self.dragging) + and self.expand_percent == 0 then + return + end + local color = { table.unpack(style.scrollbar_track) } + color[4] = color[4] * self.expand_percent + local x, y, w, h = self:get_track_rect() + renderer.draw_rect(x, y, w, h, color) +end + +---Draw the scrollbar thumb +function Scrollbar:draw_thumb() + local highlight = self.hovering.thumb or self.dragging + local color = highlight and style.scrollbar2 or style.scrollbar + local x, y, w, h = self:get_thumb_rect() + renderer.draw_rect(x, y, w, h, color) +end + +---Draw both the scrollbar track and thumb +function Scrollbar:draw() + self:draw_track() + self:draw_thumb() +end + + +return Scrollbar diff --git a/data/core/statusview.lua b/data/core/statusview.lua index 48ce24cf..e2bfdbe4 100644 --- a/data/core/statusview.lua +++ b/data/core/statusview.lua @@ -1053,9 +1053,13 @@ function StatusView:on_mouse_released(button, x, y) end -function StatusView:on_mouse_wheel(y) +function StatusView:on_mouse_wheel(y, x) if not self.visible then return end - self:drag_panel(self.hovered_panel, y * self.left_width / 10) + if x ~= 0 then + self:drag_panel(self.hovered_panel, x * self.left_width / 10) + else + self:drag_panel(self.hovered_panel, y * self.left_width / 10) + end end diff --git a/data/core/view.lua b/data/core/view.lua index 8a12d025..aefc7aef 100644 --- a/data/core/view.lua +++ b/data/core/view.lua @@ -1,8 +1,8 @@ local core = require "core" local config = require "core.config" -local style = require "core.style" local common = require "core.common" local Object = require "core.object" +local Scrollbar = require "core.scrollbar" ---@class core.view.position ---@field x number @@ -28,10 +28,6 @@ local Object = require "core.object" ---@field w core.view.thumbtrackwidth ---@field h core.view.thumbtrack ----@class core.view.increment ----@field value number ----@field to number - ---@alias core.view.cursor "'arrow'" | "'ibeam'" | "'sizeh'" | "'sizev'" | "'hand'" ---@alias core.view.mousebutton "'left'" | "'right'" @@ -47,8 +43,8 @@ local Object = require "core.object" ---@field scroll core.view.scroll ---@field cursor core.view.cursor ---@field scrollable boolean ----@field scrollbar core.view.scrollbar ----@field scrollbar_alpha core.view.increment +---@field v_scrollbar core.scrollbar +---@field h_scrollbar core.scrollbar ---@field current_scale number local View = Object:extend() @@ -63,13 +59,8 @@ function View:new() self.scroll = { x = 0, y = 0, to = { x = 0, y = 0 } } self.cursor = "arrow" self.scrollable = false - self.scrollbar = { - x = { thumb = 0, track = 0 }, - y = { thumb = 0, track = 0 }, - w = { thumb = 0, track = 0, to = { thumb = 0, track = 0 } }, - h = { thumb = 0, track = 0 }, - } - self.scrollbar_alpha = { value = 0, to = 0 } + self.v_scrollbar = Scrollbar("v", "e") + self.h_scrollbar = Scrollbar("h", "e") self.current_scale = SCALE end @@ -111,47 +102,9 @@ function View:get_scrollable_size() return math.huge end - ----@return number x ----@return number y ----@return number width ----@return number height -function View:get_scrollbar_track_rect() - local sz = self:get_scrollable_size() - if sz <= self.size.y or sz == math.huge then - return 0, 0, 0, 0 - end - local width = style.scrollbar_size - if self.hovered_scrollbar_track or self.dragging_scrollbar then - width = style.expanded_scrollbar_size - end - return - self.position.x + self.size.x - width, - self.position.y, - width, - self.size.y -end - - ----@return number x ----@return number y ----@return number width ----@return number height -function View:get_scrollbar_rect() - local sz = self:get_scrollable_size() - if sz <= self.size.y or sz == math.huge then - return 0, 0, 0, 0 - end - local h = math.max(20, self.size.y * self.size.y / sz) - local width = style.scrollbar_size - if self.hovered_scrollbar_track or self.dragging_scrollbar then - width = style.expanded_scrollbar_size - end - return - self.position.x + self.size.x - width, - self.position.y + self.scroll.y * (self.size.y - h) / (sz - self.size.y), - width, - h +---@return number +function View:get_h_scrollable_size() + return 0 end @@ -159,16 +112,19 @@ end ---@param y number ---@return boolean function View:scrollbar_overlaps_point(x, y) - local sx, sy, sw, sh = self:get_scrollbar_rect() - return x >= sx - style.scrollbar_size * 3 and x < sx + sw and y > sy and y <= sy + sh + return not (not (self.v_scrollbar:overlaps(x, y) or self.h_scrollbar:overlaps(x, y))) end ----@param x number ----@param y number + ---@return boolean -function View:scrollbar_track_overlaps_point(x, y) - local sx, sy, sw, sh = self:get_scrollbar_track_rect() - return x >= sx - style.scrollbar_size * 3 and x < sx + sw and y > sy and y <= sy + sh +function View:scrollbar_dragging() + return self.v_scrollbar.dragging or self.h_scrollbar.dragging +end + + +---@return boolean +function View:scrollbar_hovering() + return self.v_scrollbar.hovering.track or self.h_scrollbar.hovering.track end @@ -178,14 +134,18 @@ end ---@param clicks integer ---return boolean function View:on_mouse_pressed(button, x, y, clicks) - if self:scrollbar_track_overlaps_point(x, y) then - if self:scrollbar_overlaps_point(x, y) then - self.dragging_scrollbar = true - else - local _, _, _, sh = self:get_scrollbar_rect() - local ly = (y - self.position.y) - sh / 2 - local pct = common.clamp(ly / self.size.y, 0, 100) - self.scroll.to.y = self:get_scrollable_size() * pct + if not self.scrollable then return end + local result = self.v_scrollbar:on_mouse_pressed(button, x, y, clicks) + if result then + if result ~= true then + self.scroll.to.y = result * self:get_scrollable_size() + end + return true + end + result = self.h_scrollbar:on_mouse_pressed(button, x, y, clicks) + if result then + if result ~= true then + self.scroll.to.x = result * self:get_h_scrollable_size() end return true end @@ -196,7 +156,9 @@ end ---@param x number ---@param y number function View:on_mouse_released(button, x, y) - self.dragging_scrollbar = false + if not self.scrollable then return end + self.v_scrollbar:on_mouse_released(button, x, y) + self.h_scrollbar:on_mouse_released(button, x, y) end @@ -205,22 +167,41 @@ end ---@param dx number ---@param dy number function View:on_mouse_moved(x, y, dx, dy) - if self.dragging_scrollbar then - local delta = self:get_scrollable_size() / self.size.y * dy - self.scroll.to.y = self.scroll.to.y + delta - if not config.animate_drag_scroll then - self:clamp_scroll_position() - self.scroll.y = self.scroll.to.y + if not self.scrollable then return end + local result + if self.h_scrollbar.dragging then goto skip_v_scrollbar end + result = self.v_scrollbar:on_mouse_moved(x, y, dx, dy) + if result then + if result ~= true then + self.scroll.to.y = result * self:get_scrollable_size() + if not config.animate_drag_scroll then + self:clamp_scroll_position() + self.scroll.y = self.scroll.to.y + end end + -- hide horizontal scrollbar + self.h_scrollbar:on_mouse_left() + return true + end + ::skip_v_scrollbar:: + result = self.h_scrollbar:on_mouse_moved(x, y, dx, dy) + if result then + if result ~= true then + self.scroll.to.x = result * self:get_h_scrollable_size() + if not config.animate_drag_scroll then + self:clamp_scroll_position() + self.scroll.x = self.scroll.to.x + end + end + return true end - self.hovered_scrollbar = self:scrollbar_overlaps_point(x, y) - self.hovered_scrollbar_track = self.hovered_scrollbar or self:scrollbar_track_overlaps_point(x, y) end function View:on_mouse_left() - self.hovered_scrollbar = false - self.hovered_scrollbar_track = false + if not self.scrollable then return end + self.v_scrollbar:on_mouse_left() + self.h_scrollbar:on_mouse_left() end @@ -238,14 +219,17 @@ function View:on_text_input(text) -- no-op end + function View:on_ime_text_editing(text, start, length) -- no-op end ----@param y number ----@return boolean -function View:on_mouse_wheel(y) +---@param y number @Vertical scroll delta; positive is "up" +---@param x number @Horizontal scroll delta; positive is "left" +---@return boolean @Capture event +function View:on_mouse_wheel(y, x) + -- no-op end ---Can be overriden to listen for scale change events to apply @@ -273,27 +257,22 @@ end function View:clamp_scroll_position() local max = self:get_scrollable_size() - self.size.y self.scroll.to.y = common.clamp(self.scroll.to.y, 0, max) + + max = self:get_h_scrollable_size() - self.size.x + self.scroll.to.x = common.clamp(self.scroll.to.x, 0, max) end function View:update_scrollbar() - local x, y, w, h = self:get_scrollbar_rect() - self.scrollbar.w.to.thumb = w - self:move_towards(self.scrollbar.w, "thumb", self.scrollbar.w.to.thumb, 0.3, "scroll") - self.scrollbar.x.thumb = x + w - self.scrollbar.w.thumb - self.scrollbar.y.thumb = y - self.scrollbar.h.thumb = h + local v_scrollable = self:get_scrollable_size() + self.v_scrollbar:set_size(self.position.x, self.position.y, self.size.x, self.size.y, v_scrollable) + self.v_scrollbar:set_percent(self.scroll.y/v_scrollable) + self.v_scrollbar:update() - local x, y, w, h = self:get_scrollbar_track_rect() - self.scrollbar.w.to.track = w - self:move_towards(self.scrollbar.w, "track", self.scrollbar.w.to.track, 0.3, "scroll") - self.scrollbar.x.track = x + w - self.scrollbar.w.track - self.scrollbar.y.track = y - self.scrollbar.h.track = h - - -- we use 100 for a smoother transition - self.scrollbar_alpha.to = (self.hovered_scrollbar_track or self.dragging_scrollbar) and 100 or 0 - self:move_towards(self.scrollbar_alpha, "value", self.scrollbar_alpha.to, 0.3, "scroll") + local h_scrollable = self:get_h_scrollable_size() + self.h_scrollbar:set_size(self.position.x, self.position.y, self.size.x, self.size.y, h_scrollable) + self.h_scrollbar:set_percent(self.scroll.x/h_scrollable) + self.h_scrollbar:update() end @@ -306,7 +285,7 @@ function View:update() self:clamp_scroll_position() self:move_towards(self.scroll, "x", self.scroll.to.x, 0.3, "scroll") self:move_towards(self.scroll, "y", self.scroll.to.y, 0.3, "scroll") - + if not self.scrollable then return end self:update_scrollbar() end @@ -319,29 +298,11 @@ function View:draw_background(color) end -function View:draw_scrollbar_track() - if not (self.hovered_scrollbar_track or self.dragging_scrollbar) - and self.scrollbar_alpha.value == 0 then - return - end - local color = { table.unpack(style.scrollbar_track) } - color[4] = color[4] * self.scrollbar_alpha.value / 100 - renderer.draw_rect(self.scrollbar.x.track, self.scrollbar.y.track, - self.scrollbar.w.track, self.scrollbar.h.track, color) -end - - -function View:draw_scrollbar_thumb() - local highlight = self.hovered_scrollbar or self.dragging_scrollbar - local color = highlight and style.scrollbar2 or style.scrollbar - renderer.draw_rect(self.scrollbar.x.thumb, self.scrollbar.y.thumb, - self.scrollbar.w.thumb, self.scrollbar.h.thumb, color) -end - - function View:draw_scrollbar() - self:draw_scrollbar_track() - self:draw_scrollbar_thumb() + self.v_scrollbar:draw_track() + self.v_scrollbar:draw_thumb() + self.h_scrollbar:draw_track() + self.h_scrollbar:draw_thumb() end diff --git a/data/plugins/linewrapping.lua b/data/plugins/linewrapping.lua index 66b303ee..b8ea4c79 100644 --- a/data/plugins/linewrapping.lua +++ b/data/plugins/linewrapping.lua @@ -219,7 +219,7 @@ function LineWrapping.draw_guide(docview) end function LineWrapping.update_docview_breaks(docview) - local x,y,w,h = docview:get_scrollbar_rect() + local x,y,w,h = docview.v_scrollbar:get_thumb_rect() local width = (type(config.plugins.linewrapping.width_override) == "function" and config.plugins.linewrapping.width_override(docview)) or config.plugins.linewrapping.width_override or (docview.size.x - docview:get_gutter_width() - w) if (not docview.wrapped_settings or docview.wrapped_settings.width == nil or width ~= docview.wrapped_settings.width) then diff --git a/data/plugins/treeview.lua b/data/plugins/treeview.lua index 0a14e9b7..023bcb25 100644 --- a/data/plugins/treeview.lua +++ b/data/plugins/treeview.lua @@ -195,10 +195,10 @@ end function TreeView:on_mouse_moved(px, py, ...) if not self.visible then return end - TreeView.super.on_mouse_moved(self, px, py, ...) self.cursor_pos.x = px self.cursor_pos.y = py - if self.dragging_scrollbar then + if TreeView.super.on_mouse_moved(self, px, py, ...) then + -- mouse movement handled by the View (scrollbar) self.hovered_item = nil return end diff --git a/src/api/system.c b/src/api/system.c index 74ecc4c8..c0e0855d 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -301,8 +301,15 @@ top: case SDL_MOUSEWHEEL: lua_pushstring(L, "mousewheel"); +#if SDL_VERSION_ATLEAST(2, 0, 18) + lua_pushnumber(L, e.wheel.preciseY); + // Use -x to keep consistency with vertical scrolling values (e.g. shift+scroll) + lua_pushnumber(L, -e.wheel.preciseX); +#else lua_pushinteger(L, e.wheel.y); - return 2; + lua_pushinteger(L, -e.wheel.x); +#endif + return 3; default: goto top;