commit before doing some hefty shapekey change, will break compilation
[blender-staging.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_api.h"
43 #include "WM_types.h"
44
45 #include "text_intern.h"
46
47 int text_do_suggest_select(SpaceText *st, ARegion *ar)
48 {
49         SuggItem *item, *first, *last, *sel;
50         TextLine *tmp;
51         int l, x, y, w, h, i;
52         int tgti, *top;
53         short mval[2] = {0, 0};
54         
55         if(!st || !st->text) return 0;
56         if(!texttool_text_is_active(st->text)) return 0;
57
58         first = texttool_suggest_first();
59         last = texttool_suggest_last();
60         sel = texttool_suggest_selected();
61         top = texttool_suggest_top();
62
63         if(!last || !first)
64                 return 0;
65
66         /* Count the visible lines to the cursor */
67         for(tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
68         if(l<0) return 0;
69
70         text_update_character_width(st);
71         
72         if(st->showlinenrs) {
73                 x = st->cwidth*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
74         }
75         else {
76                 x = st->cwidth*(st->text->curc-st->left) + TXT_OFFSET - 4;
77         }
78         y = ar->winy - st->lheight*l - 2;
79
80         w = SUGG_LIST_WIDTH*st->cwidth + 20;
81         h = SUGG_LIST_SIZE*st->lheight + 8;
82
83         // XXX getmouseco_areawin(mval);
84
85         if(mval[0]<x || x+w<mval[0] || mval[1]<y-h || y<mval[1])
86                 return 0;
87
88         /* Work out which of the items is at the top of the visible list */
89         for(i=0, item=first; i<*top && item->next; i++, item=item->next);
90
91         /* Work out the target item index in the visible list */
92         tgti = (y-mval[1]-4) / st->lheight;
93         if(tgti<0 || tgti>SUGG_LIST_SIZE)
94                 return 1;
95
96         for(i=tgti; i>0 && item->next; i--, item=item->next);
97         if(item)
98                 texttool_suggest_select(item);
99         return 1;
100 }
101
102 void text_pop_suggest_list()
103 {
104         SuggItem *item, *sel;
105         int *top, i;
106
107         item= texttool_suggest_first();
108         sel= texttool_suggest_selected();
109         top= texttool_suggest_top();
110
111         i= 0;
112         while(item && item != sel) {
113                 item= item->next;
114                 i++;
115         }
116         if(i > *top+SUGG_LIST_SIZE-1)
117                 *top= i-SUGG_LIST_SIZE+1;
118         else if(i < *top)
119                 *top= i;
120 }
121
122 static void get_suggest_prefix(Text *text, int offset)
123 {
124         int i, len;
125         char *line, tmp[256];
126
127         if(!text) return;
128         if(!texttool_text_is_active(text)) return;
129
130         line= text->curl->line;
131         for(i=text->curc-1+offset; i>=0; i--)
132                 if(!text_check_identifier(line[i]))
133                         break;
134         i++;
135         len= text->curc-i+offset;
136         if(len > 255) {
137                 printf("Suggestion prefix too long\n");
138                 len = 255;
139         }
140         BLI_strncpy(tmp, line+i, len);
141         tmp[len]= '\0';
142         texttool_suggest_prefix(tmp);
143 }
144
145 static void confirm_suggestion(Text *text, int skipleft)
146 {
147         SuggItem *sel;
148         int i, over=0;
149         char *line;
150
151         if(!text) return;
152         if(!texttool_text_is_active(text)) return;
153
154         sel = texttool_suggest_selected();
155         if(!sel) return;
156
157         line= text->curl->line;
158         i=text->curc-skipleft-1;
159         while(i>=0) {
160                 if(!text_check_identifier(line[i]))
161                         break;
162                 over++;
163                 i--;
164         }
165
166         for(i=0; i<skipleft; i++)
167                 txt_move_left(text, 0);
168         for(i=0; i<over; i++)
169                 txt_move_left(text, 1);
170
171         txt_insert_buf(text, sel->name);
172         
173         for(i=0; i<skipleft; i++)
174                 txt_move_right(text, 0);
175
176         texttool_text_clear();
177 }
178
179 // XXX
180 #define L_MOUSE 0
181 #define M_MOUSE 0
182 #define R_MOUSE 0
183 #define LR_SHIFTKEY 0
184 #define LR_ALTKEY 0
185 #define LR_CTRLKEY 0
186 #define LR_COMMANDKEY 0
187
188 // XXX
189 static int doc_scroll= 0;
190
191 short do_texttools(SpaceText *st, char ascii, unsigned short evnt, short val)
192 {
193         ARegion *ar= NULL; // XXX
194         int qual= 0; // XXX
195         int draw=0, tools=0, swallow=0, scroll=1;
196         if(!texttool_text_is_active(st->text)) return 0;
197         if(!st->text || st->text->id.lib) return 0;
198
199         if(st->doplugins && texttool_text_is_active(st->text)) {
200                 if(texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
201                 if(texttool_docs_get()) tools |= TOOL_DOCUMENT;
202         }
203
204         if(ascii) {
205                 if(tools & TOOL_SUGG_LIST) {
206                         if((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) {
207                                 confirm_suggestion(st->text, 0);
208                                 text_update_line_edited(st->text, st->text->curl);
209                         }
210                         else if((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) {
211                                 get_suggest_prefix(st->text, 0);
212                                 text_pop_suggest_list();
213                                 swallow= 1;
214                                 draw= 1;
215                         }
216                 }
217                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
218
219         }
220         else if(val==1 && evnt) {
221                 switch (evnt) {
222                         case LEFTMOUSE:
223                                 if(text_do_suggest_select(st, ar))
224                                         swallow= 1;
225                                 else {
226                                         if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
227                                         if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
228                                 }
229                                 draw= 1;
230                                 break;
231                         case MIDDLEMOUSE:
232                                 if(text_do_suggest_select(st, ar)) {
233                                         confirm_suggestion(st->text, 0);
234                                         text_update_line_edited(st->text, st->text->curl);
235                                         swallow= 1;
236                                 }
237                                 else {
238                                         if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
239                                         if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
240                                 }
241                                 draw= 1;
242                                 break;
243                         case ESCKEY:
244                                 draw= swallow= 1;
245                                 if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
246                                 else if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
247                                 else draw= swallow= 0;
248                                 break;
249                         case RETKEY:
250                                 if(tools & TOOL_SUGG_LIST) {
251                                         confirm_suggestion(st->text, 0);
252                                         text_update_line_edited(st->text, st->text->curl);
253                                         swallow= 1;
254                                         draw= 1;
255                                 }
256                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
257                                 break;
258                         case LEFTARROWKEY:
259                         case BACKSPACEKEY:
260                                 if(tools & TOOL_SUGG_LIST) {
261                                         if(qual)
262                                                 texttool_suggest_clear();
263                                         else {
264                                                 /* Work out which char we are about to delete/pass */
265                                                 if(st->text->curl && st->text->curc > 0) {
266                                                         char ch= st->text->curl->line[st->text->curc-1];
267                                                         if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
268                                                                 get_suggest_prefix(st->text, -1);
269                                                                 text_pop_suggest_list();
270                                                         }
271                                                         else
272                                                                 texttool_suggest_clear();
273                                                 }
274                                                 else
275                                                         texttool_suggest_clear();
276                                         }
277                                 }
278                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
279                                 break;
280                         case RIGHTARROWKEY:
281                                 if(tools & TOOL_SUGG_LIST) {
282                                         if(qual)
283                                                 texttool_suggest_clear();
284                                         else {
285                                                 /* Work out which char we are about to pass */
286                                                 if(st->text->curl && st->text->curc < st->text->curl->len) {
287                                                         char ch= st->text->curl->line[st->text->curc+1];
288                                                         if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
289                                                                 get_suggest_prefix(st->text, 1);
290                                                                 text_pop_suggest_list();
291                                                         }
292                                                         else
293                                                                 texttool_suggest_clear();
294                                                 }
295                                                 else
296                                                         texttool_suggest_clear();
297                                         }
298                                 }
299                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
300                                 break;
301                         case PAGEDOWNKEY:
302                                 scroll= SUGG_LIST_SIZE-1;
303                         case WHEELDOWNMOUSE:
304                         case DOWNARROWKEY:
305                                 if(tools & TOOL_DOCUMENT) {
306                                         doc_scroll++;
307                                         swallow= 1;
308                                         draw= 1;
309                                         break;
310                                 }
311                                 else if(tools & TOOL_SUGG_LIST) {
312                                         SuggItem *sel = texttool_suggest_selected();
313                                         if(!sel) {
314                                                 texttool_suggest_select(texttool_suggest_first());
315                                         }
316                                         else while(sel && sel!=texttool_suggest_last() && sel->next && scroll--) {
317                                                 texttool_suggest_select(sel->next);
318                                                 sel= sel->next;
319                                         }
320                                         text_pop_suggest_list();
321                                         swallow= 1;
322                                         draw= 1;
323                                         break;
324                                 }
325                         case PAGEUPKEY:
326                                 scroll= SUGG_LIST_SIZE-1;
327                         case WHEELUPMOUSE:
328                         case UPARROWKEY:
329                                 if(tools & TOOL_DOCUMENT) {
330                                         if(doc_scroll>0) doc_scroll--;
331                                         swallow= 1;
332                                         draw= 1;
333                                         break;
334                                 }
335                                 else if(tools & TOOL_SUGG_LIST) {
336                                         SuggItem *sel = texttool_suggest_selected();
337                                         while(sel && sel!=texttool_suggest_first() && sel->prev && scroll--) {
338                                                 texttool_suggest_select(sel->prev);
339                                                 sel= sel->prev;
340                                         }
341                                         text_pop_suggest_list();
342                                         swallow= 1;
343                                         draw= 1;
344                                         break;
345                                 }
346                         case RIGHTSHIFTKEY:
347                         case LEFTSHIFTKEY:
348                                 break;
349                         default:
350                                 if(tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw= 1;
351                                 if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
352                 }
353         }
354
355         if(draw)
356                 {}; // XXX redraw_alltext();
357         
358         return swallow;
359 }
360
361 #if 0
362 #ifndef DISABLE_PYTHON  
363         /* Run text plugin scripts if enabled */
364         if(st->doplugins && event && val) {
365                 if(BPY_menu_do_shortcut(PYMENU_TEXTPLUGIN, event, qual)) {
366                         do_draw= 1;
367                 }
368         }
369 #endif
370         if(do_draw)
371                 ; // XXX redraw_alltext();
372 #endif
373
374 short do_textmarkers(SpaceText *st, char ascii, unsigned short evnt, short val)
375 {
376         Text *text;
377         TextMarker *marker, *mrk, *nxt;
378         int c, s, draw=0, swallow=0;
379         int qual= 0; // XXX
380
381         text= st->text;
382         if(!text || text->id.lib || text->curl != text->sell) return 0;
383
384         marker= txt_find_marker(text, text->sell, text->selc, 0, 0);
385         if(marker && (marker->start > text->curc || marker->end < text->curc))
386                 marker= NULL;
387
388         if(!marker) {
389                 /* Find the next temporary marker */
390                 if(evnt==TABKEY) {
391                         int lineno= txt_get_span(text->lines.first, text->curl);
392                         TextMarker *mrk= text->markers.first;
393                         while(mrk) {
394                                 if(!marker && (mrk->flags & TMARK_TEMP)) marker= mrk;
395                                 if((mrk->flags & TMARK_TEMP) && (mrk->lineno > lineno || (mrk->lineno==lineno && mrk->end > text->curc))) {
396                                         marker= mrk;
397                                         break;
398                                 }
399                                 mrk= mrk->next;
400                         }
401                         if(marker) {
402                                 txt_move_to(text, marker->lineno, marker->start, 0);
403                                 txt_move_to(text, marker->lineno, marker->end, 1);
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, st->text->curl);
434                                 }
435                                 else {
436                                         if(txt_add_char(text, ascii)) {
437                                                 text_update_line_edited(st->text, 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, 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, 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 WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
508                                 }
509                                 swallow= 1;
510                                 draw= 1;
511                                 break;
512
513                         /* Events that should clear markers */
514                         case UKEY: if(!(qual & LR_ALTKEY)) break;
515                         case ZKEY: if(evnt==ZKEY && !(qual & LR_CTRLKEY)) break;
516                         case RETKEY:
517                         case ESCKEY:
518                                 if(marker->flags & (TMARK_EDITALL | TMARK_TEMP))
519                                         txt_clear_markers(text, marker->group, 0);
520                                 else
521                                         BLI_freelinkN(&text->markers, marker);
522                                 swallow= 1;
523                                 draw= 1;
524                                 break;
525                         case RIGHTMOUSE: /* Marker context menu? */
526                         case LEFTMOUSE:
527                                 break;
528                         case FKEY: /* Allow find */
529                                 if(qual & LR_SHIFTKEY) swallow= 1;
530                                 break;
531
532                         default:
533                                 if(qual!=0 && qual!=LR_SHIFTKEY)
534                                         swallow= 1; /* Swallow all other shortcut events */
535                 }
536         }
537         
538         if(draw)
539                 {}; // XXX redraw_alltext();
540         
541         return swallow;
542 }
543