Text Editor (GSOC 2008)
======================= Merge of branch soc-2008-quorn to trunk: Merged 14970:16308 to trunk@16307, updated to HEAD. Merged 16318 Main features from this branch: - Python text plugins - Suggestions and documentation elements - Improved syntax highlighting - Word wrap - Additional editing tools - Various undo and clipboard fixes - File header info and modification checks
This commit is contained in:
commit
aa4e4da8c3
@ -917,8 +917,12 @@ GHOST_TUns8* GHOST_SystemWin32::getClipboard(int flag) const
|
||||
char *buffer;
|
||||
char *temp_buff;
|
||||
|
||||
if ( OpenClipboard(NULL) ) {
|
||||
if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) {
|
||||
HANDLE hData = GetClipboardData( CF_TEXT );
|
||||
if (hData == NULL) {
|
||||
CloseClipboard();
|
||||
return NULL;
|
||||
}
|
||||
buffer = (char*)GlobalLock( hData );
|
||||
|
||||
temp_buff = (char*) malloc(strlen(buffer)+1);
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 66 KiB |
814
release/scripts/bpymodules/BPyTextPlugin.py
Normal file
814
release/scripts/bpymodules/BPyTextPlugin.py
Normal file
@ -0,0 +1,814 @@
|
||||
"""The BPyTextPlugin Module
|
||||
|
||||
Use get_cached_descriptor(txt) to retrieve information about the script held in
|
||||
the txt Text object.
|
||||
|
||||
Use print_cache_for(txt) to print the information to the console.
|
||||
|
||||
Use line, cursor = current_line(txt) to get the logical line and cursor position
|
||||
|
||||
Use get_targets(line, cursor) to find out what precedes the cursor:
|
||||
aaa.bbb.cc|c.ddd -> ['aaa', 'bbb', 'cc']
|
||||
|
||||
Use resolve_targets(txt, targets) to turn a target list into a usable object if
|
||||
one is found to match.
|
||||
"""
|
||||
|
||||
import bpy, sys, os
|
||||
import __builtin__, tokenize
|
||||
from Blender.sys import time
|
||||
from tokenize import generate_tokens, TokenError, \
|
||||
COMMENT, DEDENT, INDENT, NAME, NEWLINE, NL, STRING, NUMBER
|
||||
|
||||
class Definition():
|
||||
"""Describes a definition or defined object through its name, line number
|
||||
and docstring. This is the base class for definition based descriptors.
|
||||
"""
|
||||
|
||||
def __init__(self, name, lineno, doc=''):
|
||||
self.name = name
|
||||
self.lineno = lineno
|
||||
self.doc = doc
|
||||
|
||||
class ScriptDesc():
|
||||
"""Describes a script through lists of further descriptor objects (classes,
|
||||
defs, vars) and dictionaries to built-in types (imports). If a script has
|
||||
not been fully parsed, its incomplete flag will be set. The time of the last
|
||||
parse is held by the time field and the name of the text object from which
|
||||
it was parsed, the name field.
|
||||
"""
|
||||
|
||||
def __init__(self, name, imports, classes, defs, vars, incomplete=False):
|
||||
self.name = name
|
||||
self.imports = imports
|
||||
self.classes = classes
|
||||
self.defs = defs
|
||||
self.vars = vars
|
||||
self.incomplete = incomplete
|
||||
self.parse_due = 0
|
||||
|
||||
def set_delay(self, delay):
|
||||
self.parse_due = time() + delay
|
||||
|
||||
class ClassDesc(Definition):
|
||||
"""Describes a class through lists of further descriptor objects (defs and
|
||||
vars). The name of the class is held by the name field and the line on
|
||||
which it is defined is held in lineno.
|
||||
"""
|
||||
|
||||
def __init__(self, name, parents, defs, vars, lineno, doc=''):
|
||||
Definition.__init__(self, name, lineno, doc)
|
||||
self.parents = parents
|
||||
self.defs = defs
|
||||
self.vars = vars
|
||||
|
||||
class FunctionDesc(Definition):
|
||||
"""Describes a function through its name and list of parameters (name,
|
||||
params) and the line on which it is defined (lineno).
|
||||
"""
|
||||
|
||||
def __init__(self, name, params, lineno, doc=''):
|
||||
Definition.__init__(self, name, lineno, doc)
|
||||
self.params = params
|
||||
|
||||
class VarDesc(Definition):
|
||||
"""Describes a variable through its name and type (if ascertainable) and the
|
||||
line on which it is defined (lineno). If no type can be determined, type
|
||||
will equal None.
|
||||
"""
|
||||
|
||||
def __init__(self, name, type, lineno):
|
||||
Definition.__init__(self, name, lineno)
|
||||
self.type = type # None for unknown (supports: dict/list/str)
|
||||
|
||||
# Context types
|
||||
CTX_UNSET = -1
|
||||
CTX_NORMAL = 0
|
||||
CTX_SINGLE_QUOTE = 1
|
||||
CTX_DOUBLE_QUOTE = 2
|
||||
CTX_COMMENT = 3
|
||||
|
||||
# Python keywords
|
||||
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' ]
|
||||
|
||||
# Module file extensions
|
||||
MODULE_EXTS = ['.py', '.pyc', '.pyo', '.pyw', '.pyd']
|
||||
|
||||
ModuleType = type(__builtin__)
|
||||
NoneScriptDesc = ScriptDesc('', dict(), dict(), dict(), dict(), True)
|
||||
|
||||
_modules = {}
|
||||
_modules_updated = 0
|
||||
_parse_cache = dict()
|
||||
|
||||
def _load_module_names():
|
||||
"""Searches the sys.path for module files and lists them, along with
|
||||
sys.builtin_module_names, in the global dict _modules.
|
||||
"""
|
||||
|
||||
global _modules
|
||||
|
||||
for n in sys.builtin_module_names:
|
||||
_modules[n] = None
|
||||
for p in sys.path:
|
||||
if p == '': p = os.curdir
|
||||
if not os.path.isdir(p): continue
|
||||
for f in os.listdir(p):
|
||||
for ext in MODULE_EXTS:
|
||||
if f.endswith(ext):
|
||||
_modules[f[:-len(ext)]] = None
|
||||
break
|
||||
|
||||
_load_module_names()
|
||||
|
||||
def _trim_doc(doc):
|
||||
"""Trims the quotes from a quoted STRING token (eg. "'''text'''" -> "text")
|
||||
"""
|
||||
|
||||
l = len(doc)
|
||||
i = 0
|
||||
while i < l/2 and (doc[i] == "'" or doc[i] == '"'):
|
||||
i += 1
|
||||
return doc[i:-i]
|
||||
|
||||
def resolve_targets(txt, targets):
|
||||
"""Attempts to return a useful object for the locally or externally defined
|
||||
entity described by targets. If the object is local (defined in txt), a
|
||||
Definition instance is returned. If the object is external (imported or
|
||||
built in), the object itself is returned. If no object can be found, None is
|
||||
returned.
|
||||
"""
|
||||
|
||||
count = len(targets)
|
||||
if count==0: return None
|
||||
|
||||
obj = None
|
||||
local = None
|
||||
i = 1
|
||||
|
||||
desc = get_cached_descriptor(txt)
|
||||
b = targets[0].find('(')
|
||||
if b==-1: b = None # Trick to let us use [:b] and get the whole string
|
||||
|
||||
if desc.classes.has_key(targets[0][:b]):
|
||||
local = desc.classes[targets[0][:b]]
|
||||
elif desc.defs.has_key(targets[0]):
|
||||
local = desc.defs[targets[0]]
|
||||
elif desc.vars.has_key(targets[0]):
|
||||
obj = desc.vars[targets[0]].type
|
||||
|
||||
if local:
|
||||
while i < count:
|
||||
b = targets[i].find('(')
|
||||
if b==-1: b = None
|
||||
if hasattr(local, 'classes') and local.classes.has_key(targets[i][:b]):
|
||||
local = local.classes[targets[i][:b]]
|
||||
elif hasattr(local, 'defs') and local.defs.has_key(targets[i]):
|
||||
local = local.defs[targets[i]]
|
||||
elif hasattr(local, 'vars') and local.vars.has_key(targets[i]):
|
||||
obj = local.vars[targets[i]].type
|
||||
local = None
|
||||
i += 1
|
||||
break
|
||||
else:
|
||||
local = None
|
||||
break
|
||||
i += 1
|
||||
|
||||
if local: return local
|
||||
|
||||
if not obj:
|
||||
if desc.imports.has_key(targets[0]):
|
||||
obj = desc.imports[targets[0]]
|
||||
else:
|
||||
builtins = get_builtins()
|
||||
if builtins.has_key(targets[0]):
|
||||
obj = builtins[targets[0]]
|
||||
|
||||
while obj and i < count:
|
||||
if hasattr(obj, targets[i]):
|
||||
obj = getattr(obj, targets[i])
|
||||
else:
|
||||
obj = None
|
||||
break
|
||||
i += 1
|
||||
|
||||
return obj
|
||||
|
||||
def get_cached_descriptor(txt, force_parse=0):
|
||||
"""Returns the cached ScriptDesc for the specified Text object 'txt'. If the
|
||||
script has not been parsed in the last 'period' seconds it will be reparsed
|
||||
to obtain this descriptor.
|
||||
|
||||
Specifying TP_AUTO for the period (default) will choose a period based on the
|
||||
size of the Text object. Larger texts are parsed less often.
|
||||
"""
|
||||
|
||||
global _parse_cache
|
||||
|
||||
parse = True
|
||||
key = hash(txt)
|
||||
if not force_parse and _parse_cache.has_key(key):
|
||||
desc = _parse_cache[key]
|
||||
if desc.parse_due > time():
|
||||
parse = desc.incomplete
|
||||
|
||||
if parse:
|
||||
desc = parse_text(txt)
|
||||
|
||||
return desc
|
||||
|
||||
def parse_text(txt):
|
||||
"""Parses an entire script's text and returns a ScriptDesc instance
|
||||
containing information about the script.
|
||||
|
||||
If the text is not a valid Python script (for example if brackets are left
|
||||
open), parsing may fail to complete. However, if this occurs, no exception
|
||||
is thrown. Instead the returned ScriptDesc instance will have its incomplete
|
||||
flag set and information processed up to this point will still be accessible.
|
||||
"""
|
||||
|
||||
start_time = time()
|
||||
txt.reset()
|
||||
tokens = generate_tokens(txt.readline) # Throws TokenError
|
||||
|
||||
curl, cursor = txt.getCursorPos()
|
||||
linen = curl + 1 # Token line numbers are one-based
|
||||
|
||||
imports = dict()
|
||||
imp_step = 0
|
||||
|
||||
classes = dict()
|
||||
cls_step = 0
|
||||
|
||||
defs = dict()
|
||||
def_step = 0
|
||||
|
||||
vars = dict()
|
||||
var1_step = 0
|
||||
var2_step = 0
|
||||
var3_step = 0
|
||||
var_accum = dict()
|
||||
var_forflag = False
|
||||
|
||||
indent = 0
|
||||
prev_type = -1
|
||||
prev_text = ''
|
||||
incomplete = False
|
||||
|
||||
while True:
|
||||
try:
|
||||
type, text, start, end, line = tokens.next()
|
||||
except StopIteration:
|
||||
break
|
||||
except (TokenError, IndentationError):
|
||||
incomplete = True
|
||||
break
|
||||
|
||||
# Skip all comments and line joining characters
|
||||
if type == COMMENT or type == NL:
|
||||
continue
|
||||
|
||||
#################
|
||||
## Indentation ##
|
||||
#################
|
||||
|
||||
if type == INDENT:
|
||||
indent += 1
|
||||
elif type == DEDENT:
|
||||
indent -= 1
|
||||
|
||||
#########################
|
||||
## Module importing... ##
|
||||
#########################
|
||||
|
||||
imp_store = False
|
||||
|
||||
# Default, look for 'from' or 'import' to start
|
||||
if imp_step == 0:
|
||||
if text == 'from':
|
||||
imp_tmp = []
|
||||
imp_step = 1
|
||||
elif text == 'import':
|
||||
imp_from = None
|
||||
imp_tmp = []
|
||||
imp_step = 2
|
||||
|
||||
# Found a 'from', create imp_from in form '???.???...'
|
||||
elif imp_step == 1:
|
||||
if text == 'import':
|
||||
imp_from = '.'.join(imp_tmp)
|
||||
imp_tmp = []
|
||||
imp_step = 2
|
||||
elif type == NAME:
|
||||
imp_tmp.append(text)
|
||||
elif text != '.':
|
||||
imp_step = 0 # Invalid syntax
|
||||
|
||||
# Found 'import', imp_from is populated or None, create imp_name
|
||||
elif imp_step == 2:
|
||||
if text == 'as':
|
||||
imp_name = '.'.join(imp_tmp)
|
||||
imp_step = 3
|
||||
elif type == NAME or text == '*':
|
||||
imp_tmp.append(text)
|
||||
elif text != '.':
|
||||
imp_name = '.'.join(imp_tmp)
|
||||
imp_symb = imp_name
|
||||
imp_store = True
|
||||
|
||||
# Found 'as', change imp_symb to this value and go back to step 2
|
||||
elif imp_step == 3:
|
||||
if type == NAME:
|
||||
imp_symb = text
|
||||
else:
|
||||
imp_store = True
|
||||
|
||||
# Both imp_name and imp_symb have now been populated so we can import
|
||||
if imp_store:
|
||||
|
||||
# Handle special case of 'import *'
|
||||
if imp_name == '*':
|
||||
parent = get_module(imp_from)
|
||||
imports.update(parent.__dict__)
|
||||
|
||||
else:
|
||||
# Try importing the name as a module
|
||||
try:
|
||||
if imp_from:
|
||||
module = get_module(imp_from +'.'+ imp_name)
|
||||
else:
|
||||
module = get_module(imp_name)
|
||||
except (ImportError, ValueError, AttributeError, TypeError):
|
||||
# Try importing name as an attribute of the parent
|
||||
try:
|
||||
module = __import__(imp_from, globals(), locals(), [imp_name])
|
||||
imports[imp_symb] = getattr(module, imp_name)
|
||||
except (ImportError, ValueError, AttributeError, TypeError):
|
||||
pass
|
||||
else:
|
||||
imports[imp_symb] = module
|
||||
|
||||
# More to import from the same module?
|
||||
if text == ',':
|
||||
imp_tmp = []
|
||||
imp_step = 2
|
||||
else:
|
||||
imp_step = 0
|
||||
|
||||
###################
|
||||
## Class parsing ##
|
||||
###################
|
||||
|
||||
# If we are inside a class then def and variable parsing should be done
|
||||
# for the class. Otherwise the definitions are considered global
|
||||
|
||||
# Look for 'class'
|
||||
if cls_step == 0:
|
||||
if text == 'class':
|
||||
cls_name = None
|
||||
cls_lineno = start[0]
|
||||
cls_indent = indent
|
||||
cls_step = 1
|
||||
|
||||
# Found 'class', look for cls_name followed by '(' parents ')'
|
||||
elif cls_step == 1:
|
||||
if not cls_name:
|
||||
if type == NAME:
|
||||
cls_name = text
|
||||
cls_sline = False
|
||||
cls_parents = dict()
|
||||
cls_defs = dict()
|
||||
cls_vars = dict()
|
||||
elif type == NAME:
|
||||
if classes.has_key(text):
|
||||
parent = classes[text]
|
||||
cls_parents[text] = parent
|
||||
cls_defs.update(parent.defs)
|
||||
cls_vars.update(parent.vars)
|
||||
elif text == ':':
|
||||
cls_step = 2
|
||||
|
||||
# Found 'class' name ... ':', now check if it's a single line statement
|
||||
elif cls_step == 2:
|
||||
if type == NEWLINE:
|
||||
cls_sline = False
|
||||
else:
|
||||
cls_sline = True
|
||||
cls_doc = ''
|
||||
cls_step = 3
|
||||
|
||||
elif cls_step == 3:
|
||||
if not cls_doc and type == STRING:
|
||||
cls_doc = _trim_doc(text)
|
||||
if cls_sline:
|
||||
if type == NEWLINE:
|
||||
classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
|
||||
cls_step = 0
|
||||
else:
|
||||
if type == DEDENT and indent <= cls_indent:
|
||||
classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
|
||||
cls_step = 0
|
||||
|
||||
#################
|
||||
## Def parsing ##
|
||||
#################
|
||||
|
||||
# Look for 'def'
|
||||
if def_step == 0:
|
||||
if text == 'def':
|
||||
def_name = None
|
||||
def_lineno = start[0]
|
||||
def_step = 1
|
||||
|
||||
# Found 'def', look for def_name followed by '('
|
||||
elif def_step == 1:
|
||||
if type == NAME:
|
||||
def_name = text
|
||||
def_params = []
|
||||
elif def_name and text == '(':
|
||||
def_step = 2
|
||||
|
||||
# Found 'def' name '(', now identify the parameters upto ')'
|
||||
# TODO: Handle ellipsis '...'
|
||||
elif def_step == 2:
|
||||
if type == NAME:
|
||||
def_params.append(text)
|
||||
elif text == ':':
|
||||
def_step = 3
|
||||
|
||||
# Found 'def' ... ':', now check if it's a single line statement
|
||||
elif def_step == 3:
|
||||
if type == NEWLINE:
|
||||
def_sline = False
|
||||
else:
|
||||
def_sline = True
|
||||
def_doc = ''
|
||||
def_step = 4
|
||||
|
||||
elif def_step == 4:
|
||||
if type == STRING:
|
||||
def_doc = _trim_doc(text)
|
||||
newdef = None
|
||||
if def_sline:
|
||||
if type == NEWLINE:
|
||||
newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
|
||||
else:
|
||||
if type == NAME:
|
||||
newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
|
||||
if newdef:
|
||||
if cls_step > 0: # Parsing a class
|
||||
cls_defs[def_name] = newdef
|
||||
else:
|
||||
defs[def_name] = newdef
|
||||
def_step = 0
|
||||
|
||||
##########################
|
||||
## Variable assignation ##
|
||||
##########################
|
||||
|
||||
if cls_step > 0: # Parsing a class
|
||||
# Look for 'self.???'
|
||||
if var1_step == 0:
|
||||
if text == 'self':
|
||||
var1_step = 1
|
||||
elif var1_step == 1:
|
||||
if text == '.':
|
||||
var_name = None
|
||||
var1_step = 2
|
||||
else:
|
||||
var1_step = 0
|
||||
elif var1_step == 2:
|
||||
if type == NAME:
|
||||
var_name = text
|
||||
if cls_vars.has_key(var_name):
|
||||
var_step = 0
|
||||
else:
|
||||
var1_step = 3
|
||||
elif var1_step == 3:
|
||||
if text == '=':
|
||||
var1_step = 4
|
||||
elif text != ',':
|
||||
var1_step = 0
|
||||
elif var1_step == 4:
|
||||
var_type = None
|
||||
if type == NUMBER:
|
||||
close = end[1]
|
||||
if text.find('.') != -1: var_type = float
|
||||
else: var_type = int
|
||||
elif type == STRING:
|
||||
close = end[1]
|
||||
var_type = str
|
||||
elif text == '[':
|
||||
close = line.find(']', end[1])
|
||||
var_type = list
|
||||
elif text == '(':
|
||||
close = line.find(')', end[1])
|
||||
var_type = tuple
|
||||
elif text == '{':
|
||||
close = line.find('}', end[1])
|
||||
var_type = dict
|
||||
elif text == 'dict':
|
||||
close = line.find(')', end[1])
|
||||
var_type = dict
|
||||
if var_type and close+1 < len(line):
|
||||
if line[close+1] != ' ' and line[close+1] != '\t':
|
||||
var_type = None
|
||||
cls_vars[var_name] = VarDesc(var_name, var_type, start[0])
|
||||
var1_step = 0
|
||||
|
||||
elif def_step > 0: # Parsing a def
|
||||
# Look for 'global ???[,???]'
|
||||
if var2_step == 0:
|
||||
if text == 'global':
|
||||
var2_step = 1
|
||||
elif var2_step == 1:
|
||||
if type == NAME:
|
||||
if not vars.has_key(text):
|
||||
vars[text] = VarDesc(text, None, start[0])
|
||||
elif text != ',' and type != NL:
|
||||
var2_step == 0
|
||||
|
||||
else: # In global scope
|
||||
if var3_step == 0:
|
||||
# Look for names
|
||||
if text == 'for':
|
||||
var_accum = dict()
|
||||
var_forflag = True
|
||||
elif text == '=' or (var_forflag and text == 'in'):
|
||||
var_forflag = False
|
||||
var3_step = 1
|
||||
elif type == NAME:
|
||||
if prev_text != '.' and not vars.has_key(text):
|
||||
var_accum[text] = VarDesc(text, None, start[0])
|
||||
elif not text in [',', '(', ')', '[', ']']:
|
||||
var_accum = dict()
|
||||
var_forflag = False
|
||||
elif var3_step == 1:
|
||||
if len(var_accum) != 1:
|
||||
var_type = None
|
||||
vars.update(var_accum)
|
||||
else:
|
||||
var_name = var_accum.keys()[0]
|
||||
var_type = None
|
||||
if type == NUMBER:
|
||||
if text.find('.') != -1: var_type = float
|
||||
else: var_type = int
|
||||
elif type == STRING: var_type = str
|
||||
elif text == '[': var_type = list
|
||||
elif text == '(': var_type = tuple
|
||||
elif text == '{': var_type = dict
|
||||
vars[var_name] = VarDesc(var_name, var_type, start[0])
|
||||
var3_step = 0
|
||||
|
||||
#######################
|
||||
## General utilities ##
|
||||
#######################
|
||||
|
||||
prev_type = type
|
||||
prev_text = text
|
||||
|
||||
desc = ScriptDesc(txt.name, imports, classes, defs, vars, incomplete)
|
||||
desc.set_delay(10 * (time()-start_time) + 0.05)
|
||||
|
||||
global _parse_cache
|
||||
_parse_cache[hash(txt)] = desc
|
||||
return desc
|
||||
|
||||
def get_modules(since=1):
|
||||
"""Returns the set of built-in modules and any modules that have been
|
||||
imported into the system upto 'since' seconds ago.
|
||||
"""
|
||||
|
||||
global _modules, _modules_updated
|
||||
|
||||
t = time()
|
||||
if _modules_updated < t - since:
|
||||
_modules.update(sys.modules)
|
||||
_modules_updated = t
|
||||
return _modules.keys()
|
||||
|
||||
def suggest_cmp(x, y):
|
||||
"""Use this method when sorting a list of suggestions.
|
||||
"""
|
||||
|
||||
return cmp(x[0].upper(), y[0].upper())
|
||||
|
||||
def get_module(name):
|
||||
"""Returns the module specified by its name. The module itself is imported
|
||||
by this method and, as such, any initialization code will be executed.
|
||||
"""
|
||||
|
||||
mod = __import__(name)
|
||||
components = name.split('.')
|
||||
for comp in components[1:]:
|
||||
mod = getattr(mod, comp)
|
||||
return mod
|
||||
|
||||
def type_char(v):
|
||||
"""Returns the character used to signify the type of a variable. Use this
|
||||
method to identify the type character for an item in a suggestion list.
|
||||
|
||||
The following values are returned:
|
||||
'm' if the parameter is a module
|
||||
'f' if the parameter is callable
|
||||
'v' if the parameter is variable or otherwise indeterminable
|
||||
|
||||
"""
|
||||
|
||||
if isinstance(v, ModuleType):
|
||||
return 'm'
|
||||
elif callable(v):
|
||||
return 'f'
|
||||
else:
|
||||
return 'v'
|
||||
|
||||
def get_context(txt):
|
||||
"""Establishes the context of the cursor in the given Blender Text object
|
||||
|
||||
Returns one of:
|
||||
CTX_NORMAL - Cursor is in a normal context
|
||||
CTX_SINGLE_QUOTE - Cursor is inside a single quoted string
|
||||
CTX_DOUBLE_QUOTE - Cursor is inside a double quoted string
|
||||
CTX_COMMENT - Cursor is inside a comment
|
||||
|
||||
"""
|
||||
|
||||
l, cursor = txt.getCursorPos()
|
||||
lines = txt.asLines(0, l+1)
|
||||
|
||||
# FIXME: This method is too slow in large files for it to be called as often
|
||||
# as it is. So for lines below the 1000th line we do this... (quorn)
|
||||
if l > 1000: return CTX_NORMAL
|
||||
|
||||
# Detect context (in string or comment)
|
||||
in_str = CTX_NORMAL
|
||||
for line in lines:
|
||||
if l == 0:
|
||||
end = cursor
|
||||
else:
|
||||
end = len(line)
|
||||
l -= 1
|
||||
|
||||
# Comments end at new lines
|
||||
if in_str == CTX_COMMENT:
|
||||
in_str = CTX_NORMAL
|
||||
|
||||
for i in range(end):
|
||||
if in_str == 0:
|
||||
if line[i] == "'": in_str = CTX_SINGLE_QUOTE
|
||||
elif line[i] == '"': in_str = CTX_DOUBLE_QUOTE
|
||||
elif line[i] == '#': in_str = CTX_COMMENT
|
||||
else:
|
||||
if in_str == CTX_SINGLE_QUOTE:
|
||||
if line[i] == "'":
|
||||
in_str = CTX_NORMAL
|
||||
# In again if ' escaped, out again if \ escaped, and so on
|
||||
for a in range(i-1, -1, -1):
|
||||
if line[a] == '\\': in_str = 1-in_str
|
||||
else: break
|
||||
elif in_str == CTX_DOUBLE_QUOTE:
|
||||
if line[i] == '"':
|
||||
in_str = CTX_NORMAL
|
||||
# In again if " escaped, out again if \ escaped, and so on
|
||||
for a in range(i-1, -1, -1):
|
||||
if line[i-a] == '\\': in_str = 2-in_str
|
||||
else: break
|
||||
|
||||
return in_str
|
||||
|
||||
def current_line(txt):
|
||||
"""Extracts the Python script line at the cursor in the Blender Text object
|
||||
provided and cursor position within this line as the tuple pair (line,
|
||||
cursor).
|
||||
"""
|
||||
|
||||
lineindex, cursor = txt.getCursorPos()
|
||||
lines = txt.asLines()
|
||||
line = lines[lineindex]
|
||||
|
||||
# Join previous lines to this line if spanning
|
||||
i = lineindex - 1
|
||||
while i > 0:
|
||||
earlier = lines[i].rstrip()
|
||||
if earlier.endswith('\\'):
|
||||
line = earlier[:-1] + ' ' + line
|
||||
cursor += len(earlier)
|
||||
i -= 1
|
||||
|
||||
# Join later lines while there is an explicit joining character
|
||||
i = lineindex
|
||||
while i < len(lines)-1 and lines[i].rstrip().endswith('\\'):
|
||||
later = lines[i+1].strip()
|
||||
line = line + ' ' + later[:-1]
|
||||
i += 1
|
||||
|
||||
return line, cursor
|
||||
|
||||
def get_targets(line, cursor):
|
||||
"""Parses a period separated string of valid names preceding the cursor and
|
||||
returns them as a list in the same order.
|
||||
"""
|
||||
|
||||
brk = 0
|
||||
targets = []
|
||||
j = cursor
|
||||
i = j-1
|
||||
while i >= 0:
|
||||
if line[i] == ')': brk += 1
|
||||
elif brk:
|
||||
if line[i] == '(': brk -= 1
|
||||
else:
|
||||
if line[i] == '.':
|
||||
targets.insert(0, line[i+1:j]); j=i
|
||||
elif not (line[i].isalnum() or line[i] == '_' or line[i] == '.'):
|
||||
break
|
||||
i -= 1
|
||||
targets.insert(0, line[i+1:j])
|
||||
return targets
|
||||
|
||||
def get_defs(txt):
|
||||
"""Returns a dictionary which maps definition names in the source code to
|
||||
a list of their parameter names.
|
||||
|
||||
The line 'def doit(one, two, three): print one' for example, results in the
|
||||
mapping 'doit' : [ 'one', 'two', 'three' ]
|
||||
"""
|
||||
|
||||
return get_cached_descriptor(txt).defs
|
||||
|
||||
def get_vars(txt):
|
||||
"""Returns a dictionary of variable names found in the specified Text
|
||||
object. This method locates all names followed directly by an equal sign:
|
||||
'a = ???' or indirectly as part of a tuple/list assignment or inside a
|
||||
'for ??? in ???:' block.
|
||||
"""
|
||||
|
||||
return get_cached_descriptor(txt).vars
|
||||
|
||||
def get_imports(txt):
|
||||
"""Returns a dictionary which maps symbol names in the source code to their
|
||||
respective modules.
|
||||
|
||||
The line 'from Blender import Text as BText' for example, results in the
|
||||
mapping 'BText' : <module 'Blender.Text' (built-in)>
|
||||
|
||||
Note that this method imports the modules to provide this mapping as as such
|
||||
will execute any initilization code found within.
|
||||
"""
|
||||
|
||||
return get_cached_descriptor(txt).imports
|
||||
|
||||
def get_builtins():
|
||||
"""Returns a dictionary of built-in modules, functions and variables."""
|
||||
|
||||
return __builtin__.__dict__
|
||||
|
||||
|
||||
#################################
|
||||
## Debugging utility functions ##
|
||||
#################################
|
||||
|
||||
def print_cache_for(txt, period=sys.maxint):
|
||||
"""Prints out the data cached for a given Text object. If no period is
|
||||
given the text will not be reparsed and the cached version will be returned.
|
||||
Otherwise if the period has expired the text will be reparsed.
|
||||
"""
|
||||
|
||||
desc = get_cached_descriptor(txt, period)
|
||||
print '================================================'
|
||||
print 'Name:', desc.name, '('+str(hash(txt))+')'
|
||||
print '------------------------------------------------'
|
||||
print 'Defs:'
|
||||
for name, ddesc in desc.defs.items():
|
||||
print ' ', name, ddesc.params, ddesc.lineno
|
||||
print ' ', ddesc.doc
|
||||
print '------------------------------------------------'
|
||||
print 'Vars:'
|
||||
for name, vdesc in desc.vars.items():
|
||||
print ' ', name, vdesc.type, vdesc.lineno
|
||||
print '------------------------------------------------'
|
||||
print 'Imports:'
|
||||
for name, item in desc.imports.items():
|
||||
print ' ', name.ljust(15), item
|
||||
print '------------------------------------------------'
|
||||
print 'Classes:'
|
||||
for clsnme, clsdsc in desc.classes.items():
|
||||
print ' *********************************'
|
||||
print ' Name:', clsnme
|
||||
print ' ', clsdsc.doc
|
||||
print ' ---------------------------------'
|
||||
print ' Defs:'
|
||||
for name, ddesc in clsdsc.defs.items():
|
||||
print ' ', name, ddesc.params, ddesc.lineno
|
||||
print ' ', ddesc.doc
|
||||
print ' ---------------------------------'
|
||||
print ' Vars:'
|
||||
for name, vdesc in clsdsc.vars.items():
|
||||
print ' ', name, vdesc.type, vdesc.lineno
|
||||
print ' *********************************'
|
||||
print '================================================'
|
69
release/scripts/scripttemplate_text_plugin.py
Normal file
69
release/scripts/scripttemplate_text_plugin.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Text Plugin'
|
||||
Blender: 246
|
||||
Group: 'ScriptTemplate'
|
||||
Tooltip: 'Add a new text for writing a text plugin'
|
||||
"""
|
||||
|
||||
from Blender import Window
|
||||
import bpy
|
||||
|
||||
script_data = \
|
||||
'''#!BPY
|
||||
"""
|
||||
Name: 'My Plugin Script'
|
||||
Blender: 246
|
||||
Group: 'TextPlugin'
|
||||
Shortcut: 'Ctrl+Alt+U'
|
||||
Tooltip: 'Put some useful info here'
|
||||
"""
|
||||
|
||||
# Add a licence here if you wish to re-distribute, we recommend the GPL
|
||||
|
||||
from Blender import Window, sys
|
||||
import BPyTextPlugin, bpy
|
||||
|
||||
def my_script_util(txt):
|
||||
# This function prints out statistical information about a script
|
||||
|
||||
desc = BPyTextPlugin.get_cached_descriptor(txt)
|
||||
print '---------------------------------------'
|
||||
print 'Script Name:', desc.name
|
||||
print 'Classes:', len(desc.classes)
|
||||
print ' ', desc.classes.keys()
|
||||
print 'Functions:', len(desc.defs)
|
||||
print ' ', desc.defs.keys()
|
||||
print 'Variables:', len(desc.vars)
|
||||
print ' ', desc.vars.keys()
|
||||
|
||||
def main():
|
||||
|
||||
# Gets the active text object, there can be many in one blend file.
|
||||
txt = bpy.data.texts.active
|
||||
|
||||
# Silently return if the script has been run with no active text
|
||||
if not txt:
|
||||
return
|
||||
|
||||
# Text plug-ins should run quickly so we time it here
|
||||
Window.WaitCursor(1)
|
||||
t = sys.time()
|
||||
|
||||
# Run our utility function
|
||||
my_script_util(txt)
|
||||
|
||||
# Timing the script is a good way to be aware on any speed hits when scripting
|
||||
print 'Plugin script finished in %.2f seconds' % (sys.time()-t)
|
||||
Window.WaitCursor(0)
|
||||
|
||||
|
||||
# This lets you import the script without running it
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
'''
|
||||
|
||||
new_text = bpy.data.texts.new('textplugin_template.py')
|
||||
new_text.write(script_data)
|
||||
bpy.data.texts.active = new_text
|
||||
Window.RedrawAll()
|
64
release/scripts/textplugin_functiondocs.py
Normal file
64
release/scripts/textplugin_functiondocs.py
Normal file
@ -0,0 +1,64 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Function Documentation | Ctrl I'
|
||||
Blender: 246
|
||||
Group: 'TextPlugin'
|
||||
Shortcut: 'Ctrl+I'
|
||||
Tooltip: 'Attempts to display documentation about the function preceding the cursor.'
|
||||
"""
|
||||
|
||||
# Only run if we have the required modules
|
||||
try:
|
||||
import bpy
|
||||
from BPyTextPlugin import *
|
||||
except ImportError:
|
||||
OK = False
|
||||
else:
|
||||
OK = True
|
||||
|
||||
def main():
|
||||
txt = bpy.data.texts.active
|
||||
if not txt:
|
||||
return
|
||||
|
||||
(line, c) = current_line(txt)
|
||||
|
||||
# Check we are in a normal context
|
||||
if get_context(txt) != CTX_NORMAL:
|
||||
return
|
||||
|
||||
# Identify the name under the cursor
|
||||
llen = len(line)
|
||||
while c<llen and (line[c].isalnum() or line[c]=='_'):
|
||||
c += 1
|
||||
|
||||
targets = get_targets(line, c)
|
||||
|
||||
# If no name under cursor, look backward to see if we're in function parens
|
||||
if len(targets) == 0 or targets[0] == '':
|
||||
# Look backwards for first '(' without ')'
|
||||
b = 0
|
||||
found = False
|
||||
for i in range(c-1, -1, -1):
|
||||
if line[i] == ')': b += 1
|
||||
elif line[i] == '(':
|
||||
b -= 1
|
||||
if b < 0:
|
||||
found = True
|
||||
c = i
|
||||
break
|
||||
if found: targets = get_targets(line, c)
|
||||
if len(targets) == 0 or targets[0] == '':
|
||||
return
|
||||
|
||||
obj = resolve_targets(txt, targets)
|
||||
if not obj: return
|
||||
|
||||
if isinstance(obj, Definition): # Local definition
|
||||
txt.showDocs(obj.doc)
|
||||
elif hasattr(obj, '__doc__') and obj.__doc__:
|
||||
txt.showDocs(obj.__doc__)
|
||||
|
||||
# Check we are running as a script and not imported as a module
|
||||
if __name__ == "__main__" and OK:
|
||||
main()
|
91
release/scripts/textplugin_imports.py
Normal file
91
release/scripts/textplugin_imports.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Import Complete|Space'
|
||||
Blender: 246
|
||||
Group: 'TextPlugin'
|
||||
Shortcut: 'Space'
|
||||
Tooltip: 'Lists modules when import or from is typed'
|
||||
"""
|
||||
|
||||
# Only run if we have the required modules
|
||||
try:
|
||||
import bpy, sys
|
||||
from BPyTextPlugin import *
|
||||
except ImportError:
|
||||
OK = False
|
||||
else:
|
||||
OK = True
|
||||
|
||||
def main():
|
||||
txt = bpy.data.texts.active
|
||||
if not txt:
|
||||
return
|
||||
|
||||
line, c = current_line(txt)
|
||||
|
||||
# Check we are in a normal context
|
||||
if get_context(txt) != CTX_NORMAL:
|
||||
return
|
||||
|
||||
pos = line.rfind('from ', 0, c)
|
||||
|
||||
# No 'from' found
|
||||
if pos == -1:
|
||||
# Check instead for straight 'import xxxx'
|
||||
pos2 = line.rfind('import ', 0, c)
|
||||
if pos2 != -1:
|
||||
pos2 += 7
|
||||
for i in range(pos2, c):
|
||||
if line[i]==',' or (line[i]==' ' and line[i-1]==','):
|
||||
pos2 = i+1
|
||||
elif not line[i].isalnum() and line[i] != '_':
|
||||
return
|
||||
items = [(m, 'm') for m in get_modules()]
|
||||
items.sort(cmp = suggest_cmp)
|
||||
txt.suggest(items, line[pos2:c].strip())
|
||||
return
|
||||
|
||||
# Found 'from xxxxx' before cursor
|
||||
immediate = True
|
||||
pos += 5
|
||||
for i in range(pos, c):
|
||||
if not line[i].isalnum() and line[i] != '_' and line[i] != '.':
|
||||
immediate = False
|
||||
break
|
||||
|
||||
# Immediate 'from' followed by at most a module name
|
||||
if immediate:
|
||||
items = [(m, 'm') for m in get_modules()]
|
||||
items.sort(cmp = suggest_cmp)
|
||||
txt.suggest(items, line[pos:c])
|
||||
return
|
||||
|
||||
# Found 'from' earlier, suggest import if not already there
|
||||
pos2 = line.rfind('import ', pos, c)
|
||||
|
||||
# No 'import' found after 'from' so suggest it
|
||||
if pos2 == -1:
|
||||
txt.suggest([('import', 'k')], '')
|
||||
return
|
||||
|
||||
# Immediate 'import' before cursor and after 'from...'
|
||||
for i in range(pos2+7, c):
|
||||
if line[i]==',' or (line[i]==' ' and line[i-1]==','):
|
||||
pass
|
||||
elif not line[i].isalnum() and line[i] != '_':
|
||||
return
|
||||
between = line[pos:pos2-1].strip()
|
||||
try:
|
||||
mod = get_module(between)
|
||||
except ImportError:
|
||||
return
|
||||
|
||||
items = [('*', 'k')]
|
||||
for (k,v) in mod.__dict__.items():
|
||||
items.append((k, type_char(v)))
|
||||
items.sort(cmp = suggest_cmp)
|
||||
txt.suggest(items, '')
|
||||
|
||||
# Check we are running as a script and not imported as a module
|
||||
if __name__ == "__main__" and OK:
|
||||
main()
|
90
release/scripts/textplugin_membersuggest.py
Normal file
90
release/scripts/textplugin_membersuggest.py
Normal file
@ -0,0 +1,90 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Member Suggest | .'
|
||||
Blender: 246
|
||||
Group: 'TextPlugin'
|
||||
Shortcut: 'Period'
|
||||
Tooltip: 'Lists members of the object preceding the cursor in the current text space'
|
||||
"""
|
||||
|
||||
# Only run if we have the required modules
|
||||
try:
|
||||
import bpy
|
||||
from BPyTextPlugin import *
|
||||
except ImportError:
|
||||
OK = False
|
||||
else:
|
||||
OK = True
|
||||
|
||||
def main():
|
||||
txt = bpy.data.texts.active
|
||||
if not txt:
|
||||
return
|
||||
|
||||
(line, c) = current_line(txt)
|
||||
|
||||
# Check we are in a normal context
|
||||
if get_context(txt) != CTX_NORMAL:
|
||||
return
|
||||
|
||||
targets = get_targets(line, c)
|
||||
|
||||
if targets[0] == '': # Check if we are looking at a constant [] {} '' etc.
|
||||
i = c - len('.'.join(targets)) - 1
|
||||
if i >= 0:
|
||||
if line[i] == '"' or line[i] == "'":
|
||||
targets[0] = 'str'
|
||||
elif line[i] == '}':
|
||||
targets[0] = 'dict'
|
||||
elif line[i] == ']': # Could be array elem x[y] or list [y]
|
||||
i = line.rfind('[', 0, i) - 1
|
||||
while i >= 0:
|
||||
if line[i].isalnum() or line[i] == '_':
|
||||
break
|
||||
elif line[i] != ' ' and line[i] != '\t':
|
||||
i = -1
|
||||
break
|
||||
i -= 1
|
||||
if i < 0:
|
||||
targets[0] = 'list'
|
||||
|
||||
obj = resolve_targets(txt, targets[:-1])
|
||||
if not obj:
|
||||
return
|
||||
|
||||
items = []
|
||||
|
||||
if isinstance(obj, VarDesc):
|
||||
obj = obj.type
|
||||
|
||||
if isinstance(obj, Definition): # Locally defined
|
||||
if hasattr(obj, 'classes'):
|
||||
items.extend([(s, 'f') for s in obj.classes.keys()])
|
||||
if hasattr(obj, 'defs'):
|
||||
items.extend([(s, 'f') for s in obj.defs.keys()])
|
||||
if hasattr(obj, 'vars'):
|
||||
items.extend([(s, 'v') for s in obj.vars.keys()])
|
||||
|
||||
else: # Otherwise we have an imported or builtin object
|
||||
try:
|
||||
attr = obj.__dict__.keys()
|
||||
except AttributeError:
|
||||
attr = dir(obj)
|
||||
else:
|
||||
if not attr: attr = dir(obj)
|
||||
|
||||
for k in attr:
|
||||
try:
|
||||
v = getattr(obj, k)
|
||||
except (AttributeError, TypeError): # Some attributes are not readable
|
||||
pass
|
||||
else:
|
||||
items.append((k, type_char(v)))
|
||||
|
||||
if items != []:
|
||||
items.sort(cmp = suggest_cmp)
|
||||
txt.suggest(items, targets[-1])
|
||||
|
||||
# Check we are running as a script and not imported as a module
|
||||
if __name__ == "__main__" and OK:
|
||||
main()
|
142
release/scripts/textplugin_outliner.py
Normal file
142
release/scripts/textplugin_outliner.py
Normal file
@ -0,0 +1,142 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Code Outline | Ctrl T'
|
||||
Blender: 246
|
||||
Group: 'TextPlugin'
|
||||
Shortcut: 'Ctrl+T'
|
||||
Tooltip: 'Provides a menu for jumping to class and functions definitions.'
|
||||
"""
|
||||
|
||||
# Only run if we have the required modules
|
||||
try:
|
||||
import bpy
|
||||
from BPyTextPlugin import *
|
||||
from Blender import Draw
|
||||
except ImportError:
|
||||
OK = False
|
||||
else:
|
||||
OK = True
|
||||
|
||||
def make_menu(items, eventoffs):
|
||||
n = len(items)
|
||||
if n < 20:
|
||||
return [(items[i], i+1+eventoffs) for i in range(len(items))]
|
||||
|
||||
letters = []
|
||||
check = 'abcdefghijklmnopqrstuvwxyz_' # Names cannot start 0-9
|
||||
for c in check:
|
||||
for item in items:
|
||||
if item[0].lower() == c:
|
||||
letters.append(c)
|
||||
break
|
||||
|
||||
entries = {}
|
||||
i = 0
|
||||
for item in items:
|
||||
i += 1
|
||||
c = item[0].lower()
|
||||
entries.setdefault(c, []).append((item, i+eventoffs))
|
||||
|
||||
subs = []
|
||||
for c in letters:
|
||||
subs.append((c, entries[c]))
|
||||
|
||||
return subs
|
||||
|
||||
def find_word(txt, word):
|
||||
i = 0
|
||||
txt.reset()
|
||||
while True:
|
||||
try:
|
||||
line = txt.readline()
|
||||
except StopIteration:
|
||||
break
|
||||
c = line.find(word)
|
||||
if c != -1:
|
||||
txt.setCursorPos(i, c)
|
||||
break
|
||||
i += 1
|
||||
|
||||
def main():
|
||||
txt = bpy.data.texts.active
|
||||
if not txt:
|
||||
return
|
||||
|
||||
# Identify word under cursor
|
||||
if get_context(txt) == CTX_NORMAL:
|
||||
line, c = current_line(txt)
|
||||
start = c-1
|
||||
end = c
|
||||
while start >= 0:
|
||||
if not line[start].lower() in 'abcdefghijklmnopqrstuvwxyz0123456789_':
|
||||
break
|
||||
start -= 1
|
||||
while end < len(line):
|
||||
if not line[end].lower() in 'abcdefghijklmnopqrstuvwxyz0123456789_':
|
||||
break
|
||||
end += 1
|
||||
word = line[start+1:end]
|
||||
if word in KEYWORDS:
|
||||
word = None
|
||||
else:
|
||||
word = None
|
||||
|
||||
script = get_cached_descriptor(txt)
|
||||
items = []
|
||||
desc = None
|
||||
|
||||
tmp = script.classes.keys()
|
||||
tmp.sort(cmp = suggest_cmp)
|
||||
class_menu = make_menu(tmp, len(items))
|
||||
class_menu_length = len(tmp)
|
||||
items.extend(tmp)
|
||||
|
||||
tmp = script.defs.keys()
|
||||
tmp.sort(cmp = suggest_cmp)
|
||||
defs_menu = make_menu(tmp, len(items))
|
||||
defs_menu_length = len(tmp)
|
||||
items.extend(tmp)
|
||||
|
||||
tmp = script.vars.keys()
|
||||
tmp.sort(cmp = suggest_cmp)
|
||||
vars_menu = make_menu(tmp, len(items))
|
||||
vars_menu_length = len(tmp)
|
||||
items.extend(tmp)
|
||||
|
||||
menu = [('Script %t', 0),
|
||||
('Classes', class_menu),
|
||||
('Functions', defs_menu),
|
||||
('Variables', vars_menu)]
|
||||
if word:
|
||||
menu.extend([None, ('Locate', [(word, -10)])])
|
||||
|
||||
i = Draw.PupTreeMenu(menu)
|
||||
if i == -1:
|
||||
return
|
||||
|
||||
# Chosen to search for word under cursor
|
||||
if i == -10:
|
||||
if script.classes.has_key(word):
|
||||
desc = script.classes[word]
|
||||
elif script.defs.has_key(word):
|
||||
desc = script.defs[word]
|
||||
elif script.vars.has_key(word):
|
||||
desc = script.vars[word]
|
||||
else:
|
||||
find_word(txt, word)
|
||||
return
|
||||
else:
|
||||
i -= 1
|
||||
if i < class_menu_length:
|
||||
desc = script.classes[items[i]]
|
||||
elif i < class_menu_length + defs_menu_length:
|
||||
desc = script.defs[items[i]]
|
||||
elif i < class_menu_length + defs_menu_length + vars_menu_length:
|
||||
desc = script.vars[items[i]]
|
||||
|
||||
if desc:
|
||||
txt.setCursorPos(desc.lineno-1, 0)
|
||||
|
||||
# Check we are running as a script and not imported as a module
|
||||
if __name__ == "__main__" and OK:
|
||||
main()
|
94
release/scripts/textplugin_suggest.py
Normal file
94
release/scripts/textplugin_suggest.py
Normal file
@ -0,0 +1,94 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Suggest All | Ctrl Space'
|
||||
Blender: 246
|
||||
Group: 'TextPlugin'
|
||||
Shortcut: 'Ctrl+Space'
|
||||
Tooltip: 'Performs suggestions based on the context of the cursor'
|
||||
"""
|
||||
|
||||
# Only run if we have the required modules
|
||||
try:
|
||||
import bpy
|
||||
from BPyTextPlugin import *
|
||||
except ImportError:
|
||||
OK = False
|
||||
else:
|
||||
OK = True
|
||||
|
||||
def check_membersuggest(line, c):
|
||||
pos = line.rfind('.', 0, c)
|
||||
if pos == -1:
|
||||
return False
|
||||
for s in line[pos+1:c]:
|
||||
if not s.isalnum() and s != '_':
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_imports(line, c):
|
||||
pos = line.rfind('import ', 0, c)
|
||||
if pos > -1:
|
||||
for s in line[pos+7:c]:
|
||||
if not s.isalnum() and s != '_':
|
||||
return False
|
||||
return True
|
||||
pos = line.rfind('from ', 0, c)
|
||||
if pos > -1:
|
||||
for s in line[pos+5:c]:
|
||||
if not s.isalnum() and s != '_':
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
def main():
|
||||
txt = bpy.data.texts.active
|
||||
if not txt:
|
||||
return
|
||||
|
||||
line, c = current_line(txt)
|
||||
|
||||
# Check we are in a normal context
|
||||
if get_context(txt) != CTX_NORMAL:
|
||||
return
|
||||
|
||||
# Check the character preceding the cursor and execute the corresponding script
|
||||
|
||||
if check_membersuggest(line, c):
|
||||
import textplugin_membersuggest
|
||||
textplugin_membersuggest.main()
|
||||
return
|
||||
|
||||
elif check_imports(line, c):
|
||||
import textplugin_imports
|
||||
textplugin_imports.main()
|
||||
return
|
||||
|
||||
# Otherwise we suggest globals, keywords, etc.
|
||||
list = []
|
||||
targets = get_targets(line, c)
|
||||
desc = get_cached_descriptor(txt)
|
||||
|
||||
for k in KEYWORDS:
|
||||
list.append((k, 'k'))
|
||||
|
||||
for k, v in get_builtins().items():
|
||||
list.append((k, type_char(v)))
|
||||
|
||||
for k, v in desc.imports.items():
|
||||
list.append((k, type_char(v)))
|
||||
|
||||
for k, v in desc.classes.items():
|
||||
list.append((k, 'f'))
|
||||
|
||||
for k, v in desc.defs.items():
|
||||
list.append((k, 'f'))
|
||||
|
||||
for k, v in desc.vars.items():
|
||||
list.append((k, 'v'))
|
||||
|
||||
list.sort(cmp = suggest_cmp)
|
||||
txt.suggest(list, targets[-1])
|
||||
|
||||
# Check we are running as a script and not imported as a module
|
||||
if __name__ == "__main__" and OK:
|
||||
main()
|
123
release/scripts/textplugin_templates.py
Normal file
123
release/scripts/textplugin_templates.py
Normal file
@ -0,0 +1,123 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Template Completion | Tab'
|
||||
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}',
|
||||
'class':
|
||||
'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
|
||||
|
||||
row, c = txt.getCursorPos()
|
||||
line = txt.asLines(row, row+1)[0]
|
||||
indent=0
|
||||
while indent<c 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)) & 0xFFFF, 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()
|
93
source/blender/blenkernel/BKE_suggestions.h
Normal file
93
source/blender/blenkernel/BKE_suggestions.h
Normal file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* $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 should be added in sorted order although a linear sorting method is
|
||||
implemented. 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;
|
||||
SuggItem *selected;
|
||||
int top;
|
||||
} SuggList;
|
||||
|
||||
/* Free all text tool memory */
|
||||
void free_texttools();
|
||||
|
||||
/* Used to identify which Text object the current tools should appear against */
|
||||
void texttool_text_set_active(Text *text);
|
||||
void texttool_text_clear();
|
||||
short texttool_text_is_active(Text *text);
|
||||
|
||||
/* Suggestions */
|
||||
void texttool_suggest_add(const char *name, char type);
|
||||
void texttool_suggest_prefix(const char *prefix);
|
||||
void texttool_suggest_clear();
|
||||
SuggItem *texttool_suggest_first();
|
||||
SuggItem *texttool_suggest_last();
|
||||
void texttool_suggest_select(SuggItem *sel);
|
||||
SuggItem *texttool_suggest_selected();
|
||||
int *texttool_suggest_top();
|
||||
|
||||
/* Documentation */
|
||||
void texttool_docs_show(const char *docs);
|
||||
char *texttool_docs_get();
|
||||
void texttool_docs_clear();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -52,20 +52,24 @@ void txt_free_cut_buffer (void);
|
||||
char* txt_to_buf (struct Text *text);
|
||||
void txt_clean_text (struct Text *text);
|
||||
void txt_order_cursors (struct Text *text);
|
||||
int txt_find_string (struct Text *text, char *findstr);
|
||||
int txt_find_string (struct Text *text, char *findstr, int wrap);
|
||||
int txt_has_sel (struct Text *text);
|
||||
int txt_get_span (struct TextLine *from, struct TextLine *to);
|
||||
void txt_move_up (struct Text *text, short sel);
|
||||
void txt_move_down (struct Text *text, short sel);
|
||||
void txt_move_left (struct Text *text, short sel);
|
||||
void txt_move_right (struct Text *text, short sel);
|
||||
void txt_jump_left (struct Text *text, short sel);
|
||||
void txt_jump_right (struct Text *text, short sel);
|
||||
void txt_move_bof (struct Text *text, short sel);
|
||||
void txt_move_eof (struct Text *text, short sel);
|
||||
void txt_move_bol (struct Text *text, short sel);
|
||||
void txt_move_eol (struct Text *text, short sel);
|
||||
void txt_move_toline (struct Text *text, unsigned int line, short sel);
|
||||
void txt_move_to (struct Text *text, unsigned int line, unsigned int ch, short sel);
|
||||
void txt_pop_sel (struct Text *text);
|
||||
void txt_delete_char (struct Text *text);
|
||||
void txt_delete_word (struct Text *text);
|
||||
void txt_copy_sel (struct Text *text);
|
||||
void txt_sel_all (struct Text *text);
|
||||
void txt_sel_line (struct Text *text);
|
||||
@ -80,8 +84,10 @@ void txt_do_undo (struct Text *text);
|
||||
void txt_do_redo (struct Text *text);
|
||||
void txt_split_curline (struct Text *text);
|
||||
void txt_backspace_char (struct Text *text);
|
||||
void txt_backspace_word (struct Text *text);
|
||||
int txt_add_char (struct Text *text, char add);
|
||||
void txt_find_panel (struct SpaceText *st, int again);
|
||||
int txt_replace_char (struct Text *text, char add);
|
||||
void find_and_replace (struct SpaceText *st, short mode);
|
||||
void run_python_script (struct SpaceText *st);
|
||||
int jumptoline_interactive (struct SpaceText *st);
|
||||
void txt_export_to_object (struct Text *text);
|
||||
@ -94,6 +100,17 @@ int setcurr_tab (struct Text *text);
|
||||
void convert_tabs (struct SpaceText *st, int tab);
|
||||
void txt_copy_clipboard (struct Text *text);
|
||||
void txt_paste_clipboard (struct Text *text);
|
||||
|
||||
void txt_add_marker (struct Text *text, struct TextLine *line, int start, int end, char color[4], int group, int flags);
|
||||
short txt_clear_marker_region (struct Text *text, struct TextLine *line, int start, int end, int group, int flags);
|
||||
short txt_clear_markers (struct Text *text, int group, int flags);
|
||||
struct TextMarker *txt_find_marker (struct Text *text, struct TextLine *line, int curs, int group, int flags);
|
||||
struct TextMarker *txt_find_marker_region (struct Text *text, struct TextLine *line, int start, int end, int group, int flags);
|
||||
struct TextMarker *txt_prev_marker (struct Text *text, struct TextMarker *marker);
|
||||
struct TextMarker *txt_next_marker (struct Text *text, struct TextMarker *marker);
|
||||
struct TextMarker *txt_prev_marker_color (struct Text *text, struct TextMarker *marker);
|
||||
struct TextMarker *txt_next_marker_color (struct Text *text, struct TextMarker *marker);
|
||||
|
||||
/* Undo opcodes */
|
||||
|
||||
/* Simple main cursor movement */
|
||||
@ -135,6 +152,14 @@ void txt_paste_clipboard (struct Text *text);
|
||||
#define UNDO_COMMENT 034
|
||||
#define UNDO_UNCOMMENT 035
|
||||
|
||||
/* Find and replace flags */
|
||||
#define TXT_FIND_WRAP 0x01
|
||||
#define TXT_FIND_ALLTEXTS 0x02
|
||||
|
||||
/* Marker flags */
|
||||
#define TMARK_TEMP 0x01 /* Remove on non-editing events, don't save */
|
||||
#define TMARK_EDITALL 0x02 /* Edit all markers of the same group as one */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
254
source/blender/blenkernel/intern/suggestions.c
Normal file
254
source/blender/blenkernel/intern/suggestions.c
Normal file
@ -0,0 +1,254 @@
|
||||
/**
|
||||
* $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): Ian Thompson.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "DNA_text_types.h"
|
||||
#include "BKE_text.h"
|
||||
#include "BKE_suggestions.h"
|
||||
|
||||
/**********************/
|
||||
/* Static definitions */
|
||||
/**********************/
|
||||
|
||||
static Text *activeToolText = NULL;
|
||||
static SuggList suggestions = {NULL, NULL, NULL, NULL, NULL};
|
||||
static char *documentation = NULL;
|
||||
static int doc_lines = 0;
|
||||
|
||||
static int txttl_cmp(const char *first, const char *second, int len) {
|
||||
int cmp, i;
|
||||
for (cmp=0, i=0; i<len; i++) {
|
||||
if (cmp= toupper(first[i])-toupper(second[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
static void txttl_free_suggest() {
|
||||
SuggItem *item, *prev;
|
||||
for (item = suggestions.last; item; item=prev) {
|
||||
prev = item->prev;
|
||||
MEM_freeN(item);
|
||||
}
|
||||
suggestions.first = suggestions.last = NULL;
|
||||
suggestions.firstmatch = suggestions.lastmatch = NULL;
|
||||
suggestions.selected = NULL;
|
||||
suggestions.top = 0;
|
||||
}
|
||||
|
||||
static void txttl_free_docs() {
|
||||
if (documentation) {
|
||||
MEM_freeN(documentation);
|
||||
documentation = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************/
|
||||
/* General tool functions */
|
||||
/**************************/
|
||||
|
||||
void free_texttools() {
|
||||
txttl_free_suggest();
|
||||
txttl_free_docs();
|
||||
}
|
||||
|
||||
void texttool_text_set_active(Text *text) {
|
||||
if (activeToolText == text) return;
|
||||
texttool_text_clear();
|
||||
activeToolText = text;
|
||||
}
|
||||
|
||||
void texttool_text_clear() {
|
||||
free_texttools();
|
||||
activeToolText = NULL;
|
||||
}
|
||||
|
||||
short texttool_text_is_active(Text *text) {
|
||||
return activeToolText==text ? 1 : 0;
|
||||
}
|
||||
|
||||
/***************************/
|
||||
/* Suggestion list methods */
|
||||
/***************************/
|
||||
|
||||
void texttool_suggest_add(const char *name, char type) {
|
||||
SuggItem *newitem, *item;
|
||||
int len, cmp;
|
||||
|
||||
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);
|
||||
len = strlen(name);
|
||||
strncpy(newitem->name, name, len);
|
||||
newitem->name[len] = '\0';
|
||||
newitem->type = type;
|
||||
newitem->prev = newitem->next = NULL;
|
||||
|
||||
/* Perform simple linear search for ordered storage */
|
||||
if (!suggestions.first || !suggestions.last) {
|
||||
suggestions.first = suggestions.last = newitem;
|
||||
} else {
|
||||
cmp = -1;
|
||||
for (item=suggestions.last; item; item=item->prev) {
|
||||
cmp = txttl_cmp(name, item->name, len);
|
||||
|
||||
/* Newitem comes after this item, insert here */
|
||||
if (cmp >= 0) {
|
||||
newitem->prev = item;
|
||||
if (item->next)
|
||||
item->next->prev = newitem;
|
||||
newitem->next = item->next;
|
||||
item->next = newitem;
|
||||
|
||||
/* At last item, set last pointer here */
|
||||
if (item == suggestions.last)
|
||||
suggestions.last = newitem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Reached beginning of list, insert before first */
|
||||
if (cmp < 0) {
|
||||
newitem->next = suggestions.first;
|
||||
suggestions.first->prev = newitem;
|
||||
suggestions.first = newitem;
|
||||
}
|
||||
}
|
||||
suggestions.firstmatch = suggestions.lastmatch = suggestions.selected = NULL;
|
||||
suggestions.top= 0;
|
||||
}
|
||||
|
||||
void texttool_suggest_prefix(const char *prefix) {
|
||||
SuggItem *match, *first, *last;
|
||||
int cmp, len = strlen(prefix), top = 0;
|
||||
|
||||
if (!suggestions.first) return;
|
||||
if (len==0) {
|
||||
suggestions.selected = suggestions.firstmatch = suggestions.first;
|
||||
suggestions.lastmatch = suggestions.last;
|
||||
return;
|
||||
}
|
||||
|
||||
first = last = NULL;
|
||||
for (match=suggestions.first; match; match=match->next) {
|
||||
cmp = txttl_cmp(prefix, match->name, len);
|
||||
if (cmp==0) {
|
||||
if (!first) {
|
||||
first = match;
|
||||
suggestions.top = top;
|
||||
}
|
||||
} else if (cmp<0) {
|
||||
if (!last) {
|
||||
last = match->prev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
top++;
|
||||
}
|
||||
if (first) {
|
||||
if (!last) last = suggestions.last;
|
||||
suggestions.firstmatch = first;
|
||||
suggestions.lastmatch = last;
|
||||
suggestions.selected = first;
|
||||
} else {
|
||||
suggestions.firstmatch = NULL;
|
||||
suggestions.lastmatch = NULL;
|
||||
suggestions.selected = NULL;
|
||||
suggestions.top = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void texttool_suggest_clear() {
|
||||
txttl_free_suggest();
|
||||
}
|
||||
|
||||
SuggItem *texttool_suggest_first() {
|
||||
return suggestions.firstmatch;
|
||||
}
|
||||
|
||||
SuggItem *texttool_suggest_last() {
|
||||
return suggestions.lastmatch;
|
||||
}
|
||||
|
||||
void texttool_suggest_select(SuggItem *sel) {
|
||||
suggestions.selected = sel;
|
||||
}
|
||||
|
||||
SuggItem *texttool_suggest_selected() {
|
||||
return suggestions.selected;
|
||||
}
|
||||
|
||||
int *texttool_suggest_top() {
|
||||
return &suggestions.top;
|
||||
}
|
||||
|
||||
/*************************/
|
||||
/* Documentation methods */
|
||||
/*************************/
|
||||
|
||||
void texttool_docs_show(const char *docs) {
|
||||
int len;
|
||||
|
||||
if (!docs) return;
|
||||
|
||||
len = strlen(docs);
|
||||
|
||||
if (documentation) {
|
||||
MEM_freeN(documentation);
|
||||
documentation = NULL;
|
||||
}
|
||||
|
||||
/* Ensure documentation ends with a '\n' */
|
||||
if (docs[len-1] != '\n') {
|
||||
documentation = MEM_mallocN(len+2, "Documentation");
|
||||
strncpy(documentation, docs, len);
|
||||
documentation[len++] = '\n';
|
||||
} else {
|
||||
documentation = MEM_mallocN(len+1, "Documentation");
|
||||
strncpy(documentation, docs, len);
|
||||
}
|
||||
documentation[len] = '\0';
|
||||
}
|
||||
|
||||
char *texttool_docs_get() {
|
||||
return documentation;
|
||||
}
|
||||
|
||||
void texttool_docs_clear() {
|
||||
txttl_free_docs();
|
||||
}
|
@ -30,6 +30,8 @@
|
||||
*/
|
||||
|
||||
#include <string.h> /* strstr */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
@ -81,12 +83,19 @@ The st->top determines at what line the top of the text is displayed.
|
||||
If the user moves the cursor the st containing that cursor should
|
||||
be popped ... other st's retain their own top location.
|
||||
|
||||
*/ /***************/
|
||||
Markers
|
||||
--
|
||||
The mrk->flags define the behaviour and relationships between markers. The
|
||||
upper two bytes are used to hold a group ID, the lower two are normal flags. If
|
||||
TMARK_EDITALL is set the group ID defines which other markers should be edited.
|
||||
|
||||
The mrk->clr field is used to visually group markers where the flags may not
|
||||
match. A template system, for example, may allow editing of repeating tokens
|
||||
(in one group) but include other marked positions (in another group) all in the
|
||||
same template with the same colour.
|
||||
|
||||
/****************/ /*
|
||||
Undo
|
||||
|
||||
Undo
|
||||
--
|
||||
Undo/Redo works by storing
|
||||
events in a queue, and a pointer
|
||||
to the current position in the
|
||||
@ -145,6 +154,7 @@ void free_text(Text *text)
|
||||
}
|
||||
|
||||
BLI_freelistN(&text->lines);
|
||||
BLI_freelistN(&text->markers);
|
||||
|
||||
if(text->name) MEM_freeN(text->name);
|
||||
MEM_freeN(text->undo_buf);
|
||||
@ -169,10 +179,11 @@ Text *add_empty_text(char *name)
|
||||
ta->flags= TXT_ISDIRTY | TXT_ISTMP | TXT_ISMEM;
|
||||
|
||||
ta->lines.first= ta->lines.last= NULL;
|
||||
ta->markers.first= ta->markers.last= NULL;
|
||||
|
||||
tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= (char*) MEM_mallocN(1, "textline_string");
|
||||
tmp->format= (char*) MEM_mallocN(2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
tmp->line[0]=0;
|
||||
tmp->len= 0;
|
||||
@ -209,11 +220,12 @@ static void cleanup_textline(TextLine * tl)
|
||||
int reopen_text(Text *text)
|
||||
{
|
||||
FILE *fp;
|
||||
int i, llen, len;
|
||||
int i, llen, len, res;
|
||||
unsigned char *buffer;
|
||||
TextLine *tmp;
|
||||
char sfile[FILE_MAXFILE];
|
||||
char str[FILE_MAXDIR+FILE_MAXFILE];
|
||||
struct stat st;
|
||||
|
||||
if (!text || !text->name) return 0;
|
||||
|
||||
@ -242,7 +254,7 @@ int reopen_text(Text *text)
|
||||
text->undo_len= TXT_INIT_UNDO;
|
||||
text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
|
||||
|
||||
text->flags= TXT_ISDIRTY | TXT_ISTMP;
|
||||
text->flags= TXT_ISTMP;
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
len= ftell(fp);
|
||||
@ -256,6 +268,9 @@ int reopen_text(Text *text)
|
||||
len = fread(buffer, 1, len, fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
res= stat(str, &st);
|
||||
text->mtime= st.st_mtime;
|
||||
|
||||
text->nlines=0;
|
||||
i=0;
|
||||
@ -264,7 +279,7 @@ int reopen_text(Text *text)
|
||||
if (buffer[i]=='\n') {
|
||||
tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
|
||||
tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
|
||||
tmp->line[llen]=0;
|
||||
@ -284,7 +299,7 @@ int reopen_text(Text *text)
|
||||
if (llen!=0 || text->nlines==0) {
|
||||
tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
|
||||
tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
|
||||
|
||||
@ -307,12 +322,13 @@ int reopen_text(Text *text)
|
||||
Text *add_text(char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
int i, llen, len;
|
||||
int i, llen, len, res;
|
||||
unsigned char *buffer;
|
||||
TextLine *tmp;
|
||||
Text *ta;
|
||||
char sfile[FILE_MAXFILE];
|
||||
char str[FILE_MAXDIR+FILE_MAXFILE];
|
||||
struct stat st;
|
||||
|
||||
BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
|
||||
if (G.scene) /* can be NULL (bg mode) */
|
||||
@ -326,6 +342,7 @@ Text *add_text(char *file)
|
||||
ta->id.us= 1;
|
||||
|
||||
ta->lines.first= ta->lines.last= NULL;
|
||||
ta->markers.first= ta->markers.last= NULL;
|
||||
ta->curl= ta->sell= NULL;
|
||||
|
||||
/* ta->flags= TXT_ISTMP | TXT_ISEXT; */
|
||||
@ -348,6 +365,9 @@ Text *add_text(char *file)
|
||||
len = fread(buffer, 1, len, fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
res= stat(str, &st);
|
||||
ta->mtime= st.st_mtime;
|
||||
|
||||
ta->nlines=0;
|
||||
i=0;
|
||||
@ -356,7 +376,7 @@ Text *add_text(char *file)
|
||||
if (buffer[i]=='\n') {
|
||||
tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
|
||||
tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
|
||||
tmp->line[llen]=0;
|
||||
@ -376,7 +396,7 @@ Text *add_text(char *file)
|
||||
if (llen!=0 || ta->nlines==0) {
|
||||
tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
|
||||
tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
|
||||
|
||||
@ -410,6 +430,7 @@ Text *copy_text(Text *ta)
|
||||
tan->flags = ta->flags | TXT_ISDIRTY | TXT_ISTMP;
|
||||
|
||||
tan->lines.first= tan->lines.last= NULL;
|
||||
tan->markers.first= tan->markers.last= NULL;
|
||||
tan->curl= tan->sell= NULL;
|
||||
|
||||
tan->nlines= ta->nlines;
|
||||
@ -419,7 +440,7 @@ Text *copy_text(Text *ta)
|
||||
while (line) {
|
||||
tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= MEM_mallocN(line->len+1, "textline_string");
|
||||
tmp->format= MEM_mallocN(line->len+2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
strcpy(tmp->line, line->line);
|
||||
|
||||
@ -440,14 +461,14 @@ Text *copy_text(Text *ta)
|
||||
/* Editing utility functions */
|
||||
/*****************************/
|
||||
|
||||
static void make_new_line (TextLine *line, char *newline, char *newformat)
|
||||
static void make_new_line (TextLine *line, char *newline)
|
||||
{
|
||||
if (line->line) MEM_freeN(line->line);
|
||||
if (line->format) MEM_freeN(line->format);
|
||||
|
||||
line->line= newline;
|
||||
line->len= strlen(newline);
|
||||
line->format= newformat;
|
||||
line->format= NULL;
|
||||
}
|
||||
|
||||
static TextLine *txt_new_line(char *str)
|
||||
@ -458,7 +479,7 @@ static TextLine *txt_new_line(char *str)
|
||||
|
||||
tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
|
||||
tmp->format= MEM_mallocN(strlen(str)+2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
strcpy(tmp->line, str);
|
||||
|
||||
@ -476,7 +497,7 @@ static TextLine *txt_new_linen(char *str, int n)
|
||||
|
||||
tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
|
||||
tmp->line= MEM_mallocN(n+1, "textline_string");
|
||||
tmp->format= MEM_mallocN(n+2, "Syntax_format");
|
||||
tmp->format= NULL;
|
||||
|
||||
BLI_strncpy(tmp->line, str, n+1);
|
||||
|
||||
@ -553,6 +574,19 @@ static void txt_make_dirty (Text *text)
|
||||
if (text->compiled) BPY_free_compiled_text(text);
|
||||
}
|
||||
|
||||
/* 0:whitespace, 1:punct, 2:alphanumeric */
|
||||
static short txt_char_type (char ch)
|
||||
{
|
||||
if (ch <= ' ') return 0;
|
||||
if (ch <= '/') return 1;
|
||||
if (ch <= '9') return 2;
|
||||
if (ch <= '@') return 1;
|
||||
if (ch <= 'Z') return 2;
|
||||
if (ch <= '`') return 1;
|
||||
if (ch <= 'z') return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************/
|
||||
/* Cursor utility functions */
|
||||
/****************************/
|
||||
@ -606,8 +640,7 @@ void txt_move_up(Text *text, short sel)
|
||||
if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
|
||||
}
|
||||
} else {
|
||||
*charp= 0;
|
||||
if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
|
||||
txt_move_bol(text, sel);
|
||||
}
|
||||
|
||||
if(!sel) txt_pop_sel(text);
|
||||
@ -632,8 +665,7 @@ void txt_move_down(Text *text, short sel)
|
||||
} else
|
||||
if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
|
||||
} else {
|
||||
*charp= (*linep)->len;
|
||||
if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
|
||||
txt_move_eol(text, sel);
|
||||
}
|
||||
|
||||
if(!sel) txt_pop_sel(text);
|
||||
@ -689,6 +721,68 @@ void txt_move_right(Text *text, short sel)
|
||||
if(!sel) txt_pop_sel(text);
|
||||
}
|
||||
|
||||
void txt_jump_left(Text *text, short sel)
|
||||
{
|
||||
TextLine **linep, *oldl;
|
||||
int *charp, oldc, count, i;
|
||||
unsigned char oldu;
|
||||
|
||||
if (!text) return;
|
||||
if(sel) txt_curs_sel(text, &linep, &charp);
|
||||
else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
|
||||
if (!*linep) return;
|
||||
|
||||
oldl= *linep;
|
||||
oldc= *charp;
|
||||
oldu= undoing;
|
||||
undoing= 1; /* Don't push individual moves to undo stack */
|
||||
|
||||
count= 0;
|
||||
for (i=0; i<3; i++) {
|
||||
if (count < 2) {
|
||||
while (*charp>0 && txt_char_type((*linep)->line[*charp-1])==i) {
|
||||
txt_move_left(text, sel);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count==0) txt_move_left(text, sel);
|
||||
|
||||
undoing= oldu;
|
||||
if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
|
||||
}
|
||||
|
||||
void txt_jump_right(Text *text, short sel)
|
||||
{
|
||||
TextLine **linep, *oldl;
|
||||
int *charp, oldc, count, i;
|
||||
unsigned char oldu;
|
||||
|
||||
if (!text) return;
|
||||
if(sel) txt_curs_sel(text, &linep, &charp);
|
||||
else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
|
||||
if (!*linep) return;
|
||||
|
||||
oldl= *linep;
|
||||
oldc= *charp;
|
||||
oldu= undoing;
|
||||
undoing= 1; /* Don't push individual moves to undo stack */
|
||||
|
||||
count= 0;
|
||||
for (i=0; i<3; i++) {
|
||||
if (count < 2) {
|
||||
while (*charp<(*linep)->len && txt_char_type((*linep)->line[*charp])==i) {
|
||||
txt_move_right(text, sel);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count==0) txt_move_right(text, sel);
|
||||
|
||||
undoing= oldu;
|
||||
if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
|
||||
}
|
||||
|
||||
void txt_move_bol (Text *text, short sel)
|
||||
{
|
||||
TextLine **linep;
|
||||
@ -760,6 +854,11 @@ void txt_move_eof (Text *text, short sel)
|
||||
}
|
||||
|
||||
void txt_move_toline (Text *text, unsigned int line, short sel)
|
||||
{
|
||||
txt_move_to(text, line, 0, sel);
|
||||
}
|
||||
|
||||
void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
|
||||
{
|
||||
TextLine **linep, *oldl;
|
||||
int *charp, oldc;
|
||||
@ -777,10 +876,12 @@ void txt_move_toline (Text *text, unsigned int line, short sel)
|
||||
if ((*linep)->next) *linep= (*linep)->next;
|
||||
else break;
|
||||
}
|
||||
*charp= 0;
|
||||
if (ch>(*linep)->len)
|
||||
ch= (*linep)->len;
|
||||
*charp= ch;
|
||||
|
||||
if(!sel) txt_pop_sel(text);
|
||||
if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
|
||||
if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
|
||||
}
|
||||
|
||||
/****************************/
|
||||
@ -865,7 +966,9 @@ int txt_has_sel(Text *text)
|
||||
static void txt_delete_sel (Text *text)
|
||||
{
|
||||
TextLine *tmpl;
|
||||
char *buf, *format;
|
||||
TextMarker *mrk;
|
||||
char *buf;
|
||||
int move, lineno;
|
||||
|
||||
if (!text) return;
|
||||
if (!text->curl) return;
|
||||
@ -882,13 +985,33 @@ static void txt_delete_sel (Text *text)
|
||||
}
|
||||
|
||||
buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
|
||||
format= MEM_mallocN(text->curc+(text->sell->len - text->selc)+2, "Syntax_format");
|
||||
|
||||
if (text->curl != text->sell) {
|
||||
txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
|
||||
move= txt_get_span(text->curl, text->sell);
|
||||
} else {
|
||||
mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
|
||||
if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
|
||||
txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
|
||||
move= 0;
|
||||
}
|
||||
|
||||
mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
|
||||
if (mrk) {
|
||||
lineno= mrk->lineno;
|
||||
do {
|
||||
mrk->lineno -= move;
|
||||
if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
|
||||
mrk->end -= text->selc - text->curc;
|
||||
mrk= mrk->next;
|
||||
} while (mrk && mrk->lineno==lineno);
|
||||
}
|
||||
|
||||
strncpy(buf, text->curl->line, text->curc);
|
||||
strcpy(buf+text->curc, text->sell->line + text->selc);
|
||||
buf[text->curc+(text->sell->len - text->selc)]=0;
|
||||
|
||||
make_new_line(text->curl, buf, format);
|
||||
make_new_line(text->curl, buf);
|
||||
|
||||
tmpl= text->sell;
|
||||
while (tmpl != text->curl) {
|
||||
@ -995,22 +1118,31 @@ char *txt_to_buf (Text *text)
|
||||
return buf;
|
||||
}
|
||||
|
||||
int txt_find_string(Text *text, char *findstr)
|
||||
int txt_find_string(Text *text, char *findstr, int wrap)
|
||||
{
|
||||
TextLine *tl, *startl;
|
||||
char *s= NULL;
|
||||
int oldcl, oldsl, oldcc, oldsc;
|
||||
|
||||
if (!text || !text->curl || !text->sell) return 0;
|
||||
|
||||
txt_order_cursors(text);
|
||||
|
||||
oldcl= txt_get_span(text->lines.first, text->curl);
|
||||
oldsl= txt_get_span(text->lines.first, text->sell);
|
||||
tl= startl= text->sell;
|
||||
oldcc= text->curc;
|
||||
oldsc= text->selc;
|
||||
|
||||
s= strstr(&tl->line[text->selc], findstr);
|
||||
while (!s) {
|
||||
tl= tl->next;
|
||||
if (!tl)
|
||||
tl= text->lines.first;
|
||||
if (!tl) {
|
||||
if (wrap)
|
||||
tl= text->lines.first;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
s= strstr(tl->line, findstr);
|
||||
if (tl==startl)
|
||||
@ -1018,10 +1150,10 @@ int txt_find_string(Text *text, char *findstr)
|
||||
}
|
||||
|
||||
if (s) {
|
||||
text->curl= text->sell= tl;
|
||||
text->curc= (int) (s-tl->line);
|
||||
text->selc= text->curc + strlen(findstr);
|
||||
|
||||
int newl= txt_get_span(text->lines.first, tl);
|
||||
int newc= (int)(s-tl->line);
|
||||
txt_move_to(text, newl, newc, 0);
|
||||
txt_move_to(text, newl, newc + strlen(findstr), 1);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
@ -1621,7 +1753,6 @@ void txt_do_undo(Text *text)
|
||||
|
||||
case UNDO_SWAP:
|
||||
txt_curs_swap(text);
|
||||
txt_do_undo(text); /* swaps should appear transparent */
|
||||
break;
|
||||
|
||||
case UNDO_DBLOCK:
|
||||
@ -1736,6 +1867,19 @@ void txt_do_undo(Text *text)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* next undo step may need evaluating */
|
||||
if (text->undo_pos>=0) {
|
||||
switch (text->undo_buf[text->undo_pos]) {
|
||||
case UNDO_STO:
|
||||
txt_do_undo(text);
|
||||
txt_do_redo(text); /* selections need restoring */
|
||||
break;
|
||||
case UNDO_SWAP:
|
||||
txt_do_undo(text); /* swaps should appear transparent */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
undoing= 0;
|
||||
}
|
||||
@ -1810,7 +1954,7 @@ void txt_do_redo(Text *text)
|
||||
|
||||
case UNDO_SWAP:
|
||||
txt_curs_swap(text);
|
||||
txt_do_undo(text); /* swaps should appear transparent a*/
|
||||
txt_do_redo(text); /* swaps should appear transparent a*/
|
||||
break;
|
||||
|
||||
case UNDO_CTO:
|
||||
@ -1947,22 +2091,37 @@ void txt_do_redo(Text *text)
|
||||
void txt_split_curline (Text *text)
|
||||
{
|
||||
TextLine *ins;
|
||||
char *left, *right, *fleft, *fright;
|
||||
TextMarker *mrk;
|
||||
char *left, *right;
|
||||
int lineno= -1;
|
||||
|
||||
if (!text) return;
|
||||
if (!text->curl) return;
|
||||
|
||||
txt_delete_sel(text);
|
||||
txt_delete_sel(text);
|
||||
|
||||
/* Move markers */
|
||||
|
||||
lineno= txt_get_span(text->lines.first, text->curl);
|
||||
mrk= text->markers.first;
|
||||
while (mrk) {
|
||||
if (mrk->lineno==lineno && mrk->start>text->curc) {
|
||||
mrk->lineno++;
|
||||
mrk->start -= text->curc;
|
||||
mrk->end -= text->curc;
|
||||
} else if (mrk->lineno > lineno) {
|
||||
mrk->lineno++;
|
||||
}
|
||||
mrk= mrk->next;
|
||||
}
|
||||
|
||||
/* Make the two half strings */
|
||||
|
||||
left= MEM_mallocN(text->curc+1, "textline_string");
|
||||
fleft= MEM_mallocN(text->curc+2, "Syntax_format");
|
||||
if (text->curc) memcpy(left, text->curl->line, text->curc);
|
||||
left[text->curc]=0;
|
||||
|
||||
right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
|
||||
fright= MEM_mallocN(text->curl->len - text->curc+2, "Syntax_format");
|
||||
if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
|
||||
right[text->curl->len - text->curc]=0;
|
||||
|
||||
@ -1973,11 +2132,11 @@ void txt_split_curline (Text *text)
|
||||
|
||||
ins= MEM_mallocN(sizeof(TextLine), "textline");
|
||||
ins->line= left;
|
||||
ins->format= fleft;
|
||||
ins->format= NULL;
|
||||
ins->len= text->curc;
|
||||
|
||||
text->curl->line= right;
|
||||
text->curl->format= fright;
|
||||
text->curl->format= NULL;
|
||||
text->curl->len= text->curl->len - text->curc;
|
||||
|
||||
BLI_insertlinkbefore(&text->lines, text->curl, ins);
|
||||
@ -1993,9 +2152,23 @@ void txt_split_curline (Text *text)
|
||||
|
||||
static void txt_delete_line (Text *text, TextLine *line)
|
||||
{
|
||||
TextMarker *mrk=NULL, *nxt;
|
||||
int lineno= -1;
|
||||
|
||||
if (!text) return;
|
||||
if (!text->curl) return;
|
||||
|
||||
lineno= txt_get_span(text->lines.first, line);
|
||||
mrk= text->markers.first;
|
||||
while (mrk) {
|
||||
nxt= mrk->next;
|
||||
if (mrk->lineno==lineno)
|
||||
BLI_freelinkN(&text->markers, mrk);
|
||||
else if (mrk->lineno > lineno)
|
||||
mrk->lineno--;
|
||||
mrk= nxt;
|
||||
}
|
||||
|
||||
BLI_remlink (&text->lines, line);
|
||||
|
||||
if (line->line) MEM_freeN(line->line);
|
||||
@ -2009,21 +2182,35 @@ static void txt_delete_line (Text *text, TextLine *line)
|
||||
|
||||
static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
|
||||
{
|
||||
char *tmp, *format;
|
||||
char *tmp;
|
||||
TextMarker *mrk= NULL;
|
||||
int lineno=-1;
|
||||
|
||||
if (!text) return;
|
||||
|
||||
if(!linea || !lineb) return;
|
||||
|
||||
mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
|
||||
if (mrk) {
|
||||
lineno= mrk->lineno;
|
||||
do {
|
||||
mrk->lineno--;
|
||||
mrk->start += linea->len;
|
||||
mrk->end += linea->len;
|
||||
mrk= mrk->next;
|
||||
} while (mrk && mrk->lineno==lineno);
|
||||
}
|
||||
if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
|
||||
if (!mrk) mrk= text->markers.first;
|
||||
|
||||
tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
|
||||
format= MEM_mallocN(linea->len+lineb->len+1, "Syntax_format");
|
||||
|
||||
strcpy(tmp, linea->line);
|
||||
strcat(tmp, lineb->line);
|
||||
|
||||
make_new_line(linea, tmp, format);
|
||||
make_new_line(linea, tmp);
|
||||
|
||||
txt_delete_line(text, lineb);
|
||||
txt_delete_line(text, lineb);
|
||||
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
@ -2037,8 +2224,9 @@ void txt_delete_char (Text *text)
|
||||
if (!text->curl) return;
|
||||
|
||||
if (txt_has_sel(text)) { /* deleting a selection */
|
||||
txt_delete_sel(text);
|
||||
return;
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
return;
|
||||
}
|
||||
else if (text->curc== text->curl->len) { /* Appending two lines */
|
||||
if (text->curl->next) {
|
||||
@ -2047,6 +2235,25 @@ void txt_delete_char (Text *text)
|
||||
}
|
||||
} else { /* Just deleting a char */
|
||||
int i= text->curc;
|
||||
|
||||
TextMarker *mrk= txt_find_marker_region(text, text->curl, i-1, text->curl->len, 0, 0);
|
||||
if (mrk) {
|
||||
int lineno= mrk->lineno;
|
||||
if (mrk->end==i) {
|
||||
if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
|
||||
txt_clear_markers(text, mrk->group, TMARK_TEMP);
|
||||
} else {
|
||||
TextMarker *nxt= mrk->next;
|
||||
BLI_freelinkN(&text->markers, mrk);
|
||||
}
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if (mrk->start>i) mrk->start--;
|
||||
mrk->end--;
|
||||
mrk= mrk->next;
|
||||
} while (mrk && mrk->lineno==lineno);
|
||||
}
|
||||
|
||||
c= text->curl->line[i];
|
||||
while(i< text->curl->len) {
|
||||
@ -2064,6 +2271,12 @@ void txt_delete_char (Text *text)
|
||||
if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
|
||||
}
|
||||
|
||||
void txt_delete_word (Text *text)
|
||||
{
|
||||
txt_jump_right(text, 1);
|
||||
txt_delete_sel(text);
|
||||
}
|
||||
|
||||
void txt_backspace_char (Text *text)
|
||||
{
|
||||
char c='\n';
|
||||
@ -2072,8 +2285,9 @@ void txt_backspace_char (Text *text)
|
||||
if (!text->curl) return;
|
||||
|
||||
if (txt_has_sel(text)) { /* deleting a selection */
|
||||
txt_delete_sel(text);
|
||||
return;
|
||||
txt_delete_sel(text);
|
||||
txt_make_dirty(text);
|
||||
return;
|
||||
}
|
||||
else if (text->curc==0) { /* Appending two lines */
|
||||
if (!text->curl->prev) return;
|
||||
@ -2083,19 +2297,38 @@ void txt_backspace_char (Text *text)
|
||||
|
||||
txt_combine_lines(text, text->curl, text->curl->next);
|
||||
txt_pop_sel(text);
|
||||
}
|
||||
}
|
||||
else { /* Just backspacing a char */
|
||||
int i= text->curc-1;
|
||||
int i= text->curc-1;
|
||||
|
||||
TextMarker *mrk= txt_find_marker_region(text, text->curl, i, text->curl->len, 0, 0);
|
||||
if (mrk) {
|
||||
int lineno= mrk->lineno;
|
||||
if (mrk->start==i+1) {
|
||||
if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
|
||||
txt_clear_markers(text, mrk->group, TMARK_TEMP);
|
||||
} else {
|
||||
TextMarker *nxt= mrk->next;
|
||||
BLI_freelinkN(&text->markers, mrk);
|
||||
}
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if (mrk->start>i) mrk->start--;
|
||||
mrk->end--;
|
||||
mrk= mrk->next;
|
||||
} while (mrk && mrk->lineno==lineno);
|
||||
}
|
||||
|
||||
c= text->curl->line[i];
|
||||
while(i< text->curl->len) {
|
||||
text->curl->line[i]= text->curl->line[i+1];
|
||||
i++;
|
||||
}
|
||||
text->curl->len--;
|
||||
text->curc--;
|
||||
|
||||
txt_pop_sel(text);
|
||||
c= text->curl->line[i];
|
||||
while(i< text->curl->len) {
|
||||
text->curl->line[i]= text->curl->line[i+1];
|
||||
i++;
|
||||
}
|
||||
text->curl->len--;
|
||||
text->curc--;
|
||||
|
||||
txt_pop_sel(text);
|
||||
}
|
||||
|
||||
txt_make_dirty(text);
|
||||
@ -2104,10 +2337,17 @@ void txt_backspace_char (Text *text)
|
||||
if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
|
||||
}
|
||||
|
||||
void txt_backspace_word (Text *text)
|
||||
{
|
||||
txt_jump_left(text, 1);
|
||||
txt_delete_sel(text);
|
||||
}
|
||||
|
||||
int txt_add_char (Text *text, char add)
|
||||
{
|
||||
int len;
|
||||
char *tmp, *format;
|
||||
int len, lineno;
|
||||
char *tmp;
|
||||
TextMarker *mrk;
|
||||
|
||||
if (!text) return 0;
|
||||
if (!text->curl) return 0;
|
||||
@ -2119,8 +2359,17 @@ int txt_add_char (Text *text, char add)
|
||||
|
||||
txt_delete_sel(text);
|
||||
|
||||
mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
|
||||
if (mrk) {
|
||||
lineno= mrk->lineno;
|
||||
do {
|
||||
if (mrk->start>text->curc) mrk->start++;
|
||||
mrk->end++;
|
||||
mrk= mrk->next;
|
||||
} while (mrk && mrk->lineno==lineno);
|
||||
}
|
||||
|
||||
tmp= MEM_mallocN(text->curl->len+2, "textline_string");
|
||||
format= MEM_mallocN(text->curl->len+4, "Syntax_format");
|
||||
|
||||
if(text->curc) memcpy(tmp, text->curl->line, text->curc);
|
||||
tmp[text->curc]= add;
|
||||
@ -2128,7 +2377,7 @@ int txt_add_char (Text *text, char add)
|
||||
len= text->curl->len - text->curc;
|
||||
if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
|
||||
tmp[text->curl->len+1]=0;
|
||||
make_new_line(text->curl, tmp, format);
|
||||
make_new_line(text->curl, tmp);
|
||||
|
||||
text->curc++;
|
||||
|
||||
@ -2141,10 +2390,42 @@ int txt_add_char (Text *text, char add)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int txt_replace_char (Text *text, char add)
|
||||
{
|
||||
char del;
|
||||
|
||||
if (!text) return 0;
|
||||
if (!text->curl) return 0;
|
||||
|
||||
/* If text is selected or we're at the end of the line just use txt_add_char */
|
||||
if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
|
||||
TextMarker *mrk;
|
||||
int i= txt_add_char(text, add);
|
||||
mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
|
||||
if (mrk && mrk->end==text->curc) mrk->end--;
|
||||
return i;
|
||||
}
|
||||
|
||||
del= text->curl->line[text->curc];
|
||||
text->curl->line[text->curc]= (unsigned char) add;
|
||||
text->curc++;
|
||||
txt_pop_sel(text);
|
||||
|
||||
txt_make_dirty(text);
|
||||
txt_clean_text(text);
|
||||
|
||||
/* Should probably create a new op for this */
|
||||
if(!undoing) {
|
||||
txt_undo_add_charop(text, UNDO_DEL, del);
|
||||
txt_undo_add_charop(text, UNDO_INSERT, add);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void indent(Text *text)
|
||||
{
|
||||
int len, num;
|
||||
char *tmp, *format;
|
||||
char *tmp;
|
||||
char add = '\t';
|
||||
|
||||
if (!text) return;
|
||||
@ -2155,7 +2436,6 @@ void indent(Text *text)
|
||||
while (TRUE)
|
||||
{
|
||||
tmp= MEM_mallocN(text->curl->len+2, "textline_string");
|
||||
format= MEM_mallocN(text->curl->len+3, "Syntax_format");
|
||||
|
||||
text->curc = 0;
|
||||
if(text->curc) memcpy(tmp, text->curl->line, text->curc);
|
||||
@ -2165,7 +2445,7 @@ void indent(Text *text)
|
||||
if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
|
||||
tmp[text->curl->len+1]=0;
|
||||
|
||||
make_new_line(text->curl, tmp, format);
|
||||
make_new_line(text->curl, tmp);
|
||||
|
||||
text->curc++;
|
||||
|
||||
@ -2246,7 +2526,7 @@ void unindent(Text *text)
|
||||
void comment(Text *text)
|
||||
{
|
||||
int len, num;
|
||||
char *tmp, *format;
|
||||
char *tmp;
|
||||
char add = '#';
|
||||
|
||||
if (!text) return;
|
||||
@ -2257,7 +2537,6 @@ void comment(Text *text)
|
||||
while (TRUE)
|
||||
{
|
||||
tmp= MEM_mallocN(text->curl->len+2, "textline_string");
|
||||
format = MEM_mallocN(text->curl->len+3, "Syntax_format");
|
||||
|
||||
text->curc = 0;
|
||||
if(text->curc) memcpy(tmp, text->curl->line, text->curc);
|
||||
@ -2267,7 +2546,7 @@ void comment(Text *text)
|
||||
if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
|
||||
tmp[text->curl->len+1]=0;
|
||||
|
||||
make_new_line(text->curl, tmp, format);
|
||||
make_new_line(text->curl, tmp);
|
||||
|
||||
text->curc++;
|
||||
|
||||
@ -2398,3 +2677,148 @@ int setcurr_tab (Text *text)
|
||||
return i;
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* Text marker utility functions */
|
||||
/*********************************/
|
||||
|
||||
static int color_match(TextMarker *a, TextMarker *b) {
|
||||
return (a->color[0]==b->color[0] &&
|
||||
a->color[1]==b->color[1] &&
|
||||
a->color[2]==b->color[2] &&
|
||||
a->color[3]==b->color[3]);
|
||||
}
|
||||
|
||||
/* Creates and adds a marker to the list maintaining sorted order */
|
||||
void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
|
||||
TextMarker *tmp, *marker;
|
||||
|
||||
marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
|
||||
|
||||
marker->lineno= txt_get_span(text->lines.first, line);
|
||||
marker->start= MIN2(start, end);
|
||||
marker->end= MAX2(start, end);
|
||||
marker->group= group;
|
||||
marker->flags= flags;
|
||||
|
||||
marker->color[0]= color[0];
|
||||
marker->color[1]= color[1];
|
||||
marker->color[2]= color[2];
|
||||
marker->color[3]= color[3];
|
||||
|
||||
for (tmp=text->markers.last; tmp; tmp=tmp->prev)
|
||||
if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
|
||||
break;
|
||||
|
||||
if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
|
||||
else BLI_addhead(&text->markers, marker);
|
||||
}
|
||||
|
||||
/* Returns the first matching marker on the specified line between two points.
|
||||
If the group or flags fields are non-zero the returned flag must be in the
|
||||
specified group and have at least the specified flags set. */
|
||||
TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
|
||||
TextMarker *marker, *next;
|
||||
int lineno= txt_get_span(text->lines.first, line);
|
||||
|
||||
for (marker=text->markers.first; marker; marker=next) {
|
||||
next= marker->next;
|
||||
|
||||
if (group && marker->group != group) continue;
|
||||
else if ((marker->flags & flags) != flags) continue;
|
||||
else if (marker->lineno < lineno) continue;
|
||||
else if (marker->lineno > lineno) break;
|
||||
|
||||
if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
|
||||
(marker->start<end && marker->end>start))
|
||||
return marker;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Clears all markers on the specified line between two points. If the group or
|
||||
flags fields are non-zero the returned flag must be in the specified group
|
||||
and have at least the specified flags set. */
|
||||
short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) {
|
||||
TextMarker *marker, *next;
|
||||
int lineno= txt_get_span(text->lines.first, line);
|
||||
short cleared= 0;
|
||||
|
||||
for (marker=text->markers.first; marker; marker=next) {
|
||||
next= marker->next;
|
||||
|
||||
if (group && marker->group != group) continue;
|
||||
else if ((marker->flags & flags) != flags) continue;
|
||||
else if (marker->lineno < lineno) continue;
|
||||
else if (marker->lineno > lineno) break;
|
||||
|
||||
if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
|
||||
(marker->start<end && marker->end>start)) {
|
||||
BLI_freelinkN(&text->markers, marker);
|
||||
cleared= 1;
|
||||
}
|
||||
}
|
||||
return cleared;
|
||||
}
|
||||
|
||||
/* Clears all markers in the specified group (if given) with at least the
|
||||
specified flags set. Useful for clearing temporary markers (group=0,
|
||||
flags=TMARK_TEMP) */
|
||||
short txt_clear_markers(Text *text, int group, int flags) {
|
||||
TextMarker *marker, *next;
|
||||
short cleared= 0;
|
||||
|
||||
for (marker=text->markers.first; marker; marker=next) {
|
||||
next= marker->next;
|
||||
|
||||
if ((!group || marker->group==group) &&
|
||||
(marker->flags & flags) == flags) {
|
||||
BLI_freelinkN(&text->markers, marker);
|
||||
cleared= 1;
|
||||
}
|
||||
}
|
||||
return cleared;
|
||||
}
|
||||
|
||||
/* Finds the marker at the specified line and cursor position with at least the
|
||||
specified flags set in the given group (if non-zero). */
|
||||
TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) {
|
||||
TextMarker *marker;
|
||||
int lineno= txt_get_span(text->lines.first, line);
|
||||
|
||||
for (marker=text->markers.first; marker; marker=marker->next) {
|
||||
if (group && marker->group != group) continue;
|
||||
else if ((marker->flags & flags) != flags) continue;
|
||||
else if (marker->lineno < lineno) continue;
|
||||
else if (marker->lineno > lineno) break;
|
||||
|
||||
if (marker->start <= curs && curs <= marker->end)
|
||||
return marker;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Finds the previous marker in the same group. If no other is found, the same
|
||||
marker will be returned */
|
||||
TextMarker *txt_prev_marker(Text *text, TextMarker *marker) {
|
||||
TextMarker *tmp= marker;
|
||||
while (tmp) {
|
||||
if (tmp->prev) tmp= tmp->prev;
|
||||
else tmp= text->markers.last;
|
||||
if (tmp->group == marker->group)
|
||||
return tmp;
|
||||
}
|
||||
return NULL; /* Only if marker==NULL */
|
||||
}
|
||||
|
||||
/* Finds the next marker in the same group. If no other is found, the same
|
||||
marker will be returned */
|
||||
TextMarker *txt_next_marker(Text *text, TextMarker *marker) {
|
||||
TextMarker *tmp= marker;
|
||||
while (tmp) {
|
||||
if (tmp->next) tmp= tmp->next;
|
||||
else tmp= text->markers.first;
|
||||
if (tmp->group == marker->group)
|
||||
return tmp;
|
||||
}
|
||||
return NULL; /* Only if marker==NULL */
|
||||
}
|
||||
|
@ -2273,6 +2273,7 @@ static void direct_link_text(FileData *fd, Text *text)
|
||||
*/
|
||||
|
||||
link_list(fd, &text->lines);
|
||||
link_list(fd, &text->markers);
|
||||
|
||||
text->curl= newdataadr(fd, text->curl);
|
||||
text->sell= newdataadr(fd, text->sell);
|
||||
|
@ -1849,6 +1849,7 @@ static void write_texts(WriteData *wd, ListBase *idbase)
|
||||
{
|
||||
Text *text;
|
||||
TextLine *tmp;
|
||||
TextMarker *mrk;
|
||||
|
||||
text= idbase->first;
|
||||
while(text) {
|
||||
@ -1872,7 +1873,16 @@ static void write_texts(WriteData *wd, ListBase *idbase)
|
||||
writedata(wd, DATA, tmp->len+1, tmp->line);
|
||||
tmp= tmp->next;
|
||||
}
|
||||
|
||||
/* write markers */
|
||||
mrk= text->markers.first;
|
||||
while (mrk) {
|
||||
writestruct(wd, DATA, "TextMarker", 1, mrk);
|
||||
mrk= mrk->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
text= text->id.next;
|
||||
}
|
||||
|
||||
|
@ -38,14 +38,15 @@ void unlink_text(struct Text *text);
|
||||
|
||||
void free_textspace(struct SpaceText *st);
|
||||
|
||||
int txt_file_modified(struct Text *text);
|
||||
void txt_write_file(struct Text *text);
|
||||
void add_text_fs(char *file);
|
||||
|
||||
void free_txt_data(void);
|
||||
void pop_space_text(struct SpaceText *st);
|
||||
|
||||
void get_format_string(struct SpaceText *st);
|
||||
void do_brackets(void);
|
||||
void txt_format_text(struct SpaceText *st);
|
||||
void txt_format_line(struct SpaceText *st, struct TextLine *line, int do_next);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -31,6 +31,9 @@
|
||||
#define BIF_KEYVAL_H
|
||||
|
||||
char *key_event_to_string(unsigned short event);
|
||||
int decode_key_string(char *str, unsigned short *key, unsigned short *qual);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
@ -57,8 +57,8 @@ typedef enum {
|
||||
ICON_TRIA_UP,
|
||||
ICON_FONTPREVIEW,
|
||||
ICON_BLANK4,
|
||||
ICON_BLANK5,
|
||||
ICON_BLANK6,
|
||||
ICON_WORDWRAP,
|
||||
ICON_WORDWRAP_OFF,
|
||||
|
||||
ICON_ORTHO,
|
||||
ICON_PERSP,
|
||||
@ -108,7 +108,7 @@ typedef enum {
|
||||
ICON_FF,
|
||||
ICON_REW,
|
||||
ICON_PYTHON,
|
||||
ICON_BLANK11,
|
||||
ICON_PYTHON_ON,
|
||||
ICON_BLANK12,
|
||||
ICON_BLANK13,
|
||||
ICON_BLANK14,
|
||||
|
@ -83,6 +83,9 @@ struct SpaceOops;
|
||||
/* nodes handler codes */
|
||||
#define NODES_HANDLER_GREASEPENCIL 80
|
||||
|
||||
/* text handler codes */
|
||||
#define TEXT_HANDLER_FIND 90
|
||||
|
||||
/* theme codes */
|
||||
#define B_ADD_THEME 3301
|
||||
#define B_DEL_THEME 3302
|
||||
|
@ -377,6 +377,13 @@
|
||||
#define B_TEXTLINENUM 507
|
||||
#define B_TAB_NUMBERS 508
|
||||
#define B_SYNTAX 509
|
||||
#define B_WORDWRAP 510
|
||||
#define B_TEXTPLUGINS 511
|
||||
#define B_PASTEFIND 512
|
||||
#define B_PASTEREPLACE 513
|
||||
#define B_TEXTREPLACE 514
|
||||
#define B_TEXTFIND 515
|
||||
#define B_TEXTMARKALL 516
|
||||
|
||||
/* SCRIPT: 525 */
|
||||
#define B_SCRIPTBROWSE 526
|
||||
|
@ -276,22 +276,23 @@ typedef struct SpaceText {
|
||||
struct Text *text;
|
||||
|
||||
int top, viewlines;
|
||||
short flags, menunr;
|
||||
|
||||
int font_id;
|
||||
short flags, menunr;
|
||||
int font_id;
|
||||
|
||||
int lheight;
|
||||
int left;
|
||||
int showlinenrs;
|
||||
|
||||
int tabnumber;
|
||||
|
||||
int currtab_set;
|
||||
int showsyntax;
|
||||
int unused_padd;
|
||||
|
||||
int overwrite;
|
||||
float pix_per_line;
|
||||
|
||||
struct rcti txtscroll, txtbar;
|
||||
|
||||
int wordwrap, doplugins;
|
||||
|
||||
} SpaceText;
|
||||
|
||||
typedef struct Script {
|
||||
|
@ -38,25 +38,36 @@ typedef struct TextLine {
|
||||
struct TextLine *next, *prev;
|
||||
|
||||
char *line;
|
||||
char *format;
|
||||
int len, blen;
|
||||
char *format; /* may be NULL if syntax is off or not yet formatted */
|
||||
int len, blen; /* blen unused */
|
||||
} TextLine;
|
||||
|
||||
typedef struct TextMarker {
|
||||
struct TextMarker *next, *prev;
|
||||
|
||||
int lineno, start, end, pad1; /* line number and start/end character indices */
|
||||
|
||||
int group, flags; /* see BKE_text.h for flag defines */
|
||||
char color[4], pad[4]; /* draw color of the marker */
|
||||
} TextMarker;
|
||||
|
||||
typedef struct Text {
|
||||
ID id;
|
||||
|
||||
char *name;
|
||||
|
||||
|
||||
int flags, nlines;
|
||||
|
||||
ListBase lines;
|
||||
TextLine *curl, *sell;
|
||||
int curc, selc;
|
||||
ListBase markers;
|
||||
|
||||
char *undo_buf;
|
||||
int undo_pos, undo_len;
|
||||
|
||||
void *compiled;
|
||||
double mtime;
|
||||
} Text;
|
||||
|
||||
|
||||
@ -74,4 +85,12 @@ typedef struct Text {
|
||||
#define TXT_READONLY 0x0100
|
||||
#define TXT_FOLLOW 0x0200 /* always follow cursor (console) */
|
||||
|
||||
/* format continuation flags */
|
||||
#define TXT_NOCONT 0x00 /* no continuation */
|
||||
#define TXT_SNGQUOTSTR 0x01 /* single quotes */
|
||||
#define TXT_DBLQUOTSTR 0x02 /* double quotes */
|
||||
#define TXT_TRISTR 0x04 /* triplets of quotes: """ or ''' */
|
||||
#define TXT_SNGTRISTR 0x05 /*(TXT_TRISTR | TXT_SNGQUOTSTR)*/
|
||||
#define TXT_DBLTRISTR 0x06 /*(TXT_TRISTR | TXT_DBLQUOTSTR)*/
|
||||
|
||||
#endif
|
||||
|
@ -48,6 +48,7 @@ struct bPythonConstraint; /* DNA_constraint_types.h */
|
||||
struct bConstraintOb; /* DNA_constraint_types.h */
|
||||
struct bConstraintTarget; /* DNA_constraint_types.h*/
|
||||
struct Script; /* DNA_screen_types.h */
|
||||
struct BPyMenu;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -91,6 +92,8 @@ extern "C" {
|
||||
|
||||
int BPY_txt_do_python_Text( struct Text *text );
|
||||
int BPY_menu_do_python( short menutype, int event );
|
||||
int BPY_menu_do_shortcut( short menutype, unsigned short key, unsigned short modifiers );
|
||||
int BPY_menu_invoke( struct BPyMenu *pym, short menutype );
|
||||
void BPY_run_python_script( char *filename );
|
||||
int BPY_run_script(struct Script *script);
|
||||
void BPY_free_compiled_text( struct Text *text );
|
||||
|
@ -556,6 +556,7 @@ void BPY_Err_Handle( char *script_name )
|
||||
if( exception
|
||||
&& PyErr_GivenExceptionMatches( exception, PyExc_SyntaxError ) ) {
|
||||
/* no traceback available when SyntaxError */
|
||||
PyErr_NormalizeException( &exception, &err, &tb );
|
||||
PyErr_Restore( exception, err, tb ); /* takes away reference! */
|
||||
PyErr_Print( );
|
||||
v = PyObject_GetAttrString( err, "lineno" );
|
||||
@ -965,8 +966,38 @@ int BPY_run_script(Script *script)
|
||||
*****************************************************************************/
|
||||
int BPY_menu_do_python( short menutype, int event )
|
||||
{
|
||||
char *argstr = NULL;
|
||||
BPyMenu *pym;
|
||||
pym = BPyMenu_GetEntry( menutype, ( short ) event );
|
||||
return BPY_menu_invoke( pym, menutype );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Description: This function executes the script by its shortcut.
|
||||
* Notes: It is called by the ui code in src/???.c when a user presses an
|
||||
* unassigned key combination. Scripts are searched in the BPyMenuTable,
|
||||
* using the given menutype and event values to know which one to invoke.
|
||||
*****************************************************************************/
|
||||
int BPY_menu_do_shortcut( short menutype, unsigned short key, unsigned short qual )
|
||||
{
|
||||
BPyMenu *pym;
|
||||
pym = BPyMenu_GetEntry( menutype, 0 );
|
||||
|
||||
while ( pym ) {
|
||||
if ( pym->key && pym->key == key && pym->qual == qual ) {
|
||||
return BPY_menu_invoke( pym, menutype );
|
||||
}
|
||||
pym = pym->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Description: This function executes the script described by a menu item.
|
||||
*****************************************************************************/
|
||||
int BPY_menu_invoke( BPyMenu *pym, short menutype )
|
||||
{
|
||||
char *argstr = NULL;
|
||||
BPySubMenu *pysm;
|
||||
char scriptname[21];
|
||||
Script *script = NULL;
|
||||
@ -974,8 +1005,6 @@ int BPY_menu_do_python( short menutype, int event )
|
||||
PyGILState_STATE gilstate;
|
||||
char filestr[FILE_MAX];
|
||||
|
||||
pym = BPyMenu_GetEntry( menutype, ( short ) event );
|
||||
|
||||
if( !pym )
|
||||
return 0;
|
||||
|
||||
@ -1059,6 +1088,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;
|
||||
|
||||
|
@ -42,6 +42,7 @@
|
||||
#endif
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BIF_keyval.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "DNA_userdef_types.h" /* for U.pythondir */
|
||||
@ -106,6 +107,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 +187,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;
|
||||
@ -328,6 +334,23 @@ static void bpymenu_set_tooltip( BPyMenu * pymenu, char *tip )
|
||||
return;
|
||||
}
|
||||
|
||||
static void bpymenu_set_shortcut( BPyMenu * pymenu, char *combi )
|
||||
{
|
||||
unsigned short key, qual;
|
||||
|
||||
if( !pymenu )
|
||||
return;
|
||||
|
||||
if (!decode_key_string(combi, &key, &qual)) {
|
||||
return; /* TODO: Print some error */
|
||||
}
|
||||
|
||||
pymenu->key = key;
|
||||
pymenu->qual = qual;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* bpymenu_AddEntry:
|
||||
* try to find an existing pymenu entry with the given type and name;
|
||||
* if found, update it with new info, otherwise create a new one and fill it.
|
||||
@ -688,6 +711,7 @@ void BPyMenu_PrintAllEntries( void )
|
||||
* # Blender: <code>short int</code> (minimal Blender version)
|
||||
* # Group: 'group name' (defines menu)
|
||||
* # Submenu: 'submenu name' related_1word_arg
|
||||
* # Shortcut: Modifier+Key (optional shortcut combination for supported groups)
|
||||
* # Tooltip: 'tooltip for the menu'
|
||||
* # \"\"\"
|
||||
*
|
||||
@ -796,13 +820,19 @@ static int bpymenu_ParseFile(FILE *file, char *fname, int is_userdir)
|
||||
if ((matches == 3) && (strstr(head, "Submenu:") != NULL)) {
|
||||
bpymenu_AddSubEntry(scriptMenu, middle, tail);
|
||||
} else {
|
||||
/* Tooltip: 'tooltip for the menu */
|
||||
/* Shortcut: 'key+combination' */
|
||||
matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
|
||||
if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) ||
|
||||
(strstr(head, "Tip:") != NULL))) {
|
||||
bpymenu_set_tooltip(scriptMenu, middle);
|
||||
if ((matches == 3) && (strstr(head, "Shortcut:") != NULL)) {
|
||||
bpymenu_set_shortcut(scriptMenu, middle);
|
||||
} else {
|
||||
/* Tooltip: 'tooltip for the menu */
|
||||
matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
|
||||
if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) ||
|
||||
(strstr(head, "Tip:") != NULL))) {
|
||||
bpymenu_set_tooltip(scriptMenu, middle);
|
||||
}
|
||||
parser_state = 0;
|
||||
}
|
||||
parser_state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -59,6 +59,7 @@ typedef struct BPyMenu {
|
||||
char *name;
|
||||
char *filename;
|
||||
char *tooltip;
|
||||
unsigned short key, qual; /* Registered shortcut key */
|
||||
short version; /* Blender version */
|
||||
int dir; /* 0: default, 1: U.pythondir */
|
||||
struct BPySubMenu *submenus;
|
||||
@ -99,6 +100,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 */
|
||||
|
@ -34,9 +34,13 @@
|
||||
#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"
|
||||
@ -90,9 +94,20 @@ 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 );
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python BPy_Text methods table: */
|
||||
@ -109,12 +124,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 +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;
|
||||
@ -310,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 );
|
||||
}
|
||||
|
||||
@ -327,6 +377,8 @@ PyObject *Text_CreatePyObject( Text * txt )
|
||||
"couldn't create BPy_Text PyObject" );
|
||||
|
||||
pytxt->text = txt;
|
||||
pytxt->iol = NULL;
|
||||
pytxt->ioc = -1;
|
||||
|
||||
return ( PyObject * ) pytxt;
|
||||
}
|
||||
@ -376,25 +428,49 @@ static PyObject *Text_clear( BPy_Text * self)
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *Text_set( BPy_Text * self, PyObject * args )
|
||||
static PyObject *Text_reset( BPy_Text * self )
|
||||
{
|
||||
int ival;
|
||||
char *attr;
|
||||
|
||||
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;
|
||||
}
|
||||
self->iol = NULL;
|
||||
self->ioc = -1;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *Text_readline( BPy_Text * self )
|
||||
{
|
||||
PyObject *tmpstr;
|
||||
|
||||
if( !self->text )
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"This object isn't linked to a Blender Text Object" );
|
||||
|
||||
/* Reset */
|
||||
if (!self->iol && self->ioc == -1) {
|
||||
self->iol = self->text->lines.first;
|
||||
self->ioc = 0;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
char *str = PyString_AsString(value);
|
||||
@ -413,35 +489,324 @@ static PyObject *Text_write( BPy_Text * self, PyObject * value )
|
||||
txt_move_eof( self->text, 0 );
|
||||
txt_set_undostate( oldstate );
|
||||
|
||||
Text_reset( self );
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *Text_asLines( BPy_Text * self )
|
||||
static PyObject *Text_insert( BPy_Text * self, PyObject * value )
|
||||
{
|
||||
TextLine *line;
|
||||
PyObject *list, *tmpstr;
|
||||
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" );
|
||||
|
||||
oldstate = txt_get_undostate( );
|
||||
txt_insert_buf( self->text, str );
|
||||
txt_set_undostate( oldstate );
|
||||
|
||||
Text_reset( self );
|
||||
|
||||
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 );
|
||||
|
||||
Text_reset( self );
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *Text_set( BPy_Text * self, PyObject * args )
|
||||
{
|
||||
int ival;
|
||||
char *attr;
|
||||
|
||||
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" );
|
||||
|
||||
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 = 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->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;
|
||||
|
||||
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, 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 = 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 color[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.");
|
||||
|
||||
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, *resl = NULL;
|
||||
int list_len, i;
|
||||
char *prefix = NULL, *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 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;
|
||||
|
||||
if (!self->text)
|
||||
return EXPP_ReturnPyObjError(PyExc_RuntimeError,
|
||||
"This object isn't linked to a Blender Text Object");
|
||||
|
||||
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 */
|
||||
|
@ -41,6 +41,8 @@ extern PyTypeObject Text_Type;
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Text * text; /* libdata must be second */
|
||||
TextLine * iol; /* current line being read or NULL if reset */
|
||||
int ioc; /* character offset in line being read */
|
||||
} BPy_Text;
|
||||
|
||||
PyObject *Text_Init( void );
|
||||
|
@ -357,12 +357,14 @@ def PupTreeMenu( menu ):
|
||||
"""
|
||||
Create a popup menu tree.
|
||||
|
||||
Each item in the list is a menu item - (str, event), separator - None or submenu - (str, [...]).
|
||||
Each item in the list is: a menu item - (str, event); a separator - None;
|
||||
or submenu - (str, [...]).
|
||||
|
||||
Submenus list uses the same syntax as the menu list.
|
||||
Submenus list uses the same syntax as the menu list. To add a title to the
|
||||
main menu, end the first entry str with '%t' - the event is ignored.
|
||||
|
||||
Example::
|
||||
result = Draw.PupTreeMenu( [ ("Menu Item 1", 10), ("Menu Item 2", 12), ("SubMenu", [("Menu Item 3", 100), ("MenuItem4", 101) ] ) ] )
|
||||
result = Draw.PupTreeMenu( [ ("Title%t", 0), ("Menu Item 1", 10), ("Menu Item 2", 12), ("SubMenu", [("Menu Item 3", 100), ("MenuItem4", 101) ] ) ] )
|
||||
|
||||
@type menu: string
|
||||
@param menu: A menu list
|
||||
|
@ -100,6 +100,19 @@ class Text:
|
||||
Clear this Text object: its buffer becomes empty.
|
||||
"""
|
||||
|
||||
def reset():
|
||||
"""
|
||||
Reset the read IO pointer to the start of the buffer.
|
||||
"""
|
||||
|
||||
def readline():
|
||||
"""
|
||||
Reads a line of text from the buffer from the current IO pointer
|
||||
position to the end of the line. If the text has changed since the last
|
||||
read, reset() *must* be called.
|
||||
@rtype: string
|
||||
"""
|
||||
|
||||
def set(attribute, value):
|
||||
"""
|
||||
Set this Text's attributes.
|
||||
@ -118,12 +131,94 @@ class Text:
|
||||
@param data: The string to append to the text buffer.
|
||||
"""
|
||||
|
||||
def asLines():
|
||||
def insert(data):
|
||||
"""
|
||||
Retrieve the contents of this Text buffer as a list of strings.
|
||||
Inserts a string into this Text buffer at the cursor.
|
||||
@type data: string
|
||||
@param data: The string to insert into the text buffer.
|
||||
"""
|
||||
|
||||
def asLines(start=0, end=-1):
|
||||
"""
|
||||
Retrieve the contents of this Text buffer as a list of strings between
|
||||
the start and end lines specified. If end < 0 all lines from start will
|
||||
be included.
|
||||
@type start int
|
||||
@param start: Optional index of first line of the span to return
|
||||
@type end int
|
||||
@param end: Optional index of the line to which the span is taken or
|
||||
-1 to include all lines from start
|
||||
@rtype: list of strings
|
||||
@return: A list of strings, one for each line in the buffer
|
||||
@return: A list of strings, one for each line in the buffer between
|
||||
start and end.
|
||||
"""
|
||||
|
||||
def getCursorPos():
|
||||
"""
|
||||
Retrieve the position of the cursor in this Text buffer.
|
||||
@rtype: (int, int)
|
||||
@return: A pair (row, col) indexing the line and character of the
|
||||
cursor.
|
||||
"""
|
||||
|
||||
def setCursorPos(row, col):
|
||||
"""
|
||||
Set the position of the cursor in this Text buffer. Any selection will
|
||||
be cleared. Use setSelectPos to extend a selection from the point
|
||||
specified here.
|
||||
@type row: int
|
||||
@param row: The index of the line in which to position the cursor.
|
||||
@type col: int
|
||||
@param col: The index of the character within the line to position the
|
||||
cursor.
|
||||
"""
|
||||
|
||||
def getSelectPos():
|
||||
"""
|
||||
Retrieve the position of the selection cursor in this Text buffer.
|
||||
@rtype: (int, int)
|
||||
@return: A pair (row, col) indexing the line and character of the
|
||||
selection cursor.
|
||||
"""
|
||||
|
||||
def setSelectPos(row, col):
|
||||
"""
|
||||
Set the position of the selection cursor in this Text buffer. This
|
||||
method should be called after setCursorPos to extend the selection to
|
||||
the specified point.
|
||||
@type row: int
|
||||
@param row: The index of the line in which to position the cursor.
|
||||
@type col: int
|
||||
@param col: The index of the character within the line to position the
|
||||
cursor.
|
||||
"""
|
||||
|
||||
def suggest(list, prefix=''):
|
||||
"""
|
||||
Suggest a list of names. If list is a list of tuples (name, type) the
|
||||
list will be formatted to syntax-highlight each entry type. Types must
|
||||
be strings in the list ['m', 'f', 'v', 'k', '?']. It is recommended that
|
||||
the list be sorted, case-insensitively by name.
|
||||
|
||||
@type list: list of tuples or strings
|
||||
@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), 'k' (keyword), '?' (other).
|
||||
Lists of plain strings are also accepted where the type is always
|
||||
'?'.
|
||||
@type prefix: string
|
||||
@param prefix: The optional prefix used to limit what is suggested from
|
||||
the list. This is usually whatever precedes the cursor so that
|
||||
backspace will update it.
|
||||
"""
|
||||
|
||||
def showDocs(docs):
|
||||
"""
|
||||
Displays a word-wrapped message box containing the specified
|
||||
documentation when this Text object is visible.
|
||||
@type docs: string
|
||||
@param docs: The documentation string to display.
|
||||
"""
|
||||
|
||||
import id_generics
|
||||
Text.__doc__ += id_generics.attributes
|
||||
Text.__doc__ += id_generics.attributes
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -42,6 +42,7 @@
|
||||
|
||||
#include "BMF_Api.h"
|
||||
#include "BIF_language.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BSE_headerbuttons.h"
|
||||
|
||||
@ -52,6 +53,7 @@
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_action_types.h"
|
||||
|
||||
#include "BIF_gl.h" /* for glRasterPos2i */
|
||||
#include "BIF_drawtext.h"
|
||||
#include "BIF_interface.h"
|
||||
#include "BIF_resources.h"
|
||||
@ -128,7 +130,7 @@ void do_text_buttons(unsigned short event)
|
||||
st->top= 0;
|
||||
|
||||
pop_space_text(st);
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
if (st->showsyntax) txt_format_text(st);
|
||||
allqueue(REDRAWTEXT, 0);
|
||||
allqueue(REDRAWHEADERS, 0);
|
||||
}
|
||||
@ -194,14 +196,20 @@ void do_text_buttons(unsigned short event)
|
||||
|
||||
break;
|
||||
case B_TAB_NUMBERS:
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
if (st->showsyntax) txt_format_text(st);
|
||||
allqueue(REDRAWTEXT, 0);
|
||||
allqueue(REDRAWHEADERS, 0);
|
||||
break;
|
||||
case B_SYNTAX:
|
||||
if (st->showsyntax) {
|
||||
get_format_string(st);
|
||||
}
|
||||
if (st->showsyntax) txt_format_text(st);
|
||||
allqueue(REDRAWTEXT, 0);
|
||||
allqueue(REDRAWHEADERS, 0);
|
||||
break;
|
||||
case B_TEXTPLUGINS:
|
||||
allqueue(REDRAWHEADERS, 0);
|
||||
break;
|
||||
case B_WORDWRAP:
|
||||
st->left= 0;
|
||||
allqueue(REDRAWTEXT, 0);
|
||||
allqueue(REDRAWHEADERS, 0);
|
||||
break;
|
||||
@ -239,6 +247,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)
|
||||
{
|
||||
@ -268,7 +307,7 @@ static void do_text_filemenu(void *arg, int event)
|
||||
if (!reopen_text(text)) {
|
||||
error("Could not reopen file");
|
||||
}
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
if (st->showsyntax) txt_format_text(st);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
@ -277,9 +316,14 @@ static void do_text_filemenu(void *arg, int event)
|
||||
txt_write_file(text);
|
||||
break;
|
||||
case 6:
|
||||
run_python_script(st);
|
||||
text->flags |= TXT_ISMEM | TXT_ISDIRTY | TXT_ISTMP;
|
||||
MEM_freeN(text->name);
|
||||
text->name= NULL;
|
||||
break;
|
||||
case 7:
|
||||
run_python_script(st);
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
Object *ob;
|
||||
bConstraint *con;
|
||||
@ -340,11 +384,17 @@ static void do_text_editmenu(void *arg, int event)
|
||||
switch(event) {
|
||||
case 1:
|
||||
txt_do_undo(text);
|
||||
pop_space_text(st);
|
||||
break;
|
||||
case 2:
|
||||
txt_do_redo(text);
|
||||
pop_space_text(st);
|
||||
break;
|
||||
case 3:
|
||||
if (text && text->id.lib) {
|
||||
error_libdata();
|
||||
break;
|
||||
}
|
||||
txt_copy_clipboard(text);
|
||||
txt_cut_sel(text);
|
||||
pop_space_text(st);
|
||||
@ -354,8 +404,12 @@ static void do_text_editmenu(void *arg, int event)
|
||||
txt_copy_clipboard(text);
|
||||
break;
|
||||
case 5:
|
||||
if (text && text->id.lib) {
|
||||
error_libdata();
|
||||
break;
|
||||
}
|
||||
txt_paste_clipboard(text);
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
if (st->showsyntax) txt_format_text(st);
|
||||
break;
|
||||
case 6:
|
||||
txt_print_cutbuffer();
|
||||
@ -364,10 +418,11 @@ static void do_text_editmenu(void *arg, int event)
|
||||
jumptoline_interactive(st);
|
||||
break;
|
||||
case 8:
|
||||
txt_find_panel(st,1);
|
||||
break;
|
||||
case 9:
|
||||
txt_find_panel(st,0);
|
||||
find_and_replace(st, 0);
|
||||
break;
|
||||
case 10:
|
||||
find_and_replace(st, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -443,6 +498,57 @@ static void do_text_editmenu_selectmenu(void *arg, int event)
|
||||
}
|
||||
}
|
||||
|
||||
/* action executed after clicking in Markers menu */
|
||||
static void do_text_editmenu_markermenu(void *arg, int event)
|
||||
{
|
||||
SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
|
||||
Text *text;
|
||||
TextMarker *mrk;
|
||||
ScrArea *sa;
|
||||
int lineno;
|
||||
|
||||
if (st==NULL || st->spacetype != SPACE_TEXT) return;
|
||||
|
||||
text = st->text;
|
||||
|
||||
switch(event) {
|
||||
case 1:
|
||||
txt_clear_markers(text, 0, 0);
|
||||
break;
|
||||
case 2:
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
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);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
|
||||
SpaceText *st= sa->spacedata.first;
|
||||
if (st && st->spacetype==SPACE_TEXT) {
|
||||
scrarea_queue_redraw(sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* action executed after clicking in Format menu */
|
||||
static void do_text_formatmenu(void *arg, int event)
|
||||
{
|
||||
@ -456,6 +562,10 @@ static void do_text_formatmenu(void *arg, int event)
|
||||
|
||||
switch(event) {
|
||||
case 3:
|
||||
if (text && text->id.lib) {
|
||||
error_libdata();
|
||||
break;
|
||||
}
|
||||
if (txt_has_sel(text)) {
|
||||
txt_order_cursors(text);
|
||||
indent(text);
|
||||
@ -466,6 +576,10 @@ static void do_text_formatmenu(void *arg, int event)
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
if (text && text->id.lib) {
|
||||
error_libdata();
|
||||
break;
|
||||
}
|
||||
if ( txt_has_sel(text)) {
|
||||
txt_order_cursors(text);
|
||||
unindent(text);
|
||||
@ -473,18 +587,26 @@ static void do_text_formatmenu(void *arg, int event)
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (text && text->id.lib) {
|
||||
error_libdata();
|
||||
break;
|
||||
}
|
||||
if ( txt_has_sel(text)) {
|
||||
txt_order_cursors(text);
|
||||
comment(text);
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
if (st->showsyntax) txt_format_text(st);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (text && text->id.lib) {
|
||||
error_libdata();
|
||||
break;
|
||||
}
|
||||
if ( txt_has_sel(text)) {
|
||||
txt_order_cursors(text);
|
||||
uncomment(text);
|
||||
if (st->showsyntax) get_format_string(st);
|
||||
if (st->showsyntax) txt_format_text(st);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -536,6 +658,25 @@ static uiBlock *text_editmenu_selectmenu(void *arg_unused)
|
||||
return block;
|
||||
}
|
||||
|
||||
/* Select menu */
|
||||
static uiBlock *text_editmenu_markermenu(void *arg_unused)
|
||||
{
|
||||
uiBlock *block;
|
||||
short yco = 20, menuwidth = 120;
|
||||
|
||||
block= uiNewBlock(&curarea->uiblocks, "text_editmenu_markermenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
|
||||
uiBlockSetButmFunc(block, do_text_editmenu_markermenu, NULL);
|
||||
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear All", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Next Marker", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Previous Marker", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
|
||||
|
||||
uiBlockSetDirection(block, UI_RIGHT);
|
||||
uiTextBoundsBlock(block, 60);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
void do_text_formatmenu_convert(void *arg, int event)
|
||||
{
|
||||
SpaceText *st= curarea->spacedata.first; /* bad but cant pass as an arg here */
|
||||
@ -649,10 +790,12 @@ static uiBlock *text_editmenu(void *arg_unused)
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
uiDefIconTextBlockBut(block, text_editmenu_viewmenu, NULL, ICON_RIGHTARROW_THIN, "View|Alt Shift V ", 0, yco-=20, 120, 19, "");
|
||||
uiDefIconTextBlockBut(block, text_editmenu_selectmenu, NULL, ICON_RIGHTARROW_THIN, "Select|Alt Shift S ", 0, yco-=20, 120, 19, "");
|
||||
uiDefIconTextBlockBut(block, text_editmenu_markermenu, NULL, ICON_RIGHTARROW_THIN, "Markers", 0, yco-=20, 120, 19, "");
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump...|Alt J", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find...|Alt Ctrl F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Again|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find And Replace...|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Next|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Replace|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
uiDefIconTextBlockBut(block, text_editmenu_to3dmenu, NULL, ICON_RIGHTARROW_THIN, "Text to 3d Object", 0, yco-=20, 120, 19, "");
|
||||
|
||||
@ -690,17 +833,21 @@ static uiBlock *text_filemenu(void *arg_unused)
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save As...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
|
||||
|
||||
if (text->name)
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Internal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Run Python Script|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Run Python Script|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
|
||||
|
||||
if (BPY_is_pyconstraint(text))
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Refresh All PyConstraints", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Refresh All PyConstraints", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
}
|
||||
|
||||
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);
|
||||
@ -715,13 +862,15 @@ static uiBlock *text_filemenu(void *arg_unused)
|
||||
}
|
||||
|
||||
/* header */
|
||||
#define PATH_MAX 260
|
||||
void text_buttons(void)
|
||||
{
|
||||
uiBlock *block;
|
||||
SpaceText *st= curarea->spacedata.first;
|
||||
Text *text;
|
||||
short xco, xmax;
|
||||
char naam[256];
|
||||
char naam[256], fname[PATH_MAX], headtxt[PATH_MAX+17];
|
||||
int len;
|
||||
|
||||
if (st==NULL || st->spacetype != SPACE_TEXT) return;
|
||||
|
||||
@ -779,8 +928,9 @@ void text_buttons(void)
|
||||
else uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Makes current window full screen (CTRL+Down arrow)");
|
||||
|
||||
uiDefIconButI(block, ICONTOG, B_TEXTLINENUM, ICON_LONGDISPLAY, xco+=XIC,0,XIC,YIC, &st->showlinenrs, 0, 0, 0, 0, "Displays line numbers");
|
||||
|
||||
uiDefIconButI(block, ICONTOG, B_SYNTAX, ICON_SYNTAX, xco+=XIC,0,XIC,YIC, &st->showsyntax, 0, 0, 0, 0, "Enables Syntax Highlighting");
|
||||
uiDefIconButI(block, ICONTOG, B_WORDWRAP, ICON_WORDWRAP, xco+=XIC,0,XIC,YIC, &st->wordwrap, 0, 0, 0, 0, "Enables word wrap");
|
||||
uiDefIconButI(block, ICONTOG, B_SYNTAX, ICON_SYNTAX, xco+=XIC,0,XIC,YIC, &st->showsyntax, 0, 0, 0, 0, "Enables syntax highlighting");
|
||||
uiDefIconButI(block, ICONTOG, B_TEXTPLUGINS, ICON_PYTHON, xco+=XIC,0,XIC,YIC, &st->doplugins, 0, 0, 0, 0, "Enables Python text plugins");
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
/* STD TEXT BUTTONS */
|
||||
@ -804,9 +954,30 @@ void text_buttons(void)
|
||||
uiDefButI(block, MENU, B_TEXTFONT, "Screen 12 %x0|Screen 15%x1", xco,0,100,YIC, &st->font_id, 0, 0, 0, 0, "Displays available fonts");
|
||||
xco+=110;
|
||||
|
||||
uiDefButI(block, NUM, B_TAB_NUMBERS, "Tab:", xco, 0, XIC+50, YIC, &st->tabnumber, 2, 8, 0, 0, "Set spacing of Tab");
|
||||
uiDefButI(block, NUM, B_TAB_NUMBERS, "Tab:", xco, 0, XIC+50, YIC, &st->tabnumber, 2, 8, 0, 0, "Set spacing of Tab");
|
||||
xco+= XIC+50;
|
||||
|
||||
|
||||
/* File info */
|
||||
if (text) {
|
||||
if (text->name) {
|
||||
len = strlen(text->name);
|
||||
if (len > PATH_MAX-1)
|
||||
len = 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");
|
||||
}
|
||||
BIF_ThemeColor(TH_MENU_TEXT);
|
||||
glRasterPos2i(xco+=XIC, 5);
|
||||
BMF_DrawString(G.font, headtxt);
|
||||
xco += BMF_GetStringWidth(G.font, headtxt);
|
||||
}
|
||||
|
||||
/* always as last */
|
||||
curarea->headbutlen= xco+2*XIC;
|
||||
|
||||
|
@ -27,6 +27,11 @@
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "stdio.h"
|
||||
#include "ctype.h"
|
||||
#include "string.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BIF_keyval.h"
|
||||
@ -349,3 +354,193 @@ char *key_event_to_string(unsigned short event)
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes key combination strings [qual1+[qual2+[...]]]keyname
|
||||
* The '+'s may be replaced by '-' or ' ' characters to support different
|
||||
* formats. No additional whitespace is allowed. The keyname may be an internal
|
||||
* name, like "RETKEY", or a more common name, like "Return". Decoding is case-
|
||||
* insensitive.
|
||||
*
|
||||
* Example strings: "Ctrl+L", "ALT-ESC", "Shift A"
|
||||
*
|
||||
* Returns 1 if successful.
|
||||
*/
|
||||
int decode_key_string(char *str, unsigned short *key, unsigned short *qual)
|
||||
{
|
||||
int i, prev, len, invalid=0;
|
||||
|
||||
len= strlen(str);
|
||||
*key= *qual= 0;
|
||||
|
||||
/* Convert to upper case */
|
||||
for (i=0; i<len; i++) {
|
||||
str[i]= toupper(str[i]);
|
||||
}
|
||||
|
||||
/* Handle modifiers */
|
||||
for (prev=i=0; i<len; i++) {
|
||||
if (str[i]==' ' || str[i]=='+' || str[i]=='-') {
|
||||
if (!strncmp(str+prev, "CTRL", i-prev)) *qual |= LR_CTRLKEY;
|
||||
else if (!strncmp(str+prev, "ALT", i-prev)) *qual |= LR_ALTKEY;
|
||||
else if (!strncmp(str+prev, "SHIFT", i-prev)) *qual |= LR_SHIFTKEY;
|
||||
else if (!strncmp(str+prev, "COMMAND", i-prev)) *qual |= LR_COMMANDKEY;
|
||||
prev=i+1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare last part against key names */
|
||||
if (len-prev==1 || len-prev==4 && !strncmp(str+prev, "KEY", 3)) {
|
||||
|
||||
if (str[prev]>='A' && str[prev]<='Z') {
|
||||
*key= str[prev]-'A'+AKEY;
|
||||
} else if (str[prev]>='0' && str[prev]<='9') {
|
||||
*key= str[prev]-'0'+ZEROKEY;
|
||||
} else {
|
||||
invalid= 1;
|
||||
}
|
||||
|
||||
} else if (!strncmp(str+prev, "ZEROKEY", len-prev) || !strncmp(str+prev, "ZERO", len-prev)) {
|
||||
*key= ZEROKEY;
|
||||
} else if (!strncmp(str+prev, "ONEKEY", len-prev) || !strncmp(str+prev, "ONE", len-prev)) {
|
||||
*key= ONEKEY;
|
||||
} else if (!strncmp(str+prev, "TWOKEY", len-prev) || !strncmp(str+prev, "TWO", len-prev)) {
|
||||
*key= TWOKEY;
|
||||
} else if (!strncmp(str+prev, "THREEKEY", len-prev) || !strncmp(str+prev, "THREE", len-prev)) {
|
||||
*key= THREEKEY;
|
||||
} else if (!strncmp(str+prev, "FOURKEY", len-prev) || !strncmp(str+prev, "FOUR", len-prev)) {
|
||||
*key= FOURKEY;
|
||||
} else if (!strncmp(str+prev, "FIVEKEY", len-prev) || !strncmp(str+prev, "FIVE", len-prev)) {
|
||||
*key= FIVEKEY;
|
||||
} else if (!strncmp(str+prev, "SIZEKEY", len-prev) || !strncmp(str+prev, "SIX", len-prev)) {
|
||||
*key= SIXKEY;
|
||||
} else if (!strncmp(str+prev, "SEVENKEY", len-prev) || !strncmp(str+prev, "SEVEN", len-prev)) {
|
||||
*key= SEVENKEY;
|
||||
} else if (!strncmp(str+prev, "EIGHTKEY", len-prev) || !strncmp(str+prev, "EIGHT", len-prev)) {
|
||||
*key= EIGHTKEY;
|
||||
} else if (!strncmp(str+prev, "NINEKEY", len-prev) || !strncmp(str+prev, "NINE", len-prev)) {
|
||||
*key= NINEKEY;
|
||||
|
||||
} else if (!strncmp(str+prev, "ESCKEY", len-prev) || !strncmp(str+prev, "ESC", len-prev)) {
|
||||
*key= ESCKEY;
|
||||
} else if (!strncmp(str+prev, "TABKEY", len-prev) || !strncmp(str+prev, "TAB", len-prev)) {
|
||||
*key= TABKEY;
|
||||
} else if (!strncmp(str+prev, "RETKEY", len-prev) || !strncmp(str+prev, "RETURN", len-prev) || !strncmp(str+prev, "ENTER", len-prev)) {
|
||||
*key= RETKEY;
|
||||
} else if (!strncmp(str+prev, "SPACEKEY", len-prev) || !strncmp(str+prev, "SPACE", len-prev)) {
|
||||
*key= SPACEKEY;
|
||||
} else if (!strncmp(str+prev, "LINEFEEDKEY", len-prev) || !strncmp(str+prev, "LINEFEED", len-prev)) {
|
||||
*key= LINEFEEDKEY;
|
||||
} else if (!strncmp(str+prev, "BACKSPACEKEY", len-prev) || !strncmp(str+prev, "BACKSPACE", len-prev)) {
|
||||
*key= BACKSPACEKEY;
|
||||
} else if (!strncmp(str+prev, "DELKEY", len-prev) || !strncmp(str+prev, "DELETE", len-prev)) {
|
||||
*key= DELKEY;
|
||||
|
||||
} else if (!strncmp(str+prev, "SEMICOLONKEY", len-prev) || !strncmp(str+prev, "SEMICOLON", len-prev)) {
|
||||
*key= SEMICOLONKEY;
|
||||
} else if (!strncmp(str+prev, "PERIODKEY", len-prev) || !strncmp(str+prev, "PERIOD", len-prev)) {
|
||||
*key= PERIODKEY;
|
||||
} else if (!strncmp(str+prev, "COMMAKEY", len-prev) || !strncmp(str+prev, "COMMA", len-prev)) {
|
||||
*key= COMMAKEY;
|
||||
} else if (!strncmp(str+prev, "QUOTEKEY", len-prev) || !strncmp(str+prev, "QUOTE", len-prev)) {
|
||||
*key= QUOTEKEY;
|
||||
} else if (!strncmp(str+prev, "ACCENTGRAVEKEY", len-prev) || !strncmp(str+prev, "ACCENTGRAVE", len-prev)) {
|
||||
*key= ACCENTGRAVEKEY;
|
||||
} else if (!strncmp(str+prev, "MINUSKEY", len-prev) || !strncmp(str+prev, "MINUS", len-prev)) {
|
||||
*key= MINUSKEY;
|
||||
} else if (!strncmp(str+prev, "SLASHKEY", len-prev) || !strncmp(str+prev, "SLASH", len-prev)) {
|
||||
*key= SLASHKEY;
|
||||
} else if (!strncmp(str+prev, "BACKSLASHKEY", len-prev) || !strncmp(str+prev, "BACKSLASH", len-prev)) {
|
||||
*key= BACKSLASHKEY;
|
||||
} else if (!strncmp(str+prev, "EQUALKEY", len-prev) || !strncmp(str+prev, "EQUAL", len-prev)) {
|
||||
*key= EQUALKEY;
|
||||
} else if (!strncmp(str+prev, "LEFTBRACKETKEY", len-prev) || !strncmp(str+prev, "LEFTBRACKET", len-prev)) {
|
||||
*key= LEFTBRACKETKEY;
|
||||
} else if (!strncmp(str+prev, "RIGHTBRACKETKEY", len-prev) || !strncmp(str+prev, "RIGHTBRACKET", len-prev)) {
|
||||
*key= RIGHTBRACKETKEY;
|
||||
} else if (!strncmp(str+prev, "DELKEY", len-prev) || !strncmp(str+prev, "DELETE", len-prev)) {
|
||||
*key= DELKEY;
|
||||
|
||||
} else if (!strncmp(str+prev, "LEFTARROWKEY", len-prev) || !strncmp(str+prev, "LEFTARROW", len-prev)) {
|
||||
*key= LEFTARROWKEY;
|
||||
} else if (!strncmp(str+prev, "DOWNARROWKEY", len-prev) || !strncmp(str+prev, "DOWNARROW", len-prev)) {
|
||||
*key= DOWNARROWKEY;
|
||||
} else if (!strncmp(str+prev, "RIGHTARROWKEY", len-prev) || !strncmp(str+prev, "RIGHTARROW", len-prev)) {
|
||||
*key= RIGHTARROWKEY;
|
||||
} else if (!strncmp(str+prev, "UPARROWKEY", len-prev) || !strncmp(str+prev, "UPARROW", len-prev)) {
|
||||
*key= UPARROWKEY;
|
||||
|
||||
} else if (!strncmp(str+prev, "PAD", 3)) {
|
||||
|
||||
if (len-prev<=4) {
|
||||
|
||||
if (str[prev]>='0' && str[prev]<='9') {
|
||||
*key= str[prev]-'0'+ZEROKEY;
|
||||
} else {
|
||||
invalid= 1;
|
||||
}
|
||||
|
||||
} else if (!strncmp(str+prev+3, "PERIODKEY", len-prev-3) || !strncmp(str+prev+3, "PERIOD", len-prev-3)) {
|
||||
*key= PADPERIOD;
|
||||
} else if (!strncmp(str+prev+3, "SLASHKEY", len-prev-3) || !strncmp(str+prev+3, "SLASH", len-prev-3)) {
|
||||
*key= PADSLASHKEY;
|
||||
} else if (!strncmp(str+prev+3, "ASTERKEY", len-prev-3) || !strncmp(str+prev+3, "ASTERISK", len-prev-3)) {
|
||||
*key= PADASTERKEY;
|
||||
} else if (!strncmp(str+prev+3, "MINUSKEY", len-prev-3) || !strncmp(str+prev+3, "MINUS", len-prev-3)) {
|
||||
*key= PADMINUS;
|
||||
} else if (!strncmp(str+prev+3, "ENTERKEY", len-prev-3) || !strncmp(str+prev+3, "ENTER", len-prev-3)) {
|
||||
*key= PADENTER;
|
||||
} else if (!strncmp(str+prev+3, "PLUSKEY", len-prev-3) || !strncmp(str+prev+3, "PLUS", len-prev-3)) {
|
||||
*key= PADPLUSKEY;
|
||||
} else {
|
||||
invalid= 1;
|
||||
}
|
||||
|
||||
} else if (!strncmp(str+prev, "F1KEY", len-prev) || !strncmp(str+prev, "F1", len-prev)) {
|
||||
*key= F1KEY;
|
||||
} else if (!strncmp(str+prev, "F2KEY", len-prev) || !strncmp(str+prev, "F2", len-prev)) {
|
||||
*key= F2KEY;
|
||||
} else if (!strncmp(str+prev, "F3KEY", len-prev) || !strncmp(str+prev, "F3", len-prev)) {
|
||||
*key= F3KEY;
|
||||
} else if (!strncmp(str+prev, "F4KEY", len-prev) || !strncmp(str+prev, "F4", len-prev)) {
|
||||
*key= F4KEY;
|
||||
} else if (!strncmp(str+prev, "F5KEY", len-prev) || !strncmp(str+prev, "F5", len-prev)) {
|
||||
*key= F5KEY;
|
||||
} else if (!strncmp(str+prev, "F6KEY", len-prev) || !strncmp(str+prev, "F6", len-prev)) {
|
||||
*key= F6KEY;
|
||||
} else if (!strncmp(str+prev, "F7KEY", len-prev) || !strncmp(str+prev, "F7", len-prev)) {
|
||||
*key= F7KEY;
|
||||
} else if (!strncmp(str+prev, "F8KEY", len-prev) || !strncmp(str+prev, "F8", len-prev)) {
|
||||
*key= F8KEY;
|
||||
} else if (!strncmp(str+prev, "F9KEY", len-prev) || !strncmp(str+prev, "F9", len-prev)) {
|
||||
*key= F9KEY;
|
||||
} else if (!strncmp(str+prev, "F10KEY", len-prev) || !strncmp(str+prev, "F10", len-prev)) {
|
||||
*key= F10KEY;
|
||||
} else if (!strncmp(str+prev, "F11KEY", len-prev) || !strncmp(str+prev, "F11", len-prev)) {
|
||||
*key= F11KEY;
|
||||
} else if (!strncmp(str+prev, "F12KEY", len-prev) || !strncmp(str+prev, "F12", len-prev)) {
|
||||
*key= F12KEY;
|
||||
|
||||
} else if (!strncmp(str+prev, "PAUSEKEY", len-prev) || !strncmp(str+prev, "PAUSE", len-prev)) {
|
||||
*key= PAUSEKEY;
|
||||
} else if (!strncmp(str+prev, "INSERTKEY", len-prev) || !strncmp(str+prev, "INSERT", len-prev)) {
|
||||
*key= INSERTKEY;
|
||||
} else if (!strncmp(str+prev, "HOMEKEY", len-prev) || !strncmp(str+prev, "HOME", len-prev)) {
|
||||
*key= HOMEKEY;
|
||||
} else if (!strncmp(str+prev, "PAGEUPKEY", len-prev) || !strncmp(str+prev, "PAGEUP", len-prev)) {
|
||||
*key= PAGEUPKEY;
|
||||
} else if (!strncmp(str+prev, "PAGEDOWNKEY", len-prev) || !strncmp(str+prev, "PAGEDOWN", len-prev)) {
|
||||
*key= PAGEDOWNKEY;
|
||||
} else if (!strncmp(str+prev, "ENDKEY", len-prev) || !strncmp(str+prev, "END", len-prev)) {
|
||||
*key= ENDKEY;
|
||||
|
||||
} else {
|
||||
invalid= 1;
|
||||
}
|
||||
|
||||
if (!invalid && *key) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6060,6 +6060,10 @@ static void init_textspace(ScrArea *sa)
|
||||
st->lheight= 12;
|
||||
st->showlinenrs= 0;
|
||||
st->tabnumber = 4;
|
||||
st->showsyntax= 0;
|
||||
st->doplugins= 0;
|
||||
st->overwrite= 0;
|
||||
st->wordwrap= 0;
|
||||
st->currtab_set = 0;
|
||||
|
||||
st->top= 0;
|
||||
|
@ -2282,7 +2282,7 @@ void toolbox_generic( TBitem *generic_menu )
|
||||
uiBlock *block;
|
||||
uiBut *but;
|
||||
TBitem *menu;
|
||||
int dx=96;
|
||||
int dx=96, first=1, len;
|
||||
short event, mval[2];
|
||||
intptr_t ypos = -5;
|
||||
|
||||
@ -2303,11 +2303,17 @@ void toolbox_generic( TBitem *generic_menu )
|
||||
|
||||
/* Add the menu */
|
||||
for (menu = generic_menu; menu->icon != -1; menu++) {
|
||||
if(strcmp(menu->name, "SEPR")==0) {
|
||||
if (first && (len=strlen(menu->name)) > 2 && menu->name[len-2]=='%' && menu->name[len-1]=='t') {
|
||||
menu->name[len-2] = '\0';
|
||||
uiSetCurFont(block, UI_HELVB);
|
||||
uiDefIconTextBut(block, LABEL, 0, ICON_BLANK1, menu->name, mval[0]+tb_mainx,mval[1]+tb_mainy+ypos+5, dx, 19, NULL, 0.0, 0.0, 0, 0, "");
|
||||
uiSetCurFont(block, UI_HELV);
|
||||
ypos-=20;
|
||||
} else if(strcmp(menu->name, "SEPR")==0) {
|
||||
uiDefBut(block, SEPR, 0, "", mval[0]+tb_mainx,mval[1]+tb_mainy+ypos+5, dx, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
ypos-=6;
|
||||
} else {
|
||||
if (menu->poin) {
|
||||
if (menu->poin) {
|
||||
but=uiDefIconTextBlockBut(block, tb_makemenu, menu->poin, ICON_RIGHTARROW_THIN, menu->name, mval[0]+tb_mainx,mval[1]+tb_mainy+ypos+5, dx, 19, "");
|
||||
uiButSetFlag(but, UI_MAKE_RIGHT);
|
||||
|
||||
@ -2318,6 +2324,7 @@ void toolbox_generic( TBitem *generic_menu )
|
||||
}
|
||||
ypos-=20;
|
||||
}
|
||||
first= 0;
|
||||
}
|
||||
|
||||
uiBlockSetButmFunc(block, menu->poin, NULL);
|
||||
|
@ -69,6 +69,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"
|
||||
@ -81,6 +82,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"
|
||||
@ -1107,6 +1109,7 @@ void exit_usiblender(void)
|
||||
free_actcopybuf();
|
||||
free_vertexpaint();
|
||||
free_imagepaint();
|
||||
free_texttools();
|
||||
|
||||
/* editnurb can remain to exist outside editmode */
|
||||
freeNurblist(&editNurb);
|
||||
|
Loading…
Reference in New Issue
Block a user