diff options
-rw-r--r-- | release/scripts/textplugin_templates.py | 114 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/text.c | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Text.c | 129 | ||||
-rw-r--r-- | source/blender/src/drawtext.c | 53 |
4 files changed, 274 insertions, 24 deletions
diff --git a/release/scripts/textplugin_templates.py b/release/scripts/textplugin_templates.py new file mode 100644 index 00000000000..e0e7746abca --- /dev/null +++ b/release/scripts/textplugin_templates.py @@ -0,0 +1,114 @@ +#!BPY +""" +Name: 'Templates' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Tab' +Tooltip: 'Completes templates based on the text preceding the cursor' +""" + +# Only run if we have the required modules +try: + import bpy + from BPyTextPlugin import * + from Blender import Text +except ImportError: + OK = False +else: + OK = True + +templates = { + 'ie': + 'if ${1:cond}:\n' + '\t${2}\n' + 'else:\n' + '\t${3}\n', + 'iei': + 'if ${1:cond}:\n' + '\t${2}\n' + 'elif:\n' + '\t${3}\n' + 'else:\n' + '\t${4}\n', + 'def': + 'def ${1:name}(${2:params}):\n' + '\t"""(${2}) - ${3:comment}"""\n' + '\t${4}', + 'cls': + 'class ${1:name}(${2:parent}):\n' + '\t"""${3:docs}"""\n' + '\t\n' + '\tdef __init__(self, ${4:params}):\n' + '\t\t"""Creates a new ${1}"""\n' + '\t\t${5}' +} + +def main(): + txt = bpy.data.texts.active + if not txt: + return + + line, c = current_line(txt) + indent=0 + while indent<len(line) and (line[indent]==' ' or line[indent]=='\t'): + indent += 1 + + # Check we are in a normal context + if get_context(txt) != CTX_NORMAL: + return + + targets = get_targets(line, c-1); + if len(targets) != 1: return + + color = (0, 192, 32) + + for trigger, template in templates.items(): + if trigger != targets[0]: continue + inserts = {} + txt.delete(-len(trigger)-1) + y, x = txt.getCursorPos() + first = None + + # Insert template text and parse for insertion points + count = len(template); i = 0 + while i < count: + if i<count-1 and template[i]=='$' and template[i+1]=='{': + i += 2 + e = template.find('}', i) + item = template[i:e].split(':') + if len(item)<2: item.append('') + if not inserts.has_key(item[0]): + inserts[item[0]] = (item[1], [(x, y)]) + else: + inserts[item[0]][1].append((x, y)) + item[1] = inserts[item[0]][0] + if not first: first = (item[1], x, y) + txt.insert(item[1]) + x += len(item[1]) + i = e + else: + txt.insert(template[i]) + if template[i] == '\n': + txt.insert(line[:indent]) + y += 1 + x = indent + else: + x += 1 + i += 1 + + # Insert markers at insertion points + for id, (text, points) in inserts.items(): + for x, y in points: + txt.setCursorPos(y, x) + txt.setSelectPos(y, x+len(text)) + txt.markSelection(hash(text)+int(id), color, Text.TMARK_TEMP | Text.TMARK_EDITALL) + if first: + text, x, y = first + txt.setCursorPos(y, x) + txt.setSelectPos(y, x+len(text)) + break + + +# Check we are running as a script and not imported as a module +if __name__ == "__main__" and OK: + main() diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 611eed3999e..47f8fc708c2 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -2773,4 +2773,4 @@ TextMarker *txt_next_marker(Text *text, TextMarker *marker) { return tmp; } return NULL; /* Only if marker==NULL */ -}
\ No newline at end of file +} diff --git a/source/blender/python/api2_2x/Text.c b/source/blender/python/api2_2x/Text.c index ae847d26f2d..0f0abda04e1 100644 --- a/source/blender/python/api2_2x/Text.c +++ b/source/blender/python/api2_2x/Text.c @@ -98,10 +98,14 @@ 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_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 ); @@ -128,6 +132,8 @@ static PyMethodDef BPy_Text_methods[] = { "(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, @@ -136,6 +142,12 @@ static PyMethodDef BPy_Text_methods[] = { "() - 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, @@ -327,7 +339,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; @@ -335,6 +347,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 ); } @@ -483,6 +508,33 @@ static PyObject *Text_insert( BPy_Text * self, PyObject * value ) Py_RETURN_NONE; } +static PyObject *Text_delete( BPy_Text * self, PyObject * value ) +{ + int num = PyInt_AsLong(value); + int oldstate; + + if( !self->text ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object" ); + + if( !num ) + 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 ); + + Py_RETURN_NONE; +} + static PyObject *Text_set( BPy_Text * self, PyObject * args ) { int ival; @@ -549,7 +601,6 @@ static PyObject *Text_getCursorPos( BPy_Text * self ) static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args ) { int row, col; - int oldstate; SpaceText *st; if (!self->text) @@ -559,12 +610,10 @@ static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args ) 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; - if (col>self->text->curl->len) col=self->text->curl->len; - oldstate = txt_get_undostate(); txt_move_to(self->text, row, col, 0); - txt_set_undostate(oldstate); if (curarea->spacetype == SPACE_TEXT && (st=curarea->spacedata.first)) pop_space_text(st); @@ -572,6 +621,76 @@ static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args ) Py_RETURN_NONE; } +static PyObject *Text_getSelectPos( BPy_Text * self ) +{ + Text *text; + TextLine *linep; + int row, col; + + text = self->text; + if( !text ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object" ); + + 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; + + if (!self->text) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object"); + + 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 clr[4]; + + text = self->text; + if (!text) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, + "This object isn't linked to a Blender Text Object"); + + 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."); + + clr[0] = (char) (r&0xFF); + clr[1] = (char) (g&0xFF); + clr[2] = (char) (b&0xFF); + clr[3] = 255; + + txt_add_marker(text, text->curl, text->curc, text->selc, clr, ((group+2)<<16)|flags); + + Py_RETURN_NONE; +} + static PyObject *Text_suggest( BPy_Text * self, PyObject * args ) { PyObject *item = NULL, *tup1 = NULL, *tup2 = NULL; diff --git a/source/blender/src/drawtext.c b/source/blender/src/drawtext.c index 951e71e1f81..5a96a2548d7 100644 --- a/source/blender/src/drawtext.c +++ b/source/blender/src/drawtext.c @@ -814,17 +814,17 @@ static void draw_markers(SpaceText *st) { if (y1==y2) { y -= y1*st->lheight; glBegin(GL_LINE_LOOP); - glVertex2i(x+x2*spacetext_get_fontwidth(st), y); - glVertex2i(x+x1*spacetext_get_fontwidth(st)-1, y); - glVertex2i(x+x1*spacetext_get_fontwidth(st)-1, y-st->lheight); - glVertex2i(x+x2*spacetext_get_fontwidth(st), y-st->lheight); + glVertex2i(x+x2*spacetext_get_fontwidth(st)+1, y); + glVertex2i(x+x1*spacetext_get_fontwidth(st)-2, y); + glVertex2i(x+x1*spacetext_get_fontwidth(st)-2, y-st->lheight); + glVertex2i(x+x2*spacetext_get_fontwidth(st)+1, y-st->lheight); glEnd(); } else { y -= y1*st->lheight; glBegin(GL_LINE_STRIP); glVertex2i(curarea->winx, y); - glVertex2i(x+x1*spacetext_get_fontwidth(st)-1, y); - glVertex2i(x+x1*spacetext_get_fontwidth(st)-1, y-st->lheight); + glVertex2i(x+x1*spacetext_get_fontwidth(st)-2, y); + glVertex2i(x+x1*spacetext_get_fontwidth(st)-2, y-st->lheight); glVertex2i(curarea->winx, y-st->lheight); glEnd(); y-=st->lheight; @@ -839,8 +839,8 @@ static void draw_markers(SpaceText *st) { } glBegin(GL_LINE_STRIP); glVertex2i(x, y); - glVertex2i(x+x2*spacetext_get_fontwidth(st), y); - glVertex2i(x+x2*spacetext_get_fontwidth(st), y-st->lheight); + glVertex2i(x+x2*spacetext_get_fontwidth(st)+1, y); + glVertex2i(x+x2*spacetext_get_fontwidth(st)+1, y-st->lheight); glVertex2i(x, y-st->lheight); glEnd(); } @@ -2329,10 +2329,23 @@ static short do_markers(SpaceText *st, char ascii, unsigned short evnt, short va } break; case TABKEY: - marker= (G.qual & LR_SHIFTKEY) ? txt_prev_marker(text, marker) : txt_next_marker(text, marker); - txt_move_to(text, marker->lineno, marker->start, 0); - txt_move_to(text, marker->lineno, marker->end, 1); - pop_space_text(st); + if (G.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); + pop_space_text(st); + } swallow= 1; draw= 1; break; @@ -2707,7 +2720,7 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt) } break; /* BREAK S */ case UKEY: - txt_print_undo(text); //debug buffer in console + //txt_print_undo(text); //debug buffer in console if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) { txt_do_redo(text); do_draw= 1; @@ -2785,17 +2798,21 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt) error_libdata(); break; } else { - if (G.qual & LR_SHIFTKEY) { - if (txt_has_sel(text)) { + if (txt_has_sel(text)) { + if (G.qual & LR_SHIFTKEY) { txt_order_cursors(text); unindent(text); if (st->showsyntax) txt_format_text(st); - } - } else { - if ( txt_has_sel(text)) { + } else { txt_order_cursors(text); indent(text); if (st->showsyntax) txt_format_text(st); + } + } else { + TextMarker *mrk= txt_find_marker_region(text, text->curl, 0, text->curl->len, 0); + if (mrk) { + txt_move_to(text, mrk->lineno, mrk->start, 0); + txt_move_to(text, mrk->lineno, mrk->end, 1); } else { txt_add_char(text, '\t'); if (st->showsyntax) txt_format_line(st, text->curl, 1); |