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
This commit is contained in:
parent
5c2c95765e
commit
6b754eb628
|
@ -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
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -34,6 +34,7 @@ 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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -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 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
|
||||
self.hovered_scrollbar = self:scrollbar_overlaps_point(x, y)
|
||||
self.hovered_scrollbar_track = self.hovered_scrollbar or self:scrollbar_track_overlaps_point(x, y)
|
||||
-- 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
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue