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