Merge topic branch for tabs scrolling buttons

This commit is contained in:
Francesco Abbate
2021-05-19 22:59:29 +02:00
5 changed files with 152 additions and 481 deletions
+1
View File
@@ -11,6 +11,7 @@ config.symbol_pattern = "[%a_][%w_]*"
config.non_word_chars = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
config.undo_merge_timeout = 0.3
config.max_undos = 10000
config.max_tabs = 10
config.highlight_current_line = true
config.line_height = 1.2
config.indent_size = 2
+121 -15
View File
@@ -1,5 +1,6 @@
local core = require "core"
local common = require "core.common"
local config = require "core.config"
local style = require "core.style"
local keymap = require "core.keymap"
local Object = require "core.object"
@@ -59,7 +60,9 @@ function Node:new(type)
end
self.hovered = {x = -1, y = -1 }
self.hovered_close = 0
self.tab_margin = style.padding.x
self.tab_shift = 0
self.tab_offset = 1
self.tab_width = style.tab_width
self.move_towards = View.move_towards
end
@@ -221,6 +224,15 @@ function Node:get_children(t)
end
-- return the width including the padding space and separately
-- the padding space itself
local function get_scroll_button_width()
local w = style.icon_font:get_width(">")
local pad = w
return w + 2 * pad, pad
end
function Node:get_divider_overlapping_point(px, py)
if self.type ~= "leaf" then
local p = 6
@@ -236,11 +248,18 @@ function Node:get_divider_overlapping_point(px, py)
end
function Node:get_visible_tabs_number()
return math.min(#self.views - self.tab_offset + 1, config.max_tabs)
end
function Node:get_tab_overlapping_point(px, py)
if #self.views == 1 then return nil end
local x, y, w, h = self:get_tab_rect(1)
if px >= x and py >= y and px < x + w * #self.views and py < y + h then
return math.floor((px - x) / w) + 1
local tabs_number = self:get_visible_tabs_number()
local x1, y1, w, h = self:get_tab_rect(self.tab_offset)
local x2, y2 = self:get_tab_rect(self.tab_offset + tabs_number)
if px >= x1 and py >= y1 and px < x2 and py < y1 + h then
return math.floor((px - x1) / w) + self.tab_offset
end
end
@@ -252,18 +271,30 @@ local function close_button_location(x, w)
end
function Node:get_scroll_button_index(px, py)
for i = 1, 2 do
local x, y, w, h = self:get_scroll_button_rect(i)
if px >= x and px < x + w and py >= y and py < y + h then
return i
end
end
end
function Node:tab_hovered_update(px, py)
local tab_index = self:get_tab_overlapping_point(px, py)
self.hovered_tab = tab_index
self.hovered_close = 0
self.hovered_scroll_button = 0
if tab_index then
local x, y, w, h = self:get_tab_rect(tab_index)
local cx, cw = close_button_location(x, w)
if px >= cx and px < cx + cw and py >= y and py < y + h then
self.hovered_close = tab_index
return
end
else
self.hovered_scroll_button = self:get_scroll_button_index(px, py) or 0
end
self.hovered_close = 0
end
@@ -280,10 +311,20 @@ function Node:get_child_overlapping_point(x, y)
end
function Node:get_scroll_button_rect(index)
local w, pad = get_scroll_button_width()
local h = style.font:get_height() + style.padding.y * 2
local x = self.position.x + (index == 1 and 0 or self.size.x - w)
return x, self.position.y, w, h, pad
end
function Node:get_tab_rect(idx)
local tw = math.min(style.tab_width, (self.size.x - self.tab_margin) / #self.views)
local x_left = self.position.x + tw * (idx - 1)
local x1, x2 = math.floor(x_left), math.floor(x_left + tw)
local sbw = get_scroll_button_width()
local maxw = self.size.x - 2 * sbw
local x0 = self.position.x + sbw
local x1 = x0 + common.clamp(self.tab_width * (idx - 1) - self.tab_shift, 0, maxw)
local x2 = x0 + common.clamp(self.tab_width * idx - self.tab_shift, 0, maxw)
local h = style.font:get_height() + style.padding.y * 2
return x1, self.position.y, x2 - x1, h
end
@@ -386,13 +427,61 @@ function Node:update_layout()
end
function Node:scroll_tabs_to_visible()
local index = self:get_view_idx(self.active_view)
if index then
local tabs_number = self:get_visible_tabs_number()
if self.tab_offset > index then
self.tab_offset = index
elseif self.tab_offset + tabs_number - 1 < index then
self.tab_offset = index - tabs_number + 1
elseif tabs_number < config.max_tabs and self.tab_offset > 1 then
self.tab_offset = #self.views - config.max_tabs + 1
end
end
end
function Node:scroll_tabs(dir)
local view_index = self:get_view_idx(self.active_view)
if dir == 1 then
if self.tab_offset > 1 then
self.tab_offset = self.tab_offset - 1
local last_index = self.tab_offset + self:get_visible_tabs_number() - 1
if view_index > last_index then
self:set_active_view(self.views[last_index])
end
end
elseif dir == 2 then
local tabs_number = self:get_visible_tabs_number()
if self.tab_offset + tabs_number - 1 < #self.views then
self.tab_offset = self.tab_offset + 1
local view_index = self:get_view_idx(self.active_view)
if view_index < self.tab_offset then
self:set_active_view(self.views[self.tab_offset])
end
end
end
end
function Node:target_tab_width()
local n = self:get_visible_tabs_number()
local w = self.size.x - get_scroll_button_width() * 2
return common.clamp(style.tab_width, w / config.max_tabs, w / n)
end
function Node:update()
if self.type == "leaf" then
self:scroll_tabs_to_visible()
for _, view in ipairs(self.views) do
view:update()
end
self:tab_hovered_update(self.hovered.x, self.hovered.y)
self:move_towards("tab_margin", style.padding.x)
local tab_width = self:target_tab_width()
self:move_towards("tab_shift", tab_width * (self.tab_offset - 1))
self:move_towards("tab_width", tab_width)
else
self.a:update()
self.b:update()
@@ -401,14 +490,27 @@ end
function Node:draw_tabs()
local x, y, _, h = self:get_tab_rect(1)
local x, y, w, h, scroll_padding = self:get_scroll_button_rect(1)
local ds = style.divider_size
local dots_width = style.font:get_width("")
core.push_clip_rect(x, y, self.size.x, h)
renderer.draw_rect(x, y, self.size.x, h, style.background2)
renderer.draw_rect(x, y + h - ds, self.size.x, ds, style.divider)
for i, view in ipairs(self.views) do
if self.tab_offset > 1 then
local button_style = self.hovered_scroll_button == 1 and style.text or style.dim
common.draw_text(style.icon_font, button_style, "<", nil, x + scroll_padding, y, 0, h)
end
local tabs_number = self:get_visible_tabs_number()
if #self.views > self.tab_offset + tabs_number - 1 then
local xrb, yrb, wrb = self:get_scroll_button_rect(2)
local button_style = self.hovered_scroll_button == 2 and style.text or style.dim
common.draw_text(style.icon_font, button_style, ">", nil, xrb + scroll_padding, yrb, 0, h)
end
for i = self.tab_offset, self.tab_offset + tabs_number - 1 do
local view = self.views[i]
local x, y, w, h = self:get_tab_rect(i)
local text = view:get_name()
local color = style.dim
@@ -637,11 +739,13 @@ function RootView:on_mouse_pressed(button, x, y, clicks)
return
end
local node = self.root_node:get_child_overlapping_point(x, y)
if node.hovered_scroll_button > 0 then
node:scroll_tabs(node.hovered_scroll_button)
return
end
local idx = node:get_tab_overlapping_point(x, y)
if idx then
if button == "middle" or node.hovered_close == idx then
local _, _, tw = node:get_tab_rect(idx)
node.tab_margin = node.tab_margin + tw
node:close_view(self.root_node, node.views[idx])
else
self.dragged_node = idx
@@ -702,7 +806,9 @@ function RootView:on_mouse_moved(x, y, dx, dy)
local node = self.root_node:get_child_overlapping_point(x, y)
local div = self.root_node:get_divider_overlapping_point(x, y)
local tab_index = node and node:get_tab_overlapping_point(x, y)
if div then
if node and node:get_scroll_button_index(x, y) then
system.set_cursor("arrow")
elseif div then
local axis = (div.type == "hsplit" and "x" or "y")
if div.a:is_resizable(axis) and div.b:is_resizable(axis) then
system.set_cursor(div.type == "hsplit" and "sizeh" or "sizev")
Binary file not shown.