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