aboutsummaryrefslogtreecommitdiff
path: root/plugins/draganddropselectedtext.lua
blob: d27169d6a38b0b9342e486785d62c3094cf5de78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
--[[
    draganddropselectedtext.lua
    provides basic drag and drop of selected text (in same document)
    version: 20200626_013631
    originally by SwissalpS

    TODO: use OS drag and drop events
    TODO: change mouse cursor when duplicating
    TODO: add dragging image
--]]
local DocView = require "core.docview"
local core = require "core"
local keymap = require "core.keymap"

-- helper function for on_mouse_pressed to determine if mouse down is in selection
-- iLine is line number where mouse down happened
-- iCol is column where mouse down happened
-- iSelLine1 is line number where selection starts
-- iSelCol1 is column where selection starts
-- iSelLine2 is line number where selection ends
-- iSelCol2 is column where selection ends
local function isInSelection(iLine, iCol, iSelLine1, iSelCol1, iSelLine2, iSelCol2)
    if iLine < iSelLine1 then return false end
    if iLine > iSelLine2 then return false end
    if (iLine == iSelLine1) and (iCol < iSelCol1) then return false end
    if (iLine == iSelLine2) and (iCol > iSelCol2) then return false end
    return true
end -- isInSelection

-- override DocView:on_mouse_moved
local on_mouse_moved = DocView.on_mouse_moved
function DocView:on_mouse_moved(x, y, ...)

    -- make sure we only act if previously on_mouse_pressed was in selection
    if self.bClickedIntoSelection then

        -- check for modifier to duplicate
        -- (may want to set a flag as this only needs to be done once)
        -- TODO: make image to drag with and/or hand over to OS dnd event
        if not keymap.modkeys['ctrl'] then
            -- TODO: maybe check if moved at all and only delete then or
            -- as some editors do, only when dropped. I do like it going
            -- instantly as that reduces the travel-distance.
            self.doc:delete_to(0)
            --self.cursor = 'arrowWithPlus'
        end
        -- calculate line and column for current mouse position
        local iLine, iCol = self:resolve_screen_position(x, y)
        -- move text cursor
        self.doc:set_selection(iLine, iCol)
        -- update scroll position
        self:scroll_to_line(iLine, true)

    end -- if previously clicked into selection

    -- hand off to 'old' on_mouse_moved()
    return on_mouse_moved(self, x, y, ...)

end -- DocView:on_mouse_moved

-- override DocView:on_mouse_pressed
local on_mouse_pressed = DocView.on_mouse_pressed
function DocView:on_mouse_pressed(button, x, y, clicks)

    -- no need to proceed if not left button or has no selection
    if ('left' ~= button)
      or (not self.doc:has_selection())
      or (1 < clicks) then
        return on_mouse_pressed(self, button, x, y, clicks)
    end
    -- convert pixel coordinates to line and column coordinates
    local iLine, iCol = self:resolve_screen_position(x, y)
    -- get selection coordinates
    local iSelLine1, iSelCol1, iSelLine2, iSelCol2 = self.doc:get_selection(true)
    -- set flag for on_mouse_released and on_mouse_moved() methods to detect dragging
    self.bClickedIntoSelection = isInSelection(iLine, iCol, iSelLine1, iSelCol1,
                                               iSelLine2, iSelCol2)
    if self.bClickedIntoSelection then
        -- stash selection for inserting later
        self.sDraggedText = self.doc:get_text(self.doc:get_selection())
    else
        -- let 'old' on_mouse_pressed() do whatever it needs to do
        on_mouse_pressed(self, button, x, y, clicks)
    end

end -- DocView:on_mouse_pressed

-- override DocView:on_mouse_released()
local on_mouse_released = DocView.on_mouse_released
function DocView:on_mouse_released(button)

    if self.bClickedIntoSelection then
        -- insert stashed selected text at current position
        self.doc:text_input(self.sDraggedText)
        -- unset stash and flag(s) TODO:
        self.sDraggedText = ''
        self.bClickedIntoSelection = nil
    end

    -- hand over to old handler
    on_mouse_released(self, button)

end -- DocView:on_mouse_released