2
0
Эх сурвалжийг харах

Merge pull request #2274 from MarianoGnu/master

Improve Visual Shader Editor responsiveness
Juan Linietsky 10 жил өмнө
parent
commit
1db523d0bb

+ 32 - 32
core/object.h

@@ -49,7 +49,7 @@
 
 enum PropertyHint {
 	PROPERTY_HINT_NONE, ///< no hint provided.
-	PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step"
+	PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional"
 	PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit
 	PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
 	PROPERTY_HINT_EXP_EASING, /// exponential easing funciton (Math::ease)
@@ -58,12 +58,12 @@ enum PropertyHint {
 	PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
 	PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
 	PROPERTY_HINT_ALL_FLAGS,
-	PROPERTY_HINT_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc," 
+	PROPERTY_HINT_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
 	PROPERTY_HINT_DIR, ///< a directort path must be passed
 	PROPERTY_HINT_GLOBAL_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
 	PROPERTY_HINT_GLOBAL_DIR, ///< a directort path must be passed
 	PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type
-	PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines	
+	PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines
 	PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
@@ -71,7 +71,7 @@ enum PropertyHint {
 };
 
 enum PropertyUsageFlags {
-	
+
 	PROPERTY_USAGE_STORAGE=1,
 	PROPERTY_USAGE_EDITOR=2,
 	PROPERTY_USAGE_NETWORK=4,
@@ -102,15 +102,15 @@ enum PropertyUsageFlags {
 #define ADD_PROPERTYINO( m_property, m_setter, m_getter, m_index ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), m_setter, m_getter, m_index )
 
 struct PropertyInfo {
-	
-	Variant::Type type;	
+
+	Variant::Type type;
 	String name;
 	PropertyHint hint;
-	String hint_string;	
+	String hint_string;
 	uint32_t usage;
 
 	_FORCE_INLINE_ PropertyInfo added_usage(int p_fl) const { PropertyInfo pi=*this; pi.usage|=p_fl; return pi; }
-	
+
 	PropertyInfo() { type=Variant::NIL; hint=PROPERTY_HINT_NONE; usage = PROPERTY_USAGE_DEFAULT; }
 	PropertyInfo( Variant::Type p_type, const String p_name, PropertyHint p_hint=PROPERTY_HINT_NONE, const String& p_hint_string="",uint32_t p_usage=PROPERTY_USAGE_DEFAULT) {
 		type=p_type; name=p_name; hint=p_hint; hint_string=p_hint_string; usage=p_usage;
@@ -125,23 +125,23 @@ struct PropertyInfo {
 Array convert_property_list(const List<PropertyInfo> * p_list);
 
 struct MethodInfo {
-	
+
 	String name;
 	List<PropertyInfo> arguments;
 	Vector<Variant> default_arguments;
 	PropertyInfo return_val;
 	uint32_t flags;
 	int id;
-	
+
 	inline bool  operator<(const MethodInfo& p_method) const { return id==p_method.id?(name < p_method.name):(id<p_method.id); }
-	
+
 	MethodInfo();
 	MethodInfo(const String& p_name);
 	MethodInfo(const String& p_name, const PropertyInfo& p_param1);
 	MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2);
 	MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3);
 	MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3,const PropertyInfo& p_param4);
-	MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3,const PropertyInfo& p_param4,const PropertyInfo& p_param5);															
+	MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3,const PropertyInfo& p_param4,const PropertyInfo& p_param5);
 	MethodInfo(Variant::Type ret);
 	MethodInfo(Variant::Type ret,const String& p_name);
 	MethodInfo(Variant::Type ret,const String& p_name, const PropertyInfo& p_param1);
@@ -158,7 +158,7 @@ struct MethodInfo {
 //return NULL;
 
 /*
-   the following is an uncomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model. 
+   the following is an uncomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model.
 */
 
 #define REVERSE_GET_PROPERTY_LIST \
@@ -314,7 +314,7 @@ private:
 class ScriptInstance;
 typedef uint32_t ObjectID;
 
-class Object {		
+class Object {
 public:
 
 	enum ConnectFlags {
@@ -404,7 +404,7 @@ friend void postinitialize_handler(Object*);
 
 	void property_list_changed_notify();
 
-protected:	
+protected:
 
 	virtual bool _use_builtin_script() const { return false; }
 	virtual void _initialize_typev() { initialize_type(); }
@@ -412,14 +412,14 @@ protected:
 	virtual bool _getv(const StringName& p_name,Variant &r_property) const { return false; };
 	virtual void _get_property_listv(List<PropertyInfo> *p_list,bool p_reversed) const {};
 	virtual void _notificationv(int p_notification,bool p_reversed) {};
-	
+
 	static String _get_category() { return ""; }
 	static void _bind_methods();
 	bool _set(const StringName& p_name,const Variant &p_property) { return false; };
 	bool _get(const StringName& p_name,Variant &r_property) const { return false;  };
 	void _get_property_list(List<PropertyInfo> *p_list) const {};
 	void _notification(int p_notification) {};
-	
+
 	_FORCE_INLINE_ static void (*_get_bind_methods())() {
 		return &Object::_bind_methods;
 	}
@@ -431,13 +431,13 @@ protected:
 	}
 	_FORCE_INLINE_ void (Object::* (_get_get_property_list() const))(List<PropertyInfo> *p_list) const{
 			return &Object::_get_property_list;
-	}	
+	}
 	_FORCE_INLINE_ void (Object::* (_get_notification() const))(int){
 			return &Object::_notification;
-	}	
+	}
 	static void get_valid_parents_static(List<String> *p_parents);
 	static void _get_valid_parents_static(List<String> *p_parents);
-		
+
 
 	void cancel_delete();
 
@@ -485,7 +485,7 @@ public:
 
 	void add_change_receptor( Object *p_receptor );
 	void remove_change_receptor( Object *p_receptor );
-	
+
 	template<class T>
 	T *cast_to() {
 
@@ -500,7 +500,7 @@ public:
 			return NULL;
 #endif
 	}
-		
+
 	template<class T>
 	const T *cast_to() const {
 
@@ -517,11 +517,11 @@ public:
 	}
 
 	enum {
-		
+
 		NOTIFICATION_POSTINITIALIZE=0,
 		NOTIFICATION_PREDELETE=1
 	};
-	
+
 	/* TYPE API */
 	static void get_inheritance_list_static(List<String>* p_inheritance_list) {  p_inheritance_list->push_back("Object"); }
 
@@ -545,7 +545,7 @@ public:
 			return *_type_ptr;
 		}
 	}
-	
+
 	/* IAPI */
 //	void set(const String& p_name, const Variant& p_value);
 //	Variant get(const String& p_name) const;
@@ -554,7 +554,7 @@ public:
 	Variant get(const StringName& p_name, bool *r_valid=NULL) const;
 
 	void get_property_list(List<PropertyInfo> *p_list,bool p_reversed=false) const;
-	
+
 	bool has_method(const StringName& p_method) const;
 	void get_method_list(List<MethodInfo> *p_list) const;
 	Variant callv(const StringName& p_method,const Array& p_args);
@@ -564,14 +564,14 @@ public:
 	Variant call(const StringName& p_name, VARIANT_ARG_LIST); // C++ helper
 	void call_multilevel(const StringName& p_name, VARIANT_ARG_LIST); // C++ helper
 
-	void notification(int p_notification,bool p_reversed=false);	
+	void notification(int p_notification,bool p_reversed=false);
 
 	//used mainly by script, get and set all INCLUDING string
 	virtual Variant getvar(const Variant& p_key, bool *r_valid=NULL) const;
 	virtual void setvar(const Variant& p_key, const Variant& p_value,bool *r_valid=NULL);
 
 	/* SCRIPT */
-	
+
 	void set_script(const RefPtr& p_script);
 	RefPtr get_script() const;
 
@@ -614,14 +614,14 @@ public:
 	StringName tr(const StringName& p_message) const; //translate message (alternative)
 
 	bool _is_queued_for_deletion; // set to true by SceneTree::queue_delete()
-	bool is_queued_for_deletion() const; 
+	bool is_queued_for_deletion() const;
 
 	_FORCE_INLINE_ void set_message_translation(bool p_enable) { _can_translate=p_enable; }
 	_FORCE_INLINE_ bool can_translate_messages() const { return _can_translate; }
 
 	void clear_internal_resource_paths();
 
-	Object();	
+	Object();
 	virtual ~Object();
 
 };
@@ -649,13 +649,13 @@ class ObjectDB {
 	static HashMap<Object*,ObjectID,ObjectPtrHash> instance_checks;
 
 	static uint32_t instance_counter;
-friend class Object;	
+friend class Object;
 friend void unregister_core_types();
 
 	static void cleanup();
 	static uint32_t add_instance(Object *p_object);
 	static void remove_instance(Object *p_object);
-public:	
+public:
 
 	typedef void (*DebugFunc)(Object *p_obj);
 

+ 193 - 6
scene/gui/graph_edit.cpp

@@ -141,9 +141,6 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
 
 	GraphNode *gn=p_gn->cast_to<GraphNode>();
 	ERR_FAIL_COND(!gn);
-
-	//gn->set_pos(gn->get_offset()+scroll_offset);
-
 	top_layer->update();
 }
 
@@ -172,7 +169,6 @@ void GraphEdit::remove_child_notify(Node *p_child) {
 void GraphEdit::_notification(int p_what) {
 
 	if (p_what==NOTIFICATION_READY) {
-		Size2 size = top_layer->get_size();
 		Size2 hmin = h_scroll->get_combined_minimum_size();
 		Size2 vmin = v_scroll->get_combined_minimum_size();
 
@@ -491,7 +487,8 @@ void GraphEdit::_top_layer_draw() {
 		connections.erase(to_erase.front()->get());
 		to_erase.pop_front();
 	}
-	//draw connections
+	if (box_selecting)
+		top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3));
 }
 
 void GraphEdit::_input_event(const InputEvent& p_ev) {
@@ -500,6 +497,187 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
 		h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x );
 		v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y );
 	}
