diff --git a/data/core/config.lua b/data/core/config.lua index f9b4e87f..74ca3d2f 100644 --- a/data/core/config.lua +++ b/data/core/config.lua @@ -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 diff --git a/data/core/rootview.lua b/data/core/rootview.lua index da628c7e..7cdc78cb 100644 --- a/data/core/rootview.lua +++ b/data/core/rootview.lua @@ -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") diff --git a/data/fonts/icons.ttf b/data/fonts/icons.ttf index 00b4cc3b..43ab3767 100644 Binary files a/data/fonts/icons.ttf and b/data/fonts/icons.ttf differ diff --git a/dev-utils/fontello-config-small.json b/dev-utils/fontello-config-small.json deleted file mode 100644 index 895de303..00000000 --- a/dev-utils/fontello-config-small.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "name": "icons", - "css_prefix_text": "icon-", - "css_use_suffix": false, - "hinting": true, - "units_per_em": 1000, - "ascent": 850, - "glyphs": [ - { - "uid": "9dd9e835aebe1060ba7190ad2b2ed951", - "css": "search-1", - "code": 76, - "src": "fontawesome" - }, - { - "uid": "c76b7947c957c9b78b11741173c8349b", - "css": "attention-1", - "code": 33, - "src": "fontawesome" - }, - { - "uid": "1b5a5d7b7e3c71437f5a26befdd045ed", - "css": "doc-1", - "code": 102, - "src": "fontawesome" - }, - { - "uid": "f8aa663c489bcbd6e68ec8147dca841e", - "css": "folder-1", - "code": 100, - "src": "fontawesome" - }, - { - "uid": "c95735c17a10af81448c7fed98a04546", - "css": "folder-open-1", - "code": 68, - "src": "fontawesome" - }, - { - "uid": "e99461abfef3923546da8d745372c995", - "css": "cog", - "code": 80, - "src": "fontawesome" - }, - { - "uid": "7bf14281af5633a597f85b061ef1cfb9", - "css": "angle-right", - "code": 43, - "src": "fontawesome" - }, - { - "uid": "e4dde1992f787163e2e2b534b8c8067d", - "css": "angle-down", - "code": 45, - "src": "fontawesome" - }, - { - "uid": "ea2d9a8c51ca42b38ef0d2a07f16d9a7", - "css": "chart-line", - "code": 103, - "src": "fontawesome" - }, - { - "uid": "f4445feb55521283572ee88bc304f928", - "css": "floppy", - "code": 83, - "src": "fontawesome" - }, - { - "uid": "9755f76110ae4d12ac5f9466c9152031", - "css": "book", - "code": 66, - "src": "fontawesome" - }, - { - "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", - "css": "info-circled-1", - "code": 105, - "src": "fontawesome" - }, - { - "uid": "5211af474d3a9848f67f945e2ccaf143", - "css": "cancel-1", - "code": 67, - "src": "fontawesome" - }, - { - "uid": "04f022b8bd044d4ccfffd3887ff72088", - "css": "window-minimize", - "code": 95, - "src": "fontawesome" - }, - { - "uid": "d0e62145dbf40f30e47b3819b8b43a8f", - "css": "window-restore", - "code": 119, - "src": "fontawesome" - }, - { - "uid": "7394501fc0b17cb7bda99538f92e26d6", - "css": "window-close", - "code": 88, - "src": "fontawesome" - }, - { - "uid": "559647a6f430b3aeadbecd67194451dd", - "css": "menu-1", - "code": 77, - "src": "fontawesome" - }, - { - "uid": "07f0832c07f3d9713fffb06c8bffa027", - "css": "window-maximize", - "code": 87, - "src": "fontawesome" - } - ] -} \ No newline at end of file diff --git a/dev-utils/fontello-config.json b/dev-utils/fontello-config.json index 9dd4681d..42334c2f 100644 --- a/dev-utils/fontello-config.json +++ b/dev-utils/fontello-config.json @@ -1,5 +1,5 @@ { - "name": "", + "name": "icons", "css_prefix_text": "icon-", "css_use_suffix": false, "hinting": true, @@ -12,234 +12,18 @@ "code": 76, "src": "fontawesome" }, - { - "uid": "12f4ece88e46abd864e40b35e05b11cd", - "css": "ok-1", - "code": 59402, - "src": "fontawesome" - }, - { - "uid": "43ab845088317bd348dee1d975700c48", - "css": "ok-circled-1", - "code": 59403, - "src": "fontawesome" - }, - { - "uid": "ad33e708f4d2e25c5056c931da1528d6", - "css": "ok-circled2", - "code": 59405, - "src": "fontawesome" - }, - { - "uid": "1400d5103edd2fa6d2d61688fee79a5a", - "css": "ok-squared", - "code": 61770, - "src": "fontawesome" - }, - { - "uid": "5211af474d3a9848f67f945e2ccaf143", - "css": "cancel-1", - "code": 67, - "src": "fontawesome" - }, - { - "uid": "0f4cae16f34ae243a6144c18a003f2d8", - "css": "cancel-circled-1", - "code": 99, - "src": "fontawesome" - }, - { - "uid": "d7271d490b71df4311e32cdacae8b331", - "css": "home-1", - "code": 59407, - "src": "fontawesome" - }, - { - "uid": "3d4ea8a78dc34efe891f3a0f3d961274", - "css": "info", - "code": 61737, - "src": "fontawesome" - }, - { - "uid": "ce3cf091d6ebd004dd0b52d24074e6e3", - "css": "help", - "code": 61736, - "src": "fontawesome" - }, - { - "uid": "17ebadd1e3f274ff0205601eef7b9cc4", - "css": "help-circled-1", - "code": 59408, - "src": "fontawesome" - }, - { - "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", - "css": "info-circled-1", - "code": 59409, - "src": "fontawesome" - }, - { - "uid": "c1f1975c885aa9f3dad7810c53b82074", - "css": "lock", - "code": 59410, - "src": "fontawesome" - }, - { - "uid": "657ab647f6248a6b57a5b893beaf35a9", - "css": "lock-open-1", - "code": 59411, - "src": "fontawesome" - }, - { - "uid": "05376be04a27d5a46e855a233d6e8508", - "css": "lock-open-alt-1", - "code": 61758, - "src": "fontawesome" - }, - { - "uid": "3db5347bd219f3bce6025780f5d9ef45", - "css": "tag", - "code": 59412, - "src": "fontawesome" - }, - { - "uid": "a3f89e106175a5c5c4e9738870b12e55", - "css": "tags", - "code": 59413, - "src": "fontawesome" - }, - { - "uid": "7034e4d22866af82bef811f52fb1ba46", - "css": "code", - "code": 61729, - "src": "fontawesome" - }, - { - "uid": "d35a1d35efeb784d1dc9ac18b9b6c2b6", - "css": "pencil-1", - "code": 59414, - "src": "fontawesome" - }, - { - "uid": "44fae3bfdd54754dc68ec50d37efea37", - "css": "pencil-squared", - "code": 61771, - "src": "fontawesome" - }, - { - "uid": "41087bc74d4b20b55059c60a33bf4008", - "css": "edit", - "code": 59415, - "src": "fontawesome" - }, - { - "uid": "ecb97add13804c190456025e43ec003b", - "css": "keyboard", - "code": 61724, - "src": "fontawesome" - }, { "uid": "c76b7947c957c9b78b11741173c8349b", "css": "attention-1", "code": 33, "src": "fontawesome" }, - { - "uid": "00391fac5d419345ffcccd95b6f76263", - "css": "attention-alt-1", - "code": 61738, - "src": "fontawesome" - }, - { - "uid": "b035c28eba2b35c6ffe92aee8b0df507", - "css": "attention-circled", - "code": 59417, - "src": "fontawesome" - }, - { - "uid": "f48ae54adfb27d8ada53d0fd9e34ee10", - "css": "trash-empty", - "code": 59418, - "src": "fontawesome" - }, { "uid": "1b5a5d7b7e3c71437f5a26befdd045ed", "css": "doc-1", "code": 102, "src": "fontawesome" }, - { - "uid": "c8585e1e5b0467f28b70bce765d5840c", - "css": "docs", - "code": 61637, - "src": "fontawesome" - }, - { - "uid": "5408be43f7c42bccee419c6be53fdef5", - "css": "doc-text", - "code": 61686, - "src": "fontawesome" - }, - { - "uid": "178053298e3e5b03551d754d4b9acd8b", - "css": "doc-inv", - "code": 61787, - "src": "fontawesome" - }, - { - "uid": "c08a1cde48d96cba21d8c05fa7d7feb1", - "css": "doc-text-inv", - "code": 61788, - "src": "fontawesome" - }, - { - "uid": "9daa1fdf0838118518a7e22715e83abc", - "css": "file-pdf", - "code": 61889, - "src": "fontawesome" - }, - { - "uid": "310ffd629da85142bc8669f010556f2d", - "css": "file-word", - "code": 61890, - "src": "fontawesome" - }, - { - "uid": "edcd4022de8d8df266ef7c42d2658ca5", - "css": "file-powerpoint", - "code": 61892, - "src": "fontawesome" - }, - { - "uid": "3c961c1a8d874815856fc6637dc5a13c", - "css": "file-image", - "code": 61893, - "src": "fontawesome" - }, - { - "uid": "e80ae555c1413a4ec18b33fb348b4049", - "css": "file-archive", - "code": 61894, - "src": "fontawesome" - }, - { - "uid": "81db033e704eb7c586a365559d7c0f36", - "css": "file-audio", - "code": 61895, - "src": "fontawesome" - }, - { - "uid": "dd69d9aa589ea7bc0a82a3fe67039f4b", - "css": "file-video", - "code": 61896, - "src": "fontawesome" - }, - { - "uid": "26613a2e6bc41593c54bead46f8c8ee3", - "css": "file-code", - "code": 61897, - "src": "fontawesome" - }, { "uid": "f8aa663c489bcbd6e68ec8147dca841e", "css": "folder-1", @@ -252,58 +36,10 @@ "code": 68, "src": "fontawesome" }, - { - "uid": "b091a8bd0fdade174951f17d936f51e4", - "css": "folder-empty-1", - "code": 61716, - "src": "fontawesome" - }, - { - "uid": "6533bdc16ab201eb3f3b27ce989cab33", - "css": "folder-open-empty-1", - "code": 61717, - "src": "fontawesome" - }, - { - "uid": "559647a6f430b3aeadbecd67194451dd", - "css": "menu-1", - "code": 61641, - "src": "fontawesome" - }, { "uid": "e99461abfef3923546da8d745372c995", "css": "cog", - "code": 59422, - "src": "fontawesome" - }, - { - "uid": "98687378abd1faf8f6af97c254eb6cd6", - "css": "cog-alt", - "code": 59423, - "src": "fontawesome" - }, - { - "uid": "5bb103cd29de77e0e06a52638527b575", - "css": "wrench", - "code": 59424, - "src": "fontawesome" - }, - { - "uid": "0b2b66e526028a6972d51a6f10281b4b", - "css": "zoom-in", - "code": 59425, - "src": "fontawesome" - }, - { - "uid": "d25d10efa900f529ad1d275657cfd30e", - "css": "zoom-out", - "code": 59426, - "src": "fontawesome" - }, - { - "uid": "f3f90c8c89795da30f7444634476ea4f", - "css": "angle-left", - "code": 61700, + "code": 80, "src": "fontawesome" }, { @@ -312,24 +48,12 @@ "code": 43, "src": "fontawesome" }, - { - "uid": "5de9370846a26947e03f63142a3f1c07", - "css": "angle-up", - "code": 61701, - "src": "fontawesome" - }, { "uid": "e4dde1992f787163e2e2b534b8c8067d", "css": "angle-down", "code": 45, "src": "fontawesome" }, - { - "uid": "bbfb51903f40597f0b70fd75bc7b5cac", - "css": "trash", - "code": 61944, - "src": "fontawesome" - }, { "uid": "ea2d9a8c51ca42b38ef0d2a07f16d9a7", "css": "chart-line", @@ -342,106 +66,64 @@ "code": 83, "src": "fontawesome" }, - { - "uid": "b429436ec5a518c78479d44ef18dbd60", - "css": "paste", - "code": 61674, - "src": "fontawesome" - }, - { - "uid": "8772331a9fec983cdb5d72902a6f9e0e", - "css": "scissors", - "code": 59428, - "src": "fontawesome" - }, { "uid": "9755f76110ae4d12ac5f9466c9152031", "css": "book", - "code": 59429, + "code": 66, "src": "fontawesome" }, { - "uid": "f9cbf7508cd04145ade2800169959eef", - "css": "font", - "code": 59430, + "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", + "css": "info-circled-1", + "code": 105, "src": "fontawesome" }, { - "uid": "d3b3f17bc3eb7cd809a07bbd4d178bee", - "css": "resize-vertical", - "code": 59431, + "uid": "5211af474d3a9848f67f945e2ccaf143", + "css": "cancel-1", + "code": 67, "src": "fontawesome" }, { - "uid": "3c73d058e4589b65a8d959c0fc8f153d", - "css": "resize-horizontal", - "code": 59432, + "uid": "04f022b8bd044d4ccfffd3887ff72088", + "css": "window-minimize", + "code": 95, "src": "fontawesome" }, { - "uid": "e594fc6e5870b4ab7e49f52571d52577", - "css": "resize-full", - "code": 59433, + "uid": "d0e62145dbf40f30e47b3819b8b43a8f", + "css": "window-restore", + "code": 119, "src": "fontawesome" }, { - "uid": "5278ef7773e948d56c4d442c8c8c98cf", - "css": "lightbulb", - "code": 61675, + "uid": "7394501fc0b17cb7bda99538f92e26d6", + "css": "window-close", + "code": 88, "src": "fontawesome" }, { - "uid": "598a5f2bcf3521d1615de8e1881ccd17", - "css": "clock", - "code": 59434, + "uid": "559647a6f430b3aeadbecd67194451dd", + "css": "menu-1", + "code": 77, "src": "fontawesome" }, { - "uid": "1c4068ed75209e21af36017df8871802", - "css": "down-big", - "code": 59435, + "uid": "07f0832c07f3d9713fffb06c8bffa027", + "css": "window-maximize", + "code": 87, "src": "fontawesome" }, { - "uid": "555ef8c86832e686fef85f7af2eb7cde", - "css": "left-big", - "code": 59436, + "uid": "d870630ff8f81e6de3958ecaeac532f2", + "css": "left-open", + "code": 60, "src": "fontawesome" }, { - "uid": "ad6b3fbb5324abe71a9c0b6609cbb9f1", - "css": "right-big", - "code": 59437, - "src": "fontawesome" - }, - { - "uid": "95376bf082bfec6ce06ea1cda7bd7ead", - "css": "up-big", - "code": 59438, - "src": "fontawesome" - }, - { - "uid": "107ce08c7231097c7447d8f4d059b55f", - "css": "ellipsis", - "code": 61761, - "src": "fontawesome" - }, - { - "uid": "750058837a91edae64b03d60fc7e81a7", - "css": "ellipsis-vert", - "code": 61762, - "src": "fontawesome" - }, - { - "uid": "8fb55fd696d9a0f58f3b27c1d8633750", - "css": "table", - "code": 61646, - "src": "fontawesome" - }, - { - "uid": "53dd31a6cc6438192b2d7b09b1c1dd45", - "css": "columns", - "code": 61659, + "uid": "399ef63b1e23ab1b761dfbb5591fa4da", + "css": "right-open", + "code": 62, "src": "fontawesome" } ]