Initial revision
[blender.git] / source / blender / src / drawtext.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <math.h>
35 #ifndef _WIN32
36 #include <unistd.h>
37 #else
38 #include <io.h>
39 #include "BLI_winstuff.h"
40 #endif   
41 #include "MEM_guardedalloc.h"
42 #include "PIL_time.h"
43
44 #include "BMF_Api.h"
45
46 #include "BLI_blenlib.h"
47 #include "BLI_arithb.h"
48 #include "BLI_editVert.h"
49
50 #include "DNA_text_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_screen_types.h"
53
54 #include "BKE_utildefines.h"
55 #include "BKE_text.h"
56 #include "BKE_global.h"
57 #include "BKE_main.h"
58
59 #include "BPY_extern.h"
60
61 #include "BIF_gl.h"
62 #include "BIF_keyval.h"
63 #include "BIF_interface.h"
64 #include "BIF_drawtext.h"
65 #include "BIF_spacetypes.h"
66 #include "BIF_usiblender.h"
67 #include "BIF_screen.h"
68 #include "BIF_toolbox.h"
69 #include "BIF_space.h"
70 #include "BIF_mywindow.h"
71
72 #include "BSE_filesel.h"
73
74 #include "mydevice.h"
75 #include "blendef.h" 
76 #include "interface.h"
77
78 /* locals */
79 void drawtextspace(void);
80 void winqreadtextspace(unsigned short event, short val, char ascii);
81
82 static void *last_txt_find_string= NULL;
83
84 static BMF_Font *spacetext_get_font(SpaceText *st) {
85         static BMF_Font *scr12= NULL;
86         static BMF_Font *scr15= NULL;
87         
88         switch (st->font_id) {
89         default:
90         case 0:
91                 if (!scr12)
92                         scr12= BMF_GetFont(BMF_kScreen12);
93                 return scr12;
94         case 1:
95                 if (!scr15)
96                         scr15= BMF_GetFont(BMF_kScreen15);
97                 return scr15;
98         }
99 }
100
101 static int spacetext_get_fontwidth(SpaceText *st) {
102         return BMF_GetCharacterWidth(spacetext_get_font(st), ' ');
103 }
104
105 static char *temp_char_buf= NULL;
106 static int *temp_char_accum= NULL;
107 static int temp_char_len= 0;
108 static int temp_char_pos= 0;
109
110 static void temp_char_write(char c, int accum) {
111         if (temp_char_len==0 || temp_char_pos>=temp_char_len) {
112                 char *nbuf; int *naccum;
113                 int olen= temp_char_len;
114                 
115                 if (olen) temp_char_len*= 2;
116                 else temp_char_len= 256;
117                 
118                 nbuf= MEM_mallocN(sizeof(*temp_char_buf)*temp_char_len, "temp_char_buf");
119                 naccum= MEM_mallocN(sizeof(*temp_char_accum)*temp_char_len, "temp_char_accum");
120                 
121                 if (olen) {
122                         memcpy(nbuf, temp_char_buf, olen);
123                         memcpy(naccum, temp_char_accum, olen);
124                         
125                         MEM_freeN(temp_char_buf);
126                         MEM_freeN(temp_char_accum);
127                 }
128                 
129                 temp_char_buf= nbuf;
130                 temp_char_accum= naccum;
131         }
132         
133         temp_char_buf[temp_char_pos]= c;        
134         temp_char_accum[temp_char_pos]= accum;
135         
136         if (c==0) temp_char_pos= 0;
137         else temp_char_pos++;
138 }
139
140 void free_txt_data(void) {
141         txt_free_cut_buffer();
142         
143         if (last_txt_find_string) MEM_freeN(last_txt_find_string);
144         if (temp_char_buf) MEM_freeN(temp_char_buf);
145         if (temp_char_accum) MEM_freeN(temp_char_accum);        
146 }
147
148 static int render_string (char *in) {
149         int r= 0, i;
150         
151         while(*in) {
152                 if (*in=='\t') {
153                         if (temp_char_pos && *(in-1)=='\t') i= TXT_TABSIZE;
154                         else i= TXT_TABSIZE - (temp_char_pos%TXT_TABSIZE);
155
156                         while(i--) temp_char_write(' ', r);
157                 } else temp_char_write(*in, r);
158
159                 r++;
160                 in++;
161         }
162         r= temp_char_pos;
163         temp_char_write(0, 0);
164                 
165         return r;
166 }
167
168 static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y) {
169         int r=0, w= 0;
170         char *in;
171         int *acc;
172
173         w= render_string(str);
174         if(w<cshift ) return 0; /* String is shorter than shift */
175         
176         in= temp_char_buf+cshift;
177         acc= temp_char_accum+cshift;
178         w= w-cshift;
179         
180         if (draw) {
181                 glRasterPos2i(x, y);
182                 BMF_DrawString(spacetext_get_font(st), in);
183         } else {
184                 while (w-- && *acc++ < maxwidth) {
185                         r+= spacetext_get_fontwidth(st);
186                 }
187         }
188
189         if (cshift && r==0) return 0;
190         else return r+TXT_OFFSET;
191 }
192
193 static void set_cursor_to_pos (SpaceText *st, int x, int y, int sel) 
194 {
195         Text *text;
196         TextLine **linep;
197         int *charp;
198         int w;
199         
200         text= st->text;
201
202         if(sel) { linep= &text->sell; charp= &text->selc; } 
203         else { linep= &text->curl; charp= &text->curc; }
204         
205         y= (curarea->winy - y)/st->lheight;
206         
207         y-= txt_get_span(text->lines.first, *linep) - st->top;
208         
209         if (y>0) {
210                 while (y-- != 0) if((*linep)->next) *linep= (*linep)->next;
211         } else if (y<0) {
212                 while (y++ != 0) if((*linep)->prev) *linep= (*linep)->prev;
213         }
214
215         x-= TXT_OFFSET;
216         if (x<0) x= 0;
217         x = (x/spacetext_get_fontwidth(st)) + st->left;
218         
219         w= render_string((*linep)->line);
220         if(x<w) *charp= temp_char_accum[x];
221         else *charp= (*linep)->len;
222         
223         if(!sel) txt_pop_sel(text);
224 }
225
226 static void draw_cursor(SpaceText *st) {
227         int h, x, i;
228         Text *text= st->text;
229         TextLine *linef, *linel;
230         int charf, charl;
231         
232         if (text->curl==text->sell && text->curc==text->selc) {
233                 x= text_draw(st, text->curl->line, st->left, text->curc, 0, 0, 0);
234
235                 if (x) {
236                         h= txt_get_span(text->lines.first, text->curl) - st->top;
237
238                         glColor3f(1.0, 0.0, 0.0);
239                         
240                         glRecti(x-1, curarea->winy-st->lheight*(h)-2, x+1, curarea->winy-st->lheight*(h+1)-2);
241                 }
242         } else {
243                 int span= txt_get_span(text->curl, text->sell);
244                 
245                 if (span<0) {
246                         linef= text->sell;
247                         charf= text->selc;
248                         
249                         linel= text->curl;
250                         charl= text->curc;
251                 } else if (span>0) {
252                         linef= text->curl;
253                         charf= text->curc;
254         
255                         linel= text->sell;              
256                         charl= text->selc;
257                 } else {
258                         linef= linel= text->curl;
259                         
260                         if (text->curc<text->selc) {
261                                 charf= text->curc;
262                                 charl= text->selc;
263                         } else {
264                                 charf= text->selc;
265                                 charl= text->curc;
266                         }
267                 }
268         
269                         /* Walk to the beginning of visible text */
270                 h= txt_get_span(text->lines.first, linef) - st->top;
271                 while (h++<-1 && linef!=linel) linef= linef->next;
272         
273                 x= text_draw(st, linef->line, st->left, charf, 0, 0, 0);
274
275                 glColor3f(0.75, 0.44, 0.44);
276
277                 if (!x) x= TXT_OFFSET-10;
278                 while (linef && linef != linel) {
279                         h= txt_get_span(text->lines.first, linef) - st->top;
280                         if (h>st->viewlines) break;
281                         
282                         glRecti(x, curarea->winy-st->lheight*(h)-2, curarea->winx, curarea->winy-st->lheight*(h+1)-2);
283                         glRecti(TXT_OFFSET-10, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET, curarea->winy-st->lheight*(h+2)-2);
284                         x= TXT_OFFSET;
285                         
286                         linef= linef->next;
287                 }
288                 
289                 h= txt_get_span(text->lines.first, linef) - st->top;
290
291                 i= text_draw(st, linel->line, st->left, charl, 0, 0, 0);
292                 if(i) glRecti(x, curarea->winy-st->lheight*(h)-2, i, curarea->winy-st->lheight*(h+1)-2);
293         }
294
295         glColor3f(0.0, 0.0, 0.0);
296 }
297
298 static void calc_text_rcts(SpaceText *st)
299 {
300         short barheight, barstart;
301         int lbarstart, lbarh, ltexth;
302
303         lbarstart= st->top;
304         lbarh=  st->viewlines;
305         ltexth= txt_get_span(st->text->lines.first, st->text->lines.last)+1;
306
307         barheight= (lbarh*(curarea->winy-4))/ltexth;
308         if (barheight<20) barheight=20;
309         
310         barstart= (lbarstart*(curarea->winy-4))/ltexth + 8;
311
312         st->txtbar.xmin= 5;
313         st->txtbar.xmax= 17;
314         st->txtbar.ymax= curarea->winy - barstart;
315         st->txtbar.ymin= st->txtbar.ymax - barheight;
316
317         CLAMP(st->txtbar.ymin, 2, curarea->winy-2);
318         CLAMP(st->txtbar.ymax, 2, curarea->winy-2);
319
320         st->pix_per_line= (float) ltexth/curarea->winy;
321         if (st->pix_per_line<.1) st->pix_per_line=.1;
322
323         lbarstart= MIN2(txt_get_span(st->text->lines.first, st->text->curl), 
324                                 txt_get_span(st->text->lines.first, st->text->sell));
325         lbarh= abs(txt_get_span(st->text->lines.first, st->text->curl)-txt_get_span(st->text->lines.first, st->text->sell));
326         
327         barheight= (lbarh*(curarea->winy-4))/ltexth;
328         if (barheight<2) barheight=2; 
329         
330         barstart= (lbarstart*(curarea->winy-4))/ltexth + 8;
331         
332         st->txtscroll.xmin= 5;
333         st->txtscroll.xmax= 17;
334         st->txtscroll.ymax= curarea->winy-barstart;
335         st->txtscroll.ymin= st->txtscroll.ymax - barheight;
336
337         CLAMP(st->txtscroll.ymin, 2, curarea->winy-2);
338         CLAMP(st->txtscroll.ymax, 2, curarea->winy-2);
339 }
340
341 static void draw_textscroll(SpaceText *st)
342 {
343         if (!st->text) return;
344
345         calc_text_rcts(st);
346         
347         cpack(0x707070);
348         glRecti(2, 2, 20, curarea->winy-6);
349         uiEmboss(2, 2, 20, curarea->winy-6, 1);
350
351         cpack(0x909090);
352         glRecti(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax);
353
354         cpack(0x7777c6);
355         glRecti(st->txtscroll.xmin, st->txtscroll.ymin, st->txtscroll.xmax, st->txtscroll.ymax);
356
357         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
358 }
359
360 static void screen_skip(SpaceText *st, int lines)
361 {
362         int last;
363         
364         if (!st) return;
365         if (st->spacetype != SPACE_TEXT) return;
366         if (!st->text) return;
367
368         st->top += lines;
369
370         last= txt_get_span(st->text->lines.first, st->text->lines.last);
371         last= last - (st->viewlines/2);
372         
373         if (st->top>last) st->top= last;
374         if (st->top<0) st->top= 0;
375 }
376
377 /* 
378  * mode 1 == view scroll
379  * mode 2 == scrollbar
380  */
381 static void do_textscroll(SpaceText *st, int mode)
382 {
383         short delta[2]= {0, 0};
384         short mval[2], hold[2], old[2];
385         
386         if (!st->text) return;
387         
388         calc_text_rcts(st);
389
390         st->flags|= ST_SCROLL_SELECT;
391
392         glDrawBuffer(GL_FRONT);
393         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
394         glDrawBuffer(GL_BACK);
395
396         getmouseco_areawin(mval);
397         old[0]= hold[0]= mval[0];
398         old[1]= hold[1]= mval[1];
399
400         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
401                 getmouseco_areawin(mval);
402
403                 if(old[0]!=mval[0] || old[1]!=mval[1]) {
404                         if (mode==1) {
405                                 delta[0]= (hold[0]-mval[0])/spacetext_get_fontwidth(st);
406                                 delta[1]= (mval[1]-hold[1])/st->lheight;
407                         }
408                         else delta[1]= (hold[1]-mval[1])*st->pix_per_line;
409                         
410                         if (delta[0] || delta[1]) {
411                                 screen_skip(st, delta[1]);
412                                 st->left+= delta[0];
413                                 if (st->left<0) st->left= 0;
414                                 
415                                 scrarea_do_windraw(curarea);
416                                 screen_swapbuffers();
417                                 
418                                 hold[0]=mval[0];
419                                 hold[1]=mval[1];
420                         }
421                         old[0]=mval[0];
422                         old[1]=mval[1];
423                 } else {
424                         BIF_wait_for_statechange();
425                 }
426         }
427         st->flags^= ST_SCROLL_SELECT;
428
429         glDrawBuffer(GL_FRONT);
430         uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
431         glDrawBuffer(GL_BACK);
432 }
433
434 static void do_selection(SpaceText *st, int selecting)
435 {
436         short mval[2], old[2];
437         int sell, selc;
438         int linep2, charp2;
439         int first= 1;
440
441         getmouseco_areawin(mval);
442         old[0]= mval[0];
443         old[1]= mval[1];
444
445         if (!selecting) {
446                 int curl= txt_get_span(st->text->lines.first, st->text->curl);
447                 int curc= st->text->curc;                       
448                 int linep2, charp2;
449                                         
450                 set_cursor_to_pos(st, mval[0], mval[1], 0);
451
452                 linep2= txt_get_span(st->text->lines.first, st->text->curl);
453                 charp2= st->text->selc;
454                                 
455                 if (curl!=linep2 || curc!=charp2)
456                         txt_undo_add_toop(st->text, UNDO_CTO, curl, curc, linep2, charp2);
457         }
458
459         sell= txt_get_span(st->text->lines.first, st->text->sell);
460         selc= st->text->selc;
461
462         while(get_mbut()&L_MOUSE) {
463                 getmouseco_areawin(mval);
464
465                 if (mval[1]<0 || mval[1]>curarea->winy) {
466                         int d= (old[1]-mval[1])*st->pix_per_line;
467                         if (d) screen_skip(st, d);
468
469                         set_cursor_to_pos(st, mval[0], mval[1]<0?0:curarea->winy, 1);
470
471                         scrarea_do_windraw(curarea);
472                         screen_swapbuffers();
473                 } else if (mval[0]<0 || mval[0]>curarea->winx) {
474                         if (mval[0]>curarea->winx) st->left++;
475                         else if (mval[0]<0 && st->left>0) st->left--;
476                         
477                         set_cursor_to_pos(st, mval[0], mval[1], 1);
478                         
479                         scrarea_do_windraw(curarea);
480                         screen_swapbuffers();
481                         
482                         PIL_sleep_ms(10);
483                 } else if (first || old[0]!=mval[0] || old[1]!=mval[1]) {
484                         set_cursor_to_pos(st, mval[0], mval[1], 1);
485
486                         scrarea_do_windraw(curarea);
487                         screen_swapbuffers();
488
489                         old[0]= mval[0];
490                         old[1]= mval[1];
491                         first= 1;
492                 } else {
493                         BIF_wait_for_statechange();
494                 }
495         }
496
497         linep2= txt_get_span(st->text->lines.first, st->text->sell);
498         charp2= st->text->selc;
499                 
500         if (sell!=linep2 || selc!=charp2)
501                 txt_undo_add_toop(st->text, UNDO_STO, sell, selc, linep2, charp2);
502 }
503
504 void drawtextspace(void)
505 {
506         SpaceText *st= curarea->spacedata.first;
507         Text *text;
508         int i;
509         TextLine *tmp;
510
511         if (BPY_spacetext_is_pywin(st)) {
512                 BPY_spacetext_do_pywin_draw(st);
513                 return;
514         }
515         
516         glClearColor(0.6, 0.6,  0.6, 1.0);
517         glClear(GL_COLOR_BUFFER_BIT);
518         myortho2(-0.5, curarea->winrct.xmax-curarea->winrct.xmin-0.5, -0.5, curarea->winrct.ymax-curarea->winrct.ymin-0.5);
519
520         text= st->text;
521         if(!text) return;
522         
523         /* Make sure all the positional pointers exist */
524         if (!text->curl || !text->sell || !text->lines.first || !text->lines.last)
525                 txt_clean_text(text);
526         
527         if(st->lheight) st->viewlines= (int) curarea->winy/st->lheight;
528         else st->viewlines= 0;
529         
530         glColor3f(0.0, 0.0, 0.0);
531
532         draw_cursor(st);
533
534         tmp= text->lines.first;
535         for (i= 0; i<st->top && tmp; i++)
536                 tmp= tmp->next;
537         for (i=0; i<st->viewlines && tmp; i++, tmp= tmp->next)
538                 text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET, curarea->winy-st->lheight*(i+1));
539
540         draw_textscroll(st);
541
542         curarea->win_swap= WIN_BACK_OK;
543 }
544
545 void pop_space_text (SpaceText *st)
546 {
547         int i, x;
548
549         if(!st) return;
550         if(!st->text) return;
551         if(!st->text->curl) return;
552                 
553         i= txt_get_span(st->text->lines.first, st->text->curl);
554         if (st->top+st->viewlines <= i || st->top > i) {
555                 st->top= i - st->viewlines/2;
556         }
557         
558         x= text_draw(st, st->text->curl->line, st->left, st->text->curc, 0, 0, 0);
559
560         if (x==0 || x>curarea->winx) {
561                 st->left= st->text->curc-0.5*(curarea->winx)/spacetext_get_fontwidth(st);
562         }
563
564         if (st->top < 0) st->top= 0;
565         if (st->left <0) st->left= 0;
566 }
567
568 void add_text_fs(char *file) 
569 {
570         SpaceText *st= curarea->spacedata.first;
571         Text *text;
572
573         if (!st) return;
574         if (st->spacetype != SPACE_TEXT) return;
575
576         text= add_text(file);
577
578         st->text= text;
579
580         st->top= 0;
581                         
582         allqueue(REDRAWTEXT, 0);
583         allqueue(REDRAWHEADERS, 0);     
584 }
585
586 void free_textspace(SpaceText *st)
587 {
588         if (!st) return;
589
590         st->text= NULL;
591 }
592
593 static void save_mem_text(char *str)
594 {
595         SpaceText *st= curarea->spacedata.first;
596         Text *text;
597         
598         if (!str) return;
599         
600         if (!st) return;
601         if (st->spacetype != SPACE_TEXT) return;
602
603         text= st->text;
604         if(!text) return;
605         
606         if (text->name) MEM_freeN(text->name);
607         text->name= MEM_mallocN(strlen(str)+1, "textname");
608         strcpy(text->name, str);
609
610         text->flags ^= TXT_ISMEM;
611                 
612         txt_write_file(text);
613 }
614
615 void txt_write_file(Text *text) 
616 {
617         FILE *fp;
618         TextLine *tmp;
619         
620         /* Do we need to get a filename? */
621         if (text->flags & TXT_ISMEM) {
622                 activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", G.sce, save_mem_text);
623                 return; 
624         }
625         
626         /* Should we ask to save over? */
627         if (text->flags & TXT_ISTMP) {
628                 if (BLI_exists(text->name)) {
629                         if (!okee("Save over?")) return;
630                 } else if (!okee("Create new file?")) return;
631
632                 text->flags ^= TXT_ISTMP;
633         }
634                 
635         fp= fopen(text->name, "w");
636         if (fp==NULL) {
637                 error("Unable to save file");
638                 return;
639         }
640
641         tmp= text->lines.first;
642         while (tmp) {
643                 if (tmp->next) fprintf(fp, "%s\n", tmp->line);
644                 else fprintf(fp, "%s", tmp->line);
645                 
646                 tmp= tmp->next;
647         }
648         
649         fclose (fp);
650         
651         if (text->flags & TXT_ISDIRTY) text->flags ^= TXT_ISDIRTY;
652 }
653
654 void unlink_text(Text *text)
655 {
656         bScreen *scr;
657         ScrArea *area;
658         SpaceLink *sl;
659         
660         for (scr= G.main->screen.first; scr; scr= scr->id.next) {
661                 for (area= scr->areabase.first; area; area= area->next) {
662                         for (sl= area->spacedata.first; sl; sl= sl->next) {
663                                 if (sl->spacetype==SPACE_TEXT) {
664                                         SpaceText *st= (SpaceText*) sl;
665                                         
666                                         if (st->text==text) {
667                                                 st->text= NULL;
668                                                 st->top= 0;
669                                                 
670                                                 if (st==area->spacedata.first) {
671                                                         scrarea_queue_redraw(area);
672                                                 }
673                                         }
674                                 }
675                         }
676                 }
677         }
678 }
679
680 static int jumptoline_interactive(SpaceText *st) {
681         short nlines= txt_get_span(st->text->lines.first, st->text->lines.last)+1;
682         short tmp= txt_get_span(st->text->lines.first, st->text->curl)+1;
683
684         if (button(&tmp, 1, nlines, "Jump to line:")) {
685                 txt_move_toline(st->text, tmp-1, 0);
686                 pop_space_text(st);
687                 return 1;
688         } else {
689                 return 0;
690         }
691 }
692
693 void winqreadtextspace(unsigned short event, short val, char ascii)
694 {
695         SpaceText *st= curarea->spacedata.first;
696         Text *text= st->text;
697         char *py_filename;
698         int do_draw=0, p;
699
700         if (BPY_spacetext_is_pywin(st)) {
701                 BPY_spacetext_do_pywin_event(st, event, val);
702                 return;
703         }
704
705         text= st->text;
706         
707         if (!text) {
708                 if (val && !ELEM(G.qual, 0, LR_SHIFTKEY)) {
709                         if (event==FKEY && (G.qual & LR_ALTKEY) && (G.qual & LR_SHIFTKEY)) {
710                                 switch (pupmenu("File %t|New %x0|Open... %x1")) {
711                                 case 0:
712                                         st->text= add_empty_text();
713                                         st->top= 0;
714                                 
715                                         allqueue(REDRAWTEXT, 0);
716                                         allqueue(REDRAWHEADERS, 0);
717                                         break;
718                                 case 1:
719                                         activate_fileselect(FILE_SPECIAL, "LOAD TEXT FILE", G.sce, add_text_fs);
720                                         break;
721                                 }
722                         } else if (event==QKEY) {
723                                 if(okee("QUIT BLENDER")) exit_usiblender();
724                         }
725                 }
726                 
727                 return;
728         }
729         
730         if (event==LEFTMOUSE) {
731                 if (val) {
732                         short mval[2];
733
734                         getmouseco_areawin(mval);
735
736                         if (mval[0]>2 && mval[0]<20 && mval[1]>2 && mval[1]<curarea->winy-2) {
737                                 do_textscroll(st, 2);
738                         } else {                        
739                                 do_selection(st, G.qual&LR_SHIFTKEY);
740                                 do_draw= 1;
741                         }
742                 }
743         } else if (event==MIDDLEMOUSE) {
744                 if (val) {
745                         do_textscroll(st, 1);
746                 }
747         } else if (ascii) {
748                 if (txt_add_char(text, ascii)) {
749                         pop_space_text(st);
750                         do_draw= 1;
751                 }
752         } else if (val) {
753                 switch (event) {
754                 case FKEY:
755                         if ((G.qual & LR_ALTKEY) && (G.qual & LR_SHIFTKEY)) {
756                                 p= pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3");
757
758                                 switch(p) {
759                                 case 0:
760                                         st->text= add_empty_text();
761                                         st->top= 0;
762                                         
763                                         allqueue(REDRAWTEXT, 0);
764                                         allqueue(REDRAWHEADERS, 0);
765                                         break;
766
767                                 case 1:
768                                         activate_fileselect(FILE_SPECIAL, "LOAD TEXT FILE", G.sce, add_text_fs);
769                                         break;
770
771                                 case 3:
772                                         text->flags |= TXT_ISMEM;
773                                         
774                                 case 2:
775                                         txt_write_file(text);
776                                         do_draw= 1;
777                                         break;
778
779                                 default:
780                                         break;
781                                 }
782                         } else if (G.qual & LR_ALTKEY) {
783                                 char *findstr= last_txt_find_string;
784                                 
785                                 if (txt_has_sel(text) && !(G.qual & LR_CTRLKEY)) {
786                                         findstr= txt_sel_to_buf(text);
787                                 } else if (!last_txt_find_string || (G.qual & LR_CTRLKEY)) {
788                                         char buf[256];
789
790                                         if (findstr && strlen(findstr)<(sizeof(buf)-1))
791                                                 strcpy(buf, findstr);
792                                         else
793                                                 buf[0]= 0;
794                                         
795                                         if (sbutton(buf, 0, sizeof(buf)-1, "Find: ") && buf[0])
796                                                 findstr= BLI_strdup(buf);
797                                         else
798                                                 findstr= NULL;
799                                 }
800
801                                 if (findstr!=last_txt_find_string) {
802                                         if (last_txt_find_string)
803                                                 MEM_freeN(last_txt_find_string);
804                                         last_txt_find_string= findstr;
805                                 }
806                                 
807                                 if (findstr) {
808                                         if (txt_find_string(text, findstr))
809                                                 pop_space_text(st);
810                                         else
811                                                 error("Not found: %s", findstr);
812                                 }
813                                         
814                                 do_draw= 1;
815                         }
816                         
817                         break;
818
819                 case EKEY:
820                         if (G.qual & LR_ALTKEY && G.qual & LR_SHIFTKEY) {
821                                 p= pupmenu("Edit %t|"
822                                                         "Cut %x0|"
823                                                         "Copy %x1|"
824                                                         "Paste %x2|"
825                                                         "Print Cut Buffer %x3");
826                                 switch(p) {
827                                 case 0:
828                                         txt_cut_sel(text);
829                                         do_draw= 1;
830                                         break;
831                                 case 1:
832                                         txt_copy_sel(text);
833                                         do_draw= 1;
834                                         break;
835                                 case 2:
836                                         txt_paste(text);
837                                         do_draw= 1;
838                                         break;
839                                 case 3:
840                                         txt_print_cutbuffer();
841                                         break;
842                                 }
843                         }
844                         break;
845
846                 case VKEY:
847                         if (G.qual & LR_ALTKEY && G.qual & LR_SHIFTKEY) {
848                                 p= pupmenu("View %t|"
849                                                         "Top of File %x0|"
850                                                         "Bottom of File %x1|"
851                                                         "Page Up %x2|"
852                                                         "Page Down %x3");
853                                 switch(p) {
854                                 case 0:
855                                         txt_move_bof(text, 0);
856                                         do_draw= 1;
857                                         pop_space_text(st);
858                                         break;
859                                         
860                                 case 1:
861                                         txt_move_eof(text, 0);
862                                         do_draw= 1;
863                                         pop_space_text(st);
864                                         break;
865                                         
866                                 case 2:
867                                         screen_skip(st, -st->viewlines);
868                                         do_draw= 1;
869                                         break;
870                                         
871                                 case 3:
872                                         screen_skip(st, st->viewlines);
873                                         do_draw= 1;
874                                         break;
875                                 }
876                         }
877                         break;
878
879                 case SKEY:
880                         if (G.qual & LR_ALTKEY && G.qual & LR_SHIFTKEY) {
881                                 p= pupmenu("Select %t|"
882                                                         "Select All %x0|"
883                                                         "Select Line %x1|"
884                                                         "Jump to Line %x3");
885                                 switch(p) {
886                                 case 0:
887                                         txt_sel_all(text);
888                                         do_draw= 1;
889                                         break;
890                                         
891                                 case 1:
892                                         txt_sel_line(text);
893                                         do_draw= 1;
894                                         break;
895                                                                                 
896                                 case 3:
897                                         do_draw= jumptoline_interactive(st);
898                                         break;
899                                 }
900                         }
901                         break;
902                         
903                 case QKEY:
904                         if(okee("QUIT BLENDER")) exit_usiblender();
905                         break;
906                 }
907
908                 switch(event) {
909                 case AKEY:
910                         if (G.qual & LR_CTRLKEY) {
911                                 txt_move_bol(text, G.qual & LR_SHIFTKEY);
912                                 do_draw= 1;
913                                 pop_space_text(st);
914                         } else if (G.qual & LR_ALTKEY) {
915                                 txt_sel_all(text);
916                                 do_draw= 1;
917                         }
918                         break;
919
920                 case CKEY:
921                         if (G.qual & LR_ALTKEY) {
922                                 txt_copy_sel(text);
923                                 do_draw= 1;     
924                         }
925                         break;
926
927                 case DKEY:
928                         if (G.qual & LR_CTRLKEY) {
929                                 txt_delete_char(text);
930                                 do_draw= 1;
931                                 pop_space_text(st);
932                         }
933                         break;
934
935                 case EKEY:
936                         if (G.qual & LR_CTRLKEY) {
937                                 txt_move_eol(text, G.qual & LR_SHIFTKEY);
938                                 do_draw= 1;
939                                 pop_space_text(st);
940                         }
941                         break;
942
943                 case JKEY:
944                         if (G.qual & LR_ALTKEY) {
945                                 do_draw= jumptoline_interactive(st);
946                         }
947                         break;
948
949                 case OKEY:
950                         if (G.qual & LR_ALTKEY) {
951                                 activate_fileselect(FILE_SPECIAL, "LOAD TEXT FILE", G.sce, add_text_fs);
952                         }
953                         break;
954                         
955                 case PKEY:
956                         if (G.qual & LR_ALTKEY) {
957                                 if (!BPY_txt_do_python(st)) {
958                                         int lineno = BPY_Err_getLinenumber();
959                                         // jump to error if happened in current text:
960                                         py_filename = (char*) BPY_Err_getFilename();
961                                         if (!strcmp(py_filename, st->text->id.name+2)) {
962                                                 error("Python script error, check console");
963                                                 if (lineno >= 0) {
964                                                         txt_move_toline(text, lineno-1, 0);
965                                                         txt_sel_line(text);
966                                                         do_draw= 1;
967                                                         pop_space_text(st);
968                                                 }       
969                                         } else {
970                                                 error("Error in other (possibly external) file, "\
971                                                 "check console");
972                                         }       
973                                 }
974                         }
975                         break;
976                         
977                 case RKEY:
978                         if (G.qual & LR_ALTKEY) {
979                                 txt_do_redo(text);
980                                 do_draw= 1;     
981                         }
982                         if (G.qual & LR_CTRLKEY) {
983                                 if (text->compiled) BPY_free_compiled_text(text);
984                                 text->compiled = NULL;
985                                 if (okee("Reopen Text")) {
986                                         if (!reopen_text(text)) {
987                                                 error("Could not reopen file");
988                                         }
989                                 }
990                                 do_draw= 1;     
991                         }
992                         break;
993                 
994                 case SKEY:
995                         if (G.qual & LR_ALTKEY) {
996                                 if (G.qual & LR_SHIFTKEY) 
997                                         if (text) text->flags |= TXT_ISMEM;
998                                         
999                                 txt_write_file(text);
1000                                 do_draw= 1;
1001                         }
1002                         break;
1003                         
1004                 case UKEY:
1005                         if (G.qual & LR_ALTKEY) {
1006                                 if (G.qual & LR_SHIFTKEY) txt_print_undo(text);
1007                                 else {
1008                                         txt_do_undo(text);
1009                                         do_draw= 1;
1010                                 }
1011                         }
1012                         break;
1013
1014                 case VKEY:
1015                         if (G.qual & LR_ALTKEY) {
1016                                 txt_paste(text);
1017                                 do_draw= 1;     
1018                                 pop_space_text(st);
1019                         }
1020                         break;
1021
1022                 case XKEY:
1023                         if (G.qual & LR_ALTKEY) {
1024                                 txt_cut_sel(text);
1025                                 do_draw= 1;     
1026                                 pop_space_text(st);
1027                         }
1028                         break;
1029                 
1030                 case TABKEY:
1031                         txt_add_char(text, '\t');
1032                         pop_space_text(st);
1033                         do_draw= 1;
1034                         break;
1035
1036                 case RETKEY:
1037                         txt_split_curline(text);
1038                         do_draw= 1;
1039                         pop_space_text(st);
1040                         break;
1041
1042                 case BACKSPACEKEY:
1043                         txt_backspace_char(text);
1044                         do_draw= 1;
1045                         pop_space_text(st);
1046                         break;
1047
1048                 case DELKEY:
1049                         txt_delete_char(text);
1050                         do_draw= 1;
1051                         pop_space_text(st);
1052                         break;
1053
1054                 case DOWNARROWKEY:
1055                         txt_move_down(text, G.qual & LR_SHIFTKEY);
1056                         do_draw= 1;
1057                         pop_space_text(st);
1058                         break;
1059
1060                 case LEFTARROWKEY:
1061                         txt_move_left(text, G.qual & LR_SHIFTKEY);
1062                         do_draw= 1;
1063                         pop_space_text(st);
1064                         break;
1065
1066                 case RIGHTARROWKEY:
1067                         txt_move_right(text, G.qual & LR_SHIFTKEY);
1068                         do_draw= 1;
1069                         pop_space_text(st);
1070                         break;
1071
1072                 case UPARROWKEY:
1073                         txt_move_up(text, G.qual & LR_SHIFTKEY);
1074                         do_draw= 1;
1075                         pop_space_text(st);
1076                         break;
1077
1078                 case PAGEDOWNKEY:
1079                         screen_skip(st, st->viewlines);
1080                         do_draw= 1;
1081                         break;
1082
1083                 case PAGEUPKEY:
1084                         screen_skip(st, -st->viewlines);
1085                         do_draw= 1;
1086                         break;
1087                 }
1088         }
1089
1090         if (do_draw) {
1091                 ScrArea *sa;
1092                 
1093                 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1094                         SpaceText *st= sa->spacedata.first;
1095                         
1096                         if (st && st->spacetype==SPACE_TEXT) {
1097                                 scrarea_queue_redraw(sa);
1098                         }
1099                 }
1100         }
1101 }