+
+	if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) {
+
+		just_selected=true;
+		drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
+		for(int i=get_child_count()-1;i>=0;i--) {
+			GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+			if (gn && gn->is_selected())
+				gn->set_offset(gn->get_drag_from()+drag_accum);
+		}
+	}
+
+	if (p_ev.type==InputEvent::MOUSE_MOTION && box_selecting) {
+		box_selecting_to = get_local_mouse_pos();
+
+		box_selecting_rect = Rect2(MIN(box_selecting_from.x,box_selecting_to.x),
+								   MIN(box_selecting_from.y,box_selecting_to.y),
+								   ABS(box_selecting_from.x-box_selecting_to.x),
+								   ABS(box_selecting_from.y-box_selecting_to.y));
+
+		for(int i=get_child_count()-1;i>=0;i--) {
+
+			GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+			if (!gn)
+				continue;
+
+			bool in_box = gn->get_rect().intersects(box_selecting_rect);
+
+			if (in_box)
+				gn->set_selected(box_selection_mode_aditive);
+			else
+				gn->set_selected(previus_selected.find(gn)!=NULL);
+		}
+
+		top_layer->update();
+	}
+
+	if (p_ev.type==InputEvent::MOUSE_BUTTON) {
+
+		const InputEventMouseButton &b=p_ev.mouse_button;
+
+		if (b.button_index==BUTTON_RIGHT && b.pressed)
+		{
+			if (box_selecting) {
+				box_selecting = false;
+				for(int i=get_child_count()-1;i>=0;i--) {
+
+					GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+					if (!gn)
+						continue;
+
+					gn->set_selected(previus_selected.find(gn)!=NULL);
+				}
+				top_layer->update();
+			} else {
+				emit_signal("popup_request", Vector2(b.global_x, b.global_y));
+			}
+		}
+
+		if (b.button_index==BUTTON_LEFT && !b.pressed && dragging) {
+			if (!just_selected && drag_accum==Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+				//deselect current node
+				for(int i=get_child_count()-1;i>=0;i--) {
+					GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+
+					if (gn && gn->get_rect().has_point(get_local_mouse_pos()))
+						gn->set_selected(false);
+				}
+			}
+
+			if (drag_accum!=Vector2()) {
+
+				emit_signal("_begin_node_move");
+
+				for(int i=get_child_count()-1;i>=0;i--) {
+					GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+					if (gn && gn->is_selected())
+						gn->set_drag(false);
+				}
+
+				emit_signal("_end_node_move");
+			}
+
+			dragging = false;
+
+			top_layer->update();
+		}
+
+		if (b.button_index==BUTTON_LEFT && b.pressed) {
+
+			GraphNode *gn;
+			for(int i=get_child_count()-1;i>=0;i--) {
+
+				gn=get_child(i)->cast_to<GraphNode>();
+
+				if (gn && gn->get_rect().has_point(get_local_mouse_pos()))
+					break;
+			}
+
+			if (gn) {
+
+				if (_filter_input(Vector2(b.x,b.y)))
+					return;
+
+				dragging = true;
+				drag_accum = Vector2();
+				just_selected = !gn->is_selected();
+				if(!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+					for (int i = 0; i < get_child_count(); i++) {
+						GraphNode *o_gn = get_child(i)->cast_to<GraphNode>();
+						if (o_gn)
+							o_gn->set_selected(o_gn == gn);
+					}
+				}
+
+				gn->set_selected(true);
+				for (int i = 0; i < get_child_count(); i++) {
+					GraphNode *o_gn = get_child(i)->cast_to<GraphNode>();
+					if (!o_gn)
+						continue;
+					if (o_gn->is_selected())
+						o_gn->set_drag(true);
+				}
+
+			} else {
+				box_selecting = true;
+				box_selecting_from = get_local_mouse_pos();
+				if (b.mod.control) {
+					box_selection_mode_aditive = true;
+					previus_selected.clear();
+					for(int i=get_child_count()-1;i>=0;i--) {
+
+						GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+						if (!gn || !gn->is_selected())
+							continue;
+
+						previus_selected.push_back(gn);
+					}
+				} else if (b.mod.shift) {
+					box_selection_mode_aditive = false;
+					previus_selected.clear();
+					for(int i=get_child_count()-1;i>=0;i--) {
+
+						GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+						if (!gn || !gn->is_selected())
+							continue;
+
+						previus_selected.push_back(gn);
+					}
+				} else {
+					box_selection_mode_aditive = true;
+					previus_selected.clear();
+					for(int i=get_child_count()-1;i>=0;i--) {
+
+						GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+						if (!gn)
+							continue;
+
+						gn->set_selected(false);
+					}
+				}
+			}
+		}
+
+		if (b.button_index==BUTTON_LEFT && !b.pressed && box_selecting) {
+			box_selecting = false;
+			previus_selected.clear();
+			top_layer->update();
+		}
+	}
+
+	if (p_ev.type==InputEvent::KEY && p_ev.key.scancode==KEY_D && p_ev.key.pressed && p_ev.key.mod.command) {
+		emit_signal("duplicate_nodes_request");
+		accept_event();
+	}
+
+	if (p_ev.type==InputEvent::KEY && p_ev.key.scancode==KEY_DELETE && p_ev.key.pressed) {
+		emit_signal("delete_nodes_request");
+		accept_event();
+	}
+
 }
 
 void GraphEdit::clear_connections() {
@@ -555,12 +733,18 @@ void GraphEdit::_bind_methods() {
 
 	ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
 	ADD_SIGNAL(MethodInfo("disconnection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
-
+	ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2,"p_position")));
+	ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
+	ADD_SIGNAL(MethodInfo("delete_nodes_request"));
+	ADD_SIGNAL(MethodInfo("_begin_node_move"));
+	ADD_SIGNAL(MethodInfo("_end_node_move"));
 }
 
 
 
 GraphEdit::GraphEdit() {
+	set_focus_mode(FOCUS_ALL);
+
 	top_layer=NULL;
 	top_layer=memnew(GraphEditFilter(this));
 	add_child(top_layer);
@@ -581,6 +765,9 @@ GraphEdit::GraphEdit() {
 	connecting=false;
 	right_disconnects=false;
 
+	box_selecting = false;
+	dragging = false;
+
 	h_scroll->connect("value_changed", this,"_scroll_moved");
 	v_scroll->connect("value_changed", this,"_scroll_moved");
 }

+ 11 - 2
scene/gui/graph_edit.h

@@ -10,7 +10,7 @@ class GraphEditFilter : public Control {
 
 	OBJ_TYPE(GraphEditFilter,Control);
 
-friend class GraphEdit;
+	friend class GraphEdit;
 	GraphEdit *ge;
 	virtual bool has_point(const Point2& p_point) const;
 
@@ -49,7 +49,16 @@ private:
 	String connecting_target_to;
 	int connecting_target_index;
 
+	bool dragging;
+	bool just_selected;
+	Vector2 drag_accum;
 
+	bool box_selecting;
+	bool box_selection_mode_aditive;
+	Point2 box_selecting_from;
+	Point2 box_selecting_to;
+	Rect2 box_selecting_rect;
+	List<GraphNode*> previus_selected;
 
 	bool right_disconnects;
 	bool updating;
@@ -71,7 +80,7 @@ private:
 
 	Array _get_connection_list() const;
 
-friend class GraphEditFilter;
+	friend class GraphEditFilter;
 	bool _filter_input(const Point2& p_point);
 protected:
 

+ 34 - 28
scene/gui/graph_node.cpp

@@ -40,7 +40,7 @@ bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{
 
 
 
-	if (!p_name.operator String().begins_with("slot/")) {		
+	if (!p_name.operator String().begins_with("slot/")) {
 		return false;
 	}
 
@@ -160,7 +160,7 @@ void GraphNode::_notification(int p_what) {
 
 	if (p_what==NOTIFICATION_DRAW) {
 
-		Ref<StyleBox> sb=get_stylebox("frame");
+		Ref<StyleBox> sb=get_stylebox(selected ? "selectedframe" : "frame");
 		Ref<Texture> port =get_icon("port");
 		Ref<Texture> close =get_icon("close");
 		int close_offset = get_constant("close_offset");
@@ -360,6 +360,29 @@ Vector2 GraphNode::get_offset() const {
 	return offset;
 }
 
+void GraphNode::set_selected(bool p_selected)
+{
+	selected = p_selected;
+	update();
+}
+
+bool GraphNode::is_selected()
+{
+	return selected;
+}
+
+void GraphNode::set_drag(bool p_drag)
+{
+	if (p_drag)
+		drag_from=get_offset();
+	else
+		emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo
+}
+
+Vector2 GraphNode::get_drag_from()
+{
+	return drag_from;
+}
 
 
 void GraphNode::set_show_close_button(bool p_enable){
@@ -379,7 +402,6 @@ void GraphNode::_connpos_update() {
 	int sep=get_constant("separation");
 
 	Ref<StyleBox> sb=get_stylebox("frame");
-	Ref<Texture> port =get_icon("port");
 	conn_input_cache.clear();
 	conn_output_cache.clear();
 	int vofs=0;
@@ -503,31 +525,17 @@ Color GraphNode::get_connection_output_color(int p_idx) {
 
 void GraphNode::_input_event(const InputEvent& p_ev) {
 
-	if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+	if (p_ev.type==InputEvent::MOUSE_BUTTON) {
+		get_parent_control()->grab_focus();
+		if(p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
 
-		Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
-		if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
-			emit_signal("close_request");
-			return;
+			Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
+			if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
+				emit_signal("close_request");
+				return;
+			}
+			emit_signal("raise_request");
 		}
-
-		drag_from=get_offset();
-		drag_accum=Vector2();
-		dragging=true;
-		emit_signal("raise_request");
-
-	}
-
-	if (p_ev.type==InputEvent::MOUSE_BUTTON && !p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
-
-		dragging=false;
-		emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo
-	}
-
-	if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) {
-
-		drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
-		set_offset(drag_from+drag_accum);
 	}
 
 }
@@ -576,8 +584,6 @@ void GraphNode::_bind_methods() {
 }
 
 GraphNode::GraphNode() {
-
-	dragging=false;
 	show_close=false;
 	connpos_dirty=true;
 }

+ 8 - 3
scene/gui/graph_node.h

@@ -18,7 +18,7 @@ class GraphNode : public Container {
 		Color color_right;
 
 
-		Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); };
+		Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }
 	};
 
 	String title;
@@ -46,8 +46,7 @@ class GraphNode : public Container {
 	void _resort();
 
 	Vector2 drag_from;
-	Vector2 drag_accum;
-	bool dragging;
+	bool selected;
 protected:
 
 	void _input_event(const InputEvent& p_ev);
@@ -79,6 +78,12 @@ public:
 	void set_offset(const Vector2& p_offset);
 	Vector2 get_offset() const;
 
+	void set_selected(bool p_selected);
+	bool is_selected();
+
+	void set_drag(bool p_drag);
+	Vector2 get_drag_from();
+
 	void set_show_close_button(bool p_enable);
 	bool is_close_button_visible() const;
 

+ 171 - 171
scene/gui/tree.cpp

@@ -121,7 +121,7 @@ void TreeItem::set_cell_mode( int p_column, TreeCellMode p_mode ) {
 	c.val=0;
 	c.checked=false;
 	c.icon=Ref<Texture>();
-	c.text="";	
+	c.text="";
 	c.icon_max_w=0;
 	_changed_notify(p_column);
 }
@@ -153,9 +153,9 @@ void TreeItem::set_text(int p_column,String p_text) {
 
 	ERR_FAIL_INDEX( p_column, cells.size() );
 	cells[p_column].text=p_text;
-	
+
 	if (cells[p_column].mode==TreeItem::CELL_MODE_RANGE) {
-		
+
 		cells[p_column].min=0;
 		cells[p_column].max=p_text.get_slice_count(",");
 		cells[p_column].step=0;
@@ -225,7 +225,7 @@ void TreeItem::set_range(int p_column,double p_value) {
 		p_value=cells[p_column].min;
 	if (p_value>cells[p_column].max)
 		p_value=cells[p_column].max;
-	
+
 	cells[p_column].val=p_value;
 	_changed_notify(p_column);
 
@@ -237,7 +237,7 @@ double TreeItem::get_range(int p_column) const {
 	return cells[p_column].val;
 }
 
-		
+
 bool TreeItem::is_range_exponential(int p_column) const {
 
 	ERR_FAIL_INDEX_V( p_column, cells.size(), false);
@@ -304,7 +304,7 @@ void TreeItem::set_collapsed(bool p_collapsed) {
 
 			if (tree->select_mode==Tree::SELECT_MULTI) {
 
-				tree->selected_item=this;				
+				tree->selected_item=this;
 				emit_signal("cell_selected");
 			} else {
 
@@ -337,11 +337,11 @@ TreeItem *TreeItem::get_prev() {
 
 	if (!parent || parent->childs==this)
 		return NULL;
-	
+
 	TreeItem *prev = parent->childs;
 	while(prev && prev->next!=this)
 		prev=prev->next;
-	
+
 	return prev;
 }
 
@@ -636,14 +636,14 @@ void TreeItem::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_range","column"),&TreeItem::get_range);
 	ObjectTypeDB::bind_method(_MD("set_range_config","column","min","max","step","expr"),&TreeItem::set_range_config,DEFVAL(false));
 	ObjectTypeDB::bind_method(_MD("get_range_config","column"),&TreeItem::_get_range_config);
-	
+
 	ObjectTypeDB::bind_method(_MD("set_metadata","column","meta"),&TreeItem::set_metadata);
 	ObjectTypeDB::bind_method(_MD("get_metadata","column"),&TreeItem::get_metadata);
 
 	ObjectTypeDB::bind_method(_MD("set_custom_draw","column","object","callback"),&TreeItem::set_custom_draw);
 
 	ObjectTypeDB::bind_method(_MD("set_collapsed","enable"),&TreeItem::set_collapsed);
-	ObjectTypeDB::bind_method(_MD("is_collapsed"),&TreeItem::is_collapsed);	
+	ObjectTypeDB::bind_method(_MD("is_collapsed"),&TreeItem::is_collapsed);
 
 	ObjectTypeDB::bind_method(_MD("get_next:TreeItem"),&TreeItem::get_next);
 	ObjectTypeDB::bind_method(_MD("get_prev:TreeItem"),&TreeItem::get_prev);
@@ -654,17 +654,17 @@ void TreeItem::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_prev_visible:TreeItem"),&TreeItem::get_prev_visible);
 
 	ObjectTypeDB::bind_method(_MD("remove_child:TreeItem","child"),&TreeItem::_remove_child);
-	
+
 	ObjectTypeDB::bind_method(_MD("set_selectable","column","selectable"),&TreeItem::set_selectable);
 	ObjectTypeDB::bind_method(_MD("is_selectable","column"),&TreeItem::is_selectable);
 
 	ObjectTypeDB::bind_method(_MD("is_selected","column"),&TreeItem::is_selected);
 	ObjectTypeDB::bind_method(_MD("select","column"),&TreeItem::select);
 	ObjectTypeDB::bind_method(_MD("deselect","column"),&TreeItem::deselect);
-	
+
 	ObjectTypeDB::bind_method(_MD("set_editable","column","enabled"),&TreeItem::set_editable);
 	ObjectTypeDB::bind_method(_MD("is_editable","column"),&TreeItem::is_editable);
-	
+
 	ObjectTypeDB::bind_method(_MD("set_custom_color","column","color"),&TreeItem::set_custom_color);
 	ObjectTypeDB::bind_method(_MD("clear_custom_color","column"),&TreeItem::clear_custom_color);
 
@@ -688,7 +688,7 @@ void TreeItem::_bind_methods() {
 	BIND_CONSTANT( CELL_MODE_RANGE );
 	BIND_CONSTANT( CELL_MODE_ICON );
 	BIND_CONSTANT( CELL_MODE_CUSTOM );
-			
+
 
 }
 
@@ -774,7 +774,7 @@ void Tree::update_cache() {
 	cache.arrow =get_icon("arrow");
 	cache.select_arrow =get_icon("select_arrow");
 	cache.updown=get_icon("updown");
-	
+
 	cache.font_color=get_color("font_color");
 	cache.font_color_selected=get_color("font_color_selected");
 	cache.guide_color=get_color("guide_color");
@@ -802,10 +802,10 @@ int Tree::compute_item_height(TreeItem *p_item) const {
 
 	if (p_item==root && hide_root)
 		return 0;
-		
+
 	int height=cache.font->get_height();
 
-	
+
 	for (int i=0;i<columns.size();i++) {
 
 
@@ -819,23 +819,23 @@ int Tree::compute_item_height(TreeItem *p_item) const {
 		}
 
 		switch(p_item->cells[i].mode) {
-	
+
 			case TreeItem::CELL_MODE_CHECK: {
-	
+
 				int check_icon_h = cache.checked->get_height();
 				if (height<check_icon_h)
 					height=check_icon_h;
-	
-	
-	
+
+
+
 			}
 			case TreeItem::CELL_MODE_STRING:
 			case TreeItem::CELL_MODE_CUSTOM:
 			case TreeItem::CELL_MODE_ICON: {
-	
+
 				Ref<Texture> icon = p_item->cells[i].icon;
 				if (!icon.is_null()) {
-	
+
 					Size2i s = p_item->cells[i].get_icon_size();
 					if (p_item->cells[i].icon_max_w>0 && s.width > p_item->cells[i].icon_max_w ) {
 						s.height=s.height * p_item->cells[i].icon_max_w / s.width;
@@ -843,15 +843,15 @@ int Tree::compute_item_height(TreeItem *p_item) const {
 					if (s.height > height )
 						height=s.height;
 				}
-	
+
 			} break;
 			default: {}
 		}
 	}
-	
-	
+
+
 	height += cache.vseparation;
-	
+
 	return height;
 
 }
@@ -927,7 +927,7 @@ void Tree::draw_item_text(String p_text,const Ref<Texture>& p_icon,int p_icon_ma
 		p_rect.size.x-=Math::floor(p_rect.size.y/2);
 
 	Ref<Font> font = cache.font;
-	
+
 	p_rect.pos.y+=Math::floor((p_rect.size.y-font->get_height())/2.0) +font->get_ascent();
 	font->draw(ci,p_rect.pos,p_text,p_color,p_rect.size.x);
 }
@@ -950,13 +950,13 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 
 	Point2i guide_from;
 
-    	bool skip=(p_item==root && hide_root);
+		bool skip=(p_item==root && hide_root);
    // printf("skip (%p == %p && %i) %i\n",p_item,root,hide_root,skip);
 
 
 	if (!skip && (p_pos.y+label_h-cache.offset.y)>0) {
 
-      //  printf("entering\n");
+	  //  printf("entering\n");
 
 		int height=label_h;
 
@@ -965,7 +965,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 		if (p_item->childs) { //has childs, draw the guide box
 
 			Ref<Texture> arrow;
-			
+
 			if (p_item->collapsed) {
 
 				arrow=cache.arrow_collapsed;
@@ -983,7 +983,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 //		if (p_item->get_parent()!=root || !hide_root)
 
 		Ref<Font> font = cache.font;
-		
+
 		int font_ascent=font->get_ascent();
 
 		int ofs = p_pos.x + cache.item_margin;
@@ -1066,7 +1066,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 			}
 
 			Color col=p_item->cells[i].custom_color?p_item->cells[i].color:get_color( p_item->cells[i].selected?"font_color_selected":"font_color");
-			
+
 			Point2i text_pos=item_rect.pos;
 			text_pos.y+=Math::floor((item_rect.size.y-font->get_height())/2) + font_ascent;
 
@@ -1104,7 +1104,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 
 				} break;
 				case TreeItem::CELL_MODE_RANGE: {
-						
+
 					if (p_item->cells[i].text!="") {
 
 						if (!p_item->cells[i].editable)
@@ -1128,7 +1128,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 					} else {
 
 						Ref<Texture> updown = cache.updown;
-					
+
 						String valtext = String::num( p_item->cells[i].val, Math::decimals( p_item->cells[i].step ) );
 						font->draw( ci, text_pos, valtext, col, item_rect.size.x-updown->get_width());
 
@@ -1185,7 +1185,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 					Rect2i ir=item_rect;
 					ir.size.width-=downarrow->get_width();
 					draw_item_rect(p_item->cells[i],ir,col);
-					
+
 					Point2i arrow_pos=item_rect.pos;
 					arrow_pos.x+=item_rect.size.x-downarrow->get_width();
 					arrow_pos.y+=Math::floor(((item_rect.size.y-downarrow->get_height()))/2.0);
@@ -1227,7 +1227,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
 		children_pos.x+=cache.item_margin;
 		htotal+=label_h;
 		children_pos.y+=htotal;
-     	   
+
 	}
 
 
@@ -1272,12 +1272,12 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
 			continue;
 
 		if (select_mode==SELECT_ROW) {
-	
+
 
 			if (p_selected==p_current) {
-	
+
 				if (!c.selected) {
-		
+
 					c.selected=true;
 					selected_item=p_selected;
 					selected_col=0;
@@ -1286,26 +1286,26 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
 					//if (p_col==i)
 					//	p_current->selected_signal.call(p_col);
 				}
-		
+
 			} else {
-		
+
 				if (c.selected) {
-		
-					c.selected=false;					
+
+					c.selected=false;
 					//p_current->deselected_signal.call(p_col);
 				}
-	
+
 			}
-	
+
 		} else if (select_mode==SELECT_SINGLE || select_mode==SELECT_MULTI) {
-	
+
 			if (!r_in_range && &selected_cell==&c) {
-		
+
 
 				if (!selected_cell.selected) {
-		
+
 					selected_cell.selected=true;
-					
+
 					selected_item=p_selected;
 					selected_col=i;
 
@@ -1321,7 +1321,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
 
 				}
 			} else {
-			
+
 
 				if (r_in_range && *r_in_range) {
 
@@ -1372,7 +1372,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 	int item_h=compute_item_height( p_item )+cache.vseparation;
 
 	bool skip=(p_item==root && hide_root);
-	
+
 	if (!skip && p_pos.y<item_h) {
 		// check event!
 
@@ -1384,7 +1384,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 
 			return -1; //handled!
 		}
-		
+
 		int x=p_pos.x;
 		/* find clicked column */
 		int col=-1;
@@ -1403,7 +1403,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 			break;
 		}
 
-		
+
 
 		if (col==-1)
 			return -1;
@@ -1487,8 +1487,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 					//}
 					update();
 				}
-				
-				
+
+
 			}
 		}
 
@@ -1514,14 +1514,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 
 			} break;
 			case TreeItem::CELL_MODE_CHECK: {
-				
+
 				Ref<Texture> checked = cache.checked;
 				bring_up_editor=false; //checkboxes are not edited with editor
 				if (x>=0 && x<= checked->get_width()+cache.hseparation ) {
 
-					
+
 					p_item->set_checked(col,!c.checked);
-					item_edited(col,p_item); 
+					item_edited(col,p_item);
 					click_handled=true;
 					//p_item->edited_signal.call(col);
 				}
@@ -1549,37 +1549,37 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 					//}
 					bring_up_editor=false;
 				} else {
-					
+
 					Ref<Texture> updown = cache.updown;
-					
-					
+
+
 					if (x >= (col_width-item_h/2)) {
-					
+
 						/* touching the combo */
 						bool up=p_pos.y < (item_h /2);
-						
+
 						if (p_button==BUTTON_LEFT) {
 							p_item->set_range( col, c.val + (up?1.0:-1.0) * c.step );
-						
-							item_edited(col,p_item); 	
+
+							item_edited(col,p_item);
 						} else if (p_button==BUTTON_RIGHT) {
-	
+
 							p_item->set_range( col, (up?c.max:c.min) );
-							item_edited(col,p_item); 
+							item_edited(col,p_item);
 						} else if (p_button==BUTTON_WHEEL_UP) {
-	
+
 							p_item->set_range( col, c.val + c.step );
-							item_edited(col,p_item); 
+							item_edited(col,p_item);
 						} else if (p_button==BUTTON_WHEEL_DOWN) {
-	
+
 							p_item->set_range( col, c.val - c.step );
-							item_edited(col,p_item); 
+							item_edited(col,p_item);
 						}
-	
-						//p_item->edited_signal.call(col);	
+
+						//p_item->edited_signal.call(col);
 						bring_up_editor=false;
-						
-						
+
+
 					}  else {
 
 						editor_text=String::num( p_item->cells[col].val, Math::decimals( p_item->cells[col].step ) );
@@ -1587,7 +1587,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 						if (select_mode==SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id)
 							bring_up_editor=false;
 
-					}	
+					}
 
 				}
 				click_handled=true;
@@ -1598,12 +1598,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 			} break;
 			case TreeItem::CELL_MODE_CUSTOM: {
 				edited_item=p_item;
-				edited_col=col;					
+				edited_col=col;
 				custom_popup_rect=Rect2i(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs+item_h-cache.offset.y), Size2(get_column_width(col),item_h));
 				emit_signal("custom_popup_edited",((bool)(x >= (col_width-item_h/2))));
 
 				bring_up_editor=false;
-				item_edited(col,p_item); 
+				item_edited(col,p_item);
 				click_handled=true;
 				return -1;
 			} break;
@@ -1615,7 +1615,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 
 
 
-		click_handled=true;		
+		click_handled=true;
 		popup_edited_item=p_item;
 		popup_edited_item_col=col;
 
@@ -1627,14 +1627,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 	} else {
 
 		Point2i new_pos=p_pos;
-		
+
 		if (!skip) {
 			x_ofs+=cache.item_margin;
 			//new_pos.x-=cache.item_margin;
 			y_ofs+=item_h;
 			new_pos.y-=item_h;
 		}
-		
+
 
 		if (!p_item->collapsed) { /* if not collapsed, check the childs */
 
@@ -1697,7 +1697,7 @@ void Tree::text_editor_enter(String p_text) {
 	default: { ERR_FAIL(); }
 	}
 
-	item_edited(popup_edited_item_col,popup_edited_item);	
+	item_edited(popup_edited_item_col,popup_edited_item);
 	update();
 
 }
@@ -1725,19 +1725,19 @@ void Tree::popup_select(int p_option) {
 	if (popup_edited_item_col<0 || popup_edited_item_col>columns.size())
 		return;
 
-	
+
 	popup_edited_item->cells[popup_edited_item_col].val=p_option;
 	//popup_edited_item->edited_signal.call( popup_edited_item_col );
 	update();
-	item_edited(popup_edited_item_col,popup_edited_item);	
+	item_edited(popup_edited_item_col,popup_edited_item);
 }
 
 
 
 void Tree::_input_event(InputEvent p_event) {
-	
+
 	switch (p_event.type) {
-		
+
 		case InputEvent::KEY: {
 
 			if (!p_event.key.pressed)
@@ -2091,12 +2091,12 @@ void Tree::_input_event(InputEvent p_event) {
 			}
 		} break;
 		case InputEvent::MOUSE_BUTTON: {
-			
+
 
 
 			if (cache.font.is_null()) // avoid a strange case that may fuckup stuff
 				update_cache();
-			const InputEventMouseButton& b=p_event.mouse_button;			
+			const InputEventMouseButton& b=p_event.mouse_button;
 
 
 			if (!b.pressed) {
@@ -2160,7 +2160,7 @@ void Tree::_input_event(InputEvent p_event) {
 			switch(b.button_index) {
 				case BUTTON_LEFT: {
 					Ref<StyleBox> bg = cache.bg;
-					
+
 					Point2 pos = Point2(b.x,b.y) - bg->get_offset();
 					cache.click_type=Cache::CLICK_NONE;
 					if (show_column_titles) {
@@ -2222,18 +2222,18 @@ void Tree::_input_event(InputEvent p_event) {
 
 
 				} break;
-				case BUTTON_WHEEL_UP: {				
+				case BUTTON_WHEEL_UP: {
 					v_scroll->set_val( v_scroll->get_val()-v_scroll->get_page()/8 );
 				} break;
 				case BUTTON_WHEEL_DOWN: {
-				
+
 					v_scroll->set_val( v_scroll->get_val()+v_scroll->get_page()/8 );
 				} break;
 			}
-				
+
 		} break;
 	}
-	
+
 }
 
 
@@ -2331,10 +2331,10 @@ Size2 Tree::get_internal_min_size() const {
 	if (root)
 		size.height+=get_item_height(root);
 	for (int i=0;i<columns.size();i++) {
-	
+
 		size.width+=columns[i].min_width;
 	}
-	
+
 	return size;
 }
 
@@ -2353,39 +2353,39 @@ void Tree::update_scrollbars() {
 	Size2 vmin = v_scroll->get_combined_minimum_size();
 
 
-	
+
 	v_scroll->set_begin( Point2(size.width - vmin.width , cache.bg->get_margin(MARGIN_TOP)) );
 	v_scroll->set_end( Point2(size.width, size.height-cache.bg->get_margin(MARGIN_TOP)-cache.bg->get_margin(MARGIN_BOTTOM)) );
-	
+
 	h_scroll->set_begin( Point2( 0, size.height - hmin.height) );
 	h_scroll->set_end( Point2(size.width-vmin.width, size.height) );
-	
-	
+
+
 	Size2 min = get_internal_min_size();
-	
+
 	if (min.height < size.height - hmin.height) {
-	
+
 		v_scroll->hide();
 		cache.offset.y=0;
 	} else {
-	
+
 		v_scroll->show();
 		v_scroll->set_max(min.height);
 		v_scroll->set_page(size.height - hmin.height - tbh);
 		cache.offset.y=v_scroll->get_val();
 	}
-	
+
 	if (min.width < size.width - vmin.width) {
-	
+
 		h_scroll->hide();
 		cache.offset.x=0;
 	} else {
-	
+
 		h_scroll->show();
 		h_scroll->set_max(min.width);
 		h_scroll->set_page(size.width - vmin.width);
 		cache.offset.x=h_scroll->get_val();
-	}	
+	}
 }
 
 
@@ -2464,16 +2464,16 @@ void Tree::_notification(int p_what) {
 	}
 
 	if (p_what==NOTIFICATION_DRAW) {
-	
+
 		update_cache();
 		update_scrollbars();
-		RID ci = get_canvas_item();	
-		
+		RID ci = get_canvas_item();
+
 		VisualServer::get_singleton()->canvas_item_set_clip(ci,true);
-		
+
 		Ref<StyleBox> bg = cache.bg;
 		Ref<StyleBox> bg_focus = get_stylebox("bg_focus");
-						
+
 		Point2 draw_ofs;
 		draw_ofs+=bg->get_offset();
 		Size2 draw_size=get_size()-bg->get_minimum_size();
@@ -2491,7 +2491,7 @@ void Tree::_notification(int p_what) {
 		draw_size.y-=tbh;
 
 		if (root) {
-		
+
 
 			draw_item( Point2(),draw_ofs,draw_size,root);
 
@@ -2502,10 +2502,10 @@ void Tree::_notification(int p_what) {
 //		int size_y=exposed.size.height-bg->get_minimum_size().height;
 
 		for (int i=0;i<(columns.size()-1-1);i++) {
-			
+
 			ofs+=get_column_width(i);
 			//get_painter()->draw_fill_rect( Point2(ofs+cache.hseparation/2, from_y), Size2( 1, size_y ),color( COLOR_TREE_GRID) );
-		}	
+		}
 
 		if (show_column_titles) {
 
@@ -2605,7 +2605,7 @@ TreeItem* Tree::get_last_item() {
 }
 
 void Tree::item_edited(int p_column,TreeItem *p_item) {
-	
+
 	edited_item=p_item;
 	edited_col=p_column;
 	emit_signal("item_edited");
@@ -2613,14 +2613,14 @@ void Tree::item_edited(int p_column,TreeItem *p_item) {
 
 void Tree::item_changed(int p_column,TreeItem *p_item) {
 
-	update(); 
+	update();
 }
 
 void Tree::item_selected(int p_column,TreeItem *p_item) {
 
 
 	if (select_mode==SELECT_MULTI) {
-		
+
 		if (!p_item->cells[p_column].selectable)
 			return;
 
@@ -2636,16 +2636,16 @@ void Tree::item_selected(int p_column,TreeItem *p_item) {
 void Tree::item_deselected(int p_column,TreeItem *p_item) {
 
 	if (select_mode==SELECT_MULTI) {
-		
+
 		p_item->cells[p_column].selected=false;
-	} 
+	}
 	update();
 }
 
 
 void Tree::set_select_mode(SelectMode p_mode) {
 
-    select_mode=p_mode;
+	select_mode=p_mode;
 }
 
 void Tree::clear() {
@@ -2675,15 +2675,15 @@ void Tree::set_hide_root(bool p_enabled) {
 
 
 
-    hide_root=p_enabled;
-    update();
+	hide_root=p_enabled;
+	update();
 }
 
 void Tree::set_column_min_width(int p_column,int p_min_width) {
 
 
 	ERR_FAIL_INDEX(p_column,columns.size());
-	
+
 	if (p_min_width<1)
 		return;
 	columns[p_column].min_width=p_min_width;
@@ -2693,8 +2693,8 @@ void Tree::set_column_min_width(int p_column,int p_min_width) {
 void Tree::set_column_expand(int p_column,bool p_expand) {
 
 	ERR_FAIL_INDEX(p_column,columns.size());
-	
- 	columns[p_column].expand=p_expand;
+
+	columns[p_column].expand=p_expand;
 	update();
 }
 
@@ -2709,78 +2709,78 @@ int Tree::get_selected_column() const {
 }
 
 TreeItem *Tree::get_edited() const {
-	
+
 	return edited_item;
 }
 
 int Tree::get_edited_column() const {
-	
+
 	return edited_col;
 }
 
 TreeItem* Tree::get_next_selected( TreeItem* p_item) {
-	
+
 	//if (!p_item)
 	//	return NULL;
 	if (!root)
-		return NULL;				
-	
+		return NULL;
+
 	while(true) {
-	
-		
+
+
 		if (!p_item) {
 			p_item=root;
 		} else {
-				
+
 			if (p_item->childs) {
-				
+
 				p_item=p_item->childs;
-				
+
 			} else if (p_item->next) {
-			
-				p_item=p_item->next;			
+
+				p_item=p_item->next;
 			} else {
-			
+
 				while(!p_item->next) {
-			
+
 					p_item=p_item->parent;
 					if (p_item==NULL)
 						return NULL;
 				}
-				
+
 				p_item=p_item->next;
 			}
-			
+
 		}
-	
+
 		for (int i=0;i<columns.size();i++)
 			if (p_item->cells[i].selected)
 				return p_item;
 	}
-	
+
 	return NULL;
 }
 
 int Tree::get_column_width(int p_column) const {
-	
+
 	ERR_FAIL_INDEX_V(p_column,columns.size(),-1);
-	
-	
+
+
 	if (!columns[p_column].expand)
 		return columns[p_column].min_width;
-	
+
 	Ref<StyleBox> bg = cache.bg;
-	
+
 	int expand_area=get_size().width-(bg->get_margin(MARGIN_LEFT)+bg->get_margin(MARGIN_RIGHT));
-	
+
 	if (v_scroll->is_visible())
 		expand_area-=v_scroll->get_combined_minimum_size().width;
-	
+
 	int expanding_columns=0;
 	int expanding_total=0;
-	
+
 	for (int i=0;i<columns.size();i++) {
-		
+
 		if (!columns[i].expand) {
 			expand_area-=columns[i].min_width;
 		} else {
@@ -2791,30 +2791,30 @@ int Tree::get_column_width(int p_column) const {
 
 	if (expand_area<expanding_total)
 		return columns[p_column].min_width;
-	
+
 	ERR_FAIL_COND_V(expanding_columns==0,-1); // shouldnt happen
-	
+
 	return expand_area * columns[p_column].min_width / expanding_total;
 }
 
 void Tree::propagate_set_columns(TreeItem *p_item) {
-	
+
 	p_item->cells.resize( columns.size() );
-	
+
 	TreeItem *c = p_item->get_children();
 	while(c) {
-		
+
 		propagate_set_columns(c);
 		c=c->get_next();
 	}
 }
 
 void Tree::set_columns(int p_columns) {
-	
+
 	ERR_FAIL_COND(p_columns<1);
 	ERR_FAIL_COND(blocked>0);
 	columns.resize(p_columns);
-	
+
 	if (root)
 		propagate_set_columns(root);
 	if (selected_col>=p_columns)
@@ -2824,17 +2824,17 @@ void Tree::set_columns(int p_columns) {
 }
 
 int Tree::get_columns() const {
-	
+
 	return columns.size();
 }
 
 void Tree::_scroll_moved(float) {
-	
+
 	update();
 }
 
 Rect2 Tree::get_custom_popup_rect() const {
-	
+
 	return custom_popup_rect;
 }
 
@@ -3116,7 +3116,7 @@ bool Tree::can_cursor_exit_tree() const {
 
 
 void Tree::_bind_methods() {
-	
+
 	ObjectTypeDB::bind_method(_MD("_input_event"),&Tree::_input_event);
 	ObjectTypeDB::bind_method(_MD("_popup_select"),&Tree::popup_select);
 	ObjectTypeDB::bind_method(_MD("_text_editor_enter"),&Tree::text_editor_enter);
@@ -3140,7 +3140,7 @@ void Tree::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("set_columns","amount"),&Tree::set_columns);
 	ObjectTypeDB::bind_method(_MD("get_columns"),&Tree::get_columns);
-	
+
 	ObjectTypeDB::bind_method(_MD("get_edited:TreeItem"),&Tree::get_edited);
 	ObjectTypeDB::bind_method(_MD("get_edited_column"),&Tree::get_edited_column);
 	ObjectTypeDB::bind_method(_MD("get_custom_popup_rect"),&Tree::get_custom_popup_rect);
@@ -3179,7 +3179,7 @@ Tree::Tree() {
 	edited_item=NULL;
 	selected_col=-1;
 	edited_col=-1;
-	
+
 	hide_root=false;
 	select_mode=SELECT_SINGLE;
 	root=0;
@@ -3187,8 +3187,8 @@ Tree::Tree() {
 	popup_edited_item=NULL;
 	text_editor=NULL;
 	set_focus_mode(FOCUS_ALL);
-	
-		
+
+
 	popup_menu = memnew( PopupMenu );
 	popup_menu->hide();
 	add_child(popup_menu);
@@ -3204,7 +3204,7 @@ Tree::Tree() {
 
 	h_scroll = memnew( HScrollBar );
 	v_scroll = memnew( VScrollBar );
-	
+
 	add_child(h_scroll);
 	add_child(v_scroll);
 
@@ -3250,6 +3250,6 @@ Tree::~Tree() {
 	if (root) {
 		memdelete( root );
 	}
-	
+
 }
 

+ 50 - 44
scene/resources/default_theme/default_theme.cpp

@@ -31,7 +31,7 @@ static  TexCacheMap *tex_cache;
 
 template<class T>
 static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, float p_right, float p_botton,float p_margin_left=-1, float p_margin_top=-1, float p_margin_right=-1, float p_margin_botton=-1, bool p_draw_center=true) {
-	
+
 	Ref<ImageTexture> texture;
 
 
@@ -56,17 +56,17 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, flo
 	style->set_default_margin( MARGIN_BOTTOM, p_margin_botton );
 	style->set_default_margin( MARGIN_TOP, p_margin_top );
 	style->set_draw_center(p_draw_center);
-	
+
 	return style;
 }
 
 template<class T>
 static Ref<Texture> make_icon(T p_src) {
-	
-	
+
+
 	Ref<ImageTexture> texture( memnew( ImageTexture ) );
 	texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER );
-		
+
 	return texture;
 }
 
@@ -75,7 +75,7 @@ static Ref<Font> make_font(int p_height,int p_ascent, int p_valign, int p_charco
 
 	Ref<Font> font( memnew( Font ) );
 	font->add_texture( p_texture );
-	
+
 	for (int i=0;i<p_charcount;i++) {
 
 		const int *c = &p_chars[i*8];
@@ -91,9 +91,9 @@ static Ref<Font> make_font(int p_height,int p_ascent, int p_valign, int p_charco
 
 
 		font->add_char( chr, 0, frect, align,advance );
-		
+
 	}
-	
+
 	font->set_height( p_height );
 	font->set_ascent( p_ascent );
 
@@ -152,12 +152,12 @@ static Ref<Font> make_font2(int p_height,int p_ascent, int p_charcount, const in
 static Ref<StyleBox> make_empty_stylebox(float p_margin_left=-1, float p_margin_top=-1, float p_margin_right=-1, float p_margin_botton=-1) {
 
 	Ref<StyleBox> style( memnew( StyleBoxEmpty) );
-	
+
 	style->set_default_margin( MARGIN_LEFT, p_margin_left );
 	style->set_default_margin( MARGIN_RIGHT, p_margin_right );
 	style->set_default_margin( MARGIN_BOTTOM, p_margin_botton );
 	style->set_default_margin( MARGIN_TOP, p_margin_top );
-	
+
 	return style;
 }
 
@@ -299,49 +299,49 @@ void make_default_theme() {
 
 	t->set_constant("hseparation","MenuButton", 3 );
 
-    // CheckBox
+	// CheckBox
 
-    Ref<StyleBox> cbx_empty = memnew( StyleBoxEmpty );
-    cbx_empty->set_default_margin(MARGIN_LEFT,22);
-    cbx_empty->set_default_margin(MARGIN_RIGHT,4);
-    cbx_empty->set_default_margin(MARGIN_TOP,4);
-    cbx_empty->set_default_margin(MARGIN_BOTTOM,5);
-    Ref<StyleBox> cbx_focus = focus;
-    cbx_focus->set_default_margin(MARGIN_LEFT,4);
-    cbx_focus->set_default_margin(MARGIN_RIGHT,22);
-    cbx_focus->set_default_margin(MARGIN_TOP,4);
-    cbx_focus->set_default_margin(MARGIN_BOTTOM,5);
+	Ref<StyleBox> cbx_empty = memnew( StyleBoxEmpty );
+	cbx_empty->set_default_margin(MARGIN_LEFT,22);
+	cbx_empty->set_default_margin(MARGIN_RIGHT,4);
+	cbx_empty->set_default_margin(MARGIN_TOP,4);
+	cbx_empty->set_default_margin(MARGIN_BOTTOM,5);
+	Ref<StyleBox> cbx_focus = focus;
+	cbx_focus->set_default_margin(MARGIN_LEFT,4);
+	cbx_focus->set_default_margin(MARGIN_RIGHT,22);
+	cbx_focus->set_default_margin(MARGIN_TOP,4);
+	cbx_focus->set_default_margin(MARGIN_BOTTOM,5);
 
-    t->set_stylebox("normal","CheckBox", cbx_empty );
-    t->set_stylebox("pressed","CheckBox", cbx_empty );
-    t->set_stylebox("disabled","CheckBox", cbx_empty );
-    t->set_stylebox("hover","CheckBox", cbx_empty );
-    t->set_stylebox("focus","CheckBox", cbx_focus );
+	t->set_stylebox("normal","CheckBox", cbx_empty );
+	t->set_stylebox("pressed","CheckBox", cbx_empty );
+	t->set_stylebox("disabled","CheckBox", cbx_empty );
+	t->set_stylebox("hover","CheckBox", cbx_empty );
+	t->set_stylebox("focus","CheckBox", cbx_focus );
 
-    t->set_icon("checked", "CheckBox", make_icon(checked_png));
-    t->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
-    t->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
-    t->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
+	t->set_icon("checked", "CheckBox", make_icon(checked_png));
+	t->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
+	t->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
+	t->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
 
-    t->set_font("font","CheckBox", default_font );
+	t->set_font("font","CheckBox", default_font );
 
-    t->set_color("font_color","CheckBox", control_font_color );
-    t->set_color("font_color_pressed","CheckBox", control_font_color_pressed );
-    t->set_color("font_color_hover","CheckBox", control_font_color_hover );
-    t->set_color("font_color_disabled","CheckBox", control_font_color_disabled );
+	t->set_color("font_color","CheckBox", control_font_color );
+	t->set_color("font_color_pressed","CheckBox", control_font_color_pressed );
+	t->set_color("font_color_hover","CheckBox", control_font_color_hover );
+	t->set_color("font_color_disabled","CheckBox", control_font_color_disabled );
 
-    t->set_constant("hseparation","CheckBox",4);
-    t->set_constant("check_vadjust","CheckBox",0);
+	t->set_constant("hseparation","CheckBox",4);
+	t->set_constant("check_vadjust","CheckBox",0);
 
 
 
 	// CheckButton
-	
+
 	Ref<StyleBox> cb_empty = memnew( StyleBoxEmpty );
 	cb_empty->set_default_margin(MARGIN_LEFT,6);
 	cb_empty->set_default_margin(MARGIN_RIGHT,70);
 	cb_empty->set_default_margin(MARGIN_TOP,4);
-    cb_empty->set_default_margin(MARGIN_BOTTOM,4);
+	cb_empty->set_default_margin(MARGIN_BOTTOM,4);
 
 	t->set_stylebox("normal","CheckButton", cb_empty );
 	t->set_stylebox("pressed","CheckButton", cb_empty );
@@ -365,7 +365,7 @@ void make_default_theme() {
 
 
 	// Label
-	            
+
 	t->set_font("font","Label", default_font );
 
 	t->set_color("font_color","Label", Color(1,1,1) );
@@ -556,10 +556,16 @@ void make_default_theme() {
 
 	// GraphNode
 
-	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
+	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,3,24,16,5);
+	Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,3,24,16,5);
+	Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png,4,4,4,4,6,4,4,4);
+	Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png,4,4,4,4,6,4,4,4);
 	//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
 	//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
 	t->set_stylebox("frame","GraphNode", graphsb );
+	t->set_stylebox("selectedframe","GraphNode", graphsbselected );
+	t->set_stylebox("defaultframe", "GraphNode", graphsbdefault );
+	t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus );
 	t->set_constant("separation","GraphNode", 1 );
 	t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
 	t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
@@ -713,7 +719,7 @@ void make_default_theme() {
 
 
 	// FileDialog
-	
+
 	t->set_icon("folder","FileDialog",make_icon(icon_folder_png));
 	t->set_color("files_disabled","FileDialog",Color(0,0,0,0.7));
 
@@ -877,10 +883,10 @@ void make_default_theme() {
 
 #endif
 void clear_default_theme() {
-	
+
 	Theme::set_default( Ref<Theme>() );
 	Theme::set_default_icon( Ref< Texture >() );
-	Theme::set_default_style( Ref< StyleBox >() );	
+	Theme::set_default_style( Ref< StyleBox >() );
 	Theme::set_default_font( Ref< Font >() );
 
 }

BIN
scene/resources/default_theme/graph_node_default.png


BIN
scene/resources/default_theme/graph_node_default_focus.png


BIN
scene/resources/default_theme/graph_node_selected.png


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 11 - 0
scene/resources/default_theme/theme_data.h


+ 234 - 53
scene/resources/shader_graph.cpp

@@ -80,12 +80,15 @@ void ShaderGraph::_set_data(const Dictionary &p_data) {
 			ERR_FAIL_COND((conns.size()%3)!=0);
 
 			for(int j=0;j<conns.size();j+=3) {
-
 				SourceSlot ss;
 				int ls=conns[j+0];
-				ss.id=conns[j+1];
-				ss.slot=conns[j+2];
-				n.connections[ls]=ss;
+				if (ls == SLOT_DEFAULT_VALUE) {
+					n.defaults[conns[j+1]]=conns[j+2];
+				} else {
+					ss.id=conns[j+1];
+					ss.slot=conns[j+2];
+					n.connections[ls]=ss;
+				}
 			}
 			shader[t].node_map[n.id]=n;
 
@@ -114,7 +117,7 @@ Dictionary ShaderGraph::_get_data() const {
 			data[idx+4]=E->get().param2;
 
 			Array conns;
-			conns.resize(E->get().connections.size()*3);
+			conns.resize(E->get().connections.size()*3+E->get().defaults.size()*3);
 			int idx2=0;
 			for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) {
 
@@ -123,6 +126,14 @@ Dictionary ShaderGraph::_get_data() const {
 				conns[idx2+2]=F->get().slot;
 				idx2+=3;
 			}
+			for(Map<int,Variant>::Element*F=E->get().defaults.front();F;F=F->next()) {
+
+				conns[idx2+0]=SLOT_DEFAULT_VALUE;
+				conns[idx2+1]=F->key();
+				conns[idx2+2]=F->get();
+				idx2+=3;
+			}
+
 			data[idx+5]=conns;
 			idx+=6;
 		}
@@ -142,6 +153,15 @@ ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
 	return shader[p_type].error;
 }
 
+int ShaderGraph::node_count(ShaderType p_which, int p_type)
+{
+	int count=0;
+	for (Map<int,Node>::Element *E=shader[p_which].node_map.front();E;E=E->next())
+		if (E->get().type==p_type)
+			count++;
+	return count;
+}
+
 void ShaderGraph::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
@@ -155,6 +175,9 @@ void ShaderGraph::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
 
+	ObjectTypeDB::bind_method(_MD("default_set_value","shader_type","id","param_id","value"), &ShaderGraph::default_set_value);
+	ObjectTypeDB::bind_method(_MD("default_get_value","shader_type","id","param_id"), &ShaderGraph::default_get_value);
+
 	ObjectTypeDB::bind_method(_MD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value);
 	ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_set_value);
 
@@ -537,7 +560,7 @@ void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
 		case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
 		case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
 		case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
-		case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)			
+		case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
 		case NODE_DEFAULT_TEXTURE: {}; break;
 		case NODE_OUTPUT: {} break; // output (shader type dependent)
 		case NODE_COMMENT: {} break; // comment
@@ -683,6 +706,18 @@ void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_con
 	}
 }
 
+bool ShaderGraph::is_slot_connected(ShaderGraph::ShaderType p_type, int p_dst_id, int slot_id)
+{
+	for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+		for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
+
+			if (p_dst_id == E->key() && slot_id==F->key())
+				return true;
+		}
+	}
+	return false;
+}
+
 
 void ShaderGraph::clear(ShaderType p_type) {
 
@@ -824,6 +859,47 @@ float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id
 	return arr[1];
 }
 
+void ShaderGraph::duplicate_nodes(ShaderType p_which, List<int> &p_nodes)
+{
+	//Create new node IDs
+	Map<int,int> duplicates = Map<int,int>();
+	int i=1;
+	for(List<int>::Element *E=p_nodes.front();E; E=E->next()) {
+		while (shader[p_which].node_map.has(i))
+			i++;
+		duplicates.insert(E->get(), i);
+		i++;
+	}
+
+	for(List<int>::Element *E = p_nodes.front();E; E=E->next()) {
+
+		const Node &n=shader[p_which].node_map[E->get()];
+		Node nn=n;
+		nn.id=duplicates.find(n.id)->get();
+		nn.pos += Vector2(0,100);
+		for (Map<int,SourceSlot>::Element *C=nn.connections.front();C;C=C->next()) {
+			SourceSlot &c=C->get();
+			if (p_nodes.find(c.id))
+				c.id=duplicates.find(c.id)->get();
+		}
+		shader[p_which].node_map[nn.id]=nn;
+	}
+	_request_update();
+}
+
+List<int> ShaderGraph::generate_ids(ShaderType p_type, int count)
+{
+	List<int> ids = List<int>();
+	int i=1;
+	while (ids.size() < count) {
+		while (shader[p_type].node_map.has(i))
+			i++;
+		ids.push_back(i);
+		i++;
+	}
+	return ids;
+}
+
 
 void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){
 
@@ -955,6 +1031,33 @@ ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_
 	return ScalarFunc(func);
 }
 
+void ShaderGraph::default_set_value(ShaderGraph::ShaderType p_which, int p_id, int p_param, const Variant &p_value)
+{
+	ERR_FAIL_INDEX(p_which,3);
+	ERR_FAIL_COND(!shader[p_which].node_map.has(p_id));
+	Node& n = shader[p_which].node_map[p_id];
+	if(p_value.get_type()==Variant::NIL)
+		n.defaults.erase(n.defaults.find(p_param));
+	else
+		n.defaults[p_param]=p_value;
+
+	_request_update();
+
+}
+
+Variant ShaderGraph::default_get_value(ShaderGraph::ShaderType p_which, int p_id, int p_param)
+{
+	ERR_FAIL_INDEX_V(p_which,3,Variant());
+	ERR_FAIL_COND_V(!shader[p_which].node_map.has(p_id),Variant());
+	const Node& n = shader[p_which].node_map[p_id];
+
+	if (!n.defaults.has(p_param))
+		return Variant();
+	return n.defaults[p_param];
+}
+
+
+
 void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){
 
 	ERR_FAIL_INDEX(p_type,3);
@@ -980,52 +1083,52 @@ ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type,
 
 void ShaderGraph::color_ramp_node_set_ramp(ShaderType p_type,int p_id,const DVector<Color>& p_colors, const DVector<real_t>& p_offsets){
 
-    ERR_FAIL_INDEX(p_type,3);
-    ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
-    ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
-    Node& n = shader[p_type].node_map[p_id];
-    n.param1=p_colors;
-    n.param2=p_offsets;
-    _request_update();
+	ERR_FAIL_INDEX(p_type,3);
+	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+	ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
+	Node& n = shader[p_type].node_map[p_id];
+	n.param1=p_colors;
+	n.param2=p_offsets;
+	_request_update();
 
 }
 
 DVector<Color> ShaderGraph::color_ramp_node_get_colors(ShaderType p_type,int p_id) const{
 
-    ERR_FAIL_INDEX_V(p_type,3,DVector<Color>());
-    ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Color>());
-    const Node& n = shader[p_type].node_map[p_id];
-    return n.param1;
+	ERR_FAIL_INDEX_V(p_type,3,DVector<Color>());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Color>());
+	const Node& n = shader[p_type].node_map[p_id];
+	return n.param1;
 
 
 }
 
 DVector<real_t> ShaderGraph::color_ramp_node_get_offsets(ShaderType p_type,int p_id) const{
 
-    ERR_FAIL_INDEX_V(p_type,3,DVector<real_t>());
-    ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<real_t>());
-    const Node& n = shader[p_type].node_map[p_id];
-    return n.param2;
+	ERR_FAIL_INDEX_V(p_type,3,DVector<real_t>());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<real_t>());
+	const Node& n = shader[p_type].node_map[p_id];
+	return n.param2;
 
 }
 
 
 void ShaderGraph::curve_map_node_set_points(ShaderType p_type,int p_id,const DVector<Vector2>& p_points) {
 
-    ERR_FAIL_INDEX(p_type,3);
-    ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
-    Node& n = shader[p_type].node_map[p_id];
-    n.param1=p_points;
-    _request_update();
+	ERR_FAIL_INDEX(p_type,3);
+	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+	Node& n = shader[p_type].node_map[p_id];
+	n.param1=p_points;
+	_request_update();
 
 }
 
 DVector<Vector2> ShaderGraph::curve_map_node_get_points(ShaderType p_type,int p_id) const{
 
-    ERR_FAIL_INDEX_V(p_type,3,DVector<Vector2>());
-    ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Vector2>());
-    const Node& n = shader[p_type].node_map[p_id];
-    return n.param1;
+	ERR_FAIL_INDEX_V(p_type,3,DVector<Vector2>());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Vector2>());
+	const Node& n = shader[p_type].node_map[p_id];
+	return n.param1;
 
 }
 
@@ -1215,6 +1318,12 @@ Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
 	s["pos"]=n.pos;
 	s["param1"]=n.param1;
 	s["param2"]=n.param2;
+	Array keys;
+	for (Map<int,Variant>::Element *E=n.defaults.front();E;E=E->next()) {
+		keys.append(E->key());
+		s[E->key()]=E->get();
+	}
+	s["default_keys"]=keys;
 	return s;
 
 }
@@ -1227,10 +1336,15 @@ void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_sta
 	ERR_FAIL_COND(!d.has("pos"));
 	ERR_FAIL_COND(!d.has("param1"));
 	ERR_FAIL_COND(!d.has("param2"));
+	ERR_FAIL_COND(!d.has("default_keys"));
+
 	n.pos=d["pos"];
 	n.param1=d["param1"];
 	n.param2=d["param2"];
-
+	Array keys = d["default_keys"];
+	for(int i=0;i<keys.size();i++) {
+		n.defaults[keys[i]]=d[keys[i]];
+	}
 }
 
 ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
@@ -1735,17 +1849,17 @@ void ShaderGraph::_update_shader() {
 				Vector<String> inputs;
 				int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type);
 				for(int k=0;k<max;k++) {
+					String iname;
 					if (!n->connections.has(k)) {
-						shader[i].error=GRAPH_ERROR_MISSING_CONNECTIONS;
-						failed=true;
-						break;
+						iname="nd"+itos(n->id)+"sl"+itos(k)+"def";
+					} else {
+						iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
+						if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
+							inputs_used.insert(iname);
+						}
+
 					}
-					String iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
 					inputs.push_back(iname);
-					if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
-						inputs_used.insert(iname);
-					}
-
 				}
 
 				if (failed)
@@ -1874,27 +1988,27 @@ void ShaderGraph::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector
 	};
 
 	for (i = 0; i < 4; i++)
-	    {
-	      for (j = 0; j < 4; j++)
+		{
+		  for (j = 0; j < 4; j++)
 		{
 		  tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
-			      CR_basis[i][1] * geometry[1][j] +
-			      CR_basis[i][2] * geometry[2][j] +
-			      CR_basis[i][3] * geometry[3][j]);
+				  CR_basis[i][1] * geometry[1][j] +
+				  CR_basis[i][2] * geometry[2][j] +
+				  CR_basis[i][3] * geometry[3][j]);
+		}
 		}
-	    }
 	/* compose the above results to get the deltas matrix */
 
 	for (i = 0; i < 4; i++)
-	    {
-	      for (j = 0; j < 4; j++)
+		{
+		  for (j = 0; j < 4; j++)
 		{
 		  deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
-			      tmp2[i][1] * tmp1[1][j] +
-			      tmp2[i][2] * tmp1[2][j] +
-			      tmp2[i][3] * tmp1[3][j]);
+				  tmp2[i][1] * tmp1[1][j] +
+				  tmp2[i][2] * tmp1[2][j] +
+				  tmp2[i][3] * tmp1[3][j]);
+		}
 		}
-	    }
 
 
 	/* extract the x deltas */
@@ -1951,6 +2065,31 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 	const char *typestr[4]={"float","vec3","mat4","texture"};
 #define OUTNAME(id,slot) (String(typestr[get_node_output_slot_type(get_mode(),p_type,p_node->type,slot)])+" "+("nd"+itos(id)+"sl"+itos(slot)))
 #define OUTVAR(id,slot) ("nd"+itos(id)+"sl"+itos(slot))
+#define DEF_VEC(slot)\
+	if (p_inputs[slot].ends_with("def")){\
+		Vector3 v = p_node->defaults[slot];\
+		code+=String(typestr[1])+" "+p_inputs[slot]+"=vec3("+v+");\n";\
+	}
+#define DEF_SCALAR(slot)\
+	if (p_inputs[slot].ends_with("def")){\
+		double v = p_node->defaults[slot];\
+		code+=String(typestr[0])+" "+p_inputs[slot]+"="+rtos(v)+";\n";\
+	}
+#define DEF_COLOR(slot)\
+	if (p_inputs[slot].ends_with("def")){\
+		Color col = p_node->defaults[slot];\
+		code+=String(typestr[1])+" "+p_inputs[slot]+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";\
+	}
+#define DEF_MATRIX(slot) \
+	if (p_inputs[slot].ends_with("def")){\
+		Transform xf = p_node->defaults[slot]; \
+		code+=String(typestr[3])+" "+p_inputs[slot]+"=mat4(\n";\
+		code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n";\
+		code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n";\
+		code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n";\
+		code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n";\
+		code+=");\n";\
+	}
 
 	switch(p_node->type) {
 
@@ -1987,9 +2126,12 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 			code+=OUTNAME(p_node->id,0)+"=TIME;\n";
 		}break;
 		case NODE_SCREEN_TEX: {
+			DEF_VEC(0);
 			code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+".xy);\n";
 		}break;
 		case NODE_SCALAR_OP: {
+			DEF_SCALAR(0);
+			DEF_SCALAR(1);
 			int op = p_node->param1;
 			String optxt;
 			switch(op) {
@@ -2009,6 +2151,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}break;
 		case NODE_VEC_OP: {
+			DEF_VEC(0);
+			DEF_VEC(1);
 			int op = p_node->param1;
 			String optxt;
 			switch(op) {
@@ -2026,6 +2170,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}break;
 		case NODE_VEC_SCALAR_OP: {
+			DEF_VEC(0);
+			DEF_SCALAR(1);
 			int op = p_node->param1;
 			String optxt;
 			switch(op) {
@@ -2037,6 +2183,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}break;
 		case NODE_RGB_OP: {
+			DEF_COLOR(0);
+			DEF_COLOR(1);
 
 			int op = p_node->param1;
 			static const char*axisn[3]={"x","y","z"};
@@ -2048,7 +2196,6 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 				case RGB_OP_DIFFERENCE: {
 
 					code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
-
 				} break;
 				case RGB_OP_DARKEN: {
 
@@ -2119,11 +2266,15 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 			}
 		}break;
 		case NODE_XFORM_MULT: {
+			DEF_MATRIX(0);
+			DEF_MATRIX(1);
 
 			code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n";
 
 		}break;
 		case NODE_XFORM_VEC_MULT: {
+			DEF_MATRIX(0);
+			DEF_VEC(1);
 
 			bool no_translation = p_node->param1;
 			if (no_translation) {
@@ -2134,6 +2285,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}break;
 		case NODE_XFORM_VEC_INV_MULT: {
+			DEF_VEC(0);
+			DEF_MATRIX(1);
 			bool no_translation = p_node->param1;
 			if (no_translation) {
 				code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n";
@@ -2142,6 +2295,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 			}
 		}break;
 		case NODE_SCALAR_FUNC: {
+			DEF_SCALAR(0);
 			static const char*scalar_func_id[SCALAR_MAX_FUNC]={
 				"sin($)",
 				"cos($)",
@@ -2171,6 +2325,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		} break;
 		case NODE_VEC_FUNC: {
+			DEF_VEC(0);
 			static const char*vec_func_id[VEC_MAX_FUNC]={
 				"normalize($)",
 				"max(min($,vec3(1,1,1)),vec3(0,0,0))",
@@ -2208,44 +2363,63 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 			}
 		}break;
 		case NODE_VEC_LEN: {
+			DEF_VEC(0);
 
 			code += OUTNAME(p_node->id,0)+"=length("+p_inputs[0]+");\n";
 
 		}break;
 		case NODE_DOT_PROD: {
+			DEF_VEC(0);
+			DEF_VEC(1);
 			code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n";
 
 		}break;
 		case NODE_VEC_TO_SCALAR: {
+			DEF_VEC(0);
 			code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
 			code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
 			code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
 
 		}break;
 		case NODE_SCALAR_TO_VEC: {
+			DEF_SCALAR(0);
+			DEF_SCALAR(1);
+			DEF_SCALAR(2);
 			code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n";
 
 		}break;
 		case NODE_VEC_TO_XFORM: {
+			DEF_VEC(0);
+			DEF_VEC(1);
+			DEF_VEC(2);
+			DEF_VEC(3);
 			code += OUTNAME(p_node->id,0)+"=xform("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+","+","+p_inputs[3]+");\n";
 
 		}break;
 		case NODE_XFORM_TO_VEC: {
+			DEF_MATRIX(0);
 			code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
 			code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
 			code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
 			code += OUTNAME(p_node->id,3)+"="+p_inputs[0]+".o;\n";
 		}break;
 		case NODE_SCALAR_INTERP: {
+			DEF_SCALAR(0);
+			DEF_SCALAR(1);
+			DEF_SCALAR(2);
 
 			code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
 
 		}break;
 		case NODE_VEC_INTERP: {
+			DEF_VEC(0);
+			DEF_VEC(1);
+			DEF_SCALAR(2);
 			code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
 
 		}break;
 		case NODE_COLOR_RAMP: {
+			DEF_SCALAR(0);
 
 			static const int color_ramp_len=512;
 			DVector<uint8_t> cramp;
@@ -2302,6 +2476,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}break;
 		case NODE_CURVE_MAP: {
+			DEF_SCALAR(0);
 			static const int curve_map_len=256;
 			bool mapped[256];
 			zeromem(mapped,sizeof(mapped));
@@ -2406,6 +2581,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}break;
 		case NODE_TEXTURE_INPUT: {
+			DEF_VEC(0);
 			String name = p_node->param1;
 			String rname="rt_read_tex"+itos(p_node->id);
 			code +="uniform texture "+name+";";
@@ -2415,7 +2591,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}break;
 		case NODE_CUBEMAP_INPUT: {
-
+			DEF_VEC(0);
 			String name = p_node->param1;
 			code +="uniform cubemap "+name+";";
 			String rname="rt_read_tex"+itos(p_node->id);
@@ -2424,6 +2600,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 			code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
 		}break;
 		case NODE_DEFAULT_TEXTURE: {
+			DEF_VEC(0);
 
 			if (get_mode()==MODE_CANVAS_ITEM && p_type==SHADER_TYPE_FRAGMENT) {
 
@@ -2450,4 +2627,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 		}
 	}
+#undef DEF_SCALAR
+#undef DEF_COLOR
+#undef DEF_MATRIX
+#undef DEF_VEC
 }

+ 14 - 1
scene/resources/shader_graph.h

@@ -68,7 +68,7 @@ public:
 		NODE_VEC_INTERP, // vec3 interpolation  (with optional curve)
 		NODE_COLOR_RAMP, //take scalar, output vec3
 		NODE_CURVE_MAP, //take scalar, otput scalar
-		NODE_SCALAR_INPUT, // scalar uniform (assignable in material)		
+		NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
 		NODE_VEC_INPUT, // vec3 uniform (assignable in material)
 		NODE_RGB_INPUT, // color uniform (assignable in material)
 		NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
@@ -120,6 +120,7 @@ private:
 
 	String _find_unique_name(const String& p_base);
 
+	enum {SLOT_DEFAULT_VALUE = 0x7FFFFFFF};
 	struct SourceSlot {
 
 		int id;
@@ -135,6 +136,7 @@ private:
 		NodeType type;
 		Variant param1;
 		Variant param2;
+		Map<int, Variant> defaults;
 		int id;
 		mutable int order; // used for sorting
 		int sort_order;
@@ -216,6 +218,10 @@ public:
 	void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength);
 	float texture_node_get_filter_strength(ShaderType p_which,float p_id) const;
 
+	void duplicate_nodes(ShaderType p_which, List<int> &p_nodes);
+
+	List<int> generate_ids(ShaderType p_type, int count);
+
 	enum ScalarOp {
 		SCALAR_OP_ADD,
 		SCALAR_OP_SUB,
@@ -314,6 +320,9 @@ public:
 		VEC_MAX_FUNC
 	};
 
+	void default_set_value(ShaderType p_which,int p_id,int p_param, const Variant& p_value);
+	Variant default_get_value(ShaderType p_which,int p_id,int p_param);
+
 	void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);
 	VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const;
 
@@ -354,6 +363,8 @@ public:
 
 	void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const;
 
+	bool is_slot_connected(ShaderType p_which,int p_dst_id,int slot_id);
+
 	void clear(ShaderType p_which);
 
 	Variant node_get_state(ShaderType p_type, int p_node) const;
@@ -361,6 +372,8 @@ public:
 
 	GraphError get_graph_error(ShaderType p_type) const;
 
+	int node_count(ShaderType p_which, int p_type);
+
 	static int get_type_input_count(NodeType p_type);
 	static int get_type_output_count(NodeType p_type);
 	static SlotType get_type_input_type(NodeType p_type,int p_idx);

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 1196 - 768
tools/editor/plugins/shader_graph_editor_plugin.cpp


+ 15 - 2
tools/editor/plugins/shader_graph_editor_plugin.h

@@ -129,6 +129,7 @@ class ShaderGraphView : public Node {
 	GraphEdit *graph_edit;
 	Ref<ShaderGraph> graph;
 	int edited_id;
+	int edited_def;
 
 	ShaderGraph::ShaderType type;
 
@@ -136,13 +137,23 @@ class ShaderGraphView : public Node {
 	void _create_node(int p_id);
 
 
+	ToolButton *make_label(String text, Variant::Type v_type = Variant::NIL);
+	ToolButton *make_editor(String text, GraphNode* gn, int p_id, int param, Variant::Type type, String p_hint="");
 
 	void _connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot);
 	void _disconnection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot);
 
 	void _node_removed(int p_id);
+	void _begin_node_move();
 	void _node_moved(const Vector2& p_from, const Vector2& p_to,int p_id);
+	void _end_node_move();
 	void _move_node(int p_id,const Vector2& p_to);
+	void _duplicate_nodes_request();
+	void _duplicate_nodes(Array &p_nodes);
+	void _delete_nodes_request();
+
+
+	void _default_changed(int p_id, Node* p_button, int p_param, int v_type, String p_hint);
 
 	void _scalar_const_changed(double p_value,int p_id);
 	void _vec_const_changed(double p_value, int p_id, Array p_arr);
@@ -175,7 +186,7 @@ protected:
 	static void _bind_methods();
 public:
 
-	void add_node(int p_type);
+	void add_node(int p_type, const Vector2 &location);
 	GraphEdit *get_graph_edit() { return graph_edit; }
 	void set_graph(Ref<ShaderGraph> p_graph);
 
@@ -186,13 +197,15 @@ class ShaderGraphEditor : public VBoxContainer {
 
 	OBJ_TYPE(ShaderGraphEditor,VBoxContainer);
 
-	MenuButton *menu;
+	PopupMenu *popup;
 	TabContainer *tabs;
 	ShaderGraphView *graph_edits[ShaderGraph::SHADER_TYPE_MAX];
 	static const char* node_names[ShaderGraph::NODE_TYPE_MAX];
+	Vector2 next_location;
 
 	bool _2d;
 	void _add_node(int p_type);
+	void _popup_requested(const Vector2 &p_position);
 protected:
 	void _notification(int p_what);
 	static void _bind_methods();

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 247 - 190
tools/editor/property_editor.cpp


+ 21 - 19
tools/editor/property_editor.h

@@ -46,9 +46,9 @@
 */
 
 class CustomPropertyEditor : public Popup {
-	
+
 	OBJ_TYPE( CustomPropertyEditor, Popup );
-	
+
 	enum {
 		MAX_VALUE_EDITORS=12,
 		MAX_ACTION_BUTTONS=5,
@@ -93,7 +93,8 @@ class CustomPropertyEditor : public Popup {
 	TextEdit *text_edit;
 	bool read_only;
 	Button *checks20[20];
-
+	SpinBox *spinbox;
+	HSlider *slider;
 
 
 	Control *easing_draw;
@@ -106,6 +107,7 @@ class CustomPropertyEditor : public Popup {
 	void _file_selected(String p_file);
 	void _scroll_modified(double p_value);
 	void _modified(String p_string);
+	void _range_modified(double p_value);
 	void _focus_enter();
 	void _focus_exit();
 	void _action_pressed(int p_which);
@@ -114,7 +116,7 @@ class CustomPropertyEditor : public Popup {
 	void _color_changed(const Color& p_color);
 	void _draw_easing();
 	void _menu_option(int p_which);
-	
+
 	void _drag_easing(const InputEvent& p_ev);
 
 	void _node_path_selected(NodePath p_path);
@@ -125,23 +127,23 @@ class CustomPropertyEditor : public Popup {
 protected:
 
 	void _notification(int p_what);
-	static void _bind_methods();			
-	
-public:	
+	static void _bind_methods();
+
+public:
 	Variant get_variant() const;
 	String get_name() const;
-	
+
 	void set_read_only(bool p_read_only) { read_only=p_read_only; }
 
 	bool edit(Object* p_owner,const String& p_name,Variant::Type p_type, const Variant& p_variant,int p_hint,String p_hint_text);
-	
+
 	CustomPropertyEditor();
 };
 
 class PropertyEditor : public Control {
-	
+
 	OBJ_TYPE( PropertyEditor, Control );
-	
+
 	Tree *tree;
 	Label *top_label;
 	//Object *object;
@@ -168,26 +170,26 @@ class PropertyEditor : public Control {
 	Map<StringName,String > class_descr_cache;
 	
 	CustomPropertyEditor *custom_editor;
-	
+
 	void _resource_edit_request();
 	void _custom_editor_edited();
 	void _custom_editor_request(bool p_arrow);
-	
+
 	void _item_selected();
 	void _item_edited();
 	TreeItem *get_parent_node(String p_path,HashMap<String,TreeItem*>& item_paths,TreeItem *root);
-	
+
 	void set_item_text(TreeItem *p_item, int p_type, const String& p_name, int p_hint=PROPERTY_HINT_NONE, const String& p_hint_text="");
-		
+
 	TreeItem *find_item(TreeItem *p_item,const String& p_name);
-		
-	
+
+
 	virtual void _changed_callback(Object *p_changed,const char * p_what);
 	virtual void _changed_callbacks(Object *p_changed,const String& p_callback);
 
 
 	void _edit_button(Object *p_item, int p_column, int p_button);
-	
+
 	void _node_removed(Node *p_node);
 	void _edit_set(const String& p_name, const Variant& p_value);
 	void _draw_flags(Object *ti,const Rect2& p_rect);
@@ -201,7 +203,7 @@ class PropertyEditor : public Control {
 
 	UndoRedo *undo_redo;
 protected:
-	
+
 	void _notification(int p_what);
 	static void _bind_methods();
 public:

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно