123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- local core = require "core"
- local common = require "core.common"
- local command = require "core.command"
- local config = require "core.config"
- local keymap = require "core.keymap"
- local style = require "core.style"
- local View = require "core.view"
- local TreeView = View:extend()
- local function get_depth(filename)
- local n = 0
- for sep in filename:gmatch("[\\/]") do
- n = n + 1
- end
- return n
- end
- function TreeView:new()
- TreeView.super.new(self)
- self.scrollable = true
- self.focusable = false
- self.visible = true
- self.cache = {}
- end
- function TreeView:get_cached(item)
- local t = self.cache[item.filename]
- if not t then
- t = {}
- t.filename = item.filename
- t.abs_filename = system.absolute_path(item.filename)
- t.path, t.name = t.filename:match("^(.*)[\\/](.+)$")
- t.depth = get_depth(t.filename)
- t.type = item.type
- self.cache[t.filename] = t
- end
- return t
- end
- function TreeView:get_name()
- return "Project"
- end
- function TreeView:get_item_height()
- return style.font:get_height() + style.padding.y
- end
- function TreeView:check_cache()
- -- invalidate cache's skip values if project_files has changed
- if core.project_files ~= self.last_project_files then
- for _, v in pairs(self.cache) do
- v.skip = nil
- end
- self.last_project_files = core.project_files
- end
- end
- function TreeView:each_item()
- return coroutine.wrap(function()
- self:check_cache()
- local ox, oy = self:get_content_offset()
- local y = oy + style.padding.y
- local w = self.size.x
- local h = self:get_item_height()
- local i = 1
- while i <= #core.project_files do
- local item = core.project_files[i]
- local cached = self:get_cached(item)
- coroutine.yield(cached, ox, y, w, h)
- y = y + h
- i = i + 1
- if not cached.expanded then
- if cached.skip then
- i = cached.skip
- else
- local depth = cached.depth
- while i <= #core.project_files do
- local filename = core.project_files[i].filename
- if get_depth(filename) <= depth then break end
- i = i + 1
- end
- cached.skip = i
- end
- end
- end
- end)
- end
- function TreeView:on_mouse_moved(px, py)
- self.hovered_item = nil
- for item, x,y,w,h in self:each_item() do
- if px > x and py > y and px <= x + w and py <= y + h then
- self.hovered_item = item
- break
- end
- end
- end
- function TreeView:on_mouse_pressed(button, x, y)
- if not self.hovered_item then
- return
- elseif self.hovered_item.type == "dir" then
- self.hovered_item.expanded = not self.hovered_item.expanded
- else
- core.try(function()
- core.root_view:open_doc(core.open_doc(self.hovered_item.filename))
- end)
- end
- end
- function TreeView:update()
- self.scroll.to.y = math.max(0, self.scroll.to.y)
- -- update width
- local dest = self.visible and config.treeview_size or 0
- self:move_towards(self.size, "x", dest)
- TreeView.super.update(self)
- end
- function TreeView:draw()
- self:draw_background(style.background2)
- local h = self:get_item_height()
- local icon_width = style.icon_font:get_width("D")
- local spacing = style.font:get_width(" ") * 2
- local root_depth = get_depth(core.project_dir) + 1
- local doc = core.active_view.doc
- local active_filename = doc and system.absolute_path(doc.filename or "")
- for item, x,y,w,h in self:each_item() do
- local color = style.text
- -- highlight active_view doc
- if item.abs_filename == active_filename then
- color = style.accent
- end
- -- hovered item background
- if item == self.hovered_item then
- renderer.draw_rect(x, y, w, h, style.line_highlight)
- color = style.accent
- end
- -- icons
- x = x + (item.depth - root_depth) * style.padding.x + style.padding.x
- if item.type == "dir" then
- local icon1 = item.expanded and "e" or "c"
- local icon2 = item.expanded and "D" or "d"
- common.draw_text(style.icon_font, color, icon1, nil, x, y, 0, h)
- x = x + style.padding.x
- common.draw_text(style.icon_font, color, icon2, nil, x, y, 0, h)
- x = x + icon_width
- else
- x = x + style.padding.x
- common.draw_text(style.icon_font, color, "f", nil, x, y, 0, h)
- x = x + icon_width
- end
- -- text
- x = x + spacing
- x = common.draw_text(style.font, color, item.name, nil, x, y, 0, h)
- end
- end
- -- init
- local view = TreeView()
- local node = core.root_view:get_active_node()
- view.size.x = config.treeview_size
- node:split("left", view, true)
- -- register commands and keymap
- command.add(nil, {
- ["treeview:toggle"] = function()
- view.visible = not view.visible
- end,
- })
- keymap.add { ["ctrl+\\"] = "treeview:toggle" }
|