Fix dangling value in all GUI drivers.
[mp-5.x.git] / mp_clipboard.mpsl
blobfd72da7245f200ba4c1fb8e32c8f35df0324699b
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Clipboard routines.
8     Copyright (C) 1991-2007 Angel Ortega <angel@triptico.com>
10     This program is free software; you can redistribute it and/or
11     modify it under the terms of the GNU General Public License
12     as published by the Free Software Foundation; either version 2
13     of the License, or (at your option) any later version.
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24     http://www.triptico.com
28 /** editor actions **/
31 mp.actions['unmark']    = sub (d) { mp.unmark(d); };
32 mp.actions['mark']      = sub (d) { mp.mark(d); };
33 mp.actions['mark_vertical'] = sub (d) { mp.mark_vertical(d); };
34 mp.actions['copy_mark'] = sub (d) {
35                                         mp.busy(1);
36                                         mp.copy(d);
37                                         mp.unmark(d);
38                                         mp.busy(0);
39                                 };
41 mp.actions['paste_mark'] = sub (d) {
42                                         mp.busy(1);
43                                         mp.store_undo(d);
44                                         mp.paste(d);
45                                         mp.busy(0);
46                                 };
48 mp.actions['cut_mark']  = sub (d) {
49                                         mp.busy(1);
50                                         mp.store_undo(d);
51                                         mp.cut(d);
52                                         mp.busy(0);
53                                 };
55 mp.actions['delete_mark'] = sub (d) {
56                                         mp.busy(1);
57                                         mp.store_undo(d);
58                                         mp.delete_mark(d);
59                                         mp.busy(0);
60                                 };
62 mp.actions['mouse_drag_mark'] = sub (d) {
64         /* no selection yet? move to initial click and mark */
65         if (d.txt.mark == NULL)
66                 mp.mark(d);
68         /* move to drag position */
69         mp.move_to_coords_xy(d, mp.mouse_to_x, mp.mouse_to_y);
71         /* and mark */
72         mp.mark(d);
75 /** default key bindings **/
77 mp.keycodes['f8']               = "unmark";
78 mp.keycodes['f9']               = "mark";
79 mp.keycodes['ctrl-b']           = "mark_vertical";
80 mp.keycodes['ctrl-c']           = "copy_mark";
81 mp.keycodes['ctrl-v']           = "paste_mark";
82 mp.keycodes['ctrl-x']           = "cut_mark";
83 mp.keycodes['mouse-drag']       = "mouse_drag_mark";
85 /** action descriptions **/
87 mp.actdesc['unmark']            = LL("Unmark block");
88 mp.actdesc['mark']              = LL("Mark beginning/end of block");
89 mp.actdesc['mark_vertical']     = LL("Mark vertical block");
90 mp.actdesc['copy_mark']         = LL("Copy block");
91 mp.actdesc['paste_mark']        = LL("Paste block");
92 mp.actdesc['cut_mark']          = LL("Cut block");
93 mp.actdesc['delete_mark']       = LL("Delete block");
94 mp.actdesc['mouse_drag_mark']   = LL("Mark using mouse dragging");
96 /** code **/
99 sub mp.unmark(doc)
100 /* unmarks the block */
102         /* just destroy the mark */
103         doc.txt.mark = NULL;
105         return doc;
109 sub mp.mark(doc)
110 /* marks the start or end of the block */
112         local txt = doc.txt;
114         if (txt.mark == NULL) {
115                 /* no mark; create one */
116                 txt.mark = {};
117                 txt.mark.ax = txt.mark.bx = txt.mark.ex = txt.x;
118                 txt.mark.ay = txt.mark.by = txt.mark.ey = txt.y;
119                 txt.mark.vertical = 0;
120                 txt.mark.incomplete = 1;
121         }
122         else {
123                 /* mark exists; extend current one */
124                 if (txt.mark.vertical == 0) {
125                         /* normal selection */
126                         if (txt.y < txt.mark.ay ||
127                                 (txt.y == txt.mark.ay && txt.x < txt.mark.ax)) {
128                                 /* move the beginning of the block */
129                                 txt.mark.bx = txt.x;
130                                 txt.mark.by = txt.y;
131                                 txt.mark.ex = txt.mark.ax;
132                                 txt.mark.ey = txt.mark.ay;
133                         }
134                         else {
135                                 /* move the end of the block */
136                                 txt.mark.ex = txt.x;
137                                 txt.mark.ey = txt.y;
138                                 txt.mark.bx = txt.mark.ax;
139                                 txt.mark.by = txt.mark.ay;
140                         }
141                 }
142                 else {
143                         /* vertical selection */
144                         txt.mark.by = txt.mark.ay;
145                         txt.mark.ey = txt.y;
146                         if (txt.y < txt.mark.ay) {
147                                 txt.mark.by = txt.y;
148                                 txt.mark.ey = txt.mark.ay;
149                         }
151                         txt.mark.bx = txt.mark.ax;
152                         txt.mark.ex = txt.x;
153                         if (txt.x < txt.mark.ax) {
154                                 txt.mark.bx = txt.x;
155                                 txt.mark.ex = txt.mark.ax;
156                         }
157                 }
159                 txt.mark.incomplete = 0;
160         }
162         return doc;
166 sub mp.mark_vertical(doc)
167 /* start vertical block selection */
169         mp.mark(doc);
170         doc.txt.mark.vertical = 1;
172         return doc;
176 sub mp.get_active_area(doc)
177 /* returns the active area: the selection or the full document */
179         local m;
181         if ((m = doc.txt.mark) == NULL)
182                 return doc.txt.lines;
183         else
184                 return mp.get_range(doc, m.bx, m.by, m.ex, m.ey, m.vertical);
189  * mp.copy - Copies the selected block or a string to the clipboard
190  * @doc: the source of the copy
192  * If @doc is a document, it copies to the clipboard the content of the
193  * selected block, if one exists. If @doc is an array or scalar, it copies
194  * that data directly into it.
195  */
196 sub mp.copy(doc)
198         if (is_hash(doc)) {
199                 if (doc.txt.mark) {
200                         mp.clipboard = mp.get_active_area(doc);
201                         mp.clipboard_vertical = doc.txt.mark.vertical;
203                         mp.drv.clip_to_sys();
204                 }
205         }
206         else {
207                 if (!is_array(doc))
208                         doc = split("\n", doc);
210                 mp.clipboard = doc;
211                 mp.clipboard_vertical = 0;
212                 mp.drv.clip_to_sys();
213         }
215         return doc;
219 sub mp.delete_mark(doc)
220 /* deletes current selection */
222         local txt = doc.txt;
224         /* no mark? done */
225         if (txt.mark != NULL) {
226                 /* deletes the range */
227                 mp.delete_range(doc, txt.mark.bx, txt.mark.by,
228                                         txt.mark.ex, txt.mark.ey, txt.mark.vertical);
230                 mp.unmark(doc);
231         }
233         return doc;
237 sub mp.cut(doc)
238 /* cut (copy + delete) selected mark */
240         mp.copy(doc);
241         mp.delete_mark(doc);
242         mp.drv.clip_to_sys();
244         return doc;
249  * mp.paste - Pastes from the clipboard into a text or as a value
250  * @doc: the destination of the copy
252  * If @doc is NULL, returns the content of the clipboard as a
253  * scalar string; if it's not, is assumed to be a document and
254  * pastes the content of the clipboard into the cursor position.
255  */
256 sub mp.paste(doc)
258         mp.drv.sys_to_clip();
260         if (doc == NULL)
261                 return join("\n", mp.clipboard);
263         if (size(mp.clipboard) == 0)
264                 return doc;
266         local t = mp.config.auto_indent;
267         mp.config.auto_indent = 0;
269         /* is there a block? replace it */
270         if (doc.txt.mark != NULL) {
271                 /* move there */
272                 doc.txt.x = doc.txt.mark.bx;
273                 doc.txt.y = doc.txt.mark.by;
275                 /* and delete the block */
276                 mp.delete_mark(doc);
277         }
279         if (mp.clipboard_vertical == 0) {
280                 /* normal selection in clipboard */
281                 mp.insert(doc, mp.clipboard);
282         }
283         else {
284                 /* vertical selection in clipboard */
285                 local txt = doc.txt;
286                 local s = size(mp.clipboard);
287                 local i = 0;
288                 local w;
289                 local e;
290                 while (i < s) {
291                         /* pad out to current x position */
292                         e = txt.x - size(txt.lines[txt.y]);
294                         while(e-- > 0)
295                                 txt.lines[txt.y] = txt.lines[txt.y] ~ " ";
296                         
297                         /* insert this line of the clipboard */
298                         w = splice(txt.lines[txt.y], mp.clipboard[i++], txt.x, 0);
299                         txt.lines[txt.y++] = w[0];
300                 }
301                 txt.y--;
302                 txt.mod++;
303         }
305         mp.config.auto_indent = t;
307         return doc;