Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2009-03-01 02:33:35 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2009-03-01 02:33:35 +0300
commit6cc89b9d4e6ab17bea0631b1be800dd9a022db23 (patch)
tree356e3649b94ec7f5a144f1fa6304f5646c4b9bf1 /source/blender/editors/space_text
parent2469305376856e0f53b4ffdbe2bf2576fa25809c (diff)
2.5: Text Editor back.
There was very little structure in this code, using many globals and duplicated code. Now it should be better structured. Most things should work, the main parts that are not back yet are the python plugins and markers. Notes: * Blenfont is used for drawing the text, nicely anti-aliased. * A monospace truetype font was added, since that is needed for the text editor. It's Bitstream Vera Sans Mono. This is the default gnome terminal font, but it doesn't fit entirely well with the other font I think, can be changed easily of course. * Clipboard copy/cut/paste now always uses the system clipboard, the code for the own cut buffer was removed. * The interface buttons should support copy/cut/paste again now as well. * WM_clipboard_text_get/WM_clipboard_text_set were added to the windowmanager code. * Find panel is now a kind of second header, instead of a panel. This needs especially a way to start editing the text field immediately on open still. * Operators are independent of the actual space when possible, was a bit of puzzling but got it solved nice with notifiers, and some lazy init for syntax highlight in the drawing code. * RNA was created for the text editor space and used for buttons. * Operators: * New, Open, Reload, Save, Save As, Make Internal * Run Script, Refresh Pyconstraints * Copy, Cut, Paste * Convert Whitespace, Uncomment, Comment, Indent, Unindent * Line Break, Insert * Next Marker, Previous Marker, Clear All Markers, Mark All * Select Line, Select All * Jump, Move, Move Select, Delete, Toggle Overwrite * Scroll, Scroll Bar, Set Cursor, Line Number * Find and Replace, Find, Replace, Find Set Selected, Replace Set Selected * To 3D Object * Resolve Conflict
Diffstat (limited to 'source/blender/editors/space_text')
-rw-r--r--source/blender/editors/space_text/Makefile2
-rw-r--r--source/blender/editors/space_text/SConscript4
-rw-r--r--source/blender/editors/space_text/space_text.c250
-rw-r--r--source/blender/editors/space_text/text_draw.c1381
-rw-r--r--source/blender/editors/space_text/text_header.c582
-rw-r--r--source/blender/editors/space_text/text_intern.h122
-rw-r--r--source/blender/editors/space_text/text_ops.c2563
-rw-r--r--source/blender/editors/space_text/text_python.c541
8 files changed, 5394 insertions, 51 deletions
diff --git a/source/blender/editors/space_text/Makefile b/source/blender/editors/space_text/Makefile
index fb685389d56..33e12dc1abb 100644
--- a/source/blender/editors/space_text/Makefile
+++ b/source/blender/editors/space_text/Makefile
@@ -43,7 +43,9 @@ CPPFLAGS += -I../../windowmanager
CPPFLAGS += -I../../blenloader
CPPFLAGS += -I../../blenkernel
CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../blenfont
CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../makesrna
CPPFLAGS += -I../../imbuf
CPPFLAGS += -I../../python
CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
diff --git a/source/blender/editors/space_text/SConscript b/source/blender/editors/space_text/SConscript
index c3438dd7695..199ea0939e6 100644
--- a/source/blender/editors/space_text/SConscript
+++ b/source/blender/editors/space_text/SConscript
@@ -5,5 +5,9 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+incs += ' #/intern/bmfont ../../python ../../makesrna ../../blenfont'
+
+if not env['WITH_BF_PYTHON']:
+ defs.append('DISABLE_PYTHON')
env.BlenderLib ( 'bf_editors_space_text', sources, Split(incs), [], libtype=['core'], priority=[95] )
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 4187bd13cb1..6418576cb57 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -34,6 +34,7 @@
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
@@ -57,6 +58,8 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "RNA_access.h"
+
#include "ED_markers.h"
#include "text_intern.h" // own include
@@ -71,7 +74,6 @@ static SpaceLink *text_new(const bContext *C)
stext= MEM_callocN(sizeof(SpaceText), "inittext");
stext->spacetype= SPACE_TEXT;
-
/* header */
ar= MEM_callocN(sizeof(ARegion), "header for text");
@@ -85,9 +87,6 @@ static SpaceLink *text_new(const bContext *C)
BLI_addtail(&stext->regionbase, ar);
ar->regiontype= RGN_TYPE_WINDOW;
- /* channel list region XXX */
-
-
return (SpaceLink *)stext;
}
@@ -115,7 +114,185 @@ static SpaceLink *text_duplicate(SpaceLink *sl)
return (SpaceLink *)stextn;
}
+static void text_listener(ScrArea *sa, wmNotifier *wmn)
+{
+ SpaceText *st= sa->spacedata.first;
+
+ /* context changes */
+ switch(wmn->category) {
+ case NC_TEXT:
+ if(!wmn->reference || wmn->reference == st->text) {
+ ED_area_tag_redraw(sa);
+
+ if(wmn->data == ND_CURSOR) {
+ ARegion *ar;
+
+ for(ar=sa->regionbase.first; ar; ar= ar->next)
+ if(ar->regiontype==RGN_TYPE_WINDOW)
+ text_update_cursor_moved(st, ar);
+ }
+ }
+ else if(wmn->data == ND_DISPLAY)
+ ED_area_tag_redraw(sa);
+
+ break;
+ }
+}
+
+static void text_operatortypes(void)
+{
+ WM_operatortype_append(TEXT_OT_new);
+ WM_operatortype_append(TEXT_OT_open);
+ WM_operatortype_append(TEXT_OT_reload);
+ WM_operatortype_append(TEXT_OT_save);
+ WM_operatortype_append(TEXT_OT_save_as);
+ WM_operatortype_append(TEXT_OT_make_internal);
+ WM_operatortype_append(TEXT_OT_run_script);
+ WM_operatortype_append(TEXT_OT_refresh_pyconstraints);
+
+ WM_operatortype_append(TEXT_OT_paste);
+ WM_operatortype_append(TEXT_OT_copy);
+ WM_operatortype_append(TEXT_OT_cut);
+
+ WM_operatortype_append(TEXT_OT_convert_whitespace);
+ WM_operatortype_append(TEXT_OT_uncomment);
+ WM_operatortype_append(TEXT_OT_comment);
+ WM_operatortype_append(TEXT_OT_unindent);
+ WM_operatortype_append(TEXT_OT_indent);
+
+ WM_operatortype_append(TEXT_OT_clear_all_markers);
+ WM_operatortype_append(TEXT_OT_next_marker);
+ WM_operatortype_append(TEXT_OT_previous_marker);
+
+ WM_operatortype_append(TEXT_OT_select_line);
+ WM_operatortype_append(TEXT_OT_select_all);
+
+ WM_operatortype_append(TEXT_OT_jump);
+ WM_operatortype_append(TEXT_OT_move);
+ WM_operatortype_append(TEXT_OT_move_select);
+ WM_operatortype_append(TEXT_OT_delete);
+ WM_operatortype_append(TEXT_OT_toggle_overwrite);
+
+ WM_operatortype_append(TEXT_OT_set_cursor);
+ WM_operatortype_append(TEXT_OT_scroll);
+ WM_operatortype_append(TEXT_OT_scroll_bar);
+ WM_operatortype_append(TEXT_OT_line_number);
+
+ WM_operatortype_append(TEXT_OT_line_break);
+ WM_operatortype_append(TEXT_OT_insert);
+
+ WM_operatortype_append(TEXT_OT_find_and_replace);
+ WM_operatortype_append(TEXT_OT_find);
+ WM_operatortype_append(TEXT_OT_find_set_selected);
+ WM_operatortype_append(TEXT_OT_replace);
+ WM_operatortype_append(TEXT_OT_replace_set_selected);
+ WM_operatortype_append(TEXT_OT_mark_all);
+
+ WM_operatortype_append(TEXT_OT_to_3d_object);
+
+ WM_operatortype_append(TEXT_OT_resolve_conflict);
+}
+
+static void text_keymap(struct wmWindowManager *wm)
+{
+ ListBase *keymap= WM_keymap_listbase(wm, "Text", SPACE_TEXT, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_new", NKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_open", OKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_reload", RKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_save", SKEY, KM_PRESS, KM_ALT, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_run_script", PKEY, KM_PRESS, KM_ALT, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_cut", XKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_cut", XKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_copy", CKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_paste", VKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+
+ if(U.uiflag & USER_MMB_PASTE) // XXX not dynamic
+ RNA_boolean_set(WM_keymap_add_item(keymap, "TEXT_OT_paste", MIDDLEMOUSE, KM_PRESS, 0, 0)->ptr, "selection", 1);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_jump", JKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_find", FKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_find_and_replace", FKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_find_and_replace", FKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_replace", HKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_replace", HKEY, KM_PRESS, KM_CTRL, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_to_3d_object", MKEY, KM_PRESS, KM_ALT, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_select_all", AKEY, KM_PRESS, KM_CTRL, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_indent", TABKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_unindent", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_uncomment", DKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
+
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", RIGHTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", EKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", LINE_END);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", EKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "type", LINE_END);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_CHAR);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_CHAR);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_LINE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_LINE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_PAGE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_PAGE);
+
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", HOMEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", LINE_BEGIN);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", ENDKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", LINE_END);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_CHAR);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_CHAR);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0)->ptr, "type", PREV_WORD);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0)->ptr, "type", NEXT_WORD);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_LINE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_LINE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_PAGE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_PAGE);
+
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_CHAR);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", DKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_CHAR);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_CHAR);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD);
+ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_toggle_overwrite", INSERTKEY, KM_PRESS, 0, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_scroll", MIDDLEMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_scroll_bar", LEFTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_set_cursor", LEFTMOUSE, KM_PRESS, 0, 0);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "TEXT_OT_set_cursor", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "select", 1);
+ RNA_int_set(WM_keymap_add_item(keymap, "TEXT_OT_scroll", WHEELUPMOUSE, KM_PRESS, 0, 0)->ptr, "lines", -1);
+ RNA_int_set(WM_keymap_add_item(keymap, "TEXT_OT_scroll", WHEELDOWNMOUSE, KM_PRESS, 0, 0)->ptr, "lines", 1);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_to_3d_object", MKEY, KM_PRESS, KM_ALT, 0);
+
+ WM_keymap_add_item(keymap, "TEXT_OT_line_break", RETKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_line_number", KM_TEXTINPUT, KM_ANY, KM_ANY, 0);
+ WM_keymap_add_item(keymap, "TEXT_OT_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last!
+}
+
+static int text_context(const bContext *C, bContextDataMember member, bContextDataResult *result)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+
+ if(member == CTX_DATA_EDIT_TEXT) {
+ CTX_data_pointer_set(result, st->text);
+ return 1;
+ }
+
+ return 0;
+}
+/********************* main region ********************/
/* add handlers, stuff you only do once or on area/region changes */
static void text_main_area_init(wmWindowManager *wm, ARegion *ar)
@@ -132,8 +309,8 @@ static void text_main_area_init(wmWindowManager *wm, ARegion *ar)
static void text_main_area_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
- // SpaceText *stext= (SpaceText*)CTX_wm_space_data(C);
- View2D *v2d= &ar->v2d;
+ SpaceText *st= CTX_wm_space_text(C);
+ //View2D *v2d= &ar->v2d;
float col[3];
/* clear and setup matrix */
@@ -141,31 +318,23 @@ static void text_main_area_draw(const bContext *C, ARegion *ar)
glClearColor(col[0], col[1], col[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
- UI_view2d_view_ortho(C, v2d);
+ // UI_view2d_view_ortho(C, v2d);
/* data... */
-
+ draw_text_main(st, ar);
/* reset view matrix */
- UI_view2d_view_restore(C);
+ // UI_view2d_view_restore(C);
/* scrollers? */
}
-static void text_operatortypes(void)
-{
-
-}
-
static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
WM_cursor_set(win, BC_TEXTEDITCURSOR);
}
-static void text_keymap(struct wmWindowManager *wm)
-{
-
-}
+/****************** header region ******************/
/* add handlers, stuff you only do once or on area/region changes */
static void text_header_area_init(wmWindowManager *wm, ARegion *ar)
@@ -195,11 +364,38 @@ static void text_header_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
-static void text_main_area_listener(ARegion *ar, wmNotifier *wmn)
+/****************** find & replace region ******************/
+
+/* add handlers, stuff you only do once or on area/region changes */
+static void text_find_area_init(wmWindowManager *wm, ARegion *ar)
{
- /* context changes */
+ UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
}
+static void text_find_area_draw(const bContext *C, ARegion *ar)
+{
+ float col[3];
+
+ /* clear */
+ if(ED_screen_area_active(C))
+ UI_GetThemeColor3fv(TH_HEADER, col);
+ else
+ UI_GetThemeColor3fv(TH_HEADERDESEL, col);
+
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* set view2d view matrix for scrolling (without scrollers) */
+ UI_view2d_view_ortho(C, &ar->v2d);
+
+ text_find_buttons(C, ar);
+
+ /* restore view matrix? */
+ UI_view2d_view_restore(C);
+}
+
+/********************* registration ********************/
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_text(void)
{
@@ -214,14 +410,14 @@ void ED_spacetype_text(void)
st->duplicate= text_duplicate;
st->operatortypes= text_operatortypes;
st->keymap= text_keymap;
+ st->listener= text_listener;
+ st->context= text_context;
/* regions: main window */
art= MEM_callocN(sizeof(ARegionType), "spacetype text region");
art->regionid = RGN_TYPE_WINDOW;
art->init= text_main_area_init;
art->draw= text_main_area_draw;
- art->listener= text_main_area_listener;
- art->keymapflag= ED_KEYMAP_VIEW2D;
art->cursor= text_cursor;
BLI_addhead(&st->regiontypes, art);
@@ -237,6 +433,16 @@ void ED_spacetype_text(void)
BLI_addhead(&st->regiontypes, art);
+ /* regions: find & replace */
+ art= MEM_callocN(sizeof(ARegionType), "spacetype text region");
+ art->regionid = RGN_TYPE_UI;
+ art->minsizey= HEADERY;
+ art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D;
+
+ art->init= text_find_area_init;
+ art->draw= text_find_area_draw;
+
+ BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
new file mode 100644
index 00000000000..456060d77a7
--- /dev/null
+++ b/source/blender/editors/space_text/text_draw.c
@@ -0,0 +1,1381 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLF_api.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_suggestions.h"
+#include "BKE_text.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "ED_datafiles.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "text_intern.h"
+
+/******************** text font drawing ******************/
+
+static void text_font_begin(SpaceText *st)
+{
+ static int mono= -1; // XXX needs proper storage
+
+ if(mono == -1)
+ mono= BLF_load_mem("monospace", (unsigned char*)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
+
+ BLF_set(mono);
+ BLF_aspect(1.0);
+
+ BLF_size(st->lheight, 72);
+}
+
+static void text_font_end(SpaceText *st)
+{
+}
+
+static int text_font_draw(SpaceText *st, int x, int y, char *str)
+{
+ BLF_position(x, y, 0);
+ BLF_draw(str);
+
+ return BLF_width(str);
+}
+
+static int text_font_draw_character(SpaceText *st, int x, int y, char c)
+{
+ char str[2];
+
+ str[0]= c;
+ str[1]= '\0';
+
+ BLF_position(x, y, 0);
+ BLF_draw(str);
+
+ return text_font_width_character(st);
+}
+
+int text_font_width_character(SpaceText *st)
+{
+ // XXX need quick BLF function, or cache it somewhere
+ return (st->lheight == 12)? 7: 8;
+}
+
+int text_font_width(SpaceText *st, char *str)
+{
+ return BLF_width(str);
+}
+
+/****************** flatten string **********************/
+
+static void flatten_string_append(FlattenString *fs, char c, int accum)
+{
+ if(fs->pos>=fs->len && fs->pos>=sizeof(fs->fixedbuf)-1) {
+ char *nbuf; int *naccum;
+ int olen= fs->len;
+
+ if(olen) fs->len*= 2;
+ else fs->len= 256;
+
+ nbuf= MEM_mallocN(sizeof(*fs->buf)*fs->len, "fs->buf");
+ naccum= MEM_mallocN(sizeof(*fs->accum)*fs->len, "fs->accum");
+
+ if(olen) {
+ memcpy(nbuf, fs->buf, olen);
+ memcpy(naccum, fs->accum, olen);
+
+ if(fs->buf != fs->fixedbuf) {
+ MEM_freeN(fs->buf);
+ MEM_freeN(fs->accum);
+ }
+ }
+
+ fs->buf= nbuf;
+ fs->accum= naccum;
+ }
+
+ fs->buf[fs->pos]= c;
+ fs->accum[fs->pos]= accum;
+
+ if(c==0) fs->pos= 0;
+ else fs->pos++;
+}
+
+int flatten_string(SpaceText *st, FlattenString *fs, char *in)
+{
+ int r = 0, i = 0;
+
+ memset(fs, 0, sizeof(FlattenString));
+ fs->buf= fs->fixedbuf;
+ fs->accum= fs->fixedaccum;
+
+ for(r=0, i=0; *in; r++, in++) {
+ if(*in=='\t') {
+ if(fs->pos && *(in-1)=='\t')
+ i= st->tabnumber;
+ else if(st->tabnumber > 0)
+ i= st->tabnumber - (fs->pos%st->tabnumber);
+
+ while(i--)
+ flatten_string_append(fs, ' ', r);
+ }
+ else
+ flatten_string_append(fs, *in, r);
+ }
+
+ return fs->pos;
+}
+
+void flatten_string_free(FlattenString *fs)
+{
+ if(fs->buf != fs->fixedbuf)
+ MEM_freeN(fs->buf);
+ if(fs->accum != fs->fixedaccum)
+ MEM_freeN(fs->accum);
+}
+
+/* Checks the specified source string for a Python built-in function name. This
+ name must start at the beginning of the source string and must be followed by
+ a non-identifier (see text_check_identifier(char)) or null character.
+
+ If a built-in function is found, the length of the matching name is returned.
+ Otherwise, -1 is returned. */
+
+static int find_builtinfunc(char *string)
+{
+ int a, i;
+ char builtinfuncs[][11] = {"and", "as", "assert", "break", "class", "continue", "def",
+ "del", "elif", "else", "except", "exec", "finally",
+ "for", "from", "global", "if", "import", "in",
+ "is", "lambda", "not", "or", "pass", "print",
+ "raise", "return", "try", "while", "yield"};
+ for(a=0; a<30; a++) {
+ i = 0;
+ while(1) {
+ /* If we hit the end of a keyword... (eg. "def") */
+ if(builtinfuncs[a][i]=='\0') {
+ /* If we still have identifier chars in the source (eg. "definate") */
+ if(text_check_identifier(string[i]))
+ i = -1; /* No match */
+ break; /* Next keyword if no match, otherwise we're done */
+
+ /* If chars mismatch, move on to next keyword */
+ }
+ else if(string[i]!=builtinfuncs[a][i]) {
+ i = -1;
+ break; /* Break inner loop, start next keyword */
+ }
+ i++;
+ }
+ if(i>0) break; /* If we have a match, we're done */
+ }
+ return i;
+}
+
+/* Checks the specified source string for a Python special name. This name must
+ start at the beginning of the source string and must be followed by a non-
+ identifier (see text_check_identifier(char)) or null character.
+
+ If a special name is found, the length of the matching name is returned.
+ Otherwise, -1 is returned. */
+
+static int find_specialvar(char *string)
+{
+ int i = 0;
+ /* Check for "def" */
+ if(string[0]=='d' && string[1]=='e' && string[2]=='f')
+ i = 3;
+ /* Check for "class" */
+ else if(string[0]=='c' && string[1]=='l' && string[2]=='a' && string[3]=='s' && string[4]=='s')
+ i = 5;
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ if(i==0 || text_check_identifier(string[i]))
+ return -1;
+ return i;
+}
+
+/* Ensures the format string for the given line is long enough, reallocating
+ as needed. Allocation is done here, alone, to ensure consistency. */
+int text_check_format_len(TextLine *line, unsigned int len)
+{
+ if(line->format) {
+ if(strlen(line->format) < len) {
+ MEM_freeN(line->format);
+ line->format = MEM_mallocN(len+2, "SyntaxFormat");
+ if(!line->format) return 0;
+ }
+ }
+ else {
+ line->format = MEM_mallocN(len+2, "SyntaxFormat");
+ if(!line->format) return 0;
+ }
+
+ return 1;
+}
+
+/* Formats the specified line. If do_next is set, the process will move on to
+ the succeeding line if it is affected (eg. multiline strings). Format strings
+ may contain any of the following characters:
+ '_' Whitespace
+ '#' Comment text
+ '!' Punctuation and other symbols
+ 'n' Numerals
+ 'l' String letters
+ 'v' Special variables (class, def)
+ 'b' Built-in names (print, for, etc.)
+ 'q' Other text (identifiers, etc.)
+ It is terminated with a null-terminator '\0' followed by a continuation
+ flag indicating whether the line is part of a multi-line string. */
+
+static void txt_format_line(SpaceText *st, TextLine *line, int do_next)
+{
+ FlattenString fs;
+ char *str, *fmt, orig, cont, find, prev = ' ';
+ int len, i;
+
+ /* Get continuation from previous line */
+ if(line->prev && line->prev->format != NULL) {
+ fmt= line->prev->format;
+ cont = fmt[strlen(fmt)+1]; /* Just after the null-terminator */
+ }
+ else cont = 0;
+
+ /* Get original continuation from this line */
+ if(line->format != NULL) {
+ fmt= line->format;
+ orig = fmt[strlen(fmt)+1]; /* Just after the null-terminator */
+ }
+ else orig = 0xFF;
+
+ flatten_string(st, &fs, line->line);
+ str = fs.buf;
+ len = strlen(str);
+ if(!text_check_format_len(line, len)) {
+ flatten_string_free(&fs);
+ return;
+ }
+ fmt = line->format;
+
+ while(*str) {
+ /* Handle escape sequences by skipping both \ and next char */
+ if(*str == '\\') {
+ *fmt = prev; fmt++; str++;
+ if(*str == '\0') break;
+ *fmt = prev; fmt++; str++;
+ continue;
+ }
+ /* Handle continuations */
+ else if(cont) {
+ /* Triple strings ("""...""" or '''...''') */
+ if(cont & TXT_TRISTR) {
+ find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
+ if(*str==find && *(str+1)==find && *(str+2)==find) {
+ *fmt = 'l'; fmt++; str++;
+ *fmt = 'l'; fmt++; str++;
+ cont = 0;
+ }
+ /* Handle other strings */
+ }
+ else {
+ find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
+ if(*str == find) cont = 0;
+ }
+
+ *fmt = 'l';
+ }
+ /* Not in a string... */
+ else {
+ /* Deal with comments first */
+ if(prev == '#' || *str == '#')
+ *fmt = '#';
+ /* Strings */
+ else if(*str == '"' || *str == '\'') {
+ find = *str;
+ cont = (*str== '"') ? TXT_DBLQUOTSTR : TXT_SNGQUOTSTR;
+ if(*(str+1) == find && *(str+2) == find) {
+ *fmt = 'l'; fmt++; str++;
+ *fmt = 'l'; fmt++; str++;
+ cont |= TXT_TRISTR;
+ }
+ *fmt = 'l';
+ }
+ /* Whitespace (all ws. has been converted to spaces) */
+ else if(*str == ' ')
+ *fmt = '_';
+ /* Numbers (digits not part of an identifier and periods followed by digits) */
+ else if((prev != 'q' && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str+1))))
+ *fmt = 'n';
+ /* Punctuation */
+ else if(text_check_delim(*str))
+ *fmt = '!';
+ /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ else if(prev == 'q')
+ *fmt = 'q';
+ /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ else {
+ /* Special vars(v) or built-in keywords(b) */
+ if((i=find_specialvar(str)) != -1)
+ prev = 'v';
+ else if((i=find_builtinfunc(str)) != -1)
+ prev = 'b';
+ if(i>0) {
+ while(i>1) {
+ *fmt = prev; fmt++; str++;
+ i--;
+ }
+ *fmt = prev;
+ }
+ else
+ *fmt = 'q';
+ }
+ }
+ prev = *fmt;
+ fmt++;
+ str++;
+ }
+
+ /* Terminate and add continuation char */
+ *fmt = '\0'; fmt++;
+ *fmt = cont;
+
+ /* Debugging */
+ //print_format(st, line);
+
+ /* If continuation has changed and we're allowed, process the next line */
+ if(cont!=orig && do_next && line->next) {
+ txt_format_line(st, line->next, do_next);
+ }
+
+ flatten_string_free(&fs);
+}
+
+#if 0
+/* Formats every line of the current text */
+static void txt_format_text(SpaceText *st)
+{
+ TextLine *linep;
+
+ if(!st->text) return;
+
+ for(linep=st->text->lines.first; linep; linep=linep->next)
+ txt_format_line(st, linep, 0);
+}
+#endif
+
+/* Sets the current drawing color based on the format character specified */
+static void format_draw_color(char formatchar)
+{
+ switch (formatchar) {
+ case '_': /* Whitespace */
+ break;
+ case '!': /* Symbols */
+ UI_ThemeColorBlend(TH_TEXT, TH_BACK, 0.5f);
+ break;
+ case '#': /* Comments */
+ UI_ThemeColor(TH_SYNTAX_C);
+ break;
+ case 'n': /* Numerals */
+ UI_ThemeColor(TH_SYNTAX_N);
+ break;
+ case 'l': /* Strings */
+ UI_ThemeColor(TH_SYNTAX_L);
+ break;
+ case 'v': /* Specials: class, def */
+ UI_ThemeColor(TH_SYNTAX_V);
+ break;
+ case 'b': /* Keywords: for, print, etc. */
+ UI_ThemeColor(TH_SYNTAX_B);
+ break;
+ case 'q': /* Other text (identifiers) */
+ default:
+ UI_ThemeColor(TH_TEXT);
+ break;
+ }
+}
+
+/*********************** utilities ************************/
+
+int text_check_bracket(char ch)
+{
+ int a;
+ char opens[] = "([{";
+ char close[] = ")]}";
+
+ for(a=0; a<3; a++) {
+ if(ch==opens[a])
+ return a+1;
+ else if(ch==close[a])
+ return -(a+1);
+ }
+ return 0;
+}
+
+int text_check_delim(char ch)
+{
+ int a;
+ char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,";
+
+ for(a=0; a<28; a++) {
+ if(ch==delims[a])
+ return 1;
+ }
+ return 0;
+}
+
+int text_check_digit(char ch)
+{
+ if(ch < '0') return 0;
+ if(ch <= '9') return 1;
+ return 0;
+}
+
+int text_check_identifier(char ch)
+{
+ if(ch < '0') return 0;
+ if(ch <= '9') return 1;
+ if(ch < 'A') return 0;
+ if(ch <= 'Z' || ch == '_') return 1;
+ if(ch < 'a') return 0;
+ if(ch <= 'z') return 1;
+ return 0;
+}
+
+int text_check_whitespace(char ch)
+{
+ if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
+ return 1;
+ return 0;
+}
+
+/************************** draw text *****************************/
+
+/***********************/ /*
+
+Notes on word-wrap
+--
+All word-wrap functions follow the algorithm below to maintain consistency.
+ line The line to wrap (tabs converted to spaces)
+ view_width The maximum number of characters displayable in the region
+ This equals region_width/font_width for the region
+ wrap_chars Characters that allow wrapping. This equals [' ', '\t', '-']
+
+def wrap(line, view_width, wrap_chars):
+ draw_start = 0
+ draw_end = view_width
+ pos = 0
+ for c in line:
+ if pos-draw_start >= view_width:
+ print line[draw_start:draw_end]
+ draw_start = draw_end
+ draw_end += view_width
+ elif c in wrap_chars:
+ draw_end = pos+1
+ pos += 1
+ print line[draw_start:]
+
+*/ /***********************/
+
+int wrap_width(SpaceText *st, ARegion *ar)
+{
+ int x, max;
+
+ x= st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ max= (ar->winx-x)/text_font_width_character(st);
+ return max>8 ? max : 8;
+}
+
+/* Sets (offl, offc) for transforming (line, curs) to its wrapped position */
+void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc)
+{
+ Text *text;
+ TextLine *linep;
+ int i, j, start, end, chars, max, chop;
+ char ch;
+
+ *offl= *offc= 0;
+
+ if(!st->text) return;
+ if(!st->wordwrap) return;
+
+ text= st->text;
+
+ /* Move pointer to first visible line (top) */
+ linep= text->lines.first;
+ i= st->top;
+ while(i>0 && linep) {
+ if(linep == linein) return; /* Line before top */
+ linep= linep->next;
+ i--;
+ }
+
+ max= wrap_width(st, ar);
+
+ while(linep) {
+ start= 0;
+ end= max;
+ chop= 1;
+ chars= 0;
+ *offc= 0;
+ for(i=0, j=0; linep->line[j]!='\0'; j++) {
+
+ /* Mimic replacement of tabs */
+ ch= linep->line[j];
+ if(ch=='\t') {
+ chars= st->tabnumber-i%st->tabnumber;
+ if(linep==linein && i<cursin) cursin += chars-1;
+ ch= ' ';
+ }
+ else
+ chars= 1;
+
+ while(chars--) {
+ if(i-start>=max) {
+ if(chop && linep==linein && i >= cursin)
+ return;
+ (*offl)++;
+ *offc -= end-start;
+ start= end;
+ end += max;
+ chop= 1;
+ }
+ else if(ch==' ' || ch=='-') {
+ end = i+1;
+ chop= 0;
+ if(linep==linein && i >= cursin)
+ return;
+ }
+ i++;
+ }
+ }
+ if(linep==linein) break;
+ linep= linep->next;
+ }
+}
+
+static int get_char_pos(SpaceText *st, char *line, int cur)
+{
+ int a=0, i;
+
+ for(i=0; i<cur && line[i]; i++) {
+ if(line[i]=='\t')
+ a += st->tabnumber-a%st->tabnumber;
+ else
+ a++;
+ }
+ return a;
+}
+
+static int text_draw_wrapped(SpaceText *st, char *str, int x, int y, int w, char *format)
+{
+ FlattenString fs;
+ int basex, i, a, len, start, end, max, lines;
+
+ len= flatten_string(st, &fs, str);
+ str= fs.buf;
+ max= w/text_font_width_character(st);
+ if(max<8) max= 8;
+ basex= x;
+
+ lines= 1;
+ start= 0;
+ end= max;
+ for(i=0; i<len; i++) {
+ if(i-start >= max) {
+ /* Draw the visible portion of text on the overshot line */
+ for(a=start; a<end; a++) {
+ if(st->showsyntax && format) format_draw_color(format[a]);
+ x += text_font_draw_character(st, x, y, str[a]);
+ }
+ y -= st->lheight;
+ x= basex;
+ lines++;
+ start= end;
+ end += max;
+ }
+ else if(str[i]==' ' || str[i]=='-') {
+ end = i+1;
+ }
+ }
+
+ /* Draw the remaining text */
+ for(a=start; a<len; a++) {
+ if(st->showsyntax && format)
+ format_draw_color(format[a]);
+
+ x += text_font_draw_character(st, x, y, str[a]);
+ }
+
+ flatten_string_free(&fs);
+
+ return lines;
+}
+
+static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, char *format)
+{
+ FlattenString fs;
+ int r=0, w= 0;
+ int *acc;
+ char *in;
+
+ w= flatten_string(st, &fs, str);
+ if(w < cshift) {
+ flatten_string_free(&fs);
+ return 0; /* String is shorter than shift */
+ }
+
+ in= fs.buf+cshift;
+ acc= fs.accum+cshift;
+ w= w-cshift;
+
+ if(draw) {
+ if(st->showsyntax && format) {
+ int amount, a;
+ format = format+cshift;
+
+ amount = strlen(in);
+
+ for(a = 0; a < amount; a++) {
+ format_draw_color(format[a]);
+ x += text_font_draw_character(st, x, y, in[a]);
+ }
+ }
+ else
+ text_font_draw(st, x, y, in);
+ }
+ else {
+ while(w-- && *acc++ < maxwidth)
+ r+= text_font_width_character(st);
+ }
+
+ flatten_string_free(&fs);
+
+ if(cshift && r==0)
+ return 0;
+ else if(st->showlinenrs)
+ return r+TXT_OFFSET+TEXTXLOC;
+ else
+ return r+TXT_OFFSET;
+}
+
+/************************ draw scrollbar *****************************/
+
+static void calc_text_rcts(SpaceText *st, ARegion *ar)
+{
+ int lhlstart, lhlend, ltexth;
+ short barheight, barstart, hlstart, hlend, blank_lines;
+ short pix_available, pix_top_margin, pix_bottom_margin, pix_bardiff;
+
+ pix_top_margin = 8;
+ pix_bottom_margin = 4;
+ pix_available = ar->winy - pix_top_margin - pix_bottom_margin;
+ ltexth= txt_get_span(st->text->lines.first, st->text->lines.last);
+ blank_lines = st->viewlines / 2;
+
+ /* when resizing a vieport with the bar at the bottom to a greater height more blank lines will be added */
+ if(ltexth + blank_lines < st->top + st->viewlines) {
+ blank_lines = st->top + st->viewlines - ltexth;
+ }
+
+ ltexth += blank_lines;
+
+ barheight = (ltexth > 0)? (st->viewlines*pix_available)/ltexth: 0;
+ pix_bardiff = 0;
+ if(barheight < 20) {
+ pix_bardiff = 20 - barheight; /* take into account the now non-linear sizing of the bar */
+ barheight = 20;
+ }
+ barstart = (ltexth > 0)? ((pix_available - pix_bardiff) * st->top)/ltexth: 0;
+
+ st->txtbar.xmin = 5;
+ st->txtbar.xmax = 17;
+ st->txtbar.ymax = ar->winy - pix_top_margin - barstart;
+ st->txtbar.ymin = st->txtbar.ymax - barheight;
+
+ CLAMP(st->txtbar.ymin, pix_bottom_margin, ar->winy - pix_top_margin);
+ CLAMP(st->txtbar.ymax, pix_bottom_margin, ar->winy - pix_top_margin);
+
+ st->pix_per_line= (pix_available > 0)? (float) ltexth/pix_available: 0;
+ if(st->pix_per_line<.1) st->pix_per_line=.1f;
+
+ lhlstart = MIN2(txt_get_span(st->text->lines.first, st->text->curl),
+ txt_get_span(st->text->lines.first, st->text->sell));
+ lhlend = MAX2(txt_get_span(st->text->lines.first, st->text->curl),
+ txt_get_span(st->text->lines.first, st->text->sell));
+
+ if(ltexth > 0) {
+ hlstart = (lhlstart * pix_available)/ltexth;
+ hlend = (lhlend * pix_available)/ltexth;
+
+ /* the scrollbar is non-linear sized */
+ if(pix_bardiff > 0) {
+ /* the start of the highlight is in the current viewport */
+ if(ltexth && st->viewlines && lhlstart >= st->top && lhlstart <= st->top + st->viewlines) {
+ /* speed the progresion of the start of the highlight through the scrollbar */
+ hlstart = ( ( (pix_available - pix_bardiff) * lhlstart) / ltexth) + (pix_bardiff * (lhlstart - st->top) / st->viewlines);
+ }
+ else if(lhlstart > st->top + st->viewlines && hlstart < barstart + barheight && hlstart > barstart) {
+ /* push hl start down */
+ hlstart = barstart + barheight;
+ }
+ else if(lhlend > st->top && lhlstart < st->top && hlstart > barstart) {
+ /*fill out start */
+ hlstart = barstart;
+ }
+
+ if(hlend <= hlstart) {
+ hlend = hlstart + 2;
+ }
+
+ /* the end of the highlight is in the current viewport */
+ if(ltexth && st->viewlines && lhlend >= st->top && lhlend <= st->top + st->viewlines) {
+ /* speed the progresion of the end of the highlight through the scrollbar */
+ hlend = (((pix_available - pix_bardiff )*lhlend)/ltexth) + (pix_bardiff * (lhlend - st->top)/st->viewlines);
+ }
+ else if(lhlend < st->top && hlend >= barstart - 2 && hlend < barstart + barheight) {
+ /* push hl end up */
+ hlend = barstart;
+ }
+ else if(lhlend > st->top + st->viewlines && lhlstart < st->top + st->viewlines && hlend < barstart + barheight) {
+ /* fill out end */
+ hlend = barstart + barheight;
+ }
+
+ if(hlend <= hlstart) {
+ hlstart = hlend - 2;
+ }
+ }
+ }
+ else {
+ hlstart = 0;
+ hlend = 0;
+ }
+
+ if(hlend - hlstart < 2) {
+ hlend = hlstart + 2;
+ }
+
+ st->txtscroll.xmin= 5;
+ st->txtscroll.xmax= 17;
+ st->txtscroll.ymax= ar->winy - pix_top_margin - hlstart;
+ st->txtscroll.ymin= ar->winy - pix_top_margin - hlend;
+
+ CLAMP(st->txtscroll.ymin, pix_bottom_margin, ar->winy - pix_top_margin);
+ CLAMP(st->txtscroll.ymax, pix_bottom_margin, ar->winy - pix_top_margin);
+}
+
+static void draw_textscroll(SpaceText *st, ARegion *ar)
+{
+ UI_ThemeColorShade(TH_SHADE1, -20);
+ glRecti(2, 2, 20, ar->winy-6);
+ uiEmboss(2, 2, 20, ar->winy-6, 1);
+
+ UI_ThemeColor(TH_SHADE1);
+ glRecti(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax);
+
+ UI_ThemeColor(TH_SHADE2);
+ glRecti(st->txtscroll.xmin, st->txtscroll.ymin, st->txtscroll.xmax, st->txtscroll.ymax);
+
+ uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
+}
+
+/************************** draw markers **************************/
+
+static void draw_markers(SpaceText *st, ARegion *ar)
+{
+ Text *text= st->text;
+ TextMarker *marker, *next;
+ TextLine *top, *bottom, *line;
+ int offl, offc, i, cy, x1, x2, y1, y2, x, y;
+
+ for(i=st->top, top= text->lines.first; top->next && i>0; i--)
+ top= top->next;
+
+ for(i=st->viewlines-1, bottom=top; bottom->next && i>0; i--)
+ bottom= bottom->next;
+
+ for(marker= text->markers.first; marker; marker= next) {
+ next= marker->next;
+
+ for(cy= 0, line= top; line; cy++, line= line->next) {
+ if(cy+st->top==marker->lineno) {
+ /* Remove broken markers */
+ if(marker->end>line->len || marker->start>marker->end) {
+ BLI_freelinkN(&text->markers, marker);
+ break;
+ }
+
+ wrap_offset(st, ar, line, marker->start, &offl, &offc);
+ x1= get_char_pos(st, line->line, marker->start) - st->left + offc;
+ y1= cy + offl;
+ wrap_offset(st, ar, line, marker->end, &offl, &offc);
+ x2= get_char_pos(st, line->line, marker->end) - st->left + offc;
+ y2= cy + offl;
+
+ glColor3ub(marker->color[0], marker->color[1], marker->color[2]);
+ x= st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ y= ar->winy-3;
+
+ if(y1==y2) {
+ y -= y1*st->lheight;
+ glBegin(GL_LINE_LOOP);
+ glVertex2i(x+x2*text_font_width_character(st)+1, y);
+ glVertex2i(x+x1*text_font_width_character(st)-2, y);
+ glVertex2i(x+x1*text_font_width_character(st)-2, y-st->lheight);
+ glVertex2i(x+x2*text_font_width_character(st)+1, y-st->lheight);
+ glEnd();
+ }
+ else {
+ y -= y1*st->lheight;
+ glBegin(GL_LINE_STRIP);
+ glVertex2i(ar->winx, y);
+ glVertex2i(x+x1*text_font_width_character(st)-2, y);
+ glVertex2i(x+x1*text_font_width_character(st)-2, y-st->lheight);
+ glVertex2i(ar->winx, y-st->lheight);
+ glEnd();
+ y-=st->lheight;
+
+ for(i=y1+1; i<y2; i++) {
+ glBegin(GL_LINES);
+ glVertex2i(x, y);
+ glVertex2i(ar->winx, y);
+ glVertex2i(x, y-st->lheight);
+ glVertex2i(ar->winx, y-st->lheight);
+ glEnd();
+ y-=st->lheight;
+ }
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2i(x, y);
+ glVertex2i(x+x2*text_font_width_character(st)+1, y);
+ glVertex2i(x+x2*text_font_width_character(st)+1, y-st->lheight);
+ glVertex2i(x, y-st->lheight);
+ glEnd();
+ }
+
+ break;
+ }
+
+ if(line==bottom) break;
+ }
+ }
+}
+
+/*********************** draw documentation *******************************/
+
+static void draw_documentation(SpaceText *st, ARegion *ar)
+{
+ TextLine *tmp;
+ char *docs, buf[DOC_WIDTH+1], *p;
+ int len, i, br, lines;
+ int boxw, boxh, l, x, y, top;
+
+ if(!st || !st->text) return;
+ if(!texttool_text_is_active(st->text)) return;
+
+ docs = texttool_docs_get();
+
+ if(!docs) return;
+
+ /* Count the visible lines to the cursor */
+ for(tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
+ if(l<0) return;
+
+ if(st->showlinenrs) {
+ x= text_font_width_character(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
+ }
+ else {
+ x= text_font_width_character(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
+ }
+ if(texttool_suggest_first()) {
+ x += SUGG_LIST_WIDTH*text_font_width_character(st) + 50;
+ }
+
+ top= y= ar->winy - st->lheight*l - 2;
+ len= strlen(docs);
+ boxw= DOC_WIDTH*text_font_width_character(st) + 20;
+ boxh= (DOC_HEIGHT+1)*st->lheight;
+
+ /* Draw panel */
+ UI_ThemeColor(TH_BACK);
+ glRecti(x, y, x+boxw, y-boxh);
+ UI_ThemeColor(TH_SHADE1);
+ glBegin(GL_LINE_LOOP);
+ glVertex2i(x, y);
+ glVertex2i(x+boxw, y);
+ glVertex2i(x+boxw, y-boxh);
+ glVertex2i(x, y-boxh);
+ glEnd();
+ glBegin(GL_LINE_LOOP);
+ glVertex2i(x+boxw-10, y-7);
+ glVertex2i(x+boxw-4, y-7);
+ glVertex2i(x+boxw-7, y-2);
+ glEnd();
+ glBegin(GL_LINE_LOOP);
+ glVertex2i(x+boxw-10, y-boxh+7);
+ glVertex2i(x+boxw-4, y-boxh+7);
+ glVertex2i(x+boxw-7, y-boxh+2);
+ glEnd();
+ UI_ThemeColor(TH_TEXT);
+
+ i= 0; br= DOC_WIDTH; lines= 0; // XXX -doc_scroll;
+ for(p=docs; *p; p++) {
+ if(*p == '\r' && *(++p) != '\n') *(--p)= '\n'; /* Fix line endings */
+ if(*p == ' ' || *p == '\t')
+ br= i;
+ else if(*p == '\n') {
+ buf[i]= '\0';
+ if(lines>=0) {
+ y -= st->lheight;
+ text_draw(st, buf, 0, 0, 1, x+4, y-3, NULL);
+ }
+ i= 0; br= DOC_WIDTH; lines++;
+ }
+ buf[i++]= *p;
+ if(i == DOC_WIDTH) { /* Reached the width, go to last break and wrap there */
+ buf[br]= '\0';
+ if(lines>=0) {
+ y -= st->lheight;
+ text_draw(st, buf, 0, 0, 1, x+4, y-3, NULL);
+ }
+ p -= i-br-1; /* Rewind pointer to last break */
+ i= 0; br= DOC_WIDTH; lines++;
+ }
+ if(lines >= DOC_HEIGHT) break;
+ }
+
+ if(0 /* XXX doc_scroll*/ > 0 && lines < DOC_HEIGHT) {
+ // XXX doc_scroll--;
+ draw_documentation(st, ar);
+ }
+}
+
+/*********************** draw suggestion list *******************************/
+
+static void draw_suggestion_list(SpaceText *st, ARegion *ar)
+{
+ SuggItem *item, *first, *last, *sel;
+ TextLine *tmp;
+ char str[SUGG_LIST_WIDTH+1];
+ int w, boxw=0, boxh, i, l, x, y, b, *top;
+
+ if(!st || !st->text) return;
+ if(!texttool_text_is_active(st->text)) return;
+
+ first = texttool_suggest_first();
+ last = texttool_suggest_last();
+
+ if(!first || !last) return;
+
+ text_pop_suggest_list();
+ sel = texttool_suggest_selected();
+ top = texttool_suggest_top();
+
+ /* Count the visible lines to the cursor */
+ for(tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
+ if(l<0) return;
+
+ if(st->showlinenrs) {
+ x = text_font_width_character(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
+ }
+ else {
+ x = text_font_width_character(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
+ }
+ y = ar->winy - st->lheight*l - 2;
+
+ boxw = SUGG_LIST_WIDTH*text_font_width_character(st) + 20;
+ boxh = SUGG_LIST_SIZE*st->lheight + 8;
+
+ UI_ThemeColor(TH_SHADE1);
+ glRecti(x-1, y+1, x+boxw+1, y-boxh-1);
+ UI_ThemeColor(TH_BACK);
+ glRecti(x, y, x+boxw, y-boxh);
+
+ /* Set the top 'item' of the visible list */
+ for(i=0, item=first; i<*top && item->next; i++, item=item->next);
+
+ for(i=0; i<SUGG_LIST_SIZE && item; i++, item=item->next) {
+
+ y -= st->lheight;
+
+ strncpy(str, item->name, SUGG_LIST_WIDTH);
+ str[SUGG_LIST_WIDTH] = '\0';
+
+ w = text_font_width(st, str);
+
+ if(item == sel) {
+ UI_ThemeColor(TH_SHADE2);
+ glRecti(x+16, y-3, x+16+w, y+st->lheight-3);
+ }
+ b=1; /* b=1 colour block, text is default. b=0 no block, colour text */
+ switch (item->type) {
+ case 'k': UI_ThemeColor(TH_SYNTAX_B); b=0; break;
+ case 'm': UI_ThemeColor(TH_TEXT); break;
+ case 'f': UI_ThemeColor(TH_SYNTAX_L); break;
+ case 'v': UI_ThemeColor(TH_SYNTAX_N); break;
+ case '?': UI_ThemeColor(TH_TEXT); b=0; break;
+ }
+ if(b) {
+ glRecti(x+8, y+2, x+11, y+5);
+ UI_ThemeColor(TH_TEXT);
+ }
+ text_draw(st, str, 0, 0, 1, x+16, y-1, NULL);
+
+ if(item == last) break;
+ }
+}
+
+/*********************** draw cursor ************************/
+
+static void draw_cursor(SpaceText *st, ARegion *ar)
+{
+ Text *text= st->text;
+ int vcurl, vcurc, vsell, vselc, hidden=0;
+ int offl, offc, x, y, w, i;
+
+ /* Draw the selection */
+ if(text->curl!=text->sell || text->curc!=text->selc) {
+ /* Convert all to view space character coordinates */
+ wrap_offset(st, ar, text->curl, text->curc, &offl, &offc);
+ vcurl = txt_get_span(text->lines.first, text->curl) - st->top + offl;
+ vcurc = get_char_pos(st, text->curl->line, text->curc) - st->left + offc;
+ wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
+ vsell = txt_get_span(text->lines.first, text->sell) - st->top + offl;
+ vselc = get_char_pos(st, text->sell->line, text->selc) - st->left + offc;
+
+ if(vcurc<0) vcurc=0;
+ if(vselc<0) vselc=0, hidden=1;
+
+ UI_ThemeColor(TH_SHADE2);
+ x= st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ y= ar->winy-2;
+
+ if(vcurl==vsell) {
+ y -= vcurl*st->lheight;
+ if(vcurc < vselc)
+ glRecti(x+vcurc*text_font_width_character(st)-1, y, x+vselc*text_font_width_character(st), y-st->lheight);
+ else
+ glRecti(x+vselc*text_font_width_character(st)-1, y, x+vcurc*text_font_width_character(st), y-st->lheight);
+ }
+ else {
+ int froml, fromc, tol, toc;
+
+ if(vcurl < vsell) {
+ froml= vcurl; tol= vsell;
+ fromc= vcurc; toc= vselc;
+ }
+ else {
+ froml= vsell; tol= vcurl;
+ fromc= vselc; toc= vcurc;
+ }
+
+ y -= froml*st->lheight;
+ glRecti(x+fromc*text_font_width_character(st)-1, y, ar->winx, y-st->lheight); y-=st->lheight;
+ for(i=froml+1; i<tol; i++)
+ glRecti(x-4, y, ar->winx, y-st->lheight), y-=st->lheight;
+
+ glRecti(x-4, y, x+toc*text_font_width_character(st), y-st->lheight); y-=st->lheight;
+ }
+ }
+ else {
+ wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
+ vsell = txt_get_span(text->lines.first, text->sell) - st->top + offl;
+ vselc = get_char_pos(st, text->sell->line, text->selc) - st->left + offc;
+
+ if(vselc<0) {
+ vselc= 0;
+ hidden= 1;
+ }
+ }
+
+ if(!hidden) {
+ /* Draw the cursor itself (we draw the sel. cursor as this is the leading edge) */
+ x= st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ x += vselc*text_font_width_character(st);
+ y= ar->winy-2 - vsell*st->lheight;
+
+ if(st->overwrite) {
+ char ch= text->sell->line[text->selc];
+ if(!ch) ch= ' ';
+ w= text_font_width_character(st);
+ UI_ThemeColor(TH_HILITE);
+ glRecti(x, y-st->lheight-1, x+w, y-st->lheight+1);
+ }
+ else {
+ UI_ThemeColor(TH_HILITE);
+ glRecti(x-1, y, x+1, y-st->lheight);
+ }
+ }
+}
+
+/******************* draw matching brackets *********************/
+
+static void draw_brackets(SpaceText *st, ARegion *ar)
+{
+ TextLine *startl, *endl, *linep;
+ Text *text = st->text;
+ int b, c, startc, endc, find, stack;
+ int viewc, viewl, offl, offc, x, y;
+ char ch;
+
+ if(!text->curl) return;
+
+ startl= text->curl;
+ startc= text->curc;
+ b= text_check_bracket(startl->line[startc]);
+ if(b==0 && startc>0) b = text_check_bracket(startl->line[--startc]);
+ if(b==0) return;
+
+ linep= startl;
+ c= startc;
+ endl= NULL;
+ endc= -1;
+ find= -b;
+ stack= 0;
+
+ if(b>0) {
+ /* opening bracket, search forward for close */
+ c++;
+ while(linep) {
+ while(c<linep->len) {
+ b= text_check_bracket(linep->line[c]);
+ if(b==find) {
+ if(stack==0) {
+ endl= linep;
+ endc= c;
+ break;
+ }
+ stack--;
+ }
+ else if(b==-find) {
+ stack++;
+ }
+ c++;
+ }
+ if(endl) break;
+ linep= linep->next;
+ c= 0;
+ }
+ }
+ else {
+ /* closing bracket, search backward for open */
+ c--;
+ while(linep) {
+ while(c>=0) {
+ b= text_check_bracket(linep->line[c]);
+ if(b==find) {
+ if(stack==0) {
+ endl= linep;
+ endc= c;
+ break;
+ }
+ stack--;
+ }
+ else if(b==-find) {
+ stack++;
+ }
+ c--;
+ }
+ if(endl) break;
+ linep= linep->prev;
+ if(linep) c= linep->len-1;
+ }
+ }
+
+ if(!endl || endc==-1)
+ return;
+
+ UI_ThemeColor(TH_HILITE);
+ x= st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ y= ar->winy - st->lheight;
+
+ /* draw opening bracket */
+ ch= startl->line[startc];
+ wrap_offset(st, ar, startl, startc, &offl, &offc);
+ viewc= get_char_pos(st, startl->line, startc) - st->left + offc;
+
+ if(viewc >= 0){
+ viewl= txt_get_span(text->lines.first, startl) - st->top + offl;
+
+ text_font_draw_character(st, x+viewc*text_font_width_character(st), y-viewl*st->lheight, ch);
+ text_font_draw_character(st, x+viewc*text_font_width_character(st)+1, y-viewl*st->lheight, ch);
+ }
+
+ /* draw closing bracket */
+ ch= endl->line[endc];
+ wrap_offset(st, ar, endl, endc, &offl, &offc);
+ viewc= get_char_pos(st, endl->line, endc) - st->left + offc;
+
+ if(viewc >= 0) {
+ viewl= txt_get_span(text->lines.first, endl) - st->top + offl;
+
+ text_font_draw_character(st, x+viewc*text_font_width_character(st), y-viewl*st->lheight, ch);
+ text_font_draw_character(st, x+viewc*text_font_width_character(st)+1, y-viewl*st->lheight, ch);
+ }
+}
+
+/*********************** main area drawing *************************/
+
+void draw_text_main(SpaceText *st, ARegion *ar)
+{
+ Text *text= st->text;
+ TextLine *tmp;
+ char linenr[12];
+ int i, x, y, linecount= 0;
+
+ /* if no text, nothing to do */
+ if(!text)
+ return;
+
+ /* make sure all the positional pointers exist */
+ if(!text->curl || !text->sell || !text->lines.first || !text->lines.last)
+ txt_clean_text(text);
+
+ if(st->lheight) st->viewlines= (int)ar->winy/st->lheight;
+ else st->viewlines= 0;
+
+ /* update rects for scroll */
+ calc_text_rcts(st, ar);
+
+ /* update syntax formatting if needed */
+ tmp= text->lines.first;
+ for(i= 0; i<st->top && tmp; i++) {
+ if(st->showsyntax && !tmp->format)
+ txt_format_line(st, tmp, 0);
+
+ tmp= tmp->next;
+ linecount++;
+ }
+
+ /* draw line numbers background */
+ if(st->showlinenrs) {
+ UI_ThemeColor(TH_GRID);
+ glRecti(23, 0, (st->lheight==15)? 63: 59, ar->winy - 2);
+ }
+
+ text_font_begin(st);
+
+ /* draw cursor */
+ draw_cursor(st, ar);
+
+ /* draw the text */
+ UI_ThemeColor(TH_TEXT);
+
+ y= ar->winy-st->lheight;
+ x= (st->showlinenrs)? TXT_OFFSET + TEXTXLOC: TXT_OFFSET;
+
+ for(i=0; y>0 && i<st->viewlines && tmp; i++, tmp= tmp->next) {
+ if(st->showsyntax && !tmp->format)
+ txt_format_line(st, tmp, 0);
+
+ if(st->showlinenrs) {
+ /* draw line number */
+ if(tmp == text->curl)
+ UI_ThemeColor(TH_HILITE);
+ else
+ UI_ThemeColor(TH_TEXT);
+
+ if(((float)(i + linecount + 1)/10000.0) < 1.0) {
+ sprintf(linenr, "%4d", i + linecount + 1);
+ text_font_draw(st, TXT_OFFSET - 7, y, linenr);
+ }
+ else {
+ sprintf(linenr, "%5d", i + linecount + 1);
+ text_font_draw(st, TXT_OFFSET - 11, y, linenr);
+ }
+
+ UI_ThemeColor(TH_TEXT);
+ }
+
+ if(st->wordwrap) {
+ /* draw word wrapped text */
+ int lines = text_draw_wrapped(st, tmp->line, x, y, ar->winx-x, tmp->format);
+ y -= lines*st->lheight;
+ }
+ else {
+ /* draw unwrapped text */
+ text_draw(st, tmp->line, st->left, 0, 1, x, y, tmp->format);
+ y -= st->lheight;
+ }
+ }
+
+ /* draw other stuff */
+ draw_brackets(st, ar);
+ draw_markers(st, ar);
+ draw_textscroll(st, ar);
+ draw_documentation(st, ar);
+ draw_suggestion_list(st, ar);
+
+ text_font_end(st);
+}
+
+/************************** update ***************************/
+
+/* Moves the view to the cursor location,
+ also used to make sure the view isnt outside the file */
+void text_update_cursor_moved(SpaceText *st, ARegion *ar)
+{
+ Text *text= st->text;
+ int i, x;
+
+ if(!text || !text->curl) return;
+
+ i= txt_get_span(text->lines.first, text->sell);
+ if(st->top+st->viewlines <= i || st->top > i)
+ st->top= i - st->viewlines/2;
+
+ if(st->wordwrap) {
+ st->left= 0;
+ }
+ else {
+ x= text_draw(st, text->sell->line, st->left, text->selc, 0, 0, 0, NULL);
+
+ if(x==0 || x>ar->winx)
+ st->left= text->curc-0.5*(ar->winx)/text_font_width_character(st);
+ }
+
+ if(st->top < 0) st->top= 0;
+ if(st->left <0) st->left= 0;
+}
+
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index b8898e40f01..ea0005fd716 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -26,12 +26,26 @@
* ***** END GPL LICENSE BLOCK *****
*/
+#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+/* file time checking */
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#include "BLI_winstuff.h"
+#endif
+
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_text_types.h"
#include "DNA_windowmanager_types.h"
#include "MEM_guardedalloc.h"
@@ -39,7 +53,11 @@
#include "BLI_blenlib.h"
#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_text.h"
#include "ED_screen.h"
#include "ED_types.h"
@@ -53,81 +71,591 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "UI_text.h"
#include "UI_view2d.h"
+#include "RNA_access.h"
+
+#ifndef DISABLE_PYTHON
+#include "BPY_extern.h"
+// XXX #include "BPY_menus.h"
+#endif
+
#include "text_intern.h"
+#define HEADER_PATH_MAX 260
/* ************************ header area region *********************** */
-static void do_viewmenu(bContext *C, void *arg, int event)
+#ifndef DISABLE_PYTHON
+static void do_text_template_scriptsmenu(bContext *C, void *arg, int event)
{
-
+ // XXX BPY_menu_do_python(PYMENU_SCRIPTTEMPLATE, event);
}
-static uiBlock *dummy_viewmenu(bContext *C, ARegion *ar, void *arg_unused)
+uiBlock *text_template_scriptsmenu(bContext *C, void *args_unused)
{
- ScrArea *curarea= CTX_wm_area(C);
+ ARegion *ar= CTX_wm_region(C);
uiBlock *block;
- short yco= 0, menuwidth=120;
-
- block= uiBeginBlock(C, ar, "dummy_viewmenu", UI_EMBOSSP, UI_HELV);
- uiBlockSetButmFunc(block, do_viewmenu, NULL);
+ // XXX BPyMenu *pym;
+ // int i= 0;
+ // short yco = 20, menuwidth = 120;
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Nothing yet", 0, yco-=20,
- menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ block= uiBeginBlock(C, ar, "text_template_scriptsmenu", UI_EMBOSSP, UI_HELV);
+ uiBlockSetButmFunc(block, do_text_template_scriptsmenu, NULL);
- if(curarea->headertype==HEADERTOP) {
- uiBlockSetDirection(block, UI_DOWN);
- }
- else {
- uiBlockSetDirection(block, UI_TOP);
- uiBlockFlipOrder(block);
- }
+ /* note that we acount for the N previous entries with i+20: */
+ /* XXX for (pym = BPyMenuTable[PYMENU_SCRIPTTEMPLATE]; pym; pym = pym->next, i++) {
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19,
+ NULL, 0.0, 0.0, 1, i,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }*/
- uiTextBoundsBlock(block, 50);
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
uiEndBlock(C, block);
+ uiDrawBlock(C, block);
+
+ return block;
+}
+
+static void do_text_plugin_scriptsmenu(bContext *C, void *arg, int event)
+{
+ // XXX BPY_menu_do_python(PYMENU_TEXTPLUGIN, event);
+}
+
+uiBlock *text_plugin_scriptsmenu(bContext *C, void *args_unused)
+{
+ ARegion *ar= CTX_wm_region(C);
+ uiBlock *block;
+ // XXX BPyMenu *pym;
+ // int i= 0;
+ // short yco = 20, menuwidth = 120;
+
+ block= uiBeginBlock(C, ar, "text_plugin_scriptsmenu", UI_EMBOSSP, UI_HELV);
+ uiBlockSetButmFunc(block, do_text_plugin_scriptsmenu, NULL);
+ /* note that we acount for the N previous entries with i+20: */
+ /* XXX for (pym = BPyMenuTable[PYMENU_TEXTPLUGIN]; pym; pym = pym->next, i++) {
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19,
+ NULL, 0.0, 0.0, 1, i,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }*/
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ uiEndBlock(C, block);
+ uiDrawBlock(C, block);
+
return block;
}
+#endif
+
+static void text_editmenu_viewmenu(bContext *C, uiMenuItem *head, void *arg_unused)
+{
+ uiMenuItemEnumO(head, "Top of File", 0, "TEXT_OT_move", "type", FILE_TOP);
+ uiMenuItemEnumO(head, "Bottom of File", 0, "TEXT_OT_move", "type", FILE_BOTTOM);
+}
+
+static void text_editmenu_selectmenu(bContext *C, uiMenuItem *head, void *arg_unused)
+{
+ uiMenuItemO(head, 0, "TEXT_OT_select_all");
+ uiMenuItemO(head, 0, "TEXT_OT_select_line");
+}
+
+static void text_editmenu_markermenu(bContext *C, uiMenuItem *head, void *arg_unused)
+{
+ uiMenuItemO(head, 0, "TEXT_OT_clear_all_markers");
+ uiMenuItemO(head, 0, "TEXT_OT_next_marker");
+ uiMenuItemO(head, 0, "TEXT_OT_previous_marker");
+}
+
+static void text_formatmenu(bContext *C, uiMenuItem *head, void *arg_unused)
+{
+ uiMenuItemO(head, 0, "TEXT_OT_indent");
+ uiMenuItemO(head, 0, "TEXT_OT_unindent");
+
+ uiMenuSeparator(head);
+
+ uiMenuItemO(head, 0, "TEXT_OT_comment");
+ uiMenuItemO(head, 0, "TEXT_OT_uncomment");
+
+ uiMenuSeparator(head);
+
+ uiMenuLevelEnumO(head, "TEXT_OT_convert_whitespace", "type");
+}
-static void do_text_buttons(bContext *C, void *arg, int event)
+static void text_editmenu_to3dmenu(bContext *C, uiMenuItem *head, void *arg_unused)
{
+ uiMenuItemBooleanO(head, "One Object", 0, "TEXT_OT_to_3d_object", "split_lines", 0);
+ uiMenuItemBooleanO(head, "One Object Per Line", 0, "TEXT_OT_to_3d_object", "split_lines", 1);
+}
+
+static void text_editmenu(bContext *C, uiMenuItem *head, void *arg_unused)
+{
+ uiMenuItemO(head, 0, "ED_OT_undo");
+ uiMenuItemO(head, 0, "ED_OT_redo");
+
+ uiMenuSeparator(head);
+
+ uiMenuItemO(head, 0, "TEXT_OT_cut");
+ uiMenuItemO(head, 0, "TEXT_OT_copy");
+ uiMenuItemO(head, 0, "TEXT_OT_paste");
+
+ uiMenuSeparator(head);
+
+ uiMenuLevel(head, "View", text_editmenu_viewmenu);
+ uiMenuLevel(head, "Select", text_editmenu_selectmenu);
+ uiMenuLevel(head, "Markers", text_editmenu_markermenu);
+
+ uiMenuSeparator(head);
+
+ uiMenuItemO(head, 0, "TEXT_OT_jump");
+ uiMenuItemO(head, 0, "TEXT_OT_find_and_replace");
+
+ uiMenuSeparator(head);
+
+ uiMenuLevel(head, "Text to 3D Object", text_editmenu_to3dmenu);
+}
+
+static void text_filemenu(bContext *C, uiMenuItem *head, void *arg_unused)
+{
+ SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
+ Text *text= st->text;
+
+ uiMenuItemO(head, 0, "TEXT_OT_new");
+ uiMenuItemO(head, 0, "TEXT_OT_open");
+
+ if(text) {
+ uiMenuItemO(head, 0, "TEXT_OT_reload");
+
+ uiMenuSeparator(head);
+
+ uiMenuItemO(head, 0, "TEXT_OT_save");
+ uiMenuItemO(head, 0, "TEXT_OT_save_as");
+
+ if(text->name)
+ uiMenuItemO(head, 0, "TEXT_OT_make_internal");
+
+ uiMenuSeparator(head);
+
+ uiMenuItemO(head, 0, "TEXT_OT_run_script");
+
+#ifndef DISABLE_PYTHON
+ if(BPY_is_pyconstraint(text))
+ uiMenuItemO(head, 0, "TEXT_OT_refresh_pyconstraints");
+#endif
+ }
+
+#ifndef DISABLE_PYTHON
+ // XXX uiMenuSeparator(head);
+
+ // XXX uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, "");
+ // XXX uiDefIconTextBlockBut(block, text_plugin_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Text Plugins", 0, yco-=20, 120, 19, "");
+#endif
+}
+
+/*********************** datablock browse *************************/
+
+static void text_unlink(Main *bmain, Text *text)
+{
+ bScreen *scr;
+ ScrArea *area;
+ SpaceLink *sl;
+
+ /* XXX this ifdef is in fact dangerous, if python is
+ * disabled it will leave invalid pointers in files! */
+
+#ifndef DISABLE_PYTHON
+ // XXX BPY_clear_bad_scriptlinks(text);
+ // XXX BPY_free_pyconstraint_links(text);
+ // XXX free_text_controllers(text);
+
+ /* check if this text was used as script link:
+ * this check function unsets the pointers and returns how many
+ * script links used this Text */
+ if(0) // XXX BPY_text_check_all_scriptlinks (text))
+ ; // XXX notifier: allqueue(REDRAWBUTSSCRIPT, 0);
+
+ /* equivalently for pynodes: */
+ if(0) // XXX nodeDynamicUnlinkText ((ID*)text))
+ ; // XXX notifier: allqueue(REDRAWNODE, 0);
+#endif
+
+ for(scr= bmain->screen.first; scr; scr= scr->id.next) {
+ for(area= scr->areabase.first; area; area= area->next) {
+ for(sl= area->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText*) sl;
+
+ if(st->text==text) {
+ st->text= NULL;
+ st->top= 0;
+
+ if(st==area->spacedata.first)
+ ED_area_tag_redraw(area);
+ }
+ }
+ }
+ }
+ }
+
+ free_libblock(&bmain->text, text);
+}
+
+static void text_idpoin_handle(bContext *C, ID *id, int event)
+{
+ SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
+ Text *text;
+
switch(event) {
+ case UI_ID_BROWSE:
+ st->text= (Text*)id;
+ st->top= 0;
+
+ text_update_edited(st->text);
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
+
+ ED_undo_push(C, "Browse Text");
+ break;
+ case UI_ID_DELETE:
+ text= st->text;
+
+ /* make the previous text active, if its not there make the next text active */
+ if(text->id.prev) {
+ st->text = text->id.prev;
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
+ }
+ else if(text->id.next) {
+ st->text = text->id.next;
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
+ }
+
+ text_unlink(CTX_data_main(C), text);
+ WM_event_add_notifier(C, NC_TEXT|NA_REMOVED, text);
+
+ ED_undo_push(C, "Delete Text");
+ break;
+ case UI_ID_RENAME:
+ break;
+ case UI_ID_ADD_NEW:
+ WM_operator_name_call(C, "TEXT_OT_new", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
+ case UI_ID_OPEN:
+ WM_operator_name_call(C, "TEXT_OT_open", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
}
}
+/********************** header buttons ***********************/
void text_header_buttons(const bContext *C, ARegion *ar)
{
+ bScreen *sc= CTX_wm_screen(C);
+ SpaceText *st= (SpaceText*)CTX_wm_space_data(C);
+ PointerRNA spaceptr;
+ Text *text= st->text;
ScrArea *sa= CTX_wm_area(C);
uiBlock *block;
- int xco, yco= 3;
+ int xco, yco= 3, xmax, oldcol;
+ RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
+
block= uiBeginBlock(C, ar, "header buttons", UI_EMBOSS, UI_HELV);
- uiBlockSetHandleFunc(block, do_text_buttons, NULL);
xco= ED_area_header_standardbuttons(C, block, yco);
if((sa->flag & HEADER_NO_PULLDOWN)==0) {
- int xmax;
-
/* pull down menus */
uiBlockSetEmboss(block, UI_EMBOSSP);
- xmax= GetButStringLength("View");
- uiDefPulldownBut(block, dummy_viewmenu, CTX_wm_area(C),
- "View", xco, yco-2, xmax-3, 24, "");
- xco+=XIC+xmax;
+ xmax= GetButStringLength("Text");
+ uiDefMenuBut(block, text_filemenu, NULL, "Text", xco, yco-2, xmax-3, 24, "");
+ xco+=xmax;
+
+ if(text) {
+ xmax= GetButStringLength("Edit");
+ uiDefMenuBut(block, text_editmenu, NULL, "Edit", xco, yco-2, xmax-3, 24, "");
+ xco+=xmax;
+
+ xmax= GetButStringLength("Format");
+ uiDefMenuBut(block, text_formatmenu, NULL, "Format", xco, yco-2, xmax-3, 24, "");
+ xco+=xmax;
+ }
}
uiBlockSetEmboss(block, UI_EMBOSS);
+ uiBlockBeginAlign(block);
+ uiDefIconButR(block, ICONTOG, 0, ICON_LINENUMBERS_OFF, xco, yco,XIC,YIC, &spaceptr, "line_numbers", 0, 0, 0, 0, 0, NULL);
+ uiDefIconButR(block, ICONTOG, 0, ICON_WORDWRAP_OFF, xco+=XIC, yco,XIC,YIC, &spaceptr, "word_wrap", 0, 0, 0, 0, 0, NULL);
+ uiDefIconButR(block, ICONTOG, 0, ICON_SYNTAX_OFF, xco+=XIC, yco,XIC,YIC, &spaceptr, "syntax_highlight", 0, 0, 0, 0, 0, NULL);
+ // uiDefIconButR(block, ICONTOG, 0, ICON_SCRIPTPLUGINS, xco+=XIC, yco,XIC,YIC, &spaceptr, "do_python_plugins", 0, 0, 0, 0, 0, "Enables Python text plugins");
+ uiBlockEndAlign(block);
+
+ /* warning button if text is out of date */
+ if(text && text_file_modified(text)) {
+ xco+= XIC;
+
+ oldcol= uiBlockGetCol(block);
+ uiBlockSetCol(block, TH_REDALERT);
+ uiDefIconButO(block, BUT, "TEXT_OT_resolve_conflict", WM_OP_INVOKE_DEFAULT, ICON_HELP, xco+=XIC,yco,XIC,YIC, "External text is out of sync, click for options to resolve the conflict");
+ uiBlockSetCol(block, oldcol);
+ }
+
+ /* browse text datablock */
+ xco+= 2*XIC;
+ xco= uiDefIDPoinButs(block, CTX_data_main(C), NULL, (ID*)st->text, ID_TXT, NULL, xco, yco,
+ text_idpoin_handle, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_ADD_NEW|UI_ID_OPEN|UI_ID_DELETE);
+ xco+=XIC;
+
+ /*
+ if(st->text) {
+ if(st->text->flags & TXT_ISDIRTY && (st->text->flags & TXT_ISEXT || !(st->text->flags & TXT_ISMEM)))
+ uiDefIconBut(block, BUT,0, ICON_ERROR, xco+=XIC,yco,XIC,YIC, 0, 0, 0, 0, 0, "The text has been changed");
+ if(st->text->flags & TXT_ISEXT)
+ uiDefBut(block, BUT,B_TEXTSTORE, ICON(), xco+=XIC,yco,XIC,YIC, 0, 0, 0, 0, 0, "Stores text in project file");
+ else
+ uiDefBut(block, BUT,B_TEXTSTORE, ICON(), xco+=XIC,yco,XIC,YIC, 0, 0, 0, 0, 0, "Disables storing of text in project file");
+ xco+=10;
+ }
+ */
+
+ /* display settings */
+ if(st->font_id>1) st->font_id= 0;
+ uiDefButR(block, MENU, 0, NULL, xco,yco,100,YIC, &spaceptr, "font_size", 0, 0, 0, 0, 0, NULL);
+ xco+=105;
+
+ uiDefButR(block, NUM, 0, "Tab:", xco,yco,XIC+50,YIC, &spaceptr, "tab_width", 0, 0, 0, 0, 0, NULL);
+ xco+= XIC+50;
+
+ /* file info */
+ if(text) {
+ char fname[HEADER_PATH_MAX], headtxt[HEADER_PATH_MAX+17];
+ int len;
+
+ if(text->name) {
+ len = strlen(text->name);
+ if(len > HEADER_PATH_MAX-1)
+ len = HEADER_PATH_MAX-1;
+ strncpy(fname, text->name, len);
+ fname[len]='\0';
+ if(text->flags & TXT_ISDIRTY)
+ sprintf(headtxt, "File: *%s (unsaved)", fname);
+ else
+ sprintf(headtxt, "File: %s", fname);
+ }
+ else
+ sprintf(headtxt, text->id.lib? "Text: External": "Text: Internal");
+
+ UI_ThemeColor(TH_MENU_TEXT);
+ UI_RasterPos(xco+=XIC, yco+6);
+
+ UI_DrawString(G.font, headtxt, 0);
+ xco += UI_GetStringWidth(G.font, headtxt, 0);
+ }
+
+ uiEndBlock(C, block);
+ uiDrawBlock(C, block);
+
/* always as last */
UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
+}
+
+/************************* find & replace ***************************/
+
+void text_find_buttons(const bContext *C, ARegion *ar)
+{
+ bScreen *sc= CTX_wm_screen(C);
+ SpaceText *st= CTX_wm_space_text(C);
+ PointerRNA spaceptr;
+ uiBlock *block;
+ int xco= 5, yco= 3;
+
+ RNA_pointer_create(&sc->id, &RNA_SpaceTextEditor, st, &spaceptr);
+
+ block= uiBeginBlock(C, ar, "find buttons", UI_EMBOSS, UI_HELV);
+
+ /* find */
+ uiBlockBeginAlign(block);
+ uiDefButR(block, TEX, 0, "Find: ", xco, yco,220,20, &spaceptr, "find_text", 0, 0, 0, 0, 0, NULL);
+ xco += 220;
+ uiDefIconButO(block, BUT, "TEXT_OT_find_set_selected", WM_OP_INVOKE_DEFAULT, ICON_TEXT, xco,yco,20,20, "Copy from selection");
+ xco += 20+XIC;
+ uiBlockEndAlign(block);
+
+ /* replace */
+ uiBlockBeginAlign(block);
+ uiDefButR(block, TEX, 0, "Replace: ", xco, yco,220,20, &spaceptr, "replace_text", 0, 0, 0, 0, 0, NULL);
+ xco += 220;
+ uiDefIconButO(block, BUT, "TEXT_OT_replace_set_selected", WM_OP_INVOKE_DEFAULT, ICON_TEXT, xco,yco,20,20, "Copy from selection");
+ xco += 20+XIC;
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButR(block, TOG, 0, "Wrap", xco, yco,60,20, &spaceptr, "find_wrap", 0, 0, 0, 0, 0, NULL);
+ xco += 60;
+ uiDefButR(block, TOG, 0, "All", xco, yco,60,20, &spaceptr, "find_all", 0, 0, 0, 0, 0, NULL);
+ xco += 50+XIC;
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButO(block, BUT, "TEXT_OT_find", WM_OP_INVOKE_REGION_WIN, "Find", xco,yco,50,20, "Find next.");
+ xco += 50;
+ uiDefButO(block, BUT, "TEXT_OT_replace", WM_OP_INVOKE_REGION_WIN, "Replace", xco,yco,70,20, "Replace then find next.");
+ xco += 70;
+ uiDefButO(block, BUT, "TEXT_OT_mark_all", WM_OP_INVOKE_REGION_WIN, "Mark All", xco,yco,80,20, "Mark each occurrence to edit all from one");
+ xco += 80;
+ uiBlockEndAlign(block);
uiEndBlock(C, block);
uiDrawBlock(C, block);
+
+ /* always as last */
+ UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
}
+ARegion *text_has_find_region(ScrArea *sa)
+{
+ ARegion *ar, *arnew;
+
+ for(ar= sa->regionbase.first; ar; ar= ar->next)
+ if(ar->regiontype==RGN_TYPE_UI)
+ return ar;
+
+ /* add subdiv level; after header */
+ for(ar= sa->regionbase.first; ar; ar= ar->next)
+ if(ar->regiontype==RGN_TYPE_HEADER)
+ break;
+
+ /* is error! */
+ if(ar==NULL) return NULL;
+
+ arnew= MEM_callocN(sizeof(ARegion), "find and replace region");
+
+ BLI_insertlinkafter(&sa->regionbase, ar, arnew);
+ arnew->regiontype= RGN_TYPE_UI;
+ arnew->alignment= RGN_ALIGN_BOTTOM;
+
+ arnew->flag = RGN_FLAG_HIDDEN;
+
+ return arnew;
+}
+
+static int find_and_replace_poll(bContext *C)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+
+ return (st && text);
+}
+
+static int find_and_replace_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *sa= CTX_wm_area(C);
+ ARegion *ar= text_has_find_region(sa);
+
+ if(ar) {
+ ar->flag ^= RGN_FLAG_HIDDEN;
+ ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
+
+ ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
+ ED_area_tag_redraw(sa);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_find_and_replace(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Find and Replace";
+ ot->idname= "TEXT_OT_find_and_replace";
+
+ /* api callbacks */
+ ot->exec= find_and_replace_exec;
+ ot->poll= find_and_replace_poll;
+}
+
+/******************** XXX popup menus *******************/
+
+#if 0
+{
+ // RMB
+
+ uiMenuItem *head;
+
+ if(text) {
+ head= uiPupMenuBegin("Text", 0);
+ if(txt_has_sel(text)) {
+ uiMenuItemO(head, 0, "TEXT_OT_cut");
+ uiMenuItemO(head, 0, "TEXT_OT_copy");
+ }
+ uiMenuItemO(head, 0, "TEXT_OT_paste");
+ uiMenuItemO(head, 0, "TEXT_OT_new");
+ uiMenuItemO(head, 0, "TEXT_OT_open");
+ uiMenuItemO(head, 0, "TEXT_OT_save");
+ uiMenuItemO(head, 0, "TEXT_OT_save_as");
+ uiMenuItemO(head, 0, "TEXT_OT_run_script");
+ uiPupMenuEnd(C, head);
+ }
+ else {
+ head= uiPupMenuBegin("File", 0);
+ uiMenuItemO(head, 0, "TEXT_OT_new");
+ uiMenuItemO(head, 0, "TEXT_OT_open");
+ uiPupMenuEnd(C, head);
+ }
+}
+
+{
+ // Alt+Shift+E
+
+ uiMenuItem *head;
+
+ head= uiPupMenuBegin("Edit", 0);
+ uiMenuItemO(head, 0, "TEXT_OT_cut");
+ uiMenuItemO(head, 0, "TEXT_OT_copy");
+ uiMenuItemO(head, 0, "TEXT_OT_paste");
+ uiPupMenuEnd(C, head);
+}
+
+{
+ // Alt+Shift+F
+
+ uiMenuItem *head;
+
+ if(text) {
+ head= uiPupMenuBegin("Text", 0);
+ uiMenuItemO(head, 0, "TEXT_OT_new");
+ uiMenuItemO(head, 0, "TEXT_OT_open");
+ uiMenuItemO(head, 0, "TEXT_OT_save");
+ uiMenuItemO(head, 0, "TEXT_OT_save_as");
+ uiMenuItemO(head, 0, "TEXT_OT_run_script");
+ uiPupMenuEnd(C, head);
+ }
+ else {
+ head= uiPupMenuBegin("File", 0);
+ uiMenuItemO(head, 0, "TEXT_OT_new");
+ uiMenuItemO(head, 0, "TEXT_OT_open");
+ uiPupMenuEnd(C, head);
+ }
+}
+
+{
+ // Alt+Shift+V
+
+ uiMenuItem *head;
+
+ head= uiPupMenuBegin("Text", 0);
+ uiMenuItemEnumO(head, "Top of File", 0, "TEXT_OT_move", "type", FILE_TOP);
+ uiMenuItemEnumO(head, "Bottom of File", 0, "TEXT_OT_move", "type", FILE_BOTTOM);
+ uiMenuItemEnumO(head, "Page Up", 0, "TEXT_OT_move", "type", PREV_PAGE);
+ uiMenuItemEnumO(head, "Page Down", 0, "TEXT_OT_move", "type", NEXT_PAGE);
+ uiPupMenuEnd(C, head);
+}
+#endif
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 9fb2f0e07c3..b7e45501047 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
* All rights reserved.
*
*
@@ -30,10 +30,128 @@
/* internal exports only */
+struct ARegion;
+struct bContext;
+struct BMF_Font;
+struct ReportList;
+struct ScrArea;
+struct SpaceText;
+struct Text;
+struct TextLine;
+struct wmOperatorType;
+struct wmWindowManager;
/* text_header.c */
-void text_header_buttons(const bContext *C, ARegion *ar);
+void text_header_buttons(const struct bContext *C, struct ARegion *ar);
+void text_find_buttons(const struct bContext *C, struct ARegion *ar);
+/* text_draw.c */
+void draw_text_main(struct SpaceText *st, struct ARegion *ar);
+
+int text_check_bracket(char ch);
+int text_check_delim(char ch);
+int text_check_digit(char ch);
+int text_check_identifier(char ch);
+int text_check_whitespace(char ch);
+
+int text_font_width_character(struct SpaceText *st);
+int text_font_width(struct SpaceText *st, char *str);
+
+void text_update_line_edited(struct Text *text, struct TextLine *line);
+void text_update_edited(struct Text *text);
+void text_update_cursor_moved(struct SpaceText *st, struct ARegion *ar);
+
+#define TEXTXLOC 38
+
+#define SUGG_LIST_SIZE 7
+#define SUGG_LIST_WIDTH 20
+#define DOC_WIDTH 40
+#define DOC_HEIGHT 10
+
+#define TOOL_SUGG_LIST 0x01
+#define TOOL_DOCUMENT 0x02
+
+#define TMARK_GRP_CUSTOM 0x00010000 /* Lower 2 bytes used for Python groups */
+#define TMARK_GRP_FINDALL 0x00020000
+
+typedef struct FlattenString {
+ char fixedbuf[256];
+ int fixedaccum[256];
+
+ char *buf;
+ int *accum;
+ int pos, len;
+} FlattenString;
+
+int flatten_string(struct SpaceText *st, FlattenString *fs, char *in);
+void flatten_string_free(FlattenString *fs);
+
+void unlink_text(struct Text *text);
+
+int wrap_width(struct SpaceText *st, struct ARegion *ar);
+void wrap_offset(struct SpaceText *st, struct ARegion *ar, struct TextLine *linein, int cursin, int *offl, int *offc);
+
+int text_file_modified(struct Text *text);
+
+int text_do_suggest_select(struct SpaceText *st, struct ARegion *ar);
+void text_pop_suggest_list();
+
+
+/* text_ops.c */
+enum { LINE_BEGIN, LINE_END, FILE_TOP, FILE_BOTTOM, PREV_CHAR, NEXT_CHAR,
+ PREV_WORD, NEXT_WORD, PREV_LINE, NEXT_LINE, PREV_PAGE, NEXT_PAGE };
+enum { DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD };
+
+void TEXT_OT_new(struct wmOperatorType *ot);
+void TEXT_OT_open(struct wmOperatorType *ot);
+void TEXT_OT_reload(struct wmOperatorType *ot);
+void TEXT_OT_save(struct wmOperatorType *ot);
+void TEXT_OT_save_as(struct wmOperatorType *ot);
+void TEXT_OT_make_internal(struct wmOperatorType *ot);
+void TEXT_OT_run_script(struct wmOperatorType *ot);
+void TEXT_OT_refresh_pyconstraints(struct wmOperatorType *ot);
+
+void TEXT_OT_paste(struct wmOperatorType *ot);
+void TEXT_OT_copy(struct wmOperatorType *ot);
+void TEXT_OT_cut(struct wmOperatorType *ot);
+
+void TEXT_OT_convert_whitespace(struct wmOperatorType *ot);
+void TEXT_OT_uncomment(struct wmOperatorType *ot);
+void TEXT_OT_comment(struct wmOperatorType *ot);
+void TEXT_OT_unindent(struct wmOperatorType *ot);
+void TEXT_OT_indent(struct wmOperatorType *ot);
+
+void TEXT_OT_line_break(struct wmOperatorType *ot);
+void TEXT_OT_insert(struct wmOperatorType *ot);
+
+void TEXT_OT_clear_all_markers(struct wmOperatorType *ot);
+void TEXT_OT_next_marker(struct wmOperatorType *ot);
+void TEXT_OT_previous_marker(struct wmOperatorType *ot);
+
+void TEXT_OT_select_line(struct wmOperatorType *ot);
+void TEXT_OT_select_all(struct wmOperatorType *ot);
+
+void TEXT_OT_jump(struct wmOperatorType *ot);
+void TEXT_OT_move(struct wmOperatorType *ot);
+void TEXT_OT_move_select(struct wmOperatorType *ot);
+void TEXT_OT_delete(struct wmOperatorType *ot);
+void TEXT_OT_toggle_overwrite(struct wmOperatorType *ot);
+
+void TEXT_OT_scroll(struct wmOperatorType *ot);
+void TEXT_OT_scroll_bar(struct wmOperatorType *ot);
+void TEXT_OT_set_cursor(struct wmOperatorType *ot);
+void TEXT_OT_line_number(struct wmOperatorType *ot);
+
+void TEXT_OT_find_and_replace(struct wmOperatorType *ot);
+void TEXT_OT_find(struct wmOperatorType *ot);
+void TEXT_OT_find_set_selected(struct wmOperatorType *ot);
+void TEXT_OT_replace(struct wmOperatorType *ot);
+void TEXT_OT_replace_set_selected(struct wmOperatorType *ot);
+void TEXT_OT_mark_all(struct wmOperatorType *ot);
+
+void TEXT_OT_to_3d_object(struct wmOperatorType *ot);
+
+void TEXT_OT_resolve_conflict(struct wmOperatorType *ot);
#endif /* ED_TEXT_INTERN_H */
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
new file mode 100644
index 00000000000..6e7a507b35b
--- /dev/null
+++ b/source/blender/editors/space_text/text_ops.c
@@ -0,0 +1,2563 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h> /* ispunct */
+#include <sys/stat.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_action_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_text_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_blenlib.h"
+#include "PIL_time.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_suggestions.h"
+#include "BKE_text.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_curve.h"
+#include "ED_screen.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#ifndef DISABLE_PYTHON
+#include "BPY_extern.h"
+#endif
+
+#include "text_intern.h"
+
+/************************ poll ***************************/
+
+static int text_new_poll(bContext *C)
+{
+ return 1;
+}
+
+static int text_edit_poll(bContext *C)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(!text)
+ return 0;
+
+ if(text->id.lib) {
+ // BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int text_space_edit_poll(bContext *C)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+
+ if(!st || !text)
+ return 0;
+
+ if(text->id.lib) {
+ // BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int text_region_edit_poll(bContext *C)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+ ARegion *ar= CTX_wm_region(C);
+
+ if(!st || !text)
+ return 0;
+
+ if(!ar || ar->regiontype != RGN_TYPE_WINDOW)
+ return 0;
+
+ if(text->id.lib) {
+ // BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/********************** updates *********************/
+
+void text_update_line_edited(Text *text, TextLine *line)
+{
+ if(!line)
+ return;
+
+ /* we just free format here, and let it rebuild during draw */
+ if(line->format) {
+ MEM_freeN(line->format);
+ line->format= NULL;
+ }
+}
+
+void text_update_edited(Text *text)
+{
+ TextLine *line;
+
+ for(line=text->lines.first; line; line=line->next)
+ text_update_line_edited(text, line);
+}
+
+/******************* new operator *********************/
+
+static int new_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text;
+
+ text= add_empty_text("Text");
+
+ if(st) {
+ st->text= text;
+ st->top= 0;
+ }
+
+ WM_event_add_notifier(C, NC_TEXT|NA_ADDED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "New";
+ ot->idname= "TEXT_OT_new";
+
+ /* api callbacks */
+ ot->exec= new_exec;
+ ot->poll= text_new_poll;
+}
+
+/******************* open operator *********************/
+
+static int open_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text;
+ char str[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filename", str);
+
+ text= add_text(str, G.sce);
+
+ if(st) {
+ st->text= text;
+ st->top= 0;
+ }
+
+ WM_event_add_notifier(C, NC_TEXT|NA_ADDED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Text *text= CTX_data_edit_text(C);
+ char *path= (text && text->name)? text->name: G.sce;
+
+ if(RNA_property_is_set(op->ptr, "filename"))
+ return open_exec(C, op);
+
+ RNA_string_set(op->ptr, "filename", path);
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void TEXT_OT_open(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Open";
+ ot->idname= "TEXT_OT_open";
+
+ /* api callbacks */
+ ot->exec= open_exec;
+ ot->invoke= open_invoke;
+ ot->poll= text_new_poll;
+
+ /* properties */
+ RNA_def_string_file_path(ot->srna, "filename", "", FILE_MAX, "Filename", "File path of image to open.");
+}
+
+/******************* reload operator *********************/
+
+static int reload_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(!reopen_text(text)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not reopen file");
+ return OPERATOR_CANCELLED;
+ }
+
+#ifndef DISABLE_PYTHON
+ if(text->compiled)
+ BPY_free_compiled_text(text);
+
+ text->compiled = NULL;
+#endif
+
+ text_update_edited(text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_reload(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reload";
+ ot->idname= "TEXT_OT_reload";
+
+ /* api callbacks */
+ ot->exec= reload_exec;
+ ot->invoke= WM_operator_confirm;
+ ot->poll= text_edit_poll;
+}
+
+/******************* make internal operator *********************/
+
+static int make_internal_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ text->flags |= TXT_ISMEM | TXT_ISDIRTY;
+
+ if(text->name) {
+ MEM_freeN(text->name);
+ text->name= NULL;
+ }
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_make_internal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Make Internal";
+ ot->idname= "TEXT_OT_make_internal";
+
+ /* api callbacks */
+ ot->exec= make_internal_exec;
+ ot->poll= text_edit_poll;
+}
+
+/******************* save operator *********************/
+
+static int save_poll(bContext *C)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(!text_edit_poll(C))
+ return 0;
+
+ return (text->name != NULL && !(text->flags & TXT_ISMEM));
+}
+
+static void txt_write_file(Text *text, ReportList *reports)
+{
+ FILE *fp;
+ TextLine *tmp;
+ struct stat st;
+ int res;
+ char file[FILE_MAXDIR+FILE_MAXFILE];
+
+ BLI_strncpy(file, text->name, FILE_MAXDIR+FILE_MAXFILE);
+ BLI_convertstringcode(file, G.sce);
+
+ fp= fopen(file, "w");
+ if(fp==NULL) {
+ BKE_report(reports, RPT_ERROR, "Unable to save file.");
+ return;
+ }
+
+ tmp= text->lines.first;
+ while(tmp) {
+ if(tmp->next) fprintf(fp, "%s\n", tmp->line);
+ else fprintf(fp, "%s", tmp->line);
+
+ tmp= tmp->next;
+ }
+
+ fclose (fp);
+
+ res= stat(file, &st);
+ text->mtime= st.st_mtime;
+
+ if(text->flags & TXT_ISDIRTY)
+ text->flags ^= TXT_ISDIRTY;
+}
+
+static int save_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ txt_write_file(text, op->reports);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_save(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Save";
+ ot->idname= "TEXT_OT_save";
+
+ /* api callbacks */
+ ot->exec= save_exec;
+ ot->poll= save_poll;
+}
+
+/******************* save as operator *********************/
+
+static int save_as_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ char str[FILE_MAX];
+
+ if(!text)
+ return OPERATOR_CANCELLED;
+
+ RNA_string_get(op->ptr, "filename", str);
+
+ if(text->name) MEM_freeN(text->name);
+ text->name= BLI_strdup(str);
+ text->flags &= ~TXT_ISMEM;
+
+ txt_write_file(text, op->reports);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Text *text= CTX_data_edit_text(C);
+ char *str;
+
+ if(RNA_property_is_set(op->ptr, "filename"))
+ return save_as_exec(C, op);
+
+ if(text->name)
+ str= text->name;
+ else if(text->flags & TXT_ISMEM)
+ str= text->id.name+2;
+ else
+ str= G.sce;
+
+ RNA_string_set(op->ptr, "filename", str);
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void TEXT_OT_save_as(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Save As";
+ ot->idname= "TEXT_OT_save_as";
+
+ /* api callbacks */
+ ot->exec= save_as_exec;
+ ot->invoke= save_as_invoke;
+ ot->poll= text_edit_poll;
+
+ /* properties */
+ RNA_def_string_file_path(ot->srna, "filename", "", FILE_MAX, "Filename", "File path to save image to.");
+}
+
+/******************* run script operator *********************/
+
+static int run_script_exec(bContext *C, wmOperator *op)
+{
+#ifdef DISABLE_PYTHON
+ BKE_report(op->reports, RPT_ERROR, "Python disabled in this build");
+
+ return OPERATOR_CANCELLED;
+#else
+ Text *text= CTX_data_edit_text(C);
+ char *py_filename;
+
+ if(0) { // XXX !BPY_txt_do_python_Text(text)) {
+ int lineno = 0; // XXX BPY_Err_getLinenumber();
+ // jump to error if happened in current text:
+ py_filename = (char*) NULL; // XXX BPY_Err_getFilename();
+
+ /* st->text can become NULL: user called Blender.Load(blendfile)
+ * before the end of the script. */
+ text= CTX_data_edit_text(C);
+
+ if(!strcmp(py_filename, text->id.name+2)) {
+ // XXX error_pyscript( );
+ if(lineno >= 0) {
+ txt_move_toline(text, lineno-1, 0);
+ txt_sel_line(text);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ }
+ }
+ else
+ BKE_report(op->reports, RPT_ERROR, "Error in other (possibly external) file, check console.");
+ }
+
+ return OPERATOR_FINISHED;
+#endif
+}
+
+void TEXT_OT_run_script(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Run Script";
+ ot->idname= "TEXT_OT_run_script";
+
+ /* api callbacks */
+ ot->exec= run_script_exec;
+ ot->poll= text_edit_poll;
+}
+
+/******************* refresh pyconstraints operator *********************/
+
+static int refresh_pyconstraints_exec(bContext *C, wmOperator *op)
+{
+#ifndef DISABLE_PYTHON
+ Text *text= CTX_data_edit_text(C);
+ Scene *scene= CTX_data_scene(C);
+ Object *ob;
+ bConstraint *con;
+ short update;
+
+ /* check all pyconstraints */
+ for(ob= CTX_data_main(C)->object.first; ob; ob= ob->id.next) {
+ update = 0;
+ if(ob->type==OB_ARMATURE && ob->pose) {
+ bPoseChannel *pchan;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for(con = pchan->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if(data->text==text) BPY_pyconstraint_update(ob, con);
+ update = 1;
+
+ }
+ }
+ }
+ }
+ for(con = ob->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if(data->text==text) BPY_pyconstraint_update(ob, con);
+ update = 1;
+ }
+ }
+
+ if(update) {
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ }
+ }
+#endif
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_refresh_pyconstraints(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Refresh PyConstraints";
+ ot->idname= "TEXT_OT_refresh_pyconstraints";
+
+ /* api callbacks */
+ ot->exec= refresh_pyconstraints_exec;
+ ot->poll= text_edit_poll;
+}
+
+/******************* paste operator *********************/
+
+static char *txt_copy_selected(Text *text)
+{
+ TextLine *tmp, *linef, *linel;
+ char *buf= NULL;
+ int charf, charl, length= 0;
+
+ if(!text) return NULL;
+ if(!text->curl) return NULL;
+ if(!text->sell) return NULL;
+
+ if(!txt_has_sel(text)) return NULL;
+
+ if(text->curl==text->sell) {
+ linef= linel= text->curl;
+
+ if(text->curc < text->selc) {
+ charf= text->curc;
+ charl= text->selc;
+ }
+ else{
+ charf= text->selc;
+ charl= text->curc;
+ }
+ }
+ else if(txt_get_span(text->curl, text->sell)<0) {
+ linef= text->sell;
+ linel= text->curl;
+
+ charf= text->selc;
+ charl= text->curc;
+ }
+ else {
+ linef= text->curl;
+ linel= text->sell;
+
+ charf= text->curc;
+ charl= text->selc;
+ }
+
+ if(linef == linel) {
+ length= charl-charf;
+
+ buf= MEM_callocN(length+1, "cut buffera");
+
+ BLI_strncpy(buf, linef->line + charf, length+1);
+ }
+ else {
+ length+= linef->len - charf;
+ length+= charl;
+ length++; /* For the '\n' */
+
+ tmp= linef->next;
+ while(tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ buf= MEM_callocN(length+1, "cut bufferb");
+
+ strncpy(buf, linef->line+ charf, linef->len-charf);
+ length= linef->len-charf;
+
+ buf[length++]='\n';
+
+ tmp= linef->next;
+ while(tmp && tmp!=linel) {
+ strncpy(buf+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ buf[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(buf+length, linel->line, charl);
+ length+= charl;
+
+ buf[length]=0;
+ }
+
+ return buf;
+}
+
+static int paste_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ char *buf;
+ int selection= RNA_boolean_get(op->ptr, "selection");
+
+ buf= WM_clipboard_text_get(selection);
+
+ if(!buf)
+ return OPERATOR_CANCELLED;
+
+ txt_insert_buf(text, buf);
+ text_update_edited(text);
+
+ MEM_freeN(buf);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_paste(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Paste";
+ ot->idname= "TEXT_OT_paste";
+
+ /* api callbacks */
+ ot->exec= paste_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "selection", 0, "Selection", "Paste text selected elsewhere rather than copied, X11 only.");
+}
+
+/******************* copy operator *********************/
+
+static void txt_copy_clipboard(Text *text)
+{
+ char *buf;
+
+ buf= txt_copy_selected(text);
+
+ if(buf) {
+ WM_clipboard_text_set(buf, 0);
+ MEM_freeN(buf);
+ }
+}
+
+static int copy_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ txt_copy_clipboard(text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Copy";
+ ot->idname= "TEXT_OT_copy";
+
+ /* api callbacks */
+ ot->exec= copy_exec;
+ ot->poll= text_edit_poll;
+}
+
+/******************* cut operator *********************/
+
+static int cut_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ txt_copy_clipboard(text);
+ txt_delete_selected(text);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_cut(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Cut";
+ ot->idname= "TEXT_OT_cut";
+
+ /* api callbacks */
+ ot->exec= cut_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* indent operator *********************/
+
+static int indent_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(txt_has_sel(text)) {
+ txt_order_cursors(text);
+ indent(text);
+ }
+ else
+ txt_add_char(text, '\t');
+
+ text_update_edited(text);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_indent(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Indent";
+ ot->idname= "TEXT_OT_indent";
+
+ /* api callbacks */
+ ot->exec= indent_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* unindent operator *********************/
+
+static int unindent_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(txt_has_sel(text)) {
+ txt_order_cursors(text);
+ unindent(text);
+
+ text_update_edited(text);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void TEXT_OT_unindent(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Unindent";
+ ot->idname= "TEXT_OT_unindent";
+
+ /* api callbacks */
+ ot->exec= unindent_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* line break operator *********************/
+
+static int line_break_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ int a, curtab;
+
+ // double check tabs before splitting the line
+ curtab= setcurr_tab(text);
+ txt_split_curline(text);
+
+ for(a=0; a < curtab; a++)
+ txt_add_char(text, '\t');
+
+ if(text->curl) {
+ if(text->curl->prev)
+ text_update_line_edited(text, text->curl->prev);
+ text_update_line_edited(text, text->curl);
+ }
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_CANCELLED;
+}
+
+void TEXT_OT_line_break(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Line Break";
+ ot->idname= "TEXT_OT_line_break";
+
+ /* api callbacks */
+ ot->exec= line_break_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* comment operator *********************/
+
+static int comment_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(txt_has_sel(text)) {
+ txt_order_cursors(text);
+ comment(text);
+ text_update_edited(text);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void TEXT_OT_comment(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Comment";
+ ot->idname= "TEXT_OT_comment";
+
+ /* api callbacks */
+ ot->exec= comment_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* uncomment operator *********************/
+
+static int uncomment_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(txt_has_sel(text)) {
+ txt_order_cursors(text);
+ uncomment(text);
+ text_update_edited(text);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void TEXT_OT_uncomment(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Uncomment";
+ ot->idname= "TEXT_OT_uncomment";
+
+ /* api callbacks */
+ ot->exec= uncomment_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* convert whitespace operator *********************/
+
+enum { TO_SPACES, TO_TABS };
+static EnumPropertyItem whitespace_type_items[]= {
+ {TO_SPACES, "SPACES", "To Spaces", NULL},
+ {TO_TABS, "TABS", "To Tabs", NULL},
+ {0, NULL, NULL, NULL}};
+
+static int convert_whitespace_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+ TextLine *tmp;
+ FlattenString fs;
+ size_t a, j;
+ char *text_check_line, *new_line;
+ int extra, number; //unknown for now
+ int type= RNA_enum_get(op->ptr, "type");
+
+ tmp = text->lines.first;
+
+ //first convert to all space, this make it alot easier to convert to tabs because there is no mixtures of ' ' && '\t'
+ while(tmp) {
+ text_check_line = tmp->line;
+ number = flatten_string(st, &fs, text_check_line)+1;
+ flatten_string_free(&fs);
+ new_line = MEM_callocN(number, "Converted_Line");
+ j = 0;
+ for(a=0; a < strlen(text_check_line); a++) { //foreach char in line
+ if(text_check_line[a] == '\t') { //checking for tabs
+ //get the number of spaces this tabs is showing
+ //i dont like doing it this way but will look into it later
+ new_line[j] = '\0';
+ number = flatten_string(st, &fs, new_line);
+ flatten_string_free(&fs);
+ new_line[j] = '\t';
+ new_line[j+1] = '\0';
+ number = flatten_string(st, &fs, new_line)-number;
+ flatten_string_free(&fs);
+
+ for(extra = 0; extra < number; extra++) {
+ new_line[j] = ' ';
+ j++;
+ }
+ }
+ else {
+ new_line[j] = text_check_line[a];
+ ++j;
+ }
+ }
+ new_line[j] = '\0';
+ // put new_line in the tmp->line spot still need to try and set the curc correctly
+ if(tmp->line) MEM_freeN(tmp->line);
+ if(tmp->format) MEM_freeN(tmp->format);
+
+ tmp->line = new_line;
+ tmp->len = strlen(new_line);
+ tmp->format = NULL;
+ tmp = tmp->next;
+ }
+
+ if(type == TO_TABS) // Converting to tabs
+ { //start over from the begining
+ tmp = text->lines.first;
+
+ while(tmp) {
+ text_check_line = tmp->line;
+ extra = 0;
+ for(a = 0; a < strlen(text_check_line); a++) {
+ number = 0;
+ for(j = 0; j < (size_t)st->tabnumber; j++) {
+ if((a+j) <= strlen(text_check_line)) { //check to make sure we are not pass the end of the line
+ if(text_check_line[a+j] != ' ') {
+ number = 1;
+ }
+ }
+ }
+ if(!number) { //found all number of space to equal a tab
+ a = a+(st->tabnumber-1);
+ extra = extra+1;
+ }
+ }
+
+ if( extra > 0 ) { //got tabs make malloc and do what you have to do
+ new_line = MEM_callocN(strlen(text_check_line)-(((st->tabnumber*extra)-extra)-1), "Converted_Line");
+ extra = 0; //reuse vars
+ for(a = 0; a < strlen(text_check_line); a++) {
+ number = 0;
+ for(j = 0; j < (size_t)st->tabnumber; j++) {
+ if((a+j) <= strlen(text_check_line)) { //check to make sure we are not pass the end of the line
+ if(text_check_line[a+j] != ' ') {
+ number = 1;
+ }
+ }
+ }
+
+ if(!number) { //found all number of space to equal a tab
+ new_line[extra] = '\t';
+ a = a+(st->tabnumber-1);
+ ++extra;
+
+ }
+ else { //not adding a tab
+ new_line[extra] = text_check_line[a];
+ ++extra;
+ }
+ }
+ new_line[extra] = '\0';
+ // put new_line in the tmp->line spot still need to try and set the curc correctly
+ if(tmp->line) MEM_freeN(tmp->line);
+ if(tmp->format) MEM_freeN(tmp->format);
+
+ tmp->line = new_line;
+ tmp->len = strlen(new_line);
+ tmp->format = NULL;
+ }
+ tmp = tmp->next;
+ }
+ }
+
+ text_update_edited(text);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_convert_whitespace(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Convert Whitespace";
+ ot->idname= "TEXT_OT_convert_whitespace";
+
+ /* api callbacks */
+ ot->exec= convert_whitespace_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "type", whitespace_type_items, TO_SPACES, "type", "Type of whitespace to convert to.");
+}
+
+/******************* select all operator *********************/
+
+static int select_all_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ txt_sel_all(text);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select All";
+ ot->idname= "TEXT_OT_select_all";
+
+ /* api callbacks */
+ ot->exec= select_all_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* select line operator *********************/
+
+static int select_line_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ txt_sel_line(text);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_select_line(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Line";
+ ot->idname= "TEXT_OT_select_line";
+
+ /* api clinebacks */
+ ot->exec= select_line_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* previous marker operator *********************/
+
+static int previous_marker_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ TextMarker *mrk;
+ int lineno;
+
+ lineno= txt_get_span(text->lines.first, text->curl);
+ mrk= text->markers.last;
+ while(mrk && (mrk->lineno>lineno || (mrk->lineno==lineno && mrk->end > text->curc)))
+ mrk= mrk->prev;
+ if(!mrk) mrk= text->markers.last;
+ if(mrk) {
+ txt_move_to(text, mrk->lineno, mrk->start, 0);
+ txt_move_to(text, mrk->lineno, mrk->end, 1);
+ }
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_previous_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Previous Marker";
+ ot->idname= "TEXT_OT_previous_marker";
+
+ /* api callbacks */
+ ot->exec= previous_marker_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* next marker operator *********************/
+
+static int next_marker_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ TextMarker *mrk;
+ int lineno;
+
+ lineno= txt_get_span(text->lines.first, text->curl);
+ mrk= text->markers.first;
+ while(mrk && (mrk->lineno<lineno || (mrk->lineno==lineno && mrk->start <= text->curc)))
+ mrk= mrk->next;
+ if(!mrk) mrk= text->markers.first;
+ if(mrk) {
+ txt_move_to(text, mrk->lineno, mrk->start, 0);
+ txt_move_to(text, mrk->lineno, mrk->end, 1);
+ }
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_next_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Next Marker";
+ ot->idname= "TEXT_OT_next_marker";
+
+ /* api callbacks */
+ ot->exec= next_marker_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* clear all markers operator *********************/
+
+static int clear_all_markers_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ txt_clear_markers(text, 0, 0);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_clear_all_markers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Clear All Markers";
+ ot->idname= "TEXT_OT_clear_all_markers";
+
+ /* api callbacks */
+ ot->exec= clear_all_markers_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/************************ move operator ************************/
+
+static EnumPropertyItem move_type_items[]= {
+ {LINE_BEGIN, "LINE_BEGIN", "Line Begin", ""},
+ {LINE_END, "LINE_END", "Line End", ""},
+ {FILE_TOP, "FILE_TOP", "File Top", ""},
+ {FILE_BOTTOM, "FILE_BOTTOM", "File Bottom", ""},
+ {PREV_CHAR, "PREVIOUS_CHARACTER", "Previous Character", ""},
+ {NEXT_CHAR, "NEXT_CHARACTER", "Next Character", ""},
+ {PREV_WORD, "PREVIOUS_WORD", "Previous Word", ""},
+ {NEXT_WORD, "NEXT_WORD", "Next Word", ""},
+ {PREV_LINE, "PREVIOUS_LINE", "Previous Line", ""},
+ {NEXT_LINE, "NEXT_LINE", "Next Line", ""},
+ {PREV_PAGE, "PREVIOUS_PAGE", "Previous Page", ""},
+ {NEXT_PAGE, "NEXT_PAGE", "Next Page", ""},
+ {0, NULL, NULL, NULL}};
+
+static void wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
+{
+ Text *text= st->text;
+ int offl, offc, lin;
+
+ lin= txt_get_span(text->lines.first, text->sell);
+ wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
+
+ if (sel) {
+ txt_undo_add_toop(text, UNDO_STO, lin, text->selc, lin, -offc);
+ text->selc= -offc;
+ } else {
+ txt_undo_add_toop(text, UNDO_CTO, lin, text->curc, lin, -offc);
+ text->curc= -offc;
+ txt_pop_sel(text);
+ }
+}
+
+static void wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
+{
+ Text *text= st->text;
+ int offl, offc, lin, startl, c;
+
+ lin= txt_get_span(text->lines.first, text->sell);
+ wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
+ startl= offl;
+ c= text->selc;
+ while (offl==startl && text->sell->line[c]!='\0') {
+ c++;
+ wrap_offset(st, ar, text->sell, c, &offl, &offc);
+ } if (offl!=startl) c--;
+
+ if (sel) {
+ txt_undo_add_toop(text, UNDO_STO, lin, text->selc, lin, c);
+ text->selc= c;
+ } else {
+ txt_undo_add_toop(text, UNDO_CTO, lin, text->curc, lin, c);
+ text->curc= c;
+ txt_pop_sel(text);
+ }
+}
+
+static void wrap_move_up(SpaceText *st, ARegion *ar, short sel)
+{
+ Text *text= st->text;
+ int offl, offl_1, offc, fromline, toline, c, target;
+
+ wrap_offset(st, ar, text->sell, 0, &offl_1, &offc);
+ wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
+ fromline= toline= txt_get_span(text->lines.first, text->sell);
+ target= text->selc + offc;
+
+ if (offl==offl_1) {
+ if (!text->sell->prev) {
+ txt_move_bol(text, sel);
+ return;
+ }
+ toline--;
+ c= text->sell->prev->len; /* End of prev. line */
+ wrap_offset(st, ar, text->sell->prev, c, &offl, &offc);
+ c= -offc+target;
+ } else {
+ c= -offc-1; /* End of prev. line */
+ wrap_offset(st, ar, text->sell, c, &offl, &offc);
+ c= -offc+target;
+ }
+ if (c<0) c=0;
+
+ if (sel) {
+ txt_undo_add_toop(text, UNDO_STO, fromline, text->selc, toline, c);
+ if (toline<fromline) text->sell= text->sell->prev;
+ if(text->sell) {
+ if (c>text->sell->len) c= text->sell->len;
+ text->selc= c;
+ }
+ }
+ else if(text->curl) {
+ txt_undo_add_toop(text, UNDO_CTO, fromline, text->curc, toline, c);
+ if (toline<fromline) text->curl= text->curl->prev;
+ if(text->curl) {
+ if (c>text->curl->len) c= text->curl->len;
+ text->curc= c;
+ txt_pop_sel(text);
+ }
+ }
+}
+
+static void wrap_move_down(SpaceText *st, ARegion *ar, short sel)
+{
+ Text *text= st->text;
+ int offl, startoff, offc, fromline, toline, c, target;
+
+ wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
+ fromline= toline= txt_get_span(text->lines.first, text->sell);
+ target= text->selc + offc;
+ startoff= offl;
+ c= text->selc;
+ while (offl==startoff && text->sell->line[c]!='\0') {
+ c++;
+ wrap_offset(st, ar, text->sell, c, &offl, &offc);
+ }
+
+ if (text->sell->line[c]=='\0') {
+ if (!text->sell->next) {
+ txt_move_eol(text, sel);
+ return;
+ }
+ toline++;
+ c= target;
+ } else {
+ c += target;
+ if (c > text->sell->len) c= text->sell->len;
+ }
+ if (c<0) c=0;
+
+ if (sel) {
+ txt_undo_add_toop(text, UNDO_STO, fromline, text->selc, toline, c);
+ if (toline>fromline) text->sell= text->sell->next;
+ if(text->sell) {
+ if (c>text->sell->len) c= text->sell->len;
+ text->selc= c;
+ }
+ }
+ else if(text->curl) {
+ txt_undo_add_toop(text, UNDO_CTO, fromline, text->curc, toline, c);
+ if (toline>fromline) text->curl= text->curl->next;
+ if(text->curl) {
+ if (c > text->curl->len) c= text->curl->len;
+ text->curc= c;
+ txt_pop_sel(text);
+ }
+ }
+}
+
+/* Moves the cursor vertically by the specified number of lines.
+ If the destination line is shorter than the current cursor position, the
+ cursor will be positioned at the end of this line.
+
+ This is to replace screen_skip for PageUp/Down operations.
+ */
+static void cursor_skip(Text *text, int lines, int sel)
+{
+ TextLine **linep;
+ int oldl, oldc, *charp;
+
+ if (sel) linep= &text->sell, charp= &text->selc;
+ else linep= &text->curl, charp= &text->curc;
+ oldl= txt_get_span(text->lines.first, *linep);
+ oldc= *charp;
+
+ while (lines>0 && (*linep)->next) {
+ *linep= (*linep)->next;
+ lines--;
+ }
+ while (lines<0 && (*linep)->prev) {
+ *linep= (*linep)->prev;
+ lines++;
+ }
+
+ if (*charp > (*linep)->len) *charp= (*linep)->len;
+
+ if (!sel) txt_pop_sel(text);
+ txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, oldl, oldc, txt_get_span(text->lines.first, *linep), *charp);
+}
+
+static int move_cursor(bContext *C, int type, int select)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+ ARegion *ar= CTX_wm_region(C);
+
+ /* ensure we have the right region, it's optional */
+ if(ar->regiontype != RGN_TYPE_WINDOW)
+ ar= NULL;
+
+ switch(type) {
+ case LINE_BEGIN:
+ if(st && st->wordwrap && ar) wrap_move_bol(st, ar, select);
+ else txt_move_bol(text, select);
+ break;
+
+ case LINE_END:
+ if(st && st->wordwrap && ar) wrap_move_eol(st, ar, select);
+ else txt_move_eol(text, select);
+ break;
+
+ case FILE_TOP:
+ txt_move_bof(text, select);
+ break;
+
+ case FILE_BOTTOM:
+ txt_move_eof(text, select);
+ break;
+
+ case PREV_WORD:
+ txt_jump_left(text, select);
+ break;
+
+ case NEXT_WORD:
+ txt_jump_right(text, select);
+ break;
+
+ case PREV_CHAR:
+ txt_move_left(text, select);
+ break;
+
+ case NEXT_CHAR:
+ txt_move_right(text, select);
+ break;
+
+ case PREV_LINE:
+ if(st && st->wordwrap && ar) wrap_move_up(st, ar, select);
+ else txt_move_up(text, select);
+ break;
+
+ case NEXT_LINE:
+ if(st && st->wordwrap && ar) wrap_move_down(st, ar, select);
+ else txt_move_down(text, select);
+ break;
+
+ case PREV_PAGE:
+ if(st) cursor_skip(text, -st->viewlines, select);
+ else cursor_skip(text, -10, select);
+ break;
+
+ case NEXT_PAGE:
+ if(st) cursor_skip(text, st->viewlines, select);
+ else cursor_skip(text, 10, select);
+ break;
+ }
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+static int move_exec(bContext *C, wmOperator *op)
+{
+ int type= RNA_enum_get(op->ptr, "type");
+
+ return move_cursor(C, type, 0);
+}
+
+void TEXT_OT_move(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Move Cursor";
+ ot->idname= "TEXT_OT_move";
+
+ /* api callbacks */
+ ot->exec= move_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to.");
+}
+
+/******************* move select operator ********************/
+
+static int move_select_exec(bContext *C, wmOperator *op)
+{
+ int type= RNA_enum_get(op->ptr, "type");
+
+ return move_cursor(C, type, 1);
+}
+
+void TEXT_OT_move_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Move Select";
+ ot->idname= "TEXT_OT_move_select";
+
+ /* api callbacks */
+ ot->exec= move_select_exec;
+ ot->poll= text_space_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to, to make a selection.");
+}
+
+/******************* jump operator *********************/
+
+static int jump_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ int line= RNA_int_get(op->ptr, "line");
+ short nlines= txt_get_span(text->lines.first, text->lines.last)+1;
+
+ if(line < 1 || line > nlines)
+ return OPERATOR_CANCELLED;
+
+ txt_move_toline(text, line-1, 0);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+
+ return OPERATOR_FINISHED;
+}
+
+// XXX invoke
+// short tmp= txt_get_span(text->lines.first, text->curl)+1;
+// button(&tmp, 1, nlines, "Jump to line:"))
+
+void TEXT_OT_jump(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Jump";
+ ot->idname= "TEXT_OT_jump";
+
+ /* api callbacks */
+ ot->exec= jump_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_int(ot->srna, "line", 1, INT_MAX, 1, "Line", "Line number to jump to.", 1, 10000);
+}
+
+/******************* delete operator **********************/
+
+static EnumPropertyItem delete_type_items[]= {
+ {DEL_NEXT_CHAR, "NEXT_CHARACTER", "Next Character", ""},
+ {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", "Previous Character", ""},
+ {DEL_NEXT_WORD, "NEXT_WORD", "Next Word", ""},
+ {DEL_PREV_WORD, "PREVIOUS_WORD", "Previous Word", ""},
+ {0, NULL, NULL, NULL}};
+
+static int delete_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ int type= RNA_enum_get(op->ptr, "type");
+
+ if(type == DEL_PREV_WORD)
+ txt_backspace_word(text);
+ else if(type == DEL_PREV_CHAR)
+ txt_backspace_char(text);
+ else if(type == DEL_NEXT_WORD)
+ txt_delete_word(text);
+ else if(type == DEL_NEXT_CHAR)
+ txt_delete_char(text);
+
+ text_update_line_edited(text, text->curl);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Delete";
+ ot->idname= "TEXT_OT_delete";
+
+ /* api callbacks */
+ ot->exec= delete_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "type", delete_type_items, DEL_NEXT_CHAR, "Type", "Which part of the text to delete.");
+}
+
+/******************* toggle overwrite operator **********************/
+
+static int toggle_overwrite_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+
+ st->overwrite= !st->overwrite;
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_toggle_overwrite(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Toggle Overwrite";
+ ot->idname= "TEXT_OT_toggle_overwrite";
+
+ /* api callbacks */
+ ot->exec= toggle_overwrite_exec;
+ ot->poll= text_space_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+/******************* scroll operator **********************/
+
+/* Moves the view vertically by the specified number of lines */
+static void screen_skip(SpaceText *st, int lines)
+{
+ int last;
+
+ st->top += lines;
+
+ last= txt_get_span(st->text->lines.first, st->text->lines.last);
+ last= last - (st->viewlines/2);
+
+ if(st->top>last) st->top= last;
+ if(st->top<0) st->top= 0;
+}
+
+typedef struct TextScroll {
+ short old[2];
+ short hold[2];
+ short delta[2];
+
+ int first;
+ int characters;
+ int lines;
+ int scrollbar;
+} TextScroll;
+
+static int scroll_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ int lines= RNA_int_get(op->ptr, "lines");
+
+ if(lines == 0)
+ return OPERATOR_CANCELLED;
+
+ screen_skip(st, lines*U.wheellinescroll);
+
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, st->text);
+
+ return OPERATOR_FINISHED;
+}
+
+static int scroll_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ TextScroll *tsc;
+
+ if(RNA_property_is_set(op->ptr, "lines"))
+ return scroll_exec(C, op);
+
+ tsc= MEM_callocN(sizeof(TextScroll), "TextScroll");
+ tsc->first= 1;
+ op->customdata= tsc;
+
+ st->flags|= ST_SCROLL_SELECT;
+
+ WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void scroll_apply(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ TextScroll *tsc= op->customdata;
+ short *mval= event->mval;
+
+ if(tsc->first) {
+ tsc->old[0]= mval[0];
+ tsc->old[1]= mval[1];
+ tsc->hold[0]= mval[0];
+ tsc->hold[1]= mval[1];
+ tsc->first= 0;
+ }
+
+ if(!tsc->scrollbar) {
+ tsc->delta[0]= (tsc->hold[0]-mval[0])/text_font_width_character(st);
+ tsc->delta[1]= (mval[1]-tsc->hold[1])/st->lheight;
+ }
+ else
+ tsc->delta[1]= (tsc->hold[1]-mval[1])*st->pix_per_line;
+
+ if(tsc->delta[0] || tsc->delta[1]) {
+ screen_skip(st, tsc->delta[1]);
+
+ tsc->lines += tsc->delta[1];
+
+ if(st->wordwrap) {
+ st->left= 0;
+ }
+ else {
+ st->left+= tsc->delta[0];
+ if(st->left<0) st->left= 0;
+ }
+
+ tsc->hold[0]= mval[0];
+ tsc->hold[1]= mval[1];
+
+ ED_area_tag_redraw(CTX_wm_area(C));
+ }
+
+ tsc->old[0]= mval[0];
+ tsc->old[1]= mval[1];
+}
+
+static void scroll_exit(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+
+ st->flags &= ~ST_SCROLL_SELECT;
+ MEM_freeN(op->customdata);
+}
+
+static int scroll_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+ switch(event->type) {
+ case MOUSEMOVE:
+ scroll_apply(C, op, event);
+ break;
+ case LEFTMOUSE:
+ case RIGHTMOUSE:
+ case MIDDLEMOUSE:
+ scroll_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int scroll_cancel(bContext *C, wmOperator *op)
+{
+ scroll_exit(C, op);
+
+ return OPERATOR_CANCELLED;
+}
+
+void TEXT_OT_scroll(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Scroll";
+ ot->idname= "TEXT_OT_scroll";
+
+ /* api callbacks */
+ ot->exec= scroll_exec;
+ ot->invoke= scroll_invoke;
+ ot->modal= scroll_modal;
+ ot->cancel= scroll_cancel;
+ ot->poll= text_space_edit_poll;
+
+ /* properties */
+ RNA_def_int(ot->srna, "lines", INT_MIN, INT_MAX, 1, "Lines", "Number of lines to scroll.", -100, 100);
+}
+
+/******************** scroll bar operator *******************/
+
+static int scroll_bar_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ ARegion *ar= CTX_wm_region(C);
+ TextScroll *tsc;
+ short *mval= event->mval;
+
+ if(RNA_property_is_set(op->ptr, "lines"))
+ return scroll_exec(C, op);
+
+ /* verify we are in the right zone */
+ if(!(mval[0]>2 && mval[0]<20 && mval[1]>2 && mval[1]<ar->winy))
+ return OPERATOR_PASS_THROUGH;
+
+ tsc= MEM_callocN(sizeof(TextScroll), "TextScroll");
+ tsc->first= 1;
+ tsc->scrollbar= 1;
+ op->customdata= tsc;
+
+ st->flags|= ST_SCROLL_SELECT;
+
+ WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void TEXT_OT_scroll_bar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Scrollbar";
+ ot->idname= "TEXT_OT_scroll_bar";
+
+ /* api callbacks */
+ ot->invoke= scroll_bar_invoke;
+ ot->modal= scroll_modal;
+ ot->cancel= scroll_cancel;
+ ot->poll= text_region_edit_poll;
+
+ /* properties */
+ RNA_def_int(ot->srna, "lines", INT_MIN, INT_MAX, 1, "Lines", "Number of lines to scroll.", -100, 100);
+}
+
+/******************* set cursor operator **********************/
+
+typedef struct SetCursor {
+ int selecting;
+ int selc, sell;
+ short old[2];
+} SetCursor;
+
+static void set_cursor_to_pos(SpaceText *st, ARegion *ar, int x, int y, int sel)
+{
+ FlattenString fs;
+ Text *text= st->text;
+ TextLine **linep;
+ int *charp;
+ int w;
+
+ if(sel) { linep= &text->sell; charp= &text->selc; }
+ else { linep= &text->curl; charp= &text->curc; }
+
+ y= (ar->winy - y)/st->lheight;
+
+ if(st->showlinenrs)
+ x-= TXT_OFFSET+TEXTXLOC;
+ else
+ x-= TXT_OFFSET;
+
+ if(x<0) x= 0;
+ x = (x/text_font_width_character(st)) + st->left;
+
+ if(st->wordwrap) {
+ int i, j, endj, curs, max, chop, start, end, chars, loop;
+ char ch;
+
+ /* Point to first visible line */
+ *linep= text->lines.first;
+ for(i=0; i<st->top && (*linep)->next; i++) *linep= (*linep)->next;
+
+ max= wrap_width(st, ar);
+
+ loop= 1;
+ while(loop && *linep) {
+ start= 0;
+ end= max;
+ chop= 1;
+ chars= 0;
+ curs= 0;
+ endj= 0;
+ for(i=0, j=0; loop; j++) {
+
+ /* Mimic replacement of tabs */
+ ch= (*linep)->line[j];
+ if(ch=='\t') {
+ chars= st->tabnumber-i%st->tabnumber;
+ ch= ' ';
+ }
+ else
+ chars= 1;
+
+ while(chars--) {
+ /* Gone too far, go back to last wrap point */
+ if(y<0) {
+ *charp= endj;
+ loop= 0;
+ break;
+ /* Exactly at the cursor, done */
+ }
+ else if(y==0 && i-start==x) {
+ *charp= curs= j;
+ loop= 0;
+ break;
+ /* Prepare curs for next wrap */
+ }
+ else if(i-end==x) {
+ curs= j;
+ }
+ if(i-start>=max) {
+ if(chop) endj= j;
+ y--;
+ start= end;
+ end += max;
+ chop= 1;
+ if(y==0 && i-start>=x) {
+ *charp= curs;
+ loop= 0;
+ break;
+ }
+ }
+ else if(ch==' ' || ch=='-' || ch=='\0') {
+ if(y==0 && i-start>=x) {
+ *charp= curs;
+ loop= 0;
+ break;
+ }
+ end = i+1;
+ endj = j;
+ chop= 0;
+ }
+ i++;
+ }
+ if(ch=='\0') break;
+ }
+ if(!loop || y<0) break;
+
+ if(!(*linep)->next) {
+ *charp= (*linep)->len;
+ break;
+ }
+
+ /* On correct line but didn't meet cursor, must be at end */
+ if(y==0) {
+ *charp= (*linep)->len;
+ break;
+ }
+ *linep= (*linep)->next;
+ y--;
+ }
+
+ }
+ else {
+ y-= txt_get_span(text->lines.first, *linep) - st->top;
+
+ if(y>0) {
+ while(y-- != 0) if((*linep)->next) *linep= (*linep)->next;
+ }
+ else if(y<0) {
+ while(y++ != 0) if((*linep)->prev) *linep= (*linep)->prev;
+ }
+
+
+ w= flatten_string(st, &fs, (*linep)->line);
+ if(x<w) *charp= fs.accum[x];
+ else *charp= (*linep)->len;
+ flatten_string_free(&fs);
+ }
+ if(!sel) txt_pop_sel(text);
+}
+
+static void set_cursor_apply(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ ARegion *ar= CTX_wm_region(C);
+ SetCursor *scu= op->customdata;
+
+ if(event->mval[1]<0 || event->mval[1]>ar->winy) {
+ int d= (scu->old[1]-event->mval[1])*st->pix_per_line;
+ if(d) screen_skip(st, d);
+
+ set_cursor_to_pos(st, ar, event->mval[0], event->mval[1]<0?0:ar->winy, 1);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
+ }
+ else if(!st->wordwrap && (event->mval[0]<0 || event->mval[0]>ar->winx)) {
+ if(event->mval[0]>ar->winx) st->left++;
+ else if(event->mval[0]<0 && st->left>0) st->left--;
+
+ set_cursor_to_pos(st, ar, event->mval[0], event->mval[1], 1);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
+ // XXX PIL_sleep_ms(10);
+ }
+ else {
+ set_cursor_to_pos(st, ar, event->mval[0], event->mval[1], 1);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
+
+ scu->old[0]= event->mval[0];
+ scu->old[1]= event->mval[1];
+ }
+}
+
+static void set_cursor_exit(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= st->text;
+ SetCursor *scu= op->customdata;
+ int linep2, charp2;
+ char *buffer;
+
+ if(txt_has_sel(text)) {
+ buffer = txt_sel_to_buf(text);
+ WM_clipboard_text_set(buffer, 1);
+ MEM_freeN(buffer);
+ }
+
+ linep2= txt_get_span(st->text->lines.first, st->text->sell);
+ charp2= st->text->selc;
+
+ if(scu->sell!=linep2 || scu->selc!=charp2)
+ txt_undo_add_toop(st->text, UNDO_STO, scu->sell, scu->selc, linep2, charp2);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, st->text);
+
+ MEM_freeN(scu);
+}
+
+static int set_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ ARegion *ar= CTX_wm_region(C);
+ SetCursor *scu;
+
+ op->customdata= MEM_callocN(sizeof(SetCursor), "SetCursor");
+ scu= op->customdata;
+ scu->selecting= RNA_boolean_get(op->ptr, "select");
+
+ scu->old[0]= event->mval[0];
+ scu->old[1]= event->mval[1];
+
+ if(!scu->selecting) {
+ int curl= txt_get_span(st->text->lines.first, st->text->curl);
+ int curc= st->text->curc;
+ int linep2, charp2;
+
+ set_cursor_to_pos(st, ar, event->mval[0], event->mval[1], 0);
+
+ linep2= txt_get_span(st->text->lines.first, st->text->curl);
+ charp2= st->text->selc;
+
+ if(curl!=linep2 || curc!=charp2)
+ txt_undo_add_toop(st->text, UNDO_CTO, curl, curc, linep2, charp2);
+ }
+
+ scu->sell= txt_get_span(st->text->lines.first, st->text->sell);
+ scu->selc= st->text->selc;
+
+ WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+
+ set_cursor_apply(C, op, event);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int set_cursor_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+ switch(event->type) {
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE:
+ set_cursor_exit(C, op);
+ return OPERATOR_FINISHED;
+ case MOUSEMOVE:
+ set_cursor_apply(C, op, event);
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int set_cursor_cancel(bContext *C, wmOperator *op)
+{
+ set_cursor_exit(C, op);
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_set_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Set Cursor";
+ ot->idname= "TEXT_OT_set_cursor";
+
+ /* api callbacks */
+ ot->invoke= set_cursor_invoke;
+ ot->modal= set_cursor_modal;
+ ot->cancel= set_cursor_cancel;
+ ot->poll= text_region_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "select", 0, "Select", "Set selection end rather than cursor.");
+}
+
+/******************* line number operator **********************/
+
+static int line_number_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+ ARegion *ar= CTX_wm_region(C);
+ short *mval= event->mval;
+ double time;
+ static int jump_to= 0;
+ static double last_jump= 0;
+
+ if(!st->showlinenrs)
+ return OPERATOR_PASS_THROUGH;
+
+ if(!(mval[0]>2 && mval[0]<60 && mval[1]>2 && mval[1]<ar->winy-2))
+ return OPERATOR_PASS_THROUGH;
+
+ if(!(event->ascii>='0' && event->ascii<='9'))
+ return OPERATOR_PASS_THROUGH;
+
+ time = PIL_check_seconds_timer();
+ if(last_jump < time-1)
+ jump_to= 0;
+
+ jump_to *= 10;
+ jump_to += (int)(event->ascii-'0');
+
+ txt_move_toline(text, jump_to-1, 0);
+ last_jump= time;
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_line_number(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Line Number";
+ ot->idname= "TEXT_OT_line_number";
+
+ /* api callbacks */
+ ot->invoke= line_number_invoke;
+ ot->poll= text_region_edit_poll;
+}
+
+/******************* insert operator **********************/
+
+static int insert_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+ char *str;
+ int done, ascii;
+
+ str= RNA_string_get_alloc(op->ptr, "text", NULL, 0);
+ ascii= str[0];
+ MEM_freeN(str);
+
+ if(!ascii)
+ return OPERATOR_CANCELLED;
+
+ if(st && st->overwrite)
+ done= txt_replace_char(text, ascii);
+ else
+ done= txt_add_char(text, ascii);
+
+ if(!done)
+ return OPERATOR_CANCELLED;
+
+ text_update_line_edited(text, text->curl);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+
+ return OPERATOR_FINISHED;
+}
+
+static int insert_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ char str[2];
+
+ /* XXX old code from winqreadtextspace, is it still needed somewhere? */
+ /* smartass code to prevent the CTRL/ALT events below from not working! */
+ /*if(qual & (LR_ALTKEY|LR_CTRLKEY))
+ if(!ispunct(ascii))
+ ascii= 0;*/
+
+ str[0]= event->ascii;
+ str[1]= '\0';
+
+ RNA_string_set(op->ptr, "text", str);
+
+ return insert_exec(C, op);
+}
+
+void TEXT_OT_insert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Insert";
+ ot->idname= "TEXT_OT_insert";
+
+ /* api callbacks */
+ ot->exec= insert_exec;
+ ot->invoke= insert_invoke;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");
+}
+
+/******************* find operator *********************/
+
+/* mode */
+#define TEXT_FIND 0
+#define TEXT_REPLACE 1
+#define TEXT_MARK_ALL 2
+
+static int find_and_replace(bContext *C, wmOperator *op, short mode)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *start= NULL, *text= st->text;
+ int flags, first= 1;
+ char *tmp;
+
+ if(!st->findstr[0] || (mode == TEXT_REPLACE && !st->replacestr[0]))
+ return OPERATOR_CANCELLED;
+
+ flags= st->flags;
+ if(flags & ST_FIND_ALL)
+ flags ^= ST_FIND_WRAP;
+
+ do {
+ if(first)
+ txt_clear_markers(text, TMARK_GRP_FINDALL, 0);
+
+ first= 0;
+
+ /* Replace current */
+ if(mode!=TEXT_FIND && txt_has_sel(text)) {
+ tmp= txt_sel_to_buf(text);
+
+ if(strcmp(st->findstr, tmp)==0) {
+ if(mode==TEXT_REPLACE) {
+ txt_insert_buf(text, st->replacestr);
+ if(text->curl && text->curl->format) {
+ MEM_freeN(text->curl->format);
+ text->curl->format= NULL;
+ }
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+ }
+ else if(mode==TEXT_MARK_ALL) {
+ char color[4];
+ UI_GetThemeColor4ubv(TH_SHADE2, color);
+
+ if(txt_find_marker(text, text->curl, text->selc, TMARK_GRP_FINDALL, 0)) {
+ if(tmp) MEM_freeN(tmp), tmp=NULL;
+ break;
+ }
+
+ txt_add_marker(text, text->curl, text->curc, text->selc, color, TMARK_GRP_FINDALL, TMARK_EDITALL);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+ }
+ }
+ MEM_freeN(tmp);
+ tmp= NULL;
+ }
+
+ /* Find next */
+ if(txt_find_string(text, st->findstr, flags & ST_FIND_WRAP)) {
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ }
+ else if(flags & ST_FIND_ALL) {
+ if(text==start) break;
+ if(!start) start= text;
+ if(text->id.next)
+ text= st->text= text->id.next;
+ else
+ text= st->text= G.main->text.first;
+ txt_move_toline(text, 0, 0);
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ first= 1;
+ }
+ else {
+ BKE_reportf(op->reports, RPT_INFO, "Text not found: %s", st->findstr);
+ break;
+ }
+ } while(mode==TEXT_MARK_ALL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int find_exec(bContext *C, wmOperator *op)
+{
+ return find_and_replace(C, op, TEXT_FIND);
+}
+
+void TEXT_OT_find(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Find";
+ ot->idname= "TEXT_OT_find";
+
+ /* api callbacks */
+ ot->exec= find_exec;
+ ot->poll= text_space_edit_poll;
+}
+
+/******************* replace operator *********************/
+
+static int replace_exec(bContext *C, wmOperator *op)
+{
+ return find_and_replace(C, op, TEXT_REPLACE);
+}
+
+void TEXT_OT_replace(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Replace";
+ ot->idname= "TEXT_OT_replace";
+
+ /* api callbacks */
+ ot->exec= replace_exec;
+ ot->poll= text_space_edit_poll;
+}
+
+/******************* mark all operator *********************/
+
+static int mark_all_exec(bContext *C, wmOperator *op)
+{
+ return find_and_replace(C, op, TEXT_MARK_ALL);
+}
+
+void TEXT_OT_mark_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark All";
+ ot->idname= "TEXT_OT_mark_all";
+
+ /* api callbacks */
+ ot->exec= mark_all_exec;
+ ot->poll= text_space_edit_poll;
+}
+
+/******************* find set selected *********************/
+
+static int find_set_selected_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+ char *tmp;
+
+ tmp= txt_sel_to_buf(text);
+ BLI_strncpy(st->findstr, tmp, ST_MAX_FIND_STR);
+ MEM_freeN(tmp);
+
+ if(!st->findstr[0])
+ return OPERATOR_FINISHED;
+
+ return find_and_replace(C, op, TEXT_FIND);
+}
+
+void TEXT_OT_find_set_selected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Find Set Selected";
+ ot->idname= "TEXT_OT_find_set_selected";
+
+ /* api callbacks */
+ ot->exec= find_set_selected_exec;
+ ot->poll= text_space_edit_poll;
+}
+
+/******************* replace set selected *********************/
+
+static int replace_set_selected_exec(bContext *C, wmOperator *op)
+{
+ SpaceText *st= CTX_wm_space_text(C);
+ Text *text= CTX_data_edit_text(C);
+ char *tmp;
+
+ tmp= txt_sel_to_buf(text);
+ BLI_strncpy(st->replacestr, tmp, ST_MAX_FIND_STR);
+ MEM_freeN(tmp);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_replace_set_selected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Replace Set Selected";
+ ot->idname= "TEXT_OT_replace_set_selected";
+
+ /* api callbacks */
+ ot->exec= replace_set_selected_exec;
+ ot->poll= text_space_edit_poll;
+}
+
+/****************** resolve conflict operator ******************/
+
+enum { RESOLVE_IGNORE, RESOLVE_RELOAD, RESOLVE_SAVE, RESOLVE_MAKE_INTERNAL };
+static EnumPropertyItem resolution_items[]= {
+ {RESOLVE_IGNORE, "IGNORE", "Ignore", ""},
+ {RESOLVE_RELOAD, "RELOAD", "Reload", ""},
+ {RESOLVE_SAVE, "SAVE", "Save", ""},
+ {RESOLVE_MAKE_INTERNAL, "MAKE_INTERNAL", "Make Internal", ""},
+ {0, NULL, NULL, NULL}};
+
+/* returns 0 if file on disk is the same or Text is in memory only
+ returns 1 if file has been modified on disk since last local edit
+ returns 2 if file on disk has been deleted
+ -1 is returned if an error occurs */
+
+int text_file_modified(Text *text)
+{
+ struct stat st;
+ int result;
+ char file[FILE_MAXDIR+FILE_MAXFILE];
+
+ if(!text || !text->name)
+ return 0;
+
+ BLI_strncpy(file, text->name, FILE_MAXDIR+FILE_MAXFILE);
+ BLI_convertstringcode(file, G.sce);
+
+ if(!BLI_exists(file))
+ return 2;
+
+ result = stat(file, &st);
+
+ if(result == -1)
+ return -1;
+
+ if((st.st_mode & S_IFMT) != S_IFREG)
+ return -1;
+
+ if(st.st_mtime > text->mtime)
+ return 1;
+
+ return 0;
+}
+
+static void text_ignore_modified(Text *text)
+{
+ struct stat st;
+ int result;
+ char file[FILE_MAXDIR+FILE_MAXFILE];
+
+ if(!text || !text->name) return;
+
+ BLI_strncpy(file, text->name, FILE_MAXDIR+FILE_MAXFILE);
+ BLI_convertstringcode(file, G.sce);
+
+ if(!BLI_exists(file)) return;
+
+ result = stat(file, &st);
+
+ if(result == -1 || (st.st_mode & S_IFMT) != S_IFREG)
+ return;
+
+ text->mtime= st.st_mtime;
+}
+
+static int resolve_conflict_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ int resolution= RNA_enum_get(op->ptr, "resolution");
+
+ switch(resolution) {
+ case RESOLVE_RELOAD:
+ return reload_exec(C, op);
+ case RESOLVE_SAVE:
+ return save_exec(C, op);
+ case RESOLVE_MAKE_INTERNAL:
+ return make_internal_exec(C, op);
+ case RESOLVE_IGNORE:
+ text_ignore_modified(text);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static int resolve_conflict_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Text *text= CTX_data_edit_text(C);
+ uiMenuItem *head;
+
+ switch(text_file_modified(text)) {
+ case 1:
+ if(text->flags & TXT_ISDIRTY) {
+ /* modified locally and externally, ahhh. offer more possibilites. */
+ head= uiPupMenuBegin("File Modified Outside and Inside Blender", 0);
+ uiMenuItemEnumO(head, "Reload from disk (ignore local changes)", 0, op->type->idname, "resolution", RESOLVE_RELOAD);
+ uiMenuItemEnumO(head, "Save to disk (ignore outside changes)", 0, op->type->idname, "resolution", RESOLVE_SAVE);
+ uiMenuItemEnumO(head, "Make text internal (separate copy)", 0, op->type->idname, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiPupMenuEnd(C, head);
+ }
+ else {
+ head= uiPupMenuBegin("File Modified Outside Blender", 0);
+ uiMenuItemEnumO(head, "Reload from disk", 0, op->type->idname, "resolution", RESOLVE_RELOAD);
+ uiMenuItemEnumO(head, "Make text internal (separate copy)", 0, op->type->idname, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiMenuItemEnumO(head, "Ignore", 0, op->type->idname, "resolution", RESOLVE_IGNORE);
+ uiPupMenuEnd(C, head);
+ }
+ break;
+ case 2:
+ head= uiPupMenuBegin("File Deleted Outside Blender", 0);
+ uiMenuItemEnumO(head, "Make text internal", 0, op->type->idname, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiMenuItemEnumO(head, "Recreate file", 0, op->type->idname, "resolution", RESOLVE_SAVE);
+ uiPupMenuEnd(C, head);
+ break;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void TEXT_OT_resolve_conflict(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Resolve Conflict";
+ ot->idname= "TEXT_OT_resolve_conflict";
+
+ /* api callbacks */
+ ot->exec= resolve_conflict_exec;
+ ot->invoke= resolve_conflict_invoke;
+ ot->poll= save_poll;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "resolution", resolution_items, RESOLVE_IGNORE, "Resolution", "How to solve conflict due to different in internal and external text.");
+}
+
+/********************** to 3d object operator *****************/
+
+static int to_3d_object_exec(bContext *C, wmOperator *op)
+{
+ Text *text= CTX_data_edit_text(C);
+ int split_lines= RNA_boolean_get(op->ptr, "split_lines");
+
+ ED_text_to_object(C, text, split_lines);
+
+ return OPERATOR_FINISHED;
+}
+
+void TEXT_OT_to_3d_object(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "To 3D Object";
+ ot->idname= "TEXT_OT_to_3d_object";
+
+ /* api callbacks */
+ ot->exec= to_3d_object_exec;
+ ot->poll= text_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "split_lines", 0, "Split Lines", "Create one object per line in the text.");
+}
+
+/************************ undo ******************************/
+
+void ED_text_undo_step(bContext *C, int step)
+{
+ Text *text= CTX_data_edit_text(C);
+
+ if(!text)
+ return;
+
+ if(step==1)
+ txt_do_undo(text);
+ else if(step==-1)
+ txt_do_redo(text);
+
+ text_update_edited(text);
+
+ WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ WM_event_add_notifier(C, NC_TEXT|NA_EDITED, text);
+}
+
diff --git a/source/blender/editors/space_text/text_python.c b/source/blender/editors/space_text/text_python.c
new file mode 100644
index 00000000000..4fa54cdf27b
--- /dev/null
+++ b/source/blender/editors/space_text/text_python.c
@@ -0,0 +1,541 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_text_types.h"
+
+#include "BKE_suggestions.h"
+#include "BKE_text.h"
+
+#include "BLI_blenlib.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "text_intern.h"
+
+int text_do_suggest_select(SpaceText *st, ARegion *ar)
+{
+ SuggItem *item, *first, *last, *sel;
+ TextLine *tmp;
+ int l, x, y, w, h, i;
+ int tgti, *top;
+ short mval[2];
+
+ if(!st || !st->text) return 0;
+ if(!texttool_text_is_active(st->text)) return 0;
+
+ first = texttool_suggest_first();
+ last = texttool_suggest_last();
+ sel = texttool_suggest_selected();
+ top = texttool_suggest_top();
+
+ if(!last || !first)
+ return 0;
+
+ /* Count the visible lines to the cursor */
+ for(tmp=st->text->curl, l=-st->top; tmp; tmp=tmp->prev, l++);
+ if(l<0) return 0;
+
+ if(st->showlinenrs) {
+ x = text_font_width_character(st)*(st->text->curc-st->left) + TXT_OFFSET + TEXTXLOC - 4;
+ }
+ else {
+ x = text_font_width_character(st)*(st->text->curc-st->left) + TXT_OFFSET - 4;
+ }
+ y = ar->winy - st->lheight*l - 2;
+
+ w = SUGG_LIST_WIDTH*text_font_width_character(st) + 20;
+ h = SUGG_LIST_SIZE*st->lheight + 8;
+
+ // XXX getmouseco_areawin(mval);
+
+ if(mval[0]<x || x+w<mval[0] || mval[1]<y-h || y<mval[1])
+ return 0;
+
+ /* Work out which of the items is at the top of the visible list */
+ for(i=0, item=first; i<*top && item->next; i++, item=item->next);
+
+ /* Work out the target item index in the visible list */
+ tgti = (y-mval[1]-4) / st->lheight;
+ if(tgti<0 || tgti>SUGG_LIST_SIZE)
+ return 1;
+
+ for(i=tgti; i>0 && item->next; i--, item=item->next);
+ if(item)
+ texttool_suggest_select(item);
+ return 1;
+}
+
+void text_pop_suggest_list()
+{
+ SuggItem *item, *sel;
+ int *top, i;
+
+ item= texttool_suggest_first();
+ sel= texttool_suggest_selected();
+ top= texttool_suggest_top();
+
+ i= 0;
+ while(item && item != sel) {
+ item= item->next;
+ i++;
+ }
+ if(i > *top+SUGG_LIST_SIZE-1)
+ *top= i-SUGG_LIST_SIZE+1;
+ else if(i < *top)
+ *top= i;
+}
+
+static void get_suggest_prefix(Text *text, int offset)
+{
+ int i, len;
+ char *line, tmp[256];
+
+ if(!text) return;
+ if(!texttool_text_is_active(text)) return;
+
+ line= text->curl->line;
+ for(i=text->curc-1+offset; i>=0; i--)
+ if(!text_check_identifier(line[i]))
+ break;
+ i++;
+ len= text->curc-i+offset;
+ if(len > 255) {
+ printf("Suggestion prefix too long\n");
+ len = 255;
+ }
+ BLI_strncpy(tmp, line+i, len);
+ tmp[len]= '\0';
+ texttool_suggest_prefix(tmp);
+}
+
+static void confirm_suggestion(Text *text, int skipleft)
+{
+ SuggItem *sel;
+ int i, over=0;
+ char *line;
+
+ if(!text) return;
+ if(!texttool_text_is_active(text)) return;
+
+ sel = texttool_suggest_selected();
+ if(!sel) return;
+
+ line= text->curl->line;
+ i=text->curc-skipleft-1;
+ while(i>=0) {
+ if(!text_check_identifier(line[i]))
+ break;
+ over++;
+ i--;
+ }
+
+ for(i=0; i<skipleft; i++)
+ txt_move_left(text, 0);
+ for(i=0; i<over; i++)
+ txt_move_left(text, 1);
+
+ txt_insert_buf(text, sel->name);
+
+ for(i=0; i<skipleft; i++)
+ txt_move_right(text, 0);
+
+ texttool_text_clear();
+}
+
+// XXX
+#define L_MOUSE 0
+#define M_MOUSE 0
+#define R_MOUSE 0
+#define LR_SHIFTKEY 0
+#define LR_ALTKEY 0
+#define LR_CTRLKEY 0
+#define LR_COMMANDKEY 0
+
+// XXX
+static int doc_scroll= 0;
+
+short do_texttools(SpaceText *st, char ascii, unsigned short evnt, short val)
+{
+ ARegion *ar= NULL; // XXX
+ int qual= 0; // XXX
+ int draw=0, tools=0, swallow=0, scroll=1;
+ if(!texttool_text_is_active(st->text)) return 0;
+ if(!st->text || st->text->id.lib) return 0;
+
+ if(st->doplugins && texttool_text_is_active(st->text)) {
+ if(texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
+ if(texttool_docs_get()) tools |= TOOL_DOCUMENT;
+ }
+
+ if(ascii) {
+ if(tools & TOOL_SUGG_LIST) {
+ if((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) {
+ confirm_suggestion(st->text, 0);
+ text_update_line_edited(st->text, st->text->curl);
+ }
+ else if((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) {
+ get_suggest_prefix(st->text, 0);
+ text_pop_suggest_list();
+ swallow= 1;
+ draw= 1;
+ }
+ }
+ if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
+
+ }
+ else if(val==1 && evnt) {
+ switch (evnt) {
+ case LEFTMOUSE:
+ if(text_do_suggest_select(st, ar))
+ swallow= 1;
+ else {
+ if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
+ if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
+ }
+ draw= 1;
+ break;
+ case MIDDLEMOUSE:
+ if(text_do_suggest_select(st, ar)) {
+ confirm_suggestion(st->text, 0);
+ text_update_line_edited(st->text, st->text->curl);
+ swallow= 1;
+ }
+ else {
+ if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
+ if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
+ }
+ draw= 1;
+ break;
+ case ESCKEY:
+ draw= swallow= 1;
+ if(tools & TOOL_SUGG_LIST) texttool_suggest_clear();
+ else if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
+ else draw= swallow= 0;
+ break;
+ case RETKEY:
+ if(tools & TOOL_SUGG_LIST) {
+ confirm_suggestion(st->text, 0);
+ text_update_line_edited(st->text, st->text->curl);
+ swallow= 1;
+ draw= 1;
+ }
+ if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
+ break;
+ case LEFTARROWKEY:
+ case BACKSPACEKEY:
+ if(tools & TOOL_SUGG_LIST) {
+ if(qual)
+ texttool_suggest_clear();
+ else {
+ /* Work out which char we are about to delete/pass */
+ if(st->text->curl && st->text->curc > 0) {
+ char ch= st->text->curl->line[st->text->curc-1];
+ if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
+ get_suggest_prefix(st->text, -1);
+ text_pop_suggest_list();
+ }
+ else
+ texttool_suggest_clear();
+ }
+ else
+ texttool_suggest_clear();
+ }
+ }
+ if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
+ break;
+ case RIGHTARROWKEY:
+ if(tools & TOOL_SUGG_LIST) {
+ if(qual)
+ texttool_suggest_clear();
+ else {
+ /* Work out which char we are about to pass */
+ if(st->text->curl && st->text->curc < st->text->curl->len) {
+ char ch= st->text->curl->line[st->text->curc+1];
+ if((ch=='_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
+ get_suggest_prefix(st->text, 1);
+ text_pop_suggest_list();
+ }
+ else
+ texttool_suggest_clear();
+ }
+ else
+ texttool_suggest_clear();
+ }
+ }
+ if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0;
+ break;
+ case PAGEDOWNKEY:
+ scroll= SUGG_LIST_SIZE-1;
+ case WHEELDOWNMOUSE:
+ case DOWNARROWKEY:
+ if(tools & TOOL_DOCUMENT) {
+ doc_scroll++;
+ swallow= 1;
+ draw= 1;
+ break;
+ }
+ else if(tools & TOOL_SUGG_LIST) {
+ SuggItem *sel = texttool_suggest_selected();
+ if(!sel) {
+ texttool_suggest_select(texttool_suggest_first());
+ }
+ else while(sel && sel!=texttool_suggest_last() && sel->next && scroll--) {
+ texttool_suggest_select(sel->next);
+ sel= sel->next;
+ }
+ text_pop_suggest_list();
+ swallow= 1;
+ draw= 1;
+ break;
+ }
+ case PAGEUPKEY:
+ scroll= SUGG_LIST_SIZE-1;
+ case WHEELUPMOUSE:
+ case UPARROWKEY:
+ if(tools & TOOL_DOCUMENT) {
+ if(doc_scroll>0) doc_scroll--;
+ swallow= 1;
+ draw= 1;
+ break;
+ }
+ else if(tools & TOOL_SUGG_LIST) {
+ SuggItem *sel = texttool_suggest_selected();
+ while(sel && sel!=texttool_suggest_first() && sel->prev && scroll--) {
+ texttool_suggest_select(sel->prev);
+ sel= sel->prev;
+ }
+ text_pop_suggest_list();
+ swallow= 1;
+ draw= 1;
+ break;
+ }
+ case RIGHTSHIFTKEY:
+ case LEFTSHIFTKEY:
+ break;
+ default:
+ if(tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw= 1;
+ if(tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll= 0, draw= 1;
+ }
+ }
+
+ if(draw)
+ ; // XXX redraw_alltext();
+
+ return swallow;
+}
+
+#if 0
+#ifndef DISABLE_PYTHON
+ /* Run text plugin scripts if enabled */
+ if(st->doplugins && event && val) {
+ if(BPY_menu_do_shortcut(PYMENU_TEXTPLUGIN, event, qual)) {
+ do_draw= 1;
+ }
+ }
+#endif
+ if(do_draw)
+ ; // XXX redraw_alltext();
+#endif
+
+short do_textmarkers(SpaceText *st, char ascii, unsigned short evnt, short val)
+{
+ Text *text;
+ TextMarker *marker, *mrk, *nxt;
+ int c, s, draw=0, swallow=0;
+ int qual= 0; // XXX
+
+ text= st->text;
+ if(!text || text->id.lib || text->curl != text->sell) return 0;
+
+ marker= txt_find_marker(text, text->sell, text->selc, 0, 0);
+ if(marker && (marker->start > text->curc || marker->end < text->curc))
+ marker= NULL;
+
+ if(!marker) {
+ /* Find the next temporary marker */
+ if(evnt==TABKEY) {
+ int lineno= txt_get_span(text->lines.first, text->curl);
+ TextMarker *mrk= text->markers.first;
+ while(mrk) {
+ if(!marker && (mrk->flags & TMARK_TEMP)) marker= mrk;
+ if((mrk->flags & TMARK_TEMP) && (mrk->lineno > lineno || (mrk->lineno==lineno && mrk->end > text->curc))) {
+ marker= mrk;
+ break;
+ }
+ mrk= mrk->next;
+ }
+ if(marker) {
+ txt_move_to(text, marker->lineno, marker->start, 0);
+ txt_move_to(text, marker->lineno, marker->end, 1);
+ // XXX WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ evnt= ascii= val= 0;
+ draw= 1;
+ swallow= 1;
+ }
+ }
+ else if(evnt==ESCKEY) {
+ if(txt_clear_markers(text, 0, TMARK_TEMP)) swallow= 1;
+ else if(txt_clear_markers(text, 0, 0)) swallow= 1;
+ else return 0;
+ evnt= ascii= val= 0;
+ draw= 1;
+ }
+ if(!swallow) return 0;
+ }
+
+ if(ascii) {
+ if(marker->flags & TMARK_EDITALL) {
+ c= text->curc-marker->start;
+ s= text->selc-marker->start;
+ if(s<0 || s>marker->end-marker->start) return 0;
+
+ mrk= txt_next_marker(text, marker);
+ while(mrk) {
+ nxt=txt_next_marker(text, mrk); /* mrk may become invalid */
+ txt_move_to(text, mrk->lineno, mrk->start+c, 0);
+ if(s!=c) txt_move_to(text, mrk->lineno, mrk->start+s, 1);
+ if(st->overwrite) {
+ if(txt_replace_char(text, ascii))
+ text_update_line_edited(st->text, st->text->curl);
+ }
+ else {
+ if(txt_add_char(text, ascii)) {
+ text_update_line_edited(st->text, st->text->curl);
+ }
+ }
+
+ if(mrk==marker || mrk==nxt) break;
+ mrk=nxt;
+ }
+ swallow= 1;
+ draw= 1;
+ }
+ }
+ else if(val) {
+ switch(evnt) {
+ case BACKSPACEKEY:
+ if(marker->flags & TMARK_EDITALL) {
+ c= text->curc-marker->start;
+ s= text->selc-marker->start;
+ if(s<0 || s>marker->end-marker->start) return 0;
+
+ mrk= txt_next_marker(text, marker);
+ while(mrk) {
+ nxt= txt_next_marker(text, mrk); /* mrk may become invalid */
+ txt_move_to(text, mrk->lineno, mrk->start+c, 0);
+ if(s!=c) txt_move_to(text, mrk->lineno, mrk->start+s, 1);
+ txt_backspace_char(text);
+ text_update_line_edited(st->text, st->text->curl);
+ if(mrk==marker || mrk==nxt) break;
+ mrk= nxt;
+ }
+ swallow= 1;
+ draw= 1;
+ }
+ break;
+ case DELKEY:
+ if(marker->flags & TMARK_EDITALL) {
+ c= text->curc-marker->start;
+ s= text->selc-marker->start;
+ if(s<0 || s>marker->end-marker->start) return 0;
+
+ mrk= txt_next_marker(text, marker);
+ while(mrk) {
+ nxt= txt_next_marker(text, mrk); /* mrk may become invalid */
+ txt_move_to(text, mrk->lineno, mrk->start+c, 0);
+ if(s!=c) txt_move_to(text, mrk->lineno, mrk->start+s, 1);
+ txt_delete_char(text);
+ text_update_line_edited(st->text, st->text->curl);
+ if(mrk==marker || mrk==nxt) break;
+ mrk= nxt;
+ }
+ swallow= 1;
+ draw= 1;
+ }
+ break;
+ case TABKEY:
+ if(qual & LR_SHIFTKEY) {
+ nxt= marker->prev;
+ if(!nxt) nxt= text->markers.last;
+ }
+ else {
+ nxt= marker->next;
+ if(!nxt) nxt= text->markers.first;
+ }
+ if(marker->flags & TMARK_TEMP) {
+ if(nxt==marker) nxt= NULL;
+ BLI_freelinkN(&text->markers, marker);
+ }
+ mrk= nxt;
+ if(mrk) {
+ txt_move_to(text, mrk->lineno, mrk->start, 0);
+ txt_move_to(text, mrk->lineno, mrk->end, 1);
+ // XXX WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
+ }
+ swallow= 1;
+ draw= 1;
+ break;
+
+ /* Events that should clear markers */
+ case UKEY: if(!(qual & LR_ALTKEY)) break;
+ case ZKEY: if(evnt==ZKEY && !(qual & LR_CTRLKEY)) break;
+ case RETKEY:
+ case ESCKEY:
+ if(marker->flags & (TMARK_EDITALL | TMARK_TEMP))
+ txt_clear_markers(text, marker->group, 0);
+ else
+ BLI_freelinkN(&text->markers, marker);
+ swallow= 1;
+ draw= 1;
+ break;
+ case RIGHTMOUSE: /* Marker context menu? */
+ case LEFTMOUSE:
+ break;
+ case FKEY: /* Allow find */
+ if(qual & LR_SHIFTKEY) swallow= 1;
+ break;
+
+ default:
+ if(qual!=0 && qual!=LR_SHIFTKEY)
+ swallow= 1; /* Swallow all other shortcut events */
+ }
+ }
+
+ if(draw)
+ ; // XXX redraw_alltext();
+
+ return swallow;
+}
+