diff options
Diffstat (limited to 'source/blender/python/api2_2x/Text.c')
-rw-r--r-- | source/blender/python/api2_2x/Text.c | 416 |
1 files changed, 387 insertions, 29 deletions
diff --git a/source/blender/python/api2_2x/Text.c b/source/blender/python/api2_2x/Text.c index 308ad094c7b..c8b96fbd97e 100644 --- a/source/blender/python/api2_2x/Text.c +++ b/source/blender/python/api2_2x/Text.c @@ -34,15 +34,23 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BIF_drawtext.h" +#include "BIF_screen.h" #include "BKE_text.h" +#include "BKE_suggestions.h" #include "BLI_blenlib.h" +#include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "MEM_guardedalloc.h" #include "gen_utils.h" #include "gen_library.h" #include "../BPY_extern.h" #define EXPP_TEXT_MODE_FOLLOW TXT_FOLLOW +/* checks for the group being removed */ +#define TEXT_DEL_CHECK_PY(bpy_text) if (!(bpy_text->text)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Text has been removed" ) ) +#define TEXT_DEL_CHECK_INT(bpy_text) if (!(bpy_text->text)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Text has been removed" ) ) + /*****************************************************************************/ /* Python API function prototypes for the Text module. */ /*****************************************************************************/ @@ -90,9 +98,22 @@ struct PyMethodDef M_Text_methods[] = { static PyObject *Text_getFilename( BPy_Text * self ); static PyObject *Text_getNLines( BPy_Text * self ); static PyObject *Text_clear( BPy_Text * self ); +static PyObject *Text_reset( BPy_Text * self ); +static PyObject *Text_readline( BPy_Text * self ); static PyObject *Text_write( BPy_Text * self, PyObject * value ); +static PyObject *Text_insert( BPy_Text * self, PyObject * value ); +static PyObject *Text_delete( BPy_Text * self, PyObject * value ); static PyObject *Text_set( BPy_Text * self, PyObject * args ); -static PyObject *Text_asLines( BPy_Text * self ); +static PyObject *Text_asLines( BPy_Text * self, PyObject * args ); +static PyObject *Text_getCursorPos( BPy_Text * self ); +static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args ); +static PyObject *Text_getSelectPos( BPy_Text * self ); +static PyObject *Text_setSelectPos( BPy_Text * self, PyObject * args ); +static PyObject *Text_markSelection( BPy_Text * self, PyObject * args ); +static PyObject *Text_suggest( BPy_Text * self, PyObject * args ); +static PyObject *Text_showDocs( BPy_Text * self, PyObject * args ); + +static void text_reset_internal( BPy_Text * self ); /* internal func */ /*****************************************************************************/ /* Python BPy_Text methods table: */ @@ -109,12 +130,34 @@ static PyMethodDef BPy_Text_methods[] = { "(str) - Change Text Object name"}, {"clear", ( PyCFunction ) Text_clear, METH_NOARGS, "() - Clear Text buffer"}, + {"reset", ( PyCFunction ) Text_reset, METH_NOARGS, + "() - Moves the IO pointer back to the start of the Text buffer for reading"}, + {"readline", ( PyCFunction ) Text_readline, METH_NOARGS, + "() - Reads a line of text from the buffer and returns it incrementing the internal IO pointer."}, {"write", ( PyCFunction ) Text_write, METH_O, "(line) - Append string 'str' to Text buffer"}, + {"insert", ( PyCFunction ) Text_insert, METH_O, + "(line) - Insert string 'str' to Text buffer at cursor location"}, + {"delete", ( PyCFunction ) Text_delete, METH_O, + "(chars) - Deletes a number of characters to the left (chars<0) or right (chars>0)"}, {"set", ( PyCFunction ) Text_set, METH_VARARGS, "(name, val) - Set attribute 'name' to value 'val'"}, - {"asLines", ( PyCFunction ) Text_asLines, METH_NOARGS, - "() - Return text buffer as a list of lines"}, + {"asLines", ( PyCFunction ) Text_asLines, METH_VARARGS, + "(start=0, end=nlines) - Return text buffer as a list of lines between start and end"}, + {"getCursorPos", ( PyCFunction ) Text_getCursorPos, METH_NOARGS, + "() - Return cursor position as (row, col) tuple"}, + {"setCursorPos", ( PyCFunction ) Text_setCursorPos, METH_VARARGS, + "(row, col) - Set the cursor position to (row, col)"}, + {"getSelectPos", ( PyCFunction ) Text_getSelectPos, METH_NOARGS, + "() - Return the selection cursor position as (row, col) tuple"}, + {"setSelectPos", ( PyCFunction ) Text_setSelectPos, METH_VARARGS, + "(row, col) - Set the selection cursor position to (row, col)"}, + {"markSelection", ( PyCFunction ) Text_markSelection, METH_VARARGS, + "(group, (r, g, b), flags) - Places a marker over the current selection. Group: number > 0, flags: TMARK_TEMP, TMARK_EDITALL, etc."}, + {"suggest", ( PyCFunction ) Text_suggest, METH_VARARGS, + "(list, prefix='') - Presents a list of suggestions. List is of strings, or tuples. Tuples must be of the form (name, type) where type is one of 'm', 'v', 'f', 'k' for module, variable, function and keyword respectively or '?' for other types"}, + {"showDocs", ( PyCFunction ) Text_showDocs, METH_VARARGS, + "(docs) - Documentation string"}, {NULL, NULL, 0, NULL} }; @@ -302,7 +345,7 @@ static PyObject *M_Text_unlink( PyObject * self, PyObject * args ) /*****************************************************************************/ PyObject *Text_Init( void ) { - PyObject *submodule; + PyObject *submodule, *dict; if( PyType_Ready( &Text_Type ) < 0 ) return NULL; @@ -310,6 +353,19 @@ PyObject *Text_Init( void ) submodule = Py_InitModule3( "Blender.Text", M_Text_methods, M_Text_doc ); + dict = PyModule_GetDict( submodule ); + +#define EXPP_ADDCONST(x) \ + EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(x)) + + /* So, for example: + * EXPP_ADDCONST(LEFTMOUSE) becomes + * EXPP_dict_set_item_str(dict, "LEFTMOUSE", PyInt_FromLong(LEFTMOUSE)) + */ + + EXPP_ADDCONST( TMARK_TEMP ); + EXPP_ADDCONST( TMARK_EDITALL ); + return ( submodule ); } @@ -327,6 +383,7 @@ PyObject *Text_CreatePyObject( Text * txt ) "couldn't create BPy_Text PyObject" ); pytxt->text = txt; + text_reset_internal(pytxt); return ( PyObject * ) pytxt; } @@ -336,6 +393,7 @@ PyObject *Text_CreatePyObject( Text * txt ) /*****************************************************************************/ static PyObject *Text_getFilename( BPy_Text * self ) { + TEXT_DEL_CHECK_PY(self); if( self->text->name ) return PyString_FromString( self->text->name ); @@ -346,7 +404,9 @@ static PyObject *Text_getNLines( BPy_Text * self ) { /* text->nlines isn't updated in Blender (?) */ int nlines = 0; TextLine *line; - + + TEXT_DEL_CHECK_PY(self); + line = self->text->lines.first; while( line ) { /* so we have to count them ourselves */ @@ -363,9 +423,7 @@ static PyObject *Text_clear( BPy_Text * self) { int oldstate; - if( !self->text ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "This object isn't linked to a Blender Text Object" ); + TEXT_DEL_CHECK_PY(self); oldstate = txt_get_undostate( ); txt_set_undostate( 1 ); @@ -376,23 +434,49 @@ static PyObject *Text_clear( BPy_Text * self) Py_RETURN_NONE; } -static PyObject *Text_set( BPy_Text * self, PyObject * args ) +static void text_reset_internal( BPy_Text * self ) { - int ival; - char *attr; + self->iol = NULL; + self->ioc = -1; +} - if( !PyArg_ParseTuple( args, "si", &attr, &ival ) ) - return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected a string and an int as arguments" ); +static PyObject *Text_reset( BPy_Text * self ) +{ + text_reset_internal(self); + Py_RETURN_NONE; +} - if( strcmp( "follow_cursor", attr ) == 0 ) { - if( ival ) - self->text->flags |= EXPP_TEXT_MODE_FOLLOW; - else - self->text->flags &= EXPP_TEXT_MODE_FOLLOW; +static PyObject *Text_readline( BPy_Text * self ) +{ + PyObject *tmpstr; + + TEXT_DEL_CHECK_PY(self); + + /* Reset */ + if (!self->iol && self->ioc == -1) { + self->iol = self->text->lines.first; + self->ioc = 0; } - Py_RETURN_NONE; + if (!self->iol) { + PyErr_SetString( PyExc_StopIteration, "End of buffer reached" ); + return PyString_FromString( "" ); + } + + if (self->ioc > self->iol->len) { + self->iol = NULL; + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Line length exceeded, text may have changed while reading" ); + } + + tmpstr = PyString_FromString( self->iol->line + self->ioc ); + if (self->iol->next) + PyString_ConcatAndDel( &tmpstr, PyString_FromString("\n") ); + + self->iol = self->iol->next; + self->ioc = 0; + + return tmpstr; } static PyObject *Text_write( BPy_Text * self, PyObject * value ) @@ -400,48 +484,321 @@ static PyObject *Text_write( BPy_Text * self, PyObject * value ) char *str = PyString_AsString(value); int oldstate; - if( !self->text ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "This object isn't linked to a Blender Text Object" ); - if( !str ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected string argument" ); + TEXT_DEL_CHECK_PY(self); + oldstate = txt_get_undostate( ); txt_insert_buf( self->text, str ); txt_move_eof( self->text, 0 ); txt_set_undostate( oldstate ); + text_reset_internal( self ); + + Py_RETURN_NONE; +} + +static PyObject *Text_insert( BPy_Text * self, PyObject * value ) +{ + char *str = PyString_AsString(value); + int oldstate; + + if( !str ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string argument" ); + + TEXT_DEL_CHECK_PY(self); + + oldstate = txt_get_undostate( ); + txt_insert_buf( self->text, str ); + txt_set_undostate( oldstate ); + + text_reset_internal( self ); + Py_RETURN_NONE; } -static PyObject *Text_asLines( BPy_Text * self ) +static PyObject *Text_delete( BPy_Text * self, PyObject * value ) +{ + int num = PyInt_AsLong(value); + int oldstate; + + TEXT_DEL_CHECK_PY(self); + + /* zero num is invalid and -1 is an error value */ + if( !num || (num==-1 && PyErr_Occurred())) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected non-zero int argument" ); + + oldstate = txt_get_undostate( ); + while (num<0) { + txt_backspace_char(self->text); + num++; + } + while (num>0) { + txt_delete_char(self->text); + num--; + } + txt_set_undostate( oldstate ); + + text_reset_internal( self ); + + Py_RETURN_NONE; +} + +static PyObject *Text_set( BPy_Text * self, PyObject * args ) +{ + int ival; + char *attr; + + TEXT_DEL_CHECK_PY(self); + + if( !PyArg_ParseTuple( args, "si", &attr, &ival ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string and an int as arguments" ); + + if( strcmp( "follow_cursor", attr ) == 0 ) { + if( ival ) + self->text->flags |= EXPP_TEXT_MODE_FOLLOW; + else + self->text->flags &= EXPP_TEXT_MODE_FOLLOW; + } + + Py_RETURN_NONE; +} + +static PyObject *Text_asLines( BPy_Text * self, PyObject * args ) { TextLine *line; PyObject *list, *tmpstr; + int start=0, end=-1, i; - if( !self->text ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "This object isn't linked to a Blender Text Object" ); + TEXT_DEL_CHECK_PY(self); + + if( !PyArg_ParseTuple( args, "|ii", &start, &end ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected upto two optional ints as arguments" ); + + if (start<0) + start=0; line = self->text->lines.first; + for (i = 0; i < start && line->next; i++) + line= line->next; + list = PyList_New( 0 ); if( !list ) return EXPP_ReturnPyObjError( PyExc_MemoryError, "couldn't create PyList" ); - while( line ) { + while( line && (i < end || end == -1) ) { tmpstr = PyString_FromString( line->line ); PyList_Append( list, tmpstr ); Py_DECREF(tmpstr); line = line->next; + i++; } return list; } +static PyObject *Text_getCursorPos( BPy_Text * self ) +{ + Text *text; + TextLine *linep; + int row, col; + + TEXT_DEL_CHECK_PY(self); + + text = self->text; + + for (row=0,linep=text->lines.first; linep!=text->curl; linep=linep->next) + row++; + col= text->curc; + + return Py_BuildValue( "ii", row, col ); +} + +static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args ) +{ + int row, col; + SpaceText *st; + + TEXT_DEL_CHECK_PY(self); + + if (!PyArg_ParseTuple(args, "ii", &row, &col)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expected two ints as arguments."); + if (row<0) row=0; + if (col<0) col=0; + + txt_move_to(self->text, row, col, 0); + + if (curarea->spacetype == SPACE_TEXT && (st=curarea->spacedata.first)) + pop_space_text(st); + + Py_RETURN_NONE; +} + +static PyObject *Text_getSelectPos( BPy_Text * self ) +{ + Text *text; + TextLine *linep; + int row, col; + + TEXT_DEL_CHECK_PY(self); + + text = self->text; + + for (row=0,linep=text->lines.first; linep!=text->sell; linep=linep->next) + row++; + col= text->selc; + + return Py_BuildValue( "ii", row, col ); +} + +static PyObject *Text_setSelectPos( BPy_Text * self, PyObject * args ) +{ + int row, col; + SpaceText *st; + + TEXT_DEL_CHECK_PY(self); + + if (!PyArg_ParseTuple(args, "ii", &row, &col)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expected two ints as arguments."); + if (row<0) row=0; + if (col<0) col=0; + + txt_move_to(self->text, row, col, 1); + + if (curarea->spacetype == SPACE_TEXT && (st=curarea->spacedata.first)) + pop_space_text(st); + + Py_RETURN_NONE; +} + +static PyObject *Text_markSelection( BPy_Text * self, PyObject * args ) +{ + int group = 0, flags = 0,r, g, b; + Text *text; + char color[4]; + + TEXT_DEL_CHECK_PY(self); + + text = self->text; + + if (!PyArg_ParseTuple(args, "i(iii)i", &group, &r, &g, &b, &flags)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expected int, 3-tuple of ints and int as arguments."); + + if (text->curl != text->sell) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "Cannot mark multi-line selection."); + + color[0] = (char) (r&0xFF); + color[1] = (char) (g&0xFF); + color[2] = (char) (b&0xFF); + color[3] = 255; + + group &= 0xFFFF; + + txt_add_marker(text, text->curl, text->curc, text->selc, color, group, flags); + + Py_RETURN_NONE; +} + +static PyObject *Text_suggest( BPy_Text * self, PyObject * args ) +{ + PyObject *item = NULL, *tup1 = NULL, *tup2 = NULL; + PyObject *list = NULL; + int list_len, i; + char *prefix = NULL, *name, type; + SpaceText *st; + + TEXT_DEL_CHECK_PY(self); + + /* Parse args for a list of strings/tuples */ + if (!PyArg_ParseTuple(args, "O!|s", &PyList_Type, &list, &prefix)) + return EXPP_ReturnPyObjError(PyExc_TypeError, + "expected list of strings or tuples followed by an optional string"); + + if (curarea->spacetype != SPACE_TEXT) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "Active space type is not text"); + + st = curarea->spacedata.first; + if (!st || !st->text) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "Active text area has no Text object"); + + texttool_suggest_clear(); + texttool_text_set_active(st->text); + list_len = PyList_Size(list); + + for (i = 0; i < list_len; i++) { + item = PyList_GetItem(list, i); + + if (PyString_Check(item)) { + name = PyString_AsString(item); + type = '?'; + } else if (PyTuple_Check(item) && PyTuple_GET_SIZE(item) == 2) { + tup1 = PyTuple_GetItem(item, 0); + tup2 = PyTuple_GetItem(item, 1); + if (PyString_Check(tup1) && PyString_Check(tup2)) { + name = PyString_AsString(tup1); + type = PyString_AsString(tup2)[0]; + } else + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "list must contain tuples of two strings only: (name, type)" ); + } else + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "list must contain only individual strings or tuples of size 2" ); + + if (!strlen(name) || (type!='m' && type!='v' && type!='f' && type!='k' && type!='?')) + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "names must be non-empty and types in ['m', 'v', 'f', 'k', '?']" ); + + texttool_suggest_add(name, type); + } + if (!prefix) + prefix = ""; + texttool_suggest_prefix(prefix); + scrarea_queue_redraw(curarea); + + Py_RETURN_NONE; +} + +static PyObject *Text_showDocs( BPy_Text * self, PyObject * args ) +{ + char *docs; + SpaceText *st; + + TEXT_DEL_CHECK_PY(self); + + if (!PyArg_ParseTuple(args, "s", &docs)) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a string as argument" ); + + if (curarea->spacetype != SPACE_TEXT) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "Active space type is not text"); + + st = curarea->spacedata.first; + if (!st || !st->text) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "Active text area has no Text object"); + + texttool_text_set_active(st->text); + texttool_docs_show(docs); + scrarea_queue_redraw(curarea); + + Py_RETURN_NONE; +} + /*****************************************************************************/ /* Function: Text_compare */ /* Description: This is a callback function for the BPy_Text type. It */ @@ -474,6 +831,7 @@ static PyObject *Text_repr( BPy_Text * self ) /*****************************************************************************/ static PyObject *Text_getMode(BPy_Text * self) { + TEXT_DEL_CHECK_PY(self); return PyInt_FromLong( self->text->flags ); } |