summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.cpp13
-rw-r--r--scene/gui/color_picker.cpp65
-rw-r--r--scene/gui/color_picker.h1
-rw-r--r--scene/gui/container.cpp8
-rw-r--r--scene/gui/control.cpp125
-rw-r--r--scene/gui/control.h19
-rw-r--r--scene/gui/dialogs.cpp2
-rw-r--r--scene/gui/file_dialog.cpp19
-rw-r--r--scene/gui/file_dialog.h2
-rw-r--r--scene/gui/graph_edit.cpp522
-rw-r--r--scene/gui/graph_edit.h63
-rw-r--r--scene/gui/graph_node.cpp184
-rw-r--r--scene/gui/graph_node.h40
-rw-r--r--scene/gui/item_list.cpp71
-rw-r--r--scene/gui/item_list.h6
-rw-r--r--scene/gui/label.cpp20
-rw-r--r--scene/gui/label.h1
-rw-r--r--scene/gui/line_edit.cpp84
-rw-r--r--scene/gui/line_edit.h8
-rw-r--r--scene/gui/menu_button.cpp7
-rw-r--r--scene/gui/popup.cpp4
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--scene/gui/scroll_container.cpp4
-rw-r--r--scene/gui/slider.cpp9
-rw-r--r--scene/gui/spin_box.cpp2
-rw-r--r--scene/gui/tab_container.cpp3
-rw-r--r--scene/gui/text_edit.cpp89
-rw-r--r--scene/gui/text_edit.h11
-rw-r--r--scene/gui/texture_progress.cpp1
-rw-r--r--scene/gui/tree.cpp102
-rw-r--r--scene/gui/tree.h10
31 files changed, 1269 insertions, 230 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 699062fee4..6479dd2d02 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -55,6 +55,8 @@ void BaseButton::_input_event(InputEvent p_event) {
if (b.pressed) {
+ emit_signal("button_down");
+
if (!toggle_mode) { //mouse press attempt
status.press_attempt=true;
@@ -86,6 +88,8 @@ void BaseButton::_input_event(InputEvent p_event) {
} else {
+ emit_signal("button_up");
+
if (status.press_attempt && status.pressing_inside) {
// released();
emit_signal("released");
@@ -100,9 +104,11 @@ void BaseButton::_input_event(InputEvent p_event) {
status.press_attempt=true;
status.pressing_inside=true;
+ emit_signal("button_down");
} else {
+ emit_signal("button_up");
if (status.press_attempt &&status.pressing_inside) {
@@ -173,6 +179,7 @@ void BaseButton::_input_event(InputEvent p_event) {
status.pressing_button++;
status.press_attempt=true;
status.pressing_inside=true;
+ emit_signal("button_down");
} else if (status.press_attempt) {
@@ -185,6 +192,8 @@ void BaseButton::_input_event(InputEvent p_event) {
status.press_attempt=false;
status.pressing_inside=false;
+ emit_signal("button_up");
+
if (!toggle_mode) { //mouse press attempt
pressed();
@@ -416,7 +425,7 @@ Ref<ShortCut> BaseButton:: get_shortcut() const {
void BaseButton::_unhandled_input(InputEvent p_event) {
- if (!is_disabled() && is_visible() && p_event.is_pressed() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) {
+ if (!is_disabled() && is_visible() && p_event.is_pressed() && !p_event.is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) {
if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this))
return; //ignore because of modal window
@@ -467,6 +476,8 @@ void BaseButton::_bind_methods() {
ADD_SIGNAL( MethodInfo("pressed" ) );
ADD_SIGNAL( MethodInfo("released" ) );
+ ADD_SIGNAL( MethodInfo("button_up") );
+ ADD_SIGNAL( MethodInfo("button_down") );
ADD_SIGNAL( MethodInfo("toggled", PropertyInfo( Variant::BOOL,"pressed") ) );
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode"));
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 06f8c27957..5e66544153 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -41,13 +41,13 @@ void update_material(Ref<CanvasItemMaterial>mat,const Color& p_color,float h,flo
if (!sdr.is_valid())
return;
- mat->set_shader_param("R",p_color.r);
- mat->set_shader_param("G",p_color.g);
- mat->set_shader_param("B",p_color.b);
- mat->set_shader_param("H",h);
- mat->set_shader_param("S",s);
- mat->set_shader_param("V",v);
- mat->set_shader_param("A",p_color.a);
+ mat->set_shader_param("R",p_color.r);
+ mat->set_shader_param("G",p_color.g);
+ mat->set_shader_param("B",p_color.b);
+ mat->set_shader_param("H",h);
+ mat->set_shader_param("S",s);
+ mat->set_shader_param("V",v);
+ mat->set_shader_param("A",p_color.a);
}
void ColorPicker::_notification(int p_what) {
@@ -140,14 +140,13 @@ void ColorPicker::_value_changed(double) {
if (updating)
return;
- for(int i=0;i<3;i++) {
+ for(int i=0;i<4;i++) {
color.components[i] = scroll[i]->get_val()/(raw_mode_enabled?1.0:255.0);
}
- color.components[3] = scroll[3]->get_val()/255.0;
set_color(color);
- c_text->set_text(color.to_html(edit_alpha && color.a<1));
+ _update_text_value();
emit_signal("color_changed",color);
@@ -174,22 +173,16 @@ void ColorPicker::_update_color() {
for(int i=0;i<4;i++) {
scroll[i]->set_max(255);
scroll[i]->set_step(0.01);
- if (raw_mode_enabled && i != 3)
+ if (raw_mode_enabled) {
+ if (i == 3)
+ scroll[i]->set_max(1);
scroll[i]->set_val(color.components[i]);
- else
- scroll[i]->set_val(color.components[i]*255);
+ } else {
+ scroll[i]->set_val(color.components[i] * 255);
+ }
}
- if (text_is_constructor) {
- String t = "Color("+String::num(color.r)+","+String::num(color.g)+","+String::num(color.b);
- if (edit_alpha && color.a<1)
- t+=(","+String::num(color.a)+")") ;
- else
- t+=")";
- c_text->set_text(t);
- } else {
- c_text->set_text(color.to_html(edit_alpha && color.a<1));
- }
+ _update_text_value();
sample->update();
updating=false;
@@ -262,6 +255,20 @@ bool ColorPicker::is_raw_mode() const {
return raw_mode_enabled;
}
+
+void ColorPicker::_update_text_value() {
+ if (text_is_constructor) {
+ String t = "Color("+String::num(color.r)+","+String::num(color.g)+","+String::num(color.b);
+ if (edit_alpha && color.a<1)
+ t+=(","+String::num(color.a)+")") ;
+ else
+ t+=")";
+ c_text->set_text(t);
+ } else {
+ c_text->set_text(color.to_html(edit_alpha && color.a<1));
+ }
+}
+
void ColorPicker::_sample_draw() {
sample->draw_rect(Rect2(Point2(),Size2(256,20)),color);
}
@@ -271,12 +278,12 @@ void ColorPicker::_hsv_draw(int p_wich,Control* c)
if (!c)
return;
if (p_wich==0) {
- int x=c->get_size().x*s;
- int y=c->get_size().y-c->get_size().y*v;
+ int x = CLAMP(c->get_size().x * s, 0, c->get_size().x);
+ int y = CLAMP(c->get_size().y-c->get_size().y * v, 0, c->get_size().y);
Color col = color;
col.a=1;
c->draw_line(Point2(x,0),Point2(x,c->get_size().y),col.inverted());
- c->draw_line(Point2(0,y),Point2(c->get_size().x,y),col.inverted());
+ c->draw_line(Point2(0, y),Point2(c->get_size().x, y),col.inverted());
c->draw_line(Point2(x,y),Point2(x,y),Color(1,1,1),2);
} else if (p_wich==1) {
int y=c->get_size().y-c->get_size().y*h;
@@ -390,9 +397,10 @@ void ColorPicker::_screen_input(const InputEvent &ev)
if (!r->get_rect().has_point(Point2(mev.global_x,mev.global_y)))
return;
Image img =r->get_screen_capture();
- if (!img.empty())
+ if (!img.empty()) {
last_capture=img;
r->queue_screen_capture();
+ }
if (!last_capture.empty())
set_color(last_capture.get_pixel(mev.global_x,mev.global_y));
}
@@ -408,11 +416,12 @@ void ColorPicker::_screen_pick_pressed()
if (!screen) {
screen=memnew( Control );
r->add_child(screen);
+ screen->set_as_toplevel(true);
screen->set_area_as_parent_rect();
screen->connect("input_event",this,"_screen_input");
}
screen->raise();
- screen->show();
+ screen->show_modal();
r->queue_screen_capture();
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index b9ef1f1e2f..5e2cc57274 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -80,6 +80,7 @@ private:
void _update_controls();
void _update_color();
void _update_presets();
+ void _update_text_value();
void _text_type_toggled();
void _sample_draw();
void _hsv_draw(int p_wich,Control *c);
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 920c6bf1e6..feaf516f42 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -41,6 +41,8 @@ void Container::_child_minsize_changed() {
void Container::add_child_notify(Node *p_child) {
+ Control::add_child_notify(p_child);
+
Control *control = p_child->cast_to<Control>();
if (!control)
return;
@@ -50,18 +52,24 @@ void Container::add_child_notify(Node *p_child) {
control->connect("visibility_changed",this,"_child_minsize_changed");
queue_sort();
+
}
void Container::move_child_notify(Node *p_child) {
+ Control::move_child_notify(p_child);
+
if (!p_child->cast_to<Control>())
return;
queue_sort();
+
+
}
void Container::remove_child_notify(Node *p_child) {
+ Control::remove_child_notify(p_child);
Control *control = p_child->cast_to<Control>();
if (!control)
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index fc27c0d24f..bf35fd25bd 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -422,7 +422,40 @@ void Control::_resize(const Size2& p_size) {
_size_changed();
}
+//moved theme configuration here, so controls can set up even if still not inside active scene
+void Control::add_child_notify(Node *p_child) {
+
+ Control *child_c=p_child->cast_to<Control>();
+ if (!child_c)
+ return;
+
+ if (child_c->data.theme.is_null() && data.theme_owner) {
+ child_c->data.theme_owner=data.theme_owner;
+ child_c->notification(NOTIFICATION_THEME_CHANGED);
+ }
+}
+
+void Control::remove_child_notify(Node *p_child) {
+
+ Control *child_c=p_child->cast_to<Control>();
+ if (!child_c)
+ return;
+
+ if (child_c->data.theme_owner && child_c->data.theme.is_null()) {
+ child_c->data.theme_owner=NULL;
+ //notification(NOTIFICATION_THEME_CHANGED);
+ }
+
+}
+
+void Control::_update_canvas_item_transform() {
+
+ Matrix32 xform=Matrix32(data.rotation,get_pos());
+ xform.scale_basis(data.scale);
+ VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),xform);
+
+}
void Control::_notification(int p_notification) {
@@ -512,10 +545,10 @@ void Control::_notification(int p_notification) {
}
- if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) {
- data.theme_owner=data.parent->data.theme_owner;
- notification(NOTIFICATION_THEME_CHANGED);
- }
+ //if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) {
+ // data.theme_owner=data.parent->data.theme_owner;
+ // notification(NOTIFICATION_THEME_CHANGED);
+ //}
} break;
case NOTIFICATION_EXIT_CANVAS: {
@@ -547,10 +580,10 @@ void Control::_notification(int p_notification) {
data.parent=NULL;
data.parent_canvas_item=NULL;
- if (data.theme_owner && data.theme.is_null()) {
- data.theme_owner=NULL;
+ //if (data.theme_owner && data.theme.is_null()) {
+ // data.theme_owner=NULL;
//notification(NOTIFICATION_THEME_CHANGED);
- }
+ //}
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
@@ -574,10 +607,9 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_DRAW: {
- Matrix32 xform=Matrix32(data.rotation,get_pos());
- xform.scale_basis(data.scale);
- VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),xform);
- VisualServer::get_singleton()->canvas_item_set_custom_rect( get_canvas_item(),true, Rect2(Point2(),get_size()));
+ _update_canvas_item_transform();
+ VisualServer::get_singleton()->canvas_item_set_custom_rect( get_canvas_item(),!data.disable_visibility_clip, Rect2(Point2(),get_size()));
+
//emit_signal(SceneStringNames::get_singleton()->draw);
} break;
@@ -1246,17 +1278,24 @@ void Control::_size_changed() {
new_size_cache.x = MAX( minimum_size.x, new_size_cache.x );
new_size_cache.y = MAX( minimum_size.y, new_size_cache.y );
-
- if (new_pos_cache == data.pos_cache && new_size_cache == data.size_cache)
- return; // did not change, don't emit signal
+ bool pos_changed = new_pos_cache != data.pos_cache;
+ bool size_changed = new_size_cache != data.size_cache;
data.pos_cache=new_pos_cache;
data.size_cache=new_size_cache;
- notification(NOTIFICATION_RESIZED);
- item_rect_changed();
- _change_notify_margins();
- _notify_transform();
+ if (size_changed) {
+ notification(NOTIFICATION_RESIZED);
+ }
+ if (pos_changed || size_changed) {
+ item_rect_changed(size_changed);
+ _change_notify_margins();
+ _notify_transform();
+ }
+
+ if (pos_changed && !size_changed) {
+ _update_canvas_item_transform(); //move because it won't be updated
+ }
}
float Control::_get_parent_range(int p_idx) const {
@@ -1865,7 +1904,7 @@ void Control::_modal_stack_remove() {
}
-void Control::_propagate_theme_changed(CanvasItem *p_at,Control *p_owner) {
+void Control::_propagate_theme_changed(CanvasItem *p_at,Control *p_owner,bool p_assign) {
Control *c = p_at->cast_to<Control>();
@@ -1884,15 +1923,30 @@ void Control::_propagate_theme_changed(CanvasItem *p_at,Control *p_owner) {
if (c) {
- c->data.theme_owner=p_owner;
+ if (p_assign) {
+ c->data.theme_owner=p_owner;
+ }
c->_notification(NOTIFICATION_THEME_CHANGED);
c->update();
}
}
+
+void Control::_theme_changed() {
+
+ _propagate_theme_changed(this,this,false);
+}
+
void Control::set_theme(const Ref<Theme>& p_theme) {
+ if (data.theme==p_theme)
+ return;
+
+ if (data.theme.is_valid()) {
+ data.theme->disconnect("changed",this,"_theme_changed");
+ }
+
data.theme=p_theme;
if (!p_theme.is_null()) {
@@ -1909,6 +1963,9 @@ void Control::set_theme(const Ref<Theme>& p_theme) {
}
+ if (data.theme.is_valid()) {
+ data.theme->connect("changed",this,"_theme_changed");
+ }
}
@@ -2170,7 +2227,7 @@ void Control::grab_click_focus() {
void Control::minimum_size_changed() {
- if (!is_inside_tree())
+ if (!is_inside_tree() || data.block_minimum_size_adjust)
return;
if (data.pending_min_size_update)
@@ -2244,6 +2301,7 @@ void Control::set_rotation(float p_radians) {
data.rotation=p_radians;
update();
_notify_transform();
+ _change_notify("rect/rotation");
}
float Control::get_rotation() const{
@@ -2329,7 +2387,26 @@ Control *Control::get_root_parent_control() const {
return const_cast<Control*>(root);
}
+void Control::set_block_minimum_size_adjust(bool p_block) {
+ data.block_minimum_size_adjust=p_block;
+}
+bool Control::is_minimum_size_adjust_blocked() const {
+
+ return data.block_minimum_size_adjust;
+}
+
+
+void Control::set_disable_visibility_clip(bool p_ignore) {
+
+ data.disable_visibility_clip=p_ignore;
+ update();
+}
+
+bool Control::is_visibility_clip_disabled() const {
+
+ return data.disable_visibility_clip;
+}
void Control::_bind_methods() {
@@ -2448,6 +2525,10 @@ void Control::_bind_methods() {
ObjectTypeDB::bind_method(_MD("minimum_size_changed"), &Control::minimum_size_changed);
+ ObjectTypeDB::bind_method(_MD("_theme_changed"), &Control::_theme_changed);
+
+
+
ObjectTypeDB::bind_method(_MD("_font_changed"), &Control::_font_changed);
BIND_VMETHOD(MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"event")));
@@ -2554,6 +2635,8 @@ Control::Control() {
data.scale=Vector2(1,1);
data.drag_owner=0;
data.modal_frame=0;
+ data.block_minimum_size_adjust=false;
+ data.disable_visibility_clip=false;
for (int i=0;i<4;i++) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 830ebd1620..558439efbf 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -128,6 +128,9 @@ private:
bool ignore_mouse;
bool stop_mouse;
+ bool block_minimum_size_adjust;
+ bool disable_visibility_clip;
+
Control *parent;
ObjectID drag_owner;
bool modal;
@@ -172,7 +175,9 @@ private:
float _get_range(int p_idx) const;
float _s2a(float p_val, AnchorType p_anchor,float p_range) const;
float _a2s(float p_val, AnchorType p_anchor,float p_range) const;
- void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner);
+ void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign=true);
+ void _theme_changed();
+
void _change_notify_margins();
void _update_minimum_size();
@@ -191,6 +196,8 @@ private:
void _unref_font( Ref<Font> p_sc);
void _font_changed();
+ void _update_canvas_item_transform();
+
friend class Viewport;
void _modal_stack_remove();
@@ -198,6 +205,9 @@ friend class Viewport;
protected:
+ virtual void add_child_notify(Node *p_child);
+ virtual void remove_child_notify(Node *p_child);
+
//virtual void _window_input_event(InputEvent p_event);
bool _set(const StringName& p_name, const Variant& p_value);
@@ -390,6 +400,13 @@ public:
Control *get_root_parent_control() const;
+
+ void set_block_minimum_size_adjust(bool p_block);
+ bool is_minimum_size_adjust_blocked() const;
+
+ void set_disable_visibility_clip(bool p_ignore);
+ bool is_visibility_clip_disabled() const;
+
Control();
~Control();
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 4dbc106834..93e46da82b 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -399,8 +399,6 @@ AcceptDialog::AcceptDialog() {
add_child(label);
hbc = memnew( HBoxContainer );
- hbc->set_area_as_parent_rect(margin);
- hbc->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,button_margin);
add_child(hbc);
hbc->add_spacer();
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index d335399caa..6b43425edc 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -475,7 +475,7 @@ void FileDialog::update_filters() {
String flt=filters[i].get_slice(";",0).strip_edges();
String desc=filters[i].get_slice(";",1).strip_edges();
if (desc.length())
- filter->add_item(desc+" ( "+flt+" )");
+ filter->add_item(String(XL_MESSAGE(desc))+" ( "+flt+" )");
else
filter->add_item("( "+flt+" )");
}
@@ -498,6 +498,16 @@ void FileDialog::add_filter(const String& p_filter) {
}
+void FileDialog::set_filters(const Vector<String>& p_filters){
+ filters=p_filters;
+ update_filters();
+ invalidate();
+}
+
+Vector<String> FileDialog::get_filters() const{
+ return filters;
+}
+
String FileDialog::get_current_dir() const {
return dir->get_text();
@@ -686,6 +696,8 @@ void FileDialog::_bind_methods() {
ObjectTypeDB::bind_method(_MD("clear_filters"),&FileDialog::clear_filters);
ObjectTypeDB::bind_method(_MD("add_filter","filter"),&FileDialog::add_filter);
+ ObjectTypeDB::bind_method(_MD("set_filters","filters"),&FileDialog::set_filters);
+ ObjectTypeDB::bind_method(_MD("get_filters"),&FileDialog::get_filters);
ObjectTypeDB::bind_method(_MD("get_current_dir"),&FileDialog::get_current_dir);
ObjectTypeDB::bind_method(_MD("get_current_file"),&FileDialog::get_current_file);
ObjectTypeDB::bind_method(_MD("get_current_path"),&FileDialog::get_current_path);
@@ -722,6 +734,11 @@ void FileDialog::_bind_methods() {
BIND_CONSTANT( ACCESS_USERDATA );
BIND_CONSTANT( ACCESS_FILESYSTEM );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"),_SCS("set_mode"),_SCS("get_mode") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"),_SCS("set_access"),_SCS("get_access") );
+ ADD_PROPERTY( PropertyInfo(Variant::STRING_ARRAY, "filters"),_SCS("set_filters"),_SCS("get_filters") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "show_hidden_files"),_SCS("set_show_hidden_files"),_SCS("is_showing_hidden_files") );
+
}
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 1fcf8387ce..150b24cb3f 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -131,6 +131,8 @@ public:
void clear_filters();
void add_filter(const String& p_filter);
+ void set_filters(const Vector<String>& p_filters);
+ Vector<String> get_filters() const;
void set_enable_multiple_selection(bool p_enable);
Vector<String> get_selected_files() const;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 06b1c42690..0de6add8cb 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -61,6 +61,8 @@ Error GraphEdit::connect_node(const StringName& p_from, int p_from_port,const St
c.to_port=p_to_port;
connections.push_back(c);
top_layer->update();
+ update();
+ connections_layer->update();
return OK;
}
@@ -85,6 +87,8 @@ void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const
connections.erase(E);
top_layer->update();
+ update();
+ connections_layer->update();
return;
}
}
@@ -100,6 +104,15 @@ void GraphEdit::get_connection_list(List<Connection> *r_connections) const {
*r_connections=connections;
}
+void GraphEdit::set_scroll_ofs(const Vector2& p_ofs) {
+
+ setting_scroll_ofs=true;
+ h_scroll->set_val(p_ofs.x);
+ v_scroll->set_val(p_ofs.y);
+ _update_scroll();
+ setting_scroll_ofs=false;
+}
+
Vector2 GraphEdit::get_scroll_ofs() const{
return Vector2(h_scroll->get_val(),v_scroll->get_val());
@@ -107,12 +120,23 @@ Vector2 GraphEdit::get_scroll_ofs() const{
void GraphEdit::_scroll_moved(double) {
- _update_scroll_offset();
+
+ if (!awaiting_scroll_offset_update) {
+ call_deferred("_update_scroll_offset");
+ awaiting_scroll_offset_update=true;
+ }
top_layer->update();
+ update();
+
+ if (!setting_scroll_ofs) {//in godot, signals on change value are avoided as a convention
+ emit_signal("scroll_offset_changed",get_scroll_ofs());
+ }
}
void GraphEdit::_update_scroll_offset() {
+ set_block_minimum_size_adjust(true);
+
for(int i=0;i<get_child_count();i++) {
GraphNode *gn=get_child(i)->cast_to<GraphNode>();
@@ -122,9 +146,15 @@ void GraphEdit::_update_scroll_offset() {
Point2 pos=gn->get_offset()*zoom;
pos-=Point2(h_scroll->get_val(),v_scroll->get_val());
gn->set_pos(pos);
- gn->set_scale(Vector2(zoom,zoom));
+ if (gn->get_scale()!=Vector2(zoom,zoom)) {
+ gn->set_scale(Vector2(zoom,zoom));
+ }
}
+ connections_layer->set_pos(-Point2(h_scroll->get_val(),v_scroll->get_val())*zoom);
+ set_block_minimum_size_adjust(false);
+ awaiting_scroll_offset_update=false;
+
}
void GraphEdit::_update_scroll() {
@@ -133,6 +163,9 @@ void GraphEdit::_update_scroll() {
return;
updating=true;
+
+ set_block_minimum_size_adjust(true);
+
Rect2 screen;
for(int i=0;i<get_child_count();i++) {
@@ -167,7 +200,13 @@ void GraphEdit::_update_scroll() {
else
v_scroll->show();
- _update_scroll_offset();
+ set_block_minimum_size_adjust(false);
+
+ if (!awaiting_scroll_offset_update) {
+ call_deferred("_update_scroll_offset");
+ awaiting_scroll_offset_update=true;
+ }
+
updating=false;
}
@@ -177,7 +216,21 @@ void GraphEdit::_graph_node_raised(Node* p_gn) {
GraphNode *gn=p_gn->cast_to<GraphNode>();
ERR_FAIL_COND(!gn);
gn->raise();
+ if (gn->is_comment()) {
+ move_child(gn,0);
+ }
+ int first_not_comment=0;
+ for(int i=0;i<get_child_count();i++) {
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (gn && !gn->is_comment()) {
+ first_not_comment=i;
+ break;
+ }
+ }
+
+ move_child(connections_layer,first_not_comment);
top_layer->raise();
+ emit_signal("node_selected",p_gn);
}
@@ -187,10 +240,14 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
GraphNode *gn=p_gn->cast_to<GraphNode>();
ERR_FAIL_COND(!gn);
top_layer->update();
+ update();
+ connections_layer->update();
}
void GraphEdit::add_child_notify(Node *p_child) {
+ Control::add_child_notify(p_child);
+
top_layer->call_deferred("raise"); //top layer always on top!
GraphNode *gn = p_child->cast_to<GraphNode>();
if (gn) {
@@ -200,10 +257,14 @@ void GraphEdit::add_child_notify(Node *p_child) {
_graph_node_moved(gn);
gn->set_stop_mouse(false);
}
+
+
}
void GraphEdit::remove_child_notify(Node *p_child) {
+ Control::remove_child_notify(p_child);
+
top_layer->call_deferred("raise"); //top layer always on top!
GraphNode *gn = p_child->cast_to<GraphNode>();
if (gn) {
@@ -228,18 +289,70 @@ void GraphEdit::_notification(int p_what) {
h_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,hmin.height);
h_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0);
+
+ zoom_minus->set_icon(get_icon("minus"));
+ zoom_reset->set_icon(get_icon("reset"));
+ zoom_plus->set_icon(get_icon("more"));
+ snap_button->set_icon(get_icon("snap"));
// zoom_icon->set_texture( get_icon("Zoom", "EditorIcons"));
}
if (p_what==NOTIFICATION_DRAW) {
+
+
draw_style_box( get_stylebox("bg"),Rect2(Point2(),get_size()) );
VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
+ if (is_using_snap()) {
+ //draw grid
+
+ int snap = get_snap();
+
+ Vector2 offset = get_scroll_ofs()/zoom;
+ Size2 size = get_size()/zoom;
+
+ Point2i from = (offset/float(snap)).floor();
+ Point2i len = (size/float(snap)).floor()+Vector2(1,1);
+
+ Color grid_minor = get_color("grid_minor");
+ Color grid_major = get_color("grid_major");
+
+ for(int i=from.x;i<from.x+len.x;i++) {
+
+ Color color;
+
+ if (ABS(i)%10==0)
+ color=grid_major;
+ else
+ color=grid_minor;
+
+ float base_ofs = i*snap*zoom - offset.x*zoom;
+ draw_line(Vector2(base_ofs,0),Vector2(base_ofs,get_size().height),color);
+ }
+
+ for(int i=from.y;i<from.y+len.y;i++) {
+
+ Color color;
+
+ if (ABS(i)%10==0)
+ color=grid_major;
+ else
+ color=grid_minor;
+
+ float base_ofs = i*snap*zoom - offset.y*zoom;
+ draw_line(Vector2(0,base_ofs),Vector2(get_size().width,base_ofs),color);
+ }
+
+ }
+
+
+
}
if (p_what==NOTIFICATION_RESIZED) {
_update_scroll();
top_layer->update();
+
}
}
@@ -247,7 +360,8 @@ bool GraphEdit::_filter_input(const Point2& p_point) {
Ref<Texture> port =get_icon("port","GraphNode");
- float grab_r=port->get_width()*0.5;
+ float grab_r_extend = 2.0;
+ float grab_r=port->get_width()*0.5*grab_r_extend;
for(int i=get_child_count()-1;i>=0;i--) {
GraphNode *gn=get_child(i)->cast_to<GraphNode>();
@@ -266,8 +380,9 @@ bool GraphEdit::_filter_input(const Point2& p_point) {
for(int j=0;j<gn->get_connection_input_count();j++) {
Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
- if (pos.distance_to(p_point)<grab_r)
+ if (pos.distance_to(p_point)<grab_r) {
return true;
+ }
}
@@ -279,11 +394,13 @@ bool GraphEdit::_filter_input(const Point2& p_point) {
void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
+
+ float grab_r_extend = 2.0;
if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && p_ev.mouse_button.pressed) {
Ref<Texture> port =get_icon("port","GraphNode");
Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y);
- float grab_r=port->get_width()*0.5;
+ float grab_r=port->get_width()*0.5*grab_r_extend;
for(int i=get_child_count()-1;i>=0;i--) {
GraphNode *gn=get_child(i)->cast_to<GraphNode>();
@@ -295,6 +412,37 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
if (pos.distance_to(mpos)<grab_r) {
+
+ if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
+ //check disconnect
+ for (List<Connection>::Element*E=connections.front();E;E=E->next()) {
+
+ if (E->get().from==gn->get_name() && E->get().from_port==j) {
+
+ Node*to = get_node(String(E->get().to));
+ if (to && to->cast_to<GraphNode>()) {
+
+ connecting_from=E->get().to;
+ connecting_index=E->get().to_port;
+ connecting_out=false;
+ connecting_type=to->cast_to<GraphNode>()->get_connection_input_type(E->get().to_port);
+ connecting_color=to->cast_to<GraphNode>()->get_connection_input_color(E->get().to_port);
+ connecting_target=false;
+ connecting_to=pos;
+ just_disconected=true;
+
+ emit_signal("disconnection_request",E->get().from,E->get().from_port,E->get().to,E->get().to_port);
+ to = get_node(String(connecting_from)); //maybe it was erased
+ if (to && to->cast_to<GraphNode>()) {
+ connecting=true;
+ }
+ return;
+ }
+
+ }
+ }
+ }
+
connecting=true;
connecting_from=gn->get_name();
connecting_index=j;
@@ -303,6 +451,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
connecting_color=gn->get_connection_output_color(j);
connecting_target=false;
connecting_to=pos;
+ just_disconected=false;
return;
}
@@ -315,7 +464,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
if (pos.distance_to(mpos)<grab_r) {
- if (right_disconnects) {
+ if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
for (List<Connection>::Element*E=connections.front();E;E=E->next()) {
@@ -331,6 +480,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
connecting_color=fr->cast_to<GraphNode>()->get_connection_output_color(E->get().from_port);
connecting_target=false;
connecting_to=pos;
+ just_disconected=true;
emit_signal("disconnection_request",E->get().from,E->get().from_port,E->get().to,E->get().to_port);
fr = get_node(String(connecting_from)); //maybe it was erased
@@ -353,6 +503,8 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
connecting_color=gn->get_connection_input_color(j);
connecting_target=false;
connecting_to=pos;
+ just_disconected=true;
+
return;
}
@@ -365,11 +517,11 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
connecting_to=Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y);
connecting_target=false;
- top_layer->update();
+ top_layer->update();
Ref<Texture> port =get_icon("port","GraphNode");
Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y);
- float grab_r=port->get_width()*0.5;
+ float grab_r=port->get_width()*0.5*grab_r_extend;
for(int i=get_child_count()-1;i>=0;i--) {
GraphNode *gn=get_child(i)->cast_to<GraphNode>();
@@ -381,7 +533,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
int type =gn->get_connection_output_type(j);
- if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+ if ((type==connecting_type ||valid_connection_types.has(ConnType(type,connecting_type))) && pos.distance_to(mpos)<grab_r) {
connecting_target=true;
connecting_to=pos;
@@ -398,7 +550,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
int type =gn->get_connection_input_type(j);
- if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+ if ((type==connecting_type ||valid_connection_types.has(ConnType(type,connecting_type))) && pos.distance_to(mpos)<grab_r) {
connecting_target=true;
connecting_to=pos;
connecting_target_to=gn->get_name();
@@ -425,18 +577,91 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
}
emit_signal("connection_request",from,from_slot,to,to_slot);
+ } else if (!just_disconected) {
+ String from = connecting_from;
+ int from_slot = connecting_index;
+ Vector2 ofs = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
+ emit_signal("connection_to_empty",from,from_slot,ofs);
}
connecting=false;
top_layer->update();
+ update();
+ connections_layer->update();
}
}
-void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) {
+
+template<class Vector2>
+static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 control_1, Vector2 control_2, Vector2 end) {
+ /* Formula from Wikipedia article on Bezier curves. */
+ real_t omt = (1.0 - t);
+ real_t omt2 = omt*omt;
+ real_t omt3 = omt2*omt;
+ real_t t2 = t*t;
+ real_t t3 = t2*t;
+
+ return start * omt3
+ + control_1 * omt2 * t * 3.0
+ + control_2 * omt * t2 * 3.0
+ + end * t3;
+}
+
+
+void GraphEdit::_bake_segment2d(CanvasItem* p_where,float p_begin, float p_end,const Vector2& p_a,const Vector2& p_out,const Vector2& p_b, const Vector2& p_in,int p_depth,int p_min_depth,int p_max_depth,float p_tol,const Color& p_color,const Color& p_to_color,int &lines) const {
+
+ float mp = p_begin+(p_end-p_begin)*0.5;
+ Vector2 beg = _bezier_interp(p_begin,p_a,p_a+p_out,p_b+p_in,p_b);
+ Vector2 mid = _bezier_interp(mp,p_a,p_a+p_out,p_b+p_in,p_b);
+ Vector2 end = _bezier_interp(p_end,p_a,p_a+p_out,p_b+p_in,p_b);
+
+ Vector2 na = (mid-beg).normalized();
+ Vector2 nb = (end-mid).normalized();
+ float dp = Math::rad2deg(Math::acos(na.dot(nb)));
+
+ if (p_depth>=p_min_depth && ( dp<p_tol || p_depth>=p_max_depth)) {
+
+
+
+ p_where->draw_line(beg,end,p_color.linear_interpolate(p_to_color,mp),2,true);
+ lines++;
+ } else {
+ _bake_segment2d(p_where,p_begin,mp,p_a,p_out,p_b,p_in,p_depth+1,p_min_depth,p_max_depth,p_tol,p_color,p_to_color,lines);
+ _bake_segment2d(p_where,mp,p_end,p_a,p_out,p_b,p_in,p_depth+1,p_min_depth,p_max_depth,p_tol,p_color,p_to_color,lines);
+ }
+}
+
+
+void GraphEdit::_draw_cos_line(CanvasItem* p_where,const Vector2& p_from, const Vector2& p_to,const Color& p_color,const Color& p_to_color) {
+
+
+#if 1
+
+ //cubic bezier code
+ float diff = p_to.x-p_from.x;
+ float cp_offset;
+ int cp_len = get_constant("bezier_len_pos");
+ int cp_neg_len = get_constant("bezier_len_neg");
+
+ if (diff>0) {
+ cp_offset=MAX(cp_len,diff*0.5);
+ } else {
+ cp_offset=MAX(MIN(cp_len-diff,cp_neg_len),-diff*0.5);
+ }
+
+ Vector2 c1 = Vector2(cp_offset,0);
+ Vector2 c2 = Vector2(-cp_offset,0);
+
+ int lines=0;
+ _bake_segment2d(p_where,0,1,p_from,c1,p_to,c2,0,3,9,8,p_color,p_to_color,lines);
+
+
+#else
static const int steps = 20;
+ //old cosine code
Rect2 r;
r.pos=p_from;
r.expand_to(p_to);
@@ -446,6 +671,7 @@ void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const
Vector2 prev;
for(int i=0;i<=steps;i++) {
+
float d = i/float(steps);
float c=-Math::cos(d*Math_PI) * 0.5+0.5;
if (flip)
@@ -454,11 +680,65 @@ void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const
if (i>0) {
- top_layer->draw_line(prev,p,p_color,2);
+ p_where->draw_line(prev,p,p_color.linear_interpolate(p_to_color,d),2);
}
prev=p;
}
+#endif
+}
+
+
+void GraphEdit::_connections_layer_draw() {
+
+
+ {
+ //draw connections
+ List<List<Connection>::Element* > to_erase;
+ for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
+
+ NodePath fromnp(E->get().from);
+
+ Node * from = get_node(fromnp);
+ if (!from) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ GraphNode *gfrom = from->cast_to<GraphNode>();
+
+ if (!gfrom) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ NodePath tonp(E->get().to);
+ Node * to = get_node(tonp);
+ if (!to) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ GraphNode *gto = to->cast_to<GraphNode>();
+
+ if (!gto) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_offset();
+ Color color = gfrom->get_connection_output_color(E->get().from_port);
+ Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_offset();
+ Color tocolor = gto->get_connection_input_color(E->get().to_port);
+ _draw_cos_line(connections_layer,frompos,topos,color,tocolor);
+
+ }
+
+ while(to_erase.size()) {
+ connections.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+ }
}
void GraphEdit::_top_layer_draw() {
@@ -488,54 +768,28 @@ void GraphEdit::_top_layer_draw() {
col.g+=0.4;
col.b+=0.4;
}
- _draw_cos_line(pos,topos,col);
- }
- List<List<Connection>::Element* > to_erase;
- for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
-
- NodePath fromnp(E->get().from);
-
- Node * from = get_node(fromnp);
- if (!from) {
- to_erase.push_back(E);
- continue;
+ if (!connecting_out) {
+ SWAP(pos,topos);
}
+ _draw_cos_line(top_layer,pos,topos,col,col);
+ }
- GraphNode *gfrom = from->cast_to<GraphNode>();
- if (!gfrom) {
- to_erase.push_back(E);
- continue;
- }
+ if (box_selecting)
+ top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3));
+}
- NodePath tonp(E->get().to);
- Node * to = get_node(tonp);
- if (!to) {
- to_erase.push_back(E);
- continue;
- }
+void GraphEdit::set_selected(Node* p_child) {
- GraphNode *gto = to->cast_to<GraphNode>();
+ for(int i=get_child_count()-1;i>=0;i--) {
- if (!gto) {
- to_erase.push_back(E);
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
continue;
- }
-
- Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos();
- Color color = gfrom->get_connection_output_color(E->get().from_port);
- Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos();
- _draw_cos_line(frompos,topos,color);
+ gn->set_selected(gn==p_child);
}
-
- while(to_erase.size()) {
- connections.erase(to_erase.front()->get());
- to_erase.pop_front();
- }
- 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) {
@@ -548,11 +802,21 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
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);
+ // TODO: Remove local mouse pos hack if/when InputEventMouseMotion is fixed to support floats
+ //drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
+ drag_accum = get_local_mouse_pos() - drag_origin;
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()*zoom+drag_accum)/zoom);
+ if (gn && gn->is_selected()) {
+
+ Vector2 pos = (gn->get_drag_from()*zoom+drag_accum)/zoom;
+ if (is_using_snap()) {
+ int snap = get_snap();
+ pos = pos.snapped(Vector2(snap,snap));
+ }
+
+ gn->set_offset(pos);
+ }
}
}
@@ -641,6 +905,8 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
dragging = false;
top_layer->update();
+ update();
+ connections_layer->update();
}
if (b.button_index==BUTTON_LEFT && b.pressed) {
@@ -651,6 +917,10 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
gn=get_child(i)->cast_to<GraphNode>();
if (gn) {
+
+ if (gn->is_resizing())
+ continue;
+
Rect2 r = gn->get_rect();
r.size*=zoom;
if (r.has_point(get_local_mouse_pos()))
@@ -665,6 +935,7 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
dragging = true;
drag_accum = Vector2();
+ drag_origin = get_local_mouse_pos();
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++) {
@@ -761,6 +1032,7 @@ void GraphEdit::clear_connections() {
connections.clear();
update();
+ connections_layer->update();
}
void GraphEdit::set_zoom(float p_zoom) {
@@ -804,6 +1076,29 @@ bool GraphEdit::is_right_disconnects_enabled() const{
return right_disconnects;
}
+void GraphEdit::add_valid_right_disconnect_type(int p_type) {
+
+ valid_right_disconnect_types.insert(p_type);
+}
+
+void GraphEdit::remove_valid_right_disconnect_type(int p_type){
+
+ valid_right_disconnect_types.erase(p_type);
+
+}
+
+void GraphEdit::add_valid_left_disconnect_type(int p_type){
+
+ valid_left_disconnect_types.insert(p_type);
+
+}
+
+void GraphEdit::remove_valid_left_disconnect_type(int p_type){
+
+ valid_left_disconnect_types.erase(p_type);
+
+}
+
Array GraphEdit::_get_connection_list() const {
List<Connection> conns;
@@ -838,6 +1133,68 @@ void GraphEdit::_zoom_plus() {
set_zoom(zoom*ZOOM_SCALE);
}
+void GraphEdit::add_valid_connection_type(int p_type,int p_with_type) {
+
+ ConnType ct;
+ ct.type_a=p_type;
+ ct.type_b=p_with_type;
+
+ valid_connection_types.insert(ct);
+}
+
+void GraphEdit::remove_valid_connection_type(int p_type,int p_with_type) {
+
+ ConnType ct;
+ ct.type_a=p_type;
+ ct.type_b=p_with_type;
+
+ valid_connection_types.erase(ct);
+
+}
+
+bool GraphEdit::is_valid_connection_type(int p_type,int p_with_type) const {
+
+ ConnType ct;
+ ct.type_a=p_type;
+ ct.type_b=p_with_type;
+
+ return valid_connection_types.has(ct);
+
+}
+
+void GraphEdit::set_use_snap(bool p_enable) {
+
+ snap_button->set_pressed(p_enable);
+ update();
+
+}
+
+bool GraphEdit::is_using_snap() const{
+
+ return snap_button->is_pressed();
+
+}
+
+int GraphEdit::get_snap() const{
+
+ return snap_amount->get_val();
+}
+
+void GraphEdit::set_snap(int p_snap) {
+
+ ERR_FAIL_COND(p_snap<5);
+ snap_amount->set_val(p_snap);
+ update();
+}
+void GraphEdit::_snap_toggled() {
+ update();
+}
+
+void GraphEdit::_snap_value_changed(double) {
+
+ update();
+}
+
void GraphEdit::_bind_methods() {
@@ -846,10 +1203,17 @@ void GraphEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node);
ObjectTypeDB::bind_method(_MD("get_connection_list"),&GraphEdit::_get_connection_list);
ObjectTypeDB::bind_method(_MD("get_scroll_ofs"),&GraphEdit::get_scroll_ofs);
+ ObjectTypeDB::bind_method(_MD("set_scroll_ofs","ofs"),&GraphEdit::set_scroll_ofs);
ObjectTypeDB::bind_method(_MD("set_zoom","p_zoom"),&GraphEdit::set_zoom);
ObjectTypeDB::bind_method(_MD("get_zoom"),&GraphEdit::get_zoom);
+ ObjectTypeDB::bind_method(_MD("set_snap","pixels"),&GraphEdit::set_snap);
+ ObjectTypeDB::bind_method(_MD("get_snap"),&GraphEdit::get_snap);
+
+ ObjectTypeDB::bind_method(_MD("set_use_snap","enable"),&GraphEdit::set_use_snap);
+ ObjectTypeDB::bind_method(_MD("is_using_snap"),&GraphEdit::is_using_snap);
+
ObjectTypeDB::bind_method(_MD("set_right_disconnects","enable"),&GraphEdit::set_right_disconnects);
ObjectTypeDB::bind_method(_MD("is_right_disconnects_enabled"),&GraphEdit::is_right_disconnects_enabled);
@@ -862,16 +1226,27 @@ void GraphEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_zoom_minus"),&GraphEdit::_zoom_minus);
ObjectTypeDB::bind_method(_MD("_zoom_reset"),&GraphEdit::_zoom_reset);
ObjectTypeDB::bind_method(_MD("_zoom_plus"),&GraphEdit::_zoom_plus);
+ ObjectTypeDB::bind_method(_MD("_snap_toggled"),&GraphEdit::_snap_toggled);
+ ObjectTypeDB::bind_method(_MD("_snap_value_changed"),&GraphEdit::_snap_value_changed);
ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event);
+ ObjectTypeDB::bind_method(_MD("_update_scroll_offset"),&GraphEdit::_update_scroll_offset);
+ ObjectTypeDB::bind_method(_MD("_connections_layer_draw"),&GraphEdit::_connections_layer_draw);
+
+
+
+ ObjectTypeDB::bind_method(_MD("set_selected","node"),&GraphEdit::set_selected);
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("node_selected",PropertyInfo(Variant::OBJECT,"node")));
+ ADD_SIGNAL(MethodInfo("connection_to_empty",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::VECTOR2,"release_pos")));
ADD_SIGNAL(MethodInfo("delete_nodes_request"));
ADD_SIGNAL(MethodInfo("_begin_node_move"));
ADD_SIGNAL(MethodInfo("_end_node_move"));
+ ADD_SIGNAL(MethodInfo("scroll_offset_changed",PropertyInfo(Variant::VECTOR2,"ofs")));
}
@@ -879,6 +1254,7 @@ void GraphEdit::_bind_methods() {
GraphEdit::GraphEdit() {
set_focus_mode(FOCUS_ALL);
+ awaiting_scroll_offset_update=false;
top_layer=NULL;
top_layer=memnew(GraphEditFilter(this));
add_child(top_layer);
@@ -888,6 +1264,12 @@ GraphEdit::GraphEdit() {
top_layer->set_stop_mouse(false);
top_layer->connect("input_event",this,"_top_layer_input");
+ connections_layer = memnew( Control );
+ add_child(connections_layer);
+ connections_layer->connect("draw",this,"_connections_layer_draw");
+ connections_layer->set_name("CLAYER");
+ connections_layer->set_disable_visibility_clip(true); // so it can draw freely and be offseted
+
h_scroll = memnew(HScrollBar);
h_scroll->set_name("_h_scroll");
top_layer->add_child(h_scroll);
@@ -902,6 +1284,13 @@ GraphEdit::GraphEdit() {
box_selecting = false;
dragging = false;
+ //set large minmax so it can scroll even if not resized yet
+ h_scroll->set_min(-10000);
+ h_scroll->set_max(10000);
+
+ v_scroll->set_min(-10000);
+ v_scroll->set_max(10000);
+
h_scroll->connect("value_changed", this,"_scroll_moved");
v_scroll->connect("value_changed", this,"_scroll_moved");
@@ -915,17 +1304,36 @@ GraphEdit::GraphEdit() {
zoom_minus = memnew( ToolButton );
zoom_hb->add_child(zoom_minus);
zoom_minus->connect("pressed",this,"_zoom_minus");
- zoom_minus->set_icon(get_icon("minus"));
+ zoom_minus->set_focus_mode(FOCUS_NONE);
zoom_reset = memnew( ToolButton );
zoom_hb->add_child(zoom_reset);
zoom_reset->connect("pressed",this,"_zoom_reset");
- zoom_reset->set_icon(get_icon("reset"));
+ zoom_reset->set_focus_mode(FOCUS_NONE);
zoom_plus = memnew( ToolButton );
zoom_hb->add_child(zoom_plus);
zoom_plus->connect("pressed",this,"_zoom_plus");
- zoom_plus->set_icon(get_icon("more"));
+ zoom_plus->set_focus_mode(FOCUS_NONE);
+
+ snap_button = memnew( ToolButton );
+ snap_button->set_toggle_mode(true);
+ snap_button->connect("pressed",this,"_snap_toggled");
+ snap_button->set_pressed(true);
+ snap_button->set_focus_mode(FOCUS_NONE);
+ zoom_hb->add_child(snap_button);
+
+ snap_amount = memnew( SpinBox );
+ snap_amount->set_min(5);
+ snap_amount->set_max(100);
+ snap_amount->set_step(1);
+ snap_amount->set_val(20);
+ snap_amount->connect("value_changed",this,"_snap_value_changed");
+ zoom_hb->add_child(snap_amount);
+
+ setting_scroll_ofs=false;
+ just_disconected=false;
+
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index ac4e71ba49..c5174f6699 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -33,6 +33,7 @@
#include "scene/gui/scroll_bar.h"
#include "scene/gui/slider.h"
#include "scene/gui/tool_button.h"
+#include "scene/gui/spin_box.h"
#include "texture_frame.h"
class GraphEdit;
@@ -70,6 +71,9 @@ private:
ToolButton *zoom_reset;
ToolButton *zoom_plus;
+ ToolButton *snap_button;
+ SpinBox *snap_amount;
+
void _zoom_minus();
void _zoom_reset();
void _zoom_plus();
@@ -88,10 +92,12 @@ private:
Vector2 connecting_to;
String connecting_target_to;
int connecting_target_index;
+ bool just_disconected;
bool dragging;
bool just_selected;
Vector2 drag_accum;
+ Point2 drag_origin; // Workaround for GH-5907
float zoom;
@@ -102,11 +108,15 @@ private:
Rect2 box_selecting_rect;
List<GraphNode*> previus_selected;
+ bool setting_scroll_ofs;
bool right_disconnects;
bool updating;
+ bool awaiting_scroll_offset_update;
List<Connection> connections;
- void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color);
+ void _bake_segment2d(CanvasItem* p_where,float p_begin, float p_end, const Vector2& p_a, const Vector2& p_out, const Vector2& p_b, const Vector2& p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color& p_color, const Color& p_to_color, int &lines) const;
+
+ void _draw_cos_line(CanvasItem* p_where,const Vector2& p_from, const Vector2& p_to, const Color& p_color, const Color &p_to_color);
void _graph_node_raised(Node* p_gn);
void _graph_node_moved(Node *p_gn);
@@ -115,15 +125,47 @@ private:
void _scroll_moved(double);
void _input_event(const InputEvent& p_ev);
+ Control *connections_layer;
GraphEditFilter *top_layer;
void _top_layer_input(const InputEvent& p_ev);
void _top_layer_draw();
+ void _connections_layer_draw();
void _update_scroll_offset();
Array _get_connection_list() const;
+ bool lines_on_bg;
+
+
+
+ struct ConnType {
+
+ union {
+ struct {
+ uint32_t type_a;
+ uint32_t type_b;
+ };
+ uint64_t key;
+ };
+
+ bool operator<(const ConnType& p_type) const {
+ return key<p_type.key;
+ }
+
+ ConnType(uint32_t a=0, uint32_t b=0) {
+ type_a=a;
+ type_b=b;
+ }
+ };
+
+ Set<ConnType> valid_connection_types;
+ Set<int> valid_left_disconnect_types;
+ Set<int> valid_right_disconnect_types;
+
friend class GraphEditFilter;
bool _filter_input(const Point2& p_point);
+ void _snap_toggled();
+ void _snap_value_changed(double);
protected:
static void _bind_methods();
@@ -138,6 +180,10 @@ public:
void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
void clear_connections();
+ void add_valid_connection_type(int p_type,int p_with_type);
+ void remove_valid_connection_type(int p_type,int p_with_type);
+ bool is_valid_connection_type(int p_type,int p_with_type) const;
+
void set_zoom(float p_zoom);
float get_zoom() const;
@@ -147,8 +193,23 @@ public:
void set_right_disconnects(bool p_enable);
bool is_right_disconnects_enabled() const;
+ void add_valid_right_disconnect_type(int p_type);
+ void remove_valid_right_disconnect_type(int p_type);
+
+ void add_valid_left_disconnect_type(int p_type);
+ void remove_valid_left_disconnect_type(int p_type);
+
+ void set_scroll_ofs(const Vector2& p_ofs);
Vector2 get_scroll_ofs() const;
+ void set_selected(Node* p_child);
+
+ void set_use_snap(bool p_enable);
+ bool is_using_snap() const;
+
+ int get_snap() const;
+ void set_snap(int p_snap);
+
GraphEdit();
};
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 94001b2ac1..da298a795a 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -183,14 +183,45 @@ void GraphNode::_resort() {
}
+bool GraphNode::has_point(const Point2& p_point) const {
+
+ if (comment) {
+ Ref<StyleBox> comment = get_stylebox("comment");
+ Ref<Texture> resizer =get_icon("resizer");
+
+ if (Rect2(get_size()-resizer->get_size(), resizer->get_size()).has_point(p_point)) {
+ return true;
+ }
+ if (Rect2(0,0,get_size().width,comment->get_margin(MARGIN_TOP)).has_point(p_point)) {
+ return true;
+ }
+
+ return false;
+
+ } else {
+ return Control::has_point(p_point);
+ }
+}
void GraphNode::_notification(int p_what) {
if (p_what==NOTIFICATION_DRAW) {
- Ref<StyleBox> sb=get_stylebox(selected ? "selectedframe" : "frame");
+ Ref<StyleBox> sb;
+
+ if (comment) {
+ sb = get_stylebox( selected? "commentfocus" : "comment");
+
+ } else {
+
+ sb = get_stylebox( selected ? "selectedframe" : "frame");
+ }
+
+ sb=sb->duplicate();
+ sb->call("set_modulate",modulate);
Ref<Texture> port =get_icon("port");
Ref<Texture> close =get_icon("close");
+ Ref<Texture> resizer =get_icon("resizer");
int close_offset = get_constant("close_offset");
Ref<Font> title_font = get_font("title_font");
int title_offset = get_constant("title_offset");
@@ -198,8 +229,25 @@ void GraphNode::_notification(int p_what) {
Point2i icofs = -port->get_size()*0.5;
int edgeofs=get_constant("port_offset");
icofs.y+=sb->get_margin(MARGIN_TOP);
+
+
+
draw_style_box(sb,Rect2(Point2(),get_size()));
+ switch(overlay) {
+ case OVERLAY_DISABLED: {
+
+ } break;
+ case OVERLAY_BREAKPOINT: {
+
+ draw_style_box(get_stylebox("breakpoint"),Rect2(Point2(),get_size()));
+ } break;
+ case OVERLAY_POSITION: {
+ draw_style_box(get_stylebox("position"),Rect2(Point2(),get_size()));
+
+ } break;
+ }
+
int w = get_size().width-sb->get_minimum_size().x;
if (show_close)
@@ -223,11 +271,26 @@ void GraphNode::_notification(int p_what) {
continue;
const Slot &s=slot_info[E->key()];
//left
- if (s.enable_left)
- port->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left);
- if (s.enable_right)
- port->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right);
+ if (s.enable_left) {
+ Ref<Texture> p = port;
+ if (s.custom_slot_left.is_valid()) {
+ p=s.custom_slot_left;
+ }
+ p->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left);
+ }
+ if (s.enable_right) {
+ Ref<Texture> p = port;
+ if (s.custom_slot_right.is_valid()) {
+ p=s.custom_slot_right;
+ }
+ p->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right);
+ }
+
+ }
+
+ if (resizeable) {
+ draw_texture(resizer,get_size()-resizer->get_size());
}
}
@@ -239,7 +302,7 @@ void GraphNode::_notification(int p_what) {
}
-void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) {
+void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right,const Ref<Texture>& p_custom_left,const Ref<Texture>& p_custom_right) {
ERR_FAIL_COND(p_idx<0);
@@ -255,6 +318,8 @@ void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Colo
s.enable_right=p_enable_right;
s.type_right=p_type_right;
s.color_right=p_color_right;
+ s.custom_slot_left=p_custom_left;
+ s.custom_slot_right=p_custom_right;
slot_info[p_idx]=s;
update();
connpos_dirty=true;
@@ -559,18 +624,99 @@ Color GraphNode::get_connection_output_color(int p_idx) {
void GraphNode::_input_event(const InputEvent& p_ev) {
if (p_ev.type==InputEvent::MOUSE_BUTTON) {
- get_parent_control()->grab_focus();
+
+ ERR_EXPLAIN("GraphNode must be the child of a GraphEdit node.");
+ ERR_FAIL_COND(get_parent_control() == NULL);
+
+ print_line("INPUT EVENT BUTTON");
+
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");
+ accept_event();
return;
}
+
+ Ref<Texture> resizer =get_icon("resizer");
+
+ if (resizeable && mpos.x > get_size().x-resizer->get_width() && mpos.y > get_size().y-resizer->get_height()) {
+
+ resizing=true;
+ resizing_from=mpos;
+ resizing_from_size=get_size();
+ accept_event();
+ return;
+ }
+
+ //send focus to parent
emit_signal("raise_request");
+ get_parent_control()->grab_focus();
+
}
+
+ if(!p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+ resizing=false;
+ }
+
}
+
+ if (resizing && p_ev.type==InputEvent::MOUSE_MOTION) {
+ Vector2 mpos = Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y);
+
+ Vector2 diff = mpos - resizing_from;
+
+ emit_signal("resize_request",resizing_from_size+diff);
+
+ }
+
+
+}
+
+void GraphNode::set_modulate(const Color &p_color) {
+
+ modulate=p_color;
+ update();
+}
+
+Color GraphNode::get_modulate() const{
+
+ return modulate;
+}
+void GraphNode::set_overlay(Overlay p_overlay) {
+
+ overlay=p_overlay;
+ update();
+}
+
+GraphNode::Overlay GraphNode::get_overlay() const{
+
+ return overlay;
+}
+
+void GraphNode::set_comment(bool p_enable) {
+
+ comment=p_enable;
+ update();
+}
+
+bool GraphNode::is_comment() const{
+
+ return comment;
+}
+
+
+void GraphNode::set_resizeable(bool p_enable) {
+
+ resizeable=p_enable;
+ update();
+}
+
+bool GraphNode::is_resizeable() const{
+
+ return resizeable;
}
@@ -580,7 +726,7 @@ void GraphNode::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title);
ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event);
- ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right"),&GraphNode::set_slot);
+ ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right","custom_left","custom_right"),&GraphNode::set_slot,DEFVAL(Ref<Texture>()),DEFVAL(Ref<Texture>()));
ObjectTypeDB::bind_method(_MD("clear_slot","idx"),&GraphNode::clear_slot);
ObjectTypeDB::bind_method(_MD("clear_all_slots","idx"),&GraphNode::clear_all_slots);
ObjectTypeDB::bind_method(_MD("is_slot_enabled_left","idx"),&GraphNode::is_slot_enabled_left);
@@ -593,6 +739,12 @@ void GraphNode::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&GraphNode::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&GraphNode::get_offset);
+ ObjectTypeDB::bind_method(_MD("set_comment","comment"),&GraphNode::set_comment);
+ ObjectTypeDB::bind_method(_MD("is_comment"),&GraphNode::is_comment);
+
+ ObjectTypeDB::bind_method(_MD("set_resizeable","resizeable"),&GraphNode::set_resizeable);
+ ObjectTypeDB::bind_method(_MD("is_resizeable"),&GraphNode::is_resizeable);
+
ObjectTypeDB::bind_method(_MD("get_connection_output_count"),&GraphNode::get_connection_output_count);
ObjectTypeDB::bind_method(_MD("get_connection_input_count"),&GraphNode::get_connection_input_count);
@@ -603,10 +755,15 @@ void GraphNode::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_connection_input_type","idx"),&GraphNode::get_connection_input_type);
ObjectTypeDB::bind_method(_MD("get_connection_input_color","idx"),&GraphNode::get_connection_input_color);
+ ObjectTypeDB::bind_method(_MD("set_modulate","color"),&GraphNode::set_modulate);
+ ObjectTypeDB::bind_method(_MD("get_modulate"),&GraphNode::get_modulate);
ObjectTypeDB::bind_method(_MD("set_show_close_button","show"),&GraphNode::set_show_close_button);
ObjectTypeDB::bind_method(_MD("is_close_button_visible"),&GraphNode::is_close_button_visible);
+ ObjectTypeDB::bind_method(_MD("set_overlay","overlay"),&GraphNode::set_overlay);
+ ObjectTypeDB::bind_method(_MD("get_overlay"),&GraphNode::get_overlay);
+
ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"show_close"),_SCS("set_show_close_button"),_SCS("is_close_button_visible"));
@@ -614,10 +771,21 @@ void GraphNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to")));
ADD_SIGNAL(MethodInfo("raise_request"));
ADD_SIGNAL(MethodInfo("close_request"));
+ ADD_SIGNAL(MethodInfo("resize_request",PropertyInfo(Variant::VECTOR2,"new_minsize")));
+
+ BIND_CONSTANT( OVERLAY_DISABLED );
+ BIND_CONSTANT( OVERLAY_BREAKPOINT );
+ BIND_CONSTANT( OVERLAY_POSITION );
}
GraphNode::GraphNode() {
+
+ overlay=OVERLAY_DISABLED;
show_close=false;
connpos_dirty=true;
set_stop_mouse(false);
+ modulate=Color(1,1,1,1);
+ comment=false;
+ resizeable=false;
+ resizing=false;
}
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 5a50d0d68d..cbfd34f556 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -34,8 +34,14 @@
class GraphNode : public Container {
OBJ_TYPE(GraphNode,Container);
+public:
-
+ enum Overlay {
+ OVERLAY_DISABLED,
+ OVERLAY_BREAKPOINT,
+ OVERLAY_POSITION
+ };
+private:
struct Slot {
bool enable_left;
@@ -44,6 +50,8 @@ class GraphNode : public Container {
bool enable_right;
int type_right;
Color color_right;
+ Ref<Texture> custom_slot_left;
+ Ref<Texture> custom_slot_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); }
@@ -52,6 +60,12 @@ class GraphNode : public Container {
String title;
bool show_close;
Vector2 offset;
+ bool comment;
+ bool resizeable;
+
+ bool resizing;
+ Vector2 resizing_from;
+ Vector2 resizing_from_size;
Rect2 close_rect;
@@ -75,6 +89,13 @@ class GraphNode : public Container {
Vector2 drag_from;
bool selected;
+
+ Overlay overlay;
+
+ Color modulate;
+
+ bool has_point(const Point2& p_point) const;
+
protected:
@@ -91,7 +112,7 @@ public:
- void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right);
+ void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right,const Ref<Texture>& p_custom_left=Ref<Texture>(),const Ref<Texture>& p_custom_right=Ref<Texture>());
void clear_slot(int p_idx);
void clear_all_slots();
bool is_slot_enabled_left(int p_idx) const;
@@ -126,10 +147,25 @@ public:
Color get_connection_output_color(int p_idx);
+ void set_modulate(const Color& p_color);
+ Color get_modulate() const;
+
+ void set_overlay(Overlay p_overlay);
+ Overlay get_overlay() const;
+
+ void set_comment(bool p_enable);
+ bool is_comment() const;
+
+ void set_resizeable(bool p_enable);
+ bool is_resizeable() const;
+
virtual Size2 get_minimum_size() const;
+ bool is_resizing() const { return resizing; }
+
GraphNode();
};
+VARIANT_ENUM_CAST( GraphNode::Overlay )
#endif // GRAPH_NODE_H
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index d63c483ef9..89cd509fbd 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -40,6 +40,7 @@ void ItemList::add_item(const String& p_item,const Ref<Texture>& p_texture,bool
item.selectable=p_selectable;
item.selected=false;
item.disabled=false;
+ item.tooltip_enabled=true;
item.custom_bg=Color(0,0,0,0);
items.push_back(item);
@@ -57,6 +58,7 @@ void ItemList::add_icon_item(const Ref<Texture>& p_item,bool p_selectable){
item.selectable=p_selectable;
item.selected=false;
item.disabled=false;
+ item.tooltip_enabled=true;
item.custom_bg=Color(0,0,0,0);
items.push_back(item);
@@ -82,6 +84,16 @@ String ItemList::get_item_text(int p_idx) const{
}
+void ItemList::set_item_tooltip_enabled(int p_idx, const bool p_enabled) {
+ ERR_FAIL_INDEX(p_idx,items.size());
+ items[p_idx].tooltip_enabled = p_enabled;
+}
+
+bool ItemList::is_item_tooltip_enabled(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx,items.size(), false);
+ return items[p_idx].tooltip_enabled;
+}
+
void ItemList::set_item_tooltip(int p_idx,const String& p_tooltip){
ERR_FAIL_INDEX(p_idx,items.size());
@@ -191,7 +203,7 @@ void ItemList::set_item_disabled(int p_idx,bool p_disabled){
ERR_FAIL_INDEX(p_idx,items.size());
items[p_idx].disabled=p_disabled;
-
+ update();
}
@@ -225,7 +237,7 @@ void ItemList::select(int p_idx,bool p_single){
if (p_single || select_mode==SELECT_SINGLE) {
- if (!items[p_idx].selectable) {
+ if (!items[p_idx].selectable || items[p_idx].disabled) {
return;
}
@@ -237,7 +249,7 @@ void ItemList::select(int p_idx,bool p_single){
ensure_selected_visible=false;
} else {
- if (items[p_idx].selectable) {
+ if (items[p_idx].selectable && !items[p_idx].disabled) {
items[p_idx].selected=true;
}
}
@@ -336,6 +348,7 @@ void ItemList::clear(){
current=-1;
ensure_selected_visible=false;
update();
+ shape_changed=true;
defer_select_single=-1;
}
@@ -461,7 +474,6 @@ void ItemList::_input_event(const InputEvent& p_event) {
pos.y+=scroll_bar->get_val();
int closest = -1;
- int closest_dist=0x7FFFFFFF;
for(int i=0;i<items.size();i++) {
@@ -474,12 +486,6 @@ void ItemList::_input_event(const InputEvent& p_event) {
closest=i;
break;
}
-
- float dist = rc.distance_to(pos);
- if (dist<closest_dist) {
- closest=i;
- closest_dist=dist;
- }
}
if (closest!=-1) {
@@ -510,7 +516,7 @@ void ItemList::_input_event(const InputEvent& p_event) {
}
} else {
- if (!mb.doubleclick && !mb.mod.command && select_mode==SELECT_MULTI && items[i].selectable && items[i].selected && p_event.mouse_button.button_index==BUTTON_LEFT) {
+ if (!mb.doubleclick && !mb.mod.command && select_mode==SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && p_event.mouse_button.button_index==BUTTON_LEFT) {
defer_select_single=i;
return;
}
@@ -546,6 +552,11 @@ void ItemList::_input_event(const InputEvent& p_event) {
return;
+ } else {
+ Vector<int> sItems = get_selected_items();
+ for(int i = 0; i < sItems.size(); i++) {
+ unselect(sItems[i]);
+ }
}
}
if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_WHEEL_UP && p_event.mouse_button.pressed) {
@@ -694,7 +705,7 @@ void ItemList::_input_event(const InputEvent& p_event) {
if (select_mode==SELECT_MULTI && current>=0 && current<items.size()) {
- if (items[current].selectable && !items[current].selected) {
+ if (items[current].selectable && !items[current].disabled && !items[current].selected) {
select(current,false);
emit_signal("multi_selected",current,true);
} else if (items[current].selected) {
@@ -823,7 +834,7 @@ void ItemList::_notification(int p_what) {
}
if (shape_changed) {
-
+
float max_column_width = 0;
//1- compute item minimum sizes
@@ -914,11 +925,11 @@ void ItemList::_notification(int p_what) {
if (i<items.size()-1)
separators.push_back(ofs.y+max_h+vseparation/2);
-
+
for(int j=i;j>=0 && col>0;j--, col--) {
items[j].rect_cache.size.y = max_h;
}
-
+
ofs.x=0;
ofs.y+=max_h+vseparation;
col=0;
@@ -1029,10 +1040,14 @@ void ItemList::_notification(int p_what) {
draw_rect.size=adj.size;
}
+ Color modulate=Color(1,1,1,1);
+ if (items[i].disabled)
+ modulate.a*=0.5;
+
if (items[i].icon_region.has_no_area())
- draw_texture_rect(items[i].icon, draw_rect );
+ draw_texture_rect(items[i].icon, draw_rect,false,modulate );
else
- draw_texture_rect_region(items[i].icon, draw_rect, items[i].icon_region);
+ draw_texture_rect_region(items[i].icon, draw_rect, items[i].icon_region,modulate);
}
@@ -1053,6 +1068,10 @@ void ItemList::_notification(int p_what) {
else
max_len=size.x;
+ Color modulate=items[i].selected?font_color_selected:font_color;
+ if (items[i].disabled)
+ modulate.a*=0.5;
+
if (icon_mode==ICON_MODE_TOP && max_text_lines>0) {
int ss = items[i].text.length();
@@ -1090,7 +1109,7 @@ void ItemList::_notification(int p_what) {
if (line>=max_text_lines)
break;
}
- ofs+=font->draw_char(get_canvas_item(),text_ofs+Vector2(ofs+(max_len-line_size_cache[line])/2,line*(font_height+line_separation)).floor(),items[i].text[j],items[i].text[j+1],items[i].selected?font_color_selected:font_color);
+ ofs+=font->draw_char(get_canvas_item(),text_ofs+Vector2(ofs+(max_len-line_size_cache[line])/2,line*(font_height+line_separation)).floor(),items[i].text[j],items[i].text[j+1],modulate);
}
//special multiline mode
@@ -1110,7 +1129,7 @@ void ItemList::_notification(int p_what) {
text_ofs+=base_ofs;
text_ofs+=items[i].rect_cache.pos;
- draw_string(font,text_ofs,items[i].text,items[i].selected?font_color_selected:font_color,max_len+1);
+ draw_string(font,text_ofs,items[i].text,modulate,max_len+1);
}
@@ -1191,6 +1210,9 @@ String ItemList::get_tooltip(const Point2& p_pos) const {
int closest = get_item_at_pos(p_pos);
if (closest!=-1) {
+ if (!items[closest].tooltip_enabled) {
+ return "";
+ }
if (items[closest].tooltip!="") {
return items[closest].tooltip;
}
@@ -1203,8 +1225,11 @@ String ItemList::get_tooltip(const Point2& p_pos) const {
}
void ItemList::sort_items_by_text() {
+
items.sort();
update();
+ shape_changed=true;
+
if (select_mode==SELECT_SINGLE) {
for(int i=0;i<items.size();i++) {
if (items[i].selected) {
@@ -1284,6 +1309,9 @@ void ItemList::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_item_custom_bg_color","idx","custom_bg_color"),&ItemList::set_item_custom_bg_color);
ObjectTypeDB::bind_method(_MD("get_item_custom_bg_color","idx"),&ItemList::get_item_custom_bg_color);
+ ObjectTypeDB::bind_method(_MD("set_item_tooltip_enabled","idx","enable"),&ItemList::set_item_tooltip_enabled);
+ ObjectTypeDB::bind_method(_MD("is_item_tooltip_enabled","idx"),&ItemList::is_item_tooltip_enabled);
+
ObjectTypeDB::bind_method(_MD("set_item_tooltip","idx","tooltip"),&ItemList::set_item_tooltip);
ObjectTypeDB::bind_method(_MD("get_item_tooltip","idx"),&ItemList::get_item_tooltip);
@@ -1296,7 +1324,7 @@ void ItemList::_bind_methods(){
ObjectTypeDB::bind_method(_MD("remove_item","idx"),&ItemList::remove_item);
ObjectTypeDB::bind_method(_MD("clear"),&ItemList::clear);
- ObjectTypeDB::bind_method(_MD("sort_items_by_text"),&ItemList::clear);
+ ObjectTypeDB::bind_method(_MD("sort_items_by_text"),&ItemList::sort_items_by_text);
ObjectTypeDB::bind_method(_MD("set_fixed_column_width","width"),&ItemList::set_fixed_column_width);
ObjectTypeDB::bind_method(_MD("get_fixed_column_width"),&ItemList::get_fixed_column_width);
@@ -1330,6 +1358,8 @@ void ItemList::_bind_methods(){
ObjectTypeDB::bind_method(_MD("ensure_current_is_visible"),&ItemList::ensure_current_is_visible);
+ ObjectTypeDB::bind_method(_MD("get_v_scroll"),&ItemList::get_v_scroll);
+
ObjectTypeDB::bind_method(_MD("_scroll_changed"),&ItemList::_scroll_changed);
ObjectTypeDB::bind_method(_MD("_input_event"),&ItemList::_input_event);
@@ -1375,4 +1405,3 @@ ItemList::ItemList() {
ItemList::~ItemList() {
}
-
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index e1902d1c1f..cb5908bc79 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -56,6 +56,7 @@ private:
bool selectable;
bool selected;
bool disabled;
+ bool tooltip_enabled;
Variant metadata;
String tooltip;
Color custom_bg;
@@ -135,6 +136,9 @@ public:
void set_item_tag_icon(int p_idx,const Ref<Texture>& p_tag_icon);
Ref<Texture> get_item_tag_icon(int p_idx) const;
+ void set_item_tooltip_enabled(int p_idx, const bool p_enabled);
+ bool is_item_tooltip_enabled(int p_idx) const;
+
void set_item_tooltip(int p_idx,const String& p_tooltip);
String get_item_tooltip(int p_idx) const;
@@ -191,6 +195,8 @@ public:
void set_icon_scale(real_t p_scale);
real_t get_icon_scale() const;
+ VScrollBar *get_v_scroll() { return scroll_bar; }
+
ItemList();
~ItemList();
};
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 0431d824fa..ec89b7b690 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -334,7 +334,7 @@ int Label::get_longest_line_width() const {
}
} else {
- int char_width=font->get_char_size(current).width;
+ int char_width=font->get_char_size(current,text[i+1]).width;
line_width+=char_width;
}
@@ -356,6 +356,21 @@ int Label::get_line_count() const {
return line_count;
}
+int Label::get_visible_line_count() const {
+
+ int line_spacing = get_constant("line_spacing");
+ int font_h = get_font("font")->get_height()+line_spacing;
+ int lines_visible = (get_size().y+line_spacing)/font_h;
+
+ if (lines_visible > line_count)
+ lines_visible = line_count;
+
+ if (max_lines_visible >= 0 && lines_visible > max_lines_visible)
+ lines_visible = max_lines_visible;
+
+ return lines_visible;
+}
+
void Label::regenerate_word_cache() {
while (word_cache) {
@@ -439,7 +454,7 @@ void Label::regenerate_word_cache() {
word_pos=i;
}
- char_width=font->get_char_size(current).width;
+ char_width=font->get_char_size(current,text[i+1]).width;
current_word_size+=char_width;
line_width+=char_width;
total_char_cache++;
@@ -640,6 +655,7 @@ void Label::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_uppercase"),&Label::is_uppercase);
ObjectTypeDB::bind_method(_MD("get_line_height"),&Label::get_line_height);
ObjectTypeDB::bind_method(_MD("get_line_count"),&Label::get_line_count);
+ ObjectTypeDB::bind_method(_MD("get_visible_line_count"),&Label::get_visible_line_count);
ObjectTypeDB::bind_method(_MD("get_total_character_count"),&Label::get_total_character_count);
ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&Label::set_visible_characters);
ObjectTypeDB::bind_method(_MD("get_visible_characters"),&Label::get_visible_characters);
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 3c14add60d..b472eca1a2 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -132,6 +132,7 @@ public:
int get_line_height() const;
int get_line_count() const;
+ int get_visible_line_count() const;
Label(const String& p_text=String());
~Label();
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 6c47072b33..90a8af9238 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -118,7 +118,7 @@ void LineEdit::_input_event(InputEvent p_event) {
const InputEventMouseMotion& m=p_event.mouse_motion;
- if (m.button_mask&1) {
+ if (m.button_mask&BUTTON_LEFT) {
if (selection.creating) {
set_cursor_at_pixel_pos(m.x);
@@ -193,8 +193,8 @@ void LineEdit::_input_event(InputEvent p_event) {
}
set_cursor_pos(0);
- emit_signal("text_changed",text);
- _change_notify("text");
+ _text_changed();
+
}
@@ -215,8 +215,7 @@ void LineEdit::_input_event(InputEvent p_event) {
selection_clear();
undo_text = text;
text = text.substr(0,cursor_pos);
- emit_signal("text_changed",text);
- _change_notify("text");
+ _text_changed();
}
} break;
@@ -468,16 +467,14 @@ void LineEdit::_input_event(InputEvent p_event) {
if (handled) {
accept_event();
- } else {
+ } else if (!k.mod.alt && !k.mod.command) {
if (k.unicode>=32 && k.scancode!=KEY_DELETE) {
if (editable) {
selection_delete();
CharType ucodestr[2]={(CharType)k.unicode,0};
append_at_cursor(ucodestr);
- emit_signal("text_changed",text);
- _change_notify("text");
-
+ _text_changed();
accept_event();
}
@@ -616,11 +613,11 @@ void LineEdit::_notification(int p_what) {
} break;
case ALIGN_CENTER: {
- x_ofs=x_ofs=int(size.width-(cached_width))/2;
+ x_ofs=int(size.width-(cached_width))/2;
} break;
case ALIGN_RIGHT: {
- x_ofs=x_ofs=int(size.width-style->get_offset().x-(cached_width));
+ x_ofs=int(size.width-style->get_offset().x-(cached_width));
} break;
}
@@ -725,8 +722,7 @@ void LineEdit::paste_text() {
if(selection.enabled) selection_delete();
append_at_cursor(paste_buffer);
- emit_signal("text_changed",text);
- _change_notify("text");
+ _text_changed();
}
@@ -750,9 +746,7 @@ void LineEdit::undo() {
set_cursor_pos(old_cursor_pos);
}
- emit_signal("text_changed",text);
- _change_notify("text");
-
+ _text_changed();
}
void LineEdit::shift_selection_check_pre(bool p_shift) {
@@ -806,13 +800,6 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
pixel_ofs+=char_w;
if (pixel_ofs > p_x) { //found what we look for
-
-
- if ( (pixel_ofs-p_x) < (char_w >> 1 ) ) {
-
- ofs+=1;
- }
-
break;
}
@@ -888,8 +875,7 @@ void LineEdit::delete_char() {
// set_window_pos(cursor_pos-get_window_length());
}
- emit_signal("text_changed",text);
- _change_notify("text");
+ _text_changed();
}
void LineEdit::delete_text(int p_from_column, int p_to_column) {
@@ -921,8 +907,7 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
window_pos=cursor_pos;
}
- emit_signal("text_changed",text);
- _change_notify("text");
+ _text_changed();
}
void LineEdit::set_text(String p_text) {
@@ -937,8 +922,7 @@ void LineEdit::set_text(String p_text) {
void LineEdit::clear() {
clear_internal();
- emit_signal("text_changed",text);
- _change_notify("text");
+ _text_changed();
}
String LineEdit::get_text() const {
@@ -1077,7 +1061,17 @@ Size2 LineEdit::get_minimum_size() const {
Size2 min=style->get_minimum_size();
min.height+=font->get_height();
- min.width+=get_constant("minimum_spaces")*font->get_char_size(' ').x;
+
+ //minimum size of text
+ int space_size = font->get_char_size(' ').x;
+ int mstext = get_constant("minimum_spaces")*space_size;
+
+ if (expand_to_text_length) {
+ mstext=MAX(mstext,font->get_string_size(text).x+space_size); //add a spce because some fonts are too exact
+ }
+
+ min.width+=mstext;
+
return min;
}
@@ -1233,6 +1227,29 @@ PopupMenu *LineEdit::get_menu() const {
}
#endif
+
+void LineEdit::set_expand_to_text_length(bool p_enabled) {
+
+ expand_to_text_length = p_enabled;
+ minimum_size_changed();
+}
+
+bool LineEdit::get_expand_to_text_length() const{
+
+ return expand_to_text_length;
+}
+
+
+void LineEdit::_text_changed() {
+
+ if (expand_to_text_length)
+ minimum_size_changed();
+
+ emit_signal("text_changed",text);
+ _change_notify("text");
+
+}
+
void LineEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_toggle_draw_caret"),&LineEdit::_toggle_draw_caret);
@@ -1255,7 +1272,9 @@ void LineEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_placeholder_alpha"),&LineEdit::get_placeholder_alpha);
ObjectTypeDB::bind_method(_MD("set_cursor_pos","pos"),&LineEdit::set_cursor_pos);
ObjectTypeDB::bind_method(_MD("get_cursor_pos"),&LineEdit::get_cursor_pos);
- ObjectTypeDB::bind_method(_MD("cursor_set_blink_enabled", "enable"),&LineEdit::cursor_set_blink_enabled);
+ ObjectTypeDB::bind_method(_MD("set_expand_to_text_length","enabled"),&LineEdit::set_expand_to_text_length);
+ ObjectTypeDB::bind_method(_MD("get_expand_to_text_length"),&LineEdit::get_expand_to_text_length);
+ ObjectTypeDB::bind_method(_MD("cursor_set_blink_enabled", "enabled"),&LineEdit::cursor_set_blink_enabled);
ObjectTypeDB::bind_method(_MD("cursor_get_blink_enabled"),&LineEdit::cursor_get_blink_enabled);
ObjectTypeDB::bind_method(_MD("cursor_set_blink_speed", "blink_speed"),&LineEdit::cursor_set_blink_speed);
ObjectTypeDB::bind_method(_MD("cursor_get_blink_speed"),&LineEdit::cursor_get_blink_speed);
@@ -1293,6 +1312,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") );
ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") );
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") );
+ ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "expand_to_len" ), _SCS("set_expand_to_text_length"),_SCS("get_expand_to_text_length") );
ADD_PROPERTY( PropertyInfo( Variant::INT,"focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_focus_mode"), _SCS("get_focus_mode") );
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret/caret_blink"), _SCS("cursor_set_blink_enabled"), _SCS("cursor_get_blink_enabled"));;
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret/caret_blink_speed",PROPERTY_HINT_RANGE,"0.1,10,0.1"), _SCS("cursor_set_blink_speed"),_SCS("cursor_get_blink_speed") );
@@ -1334,7 +1354,7 @@ LineEdit::LineEdit() {
menu->add_separator();
menu->add_item(TTR("Undo"),MENU_UNDO,KEY_MASK_CMD|KEY_Z);
menu->connect("item_pressed",this,"menu_option");
-
+ expand_to_text_length=false;
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 112e4ad55e..47d5706bbe 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -90,6 +90,11 @@ private:
} selection;
Timer *caret_blink_timer;
+
+
+ void _text_changed();
+ bool expand_to_text_length;
+
bool caret_blink_enabled;
bool draw_caret;
bool window_has_focus;
@@ -169,6 +174,9 @@ public:
virtual Size2 get_minimum_size() const;
+ void set_expand_to_text_length(bool p_len);
+ bool get_expand_to_text_length() const;
+
virtual bool is_text_field() const;
LineEdit();
~LineEdit();
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 28d67287d5..725f1ddf17 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -28,6 +28,7 @@
/*************************************************************************/
#include "menu_button.h"
#include "os/keyboard.h"
+#include "scene/main/viewport.h"
void MenuButton::_unhandled_key_input(InputEvent p_event) {
@@ -38,8 +39,12 @@ void MenuButton::_unhandled_key_input(InputEvent p_event) {
if (!get_parent() || !is_visible() || is_disabled())
return;
+ if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this))
+ return; //ignore because of modal window
- int item = popup->activate_item_by_event(p_event);
+
+ if (popup->activate_item_by_event(p_event))
+ accept_event();
}
}
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 8d02d0e4e5..5b83c3f8b8 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -125,8 +125,6 @@ void Popup::set_as_minsize() {
}
- print_line(String(c->get_type())+": "+minsize);
-
total_minsize.width = MAX( total_minsize.width, minsize.width );
total_minsize.height = MAX( total_minsize.height, minsize.height );
}
@@ -168,8 +166,6 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
}
- print_line(String(c->get_type())+": "+minsize);
-
total_minsize.width = MAX( total_minsize.width, minsize.width );
total_minsize.height = MAX( total_minsize.height, minsize.height );
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index b4fa463cde..73a3cda5f3 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -662,7 +662,9 @@ void RichTextLabel::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE: {
- set_bbcode(bbcode);
+ if (bbcode != "")
+ set_bbcode(bbcode);
+
main->first_invalid_line=0; //invalidate ALL
update();
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 190e8e141f..0fa2856ca4 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -228,14 +228,14 @@ void ScrollContainer::_notification(int p_what) {
child_max_size.y = MAX(child_max_size.y, minsize.y);
Rect2 r = Rect2(-scroll,minsize);
- if (!scroll_h) {
+ if (!h_scroll->is_visible()) {
r.pos.x=0;
if (c->get_h_size_flags()&SIZE_EXPAND)
r.size.width=MAX(size.width,minsize.width);
else
r.size.width=minsize.width;
}
- if (!scroll_v) {
+ if (!v_scroll->is_visible()) {
r.pos.y=0;
r.size.height=size.height;
if (c->get_v_size_flags()&SIZE_EXPAND)
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index d5d14ad649..3b9ca40bd8 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -47,12 +47,15 @@ void Slider::_input_event(InputEvent p_event) {
if (mb.button_index==BUTTON_LEFT) {
if (mb.pressed) {
+ Ref<Texture> grabber = get_icon(mouse_inside||has_focus()?"grabber_hilite":"grabber");
grab.pos=orientation==VERTICAL?mb.y:mb.x;
- double max = orientation==VERTICAL ? get_size().height : get_size().width ;
+ double grab_width = (double)grabber->get_size().width;
+ double grab_height = (double)grabber->get_size().height;
+ double max = orientation==VERTICAL ? get_size().height - grab_height : get_size().width - grab_width;
if (orientation==VERTICAL)
- set_unit_value( 1 - ((double)grab.pos / max) );
+ set_unit_value( 1 - (((double)grab.pos - (grab_height / 2.0)) / max) );
else
- set_unit_value((double)grab.pos / max);
+ set_unit_value(((double)grab.pos - (grab_width/2.0)) / max);
grab.active=true;
grab.uvalue=get_unit_value();
} else {
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 2b64d36a81..98e1a32aef 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -39,7 +39,7 @@ Size2 SpinBox::get_minimum_size() const {
void SpinBox::_value_changed(double) {
- String value = String::num(get_val(),Math::decimals(get_step()));
+ String value = String::num(get_val(),Math::step_decimals(get_step()));
if (prefix!="")
value=prefix+" "+value;
if (suffix!="")
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 0e0339c488..8557500488 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -400,6 +400,7 @@ void TabContainer::_child_renamed_callback() {
void TabContainer::add_child_notify(Node *p_child) {
+ Control::add_child_notify(p_child);
Control *c = p_child->cast_to<Control>();
if (!c)
@@ -532,6 +533,8 @@ Control* TabContainer::get_current_tab_control() const {
void TabContainer::remove_child_notify(Node *p_child) {
+ Control::remove_child_notify(p_child);
+
int tc = get_tab_count();
if (current==tc-1) {
current--;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index a680d5d873..4756fdee26 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -999,34 +999,39 @@ void TextEdit::_notification(int p_what) {
}
}
-
- if (str[j]>=32)
- cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color);
-
- else if (draw_tabs && str[j]=='\t') {
- int yofs= (get_row_height() - cache.tab_icon->get_height())/2;
- cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color);
- }
-
-
if (cursor.column==j && cursor.line==line) {
cursor_pos = Point2i( char_ofs+char_margin, ofs_y );
if (insert_mode) {
- cursor_pos.y += get_row_height();
+ cursor_pos.y += (get_row_height() - 3);
}
+ int caret_w = (str[j]=='\t') ? cache.font->get_char_size(' ').width : char_w;
if (draw_caret) {
if (insert_mode) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,1)),cache.caret_color);
+ int caret_h = (block_caret) ? 4 : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(caret_w,caret_h)),cache.caret_color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color);
+ caret_w = (block_caret) ? caret_w : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(caret_w,get_row_height())),cache.caret_color);
}
}
}
- char_ofs+=char_w;
+ if (cursor.column==j && cursor.line==line && block_caret && draw_caret && !insert_mode) {
+ color = cache.caret_background_color;
+ }
+
+ if (str[j]>=32)
+ cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color);
+
+ else if (draw_tabs && str[j]=='\t') {
+ int yofs= (get_row_height() - cache.tab_icon->get_height())/2;
+ cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color);
+ }
+
+ char_ofs+=char_w;
}
if (cursor.column==str.length() && cursor.line==line && (char_ofs+char_margin)>=xmargin_beg) {
@@ -1034,15 +1039,18 @@ void TextEdit::_notification(int p_what) {
cursor_pos=Point2i( char_ofs+char_margin, ofs_y );
if (insert_mode) {
- cursor_pos.y += get_row_height();
+ cursor_pos.y += (get_row_height() - 3);
}
if (draw_caret) {
if (insert_mode) {
int char_w = cache.font->get_char_size(' ').width;
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,1)),cache.caret_color);
+ int caret_h = (block_caret) ? 4 : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,caret_h)),cache.caret_color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color);
+ int char_w = cache.font->get_char_size(' ').width;
+ int caret_w = (block_caret) ? char_w : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(caret_w,get_row_height())),cache.caret_color);
}
}
}
@@ -1502,6 +1510,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
int gutter=cache.style_normal->get_margin(MARGIN_LEFT);
if (mb.x > gutter && mb.x <= gutter + cache.breakpoint_gutter_width + 3) {
set_line_as_breakpoint(row, !is_line_set_as_breakpoint(row));
+ emit_signal("breakpoint_toggled", row);
return;
}
}
@@ -1759,7 +1768,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
return;
}
- if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) {
+ if (k.scancode==KEY_ENTER || k.scancode==KEY_RETURN || k.scancode==KEY_TAB) {
_confirm_completion();
accept_event();
@@ -2984,6 +2993,34 @@ void TextEdit::adjust_viewport_to_cursor() {
}
+void TextEdit::center_viewport_to_cursor() {
+
+ if (cursor.line_ofs>cursor.line)
+ cursor.line_ofs=cursor.line;
+
+ int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w-cache.breakpoint_gutter_width;
+ if (v_scroll->is_visible())
+ visible_width-=v_scroll->get_combined_minimum_size().width;
+ visible_width-=20; // give it a little more space
+
+ int visible_rows = get_visible_rows();
+ if (h_scroll->is_visible())
+ visible_rows-=((h_scroll->get_combined_minimum_size().height-1)/get_row_height());
+
+ int max_ofs = text.size()-(scroll_past_end_of_file_enabled?1:visible_rows);
+ cursor.line_ofs=CLAMP(cursor.line-(visible_rows/2),0,max_ofs);
+
+ int cursor_x = get_column_x_offset( cursor.column, text[cursor.line] );
+
+ if (cursor_x>(cursor.x_ofs+visible_width))
+ cursor.x_ofs=cursor_x-visible_width+1;
+
+ if (cursor_x < cursor.x_ofs)
+ cursor.x_ofs=cursor_x;
+
+ update();
+}
+
void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
if (p_col<0)
@@ -3074,6 +3111,15 @@ void TextEdit::cursor_set_blink_speed(const float p_speed) {
caret_blink_timer->set_wait_time(p_speed);
}
+void TextEdit::cursor_set_block_mode(const bool p_enable){
+ block_caret = p_enable;
+ update();
+}
+
+bool TextEdit::cursor_is_block_mode() const {
+ return block_caret;
+}
+
void TextEdit::_scroll_moved(double p_to_val) {
@@ -3315,6 +3361,7 @@ void TextEdit::_update_caches() {
cache.completion_font_color=get_color("completion_font_color");
cache.font=get_font("font");
cache.caret_color=get_color("caret_color");
+ cache.caret_background_color=get_color("caret_background_color");
cache.line_number_color=get_color("line_number_color");
cache.font_color=get_color("font_color");
cache.font_selected_color=get_color("font_selected_color");
@@ -4417,6 +4464,8 @@ void TextEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("cursor_get_blink_enabled"),&TextEdit::cursor_get_blink_enabled);
ObjectTypeDB::bind_method(_MD("cursor_set_blink_speed", "blink_speed"),&TextEdit::cursor_set_blink_speed);
ObjectTypeDB::bind_method(_MD("cursor_get_blink_speed"),&TextEdit::cursor_get_blink_speed);
+ ObjectTypeDB::bind_method(_MD("cursor_set_block_mode", "enable"), &TextEdit::cursor_set_block_mode);
+ ObjectTypeDB::bind_method(_MD("cursor_is_block_mode"), &TextEdit::cursor_is_block_mode);
ObjectTypeDB::bind_method(_MD("set_readonly","enable"),&TextEdit::set_readonly);
ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap);
@@ -4459,15 +4508,18 @@ void TextEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("menu_option"),&TextEdit::menu_option);
ObjectTypeDB::bind_method(_MD("get_menu:PopupMenu"),&TextEdit::get_menu);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), _SCS("set_syntax_coloring"), _SCS("is_syntax_coloring_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), _SCS("set_show_line_numbers"), _SCS("is_show_line_numbers_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), _SCS("set_highlight_all_occurrences"), _SCS("is_highlight_all_occurrences_enabled"));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret/block_caret"), _SCS("cursor_set_block_mode"), _SCS("cursor_is_block_mode"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret/caret_blink"), _SCS("cursor_set_blink_enabled"), _SCS("cursor_get_blink_enabled"));
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret/caret_blink_speed",PROPERTY_HINT_RANGE,"0.1,10,0.1"), _SCS("cursor_set_blink_speed"),_SCS("cursor_get_blink_speed") );
ADD_SIGNAL(MethodInfo("cursor_changed"));
ADD_SIGNAL(MethodInfo("text_changed"));
ADD_SIGNAL(MethodInfo("request_completion"));
+ ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo( Variant::INT, "row")));
BIND_CONSTANT( MENU_CUT );
BIND_CONSTANT( MENU_COPY );
@@ -4527,6 +4579,7 @@ TextEdit::TextEdit() {
selection.active=false;
syntax_coloring=false;
+ block_caret=false;
caret_blink_enabled=false;
caret_blink_timer = memnew(Timer);
add_child(caret_blink_timer);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 270a1723b1..f0301fc250 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -79,6 +79,7 @@ class TextEdit : public Control {
Color completion_existing_color;
Color completion_font_color;
Color caret_color;
+ Color caret_background_color;
Color line_number_color;
Color font_color;
Color font_selected_color;
@@ -222,6 +223,7 @@ class TextEdit : public Control {
bool caret_blink_enabled;
bool draw_caret;
bool window_has_focus;
+ bool block_caret;
bool setting_row;
bool wrap;
@@ -394,6 +396,8 @@ public:
}
void set_auto_indent(bool p_auto_indent);
+ void center_viewport_to_cursor();
+
void cursor_set_column(int p_col, bool p_adjust_viewport=true);
void cursor_set_line(int p_row, bool p_adjust_viewport=true);
@@ -406,6 +410,9 @@ public:
float cursor_get_blink_speed() const;
void cursor_set_blink_speed(const float p_speed);
+ void cursor_set_block_mode(const bool p_enable);
+ bool cursor_is_block_mode() const;
+
void set_readonly(bool p_readonly);
void set_max_chars(int p_max_chars);
@@ -431,7 +438,7 @@ public:
bool is_highlight_all_occurrences_enabled() const;
bool is_selection_active() const;
int get_selection_from_line() const;
- int get_selection_from_column() const;
+ int get_selection_from_column() const;
int get_selection_to_line() const;
int get_selection_to_column() const;
String get_selection_text() const;
@@ -489,7 +496,7 @@ public:
String get_text_for_completion();
- virtual bool is_text_field() const;
+ virtual bool is_text_field() const;
TextEdit();
~TextEdit();
};
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index 923a35031c..2c576b6ba5 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -297,6 +297,7 @@ void TextureProgress::_bind_methods() {
TextureProgress::TextureProgress()
{
mode=FILL_LEFT_TO_RIGHT;
+ rad_init_angle=0;
rad_center_off=Point2();
rad_max_degrees=360;
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 305a3920da..20794b2faa 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -171,6 +171,21 @@ String TreeItem::get_text(int p_column) const {
}
+void TreeItem::set_suffix(int p_column,String p_suffix) {
+
+ ERR_FAIL_INDEX( p_column, cells.size() );
+ cells[p_column].suffix=p_suffix;
+
+ _changed_notify(p_column);
+
+}
+
+String TreeItem::get_suffix(int p_column) const {
+
+ ERR_FAIL_INDEX_V( p_column, cells.size(), "" );
+ return cells[p_column].suffix;
+
+}
void TreeItem::set_icon(int p_column,const Ref<Texture>& p_icon) {
@@ -693,6 +708,7 @@ void TreeItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_button","column","button:Texture","button_idx","disabled"),&TreeItem::add_button,DEFVAL(-1),DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_button_count","column"),&TreeItem::get_button_count);
ObjectTypeDB::bind_method(_MD("get_button:Texture","column","button_idx"),&TreeItem::get_button);
+ ObjectTypeDB::bind_method(_MD("set_button","column","button_idx","button:Texture"),&TreeItem::set_button);
ObjectTypeDB::bind_method(_MD("erase_button","column","button_idx"),&TreeItem::erase_button);
ObjectTypeDB::bind_method(_MD("is_button_disabled","column","button_idx"),&TreeItem::is_button_disabled);
@@ -926,8 +942,12 @@ void Tree::draw_item_rect(const TreeItem::Cell& p_cell,const Rect2i& p_rect,cons
Ref<Font> font = cache.font;
+ String text = p_cell.text;
+ if (p_cell.suffix!=String())
+ text+=" "+p_cell.suffix;
+
rect.pos.y+=Math::floor((rect.size.y-font->get_height())/2.0) +font->get_ascent();
- font->draw(ci,rect.pos,p_cell.text,p_color,rect.size.x);
+ font->draw(ci,rect.pos,text,p_color,rect.size.x);
}
@@ -1071,11 +1091,21 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
if (p_item->cells[i].selected && select_mode!=SELECT_ROW) {
Rect2i r(item_rect.pos,item_rect.size);
+ if (p_item->cells[i].text.size() > 0){
+ float icon_width = p_item->cells[i].get_icon_size().width;
+ r.pos.x += icon_width;
+ r.size.x -= icon_width;
+ }
//r.grow(cache.selected->get_margin(MARGIN_LEFT));
- if (has_focus())
+ if (has_focus()){
cache.selected_focus->draw(ci,r );
- else
+ p_item->set_meta("__focus_rect", Rect2(r.pos,r.size));
+ } else {
cache.selected->draw(ci,r );
+ }
+ if (text_editor->is_visible()){
+ text_editor->set_pos(get_global_pos() + r.pos);
+ }
}
if (p_item->cells[i].custom_bg_color) {
@@ -1164,6 +1194,9 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
String s = p_item->cells[i].text;
s=s.get_slicec(',',option);
+ if (p_item->cells[i].suffix!=String())
+ s+=" "+p_item->cells[i].suffix;
+
Ref<Texture> downarrow = cache.select_arrow;
font->draw(ci, text_pos, s, col,item_rect.size.x-downarrow->get_width() );
@@ -1178,8 +1211,12 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
Ref<Texture> updown = cache.updown;
- //String valtext = String::num( p_item->cells[i].val, Math::decimals( p_item->cells[i].step ) );
- String valtext = rtos( p_item->cells[i].val );
+ String valtext = String::num( p_item->cells[i].val, Math::step_decimals( p_item->cells[i].step ) );
+ //String valtext = rtos( p_item->cells[i].val );
+
+ if (p_item->cells[i].suffix!=String())
+ valtext+=" "+p_item->cells[i].suffix;
+
font->draw( ci, text_pos, valtext, col, item_rect.size.x-updown->get_width());
if (!p_item->cells[i].editable)
@@ -1745,7 +1782,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
} else {
- editor_text=String::num( p_item->cells[col].val, Math::decimals( p_item->cells[col].step ) );
+ editor_text=String::num( p_item->cells[col].val, Math::step_decimals( p_item->cells[col].step ) );
if (select_mode==SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id)
bring_up_editor=false;
@@ -2327,9 +2364,22 @@ void Tree::_input_event(InputEvent p_event) {
range_drag_enabled=false;
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
warp_mouse(range_drag_capture_pos);
- } else
- edit_selected();
+ } else {
+ if (delayed_text_editor) {
+ uint64_t diff = OS::get_singleton()->get_ticks_msec() - first_selection_time;
+ if (diff >= 400 && diff <= 800)
+ edit_selected();
+ // fast double click
+ else if (diff < 400) {
+ emit_signal("item_double_clicked");
+ }
+
+ first_selection_time = OS::get_singleton()->get_ticks_msec();
+ } else {
+ edit_selected();
+ }
+ }
pressing_for_editor=false;
}
@@ -2467,16 +2517,7 @@ bool Tree::edit_selected() {
if (!s->cells[col].editable)
return false;
- Rect2 rect;
- rect.pos.y = get_item_offset(s) - get_scroll().y;
-
- for(int i=0;i<col;i++) {
-
- rect.pos.x+=get_column_width(i);
- }
-
- rect.size.width=get_column_width(col);
- rect.size.height=compute_item_height(s)+cache.vseparation;
+ Rect2 rect = s->get_meta("__focus_rect");
popup_edited_item=s;
popup_edited_item_col=col;
@@ -2520,7 +2561,7 @@ bool Tree::edit_selected() {
text_editor->set_pos( textedpos );
text_editor->set_size( rect.size);
text_editor->clear();
- text_editor->set_text( c.mode==TreeItem::CELL_MODE_STRING?c.text:rtos(c.val) );
+ text_editor->set_text( c.mode==TreeItem::CELL_MODE_STRING?c.text:String::num( c.val, Math::step_decimals( c.step ) ) );
text_editor->select_all();
if (c.mode==TreeItem::CELL_MODE_RANGE || c.mode==TreeItem::CELL_MODE_RANGE_EXPRESSION ) {
@@ -2847,7 +2888,6 @@ void Tree::item_changed(int p_column,TreeItem *p_item) {
void Tree::item_selected(int p_column,TreeItem *p_item) {
-
if (select_mode==SELECT_MULTI) {
if (!p_item->cells[p_column].selectable)
@@ -2855,8 +2895,11 @@ void Tree::item_selected(int p_column,TreeItem *p_item) {
p_item->cells[p_column].selected=true;
//emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select
+ if (delayed_text_editor)
+ first_selection_time = OS::get_singleton()->get_ticks_msec();
} else {
+
select_single_item(p_item,root,p_column);
}
update();
@@ -3127,7 +3170,7 @@ void Tree::ensure_cursor_is_visible() {
int screenh=get_size().height-h_scroll->get_combined_minimum_size().height;
if (ofs+h>v_scroll->get_val()+screenh)
- v_scroll->set_val(ofs-screenh+h);
+ v_scroll->call_deferred("set_val", ofs-screenh+h);
else if (ofs < v_scroll->get_val())
v_scroll->set_val(ofs);
}
@@ -3502,6 +3545,16 @@ bool Tree::get_allow_rmb_select() const{
return allow_rmb_select;
}
+
+void Tree::set_delayed_text_editor(bool enabled) {
+ delayed_text_editor = enabled;
+}
+
+bool Tree::is_delayed_text_editor_enabled() const {
+ return delayed_text_editor;
+}
+
+
void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_range_click_timeout"),&Tree::_range_click_timeout);
@@ -3555,6 +3608,9 @@ void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_allow_rmb_select","allow"),&Tree::set_allow_rmb_select);
ObjectTypeDB::bind_method(_MD("get_allow_rmb_select"),&Tree::get_allow_rmb_select);
+ ObjectTypeDB::bind_method(_MD("set_delayed_text_editor","enable"),&Tree::set_delayed_text_editor);
+ ObjectTypeDB::bind_method(_MD("is_delayed_text_editor_enabled"),&Tree::is_delayed_text_editor_enabled);
+
ObjectTypeDB::bind_method(_MD("set_single_select_cell_editing_only_when_already_selected","enable"),&Tree::set_single_select_cell_editing_only_when_already_selected);
ObjectTypeDB::bind_method(_MD("get_single_select_cell_editing_only_when_already_selected"),&Tree::get_single_select_cell_editing_only_when_already_selected);
@@ -3565,6 +3621,7 @@ void Tree::_bind_methods() {
ADD_SIGNAL( MethodInfo("item_rmb_selected",PropertyInfo(Variant::VECTOR2,"pos")));
ADD_SIGNAL( MethodInfo("empty_tree_rmb_selected",PropertyInfo(Variant::VECTOR2,"pos")));
ADD_SIGNAL( MethodInfo("item_edited"));
+ ADD_SIGNAL( MethodInfo("item_double_clicked"));
ADD_SIGNAL( MethodInfo("item_collapsed",PropertyInfo(Variant::OBJECT,"item")));
//ADD_SIGNAL( MethodInfo("item_doubleclicked" ) );
ADD_SIGNAL( MethodInfo("button_pressed",PropertyInfo(Variant::OBJECT,"item"),PropertyInfo(Variant::INT,"column"),PropertyInfo(Variant::INT,"id")));
@@ -3668,6 +3725,9 @@ Tree::Tree() {
force_select_on_already_selected=false;
allow_rmb_select=false;
+
+ first_selection_time = 0;
+ delayed_text_editor = false;
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index f5100ab5b6..2124dce749 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -69,6 +69,7 @@ friend class Tree;
Ref<Texture> icon;
Rect2i icon_region;
String text;
+ String suffix;
double min,max,step,val;
int icon_max_w;
bool expr;
@@ -168,6 +169,9 @@ public:
void set_text(int p_column,String p_text);
String get_text(int p_column) const;
+ void set_suffix(int p_column,String p_suffix);
+ String get_suffix(int p_column) const;
+
void set_icon(int p_column,const Ref<Texture>& p_icon);
Ref<Texture> get_icon(int p_column) const;
@@ -433,6 +437,9 @@ friend class TreeItem;
float last_drag_time;
float time_since_motion;*/
+ bool delayed_text_editor;
+ uint64_t first_selection_time;
+
float drag_speed;
float drag_from;
float drag_accum;
@@ -527,6 +534,9 @@ public:
void set_value_evaluator(ValueEvaluator *p_evaluator);
+ void set_delayed_text_editor(bool enabled);
+ bool is_delayed_text_editor_enabled() const;
+
Tree();
~Tree();