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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
-- mod-version:2 -- lite-xl 2.0
--[[
dragdropselected.lua
provides basic drag and drop of selected text (in same document)
version: 20200627_133351
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"
local style = require "core.style"
-- 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
-- distance between two points
local function distance(x1, y1, x2, y2)
return math.sqrt(math.pow(x2-x1, 2)+math.pow(y2-y1, 2))
end
local min_drag = style.code_font:get_width(" ")
-- override DocView:on_mouse_moved
local on_mouse_moved = DocView.on_mouse_moved
function DocView:on_mouse_moved(x, y, ...)
local sCursor = nil
-- make sure we only act if previously on_mouse_pressed was in selection
if self.bClickedIntoSelection and
( -- we are already dragging or we moved enough to start dragging
not self.drag_start_loc or
distance(self.drag_start_loc[1],self.drag_start_loc[2], x, y) > min_drag
) then
self.drag_start_loc = nil
-- show that we are dragging something
sCursor = 'hand'
-- calculate line and column for current mouse position
local iLine, iCol = self:resolve_screen_position(x, y)
local iSelLine1 = self.dragged_selection[1]
local iSelCol1 = self.dragged_selection[2]
local iSelLine2 = self.dragged_selection[3]
local iSelCol2 = self.dragged_selection[4]
self.doc:set_selection(iSelLine1, iSelCol1, iSelLine2, iSelCol2)
if not isInSelection(iLine, iCol, iSelLine1, iSelCol1, iSelLine2, iSelCol2) then
-- show cursor only if outside selection
self.doc:add_selection(iLine, iCol)
end
-- update scroll position
self:scroll_to_line(iLine, true)
end -- if previously clicked into selection
-- hand off to 'old' on_mouse_moved()
on_mouse_moved(self, x, y, ...)
-- override cursor as needed
if sCursor then self.cursor = sCursor end
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
self.drag_start_loc = { x, y }
-- stash selection for inserting later
self.sDraggedText = self.doc:get_text(self.doc:get_selection())
self.dragged_selection = { iSelLine1, iSelCol1, iSelLine2, iSelCol2 }
else
self.bClickedIntoSelection = nil
self.dragged_selection = nil
-- 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, x, y)
local iLine, iCol = self:resolve_screen_position(x, y)
if self.bClickedIntoSelection then
local iSelLine1, iSelCol1, iSelLine2, iSelCol2 = table.unpack(self.dragged_selection)
if not self.drag_start_loc
and not isInSelection(iLine, iCol, iSelLine1, iSelCol1, iSelLine2, iSelCol2) then
-- insert stashed selected text at current position
if iLine < iSelLine1 or (iLine == iSelLine1 and iCol < iSelCol1) then
-- delete first
self.doc:set_selection(iSelLine1, iSelCol1, iSelLine2, iSelCol2)
if not keymap.modkeys['ctrl'] then
self.doc:delete_to(0)
end
self.doc:set_selection(iLine, iCol)
self.doc:text_input(self.sDraggedText)
else
-- insert first
self.doc:set_selection(iLine, iCol)
self.doc:text_input(self.sDraggedText)
self.doc:set_selection(iSelLine1, iSelCol1, iSelLine2, iSelCol2)
if not keymap.modkeys['ctrl'] then
self.doc:delete_to(0)
end
self.doc:set_selection(iLine, iCol)
end
elseif self.drag_start_loc then
-- deselect only if the drag never happened
self.doc:set_selection(iLine, iCol)
end
-- unset stash and flag(s) TODO:
self.sDraggedText = ''
self.bClickedIntoSelection = nil
end
-- hand over to old handler
on_mouse_released(self, button, x, y)
end -- DocView:on_mouse_released
-- override DocView:draw_caret()
local draw_caret = DocView.draw_caret
function DocView:draw_caret(x, y)
if self.bClickedIntoSelection then
local iLine, iCol = self:resolve_screen_position(x, y)
-- don't show carets inside selections
if isInSelection(iLine, iCol,
self.dragged_selection[1], self.dragged_selection[2],
self.dragged_selection[3], self.dragged_selection[4]) then
return
end
end
draw_caret(self, x, y)
end -- DocView:draw_caret()
|