summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gd_compiler.cpp73
-rw-r--r--modules/gdscript/gd_compiler.h2
-rw-r--r--modules/gdscript/gd_editor.cpp574
-rw-r--r--modules/gdscript/gd_functions.cpp62
-rw-r--r--modules/gdscript/gd_functions.h5
-rw-r--r--modules/gdscript/gd_parser.cpp97
-rw-r--r--modules/gdscript/gd_parser.h12
-rw-r--r--modules/gdscript/gd_pretty_print.cpp2
-rw-r--r--modules/gdscript/gd_pretty_print.h2
-rw-r--r--modules/gdscript/gd_script.cpp104
-rw-r--r--modules/gdscript/gd_script.h8
-rw-r--r--modules/gdscript/gd_tokenizer.cpp38
-rw-r--r--modules/gdscript/gd_tokenizer.h3
-rw-r--r--modules/gdscript/register_types.h2
-rw-r--r--modules/gridmap/grid_map.cpp10
-rw-r--r--modules/gridmap/grid_map.h2
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp164
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h23
-rw-r--r--modules/gridmap/register_types.cpp2
-rw-r--r--modules/gridmap/register_types.h2
20 files changed, 963 insertions, 224 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp
index 278651d642..a62225f663 100644
--- a/modules/gdscript/gd_compiler.cpp
+++ b/modules/gdscript/gd_compiler.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,15 +28,6 @@
/*************************************************************************/
#include "gd_compiler.h"
#include "gd_script.h"
-/* TODO:
-
- *AND and OR need early abort
- -Inheritance properly process (done?)
- *create built in initializer and constructor
- *assign operators
- *build arrays and dictionaries
- *call parent constructor
- */
void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) {
@@ -559,7 +550,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
int index;
if (named) {
+#ifdef DEBUG_ENABLED
+ if (on->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) {
+ const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name);
+ if (MI && MI->get().getter==codegen.function_node->name) {
+ String n = static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name;
+ _set_error("Must use '"+n+"' instead of 'self."+n+"' in getter.",on);
+ return -1;
+ }
+ }
+#endif
index=codegen.get_name_map_pos(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name);
} else {
@@ -703,6 +704,25 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
if (on->arguments[0]->type==GDParser::Node::TYPE_OPERATOR && (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX || static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED)) {
//SET (chained) MODE!!
+
+#ifdef DEBUG_ENABLED
+ if (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED) {
+ const GDParser::OperatorNode* inon = static_cast<GDParser::OperatorNode*>(on->arguments[0]);
+
+
+ if (inon->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) {
+
+ const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name);
+ if (MI && MI->get().setter==codegen.function_node->name) {
+ String n = static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name;
+ _set_error("Must use '"+n+"' instead of 'self."+n+"' in setter.",inon);
+ return -1;
+ }
+ }
+ }
+#endif
+
+
int slevel=p_stack_level;
GDParser::OperatorNode* op = static_cast<GDParser::OperatorNode*>(on->arguments[0]);
@@ -1368,13 +1388,14 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
int index_from=0;
+ Ref<GDNativeClass> native;
if (p_class->extends_used) {
//do inheritance
String path = p_class->extends_file;
Ref<GDScript> script;
- Ref<GDNativeClass> native;
+
if (path!="") {
//path (and optionally subclasses)
@@ -1386,7 +1407,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
_set_error("Could not resolve relative path for parent class: "+path,p_class);
return ERR_FILE_NOT_FOUND;
}
- path=base.get_base_dir().plus_file(path);
+ path=base.get_base_dir().plus_file(path).simplify_path();
}
script = ResourceLoader::load(path);
if (script.is_null()) {
@@ -1544,7 +1565,35 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
//p_script->constants[constant->value].make_const();
}
+ for(int i=0;i<p_class->_signals.size();i++) {
+
+ StringName name = p_class->_signals[i].name;
+
+ GDScript *c = p_script;
+ while(c) {
+
+ if (c->_signals.has(name)) {
+ _set_error("Signal '"+name+"' redefined (in current or parent class)",p_class);
+ return ERR_ALREADY_EXISTS;
+ }
+
+ if (c->base.is_valid()) {
+ c=c->base.ptr();
+ } else {
+ c=NULL;
+ }
+ }
+
+ if (native.is_valid()) {
+ if (ObjectTypeDB::has_signal(native->get_name(),name)) {
+ _set_error("Signal '"+name+"' redefined (original in native class '"+String(native->get_name())+"')",p_class);
+ return ERR_ALREADY_EXISTS;
+ }
+ }
+
+ p_script->_signals[name]=p_class->_signals[i].arguments;
+ }
//parse sub-classes
for(int i=0;i<p_class->subclasses.size();i++) {
diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h
index 0c34c23b25..bdf4e9816a 100644
--- a/modules/gdscript/gd_compiler.h
+++ b/modules/gdscript/gd_compiler.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index df091fbcc9..7cb9882f3a 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,11 +29,12 @@
#include "gd_script.h"
#include "gd_compiler.h"
#include "globals.h"
+#include "os/file_access.h"
void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("#");
- p_delimiters->push_back("\"\"\"");
+ p_delimiters->push_back("\"\"\" \"\"\"");
}
void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
@@ -238,26 +239,26 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p
if (_debug_parse_err_line>=0)
return;
- ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
- int l = _debug_call_stack_pos - p_level -1;
+ ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+ int l = _debug_call_stack_pos - p_level -1;
- GDInstance *instance = _call_stack[l].instance;
+ GDInstance *instance = _call_stack[l].instance;
- if (!instance)
- return;
+ if (!instance)
+ return;
- Ref<GDScript> script = instance->get_script();
- ERR_FAIL_COND( script.is_null() );
+ Ref<GDScript> script = instance->get_script();
+ ERR_FAIL_COND( script.is_null() );
- const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
+ const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
- for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) {
+ for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) {
- p_members->push_back(E->key());
- p_values->push_back( instance->debug_get_member_by_index(E->get().index));
- }
+ p_members->push_back(E->key());
+ p_values->push_back( instance->debug_get_member_by_index(E->get().index));
+ }
}
void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
@@ -317,6 +318,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam
struct GDCompletionIdentifier {
StringName obj_type;
+ Ref<GDScript> script;
Variant::Type type;
Variant value; //im case there is a value, also return it
};
@@ -381,7 +383,12 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
path=context.base_path.plus_file(path);
}
- script = ResourceLoader::load(path);
+
+ if (ScriptCodeCompletionCache::get_sigleton())
+ script = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path);
+ else
+ script = ResourceLoader::load(path);
+
if (script.is_null()) {
return REF();
}
@@ -441,7 +448,7 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
base_class=base_class->subclasses[subclass];
} else {
- print_line("Could not find subclass: "+subclass);
+ //print_line("Could not find subclass: "+subclass);
return _get_type_from_class(context); //fail please
}
}
@@ -626,7 +633,9 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
//try calling the function if constant and all args are constant, should not crash..
Object *baseptr = base.value;
- if (baseptr && mb->is_const() && pi.type==Variant::OBJECT) {
+
+ if (mb->is_const() && pi.type==Variant::OBJECT) {
+
bool all_valid=true;
Vector<Variant> args;
for(int i=2;i<op->arguments.size();i++) {
@@ -643,25 +652,88 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
all_valid=false;
}
}
- if (all_valid) {
- Vector<const Variant*> argptr;
- for(int i=0;i<args.size();i++) {
- argptr.push_back(&args[i]);
- }
- Variant::CallError ce;
- Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce);
+ if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) {
+
+ String arg1=args[0];
+ if (arg1.begins_with("/root/")) {
+ String which = arg1.get_slice("/",2);
+ if (which!="") {
+ List<PropertyInfo> props;
+ Globals::get_singleton()->get_property_list(&props);
+ //print_line("find singleton");
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
- if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ //print_line("found "+s);
+ String name = s.get_slice("/",1);
+ //print_line("name: "+name+", which: "+which);
+ if (name==which) {
+ String script = Globals::get_singleton()->get(s);
- if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) {
+ if (!script.begins_with("res://")) {
+ script="res://"+script;
+ }
- r_type=_get_type_from_variant(ret);
- return true;
+ if (!script.ends_with(".gd")) {
+ //not a script, try find the script anyway,
+ //may have some success
+ script=script.basename()+".gd";
+ }
+
+ if (FileAccess::exists(script)) {
+
+ //print_line("is a script");
+
+
+ Ref<Script> scr;
+ if (ScriptCodeCompletionCache::get_sigleton())
+ scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script);
+ else
+ scr = ResourceLoader::load(script);
+
+
+ r_type.obj_type="Node";
+ r_type.type=Variant::OBJECT;
+ r_type.script=scr;
+ r_type.value=Variant();
+
+ return true;
+
+ }
+ }
+ }
}
}
+ }
+
+
+ if (baseptr) {
+
+ if (all_valid) {
+ Vector<const Variant*> argptr;
+ for(int i=0;i<args.size();i++) {
+ argptr.push_back(&args[i]);
+ }
+
+ Variant::CallError ce;
+ Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce);
+
+
+ if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {
+
+ if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) {
+
+ r_type=_get_type_from_variant(ret);
+ return true;
+ }
+ }
+
+ }
}
}
@@ -1195,7 +1267,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
}
static const char*_type_names[Variant::VARIANT_MAX]={
- "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform",
+ "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Transform",
"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
"Vector2Array","Vector3Array","ColorArray"};
@@ -1276,6 +1348,7 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid
static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const StringName& p_method,const GDCompletionIdentifier& id, int p_argidx, Set<String>& result, String& arghint) {
+ //print_line("find type arguments?");
if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) {
List<PropertyInfo> pinfo;
@@ -1296,78 +1369,300 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
- if (!m)
- return;
+ if (!m) {
+ //not in static method, see script
+
+ //print_line("not in static: "+String(p_method));
+ Ref<GDScript> on_script;
+
+ if (id.value.get_type()) {
+ Object *obj=id.value;
+
+
+ if (obj) {
+
+
+ GDScript *scr = obj->cast_to<GDScript>();
+ if (scr) {
+ while (scr) {
+
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (E->get().is_static() && p_method==E->get().get_name()) {
+ arghint="static func "+String(p_method)+"(";
+ for(int i=0;i<E->get().get_argument_count();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+="var "+E->get().get_argument_name(i);
+ int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count();
+ if (i>=deffrom) {
+ int defidx = deffrom-i;
+ if (defidx>=0 && defidx<E->get().get_default_argument_count()) {
+ arghint+="="+E->get().get_default_argument(defidx).get_construct_string();
+ }
+ }
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ }
+ arghint+=")";
+ return; //found
+ }
+ }
+
+ if (scr->get_base().is_valid())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
+ } else {
+ on_script=obj->get_script();
+ }
+ }
+ }
+
+ //print_line("but it has a script?");
+ if (!on_script.is_valid() && id.script.is_valid()) {
+ //print_line("yes");
+ on_script=id.script;
+ }
- if (p_method.operator String()=="connect") {
+ if (on_script.is_valid()) {
+ GDScript *scr = on_script.ptr();
+ if (scr) {
+ while (scr) {
- if (p_argidx==0) {
- List<MethodInfo> sigs;
- ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
- for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
- result.insert("\""+E->get().name+"\"");
+ String code = scr->get_source_code();
+ //print_line("has source code!");
+
+ if (code!="") {
+ //if there is code, parse it. This way is slower but updates in real-time
+ GDParser p;
+ //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+ Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false);
+
+ if (err==OK) {
+ //print_line("checking the functions...");
+ //only if ok, otherwise use what is cached on the script
+ //GDParser::ClassNode *base = p.
+ const GDParser::Node *root = p.get_parse_tree();
+ ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS);
+
+ const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
+
+ const GDParser::FunctionNode* func=NULL;
+ bool st=false;
+
+ for(int i=0;i<cl->functions.size();i++) {
+ //print_line(String(cl->functions[i]->name)+" vs "+String(p_method));
+ if (cl->functions[i]->name==p_method) {
+ func=cl->functions[i];
+ }
+ }
+
+ for(int i=0;i<cl->static_functions.size();i++) {
+
+ //print_line(String(cl->static_functions[i]->name)+" vs "+String(p_method));
+ if (cl->static_functions[i]->name==p_method) {
+ func=cl->static_functions[i];
+ st=true;
+ }
+
+ }
+
+ if (func) {
+
+ arghint="func "+String(p_method)+"(";
+ if (st)
+ arghint="static "+arghint;
+ for(int i=0;i<func->arguments.size();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+="var "+String(func->arguments[i]);
+ int deffrom = func->arguments.size()-func->default_values.size();
+ if (i>=deffrom) {
+
+ int defidx = deffrom-i;
+
+ if (defidx>=0 && defidx<func->default_values.size() && func->default_values[defidx]->type==GDParser::Node::TYPE_OPERATOR) {
+ const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(func->default_values[defidx]);
+ if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
+ const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(op->arguments[1]);
+ arghint+="="+cn->value.get_construct_string();
+ }
+ }
+ }
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ }
+
+ arghint+=" )";
+ return;
+ }
+ } else {
+ //print_line("failed parsing?");
+ code="";
+ }
+
+ }
+
+ if (code=="") {
+
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (p_method==E->get().get_name()) {
+ arghint="func "+String(p_method)+"(";
+ for(int i=0;i<E->get().get_argument_count();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+="var "+E->get().get_argument_name(i);
+ int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count();
+ if (i>=deffrom) {
+ int defidx = deffrom-i;
+ if (defidx>=0 && defidx<E->get().get_default_argument_count()) {
+ arghint+="="+E->get().get_default_argument(defidx).get_construct_string();
+ }
+ }
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ }
+ arghint+=")";
+ return; //found
+ }
+ }
+#if 0
+ //use class directly, no code was found
+ if (!isfunction) {
+ for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+ options.insert(E->key());
+ }
+ }
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ options.insert(String(E->key())+"(");
+ }
+
+ for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) {
+ options.insert(E->get());
+ }
+#endif
+ }
+
+ if (scr->get_base().is_valid())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
}
}
- /*if (p_argidx==2) {
- ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR);
- const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node);
- if (op->arguments.size()>)
- }*/
} else {
+ //regular method
- Object *obj=id.value;
- if (obj) {
- List<String> options;
- obj->get_argument_options(p_method,p_argidx,&options);
- for(List<String>::Element *E=options.front();E;E=E->next()) {
+ if (p_method.operator String()=="connect") {
- result.insert(E->get());
+
+ if (p_argidx==0) {
+ List<MethodInfo> sigs;
+ ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
+ for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
+ result.insert("\""+E->get().name+"\"");
+ }
}
- }
+ /*if (p_argidx==2) {
- }
+ ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR);
+ const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node);
+ if (op->arguments.size()>)
- arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
+ }*/
+ } else {
- for(int i=0;i<m->get_argument_count();i++) {
- if (i>0)
- arghint+=", ";
- else
- arghint+=" ";
+ if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) {
- if (i==p_argidx) {
- arghint+=String::chr(0xFFFF);
- }
- String n = m->get_argument_info(i).name;
- int dp = n.find(":");
- if (dp!=-1)
- n=n.substr(0,dp);
- arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n;
- int deffrom = m->get_argument_count()-m->get_default_argument_count();
+ List<PropertyInfo> props;
+ Globals::get_singleton()->get_property_list(&props);
+
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ // print_line("found "+s);
+ String name = s.get_slice("/",1);
+ result.insert("\"/root/"+name+"\"");
+ }
+ }
- if (i>=deffrom) {
- int defidx = i-deffrom;
+ Object *obj=id.value;
+ if (obj) {
+ List<String> options;
+ obj->get_argument_options(p_method,p_argidx,&options);
- if (defidx>=0 && defidx<m->get_default_argument_count()) {
- Variant v= m->get_default_argument(i);
- arghint+="="+v.get_construct_string();
+ for(List<String>::Element *E=options.front();E;E=E->next()) {
+
+ result.insert(E->get());
+ }
}
- }
- if (i==p_argidx) {
- arghint+=String::chr(0xFFFF);
}
- }
- if (m->get_argument_count()>0)
- arghint+=" ";
+ arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
+ for(int i=0;i<m->get_argument_count();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
- arghint+=")";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ String n = m->get_argument_info(i).name;
+ int dp = n.find(":");
+ if (dp!=-1)
+ n=n.substr(0,dp);
+ arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n;
+ int deffrom = m->get_argument_count()-m->get_default_argument_count();
+
+
+ if (i>=deffrom) {
+ int defidx = i-deffrom;
+
+ if (defidx>=0 && defidx<m->get_default_argument_count()) {
+ Variant v= m->get_default_argument(i);
+ arghint+="="+v.get_construct_string();
+ }
+ }
+
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+
+ }
+ if (m->get_argument_count()>0)
+ arghint+=" ";
+
+
+ arghint+=")";
+ }
}
}
@@ -1414,7 +1709,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
arghint+=")";
} else if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
- //complete built-in function
+ //complete constructor
const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode*>(op->arguments[0]);
List<MethodInfo> mil;
@@ -1549,7 +1844,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
}
} else {
-
+ //indexed lookup
GDCompletionIdentifier ci;
if (_guess_expression_type(context,op->arguments[0],p_line,ci)) {
@@ -1661,7 +1956,9 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
//print_line( p_code.replace(String::chr(0xFFFF),"<cursor>"));
GDParser p;
- Error err = p.parse(p_code,p_base_path,true);
+ //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+ Error err = p.parse(p_code,p_base_path,false,"",true);
bool isfunction=false;
Set<String> options;
@@ -1713,20 +2010,123 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
+ Ref<GDScript> on_script;
if (t.value.get_type()) {
Object *obj=t.value;
+
+
if (obj) {
+
+
GDScript *scr = obj->cast_to<GDScript>();
+ if (scr) {
+ while (scr) {
+
+ if (!isfunction) {
+ for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+ options.insert(E->key());
+ }
+ }
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (E->get().is_static())
+ options.insert(E->key());
+ }
+
+ if (scr->get_base().is_valid())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
+ } else {
+ on_script=obj->get_script();
+ }
+ }
+ }
+
+
+ if (!on_script.is_valid() && t.script.is_valid()) {
+ on_script=t.script;
+ }
+
+ if (on_script.is_valid()) {
+
+ GDScript *scr = on_script.ptr();
+ if (scr) {
while (scr) {
- if (!isfunction) {
- for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
- options.insert(E->key());
+ String code = scr->get_source_code();
+
+ if (code!="") {
+ //if there is code, parse it. This way is slower but updates in real-time
+ GDParser p;
+ //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+ Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false);
+
+ if (err==OK) {
+ //only if ok, otherwise use what is cached on the script
+ //GDParser::ClassNode *base = p.
+ const GDParser::Node *root = p.get_parse_tree();
+ ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_PARSE_ERROR);
+
+ const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
+
+ for(int i=0;i<cl->functions.size();i++) {
+
+ if (cl->functions[i]->arguments.size())
+ options.insert(String(cl->functions[i]->name)+"(");
+ else
+ options.insert(String(cl->functions[i]->name)+"()");
+ }
+
+ for(int i=0;i<cl->static_functions.size();i++) {
+
+ if (cl->static_functions[i]->arguments.size())
+ options.insert(String(cl->static_functions[i]->name)+"(");
+ else
+ options.insert(String(cl->static_functions[i]->name)+"()");
+
+ }
+
+ if (!isfunction) {
+ for(int i=0;i<cl->variables.size();i++) {
+
+ options.insert(String(cl->variables[i].identifier));
+ }
+
+ for(int i=0;i<cl->constant_expressions.size();i++) {
+
+ options.insert(String(cl->constant_expressions[i].identifier));
+ }
+
+ }
+
+
+ } else {
+ code=""; //well, then no code
}
+
}
- for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
- options.insert(E->key());
+
+ if (code=="") {
+ //use class directly, no code was found
+ if (!isfunction) {
+ for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+ options.insert(E->key());
+ }
+ }
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (E->get().get_argument_count())
+ options.insert(String(E->key())+"()");
+ else
+ options.insert(String(E->key())+"(");
+
+ }
+
+ for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) {
+ options.insert(E->get());
+ }
}
if (scr->get_base().is_valid())
@@ -1738,6 +2138,10 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
}
+
+
+
+
if (!isfunction) {
ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options);
}
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index f37b2f645a..37ddb2bc41 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -71,6 +71,7 @@ const char *GDFunctions::get_func_name(Function p_func) {
"randi",
"randf",
"rand_range",
+ "seed",
"rand_seed",
"deg2rad",
"rad2deg",
@@ -87,6 +88,7 @@ const char *GDFunctions::get_func_name(Function p_func) {
"str",
"print",
"printt",
+ "prints",
"printerr",
"printraw",
"var2str",
@@ -97,6 +99,7 @@ const char *GDFunctions::get_func_name(Function p_func) {
"dict2inst",
"hash",
"print_stack",
+ "instance_from_id",
};
return _names[p_func];
@@ -328,6 +331,13 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_NUM(1);
r_ret=Math::random(*p_args[0],*p_args[1]);
} break;
+ case MATH_SEED: {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_NUM(0);
+ uint32_t seed=*p_args[0];
+ Math::seed(seed);
+ r_ret=Variant();
+ } break;
case MATH_RANDSEED: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
@@ -553,6 +563,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
} break;
+ case TEXT_PRINT_SPACED: {
+
+ String str;
+ for(int i=0;i<p_arg_count;i++) {
+
+ if (i)
+ str+=" ";
+ str+=p_args[i]->operator String();
+ }
+
+ //str+="\n";
+ print_line(str);
+ r_ret=Variant();
+
+
+ } break;
case TEXT_PRINTERR: {
@@ -575,7 +601,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
}
//str+="\n";
- OS::get_singleton()->print("%s\n",str.utf8().get_data());
+ OS::get_singleton()->print("%s",str.utf8().get_data());
r_ret=Variant();
} break;
@@ -895,6 +921,20 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
};
} break;
+ case INSTANCE_FROM_ID: {
+
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type()!=Variant::INT && p_args[0]->get_type()!=Variant::REAL) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_ret=Variant();
+ break;
+ }
+
+ uint32_t id=*p_args[0];
+ r_ret=ObjectDB::get_instance(id);
+
+ } break;
case FUNC_MAX: {
ERR_FAIL_V();
@@ -1130,6 +1170,11 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type=Variant::REAL;
return mi;
} break;
+ case MATH_SEED: {
+ MethodInfo mi("seed",PropertyInfo(Variant::REAL,"seed"));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+ } break;
case MATH_RANDSEED: {
MethodInfo mi("rand_seed",PropertyInfo(Variant::REAL,"seed"));
mi.return_val.type=Variant::ARRAY;
@@ -1224,6 +1269,13 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
+ case TEXT_PRINT_SPACED: {
+
+ MethodInfo mi("prints",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"..."));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+
+ } break;
case TEXT_PRINTERR: {
MethodInfo mi("printerr",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"..."));
@@ -1288,6 +1340,12 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
+ case INSTANCE_FROM_ID: {
+ MethodInfo mi("instance_from_id",PropertyInfo(Variant::INT,"instance_id"));
+ mi.return_val.type=Variant::OBJECT;
+ return mi;
+ } break;
+
case FUNC_MAX: {
ERR_FAIL_V(MethodInfo());
diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h
index 05ff6a2e73..ad35a628d5 100644
--- a/modules/gdscript/gd_functions.h
+++ b/modules/gdscript/gd_functions.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -67,6 +67,7 @@ public:
MATH_RAND,
MATH_RANDF,
MATH_RANDOM,
+ MATH_SEED,
MATH_RANDSEED,
MATH_DEG2RAD,
MATH_RAD2DEG,
@@ -83,6 +84,7 @@ public:
TEXT_STR,
TEXT_PRINT,
TEXT_PRINT_TABBED,
+ TEXT_PRINT_SPACED,
TEXT_PRINTERR,
TEXT_PRINTRAW,
VAR_TO_STR,
@@ -93,6 +95,7 @@ public:
DICT2INST,
HASH,
PRINT_STACK,
+ INSTANCE_FROM_ID,
FUNC_MAX
};
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index aa2878f9e1..afe8c9aa71 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,7 @@
#include "print_string.h"
#include "io/resource_loader.h"
#include "os/file_access.h"
+#include "script_language.h"
template<class T>
T* GDParser::alloc_node() {
@@ -116,6 +117,14 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
_make_completable_call(argidx);
completion_node=p_parent;
+ } else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING && tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) {
+ //completing a string argument..
+ completion_cursor=tokenizer->get_token_constant();
+
+ _make_completable_call(argidx);
+ completion_node=p_parent;
+ tokenizer->advance(1);
+ return false;
}
Node*arg = _parse_expression(p_parent,p_static);
@@ -277,7 +286,11 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
if (!validating) {
//this can be too slow for just validating code
- res = ResourceLoader::load(path);
+ if (for_completion && ScriptCodeCompletionCache::get_sigleton()) {
+ res = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path);
+ } else {
+ res = ResourceLoader::load(path);
+ }
if (!res.is_valid()) {
_set_error("Can't preload resource at path: "+path);
return NULL;
@@ -1075,6 +1088,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
ConstantNode *cn = alloc_node<ConstantNode>();
Array arr(!p_to_const);
+ //print_line("mk array "+itos(!p_to_const));
arr.resize(an->elements.size());
for(int i=0;i<an->elements.size();i++) {
ConstantNode *acn = static_cast<ConstantNode*>(an->elements[i]);
@@ -1461,7 +1475,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
} break;
case GDTokenizer::TK_CF_PASS: {
- if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE ) {
+ if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE && tokenizer->get_token(1)!=GDTokenizer::TK_EOF) {
_set_error("Expected ';' or <NewLine>.");
return;
@@ -1519,8 +1533,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
op->arguments.push_back(assigned);
p_block->statements.push_back(op);
- _end_statement();
-
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (var)");
+ return;
+ }
} break;
case GDTokenizer::TK_CF_IF: {
@@ -1945,8 +1961,10 @@ void GDParser::_parse_class(ClassNode *p_class) {
_parse_extends(p_class);
if (error_set)
return;
- _end_statement();
-
+ if (!_end_statement()) {
+ _set_error("Expected end of statement after extends");
+ return;
+ }
} break;
case GDTokenizer::TK_PR_TOOL: {
@@ -2226,6 +2244,53 @@ void GDParser::_parse_class(ClassNode *p_class) {
//arguments
} break;
+ case GDTokenizer::TK_PR_SIGNAL: {
+ tokenizer->advance();
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier after 'signal'.");
+ return;
+ }
+
+ ClassNode::Signal sig;
+ sig.name = tokenizer->get_token_identifier();
+ tokenizer->advance();
+
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) {
+ tokenizer->advance();
+ while(true) {
+
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ tokenizer->advance();
+ break;
+ }
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier in signal argument.");
+ return;
+ }
+
+ sig.arguments.push_back(tokenizer->get_token_identifier());
+ tokenizer->advance();
+
+ if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
+ tokenizer->advance();
+ } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ',' or ')' after signal parameter identifier.");
+ return;
+ }
+ }
+ }
+
+ p_class->_signals.push_back(sig);
+
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (signal)");
+ return;
+ }
+ } break;
case GDTokenizer::TK_PR_EXPORT: {
tokenizer->advance();
@@ -2643,8 +2708,10 @@ void GDParser::_parse_class(ClassNode *p_class) {
p_class->variables.push_back(member);
- _end_statement();
-
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (continue)");
+ return;
+ }
} break;
case GDTokenizer::TK_PR_CONST: {
//variale declaration and (eventual) initialization
@@ -2681,8 +2748,10 @@ void GDParser::_parse_class(ClassNode *p_class) {
p_class->constant_expressions.push_back(constant);
- _end_statement();
-
+ if (!_end_statement()) {
+ _set_error("Expected end of statement (constant)");
+ return;
+ }
} break;
@@ -2758,6 +2827,8 @@ Error GDParser::_parse(const String& p_base_path) {
Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) {
+ for_completion=false;
+ validating=false;
completion_type=COMPLETION_NONE;
completion_node=NULL;
completion_class=NULL;
@@ -2778,7 +2849,7 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p
}
-Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) {
+Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path,bool p_for_completion) {
completion_type=COMPLETION_NONE;
completion_node=NULL;
@@ -2795,6 +2866,7 @@ Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_ju
tt->set_code(p_code);
validating=p_just_validate;
+ for_completion=p_for_completion;
tokenizer=tt;
Error ret = _parse(p_base_path);
memdelete(tt);
@@ -2830,6 +2902,7 @@ void GDParser::clear() {
current_function=NULL;
validating=false;
+ for_completion=false;
error_set=false;
tab_level.clear();
tab_level.push_back(0);
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index 44e7b55323..fd8a2576fa 100644
--- a/modules/gdscript/gd_parser.h
+++ b/modules/gdscript/gd_parser.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -76,6 +76,7 @@ public:
StringName extends_file;
Vector<StringName> extends_class;
+
struct Member {
PropertyInfo _export;
#ifdef TOOLS_ENABLED
@@ -92,11 +93,17 @@ public:
Node *expression;
};
+ struct Signal {
+ StringName name;
+ Vector<StringName> arguments;
+ };
+
Vector<ClassNode*> subclasses;
Vector<Member> variables;
Vector<Constant> constant_expressions;
Vector<FunctionNode*> functions;
Vector<FunctionNode*> static_functions;
+ Vector<Signal> _signals;
BlockNode *initializer;
ClassNode *owner;
//Vector<Node*> initializers;
@@ -380,6 +387,7 @@ private:
T* alloc_node();
bool validating;
+ bool for_completion;
int parenthesis;
bool error_set;
String error;
@@ -436,7 +444,7 @@ public:
String get_error() const;
int get_error_line() const;
int get_error_column() const;
- Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="");
+ Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path="",const String& p_self_path="");
const Node *get_parse_tree() const;
diff --git a/modules/gdscript/gd_pretty_print.cpp b/modules/gdscript/gd_pretty_print.cpp
index a5a993bb3a..9c290eac4a 100644
--- a/modules/gdscript/gd_pretty_print.cpp
+++ b/modules/gdscript/gd_pretty_print.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gd_pretty_print.h b/modules/gdscript/gd_pretty_print.h
index fbf002295b..998fdc53ab 100644
--- a/modules/gdscript/gd_pretty_print.h
+++ b/modules/gdscript/gd_pretty_print.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index 06c746c4fb..53ae0c8702 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -140,7 +140,7 @@ String GDFunction::_get_call_error(const Variant::CallError& p_err, const String
} else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments.";
} else if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) {
- err_text="Invalid call. Unexisting "+p_where+".";
+ err_text="Invalid call. Nonexistent "+p_where+".";
} else if (p_err.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
err_text="Attempt to call "+p_where+" on a null instance.";
} else {
@@ -335,17 +335,30 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(b,3);
GET_VARIANT_PTR(dst,4);
+#ifdef DEBUG_ENABLED
+ Variant ret;
+ Variant::evaluate(op,*a,*b,ret,valid);
+#else
Variant::evaluate(op,*a,*b,*dst,valid);
+#endif
+
if (!valid) {
- if (dst->get_type()==Variant::STRING) {
+#ifdef DEBUG_ENABLED
+
+ if (ret.get_type()==Variant::STRING) {
//return a string when invalid with the error
- err_text=*dst;
+ err_text=ret;
err_text += " in operator '"+Variant::get_operator_name(op)+"'.";
} else {
err_text="Invalid operands '"+Variant::get_type_name(a->get_type())+"' and '"+Variant::get_type_name(b->get_type())+"' in operator '"+Variant::get_operator_name(op)+"'.";
}
+#endif
break;
+
}
+#ifdef DEBUG_ENABLED
+ *dst=ret;
+#endif
ip+=5;
@@ -457,8 +470,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(dst,3);
bool valid;
+#ifdef DEBUG_ENABLED
+//allow better error message in cases where src and dst are the same stack position
+ Variant ret = src->get(*index,&valid);
+#else
*dst = src->get(*index,&valid);
+#endif
if (!valid) {
String v = index->operator String();
if (v!="") {
@@ -469,6 +487,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
err_text="Invalid get index "+v+" (on base: '"+_get_var_type(src)+"').";
break;
}
+#ifdef DEBUG_ENABLED
+ *dst=ret;
+#endif
ip+=4;
} continue;
case OPCODE_SET_NAMED: {
@@ -508,7 +529,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
const StringName *index = &_global_names_ptr[indexname];
bool valid;
+#ifdef DEBUG_ENABLED
+//allow better error message in cases where src and dst are the same stack position
+ Variant ret = src->get_named(*index,&valid);
+
+#else
*dst = src->get_named(*index,&valid);
+#endif
if (!valid) {
if (src->has_method(*index)) {
@@ -518,7 +545,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
break;
}
-
+#ifdef DEBUG_ENABLED
+ *dst=ret;
+#endif
ip+=4;
} continue;
case OPCODE_ASSIGN: {
@@ -1689,7 +1718,7 @@ bool GDScript::_update_exports() {
}
- if (c->extends_used && String(c->extends_file)!="") {
+ if (c->extends_used && String(c->extends_file)!="" && String(c->extends_file) != get_path()) {
String path = c->extends_file;
if (path.is_rel_path()) {
@@ -1727,6 +1756,12 @@ bool GDScript::_update_exports() {
//print_line("found "+c->variables[i]._export.name);
member_default_values_cache[c->variables[i].identifier]=c->variables[i].default_value;
}
+
+ _signals.clear();
+
+ for(int i=0;i<c->_signals.size();i++) {
+ _signals[c->_signals[i].name]=c->_signals[i].arguments;
+ }
}
} else {
//print_line("unchaged is "+get_path());
@@ -1942,9 +1977,17 @@ void GDScript::_bind_methods() {
ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo("new"));
+ ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code);
+
}
+Vector<uint8_t> GDScript::get_as_byte_code() const {
+
+ GDTokenizerBuffer tokenizer;
+ return tokenizer.parse_code_string(source);
+};
+
Error GDScript::load_byte_code(const String& p_path) {
@@ -2071,6 +2114,47 @@ Ref<GDScript> GDScript::get_base() const {
return base;
}
+bool GDScript::has_script_signal(const StringName& p_signal) const {
+ if (_signals.has(p_signal))
+ return true;
+ if (base.is_valid()) {
+ return base->has_script_signal(p_signal);
+ }
+#ifdef TOOLS_ENABLED
+ else if (base_cache.is_valid()){
+ return base_cache->has_script_signal(p_signal);
+ }
+
+#endif
+ return false;
+}
+void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+
+ for(const Map<StringName,Vector<StringName> >::Element *E=_signals.front();E;E=E->next()) {
+
+ MethodInfo mi;
+ mi.name=E->key();
+ for(int i=0;i<E->get().size();i++) {
+ PropertyInfo arg;
+ arg.name=E->get()[i];
+ mi.arguments.push_back(arg);
+ }
+ r_signals->push_back(mi);
+ }
+
+ if (base.is_valid()) {
+ base->get_script_signal_list(r_signals);
+ }
+#ifdef TOOLS_ENABLED
+ else if (base_cache.is_valid()){
+ base_cache->get_script_signal_list(r_signals);
+ }
+
+#endif
+
+}
+
+
GDScript::GDScript() {
@@ -2102,7 +2186,6 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) {
{
const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
if (E) {
- members[E->get().index]=p_value;
if (E->get().setter) {
const Variant *val=&p_value;
Variant::CallError err;
@@ -2111,6 +2194,8 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) {
return true; //function exists, call was successful
}
}
+ else
+ members[E->get().index] = p_value;
return true;
}
}
@@ -2479,9 +2564,9 @@ void GDScriptLanguage::init() {
//populate native classes
- List<String> class_list;
+ List<StringName> class_list;
ObjectTypeDB::get_type_list(&class_list);
- for(List<String>::Element *E=class_list.front();E;E=E->next()) {
+ for(List<StringName>::Element *E=class_list.front();E;E=E->next()) {
StringName n = E->get();
String s = String(n);
@@ -2564,6 +2649,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"static",
"float",
"int",
+ "signal",
0};
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index 5574b30d44..1e1279d5f5 100644
--- a/modules/gdscript/gd_script.h
+++ b/modules/gdscript/gd_script.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -260,6 +260,7 @@ friend class GDScriptLanguage;
Map<StringName,GDFunction> member_functions;
Map<StringName,MemberInfo> member_indices; //members are just indices to the instanced script.
Map<StringName,Ref<GDScript> > subclasses;
+ Map<StringName,Vector<StringName> > _signals;
#ifdef TOOLS_ENABLED
@@ -318,6 +319,9 @@ public:
const Map<StringName,GDFunction>& get_member_functions() const { return member_functions; }
const Ref<GDNativeClass>& get_native() const { return native; }
+ virtual bool has_script_signal(const StringName& p_signal) const;
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
+
bool is_tool() const { return tool; }
Ref<GDScript> get_base() const;
@@ -345,6 +349,8 @@ public:
Error load_source_code(const String& p_path);
Error load_byte_code(const String& p_path);
+ Vector<uint8_t> get_as_byte_code() const;
+
virtual ScriptLanguage *get_language() const;
GDScript();
diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp
index 1979577a17..8b25b38bd3 100644
--- a/modules/gdscript/gd_tokenizer.cpp
+++ b/modules/gdscript/gd_tokenizer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -568,7 +568,10 @@ void GDTokenizerText::_advance() {
} else if( string_mode!=STRING_MULTILINE && CharType(GETCHAR(i))=='\n') {
_make_error("Unexpected EOL at String.");
return;
-
+ } else if( CharType(GETCHAR(i))==0xFFFF) {
+ //string ends here, next will be TK
+ i--;
+ break;
} else if (CharType(GETCHAR(i))=='\\') {
//escaped characters...
i++;
@@ -670,19 +673,19 @@ void GDTokenizerText::_advance() {
while(true) {
if (GETCHAR(i)=='.') {
if (period_found || exponent_found) {
- _make_error("Invalid numeric constant at '.'");
+ _make_error("Invalid numeric constant at '.'");
return;
}
period_found=true;
} else if (GETCHAR(i)=='x') {
- if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) {
- _make_error("Invalid numeric constant at 'x'");
+ if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) {
+ _make_error("Invalid numeric constant at 'x'");
return;
}
hexa_found=true;
- } else if (!hexa_found && GETCHAR(i)=='e') {
+ } else if (!hexa_found && GETCHAR(i)=='e') {
if (hexa_found || exponent_found) {
- _make_error("Invalid numeric constant at 'e'");
+ _make_error("Invalid numeric constant at 'e'");
return;
}
exponent_found=true;
@@ -692,7 +695,7 @@ void GDTokenizerText::_advance() {
} else if ((GETCHAR(i)=='-' || GETCHAR(i)=='+') && exponent_found) {
if (sign_found) {
- _make_error("Invalid numeric constant at '-'");
+ _make_error("Invalid numeric constant at '-'");
return;
}
sign_found=true;
@@ -703,20 +706,20 @@ void GDTokenizerText::_advance() {
i++;
}
- if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) {
- _make_error("Invalid numeric constant: "+str);
+ if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) {
+ _make_error("Invalid numeric constant: "+str);
return;
}
INCPOS(str.length());
- if (hexa_found) {
- int val = str.hex_to_int();
- _make_constant(val);
- } else if (period_found) {
+ if (hexa_found) {
+ int val = str.hex_to_int();
+ _make_constant(val);
+ } else if (period_found) {
real_t val = str.to_double();
//print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val));
_make_constant(val);
- } else {
+ } else {
int val = str.to_int();
_make_constant(val);
@@ -825,7 +828,7 @@ void GDTokenizerText::_advance() {
_make_built_in_func(GDFunctions::Function(i));
found=true;
- break;
+ break;
}
}
@@ -856,6 +859,7 @@ void GDTokenizerText::_advance() {
{TK_PR_PRELOAD,"preload"},
{TK_PR_ASSERT,"assert"},
{TK_PR_YIELD,"yield"},
+ {TK_PR_SIGNAL,"signal"},
{TK_PR_CONST,"const"},
//controlflow
{TK_CF_IF,"if"},
@@ -1036,7 +1040,7 @@ void GDTokenizerText::advance(int p_amount) {
//////////////////////////////////////////////////////////////////////////////////////////////////////
-#define BYTECODE_VERSION 3
+#define BYTECODE_VERSION 5
Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h
index ff59c249a7..d6bd63c5b8 100644
--- a/modules/gdscript/gd_tokenizer.h
+++ b/modules/gdscript/gd_tokenizer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -104,6 +104,7 @@ public:
TK_PR_PRELOAD,
TK_PR_ASSERT,
TK_PR_YIELD,
+ TK_PR_SIGNAL,
TK_BRACKET_OPEN,
TK_BRACKET_CLOSE,
TK_CURLY_BRACKET_OPEN,
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index ff7c2734df..9eb5d1846b 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 441b274e33..4f0daf329f 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -130,8 +130,8 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
} else if (name.begins_with("areas/")) {
- int which = name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int which = name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (what=="bounds") {
ERR_FAIL_COND_V(area_map.has(which),false);
create_area(which,p_value);
@@ -215,8 +215,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const {
r_ret= d;
} else if (name.begins_with("areas/")) {
- int which = name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int which = name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (what=="bounds")
r_ret= area_get_bounds(which);
else if (what=="name")
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index df805d99fa..dff9fe3d68 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index f2afffd321..3d56b04cac 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -61,7 +61,7 @@ void GridMapEditor::_menu_option(int p_option) {
case MENU_OPTION_CONFIGURE: {
-
+
} break;
case MENU_OPTION_LOCK_VIEW: {
@@ -522,7 +522,9 @@ void GridMapEditor::_duplicate_paste() {
}
bool GridMapEditor::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) {
-
+ if (!node) {
+ return false;
+ }
if (edit_mode->get_selected()==0) { // regular click
switch (p_event.type) {
@@ -706,9 +708,40 @@ struct _CGMEItemSort {
};
+void GridMapEditor::_set_display_mode(int p_mode) {
+ if (display_mode==p_mode) {
+ return;
+ }
+
+ if (p_mode == DISPLAY_LIST) {
+ mode_list->set_pressed(true);
+ mode_thumbnail->set_pressed(false);
+ } else if (p_mode == DISPLAY_THUMBNAIL) {
+ mode_list->set_pressed(false);
+ mode_thumbnail->set_pressed(true);
+ }
+
+ display_mode=p_mode;
+
+ update_pallete();
+}
+
void GridMapEditor::update_pallete() {
+ int selected = theme_pallete->get_current();
theme_pallete->clear();
+ if (display_mode == DISPLAY_THUMBNAIL) {
+ theme_pallete->set_max_columns(0);
+ theme_pallete->set_icon_mode(ItemList::ICON_MODE_TOP);
+ } else if (display_mode == DISPLAY_LIST){
+ theme_pallete->set_max_columns(1);
+ theme_pallete->set_icon_mode(ItemList::ICON_MODE_LEFT);
+ }
+
+ float min_size = EDITOR_DEF("grid_map/preview_size",64);
+ theme_pallete->set_min_icon_size(Size2(min_size, min_size));
+ theme_pallete->set_fixed_column_width(min_size*3/2);
+ theme_pallete->set_max_text_lines(2);
Ref<MeshLibrary> theme = node->get_theme();
@@ -720,10 +753,6 @@ void GridMapEditor::update_pallete() {
Vector<int> ids;
ids = theme->get_item_list();
- TreeItem *root = theme_pallete->create_item(NULL);
- theme_pallete->set_hide_root(true);
- TreeItem *selected=NULL;
-
List<_CGMEItemSort> il;
for(int i=0;i<ids.size();i++) {
@@ -734,45 +763,31 @@ void GridMapEditor::update_pallete() {
}
il.sort();
- int col=0;
- TreeItem *ti=NULL;
- int selected_col=0;
+ int item = 0;
for(List<_CGMEItemSort>::Element *E=il.front();E;E=E->next()) {
-
int id = E->get().id;
- if (col==0) {
- ti = theme_pallete->create_item(root);
- }
+ theme_pallete->add_item("");
String name=theme->get_item_name(id);
Ref<Texture> preview = theme->get_item_preview(id);
if (!preview.is_null()) {
-
- ti->set_cell_mode(col,TreeItem::CELL_MODE_ICON);
- ti->set_icon(col,preview);
- ti->set_tooltip(col,name);
- } else {
-
- ti->set_text(col,name);
+ theme_pallete->set_item_icon(item, preview);
+ theme_pallete->set_item_tooltip(item, name);
}
- ti->set_metadata(col,id);
-
- if (selected_pallete==id) {
- selected=ti;
- selected_col=col;
+ if (name!="") {
+ theme_pallete->set_item_text(item,name);
}
+ theme_pallete->set_item_metadata(item, id);
- col++;
- if (col==theme_pallete->get_columns())
- col=0;
-
+ item++;
}
- if (selected)
- selected->select(selected_col);
+ if (selected!=-1) {
+ theme_pallete->select(selected);
+ }
last_theme=theme.operator->();
}
@@ -842,6 +857,9 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,false);
}
+
+ VisualServer::get_singleton()->instance_geometry_set_flag(cursor_instance, VS::INSTANCE_FLAG_VISIBLE,false);
+
_clear_areas();
return;
@@ -868,7 +886,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
{
//update grids
- RID indicator_mat = VisualServer::get_singleton()->fixed_material_create();
+ indicator_mat = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true );
VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false );
@@ -922,7 +940,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
d[VS::ARRAY_VERTEX]=grid_points[i];
d[VS::ARRAY_COLOR]=grid_colors[i];
VisualServer::get_singleton()->mesh_add_surface(grid[i],VisualServer::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat);
}
@@ -951,7 +969,7 @@ void GridMapEditor::update_grid() {
grid_xform.origin.x-=1; //force update in hackish way.. what do i care
- VS *vs = VS::get_singleton();
+ //VS *vs = VS::get_singleton();
grid_ofs[edit_axis]=edit_floor[edit_axis]*node->get_cell_size();
@@ -976,7 +994,7 @@ void GridMapEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
- theme_pallete->connect("cell_selected", this,"_item_selected_cbk");
+ theme_pallete->connect("item_selected", this,"_item_selected_cbk");
edit_mode->connect("item_selected", this,"_edit_mode_changed");
area_list->connect("item_edited", this,"_area_renamed");
area_list->connect("item_selected", this,"_area_selected");
@@ -1014,7 +1032,7 @@ void GridMapEditor::_notification(int p_what) {
if (xf!=grid_xform) {
for(int i=0;i<3;i++) {
-
+
VS::get_singleton()->instance_set_transform(grid_instance[i],xf * edit_grid_xform);
}
grid_xform=xf;
@@ -1043,7 +1061,9 @@ void GridMapEditor::_notification(int p_what) {
}
void GridMapEditor::_update_cursor_instance() {
-
+ if (!node) {
+ return;
+ }
if (cursor_instance.is_valid())
VisualServer::get_singleton()->free(cursor_instance);
@@ -1063,18 +1083,8 @@ void GridMapEditor::_update_cursor_instance() {
}
-void GridMapEditor::_item_selected_cbk() {
-
- TreeItem *it = theme_pallete->get_selected();
- if (it) {
-
- selected_pallete=it->get_metadata(theme_pallete->get_selected_column());
-
- } else {
-
- selected_pallete=-1;
-
- }
+void GridMapEditor::_item_selected_cbk(int idx) {
+ selected_pallete=theme_pallete->get_item_metadata(idx);
_update_cursor_instance();
@@ -1092,7 +1102,9 @@ void GridMapEditor::_clear_areas() {
}
void GridMapEditor::_update_areas_display() {
-
+ if (!node) {
+ return;
+ }
_clear_areas();
List<int> areas;
@@ -1179,7 +1191,7 @@ void GridMapEditor::_bind_methods() {
ObjectTypeDB::bind_method("_area_selected",&GridMapEditor::_area_selected);
ObjectTypeDB::bind_method("_floor_changed",&GridMapEditor::_floor_changed);
-
+ ObjectTypeDB::bind_method(_MD("_set_display_mode","mode"), &GridMapEditor::_set_display_mode);
}
@@ -1240,6 +1252,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
clip_mode=CLIP_DISABLED;
options->get_popup()->connect("item_pressed", this,"_menu_option");
+ HBoxContainer *hb = memnew( HBoxContainer );
+ add_child(hb);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
edit_mode = memnew(OptionButton);
edit_mode->set_area_as_parent_rect();
@@ -1247,13 +1262,27 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
edit_mode->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,14);;
edit_mode->add_item("Tiles");
edit_mode->add_item("Areas");
- add_child(edit_mode);
-
+ hb->add_child(edit_mode);
+ edit_mode->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ mode_thumbnail = memnew( ToolButton );
+ mode_thumbnail->set_toggle_mode(true);
+ mode_thumbnail->set_pressed(true);
+ mode_thumbnail->set_icon(p_editor->get_gui_base()->get_icon("FileThumbnail","EditorIcons"));
+ hb->add_child(mode_thumbnail);
+ mode_thumbnail->connect("pressed", this, "_set_display_mode", varray(DISPLAY_THUMBNAIL));
+
+ mode_list = memnew( ToolButton );
+ mode_list->set_toggle_mode(true);
+ mode_list->set_pressed(false);
+ mode_list->set_icon(p_editor->get_gui_base()->get_icon("FileList", "EditorIcons"));
+ hb->add_child(mode_list);
+ mode_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST));
+
+ display_mode = DISPLAY_THUMBNAIL;
selected_area=-1;
-
- theme_pallete = memnew( Tree );
- theme_pallete->set_columns(3);
+ theme_pallete = memnew( ItemList );
add_child(theme_pallete);
theme_pallete->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -1340,7 +1369,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
Array d;
d.resize(VS::ARRAY_MAX);
- RID inner_mat = VisualServer::get_singleton()->fixed_material_create();
+ inner_mat = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(inner_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.3));
VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_ONTOP,true);
VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_UNSHADED,true);
@@ -1349,9 +1378,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=triangles;
VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_TRIANGLES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat);
- RID outer_mat = VisualServer::get_singleton()->fixed_material_create();
+ outer_mat = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(outer_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.8));
VisualServer::get_singleton()->material_set_line_width(outer_mat,3.0);
VisualServer::get_singleton()->material_set_flag(outer_mat,VS::MATERIAL_FLAG_ONTOP,true);
@@ -1361,10 +1390,10 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=lines;
VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat);
- RID inner_mat_dup = VisualServer::get_singleton()->fixed_material_create();
+ inner_mat_dup = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(inner_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.3));
VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_ONTOP,true);
VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_UNSHADED,true);
@@ -1373,9 +1402,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=triangles;
VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_TRIANGLES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup);
- RID outer_mat_dup = VisualServer::get_singleton()->fixed_material_create();
+ outer_mat_dup = VisualServer::get_singleton()->fixed_material_create();
VisualServer::get_singleton()->fixed_material_set_param(outer_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.8));
VisualServer::get_singleton()->material_set_line_width(outer_mat_dup,3.0);
VisualServer::get_singleton()->material_set_flag(outer_mat_dup,VS::MATERIAL_FLAG_ONTOP,true);
@@ -1385,7 +1414,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
d[VS::ARRAY_VERTEX]=lines;
VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_LINES,d);
- VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup,true);
+ VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup);
}
@@ -1409,6 +1438,11 @@ GridMapEditor::~GridMapEditor() {
VisualServer::get_singleton()->free(cursor_instance);
}
+ VisualServer::get_singleton()->free(inner_mat);
+ VisualServer::get_singleton()->free(outer_mat);
+ VisualServer::get_singleton()->free(inner_mat_dup);
+ VisualServer::get_singleton()->free(outer_mat_dup);
+
VisualServer::get_singleton()->free(selection_mesh);
if (selection_instance.is_valid())
VisualServer::get_singleton()->free(selection_instance);
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 1240d78426..26fe8f20dc 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,10 +40,8 @@
class SpatialEditorPlugin;
class GridMapEditor : public VBoxContainer {
-
OBJ_TYPE(GridMapEditor, VBoxContainer );
-
enum {
GRID_CURSOR_SIZE=50
@@ -66,6 +64,10 @@ class GridMapEditor : public VBoxContainer {
CLIP_BELOW
};
+ enum DisplayMode {
+ DISPLAY_THUMBNAIL,
+ DISPLAY_LIST
+ };
UndoRedo *undo_redo;
InputAction input_action;
@@ -73,6 +75,8 @@ class GridMapEditor : public VBoxContainer {
MenuButton * options;
SpinBox *floor;
OptionButton *edit_mode;
+ ToolButton *mode_thumbnail;
+ ToolButton *mode_list;
HBoxContainer *spatial_editor_hb;
struct SetItem {
@@ -105,6 +109,13 @@ class GridMapEditor : public VBoxContainer {
RID duplicate_mesh;
RID duplicate_instance;
+ RID indicator_mat;
+
+ RID inner_mat;
+ RID outer_mat;
+ RID inner_mat_dup;
+ RID outer_mat_dup;
+
bool updating;
@@ -125,6 +136,7 @@ class GridMapEditor : public VBoxContainer {
Vector3 cursor_origin;
Vector3 last_mouseover;
+ int display_mode;
int selected_pallete;
int selected_area;
int cursor_rot;
@@ -176,9 +188,10 @@ class GridMapEditor : public VBoxContainer {
void _configure();
void _menu_option(int);
void update_pallete();
- Tree *theme_pallete;
+ void _set_display_mode(int p_mode);
+ ItemList *theme_pallete;
Tree *area_list;
- void _item_selected_cbk();
+ void _item_selected_cbk(int idx);
void _update_cursor_transform();
void _update_cursor_instance();
void _update_clip();
diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp
index 887687a37b..2bc440759d 100644
--- a/modules/gridmap/register_types.cpp
+++ b/modules/gridmap/register_types.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h
index 5cddb96b70..326d7acf24 100644
--- a/modules/gridmap/register_types.h
+++ b/modules/gridmap/register_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */