2.5: UI Layout Engine, initial code.
[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 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 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_clear_all_markers");
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 void text_editmenu(bContext *C, uiMenuItem *head, void *arg_unused)
199 {
200         uiMenuItemO(head, 0, "ED_OT_undo");
201         uiMenuItemO(head, 0, "ED_OT_redo");
202
203         uiMenuSeparator(head);
204
205         uiMenuItemO(head, 0, "TEXT_OT_cut");
206         uiMenuItemO(head, 0, "TEXT_OT_copy");
207         uiMenuItemO(head, 0, "TEXT_OT_paste");
208
209         uiMenuSeparator(head);
210
211         uiMenuLevel(head, "View", text_editmenu_viewmenu);
212         uiMenuLevel(head, "Select", text_editmenu_selectmenu);
213         uiMenuLevel(head, "Markers", text_editmenu_markermenu);
214
215         uiMenuSeparator(head);
216
217         uiMenuItemO(head, 0, "TEXT_OT_jump");
218         uiMenuItemO(head, 0, "TEXT_OT_properties");
219
220         uiMenuSeparator(head);
221
222         uiMenuLevel(head, "Text to 3D Object", text_editmenu_to3dmenu);
223 }
224
225 static void text_filemenu(bContext *C, uiMenuItem *head, void *arg_unused)
226 {
227         SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
228         Text *text= st->text;
229
230         uiMenuItemO(head, 0, "TEXT_OT_new");
231         uiMenuItemO(head, 0, "TEXT_OT_open");
232         
233         if(text) {
234                 uiMenuItemO(head, 0, "TEXT_OT_reload");
235                 
236                 uiMenuSeparator(head);
237                 
238                 uiMenuItemO(head, 0, "TEXT_OT_save");
239                 uiMenuItemO(head, 0, "TEXT_OT_save_as");
240                 
241                 if(text->name)
242                         uiMenuItemO(head, 0, "TEXT_OT_make_internal");
243
244                 uiMenuSeparator(head);
245                 
246                 uiMenuItemO(head, 0, "TEXT_OT_run_script");
247
248 #ifndef DISABLE_PYTHON
249                 if(BPY_is_pyconstraint(text))
250                         uiMenuItemO(head, 0, "TEXT_OT_refresh_pyconstraints");
251 #endif
252         }
253
254 #ifndef DISABLE_PYTHON
255         // XXX uiMenuSeparator(head);
256
257         // XXX uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, "");
258         // XXX uiDefIconTextBlockBut(block, text_plugin_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Text Plugins", 0, yco-=20, 120, 19, "");
259 #endif
260 }
261
262 /*********************** datablock browse *************************/
263
264 static void text_unlink(Main *bmain, Text *text)
265 {
266         bScreen *scr;
267         ScrArea *area;
268         SpaceLink *sl;
269
270         /* XXX this ifdef is in fact dangerous, if python is
271          * disabled it will leave invalid pointers in files! */
272
273 #ifndef DISABLE_PYTHON
274         // XXX BPY_clear_bad_scriptlinks(text);
275         // XXX BPY_free_pyconstraint_links(text);
276         // XXX free_text_controllers(text);
277
278         /* check if this text was used as script link:
279          * this check function unsets the pointers and returns how many
280          * script links used this Text */
281         if(0) // XXX BPY_text_check_all_scriptlinks (text))
282                 ; // XXX notifier: allqueue(REDRAWBUTSSCRIPT, 0);
283
284         /* equivalently for pynodes: */
285         if(0) // XXX nodeDynamicUnlinkText ((ID*)text))
286                 ; // XXX notifier: allqueue(REDRAWNODE, 0);
287 #endif
288         
289         for(scr= bmain->screen.first; scr; scr= scr->id.next) {
290                 for(area= scr->areabase.first; area; area= area->next) {
291                         for(sl= area->spacedata.first; sl; sl= sl->next) {
292                                 if(sl->spacetype==SPACE_TEXT) {
293                                         SpaceText *st= (SpaceText*) sl;
294                                         
295                                         if(st->text==text) {
296                                                 st->text= NULL;
297                                                 st->top= 0;
298                                                 
299                                                 if(st==area->spacedata.first)
300                                                         ED_area_tag_redraw(area);
301                                         }
302                                 }
303                         }
304                 }
305         }
306
307         free_libblock(&bmain->text, text);
308 }
309
310 static void text_idpoin_handle(bContext *C, ID *id, int event)
311 {
312         SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
313         Text *text;
314
315         switch(event) {
316                 case UI_ID_BROWSE:
317                         st->text= (Text*)id;
318                         st->top= 0;
319
320                         text_update_edited(st->text);
321                         WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
322
323                         ED_undo_push(C, "Browse Text");
324                         break;
325                 case UI_ID_DELETE:
326                         text= st->text;
327
328                         /* make the previous text active, if its not there make the next text active */
329                         if(text->id.prev) {
330                                 st->text = text->id.prev;
331                                 WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
332                         }
333                         else if(text->id.next) {
334                                 st->text = text->id.next;
335                                 WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
336                         }
337
338                         text_unlink(CTX_data_main(C), text);
339                         WM_event_add_notifier(C, NC_TEXT|NA_REMOVED, text);
340
341                         ED_undo_push(C, "Delete Text");
342                         break;
343                 case UI_ID_RENAME:
344                         break;
345                 case UI_ID_ADD_NEW:
346                         WM_operator_name_call(C, "TEXT_OT_new", WM_OP_INVOKE_REGION_WIN, NULL);
347                         break;
348                 case UI_ID_OPEN:
349                         WM_operator_name_call(C, "TEXT_OT_open", WM_OP_INVOKE_REGION_WIN, NULL);
350                         break;
351         }
352 }
353
354 /********************** header buttons ***********************/
355
356 static void header_buttons(const bContext *C, uiLayout *layout)
357 {
358         bScreen *sc= CTX_wm_screen(C);
359         SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
360         PointerRNA spaceptr;
361         Text *text= st->text;
362         
363         RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
364
365         uiTemplateHeaderMenus(layout);
366         uiItemMenu(layout, UI_TSLOT_HEADER, "Text", 0, text_filemenu);
367         if(text) {
368                 uiItemMenu(layout, UI_TSLOT_HEADER, "Edit", 0, text_editmenu);
369                 uiItemMenu(layout, UI_TSLOT_HEADER, "Format", 0, text_formatmenu);
370         }
371
372         /* warning button if text is out of date */
373         if(text && text_file_modified(text)) {
374                 uiTemplateHeaderButtons(layout);
375                 uiTemplateSetColor(layout, TH_REDALERT);
376                 uiItemO(layout, UI_TSLOT_HEADER, "", ICON_HELP, "TEXT_OT_resolve_conflict");
377         }
378
379         uiTemplateHeaderButtons(layout);
380         uiItemR(layout, UI_TSLOT_HEADER, "", ICON_LINENUMBERS_OFF, &spaceptr, "line_numbers");
381         uiItemR(layout, UI_TSLOT_HEADER, "", ICON_WORDWRAP_OFF, &spaceptr, "word_wrap");
382         uiItemR(layout, UI_TSLOT_HEADER, "", ICON_SYNTAX_OFF, &spaceptr, "syntax_highlight");
383         // XXX uiItemR(layout, "", ICON_SCRIPTPLUGINS, &spaceptr, "do_python_plugins");
384
385         uiTemplateHeaderID(layout, &spaceptr, "text",
386                 UI_ID_BROWSE|UI_ID_RENAME|UI_ID_ADD_NEW|UI_ID_OPEN|UI_ID_DELETE,
387                 text_idpoin_handle);
388
389         /* file info */
390         if(text) {
391                 char fname[HEADER_PATH_MAX], headtxt[HEADER_PATH_MAX+17];
392                 int len;
393
394                 if(text->name) {
395                         len = strlen(text->name);
396                         if(len > HEADER_PATH_MAX-1)
397                                 len = HEADER_PATH_MAX-1;
398                         strncpy(fname, text->name, len);
399                         fname[len]='\0';
400                         if(text->flags & TXT_ISDIRTY)
401                                 sprintf(headtxt, "File: *%s (unsaved)", fname);
402                         else
403                                 sprintf(headtxt, "File: %s", fname);
404                 }
405                 else
406                         sprintf(headtxt, text->id.lib? "Text: External": "Text: Internal");
407
408                 uiTemplateHeaderButtons(layout);
409                 uiItemLabel(layout, UI_TSLOT_HEADER, headtxt, 0);
410         }
411 }
412
413 void text_header_buttons(const bContext *C, ARegion *ar)
414 {
415         uiHeaderLayout(C, ar, header_buttons);
416 }
417
418 /************************** properties ******************************/
419
420 void properties_buttons(const bContext *C, uiLayout *layout)
421 {
422         bScreen *sc= CTX_wm_screen(C);
423         SpaceText *st= CTX_wm_space_text(C);
424         PointerRNA spaceptr;
425         
426         RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
427
428         uiTemplateColumn(layout);
429         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, ICON_LINENUMBERS_OFF, &spaceptr, "line_numbers");
430         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, ICON_WORDWRAP_OFF, &spaceptr, "word_wrap");
431         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, ICON_SYNTAX_OFF, &spaceptr, "syntax_highlight");
432
433         uiTemplateColumn(layout);
434         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, 0, &spaceptr, "font_size");
435         uiItemR(layout, UI_TSLOT_COLUMN_1, NULL, 0, &spaceptr, "tab_width");
436 }
437
438 void find_buttons(const bContext *C, uiLayout *layout)
439 {
440         bScreen *sc= CTX_wm_screen(C);
441         SpaceText *st= CTX_wm_space_text(C);
442         PointerRNA spaceptr;
443         
444         RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
445
446         /* find */
447         uiTemplateLeftRight(layout);
448         uiItemR(layout, UI_TSLOT_LR_LEFT, "", 0, &spaceptr, "find_text");
449         uiItemO(layout, UI_TSLOT_LR_RIGHT, "", ICON_TEXT, "TEXT_OT_find_set_selected");
450         uiTemplateColumn(layout);
451         uiItemO(layout, UI_TSLOT_COLUMN_1, NULL, 0, "TEXT_OT_find");
452
453         /* replace */
454         uiTemplateLeftRight(layout);
455         uiItemR(layout, UI_TSLOT_LR_LEFT, "", 0, &spaceptr, "replace_text");
456         uiItemO(layout, UI_TSLOT_LR_RIGHT, "", ICON_TEXT, "TEXT_OT_replace_set_selected");
457         uiTemplateColumn(layout);
458         uiItemO(layout, UI_TSLOT_COLUMN_1, NULL, 0, "TEXT_OT_replace");
459
460         /* mark */
461         uiTemplateColumn(layout);
462         uiItemO(layout, UI_TSLOT_COLUMN_1, NULL, 0, "TEXT_OT_mark_all");
463
464         /* settings */
465         uiTemplateColumn(layout);
466         uiItemR(layout, UI_TSLOT_COLUMN_1, "Wrap", 0, &spaceptr, "find_wrap");
467         uiItemR(layout, UI_TSLOT_COLUMN_2, "All", 0, &spaceptr, "find_all");
468 }
469
470 void text_properties_buttons(const bContext *C, ARegion *ar)
471 {
472         uiCompactPanelLayout(C, ar, "TEXT_OT_properties", "Properties", "Text", properties_buttons, 0);
473         uiCompactPanelLayout(C, ar, "TEXT_OT_find", "Find", "Text", find_buttons, 1);
474
475         uiDrawPanels(C, 1);
476         uiMatchPanelsView2d(ar);
477 }
478
479 ARegion *text_has_properties_region(ScrArea *sa)
480 {
481         ARegion *ar, *arnew;
482         
483         for(ar= sa->regionbase.first; ar; ar= ar->next)
484                 if(ar->regiontype==RGN_TYPE_UI)
485                         return ar;
486         
487         /* add subdiv level; after header */
488         for(ar= sa->regionbase.first; ar; ar= ar->next)
489                 if(ar->regiontype==RGN_TYPE_HEADER)
490                         break;
491         
492         /* is error! */
493         if(ar==NULL) return NULL;
494         
495         arnew= MEM_callocN(sizeof(ARegion), "properties region");
496         
497         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
498         arnew->regiontype= RGN_TYPE_UI;
499         arnew->alignment= RGN_ALIGN_LEFT;
500         
501         arnew->flag = RGN_FLAG_HIDDEN;
502         
503         return arnew;
504 }
505
506 static int properties_poll(bContext *C)
507 {
508         SpaceText *st= CTX_wm_space_text(C);
509         Text *text= CTX_data_edit_text(C);
510
511         return (st && text);
512 }
513
514 static int properties_exec(bContext *C, wmOperator *op)
515 {
516         ScrArea *sa= CTX_wm_area(C);
517         ARegion *ar= text_has_properties_region(sa);
518         
519         if(ar) {
520                 ar->flag ^= RGN_FLAG_HIDDEN;
521                 ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
522                 
523                 ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
524                 ED_area_tag_redraw(sa);
525         }
526
527         return OPERATOR_FINISHED;
528 }
529
530 void TEXT_OT_properties(wmOperatorType *ot)
531 {
532         /* identifiers */
533         ot->name= "Properties";
534         ot->idname= "TEXT_OT_properties";
535         
536         /* api callbacks */
537         ot->exec= properties_exec;
538         ot->poll= properties_poll;
539 }
540
541 /******************** XXX popup menus *******************/
542
543 #if 0
544 {
545         // RMB
546
547         uiMenuItem *head;
548
549         if(text) {
550                 head= uiPupMenuBegin("Text", 0);
551                 if(txt_has_sel(text)) {
552                         uiMenuItemO(head, 0, "TEXT_OT_cut");
553                         uiMenuItemO(head, 0, "TEXT_OT_copy");
554                 }
555                 uiMenuItemO(head, 0, "TEXT_OT_paste");
556                 uiMenuItemO(head, 0, "TEXT_OT_new");
557                 uiMenuItemO(head, 0, "TEXT_OT_open");
558                 uiMenuItemO(head, 0, "TEXT_OT_save");
559                 uiMenuItemO(head, 0, "TEXT_OT_save_as");
560                 uiMenuItemO(head, 0, "TEXT_OT_run_script");
561                 uiPupMenuEnd(C, head);
562         }
563         else {
564                 head= uiPupMenuBegin("File", 0);
565                 uiMenuItemO(head, 0, "TEXT_OT_new");
566                 uiMenuItemO(head, 0, "TEXT_OT_open");
567                 uiPupMenuEnd(C, head);
568         }
569 }
570
571 {
572         // Alt+Shift+E
573
574         uiMenuItem *head;
575
576         head= uiPupMenuBegin("Edit", 0);
577         uiMenuItemO(head, 0, "TEXT_OT_cut");
578         uiMenuItemO(head, 0, "TEXT_OT_copy");
579         uiMenuItemO(head, 0, "TEXT_OT_paste");
580         uiPupMenuEnd(C, head);
581 }
582
583 {
584         // Alt+Shift+F
585
586         uiMenuItem *head;
587
588         if(text) {
589                 head= uiPupMenuBegin("Text", 0);
590                 uiMenuItemO(head, 0, "TEXT_OT_new");
591                 uiMenuItemO(head, 0, "TEXT_OT_open");
592                 uiMenuItemO(head, 0, "TEXT_OT_save");
593                 uiMenuItemO(head, 0, "TEXT_OT_save_as");
594                 uiMenuItemO(head, 0, "TEXT_OT_run_script");
595                 uiPupMenuEnd(C, head);
596         }
597         else {
598                 head= uiPupMenuBegin("File", 0);
599                 uiMenuItemO(head, 0, "TEXT_OT_new");
600                 uiMenuItemO(head, 0, "TEXT_OT_open");
601                 uiPupMenuEnd(C, head);
602         }
603 }
604
605 {
606         // Alt+Shift+V
607
608         uiMenuItem *head;
609
610         head= uiPupMenuBegin("Text", 0);
611         uiMenuItemEnumO(head, "Top of File", 0, "TEXT_OT_move", "type", FILE_TOP);
612         uiMenuItemEnumO(head, "Bottom of File", 0, "TEXT_OT_move", "type", FILE_BOTTOM);
613         uiMenuItemEnumO(head, "Page Up", 0, "TEXT_OT_move", "type", PREV_PAGE);
614         uiMenuItemEnumO(head,  "Page Down", 0, "TEXT_OT_move", "type", NEXT_PAGE);
615         uiPupMenuEnd(C, head);
616 }
617 #endif
618