UI:
[blender.git] / source / blender / editors / space_text / text_header.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) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32
33 /* file time checking */
34 #include <ctype.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #ifndef _WIN32
39 #include <unistd.h>
40 #else
41 #include <io.h>
42 #include "BLI_winstuff.h"
43 #endif
44
45 #include "DNA_space_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_text_types.h"
49 #include "DNA_windowmanager_types.h"
50
51 #include "MEM_guardedalloc.h"
52
53 #include "BLI_blenlib.h"
54
55 #include "BKE_context.h"
56 #include "BKE_global.h"
57 #include "BKE_library.h"
58 #include "BKE_main.h"
59 #include "BKE_screen.h"
60 #include "BKE_text.h"
61
62 #include "ED_screen.h"
63 #include "ED_types.h"
64 #include "ED_util.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "BIF_gl.h"
70 #include "BIF_glutil.h"
71
72 #include "UI_interface.h"
73 #include "UI_resources.h"
74 #include "UI_text.h"
75 #include "UI_view2d.h"
76
77 #include "RNA_access.h"
78
79 #ifndef DISABLE_PYTHON
80 #include "BPY_extern.h"
81 // XXX #include "BPY_menus.h"
82 #endif
83
84 #include "text_intern.h"
85
86 #define HEADER_PATH_MAX 260
87
88 /* ************************ header area region *********************** */
89
90 #ifndef DISABLE_PYTHON
91 static void do_text_template_scriptsmenu(bContext *C, void *arg, int event)
92 {
93         // XXX BPY_menu_do_python(PYMENU_SCRIPTTEMPLATE, event);
94 }
95
96 static uiBlock *text_template_scriptsmenu(bContext *C, void *args_unused)
97 {
98         ARegion *ar= CTX_wm_region(C);
99         uiBlock *block;
100         // XXX BPyMenu *pym;
101         // int i= 0;
102         // short yco = 20, menuwidth = 120;
103         
104         block= uiBeginBlock(C, ar, "text_template_scriptsmenu", UI_EMBOSSP, UI_HELV);
105         uiBlockSetButmFunc(block, do_text_template_scriptsmenu, NULL);
106         
107         /* note that we acount for the N previous entries with i+20: */
108         /* XXX for (pym = BPyMenuTable[PYMENU_SCRIPTTEMPLATE]; pym; pym = pym->next, i++) {
109                 
110                 uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, 
111                                                  NULL, 0.0, 0.0, 1, i, 
112                                                  pym->tooltip?pym->tooltip:pym->filename);
113         }*/
114         
115         uiBlockSetDirection(block, UI_RIGHT);
116         uiTextBoundsBlock(block, 60);
117
118         uiEndBlock(C, block);
119         uiDrawBlock(C, block);
120         
121         return block;
122 }
123
124 static void do_text_plugin_scriptsmenu(bContext *C, void *arg, int event)
125 {
126         // XXX BPY_menu_do_python(PYMENU_TEXTPLUGIN, event);
127 }
128
129 static uiBlock *text_plugin_scriptsmenu(bContext *C, void *args_unused)
130 {
131         ARegion *ar= CTX_wm_region(C);
132         uiBlock *block;
133         // XXX BPyMenu *pym;
134         // int i= 0;
135         // short yco = 20, menuwidth = 120;
136         
137         block= uiBeginBlock(C, ar, "text_plugin_scriptsmenu", UI_EMBOSSP, UI_HELV);
138         uiBlockSetButmFunc(block, do_text_plugin_scriptsmenu, NULL);
139         
140         /* note that we acount for the N previous entries with i+20: */
141         /* XXX for (pym = BPyMenuTable[PYMENU_TEXTPLUGIN]; pym; pym = pym->next, i++) {
142                 
143                 uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, 
144                                                  NULL, 0.0, 0.0, 1, i, 
145                                                  pym->tooltip?pym->tooltip:pym->filename);
146         }*/
147         
148         uiBlockSetDirection(block, UI_RIGHT);
149         uiTextBoundsBlock(block, 60);
150
151         uiEndBlock(C, block);
152         uiDrawBlock(C, block);
153
154         return block;
155 }
156 #endif
157
158 static void text_editmenu_viewmenu(bContext *C, uiMenuItem *head, void *arg_unused)
159 {
160         uiMenuItemEnumO(head, "Top of File", 0, "TEXT_OT_move", "type", FILE_TOP);
161         uiMenuItemEnumO(head, "Bottom of File", 0, "TEXT_OT_move", "type", FILE_BOTTOM);
162 }
163
164 static void text_editmenu_selectmenu(bContext *C, uiMenuItem *head, void *arg_unused)
165 {
166         uiMenuItemO(head, 0, "TEXT_OT_select_all");
167         uiMenuItemO(head, 0, "TEXT_OT_select_line");
168 }
169
170 static void text_editmenu_markermenu(bContext *C, uiMenuItem *head, void *arg_unused)
171 {
172         uiMenuItemO(head, 0, "TEXT_OT_markers_clear");
173         uiMenuItemO(head, 0, "TEXT_OT_next_marker");
174         uiMenuItemO(head, 0, "TEXT_OT_previous_marker");
175 }
176
177 static void text_formatmenu(bContext *C, uiMenuItem *head, void *arg_unused)
178 {
179         uiMenuItemO(head, 0, "TEXT_OT_indent");
180         uiMenuItemO(head, 0, "TEXT_OT_unindent");
181
182         uiMenuSeparator(head);
183
184         uiMenuItemO(head, 0, "TEXT_OT_comment");
185         uiMenuItemO(head, 0, "TEXT_OT_uncomment");
186
187         uiMenuSeparator(head);
188
189         uiMenuLevelEnumO(head, "TEXT_OT_convert_whitespace", "type");
190 }
191
192 static void text_editmenu_to3dmenu(bContext *C, uiMenuItem *head, void *arg_unused)
193 {
194         uiMenuItemBooleanO(head, "One Object", 0, "TEXT_OT_to_3d_object", "split_lines", 0);
195         uiMenuItemBooleanO(head, "One Object Per Line", 0, "TEXT_OT_to_3d_object", "split_lines", 1);
196 }
197
198 static int text_menu_edit_poll(bContext *C)
199 {
200         return (CTX_data_edit_text(C) != NULL);
201 }
202
203 static void text_editmenu(bContext *C, uiMenuItem *head, void *arg_unused)
204 {
205         uiMenuItemO(head, 0, "ED_OT_undo");
206         uiMenuItemO(head, 0, "ED_OT_redo");
207
208         uiMenuSeparator(head);
209
210         uiMenuItemO(head, 0, "TEXT_OT_cut");
211         uiMenuItemO(head, 0, "TEXT_OT_copy");
212         uiMenuItemO(head, 0, "TEXT_OT_paste");
213
214         uiMenuSeparator(head);
215
216         uiMenuLevel(head, "View", text_editmenu_viewmenu);
217         uiMenuLevel(head, "Select", text_editmenu_selectmenu);
218         uiMenuLevel(head, "Markers", text_editmenu_markermenu);
219
220         uiMenuSeparator(head);
221
222         uiMenuItemO(head, 0, "TEXT_OT_jump");
223         uiMenuItemO(head, 0, "TEXT_OT_properties");
224
225         uiMenuSeparator(head);
226
227         uiMenuLevel(head, "Text to 3D Object", text_editmenu_to3dmenu);
228 }
229
230 static void text_filemenu(bContext *C, uiMenuItem *head, void *arg_unused)
231 {
232         SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
233         Text *text= st->text;
234
235         uiMenuItemO(head, 0, "TEXT_OT_new");
236         uiMenuItemO(head, 0, "TEXT_OT_open");
237         
238         if(text) {
239                 uiMenuItemO(head, 0, "TEXT_OT_reload");
240                 
241                 uiMenuSeparator(head);
242                 
243                 uiMenuItemO(head, 0, "TEXT_OT_save");
244                 uiMenuItemO(head, 0, "TEXT_OT_save_as");
245                 
246                 if(text->name)
247                         uiMenuItemO(head, 0, "TEXT_OT_make_internal");
248
249                 uiMenuSeparator(head);
250                 
251                 uiMenuItemO(head, 0, "TEXT_OT_run_script");
252
253 #ifndef DISABLE_PYTHON
254                 if(BPY_is_pyconstraint(text))
255                         uiMenuItemO(head, 0, "TEXT_OT_refresh_pyconstraints");
256 #endif
257         }
258
259 #ifndef DISABLE_PYTHON
260         // XXX uiMenuSeparator(head);
261
262         // XXX uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, "");
263         // XXX uiDefIconTextBlockBut(block, text_plugin_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Text Plugins", 0, yco-=20, 120, 19, "");
264 #endif
265 }
266
267 /*********************** datablock browse *************************/
268
269 static void text_unlink(Main *bmain, Text *text)
270 {
271         bScreen *scr;
272         ScrArea *area;
273         SpaceLink *sl;
274
275         /* XXX this ifdef is in fact dangerous, if python is
276          * disabled it will leave invalid pointers in files! */
277
278 #ifndef DISABLE_PYTHON
279         // XXX BPY_clear_bad_scriptlinks(text);
280         // XXX BPY_free_pyconstraint_links(text);
281         // XXX free_text_controllers(text);
282
283         /* check if this text was used as script link:
284          * this check function unsets the pointers and returns how many
285          * script links used this Text */
286         if(0) // XXX BPY_text_check_all_scriptlinks (text))
287                 ; // XXX notifier: allqueue(REDRAWBUTSSCRIPT, 0);
288
289         /* equivalently for pynodes: */
290         if(0) // XXX nodeDynamicUnlinkText ((ID*)text))
291                 ; // XXX notifier: allqueue(REDRAWNODE, 0);
292 #endif
293         
294         for(scr= bmain->screen.first; scr; scr= scr->id.next) {
295                 for(area= scr->areabase.first; area; area= area->next) {
296                         for(sl= area->spacedata.first; sl; sl= sl->next) {
297                                 if(sl->spacetype==SPACE_TEXT) {
298                                         SpaceText *st= (SpaceText*) sl;
299                                         
300                                         if(st->text==text) {
301                                                 st->text= NULL;
302                                                 st->top= 0;
303                                                 
304                                                 if(st==area->spacedata.first)
305                                                         ED_area_tag_redraw(area);
306                                         }
307                                 }
308                         }
309                 }
310         }
311
312         free_libblock(&bmain->text, text);
313 }
314
315 static void text_idpoin_handle(bContext *C, ID *id, int event)
316 {
317         SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
318         Text *text;
319
320         switch(event) {
321                 case UI_ID_BROWSE:
322                         st->text= (Text*)id;
323                         st->top= 0;
324
325                         text_update_edited(st->text);
326                         WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
327
328                         ED_undo_push(C, "Browse Text");
329                         break;
330                 case UI_ID_DELETE:
331                         text= st->text;
332
333                         /* make the previous text active, if its not there make the next text active */
334                         if(text->id.prev) {
335                                 st->text = text->id.prev;
336                                 WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
337                         }
338                         else if(text->id.next) {
339                                 st->text = text->id.next;
340                                 WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
341                         }
342
343                         text_unlink(CTX_data_main(C), text);
344                         WM_event_add_notifier(C, NC_TEXT|NA_REMOVED, text);
345
346                         ED_undo_push(C, "Delete Text");
347                         break;
348                 case UI_ID_RENAME:
349                         break;
350                 case UI_ID_ADD_NEW:
351                         WM_operator_name_call(C, "TEXT_OT_new", WM_OP_INVOKE_REGION_WIN, NULL);
352                         break;
353                 case UI_ID_OPEN:
354                         WM_operator_name_call(C, "TEXT_OT_open", WM_OP_INVOKE_REGION_WIN, NULL);
355                         break;
356         }
357 }
358
359 /********************** header buttons ***********************/
360
361 static void text_header_draw(const bContext *C, uiLayout *layout)
362 {
363         bScreen *sc= CTX_wm_screen(C);
364         SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
365         PointerRNA spaceptr;
366         Text *text= st->text;
367         
368         RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
369
370         uiTemplateHeaderMenus(layout);
371         uiItemMenu(layout, UI_TSLOT_HEADER, "Text", 0, text_filemenu);
372         if(text) {
373                 uiItemMenu(layout, UI_TSLOT_HEADER, "Edit", 0, text_editmenu);
374                 uiItemMenu(layout, UI_TSLOT_HEADER, "Format", 0, text_formatmenu);
375         }
376
377         /* warning button if text is out of date */
378         if(text && text_file_modified(text)) {
379                 uiTemplateHeaderButtons(layout);
380                 uiTemplateSetColor(layout, TH_REDALERT);
381                 uiItemO(layout, UI_TSLOT_HEADER, "", ICON_HELP, "TEXT_OT_resolve_conflict");
382         }
383
384         uiTemplateHeaderButtons(layout);
385         uiItemR(layout, UI_TSLOT_HEADER, "", ICON_LINENUMBERS_OFF, &spaceptr, "line_numbers");
386         uiItemR(layout, UI_TSLOT_HEADER, "", ICON_WORDWRAP_OFF, &spaceptr, "word_wrap");
387         uiItemR(layout, UI_TSLOT_HEADER, "", ICON_SYNTAX_OFF, &spaceptr, "syntax_highlight");
388         // XXX uiItemR(layout, "", ICON_SCRIPTPLUGINS, &spaceptr, "do_python_plugins");
389
390         uiTemplateHeaderID(layout, &spaceptr, "text",
391                 UI_ID_BROWSE|UI_ID_RENAME|UI_ID_ADD_NEW|UI_ID_OPEN|UI_ID_DELETE,
392                 text_idpoin_handle);
393
394         /* file info */
395         if(text) {
396                 char fname[HEADER_PATH_MAX];
397                 static char headtxt[HEADER_PATH_MAX+17];
398                 int len;
399
400                 if(text->name) {
401                         len = strlen(text->name);
402                         if(len > HEADER_PATH_MAX-1)
403                                 len = HEADER_PATH_MAX-1;
404                         strncpy(fname, text->name, len);
405                         fname[len]='\0';
406                         if(text->flags & TXT_ISDIRTY)
407                                 sprintf(headtxt, "File: *%s (unsaved)", fname);
408                         else
409                                 sprintf(headtxt, "File: %s", fname);
410                 }
411                 else
412                         sprintf(headtxt, text->id.lib? "Text: External": "Text: Internal");
413
414                 uiTemplateHeaderButtons(layout);
415                 uiItemLabel(layout, UI_TSLOT_HEADER, headtxt, 0);
416         }
417 }
418
419 void text_header_register(ARegionType *art)
420 {
421         HeaderType *ht;
422
423         /* header */
424         ht= MEM_callocN(sizeof(HeaderType), "spacetype text header");
425         ht->idname= "TEXT_HT_header";
426         ht->name= "Header";
427         ht->draw= text_header_draw;
428         BLI_addhead(&art->headertypes, ht);
429 }
430
431 /************************** properties ******************************/
432
433 static void text_properties_panel_draw(const bContext *C, Panel *panel)
434 {
435         bScreen *sc= CTX_wm_screen(C);
436         SpaceText *st= CTX_wm_space_text(C);
437         uiLayout *layout= panel->layout;
438         PointerRNA spaceptr;
439         
440         RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
441
442         uiTemplateColumn(layout);
443         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, ICON_LINENUMBERS_OFF, &spaceptr, "line_numbers");
444         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, ICON_WORDWRAP_OFF, &spaceptr, "word_wrap");
445         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, ICON_SYNTAX_OFF, &spaceptr, "syntax_highlight");
446
447         uiTemplateColumn(layout);
448         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, 0, &spaceptr, "font_size");
449         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, 0, &spaceptr, "tab_width");
450 }
451
452 static void text_find_panel_draw(const bContext *C, Panel *panel)
453 {
454         bScreen *sc= CTX_wm_screen(C);
455         SpaceText *st= CTX_wm_space_text(C);
456         uiLayout *layout= panel->layout;
457         PointerRNA spaceptr;
458         
459         RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
460
461         /* find */
462         uiTemplateLeftRight(layout);
463         uiItemR(layout, UI_TSLOT_LR_LEFT, "", 0, &spaceptr, "find_text");
464         uiItemO(layout, UI_TSLOT_LR_RIGHT, "", ICON_TEXT, "TEXT_OT_find_set_selected");
465         uiTemplateColumn(layout);
466         uiItemO(layout, UI_TSLOT_COLUMN_1, NULL, 0, "TEXT_OT_find");
467
468         /* replace */
469         uiTemplateLeftRight(layout);
470         uiItemR(layout, UI_TSLOT_LR_LEFT, "", 0, &spaceptr, "replace_text");
471         uiItemO(layout, UI_TSLOT_LR_RIGHT, "", ICON_TEXT, "TEXT_OT_replace_set_selected");
472         uiTemplateColumn(layout);
473         uiItemO(layout, UI_TSLOT_COLUMN_1, NULL, 0, "TEXT_OT_replace");
474
475         /* mark */
476         uiTemplateColumn(layout);
477         uiItemO(layout, UI_TSLOT_COLUMN_1, NULL, 0, "TEXT_OT_mark_all");
478
479         /* settings */
480         uiTemplateColumn(layout);
481         uiItemR(layout, UI_TSLOT_COLUMN_1, "Wrap", 0, &spaceptr, "find_wrap");
482         uiItemR(layout, UI_TSLOT_COLUMN_2, "All", 0, &spaceptr, "find_all");
483 }
484
485 void text_properties_register(ARegionType *art)
486 {
487         PanelType *pt;
488
489         /* panels: properties */
490         pt= MEM_callocN(sizeof(PanelType), "spacetype text panel");
491         pt->idname= "TEXT_PT_properties";
492         pt->name= "Properties";
493         pt->draw= text_properties_panel_draw;
494         BLI_addtail(&art->paneltypes, pt);
495
496         /* panels: find */
497         pt= MEM_callocN(sizeof(PanelType), "spacetype text panel");
498         pt->idname= "TEXT_PT_find";
499         pt->name= "Find";
500         pt->draw= text_find_panel_draw;
501         BLI_addtail(&art->paneltypes, pt);
502 }
503
504 ARegion *text_has_properties_region(ScrArea *sa)
505 {
506         ARegion *ar, *arnew;
507         
508         for(ar= sa->regionbase.first; ar; ar= ar->next)
509                 if(ar->regiontype==RGN_TYPE_UI)
510                         return ar;
511         
512         /* add subdiv level; after header */
513         for(ar= sa->regionbase.first; ar; ar= ar->next)
514                 if(ar->regiontype==RGN_TYPE_HEADER)
515                         break;
516         
517         /* is error! */
518         if(ar==NULL) return NULL;
519         
520         arnew= MEM_callocN(sizeof(ARegion), "properties region");
521         
522         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
523         arnew->regiontype= RGN_TYPE_UI;
524         arnew->alignment= RGN_ALIGN_LEFT;
525         
526         arnew->flag = RGN_FLAG_HIDDEN;
527         
528         return arnew;
529 }
530
531 static int properties_poll(bContext *C)
532 {
533         SpaceText *st= CTX_wm_space_text(C);
534         Text *text= CTX_data_edit_text(C);
535
536         return (st && text);
537 }
538
539 static int properties_exec(bContext *C, wmOperator *op)
540 {
541         ScrArea *sa= CTX_wm_area(C);
542         ARegion *ar= text_has_properties_region(sa);
543         
544         if(ar) {
545                 ar->flag ^= RGN_FLAG_HIDDEN;
546                 ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
547                 
548                 ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
549                 ED_area_tag_redraw(sa);
550         }
551
552         return OPERATOR_FINISHED;
553 }
554
555 void TEXT_OT_properties(wmOperatorType *ot)
556 {
557         /* identifiers */
558         ot->name= "Properties";
559         ot->idname= "TEXT_OT_properties";
560         
561         /* api callbacks */
562         ot->exec= properties_exec;
563         ot->poll= properties_poll;
564 }
565
566 /******************** XXX popup menus *******************/
567
568 #if 0
569 {
570         // RMB
571
572         uiMenuItem *head;
573
574         if(text) {
575                 head= uiPupMenuBegin("Text", 0);
576                 if(txt_has_sel(text)) {
577                         uiMenuItemO(head, 0, "TEXT_OT_cut");
578                         uiMenuItemO(head, 0, "TEXT_OT_copy");
579                 }
580                 uiMenuItemO(head, 0, "TEXT_OT_paste");
581                 uiMenuItemO(head, 0, "TEXT_OT_new");
582                 uiMenuItemO(head, 0, "TEXT_OT_open");
583                 uiMenuItemO(head, 0, "TEXT_OT_save");
584                 uiMenuItemO(head, 0, "TEXT_OT_save_as");
585                 uiMenuItemO(head, 0, "TEXT_OT_run_script");
586                 uiPupMenuEnd(C, head);
587         }
588         else {
589                 head= uiPupMenuBegin("File", 0);
590                 uiMenuItemO(head, 0, "TEXT_OT_new");
591                 uiMenuItemO(head, 0, "TEXT_OT_open");
592                 uiPupMenuEnd(C, head);
593         }
594 }
595
596 {
597         // Alt+Shift+E
598
599         uiMenuItem *head;
600
601         head= uiPupMenuBegin("Edit", 0);
602         uiMenuItemO(head, 0, "TEXT_OT_cut");
603         uiMenuItemO(head, 0, "TEXT_OT_copy");
604         uiMenuItemO(head, 0, "TEXT_OT_paste");
605         uiPupMenuEnd(C, head);
606 }
607
608 {
609         // Alt+Shift+F
610
611         uiMenuItem *head;
612
613         if(text) {
614                 head= uiPupMenuBegin("Text", 0);
615                 uiMenuItemO(head, 0, "TEXT_OT_new");
616                 uiMenuItemO(head, 0, "TEXT_OT_open");
617                 uiMenuItemO(head, 0, "TEXT_OT_save");
618                 uiMenuItemO(head, 0, "TEXT_OT_save_as");
619                 uiMenuItemO(head, 0, "TEXT_OT_run_script");
620                 uiPupMenuEnd(C, head);
621         }
622         else {
623                 head= uiPupMenuBegin("File", 0);
624                 uiMenuItemO(head, 0, "TEXT_OT_new");
625                 uiMenuItemO(head, 0, "TEXT_OT_open");
626                 uiPupMenuEnd(C, head);
627         }
628 }
629
630 {
631         // Alt+Shift+V
632
633         uiMenuItem *head;
634
635         head= uiPupMenuBegin("Text", 0);
636         uiMenuItemEnumO(head, "Top of File", 0, "TEXT_OT_move", "type", FILE_TOP);
637         uiMenuItemEnumO(head, "Bottom of File", 0, "TEXT_OT_move", "type", FILE_BOTTOM);
638         uiMenuItemEnumO(head, "Page Up", 0, "TEXT_OT_move", "type", PREV_PAGE);
639         uiMenuItemEnumO(head,  "Page Down", 0, "TEXT_OT_move", "type", NEXT_PAGE);
640         uiPupMenuEnd(C, head);
641 }
642 #endif
643