Added Copy and Paste functions to GHOST.
[blender-staging.git] / source / blender / src / drawtext.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <math.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifndef _WIN32
43 #include <unistd.h>
44 #else
45 #include <io.h>
46 #include "BLI_winstuff.h"
47 #endif   
48 #include "MEM_guardedalloc.h"
49 #include "PIL_time.h"
50
51 #include "BMF_Api.h"
52
53 #include "BLI_blenlib.h"
54 #include "BLI_arithb.h"
55
56 #include "DNA_text_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_userdef_types.h"
60
61 #include "BKE_utildefines.h"
62 #include "BKE_text.h"
63 #include "BKE_global.h"
64 #include "BKE_main.h"
65 #include "BKE_node.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
85 #include "mydevice.h"
86 #include "blendef.h" 
87
88 #include "GHOST_C-api.h"
89
90 #define TEXTXLOC        38
91
92 /* forward declarations */
93
94 void drawtextspace(ScrArea *sa, void *spacedata);
95 void winqreadtextspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
96 void txt_copy_selectbuffer (Text *text);
97 void do_brackets();
98
99 void get_selection_buffer(Text *text);
100 int check_bracket(char *string);
101 static int check_delim(char *string);
102 static int check_numbers(char *string);
103 static int check_builtinfuncs(char *string);
104 static int check_specialvars(char *string);
105
106 static void *last_txt_find_string= NULL;
107
108 static BMF_Font *spacetext_get_font(SpaceText *st) {
109         static BMF_Font *scr12= NULL;
110         static BMF_Font *scr15= NULL;
111         
112         switch (st->font_id) {
113         default:
114         case 0:
115                 if (!scr12)
116                         scr12= BMF_GetFont(BMF_kScreen12);
117                 return scr12;
118         case 1:
119                 if (!scr15)
120                         scr15= BMF_GetFont(BMF_kScreen15);
121                 return scr15;
122         }
123 }
124
125 static int spacetext_get_fontwidth(SpaceText *st) {
126         return BMF_GetCharacterWidth(spacetext_get_font(st), ' ');
127 }
128
129 static char *temp_char_buf= NULL;
130 static int *temp_char_accum= NULL;
131 static int temp_char_len= 0;
132 static int temp_char_pos= 0;
133
134 static void temp_char_write(char c, int accum) {
135         if (temp_char_len==0 || temp_char_pos>=temp_char_len) {
136                 char *nbuf; int *naccum;
137                 int olen= temp_char_len;
138                 
139                 if (olen) temp_char_len*= 2;
140                 else temp_char_len= 256;
141                 
142                 nbuf= MEM_mallocN(sizeof(*temp_char_buf)*temp_char_len, "temp_char_buf");
143                 naccum= MEM_mallocN(sizeof(*temp_char_accum)*temp_char_len, "temp_char_accum");
144                 
145                 if (olen) {
146                         memcpy(nbuf, temp_char_buf, olen);
147                         memcpy(naccum, temp_char_accum, olen);
148                         
149                         MEM_freeN(temp_char_buf);
150                         MEM_freeN(temp_char_accum);
151                 }
152                 
153                 temp_char_buf= nbuf;
154                 temp_char_accum= naccum;
155         }
156         
157         temp_char_buf[temp_char_pos]= c;        
158         temp_char_accum[temp_char_pos]= accum;
159         
160         if (c==0) temp_char_pos= 0;
161         else temp_char_pos++;
162 }
163
164 void free_txt_data(void) {
165         txt_free_cut_buffer();
166         
167         if (last_txt_find_string) MEM_freeN(last_txt_find_string);
168         if (temp_char_buf) MEM_freeN(temp_char_buf);
169         if (temp_char_accum) MEM_freeN(temp_char_accum);        
170 }
171
172 static int render_string (SpaceText *st, char *in) {
173         int r = 0, i = 0;
174         
175         while(*in) {
176                 if (*in=='\t') {
177                         if (temp_char_pos && *(in-1)=='\t') i= st->tabnumber;
178                         else if (st->tabnumber > 0) i= st->tabnumber - (temp_char_pos%st->tabnumber);
179                         while(i--) temp_char_write(' ', r);
180                 } else temp_char_write(*in, r);
181
182                 r++;
183                 in++;
184         }
185         r= temp_char_pos;
186         temp_char_write(0, 0);
187                 
188         return r;
189 }
190
191 void get_format_string(SpaceText *st) 
192 {
193         Text *text = st->text;
194         TextLine *tmp;
195         char *in_line;
196         char format[2000], check[200], other[2];
197         unsigned char c;
198         int a, b, len, spot, letter, tabs, mem_amount;
199         
200         if(!text) return;
201         tmp = text->lines.first;
202         
203         while(tmp) {
204                 in_line = tmp->line;
205                 
206                 len = strlen(in_line);
207                 /* weak code... but we dont want crashes (ton) */
208                 if(len>2000-1) {
209                         if (tmp->format) MEM_freeN(tmp->format);
210                         tmp->format= NULL;
211                 }
212                 else {
213                         
214                         spot = 0;
215                         tabs = 0;
216                         //see how many tabs we have
217                         for(a = 0; a <len; a++) {
218                                 c = (unsigned char) in_line[a];
219                                 if(c == '\t') {
220                                         tabs++;
221                                 }
222                         }
223                         //calculate the amount of MEM_mallocN we neen
224                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len; // +2 for good measure
225                         if (tmp->format) MEM_freeN(tmp->format);
226                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
227                         
228                         for (a = 0; a < len; a++) {
229                                 c = (unsigned char) in_line[a];
230
231                                 check[0] = c;
232                                 check[1] = '\0';
233
234                                 if (check_delim(check))
235                                 {
236                                         switch (c) {
237                                                 case '\"':
238                                                         if(in_line[a] == '\"' && in_line[a+1] == '\"' && in_line[a+2] == '\"') { 
239                                                                 format[spot] = format[spot+1] = format[spot+2] = 'l';
240                                                                 spot +=3;
241                                                                 a += 3;
242                                                                 while(in_line[a] != '\"' || in_line[a-1] != '\"' || in_line[a-2] != '\"') {
243                                                                         c = (unsigned char) in_line[a];
244                                                                         if(a >= len) {
245                                                                                 format[spot] = '\0';
246                                                                                 memcpy(tmp->format, format, strlen(format));
247                                                                                 if(!(tmp= tmp->next)) {
248                                                                                         return;
249                                                                                 } else {
250                                                                                         in_line = tmp->line;
251                                                                                         len = strlen(in_line);
252                                                                                         tabs = 0;
253                                                                                         for(b = 0; b <len; b++) {
254                                                                                                 c = (unsigned char) in_line[b];
255                                                                                                 if(c == '\t') {
256                                                                                                         tabs++;
257                                                                                                 }
258                                                                                         }
259                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
260                                                                                         if (tmp->format) MEM_freeN(tmp->format);
261                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
262                                                                                         a = 0; spot = 0;
263                                                                                 }
264                                                                         } else {
265                                                                                 if(c == '\t' || c == ' ') {
266                                                                                         if(c == '\t') {
267                                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
268                                                                                                         format[spot] = ' ';
269                                                                                                         spot++;
270                                                                                                 }
271                                                                                                 a++;
272                                                                                         } else {
273                                                                                                 format[spot] = ' ';
274                                                                                                 a++; spot++;
275                                                                                 }
276                                                                                 } else {
277                                                                                         format[spot] = 'l';
278                                                                                         a++; spot++;
279                                                                                 }
280                                                                         }
281                                                                 }
282                                                                 format[spot] = 'l';
283                                                                 spot++;
284                                                         } else {
285                                                                 format[spot] = 'l';
286                                                                 a++; spot++;
287                                                                 while(in_line[a] != '\"') {
288                                                                         c = (unsigned char) in_line[a];
289                                                                         if(a >= len) {
290                                                                                 format[spot] = '\0';
291                                                                                 memcpy(tmp->format, format, strlen(format));
292                                                                                 if(!(tmp= tmp->next)) {
293                                                                                         return;
294                                                                                 } else {
295                                                                                         in_line = tmp->line;
296                                                                                         len = strlen(in_line);
297                                                                                         for(b = 0; b <len; b++) {
298                                                                                                 c = (unsigned char) in_line[b];
299                                                                                                 if(c == '\t') {
300                                                                                                         tabs++;
301                                                                                                 }
302                                                                                         }
303                                                                                         //calculate the amount of MEM_mallocN we neen
304                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
305                                                                                         if (tmp->format) MEM_freeN(tmp->format);
306                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
307                                                                                         a = 0; spot = 0;
308                                                                                 }
309                                                                         }
310                                                                         if(c == '\t' || c == ' ') {
311                                                                                 if(c == '\t') {
312                                                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
313                                                                                                 format[spot] = ' ';
314                                                                                                 spot++;
315                                                                                         }
316                                                                                         a++;
317                                                                                 } else {
318                                                                                         format[spot] = ' ';
319                                                                                         a++; spot++;
320                                                                                 }
321                                                                         } else {
322                                                                                 format[spot] = 'l';
323                                                                                 a++; spot++;
324                                                                         }
325                                                                 }
326                                                                 format[spot] = 'l';
327                                                                 spot++;
328                                                         }
329                                                         break;
330                                                 case '\'':
331                                                         if(in_line[a] == '\'' && in_line[a+1] == '\'' && in_line[a+2] == '\'') { 
332                                                                 format[spot] = format[spot+1] = format[spot+2] = 'l';
333                                                                 spot +=3;
334                                                                 a += 3;
335                                                                 while(in_line[a] != '\'' || in_line[a-1] != '\'' || in_line[a-2] != '\'') {
336                                                                         c = (unsigned char) in_line[a];
337                                                                         if(a >= len) {
338                                                                                 format[spot] = '\0';
339                                                                                 memcpy(tmp->format, format, strlen(format));
340                                                                                 if(!(tmp= tmp->next)) {
341                                                                                         return;
342                                                                                 } else {
343                                                                                         in_line = tmp->line;
344                                                                                         len = strlen(in_line);
345                                                                                         tabs = 0;
346                                                                                         for(b = 0; b <len; b++) {
347                                                                                                 c = (unsigned char) in_line[b];
348                                                                                                 if(c == '\t') {
349                                                                                                         tabs++;
350                                                                                                 }
351                                                                                         }
352                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
353                                                                                         if (tmp->format) MEM_freeN(tmp->format);
354                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
355                                                                                         a = 0; spot = 0;
356                                                                                 }
357                                                                         } else {
358                                                                                 if(c == '\t' || c == ' ') {
359                                                                                         if(c == '\t') {
360                                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
361                                                                                                         format[spot] = ' ';
362                                                                                                         spot++;
363                                                                                                 }
364                                                                                                 a++;
365                                                                                         } else {
366                                                                                                 format[spot] = ' ';
367                                                                                                 a++; spot++;
368                                                                                         }
369                                                                                 } else {
370                                                                                         format[spot] = 'l';
371                                                                                         a++; spot++;
372                                                                                 }
373                                                                         }
374                                                                 }
375                                                                 format[spot] = 'l';
376                                                                 spot++;
377                                                         } else {
378                                                                 format[spot] = 'l';
379                                                                 a++; spot++;
380                                                                 while(in_line[a] != '\'') {
381                                                                         c = (unsigned char) in_line[a];
382                                                                         if(a >= len) {
383                                                                                 format[spot] = '\0';
384                                                                                 memcpy(tmp->format, format, strlen(format));
385                                                                                 if(!(tmp= tmp->next)) {
386                                                                                         return;
387                                                                                 } else {
388                                                                                         in_line = tmp->line;
389                                                                                         len = strlen(in_line);
390                                                                                         for(b = 0; b <len; b++) {
391                                                                                                 c = (unsigned char) in_line[b];
392                                                                                                 if(c == '\t') {
393                                                                                                         tabs++;
394                                                                                                 }
395                                                                                         }
396                                                                                         //calculate the amount of MEM_mallocN we neen
397                                                                                         mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
398                                                                                         if (tmp->format) MEM_freeN(tmp->format);
399                                                                                         tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
400                                                                                         a = 0; spot = 0;
401                                                                                 }
402                                                                         }
403                                                                         if(c == '\t' || c == ' ') {
404                                                                                 if(c == '\t') {
405                                                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
406                                                                                                 format[spot] = ' ';
407                                                                                                 spot++;
408                                                                                         }
409                                                                                         a++;
410                                                                                 } else {
411                                                                                         format[spot] = ' ';
412                                                                                         a++; spot++;
413                                                                                 }
414                                                                         } else {
415                                                                                 format[spot] = 'l';
416                                                                                 a++; spot++;
417                                                                         }
418                                                                 }
419                                                                 format[spot] = 'l';
420                                                                 spot++;
421                                                         }
422                                                         break;
423                                                 case '#':
424                                                         while(a<len) {
425                                                                 c = (unsigned char) in_line[a];
426                                                                 if(c == '\t' || c == ' ') {
427                                                                         if(c == '\t') {
428                                                                                 for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
429                                                                                         format[spot] = '#';
430                                                                                         spot++;
431                                                                                 }
432                                                                                 a++;
433                                                                         } else {
434                                                                                 format[spot] = '#';
435                                                                                 a++; spot++;
436                                                                         }
437                                                                 } else {
438                                                                         format[spot] = '#';
439                                                                         a++; spot++;
440                                                                 }
441                                                         }
442                                                         break;
443                                                 case ' ':
444                                                         format[spot] = ' ';
445                                                         spot++;
446                                                         break;
447                                                 case '\t':
448                                                         for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
449                                                                 format[spot] = ' ';
450                                                                 spot++;
451                                                         }
452                                                         break;
453                                                 default:
454                                                         format[spot] = 'q';
455                                                         spot++;
456                                                          
457                                                         break;
458                                         }
459                                 } else if (check_numbers(check)) {
460                                         while (a < len) {
461                                                 c = (unsigned char) in_line[a];
462                                                 other[0] = c;
463                                                 other[1] = '\0';
464                                                 if (check_delim(other) && c != '.') {
465                                                         a--; break;
466                                                 } else {
467                                                         format[spot] = 'n';
468                                                         a++; spot++;
469                                                 }
470                                         }
471                                 } else {
472                                         letter = 0;
473                                         while (a < len) {
474                                                 c = (unsigned char) in_line[a];
475                                                 other[0] = c;
476                                                 other[1] = '\0';
477                                                 if (check_delim(other)) {
478                                                         a--; 
479                                                         break;
480                                                 } else {
481                                                         check[letter] = (unsigned char) in_line[a];
482                                                         letter++; 
483                                                         a++;
484                                                 }
485                                         }
486                                         check[letter] = '\0';
487                                         if (check_builtinfuncs(check)) {
488                                                 for (b = 0; b < strlen(check); b++) {
489                                                         format[spot] = 'b'; 
490                                                         spot++;
491                                                 }
492                                         } else if (check_specialvars(check)) { /*If TRUE then color and color next word*/
493                                                 for (b = 0; b < strlen(check); b++) {
494                                                         format[spot] = 'b';
495                                                         spot++;
496                                                 }
497                                                 a++;
498                                                 format[spot] = 'q';
499                                                 spot++; a++;
500                                                 letter = 0;
501                                                 while (a < len) {
502                                                         c = (unsigned char) in_line[a];
503                                                         other[0] = c;
504                                                         other[1] = '\0';
505                                                         if (check_delim(other)) {
506                                                                 a--; 
507                                                                 break;
508                                                         } else {
509                                                                 check[letter] = (unsigned char) in_line[a];
510                                                                 letter++; 
511                                                                 a++;
512                                                         }
513                                                 }
514                                                 check[letter] = '\0';
515                                                 for (b = 0; b < strlen(check); b++) {
516                                                         format[spot] = 'v';
517                                                         spot++;
518                                                 }
519                                         }else {
520                                                 for (b = 0; b < strlen(check); b++) {
521                                                         format[spot] = 'q';
522                                                         spot++;
523                                                 }
524                                         }
525                                 }
526                         }
527                         format[spot] = '\0';
528                         memcpy(tmp->format, format, strlen(format));
529                 }
530                 
531                 tmp = tmp->next;
532         }
533 }
534
535 static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, char *format) {
536         int r=0, w= 0;
537         char *in;
538         int *acc;
539
540         w= render_string(st, str);
541         if(w<cshift ) return 0; /* String is shorter than shift */
542         
543         in= temp_char_buf+cshift;
544         acc= temp_char_accum+cshift;
545         w= w-cshift;
546
547         if (draw) {
548                 if(st->showsyntax && format) {
549                         int amount, a;
550                         char out[2];
551                         format = format+cshift;
552                 
553                         amount = strlen(in);
554                         
555                         for(a = 0; a < amount; a++) {
556                                 out[0] = (unsigned char) in[a]; 
557                                 out[1] = '\0';
558                                 switch (format[a]) {
559                                         case 'l':
560                                                 BIF_ThemeColor(TH_SYNTAX_L);
561                                                 break;
562                                         case 'b':
563                                                 BIF_ThemeColor(TH_SYNTAX_B);
564                                                 break;
565                                         case '#':
566                                                 BIF_ThemeColor(TH_SYNTAX_C);
567                                                 break;
568                                         case 'v': 
569                                                 BIF_ThemeColor(TH_SYNTAX_V);
570                                                 break;
571                                         case 'n':
572                                                 BIF_ThemeColor(TH_SYNTAX_N);
573                                                 break;
574                                         case 'q':
575                                                 BIF_ThemeColor(TH_TEXT);
576                                                 break;
577                                         default:
578                                                 BIF_ThemeColor(TH_TEXT);
579                                                 break;
580                                 }
581                                 glRasterPos2i(x, y);
582                                 BMF_DrawString(spacetext_get_font(st), out);
583                                 x = x+BMF_GetStringWidth(spacetext_get_font(st), out);
584                         }
585                 } else {
586                         glRasterPos2i(x, y);
587                         BMF_DrawString(spacetext_get_font(st), in);
588                 }
589         } else {
590                 while (w-- && *acc++ < maxwidth) {
591                         r+= spacetext_get_fontwidth(st);
592                 }
593         }
594
595         if (cshift && r==0) return 0;
596         else if (st->showlinenrs)
597                 return r+TXT_OFFSET+TEXTXLOC;
598         else
599                 return r+TXT_OFFSET;
600 }
601
602 static void set_cursor_to_pos (SpaceText *st, int x, int y, int sel) 
603 {
604         Text *text;
605         TextLine **linep;
606         int *charp;
607         int w;
608         
609         text= st->text;
610
611         if(sel) { linep= &text->sell; charp= &text->selc; } 
612         else { linep= &text->curl; charp= &text->curc; }
613         
614         y= (curarea->winy - y)/st->lheight;
615         
616         y-= txt_get_span(text->lines.first, *linep) - st->top;
617         
618         if (y>0) {
619                 while (y-- != 0) if((*linep)->next) *linep= (*linep)->next;
620         } else if (y<0) {
621                 while (y++ != 0) if((*linep)->prev) *linep= (*linep)->prev;
622         }
623
624         if(st->showlinenrs)
625                 x-= TXT_OFFSET+TEXTXLOC;
626         else
627                 x-= TXT_OFFSET;
628
629         if (x<0) x= 0;
630         x = (x/spacetext_get_fontwidth(st)) + st->left;
631         
632         w= render_string(st, (*linep)->line);
633         if(x<w) *charp= temp_char_accum[x];
634         else *charp= (*linep)->len;
635         
636         if(!sel) txt_pop_sel(text);
637 }
638
639 static void draw_cursor(SpaceText *st) {
640         int h, x, i;
641         Text *text= st->text;
642         TextLine *linef, *linel;
643         int charf, charl;
644         
645         if (text->curl==text->sell && text->curc==text->selc) {
646                 x= text_draw(st, text->curl->line, st->left, text->curc, 0, 0, 0, NULL);
647
648                 if (x) {
649                         h= txt_get_span(text->lines.first, text->curl) - st->top;
650
651                         BIF_ThemeColor(TH_HILITE);
652                         
653                         glRecti(x-1, curarea->winy-st->lheight*(h)-2, x+1, curarea->winy-st->lheight*(h+1)-2);
654                 }
655         } else {
656                 int span= txt_get_span(text->curl, text->sell);
657                 
658                 if (span<0) {
659                         linef= text->sell;
660                         charf= text->selc;
661                         
662                         linel= text->curl;
663                         charl= text->curc;
664                 } else if (span>0) {
665                         linef= text->curl;
666                         charf= text->curc;
667         
668                         linel= text->sell;              
669                         charl= text->selc;
670                 } else {
671                         linef= linel= text->curl;
672                         
673                         if (text->curc<text->selc) {
674                                 charf= text->curc;
675                                 charl= text->selc;
676                         } else {
677                                 charf= text->selc;
678                                 charl= text->curc;
679                         }
680                 }
681         
682                         /* Walk to the beginning of visible text */
683                 h= txt_get_span(text->lines.first, linef) - st->top;
684                 while (h++<-1 && linef!=linel) linef= linef->next;
685         
686                 x= text_draw(st, linef->line, st->left, charf, 0, 0, 0, NULL);
687
688                 BIF_ThemeColor(TH_SHADE2);
689
690                 if(st->showlinenrs) {
691                         if (!x) x= TXT_OFFSET + TEXTXLOC -4;
692                 } else {
693                         if (!x) x= TXT_OFFSET - 4;
694                 }
695                 
696                 while (linef && linef != linel) {
697                         h= txt_get_span(text->lines.first, linef) - st->top;
698                         if (h>st->viewlines) break;
699                         
700                         glRecti(x, curarea->winy-st->lheight*(h)-2, curarea->winx, curarea->winy-st->lheight*(h+1)-2);
701                         if(st->showlinenrs)
702                                 glRecti(TXT_OFFSET+TEXTXLOC-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET+TEXTXLOC, curarea->winy-st->lheight*(h+2)-2);
703                         else
704                                 glRecti(TXT_OFFSET-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET, curarea->winy-st->lheight*(h+2)-2);
705
706                         if(st->showlinenrs)
707                                 x= TXT_OFFSET + TEXTXLOC;
708                         else
709                                 x= TXT_OFFSET;
710                         
711                         linef= linef->next;
712                 }
713                 
714                 h= txt_get_span(text->lines.first, linef) - st->top;
715
716                 i= text_draw(st, linel->line, st->left, charl, 0, 0, 0, NULL);
717                 if(i) glRecti(x, curarea->winy-st->lheight*(h)-2, i, curarea->winy-st->lheight*(h+1)-2);
718
719         }
720
721         do_brackets();
722         BIF_ThemeColor(TH_TEXT);
723 }
724
725 static void calc_text_rcts(SpaceText *st)
726 {
727         int lhlstart, lhlend, ltexth;
728         short barheight, barstart, hlstart, hlend, blank_lines;
729         short pix_available, pix_top_margin, pix_bottom_margin, pix_bardiff;
730
731         pix_top_margin = 8;
732         pix_bottom_margin = 4;
733         pix_available = curarea->winy - pix_top_margin - pix_bottom_margin;
734         ltexth= txt_get_span(st->text->lines.first, st->text->lines.last);
735         blank_lines = st->viewlines / 2;
736         
737         /* when resizing a vieport with the bar at the bottom to a greater height more blank lines will be added */
738         if (ltexth + blank_lines < st->top + st->viewlines) {
739                 blank_lines = st->top + st->viewlines - ltexth;
740         }
741         
742         ltexth += blank_lines;
743
744         barheight = (st->viewlines*pix_available) / ltexth;
745         pix_bardiff = 0;
746         if (barheight < 20) {
747                 pix_bardiff = 20 - barheight; /* take into account the now non-linear sizing of the bar */      
748                 barheight = 20;
749         }
750         barstart = ((pix_available - pix_bardiff) * st->top) / ltexth;
751
752         st->txtbar.xmin = 5;
753         st->txtbar.xmax = 17;
754         st->txtbar.ymax = curarea->winy - pix_top_margin - barstart;
755         st->txtbar.ymin = st->txtbar.ymax - barheight;
756
757         CLAMP(st->txtbar.ymin, pix_bottom_margin, curarea->winy - pix_top_margin);
758         CLAMP(st->txtbar.ymax, pix_bottom_margin, curarea->winy - pix_top_margin);
759
760         st->pix_per_line= (float) ltexth/pix_available;
761         if (st->pix_per_line<.1) st->pix_per_line=.1f;
762
763         lhlstart = MIN2(txt_get_span(st->text->lines.first, st->text->curl), 
764                                 txt_get_span(st->text->lines.first, st->text->sell));
765         lhlend = MAX2(txt_get_span(st->text->lines.first, st->text->curl), 
766                                 txt_get_span(st->text->lines.first, st->text->sell));
767
768         hlstart = (lhlstart * pix_available) / ltexth;
769         hlend = (lhlend * pix_available) / ltexth;
770
771         /* the scrollbar is non-linear sized */
772         if (pix_bardiff > 0) {
773                 /* the start of the highlight is in the current viewport */
774                 if (lhlstart >= st->top && lhlstart <= st->top + st->viewlines) { 
775                         /* speed the progresion of the start of the highlight through the scrollbar */
776                         hlstart = ( ( (pix_available - pix_bardiff) * lhlstart) / ltexth) + (pix_bardiff * (lhlstart - st->top) / st->viewlines);       
777                 }
778                 else if (lhlstart > st->top + st->viewlines && hlstart < barstart + barheight && hlstart > barstart) {
779                         /* push hl start down */
780                         hlstart = barstart + barheight;
781                 }
782                 else if (lhlend > st->top  && lhlstart < st->top && hlstart > barstart) {
783                         /*fill out start */
784                         hlstart = barstart;
785                 }
786
787                 if (hlend <= hlstart) { 
788                         hlend = hlstart + 2;
789                 }
790
791                 /* the end of the highlight is in the current viewport */
792                 if (lhlend >= st->top && lhlend <= st->top + st->viewlines) { 
793                         /* speed the progresion of the end of the highlight through the scrollbar */
794                         hlend = (((pix_available - pix_bardiff )*lhlend)/ltexth) + (pix_bardiff * (lhlend - st->top)/st->viewlines);    
795                 }
796                 else if (lhlend < st->top && hlend >= barstart - 2 && hlend < barstart + barheight) {
797                         /* push hl end up */
798                         hlend = barstart;
799                 }                                       
800                 else if (lhlend > st->top + st->viewlines && lhlstart < st->top + st->viewlines && hlend < barstart + barheight) {
801                         /* fill out end */
802                         hlend = barstart + barheight;
803                 }
804
805                 if (hlend <= hlstart) { 
806                         hlstart = hlend - 2;
807                 }       
808         }       
809
810         if (hlend - hlstart < 2) { 
811                 hlend = hlstart + 2;
812         }
813         
814         st->txtscroll.xmin= 5;
815         st->txtscroll.xmax= 17;
816         st->txtscroll.ymax= curarea->winy - pix_top_margin - hlstart;
817         st->txtscroll.ymin= curarea->winy - pix_top_margin - hlend;
818
819         CLAMP(st->txtscroll.ymin, pix_bottom_margin, curarea->winy - pix_top_margin);
820         CLAMP(st->txtscroll.ymax, pix_bottom_margin, curarea->winy - pix_top_margin);
821 }
822
823 static void draw_textscroll(SpaceText *st)
824 {
825         if (!st->text) return;
826
827         calc_text_rcts(st);
828         
829         BIF_ThemeColorShade(TH_SHADE1, -20);
830         glRecti(2, 2, 20, curarea->winy-6);
831         uiEmboss(2, 2, 20, curarea->winy-6, 1);
832
833         BIF_ThemeColor(TH_SHADE1);
834         glRecti(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax);
835
836         BIF_ThemeColor(TH_SHADE2);
837         glRecti(st->txtscroll.xmin, st->txtscroll.ymin, st->txtscroll.xmax, st->txtscroll.ymax);
838
839         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
840 }
841
842 static void screen_skip(SpaceText *st, int lines)
843 {
844         int last;
845         
846         if (!st) return;
847         if (st->spacetype != SPACE_TEXT) return;
848         if (!st->text) return;
849
850         st->top += lines;
851
852         last= txt_get_span(st->text->lines.first, st->text->lines.last);
853         last= last - (st->viewlines/2);
854         
855         if (st->top>last) st->top= last;
856         if (st->top<0) st->top= 0;
857 }
858
859 /* 
860  * mode 1 == view scroll
861  * mode 2 == scrollbar
862  */
863 static void do_textscroll(SpaceText *st, int mode)
864 {
865         short delta[2]= {0, 0};
866         short mval[2], hold[2], old[2];
867         
868         if (!st->text) return;
869         
870         calc_text_rcts(st);
871
872         st->flags|= ST_SCROLL_SELECT;
873
874         glDrawBuffer(GL_FRONT);
875         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
876         bglFlush();
877         glDrawBuffer(GL_BACK);
878
879         getmouseco_areawin(mval);
880         old[0]= hold[0]= mval[0];
881         old[1]= hold[1]= mval[1];
882
883         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
884                 getmouseco_areawin(mval);
885
886                 if(old[0]!=mval[0] || old[1]!=mval[1]) {
887                         if (mode==1) {
888                                 delta[0]= (hold[0]-mval[0])/spacetext_get_fontwidth(st);
889                                 delta[1]= (mval[1]-hold[1])/st->lheight;
890                         }
891                         else delta[1]= (hold[1]-mval[1])*st->pix_per_line;
892                         
893                         if (delta[0] || delta[1]) {
894                                 screen_skip(st, delta[1]);
895                                 st->left+= delta[0];
896                                 if (st->left<0) st->left= 0;
897                                 
898                                 scrarea_do_windraw(curarea);
899                                 screen_swapbuffers();
900                                 
901                                 hold[0]=mval[0];
902                                 hold[1]=mval[1];
903                         }
904                         old[0]=mval[0];
905                         old[1]=mval[1];
906                 } else {
907                         BIF_wait_for_statechange();
908                 }
909         }
910         st->flags^= ST_SCROLL_SELECT;
911
912         glDrawBuffer(GL_FRONT);
913         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
914         bglFlush();
915         glDrawBuffer(GL_BACK);
916 }
917
918 static void do_selection(SpaceText *st, int selecting)
919 {
920         short mval[2], old[2];
921         int sell, selc;
922         int linep2, charp2;
923         int first= 1;
924
925         getmouseco_areawin(mval);
926         old[0]= mval[0];
927         old[1]= mval[1];
928
929         if (!selecting) {
930                 int curl= txt_get_span(st->text->lines.first, st->text->curl);
931                 int curc= st->text->curc;                       
932                 int linep2, charp2;
933                                         
934                 set_cursor_to_pos(st, mval[0], mval[1], 0);
935
936                 linep2= txt_get_span(st->text->lines.first, st->text->curl);
937                 charp2= st->text->selc;
938                                 
939                 if (curl!=linep2 || curc!=charp2)
940                         txt_undo_add_toop(st->text, UNDO_CTO, curl, curc, linep2, charp2);
941         }
942
943         sell= txt_get_span(st->text->lines.first, st->text->sell);
944         selc= st->text->selc;
945
946         while(get_mbut()&L_MOUSE) {
947                 getmouseco_areawin(mval);
948
949                 if (mval[1]<0 || mval[1]>curarea->winy) {
950                         int d= (old[1]-mval[1])*st->pix_per_line;
951                         if (d) screen_skip(st, d);
952
953                         set_cursor_to_pos(st, mval[0], mval[1]<0?0:curarea->winy, 1);
954
955                         scrarea_do_windraw(curarea);
956                         screen_swapbuffers();
957                 } else if (mval[0]<0 || mval[0]>curarea->winx) {
958                         if (mval[0]>curarea->winx) st->left++;
959                         else if (mval[0]<0 && st->left>0) st->left--;
960                         
961                         set_cursor_to_pos(st, mval[0], mval[1], 1);
962                         
963                         scrarea_do_windraw(curarea);
964                         screen_swapbuffers();
965                         
966                         PIL_sleep_ms(10);
967                 } else if (first || old[0]!=mval[0] || old[1]!=mval[1]) {
968                         set_cursor_to_pos(st, mval[0], mval[1], 1);
969
970                         scrarea_do_windraw(curarea);
971                         screen_swapbuffers();
972
973                         old[0]= mval[0];
974                         old[1]= mval[1];
975                         first= 1;
976                 } else {
977                         BIF_wait_for_statechange();
978                 }
979         }
980
981         linep2= txt_get_span(st->text->lines.first, st->text->sell);
982         charp2= st->text->selc;
983                 
984         if (sell!=linep2 || selc!=charp2)
985                 txt_undo_add_toop(st->text, UNDO_STO, sell, selc, linep2, charp2);
986 }
987
988 void drawtextspace(ScrArea *sa, void *spacedata)
989 {
990         SpaceText *st= curarea->spacedata.first;
991         Text *text;
992         int i;
993         TextLine *tmp;
994         char linenr[12];
995         float col[3];
996         int linecount = 0;
997
998         if (st==NULL || st->spacetype != SPACE_TEXT) return;
999         
1000         BIF_GetThemeColor3fv(TH_BACK, col);
1001         glClearColor(col[0], col[1], col[2], 0.0);
1002         glClear(GL_COLOR_BUFFER_BIT);
1003         myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
1004
1005         draw_area_emboss(sa);
1006
1007         text= st->text;
1008         if(!text) return;
1009         
1010         /* Make sure all the positional pointers exist */
1011         if (!text->curl || !text->sell || !text->lines.first || !text->lines.last)
1012                 txt_clean_text(text);
1013         
1014         if(st->lheight) st->viewlines= (int) curarea->winy/st->lheight;
1015         else st->viewlines= 0;
1016         
1017         if(st->showlinenrs) {
1018                 cpack(0x8c787c);
1019                 glRecti(23,  0, (st->lheight==15)?63:59,  curarea->winy - 2);
1020         }
1021
1022         BIF_ThemeColor(TH_TEXT);
1023
1024         draw_cursor(st);
1025
1026         tmp= text->lines.first;
1027         for (i= 0; i<st->top && tmp; i++) {
1028                 tmp= tmp->next;
1029                 linecount++;
1030         }
1031         
1032         if(st->showsyntax) {
1033                 if (tmp && !tmp->format) {
1034                         get_format_string(st);
1035                 }
1036         }
1037         
1038         for (i=0; i<st->viewlines && tmp; i++, tmp= tmp->next) {
1039                 if(st->showlinenrs) {
1040                         BIF_ThemeColor(TH_TEXT);
1041                         if(((float)(i + linecount + 1)/10000.0) < 1.0) {
1042                                 sprintf(linenr, "%4d", i + linecount + 1);
1043                                 glRasterPos2i(TXT_OFFSET - 7, curarea->winy-st->lheight*(i+1));
1044                         } else {
1045                                 sprintf(linenr, "%5d", i + linecount + 1);
1046                                 glRasterPos2i(TXT_OFFSET - 11, curarea->winy-st->lheight*(i+1));
1047                         }
1048                         BMF_DrawString(spacetext_get_font(st), linenr);
1049                         text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET + TEXTXLOC, curarea->winy-st->lheight*(i+1), tmp->format);
1050                 } else
1051                         text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET, curarea->winy-st->lheight*(i+1), tmp->format);
1052         }
1053
1054         draw_textscroll(st);
1055
1056         curarea->win_swap= WIN_BACK_OK;
1057 }
1058
1059 /* Moves the view to the cursor location,
1060   also used to make sure the view isnt outside the file */
1061 void pop_space_text (SpaceText *st)
1062 {
1063         int i, x;
1064
1065         if(!st) return;
1066         if(!st->text) return;
1067         if(!st->text->curl) return;
1068                 
1069         i= txt_get_span(st->text->lines.first, st->text->curl);
1070         if (st->top+st->viewlines <= i || st->top > i) {
1071                 st->top= i - st->viewlines/2;
1072         }
1073         
1074         x= text_draw(st, st->text->curl->line, st->left, st->text->curc, 0, 0, 0, NULL);
1075
1076         if (x==0 || x>curarea->winx) {
1077                 st->left= st->text->curc-0.5*(curarea->winx)/spacetext_get_fontwidth(st);
1078         }
1079
1080         if (st->top < 0) st->top= 0;
1081         if (st->left <0) st->left= 0;
1082 }
1083
1084 void add_text_fs(char *file) /* bad but cant pass an as arg here */
1085 {
1086         SpaceText *st= curarea->spacedata.first;
1087         Text *text;
1088
1089         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1090
1091         text= add_text(file);
1092
1093         st->text= text;
1094
1095         st->top= 0;
1096
1097         if (st->showsyntax) get_format_string(st);
1098         allqueue(REDRAWTEXT, 0);
1099         allqueue(REDRAWHEADERS, 0);     
1100 }
1101
1102 void free_textspace(SpaceText *st)
1103 {
1104         if (!st) return;
1105
1106         st->text= NULL;
1107 }
1108
1109 static void save_mem_text(char *str)
1110 {
1111         SpaceText *st= curarea->spacedata.first;
1112         Text *text;
1113         
1114         if (!str) return;
1115         
1116         if (!st) return;
1117         if (st->spacetype != SPACE_TEXT) return;
1118
1119         text= st->text;
1120         if(!text) return;
1121         
1122         if (text->name) MEM_freeN(text->name);
1123         text->name= MEM_mallocN(strlen(str)+1, "textname");
1124         strcpy(text->name, str);
1125
1126         text->flags ^= TXT_ISMEM;
1127                 
1128         txt_write_file(text);
1129 }
1130
1131 void txt_write_file(Text *text) 
1132 {
1133         FILE *fp;
1134         TextLine *tmp;
1135         
1136         /* Do we need to get a filename? */
1137         if (text->flags & TXT_ISMEM) {
1138                 if (text->name)
1139                         activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->name, save_mem_text);
1140                 else
1141                         activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->id.name+2, save_mem_text);
1142                 return; 
1143         }
1144         
1145         /* Should we ask to save over? */
1146         if (text->flags & TXT_ISTMP) {
1147                 if (BLI_exists(text->name)) {
1148                         if (!okee("Save over")) return;
1149                 } else if (!okee("Create new file")) return;
1150
1151                 text->flags ^= TXT_ISTMP;
1152         }
1153                 
1154         fp= fopen(text->name, "w");
1155         if (fp==NULL) {
1156                 error("Unable to save file");
1157                 return;
1158         }
1159
1160         tmp= text->lines.first;
1161         while (tmp) {
1162                 if (tmp->next) fprintf(fp, "%s\n", tmp->line);
1163                 else fprintf(fp, "%s", tmp->line);
1164                 
1165                 tmp= tmp->next;
1166         }
1167         
1168         fclose (fp);
1169         
1170         if (text->flags & TXT_ISDIRTY) text->flags ^= TXT_ISDIRTY;
1171 }
1172
1173 void unlink_text(Text *text)
1174 {
1175         bScreen *scr;
1176         ScrArea *area;
1177         SpaceLink *sl;
1178         
1179         /* check if this text was used as script link:
1180          * this check function unsets the pointers and returns how many
1181          * script links used this Text */
1182         if (BPY_check_all_scriptlinks (text)) {
1183                 allqueue(REDRAWBUTSSCRIPT, 0);
1184         }
1185         /* equivalently for pynodes: */
1186         if (nodeDynamicUnlinkText ((ID*)text)) {
1187                 allqueue(REDRAWNODE, 0);
1188         }
1189
1190         for (scr= G.main->screen.first; scr; scr= scr->id.next) {
1191                 for (area= scr->areabase.first; area; area= area->next) {
1192                         for (sl= area->spacedata.first; sl; sl= sl->next) {
1193                                 if (sl->spacetype==SPACE_TEXT) {
1194                                         SpaceText *st= (SpaceText*) sl;
1195                                         
1196                                         if (st->text==text) {
1197                                                 st->text= NULL;
1198                                                 st->top= 0;
1199                                                 
1200                                                 if (st==area->spacedata.first) {
1201                                                         scrarea_queue_redraw(area);
1202                                                 }
1203                                         }
1204                                 }
1205                         }
1206                 }
1207         }
1208 }
1209
1210 int jumptoline_interactive(SpaceText *st) {
1211         short nlines= txt_get_span(st->text->lines.first, st->text->lines.last)+1;
1212         short tmp= txt_get_span(st->text->lines.first, st->text->curl)+1;
1213
1214         if (button(&tmp, 1, nlines, "Jump to line:")) {
1215                 txt_move_toline(st->text, tmp-1, 0);
1216                 pop_space_text(st);
1217                 return 1;
1218         } else {
1219                 return 0;
1220         }
1221 }
1222
1223
1224 int bufferlength;
1225 static char *copybuffer = NULL;
1226
1227 void txt_copy_selectbuffer (Text *text)
1228 {
1229         int length=0;
1230         TextLine *tmp, *linef, *linel;
1231         int charf, charl;
1232         
1233         if (!text) return;
1234         if (!text->curl) return;
1235         if (!text->sell) return;
1236
1237         if (!txt_has_sel(text)) return;
1238         
1239         if (copybuffer) {
1240                 MEM_freeN(copybuffer);
1241                 copybuffer= NULL;
1242         }
1243
1244         if (text->curl==text->sell) {
1245                 linef= linel= text->curl;
1246                 
1247                 if (text->curc < text->selc) {
1248                         charf= text->curc;
1249                         charl= text->selc;
1250                 } else{
1251                         charf= text->selc;
1252                         charl= text->curc;
1253                 }
1254         } else if (txt_get_span(text->curl, text->sell)<0) {
1255                 linef= text->sell;
1256                 linel= text->curl;
1257
1258                 charf= text->selc;              
1259                 charl= text->curc;
1260         } else {
1261                 linef= text->curl;
1262                 linel= text->sell;
1263                 
1264                 charf= text->curc;
1265                 charl= text->selc;
1266         }
1267
1268         if (linef == linel) {
1269                 length= charl-charf;
1270
1271                 copybuffer= MEM_mallocN(length+1, "cut buffera");
1272                 
1273                 BLI_strncpy(copybuffer, linef->line + charf, length+1);
1274         } else {
1275                 length+= linef->len - charf;
1276                 length+= charl;
1277                 length++; /* For the '\n' */
1278                 
1279                 tmp= linef->next;
1280                 while (tmp && tmp!= linel) {
1281                         length+= tmp->len+1;
1282                         tmp= tmp->next;
1283                 }
1284                 
1285                 copybuffer= MEM_mallocN(length+1, "cut bufferb");
1286                 
1287                 strncpy(copybuffer, linef->line+ charf, linef->len-charf);
1288                 length= linef->len-charf;
1289                 
1290                 copybuffer[length++]='\n';
1291                 
1292                 tmp= linef->next;
1293                 while (tmp && tmp!=linel) {
1294                         strncpy(copybuffer+length, tmp->line, tmp->len);
1295                         length+= tmp->len;
1296                         
1297                         copybuffer[length++]='\n';                      
1298                         
1299                         tmp= tmp->next;
1300                 }
1301                 strncpy(copybuffer+length, linel->line, charl);
1302                 length+= charl;
1303                 
1304                 copybuffer[length]=0;
1305         }
1306
1307         bufferlength = length;
1308 }
1309
1310 static char *unixNewLine(char *buffer)
1311 {
1312         char *p, *p2, *output;
1313         
1314         /* we can afford the few extra bytes */
1315         output= MEM_callocN(strlen(buffer)+1, "unixnewline");
1316         for (p= buffer, p2= output; *p; p++)
1317                 if (*p != '\r') *(p2++)= *p;
1318         
1319         *p2= 0;
1320         return(output);
1321 }
1322
1323 static char *winNewLine(char *buffer)
1324 {
1325         char *p, *p2, *output;
1326         int add= 0;
1327         
1328         for (p= buffer; *p; p++)
1329                 if (*p == '\n') add++;
1330                 
1331         bufferlength= p-buffer+add+1;
1332         output= MEM_callocN(bufferlength, "winnewline");
1333         for (p= buffer, p2= output; *p; p++, p2++) {
1334                 if (*p == '\n') { 
1335                         *(p2++)= '\r'; *p2= '\n';
1336                 } else *p2= *p;
1337         }
1338         *p2= 0;
1339         
1340         return(output);
1341 }
1342
1343 void txt_paste_clipboard(Text *text) {
1344
1345         char * buff;
1346         char *temp_buff;
1347         
1348         buff = (char*)getClipboard(0);
1349         if(buff) {
1350                 temp_buff = unixNewLine(buff);
1351                 
1352                 txt_insert_buf(text, temp_buff);
1353                 if(buff){free((void*)buff);}
1354                 if(temp_buff){MEM_freeN(temp_buff);}
1355         }
1356 }
1357
1358 void get_selection_buffer(Text *text)
1359 {
1360         char *buff = (char*)getClipboard(1);
1361         txt_insert_buf(text, buff);
1362 }
1363
1364 void txt_copy_clipboard(Text *text) {
1365         char *temp;
1366
1367         txt_copy_selectbuffer(text);
1368
1369         if (copybuffer) {
1370                 copybuffer[bufferlength] = '\0';
1371                 temp = winNewLine(copybuffer);
1372                 
1373                 putClipboard((GHOST_TInt8*)temp, 0);
1374                 MEM_freeN(temp);
1375                 MEM_freeN(copybuffer);
1376                 copybuffer= NULL;
1377         }
1378 }
1379
1380 /*
1381  * again==0 show find panel or find
1382  * again==1 find text again */
1383 void txt_find_panel(SpaceText *st, int again)
1384 {
1385         Text *text=st->text;
1386         char *findstr= last_txt_find_string;
1387                         
1388         if (again==0) {
1389                 findstr= txt_sel_to_buf(text);
1390         } else if (again==1) {
1391                 char buf[256];
1392
1393         if (findstr && strlen(findstr)<(sizeof(buf)-1))
1394                 strcpy(buf, findstr);
1395         else
1396                 buf[0]= 0;
1397                 
1398         if (sbutton(buf, 0, sizeof(buf)-1, "Find: ") && buf[0])
1399                 findstr= BLI_strdup(buf);
1400         else
1401                 findstr= NULL;
1402         }
1403
1404         if (findstr!=last_txt_find_string) {
1405                 if (last_txt_find_string)
1406                         MEM_freeN(last_txt_find_string);
1407                 last_txt_find_string= findstr;
1408         }
1409                                 
1410         if (findstr) {
1411                 if (txt_find_string(text, findstr))
1412                         pop_space_text(st);
1413                 else
1414                         error("Not found: %s", findstr);
1415         }
1416 }
1417
1418 void run_python_script(SpaceText *st)
1419 {
1420         char *py_filename;
1421         Text *text=st->text;
1422
1423         if (!BPY_txt_do_python_Text(text)) {
1424                 int lineno = BPY_Err_getLinenumber();
1425                 // jump to error if happened in current text:
1426                 py_filename = (char*) BPY_Err_getFilename();
1427
1428                 /* st->text can become NULL: user called Blender.Load(blendfile)
1429                  * before the end of the script. */
1430                 if (!st->text) return;
1431
1432                 if (!strcmp(py_filename, st->text->id.name+2)) {
1433                         error("Python script error, check console");
1434                         if (lineno >= 0) {
1435                                 txt_move_toline(text, lineno-1, 0);
1436                                 txt_sel_line(text);
1437                                 pop_space_text(st);
1438                         }       
1439                 } else {
1440                         error("Error in other (possibly external) file, "\
1441                                 "check console");
1442                 }       
1443         }
1444 }
1445
1446 static void set_tabs(Text *text)
1447 {
1448         SpaceText *st = curarea->spacedata.first;
1449         st->currtab_set = setcurr_tab(text);
1450 }
1451
1452 void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1453 {
1454         unsigned short event= evt->event;
1455         short val= evt->val;
1456         char ascii= evt->ascii;
1457         SpaceText *st= curarea->spacedata.first;
1458         Text *text;
1459         int do_draw=0, p;
1460         
1461         if (st==NULL || st->spacetype != SPACE_TEXT) return;
1462         
1463         /* smartass code to prevent the CTRL/ALT events below from not working! */
1464         if(G.qual & (LR_ALTKEY|LR_CTRLKEY))
1465                 if(!ispunct(ascii)) 
1466                         ascii= 0;
1467
1468         text= st->text;
1469         
1470         if (!text) {
1471                 if (event==RIGHTMOUSE) {
1472                         switch (pupmenu("File %t|New %x0|Open... %x1")) {
1473                         case 0:
1474                                 st->text= add_empty_text("Text");
1475                                 st->top= 0;
1476                         
1477                                 allqueue(REDRAWTEXT, 0);
1478                                 allqueue(REDRAWHEADERS, 0);
1479                                 break;
1480                         case 1:
1481                                 activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1482                                 break;
1483                         }
1484                 }
1485                 if (val && !ELEM(G.qual, 0, LR_SHIFTKEY)) {
1486                         if (event==FKEY && G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1487                                 switch (pupmenu("File %t|New %x0|Open... %x1")) {
1488                                 case 0:
1489                                         st->text= add_empty_text("Text");
1490                                         st->top= 0;
1491                                 
1492                                         allqueue(REDRAWTEXT, 0);
1493                                         allqueue(REDRAWHEADERS, 0);
1494                                         break;
1495                                 case 1:
1496                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1497                                         break;
1498                                 }
1499                         } 
1500                         else if (event==QKEY) {
1501                                 if (G.qual & LR_CTRLKEY) {
1502                                         if(okee("Quit Blender")) exit_usiblender();
1503                                 }
1504                         }
1505                         else if (event==NKEY) {
1506                                 if (G.qual & LR_ALTKEY) {
1507                                         st->text= add_empty_text("Text");
1508                                         st->top= 0;
1509                                 
1510                                         allqueue(REDRAWTEXT, 0);
1511                                         allqueue(REDRAWHEADERS, 0);
1512                                 }
1513                         }
1514                         else if (event==OKEY) {
1515                                 if (G.qual & LR_ALTKEY) {
1516                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1517                                 }
1518                         }
1519                 }
1520                 return;
1521         }
1522         
1523         if (event==LEFTMOUSE) {
1524                 if (val) {
1525                         short mval[2];
1526                         char *buffer;
1527                         set_tabs(text);
1528                         getmouseco_areawin(mval);
1529                         
1530                         if (mval[0]>2 && mval[0]<20 && mval[1]>2 && mval[1]<curarea->winy-2) {
1531                                 do_textscroll(st, 2);
1532                         } else {
1533                                 do_selection(st, G.qual&LR_SHIFTKEY);
1534                                 buffer = txt_sel_to_buf(text);
1535                                 putClipboard((GHOST_TInt8*)buffer, 1);
1536                                 MEM_freeN(buffer);
1537                                 do_draw= 1;
1538                         }
1539                 }
1540         } else if (event==MIDDLEMOUSE) {
1541                 if (val) {
1542                         #ifdef _WIN32 || __APPLE__
1543                                 do_textscroll(st, 1);
1544                         #else
1545                                 do_selection(st, G.qual&LR_SHIFTKEY);
1546                                 get_selection_buffer(text);
1547                                 do_draw= 1;
1548                         #endif
1549                 }
1550         } else if (event==RIGHTMOUSE) {
1551                 if (val) {
1552                         p= pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3|Execute Script%x4");
1553
1554                         switch(p) {
1555                                 case 0:
1556                                         st->text= add_empty_text("Text");
1557                                         st->top= 0;
1558                                         
1559                                         allqueue(REDRAWTEXT, 0);
1560                                         allqueue(REDRAWHEADERS, 0);
1561                                         break;
1562
1563                                 case 1:
1564                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1565                                         break;
1566                                         
1567                                 case 3:
1568                                         text->flags |= TXT_ISMEM;
1569                                         
1570                                 case 2:
1571                                         txt_write_file(text);
1572                                         do_draw= 1;
1573                                         break;
1574                                 case 4:
1575                                         run_python_script(st);
1576                                         do_draw= 1;
1577                                         break;
1578                                 default:
1579                                         break;
1580                         }
1581                 }
1582         } else if (ascii) {
1583                 if (txt_add_char(text, ascii)) {
1584                         if (st->showsyntax) get_format_string(st);
1585                         pop_space_text(st);
1586                         do_draw= 1;
1587                 }
1588         } else if (val) {
1589                 switch (event) {
1590                 case AKEY:
1591                         if (G.qual & LR_ALTKEY) {
1592                                 txt_move_bol(text, G.qual & LR_SHIFTKEY);
1593                                 do_draw= 1;
1594                                 pop_space_text(st);
1595                         } else if (G.qual & LR_CTRLKEY) {
1596                                 txt_sel_all(text);
1597                                 do_draw= 1;
1598                         }
1599                         break; /* BREAK A */
1600                 case CKEY:
1601                         if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
1602                                 if(G.qual & LR_SHIFTKEY)
1603                                         txt_copy_clipboard(text);
1604                                 else
1605                                         txt_copy_clipboard(text);
1606
1607                                 do_draw= 1;     
1608                         }
1609                         break; /* BREAK C */
1610                 case DKEY:
1611                         if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
1612                                 //uncommenting
1613                                 txt_order_cursors(text);
1614                                 uncomment(text);
1615                                 do_draw = 1;
1616                                 if (st->showsyntax) get_format_string(st);
1617                                 break;
1618                         } else if (G.qual == LR_CTRLKEY) {
1619                                 txt_delete_char(text);
1620                                 if (st->showsyntax) get_format_string(st);
1621                                 do_draw= 1;
1622                                 pop_space_text(st);
1623                         }
1624                         break; /* BREAK D */
1625                 case EKEY:
1626                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1627                                 switch(pupmenu("Edit %t|Cut %x0|Copy %x1|Paste %x2|Print Cut Buffer %x3")) {
1628                                 case 0:
1629                                         txt_copy_clipboard(text); //First copy to clipboard
1630                                         txt_cut_sel(text);
1631                                         do_draw= 1;
1632                                         break;
1633                                 case 1:
1634                                         txt_copy_clipboard(text);
1635                                         //txt_copy_sel(text);
1636                                         do_draw= 1;
1637                                         break;
1638                                 case 2:
1639                                         //txt_paste(text);
1640                                         txt_paste_clipboard(text);
1641                                         if (st->showsyntax) get_format_string(st);
1642                                         do_draw= 1;
1643                                         break;
1644                                 case 3:
1645                                         txt_print_cutbuffer();
1646                                         break;
1647                                 }
1648                         }
1649                         else if (G.qual == LR_CTRLKEY || G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
1650                                 txt_move_eol(text, G.qual & LR_SHIFTKEY);
1651                                 do_draw= 1;
1652                                 pop_space_text(st);
1653                         }
1654                         break; /* BREAK E */
1655                 case FKEY:
1656                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1657                                 switch(pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3")) {
1658                                 case 0:
1659                                         st->text= add_empty_text("Text");
1660                                         st->top= 0;
1661                                         
1662                                         allqueue(REDRAWTEXT, 0);
1663                                         allqueue(REDRAWHEADERS, 0);
1664                                         break;
1665                                 case 1:
1666                                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1667                                         break;
1668                                 case 3:
1669                                         text->flags |= TXT_ISMEM;
1670                                 case 2:
1671                                         txt_write_file(text);
1672                                         do_draw= 1;
1673                                         break;
1674                                 }
1675                         }
1676                         else if (G.qual == LR_ALTKEY) {
1677                                 if (txt_has_sel(text)) {
1678                                         txt_find_panel(st,0);
1679                                         do_draw= 1;
1680                                 }
1681                         }
1682                         else if (G.qual == (LR_ALTKEY|LR_CTRLKEY)) {    /* always search button */
1683                                 txt_find_panel(st,1);
1684                                 do_draw= 1;
1685                         }
1686                         break; /* BREAK F */
1687                 case JKEY:
1688                         if (G.qual == LR_ALTKEY) {
1689                                 do_draw= jumptoline_interactive(st);
1690                         }
1691                         break; /* BREAK J */
1692                 case MKEY:
1693                         if (G.qual == LR_ALTKEY) {
1694                                 txt_export_to_object(text);
1695                                 do_draw= 1;     
1696                         }
1697                         break; /* BREAK M */
1698                 case NKEY:
1699                         if (G.qual == LR_ALTKEY) {
1700                                 st->text= add_empty_text("Text");
1701                                 st->top= 0;
1702                         
1703                                 allqueue(REDRAWTEXT, 0);
1704                                 allqueue(REDRAWHEADERS, 0);
1705
1706                         }
1707                         break; /* BREAK N */
1708                 case OKEY:
1709                         if (G.qual == LR_ALTKEY) {
1710                                 activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
1711                         }
1712                         break; /* BREAK O */
1713                 case PKEY:
1714                         if (G.qual == LR_ALTKEY) {
1715                                 run_python_script(st);
1716                                 do_draw= 1;
1717                         }
1718                         break; /* BREAK P */
1719                 case QKEY:
1720                         if(okee("Quit Blender")) exit_usiblender();
1721                         break; /* BREAK Q */
1722                 case RKEY:
1723                         if (G.qual == LR_ALTKEY) {
1724                             if (text->compiled) BPY_free_compiled_text(text);
1725                                 text->compiled = NULL;
1726                                 if (okee("Reopen text")) {
1727                                         if (!reopen_text(text))
1728                                                 error("Could not reopen file");
1729                                 if (st->showsyntax) get_format_string(st);
1730                                 }
1731                                 do_draw= 1;     
1732                         }
1733                         break; /* BREAK R */
1734                 case SKEY:
1735                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1736                                 p= pupmenu("Select %t|"
1737                                                         "Select All %x0|"
1738                                                         "Select Line %x1|"
1739                                                         "Jump to Line %x3");
1740                                 switch(p) {
1741                                 case 0:
1742                                         txt_sel_all(text);
1743                                         do_draw= 1;
1744                                         break;
1745                                         
1746                                 case 1:
1747                                         txt_sel_line(text);
1748                                         do_draw= 1;
1749                                         break;
1750                                                                                 
1751                                 case 3:
1752                                         do_draw= jumptoline_interactive(st);
1753                                         break;
1754                                 }
1755                         }
1756                         else if (G.qual & LR_ALTKEY) {
1757                                 /* Event treatment CANNOT enter this if
1758                                 if (G.qual & LR_SHIFTKEY) 
1759                                         if (text) text->flags |= TXT_ISMEM;
1760                                 */
1761                                 txt_write_file(text);
1762                                 do_draw= 1;
1763                         }
1764                         break; /* BREAK S */
1765                 case UKEY:
1766                         //txt_print_undo(text); //debug buffer in console
1767                         if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
1768                                 txt_do_redo(text);
1769                                 do_draw= 1;
1770                         }
1771                         if (G.qual == LR_ALTKEY) {
1772                                 txt_do_undo(text);
1773                                 if (st->showsyntax) get_format_string(st);
1774                                 do_draw= 1;
1775                         }
1776                         break; /* BREAK U */
1777                 case VKEY:
1778                         if (G.qual == (LR_ALTKEY| LR_SHIFTKEY)) {
1779                                 switch(pupmenu("View %t|Top of File %x0|Bottom of File %x1|Page Up %x2|Page Down %x3")) {
1780                                 case 0:
1781                                         txt_move_bof(text, 0);
1782                                         do_draw= 1;
1783                                         pop_space_text(st);
1784                                         break;
1785                                 case 1:
1786                                         txt_move_eof(text, 0);
1787                                         do_draw= 1;
1788                                         pop_space_text(st);
1789                                         break;
1790                                 case 2:
1791                                         screen_skip(st, -st->viewlines);
1792                                         do_draw= 1;
1793                                         break;
1794                                 case 3:
1795                                         screen_skip(st, st->viewlines);
1796                                         do_draw= 1;
1797                                         break;
1798                                 }
1799                         }
1800                         /* Support for both Alt-V and Ctrl-V for Paste, for backward compatibility reasons */
1801                         else if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
1802                                 /* Throwing in the Shift modifier Paste from the OS clipboard */
1803                                 if (G.qual & LR_SHIFTKEY)
1804                                         txt_paste_clipboard(text);
1805                                 else
1806                                         txt_paste_clipboard(text);
1807                                 if (st->showsyntax) get_format_string(st);
1808                                 do_draw= 1;     
1809                                 pop_space_text(st);
1810                         }
1811                         break; /* BREAK V */
1812                 case XKEY:
1813                         if (G.qual == LR_ALTKEY || G.qual == LR_CTRLKEY) {
1814                                 txt_cut_sel(text);
1815                                 if (st->showsyntax) get_format_string(st);
1816                                 do_draw= 1;     
1817                                 pop_space_text(st);
1818                         }
1819                         break;
1820                 case ZKEY:
1821                         if (G.qual & (LR_ALTKEY|LR_CTRLKEY|LR_COMMANDKEY)) {
1822                                 if (G.qual & LR_SHIFTKEY) {
1823                                         txt_do_redo(text);
1824                                 } else {
1825                                         txt_do_undo(text);
1826                                 }
1827                                 if (st->showsyntax) get_format_string(st);
1828                                 do_draw= 1;
1829                         }
1830                         break;
1831                 case TABKEY:
1832                         if (G.qual & LR_SHIFTKEY) {
1833                                 if (txt_has_sel(text)) {
1834                                         txt_order_cursors(text);
1835                                         unindent(text);
1836                                         
1837                                 }
1838                         } else {
1839                                 if ( txt_has_sel(text)) {
1840                                         txt_order_cursors(text);
1841                                         indent(text);
1842                                 } else {
1843                                         txt_add_char(text, '\t');
1844                                 }
1845                         }
1846                         if (st->showsyntax) get_format_string(st);
1847                         pop_space_text(st);
1848                         do_draw= 1;
1849                         st->currtab_set = setcurr_tab(text);
1850                         break;
1851                 case RETKEY:
1852                         //double check tabs before splitting the line
1853                         st->currtab_set = setcurr_tab(text);
1854                         txt_split_curline(text);
1855                         {
1856                                 int a = 0;
1857                                 if (a < st->currtab_set)
1858                                 {
1859                                         while ( a < st->currtab_set) {
1860                                                 txt_add_char(text, '\t');
1861                                                 a++;
1862                                         }
1863                                 }
1864                         }
1865                         if (st->showsyntax) get_format_string(st);
1866                         do_draw= 1;
1867                         pop_space_text(st);
1868                         break;
1869                 case BACKSPACEKEY:
1870                         txt_backspace_char(text);
1871                         set_tabs(text);
1872                         if (st->showsyntax) get_format_string(st);
1873                         do_draw= 1;
1874                         pop_space_text(st);
1875                         break;
1876                 case DELKEY:
1877                         txt_delete_char(text);
1878                         if (st->showsyntax) get_format_string(st);
1879                         do_draw= 1;
1880                         pop_space_text(st);
1881                         st->currtab_set = setcurr_tab(text);
1882                         break;
1883                 case DOWNARROWKEY:
1884                         txt_move_down(text, G.qual & LR_SHIFTKEY);
1885                         set_tabs(text);
1886                         do_draw= 1;
1887                         pop_space_text(st);
1888                         break;
1889                 case LEFTARROWKEY:
1890                         if (G.qual & LR_COMMANDKEY)
1891                                 txt_move_bol(text, G.qual & LR_SHIFTKEY);
1892                         else
1893                                 txt_move_left(text, G.qual & LR_SHIFTKEY);
1894                         set_tabs(text);
1895                         do_draw= 1;
1896                         pop_space_text(st);
1897                         break;
1898                 case RIGHTARROWKEY:
1899                         if (G.qual & LR_COMMANDKEY)
1900                                 txt_move_eol(text, G.qual & LR_SHIFTKEY);
1901                         else
1902                                 txt_move_right(text, G.qual & LR_SHIFTKEY);
1903                         set_tabs(text);
1904                         do_draw= 1;
1905                         pop_space_text(st);
1906                         break;
1907                 case UPARROWKEY:
1908                         txt_move_up(text, G.qual & LR_SHIFTKEY);
1909                         set_tabs(text);
1910                         do_draw= 1;
1911                         pop_space_text(st);
1912                         break;
1913                 case PAGEDOWNKEY:
1914                         screen_skip(st, st->viewlines);
1915                         do_draw= 1;
1916                         break;
1917                 case PAGEUPKEY:
1918                         screen_skip(st, -st->viewlines);
1919                         do_draw= 1;
1920                         break;
1921                 case HOMEKEY:
1922                         txt_move_bol(text, G.qual & LR_SHIFTKEY);
1923                         do_draw= 1;
1924                         pop_space_text(st);
1925                         break;
1926                 case ENDKEY:
1927                         txt_move_eol(text, G.qual & LR_SHIFTKEY);
1928                         do_draw= 1;
1929                         pop_space_text(st);
1930                         break;
1931                 case WHEELUPMOUSE:
1932                         screen_skip(st, -U.wheellinescroll);
1933                         do_draw= 1;
1934                         break;
1935                 case WHEELDOWNMOUSE:
1936                         screen_skip(st, U.wheellinescroll);
1937                         do_draw= 1;
1938                         break;
1939                 }
1940         }
1941
1942         if (do_draw) {
1943                 ScrArea *sa;
1944                 
1945                 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1946                         SpaceText *st= sa->spacedata.first;
1947                         
1948                         if (st && st->spacetype==SPACE_TEXT) {
1949                                 scrarea_queue_redraw(sa);
1950                         }
1951                 }
1952         }
1953 }
1954
1955 void do_brackets(void) 
1956 {
1957         SpaceText *st = curarea->spacedata.first;
1958         Text *text = st->text;
1959         TextLine *tmp, *start;
1960         char test[2];
1961         int d, pos, open, x, y, x2, y2, h=0;
1962         
1963         if(!text) return;
1964         
1965         tmp = text->curl;
1966         start = text->curl;
1967
1968         test[0] = (unsigned char) tmp->line[text->curc];
1969         test[1] = '\0';
1970         
1971         d = check_bracket(test);
1972         if (!d) /*  If not pri char */
1973         {
1974                 test[0] = (unsigned char) tmp->line[text->curc-1];
1975                 test[1] = '\0';
1976                 d = check_bracket(test);
1977                 if(!d) {
1978                         return; /*If the current char or prev is not a bracket then return*/
1979                 } else { /* current char */
1980                         h= txt_get_span(text->lines.first, start) - st->top;
1981                         x = text_draw(st, start->line, st->left, text->curc-1, 0, 0, 0, NULL);
1982                         y = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
1983                         if (d < 4) {
1984                                 pos = text->curc;
1985                         } else {
1986                                 pos = text->curc-2;
1987                         }
1988                 }
1989         } else { /* is pri char */
1990                 h= txt_get_span(text->lines.first, start) - st->top;
1991                 x = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
1992                 y = text_draw(st, start->line, st->left, text->curc+1, 0, 0, 0, NULL);
1993                 if (d < 4) {
1994                         pos = text->curc+1;
1995                 } else {
1996                         pos = text->curc-1;
1997                 }
1998         }
1999         
2000         if (d < 4) /*reading forward*/
2001         {
2002                 open = 1; 
2003                 while ( tmp ) {
2004                         while (pos <= tmp->len) {
2005                                 test[0] = (unsigned char) tmp->line[pos];
2006                                 test[1] = '\0';
2007                                 if(check_bracket(test) == d) {
2008                                         open++;
2009                                 } else if (check_bracket(test) == d+3) {
2010                                         open--;
2011                                         if (open == 0) {
2012                                                 BIF_ThemeColorBlend(TH_BACK, TH_SHADE2, 0.5);
2013                                                 glRecti(x, curarea->winy-st->lheight*(h)-2, y, curarea->winy-st->lheight*(h+1)-2);
2014
2015                                                 h= txt_get_span(text->lines.first, tmp) - st->top;
2016                                                 x2= text_draw(st, tmp->line, st->left, pos, 0, 0, 0, NULL);
2017                                                 y2= text_draw(st, tmp->line, st->left, pos+1, 0, 0, 0, NULL);
2018                                                 glRecti(x2, curarea->winy-st->lheight*(h)-2, y2, curarea->winy-st->lheight*(h+1)-2);
2019                                                 BIF_ThemeColor(TH_TEXT);
2020                                                 return;
2021                                         }
2022                                 }
2023                                 pos++;
2024                         }
2025                         tmp = tmp->next;
2026                         pos = 0;
2027                 }
2028         } else { /*  reading back */
2029                 open = 1; 
2030                 while ( tmp ) {
2031                         while (pos >= 0) {
2032                                 test[0] = (unsigned char) tmp->line[pos];
2033                                 test[1] = '\0';
2034                                 if(check_bracket(test) == d) {
2035                                         open++;
2036                                 } else if (check_bracket(test) == d-3) {
2037                                         open--;
2038                                         if (open == 0) {
2039                                                 BIF_ThemeColorBlend(TH_BACK, TH_SHADE2, 0.5);
2040                                                 glRecti(x, curarea->winy-st->lheight*(h)-2, y, curarea->winy-st->lheight*(h+1)-2);
2041
2042                                                 h= txt_get_span(text->lines.first, tmp) - st->top;
2043                                                 x2= text_draw(st, tmp->line, st->left, pos, 0, 0, 0, NULL);
2044                                                 y2= text_draw(st, tmp->line, st->left, pos+1, 0, 0, 0, NULL);
2045                                                 glRecti(x2, curarea->winy-st->lheight*(h)-2, y2, curarea->winy-st->lheight*(h+1)-2);
2046                                                 BIF_ThemeColor(TH_TEXT);
2047                                                 return;
2048                                         }
2049                                 }
2050                                 pos--;
2051                         }
2052                         tmp = tmp->prev;
2053                         if (tmp) {
2054                                 pos = tmp->len;
2055                         }
2056                 }
2057         }
2058         
2059 }
2060
2061 int check_bracket(char *string)
2062 {
2063         int number, a = 0;
2064         char other[][3] = {"(", "[", "{", ")", "]", "}"};
2065         
2066         number = 6;
2067         
2068         while(a < number) {
2069                 if(strcmp(other[a], string) == 0)
2070                 {
2071                         return a+1;
2072                 }
2073                 a++;
2074         }
2075         return 0;
2076 }
2077
2078 static int check_builtinfuncs(char *string) 
2079 {
2080         int number = 30, a = 0;
2081         
2082         char builtinfuncs[][11] = {"and", "as", "assert", "break", "class", "continue", "def",
2083                                                                 "del", "elif", "else", "except", "exec", "finally",
2084                                                                 "for", "from", "global", "if", "import", "in",
2085                                                                 "is", "lambda", "not", "or", "pass", "print",
2086                                                                 "raise", "return", "try", "while", "yield"};
2087
2088         for( a = 0; a < number; a++) {
2089                 if(!strcmp(builtinfuncs[a], string))
2090                         return 1;
2091         }
2092         return 0;
2093 }
2094
2095 static int check_specialvars(char *string) 
2096 {
2097         int number = 2, a = 0;
2098         char specialvars[][7] = {"def", "class"};
2099         
2100         for( a = 0; a < number; a++) {
2101                 if(!strcmp(specialvars[a], string))
2102                         return a+1;
2103         }
2104         return 0;
2105 }
2106
2107 static int check_delim(char *string) 
2108 {
2109         int number = 28, a = 0;
2110         char other[][3] = {"(", ")", ":", "\"", "\'", " ", "~", "!", "%", "^", "&", "*", "-", "+", "=", "[", "]", "{", "}", ";", "/", "<", ">", "|", ".", "#", "\t", ","};
2111         
2112         for( a = 0; a < number; a++) {
2113                 if(!strcmp(other[a], string))
2114                         return 1;
2115         }
2116         return 0;
2117 }
2118
2119 static int check_numbers(char *string)
2120 {
2121         int number = 10, a = 0;
2122         char other[][2] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
2123         
2124         for( a = 0; a < number; a++) {
2125                 if(!strcmp(other[a], string))
2126                         return 1;
2127         }
2128         return 0;
2129 }
2130
2131 void convert_tabs (struct SpaceText *st, int tab)
2132 {
2133         Text *text = st->text;
2134         TextLine *tmp;
2135         char *check_line, *new_line, *format;
2136         int a, j, extra, number; //unknown for now
2137         
2138         if (!text) return;
2139         
2140         tmp = text->lines.first;
2141         
2142         //first convert to all space, this make it alot easier to convert to tabs because there is no mixtures of ' ' && '\t'
2143         while(tmp) {
2144                 check_line = tmp->line;
2145                 new_line = MEM_mallocN(render_string(st, check_line)+1, "Converted_Line");
2146                 format = MEM_mallocN(render_string(st, check_line)+1, "Converted_Syntax_format");
2147                 j = 0;
2148                 for (a=0; a < strlen(check_line); a++) { //foreach char in line
2149                         if(check_line[a] == '\t') { //checking for tabs
2150                                 //get the number of spaces this tabs is showing
2151                                 //i dont like doing it this way but will look into it later
2152                                 new_line[j] = '\0';
2153                                 number = render_string(st, new_line);
2154                                 new_line[j] = '\t';
2155                                 new_line[j+1] = '\0';
2156                                 number = render_string(st, new_line)-number;
2157                                 for(extra = 0; extra < number; extra++) {
2158                                         new_line[j] = ' ';
2159                                         j++;
2160                                 }
2161                         } else {
2162                                 new_line[j] = check_line[a];
2163                                 ++j;
2164                         }
2165                 }
2166                 new_line[j] = '\0';
2167                 // put new_line in the tmp->line spot still need to try and set the curc correctly
2168                 if (tmp->line) MEM_freeN(tmp->line);
2169                 if(tmp->format) MEM_freeN(tmp->format);
2170                 
2171                 tmp->line = new_line;
2172                 tmp->len = strlen(new_line);
2173                 tmp->format = format;
2174                 tmp = tmp->next;
2175         }
2176         
2177         if (tab) // Converting to tabs
2178         {       //start over from the begining
2179                 tmp = text->lines.first;
2180                 
2181                 while(tmp) {
2182                         check_line = tmp->line;
2183                         extra = 0;
2184                         for (a = 0; a < strlen(check_line); a++) {
2185                                 number = 0;
2186                                 for (j = 0; j < st->tabnumber; j++) {
2187                                         if ((a+j) <= strlen(check_line)) { //check to make sure we are not pass the end of the line
2188                                                 if(check_line[a+j] != ' ') {
2189                                                         number = 1;
2190                                                 }
2191                                         }
2192                                 }
2193                                 if (!number) { //found all number of space to equal a tab
2194                                         a = a+(st->tabnumber-1);
2195                                         extra = extra+1;
2196                                 }
2197                         }
2198                         
2199                         if ( extra > 0 ) { //got tabs make malloc and do what you have to do
2200                                 new_line = MEM_mallocN(strlen(check_line)-(((st->tabnumber*extra)-extra)-1), "Converted_Line");
2201                                 format = MEM_mallocN(strlen(check_line)-(((st->tabnumber*extra)-extra)-1), "Converted_Syntax_format");
2202                                 extra = 0; //reuse vars
2203                                 for (a = 0; a < strlen(check_line); a++) {
2204                                         number = 0;
2205                                         for (j = 0; j < st->tabnumber; j++) {
2206                                                 if ((a+j) <= strlen(check_line)) { //check to make sure we are not pass the end of the line
2207                                                         if(check_line[a+j] != ' ') {
2208                                                                 number = 1;
2209                                                         }
2210                                                 }
2211                                         }
2212                                         if (!number) { //found all number of space to equal a tab
2213                                                 new_line[extra] = '\t';
2214                                                 a = a+(st->tabnumber-1);
2215                                                 ++extra;
2216                                                 
2217                                         } else { //not adding a tab
2218                                                 new_line[extra] = check_line[a];
2219                                                 ++extra;
2220                                         }
2221                                 }
2222                                 new_line[extra] = '\0';
2223                                 // put new_line in the tmp->line spot still need to try and set the curc correctly
2224                                 if (tmp->line) MEM_freeN(tmp->line);
2225                                 if(tmp->format) MEM_freeN(tmp->format);
2226                                 
2227                                 tmp->line = new_line;
2228                                 tmp->len = strlen(new_line);
2229                                 tmp->format = format;
2230                         }
2231                         tmp = tmp->next;
2232                 }
2233         }
2234 }