f7e44895046246f7dc9c6fd535ee24f3c4eb36c0
[blender-staging.git] / source / blender / src / header_text.c
1 /**
2  * header_text.c oct-2003
3  *
4  * Functions to draw the "Text Editor" window header
5  * and handle user events sent to it.
6  * 
7  * $Id$
8  *
9  * ***** BEGIN GPL LICENSE BLOCK *****
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA        02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL LICENSE BLOCK *****
33  */
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdio.h>
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include "BMF_Api.h"
44 #include "BIF_language.h"
45 #include "MEM_guardedalloc.h"
46
47 #include "BSE_headerbuttons.h"
48
49 #include "DNA_ID.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_text_types.h"
53 #include "DNA_constraint_types.h"
54 #include "DNA_action_types.h"
55
56 #include "BIF_gl.h" /* for glRasterPos2i */
57 #include "BIF_drawtext.h"
58 #include "BIF_interface.h"
59 #include "BIF_resources.h"
60 #include "BIF_screen.h"
61 #include "BIF_space.h"
62 #include "BIF_toolbox.h"
63
64 #include "BKE_global.h"
65 #include "BKE_library.h"
66 #include "BKE_main.h"
67 #include "BKE_sca.h"
68 #include "BKE_text.h"
69 #include "BKE_depsgraph.h"
70
71 #include "BSE_filesel.h"
72
73 #include "BPY_extern.h"
74 #include "BPY_menus.h"
75
76 #include "blendef.h"
77 #include "mydevice.h"
78
79 void do_text_buttons(unsigned short event)
80 {
81         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
82         ID *id, *idtest;
83         int nr= 1;
84         Text *text;
85         
86         if (st==NULL || st->spacetype != SPACE_TEXT) return;
87         
88         switch (event) {
89         case B_TEXTBROWSE:
90                 if (st->menunr==-2) {
91                         activate_databrowse((ID *)st->text, ID_TXT, 0, B_TEXTBROWSE,
92                                                                                         &st->menunr, do_text_buttons);
93                         break;
94                 }
95                 if(st->menunr < 0) break;
96                         
97                 text= st->text;
98
99                 nr= 1;
100                 id= (ID *)text;
101                 
102                 if (st->menunr==32767) {
103                         st->text= (Text *)add_empty_text( "Text" );
104
105                         st->top= 0;
106                         
107                         allqueue(REDRAWTEXT, 0);
108                         allqueue(REDRAWHEADERS, 0); 
109                 }
110                 else if (st->menunr==32766) {
111                         activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs); 
112                         return;
113                 }
114                 else {          
115                         idtest= G.main->text.first;
116                         while(idtest) {
117                                 if(nr==st->menunr) {
118                                         break;
119                                 }
120                                 nr++;
121                                 idtest= idtest->next;
122                         }
123                         if(idtest==0) { /* new text */
124                                 activate_fileselect(FILE_SPECIAL, "Open Text File",
125                                                                                                 G.sce, add_text_fs); 
126                                 return;
127                         }
128                         if(idtest!=id) {
129                                 st->text= (Text *)idtest;
130                                 st->top= 0;
131                                 
132                                 pop_space_text(st);
133                                 if (st->showsyntax) txt_format_text(st);
134                                 allqueue(REDRAWTEXT, 0);
135                                 allqueue(REDRAWHEADERS, 0);
136                         }
137                 }
138                 break;
139                 
140         case B_TEXTDELETE:
141                 {
142                         text= st->text;
143                         if (!text) return;
144                         
145                         /* make the previous text active, if its not there make the next text active */
146                         if (st->text->id.prev) {
147                                 st->text = st->text->id.prev;
148                                 pop_space_text(st);
149                         } else if (st->text->id.next) {
150                                 st->text = st->text->id.next;
151                                 pop_space_text(st);
152                         }
153                         
154                         BPY_clear_bad_scriptlinks(text);
155                         BPY_free_pyconstraint_links(text);
156                         free_text_controllers(text);
157                         
158                         unlink_text(text);
159                         free_libblock(&G.main->text, text);
160                         
161                         allqueue(REDRAWTEXT, 0);
162                         allqueue(REDRAWHEADERS, 0);
163                         
164                         /*for if any object constraints were changed.*/
165                         allqueue(REDRAWVIEW3D, 0);
166                         allqueue(REDRAWBUTSOBJECT, 0);
167                         allqueue(REDRAWBUTSEDIT, 0);
168                         
169                         BIF_undo_push("Delete Text");
170                 }
171                 break;
172                 
173 /*
174         case B_TEXTSTORE:
175                 st->text->flags ^= TXT_ISEXT;
176                 
177                 allqueue(REDRAWHEADERS, 0);
178                 break;
179 */               
180         case B_TEXTLINENUM:
181                 allqueue(REDRAWTEXT, 0);
182                 allqueue(REDRAWHEADERS, 0);
183                 break;
184
185         case B_TEXTFONT:
186                 switch(st->font_id) {
187                 case 0:
188                         st->lheight= 12; break;
189                 case 1:
190                         st->lheight= 15; 
191                         break;
192                 }
193                         
194                 allqueue(REDRAWTEXT, 0);
195                 allqueue(REDRAWHEADERS, 0);
196
197                 break;
198         case B_TAB_NUMBERS:
199                 if (st->showsyntax) txt_format_text(st);
200                 allqueue(REDRAWTEXT, 0);
201                 allqueue(REDRAWHEADERS, 0);
202                 break;
203         case B_SYNTAX:
204                 if (st->showsyntax) txt_format_text(st);
205                 allqueue(REDRAWTEXT, 0);
206                 allqueue(REDRAWHEADERS, 0);
207                 break;
208         case B_TEXTPLUGINS:
209                 allqueue(REDRAWHEADERS, 0);
210                 break;
211         case B_WORDWRAP:
212                 st->left= 0;
213                 allqueue(REDRAWTEXT, 0);
214                 allqueue(REDRAWHEADERS, 0);
215                 break;
216         }
217 }
218
219 static void do_text_template_scriptsmenu(void *arg, int event)
220 {
221         BPY_menu_do_python(PYMENU_SCRIPTTEMPLATE, event);
222         
223         allqueue(REDRAWIMAGE, 0);
224 }
225
226 static uiBlock *text_template_scriptsmenu (void *args_unused)
227 {
228         uiBlock *block;
229         BPyMenu *pym;
230         int i= 0;
231         short yco = 20, menuwidth = 120;
232         
233         block= uiNewBlock(&curarea->uiblocks, "text_template_scriptsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
234         uiBlockSetButmFunc(block, do_text_template_scriptsmenu, NULL);
235         
236         /* note that we acount for the N previous entries with i+20: */
237         for (pym = BPyMenuTable[PYMENU_SCRIPTTEMPLATE]; pym; pym = pym->next, i++) {
238                 
239                 uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, 
240                                                  NULL, 0.0, 0.0, 1, i, 
241                                                  pym->tooltip?pym->tooltip:pym->filename);
242         }
243         
244         uiBlockSetDirection(block, UI_RIGHT);
245         uiTextBoundsBlock(block, 60);
246         
247         return block;
248 }
249
250 static void do_text_plugin_scriptsmenu(void *arg, int event)
251 {
252         BPY_menu_do_python(PYMENU_TEXTPLUGIN, event);
253         
254         allqueue(REDRAWIMAGE, 0);
255 }
256
257 static uiBlock *text_plugin_scriptsmenu (void *args_unused)
258 {
259         uiBlock *block;
260         BPyMenu *pym;
261         int i= 0;
262         short yco = 20, menuwidth = 120;
263         
264         block= uiNewBlock(&curarea->uiblocks, "text_plugin_scriptsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
265         uiBlockSetButmFunc(block, do_text_plugin_scriptsmenu, NULL);
266         
267         /* note that we acount for the N previous entries with i+20: */
268         for (pym = BPyMenuTable[PYMENU_TEXTPLUGIN]; pym; pym = pym->next, i++) {
269                 
270                 uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, 
271                                                  NULL, 0.0, 0.0, 1, i, 
272                                                  pym->tooltip?pym->tooltip:pym->filename);
273         }
274         
275         uiBlockSetDirection(block, UI_RIGHT);
276         uiTextBoundsBlock(block, 60);
277         
278         return block;
279 }
280
281 /* action executed after clicking in File menu */
282 static void do_text_filemenu(void *arg, int event)
283 {
284         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
285         Text *text;
286         ScrArea *sa;
287         
288         if (st==NULL || st->spacetype != SPACE_TEXT) return;
289         
290         text= st->text;
291         
292         switch(event) {
293         case 1:
294                 st->text= add_empty_text( "Text" );
295                 st->top=0;
296                 
297                 allqueue(REDRAWTEXT, 0);
298                 allqueue(REDRAWHEADERS, 0);
299                 break;
300         case 2:
301                 activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
302                 break;
303         case 3:
304                 if (text->compiled) BPY_free_compiled_text(text);
305                         text->compiled = NULL;
306                         if (okee("Reopen Text")) {
307                                 if (!reopen_text(text)) {
308                                         error("Could not reopen file");
309                                 }
310                                 if (st->showsyntax) txt_format_text(st);
311                         }
312                 break;
313         case 5:
314                 text->flags |= TXT_ISMEM;
315         case 4:
316                 txt_write_file(text);
317                 break;
318         case 6:
319                 text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
320                 MEM_freeN(text->name);
321                 text->name= NULL;
322                 break;
323         case 7:
324                 run_python_script(st);
325                 break;
326         case 8:
327         {
328                 Object *ob;
329                 bConstraint *con;
330                 short update;
331                 
332                 /* check all pyconstraints */
333                 for (ob= G.main->object.first; ob; ob= ob->id.next) {
334                         update = 0;
335                         if (ob->type==OB_ARMATURE && ob->pose) {
336                                 bPoseChannel *pchan;
337                                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
338                                         for (con = pchan->constraints.first; con; con= con->next) {
339                                                 if (con->type==CONSTRAINT_TYPE_PYTHON) {
340                                                         bPythonConstraint *data = con->data;
341                                                         if (data->text==text) BPY_pyconstraint_update(ob, con);
342                                                         update = 1;
343                                                         
344                                                 }
345                                         }
346                                 }
347                         }
348                         for (con = ob->constraints.first; con; con= con->next) {
349                                 if (con->type==CONSTRAINT_TYPE_PYTHON) {
350                                         bPythonConstraint *data = con->data;
351                                         if (data->text==text) BPY_pyconstraint_update(ob, con);
352                                         update = 1;
353                                 }
354                         }
355                         
356                         if (update) {
357                                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
358                         }
359                 }
360         }
361                 break;
362         default:
363                 break;
364         }
365         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
366                 SpaceText *st= sa->spacedata.first;
367                 if (st && st->spacetype==SPACE_TEXT) {
368                         scrarea_queue_redraw(sa);
369                 }
370         }
371 }
372
373 /* action executed after clicking in Edit menu */
374 static void do_text_editmenu(void *arg, int event)
375 {
376         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
377         Text *text;
378         ScrArea *sa;
379         
380         if (st==NULL || st->spacetype != SPACE_TEXT) return;
381         
382         text= st->text;
383         
384         switch(event) {
385         case 1:
386                 txt_do_undo(text);
387                 pop_space_text(st);
388                 break;
389         case 2:
390                 txt_do_redo(text);
391                 pop_space_text(st);
392                 break;
393         case 3:
394                 if (text && text->id.lib) {
395                         error_libdata();
396                         break;
397                 }
398                 txt_copy_clipboard(text);
399                 txt_cut_sel(text);
400                 pop_space_text(st);
401                 break;
402         case 4:
403                 //txt_copy_sel(text);
404                 txt_copy_clipboard(text);
405                 break;
406         case 5:
407                 if (text && text->id.lib) {
408                         error_libdata();
409                         break;
410                 }
411                 txt_paste_clipboard(text);
412                 if (st->showsyntax) txt_format_text(st);
413                 break;
414         case 6:
415                 txt_print_cutbuffer();
416                 break;
417         case 7:
418                 jumptoline_interactive(st);
419                 break;
420         case 8:
421         case 9:
422                 find_and_replace(st, 0);
423                 break;
424         case 10:
425                 find_and_replace(st, 1);
426                 break;
427         default:
428                 break;
429         }
430
431         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
432                 SpaceText *st= sa->spacedata.first;
433                 if (st && st->spacetype==SPACE_TEXT) {
434                         scrarea_queue_redraw(sa);
435                 }
436         }
437 }
438
439 /* action executed after clicking in View menu */
440 static void do_text_editmenu_viewmenu(void *arg, int event)
441 {
442         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
443         Text *text;
444         ScrArea *sa;
445         
446         if (st==NULL || st->spacetype != SPACE_TEXT) return;
447         
448         text = st->text;
449         
450         switch(event) {
451                 case 1:
452                         txt_move_bof(text, 0);
453                         pop_space_text(st);
454                         break;
455                 case 2:
456                         txt_move_eof(text, 0);
457                         pop_space_text(st);
458                         break;
459                 default:
460                         break;
461         }
462
463         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
464                 SpaceText *st= sa->spacedata.first;
465                 if (st && st->spacetype==SPACE_TEXT) {
466                         scrarea_queue_redraw(sa);
467                 }
468         }
469 }
470
471 /* action executed after clicking in Select menu */
472 static void do_text_editmenu_selectmenu(void *arg, int event)
473 {
474         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
475         Text *text;
476         ScrArea *sa;
477         
478         if (st==NULL || st->spacetype != SPACE_TEXT) return;
479         
480         text = st->text;
481         
482         switch(event) {
483         case 1:
484                 txt_sel_all(text);
485                 break;          
486         case 2:
487                 txt_sel_line(text);
488                 break;
489         default:
490                 break;
491         }
492
493         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
494                 SpaceText *st= sa->spacedata.first;
495                 if (st && st->spacetype==SPACE_TEXT) {
496                         scrarea_queue_redraw(sa);
497                 }
498         }
499 }
500
501 /* action executed after clicking in Markers menu */
502 static void do_text_editmenu_markermenu(void *arg, int event)
503 {
504         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
505         Text *text;
506         TextMarker *mrk;
507         ScrArea *sa;
508         int lineno;
509         
510         if (st==NULL || st->spacetype != SPACE_TEXT) return;
511         
512         text = st->text;
513         
514         switch(event) {
515         case 1:
516                 txt_clear_markers(text, 0);
517                 break;
518         case 2:
519                 lineno= txt_get_span(text->lines.first, text->curl);
520                 mrk= text->markers.first;
521                 while (mrk && (mrk->lineno<lineno || (mrk->lineno==lineno && mrk->start <= text->curc)))
522                         mrk= mrk->next;
523                 if (!mrk) mrk= text->markers.first;
524                 if (mrk) {
525                         txt_move_to(text, mrk->lineno, mrk->start, 0);
526                         txt_move_to(text, mrk->lineno, mrk->end, 1);
527                 }
528                 break;
529         case 3:
530                 lineno= txt_get_span(text->lines.first, text->curl);
531                 mrk= text->markers.last;
532                 while (mrk && (mrk->lineno>lineno || (mrk->lineno==lineno && mrk->end > text->curc)))
533                         mrk= mrk->prev;
534                 if (!mrk) mrk= text->markers.last;
535                 if (mrk) {
536                         txt_move_to(text, mrk->lineno, mrk->start, 0);
537                         txt_move_to(text, mrk->lineno, mrk->end, 1);
538                 }
539                 break;
540         default:
541                 break;
542         }
543
544         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
545                 SpaceText *st= sa->spacedata.first;
546                 if (st && st->spacetype==SPACE_TEXT) {
547                         scrarea_queue_redraw(sa);
548                 }
549         }
550 }
551
552 /* action executed after clicking in Format menu */
553 static void do_text_formatmenu(void *arg, int event)
554 {
555         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
556         Text *text;
557         ScrArea *sa;
558         
559         if (st==NULL || st->spacetype != SPACE_TEXT) return;
560         
561         text = st->text;
562         
563         switch(event) {
564         case 3:
565                 if (text && text->id.lib) {
566                         error_libdata();
567                         break;
568                 }
569                 if (txt_has_sel(text)) {
570                         txt_order_cursors(text);
571                         indent(text);
572                         break;
573                 }
574                 else {
575                         txt_add_char(text, '\t');
576                         break;
577                 }
578         case 4:
579                 if (text && text->id.lib) {
580                         error_libdata();
581                         break;
582                 }
583                 if ( txt_has_sel(text)) {
584                         txt_order_cursors(text);
585                         unindent(text);
586                         break;
587                 }
588                 break;
589         case 5:
590                 if (text && text->id.lib) {
591                         error_libdata();
592                         break;
593                 }
594                 if ( txt_has_sel(text)) {
595                         txt_order_cursors(text);
596                         comment(text);
597                         if (st->showsyntax) txt_format_text(st);
598                         break;
599                 }
600                 break;
601         case 6:
602                 if (text && text->id.lib) {
603                         error_libdata();
604                         break;
605                 }
606                 if ( txt_has_sel(text)) {
607                         txt_order_cursors(text);
608                         uncomment(text);
609                         if (st->showsyntax) txt_format_text(st);
610                         break;
611                 }
612                 break;
613         default:
614                 break;
615         }
616
617         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
618                 SpaceText *st= sa->spacedata.first;
619                 if (st && st->spacetype==SPACE_TEXT) {
620                         scrarea_queue_redraw(sa);
621                 }
622         }
623 }
624
625 /* View menu */
626 static uiBlock *text_editmenu_viewmenu(void *arg_unused)
627 {
628         uiBlock *block;
629         short yco = 20, menuwidth = 120;
630
631         block= uiNewBlock(&curarea->uiblocks, "text_editmenu_viewmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
632         uiBlockSetButmFunc(block, do_text_editmenu_viewmenu, NULL);
633
634         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Top of File", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
635         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bottom of File", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
636
637         uiBlockSetDirection(block, UI_RIGHT);
638         uiTextBoundsBlock(block, 60);
639         
640         return block;
641 }
642
643 /* Select menu */
644 static uiBlock *text_editmenu_selectmenu(void *arg_unused)
645 {
646         uiBlock *block;
647         short yco = 20, menuwidth = 120;
648
649         block= uiNewBlock(&curarea->uiblocks, "text_editmenu_selectmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
650         uiBlockSetButmFunc(block, do_text_editmenu_selectmenu, NULL);
651
652         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select All|Ctrl A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
653         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Line", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
654         
655         uiBlockSetDirection(block, UI_RIGHT);
656         uiTextBoundsBlock(block, 60);
657         
658         return block;
659 }
660
661 /* Select menu */
662 static uiBlock *text_editmenu_markermenu(void *arg_unused)
663 {
664         uiBlock *block;
665         short yco = 20, menuwidth = 120;
666
667         block= uiNewBlock(&curarea->uiblocks, "text_editmenu_markermenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
668         uiBlockSetButmFunc(block, do_text_editmenu_markermenu, NULL);
669
670         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear All", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
671         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Next Marker", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
672         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Previous Marker", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
673         
674         uiBlockSetDirection(block, UI_RIGHT);
675         uiTextBoundsBlock(block, 60);
676         
677         return block;
678 }
679
680 void do_text_formatmenu_convert(void *arg, int event)
681 {
682         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
683         
684         if (st==NULL || st->spacetype != SPACE_TEXT) return;
685         
686         switch(event) {
687         case 1: convert_tabs(st, 0); break;
688         case 2: convert_tabs(st, 1); break;
689         }
690         allqueue(REDRAWVIEW3D, 0);
691 }
692
693 static uiBlock *text_formatmenu_convert(void *arg_unused)
694 {
695         uiBlock *block;
696         short yco = 20, menuwidth = 120;
697
698         block= uiNewBlock(&curarea->uiblocks, "do_text_formatmenu_convert", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
699         uiBlockSetButmFunc(block, do_text_formatmenu_convert, NULL);
700
701         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Spaces",              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "Converts script whitespace to spaces based on Tab:");
702         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Tabs",                0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "Converts script whitespace to tabs based on Tab:");
703         
704         uiBlockSetDirection(block, UI_RIGHT);
705         uiTextBoundsBlock(block, 60);
706         return block;
707 }
708
709 /* Format menu */
710 static uiBlock *text_formatmenu(void *arg_unused)
711 {
712         uiBlock *block;
713         short yco= 0, menuwidth=120;
714
715         block= uiNewBlock(&curarea->uiblocks, "text_formatmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
716         uiBlockSetButmFunc(block, do_text_formatmenu, NULL);
717
718         uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
719         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Indent|Tab", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
720         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unindent|Shift Tab", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
721         uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
722         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Comment", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
723         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Uncomment|Ctrl Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
724         uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
725         uiDefIconTextBlockBut(block, text_formatmenu_convert, NULL, ICON_RIGHTARROW_THIN, "Convert whitespace", 0, yco-=20, menuwidth, 19, "");
726         
727         if(curarea->headertype==HEADERTOP) {
728                 uiBlockSetDirection(block, UI_DOWN);
729         }
730         else {
731                 uiBlockSetDirection(block, UI_TOP);
732                 uiBlockFlipOrder(block);
733         }
734
735         uiTextBoundsBlock(block, 50);
736         return block;
737 }
738
739
740 /* action executed after clicking in Object to 3d Sub Menu */
741 void do_text_editmenu_to3dmenu(void *arg, int event)
742 {
743         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
744         Text *text;
745         if (st==NULL || st->spacetype != SPACE_TEXT) return;
746         
747         text = st->text;
748         
749         switch(event) {
750         case 1: txt_export_to_object(text); break;
751         case 2: txt_export_to_objects(text); break;
752         }
753         allqueue(REDRAWVIEW3D, 0);
754 }
755
756 /* Object to 3d Sub Menu */
757 static uiBlock *text_editmenu_to3dmenu(void *arg_unused)
758 {
759         uiBlock *block;
760         short yco = 20, menuwidth = 120;
761
762         block= uiNewBlock(&curarea->uiblocks, "do_text_editmenu_to3dmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
763         uiBlockSetButmFunc(block, do_text_editmenu_to3dmenu, NULL);
764
765         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "One Object | Alt-M",             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
766         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "One Object Per Line",            0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
767         
768         uiBlockSetDirection(block, UI_RIGHT);
769         uiTextBoundsBlock(block, 60);
770         return block;
771 }
772
773
774 /* Edit menu */
775 static uiBlock *text_editmenu(void *arg_unused)
776 {
777         uiBlock *block;
778         short yco= 0, menuwidth=120;
779
780         block= uiNewBlock(&curarea->uiblocks, "text_editmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
781         uiBlockSetButmFunc(block, do_text_editmenu, NULL);
782
783         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo|Ctrl Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
784         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Redo|Ctrl Shift Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
785         uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
786         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cut|Alt X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
787         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Copy|Alt C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
788         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Paste|Alt V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
789         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Print Cut Buffer", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
790         uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
791         uiDefIconTextBlockBut(block, text_editmenu_viewmenu, NULL, ICON_RIGHTARROW_THIN, "View|Alt Shift V   ", 0, yco-=20, 120, 19, "");
792         uiDefIconTextBlockBut(block, text_editmenu_selectmenu, NULL, ICON_RIGHTARROW_THIN, "Select|Alt Shift S   ", 0, yco-=20, 120, 19, "");
793         uiDefIconTextBlockBut(block, text_editmenu_markermenu, NULL, ICON_RIGHTARROW_THIN, "Markers", 0, yco-=20, 120, 19, "");
794         uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
795         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump...|Alt J", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
796         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find And Replace...|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
797         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Next|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
798         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Replace|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
799         uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
800         uiDefIconTextBlockBut(block, text_editmenu_to3dmenu, NULL, ICON_RIGHTARROW_THIN, "Text to 3d Object", 0, yco-=20, 120, 19, "");
801         
802         if(curarea->headertype==HEADERTOP) {
803                 uiBlockSetDirection(block, UI_DOWN);
804         }
805         else {
806                 uiBlockSetDirection(block, UI_TOP);
807                 uiBlockFlipOrder(block);
808         }
809
810         uiTextBoundsBlock(block, 50);
811         return block;
812 }
813
814 /* File menu */
815 static uiBlock *text_filemenu(void *arg_unused)
816 {
817         SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
818         Text *text= st->text;
819         uiBlock *block;
820         short yco= 0, menuwidth=120;
821
822         block= uiNewBlock(&curarea->uiblocks, "text_filemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
823         uiBlockSetButmFunc(block, do_text_filemenu, NULL);
824
825         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "New|Alt N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
826         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Open...|Alt O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
827         
828         if(text) {
829                 uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reopen|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
830                 
831                 uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
832                 
833                 uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
834                 uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save As...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
835                 
836                 if (text->name)
837                         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Internal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
838
839                 uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
840                 
841                 uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Run Python Script|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
842                 
843                 if (BPY_is_pyconstraint(text))
844                         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Refresh All PyConstraints", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
845                         
846                 uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
847         }
848         
849         uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, "");
850         uiDefIconTextBlockBut(block, text_plugin_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Text Plugins", 0, yco-=20, 120, 19, "");
851
852         if(curarea->headertype==HEADERTOP) {
853                 uiBlockSetDirection(block, UI_DOWN);
854         }
855         else {
856                 uiBlockSetDirection(block, UI_TOP);
857                 uiBlockFlipOrder(block);
858         }
859
860         uiTextBoundsBlock(block, 50);
861         return block;
862 }
863
864 /* header */
865 #define PATH_MAX        260
866 void text_buttons(void)
867 {
868         uiBlock *block;
869         SpaceText *st= curarea->spacedata.first;
870         Text *text;
871         short xco, xmax;
872         char naam[256], fname[PATH_MAX], headtxt[PATH_MAX+17];
873         int len;
874         
875         if (st==NULL || st->spacetype != SPACE_TEXT) return;
876         
877         text = st->text;
878
879         sprintf(naam, "header %d", curarea->headwin);
880         block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
881
882         if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
883         else uiBlockSetCol(block, TH_HEADERDESEL);
884
885         curarea->butspacetype= SPACE_TEXT;
886
887         xco = 8;
888         uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
889         xco+= XIC+14;
890
891         uiBlockSetEmboss(block, UI_EMBOSSN);
892         if(curarea->flag & HEADER_NO_PULLDOWN) {
893                 uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
894                                 xco,2,XIC,YIC-2,
895                                 &(curarea->flag), 0, 0, 0, 0, "Enables display of pulldown menus");
896         } else {
897                 uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
898                                 xco,2,XIC,YIC-2,
899                                 &(curarea->flag), 0, 0, 0, 0, "Hides pulldown menus");
900         }
901         uiBlockSetEmboss(block, UI_EMBOSS);
902         xco+=XIC;
903
904         /* pull down menus */
905         if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
906                 uiBlockSetEmboss(block, UI_EMBOSSP);
907         
908                 xmax= GetButStringLength("File");
909                 uiDefPulldownBut(block,text_filemenu, NULL, "File", xco, 0, xmax, 20, "");
910                 xco+=xmax;
911         
912                 if(text) {
913                         xmax= GetButStringLength("Edit");
914                         uiDefPulldownBut(block,text_editmenu, NULL, "Edit", xco, 0, xmax, 20, "");
915                         xco+=xmax;
916                         
917                         xmax= GetButStringLength("Format");
918                         uiDefPulldownBut(block,text_formatmenu, NULL, "Format", xco, 0, xmax, 20, "");
919                         xco+=xmax;
920                 }
921         }
922         uiBlockSetEmboss(block, UI_EMBOSS);
923         xco += 10;
924         
925         /* FULL WINDOW */
926         uiBlockBeginAlign(block);
927         if(curarea->full) uiDefIconBut(block, BUT,B_FULL, ICON_SPLITSCREEN,     xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Returns to multiple views window (CTRL+Up arrow)");
928         else uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN,   xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Makes current window full screen (CTRL+Down arrow)");
929                 
930         uiDefIconButI(block, ICONTOG, B_TEXTLINENUM, ICON_LONGDISPLAY, xco+=XIC,0,XIC,YIC, &st->showlinenrs, 0, 0, 0, 0, "Displays line numbers");
931         uiDefIconButI(block, ICONTOG, B_WORDWRAP, ICON_WORDWRAP, xco+=XIC,0,XIC,YIC, &st->wordwrap, 0, 0, 0, 0, "Enables word wrap");
932         uiDefIconButI(block, ICONTOG, B_SYNTAX, ICON_SYNTAX, xco+=XIC,0,XIC,YIC, &st->showsyntax, 0, 0, 0, 0, "Enables syntax highlighting");
933         uiDefIconButI(block, ICONTOG, B_TEXTPLUGINS, ICON_PYTHON, xco+=XIC,0,XIC,YIC, &st->doplugins, 0, 0, 0, 0, "Enables Python text plugins");
934         uiBlockEndAlign(block);
935         
936         /* STD TEXT BUTTONS */
937         xco+= 2*XIC;
938         xco= std_libbuttons(block, xco, 0, 0, NULL, B_TEXTBROWSE, ID_TXT, 0, (ID*)st->text, 0, &(st->menunr), 0, 0, B_TEXTDELETE, 0, 0);
939
940         /*
941         if (st->text) {
942                 if (st->text->flags & TXT_ISDIRTY && (st->text->flags & TXT_ISEXT || !(st->text->flags & TXT_ISMEM)))
943                         uiDefIconBut(block, BUT,0, ICON_ERROR, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "The text has been changed");
944                 if (st->text->flags & TXT_ISEXT) 
945                         uiDefBut(block, BUT,B_TEXTSTORE, ICON(),        xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Stores text in project file");
946                 else 
947                         uiDefBut(block, BUT,B_TEXTSTORE, ICON(),        xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Disables storing of text in project file");
948                 xco+=10;
949         }
950         */              
951
952         xco+=XIC;
953         if(st->font_id>1) st->font_id= 0;
954         uiDefButI(block, MENU, B_TEXTFONT, "Screen 12 %x0|Screen 15%x1", xco,0,100,YIC, &st->font_id, 0, 0, 0, 0, "Displays available fonts");
955         xco+=110;
956         
957         uiDefButI(block, NUM, B_TAB_NUMBERS, "Tab:", xco, 0, XIC+50, YIC, &st->tabnumber, 2, 8, 0, 0, "Set spacing of Tab");
958         xco+= XIC+50;
959
960         /* File info */
961         if (text) {
962                 if (text->name) {
963                         len = strlen(text->name);
964                         if (len > PATH_MAX-1)
965                                 len = PATH_MAX-1;
966                         strncpy(fname, text->name, len);
967                         fname[len]='\0';
968                         if (text->flags & TXT_ISDIRTY)
969                                 sprintf(headtxt, "File: *%s (unsaved)", fname);
970                         else
971                                 sprintf(headtxt, "File: %s", fname);
972                 } else {
973                         sprintf(headtxt, text->id.lib?"Text: External":"Text: Internal");
974                 }
975                 BIF_ThemeColor(TH_MENU_TEXT);
976                 glRasterPos2i(xco+=XIC, 5);
977                 BMF_DrawString(G.font, headtxt);
978                 xco += BMF_GetStringWidth(G.font, headtxt);
979         }
980
981         /* always as last  */
982         curarea->headbutlen= xco+2*XIC;
983
984         uiDrawBlock(block);
985 }