style cleanup, brackets in else/if, some indentation.
[blender.git] / source / blender / editors / space_text / text_python.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_text/text_python.c
28  *  \ingroup sptext
29  */
30
31
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #include "DNA_screen_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_text_types.h"
39
40 #include "BKE_suggestions.h"
41 #include "BKE_text.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
45
46 #include "WM_types.h"
47
48 #include "text_intern.h"
49
50 int text_do_suggest_select(SpaceText *st, ARegion *ar)
51 {
52         SuggItem *item, *first, *last /* , *sel */ /* UNUSED */;
53         TextLine *tmp;
54         int l, x, y, w, h, i;
55         int tgti, *top;
56         int mval[2] = {0, 0};
57         
58         if(!st || !st->text) return 0;
59         if(!texttool_text_is_active(st->text)) return 0;
60
61         first = texttool_suggest_first();
62         last = texttool_suggest_last();
63         /* sel = texttool_suggest_selected(); */ /* UNUSED */
64         top = texttool_suggest_top();
65
66         if(!last || !first)
67                 return 0;
68
69         /* Count the visible lines to the cursor */
70         for(tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
71         if(l<0) return 0;
72
73         text_update_character_width(st);
74         
75         if(st->showlinenrs) {
76                 x = st->cwidth*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
77         }
78         else {
79                 x = st->cwidth*(st->text->curc-st->left) + TXT_OFFSET - 4;
80         }
81         y = ar->winy - st->lheight*l - 2;
82
83         w = SUGG_LIST_WIDTH*st->cwidth + 20;
84         h = SUGG_LIST_SIZE*st->lheight + 8;
85
86         // XXX getmouseco_areawin(mval);
87
88         if(mval[0]<x || x+w<mval[0] || mval[1]<y-h || y<mval[1])
89                 return 0;
90
91         /* Work out which of the items is at the top of the visible list */
92         for(i=0, item=first; i<*top && item->next; i++, item=item->next);
93
94         /* Work out the target item index in the visible list */
95         tgti = (y-mval[1]-4) / st->lheight;
96         if(tgti<0 || tgti>SUGG_LIST_SIZE)
97                 return 1;
98
99         for(i=tgti; i>0 && item->next; i--, item=item->next);
100         if(item)
101                 texttool_suggest_select(item);
102         return 1;
103 }
104
105 void text_pop_suggest_list(void)
106 {
107         SuggItem *item, *sel;
108         int *top, i;
109
110         item= texttool_suggest_first();
111         sel= texttool_suggest_selected();
112         top= texttool_suggest_top();
113
114         i= 0;
115         while(item && item != sel) {
116                 item= item->next;
117                 i++;
118         }
119         if(i > *top+SUGG_LIST_SIZE-1)
120                 *top= i-SUGG_LIST_SIZE+1;
121         else if(i < *top)
122                 *top= i;
123 }
124
125 static void get_suggest_prefix(Text *text, int offset)
126 {
127         int i, len;
128         char *line, tmp[256];
129
130         if(!text) return;
131         if(!texttool_text_is_active(text)) return;
132
133         line= text->curl->line;
134         for(i=text->curc-1+offset; i>=0; i--)
135                 if(!text_check_identifier(line[i]))
136                         break;
137         i++;
138         len= text->curc-i+offset;
139         if(len > 255) {
140                 printf("Suggestion prefix too long\n");
141                 len = 255;
142         }
143         BLI_strncpy(tmp, line+i, len);
144         tmp[len]= '\0';
145         texttool_suggest_prefix(tmp);
146 }
147
148 static void confirm_suggestion(Text *text, int skipleft)
149 {
150         SuggItem *sel;
151         int i, over=0;
152         char *line;
153
154         if(!text) return;
155         if(!texttool_text_is_active(text)) return;
156
157         sel = texttool_suggest_selected();
158         if(!sel) return;
159
160         line= text->curl->line;
161         i=text->curc-skipleft-1;
162         while(i>=0) {
163                 if(!text_check_identifier(line[i]))
164                         break;
165                 over++;
166                 i--;
167         }
168
169         for(i=0; i<skipleft; i++)
170                 txt_move_left(text, 0);
171         for(i=0; i<over; i++)
172                 txt_move_left(text, 1);
173
174         txt_insert_buf(text, sel->name);
175         
176         for(i=0; i<skipleft; i++)
177                 txt_move_right(text, 0);
178
179         texttool_text_clear();
180 }
181
182 // XXX
183 #define L_MOUSE 0
184 #define M_MOUSE 0
185 #define R_MOUSE 0
186 #define LR_SHIFTKEY 0
187 #define LR_ALTKEY 0
188 #define LR_CTRLKEY 0
189 #define LR_OSKEY 0
190
191 // XXX
192 static int doc_scroll= 0;
193
194 static short UNUSED_FUNCTION(do_texttools)(SpaceText *st, char ascii, unsigned short evnt, short val)
195 {
196         ARegion *ar= NULL; // XXX
197         int qual= 0; // XXX
198         int draw=0, tools=0, swallow=0, scroll=1;
199         if(!texttool_text_is_active(st->text)) return 0;
200         if(!st->text || st->text->id.lib) return 0;
201
202         if(st->doplugins && texttool_text_is_active(st->text)) {
203                 if(texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
204                 if(texttool_docs_get()) tools |= TOOL_DOCUMENT;
205         }
206
207         if(ascii) {
208                 if(tools & TOOL_SUGG_LIST) {
209                         if((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) {
210                                 confirm_suggestion(st->text, 0);
211                                 text_update_line_edited(st->text->curl);
212                         }
213                         else if((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) {
214                                 get_suggest_prefix(st->text, 0);
215                                 text_pop_suggest_list();
216                                 swallow= 1;
217                                 draw= 1;
218                         }
219                 }
220                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
221
222         }
223         else if(val==1 && evnt) {
224                 switch (evnt) {
225                         case LEFTMOUSE:
226                                 if(text_do_suggest_select(st, ar))
227                                         swallow= 1;
228                                 else {
229                                         if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
230                                         if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
231                                 }
232                                 draw= 1;
233                                 break;
234                         case MIDDLEMOUSE:
235                                 if(text_do_suggest_select(st, ar)) {
236                                         confirm_suggestion(st->text, 0);
237                                         text_update_line_edited(st->text->curl);
238                                         swallow= 1;
239                                 }
240                                 else {
241                                         if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
242                                         if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
243                                 }
244                                 draw= 1;
245                                 break;
246                         case ESCKEY:
247                                 draw= swallow= 1;
248                                 if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
249                                 else if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
250                                 else draw= swallow= 0;
251                                 break;
252                         case RETKEY:
253                                 if(tools & TOOL_SUGG_LIST) {
254                                         confirm_suggestion(st->text, 0);
255                                         text_update_line_edited(st->text->curl);
256                                         swallow= 1;
257                                         draw= 1;
258                                 }
259                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
260                                 break;
261                         case LEFTARROWKEY:
262                         case BACKSPACEKEY:
263                                 if(tools & TOOL_SUGG_LIST) {
264                                         if(qual)
265                                                 texttool_suggest_clear();
266                                         else {
267                                                 /* Work out which char we are about to delete/pass */
268                                                 if(st->text->curl && st->text->curc > 0) {
269                                                         char ch= st->text->curl->line[st->text->curc-1];
270                                                         if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
271                                                                 get_suggest_prefix(st->text, -1);
272                                                                 text_pop_suggest_list();
273                                                         }
274                                                         else
275                                                                 texttool_suggest_clear();
276                                                 }
277                                                 else
278                                                         texttool_suggest_clear();
279                                         }
280                                 }
281                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
282                                 break;
283                         case RIGHTARROWKEY:
284                                 if(tools & TOOL_SUGG_LIST) {
285                                         if(qual)
286                                                 texttool_suggest_clear();
287                                         else {
288                                                 /* Work out which char we are about to pass */
289                                                 if(st->text->curl && st->text->curc < st->text->curl->len) {
290                                                         char ch= st->text->curl->line[st->text->curc+1];
291                                                         if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
292                                                                 get_suggest_prefix(st->text, 1);
293                                                                 text_pop_suggest_list();
294                                                         }
295                                                         else
296                                                                 texttool_suggest_clear();
297                                                 }
298                                                 else
299                                                         texttool_suggest_clear();
300                                         }
301                                 }
302                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
303                                 break;
304                         case PAGEDOWNKEY:
305                                 scroll= SUGG_LIST_SIZE-1;
306                         case WHEELDOWNMOUSE:
307                         case DOWNARROWKEY:
308                                 if(tools & TOOL_DOCUMENT) {
309                                         doc_scroll++;
310                                         swallow= 1;
311                                         draw= 1;
312                                         break;
313                                 }
314                                 else if(tools & TOOL_SUGG_LIST) {
315                                         SuggItem *sel = texttool_suggest_selected();
316                                         if(!sel) {
317                                                 texttool_suggest_select(texttool_suggest_first());
318                                         }
319                                         else while(sel && sel!=texttool_suggest_last() && sel->next && scroll--) {
320                                                 texttool_suggest_select(sel->next);
321                                                 sel= sel->next;
322                                         }
323                                         text_pop_suggest_list();
324                                         swallow= 1;
325                                         draw= 1;
326                                         break;
327                                 }
328                         case PAGEUPKEY:
329                                 scroll= SUGG_LIST_SIZE-1;
330                         case WHEELUPMOUSE:
331                         case UPARROWKEY:
332                                 if(tools & TOOL_DOCUMENT) {
333                                         if(doc_scroll>0) doc_scroll--;
334                                         swallow= 1;
335                                         draw= 1;
336                                         break;
337                                 }
338                                 else if(tools & TOOL_SUGG_LIST) {
339                                         SuggItem *sel = texttool_suggest_selected();
340                                         while(sel && sel!=texttool_suggest_first() && sel->prev && scroll--) {
341                                                 texttool_suggest_select(sel->prev);
342                                                 sel= sel->prev;
343                                         }
344                                         text_pop_suggest_list();
345                                         swallow= 1;
346                                         draw= 1;
347                                         break;
348                                 }
349                         case RIGHTSHIFTKEY:
350                         case LEFTSHIFTKEY:
351                                 break;
352                         default:
353                                 if(tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw= 1;
354                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
355                 }
356         }
357
358         if (draw) {
359                 // XXX redraw_alltext();
360         }
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 UNUSED_FUNCTION(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         
548         return swallow;
549 }
550