doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / editors / space_text / text_python.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "DNA_screen_types.h"
34 #include "DNA_space_types.h"
35 #include "DNA_text_types.h"
36
37 #include "BKE_suggestions.h"
38 #include "BKE_text.h"
39
40 #include "BLI_blenlib.h"
41
42 #include "WM_types.h"
43
44 #include "text_intern.h"
45
46 int text_do_suggest_select(SpaceText *st, ARegion *ar)
47 {
48         SuggItem *item, *first, *last, *sel;
49         TextLine *tmp;
50         int l, x, y, w, h, i;
51         int tgti, *top;
52         short mval[2] = {0, 0};
53         
54         if(!st || !st->text) return 0;
55         if(!texttool_text_is_active(st->text)) return 0;
56
57         first = texttool_suggest_first();
58         last = texttool_suggest_last();
59         sel = texttool_suggest_selected();
60         top = texttool_suggest_top();
61
62         if(!last || !first)
63                 return 0;
64
65         /* Count the visible lines to the cursor */
66         for(tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
67         if(l<0) return 0;
68
69         text_update_character_width(st);
70         
71         if(st->showlinenrs) {
72                 x = st->cwidth*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
73         }
74         else {
75                 x = st->cwidth*(st->text->curc-st->left) + TXT_OFFSET - 4;
76         }
77         y = ar->winy - st->lheight*l - 2;
78
79         w = SUGG_LIST_WIDTH*st->cwidth + 20;
80         h = SUGG_LIST_SIZE*st->lheight + 8;
81
82         // XXX getmouseco_areawin(mval);
83
84         if(mval[0]<x || x+w<mval[0] || mval[1]<y-h || y<mval[1])
85                 return 0;
86
87         /* Work out which of the items is at the top of the visible list */
88         for(i=0, item=first; i<*top && item->next; i++, item=item->next);
89
90         /* Work out the target item index in the visible list */
91         tgti = (y-mval[1]-4) / st->lheight;
92         if(tgti<0 || tgti>SUGG_LIST_SIZE)
93                 return 1;
94
95         for(i=tgti; i>0 && item->next; i--, item=item->next);
96         if(item)
97                 texttool_suggest_select(item);
98         return 1;
99 }
100
101 void text_pop_suggest_list(void)
102 {
103         SuggItem *item, *sel;
104         int *top, i;
105
106         item= texttool_suggest_first();
107         sel= texttool_suggest_selected();
108         top= texttool_suggest_top();
109
110         i= 0;
111         while(item && item != sel) {
112                 item= item->next;
113                 i++;
114         }
115         if(i > *top+SUGG_LIST_SIZE-1)
116                 *top= i-SUGG_LIST_SIZE+1;
117         else if(i < *top)
118                 *top= i;
119 }
120
121 static void get_suggest_prefix(Text *text, int offset)
122 {
123         int i, len;
124         char *line, tmp[256];
125
126         if(!text) return;
127         if(!texttool_text_is_active(text)) return;
128
129         line= text->curl->line;
130         for(i=text->curc-1+offset; i>=0; i--)
131                 if(!text_check_identifier(line[i]))
132                         break;
133         i++;
134         len= text->curc-i+offset;
135         if(len > 255) {
136                 printf("Suggestion prefix too long\n");
137                 len = 255;
138         }
139         BLI_strncpy(tmp, line+i, len);
140         tmp[len]= '\0';
141         texttool_suggest_prefix(tmp);
142 }
143
144 static void confirm_suggestion(Text *text, int skipleft)
145 {
146         SuggItem *sel;
147         int i, over=0;
148         char *line;
149
150         if(!text) return;
151         if(!texttool_text_is_active(text)) return;
152
153         sel = texttool_suggest_selected();
154         if(!sel) return;
155
156         line= text->curl->line;
157         i=text->curc-skipleft-1;
158         while(i>=0) {
159                 if(!text_check_identifier(line[i]))
160                         break;
161                 over++;
162                 i--;
163         }
164
165         for(i=0; i<skipleft; i++)
166                 txt_move_left(text, 0);
167         for(i=0; i<over; i++)
168                 txt_move_left(text, 1);
169
170         txt_insert_buf(text, sel->name);
171         
172         for(i=0; i<skipleft; i++)
173                 txt_move_right(text, 0);
174
175         texttool_text_clear();
176 }
177
178 // XXX
179 #define L_MOUSE 0
180 #define M_MOUSE 0
181 #define R_MOUSE 0
182 #define LR_SHIFTKEY 0
183 #define LR_ALTKEY 0
184 #define LR_CTRLKEY 0
185 #define LR_OSKEY 0
186
187 // XXX
188 static int doc_scroll= 0;
189
190 static short do_texttools(SpaceText *st, char ascii, unsigned short evnt, short val)
191 {
192         ARegion *ar= NULL; // XXX
193         int qual= 0; // XXX
194         int draw=0, tools=0, swallow=0, scroll=1;
195         if(!texttool_text_is_active(st->text)) return 0;
196         if(!st->text || st->text->id.lib) return 0;
197
198         if(st->doplugins && texttool_text_is_active(st->text)) {
199                 if(texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
200                 if(texttool_docs_get()) tools |= TOOL_DOCUMENT;
201         }
202
203         if(ascii) {
204                 if(tools & TOOL_SUGG_LIST) {
205                         if((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) {
206                                 confirm_suggestion(st->text, 0);
207                                 text_update_line_edited(st->text->curl);
208                         }
209                         else if((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) {
210                                 get_suggest_prefix(st->text, 0);
211                                 text_pop_suggest_list();
212                                 swallow= 1;
213                                 draw= 1;
214                         }
215                 }
216                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
217
218         }
219         else if(val==1 && evnt) {
220                 switch (evnt) {
221                         case LEFTMOUSE:
222                                 if(text_do_suggest_select(st, ar))
223                                         swallow= 1;
224                                 else {
225                                         if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
226                                         if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
227                                 }
228                                 draw= 1;
229                                 break;
230                         case MIDDLEMOUSE:
231                                 if(text_do_suggest_select(st, ar)) {
232                                         confirm_suggestion(st->text, 0);
233                                         text_update_line_edited(st->text->curl);
234                                         swallow= 1;
235                                 }
236                                 else {
237                                         if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
238                                         if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
239                                 }
240                                 draw= 1;
241                                 break;
242                         case ESCKEY:
243                                 draw= swallow= 1;
244                                 if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
245                                 else if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
246                                 else draw= swallow= 0;
247                                 break;
248                         case RETKEY:
249                                 if(tools & TOOL_SUGG_LIST) {
250                                         confirm_suggestion(st->text, 0);
251                                         text_update_line_edited(st->text->curl);
252                                         swallow= 1;
253                                         draw= 1;
254                                 }
255                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
256                                 break;
257                         case LEFTARROWKEY:
258                         case BACKSPACEKEY:
259                                 if(tools & TOOL_SUGG_LIST) {
260                                         if(qual)
261                                                 texttool_suggest_clear();
262                                         else {
263                                                 /* Work out which char we are about to delete/pass */
264                                                 if(st->text->curl && st->text->curc > 0) {
265                                                         char ch= st->text->curl->line[st->text->curc-1];
266                                                         if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
267                                                                 get_suggest_prefix(st->text, -1);
268                                                                 text_pop_suggest_list();
269                                                         }
270                                                         else
271                                                                 texttool_suggest_clear();
272                                                 }
273                                                 else
274                                                         texttool_suggest_clear();
275                                         }
276                                 }
277                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
278                                 break;
279                         case RIGHTARROWKEY:
280                                 if(tools & TOOL_SUGG_LIST) {
281                                         if(qual)
282                                                 texttool_suggest_clear();
283                                         else {
284                                                 /* Work out which char we are about to pass */
285                                                 if(st->text->curl && st->text->curc < st->text->curl->len) {
286                                                         char ch= st->text->curl->line[st->text->curc+1];
287                                                         if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
288                                                                 get_suggest_prefix(st->text, 1);
289                                                                 text_pop_suggest_list();
290                                                         }
291                                                         else
292                                                                 texttool_suggest_clear();
293                                                 }
294                                                 else
295                                                         texttool_suggest_clear();
296                                         }
297                                 }
298                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
299                                 break;
300                         case PAGEDOWNKEY:
301                                 scroll= SUGG_LIST_SIZE-1;
302                         case WHEELDOWNMOUSE:
303                         case DOWNARROWKEY:
304                                 if(tools & TOOL_DOCUMENT) {
305                                         doc_scroll++;
306                                         swallow= 1;
307                                         draw= 1;
308                                         break;
309                                 }
310                                 else if(tools & TOOL_SUGG_LIST) {
311                                         SuggItem *sel = texttool_suggest_selected();
312                                         if(!sel) {
313                                                 texttool_suggest_select(texttool_suggest_first());
314                                         }
315                                         else while(sel && sel!=texttool_suggest_last() && sel->next && scroll--) {
316                                                 texttool_suggest_select(sel->next);
317                                                 sel= sel->next;
318                                         }
319                                         text_pop_suggest_list();
320                                         swallow= 1;
321                                         draw= 1;
322                                         break;
323                                 }
324                         case PAGEUPKEY:
325                                 scroll= SUGG_LIST_SIZE-1;
326                         case WHEELUPMOUSE:
327                         case UPARROWKEY:
328                                 if(tools & TOOL_DOCUMENT) {
329                                         if(doc_scroll>0) doc_scroll--;
330                                         swallow= 1;
331                                         draw= 1;
332                                         break;
333                                 }
334                                 else if(tools & TOOL_SUGG_LIST) {
335                                         SuggItem *sel = texttool_suggest_selected();
336                                         while(sel && sel!=texttool_suggest_first() && sel->prev && scroll--) {
337                                                 texttool_suggest_select(sel->prev);
338                                                 sel= sel->prev;
339                                         }
340                                         text_pop_suggest_list();
341                                         swallow= 1;
342                                         draw= 1;
343                                         break;
344                                 }
345                         case RIGHTSHIFTKEY:
346                         case LEFTSHIFTKEY:
347                                 break;
348                         default:
349                                 if(tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw= 1;
350                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
351                 }
352         }
353
354         if(draw)
355                 {}; // XXX redraw_alltext();
356         
357         return swallow;
358 }
359
360 #if 0
361 #ifdef WITH_PYTHON      
362         /* Run text plugin scripts if enabled */
363         if(st->doplugins && event && val) {
364                 if(BPY_menu_do_shortcut(PYMENU_TEXTPLUGIN, event, qual)) {
365                         do_draw= 1;
366                 }
367         }
368 #endif
369         if(do_draw)
370                 ; // XXX redraw_alltext();
371 #endif
372
373 static short do_textmarkers(SpaceText *st, char ascii, unsigned short evnt, short val)
374 {
375         Text *text;
376         TextMarker *marker, *mrk, *nxt;
377         int c, s, draw=0, swallow=0;
378         int qual= 0; // XXX
379
380         text= st->text;
381         if(!text || text->id.lib || text->curl != text->sell) return 0;
382
383         marker= txt_find_marker(text, text->sell, text->selc, 0, 0);
384         if(marker && (marker->start > text->curc || marker->end < text->curc))
385                 marker= NULL;
386
387         if(!marker) {
388                 /* Find the next temporary marker */
389                 if(evnt==TABKEY) {
390                         int lineno= txt_get_span(text->lines.first, text->curl);
391                         mrk= text->markers.first;
392                         while(mrk) {
393                                 if(!marker && (mrk->flags & TMARK_TEMP)) marker= mrk;
394                                 if((mrk->flags & TMARK_TEMP) && (mrk->lineno > lineno || (mrk->lineno==lineno && mrk->end > text->curc))) {
395                                         marker= mrk;
396                                         break;
397                                 }
398                                 mrk= mrk->next;
399                         }
400                         if(marker) {
401                                 txt_move_to(text, marker->lineno, marker->start, 0);
402                                 txt_move_to(text, marker->lineno, marker->end, 1);
403                                 // XXX text_update_cursor_moved(C);
404                                 // XXX WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
405                                 evnt= ascii= val= 0;
406                                 draw= 1;
407                                 swallow= 1;
408                         }
409                 }
410                 else if(evnt==ESCKEY) {
411                         if(txt_clear_markers(text, 0, TMARK_TEMP)) swallow= 1;
412                         else if(txt_clear_markers(text, 0, 0)) swallow= 1;
413                         else return 0;
414                         evnt= ascii= val= 0;
415                         draw= 1;
416                 }
417                 if(!swallow) return 0;
418         }
419
420         if(ascii) {
421                 if(marker->flags & TMARK_EDITALL) {
422                         c= text->curc-marker->start;
423                         s= text->selc-marker->start;
424                         if(s<0 || s>marker->end-marker->start) return 0;
425
426                         mrk= txt_next_marker(text, marker);
427                         while(mrk) {
428                                 nxt=txt_next_marker(text, mrk); /* mrk may become invalid */
429                                 txt_move_to(text, mrk->lineno, mrk->start+c, 0);
430                                 if(s!=c) txt_move_to(text, mrk->lineno, mrk->start+s, 1);
431                                 if(st->overwrite) {
432                                         if(txt_replace_char(text, ascii))
433                                                 text_update_line_edited(st->text->curl);
434                                 }
435                                 else {
436                                         if(txt_add_char(text, ascii)) {
437                                                 text_update_line_edited(st->text->curl);
438                                         }
439                                 }
440
441                                 if(mrk==marker || mrk==nxt) break;
442                                 mrk=nxt;
443                         }
444                         swallow= 1;
445                         draw= 1;
446                 }
447         }
448         else if(val) {
449                 switch(evnt) {
450                         case BACKSPACEKEY:
451                                 if(marker->flags & TMARK_EDITALL) {
452                                         c= text->curc-marker->start;
453                                         s= text->selc-marker->start;
454                                         if(s<0 || s>marker->end-marker->start) return 0;
455                                         
456                                         mrk= txt_next_marker(text, marker);
457                                         while(mrk) {
458                                                 nxt= txt_next_marker(text, mrk); /* mrk may become invalid */
459                                                 txt_move_to(text, mrk->lineno, mrk->start+c, 0);
460                                                 if(s!=c) txt_move_to(text, mrk->lineno, mrk->start+s, 1);
461                                                 txt_backspace_char(text);
462                                                 text_update_line_edited(st->text->curl);
463                                                 if(mrk==marker || mrk==nxt) break;
464                                                 mrk= nxt;
465                                         }
466                                         swallow= 1;
467                                         draw= 1;
468                                 }
469                                 break;
470                         case DELKEY:
471                                 if(marker->flags & TMARK_EDITALL) {
472                                         c= text->curc-marker->start;
473                                         s= text->selc-marker->start;
474                                         if(s<0 || s>marker->end-marker->start) return 0;
475                                         
476                                         mrk= txt_next_marker(text, marker);
477                                         while(mrk) {
478                                                 nxt= txt_next_marker(text, mrk); /* mrk may become invalid */
479                                                 txt_move_to(text, mrk->lineno, mrk->start+c, 0);
480                                                 if(s!=c) txt_move_to(text, mrk->lineno, mrk->start+s, 1);
481                                                 txt_delete_char(text);
482                                                 text_update_line_edited(st->text->curl);
483                                                 if(mrk==marker || mrk==nxt) break;
484                                                 mrk= nxt;
485                                         }
486                                         swallow= 1;
487                                         draw= 1;
488                                 }
489                                 break;
490                         case TABKEY:
491                                 if(qual & LR_SHIFTKEY) {
492                                         nxt= marker->prev;
493                                         if(!nxt) nxt= text->markers.last;
494                                 }
495                                 else {
496                                         nxt= marker->next;
497                                         if(!nxt) nxt= text->markers.first;
498                                 }
499                                 if(marker->flags & TMARK_TEMP) {
500                                         if(nxt==marker) nxt= NULL;
501                                         BLI_freelinkN(&text->markers, marker);
502                                 }
503                                 mrk= nxt;
504                                 if(mrk) {
505                                         txt_move_to(text, mrk->lineno, mrk->start, 0);
506                                         txt_move_to(text, mrk->lineno, mrk->end, 1);
507                                         // XXX text_update_cursor_moved(C);
508                                         // XXX WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
509                                 }
510                                 swallow= 1;
511                                 draw= 1;
512                                 break;
513
514                         /* Events that should clear markers */
515                         case UKEY: if(!(qual & LR_ALTKEY)) break;
516                         case ZKEY: if(evnt==ZKEY && !(qual & LR_CTRLKEY)) break;
517                         case RETKEY:
518                         case ESCKEY:
519                                 if(marker->flags & (TMARK_EDITALL | TMARK_TEMP))
520                                         txt_clear_markers(text, marker->group, 0);
521                                 else
522                                         BLI_freelinkN(&text->markers, marker);
523                                 swallow= 1;
524                                 draw= 1;
525                                 break;
526                         case RIGHTMOUSE: /* Marker context menu? */
527                         case LEFTMOUSE:
528                                 break;
529                         case FKEY: /* Allow find */
530                                 if(qual & LR_SHIFTKEY) swallow= 1;
531                                 break;
532
533                         default:
534                                 if(qual!=0 && qual!=LR_SHIFTKEY)
535                                         swallow= 1; /* Swallow all other shortcut events */
536                 }
537         }
538         
539         if(draw)
540                 {}; // XXX redraw_alltext();
541         
542         return swallow;
543 }
544