Refactor: Renamed text tool methods (suggestions and docs) for clarity and consistency.
[blender-staging.git] / source / blender / src / drawtext.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) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <math.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef _WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #include "BLI_winstuff.h"
46 #endif   
47 #include "MEM_guardedalloc.h"
48 #include "PIL_time.h"
49
50 #include "BMF_Api.h"
51
52 #include "BLI_blenlib.h"
53 #include "BLI_arithb.h"
54
55 #include "DNA_text_types.h"
56 #include "DNA_space_types.h"
57 #include "DNA_screen_types.h"
58 #include "DNA_userdef_types.h"
59
60 #include "BKE_utildefines.h"
61 #include "BKE_text.h"
62 #include "BKE_global.h"
63 #include "BKE_main.h"
64 #include "BKE_node.h"
65 #include "BKE_suggestions.h"
66
67 #include "BIF_gl.h"
68 #include "BIF_glutil.h"
69 #include "BIF_keyval.h"
70 #include "BIF_interface.h"
71 #include "BIF_drawtext.h"
72 #include "BIF_editfont.h"
73 #include "BIF_spacetypes.h"
74 #include "BIF_usiblender.h"
75 #include "BIF_screen.h"
76 #include "BIF_toolbox.h"
77 #include "BIF_space.h"
78 #include "BIF_mywindow.h"
79 #include "BIF_resources.h"
80
81 #include "BSE_filesel.h"
82
83 #include "BPY_extern.h"
84 #include "BPY_menus.h"
85
86 #include "mydevice.h"
87 #include "blendef.h" 
88 #include "winlay.h"
89
90 #define TEXTXLOC                38
91
92 #define SUGG_LIST_SIZE  7
93 #define SUGG_LIST_WIDTH 20
94 #define DOC_WIDTH               40
95
96 #define TOOL_SUGG_LIST  0x01
97 #define TOOL_DOCUMENT   0x02
98
99 /* forward declarations */
100
101 void drawtextspace(ScrArea *sa, void *spacedata);
102 void winqreadtextspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
103 void txt_copy_selectbuffer (Text *text);
104 void do_brackets();
105
106 void get_selection_buffer(Text *text);
107 int check_bracket(char *string);
108 static int check_delim(char *string);
109 static int check_numbers(char *string);
110 static int check_builtinfuncs(char *string);
111 static int check_specialvars(char *string);
112 static int check_identifier(char ch);
113 static int check_whitespace(char ch);
114
115 static void get_suggest_prefix(Text *text);
116 static void confirm_suggestion(Text *text, int skipleft);
117
118 static int last_txt_find_flags= 0;
119 static void *last_txt_find_string= NULL;
120 static void *last_txt_repl_string= NULL;
121
122 static double last_check_time= 0;
123
124 static BMF_Font *spacetext_get_font(SpaceText *st) {
125         static BMF_Font *scr12= NULL;
126         static BMF_Font *scr15= NULL;
127         
128         switch (st->font_id) {
129         default:
130         case 0:
131                 if (!scr12)
132                         scr12= BMF_GetFont(BMF_kScreen12);
133                 return scr12;
134         case 1:
135                 if (!scr15)
136                         scr15= BMF_GetFont(BMF_kScreen15);
137                 return scr15;
138         }
139 }
140
141 static int spacetext_get_fontwidth(SpaceText *st) {
142         return BMF_GetCharacterWidth(spacetext_get_font(st), ' ');
143 }
144
145 static char *temp_char_buf= NULL;
146 static int *temp_char_accum= NULL;
147 static int temp_char_len= 0;
148 static int temp_char_pos= 0;
149
150 static void temp_char_write(char c, int accum) {
151         if (temp_char_len==0 || temp_char_pos>=temp_char_len) {
152                 char *nbuf; int *naccum;
153                 int olen= temp_char_len;
154                 
155                 if (olen) temp_char_len*= 2;
156                 else temp_char_len= 256;
157                 
158                 nbuf= MEM_mallocN(sizeof(*temp_char_buf)*temp_char_len, "temp_char_buf");
159                 naccum= MEM_mallocN(sizeof(*temp_char_accum)*temp_char_len, "temp_char_accum");
160                 
161                 if (olen) {
162                         memcpy(nbuf, temp_char_buf, olen);
163                         memcpy(naccum, temp_char_accum, olen);
164                         
165                         MEM_freeN(temp_char_buf);
166                         MEM_freeN(temp_char_accum);
167                 }
168                 
169                 temp_char_buf= nbuf;
170                 temp_char_accum= naccum;
171         }
172         
173         temp_char_buf[temp_char_pos]= c;        
174         temp_char_accum[temp_char_pos]= accum;
175         
176         if (c==0) temp_char_pos= 0;
177         else temp_char_pos++;
178 }
179
180 void free_txt_data(void) {
181         txt_free_cut_buffer();
182         
183         if (last_txt_find_string) MEM_freeN(last_txt_find_string);
184         if (last_txt_repl_string) MEM_freeN(last_txt_repl_string);
185         if (temp_char_buf) MEM_freeN(temp_char_buf);
186         if (temp_char_accum) MEM_freeN(temp_char_accum);        
187 }
188
189 static int render_string (SpaceText *st, char *in) {
190         int r = 0, i = 0;
191         
192         while(*in) {
193                 if (*in=='\t') {
194                         if (temp_char_pos && *(in-1)=='\t') i= st->tabnumber;
195                         else if (st->tabnumber > 0) i= st->tabnumber - (temp_char_pos%st->tabnumber);
196                         while(i--) temp_char_write(' ', r);
197                 } else temp_char_write(*in, r);
198
199                 r++;
200                 in++;
201         }
202         r= temp_char_pos;
203         temp_char_write(0, 0);
204                 
205         return r;
206 }
207
208 void get_format_string(SpaceText *st) 
209 {
210         Text *text = st->text;
211         TextLine *tmp;
212         char *in_line;
213         char format[2000], check[200], other[2];
214         unsigned char c;
215         int spot, letter, tabs, mem_amount;
216         size_t a, b, len;
217         
218         if(!text) return;
219         tmp = text->lines.first;
220         
221         while(tmp) {
222                 in_line = tmp->line;
223                 
224                 len = strlen(in_line);
225                 /* weak code... but we dont want crashes (ton) */
226                 if(len>2000-1) {
227                         if (tmp->format) MEM_freeN(tmp->format);
228                         tmp->format= NULL;
229                 }
230                 else {
231                         
232                         spot = 0;
233                         tabs = 0;
234                         //see how many tabs we have
235                         for(a = 0; a <len; a++) {
236                                 c = (unsigned char) in_line[a];
237                                 if(c == '\t') {
238                                         tabs++;
239                                 }
240                         }
241                         //calculate the amount of MEM_mallocN we neen
242                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len; // +2 for good measure
243                         if (tmp->format) MEM_freeN(tmp->format);
244                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
245                         
246                         for (a = 0; a < len; a++) {
247                                 c = (unsigned char) in_line[a];
248
249                                 check[0] = c;
250                                 check[1] = '\0';
251
252                                 if (check_delim(check))
253                                 {
254                                         switch (c) {
255                                                 case '\"':
256                                                         if(in_line[a] == '\"' && in_line[a+1] == '\"' && in_line[a+2] == '\"') { 
257                                                                 format[spot] = format[spot+1] = format[spot+2] = 'l';
258                                                                 spot +=3;
259                                                                 a += 3;
260                                                                 while(in_line[a] != '\"' || in_line[a-1] != '\"' || in_line[a-2] != '\"') {
261                                                                         c = (unsigned char) in_line[a];
262                                                                         if(a >= len) {
263                                                                                 format[spot] = '\0';
264                                                                                 memcpy(tmp->format, format, strlen(format));
265                                                                                 if(!(tmp= tmp->next)) {
266                                                                                         return;
267                                                                                 } else {
268                                                                                         in_line = tmp->line;
269                                                                                         len = strlen(in_line);
270                                                                                         tabs = 0;
271                                                                                         for(b = 0; b <len; b++) {
272                                                                                                 c = (unsigned char) in_line[b];
273                                                                                                 if(c == '\t') {
274                                                                                                         tabs++;
275                                                                                                 }
276                                                                                         }
277                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
278                                                                                         if (tmp->format) MEM_freeN(tmp->format);
279                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
280                                                                                         a = 0; spot = 0;
281                                                                                 }
282                                                                         } else {
283                                                                                 if(c == '\t' || c == ' ') {
284                                                                                         if(c == '\t') {
285                                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
286                                                                                                         format[spot] = ' ';
287                                                                                                         spot++;
288                                                                                                 }
289                                                                                                 a++;
290                                                                                         } else {
291                                                                                                 format[spot] = ' ';
292                                                                                                 a++; spot++;
293                                                                                 }
294                                                                                 } else {
295                                                                                         format[spot] = 'l';
296                                                                                         a++; spot++;
297                                                                                 }
298                                                                         }
299                                                                 }
300                                                                 format[spot] = 'l';
301                                                                 spot++;
302                                                         } else {
303                                                                 format[spot] = 'l';
304                                                                 a++; spot++;
305                                                                 while(in_line[a] != '\"') {
306                                                                         c = (unsigned char) in_line[a];
307                                                                         if(a >= len) {
308                                                                                 format[spot] = '\0';
309                                                                                 memcpy(tmp->format, format, strlen(format));
310                                                                                 if(!(tmp= tmp->next)) {
311                                                                                         return;
312                                                                                 } else {
313                                                                                         in_line = tmp->line;
314                                                                                         len = strlen(in_line);
315                                                                                         for(b = 0; b <len; b++) {
316                                                                                                 c = (unsigned char) in_line[b];
317                                                                                                 if(c == '\t') {
318                                                                                                         tabs++;
319                                                                                                 }
320                                                                                         }
321                                                                                         //calculate the amount of MEM_mallocN we neen
322                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
323                                                                                         if (tmp->format) MEM_freeN(tmp->format);
324                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
325                                                                                         a = 0; spot = 0;
326                                                                                 }
327                                                                         }
328                                                                         if(c == '\t' || c == ' ') {
329                                                                                 if(c == '\t') {
330                                                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
331                                                                                                 format[spot] = ' ';
332                                                                                                 spot++;
333                                                                                         }
334                                                                                         a++;
335                                                                                 } else {
336                                                                                         format[spot] = ' ';
337                                                                                         a++; spot++;
338                                                                                 }
339                                                                         } else {
340                                                                                 format[spot] = 'l';
341                                                                                 a++; spot++;
342                                                                         }
343                                                                 }
344                                                                 format[spot] = 'l';
345                                                                 spot++;
346                                                         }
347                                                         break;
348                                                 case '\'':
349                                                         if(in_line[a] == '\'' && in_line[a+1] == '\'' && in_line[a+2] == '\'') { 
350                                                                 format[spot] = format[spot+1] = format[spot+2] = 'l';
351                                                                 spot +=3;
352                                                                 a += 3;
353                                                                 while(in_line[a] != '\'' || in_line[a-1] != '\'' || in_line[a-2] != '\'') {
354                                                                         c = (unsigned char) in_line[a];
355                                                                         if(a >= len) {
356                                                                                 format[spot] = '\0';
357                                                                                 memcpy(tmp->format, format, strlen(format));
358                                                                                 if(!(tmp= tmp->next)) {
359                                                                                         return;
360                                                                                 } else {
361                                                                                         in_line = tmp->line;
362                                                                                         len = strlen(in_line);
363                                                                                         tabs = 0;
364                                                                                         for(b = 0; b <len; b++) {
365                                                                                                 c = (unsigned char) in_line[b];
366                                                                                                 if(c == '\t') {
367                                                                                                         tabs++;
368                                                                                                 }
369                                                                                         }
370                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
371                                                                                         if (tmp->format) MEM_freeN(tmp->format);
372                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
373                                                                                         a = 0; spot = 0;
374                                                                                 }
375                                                                         } else {
376                                                                                 if(c == '\t' || c == ' ') {
377                                                                                         if(c == '\t') {
378                                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
379                                                                                                         format[spot] = ' ';
380                                                                                                         spot++;
381                                                                                                 }
382                                                                                                 a++;
383                                                                                         } else {
384                                                                                                 format[spot] = ' ';
385                                                                                                 a++; spot++;
386                                                                                         }
387                                                                                 } else {
388                                                                                         format[spot] = 'l';
389                                                                                         a++; spot++;
390                                                                                 }
391                                                                         }
392                                                                 }
393                                                                 format[spot] = 'l';
394                                                                 spot++;
395                                                         } else {
396                                                                 format[spot] = 'l';
397                                                                 a++; spot++;
398                                                                 while(in_line[a] != '\'') {
399                                                                         c = (unsigned char) in_line[a];
400                                                                         if(a >= len) {
401                                                                                 format[spot] = '\0';
402                                                                                 memcpy(tmp->format, format, strlen(format));
403                                                                                 if(!(tmp= tmp->next)) {
404                                                                                         return;
405                                                                                 } else {
406                                                                                         in_line = tmp->line;
407                                                                                         len = strlen(in_line);
408                                                                                         for(b = 0; b <len; b++) {
409                                                                                                 c = (unsigned char) in_line[b];
410                                                                                                 if(c == '\t') {
411                                                                                                         tabs++;
412                                                                                                 }
413                                                                                         }
414                                                                                         //calculate the amount of MEM_mallocN we neen
415                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
416                                                                                         if (tmp->format) MEM_freeN(tmp->format);
417                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
418                                                                                         a = 0; spot = 0;
419                                                                                 }
420                                                                         }
421                                                                         if(c == '\t' || c == ' ') {
422                                                                                 if(c == '\t') {
423                                                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
424                                                                                                 format[spot] = ' ';
425                                                                                                 spot++;
426                                                                                         }
427                                                                                         a++;
428                                                                                 } else {
429                                                                                         format[spot] = ' ';
430                                                                                         a++; spot++;
431                                                                                 }
432                                                                         } else {
433                                                                                 format[spot] = 'l';
434                                                                                 a++; spot++;
435                                                                         }
436                                                                 }
437                                                                 format[spot] = 'l';
438                                                                 spot++;
439                                                         }
440                                                         break;
441                                                 case '#':
442                                                         while(a<len) {
443                                                                 c = (unsigned char) in_line[a];
444                                                                 if(c == '\t' || c == ' ') {
445                                                                         if(c == '\t') {
446                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
447                                                                                         format[spot] = '#';
448                                                                                         spot++;
449                                                                                 }
450                                                                                 a++;
451                                                                         } else {
452                                                                                 format[spot] = '#';
453                                                                                 a++; spot++;
454                                                                         }
455                                                                 } else {
456                                                                         format[spot] = '#';
457                                                                         a++; spot++;
458                                                                 }
459                                                         }
460                                                         break;
461                                                 case ' ':
462                                                         format[spot] = ' ';
463                                                         spot++;
464                                                         break;
465                                                 case '\t':
466                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
467                                                                 format[spot] = ' ';
468                                                                 spot++;
469                                                         }
470                                                         break;
471                                                 default:
472                                                         format[spot] = 'q';
473                                                         spot++;
474                                                          
475                                                         break;
476                                         }
477                                 } else if (check_numbers(check)) {
478                                         while (a < len) {
479                                                 c = (unsigned char) in_line[a];
480                                                 other[0] = c;
481                                                 other[1] = '\0';
482                                                 if (check_delim(other) && c != '.') {
483                                                         a--; break;
484                                                 } else {
485                                                         format[spot] = 'n';
486                                                         a++; spot++;
487                                                 }
488                                         }
489                                 } else {
490                                         letter = 0;
491                                         while (a < len) {
492                                                 c = (unsigned char) in_line[a];
493                                                 other[0] = c;
494                                                 other[1] = '\0';
495                                                 if (check_delim(other)) {
496                                                         a--; 
497                                                         break;
498                                                 } else {
499                                                         check[letter] = (unsigned char) in_line[a];
500                                                         letter++; 
501                                                         a++;
502                                                 }
503                                         }
504                                         check[letter] = '\0';
505                                         if (check_builtinfuncs(check)) {
506                                                 for (b = 0; b < strlen(check); b++) {
507                                                         format[spot] = 'b'; 
508                                                         spot++;
509                                                 }
510                                         } else if (check_specialvars(check)) { /*If TRUE then color and color next word*/
511                                                 for (b = 0; b < strlen(check); b++) {
512                                                         format[spot] = 'b';
513                                                         spot++;
514                                                 }
515                                                 a++;
516                                                 format[spot] = 'q';
517                                                 spot++; a++;
518                                                 letter = 0;
519                                                 while (a < len) {
520                                                         c = (unsigned char) in_line[a];
521                                                         other[0] = c;
522                                                         other[1] = '\0';
523                                                         if (check_delim(other)) {
524                                                                 a--; 
525                                                                 break;
526                                                         } else {
527                                                                 check[letter] = (unsigned char) in_line[a];
528                                                                 letter++; 
529                                                                 a++;
530                                                         }
531                                                 }
532                                                 check[letter] = '\0';
533                                                 for (b = 0; b < strlen(check); b++) {
534                                                         format[spot] = 'v';
535                                                         spot++;
536                                                 }
537                                         }else {
538                                                 for (b = 0; b < strlen(check); b++) {
539                                                         format[spot] = 'q';
540                                                         spot++;
541                                                 }
542                                         }
543                                 }
544                         }
545                         format[spot] = '\0';
546                         memcpy(tmp->format, format, strlen(format));
547                 }
548                 
549                 tmp = tmp->next;
550         }
551 }
552
553 static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, char *format) {
554         int r=0, w= 0;
555         char *in;
556         int *acc;
557
558         w= render_string(st, str);
559         if(w<cshift ) return 0; /* String is shorter than shift */
560         
561         in= temp_char_buf+cshift;
562         acc= temp_char_accum+cshift;
563         w= w-cshift;
564
565         if (draw) {
566                 if(st->showsyntax && format) {
567                         int amount, a;
568                         char out[2];
569                         format = format+cshift;
570                 
571                         amount = strlen(in);
572                         
573                         for(a = 0; a < amount; a++) {
574                                 out[0] = (unsigned char) in[a]; 
575                                 out[1] = '\0';
576                                 switch (format[a]) {
577                                         case 'l':
578                                                 BIF_ThemeColor(TH_SYNTAX_L);
579                                                 break;
580                                         case 'b':
581                                                 BIF_ThemeColor(TH_SYNTAX_B);
582                                                 break;
583                                         case '#':
584                                                 BIF_ThemeColor(TH_SYNTAX_C);
585                                                 break;
586                                         case 'v': 
587                                                 BIF_ThemeColor(TH_SYNTAX_V);
588                                                 break;
589                                         case 'n':
590                                                 BIF_ThemeColor(TH_SYNTAX_N);
591                                                 break;
592                                         case 'q':
593                                                 BIF_ThemeColor(TH_TEXT);
594                                                 break;
595                                         default:
596                                                 BIF_ThemeColor(TH_TEXT);
597                                                 break;
598                                 }
599                                 glRasterPos2i(x, y);
600                                 BMF_DrawString(spacetext_get_font(st), out);
601                                 x = x+BMF_GetStringWidth(spacetext_get_font(st), out);
602                         }
603                 } else {
604                         glRasterPos2i(x, y);
605                         BMF_DrawString(spacetext_get_font(st), in);
606                 }
607         } else {
608                 while (w-- && *acc++ < maxwidth) {
609                         r+= spacetext_get_fontwidth(st);
610                 }
611         }
612
613         if (cshift && r==0) return 0;
614         else if (st->showlinenrs)
615                 return r+TXT_OFFSET+TEXTXLOC;
616         else
617                 return r+TXT_OFFSET;
618 }
619
620 static void set_cursor_to_pos (SpaceText *st, int x, int y, int sel) 
621 {
622         Text *text;
623         TextLine **linep;
624         int *charp;
625         int w;
626         
627         text= st->text;
628
629         if(sel) { linep= &text->sell; charp= &text->selc; } 
630         else { linep= &text->curl; charp= &text->curc; }
631         
632         y= (curarea->winy - y)/st->lheight;
633         
634         y-= txt_get_span(text->lines.first, *linep) - st->top;
635         
636         if (y>0) {
637                 while (y-- != 0) if((*linep)->next) *linep= (*linep)->next;
638         } else if (y<0) {
639                 while (y++ != 0) if((*linep)->prev) *linep= (*linep)->prev;
640         }
641
642         if(st->showlinenrs)
643                 x-= TXT_OFFSET+TEXTXLOC;
644         else
645                 x-= TXT_OFFSET;
646
647         if (x<0) x= 0;
648         x = (x/spacetext_get_fontwidth(st)) + st->left;
649         
650         w= render_string(st, (*linep)->line);
651         if(x<w) *charp= temp_char_accum[x];
652         else *charp= (*linep)->len;
653         
654         if(!sel) txt_pop_sel(text);
655 }
656
657 static void draw_cursor(SpaceText *st) {
658         int h, x, i, w;
659         Text *text= st->text;
660         TextLine *linef, *linel;
661         int charf, charl;
662         char ch[2];
663         
664         if (text->curl==text->sell && text->curc==text->selc) {
665                 x= text_draw(st, text->curl->line, st->left, text->curc, 0, 0, 0, NULL);
666
667                 if (x) {
668                         h= txt_get_span(text->lines.first, text->curl) - st->top;
669
670                         if (st->overwrite) {
671                                 ch[0]= (unsigned char) text->curl->line[text->curc];
672                                 if (ch[0]=='\0') ch[0]=' ';
673                                 ch[1]= '\0';
674                                 w= BMF_GetStringWidth(spacetext_get_font(st), ch);
675                                 BIF_ThemeColor(TH_SHADE2);
676                                 glRecti(x, curarea->winy-st->lheight*(h)-2, x+w, curarea->winy-st->lheight*(h+1)-2);
677                                 BIF_ThemeColor(TH_HILITE);
678                                 glRecti(x, curarea->winy-st->lheight*(h+1)-3, x+w, curarea->winy-st->lheight*(h+1)-1);
679                         } else {
680                                 BIF_ThemeColor(TH_HILITE);
681                                 glRecti(x-1, curarea->winy-st->lheight*(h)-2, x+1, curarea->winy-st->lheight*(h+1)-2);
682                         }
683                 }
684         } else {
685                 int span= txt_get_span(text->curl, text->sell);
686                 
687                 if (span<0) {
688                         linef= text->sell;
689                         charf= text->selc;
690                         
691                         linel= text->curl;
692                         charl= text->curc;
693                 } else if (span>0) {
694                         linef= text->curl;
695                         charf= text->curc;
696         
697                         linel= text->sell;              
698                         charl= text->selc;
699                 } else {
700                         linef= linel= text->curl;
701                         
702                         if (text->curc<text->selc) {
703                                 charf= text->curc;
704                                 charl= text->selc;
705                         } else {
706                                 charf= text->selc;
707                                 charl= text->curc;
708                         }
709                 }
710         
711                         /* Walk to the beginning of visible text */
712                 h= txt_get_span(text->lines.first, linef) - st->top;
713                 while (h++<-1 && linef!=linel) linef= linef->next;
714         
715                 x= text_draw(st, linef->line, st->left, charf, 0, 0, 0, NULL);
716
717                 BIF_ThemeColor(TH_SHADE2);
718
719                 if(st->showlinenrs) {
720                         if (!x) x= TXT_OFFSET + TEXTXLOC -4;
721                 } else {
722                         if (!x) x= TXT_OFFSET - 4;
723                 }
724                 
725                 while (linef && linef != linel) {
726                         h= txt_get_span(text->lines.first, linef) - st->top;
727                         if (h>st->viewlines) break;
728                         
729                         glRecti(x, curarea->winy-st->lheight*(h)-2, curarea->winx, curarea->winy-st->lheight*(h+1)-2);
730                         if(st->showlinenrs)
731                                 glRecti(TXT_OFFSET+TEXTXLOC-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET+TEXTXLOC, curarea->winy-st->lheight*(h+2)-2);
732                         else
733                                 glRecti(TXT_OFFSET-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET, curarea->winy-st->lheight*(h+2)-2);
734
735                         if(st->showlinenrs)
736                                 x= TXT_OFFSET + TEXTXLOC;
737                         else
738                                 x= TXT_OFFSET;
739                         
740                         linef= linef->next;
741                 }
742                 
743                 h= txt_get_span(text->lines.first, linef) - st->top;
744
745                 i= text_draw(st, linel->line, st->left, charl, 0, 0, 0, NULL);
746                 if(i) glRecti(x, curarea->winy-st->lheight*(h)-2, i, curarea->winy-st->lheight*(h+1)-2);
747
748         }
749
750         do_brackets();
751         BIF_ThemeColor(TH_TEXT);
752 }
753
754 static void calc_text_rcts(SpaceText *st)
755 {
756         int lhlstart, lhlend, ltexth;
757         short barheight, barstart, hlstart, hlend, blank_lines;
758         short pix_available, pix_top_margin, pix_bottom_margin, pix_bardiff;
759
760         pix_top_margin = 8;
761         pix_bottom_margin = 4;
762         pix_available = curarea->winy - pix_top_margin - pix_bottom_margin;
763         ltexth= txt_get_span(st->text->lines.first, st->text->lines.last);
764         blank_lines = st->viewlines / 2;
765         
766         /* when resizing a vieport with the bar at the bottom to a greater height more blank lines will be added */
767         if (ltexth + blank_lines < st->top + st->viewlines) {
768                 blank_lines = st->top + st->viewlines - ltexth;
769         }
770         
771         ltexth += blank_lines;
772
773         barheight = (ltexth > 0)? (st->viewlines*pix_available)/ltexth: 0;
774         pix_bardiff = 0;
775         if (barheight < 20) {
776                 pix_bardiff = 20 - barheight; /* take into account the now non-linear sizing of the bar */      
777                 barheight = 20;
778         }
779         barstart = (ltexth > 0)? ((pix_available - pix_bardiff) * st->top)/ltexth: 0;
780
781         st->txtbar.xmin = 5;
782         st->txtbar.xmax = 17;
783         st->txtbar.ymax = curarea->winy - pix_top_margin - barstart;
784         st->txtbar.ymin = st->txtbar.ymax - barheight;
785
786         CLAMP(st->txtbar.ymin, pix_bottom_margin, curarea->winy - pix_top_margin);
787         CLAMP(st->txtbar.ymax, pix_bottom_margin, curarea->winy - pix_top_margin);
788
789         st->pix_per_line= (pix_available > 0)? (float) ltexth/pix_available: 0;
790         if (st->pix_per_line<.1) st->pix_per_line=.1f;
791
792         lhlstart = MIN2(txt_get_span(st->text->lines.first, st->text->curl), 
793                                 txt_get_span(st->text->lines.first, st->text->sell));
794         lhlend = MAX2(txt_get_span(st->text->lines.first, st->text->curl), 
795                                 txt_get_span(st->text->lines.first, st->text->sell));
796
797         if(ltexth > 0) {
798                 hlstart = (lhlstart * pix_available)/ltexth;
799                 hlend = (lhlend * pix_available)/ltexth;
800
801                 /* the scrollbar is non-linear sized */
802                 if (pix_bardiff > 0) {
803                         /* the start of the highlight is in the current viewport */
804                         if (ltexth && st->viewlines && lhlstart >= st->top && lhlstart <= st->top + st->viewlines) { 
805                                 /* speed the progresion of the start of the highlight through the scrollbar */
806                                 hlstart = ( ( (pix_available - pix_bardiff) * lhlstart) / ltexth) + (pix_bardiff * (lhlstart - st->top) / st->viewlines);       
807                         }
808                         else if (lhlstart > st->top + st->viewlines && hlstart < barstart + barheight && hlstart > barstart) {
809                                 /* push hl start down */
810                                 hlstart = barstart + barheight;
811                         }
812                         else if (lhlend > st->top  && lhlstart < st->top && hlstart > barstart) {
813                                 /*fill out start */
814                                 hlstart = barstart;
815                         }
816
817                         if (hlend <= hlstart) { 
818                                 hlend = hlstart + 2;
819                         }
820
821                         /* the end of the highlight is in the current viewport */
822                         if (ltexth && st->viewlines && lhlend >= st->top && lhlend <= st->top + st->viewlines) { 
823                                 /* speed the progresion of the end of the highlight through the scrollbar */
824                                 hlend = (((pix_available - pix_bardiff )*lhlend)/ltexth) + (pix_bardiff * (lhlend - st->top)/st->viewlines);    
825                         }
826                         else if (lhlend < st->top && hlend >= barstart - 2 && hlend < barstart + barheight) {
827                                 /* push hl end up */
828                                 hlend = barstart;
829                         }                                       
830                         else if (lhlend > st->top + st->viewlines && lhlstart < st->top + st->viewlines && hlend < barstart + barheight) {
831                                 /* fill out end */
832                                 hlend = barstart + barheight;
833                         }
834
835                         if (hlend <= hlstart) { 
836                                 hlstart = hlend - 2;
837                         }       
838                 }       
839         }
840         else {
841                 hlstart = 0;
842                 hlend = 0;
843         }
844
845         if (hlend - hlstart < 2) { 
846                 hlend = hlstart + 2;
847         }
848         
849         st->txtscroll.xmin= 5;
850         st->txtscroll.xmax= 17;
851         st->txtscroll.ymax= curarea->winy - pix_top_margin - hlstart;
852         st->txtscroll.ymin= curarea->winy - pix_top_margin - hlend;
853
854         CLAMP(st->txtscroll.ymin, pix_bottom_margin, curarea->winy - pix_top_margin);
855         CLAMP(st->txtscroll.ymax, pix_bottom_margin, curarea->winy - pix_top_margin);
856 }
857
858 static void draw_textscroll(SpaceText *st)
859 {
860         if (!st->text) return;
861
862         calc_text_rcts(st);
863         
864         BIF_ThemeColorShade(TH_SHADE1, -20);
865         glRecti(2, 2, 20, curarea->winy-6);
866         uiEmboss(2, 2, 20, curarea->winy-6, 1);
867
868         BIF_ThemeColor(TH_SHADE1);
869         glRecti(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax);
870
871         BIF_ThemeColor(TH_SHADE2);
872         glRecti(st->txtscroll.xmin, st->txtscroll.ymin, st->txtscroll.xmax, st->txtscroll.ymax);
873
874         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
875 }
876
877 static void screen_skip(SpaceText *st, int lines)
878 {
879         int last;
880         
881         if (!st) return;
882         if (st->spacetype != SPACE_TEXT) return;
883         if (!st->text) return;
884
885         st->top += lines;
886
887         last= txt_get_span(st->text->lines.first, st->text->lines.last);
888         last= last - (st->viewlines/2);
889         
890         if (st->top>last) st->top= last;
891         if (st->top<0) st->top= 0;
892 }
893
894 /* 
895  * mode 1 == view scroll
896  * mode 2 == scrollbar
897  */
898 static void do_textscroll(SpaceText *st, int mode)
899 {
900         short delta[2]= {0, 0};
901         short mval[2], hold[2], old[2];
902         
903         if (!st->text) return;
904         
905         calc_text_rcts(st);
906
907         st->flags|= ST_SCROLL_SELECT;
908
909         glDrawBuffer(GL_FRONT);
910         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
911         bglFlush();
912         glDrawBuffer(GL_BACK);
913
914         getmouseco_areawin(mval);
915         old[0]= hold[0]= mval[0];
916         old[1]= hold[1]= mval[1];
917
918         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
919                 getmouseco_areawin(mval);
920
921                 if(old[0]!=mval[0] || old[1]!=mval[1]) {
922                         if (mode==1) {
923                                 delta[0]= (hold[0]-mval[0])/spacetext_get_fontwidth(st);
924                                 delta[1]= (mval[1]-hold[1])/st->lheight;
925                         }
926                         else delta[1]= (hold[1]-mval[1])*st->pix_per_line;
927                         
928                         if (delta[0] || delta[1]) {
929                                 screen_skip(st, delta[1]);
930                                 st->left+= delta[0];
931                                 if (st->left<0) st->left= 0;
932                                 
933                                 scrarea_do_windraw(curarea);
934                                 screen_swapbuffers();
935                                 
936                                 hold[0]=mval[0];
937                                 hold[1]=mval[1];
938                         }
939                         old[0]=mval[0];
940                         old[1]=mval[1];
941                 } else {
942                         BIF_wait_for_statechange();
943                 }
944         }
945         st->flags^= ST_SCROLL_SELECT;
946
947         glDrawBuffer(GL_FRONT);
948         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
949         bglFlush();
950         glDrawBuffer(GL_BACK);
951 }
952
953 static void do_selection(SpaceText *st, int selecting)
954 {
955         short mval[2], old[2];
956         int sell, selc;
957         int linep2, charp2;
958         int first= 1;
959
960         getmouseco_areawin(mval);
961         old[0]= mval[0];
962         old[1]= mval[1];
963
964         if (!selecting) {
965                 int curl= txt_get_span(st->text->lines.first, st->text->curl);
966                 int curc= st->text->curc;                       
967                 int linep2, charp2;
968                                         
969                 set_cursor_to_pos(st, mval[0], mval[1], 0);
970
971                 linep2= txt_get_span(st->text->lines.first, st->text->curl);
972                 charp2= st->text->selc;
973                                 
974                 if (curl!=linep2 || curc!=charp2)
975                         txt_undo_add_toop(st->text, UNDO_CTO, curl, curc, linep2, charp2);
976         }
977
978         sell= txt_get_span(st->text->lines.first, st->text->sell);
979         selc= st->text->selc;
980
981         while(get_mbut()&L_MOUSE) {
982                 getmouseco_areawin(mval);
983
984                 if (mval[1]<0 || mval[1]>curarea->winy) {
985                         int d= (old[1]-mval[1])*st->pix_per_line;
986                         if (d) screen_skip(st, d);
987
988                         set_cursor_to_pos(st, mval[0], mval[1]<0?0:curarea->winy, 1);
989
990                         scrarea_do_windraw(curarea);
991                         screen_swapbuffers();
992                 } else if (mval[0]<0 || mval[0]>curarea->winx) {
993                         if (mval[0]>curarea->winx) st->left++;
994                         else if (mval[0]<0 && st->left>0) st->left--;
995                         
996                         set_cursor_to_pos(st, mval[0], mval[1], 1);
997                         
998                         scrarea_do_windraw(curarea);
999                         screen_swapbuffers();
1000                         
1001                         PIL_sleep_ms(10);
1002                 } else if (first || old[0]!=mval[0] || old[1]!=mval[1]) {
1003                         set_cursor_to_pos(st, mval[0], mval[1], 1);
1004
1005                         scrarea_do_windraw(curarea);
1006                         screen_swapbuffers();
1007
1008                         old[0]= mval[0];
1009                         old[1]= mval[1];
1010                         first= 1;
1011                 } else {
1012                         BIF_wait_for_statechange();
1013                 }
1014         }
1015
1016         linep2= txt_get_span(st->text->lines.first, st->text->sell);
1017         charp2= st->text->selc;
1018                 
1019         if (sell!=linep2 || selc!=charp2)
1020                 txt_undo_add_toop(st->text, UNDO_STO, sell, selc, linep2, charp2);
1021 }
1022
1023 static int do_suggest_select(SpaceText *st)
1024 {
1025         SuggItem *item, *first, *last, *sel;
1026         short mval[2];
1027         TextLine *tmp;
1028         int l, x, y, w, h, i;
1029         int seli, tgti;
1030         
1031         if (!st || !st->text) return 0;
1032         if (!texttool_text_is_active(st->text)) return 0;
1033
1034         first = texttool_suggest_first();
1035         last = texttool_suggest_last();
1036         sel = texttool_suggest_selected();
1037
1038         if (!last || !first)
1039                 return 0;
1040
1041         /* Count the visible lines to the cursor */
1042         for (tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
1043         if (l<0) return 0;
1044         
1045         if(st->showlinenrs) {
1046                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
1047         } else {
1048                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
1049         }
1050         y = curarea->winy - st->lheight*l - 2;
1051
1052         w = SUGG_LIST_WIDTH*spacetext_get_fontwidth(st) + 20;
1053         h = SUGG_LIST_SIZE*st->lheight + 8;
1054
1055         getmouseco_areawin(mval);
1056
1057         if (mval[0]<x || x+w<mval[0] || mval[1]<y-h || y<mval[1])
1058                 return 0;
1059
1060         /* Work out which of the visible SUGG_LIST_SIZE items is selected */
1061         for (seli=0, item=sel; seli<3 && item && item!=first; seli++, item=item->prev);
1062
1063         /* Work out the target item index in the visible list */
1064         tgti = (y-mval[1]-4) / st->lheight;
1065         if (tgti<0 || tgti>SUGG_LIST_SIZE)
1066                 return 1;
1067
1068         if (seli<tgti) {
1069                 for (i=seli; i<tgti && sel && sel!=last; i++, sel=sel->next);
1070                 if (sel)
1071                         texttool_suggest_select(sel);
1072         } else {
1073                 for (i=seli; i>tgti && sel && sel!=first; i--, sel=sel->prev);
1074                 if (sel)
1075                         texttool_suggest_select(sel);
1076         }
1077         return 1;
1078 }
1079
1080 void draw_documentation(SpaceText *st)
1081 {
1082         TextLine *tmp;
1083         char *docs, buf[DOC_WIDTH+1];
1084         int len, prevsp, i, a;
1085         int boxw=0, boxh, l, x, y;
1086         
1087         if (!st || !st->text) return;
1088         if (!texttool_text_is_active(st->text)) return;
1089         
1090         docs = texttool_docs_get();
1091
1092         if (!docs) return;
1093
1094         /* Count the visible lines to the cursor */
1095         for (tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
1096         if (l<0) return;
1097         
1098         if(st->showlinenrs) {
1099                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
1100         } else {
1101                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
1102         }
1103         if (texttool_suggest_first()) {
1104                 x += SUGG_LIST_WIDTH*spacetext_get_fontwidth(st) + 50;
1105         }
1106         y = curarea->winy - st->lheight*l - 2;
1107
1108         len = strlen(docs);
1109
1110         boxw = DOC_WIDTH*spacetext_get_fontwidth(st) + 20;
1111         boxh = (2*len/DOC_WIDTH+1)*st->lheight + 8; /* Rough guess at box height */
1112         
1113         BIF_ThemeColor(TH_SHADE1);
1114         glRecti(x-1, y+1, x+boxw+1, y-boxh-1);
1115         BIF_ThemeColor(TH_BACK);
1116         glRecti(x, y, x+boxw, y-boxh);
1117         BIF_ThemeColor(TH_TEXT);
1118
1119         len = strlen(docs);
1120         prevsp = a = 0;
1121
1122         for (i=0; i<len; i++) {
1123                 if (docs[i] == ' ' || docs[i] == '\t' || docs[i] == '\n') {
1124
1125                         /* If we would exceed the line length, print up to the last space */
1126                         if (a + i-prevsp > DOC_WIDTH) {
1127                                 y -= st->lheight;
1128                                 buf[a] = '\0';
1129                                 text_draw(st, buf, 0, 0, 1, x+4, y-1, NULL);
1130                                 a = 0;
1131                         }
1132
1133                         /* Buffer up the next bit ready to draw */
1134                         if (i-prevsp > DOC_WIDTH) break; /* TODO: Deal with long, unbroken strings */
1135                         strncpy(buf+a, docs+prevsp, i-prevsp);
1136                         a += i-prevsp;
1137                         prevsp = i;
1138
1139                         /* Hit a new line, print what we have */
1140                         if (docs[i] == '\n') {
1141                                 y -= st->lheight;
1142                                 buf[a] = '\0';
1143                                 text_draw(st, buf, 0, 0, 1, x+4, y-1, NULL);
1144                                 a = 0;
1145                         }
1146                 }
1147         }
1148 }
1149
1150 void draw_suggestion_list(SpaceText *st)
1151 {
1152         SuggItem *item, *first, *last, *sel;
1153         TextLine *tmp;
1154         char str[SUGG_LIST_WIDTH+1];
1155         int w, boxw=0, boxh, i, l, x, y, b;
1156         
1157         if (!st || !st->text) return;
1158         if (!texttool_text_is_active(st->text)) return;
1159
1160         first = texttool_suggest_first();
1161         last = texttool_suggest_last();
1162
1163         if (!first || !last) return;
1164
1165         sel = texttool_suggest_selected();
1166
1167         /* Count the visible lines to the cursor */
1168         for (tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
1169         if (l<0) return;
1170         
1171         if(st->showlinenrs) {
1172                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
1173         } else {
1174                 x = spacetext_get_fontwidth(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
1175         }
1176         y = curarea->winy - st->lheight*l - 2;
1177
1178         boxw = SUGG_LIST_WIDTH*spacetext_get_fontwidth(st) + 20;
1179         boxh = SUGG_LIST_SIZE*st->lheight + 8;
1180         
1181         BIF_ThemeColor(TH_SHADE1);
1182         glRecti(x-1, y+1, x+boxw+1, y-boxh-1);
1183         BIF_ThemeColor(TH_BACK);
1184         glRecti(x, y, x+boxw, y-boxh);
1185
1186         /* Set the top 'item' of the visible list */
1187         for (i=0, item=sel; i<3 && item && item!=first; i++, item=item->prev);
1188         if (!item)
1189                 item = first;
1190
1191         for (i=0; i<SUGG_LIST_SIZE && item; i++, item=item->next) {
1192
1193                 y -= st->lheight;
1194
1195                 strncpy(str, item->name, SUGG_LIST_WIDTH);
1196                 str[SUGG_LIST_WIDTH] = '\0';
1197
1198                 w = BMF_GetStringWidth(spacetext_get_font(st), str);
1199                 
1200                 if (item == sel) {
1201                         BIF_ThemeColor(TH_SHADE2);
1202                         glRecti(x+16, y-3, x+16+w, y+st->lheight-3);
1203                 }
1204                 b=1; /* b=1 colour block, text is default. b=0 no block, colour text */
1205                 switch (item->type) {
1206                         case 'k': BIF_ThemeColor(TH_SYNTAX_B); b=0; break;
1207                         case 'm': BIF_ThemeColor(TH_TEXT); break;
1208                         case 'f': BIF_ThemeColor(TH_SYNTAX_L); break;
1209                         case 'v': BIF_ThemeColor(TH_SYNTAX_N); break;
1210                         case '?': BIF_ThemeColor(TH_TEXT); b=0; break;
1211                 }
1212                 if (b) {
1213                         glRecti(x+8, y+2, x+11, y+5);
1214                         BIF_ThemeColor(TH_TEXT);
1215                 }
1216                 text_draw(st, str, 0, 0, 1, x+16, y-1, NULL);
1217
1218                 if (item == last) break;
1219         }
1220 }
1221
1222 void drawtextspace(ScrArea *sa, void *spacedata)
1223 {
1224         SpaceText *st= curarea->spacedata.first;
1225         Text *text;
1226         int i;
1227         TextLine *tmp;
1228         char linenr[12];
1229         float col[3];
1230         int linecount = 0;
1231
1232         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1233         
1234         BIF_GetThemeColor3fv(TH_BACK, col);
1235         glClearColor(col[0], col[1], col[2], 0.0);
1236         glClear(GL_COLOR_BUFFER_BIT);
1237         myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
1238
1239         draw_area_emboss(sa);
1240
1241         text= st->text;
1242         if(!text) return;
1243         
1244         /* Make sure all the positional pointers exist */
1245         if (!text->curl || !text->sell || !text->lines.first || !text->lines.last)
1246                 txt_clean_text(text);
1247         
1248         if(st->lheight) st->viewlines= (int) curarea->winy/st->lheight;
1249         else st->viewlines= 0;
1250         
1251         if(st->showlinenrs) {
1252                 cpack(0x8c787c);
1253                 glRecti(23,  0, (st->lheight==15)?63:59,  curarea->winy - 2);
1254         }
1255
1256         BIF_ThemeColor(TH_TEXT);
1257
1258         draw_cursor(st);
1259
1260         tmp= text->lines.first;
1261         for (i= 0; i<st->top && tmp; i++) {
1262                 tmp= tmp->next;
1263                 linecount++;
1264         }
1265         
1266         if(st->showsyntax) {
1267                 if (tmp && !tmp->format) {
1268                         get_format_string(st);
1269                 }
1270         }
1271         
1272         for (i=0; i<st->viewlines && tmp; i++, tmp= tmp->next) {
1273                 if(st->showlinenrs) {
1274                         /*Change the color of the current line the cursor is on*/
1275                         if(tmp == text->curl) { 
1276                                 BIF_ThemeColor(TH_HILITE);
1277                         } else {
1278                                 BIF_ThemeColor(TH_TEXT);
1279                         }
1280                         if(((float)(i + linecount + 1)/10000.0) < 1.0) {
1281                                 sprintf(linenr, "%4d", i + linecount + 1);
1282                                 glRasterPos2i(TXT_OFFSET - 7, curarea->winy-st->lheight*(i+1));
1283                         } else {
1284                                 sprintf(linenr, "%5d", i + linecount + 1);
1285                                 glRasterPos2i(TXT_OFFSET - 11, curarea->winy-st->lheight*(i+1));
1286                         }
1287                         BIF_ThemeColor(TH_TEXT);
1288                         BMF_DrawString(spacetext_get_font(st), linenr);
1289                         text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET + TEXTXLOC, curarea->winy-st->lheight*(i+1), tmp->format);
1290                 } else
1291                         text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET, curarea->winy-st->lheight*(i+1), tmp->format);
1292         }
1293
1294         draw_textscroll(st);
1295         draw_documentation(st);
1296         draw_suggestion_list(st);
1297
1298         curarea->win_swap= WIN_BACK_OK;
1299 }
1300
1301 /* Moves the view to the cursor location,
1302   also used to make sure the view isnt outside the file */
1303 void pop_space_text (SpaceText *st)
1304 {
1305         int i, x;
1306
1307         if(!st) return;
1308         if(!st->text) return;
1309         if(!st->text->curl) return;
1310                 
1311         i= txt_get_span(st->text->lines.first, st->text->curl);
1312         if (st->top+st->viewlines <= i || st->top > i) {
1313                 st->top= i - st->viewlines/2;
1314         }
1315         
1316         x= text_draw(st, st->text->curl->line, st->left, st->text->curc, 0, 0, 0, NULL);
1317
1318         if (x==0 || x>curarea->winx) {
1319                 st->left= st->text->curc-0.5*(curarea->winx)/spacetext_get_fontwidth(st);
1320         }
1321
1322         if (st->top < 0) st->top= 0;
1323         if (st->left <0) st->left= 0;
1324 }
1325
1326 void add_text_fs(char *file) /* bad but cant pass an as arg here */
1327 {
1328         SpaceText *st= curarea->spacedata.first;
1329         Text *text;
1330
1331         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1332
1333         text= add_text(file);
1334
1335         st->text= text;
1336
1337         st->top= 0;
1338
1339         if (st->showsyntax) get_format_string(st);
1340         allqueue(REDRAWTEXT, 0);
1341         allqueue(REDRAWHEADERS, 0);     
1342 }
1343
1344 void free_textspace(SpaceText *st)
1345 {
1346         if (!st) return;
1347
1348         st->text= NULL;
1349 }
1350
1351 /* returns 0 if file on disk is the same or Text is in memory only
1352    returns 1 if file has been modified on disk since last local edit
1353    returns 2 if file on disk has been deleted
1354    -1 is returned if an error occurs
1355 */
1356 int txt_file_modified(Text *text)
1357 {
1358         struct stat st;
1359         int result;
1360
1361         if (!text || !text->name)
1362                 return 0;
1363
1364         if (!BLI_exists(text->name))
1365                 return 2;
1366
1367         result = stat(text->name, &st);
1368         
1369         if(result == -1)
1370                 return -1;
1371
1372         if((st.st_mode & S_IFMT) != S_IFREG)
1373                 return -1;
1374
1375         if (st.st_mtime > text->mtime)
1376                 return 1;
1377
1378         return 0;
1379 }
1380
1381 static void save_mem_text(char *str)
1382 {
1383         SpaceText *st= curarea->spacedata.first;
1384         Text *text;
1385         
1386         if (!str) return;
1387         
1388         if (!st) return;
1389         if (st->spacetype != SPACE_TEXT) return;
1390
1391         text= st->text;
1392         if(!text) return;
1393         
1394         if (text->name) MEM_freeN(text->name);
1395         text->name= MEM_mallocN(strlen(str)+1, "textname");
1396         strcpy(text->name, str);
1397
1398         text->flags ^= TXT_ISMEM;
1399                 
1400         txt_write_file(text);
1401 }
1402
1403 void txt_write_file(Text *text) 
1404 {
1405         FILE *fp;
1406         TextLine *tmp;
1407         int res;
1408         struct stat st;
1409         
1410         /* Do we need to get a filename? */
1411         if (text->flags & TXT_ISMEM) {
1412                 if (text->name)
1413                         activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->name, save_mem_text);
1414                 else
1415                         activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->id.name+2, save_mem_text);
1416                 return;
1417         }
1418         
1419         /* Should we ask to save over? */
1420         if (text->flags & TXT_ISTMP) {
1421                 if (BLI_exists(text->name)) {
1422                         if (!okee("Save over")) return;
1423                 } else if (!okee("Create new file")) return;
1424
1425                 text->flags ^= TXT_ISTMP;
1426         }
1427                 
1428         fp= fopen(text->name, "w");
1429         if (fp==NULL) {
1430                 error("Unable to save file");
1431                 return;
1432         }
1433
1434         tmp= text->lines.first;
1435         while (tmp) {
1436                 if (tmp->next) fprintf(fp, "%s\n", tmp->line);
1437                 else fprintf(fp, "%s", tmp->line);
1438                 
1439                 tmp= tmp->next;
1440         }
1441         
1442         fclose (fp);
1443
1444         res= stat(text->name, &st);
1445         text->mtime= st.st_mtime;
1446         
1447         if (text->flags & TXT_ISDIRTY) text->flags ^= TXT_ISDIRTY;
1448 }
1449
1450 void unlink_text(Text *text)
1451 {
1452         bScreen *scr;
1453         ScrArea *area;
1454         SpaceLink *sl;
1455         
1456         /* check if this text was used as script link:
1457          * this check function unsets the pointers and returns how many
1458          * script links used this Text */
1459         if (BPY_check_all_scriptlinks (text)) {
1460                 allqueue(REDRAWBUTSSCRIPT, 0);
1461         }
1462         /* equivalently for pynodes: */
1463         if (nodeDynamicUnlinkText ((ID*)text)) {
1464                 allqueue(REDRAWNODE, 0);
1465         }
1466
1467         for (scr= G.main->screen.first; scr; scr= scr->id.next) {
1468                 for (area= scr->areabase.first; area; area= area->next) {
1469                         for (sl= area->spacedata.first; sl; sl= sl->next) {
1470                                 if (sl->spacetype==SPACE_TEXT) {
1471                                         SpaceText *st= (SpaceText*) sl;
1472                                         
1473                                         if (st->text==text) {
1474                                                 st->text= NULL;
1475                                                 st->top= 0;
1476                                                 
1477                                                 if (st==area->spacedata.first) {
1478                                                         scrarea_queue_redraw(area);
1479                                                 }
1480                                         }
1481                                 }
1482                         }
1483                 }
1484         }
1485 }
1486
1487 int jumptoline_interactive(SpaceText *st) {
1488         short nlines= txt_get_span(st->text->lines.first, st->text->lines.last)+1;
1489         short tmp= txt_get_span(st->text->lines.first, st->text->curl)+1;
1490
1491         if (button(&tmp, 1, nlines, "Jump to line:")) {
1492                 txt_move_toline(st->text, tmp-1, 0);
1493                 pop_space_text(st);
1494                 return 1;
1495         } else {
1496                 return 0;
1497         }
1498 }
1499
1500
1501 int bufferlength;
1502 static char *copybuffer = NULL;
1503
1504 void txt_copy_selectbuffer (Text *text)
1505 {
1506         int length=0;
1507         TextLine *tmp, *linef, *linel;
1508         int charf, charl;
1509         
1510         if (!text) return;
1511         if (!text->curl) return;
1512         if (!text->sell) return;
1513
1514         if (!txt_has_sel(text)) return;
1515         
1516         if (copybuffer) {
1517                 MEM_freeN(copybuffer);
1518                 copybuffer= NULL;
1519         }
1520
1521         if (text->curl==text->sell) {
1522                 linef= linel= text->curl;
1523                 
1524                 if (text->curc < text->selc) {
1525                         charf= text->curc;
1526                         charl= text->selc;
1527                 } else{
1528                         charf= text->selc;
1529                         charl= text->curc;
1530                 }
1531         } else if (txt_get_span(text->curl, text->sell)<0) {
1532                 linef= text->sell;
1533                 linel= text->curl;
1534
1535                 charf= text->selc;              
1536                 charl= text->curc;
1537         } else {
1538                 linef= text->curl;
1539                 linel= text->sell;
1540                 
1541                 charf= text->curc;
1542                 charl= text->selc;
1543         }
1544
1545         if (linef == linel) {
1546                 length= charl-charf;
1547
1548                 copybuffer= MEM_mallocN(length+1, "cut buffera");
1549                 
1550                 BLI_strncpy(copybuffer, linef->line + charf, length+1);
1551         } else {
1552                 length+= linef->len - charf;
1553                 length+= charl;
1554                 length++; /* For the '\n' */
1555                 
1556                 tmp= linef->next;
1557                 while (tmp && tmp!= linel) {
1558                         length+= tmp->len+1;
1559                         tmp= tmp->next;
1560                 }
1561                 
1562                 copybuffer= MEM_mallocN(length+1, "cut bufferb");
1563                 
1564                 strncpy(copybuffer, linef->line+ charf, linef->len-charf);
1565                 length= linef->len-charf;
1566                 
1567                 copybuffer[length++]='\n';
1568                 
1569                 tmp= linef->next;
1570                 while (tmp && tmp!=linel) {
1571                         strncpy(copybuffer+length, tmp->line, tmp->len);
1572                         length+= tmp->len;
1573                         
1574                         copybuffer[length++]='\n';                      
1575                         
1576                         tmp= tmp->next;
1577                 }
1578                 strncpy(copybuffer+length, linel->line, charl);
1579                 length+= charl;
1580                 
1581                 copybuffer[length]=0;
1582         }
1583
1584         bufferlength = length;
1585 }
1586
1587 static char *unixNewLine(char *buffer)
1588 {
1589         char *p, *p2, *output;
1590         
1591         /* we can afford the few extra bytes */
1592         output= MEM_callocN(strlen(buffer)+1, "unixnewline");
1593         for (p= buffer, p2= output; *p; p++)
1594                 if (*p != '\r') *(p2++)= *p;
1595         
1596         *p2= 0;
1597         return(output);
1598 }
1599
1600 static char *winNewLine(char *buffer)
1601 {
1602         char *p, *p2, *output;
1603         int add= 0;
1604         
1605         for (p= buffer; *p; p++)
1606                 if (*p == '\n') add++;
1607                 
1608         bufferlength= p-buffer+add+1;
1609         output= MEM_callocN(bufferlength, "winnewline");
1610         for (p= buffer, p2= output; *p; p++, p2++) {
1611                 if (*p == '\n') { 
1612                         *(p2++)= '\r'; *p2= '\n';
1613                 } else *p2= *p;
1614         }
1615         *p2= 0;
1616         
1617         return(output);
1618 }
1619
1620 void txt_paste_clipboard(Text *text) {
1621
1622         char * buff;
1623         char *temp_buff;
1624         
1625         buff = (char*)getClipboard(0);
1626         if(buff) {
1627                 temp_buff = unixNewLine(buff);
1628                 
1629                 txt_insert_buf(text, temp_buff);
1630                 if(buff){free((void*)buff);}
1631                 if(temp_buff){MEM_freeN(temp_buff);}
1632         }
1633 }
1634
1635 void get_selection_buffer(Text *text)
1636 {
1637         char *buff = getClipboard(1);
1638         txt_insert_buf(text, buff);
1639 }
1640
1641 void txt_copy_clipboard(Text *text) {
1642         char *temp;
1643
1644         txt_copy_selectbuffer(text);
1645
1646         if (copybuffer) {
1647                 copybuffer[bufferlength] = '\0';
1648                 temp = winNewLine(copybuffer);
1649                 
1650                 putClipboard(temp, 0);
1651                 MEM_freeN(temp);
1652                 MEM_freeN(copybuffer);
1653                 copybuffer= NULL;
1654         }
1655 }
1656
1657 static short find_and_replace_popup(char *findvar, char *replvar, int *flags, short min, short max)
1658 {
1659         uiBlock *block;
1660         ListBase listb={0, 0};
1661         short x1,y1;
1662         short ret=0;
1663         char *editfindvar=NULL, *editreplvar=NULL; /* dont edit the original text, incase we cancel the popup */
1664         
1665         if(min>max) min= max;
1666
1667         block= uiNewBlock(&listb, "button", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
1668         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_ENTER_OK);
1669
1670         x1= curarea->winrct.xmax - 240;
1671         y1= curarea->winrct.ymin;
1672         
1673         editfindvar = MEM_callocN(max+1, "findvar");
1674         editreplvar = MEM_callocN(max+1, "replvar");
1675         BLI_strncpy(editfindvar, findvar, max);
1676         BLI_strncpy(editreplvar, replvar, max);
1677         
1678         uiDefButC(block, TEX, 0, "Find: ", x1+5,y1+85,225,20, editfindvar,(float)min,(float)max, 0, 0, "");
1679         uiDefButC(block, TEX, 0, "Replace: ", x1+5,y1+60,225,20, editreplvar,(float)min,(float)max, 0, 0, "");
1680         uiDefButBitI(block, TOG, TXT_FIND_REPLACE, 0, "Replace", x1+5,y1+35,55,20, flags, 0, 0, 0, 0, "Replace previous item found");
1681         uiDefButBitI(block, TOG, TXT_FIND_ALLTEXTS, 0, "All Texts", x1+60,y1+35,55,20, flags, 0, 0, 0, 0, "Search all texts");
1682         uiDefButBitI(block, TOG, TXT_FIND_WRAP, 0, "Wrap", x1+115,y1+35,55,20, flags, 0, 0, 0, 0, "Wrap search around current text");
1683         uiDefBut(block, BUT, 3, "Replace/Find", x1+125,y1+10,105,20, NULL, 0, 0, 0, 0, "");
1684
1685         uiBoundsBlock(block, 5);
1686         
1687         ret= uiDoBlocks(&listb, 0, 0);
1688
1689         if(ret==UI_RETURN_OK) {
1690                 BLI_strncpy(findvar, editfindvar, max);
1691                 BLI_strncpy(replvar, editreplvar, max);
1692                 MEM_freeN(editfindvar);
1693                 MEM_freeN(editreplvar);
1694                 return 1;
1695         }
1696         MEM_freeN(editfindvar);
1697         MEM_freeN(editreplvar);
1698         return 0;
1699         
1700 }
1701
1702 /*
1703  * again==0 always show find panel
1704  * again==1 find text again (no panel) If first find, panel shown anyway
1705  * flags:
1706  *   TXT_FIND_REPLACE  replace last found occurrence before searching again
1707  *   TXT_FIND_ALLTEXTS search through all texts (off wraps current text)
1708  */
1709 void txt_find_panel(SpaceText *st, int again, int flags)
1710 {
1711         Text *text, *start;
1712         char *tmp= NULL;
1713         char buf[256], repbuf[256];
1714         int searched, skip, noswitch;
1715
1716         text= start= st->text;
1717         if (!text) return;
1718         if (again) {
1719                 if (!last_txt_find_string) again= 0; /* Can't search again */
1720                 if (!last_txt_repl_string && (flags & TXT_FIND_REPLACE)) again= 0;
1721         }
1722
1723         if (!again) {
1724                 /* Populate tmp with selected text, or the last searched string */
1725                 if (txt_has_sel(text))
1726                         tmp= txt_sel_to_buf(text);
1727                 else if (last_txt_find_string)
1728                         tmp= BLI_strdup(last_txt_find_string);
1729
1730                 if (tmp && strlen(tmp) < sizeof(buf)-1)strcpy(buf, tmp);
1731                 else buf[0]= 0;
1732                 if (tmp) { MEM_freeN(tmp); tmp= NULL; }
1733
1734                 if (last_txt_repl_string) strcpy(repbuf, last_txt_repl_string);
1735                 else repbuf[0]= 0;
1736
1737                 searched= skip= noswitch= 0;
1738                 while (skip || find_and_replace_popup(buf, repbuf, &flags, 0, sizeof(buf)-1) && buf[0]) {
1739                         skip= 0;
1740
1741                         /* Allow us to detect when to go to the next text */
1742                         if (flags & TXT_FIND_ALLTEXTS)
1743                                 flags &= ~TXT_FIND_WRAP;
1744
1745                         /* Replace selection first */
1746                         if ((flags & TXT_FIND_REPLACE) && txt_has_sel(text)) {
1747                                 tmp= txt_sel_to_buf(text);
1748                                 if (strcmp(buf, tmp)==0) { /* Searching for same thing? */
1749                                         txt_insert_buf(text, repbuf);
1750                                         if (st->showsyntax) get_format_string(st);
1751                                 }
1752                                 MEM_freeN(tmp);
1753                                 tmp= NULL;
1754                         }
1755
1756                         /* Now find the next occurrence */
1757                         searched= 1;
1758                         if (txt_find_string(text, buf, flags&TXT_FIND_WRAP)) {
1759                                 pop_space_text(st);
1760                         } else if ((flags & TXT_FIND_ALLTEXTS) && !noswitch) {
1761                                 if (text->id.next) text= st->text= text->id.next;
1762                                 else text= st->text= G.main->text.first;
1763                                 
1764                                 /* Finish at end of this text if we've been round once */
1765                                 if (text==start)
1766                                         noswitch= 1;
1767                                 
1768                                 txt_move_toline(text, 0, 0);
1769                                 pop_space_text(st);
1770                                 skip= 1; /* Skip panel so we immediately search the next text */
1771                         } else {
1772                                 okee("Text not found: %s", buf);
1773                                 break;
1774                         }
1775                         
1776                         /* Redraw */
1777                         scrarea_do_windraw(curarea);
1778                         screen_swapbuffers();
1779                 }
1780
1781                 /* Store last search details */
1782                 if (searched) {
1783                         last_txt_find_flags= flags;
1784                         if (last_txt_find_string)
1785                                 MEM_freeN(last_txt_find_string);
1786                         last_txt_find_string= BLI_strdup(buf);
1787                         if (last_txt_repl_string)
1788                                 MEM_freeN(last_txt_repl_string);
1789                         last_txt_repl_string= BLI_strdup(repbuf);
1790                 }
1791         } else {
1792                 if (strlen(last_txt_find_string) < sizeof(buf)-1) {
1793
1794                         /* Replace current */
1795                         if ((flags & TXT_FIND_REPLACE) && last_txt_repl_string && txt_has_sel(text)) {
1796                                 tmp= txt_sel_to_buf(text);
1797                                 if (strcmp(last_txt_find_string, tmp)==0)
1798                                         txt_insert_buf(text, last_txt_repl_string);
1799                                 MEM_freeN(tmp);
1800                                 tmp= NULL;
1801                         }
1802
1803                         /* Find next */
1804                         if (flags & TXT_FIND_ALLTEXTS)
1805                                 flags &= ~TXT_FIND_WRAP;
1806                         if (txt_find_string(text, last_txt_find_string, flags & TXT_FIND_WRAP)) {
1807                                 pop_space_text(st);
1808                         } else if (flags & flags&TXT_FIND_ALLTEXTS) {
1809                                 if (text->id.next)
1810                                         text= st->text= text->id.next;
1811                                 else
1812                                         text= st->text= G.main->text.first;
1813                                 txt_move_toline(text, 0, 0);
1814                                 pop_space_text(st);
1815                         } else {
1816                                 okee("Text not found: %s", last_txt_find_string);
1817                         }
1818                 }
1819         }
1820 }
1821
1822 void run_python_script(SpaceText *st)
1823 {
1824         char *py_filename;
1825         Text *text=st->text;
1826
1827         if (!BPY_txt_do_python_Text(text)) {
1828                 int lineno = BPY_Err_getLinenumber();
1829                 // jump to error if happened in current text:
1830                 py_filename = (char*) BPY_Err_getFilename();
1831
1832                 /* st->text can become NULL: user called Blender.Load(blendfile)
1833                  * before the end of the script. */
1834                 if (!st->text) return;
1835
1836                 if (!strcmp(py_filename, st->text->id.name+2)) {
1837                         error_pyscript(  );
1838                         if (lineno >= 0) {
1839                                 txt_move_toline(text, lineno-1, 0);
1840                                 txt_sel_line(text);
1841                                 pop_space_text(st);
1842                         }       
1843                 } else {
1844                         error("Error in other (possibly external) file, "\
1845                                 "check console");
1846                 }       
1847         }
1848 }
1849
1850 static void set_tabs(Text *text)
1851 {
1852         SpaceText *st = curarea->spacedata.first;
1853         st->currtab_set = setcurr_tab(text);
1854 }
1855
1856 static void get_suggest_prefix(Text *text) {
1857         int i, len;
1858         char *line, tmp[256];
1859
1860         if (!text) return;
1861         if (!texttool_text_is_active(text)) return;
1862
1863         line= text->curl->line;
1864         for (i=text->curc-1; i>=0; i--)
1865                 if (!check_identifier(line[i]))
1866                         break;
1867         i++;
1868         len= text->curc-i;
1869         if (len > 255) {
1870                 printf("Suggestion prefix too long\n");
1871                 len = 255;
1872         }
1873         strncpy(tmp, line+i, len);
1874         tmp[len]= '\0';
1875         texttool_suggest_prefix(tmp);
1876 }
1877
1878 static void confirm_suggestion(Text *text, int skipleft) {
1879         int i, over=0;
1880         char *line;
1881         SuggItem *sel;
1882
1883         if (!text) return;
1884         if (!texttool_text_is_active(text)) return;
1885
1886         sel = texttool_suggest_selected();
1887         if (!sel) return;
1888
1889         line= text->curl->line;
1890         i=text->curc-skipleft-1;
1891         while (i>=0) {
1892                 if (!check_identifier(line[i]))
1893                         break;
1894                 over++;
1895                 i--;
1896         }
1897
1898         for (i=0; i<skipleft; i++)
1899                 txt_move_left(text, 0);
1900         for (i=0; i<over; i++)
1901                 txt_move_left(text, 1);
1902
1903         txt_insert_buf(text, sel->name);
1904         
1905         for (i=0; i<skipleft; i++)
1906                 txt_move_right(text, 0);
1907
1908         texttool_text_clear();
1909 }
1910
1911 void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1912 {
1913         unsigned short event= evt->event;
1914         short val= evt->val;
1915         char ascii= evt->ascii;
1916         SpaceText *st= curarea->spacedata.first;
1917         Text *text;
1918         int do_draw=0, p;
1919         int tools=0, tools_cancel=0, tools_update=0; /* Bitmasks for operations */
1920         
1921         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1922         
1923         /* smartass code to prevent the CTRL/ALT events below from not working! */
1924         if(G.qual & (LR_ALTKEY|LR_CTRLKEY))
1925                 if(!ispunct(ascii)) 
1926                         ascii= 0;
1927
1928         text= st->text;
1929         
1930         if (!text) {
1931                 if (event==RIGHTMOUSE) {
1932                         switch (pupmenu("File %t|New %x0|Open... %x1")) {
1933                         case 0:
1934                                 st->text= add_empty_text("Text");
1935                                 st->top= 0;
1936                         
1937                                 allqueue(REDRAWTEXT, 0);
1938                                 allqueue(REDRAWHEADERS, 0);
1939                                 break;
1940                         case 1:
1941                                 activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1942                                 break;
1943                         }
1944                 }
1945                 if (val && !ELEM(G.qual, 0, LR_SHIFTKEY)) {
1946                         if (event==FKEY && G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1947                                 switch (pupmenu("File %t|New %x0|Open... %x1")) {
1948                                 case 0:
1949                                         st->text= add_empty_text("Text");
1950                                         st->top= 0;
1951                                 
1952                                         allqueue(REDRAWTEXT, 0);
1953                                         allqueue(REDRAWHEADERS, 0);
1954                                         break;
1955                                 case 1:
1956                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1957                                         break;
1958                                 }
1959                         } 
1960                         else if (event==QKEY) {
1961                                 if (G.qual & LR_CTRLKEY) {
1962                                         if(okee("Quit Blender")) exit_usiblender();
1963                                 }
1964                         }
1965                         else if (event==NKEY) {
1966                                 if (G.qual & LR_ALTKEY) {
1967                                         st->text= add_empty_text("Text");
1968                                         st->top= 0;
1969                                 
1970                                         allqueue(REDRAWTEXT, 0);
1971                                         allqueue(REDRAWHEADERS, 0);
1972                                 }
1973                         }
1974                         else if (event==OKEY) {
1975                                 if (G.qual & LR_ALTKEY) {
1976                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1977                                 }
1978                         }
1979                 }
1980                 return;
1981         }
1982
1983         if (st->showsyntax && texttool_text_is_active(text)) {
1984                 if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
1985                 if (texttool_docs_get()) tools |= TOOL_DOCUMENT;
1986         }
1987         
1988         if (event==LEFTMOUSE) {
1989                 if (val) {
1990                         short mval[2];
1991                         char *buffer;
1992                         set_tabs(text);
1993                         getmouseco_areawin(mval);
1994                         
1995                         if (mval[0]>2 && mval[0]<20 && mval[1]>2 && mval[1]<curarea->winy-2) {
1996                                 do_textscroll(st, 2);
1997                                 tools_cancel |= TOOL_SUGG_LIST | TOOL_DOCUMENT;
1998                         } else if (do_suggest_select(st)) {
1999                                 do_draw= 1;
2000                         } else {
2001                                 do_selection(st, G.qual&LR_SHIFTKEY);
2002                                 if (txt_has_sel(text)) {
2003                                         buffer = txt_sel_to_buf(text);
2004                                         putClipboard(buffer, 1);
2005                                         MEM_freeN(buffer);
2006                                 }
2007                                 do_draw= 1;
2008                                 tools_cancel |= TOOL_SUGG_LIST | TOOL_DOCUMENT;
2009                         }
2010                 }
2011         } else if (event==MIDDLEMOUSE) {
2012                 if (val) {
2013                         if (do_suggest_select(st)) {
2014                                 confirm_suggestion(text, 0);
2015                                 do_draw= 1;
2016                         } else {
2017                                 if (U.uiflag & USER_MMB_PASTE) {
2018                                         do_selection(st, G.qual&LR_SHIFTKEY);
2019                                         get_selection_buffer(text);
2020                                         do_draw= 1;
2021                                 } else {
2022                                         do_textscroll(st, 1);
2023                                 }
2024                                 tools_cancel |= TOOL_SUGG_LIST | TOOL_DOCUMENT;
2025                         }
2026                 }
2027         } else if (event==RIGHTMOUSE) {
2028                 if (val) {
2029                         p= pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3|Execute Script%x4");
2030
2031                         switch(p) {
2032                                 case 0:
2033                                         st->text= add_empty_text("Text");
2034                                         st->top= 0;
2035                                         
2036                                         allqueue(REDRAWTEXT, 0);
2037                                         allqueue(REDRAWHEADERS, 0);
2038                                         break;
2039
2040                                 case 1:
2041                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
2042                                         break;
2043                                         
2044                                 case 3:
2045                                         text->flags |= TXT_ISMEM;
2046                                         
2047                                 case 2:
2048                                         txt_write_file(text);
2049                                         do_draw= 1;
2050                                         break;
2051                                 case 4:
2052                                         run_python_script(st);
2053                                         do_draw= 1;
2054                                         break;
2055                                 default:
2056                                         break;
2057                         }
2058                         tools_cancel |= TOOL_SUGG_LIST | TOOL_DOCUMENT;
2059                 }
2060         } else if (ascii) {
2061                 if (text && text->id.lib) {
2062                         error_libdata();
2063
2064                 } else if ((st->overwrite && txt_replace_char(text, ascii)) || txt_add_char(text, ascii)) {
2065                         if (st->showsyntax) get_format_string(st);
2066                         pop_space_text(st);
2067                         do_draw= 1;
2068                         if (tools & TOOL_SUGG_LIST) {
2069                                 if ((ascii != '_' && ascii != '*' && ispunct(ascii)) || check_whitespace(ascii)) {
2070                                         confirm_suggestion(text, 1);
2071                                         if (st->showsyntax) get_format_string(st);
2072                                 } else {
2073                                         tools_update |= TOOL_SUGG_LIST;
2074                                 }
2075                         }
2076                         tools_cancel |= TOOL_DOCUMENT;
2077                 }
2078         } else if (val) {
2079
2080                 /* Cases that require tools not to be cancelled must explicitly say so.
2081                  * The default case does this to prevent window/mousemove events
2082                  * from cancelling. */
2083                 tools_cancel |= TOOL_SUGG_LIST | TOOL_DOCUMENT;
2084
2085                 switch (event) {
2086                 case AKEY:
2087                         if (G.qual & LR_ALTKEY) {
2088                                 txt_move_bol(text, G.qual & LR_SHIFTKEY);
2089                                 do_draw= 1;
2090                                 pop_space_text(st);
2091                         } else if (G.qual & LR_CTRLKEY) {
2092                                 txt_sel_all(text);
2093                                 do_draw= 1;
2094                         }
2095                         break; /* BREAK A */
2096                 case CKEY:
2097                         if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
2098                                 if(G.qual & LR_SHIFTKEY)
2099                                         txt_copy_clipboard(text);
2100                                 else
2101                                         txt_copy_clipboard(text);
2102
2103                                 do_draw= 1;     
2104                         }
2105                         break; /* BREAK C */
2106                 case DKEY:
2107                         if (text && text->id.lib) {
2108                                 error_libdata();
2109                                 break;
2110                         }
2111                         if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
2112                                 //uncommenting
2113                                 txt_order_cursors(text);
2114                                 uncomment(text);
2115                                 do_draw = 1;
2116                                 if (st->showsyntax) get_format_string(st);
2117                                 break;
2118                         } else if (G.qual == LR_CTRLKEY) {
2119                                 txt_delete_char(text);
2120                                 if (st->showsyntax) get_format_string(st);
2121                                 do_draw= 1;
2122                                 pop_space_text(st);
2123                         }
2124                         break; /* BREAK D */
2125                 case EKEY:
2126                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
2127                                 switch(pupmenu("Edit %t|Cut %x0|Copy %x1|Paste %x2|Print Cut Buffer %x3")) {
2128                                 case 0:
2129                                         if (text && text->id.lib) {
2130                                                 error_libdata();
2131                                                 break;
2132                                         }
2133                                         txt_copy_clipboard(text); //First copy to clipboard
2134                                         txt_cut_sel(text);
2135                                         do_draw= 1;
2136                                         break;
2137                                 case 1:
2138                                         txt_copy_clipboard(text);
2139                                         //txt_copy_sel(text);
2140                                         do_draw= 1;
2141                                         break;
2142                                 case 2:
2143                                         if (text && text->id.lib) {
2144                                                 error_libdata();
2145                                                 break;
2146                                         }
2147                                         //txt_paste(text);
2148                                         txt_paste_clipboard(text);
2149                                         if (st->showsyntax) get_format_string(st);
2150                                         do_draw= 1;
2151                                         break;
2152                                 case 3:
2153                                         txt_print_cutbuffer();
2154                                         break;
2155                                 }
2156                         }
2157                         else if (G.qual == LR_CTRLKEY || G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
2158                                 txt_move_eol(text, G.qual & LR_SHIFTKEY);
2159                                 do_draw= 1;
2160                                 pop_space_text(st);
2161                         }
2162                         break; /* BREAK E */
2163                 case FKEY:
2164                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
2165                                 switch(pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3")) {
2166                                 case 0:
2167                                         st->text= add_empty_text("Text");
2168                                         st->top= 0;
2169                                         
2170                                         allqueue(REDRAWTEXT, 0);
2171                                         allqueue(REDRAWHEADERS, 0);
2172                                         break;
2173                                 case 1:
2174                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
2175                                         break;
2176                                 case 3:
2177                                         text->flags |= TXT_ISMEM;
2178                                 case 2:
2179                                         txt_write_file(text);
2180                                         do_draw= 1;
2181                                         break;
2182                                 }
2183                         }
2184                         else if (G.qual == LR_ALTKEY) {
2185                                 txt_find_panel(st, 0, last_txt_find_flags & ~TXT_FIND_REPLACE);
2186                                 do_draw= 1;
2187                         }
2188                         else if (G.qual == (LR_ALTKEY|LR_CTRLKEY)) {
2189                                 txt_find_panel(st, 1, last_txt_find_flags & ~TXT_FIND_REPLACE);
2190                                 do_draw= 1;
2191                         }
2192                         break; /* BREAK F */
2193                 case HKEY:
2194                         if (G.qual == LR_ALTKEY) {
2195                                 txt_find_panel(st, 0, last_txt_find_flags | TXT_FIND_REPLACE);
2196                                 do_draw= 1;
2197                         }
2198                         else if (G.qual == (LR_ALTKEY|LR_CTRLKEY)) {
2199                                 txt_find_panel(st, 1, last_txt_find_flags | TXT_FIND_REPLACE);
2200                                 do_draw= 1;
2201                         }
2202                         break; /* BREAK F */
2203                 case JKEY:
2204                         if (G.qual == LR_ALTKEY) {
2205                                 do_draw= jumptoline_interactive(st);
2206                         }
2207                         break; /* BREAK J */
2208                 case MKEY:
2209                         if (G.qual == LR_ALTKEY) {
2210                                 txt_export_to_object(text);
2211                                 do_draw= 1;     
2212                         }
2213                         break; /* BREAK M */
2214                 case NKEY:
2215                         if (G.qual == LR_ALTKEY) {
2216                                 st->text= add_empty_text("Text");
2217                                 st->top= 0;
2218                         
2219                                 allqueue(REDRAWTEXT, 0);
2220                                 allqueue(REDRAWHEADERS, 0);
2221
2222                         }
2223                         break; /* BREAK N */
2224                 case OKEY:
2225                         if (G.qual == LR_ALTKEY) {
2226                                 activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
2227                         }
2228                         break; /* BREAK O */
2229                 case PKEY:
2230                         if (G.qual == LR_ALTKEY) {
2231                                 run_python_script(st);
2232                                 do_draw= 1;
2233                         }
2234                         break; /* BREAK P */
2235                 case QKEY:
2236                         if(okee("Quit Blender")) exit_usiblender();
2237                         break; /* BREAK Q */
2238                 case RKEY:
2239                         if (G.qual == LR_ALTKEY) {
2240                             if (text->compiled) BPY_free_compiled_text(text);
2241                                 text->compiled = NULL;
2242                                 if (okee("Reopen text")) {
2243                                         if (!reopen_text(text))
2244                                                 error("Could not reopen file");
2245                                 if (st->showsyntax) get_format_string(st);
2246                                 }
2247                                 do_draw= 1;     
2248                         }
2249                         break; /* BREAK R */
2250                 case SKEY:
2251                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
2252                                 p= pupmenu("Select %t|"
2253                                                         "Select All %x0|"
2254                                                         "Select Line %x1|"
2255                                                         "Jump to Line %x3");
2256                                 switch(p) {
2257                                 case 0:
2258                                         txt_sel_all(text);
2259                                         do_draw= 1;
2260                                         break;
2261                                         
2262                                 case 1:
2263                                         txt_sel_line(text);
2264                                         do_draw= 1;
2265                                         break;
2266                                                                                 
2267                                 case 3:
2268                                         do_draw= jumptoline_interactive(st);
2269                                         break;
2270                                 }
2271                         }
2272                         else if (G.qual & LR_ALTKEY) {
2273                                 /* Event treatment CANNOT enter this if
2274                                 if (G.qual & LR_SHIFTKEY) 
2275                                         if (text) text->flags |= TXT_ISMEM;
2276                                 */
2277                                 txt_write_file(text);
2278                                 do_draw= 1;
2279                         }
2280                         break; /* BREAK S */
2281                 case UKEY:
2282                         txt_print_undo(text); //debug buffer in console
2283                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
2284                                 txt_do_redo(text);
2285                                 do_draw= 1;
2286                         }
2287                         if (G.qual == LR_ALTKEY) {
2288                                 txt_do_undo(text);
2289                                 if (st->showsyntax) get_format_string(st);
2290                                 do_draw= 1;
2291                         }
2292                         break; /* BREAK U */
2293                 case VKEY:
2294                         if (G.qual == (LR_ALTKEY| LR_SHIFTKEY)) {
2295                                 switch(pupmenu("View %t|Top of File %x0|Bottom of File %x1|Page Up %x2|Page Down %x3")) {
2296                                 case 0:
2297                                         txt_move_bof(text, 0);
2298                                         do_draw= 1;
2299                                         pop_space_text(st);
2300                                         break;
2301                                 case 1:
2302                                         txt_move_eof(text, 0);
2303                                         do_draw= 1;
2304                                         pop_space_text(st);
2305                                         break;
2306                                 case 2:
2307                                         screen_skip(st, -st->viewlines);
2308                                         do_draw= 1;
2309                                         break;
2310                                 case 3:
2311                                         screen_skip(st, st->viewlines);
2312                                         do_draw= 1;
2313                                         break;
2314                                 }
2315                         }
2316                         /* Support for both Alt-V and Ctrl-V for Paste, for backward compatibility reasons */
2317                         else if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
2318                                 if (text && text->id.lib) {
2319                                         error_libdata();
2320                                         break;
2321                                 }
2322                                 /* Throwing in the Shift modifier Paste from the OS clipboard */
2323                                 if (G.qual & LR_SHIFTKEY)
2324                                         txt_paste_clipboard(text);
2325                                 else
2326                                         txt_paste_clipboard(text);
2327                                 if (st->showsyntax) get_format_string(st);
2328                                 do_draw= 1;     
2329                                 pop_space_text(st);
2330                         }
2331                         break; /* BREAK V */
2332                 case XKEY:
2333                         if (G.qual == LR_ALTKEY || G.qual == LR_CTRLKEY) {
2334                                 if (text && text->id.lib) {
2335                                         error_libdata();
2336                                         break;
2337                                 }
2338                                 txt_cut_sel(text);
2339                                 if (st->showsyntax) get_format_string(st);
2340                                 do_draw= 1;     
2341                                 pop_space_text(st);
2342                         }
2343                         break;
2344                 case ZKEY:
2345                         if (G.qual & (LR_ALTKEY|LR_CTRLKEY|LR_COMMANDKEY)) {
2346                                 if (G.qual & LR_SHIFTKEY) {
2347                                         txt_do_redo(text);
2348                                 } else {
2349                                         txt_do_undo(text);
2350                                 }
2351                                 if (st->showsyntax) get_format_string(st);
2352                                 do_draw= 1;
2353                         }
2354                         break;
2355                 case ESCKEY:
2356                         /* To allow ESC to close one tool at a time we remove all others from the cancel list */
2357                         if (tools & TOOL_DOCUMENT) {
2358                                 tools_cancel &= ~TOOL_SUGG_LIST;
2359                         }
2360                         break;
2361                 case TABKEY:
2362                         if (text && text->id.lib) {
2363                                 error_libdata();
2364                                 break;
2365                         }
2366                         if (G.qual & LR_SHIFTKEY) {
2367                                 if (txt_has_sel(text)) {
2368                                         txt_order_cursors(text);
2369                                         unindent(text);
2370                                         
2371                                 }
2372                         } else {
2373                                 if ( txt_has_sel(text)) {
2374                                         txt_order_cursors(text);
2375                                         indent(text);
2376                                 } else {
2377                                         txt_add_char(text, '\t');
2378                                 }
2379                         }
2380                         if (st->showsyntax) get_format_string(st);
2381                         pop_space_text(st);
2382                         do_draw= 1;
2383                         st->currtab_set = setcurr_tab(text);
2384                         break;
2385                 case RETKEY:
2386                         if (text && text->id.lib) {
2387                                 error_libdata();
2388                                 break;
2389                         }
2390                         if (tools & TOOL_SUGG_LIST) {
2391                                 confirm_suggestion(text, 0);
2392                                 if (st->showsyntax) get_format_string(st);
2393                                 break;
2394                         }
2395                         //double check tabs before splitting the line
2396                         st->currtab_set = setcurr_tab(text);
2397                         txt_split_curline(text);
2398                         {
2399                                 int a = 0;
2400                                 if (a < st->currtab_set)
2401                                 {
2402                                         while ( a < st->currtab_set) {
2403                                                 txt_add_char(text, '\t');
2404                                                 a++;
2405                                         }
2406                                 }
2407                         }
2408                         if (st->showsyntax) get_format_string(st);
2409                         do_draw= 1;
2410                         pop_space_text(st);
2411                         break;
2412                 case BACKSPACEKEY:
2413                         if (text && text->id.lib) {
2414                                 error_libdata();
2415                                 break;
2416                         }
2417                         if (G.qual & (LR_ALTKEY | LR_CTRLKEY)) {
2418                                 txt_backspace_word(text);
2419                                 tools_cancel |= TOOL_SUGG_LIST;
2420                         } else {
2421                                 /* Work out which char we are about to delete */
2422                                 if (text && text->curl && text->curc > 0) {
2423                                         char ch= text->curl->line[text->curc-1];
2424                                         if (!ispunct(ch) && !check_whitespace(ch)) {
2425                                                 tools_update |= TOOL_SUGG_LIST;
2426                                         }
2427                                 }
2428                                 txt_backspace_char(text);
2429                         }
2430                         set_tabs(text);
2431                         if (st->showsyntax) get_format_string(st);
2432                         do_draw= 1;
2433                         pop_space_text(st);
2434                         break;
2435                 case DELKEY:
2436                         if (text && text->id.lib) {
2437                                 error_libdata();
2438                                 break;
2439                         }
2440                         if (G.qual & (LR_ALTKEY | LR_CTRLKEY)) {
2441                                 txt_delete_word(text);
2442                         } else {
2443                                 txt_delete_char(text);
2444                         }
2445                         if (st->showsyntax) get_format_string(st);
2446                         do_draw= 1;
2447                         pop_space_text(st);
2448                         st->currtab_set = setcurr_tab(text);
2449                         break;
2450                 case INSERTKEY:
2451                         st->overwrite= !st->overwrite;
2452                         do_draw= 1;
2453                         tools_cancel = 0;
2454                         break;
2455                 case DOWNARROWKEY:
2456                         if (tools & TOOL_SUGG_LIST) {
2457                                 SuggItem *sel = texttool_suggest_selected();
2458                                 if (!sel) {
2459                                         texttool_suggest_select(texttool_suggest_first());
2460                                 } else if (sel!=texttool_suggest_last() && sel->next) {
2461                                         texttool_suggest_select(sel->next);
2462                                 }
2463                                 tools_cancel &= ~TOOL_SUGG_LIST;
2464                                 break;
2465                         }
2466                         txt_move_down(text, G.qual & LR_SHIFTKEY);
2467                         set_tabs(text);
2468                         do_draw= 1;
2469                         pop_space_text(st);
2470                         break;
2471                 case LEFTARROWKEY:
2472                         if (G.qual & LR_COMMANDKEY)
2473                                 txt_move_bol(text, G.qual & LR_SHIFTKEY);
2474                         else if (G.qual & LR_ALTKEY)
2475                                 txt_jump_left(text, G.qual & LR_SHIFTKEY);
2476                         else
2477                                 txt_move_left(text, G.qual & LR_SHIFTKEY);
2478                         set_tabs(text);
2479                         do_draw= 1;
2480                         pop_space_text(st);
2481                         break;
2482                 case RIGHTARROWKEY:
2483                         if (G.qual & LR_COMMANDKEY)
2484                                 txt_move_eol(text, G.qual & LR_SHIFTKEY);
2485                         else if (G.qual & LR_ALTKEY)
2486                                 txt_jump_right(text, G.qual & LR_SHIFTKEY);
2487                         else
2488                                 txt_move_right(text, G.qual & LR_SHIFTKEY);
2489                         set_tabs(text);
2490                         do_draw= 1;
2491                         pop_space_text(st);
2492                         break;
2493                 case UPARROWKEY:
2494                         if (tools & TOOL_SUGG_LIST) {
2495                                 SuggItem *sel = texttool_suggest_selected();
2496                                 if (sel && sel!=texttool_suggest_first() && sel->prev)
2497                                         texttool_suggest_select(sel->prev);
2498                                 tools_cancel &= ~TOOL_SUGG_LIST;
2499                                 break;
2500                         }
2501                         txt_move_up(text, G.qual & LR_SHIFTKEY);
2502                         set_tabs(text);
2503                         do_draw= 1;
2504                         pop_space_text(st);
2505                         break;
2506                 case PAGEDOWNKEY:
2507                         if (tools & TOOL_SUGG_LIST) {
2508                                 int i;
2509                                 SuggItem *sel = texttool_suggest_selected();
2510                                 if (!sel)
2511                                         sel = texttool_suggest_first();
2512                                 for (i=0; i<SUGG_LIST_SIZE-1 && sel && sel!=texttool_suggest_last() && sel->next; i++, sel=sel->next)
2513                                         texttool_suggest_select(sel->next);
2514                                 tools_cancel &= ~TOOL_SUGG_LIST;
2515                                 break;
2516                         } else {
2517                                 screen_skip(st, st->viewlines);
2518                         }
2519                         do_draw= 1;
2520                         break;
2521                 case PAGEUPKEY:
2522                         if (tools & TOOL_SUGG_LIST) {
2523                                 int i;
2524                                 SuggItem *sel = texttool_suggest_selected();
2525                                 for (i=0; i<SUGG_LIST_SIZE-1 && sel && sel!=texttool_suggest_first() && sel->prev; i++, sel=sel->prev)
2526                                         texttool_suggest_select(sel->prev);
2527                                 tools_cancel &= ~TOOL_SUGG_LIST;
2528                                 break;
2529                         } else {
2530                                 screen_skip(st, -st->viewlines);
2531                         }
2532                         do_draw= 1;
2533                         break;
2534                 case HOMEKEY:
2535                         txt_move_bol(text, G.qual & LR_SHIFTKEY);
2536                         do_draw= 1;
2537                         pop_space_text(st);
2538                         break;
2539                 case ENDKEY:
2540                         txt_move_eol(text, G.qual & LR_SHIFTKEY);
2541                         do_draw= 1;
2542                         pop_space_text(st);
2543                         break;
2544                 case WHEELUPMOUSE:
2545                         if (tools & TOOL_SUGG_LIST) {
2546                                 SuggItem *sel = texttool_suggest_selected();
2547                                 if (sel && sel!=texttool_suggest_first() && sel->prev)
2548                                         texttool_suggest_select(sel->prev);
2549                                 tools_cancel &= ~TOOL_SUGG_LIST;
2550                         } else {
2551                                 screen_skip(st, -U.wheellinescroll);
2552                                 tools_cancel &= ~TOOL_DOCUMENT;
2553                         }
2554                         do_draw= 1;
2555                         break;
2556                 case WHEELDOWNMOUSE:
2557                         if (tools & TOOL_SUGG_LIST) {
2558                                 SuggItem *sel = texttool_suggest_selected();
2559                                 if (!sel) {
2560                                         texttool_suggest_select(texttool_suggest_first());
2561                                 } else if (sel && sel!=texttool_suggest_last() && sel->next) {
2562                                         texttool_suggest_select(sel->next);
2563                                 }
2564                                 tools_cancel &= ~TOOL_SUGG_LIST;
2565                         } else {
2566                                 screen_skip(st, U.wheellinescroll);
2567                                 tools_cancel &= ~TOOL_DOCUMENT;
2568                         }
2569                         do_draw= 1;
2570                         break;
2571                 default:
2572                         /* We don't want all sorts of events closing the suggestions box */
2573                         tools_cancel &= ~TOOL_SUGG_LIST & ~TOOL_DOCUMENT;
2574                 }
2575         }
2576
2577         if (event && val) {
2578                 if (BPY_menu_do_shortcut(PYMENU_TEXTPLUGIN, event, G.qual)) {
2579                         do_draw= 1;
2580                 }
2581         }
2582
2583         if (last_check_time < PIL_check_seconds_timer() - 1.0) {
2584                 switch (txt_file_modified(text)) {
2585                 case 1:
2586                         /* Modified locally and externally, ahhh. Offer more possibilites. */
2587                         if (text->flags & TXT_ISDIRTY) {
2588                                 switch (pupmenu("External File Modified with Local Changes %t|Load external changes (overwrite local) %x0|Save local changes (overwrite external) %x1|Make text internal %x2")) {
2589                                 case 0:
2590                                         reopen_text(text);
2591                                         if (st->showsyntax) get_format_string(st);
2592                                         do_draw= 1;
2593                                         break;
2594                                 case 1:
2595                                         txt_write_file(text);
2596                                         do_draw= 1;
2597                                         break;
2598                                 case 2:
2599                                         text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
2600                                         MEM_freeN(text->name);
2601                                         text->name= NULL;
2602                                         do_draw= 1;
2603                                         break;
2604                                 }
2605                         } else {
2606                                 switch (pupmenu("External File Modified %t|Reload from disk %x0|Make text internal %x1")) {
2607                                 case 0:
2608                                         reopen_text(text);
2609                                         if (st->showsyntax) get_format_string(st);
2610                                         do_draw= 1;
2611                                         break;
2612                                 case 1:
2613                                         text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
2614                                         MEM_freeN(text->name);
2615                                         text->name= NULL;
2616                                         do_draw= 1;
2617                                         break;
2618                                 }
2619                         }
2620                         break;
2621                 case 2:
2622                         switch (pupmenu("External File Deleted %t|Make text internal %x0")) {
2623                         case 0:
2624                                 text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
2625                                 MEM_freeN(text->name);
2626                                 text->name= NULL;
2627                                 do_draw= 1;
2628                                 break;
2629                         }
2630                         break;
2631                 default:
2632                         last_check_time = PIL_check_seconds_timer();
2633                 }
2634         }
2635
2636         if (tools & TOOL_SUGG_LIST) {
2637                 if (tools_update & TOOL_SUGG_LIST) {
2638                         get_suggest_prefix(text);
2639                 } else if (tools_cancel & TOOL_SUGG_LIST) {
2640                         texttool_suggest_clear();
2641                 }
2642                 do_draw= 1;
2643         }
2644         if (tools & TOOL_DOCUMENT) {
2645                 if (tools_cancel & TOOL_DOCUMENT) {
2646                         texttool_docs_clear();
2647                 }
2648                 do_draw= 1;
2649         }
2650
2651         if (do_draw) {
2652                 ScrArea *sa;
2653                 
2654                 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
2655                         SpaceText *st= sa->spacedata.first;
2656                         
2657                         if (st && st->spacetype==SPACE_TEXT) {
2658                                 scrarea_queue_redraw(sa);
2659                         }
2660                 }
2661         }
2662 }
2663
2664 void do_brackets(void) 
2665 {
2666         SpaceText *st = curarea->spacedata.first;
2667         Text *text = st->text;
2668         TextLine *tmp, *start;
2669         char test[2];
2670         int d, pos, open, x, y, x2, y2, h=0;
2671         
2672         if(!text) return;
2673         
2674         tmp = text->curl;
2675         start = text->curl;
2676
2677         test[0] = (unsigned char) tmp->line[text->curc];
2678         test[1] = '\0';
2679         
2680         d = check_bracket(test);
2681         if (!d) /*  If not pri char */
2682         {
2683                 test[0] = (unsigned char) tmp->line[text->curc-1];
2684                 test[1] = '\0';
2685                 d = check_bracket(test);
2686                 if(!d) {
2687                         return; /*If the current char or prev is not a bracket then return*/
2688                 } else { /* current char */
2689                         h= txt_get_span(text->lines.first, start) - st->top;
2690                         x = text_draw(st, start->line, st->left, text->curc-1, 0, 0, 0, NULL);
2691                         y = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
2692                         if (d < 4) {
2693                                 pos = text->curc;
2694                         } else {
2695                                 pos = text->curc-2;
2696                         }
2697                 }
2698         } else { /* is pri char */
2699                 h= txt_get_span(text->lines.first, start) - st->top;
2700                 x = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
2701                 y = text_draw(st, start->line, st->left, text->curc+1, 0, 0, 0, NULL);
2702                 if (d < 4) {
2703                         pos = text->curc+1;
2704                 } else {
2705                         pos = text->curc-1;
2706                 }
2707         }
2708         
2709         if (d < 4) /*reading forward*/
2710         {
2711                 open = 1; 
2712                 while ( tmp ) {
2713                         while (pos <= tmp->len) {
2714                                 test[0] = (unsigned char) tmp->line[pos];
2715                                 test[1] = '\0';
2716                                 if(check_bracket(test) == d) {
2717                                         open++;
2718                                 } else if (check_bracket(test) == d+3) {
2719                                         open--;
2720                                         if (open == 0) {
2721                                                 BIF_ThemeColorBlend(TH_BACK, TH_SHADE2, 0.5);
2722                                                 glRecti(x, curarea->winy-st->lheight*(h)-2, y, curarea->winy-st->lheight*(h+1)-2);
2723
2724                                                 h= txt_get_span(text->lines.first, tmp) - st->top;