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:
-rw-r--r--release/scripts/textplugin_suggest.py234
-rw-r--r--source/blender/blenkernel/BKE_suggestions.h77
-rw-r--r--source/blender/blenkernel/intern/suggestions.c125
-rw-r--r--source/blender/python/BPY_interface.c1
-rw-r--r--source/blender/python/BPY_menus.c5
-rw-r--r--source/blender/python/BPY_menus.h1
-rw-r--r--source/blender/python/api2_2x/Text.c57
-rw-r--r--source/blender/python/api2_2x/doc/Text.py12
-rw-r--r--source/blender/src/drawtext.c15
-rw-r--r--source/blender/src/header_text.c32
-rw-r--r--source/blender/src/usiblender.c3
11 files changed, 561 insertions, 1 deletions
diff --git a/release/scripts/textplugin_suggest.py b/release/scripts/textplugin_suggest.py
new file mode 100644
index 00000000000..77ae0488b1c
--- /dev/null
+++ b/release/scripts/textplugin_suggest.py
@@ -0,0 +1,234 @@
+#!BPY
+"""
+Name: 'Suggest'
+Blender: 243
+Group: 'TextPlugin'
+Tooltip: 'Suggests completions for the word at the cursor in a python script'
+"""
+
+import bpy
+from Blender import Text
+from StringIO import StringIO
+from inspect import *
+from tokenize import generate_tokens
+import token
+
+TK_TYPE = 0
+TK_TOKEN = 1
+TK_START = 2 #(srow, scol)
+TK_END = 3 #(erow, ecol)
+TK_LINE = 4
+TK_ROW = 0
+TK_COL = 1
+
+keywords = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global',
+ 'or', 'with', 'assert', 'else', 'if', 'pass', 'yield',
+ 'break', 'except', 'import', 'print', 'class', 'exec', 'in',
+ 'raise', 'continue', 'finally', 'is', 'return', 'def', 'for',
+ 'lambda', 'try' ]
+
+execs = [] # Used to establish the same import context across defs (import is scope sensitive)
+
+def getTokens(txt):
+ global tokens_cached
+ if tokens_cached==None:
+ lines = txt.asLines()
+ str = '\n'.join(lines)
+ readline = StringIO(str).readline
+ g = generate_tokens(readline)
+ tokens = []
+ for t in g: tokens.append(t)
+ tokens_cached = tokens
+ return tokens_cached
+tokens_cached = None
+
+def isNameChar(s):
+ return s.isalnum() or s in ['_']
+
+# Returns words preceding the cursor that are separated by periods as a list in the
+# same order
+def getCompletionSymbols(txt):
+ (l, c)= txt.getCursorPos()
+ lines = txt.asLines()
+ line = lines[l]
+ a=0
+ for a in range(1, c+1):
+ if not isNameChar(line[c-a]) and line[c-a]!='.':
+ a -= 1
+ break
+ return line[c-a:c].split('.')
+
+
+# Returns a list of tuples of symbol names and their types (name, type) where
+# type is one of:
+# m (module/class) Has its own members (includes classes)
+# v (variable) Has a type which may have its own members
+# f (function) Callable and may have a return type (with its own members)
+# It also updates the global import context (via execs)
+def getGlobals(txt):
+ global execs
+
+ tokens = getTokens(txt)
+ globals = dict()
+ for i in range(len(tokens)):
+
+ # Handle all import statements
+ if i>=1 and tokens[i-1][TK_TOKEN]=='import':
+
+ # Find 'from' if it exists
+ fr= -1
+ for a in range(1, i):
+ if tokens[i-a][TK_TYPE]==token.NEWLINE: break
+ if tokens[i-a][TK_TOKEN]=='from':
+ fr=i-a
+ break
+
+ # Handle: import ___[,___]
+ if fr<0:
+
+ while True:
+ if tokens[i][TK_TYPE]==token.NAME:
+ # Add the import to the execs list
+ x = tokens[i][TK_LINE].strip()
+ k = tokens[i][TK_TOKEN]
+ execs.append(x)
+
+ # Add the symbol name to the return list
+ globals[k] = 'm'
+ elif tokens[i][TK_TOKEN]!=',':
+ break
+ i += 1
+
+ # Handle statement: from ___[.___] import ___[,___]
+ else: # fr>=0:
+
+ # Add the import to the execs list
+ x = tokens[i][TK_LINE].strip()
+ execs.append(x)
+
+ # Import parent module so we can process it for sub modules
+ parent = ''.join([t[TK_TOKEN] for t in tokens[fr+1:i-1]])
+ exec "import "+parent
+
+ # All submodules, functions, etc.
+ if tokens[i][TK_TOKEN]=='*':
+
+ # Add each symbol name to the return list
+ exec "d="+parent+".__dict__.items()"
+ for k,v in d:
+ if not globals.has_key(k) or not globals[k]:
+ t='v'
+ if ismodule(v): t='m'
+ elif callable(v): t='f'
+ globals[k] = t
+
+ # Specific function, submodule, etc.
+ else:
+ while True:
+ if tokens[i][TK_TYPE]==token.NAME:
+ k = tokens[i][TK_TOKEN]
+ if not globals.has_key(k) or not globals[k]:
+ t='v'
+ try:
+ exec 'v='+parent+'.'+k
+ if ismodule(v): t='m'
+ elif callable(v): t='f'
+ except: pass
+ globals[k] = t
+ elif tokens[i][TK_TOKEN]!=',':
+ break
+ i += 1
+
+ elif tokens[i][TK_TYPE]==token.NAME and tokens[i][TK_TOKEN] not in keywords and (i==0 or tokens[i-1][TK_TOKEN]!='.'):
+ k = tokens[i][TK_TOKEN]
+ if not globals.has_key(k) or not globals[k]:
+ t=None
+ if (i>0 and tokens[i-1][TK_TOKEN]=='def'):
+ t='f'
+ else:
+ t='v'
+ globals[k] = t
+
+ return globals
+
+def cmpi0(x, y):
+ return cmp(x[0].lower(), y[0].lower())
+
+def globalSuggest(txt, cs):
+ global execs
+
+ suggestions = dict()
+ (row, col) = txt.getCursorPos()
+ globals = getGlobals(txt)
+
+ # Sometimes we have conditional includes which will fail if the module
+ # cannot be found. So we protect outselves in a try block
+ for x in execs:
+ exec 'try: '+x+'\nexcept: pass'
+
+ if len(cs)==0:
+ sub = ''
+ else:
+ sub = cs[0].lower()
+ print 'Search:', sub
+
+ for k,t in globals.items():
+ if k.lower().startswith(sub):
+ suggestions[k] = t
+
+ l = list(suggestions.items())
+ return sorted (l, cmp=cmpi0)
+
+# Only works for 'static' members (eg. Text.Get)
+def memberSuggest(txt, cs):
+ global execs
+
+ # Populate the execs for imports
+ getGlobals(txt)
+
+ # Sometimes we have conditional includes which will fail if the module
+ # cannot be found. So we protect outselves in a try block
+ for x in execs:
+ exec 'try: '+x+'\nexcept: pass'
+
+ suggestions = dict()
+ (row, col) = txt.getCursorPos()
+
+ sub = cs[len(cs)-1].lower()
+ print 'Search:', sub
+
+ t=None
+ pre='.'.join(cs[:-1])
+ try:
+ exec "t="+pre
+ except:
+ print 'Failed to assign '+pre
+ print execs
+ print cs
+
+ if t!=None:
+ for k,v in t.__dict__.items():
+ if ismodule(v): t='m'
+ elif callable(v): t='f'
+ else: t='v'
+ if k.lower().startswith(sub):
+ suggestions[k] = t
+
+ l = list(suggestions.items())
+ return sorted (l, cmp=cmpi0)
+
+def main():
+ txt = bpy.data.texts.active
+ if txt==None: return
+
+ cs = getCompletionSymbols(txt)
+
+ if len(cs)<=1:
+ l = globalSuggest(txt, cs)
+ txt.suggest(l, cs[len(cs)-1])
+
+ else:
+ l = memberSuggest(txt, cs)
+ txt.suggest(l, cs[len(cs)-1])
+
+main()
diff --git a/source/blender/blenkernel/BKE_suggestions.h b/source/blender/blenkernel/BKE_suggestions.h
new file mode 100644
index 00000000000..bc4e18f5a67
--- /dev/null
+++ b/source/blender/blenkernel/BKE_suggestions.h
@@ -0,0 +1,77 @@
+/**
+ * $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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef BKE_SUGGESTIONS_H
+#define BKE_SUGGESTIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ****************************************************************************
+Suggestions must be added in sorted order (no attempt is made to sort the list)
+The list is then divided up based on the prefix provided by update_suggestions:
+Example:
+ Prefix: ab
+ aaa <-- first
+ aab
+ aba <-- firstmatch
+ abb <-- lastmatch
+ baa
+ bab <-- last
+**************************************************************************** */
+
+struct Text;
+
+typedef struct SuggItem {
+ struct SuggItem *prev, *next;
+ char *name;
+ char type;
+} SuggItem;
+
+typedef struct SuggList {
+ SuggItem *first, *last;
+ SuggItem *firstmatch, *lastmatch;
+} SuggList;
+
+void free_suggestions();
+
+void add_suggestion(const char *name, char type);
+void update_suggestions(const char *prefix);
+SuggItem *suggest_first();
+SuggItem *suggest_last();
+
+void set_suggest_text(Text *text);
+void clear_suggest_text();
+short is_suggest_active(Text *text);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/intern/suggestions.c b/source/blender/blenkernel/intern/suggestions.c
new file mode 100644
index 00000000000..3842146376d
--- /dev/null
+++ b/source/blender/blenkernel/intern/suggestions.c
@@ -0,0 +1,125 @@
+/**
+ * $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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "DNA_text_types.h"
+#include "BKE_text.h"
+#include "BKE_suggestions.h"
+
+static SuggList suggestions= {NULL, NULL, NULL, NULL};
+static Text *suggText = NULL;
+
+void free_suggestions() {
+ SuggItem *item;
+ for (item = suggestions.last; item; item=item->prev)
+ MEM_freeN(item);
+ suggestions.first = suggestions.last = NULL;
+ suggestions.firstmatch = suggestions.lastmatch = NULL;
+}
+
+void add_suggestion(const char *name, char type) {
+ SuggItem *newitem;
+
+ newitem = MEM_mallocN(sizeof(SuggItem) + strlen(name) + 1, "SuggestionItem");
+ if (!newitem) {
+ printf("Failed to allocate memory for suggestion.\n");
+ return;
+ }
+
+ newitem->name = (char *) (newitem + 1);
+ strcpy(newitem->name, name);
+ newitem->type = type;
+ newitem->prev = newitem->next = NULL;
+
+ if (!suggestions.first) {
+ suggestions.first = suggestions.last = newitem;
+ } else {
+ newitem->prev = suggestions.last;
+ suggestions.last->next = newitem;
+ suggestions.last = newitem;
+ }
+}
+
+void update_suggestions(const char *prefix) {
+ SuggItem *match, *first, *last;
+ int cmp, len = strlen(prefix);
+
+ if (!suggestions.first) return;
+ if (len==0) {
+ suggestions.firstmatch = suggestions.first;
+ suggestions.lastmatch = suggestions.last;
+ return;
+ }
+
+ first = last = NULL;
+ for (match=suggestions.first; match; match=match->next) {
+ cmp = strncmp(prefix, match->name, len);
+ if (cmp==0) {
+ if (!first)
+ first = match;
+ } else if (cmp<0) {
+ if (!last) {
+ last = match->prev;
+ break;
+ }
+ }
+ }
+ if (first) {
+ if (!last) last = suggestions.last;
+ suggestions.firstmatch = first;
+ suggestions.lastmatch = last;
+ } else {
+ suggestions.firstmatch = suggestions.lastmatch = NULL;
+ }
+}
+
+SuggItem *suggest_first() {
+ return suggestions.firstmatch;
+}
+
+SuggItem *suggest_last() {
+ return suggestions.lastmatch;
+}
+
+void set_suggest_text(Text *text) {
+ suggText = text;
+}
+
+void clear_suggest_text() {
+ free_suggestions();
+ suggText = NULL;
+}
+
+short is_suggest_active(Text *text) {
+ return suggText==text ? 1 : 0;
+}
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c
index 7c23c86d9ba..360c8fd7f04 100644
--- a/source/blender/python/BPY_interface.c
+++ b/source/blender/python/BPY_interface.c
@@ -1066,6 +1066,7 @@ int BPY_menu_do_python( short menutype, int event )
case PYMENU_RENDER:
case PYMENU_WIZARDS:
case PYMENU_SCRIPTTEMPLATE:
+ case PYMENU_TEXTPLUGIN:
case PYMENU_MESHFACEKEY:
break;
diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c
index 82da9edbee6..08691973a92 100644
--- a/source/blender/python/BPY_menus.c
+++ b/source/blender/python/BPY_menus.c
@@ -106,6 +106,8 @@ static int bpymenu_group_atoi( char *str )
return PYMENU_ARMATURE;
else if( !strcmp( str, "ScriptTemplate" ) )
return PYMENU_SCRIPTTEMPLATE;
+ else if( !strcmp( str, "TextPlugin" ) )
+ return PYMENU_TEXTPLUGIN;
else if( !strcmp( str, "MeshFaceKey" ) )
return PYMENU_MESHFACEKEY;
else if( !strcmp( str, "AddMesh" ) )
@@ -184,6 +186,9 @@ char *BPyMenu_group_itoa( short menugroup )
case PYMENU_SCRIPTTEMPLATE:
return "ScriptTemplate";
break;
+ case PYMENU_TEXTPLUGIN:
+ return "TextPlugin";
+ break;
case PYMENU_MESHFACEKEY:
return "MeshFaceKey";
break;
diff --git a/source/blender/python/BPY_menus.h b/source/blender/python/BPY_menus.h
index 1b557f79286..e8bca09d50e 100644
--- a/source/blender/python/BPY_menus.h
+++ b/source/blender/python/BPY_menus.h
@@ -99,6 +99,7 @@ typedef enum {
PYMENU_UVCALCULATION,
PYMENU_ARMATURE,
PYMENU_SCRIPTTEMPLATE,
+ PYMENU_TEXTPLUGIN,
PYMENU_HELP,/*Main Help menu items - prob best to leave for 'official' ones*/
PYMENU_HELPSYSTEM,/* Resources, troubleshooting, system tools */
PYMENU_HELPWEBSITES,/* Help -> Websites submenu */
diff --git a/source/blender/python/api2_2x/Text.c b/source/blender/python/api2_2x/Text.c
index 603deb768ad..63c77c0bb3e 100644
--- a/source/blender/python/api2_2x/Text.c
+++ b/source/blender/python/api2_2x/Text.c
@@ -34,8 +34,11 @@
#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 "gen_utils.h"
#include "gen_library.h"
@@ -96,6 +99,7 @@ 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_suggest( BPy_Text * self, PyObject * args );
/*****************************************************************************/
/* Python BPy_Text methods table: */
@@ -124,6 +128,8 @@ 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)"},
+ {"suggest", ( PyCFunction ) Text_suggest, METH_VARARGS,
+ "(list) - List of tuples of the form (name, type) where type is one of 'm', 'v', 'f' for module, variable and function respectively"},
{NULL, NULL, 0, NULL}
};
@@ -511,6 +517,57 @@ static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args )
Py_RETURN_NONE;
}
+static PyObject *Text_suggest( BPy_Text * self, PyObject * args )
+{
+ PyObject *item = NULL;
+ PyObject *list = NULL, *resl = NULL;
+ int list_len, i;
+ char *prefix, *name, type;
+ SpaceText *st;
+
+ if(!self->text)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "This object isn't linked to a Blender Text Object");
+
+ /* Parse args for a list of tuples */
+ if(!PyArg_ParseTuple(args, "O!s", &PyList_Type, &list, &prefix))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "expected list of tuples followed by a 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");
+
+ list_len = PyList_Size(list);
+ clear_suggest_text();
+
+ for (i = 0; i < list_len; i++) {
+ item = PyList_GetItem(list, i);
+ if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "list must contain only tuples of size 2" );
+
+ name = PyString_AsString(PyTuple_GetItem(item, 0));
+ type = PyString_AsString(PyTuple_GetItem(item, 1))[0];
+
+ if (!strlen(name) || (type!='m' && type!='v' && type!='f'))
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "layer values must be in the range [1, 20]" );
+
+ add_suggestion(name, type);
+ }
+ update_suggestions(prefix);
+ set_suggest_text(st->text);
+ scrarea_queue_redraw(curarea);
+
+ Py_RETURN_NONE;
+}
+
/*****************************************************************************/
/* Function: Text_compare */
/* Description: This is a callback function for the BPy_Text type. It */
diff --git a/source/blender/python/api2_2x/doc/Text.py b/source/blender/python/api2_2x/doc/Text.py
index 4099b13828d..920908eef81 100644
--- a/source/blender/python/api2_2x/doc/Text.py
+++ b/source/blender/python/api2_2x/doc/Text.py
@@ -150,5 +150,15 @@ class Text:
cursor.
"""
+ def suggest(list):
+ """
+ Set the suggestion list to the given list of tuples. This list *must* be
+ sorted by its first element, name.
+ @type list: list of tuples
+ @param list: List of pair-tuples of the form (name, type) where name is
+ the suggested name and type is one of 'm' (module or class), 'f'
+ (function or method), 'v' (variable).
+ """
+
import id_generics
-Text.__doc__ += id_generics.attributes \ No newline at end of file
+Text.__doc__ += id_generics.attributes
diff --git a/source/blender/src/drawtext.c b/source/blender/src/drawtext.c
index 882baa90c65..227d1f08c20 100644
--- a/source/blender/src/drawtext.c
+++ b/source/blender/src/drawtext.c
@@ -60,6 +60,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_suggestions.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -999,6 +1000,19 @@ static void do_selection(SpaceText *st, int selecting)
txt_undo_add_toop(st->text, UNDO_STO, sell, selc, linep2, charp2);
}
+void draw_suggestion_list(SpaceText *st) {
+ SuggItem *item, *last;
+
+ if (!is_suggest_active(st->text)) return;
+
+ for (item=suggest_first(), last=suggest_last(); item; item=item->next) {
+ /* Useful for testing but soon to be replaced by UI list */
+ printf("Suggest: %c %s\n", item->type, item->name);
+ if (item == last)
+ break;
+ }
+}
+
void drawtextspace(ScrArea *sa, void *spacedata)
{
SpaceText *st= curarea->spacedata.first;
@@ -1072,6 +1086,7 @@ void drawtextspace(ScrArea *sa, void *spacedata)
}
draw_textscroll(st);
+ draw_suggestion_list(st);
curarea->win_swap= WIN_BACK_OK;
}
diff --git a/source/blender/src/header_text.c b/source/blender/src/header_text.c
index 7f281096479..e371bd56160 100644
--- a/source/blender/src/header_text.c
+++ b/source/blender/src/header_text.c
@@ -240,6 +240,37 @@ static uiBlock *text_template_scriptsmenu (void *args_unused)
return block;
}
+static void do_text_plugin_scriptsmenu(void *arg, int event)
+{
+ BPY_menu_do_python(PYMENU_TEXTPLUGIN, event);
+
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static uiBlock *text_plugin_scriptsmenu (void *args_unused)
+{
+ uiBlock *block;
+ BPyMenu *pym;
+ int i= 0;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "text_plugin_scriptsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_text_plugin_scriptsmenu, NULL);
+
+ /* note that we acount for the N previous entries with i+20: */
+ 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);
+
+ return block;
+}
+
/* action executed after clicking in File menu */
static void do_text_filemenu(void *arg, int event)
{
@@ -726,6 +757,7 @@ static uiBlock *text_filemenu(void *arg_unused)
}
uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, text_plugin_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Text Plugins", 0, yco-=20, 120, 19, "");
if(curarea->headertype==HEADERTOP) {
uiBlockSetDirection(block, UI_DOWN);
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
index 6c0838288b8..2e55f8cdbc2 100644
--- a/source/blender/src/usiblender.c
+++ b/source/blender/src/usiblender.c
@@ -67,6 +67,7 @@
#include "DNA_sound_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_text_types.h"
#include "BKE_blender.h"
#include "BKE_curve.h"
@@ -79,6 +80,7 @@
#include "BKE_mball.h"
#include "BKE_node.h"
#include "BKE_packedFile.h"
+#include "BKE_suggestions.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_pointcache.h"
@@ -1091,6 +1093,7 @@ void exit_usiblender(void)
free_actcopybuf();
free_vertexpaint();
free_imagepaint();
+ free_suggestions();
/* editnurb can remain to exist outside editmode */
freeNurblist(&editNurb);