Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
236 lines (205 sloc) 8.37 KB
-- Copyright 2014-18 Paul Kulchenko, ZeroBrane LLC; All rights reserved
local mappanel = "documentmappanel"
local markers = {CURRENT = "docmap.current", BACKGROUND = "docmap.background"}
local editormap, editorlinked
local id
local win = ide.osname == 'Windows'
local needupdate
local colors = { -- default values if no style colors are set
text = {64, 64, 64},
background = {208, 208, 208},
current = {240, 240, 230},
}
local function switchEditor(editor)
if editorlinked == editor then return end
if editormap then
if editor then
local font = editor:GetFont()
editormap:SetFont(font)
editormap:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, font)
-- reset styles when switching the editor
local styles = ide:GetConfig().styles
markers[markers.BACKGROUND] = ide:AddMarker(markers.BACKGROUND,
wxstc.wxSTC_MARK_BACKGROUND,
styles.text.fg or colors.text,
styles.sel.bg or colors.background)
editormap:MarkerDefine(ide:GetMarker(markers.BACKGROUND))
markers[markers.CURRENT] = ide:AddMarker(markers.CURRENT,
wxstc.wxSTC_MARK_BACKGROUND,
styles.text.fg or colors.text,
styles.caretlinebg.bg or colors.current)
editormap:MarkerDefine(ide:GetMarker(markers.CURRENT))
end
editormap:MarkerDeleteAll(markers[markers.CURRENT])
editormap:MarkerDeleteAll(markers[markers.BACKGROUND])
end
if editorlinked then
-- clear the editor in case the last editor tab was closed
if editormap and not editor
and ide:GetEditorNotebook():GetPageCount() == 1 then
editormap:SetDocPointer()
end
end
if editor then
editormap:SetDocPointer(editor:GetDocPointer())
end
editorlinked = editor
end
local function screenFirstLast(e)
local firstline = e:DocLineFromVisible(e:GetFirstVisibleLine())
local linesvisible = (e:DocLineFromVisible(e:GetFirstVisibleLine()+e:LinesOnScreen()-1)
- firstline)
return firstline, math.min(e:GetLineCount(), firstline + linesvisible)
end
local function sync(e1, e2)
local firstline, lastline = screenFirstLast(e1)
e2:MarkerDeleteAll(markers[markers.BACKGROUND])
for line = firstline, lastline do
e2:MarkerAdd(line, markers[markers.BACKGROUND])
end
local currline = e1:GetCurrentLine()
e2:MarkerDeleteAll(markers[markers.CURRENT])
e2:MarkerAdd(currline, markers[markers.CURRENT])
local linesmax1 = math.max(1, e1:GetLineCount() - (lastline-firstline))
local linesmax2 = math.max(1, e2:GetLineCount() - e2:LinesOnScreen())
local line2 = firstline * linesmax2 / linesmax1
e2:SetFirstVisibleLine(e2:VisibleFromDocLine(math.floor(line2)))
-- force refresh to keep the map editor up-to-date and reduce jumpy scroll
if win then e2:Refresh() e2:Update() end
end
return {
name = "Document Map",
description = "Adds document map.",
author = "Paul Kulchenko",
version = 0.31,
dependencies = "1.30",
onRegister = function(self)
local e = wxstc.wxStyledTextCtrl(ide:GetMainFrame(), wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxSize(20, 20), wx.wxBORDER_NONE)
editormap = e
local w, h = 150, 150
ide:AddPanel(e, mappanel, TR("Document Map"), function(pane)
pane:Dock():Right():TopDockable(false):BottomDockable(false)
:MinSize(w,-1):BestSize(w,-1):FloatingSize(w,h)
end)
-- remove all margins
for m = 0, 4 do e:SetMarginWidth(m, 0) end
e:SetUseHorizontalScrollBar(false)
e:SetUseVerticalScrollBar(false)
e:SetZoom(self:GetConfig().zoom or -7)
e:SetSelBackground(false, wx.wxBLACK)
e:SetCaretStyle(0) -- disable caret as it may be visible when selecting on inactive map
e:SetCursor(wx.wxCursor(wx.wxCURSOR_ARROW))
-- disable dragging from or to the map
e:Connect(wxstc.wxEVT_STC_START_DRAG, function(event) event:SetDragText("") end)
e:Connect(wxstc.wxEVT_STC_DO_DROP, function(event) event:SetDragResult(wx.wxDragNone) end)
do -- set readonly when switched to
local ro
e:Connect(wx.wxEVT_SET_FOCUS, function() ro = e:GetReadOnly() e:SetReadOnly(true) end)
e:Connect(wx.wxEVT_KILL_FOCUS, function() e:SetReadOnly(ro or false) end)
end
local function setFocus(editor)
editor:SetFocus()
if ide.osname == 'Macintosh' then
-- manually trigger KILL_FOCUS event on OSX: http://trac.wxwidgets.org/ticket/14142
editormap:GetEventHandler():ProcessEvent(wx.wxFocusEvent(wx.wxEVT_KILL_FOCUS))
end
end
local function jumpLinked(point)
local pos = e:PositionFromPoint(point)
local firstline, lastline = screenFirstLast(editorlinked)
local onscreen = lastline-firstline
local topline = math.floor(e:LineFromPosition(pos)-onscreen/2)
editorlinked:SetFirstVisibleLine(editorlinked:VisibleFromDocLine(topline))
end
local scroll
local function scrollLinked(point)
local onscreen = math.min(editorlinked:LinesOnScreen(), editorlinked:GetLineCount())
local line = e:LineFromPosition(e:PositionFromPoint(point))
local lineheight = e:TextHeight(line)
local count = e:GetLineCount()
local height = math.min(count * lineheight, e:GetClientSize():GetHeight())
local scrollnow = (point:GetY() - scroll) / (height - onscreen * lineheight)
local topline = math.floor((count-onscreen)*scrollnow)
editorlinked:SetFirstVisibleLine(editorlinked:VisibleFromDocLine(topline))
end
e:Connect(wx.wxEVT_LEFT_DOWN, function(event)
if not editorlinked then return end
local point = event:GetPosition()
local pos = e:PositionFromPoint(point)
local line = e:LineFromPosition(pos)
local firstline, lastline = screenFirstLast(editorlinked)
if line >= firstline and line <= lastline then
scroll = (line-firstline) * e:TextHeight(line)
if win then e:CaptureMouse() end
else
jumpLinked(point)
setFocus(editorlinked)
end
end)
e:Connect(wx.wxEVT_LEFT_UP, function(event)
if not editorlinked then return end
if scroll then
scroll = nil
setFocus(editorlinked)
if win then e:ReleaseMouse() end
end
end)
e:Connect(wx.wxEVT_MOTION, function(event)
if not editorlinked then return end
if scroll then scrollLinked(event:GetPosition()) end
end)
-- ignore all double click events as they cause selection in the editor
e:Connect(wx.wxEVT_LEFT_DCLICK, function(event) end)
-- ignore context menu
e:Connect(wx.wxEVT_CONTEXT_MENU, function(event) end)
-- set the cursor so it doesn't look like vertical beam
e:Connect(wx.wxEVT_SET_CURSOR, function(event)
event:SetCursor(wx.wxCursor(wx.wxCURSOR_ARROW))
end)
local menu = ide:FindTopMenu("&View")
id = ID("documentmap.documentmapview")
menu:InsertCheckItem(4, id, TR("Document Map Window")..KSC(id))
ide:GetMainFrame():Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, function (event)
local uimgr = ide:GetUIManager()
uimgr:GetPane(mappanel):Show(not uimgr:GetPane(mappanel):IsShown())
uimgr:Update()
end)
ide:GetMainFrame():Connect(id, wx.wxEVT_UPDATE_UI, function (event)
local pane = ide:GetUIManager():GetPane(mappanel)
ide:GetMenuBar():Enable(event:GetId(), pane:IsOk()) -- disable if doesn't exist
ide:GetMenuBar():Check(event:GetId(), pane:IsOk() and pane:IsShown())
end)
end,
onUnRegister = function(self)
switchEditor()
ide:RemoveMenuItem(id)
ide:RemovePanel(mappanel)
end,
onEditorFocusSet = function(self, editor)
if editorlinked ~= editor then
switchEditor(editor)
-- fix markers in the editor, otherwise they are shown as default markers
editor:MarkerDefine(markers[markers.CURRENT], wxstc.wxSTC_MARK_EMPTY)
editor:MarkerDefine(markers[markers.BACKGROUND], wxstc.wxSTC_MARK_EMPTY)
local doc = ide:GetDocument(editor)
if editormap and doc then editor.SetupKeywords(editormap, doc:GetFileExt()) end
needupdate = true
end
end,
onEditorClose = function(self, editor)
if editor == editorlinked then switchEditor() end
end,
onEditorUpdateUI = function(self, editor)
needupdate = true
end,
onEditorPainted = function(self, editor)
if editormap and editor == editorlinked and needupdate then
needupdate = false
sync(editorlinked, editormap)
end
end,
}
--[[ configuration example:
documentmap = {zoom = -7} -- zoom can be set from -10 (smallest) to 0 (normal)
--]]