diff options
Diffstat (limited to 'scene/gui')
39 files changed, 2317 insertions, 487 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 3bcc60b86a..2200cac5da 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -289,7 +289,7 @@ void BaseButton::set_disabled(bool p_disabled) { if (p_disabled) set_focus_mode(FOCUS_NONE); else - set_focus_mode(FOCUS_ALL); + set_focus_mode(enabled_focus_mode); } bool BaseButton::is_disabled() const { @@ -377,12 +377,56 @@ bool BaseButton::get_click_on_press() const { return status.click_on_press; } +void BaseButton::set_enabled_focus_mode(FocusMode p_mode) { + enabled_focus_mode = p_mode; + if (!status.disabled) { + set_focus_mode( p_mode ); + } +} + +Control::FocusMode BaseButton::get_enabled_focus_mode() const { + + return enabled_focus_mode; +} + +void BaseButton::set_shortcut(const Ref<ShortCut>& p_shortcut) { + + if (shortcut.is_null() == p_shortcut.is_null()) + return; + + shortcut=p_shortcut; + set_process_unhandled_input(shortcut.is_valid()); +} +Ref<ShortCut> BaseButton:: get_shortcut() const { + return shortcut; +} + +void BaseButton::_unhandled_input(InputEvent p_event) { + + if (!is_disabled() && is_visible() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { + if (is_toggle_mode()) { + set_pressed(!is_pressed()); + emit_signal("toggled",is_pressed()); + } + + emit_signal("pressed"); + } +} + +String BaseButton::get_tooltip(const Point2& p_pos) const { + + String tooltip=Control::get_tooltip(p_pos); + if (shortcut.is_valid() && shortcut->is_valid()) + tooltip+=" ("+shortcut->get_as_text()+")"; + return tooltip; +} void BaseButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&BaseButton::_input_event); + ObjectTypeDB::bind_method(_MD("_unhandled_input"),&BaseButton::_unhandled_input); ObjectTypeDB::bind_method(_MD("set_pressed","pressed"),&BaseButton::set_pressed); ObjectTypeDB::bind_method(_MD("is_pressed"),&BaseButton::is_pressed); ObjectTypeDB::bind_method(_MD("is_hovered"),&BaseButton::is_hovered); @@ -393,6 +437,10 @@ void BaseButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_click_on_press","enable"),&BaseButton::set_click_on_press); ObjectTypeDB::bind_method(_MD("get_click_on_press"),&BaseButton::get_click_on_press); ObjectTypeDB::bind_method(_MD("get_draw_mode"),&BaseButton::get_draw_mode); + ObjectTypeDB::bind_method(_MD("set_enabled_focus_mode","mode"),&BaseButton::set_enabled_focus_mode); + ObjectTypeDB::bind_method(_MD("get_enabled_focus_mode"),&BaseButton::get_enabled_focus_mode); + ObjectTypeDB::bind_method(_MD("set_shortcut","shortcut"),&BaseButton::set_shortcut); + ObjectTypeDB::bind_method(_MD("get_shortcut"),&BaseButton::get_shortcut); BIND_VMETHOD(MethodInfo("_pressed")); BIND_VMETHOD(MethodInfo("_toggled",PropertyInfo(Variant::BOOL,"pressed"))); @@ -404,6 +452,8 @@ void BaseButton::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press")); + ADD_PROPERTY( PropertyInfo( Variant::INT,"enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_enabled_focus_mode"), _SCS("get_enabled_focus_mode") ); + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "shortcut",PROPERTY_HINT_RESOURCE_TYPE,"ShortCut"), _SCS("set_shortcut"), _SCS("get_shortcut")); BIND_CONSTANT( DRAW_NORMAL ); @@ -424,6 +474,7 @@ BaseButton::BaseButton() { status.click_on_press=false; status.pressing_button=0; set_focus_mode( FOCUS_ALL ); + enabled_focus_mode = FOCUS_ALL; group=NULL; diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 9a5213d971..0056b00f33 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -42,6 +42,8 @@ class BaseButton : public Control { OBJ_TYPE( BaseButton, Control ); bool toggle_mode; + FocusMode enabled_focus_mode; + Ref<ShortCut> shortcut; struct Status { @@ -56,6 +58,7 @@ class BaseButton : public Control { } status; + ButtonGroup *group; @@ -68,6 +71,7 @@ protected: virtual void toggled(bool p_pressed); static void _bind_methods(); virtual void _input_event(InputEvent p_event); + virtual void _unhandled_input(InputEvent p_event); void _notification(int p_what); public: @@ -97,6 +101,13 @@ public: void set_click_on_press(bool p_click_on_press); bool get_click_on_press() const; + void set_enabled_focus_mode(FocusMode p_mode); + FocusMode get_enabled_focus_mode() const; + + void set_shortcut(const Ref<ShortCut>& p_shortcut); + Ref<ShortCut> get_shortcut() const; + + virtual String get_tooltip(const Point2& p_pos) const; BaseButton(); ~BaseButton(); diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index a9522cf248..a6ffc30a83 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -280,6 +280,7 @@ BoxContainer::AlignMode BoxContainer::get_alignment() const { void BoxContainer::add_spacer(bool p_begin) { Control *c = memnew( Control ); + c->set_stop_mouse(false); if (vertical) c->set_v_size_flags(SIZE_EXPAND_FILL); else diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 0f3f762ba1..579f6e08c9 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -213,7 +213,6 @@ Button::TextAlign Button::get_text_align() const { return align; } - void Button::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_text","text"),&Button::set_text); @@ -227,6 +226,10 @@ void Button::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_text_align"),&Button::get_text_align); ObjectTypeDB::bind_method(_MD("is_flat"),&Button::is_flat); + BIND_CONSTANT( ALIGN_LEFT ); + BIND_CONSTANT( ALIGN_CENTER ); + BIND_CONSTANT( ALIGN_RIGHT ); + ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL ), _SCS("set_text"),_SCS("get_text") ); ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_button_icon"),_SCS("get_button_icon") ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flat" ), _SCS("set_flat"),_SCS("is_flat") ); diff --git a/scene/gui/button.h b/scene/gui/button.h index 8a17a164a0..c39237c9af 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -54,7 +54,6 @@ private: TextAlign align; - protected: virtual Size2 get_minimum_size() const; @@ -62,6 +61,8 @@ protected: static void _bind_methods(); public: // + + void set_text(const String& p_text); String get_text() const; @@ -77,6 +78,7 @@ public: void set_text_align(TextAlign p_align); TextAlign get_text_align() const; + Button(const String& p_text=String()); ~Button(); diff --git a/scene/gui/button_array.cpp b/scene/gui/button_array.cpp index de77b83403..be48296110 100644 --- a/scene/gui/button_array.cpp +++ b/scene/gui/button_array.cpp @@ -362,10 +362,10 @@ ButtonArray::Align ButtonArray::get_align() const { } -void ButtonArray::add_button(const String& p_button) { +void ButtonArray::add_button(const String& p_text) { Button button; - button.text=p_button; + button.text=p_text; buttons.push_back(button); update(); @@ -375,10 +375,10 @@ void ButtonArray::add_button(const String& p_button) { minimum_size_changed(); } -void ButtonArray::add_icon_button(const Ref<Texture>& p_icon,const String& p_button) { +void ButtonArray::add_icon_button(const Ref<Texture>& p_icon,const String& p_text) { Button button; - button.text=p_button; + button.text=p_text; button.icon=p_icon; buttons.push_back(button); if (selected==-1) @@ -396,6 +396,7 @@ void ButtonArray::set_button_text(int p_button, const String& p_text) { minimum_size_changed(); } + void ButtonArray::set_button_icon(int p_button, const Ref<Texture>& p_icon) { ERR_FAIL_INDEX(p_button,buttons.size()); @@ -403,11 +404,13 @@ void ButtonArray::set_button_icon(int p_button, const Ref<Texture>& p_icon) { update(); minimum_size_changed(); } + String ButtonArray::get_button_text(int p_button) const { ERR_FAIL_INDEX_V(p_button,buttons.size(),""); return buttons[p_button].text; } + Ref<Texture> ButtonArray::get_button_icon(int p_button) const { ERR_FAIL_INDEX_V(p_button,buttons.size(),Ref<Texture>()); @@ -470,16 +473,16 @@ void ButtonArray::get_translatable_strings(List<String> *p_strings) const { void ButtonArray::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_button","text"),&ButtonArray::add_button); - ObjectTypeDB::bind_method(_MD("add_icon_button","icon","text"),&ButtonArray::add_icon_button,DEFVAL("")); - ObjectTypeDB::bind_method(_MD("set_button_text","button","text"),&ButtonArray::set_button_text); - ObjectTypeDB::bind_method(_MD("set_button_icon","button","icon"),&ButtonArray::set_button_icon); - ObjectTypeDB::bind_method(_MD("get_button_text","button"),&ButtonArray::get_button_text); - ObjectTypeDB::bind_method(_MD("get_button_icon","button"),&ButtonArray::get_button_icon); + ObjectTypeDB::bind_method(_MD("add_icon_button","icon:Texture","text"),&ButtonArray::add_icon_button,DEFVAL("")); + ObjectTypeDB::bind_method(_MD("set_button_text","button_idx","text"),&ButtonArray::set_button_text); + ObjectTypeDB::bind_method(_MD("set_button_icon","button_idx","icon:Texture"),&ButtonArray::set_button_icon); + ObjectTypeDB::bind_method(_MD("get_button_text","button_idx"),&ButtonArray::get_button_text); + ObjectTypeDB::bind_method(_MD("get_button_icon:Texture","button_idx"),&ButtonArray::get_button_icon); ObjectTypeDB::bind_method(_MD("get_button_count"),&ButtonArray::get_button_count); ObjectTypeDB::bind_method(_MD("get_selected"),&ButtonArray::get_selected); ObjectTypeDB::bind_method(_MD("get_hovered"),&ButtonArray::get_hovered); - ObjectTypeDB::bind_method(_MD("set_selected","button"),&ButtonArray::set_selected); - ObjectTypeDB::bind_method(_MD("erase_button","button"),&ButtonArray::erase_button); + ObjectTypeDB::bind_method(_MD("set_selected","button_idx"),&ButtonArray::set_selected); + ObjectTypeDB::bind_method(_MD("erase_button","button_idx"),&ButtonArray::erase_button); ObjectTypeDB::bind_method(_MD("clear"),&ButtonArray::clear); ObjectTypeDB::bind_method(_MD("_input_event"),&ButtonArray::_input_event); @@ -490,7 +493,7 @@ void ButtonArray::_bind_methods() { BIND_CONSTANT( ALIGN_FILL ); BIND_CONSTANT( ALIGN_EXPAND_FILL ); - ADD_SIGNAL( MethodInfo("button_selected",PropertyInfo(Variant::INT,"button"))); + ADD_SIGNAL( MethodInfo("button_selected",PropertyInfo(Variant::INT,"button_idx"))); } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index d7befd6e11..bd56369746 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -107,8 +107,32 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) { String name= p_name; - if (!name.begins_with("custom")) - return false; + if (!name.begins_with("custom")) { + if (name.begins_with("margin/")) { + String dname = name.get_slicec('/', 1); + if (dname == "left") { + set_margin(MARGIN_LEFT, p_value); + return true; + } + else if (dname == "top") { + set_margin(MARGIN_TOP, p_value); + return true; + } + else if (dname == "right") { + set_margin(MARGIN_RIGHT, p_value); + return true; + } + else if (dname == "bottom") { + set_margin(MARGIN_BOTTOM, p_value); + return true; + } + else { + return false; + } + } else { + return false; + } + } if (p_value.get_type()==Variant::NIL) { @@ -200,7 +224,30 @@ bool Control::_get(const StringName& p_name,Variant &r_ret) const { String sname=p_name; if (!sname.begins_with("custom")) - return false; + if (sname.begins_with("margin/")) { + String dname = sname.get_slicec('/', 1); + if (dname == "left") { + r_ret = get_margin(MARGIN_LEFT); + return true; + } + else if (dname == "top") { + r_ret = get_margin(MARGIN_TOP); + return true; + } + else if (dname == "right") { + r_ret = get_margin(MARGIN_RIGHT); + return true; + } + else if (dname == "bottom") { + r_ret = get_margin(MARGIN_BOTTOM); + return true; + } + else { + return false; + } + } else { + return false; + } if (sname.begins_with("custom_icons/")) { String name = sname.get_slicec('/',1); @@ -236,6 +283,36 @@ bool Control::_get(const StringName& p_name,Variant &r_ret) const { } void Control::_get_property_list( List<PropertyInfo> *p_list) const { + { + if (get_anchor(MARGIN_LEFT) == ANCHOR_RATIO) { + p_list->push_back(PropertyInfo(Variant::REAL, "margin/left", PROPERTY_HINT_RANGE, "-4096,4096,0.001")); + } + else { + p_list->push_back(PropertyInfo(Variant::INT, "margin/left", PROPERTY_HINT_RANGE, "-4096,4096")); + } + + if (get_anchor(MARGIN_TOP) == ANCHOR_RATIO) { + p_list->push_back(PropertyInfo(Variant::REAL, "margin/top", PROPERTY_HINT_RANGE, "-4096,4096,0.001")); + } + else { + p_list->push_back(PropertyInfo(Variant::INT, "margin/top", PROPERTY_HINT_RANGE, "-4096,4096")); + } + + if (get_anchor(MARGIN_RIGHT) == ANCHOR_RATIO) { + p_list->push_back(PropertyInfo(Variant::REAL, "margin/right", PROPERTY_HINT_RANGE, "-4096,4096,0.001")); + } + else { + p_list->push_back(PropertyInfo(Variant::INT, "margin/right", PROPERTY_HINT_RANGE, "-4096,4096")); + } + + if (get_anchor(MARGIN_BOTTOM) == ANCHOR_RATIO) { + p_list->push_back(PropertyInfo(Variant::REAL, "margin/bottom", PROPERTY_HINT_RANGE, "-4096,4096,0.001")); + } + else { + p_list->push_back(PropertyInfo(Variant::INT, "margin/bottom", PROPERTY_HINT_RANGE, "-4096,4096")); + } + } + Ref<Theme> theme; if (data.theme.is_valid()) { @@ -525,10 +602,13 @@ void Control::_notification(int p_notification) { if (!is_visible()) { + if(get_viewport() != NULL) + get_viewport()->_gui_hid_control(this); - get_viewport()->_gui_hid_control(this); - _modal_stack_remove(); - minimum_size_changed(); + if(is_inside_tree()) { + _modal_stack_remove(); + minimum_size_changed(); + } //remove key focus //remove modalness @@ -572,8 +652,24 @@ bool Control::has_point(const Point2& p_point) const { return Rect2( Point2(), get_size() ).has_point(p_point); } +void Control::set_drag_forwarding(Control* p_target) { + + if (p_target) + data.drag_owner=p_target->get_instance_ID(); + else + data.drag_owner=0; +} + Variant Control::get_drag_data(const Point2& p_point) { + if (data.drag_owner) { + Object *obj = ObjectDB::get_instance(data.drag_owner); + if (obj) { + Control *c = obj->cast_to<Control>(); + return c->call("get_drag_data_fw",p_point,this); + } + } + if (get_script_instance()) { Variant v=p_point; const Variant *p=&v; @@ -589,6 +685,14 @@ Variant Control::get_drag_data(const Point2& p_point) { bool Control::can_drop_data(const Point2& p_point,const Variant& p_data) const { + if (data.drag_owner) { + Object *obj = ObjectDB::get_instance(data.drag_owner); + if (obj) { + Control *c = obj->cast_to<Control>(); + return c->call("can_drop_data_fw",p_point,p_data,this); + } + } + if (get_script_instance()) { Variant v=p_point; const Variant *p[2]={&v,&p_data}; @@ -603,6 +707,15 @@ bool Control::can_drop_data(const Point2& p_point,const Variant& p_data) const { } void Control::drop_data(const Point2& p_point,const Variant& p_data){ + if (data.drag_owner) { + Object *obj = ObjectDB::get_instance(data.drag_owner); + if (obj) { + Control *c = obj->cast_to<Control>(); + c->call("drop_data_fw",p_point,p_data,this); + return; + } + } + if (get_script_instance()) { Variant v=p_point; const Variant *p[2]={&v,&p_data}; @@ -631,7 +744,6 @@ void Control::set_drag_preview(Control *p_control) { - bool Control::is_window_modal_on_top() const { if (!is_inside_tree()) @@ -658,7 +770,7 @@ Size2 Control::get_minimum_size() const { Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<Texture>* tex = data.icon_override.getptr(p_name); if (tex) @@ -688,7 +800,7 @@ Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type } Ref<Shader> Control::get_shader(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<Shader>* sdr = data.shader_override.getptr(p_name); if (sdr) @@ -718,7 +830,7 @@ Ref<Shader> Control::get_shader(const StringName& p_name,const StringName& p_typ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<StyleBox>* style = data.style_override.getptr(p_name); if (style) return *style; @@ -746,7 +858,7 @@ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p } Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<Font>* font = data.font_override.getptr(p_name); if (font) return *font; @@ -777,7 +889,7 @@ Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) c } Color Control::get_color(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Color* color = data.color_override.getptr(p_name); if (color) return *color; @@ -806,7 +918,7 @@ Color Control::get_color(const StringName& p_name,const StringName& p_type) cons int Control::get_constant(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const int* constant = data.constant_override.getptr(p_name); if (constant) return *constant; @@ -834,12 +946,64 @@ int Control::get_constant(const StringName& p_name,const StringName& p_type) con } +bool Control::has_icon_override(const StringName& p_name) const { + + const Ref<Texture>* tex = data.icon_override.getptr(p_name); + if (tex) + return true; + else + return false; +} + +bool Control::has_shader_override(const StringName &p_name) const { + + const Ref<Shader>* sdr = data.shader_override.getptr(p_name); + if (sdr) + return true; + else + return false; +} + +bool Control::has_stylebox_override(const StringName& p_name) const { + + const Ref<StyleBox>* style = data.style_override.getptr(p_name); + if (style) + return true; + else + return false; +} + +bool Control::has_font_override(const StringName& p_name) const { + + const Ref<Font>* font = data.font_override.getptr(p_name); + if (font) + return true; + else + return false; +} + +bool Control::has_color_override(const StringName& p_name) const { + + const Color* color = data.color_override.getptr(p_name); + if (color) + return true; + else + return false; +} + +bool Control::has_constant_override(const StringName& p_name) const { + + const int* constant = data.constant_override.getptr(p_name); + if (constant) + return true; + else + return false; +} bool Control::has_icon(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Ref<Texture>* tex = data.icon_override.getptr(p_name); - if (tex) + if (p_type==StringName() || p_type=="") { + if (has_icon_override(p_name) == true) return true; } @@ -865,11 +1029,10 @@ bool Control::has_icon(const StringName& p_name,const StringName& p_type) const } -bool Control::has_shader(const StringName &p_name, const StringName &p_type) const -{ - if (p_type==StringName()) { - const Ref<Shader>* sdr = data.shader_override.getptr(p_name); - if (sdr) +bool Control::has_shader(const StringName &p_name, const StringName &p_type) const { + + if (p_type==StringName() || p_type=="") { + if (has_shader_override(p_name)==true) return true; } @@ -896,10 +1059,8 @@ bool Control::has_shader(const StringName &p_name, const StringName &p_type) con } bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Ref<StyleBox>* style = data.style_override.getptr(p_name); - - if (style) + if (p_type==StringName() || p_type=="") { + if (has_stylebox_override(p_name)==true) return true; } @@ -926,9 +1087,8 @@ bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) co } bool Control::has_font(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Ref<Font>* font = data.font_override.getptr(p_name); - if (font) + if (p_type==StringName() || p_type=="") { + if (has_font_override(p_name)==true) return true; } @@ -954,11 +1114,11 @@ bool Control::has_font(const StringName& p_name,const StringName& p_type) const return Theme::get_default()->has_font( p_name, type ); } -bool Control::has_color(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Color* color = data.color_override.getptr(p_name); - if (color) +bool Control::has_color(const StringName& p_name, const StringName& p_type) const { + + if (p_type==StringName() || p_type=="") { + if (has_color_override(p_name)==true) return true; } @@ -986,10 +1146,8 @@ bool Control::has_color(const StringName& p_name,const StringName& p_type) const bool Control::has_constant(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - - const int* constant = data.constant_override.getptr(p_name); - if (constant) + if (p_type==StringName() || p_type=="") { + if (has_constant_override(p_name) == true) return true; } @@ -1175,14 +1333,13 @@ void Control::set_anchor(Margin p_margin,AnchorType p_anchor, bool p_keep_margin void Control::_set_anchor(Margin p_margin,AnchorType p_anchor) { #ifdef TOOLS_ENABLED - SceneTree *st=OS::get_singleton()->get_main_loop()->cast_to<SceneTree>(); - if (st && st->is_editor_hint()) { + if (is_inside_tree() && get_tree()->is_editor_hint()) { set_anchor(p_margin, p_anchor, EDITOR_DEF("2d_editor/keep_margins_when_changing_anchors", false)); } else { - set_anchor(p_margin, p_anchor); + set_anchor(p_margin, p_anchor, false); } #else - set_anchor(p_margin, p_anchor); + set_anchor(p_margin, p_anchor, false); #endif } @@ -1699,6 +1856,7 @@ void Control::_propagate_theme_changed(Control *p_owner) { void Control::set_theme(const Ref<Theme>& p_theme) { + data.theme=p_theme; if (!p_theme.is_null()) { @@ -2045,17 +2203,9 @@ bool Control::is_text_field() const { } -void Control::_set_rotation_deg(float p_rot) { - set_rotation(Math::deg2rad(p_rot)); -} - -float Control::_get_rotation_deg() const { - return Math::rad2deg(get_rotation()); -} - -void Control::set_rotation(float p_rotation) { +void Control::set_rotation(float p_radians) { - data.rotation=p_rotation; + data.rotation=p_radians; update(); _notify_transform(); } @@ -2065,6 +2215,25 @@ float Control::get_rotation() const{ return data.rotation; } +void Control::set_rotation_deg(float p_degrees) { + set_rotation(Math::deg2rad(p_degrees)); +} + +float Control::get_rotation_deg() const { + return Math::rad2deg(get_rotation()); +} + +// Kept for compatibility after rename to {s,g}et_rotation_deg. +// Could be removed after a couple releases. +void Control::_set_rotation_deg(float p_degrees) { + WARN_PRINT("Deprecated method Control._set_rotation_deg(): This method was renamed to set_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted."); + set_rotation_deg(p_degrees); +} +float Control::_get_rotation_deg() const { + WARN_PRINT("Deprecated method Control._get_rotation_deg(): This method was renamed to get_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted."); + return get_rotation_deg(); +} + void Control::set_scale(const Vector2& p_scale){ data.scale=p_scale; @@ -2120,8 +2289,10 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_size","size"),&Control::set_size); ObjectTypeDB::bind_method(_MD("set_custom_minimum_size","size"),&Control::set_custom_minimum_size); ObjectTypeDB::bind_method(_MD("set_global_pos","pos"),&Control::set_global_pos); - ObjectTypeDB::bind_method(_MD("set_rotation","rotation"),&Control::set_rotation); - ObjectTypeDB::bind_method(_MD("_set_rotation_deg","rotation"),&Control::_set_rotation_deg); + ObjectTypeDB::bind_method(_MD("set_rotation","radians"),&Control::set_rotation); + ObjectTypeDB::bind_method(_MD("set_rotation_deg","degrees"),&Control::set_rotation_deg); + // TODO: Obsolete this method (old name) properly (GH-4397) + ObjectTypeDB::bind_method(_MD("_set_rotation_deg","degrees"),&Control::_set_rotation_deg); ObjectTypeDB::bind_method(_MD("set_scale","scale"),&Control::set_scale); ObjectTypeDB::bind_method(_MD("get_margin","margin"),&Control::get_margin); ObjectTypeDB::bind_method(_MD("get_begin"),&Control::get_begin); @@ -2129,16 +2300,19 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_pos"),&Control::get_pos); ObjectTypeDB::bind_method(_MD("get_size"),&Control::get_size); ObjectTypeDB::bind_method(_MD("get_rotation"),&Control::get_rotation); + ObjectTypeDB::bind_method(_MD("get_rotation_deg"),&Control::get_rotation_deg); + // TODO: Obsolete this method (old name) properly (GH-4397) + ObjectTypeDB::bind_method(_MD("_get_rotation_deg"),&Control::_get_rotation_deg); ObjectTypeDB::bind_method(_MD("get_scale"),&Control::get_scale); ObjectTypeDB::bind_method(_MD("get_custom_minimum_size"),&Control::get_custom_minimum_size); ObjectTypeDB::bind_method(_MD("get_parent_area_size"),&Control::get_size); ObjectTypeDB::bind_method(_MD("get_global_pos"),&Control::get_global_pos); ObjectTypeDB::bind_method(_MD("get_rect"),&Control::get_rect); - ObjectTypeDB::bind_method(_MD("_get_rotation_deg"),&Control::_get_rotation_deg); ObjectTypeDB::bind_method(_MD("get_global_rect"),&Control::get_global_rect); ObjectTypeDB::bind_method(_MD("set_area_as_parent_rect","margin"),&Control::set_area_as_parent_rect,DEFVAL(0)); ObjectTypeDB::bind_method(_MD("show_modal","exclusive"),&Control::show_modal,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("set_focus_mode","mode"),&Control::set_focus_mode); + ObjectTypeDB::bind_method(_MD("get_focus_mode"),&Control::get_focus_mode); ObjectTypeDB::bind_method(_MD("has_focus"),&Control::has_focus); ObjectTypeDB::bind_method(_MD("grab_focus"),&Control::grab_focus); ObjectTypeDB::bind_method(_MD("release_focus"),&Control::release_focus); @@ -2169,6 +2343,17 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_color","name","type"),&Control::get_color,DEFVAL("")); ObjectTypeDB::bind_method(_MD("get_constant","name","type"),&Control::get_constant,DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_icon_override", "name"), &Control::has_icon_override); + ObjectTypeDB::bind_method(_MD("has_stylebox_override", "name"), &Control::has_stylebox_override); + ObjectTypeDB::bind_method(_MD("has_font_override", "name"), &Control::has_font_override); + ObjectTypeDB::bind_method(_MD("has_color_override", "name"), &Control::has_color_override); + ObjectTypeDB::bind_method(_MD("has_constant_override", "name"), &Control::has_constant_override); + + ObjectTypeDB::bind_method(_MD("has_icon", "name", "type"), &Control::has_icon, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_stylebox", "name", "type"), &Control::has_stylebox, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_font", "name", "type"), &Control::has_font, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_color", "name", "type"), &Control::has_color, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_constant", "name", "type"), &Control::has_constant, DEFVAL("")); ObjectTypeDB::bind_method(_MD("get_parent_control:Control"),&Control::get_parent_control); @@ -2193,10 +2378,12 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("grab_click_focus"),&Control::grab_click_focus); + ObjectTypeDB::bind_method(_MD("set_drag_forwarding","target:Control"),&Control::set_drag_forwarding); ObjectTypeDB::bind_method(_MD("set_drag_preview","control:Control"),&Control::set_drag_preview); ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"),&Control::warp_mouse); + ObjectTypeDB::bind_method(_MD("minimum_size_changed"), &Control::minimum_size_changed); BIND_VMETHOD(MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"event"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2,"get_minimum_size")); @@ -2209,15 +2396,10 @@ void Control::_bind_methods() { ADD_PROPERTYINZ( PropertyInfo(Variant::INT,"anchor/right", PROPERTY_HINT_ENUM, "Begin,End,Ratio,Center"), _SCS("_set_anchor"),_SCS("get_anchor"), MARGIN_RIGHT ); ADD_PROPERTYINZ( PropertyInfo(Variant::INT,"anchor/bottom", PROPERTY_HINT_ENUM, "Begin,End,Ratio,Center"), _SCS("_set_anchor"),_SCS("get_anchor"), MARGIN_BOTTOM ); - ADD_PROPERTYINZ( PropertyInfo(Variant::INT,"margin/left", PROPERTY_HINT_RANGE, "-4096,4096"), _SCS("set_margin"),_SCS("get_margin"), MARGIN_LEFT ); - ADD_PROPERTYINZ( PropertyInfo(Variant::INT,"margin/top", PROPERTY_HINT_RANGE, "-4096,4096"), _SCS("set_margin"),_SCS("get_margin"), MARGIN_TOP ); - ADD_PROPERTYINZ( PropertyInfo(Variant::INT,"margin/right", PROPERTY_HINT_RANGE, "-4096,4096"), _SCS("set_margin"),_SCS("get_margin"), MARGIN_RIGHT ); - ADD_PROPERTYINZ( PropertyInfo(Variant::INT,"margin/bottom", PROPERTY_HINT_RANGE, "-4096,4096"), _SCS("set_margin"),_SCS("get_margin"), MARGIN_BOTTOM ); - ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/pos", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_pos"),_SCS("get_pos") ); ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/size", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_size"),_SCS("get_size") ); ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/min_size"), _SCS("set_custom_minimum_size"),_SCS("get_custom_minimum_size") ); - ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"rect/rotation",PROPERTY_HINT_RANGE,"-1080,1080,0.01"), _SCS("_set_rotation_deg"),_SCS("_get_rotation_deg") ); + ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"rect/rotation",PROPERTY_HINT_RANGE,"-1080,1080,0.01"), _SCS("set_rotation_deg"),_SCS("get_rotation_deg") ); ADD_PROPERTYNO( PropertyInfo(Variant::VECTOR2,"rect/scale"), _SCS("set_scale"),_SCS("get_scale") ); ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"hint/tooltip", PROPERTY_HINT_MULTILINE_TEXT), _SCS("set_tooltip"),_SCS("_get_tooltip") ); ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT ); @@ -2235,7 +2417,7 @@ void Control::_bind_methods() { BIND_CONSTANT( ANCHOR_BEGIN ); BIND_CONSTANT( ANCHOR_END ); BIND_CONSTANT( ANCHOR_RATIO ); - BIND_CONSTANT( ANCHOR_CENTER ); + BIND_CONSTANT( ANCHOR_CENTER ); BIND_CONSTANT( FOCUS_NONE ); BIND_CONSTANT( FOCUS_CLICK ); BIND_CONSTANT( FOCUS_ALL ); @@ -2305,6 +2487,7 @@ Control::Control() { data.rotation=0; data.parent_canvas_item=NULL; data.scale=Vector2(1,1); + data.drag_owner=0; for (int i=0;i<4;i++) { diff --git a/scene/gui/control.h b/scene/gui/control.h index 1e2db7a575..59704ae29b 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -35,7 +35,7 @@ #include "scene/2d/canvas_item.h" #include "math_2d.h" #include "rid.h" - +#include "scene/gui/input_action.h" /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -129,6 +129,7 @@ private: bool stop_mouse; Control *parent; + ObjectID drag_owner; bool modal; bool modal_exclusive; Ref<Theme> theme; @@ -179,7 +180,8 @@ private: void _size_changed(); String _get_tooltip() const; - void _set_rotation_deg(float p_rot); + // Deprecated, should be removed in a future version. + void _set_rotation_deg(float p_degrees); float _get_rotation_deg() const; friend class Viewport; @@ -229,6 +231,7 @@ public: virtual Size2 get_combined_minimum_size() const; virtual bool has_point(const Point2& p_point) const; virtual bool clips_input() const; + virtual void set_drag_forwarding(Control* p_target); virtual Variant get_drag_data(const Point2& p_point); virtual bool can_drop_data(const Point2& p_point,const Variant& p_data) const; virtual void drop_data(const Point2& p_point,const Variant& p_data); @@ -273,8 +276,10 @@ public: Rect2 get_global_rect() const; Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server - void set_rotation(float p_rotation); + void set_rotation(float p_radians); + void set_rotation_deg(float p_degrees); float get_rotation() const; + float get_rotation_deg() const; void set_scale(const Vector2& p_scale); Vector2 get_scale() const; @@ -336,6 +341,13 @@ public: Color get_color(const StringName& p_name,const StringName& p_type=StringName()) const; int get_constant(const StringName& p_name,const StringName& p_type=StringName()) const; + bool has_icon_override(const StringName& p_name) const; + bool has_shader_override(const StringName& p_name) const; + bool has_stylebox_override(const StringName& p_name) const; + bool has_font_override(const StringName& p_name) const; + bool has_color_override(const StringName& p_name) const; + bool has_constant_override(const StringName& p_name) const; + bool has_icon(const StringName& p_name,const StringName& p_type=StringName()) const; bool has_shader(const StringName& p_name,const StringName& p_type=StringName()) const; bool has_stylebox(const StringName& p_name,const StringName& p_type=StringName()) const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index d00dacd256..6342391383 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -118,6 +118,16 @@ void WindowDialog::set_title(const String& p_title) { update(); } +Size2 WindowDialog::get_minimum_size() const { + + Ref<Font> font = get_font("title_font","WindowDialog"); + int msx=close_button->get_combined_minimum_size().x; + msx+=font->get_string_size(title).x; + + return Size2(msx,1); +} + + String WindowDialog::get_title() const { return title; @@ -192,11 +202,9 @@ void AcceptDialog::_notification(int p_what) { if (p_what==NOTIFICATION_MODAL_CLOSE) { cancel_pressed(); - } if (p_what==NOTIFICATION_DRAW) { - - - + } if (p_what==NOTIFICATION_RESIZED) { + _update_child_rect(); } } @@ -244,12 +252,69 @@ void AcceptDialog::register_text_enter(Node *p_line_edit) { p_line_edit->connect("text_entered", this,"_builtin_text_entered"); } +void AcceptDialog::_update_child_rect() { + + int margin = get_constant("margin","Dialogs"); + Size2 size = get_size(); + Size2 hminsize = hbc->get_combined_minimum_size(); + + Vector2 cpos(margin,margin); + Vector2 csize(size.x-margin*2,size.y-margin*3-hminsize.y); + label->set_pos(cpos); + label->set_size(csize); + + if (child) { + + child->set_pos(cpos); + child->set_size(csize); + } + + cpos.y+=csize.y+margin; + csize.y=hminsize.y; + + hbc->set_pos(cpos); + hbc->set_size(csize); + +} + +Size2 AcceptDialog::get_minimum_size() const { + + int margin = get_constant("margin","Dialogs"); + Size2 minsize = label->get_combined_minimum_size(); + if (child) { + + Size2 cminsize = child->get_combined_minimum_size(); + minsize.x=MAX(cminsize.x,minsize.x); + minsize.y=MAX(cminsize.y,minsize.y); + } + + Size2 hminsize = hbc->get_combined_minimum_size(); + minsize.x = MAX(hminsize.x,minsize.x); + minsize.y+=hminsize.y; + minsize.x+=margin*2; + minsize.y+=margin*3; //one as separation between hbc and child + + Size2 wmsize = WindowDialog::get_minimum_size(); + minsize.x=MAX(wmsize.x,minsize.x); + return minsize; +} + + void AcceptDialog::set_child_rect(Control *p_child) { ERR_FAIL_COND(p_child->get_parent()!=this); - p_child->set_area_as_parent_rect(get_constant("margin","Dialogs")); - p_child->set_margin(MARGIN_BOTTOM, get_constant("button_margin","Dialogs")+10); + //p_child->set_area_as_parent_rect(get_constant("margin","Dialogs")); + child=p_child; + minimum_size_changed(); + _update_child_rect(); +} + +void AcceptDialog::remove_child_notify(Node *p_child) { + + if (p_child==child) { + child=NULL; + } } void AcceptDialog::_custom_action(const String& p_action) { @@ -284,8 +349,8 @@ Button* AcceptDialog::add_cancel(const String &p_cancel) { String c = p_cancel; if (p_cancel=="") - c="Cancel"; - Button *b = swap_ok_cancel ? add_button("Cancel",true) : add_button("Cancel"); + c=RTR("Cancel"); + Button *b = swap_ok_cancel ? add_button(c,true) : add_button(c); b->connect("pressed",this,"_closed"); return b; } @@ -341,7 +406,7 @@ AcceptDialog::AcceptDialog() { hbc->add_spacer(); ok = memnew( Button ); - ok->set_text("OK"); + ok->set_text(RTR("OK")); hbc->add_child(ok); hbc->add_spacer(); //add_child(ok); @@ -351,7 +416,9 @@ AcceptDialog::AcceptDialog() { set_as_toplevel(true); hide_on_ok=true; - set_title("Alert!"); + set_title(RTR("Alert!")); + + child=NULL; } @@ -372,6 +439,6 @@ Button *ConfirmationDialog::get_cancel() { ConfirmationDialog::ConfirmationDialog() { - set_title("Please Confirm..."); + set_title(RTR("Please Confirm...")); cancel = add_cancel(); } diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index f256c49aee..d00bb41ff6 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -64,6 +64,8 @@ public: void set_title(const String& p_title); String get_title() const; + Size2 get_minimum_size() const; + WindowDialog(); ~WindowDialog(); @@ -89,6 +91,7 @@ class AcceptDialog : public WindowDialog { OBJ_TYPE(AcceptDialog,WindowDialog); + Control *child; HBoxContainer *hbc; Label *label; Button *ok; @@ -100,10 +103,12 @@ class AcceptDialog : public WindowDialog { void _ok_pressed(); void _close_pressed(); void _builtin_text_entered(const String& p_text); + void _update_child_rect(); static bool swap_ok_cancel; + virtual void remove_child_notify(Node *p_child); protected: @@ -116,6 +121,8 @@ protected: virtual void custom_action(const String&) {} public: + Size2 get_minimum_size() const; + Label *get_label() { return label; } static void set_swap_ok_cancel(bool p_swap); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 64fdfdfefe..705ce55d42 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -613,7 +613,6 @@ FileDialog::Access FileDialog::get_access() const{ void FileDialog::_make_dir_confirm() { - Error err = dir_access->make_dir( makedirname->get_text() ); if (err==OK) { dir_access->change_dir(makedirname->get_text()); @@ -623,6 +622,7 @@ void FileDialog::_make_dir_confirm() { } else { mkdirerr->popup_centered_minsize(Size2(250,50)); } + makedirname->set_text(""); // reset label } diff --git a/scene/gui/input_action.cpp b/scene/gui/input_action.cpp new file mode 100644 index 0000000000..c4e7a75298 --- /dev/null +++ b/scene/gui/input_action.cpp @@ -0,0 +1,125 @@ +#include "input_action.h" +#include "os/keyboard.h" + +void ShortCut::set_shortcut(const InputEvent& p_shortcut){ + + shortcut=p_shortcut; + emit_changed(); +} + +InputEvent ShortCut::get_shortcut() const{ + + return shortcut; +} + +bool ShortCut::is_shortcut(const InputEvent& p_event) const { + + bool same=false; + + + switch(p_event.type) { + + case InputEvent::KEY: { + + same=(shortcut.key.scancode==p_event.key.scancode && shortcut.key.mod == p_event.key.mod); + + } break; + case InputEvent::JOYSTICK_BUTTON: { + + same=(shortcut.joy_button.button_index==p_event.joy_button.button_index); + + } break; + case InputEvent::MOUSE_BUTTON: { + + same=(shortcut.mouse_button.button_index==p_event.mouse_button.button_index); + + } break; + case InputEvent::JOYSTICK_MOTION: { + + same=(shortcut.joy_motion.axis==p_event.joy_motion.axis && (shortcut.joy_motion.axis_value < 0) == (p_event.joy_motion.axis_value < 0)); + + } break; + default: {}; + } + + return same; +} + +String ShortCut::get_as_text() const { + + switch(shortcut.type) { + + case InputEvent::NONE: { + + return "None"; + } break; + case InputEvent::KEY: { + + String str; + if (shortcut.key.mod.shift) + str+=RTR("Shift+"); + if (shortcut.key.mod.alt) + str+=RTR("Alt+"); + if (shortcut.key.mod.control) + str+=RTR("Ctrl+"); + if (shortcut.key.mod.meta) + str+=RTR("Meta+"); + + str+=keycode_get_string(shortcut.key.scancode).capitalize(); + + return str; + } break; + case InputEvent::JOYSTICK_BUTTON: { + + String str = RTR("Device")+" "+itos(shortcut.device)+", "+RTR("Button")+" "+itos(shortcut.joy_button.button_index); + str+="."; + + return str; + } break; + case InputEvent::MOUSE_BUTTON: { + + String str = RTR("Device")+" "+itos(shortcut.device)+", "; + switch (shortcut.mouse_button.button_index) { + case BUTTON_LEFT: str+=RTR("Left Button."); break; + case BUTTON_RIGHT: str+=RTR("Right Button."); break; + case BUTTON_MIDDLE: str+=RTR("Middle Button."); break; + case BUTTON_WHEEL_UP: str+=RTR("Wheel Up."); break; + case BUTTON_WHEEL_DOWN: str+=RTR("Wheel Down."); break; + default: str+=RTR("Button")+" "+itos(shortcut.mouse_button.button_index)+"."; + } + + return str; + } break; + case InputEvent::JOYSTICK_MOTION: { + + int ax = shortcut.joy_motion.axis; + String str = RTR("Device")+" "+itos(shortcut.device)+", "+RTR("Axis")+" "+itos(ax)+"."; + + return str; + } break; + } + + return ""; +} + +bool ShortCut::is_valid() const { + + return shortcut.type!=InputEvent::NONE; +} + +void ShortCut::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_shortcut","event"),&ShortCut::set_shortcut); + ObjectTypeDB::bind_method(_MD("get_shortcut"),&ShortCut::get_shortcut); + + ObjectTypeDB::bind_method(_MD("is_valid"),&ShortCut::is_valid); + + ObjectTypeDB::bind_method(_MD("is_shortcut","event"),&ShortCut::is_shortcut); + ObjectTypeDB::bind_method(_MD("get_as_text"),&ShortCut::get_as_text); + + ADD_PROPERTY(PropertyInfo(Variant::INPUT_EVENT,"shortcut"),_SCS("set_shortcut"),_SCS("get_shortcut")); +} + +ShortCut::ShortCut(){ + +} diff --git a/scene/gui/input_action.h b/scene/gui/input_action.h new file mode 100644 index 0000000000..8e0e1ef0bd --- /dev/null +++ b/scene/gui/input_action.h @@ -0,0 +1,26 @@ +#ifndef INPUTACTION_H +#define INPUTACTION_H + +#include "resource.h" + +class ShortCut : public Resource { + + OBJ_TYPE(ShortCut,Resource); + + InputEvent shortcut; +protected: + + static void _bind_methods(); +public: + + void set_shortcut(const InputEvent& p_shortcut); + InputEvent get_shortcut() const; + bool is_shortcut(const InputEvent& p_Event) const; + bool is_valid() const; + + String get_as_text() const; + + ShortCut(); +}; + +#endif // INPUTACTION_H diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 171dd94bfa..fc4ab5f8ca 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -297,6 +297,7 @@ void ItemList::remove_item(int p_idx){ items.remove(p_idx); update(); shape_changed=true; + defer_select_single=-1; } @@ -307,6 +308,7 @@ void ItemList::clear(){ current=-1; ensure_selected_visible=false; update(); + defer_select_single=-1; } @@ -323,6 +325,18 @@ int ItemList::get_fixed_column_width() const{ return fixed_column_width; } +void ItemList::set_same_column_width(bool p_enable){ + + same_column_width=p_enable; + update(); + shape_changed=true; + +} +int ItemList::is_same_column_width() const{ + + return same_column_width; +} + void ItemList::set_max_text_lines(int p_lines){ ERR_FAIL_COND(p_lines<1); @@ -381,6 +395,17 @@ Size2 ItemList::get_min_icon_size() const { return min_icon_size; } + +void ItemList::set_max_icon_size(const Size2& p_size) { + + max_icon_size=p_size; + update(); +} + +Size2 ItemList::get_max_icon_size() const { + + return max_icon_size; +} Size2 ItemList::Item::get_icon_size() const { if (icon.is_null()) @@ -392,7 +417,23 @@ Size2 ItemList::Item::get_icon_size() const { } void ItemList::_input_event(const InputEvent& p_event) { - if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_LEFT && p_event.mouse_button.pressed) { + + if (defer_select_single>=0 && p_event.type==InputEvent::MOUSE_MOTION) { + defer_select_single=-1; + return; + } + + if (defer_select_single>=0 && p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_LEFT && !p_event.mouse_button.pressed) { + + select(defer_select_single,true); + + + emit_signal("multi_selected",defer_select_single,true); + defer_select_single=-1; + return; + } + + if (p_event.type==InputEvent::MOUSE_BUTTON && (p_event.mouse_button.button_index==BUTTON_LEFT || (allow_rmb_select && p_event.mouse_button.button_index==BUTTON_RIGHT)) && p_event.mouse_button.pressed) { const InputEventMouseButton &mb = p_event.mouse_button; @@ -431,6 +472,7 @@ void ItemList::_input_event(const InputEvent& p_event) { if (select_mode==SELECT_MULTI && items[i].selected && mb.mod.command) { unselect(i); emit_signal("multi_selected",i,false); + } else if (select_mode==SELECT_MULTI && mb.mod.shift && current>=0 && current<items.size() && current!=i) { int from = current; @@ -444,23 +486,45 @@ void ItemList::_input_event(const InputEvent& p_event) { if (selected) emit_signal("multi_selected",i,true); } + + if (p_event.mouse_button.button_index==BUTTON_RIGHT) { + + emit_signal("item_rmb_selected",i,Vector2(mb.x,mb.y)); + } } else { - bool selected = !items[i].selected; - select(i,select_mode==SELECT_SINGLE || !mb.mod.command); - if (selected) { - if (select_mode==SELECT_SINGLE) { - emit_signal("item_selected",i); - } else - emit_signal("multi_selected",i,true); + + if (!mb.doubleclick && !mb.mod.command && select_mode==SELECT_MULTI && items[i].selectable && items[i].selected && p_event.mouse_button.button_index==BUTTON_LEFT) { + defer_select_single=i; + return; } - if (/*select_mode==SELECT_SINGLE &&*/ mb.doubleclick) { + if (items[i].selected && p_event.mouse_button.button_index==BUTTON_RIGHT) { - emit_signal("item_activated",i); + emit_signal("item_rmb_selected",i,Vector2(mb.x,mb.y)); + } else { + bool selected = !items[i].selected; + + + select(i,select_mode==SELECT_SINGLE || !mb.mod.command); + + if (selected) { + if (select_mode==SELECT_SINGLE) { + emit_signal("item_selected",i); + } else + emit_signal("multi_selected",i,true); - } + } + if (p_event.mouse_button.button_index==BUTTON_RIGHT) { + + emit_signal("item_rmb_selected",i,Vector2(mb.x,mb.y)); + } else if (/*select_mode==SELECT_SINGLE &&*/ mb.doubleclick) { + + emit_signal("item_activated",i); + + } + } } @@ -668,6 +732,55 @@ void ItemList::ensure_current_is_visible() { update(); } +static Size2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) { + + if (p_max_size.x<=0) + p_max_size.x=1e20; + if (p_max_size.y<=0) + p_max_size.y=1e20; + + + Size2 new_size; + + if (p_size.x > p_max_size.x) { + + new_size.width=p_max_size.x; + new_size.height=p_size.height * p_max_size.width / p_size.width; + + if (new_size.height > p_max_size.height) { + new_size=Size2(); //invalid + } + } + + + if (p_size.y > p_max_size.y) { + + Size2 new_size2; + new_size2.height=p_max_size.y; + new_size2.width=p_size.width * p_max_size.height / p_size.height; + + if (new_size2.width < p_max_size.width) { + + if (new_size!=Size2()) { + + if (new_size2.x*new_size2.y > new_size.x*new_size.y) { + new_size=new_size2; + } + } else { + new_size=new_size2; + } + } + + } + + if (new_size==Size2()) + return p_size; + else + return new_size; + + +} + void ItemList::_notification(int p_what) { if (p_what==NOTIFICATION_RESIZED) { @@ -723,6 +836,8 @@ void ItemList::_notification(int p_what) { } if (shape_changed) { + + float max_column_width = 0; //1- compute item minimum sizes for(int i=0;i<items.size();i++) { @@ -730,12 +845,7 @@ void ItemList::_notification(int p_what) { Size2 minsize; if (items[i].icon.is_valid()) { - minsize=items[i].get_icon_size(); - - if (min_icon_size.x!=0) - minsize.x = MAX(minsize.x,min_icon_size.x); - if (min_icon_size.y!=0) - minsize.y = MAX(minsize.y,min_icon_size.y); + minsize=_adjust_to_max_size(items[i].get_icon_size(),max_icon_size) * icon_scale; if (items[i].text!="") { if (icon_mode==ICON_MODE_TOP) { @@ -768,10 +878,11 @@ void ItemList::_notification(int p_what) { } - - items[i].rect_cache.size=minsize; if (fixed_column_width>0) - items[i].rect_cache.size.x=fixed_column_width; + minsize.x=fixed_column_width; + max_column_width=MAX(max_column_width,minsize.x); + items[i].rect_cache.size=minsize; + items[i].min_rect_cache.size=minsize; } @@ -800,17 +911,23 @@ void ItemList::_notification(int p_what) { break; } + items[i].rect_cache=items[i].min_rect_cache; + if(same_column_width) + items[i].rect_cache.size.x=max_column_width; items[i].rect_cache.pos=ofs; max_h=MAX(max_h,items[i].rect_cache.size.y); - ofs.x+=items[i].rect_cache.size.x; + ofs.x+=items[i].rect_cache.size.x + hseparation; //print_line("item "+itos(i)+" ofs "+rtos(items[i].rect_cache.size.x)); - if (col>0) - ofs.x+=hseparation; col++; if (col==current_columns) { 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; @@ -818,6 +935,10 @@ void ItemList::_notification(int p_what) { } } + for(int j=items.size()-1;j>=0 && col>0;j--, col--) { + items[j].rect_cache.size.y = max_h; + } + if (all_fit) { float max = MAX(page,ofs.y+max_h); scroll_bar->set_max(max); @@ -880,7 +1001,7 @@ void ItemList::_notification(int p_what) { Vector2 text_ofs; if (items[i].icon.is_valid()) { - Size2 icon_size = items[i].get_icon_size(); + Size2 icon_size = _adjust_to_max_size(items[i].get_icon_size(),max_icon_size) * icon_scale; Vector2 icon_ofs; if (min_icon_size!=Vector2()) { @@ -892,7 +1013,12 @@ void ItemList::_notification(int p_what) { if (icon_mode==ICON_MODE_TOP) { pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width)/2); + pos.y += MIN( + Math::floor((items[i].rect_cache.size.height - icon_size.height)/2), + items[i].rect_cache.size.height - items[i].min_rect_cache.size.height + ); text_ofs.y = MAX(icon_size.height, min_icon_size.y) + icon_margin; + text_ofs.y += items[i].rect_cache.size.height - items[i].min_rect_cache.size.height; } else { pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height)/2); @@ -900,7 +1026,7 @@ void ItemList::_notification(int p_what) { } if (items[i].icon_region.has_no_area()) - draw_texture(items[i].icon, pos); + draw_texture_rect(items[i].icon, Rect2(pos,icon_size) ); else draw_texture_rect_region(items[i].icon, Rect2(pos, icon_size), items[i].icon_region); @@ -918,6 +1044,8 @@ void ItemList::_notification(int p_what) { Vector2 size = font->get_string_size(items[i].text); if (fixed_column_width) max_len=fixed_column_width; + else if(same_column_width) + max_len=items[i].rect_cache.size.x; else max_len=size.x; @@ -1022,8 +1150,7 @@ void ItemList::_scroll_changed(double) { update(); } - -String ItemList::get_tooltip(const Point2& p_pos) const { +int ItemList::get_item_at_pos(const Point2& p_pos, bool p_exact) const { Vector2 pos=p_pos; Ref<StyleBox> bg = get_stylebox("bg"); @@ -1046,12 +1173,19 @@ String ItemList::get_tooltip(const Point2& p_pos) const { } float dist = rc.distance_to(pos); - if (dist<closest_dist) { + if (!p_exact && dist<closest_dist) { closest=i; closest_dist=dist; } } + return closest; +} + +String ItemList::get_tooltip(const Point2& p_pos) const { + + int closest = get_item_at_pos(p_pos); + if (closest!=-1) { if (items[closest].tooltip!="") { return items[closest].tooltip; @@ -1062,8 +1196,6 @@ String ItemList::get_tooltip(const Point2& p_pos) const { } return Control::get_tooltip(p_pos); - - } void ItemList::sort_items_by_text() { @@ -1091,9 +1223,27 @@ int ItemList::find_metadata(const Variant& p_metadata) const { } + +void ItemList::set_allow_rmb_select(bool p_allow) { + allow_rmb_select=p_allow; +} + +bool ItemList::get_allow_rmb_select() const { + + return allow_rmb_select; +} + +void ItemList::set_icon_scale(real_t p_scale) { + icon_scale = p_scale; +} + +real_t ItemList::get_icon_scale() const { + return icon_scale; +} + void ItemList::_bind_methods(){ - ObjectTypeDB::bind_method(_MD("add_item","text","icon:Texture","selectable"),&ItemList::add_item,DEFVAL(Ref<Texture>()),DEFVAL(true)); + ObjectTypeDB::bind_method(_MD("add_item","text","icon:Texture","selectable"),&ItemList::add_item,DEFVAL(Variant()),DEFVAL(true)); ObjectTypeDB::bind_method(_MD("add_icon_item","icon:Texture","selectable"),&ItemList::add_icon_item,DEFVAL(true)); ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&ItemList::set_item_text); @@ -1133,6 +1283,9 @@ void ItemList::_bind_methods(){ 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); + ObjectTypeDB::bind_method(_MD("set_same_column_width","enable"),&ItemList::set_same_column_width); + ObjectTypeDB::bind_method(_MD("is_same_column_width"),&ItemList::is_same_column_width); + ObjectTypeDB::bind_method(_MD("set_max_text_lines","lines"),&ItemList::set_max_text_lines); ObjectTypeDB::bind_method(_MD("get_max_text_lines"),&ItemList::get_max_text_lines); @@ -1148,6 +1301,17 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_min_icon_size","size"),&ItemList::set_min_icon_size); ObjectTypeDB::bind_method(_MD("get_min_icon_size"),&ItemList::get_min_icon_size); + ObjectTypeDB::bind_method(_MD("set_max_icon_size","size"),&ItemList::set_max_icon_size); + ObjectTypeDB::bind_method(_MD("get_max_icon_size"),&ItemList::get_max_icon_size); + + ObjectTypeDB::bind_method(_MD("set_icon_scale","scale"),&ItemList::set_icon_scale); + ObjectTypeDB::bind_method(_MD("get_icon_scale"),&ItemList::get_icon_scale); + + ObjectTypeDB::bind_method(_MD("set_allow_rmb_select","allow"),&ItemList::set_allow_rmb_select); + ObjectTypeDB::bind_method(_MD("get_allow_rmb_select"),&ItemList::get_allow_rmb_select); + + ObjectTypeDB::bind_method(_MD("get_item_at_pos","pos","exact"),&ItemList::get_item_at_pos,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("ensure_current_is_visible"),&ItemList::ensure_current_is_visible); ObjectTypeDB::bind_method(_MD("_scroll_changed"),&ItemList::_scroll_changed); @@ -1159,6 +1323,7 @@ void ItemList::_bind_methods(){ BIND_CONSTANT( SELECT_MULTI ); ADD_SIGNAL( MethodInfo("item_selected",PropertyInfo(Variant::INT,"index"))); + ADD_SIGNAL( MethodInfo("item_rmb_selected",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::VECTOR2,"atpos"))); ADD_SIGNAL( MethodInfo("multi_selected",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::BOOL,"selected"))); ADD_SIGNAL( MethodInfo("item_activated",PropertyInfo(Variant::INT,"index"))); } @@ -1173,6 +1338,7 @@ ItemList::ItemList() { icon_mode=ICON_MODE_LEFT; fixed_column_width=0; + same_column_width = false; max_text_lines=1; max_columns=1; @@ -1186,7 +1352,10 @@ ItemList::ItemList() { current_columns=1; search_time_msec=0; ensure_selected_visible=false; + defer_select_single=-1; + allow_rmb_select=false; + icon_scale = 1.0f; } ItemList::~ItemList() { diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index c9c575fd54..087c585128 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -33,6 +33,7 @@ private: Color custom_bg; Rect2 rect_cache; + Rect2 min_rect_cache; Size2 get_icon_size() const; @@ -44,6 +45,7 @@ private: bool shape_changed; bool ensure_selected_visible; + bool same_column_width; Vector<Item> items; Vector<int> separators; @@ -59,7 +61,17 @@ private: int fixed_column_width; int max_text_lines; int max_columns; + Size2 min_icon_size; + Size2 max_icon_size; + + Size2 max_item_size_cache; + + int defer_select_single; + + bool allow_rmb_select; + + real_t icon_scale; void _scroll_changed(double); void _input_event(const InputEvent& p_event); @@ -69,6 +81,7 @@ protected: static void _bind_methods(); public: + void add_item(const String& p_item,const Ref<Texture>& p_texture=Ref<Texture>(),bool p_selectable=true); void add_icon_item(const Ref<Texture>& p_item,bool p_selectable=true); @@ -116,6 +129,9 @@ public: void set_fixed_column_width(int p_size); int get_fixed_column_width() const; + void set_same_column_width(bool p_enable); + int is_same_column_width() const; + void set_max_text_lines(int p_amount); int get_max_text_lines() const; @@ -131,12 +147,22 @@ public: void set_min_icon_size(const Size2& p_size); Size2 get_min_icon_size() const; + void set_max_icon_size(const Size2& p_size); + Size2 get_max_icon_size() const; + + void set_allow_rmb_select(bool p_allow); + bool get_allow_rmb_select() const; + void ensure_current_is_visible(); void sort_items_by_text(); int find_metadata(const Variant& p_metadata) const; virtual String get_tooltip(const Point2& p_pos) const; + int get_item_at_pos(const Point2& p_pos,bool p_exact=false) const; + + void set_icon_scale(real_t p_scale); + real_t get_icon_scale() const; ItemList(); ~ItemList(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index e8097c79a4..09c6a77b42 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -87,10 +87,11 @@ void Label::_notification(int p_what) { Color font_color_shadow = get_color("font_color_shadow"); bool use_outlinde = get_constant("shadow_as_outline"); Point2 shadow_ofs(get_constant("shadow_offset_x"),get_constant("shadow_offset_y")); + int line_spacing = get_constant("line_spacing"); VisualServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(),font.is_valid() && font->is_distance_field_hint()); - int font_h = font->get_height(); + int font_h = font->get_height()+line_spacing; int lines_visible = size.y/font_h; int space_w=font->get_char_size(' ').width; int chars_total=0; @@ -372,6 +373,7 @@ void Label::regenerate_word_cache() { int line_width=0; int space_count=0; int space_width=font->get_char_size(' ').width; + int line_spacing = get_constant("line_spacing"); line_count=1; total_char_cache=0; @@ -486,9 +488,9 @@ void Label::regenerate_word_cache() { if (!autowrap) { minsize.width=width; if (max_lines_visible > 0 && line_count > max_lines_visible) { - minsize.height=font->get_height()*max_lines_visible; + minsize.height=(font->get_height()+line_spacing)*max_lines_visible; } else { - minsize.height=font->get_height()*line_count; + minsize.height=(font->get_height()+line_spacing)*line_count; } } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 21dee62b38..44cc798447 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -41,7 +41,15 @@ void LineEdit::_input_event(InputEvent p_event) { const InputEventMouseButton &b = p_event.mouse_button; - if (b.button_index!=1) + if (b.pressed && b.button_index==BUTTON_RIGHT) { + menu->set_pos(get_global_transform().xform(get_local_mouse_pos())); + menu->set_size(Vector2(1,1)); + menu->popup(); + grab_focus(); + return; + } + + if (b.button_index!=BUTTON_LEFT) break; if (b.pressed) { @@ -143,24 +151,10 @@ void LineEdit::_input_event(InputEvent p_event) { if( k.mod.command && editable) { - int old_cursor_pos = cursor_pos; - text = undo_text; - - Ref<Font> font = get_font("font"); - - cached_width = 0; - for (int i = 0; i<text.length(); i++) - cached_width += font->get_char_size(text[i]).width; + undo(); - if(old_cursor_pos > text.length()) { - set_cursor_pos(text.length()); - } else { - set_cursor_pos(old_cursor_pos); - } } - emit_signal("text_changed",text); - _change_notify("text"); } break; @@ -460,7 +454,7 @@ void LineEdit::_notification(int p_what) { } break; } - int ofs_max=width-style->get_minimum_size().width; + int ofs_max=width-style->get_minimum_size().width+x_ofs; int char_ofs=window_pos; int y_area=height-style->get_minimum_size().height; @@ -559,6 +553,28 @@ void LineEdit::paste_text() { } +void LineEdit::undo() { + + int old_cursor_pos = cursor_pos; + text = undo_text; + + Ref<Font> font = get_font("font"); + + cached_width = 0; + for (int i = 0; i<text.length(); i++) + cached_width += font->get_char_size(text[i]).width; + + if(old_cursor_pos > text.length()) { + set_cursor_pos(text.length()); + } else { + set_cursor_pos(old_cursor_pos); + } + + emit_signal("text_changed",text); + _change_notify("text"); + +} + void LineEdit::shift_selection_check_pre(bool p_shift) { if (!selection.old_shift && p_shift) { @@ -669,6 +685,8 @@ void LineEdit::set_text(String p_text) { void LineEdit::clear() { clear_internal(); + emit_signal("text_changed",text); + _change_notify("text"); } String LineEdit::get_text() const { @@ -781,8 +799,7 @@ Size2 LineEdit::get_minimum_size() const { Ref<Font> font=get_font("font"); Size2 min=style->get_minimum_size(); - min.height+=font->get_height(); - min.width+=get_constant("minimum_spaces")*font->get_char_size(' ').x; + min+=font->get_string_size(this->text); return min; } @@ -932,6 +949,39 @@ bool LineEdit::is_text_field() const { return true; } +void LineEdit::menu_option(int p_option) { + + switch(p_option) { + case MENU_CUT: { + cut_text(); + } break; + case MENU_COPY: { + + copy_text(); + } break; + case MENU_PASTE: { + + paste_text(); + } break; + case MENU_CLEAR: { + clear(); + } break; + case MENU_SELECT_ALL: { + select_all(); + } break; + case MENU_UNDO: { + + undo(); + } break; + + } + +} + +PopupMenu *LineEdit::get_menu() const { + return menu; +} + void LineEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_align", "align"), &LineEdit::set_align); @@ -952,6 +1002,8 @@ void LineEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_secret","enabled"),&LineEdit::set_secret); ObjectTypeDB::bind_method(_MD("is_secret"),&LineEdit::is_secret); ObjectTypeDB::bind_method(_MD("select","from","to"),&LineEdit::select,DEFVAL(0),DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("menu_option","option"),&LineEdit::menu_option); + ObjectTypeDB::bind_method(_MD("get_menu:PopupMenu"),&LineEdit::get_menu); ADD_SIGNAL( MethodInfo("text_changed", PropertyInfo( Variant::STRING, "text" )) ); ADD_SIGNAL( MethodInfo("text_entered", PropertyInfo( Variant::STRING, "text" )) ); @@ -961,11 +1013,21 @@ void LineEdit::_bind_methods() { BIND_CONSTANT(ALIGN_RIGHT); BIND_CONSTANT(ALIGN_FILL); - ADD_PROPERTY( PropertyInfo( Variant::STRING, "text" ), _SCS("set_text"),_SCS("get_text") ); + BIND_CONSTANT( MENU_CUT ); + BIND_CONSTANT( MENU_COPY ); + BIND_CONSTANT( MENU_PASTE ); + BIND_CONSTANT( MENU_CLEAR ); + BIND_CONSTANT( MENU_SELECT_ALL ); + BIND_CONSTANT( MENU_UNDO ); + BIND_CONSTANT( MENU_MAX ); + + ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text" ), _SCS("set_text"),_SCS("get_text") ); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), _SCS("set_align"), _SCS("get_align")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") ); + 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_PROPERTY( PropertyInfo( Variant::INT,"focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_focus_mode"), _SCS("get_focus_mode") ); + } LineEdit::LineEdit() { @@ -984,6 +1046,20 @@ LineEdit::LineEdit() { set_stop_mouse(true); + menu = memnew( PopupMenu ); + add_child(menu); + menu->add_item(TTR("Cut"),MENU_CUT,KEY_MASK_CMD|KEY_X); + menu->add_item(TTR("Copy"),MENU_COPY,KEY_MASK_CMD|KEY_C); + menu->add_item(TTR("Paste"),MENU_PASTE,KEY_MASK_CMD|KEY_V); + menu->add_separator(); + menu->add_item(TTR("Select All"),MENU_SELECT_ALL,KEY_MASK_CMD|KEY_A); + menu->add_item(TTR("Clear"),MENU_CLEAR); + menu->add_separator(); + menu->add_item(TTR("Undo"),MENU_UNDO,KEY_MASK_CMD|KEY_Z); + menu->connect("item_pressed",this,"menu_option"); + + + } LineEdit::~LineEdit() { diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 207c6b115b..586a54e950 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -30,6 +30,8 @@ #define LINE_EDIT_H #include "scene/gui/control.h" +#include "scene/gui/popup_menu.h" + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -45,6 +47,18 @@ public: ALIGN_RIGHT, ALIGN_FILL }; + + enum MenuItems { + MENU_CUT, + MENU_COPY, + MENU_PASTE, + MENU_CLEAR, + MENU_SELECT_ALL, + MENU_UNDO, + MENU_MAX + + }; + private: Align align; @@ -54,6 +68,8 @@ private: String undo_text; String text; + PopupMenu *menu; + int cursor_pos; int window_pos; int max_length; // 0 for no maximum @@ -85,14 +101,12 @@ private: void clear_internal(); void changed_internal(); - void copy_text(); - void cut_text(); - void paste_text(); void _input_event(InputEvent p_event); void _notification(int p_what); + protected: static void _bind_methods(); public: @@ -103,6 +117,8 @@ public: virtual bool can_drop_data(const Point2& p_point,const Variant& p_data) const; virtual void drop_data(const Point2& p_point,const Variant& p_data); + void menu_option(int p_option); + PopupMenu *get_menu() const; void select_all(); @@ -116,6 +132,10 @@ public: void append_at_cursor(String p_text); void clear(); + void copy_text(); + void cut_text(); + void paste_text(); + void undo(); void set_editable(bool p_editable); bool is_editable() const; @@ -127,7 +147,7 @@ public: virtual Size2 get_minimum_size() const; - virtual bool is_text_field() const; + virtual bool is_text_field() const; LineEdit(); ~LineEdit(); diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 007d0a709e..065423ae2d 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -119,6 +119,6 @@ void LinkButton::_bind_methods() { LinkButton::LinkButton() { underline_mode=UNDERLINE_MODE_ALWAYS; - set_focus_mode(FOCUS_NONE); + set_enabled_focus_mode(FOCUS_NONE); set_default_cursor_shape(CURSOR_POINTING_HAND); } diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index fde5df6b72..5f798f445c 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -31,7 +31,10 @@ Size2 MarginContainer::get_minimum_size() const { - int margin = get_constant("margin"); + int margin_left = get_constant("margin_left"); + int margin_top = get_constant("margin_top"); + int margin_right = get_constant("margin_right"); + int margin_bottom = get_constant("margin_bottom"); Size2 max; @@ -52,9 +55,10 @@ Size2 MarginContainer::get_minimum_size() const { max.height = s.height; } - max.width += margin; - return max; + max.width += (margin_left + margin_right); + max.height += (margin_top + margin_bottom); + return max; } @@ -62,7 +66,10 @@ void MarginContainer::_notification(int p_what) { if (p_what==NOTIFICATION_SORT_CHILDREN) { - int margin = get_constant("margin"); + int margin_left = get_constant("margin_left"); + int margin_top = get_constant("margin_top"); + int margin_right = get_constant("margin_right"); + int margin_bottom = get_constant("margin_bottom"); Size2 s = get_size(); @@ -73,13 +80,10 @@ void MarginContainer::_notification(int p_what) { continue; if (c->is_set_as_toplevel()) continue; - int w; - if (c->get_h_size_flags() & Control::SIZE_EXPAND) - w=s.width-margin; - else - w=c->get_combined_minimum_size().width; - fit_child_in_rect(c,Rect2(margin,0,s.width-margin,s.height)); + int w=s.width-margin_left-margin_right; + int h=s.height-margin_top-margin_bottom; + fit_child_in_rect(c,Rect2(margin_left,margin_top,w,h)); } } diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index cb8806e2ef..28d67287d5 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -32,46 +32,15 @@ void MenuButton::_unhandled_key_input(InputEvent p_event) { - //check accelerators - if (p_event.type==InputEvent::KEY && p_event.key.pressed) { + if (p_event.is_pressed() && !p_event.is_echo() && (p_event.type==InputEvent::KEY || p_event.type==InputEvent::ACTION || p_event.type==InputEvent::JOYSTICK_BUTTON)) { if (!get_parent() || !is_visible() || is_disabled()) return; - uint32_t code=p_event.key.scancode; - if (code==0) - code=p_event.key.unicode; - if (p_event.key.mod.control) - code|=KEY_MASK_CTRL; - if (p_event.key.mod.alt) - code|=KEY_MASK_ALT; - if (p_event.key.mod.meta) - code|=KEY_MASK_META; - if (p_event.key.mod.shift) - code|=KEY_MASK_SHIFT; - - - int item = popup->find_item_by_accelerator(code); - - - if (item>=0 && ! popup->is_item_disabled(item)) - popup->activate_item(item); - /* - for(int i=0;i<items.size();i++) { - - - if (items[i].accel==0) - continue; - - if (items[i].accel==code) { - - emit_signal("item_pressed",items[i].ID); - } - }*/ + int item = popup->activate_item_by_event(p_event); } - } @@ -139,7 +108,7 @@ MenuButton::MenuButton() { set_flat(true); - set_focus_mode(FOCUS_NONE); + set_enabled_focus_mode(FOCUS_NONE); popup = memnew( PopupMenu ); popup->hide(); add_child(popup); diff --git a/scene/gui/patch_9_frame.cpp b/scene/gui/patch_9_frame.cpp index b6e261714c..3ecee7328b 100644 --- a/scene/gui/patch_9_frame.cpp +++ b/scene/gui/patch_9_frame.cpp @@ -9,10 +9,9 @@ void Patch9Frame::_notification(int p_what) { if (texture.is_null()) return; - Size2 s=get_size(); RID ci = get_canvas_item(); - VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate); + VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),region_rect,texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate); // draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); /* @@ -47,12 +46,15 @@ void Patch9Frame::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_modulate"), & Patch9Frame::get_modulate ); ObjectTypeDB::bind_method(_MD("set_patch_margin","margin","value"), & Patch9Frame::set_patch_margin ); ObjectTypeDB::bind_method(_MD("get_patch_margin","margin"), & Patch9Frame::get_patch_margin ); + ObjectTypeDB::bind_method(_MD("set_region_rect","rect"),&Patch9Frame::set_region_rect); + ObjectTypeDB::bind_method(_MD("get_region_rect"),&Patch9Frame::get_region_rect); ObjectTypeDB::bind_method(_MD("set_draw_center","draw_center"), & Patch9Frame::set_draw_center ); ObjectTypeDB::bind_method(_MD("get_draw_center"), & Patch9Frame::get_draw_center ); ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "draw_center"), _SCS("set_draw_center"),_SCS("get_draw_center") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/left",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_LEFT ); ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/top",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_TOP ); ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/right",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_RIGHT ); @@ -93,6 +95,20 @@ void Patch9Frame::set_patch_margin(Margin p_margin,int p_size) { margin[p_margin]=p_size; update(); minimum_size_changed(); + switch (p_margin) { + case MARGIN_LEFT: + _change_notify("patch_margin/left"); + break; + case MARGIN_TOP: + _change_notify("patch_margin/top"); + break; + case MARGIN_RIGHT: + _change_notify("patch_margin/right"); + break; + case MARGIN_BOTTOM: + _change_notify("patch_margin/bottom"); + break; + } } int Patch9Frame::get_patch_margin(Margin p_margin) const{ @@ -101,6 +117,22 @@ int Patch9Frame::get_patch_margin(Margin p_margin) const{ return margin[p_margin]; } +void Patch9Frame::set_region_rect(const Rect2& p_region_rect) { + + if (region_rect==p_region_rect) + return; + + region_rect=p_region_rect; + + item_rect_changed(); + _change_notify("region_rect"); +} + +Rect2 Patch9Frame::get_region_rect() const { + + return region_rect; +} + void Patch9Frame::set_draw_center(bool p_draw) { draw_center=p_draw; @@ -128,5 +160,3 @@ Patch9Frame::Patch9Frame() { Patch9Frame::~Patch9Frame() { } - - diff --git a/scene/gui/patch_9_frame.h b/scene/gui/patch_9_frame.h index 562a5b1d77..52e2324c3d 100644 --- a/scene/gui/patch_9_frame.h +++ b/scene/gui/patch_9_frame.h @@ -11,6 +11,7 @@ class Patch9Frame : public Control { bool draw_center; int margin[4]; + Rect2 region_rect; Color modulate; Ref<Texture> texture; protected: @@ -30,6 +31,9 @@ public: void set_patch_margin(Margin p_margin,int p_size); int get_patch_margin(Margin p_margin) const; + void set_region_rect(const Rect2& p_region_rect); + Rect2 get_region_rect() const; + void set_draw_center(bool p_enable); bool get_draw_center() const; diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 0d9a76937c..8d02d0e4e5 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -44,6 +44,8 @@ void Popup::_notification(int p_what) { notification(NOTIFICATION_POPUP_HIDE); emit_signal("popup_hide"); } + + update_configuration_warning(); } if (p_what==NOTIFICATION_ENTER_TREE) { @@ -282,6 +284,14 @@ Popup::Popup() { hide(); } +String Popup::get_configuration_warning() const { + + if (is_visible()) { + return TTR("Popups will hide by default unless you call popup() or any of the popup*() functions. Making them visible for editing is fine though, but they will hide upon running."); + } + + return String(); +} Popup::~Popup() { diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 8afcdc01db..dccaf2ae69 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -65,6 +65,7 @@ public: void set_as_minsize(); virtual void popup(); + virtual String get_configuration_warning() const; Popup(); ~Popup(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 3329d24890..b3f18bf8fa 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -32,9 +32,16 @@ #include "translation.h" #include "os/input.h" -String PopupMenu::_get_accel_text(uint32_t p_accel) const { +String PopupMenu::_get_accel_text(int p_item) const { + + ERR_FAIL_INDEX_V(p_item,items.size(),String()); + + if (items[p_item].shortcut.is_valid()) + return items[p_item].shortcut->get_as_text(); + else if (items[p_item].accel) + return keycode_get_string(items[p_item].accel); + return String(); - return keycode_get_string(p_accel); /* String atxt; if (p_accel&KEY_MASK_SHIFT) @@ -87,14 +94,15 @@ Size2 PopupMenu::get_minimum_size() const { size.width+=check_w+hseparation; } - size.width+=font->get_string_size(items[i].text).width; + String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].text; + size.width+=font->get_string_size(text).width; if (i>0) size.height+=vseparation; - if (items[i].accel) { + if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { int accel_w = hseparation*2; - accel_w+=font->get_string_size(_get_accel_text(items[i].accel)).width; + accel_w+=font->get_string_size(_get_accel_text(i)).width; accel_max_w = MAX( accel_w, accel_max_w ); } @@ -484,13 +492,15 @@ void PopupMenu::_notification(int p_what) { } item_ofs.y+=font->get_ascent(); - if (!items[i].separator) - font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),items[i].text,items[i].disabled?font_color_disabled:(i==mouse_over?font_color_hover:font_color)); + String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].text; + if (!items[i].separator) { + font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),text,items[i].disabled?font_color_disabled:(i==mouse_over?font_color_hover:font_color)); + } - if (items[i].accel) { + if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { //accelerator - String text = _get_accel_text(items[i].accel); + String text = _get_accel_text(i); item_ofs.x=size.width-style->get_margin(MARGIN_RIGHT)-font->get_string_size(text).width; font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),text,i==mouse_over?font_color_hover:font_color_accel); @@ -570,6 +580,64 @@ void PopupMenu::add_check_item(const String& p_label,int p_ID,uint32_t p_accel) update(); } + +void PopupMenu::add_icon_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID) { + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.icon=p_icon; + item.shortcut=p_shortcut; + items.push_back(item); + update(); + +} + +void PopupMenu::add_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID){ + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.shortcut=p_shortcut; + items.push_back(item); + update(); + +} +void PopupMenu::add_icon_check_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID){ + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.shortcut=p_shortcut; + item.checkable=true; + item.icon=p_icon; + items.push_back(item); + update(); +} + +void PopupMenu::add_check_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID){ + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.shortcut=p_shortcut; + item.checkable=true; + items.push_back(item); + update(); +} + void PopupMenu::set_item_text(int p_idx,const String& p_text) { ERR_FAIL_INDEX(p_idx,items.size()); @@ -701,6 +769,12 @@ String PopupMenu::get_item_tooltip(int p_idx) const { return items[p_idx].tooltip; } +Ref<ShortCut> PopupMenu::get_item_shortcut(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,items.size(),Ref<ShortCut>()); + return items[p_idx].shortcut; +} + void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { ERR_FAIL_INDEX(p_idx,items.size()); @@ -730,6 +804,21 @@ void PopupMenu::set_item_tooltip(int p_idx,const String& p_tooltip) { update(); } +void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut>& p_shortcut) { + ERR_FAIL_INDEX(p_idx,items.size()); + if (items[p_idx].shortcut.is_valid()) { + _unref_shortcut(items[p_idx].shortcut); + } + items[p_idx].shortcut=p_shortcut; + + if (items[p_idx].shortcut.is_valid()) { + _ref_shortcut(items[p_idx].shortcut); + } + + + update(); +} + bool PopupMenu::is_item_checkable(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,items.size(),false); return items[p_idx].checkable; @@ -740,15 +829,55 @@ int PopupMenu::get_item_count() const { return items.size(); } -int PopupMenu::find_item_by_accelerator(uint32_t p_accel) const { +bool PopupMenu::activate_item_by_event(const InputEvent& p_event) { + + uint32_t code=0; + if (p_event.type==InputEvent::KEY) { + code=p_event.key.scancode; + if (code==0) + code=p_event.key.unicode; + if (p_event.key.mod.control) + code|=KEY_MASK_CTRL; + if (p_event.key.mod.alt) + code|=KEY_MASK_ALT; + if (p_event.key.mod.meta) + code|=KEY_MASK_META; + if (p_event.key.mod.shift) + code|=KEY_MASK_SHIFT; + } + int il=items.size(); for(int i=0;i<il;i++) { + if (is_item_disabled(i)) + continue; - if (items[i].accel==p_accel) - return i; + + if (items[i].shortcut.is_valid() && items[i].shortcut->is_shortcut(p_event)) { + activate_item(i); + return true; + } + + if (code!=0 && items[i].accel==code) { + activate_item(i); + return true; + } + + if (items[i].submenu!="") { + Node* n = get_node(items[i].submenu); + if(!n) + continue; + + PopupMenu* pm = n->cast_to<PopupMenu>(); + if(!pm) + continue; + + if(pm->activate_item_by_event(p_event)) { + return true; + } + } } - return -1; + return false; } void PopupMenu::activate_item(int p_item) { @@ -773,6 +902,12 @@ void PopupMenu::activate_item(int p_item) { void PopupMenu::remove_item(int p_idx) { + ERR_FAIL_INDEX(p_idx,items.size()); + + if (items[p_idx].shortcut.is_valid()) { + _unref_shortcut(items[p_idx].shortcut); + } + items.remove(p_idx); update(); } @@ -788,6 +923,11 @@ void PopupMenu::add_separator() { void PopupMenu::clear() { + for(int i=0;i<items.size();i++) { + if (items[i].shortcut.is_valid()) { + _unref_shortcut(items[i].shortcut); + } + } items.clear(); mouse_over=-1; update(); @@ -816,6 +956,27 @@ Array PopupMenu::_get_items() const { return items; } + +void PopupMenu::_ref_shortcut( Ref<ShortCut> p_sc) { + + if (!shortcut_refcount.has(p_sc)) { + shortcut_refcount[p_sc]=1; + p_sc->connect("changed",this,"update"); + } else { + shortcut_refcount[p_sc]+=1; + } +} + +void PopupMenu::_unref_shortcut(Ref<ShortCut> p_sc) { + + ERR_FAIL_COND(!shortcut_refcount.has(p_sc)); + shortcut_refcount[p_sc]--; + if (shortcut_refcount[p_sc]==0) { + p_sc->disconnect("changed",this,"update"); + shortcut_refcount.erase(p_sc); + } +} + void PopupMenu::_set_items(const Array& p_items){ ERR_FAIL_COND(p_items.size() % 10); @@ -894,12 +1055,20 @@ void PopupMenu::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_icon_check_item","texture","label","id","accel"),&PopupMenu::add_icon_check_item,DEFVAL(-1),DEFVAL(0)); ObjectTypeDB::bind_method(_MD("add_check_item","label","id","accel"),&PopupMenu::add_check_item,DEFVAL(-1),DEFVAL(0)); ObjectTypeDB::bind_method(_MD("add_submenu_item","label","submenu","id"),&PopupMenu::add_submenu_item,DEFVAL(-1)); + + ObjectTypeDB::bind_method(_MD("add_icon_shortcut","texture","shortcut:ShortCut","id"),&PopupMenu::add_icon_shortcut,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("add_shortcut","shortcut:ShortCut","id"),&PopupMenu::add_shortcut,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("add_icon_check_shortcut","texture","shortcut:ShortCut","id"),&PopupMenu::add_icon_check_shortcut,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("add_check_shortcut","shortcut:ShortCut","id"),&PopupMenu::add_check_shortcut,DEFVAL(-1)); + + ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&PopupMenu::set_item_text); ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon"),&PopupMenu::set_item_icon); ObjectTypeDB::bind_method(_MD("set_item_accelerator","idx","accel"),&PopupMenu::set_item_accelerator); ObjectTypeDB::bind_method(_MD("set_item_metadata","idx","metadata"),&PopupMenu::set_item_metadata); ObjectTypeDB::bind_method(_MD("set_item_checked","idx","checked"),&PopupMenu::set_item_checked); ObjectTypeDB::bind_method(_MD("set_item_disabled","idx","disabled"),&PopupMenu::set_item_disabled); + ObjectTypeDB::bind_method(_MD("set_item_shortcut","idx","shortcut:ShortCut"),&PopupMenu::set_item_shortcut); ObjectTypeDB::bind_method(_MD("set_item_submenu","idx","submenu"),&PopupMenu::set_item_submenu); ObjectTypeDB::bind_method(_MD("set_item_as_separator","idx","enable"),&PopupMenu::set_item_as_separator); ObjectTypeDB::bind_method(_MD("set_item_as_checkable","idx","enable"),&PopupMenu::set_item_as_checkable); @@ -908,6 +1077,7 @@ void PopupMenu::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_item_icon","idx"),&PopupMenu::get_item_icon); ObjectTypeDB::bind_method(_MD("get_item_metadata","idx"),&PopupMenu::get_item_metadata); ObjectTypeDB::bind_method(_MD("get_item_accelerator","idx"),&PopupMenu::get_item_accelerator); + ObjectTypeDB::bind_method(_MD("get_item_shortcut:ShortCut","idx"),&PopupMenu::get_item_shortcut); ObjectTypeDB::bind_method(_MD("get_item_submenu","idx"),&PopupMenu::get_item_submenu); ObjectTypeDB::bind_method(_MD("is_item_separator","idx"),&PopupMenu::is_item_separator); ObjectTypeDB::bind_method(_MD("is_item_checkable","idx"),&PopupMenu::is_item_checkable); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 72f8795067..f35e91d4e4 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -34,6 +34,9 @@ /** @author Juan Linietsky <reduzio@gmail.com> */ + + + class PopupMenu : public Popup { OBJ_TYPE(PopupMenu, Popup ); @@ -51,6 +54,7 @@ class PopupMenu : public Popup { String tooltip; uint32_t accel; int _ofs_cache; + Ref<ShortCut> shortcut; Item() { checked=false; checkable=false; separator=false; accel=0; disabled=false; _ofs_cache=0; } }; @@ -62,7 +66,7 @@ class PopupMenu : public Popup { int mouse_over; int submenu_over; Rect2 parent_rect; - String _get_accel_text(uint32_t p_accel) const; + String _get_accel_text(int p_item) const; int _get_mouse_over(const Point2& p_over) const; virtual Size2 get_minimum_size() const; void _input_event(const InputEvent &p_event); @@ -75,6 +79,10 @@ class PopupMenu : public Popup { Array _get_items() const; void _set_items(const Array& p_items); + Map< Ref<ShortCut>, int> shortcut_refcount; + + void _ref_shortcut(Ref<ShortCut> p_sc); + void _unref_shortcut( Ref<ShortCut> p_sc); protected: virtual bool has_point(const Point2& p_point) const; @@ -90,6 +98,11 @@ public: void add_check_item(const String& p_label,int p_ID=-1,uint32_t p_accel=0); void add_submenu_item(const String& p_label,const String& p_submenu, int p_ID=-1); + void add_icon_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void add_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void add_icon_check_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void add_check_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void set_item_text(int p_idx,const String& p_text); void set_item_icon(int p_idx,const Ref<Texture>& p_icon); void set_item_checked(int p_idx,bool p_checked); @@ -101,6 +114,7 @@ public: void set_item_as_separator(int p_idx, bool p_separator); void set_item_as_checkable(int p_idx, bool p_checkable); void set_item_tooltip(int p_idx,const String& p_tooltip); + void set_item_shortcut(int p_idx, const Ref<ShortCut>& p_shortcut); String get_item_text(int p_idx) const; Ref<Texture> get_item_icon(int p_idx) const; @@ -114,10 +128,11 @@ public: bool is_item_separator(int p_idx) const; bool is_item_checkable(int p_idx) const; String get_item_tooltip(int p_idx) const; + Ref<ShortCut> get_item_shortcut(int p_idx) const; int get_item_count() const; - int find_item_by_accelerator(uint32_t p_accel) const; + bool activate_item_by_event(const InputEvent& p_event); void activate_item(int p_item); void remove_item(int p_idx); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index fc0e7be34f..02da8ff27e 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -35,7 +35,9 @@ Size2 ProgressBar::get_minimum_size() const { Ref<Font> font = get_font("font"); Size2 ms=bg->get_minimum_size()+bg->get_center_size(); - ms.height=MAX(ms.height,bg->get_minimum_size().height+font->get_height()); + if (percent_visible) { + ms.height=MAX(ms.height,bg->get_minimum_size().height+font->get_height()); + } return ms; } diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index b00fcfe42c..e056c55f71 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -78,10 +78,6 @@ void Range::set_val(double p_val) { if (p_val<shared->min) p_val=shared->min; - //avoid to set -0 - if (p_val == 0) - p_val = 0; - if (shared->val==p_val) return; diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index f66f909517..d5d14ad649 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -237,6 +237,7 @@ void Slider::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::INT, "tick_count", PROPERTY_HINT_RANGE,"0,4096,1"), _SCS("set_ticks"), _SCS("get_ticks") ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "ticks_on_borders" ), _SCS("set_ticks_on_borders"), _SCS("get_ticks_on_borders") ); + ADD_PROPERTY( PropertyInfo( Variant::INT,"focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_focus_mode"), _SCS("get_focus_mode") ); } diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 1c6a97bab8..d19e5f0d60 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -411,6 +411,10 @@ void TabContainer::_notification(int p_what) { panel->draw(ci, Rect2( 0, top_size.height, size.width, size.height-top_size.height)); } break; + case NOTIFICATION_THEME_CHANGED: { + + call_deferred("set_current_tab",get_current_tab()); //wait until all changed theme + } break; } } diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 9692d08882..eb060aa6b8 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -32,25 +32,23 @@ Size2 Tabs::get_minimum_size() const { - Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); Ref<Font> font = get_font("font"); - Size2 ms(0, MAX( tab_bg->get_minimum_size().height,tab_fg->get_minimum_size().height)+font->get_height() ); - -// h+=MIN( get_constant("label_valign_fg"), get_constant("label_valign_bg") ); + Size2 ms(0, MAX(tab_bg->get_minimum_size().height, tab_fg->get_minimum_size().height)+font->get_height()); for(int i=0;i<tabs.size();i++) { Ref<Texture> tex = tabs[i].icon; if (tex.is_valid()) { - ms.height = MAX( ms.height, tex->get_size().height ); + ms.height = MAX(ms.height, tex->get_size().height); if (tabs[i].text!="") ms.width+=get_constant("hseparation"); - } + ms.width+=font->get_string_size(tabs[i].text).width; + if (current==i) ms.width+=tab_fg->get_minimum_size().width; else @@ -58,28 +56,26 @@ Size2 Tabs::get_minimum_size() const { if (tabs[i].right_button.is_valid()) { Ref<Texture> rb=tabs[i].right_button; - Size2 bms = rb->get_size();//+get_stylebox("button")->get_minimum_size(); + Size2 bms = rb->get_size(); bms.width+=get_constant("hseparation"); - ms.width+=bms.width; ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height); } if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i==current)) { Ref<Texture> cb=get_icon("close"); - Size2 bms = cb->get_size();//+get_stylebox("button")->get_minimum_size(); + Size2 bms = cb->get_size(); bms.width+=get_constant("hseparation"); ms.width+=bms.width; ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height); } } - ms.width=0; //should make this optional + ms.width=0; //TODO: should make this optional return ms; } - void Tabs::_input_event(const InputEvent& p_event) { if (p_event.type==InputEvent::MOUSE_MOTION) { @@ -101,15 +97,14 @@ void Tabs::_input_event(const InputEvent& p_event) { } } - - + // test hovering to display right or close button int hover_buttons=-1; hover=-1; for(int i=0;i<tabs.size();i++) { - // test hovering tab to display close button if policy says so + if (i<offset) + continue; - // test hovering right button and close button if (tabs[i].rb_rect.has_point(pos)) { rb_hover=i; cb_hover=-1; @@ -123,11 +118,9 @@ void Tabs::_input_event(const InputEvent& p_event) { break; } - - } - if (hover_buttons == -1) { // no hover + if (hover_buttons == -1) { // no hover rb_hover= hover_buttons; cb_hover= hover_buttons; } @@ -137,8 +130,6 @@ void Tabs::_input_event(const InputEvent& p_event) { } - - if (rb_pressing && p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) { @@ -152,9 +143,10 @@ void Tabs::_input_event(const InputEvent& p_event) { update(); } + if (cb_pressing && p_event.type==InputEvent::MOUSE_BUTTON && - !p_event.mouse_button.pressed && - p_event.mouse_button.button_index==BUTTON_LEFT) { + !p_event.mouse_button.pressed && + p_event.mouse_button.button_index==BUTTON_LEFT) { if (cb_hover!=-1) { //pressed @@ -195,12 +187,12 @@ void Tabs::_input_event(const InputEvent& p_event) { } } - int found=-1; for(int i=0;i<tabs.size();i++) { if (i<offset) continue; + if (tabs[i].rb_rect.has_point(pos)) { rb_pressing=true; update(); @@ -213,10 +205,7 @@ void Tabs::_input_event(const InputEvent& p_event) { return; } - int ofs=tabs[i].ofs_cache; - int size = tabs[i].ofs_cache; if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) { - found=i; break; } @@ -232,8 +221,8 @@ void Tabs::_input_event(const InputEvent& p_event) { } -void Tabs::_notification(int p_what) { +void Tabs::_notification(int p_what) { switch(p_what) { @@ -259,39 +248,20 @@ void Tabs::_notification(int p_what) { Ref<Texture> close=get_icon("close"); int h = get_size().height; - - int label_valign_fg = get_constant("label_valign_fg"); - int label_valign_bg = get_constant("label_valign_bg"); - - - int w=0; - + int w = 0; int mw = 0; - { - - - // h+=MIN( get_constant("label_valign_fg"), get_constant("label_valign_bg") ); - - for(int i=0;i<tabs.size();i++) { - - int sz = get_tab_width(i); - - tabs[i].ofs_cache=mw; - mw+=sz; - - - } + for(int i=0;i<tabs.size();i++) { + tabs[i].ofs_cache = mw; + mw += get_tab_width(i); } - if (tab_align==ALIGN_CENTER) { w=(get_size().width-mw)/2; } else if (tab_align==ALIGN_RIGHT) { w=get_size().width-mw; - } if (w<0) { @@ -311,45 +281,13 @@ void Tabs::_notification(int p_what) { if (i<offset) continue; - tabs[i].ofs_cache=w; - - String s = tabs[i].text; - int lsize=0; - int slen=font->get_string_size(s).width; - lsize+=slen; - + tabs[i].ofs_cache=w; - Ref<Texture> icon; - if (tabs[i].icon.is_valid()) { - icon = tabs[i].icon; - if (icon.is_valid()) { - lsize+=icon->get_width(); - if (s!="") - lsize+=get_constant("hseparation"); - - } - } - - if (tabs[i].right_button.is_valid()) { - Ref<StyleBox> style = get_stylebox("button"); - Ref<Texture> rb=tabs[i].right_button; - - lsize+=get_constant("hseparation"); - //lsize+=style->get_margin(MARGIN_LEFT); - lsize+=rb->get_width(); - //lsize+=style->get_margin(MARGIN_RIGHT); - - } - + int lsize = get_tab_width(i); - if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i==current)) { - - lsize+=get_constant("hseparation"); - //lsize+=style->get_margin(MARGIN_LEFT); - lsize+=close->get_width(); - //lsize+=style->get_margin(MARGIN_RIGHT); - } + String text = tabs[i].text; + int slen = font->get_string_size(text).width; if (w+lsize > limit) { max_drawn_tab=i-1; @@ -360,42 +298,39 @@ void Tabs::_notification(int p_what) { } - Ref<StyleBox> sb; - int va; Color col; if (i==current) { - sb=tab_fg; - va=label_valign_fg; col=color_fg; } else { sb=tab_bg; - va=label_valign_bg; col=color_bg; } - Size2i sb_ms = sb->get_minimum_size(); - Rect2 sb_rect = Rect2( w, 0, lsize+sb_ms.width, h); - sb->draw(ci, sb_rect ); + Rect2 sb_rect = Rect2(w, 0, lsize, h); + sb->draw(ci, sb_rect); w+=sb->get_margin(MARGIN_LEFT); + Size2i sb_ms = sb->get_minimum_size(); + Ref<Texture> icon = tabs[i].icon; if (icon.is_valid()) { icon->draw(ci, Point2i( w, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-icon->get_height())/2 ) ); - if (s!="") + if (text!="") w+=icon->get_width()+get_constant("hseparation"); } - font->draw(ci, Point2i( w, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), s, col ); + font->draw(ci, Point2i( w, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), text, col ); w+=slen; if (tabs[i].right_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); Ref<Texture> rb=tabs[i].right_button; @@ -413,17 +348,12 @@ void Tabs::_notification(int p_what) { style->draw(ci,rb_rect); } - w+=style->get_margin(MARGIN_LEFT); - - rb->draw(ci,Point2i( w,rb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + rb->draw(ci,Point2i( w+style->get_margin(MARGIN_LEFT), rb_rect.pos.y+style->get_margin(MARGIN_TOP) )); w+=rb->get_width(); - w+=style->get_margin(MARGIN_RIGHT); tabs[i].rb_rect=rb_rect; - } - if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i==current)) { Ref<StyleBox> style = get_stylebox("button"); @@ -443,11 +373,8 @@ void Tabs::_notification(int p_what) { style->draw(ci,cb_rect); } - //w+=style->get_margin(MARGIN_LEFT); - - cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + cb->draw(ci,Point2i( w+style->get_margin(MARGIN_LEFT), cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); w+=cb->get_width(); - //w+=style->get_margin(MARGIN_RIGHT); tabs[i].cb_rect=cb_rect; } @@ -462,28 +389,26 @@ void Tabs::_notification(int p_what) { int vofs = (get_size().height-incr->get_size().height)/2; if (offset>0) - draw_texture(hilite_arrow==0?decr_hl:decr,Point2(limit,vofs)); + draw_texture(hilite_arrow==0 ? decr_hl : decr, Point2(limit,vofs)); else - draw_texture(decr,Point2(limit,vofs),Color(1,1,1,0.5)); + draw_texture(decr,Point2(limit,vofs), Color(1,1,1,0.5)); if (missing_right) - draw_texture(hilite_arrow==1?incr_hl:incr,Point2(limit+decr->get_size().width,vofs)); + draw_texture(hilite_arrow==1 ? incr_hl : incr, Point2(limit+decr->get_size().width,vofs)); else - draw_texture(incr,Point2(limit+decr->get_size().width,vofs),Color(1,1,1,0.5)); + draw_texture(incr,Point2(limit+decr->get_size().width,vofs), Color(1,1,1,0.5)); buttons_visible=true; } else { buttons_visible=false; } - } break; } } int Tabs::get_tab_count() const { - return tabs.size(); } @@ -492,11 +417,9 @@ void Tabs::set_current_tab(int p_current) { ERR_FAIL_INDEX( p_current, get_tab_count() ); - //printf("DEBUG %p: set_current_tab to %i\n", this, p_current); current=p_current; _change_notify("current_tab"); - //emit_signal("tab_changed",current); update(); } @@ -520,9 +443,9 @@ String Tabs::get_tab_title(int p_tab) const{ ERR_FAIL_INDEX_V(p_tab,tabs.size(),""); return tabs[p_tab].text; - } + void Tabs::set_tab_icon(int p_tab,const Ref<Texture>& p_icon){ ERR_FAIL_INDEX(p_tab,tabs.size()); @@ -531,6 +454,7 @@ void Tabs::set_tab_icon(int p_tab,const Ref<Texture>& p_icon){ minimum_size_changed(); } + Ref<Texture> Tabs::get_tab_icon(int p_tab) const{ ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>()); @@ -539,7 +463,6 @@ Ref<Texture> Tabs::get_tab_icon(int p_tab) const{ } - void Tabs::set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button){ ERR_FAIL_INDEX(p_tab,tabs.size()); @@ -589,8 +512,6 @@ void Tabs::remove_tab(int p_idx) { if (current>=tabs.size()) current=tabs.size()-1; - //emit_signal("tab_changed",current); - _ensure_no_over_offset(); } @@ -614,19 +535,20 @@ int Tabs::get_tab_width(int p_idx) const { Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); Ref<Font> font = get_font("font"); - Ref<Texture> close=get_icon("close"); + int x=0; Ref<Texture> tex = tabs[p_idx].icon; if (tex.is_valid()) { + x+=tex->get_width(); if (tabs[p_idx].text!="") x+=get_constant("hseparation"); } - x+=font->get_string_size(tabs[p_idx].text).width; + if (current==p_idx) x+=tab_fg->get_minimum_size().width; else @@ -634,17 +556,14 @@ int Tabs::get_tab_width(int p_idx) const { if (tabs[p_idx].right_button.is_valid()) { Ref<Texture> rb=tabs[p_idx].right_button; - Size2 bms = rb->get_size();//+get_stylebox("button")->get_minimum_size(); - bms.width+=get_constant("hseparation"); - - x+=bms.width; + x+=rb->get_width(); + x+=get_constant("hseparation"); } if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx==current)) { - - Size2 bms = close->get_size();//+get_stylebox("button")->get_minimum_size(); - bms.width+=get_constant("hseparation"); - x+=bms.width; + Ref<Texture> cb=get_icon("close"); + x+=cb->get_width(); + x+=get_constant("hseparation"); } return x; @@ -700,11 +619,9 @@ void Tabs::ensure_tab_visible(int p_idx) { Ref<Texture> incr = get_icon("increment"); Ref<Texture> decr = get_icon("decrement"); - int limit=get_size().width-incr->get_width()-decr->get_width(); - int x=0; for(int i=0;i<tabs.size();i++) { @@ -750,7 +667,6 @@ void Tabs::_bind_methods() { ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab"))); ADD_SIGNAL(MethodInfo("tab_close",PropertyInfo(Variant::INT,"tab"))); - ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") ); BIND_CONSTANT( ALIGN_LEFT ); @@ -774,9 +690,8 @@ Tabs::Tabs() { cb_hover=-1; cb_pressing=false; - cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER; // Default : no close button + cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER; offset=0; max_drawn_tab=0; - } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 3948de7689..fe03b34105 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -44,7 +44,20 @@ static bool _is_text_char(CharType c) { static bool _is_symbol(CharType c) { - return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t'); + return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t' || c==' '); +} + +static bool _is_char(CharType c) { + + return (c>='a' && c<='z') || (c>='A' && c<='Z') || c=='_'; +} + +static bool _is_number(CharType c) { + return (c >= '0' && c <= '9'); +} + +static bool _is_hex_symbol(CharType c) { + return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } static bool _is_pair_right_symbol(CharType c) { @@ -301,6 +314,10 @@ void TextEdit::_update_scrollbars() { if (line_numbers) total_width += cache.line_number_w; + if (draw_breakpoint_gutter) { + total_width += cache.breakpoint_gutter_width; + } + bool use_hscroll=true; bool use_vscroll=true; @@ -399,9 +416,15 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { _update_caches(); - }; + } break; case NOTIFICATION_DRAW: { + if (draw_breakpoint_gutter) { + cache.breakpoint_gutter_width = breakpoint_gutter_width; + } else { + cache.breakpoint_gutter_width = 0; + } + int line_number_char_count=0; { @@ -426,7 +449,7 @@ void TextEdit::_notification(int p_what) { RID ci = get_canvas_item(); - int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w; + int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w+cache.breakpoint_gutter_width; int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT); //let's do it easy for now: cache.style_normal->draw(ci,Rect2(Point2(),cache.size)); @@ -659,25 +682,23 @@ void TextEdit::_notification(int p_what) { int char_ofs=0; int ofs_y=i*get_row_height()+cache.line_spacing/2; bool prev_is_char=false; + bool prev_is_number = false; bool in_keyword=false; + bool in_word = false; + bool in_function_name = false; + bool in_member_variable = false; + bool is_hex_notation = false; Color keyword_color; // check if line contains highlighted word int highlighted_text_col = -1; - if (highlighted_text.length() != 0) { - highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, 0); - } + int search_text_col = -1; - if (cache.line_number_w) { - Color fcol = cache.font_color; - fcol.a*=0.4; - String fc = String::num(line+1); - while (fc.length() < line_number_char_count) { - fc="0"+fc; - } + if (!search_text.empty()) + search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0); - cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol); - } + if (highlighted_text.length() != 0 && highlighted_text != search_text) + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE|SEARCH_WHOLE_WORDS, 0); const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line); @@ -692,11 +713,28 @@ void TextEdit::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color); } - if (line==cursor.line) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(0, ofs_y,xmargin_end,get_row_height()),cache.current_line_color); + } + + // draw breakpoint marker + if (text.is_breakpoint(line)) { + if (draw_breakpoint_gutter) { + int vertical_gap = cache.breakpoint_gutter_width / 2; + int marker_size = cache.breakpoint_gutter_width - vertical_gap; + // no transparency on marker + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + 1, ofs_y + vertical_gap ,marker_size, marker_size),Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b)); + } + } + - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color); + if (cache.line_number_w) { + String fc = String::num(line+1); + while (fc.length() < line_number_char_count) { + fc="0"+fc; + } + cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT)+cache.breakpoint_gutter_width,ofs_y+cache.font->get_ascent()),fc,cache.line_number_color); } for (int j=0;j<str.length();j++) { @@ -712,13 +750,43 @@ void TextEdit::_notification(int p_what) { color = cache.font_color; //reset //find keyword - bool is_char = _is_text_char(str[j]); - bool is_symbol=_is_symbol(str[j]); + bool is_char = _is_text_char(str[j]); + bool is_symbol = _is_symbol(str[j]); + bool is_number = _is_number(str[j]); if (j==0 && in_region>=0 && color_regions[in_region].line_only) { in_region=-1; //reset regions that end at end of line } + // allow ABCDEF in hex notation + if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) { + is_number = true; + } else { + is_hex_notation = false; + } + + // check for dot or 'x' for hex notation in floating point number + if ((str[j] == '.' || str[j] == 'x') && !in_word && prev_is_number && !is_number) { + is_number = true; + is_symbol = false; + + if (str[j] == 'x' && str[j-1] == '0') { + is_hex_notation = true; + } + } + + if (!in_word && _is_char(str[j])) { + in_word = true; + } + + if ((in_keyword || in_word) && !is_hex_notation) { + is_number = false; + } + + if (is_symbol && str[j] != '.' && in_word) { + in_word = false; + } + if (is_symbol && cri_map.has(j)) { @@ -760,15 +828,49 @@ void TextEdit::_notification(int p_what) { } } + if (!in_function_name && in_word && !in_keyword) { + + int k = j; + while(k < str.length() && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + k++; + } + + if (str[k] == '(') { + in_function_name = true; + } + } + + if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) { + int k = j; + while(k > 0 && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + k--; + } + + if (str[k] == '.') { + in_member_variable = true; + } + } + + if (is_symbol) { + in_function_name = false; + in_member_variable = false; + } if (in_region>=0) color=color_regions[in_region].color; else if (in_keyword) color=keyword_color; + else if (in_member_variable) + color=cache.member_variable_color; + else if (in_function_name) + color=cache.function_color; else if (is_symbol) color=symbol_color; + else if (is_number) + color=cache.number_color; prev_is_char=is_char; + prev_is_number=is_number; } int char_w; @@ -799,20 +901,45 @@ void TextEdit::_notification(int p_what) { break; } - bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column)); + bool in_search_result=false; + if (search_text_col != -1) { + // if we are at the end check for new search result on same line + if (j >= search_text_col+search_text.length()) + search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j); + + in_search_result = j >= search_text_col && j < search_text_col+search_text.length(); + + if (in_search_result) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w, get_row_height())),cache.search_result_color); + } + } + + bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column)); if (in_selection) { //inside selection! VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color); } + if (in_search_result) { + Color border_color=(line==search_result_line && j>=search_result_col && j<search_result_col+search_text.length())?cache.font_color:cache.search_result_border_color; + + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,1)),border_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y+get_row_height()-1 ), Size2i(char_w,1)),border_color); + + if (j==search_text_col) + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(1,get_row_height())),border_color); + if (j==search_text_col+search_text.length()-1) + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin+char_w-1, ofs_y ), Size2i(1,get_row_height())),border_color); + } + if (highlight_all_occurrences) { if (highlighted_text_col != -1) { // if we are at the end check for new word on same line if (j > highlighted_text_col+highlighted_text.length()) { - highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, j); + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE|SEARCH_WHOLE_WORDS, j); } bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col+highlighted_text.length()); @@ -857,9 +984,18 @@ void TextEdit::_notification(int p_what) { if (cursor.column==j && cursor.line==line) { cursor_pos = Point2i( char_ofs+char_margin, ofs_y ); - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); + if (insert_mode) { + cursor_pos.y += get_row_height(); + } + if (draw_caret) { + if (insert_mode) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,1)),cache.caret_color); + } else { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color); + } + } } char_ofs+=char_w; @@ -868,8 +1004,19 @@ void TextEdit::_notification(int p_what) { if (cursor.column==str.length() && cursor.line==line && (char_ofs+char_margin)>=xmargin_beg) { cursor_pos=Point2i( char_ofs+char_margin, ofs_y ); - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); + if (insert_mode) { + cursor_pos.y += get_row_height(); + } + + 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); + } else { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color); + } + } } } @@ -1071,7 +1218,7 @@ void TextEdit::_consume_pair_symbol(CharType ch) { int new_column,new_line; - _begin_compex_operation(); + begin_complex_operation(); _insert_text(get_selection_from_line(), get_selection_from_column(), ch_single, &new_line, &new_column); @@ -1084,7 +1231,7 @@ void TextEdit::_consume_pair_symbol(CharType ch) { get_selection_to_column() + to_col_offset, ch_single_pair, &new_line,&new_column); - _end_compex_operation(); + end_complex_operation(); cursor_set_line(get_selection_to_line()); cursor_set_column(get_selection_to_column() + to_col_offset); @@ -1168,6 +1315,66 @@ void TextEdit::backspace_at_cursor() { } +void TextEdit::indent_selection_right() { + + if (!is_selection_active()) { + return; + } + begin_complex_operation(); + int start_line = get_selection_from_line(); + int end_line = get_selection_to_line(); + + // ignore if the cursor is not past the first column + if (get_selection_to_column() == 0) { + end_line--; + } + + for (int i = start_line; i <= end_line; i++) { + String line_text = get_line(i); + line_text = '\t' + line_text; + set_line(i, line_text); + } + + // fix selection being off by one on the last line + selection.to_column++; + end_complex_operation(); + update(); +} + +void TextEdit::indent_selection_left() { + + if (!is_selection_active()) { + return; + } + begin_complex_operation(); + int start_line = get_selection_from_line(); + int end_line = get_selection_to_line(); + + // ignore if the cursor is not past the first column + if (get_selection_to_column() == 0) { + end_line--; + } + String last_line_text = get_line(end_line); + + for (int i = start_line; i <= end_line; i++) { + String line_text = get_line(i); + + if (line_text.begins_with("\t")) { + line_text = line_text.substr(1, line_text.length()); + set_line(i, line_text); + } else if (line_text.begins_with(" ")) { + line_text = line_text.substr(4, line_text.length()); + set_line(i, line_text); + } + } + + // fix selection being off by one on the last line + if (last_line_text != get_line(end_line) && selection.to_column > 0) { + selection.to_column--; + } + end_complex_operation(); + update(); +} void TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const { @@ -1187,7 +1394,7 @@ void TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) co col=text[row].size(); } else { - col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w); + col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w+cache.breakpoint_gutter_width); col+=cursor.x_ofs; col=get_char_pos_for( col, get_line(row) ); } @@ -1256,9 +1463,20 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } if (mb.button_index==BUTTON_LEFT) { + _reset_caret_blink_timer(); + int row,col; _get_mouse_pos(Point2i(mb.x,mb.y), row,col); + // toggle breakpoint on gutter click + if (draw_breakpoint_gutter) { + 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)); + return; + } + } + int prev_col=cursor.column; int prev_line=cursor.line; @@ -1372,6 +1590,15 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { update(); } + + if (mb.button_index==BUTTON_RIGHT) { + + menu->set_pos(get_global_transform().xform(get_local_mouse_pos())); + menu->set_size(Vector2(1,1)); + menu->popup(); + grab_focus(); + + } } else { if (mb.button_index==BUTTON_LEFT) @@ -1390,6 +1617,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (selection.selecting_mode!=Selection::MODE_NONE) { + _reset_caret_blink_timer(); + int row,col; _get_mouse_pos(Point2i(mm.x,mm.y), row,col); @@ -1510,6 +1739,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.scancode==KEY_BACKSPACE) { + _reset_caret_blink_timer(); + backspace_at_cursor(); _update_completion_candidates(); accept_event(); @@ -1525,20 +1756,29 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.unicode>32) { - if (cursor.column<text[cursor.line].length() && text[cursor.line][cursor.column]==k.unicode) { - //same char, move ahead - cursor_set_column(cursor.column+1); + _reset_caret_blink_timer(); + const CharType chr[2] = {(CharType)k.unicode, 0}; + if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { + _consume_pair_symbol(chr[0]); } else { - //different char, go back - const CharType chr[2] = {(CharType)k.unicode, 0}; - if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { - _consume_pair_symbol(chr[0]); - } else { - _insert_text_at_cursor(chr); + + // remove the old character if in insert mode + if (insert_mode) { + begin_complex_operation(); + + // make sure we don't try and remove empty space + if (cursor.column < get_line(cursor.line).length()) { + _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); + } } - } + _insert_text_at_cursor(chr); + + if (insert_mode) { + end_complex_operation(); + } + } _update_completion_candidates(); accept_event(); @@ -1564,8 +1804,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { k.mod.shift=false; } - // stuff to do when selection is active.. + if (!k.mod.command) { + _reset_caret_blink_timer(); + } + // save here for insert mode, just in case it is cleared in the following section + bool had_selection = selection.active; + // stuff to do when selection is active.. if (selection.active) { if (readonly) @@ -1578,51 +1823,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { switch(k.scancode) { case KEY_TAB: { - - String txt = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - String prev_txt=txt; - if (k.mod.shift) { - - for(int i=0;i<txt.length();i++) { - if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/)) && (txt[i]=='\t' || txt[i]==' ')) { - txt.remove(i); - //i--; - } - } + indent_selection_left(); } else { - - for(int i=0;i<txt.length();i++) { - - if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/))) { - txt=txt.insert(i,"\t"); - //i--; - } - } - } - - if (txt!=prev_txt) { - - int sel_line=selection.from_line; - int sel_column=selection.from_column; - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - _begin_compex_operation(); - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - _insert_text_at_cursor(txt); - _end_compex_operation(); - selection.active=true; - selection.from_column=sel_column; - selection.from_line=sel_line; - selection.to_column=cursor.column; - selection.to_line=cursor.line; - update(); + indent_selection_right(); } - dobreak=true; accept_event(); - } break; case KEY_X: case KEY_C: @@ -1669,6 +1876,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } if (clear) { + if (!dobreak) { + begin_complex_operation(); + } selection.active=false; update(); _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); @@ -1740,7 +1950,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (completion_hint!="") { completion_hint=""; update(); - + } else { + scancode_handled=false; } } break; case KEY_TAB: { @@ -1943,7 +2154,17 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { scancode_handled=false; break; } -#ifdef APPLE_STYLE_KEYS +#ifndef APPLE_STYLE_KEYS + if (k.mod.command) { + _scroll_lines_up(); + break; + } +#else + if (k.mod.command && k.mod.alt) { + _scroll_lines_up(); + break; + } + if (k.mod.command) cursor_set_line(0); else @@ -1970,7 +2191,17 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { scancode_handled=false; break; } -#ifdef APPLE_STYLE_KEYS +#ifndef APPLE_STYLE_KEYS + if (k.mod.command) { + _scroll_lines_down(); + break; + } +#else + if (k.mod.command && k.mod.alt) { + _scroll_lines_down(); + break; + } + if (k.mod.command) cursor_set_line(text.size()-1); else @@ -2302,6 +2533,12 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } } */ + if (k.scancode==KEY_INSERT) { + set_insert_mode(!insert_mode); + accept_event(); + return; + } + if (!scancode_handled && !k.mod.command) { //for german kbds if (k.unicode>=32) { @@ -2309,6 +2546,16 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (readonly) break; + // remove the old character if in insert mode and no selection + if (insert_mode && !had_selection) { + begin_complex_operation(); + + // make sure we don't try and remove empty space + if (cursor.column < get_line(cursor.line).length()) { + _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); + } + } + const CharType chr[2] = {(CharType)k.unicode, 0}; if (completion_hint!="" && k.unicode==')') { @@ -2320,6 +2567,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { _insert_text_at_cursor(chr); } + if (insert_mode && !had_selection) { + end_complex_operation(); + } + + if (selection.active != had_selection) { + end_complex_operation(); + } accept_event(); } else { @@ -2361,6 +2615,36 @@ void TextEdit::_post_shift_selection() { selection.selecting_text=true; } +void TextEdit::_scroll_lines_up() { + // adjust the vertical scroll + if (get_v_scroll() > 0) { + set_v_scroll(get_v_scroll() - 1); + } + + // adjust the cursor + if (cursor_get_line() >= (get_visible_rows() + get_v_scroll()) && !selection.active) { + cursor_set_line((get_visible_rows() + get_v_scroll()) - 1, false); + } +} + +void TextEdit::_scroll_lines_down() { + // calculate the maximum vertical scroll position + int max_v_scroll = get_line_count() - 1; + if (!scroll_past_end_of_file_enabled) { + max_v_scroll -= get_visible_rows() - 1; + } + + // adjust the vertical scroll + if (get_v_scroll() < max_v_scroll) { + set_v_scroll(get_v_scroll() + 1); + } + + // adjust the cursor + if ((cursor_get_line()) <= get_v_scroll() - 1 && !selection.active) { + cursor_set_line(get_v_scroll(), false); + } +} + /**** TEXT EDIT CORE API ****/ void TextEdit::_base_insert_text(int p_line, int p_char,const String& p_text,int &r_end_line,int &r_end_column) { @@ -2621,7 +2905,7 @@ void TextEdit::adjust_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; + 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 @@ -2723,6 +3007,30 @@ int TextEdit::cursor_get_line() const { return cursor.line; } +bool TextEdit::cursor_get_blink_enabled() const { + return caret_blink_enabled; +} + +void TextEdit::cursor_set_blink_enabled(const bool p_enabled) { + caret_blink_enabled = p_enabled; + + if (p_enabled) { + caret_blink_timer->start(); + } else { + caret_blink_timer->stop(); + } + draw_caret = true; +} + + +float TextEdit::cursor_get_blink_speed() const { + return caret_blink_timer->get_wait_time(); +} + +void TextEdit::cursor_set_blink_speed(const float p_speed) { + ERR_FAIL_COND(p_speed <= 0); + caret_blink_timer->set_wait_time(p_speed); +} void TextEdit::_scroll_moved(double p_to_val) { @@ -2826,7 +3134,8 @@ void TextEdit::insert_text_at_cursor(const String& p_text) { } Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const { - if(completion_active && completion_rect.has_point(p_pos)) { + int gutter=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w+cache.breakpoint_gutter_width; + if((completion_active && completion_rect.has_point(p_pos)) || p_pos.x < gutter) { return CURSOR_ARROW; } return CURSOR_IBEAM; @@ -2938,20 +3247,41 @@ void TextEdit::set_max_chars(int p_max_chars) { max_chars=p_max_chars; } +void TextEdit::_reset_caret_blink_timer() { + if (caret_blink_enabled) { + caret_blink_timer->stop(); + caret_blink_timer->start(); + draw_caret = true; + update(); + } +} + +void TextEdit::_toggle_draw_caret() { + draw_caret = !draw_caret; + update(); +} + void TextEdit::_update_caches() { cache.style_normal=get_stylebox("normal"); cache.style_focus=get_stylebox("focus"); cache.font=get_font("font"); + cache.caret_color=get_color("caret_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"); cache.keyword_color=get_color("keyword_color"); + cache.function_color=get_color("function_color"); + cache.member_variable_color=get_color("member_variable_color"); + cache.number_color=get_color("number_color"); cache.selection_color=get_color("selection_color"); cache.mark_color=get_color("mark_color"); cache.current_line_color=get_color("current_line_color"); cache.breakpoint_color=get_color("breakpoint_color"); cache.brace_mismatch_color=get_color("brace_mismatch_color"); cache.word_highlighted_color=get_color("word_highlighted_color"); + cache.search_result_color=get_color("search_result_color"); + cache.search_result_border_color=get_color("search_result_border_color"); cache.line_spacing=get_constant("line_spacing"); cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon=get_icon("tab"); @@ -3213,12 +3543,26 @@ String TextEdit::get_word_under_cursor() const { return text[cursor.line].substr(prev_cc, next_cc-prev_cc); } +void TextEdit::set_search_text(const String &p_search_text) { + search_text = p_search_text; +} + +void TextEdit::set_search_flags(uint32_t p_flags) { + search_flags = p_flags; +} + +void TextEdit::set_current_search_result(int line, int col) { + search_result_line = line; + search_result_col = col; + update(); +} + void TextEdit::set_highlight_all_occurrences(const bool p_enabled) { highlight_all_occurrences = p_enabled; update(); } -int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column) { +int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column) { int col = -1; if (p_key.length() > 0 && p_search.length() > 0) { @@ -3226,12 +3570,15 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc p_from_column = 0; } - while (col == -1 && p_from_column <= p_search.length()) { - // match case - col = p_search.findn(p_key, p_from_column); + while (col == -1 && p_from_column <= p_search.length()) { + if (p_search_flags&SEARCH_MATCH_CASE) { + col = p_search.find(p_key,p_from_column); + } else { + col = p_search.findn(p_key,p_from_column); + } // whole words only - if (col != -1) { + if (col != -1 && p_search_flags&SEARCH_WHOLE_WORDS) { p_from_column=col; if (col > 0 && _is_text_char(p_search[col-1])) { @@ -3297,10 +3644,8 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li //wrapped if (p_search_flags&SEARCH_BACKWARDS) { - text_line=text_line.substr(from_column,text_line.length()); from_column=text_line.length(); } else { - text_line=text_line.substr(0,from_column); from_column=0; } @@ -3311,7 +3656,6 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li } else { - //text_line=text_line.substr(0,p_from_column); //wrap around for missing begining. if (p_search_flags&SEARCH_BACKWARDS) from_column=text_line.length()-1; else @@ -3320,12 +3664,25 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li pos=-1; - if (!(p_search_flags&SEARCH_BACKWARDS)) { + int pos_from=0; + int last_pos=-1; + while ((last_pos=(p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,pos_from):text_line.findn(p_key,pos_from))!=-1) { - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,from_column):text_line.findn(p_key,from_column); - } else { + if (p_search_flags&SEARCH_BACKWARDS) { - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.rfind(p_key,from_column):text_line.rfindn(p_key,from_column); + if (last_pos>from_column) + break; + pos=last_pos; + + } else { + + if (last_pos>=from_column) { + pos=last_pos; + break; + } + } + + pos_from=last_pos+p_key.length(); } if (pos!=-1 && (p_search_flags&SEARCH_WHOLE_WORDS)) { @@ -3509,12 +3866,12 @@ void TextEdit::clear_undo_history() { } -void TextEdit::_begin_compex_operation() { +void TextEdit::begin_complex_operation() { _push_current_op(); next_operation_is_complex=true; } -void TextEdit::_end_compex_operation() { +void TextEdit::end_complex_operation() { _push_current_op(); ERR_FAIL_COND(undo_stack.size() == 0); @@ -3561,6 +3918,15 @@ bool TextEdit::is_drawing_tabs() const{ return draw_tabs; } +void TextEdit::set_insert_mode(bool p_enabled) { + insert_mode = p_enabled; + update(); +} + +bool TextEdit::is_insert_mode() const { + return insert_mode; +} + uint32_t TextEdit::get_version() const { return current_op.version; } @@ -3710,6 +4076,9 @@ void TextEdit::_update_completion_candidates() { } } + if (l[cursor.column - 1] == '(' && !pre_keyword && !completion_strings[0].begins_with("\"")) { + cancel = true; + } update(); @@ -3725,6 +4094,10 @@ void TextEdit::_update_completion_candidates() { int ci_match=0; for(int i=0;i<completion_strings.size();i++) { if (completion_strings[i].begins_with(s)) { + // don't remove duplicates if no input is provided + if (completion_options.find(completion_strings[i]) != -1 && s != "") { + continue; + } completion_options.push_back(completion_strings[i]); int m=0; int max=MIN(completion_current.length(),completion_strings[i].length()); @@ -3883,10 +4256,60 @@ void TextEdit::set_show_line_numbers(bool p_show) { update(); } +void TextEdit::set_draw_breakpoint_gutter(bool p_draw) { + draw_breakpoint_gutter = p_draw; + update(); +} + +bool TextEdit::is_drawing_breakpoint_gutter() const { + return draw_breakpoint_gutter; +} + +void TextEdit::set_breakpoint_gutter_width(int p_gutter_width) { + breakpoint_gutter_width = p_gutter_width; + update(); +} + +int TextEdit::get_breakpoint_gutter_width() const { + return cache.breakpoint_gutter_width; +} + bool TextEdit::is_text_field() const { return true; } + +void TextEdit::menu_option(int p_option) { + + switch( p_option ) { + case MENU_CUT: { + + cut(); + } break; + case MENU_COPY: { + copy(); + } break; + case MENU_PASTE: { + + paste(); + } break; + case MENU_CLEAR: { + clear(); + } break; + case MENU_SELECT_ALL: { + select_all(); + } break; + case MENU_UNDO: { + undo(); + } break; + + }; +} + +PopupMenu *TextEdit::get_menu() const { + return menu; +} + void TextEdit::_bind_methods() { @@ -3896,6 +4319,7 @@ void TextEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit); ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op); ObjectTypeDB::bind_method(_MD("_click_selection_held"),&TextEdit::_click_selection_held); + ObjectTypeDB::bind_method(_MD("_toggle_draw_caret"),&TextEdit::_toggle_draw_caret); BIND_CONSTANT( SEARCH_MATCH_CASE ); BIND_CONSTANT( SEARCH_WHOLE_WORDS ); @@ -3918,7 +4342,10 @@ void TextEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("cursor_get_column"),&TextEdit::cursor_get_column); ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line); - + ObjectTypeDB::bind_method(_MD("cursor_set_blink_enabled", "enable"),&TextEdit::cursor_set_blink_enabled); + 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("set_readonly","enable"),&TextEdit::set_readonly); ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap); @@ -3952,12 +4379,25 @@ void TextEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color); ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color); ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors); + ObjectTypeDB::bind_method(_MD("menu_option"),&TextEdit::menu_option); + ObjectTypeDB::bind_method(_MD("get_menu:PopupMenu"),&TextEdit::get_menu); + 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")); + BIND_CONSTANT( MENU_CUT ); + BIND_CONSTANT( MENU_COPY ); + BIND_CONSTANT( MENU_PASTE ); + BIND_CONSTANT( MENU_CLEAR ); + BIND_CONSTANT( MENU_SELECT_ALL ); + BIND_CONSTANT( MENU_UNDO ); + BIND_CONSTANT( MENU_MAX ); + + } TextEdit::TextEdit() { @@ -3965,6 +4405,7 @@ TextEdit::TextEdit() { readonly=false; setting_row=false; draw_tabs=false; + draw_caret=true; max_chars=0; clear(); wrap=false; @@ -3974,6 +4415,8 @@ TextEdit::TextEdit() { cache.row_height=1; cache.line_spacing=1; cache.line_number_w=1; + cache.breakpoint_gutter_width=0; + breakpoint_gutter_width = 0; tab_size=4; text.set_tab_size(tab_size); @@ -4004,6 +4447,13 @@ TextEdit::TextEdit() { selection.active=false; syntax_coloring=false; + caret_blink_enabled=false; + caret_blink_timer = memnew(Timer); + add_child(caret_blink_timer); + caret_blink_timer->set_wait_time(0.65); + caret_blink_timer->connect("timeout", this,"_toggle_draw_caret"); + cursor_set_blink_enabled(false); + custom_bg_color=Color(0,0,0,0); idle_detect = memnew( Timer ); add_child(idle_detect); @@ -4048,11 +4498,27 @@ TextEdit::TextEdit() { completion_line_ofs=0; tooltip_obj=NULL; line_numbers=false; + draw_breakpoint_gutter=false; next_operation_is_complex=false; scroll_past_end_of_file_enabled=false; auto_brace_completion_enabled=false; brace_matching_enabled=false; auto_indent=false; + insert_mode = false; + + menu = memnew( PopupMenu ); + add_child(menu); + menu->add_item(TTR("Cut"),MENU_CUT,KEY_MASK_CMD|KEY_X); + menu->add_item(TTR("Copy"),MENU_COPY,KEY_MASK_CMD|KEY_C); + menu->add_item(TTR("Paste"),MENU_PASTE,KEY_MASK_CMD|KEY_V); + menu->add_separator(); + menu->add_item(TTR("Select All"),MENU_SELECT_ALL,KEY_MASK_CMD|KEY_A); + menu->add_item(TTR("Clear"),MENU_CLEAR); + menu->add_separator(); + menu->add_item(TTR("Undo"),MENU_UNDO,KEY_MASK_CMD|KEY_Z); + menu->connect("item_pressed",this,"menu_option"); + + } TextEdit::~TextEdit() diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 86696ca5a5..24a72afd48 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -31,6 +31,7 @@ #include "scene/gui/control.h" #include "scene/gui/scroll_bar.h" +#include "scene/gui/popup_menu.h" #include "scene/main/timer.h" @@ -73,19 +74,27 @@ class TextEdit : public Control { Ref<StyleBox> style_normal; Ref<StyleBox> style_focus; Ref<Font> font; + Color caret_color; + Color line_number_color; Color font_color; Color font_selected_color; Color keyword_color; + Color number_color; + Color function_color; + Color member_variable_color; Color selection_color; Color mark_color; Color breakpoint_color; Color current_line_color; Color brace_mismatch_color; Color word_highlighted_color; + Color search_result_color; + Color search_result_border_color; int row_height; int line_spacing; int line_number_w; + int breakpoint_gutter_width; Size2 size; } cache; @@ -205,6 +214,10 @@ class TextEdit : public Control { bool syntax_coloring; int tab_size; + Timer *caret_blink_timer; + bool caret_blink_enabled; + bool draw_caret; + bool setting_row; bool wrap; bool draw_tabs; @@ -212,6 +225,8 @@ class TextEdit : public Control { bool text_changed_dirty; bool undo_enabled; bool line_numbers; + bool draw_breakpoint_gutter; + int breakpoint_gutter_width; bool highlight_all_occurrences; bool scroll_past_end_of_file_enabled; @@ -219,6 +234,7 @@ class TextEdit : public Control { bool brace_matching_enabled; bool auto_indent; bool cut_copy_line; + bool insert_mode; uint64_t last_dblclk; @@ -238,6 +254,11 @@ class TextEdit : public Control { bool callhint_below; Vector2 callhint_offset; + String search_text; + uint32_t search_flags; + int search_result_line; + int search_result_col; + int get_visible_rows() const; int get_char_count(); @@ -253,17 +274,21 @@ class TextEdit : public Control { void _pre_shift_selection(); void _post_shift_selection(); + void _scroll_lines_up(); + void _scroll_lines_down(); + // void mouse_motion(const Point& p_pos, const Point& p_rel, int p_button_mask); Size2 get_minimum_size(); int get_row_height() const; + void _reset_caret_blink_timer(); + void _toggle_draw_caret(); + void _update_caches(); void _cursor_changed_emit(); void _text_changed_emit(); - void _begin_compex_operation(); - void _end_compex_operation(); void _push_current_op(); /* super internal api, undo/redo builds on it */ @@ -272,10 +297,12 @@ class TextEdit : public Control { String _base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const; void _base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column); - int _get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column); + int _get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column); DVector<int> _search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const; + PopupMenu *menu; + void _clear(); void _cancel_completion(); void _cancel_code_hint(); @@ -303,6 +330,17 @@ protected: public: + enum MenuItems { + MENU_CUT, + MENU_COPY, + MENU_PASTE, + MENU_CLEAR, + MENU_SELECT_ALL, + MENU_UNDO, + MENU_MAX + + }; + enum SearchFlags { SEARCH_MATCH_CASE=1, @@ -315,6 +353,9 @@ public: //void delete_char(); //void delete_line(); + void begin_complex_operation(); + void end_complex_operation(); + void set_text(String p_text); void insert_text_at_cursor(const String& p_text); void insert_at(const String& p_text, int at); @@ -328,6 +369,9 @@ public: void set_line(int line, String new_text); void backspace_at_cursor(); + void indent_selection_left(); + void indent_selection_right(); + inline void set_scroll_pass_end_of_file(bool p_enabled) { scroll_past_end_of_file_enabled = p_enabled; update(); @@ -351,6 +395,12 @@ public: int cursor_get_column() const; int cursor_get_line() const; + bool cursor_get_blink_enabled() const; + void cursor_set_blink_enabled(const bool p_enabled); + + float cursor_get_blink_speed() const; + void cursor_set_blink_speed(const float p_speed); + void set_readonly(bool p_readonly); void set_max_chars(int p_max_chars); @@ -368,6 +418,10 @@ public: void select(int p_from_line,int p_from_column,int p_to_line,int p_to_column); void deselect(); + void set_search_text(const String& p_search_text); + void set_search_flags(uint32_t p_flags); + void set_current_search_result(int line, int col); + void set_highlight_all_occurrences(const bool p_enabled); bool is_selection_active() const; int get_selection_from_line() const; @@ -388,6 +442,9 @@ public: void set_draw_tabs(bool p_draw); bool is_drawing_tabs() const; + void set_insert_mode(bool p_enabled); + bool is_insert_mode() const; + void add_keyword_color(const String& p_keyword,const Color& p_color); void add_color_region(const String& p_begin_key=String(),const String& p_end_key=String(),const Color &p_color=Color(),bool p_line_only=false); void set_symbol_color(const Color& p_color); @@ -404,8 +461,16 @@ public: uint32_t get_saved_version() const; void tag_saved_version(); + void menu_option(int p_option); + void set_show_line_numbers(bool p_show); + void set_draw_breakpoint_gutter(bool p_draw); + bool is_drawing_breakpoint_gutter() const; + + void set_breakpoint_gutter_width(int p_gutter_width); + int get_breakpoint_gutter_width() const; + void set_tooltip_request_func(Object *p_obj, const StringName& p_function, const Variant& p_udata); void set_completion(bool p_enabled,const Vector<String>& p_prefixes); @@ -413,6 +478,8 @@ public: void set_code_hint(const String& p_hint); void query_code_comple(); + PopupMenu *get_menu() const; + String get_text_for_completion(); virtual bool is_text_field() const; diff --git a/scene/gui/texture_frame.cpp b/scene/gui/texture_frame.cpp index 73fecf591a..2fe8735fda 100644 --- a/scene/gui/texture_frame.cpp +++ b/scene/gui/texture_frame.cpp @@ -37,9 +37,31 @@ void TextureFrame::_notification(int p_what) { return; - Size2 s=expand?get_size():texture->get_size(); + RID ci = get_canvas_item(); - draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); + + switch(stretch_mode) { + case STRETCH_SCALE_ON_EXPAND: { + Size2 s=expand?get_size():texture->get_size(); + draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); + } break; + case STRETCH_SCALE: { + draw_texture_rect(texture,Rect2(Point2(),get_size()),false,modulate); + } break; + case STRETCH_TILE: { + draw_texture_rect(texture,Rect2(Point2(),get_size()),true,modulate); + } break; + case STRETCH_KEEP: { + draw_texture_rect(texture,Rect2(Point2(),texture->get_size()),false,modulate); + + } break; + case STRETCH_KEEP_CENTERED: { + + Vector2 ofs = (get_size() - texture->get_size())/2; + draw_texture_rect(texture,Rect2(ofs,texture->get_size()),false,modulate); + } break; + } + /* Vector<Point2> points; @@ -76,11 +98,19 @@ void TextureFrame::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_modulate"), & TextureFrame::get_modulate ); ObjectTypeDB::bind_method(_MD("set_expand","enable"), & TextureFrame::set_expand ); ObjectTypeDB::bind_method(_MD("has_expand"), & TextureFrame::has_expand ); + ObjectTypeDB::bind_method(_MD("set_stretch_mode","stretch_mode"), & TextureFrame::set_stretch_mode ); + ObjectTypeDB::bind_method(_MD("get_stretch_mode"), & TextureFrame::get_stretch_mode ); ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") ); + ADD_PROPERTYNO( PropertyInfo( Variant::INT, "stretch_mode",PROPERTY_HINT_ENUM,"Scale On Expand (Compat),Scale,Tile,Keep,Keep Centered"), _SCS("set_stretch_mode"),_SCS("get_stretch_mode") ); + BIND_CONSTANT( STRETCH_SCALE_ON_EXPAND ); + BIND_CONSTANT( STRETCH_SCALE ); + BIND_CONSTANT( STRETCH_TILE ); + BIND_CONSTANT( STRETCH_KEEP ); + BIND_CONSTANT( STRETCH_KEEP_CENTERED ); } @@ -121,12 +151,24 @@ bool TextureFrame::has_expand() const { return expand; } +void TextureFrame::set_stretch_mode(StretchMode p_mode) { + + stretch_mode=p_mode; + update(); +} + +TextureFrame::StretchMode TextureFrame::get_stretch_mode() const { + + return stretch_mode; +} + TextureFrame::TextureFrame() { expand=false; modulate=Color(1,1,1,1); set_ignore_mouse(true); + stretch_mode=STRETCH_SCALE_ON_EXPAND; } diff --git a/scene/gui/texture_frame.h b/scene/gui/texture_frame.h index e1f0de92df..a4acf588ea 100644 --- a/scene/gui/texture_frame.h +++ b/scene/gui/texture_frame.h @@ -36,10 +36,19 @@ class TextureFrame : public Control { OBJ_TYPE(TextureFrame,Control); - +public: + enum StretchMode { + STRETCH_SCALE_ON_EXPAND, //default, for backwards compatibility + STRETCH_SCALE, + STRETCH_TILE, + STRETCH_KEEP, + STRETCH_KEEP_CENTERED, + }; +private: bool expand; Color modulate; Ref<Texture> texture; + StretchMode stretch_mode; protected: void _notification(int p_what); @@ -57,9 +66,13 @@ public: void set_expand(bool p_expand); bool has_expand() const; + void set_stretch_mode(StretchMode p_mode); + StretchMode get_stretch_mode() const; + TextureFrame(); ~TextureFrame(); }; +VARIANT_ENUM_CAST( TextureFrame::StretchMode ); #endif // TEXTURE_FRAME_H diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 718206dee1..2c39aea08c 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -154,7 +154,7 @@ void TreeItem::set_text(int p_column,String p_text) { ERR_FAIL_INDEX( p_column, cells.size() ); cells[p_column].text=p_text; - if (cells[p_column].mode==TreeItem::CELL_MODE_RANGE) { + if (cells[p_column].mode==TreeItem::CELL_MODE_RANGE || cells[p_column].mode==TreeItem::CELL_MODE_RANGE_EXPRESSION) { cells[p_column].min=0; cells[p_column].max=p_text.get_slice_count(","); @@ -604,10 +604,11 @@ String TreeItem::get_tooltip(int p_column) const{ return cells[p_column].tooltip; } -void TreeItem::set_custom_bg_color(int p_column,const Color& p_color) { +void TreeItem::set_custom_bg_color(int p_column,const Color& p_color,bool p_bg_outline) { ERR_FAIL_INDEX( p_column, cells.size() ); cells[p_column].custom_bg_color=true; + cells[p_column].custom_bg_outline=p_bg_outline; cells[p_column].bg_color=p_color; _changed_notify(p_column); } @@ -685,7 +686,7 @@ void TreeItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_custom_color","column","color"),&TreeItem::set_custom_color); ObjectTypeDB::bind_method(_MD("clear_custom_color","column"),&TreeItem::clear_custom_color); - ObjectTypeDB::bind_method(_MD("set_custom_bg_color","column","color"),&TreeItem::set_custom_bg_color); + ObjectTypeDB::bind_method(_MD("set_custom_bg_color","column","color","just_outline"),&TreeItem::set_custom_bg_color,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("clear_custom_bg_color","column"),&TreeItem::clear_custom_bg_color); ObjectTypeDB::bind_method(_MD("get_custom_bg_color","column"),&TreeItem::get_custom_bg_color); @@ -704,6 +705,7 @@ void TreeItem::_bind_methods() { BIND_CONSTANT( CELL_MODE_STRING ); BIND_CONSTANT( CELL_MODE_CHECK ); BIND_CONSTANT( CELL_MODE_RANGE ); + BIND_CONSTANT( CELL_MODE_RANGE_EXPRESSION ); BIND_CONSTANT( CELL_MODE_ICON ); BIND_CONSTANT( CELL_MODE_CUSTOM ); @@ -756,6 +758,13 @@ TreeItem::~TreeItem() { if (tree && tree->selected_item==this) tree->selected_item=NULL; + + if (tree && tree->drop_mode_over==this) + tree->drop_mode_over=NULL; + + if (tree && tree->single_select_defer==this) + tree->single_select_defer=NULL; + if (tree && tree->edited_item==this) { tree->edited_item=NULL; tree->pressing_for_editor=false; @@ -796,17 +805,13 @@ void Tree::update_cache() { cache.font_color=get_color("font_color"); cache.font_color_selected=get_color("font_color_selected"); cache.guide_color=get_color("guide_color"); + cache.drop_position_color=get_color("drop_position_color"); cache.hseparation=get_constant("hseparation"); cache.vseparation=get_constant("vseparation"); cache.item_margin=get_constant("item_margin"); cache.button_margin=get_constant("button_margin"); cache.guide_width=get_constant("guide_width"); - Ref<StyleBox> title_button; - Ref<StyleBox> title_button_hover; - Ref<StyleBox> title_button_pressed; - Color title_button_color; - cache.title_button = get_stylebox("title_button_normal"); cache.title_button_pressed = get_stylebox("title_button_pressed"); cache.title_button_hover = get_stylebox("title_button_hover"); @@ -1086,7 +1091,34 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2& Rect2 r=cell_rect; r.pos.x-=cache.hseparation; r.size.x+=cache.hseparation; - VisualServer::get_singleton()->canvas_item_add_rect(ci,r,p_item->cells[i].bg_color); + if (p_item->cells[i].custom_bg_outline) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,r.size.x,1),p_item->cells[i].bg_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y+r.size.y-1,r.size.x,1),p_item->cells[i].bg_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,1,r.size.y),p_item->cells[i].bg_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x+r.size.x-1,r.pos.y,1,r.size.y),p_item->cells[i].bg_color); + } else { + VisualServer::get_singleton()->canvas_item_add_rect(ci,r,p_item->cells[i].bg_color); + } + } + + if (drop_mode_flags && drop_mode_over==p_item) { + + Rect2 r=cell_rect; + + if (drop_mode_section==-1 || drop_mode_section==0) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,r.size.x,1),cache.drop_position_color); + + } + + if (drop_mode_section==0) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,1,r.size.y),cache.drop_position_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x+r.size.x-1,r.pos.y,1,r.size.y),cache.drop_position_color); + + } + + if (drop_mode_section==1 || drop_mode_section==0) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y+r.size.y,r.size.x,1),cache.drop_position_color); + } } Color col=p_item->cells[i].custom_color?p_item->cells[i].color:get_color( p_item->cells[i].selected?"font_color_selected":"font_color"); @@ -1127,7 +1159,8 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2& //font->draw( ci, text_pos, p_item->cells[i].text, col,item_rect.size.x-check_w ); } break; - case TreeItem::CELL_MODE_RANGE: { + case TreeItem::CELL_MODE_RANGE: + case TreeItem::CELL_MODE_RANGE_EXPRESSION: { if (p_item->cells[i].text!="") { @@ -1278,6 +1311,25 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2& } +int Tree::_count_selected_items(TreeItem* p_from) const { + + int count=0; + for(int i=0;i<columns.size();i++) { + if (p_from->is_selected(i)) + count++; + } + + if (p_from->get_children()) { + count+=_count_selected_items(p_from->get_children()); + } + + if (p_from->get_next()) { + count+=_count_selected_items(p_from->get_next()); + } + + return count; + +} void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col,TreeItem *p_prev,bool *r_in_range) { TreeItem::Cell &selected_cell=p_selected->cells[p_col]; @@ -1511,10 +1563,10 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ col_width-=w+cache.button_margin; } - if (p_button==BUTTON_LEFT) { + if (p_button==BUTTON_LEFT || (p_button==BUTTON_RIGHT && allow_rmb_select)) { /* process selection */ - if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON || c.mode==TreeItem::CELL_MODE_CHECK)) { + if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it' s confusing for check emit_signal("item_activated"); return -1; @@ -1522,10 +1574,13 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ if (select_mode==SELECT_MULTI && p_mod.command && c.selectable) { - if (!c.selected) { + if (!c.selected || p_button==BUTTON_RIGHT) { p_item->select(col); emit_signal("multi_selected",p_item,col,true); + if (p_button==BUTTON_RIGHT) { + emit_signal("item_rmb_selected",get_local_mouse_pos()); + } //p_item->selected_signal.call(col); @@ -1545,8 +1600,26 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ bool inrange=false; select_single_item( p_item, root, col,selected_item,&inrange ); + if (p_button==BUTTON_RIGHT) { + emit_signal("item_rmb_selected",get_local_mouse_pos()); + } } else { - select_single_item( p_item, root, col ); + + int icount = _count_selected_items(root); + + if (select_mode==SELECT_MULTI && icount>1 && p_button!=BUTTON_RIGHT) { + single_select_defer=p_item; + single_select_defer_column=col; + } else { + + if (p_button!=BUTTON_RIGHT || !c.selected) { + select_single_item( p_item, root, col ); + } + + if (p_button==BUTTON_RIGHT) { + emit_signal("item_rmb_selected",get_local_mouse_pos()); + } + } } //if (!c.selected && select_mode==SELECT_MULTI) { @@ -1566,7 +1639,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ /* editing */ - bool bring_up_editor=c.selected;// && already_selected; + bool bring_up_editor=force_select_on_already_selected ? (c.selected && already_selected) : c.selected; bool bring_up_value_editor=false; String editor_text=c.text; @@ -1594,7 +1667,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ } } break; - case TreeItem::CELL_MODE_RANGE: { + case TreeItem::CELL_MODE_RANGE: + case TreeItem::CELL_MODE_RANGE_EXPRESSION: { if (c.text!="") { @@ -1794,6 +1868,13 @@ void Tree::text_editor_enter(String p_text) { //popup_edited_item->edited_signal.call( popup_edited_item_col ); } break; + case TreeItem::CELL_MODE_RANGE_EXPRESSION: { + + if(evaluator) + c.val=evaluator->eval(p_text); + else + c.val=p_text.to_double(); + } break; default: { ERR_FAIL(); } } @@ -2149,6 +2230,31 @@ void Tree::_input_event(InputEvent p_event) { } + if (drop_mode_flags && root) { + + Point2 mpos=Point2(b.x,b.y); + mpos -= cache.bg->get_offset(); + mpos.y-=_get_title_button_height(); + if (mpos.y>=0) { + + if (h_scroll->is_visible()) + mpos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + mpos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,mpos,col,h,section); + + if (it!=drop_mode_over || section!=drop_mode_section) { + drop_mode_over=it; + drop_mode_section=section; + update(); + } + } + } + + + if (cache.hover_type!=old_hover || cache.hover_index!=old_index) { update(); } @@ -2201,6 +2307,12 @@ void Tree::_input_event(InputEvent p_event) { if (b.button_index==BUTTON_LEFT) { + + if (single_select_defer) { + select_single_item( single_select_defer, root, single_select_defer_column ); + single_select_defer=NULL; + } + range_click_timer->stop(); if (pressing_for_editor) { @@ -2249,12 +2361,13 @@ void Tree::_input_event(InputEvent p_event) { } switch(b.button_index) { + case BUTTON_RIGHT: case BUTTON_LEFT: { Ref<StyleBox> bg = cache.bg; Point2 pos = Point2(b.x,b.y) - bg->get_offset(); cache.click_type=Cache::CLICK_NONE; - if (show_column_titles) { + if (show_column_titles && b.button_index==BUTTON_LEFT) { pos.y-=_get_title_button_height(); if (pos.y<0) { @@ -2276,8 +2389,12 @@ void Tree::_input_event(InputEvent p_event) { } } - if (!root) + if (!root || (!root->get_children() && hide_root)) { + if (b.button_index==BUTTON_RIGHT && allow_rmb_select) { + emit_signal("empty_tree_rmb_selected",get_local_mouse_pos()); + } break; + } click_handled=false; pressing_for_editor=false; @@ -2291,6 +2408,9 @@ void Tree::_input_event(InputEvent p_event) { } + if (b.button_index==BUTTON_RIGHT) + break; + if (drag_touching) { set_fixed_process(false); drag_touching_deaccel=false; @@ -2372,7 +2492,7 @@ bool Tree::edit_selected() { item_edited(col,s); return true; - } else if (c.mode==TreeItem::CELL_MODE_RANGE && c.text!="") { + } else if ((c.mode==TreeItem::CELL_MODE_RANGE||c.mode==TreeItem::CELL_MODE_RANGE_EXPRESSION) && c.text!="") { popup_menu->clear(); for (int i=0;i<c.text.get_slice_count(",");i++) { @@ -2389,7 +2509,7 @@ bool Tree::edit_selected() { popup_edited_item_col=col; return true; - } else if (c.mode==TreeItem::CELL_MODE_STRING || c.mode==TreeItem::CELL_MODE_RANGE) { + } else if (c.mode==TreeItem::CELL_MODE_STRING || c.mode==TreeItem::CELL_MODE_RANGE || c.mode==TreeItem::CELL_MODE_RANGE_EXPRESSION ) { Point2i textedpos=get_global_pos() + rect.pos; text_editor->set_pos( textedpos ); @@ -2398,7 +2518,7 @@ bool Tree::edit_selected() { text_editor->set_text( c.mode==TreeItem::CELL_MODE_STRING?c.text:rtos(c.val) ); text_editor->select_all(); - if (c.mode==TreeItem::CELL_MODE_RANGE) { + if (c.mode==TreeItem::CELL_MODE_RANGE || c.mode==TreeItem::CELL_MODE_RANGE_EXPRESSION ) { value_editor->set_pos(textedpos + Point2i(0,text_editor->get_size().height) ); value_editor->set_size( Size2(rect.size.width,1)); @@ -2512,6 +2632,15 @@ void Tree::_notification(int p_what) { update_cache();; } + if (p_what==NOTIFICATION_DRAG_END) { + + drop_mode_flags=0; + update(); + } + if (p_what==NOTIFICATION_DRAG_BEGIN) { + + single_select_defer=NULL; + } if (p_what==NOTIFICATION_FIXED_PROCESS) { if (drag_touching) { @@ -3125,7 +3254,7 @@ void Tree::_do_incr_search(const String& p_add) { } -TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_column,int &h) const { +TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_column,int &h,int §ion) const { Point2 pos = p_pos; @@ -3135,15 +3264,33 @@ TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_co h = compute_item_height(p_item)+cache.vseparation;; if (pos.y<h) { + if (drop_mode_flags==DROP_MODE_ON_ITEM) { + section=0; + } else if (drop_mode_flags==DROP_MODE_INBETWEEN) { + section=pos.y<h/2?-1:1; + } else if (pos.y<h/4) { + section=-1; + } else if (pos.y>=(h*3/4)) { + section=1; + } else { + section=0; + } + for(int i=0;i<columns.size();i++) { int w = get_column_width(i); if (pos.x < w) { r_column=i; + + return p_item; } pos.x-=w; } + + + + return NULL; } else { @@ -3162,7 +3309,7 @@ TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_co int ch; - TreeItem *r = _find_item_at_pos(n,pos,r_column,ch); + TreeItem *r = _find_item_at_pos(n,pos,r_column,ch,section); pos.y-=ch; h+=ch; if (r) @@ -3174,6 +3321,88 @@ TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_co } +int Tree::get_column_at_pos(const Point2& p_pos) const { + + if (root) { + + Point2 pos=p_pos; + pos -= cache.bg->get_offset(); + pos.y-=_get_title_button_height(); + if (pos.y<0) + return -1; + + if (h_scroll->is_visible()) + pos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + pos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); + + if (it) { + return col; + } + } + + return -1; + +} + +int Tree::get_drop_section_at_pos(const Point2& p_pos) const { + + if (root) { + + Point2 pos=p_pos; + pos -= cache.bg->get_offset(); + pos.y-=_get_title_button_height(); + if (pos.y<0) + return -100; + + if (h_scroll->is_visible()) + pos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + pos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); + + if (it) { + return section; + } + } + + return -100; + +} +TreeItem* Tree::get_item_at_pos(const Point2& p_pos) const { + + + if (root) { + + Point2 pos=p_pos; + pos -= cache.bg->get_offset(); + pos.y-=_get_title_button_height(); + if (pos.y<0) + return NULL; + + if (h_scroll->is_visible()) + pos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + pos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); + + if (it) { + + return it; + } + } + + return NULL; + +} + String Tree::get_tooltip(const Point2& p_pos) const { if (root) { @@ -3189,8 +3418,8 @@ String Tree::get_tooltip(const Point2& p_pos) const { if (v_scroll->is_visible()) pos.y+=v_scroll->get_val(); - int col,h; - TreeItem *it = _find_item_at_pos(root,pos,col,h); + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); if (it) { @@ -3227,6 +3456,46 @@ bool Tree::is_folding_hidden() const { return hide_folding; } +void Tree::set_value_evaluator(ValueEvaluator *p_evaluator) { + evaluator = p_evaluator; +} + +void Tree::set_drop_mode_flags(int p_flags) { + if (drop_mode_flags==p_flags) + return; + drop_mode_flags=p_flags; + if (drop_mode_flags==0) { + drop_mode_over=NULL; + } + + update(); +} + +int Tree::get_drop_mode_flags() const { + + return drop_mode_flags; +} + +void Tree::set_single_select_cell_editing_only_when_already_selected(bool p_enable) { + + force_select_on_already_selected=p_enable; +} + +bool Tree::get_single_select_cell_editing_only_when_already_selected() const { + + return force_select_on_already_selected; +} + + +void Tree::set_allow_rmb_select(bool p_allow) { + + allow_rmb_select=p_allow; +} + +bool Tree::get_allow_rmb_select() const{ + + return allow_rmb_select; +} void Tree::_bind_methods() { @@ -3239,7 +3508,7 @@ void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("_scroll_moved"),&Tree::_scroll_moved); ObjectTypeDB::bind_method(_MD("clear"),&Tree::clear); - ObjectTypeDB::bind_method(_MD("create_item:TreeItem","parent:TreeItem"),&Tree::_create_item,DEFVAL((Object*)NULL)); + ObjectTypeDB::bind_method(_MD("create_item:TreeItem","parent:TreeItem"),&Tree::_create_item,DEFVAL(Variant())); ObjectTypeDB::bind_method(_MD("get_root:TreeItem"),&Tree::get_root); ObjectTypeDB::bind_method(_MD("set_column_min_width","column","min_width"),&Tree::set_column_min_width); @@ -3260,6 +3529,8 @@ void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_edited_column"),&Tree::get_edited_column); ObjectTypeDB::bind_method(_MD("get_custom_popup_rect"),&Tree::get_custom_popup_rect); ObjectTypeDB::bind_method(_MD("get_item_area_rect","item:TreeItem","column"),&Tree::_get_item_rect,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("get_item_at_pos:TreeItem","pos"),&Tree::get_item_at_pos); + ObjectTypeDB::bind_method(_MD("get_column_at_pos","pos"),&Tree::get_column_at_pos); ObjectTypeDB::bind_method(_MD("ensure_cursor_is_visible"),&Tree::ensure_cursor_is_visible); @@ -3273,10 +3544,21 @@ void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_hide_folding","hide"),&Tree::set_hide_folding); ObjectTypeDB::bind_method(_MD("is_folding_hidden"),&Tree::is_folding_hidden); + ObjectTypeDB::bind_method(_MD("set_drop_mode_flags","flags"),&Tree::set_drop_mode_flags); + ObjectTypeDB::bind_method(_MD("get_drop_mode_flags"),&Tree::get_drop_mode_flags); + + 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_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); ADD_SIGNAL( MethodInfo("item_selected")); ADD_SIGNAL( MethodInfo("cell_selected")); ADD_SIGNAL( MethodInfo("multi_selected",PropertyInfo(Variant::OBJECT,"item"),PropertyInfo(Variant::INT,"column"),PropertyInfo(Variant::BOOL,"selected")) ); + 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_collapsed",PropertyInfo(Variant::OBJECT,"item"))); //ADD_SIGNAL( MethodInfo("item_doubleclicked" ) ); @@ -3287,6 +3569,11 @@ void Tree::_bind_methods() { BIND_CONSTANT( SELECT_SINGLE ); BIND_CONSTANT( SELECT_ROW ); BIND_CONSTANT( SELECT_MULTI ); + + BIND_CONSTANT( DROP_MODE_DISABLED ); + BIND_CONSTANT( DROP_MODE_ON_ITEM ); + BIND_CONSTANT( DROP_MODE_INBETWEEN ); + } Tree::Tree() { @@ -3367,6 +3654,15 @@ Tree::Tree() { hide_folding=false; + evaluator=NULL; + + drop_mode_flags=0; + drop_mode_over=NULL; + drop_mode_section=0; + single_select_defer=NULL; + force_select_on_already_selected=false; + + allow_rmb_select=false; } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 1ba1c6a494..1dad26dffe 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -34,6 +34,7 @@ #include "scene/gui/line_edit.h" #include "scene/gui/scroll_bar.h" #include "scene/gui/slider.h" +#include "core/helper/value_evaluator.h" /** @author Juan Linietsky <reduzio@gmail.com> @@ -52,6 +53,7 @@ public: CELL_MODE_STRING, ///< just a string CELL_MODE_CHECK, ///< string + check CELL_MODE_RANGE, ///< Contains a range + CELL_MODE_RANGE_EXPRESSION, ///< Contains a range CELL_MODE_ICON, ///< Contains a icon, not editable CELL_MODE_CUSTOM, ///< Contains a custom value, show a string, and an edit button }; @@ -77,7 +79,9 @@ friend class Tree; bool custom_color; Color color; bool custom_bg_color; + bool custom_bg_outline; Color bg_color; + Variant meta; String tooltip; @@ -224,7 +228,7 @@ public: Color get_custom_color(int p_column) const; void clear_custom_color(int p_column); - void set_custom_bg_color(int p_column,const Color& p_color); + void set_custom_bg_color(int p_column, const Color& p_color, bool p_bg_outline=false); void clear_custom_bg_color(int p_column); Color get_custom_bg_color(int p_column) const; @@ -255,6 +259,12 @@ public: SELECT_MULTI }; + enum DropModeFlags { + DROP_MODE_DISABLED=0, + DROP_MODE_ON_ITEM=1, + DROP_MODE_INBETWEEN=2 + }; + private: friend class TreeItem; @@ -263,6 +273,11 @@ friend class TreeItem; TreeItem *selected_item; TreeItem *edited_item; + TreeItem *drop_mode_over; + int drop_mode_section; + + TreeItem *single_select_defer; + int single_select_defer_column; int pressed_button; bool pressing_for_editor; @@ -287,6 +302,8 @@ friend class TreeItem; int blocked; + int drop_mode_flags; + struct ColumnInfo { int min_width; @@ -359,6 +376,8 @@ friend class TreeItem; Color font_color; Color font_color_selected; Color guide_color; + Color drop_position_color; + int hseparation; int vseparation; int item_margin; @@ -403,7 +422,7 @@ friend class TreeItem; TreeItem* _search_item_text(TreeItem *p_at, const String& p_find,int *r_col,bool p_selectable,bool p_backwards=false); - TreeItem* _find_item_at_pos(TreeItem *p_current, const Point2& p_pos,int& r_column,int &h) const; + TreeItem* _find_item_at_pos(TreeItem *p_current, const Point2& p_pos, int& r_column, int &h, int §ion) const; /* float drag_speed; float drag_accum; @@ -419,9 +438,16 @@ friend class TreeItem; bool drag_touching; bool drag_touching_deaccel; bool click_handled; + bool allow_rmb_select; + + bool force_select_on_already_selected; bool hide_folding; + ValueEvaluator *evaluator; + + int _count_selected_items(TreeItem* p_from) const; + protected: static void _bind_methods(); @@ -429,10 +455,16 @@ protected: Object* _create_item(Object *p_parent) { return create_item(p_parent->cast_to<TreeItem>() ); } TreeItem *_get_next_selected(Object *p_item) { return get_next_selected(p_item->cast_to<TreeItem>() ); } Rect2 _get_item_rect(Object *p_item,int p_column) const { return get_item_rect(p_item->cast_to<TreeItem>(),p_column ); } + + public: virtual String get_tooltip(const Point2& p_pos) const; + TreeItem* get_item_at_pos(const Point2& p_pos) const; + int get_column_at_pos(const Point2& p_pos) const; + int get_drop_section_at_pos(const Point2& p_pos) const; + void clear(); TreeItem* create_item(TreeItem *p_parent=0); @@ -482,7 +514,16 @@ public: void set_hide_folding(bool p_hide); bool is_folding_hidden() const; + void set_drop_mode_flags(int p_flags); + int get_drop_mode_flags() const; + + void set_single_select_cell_editing_only_when_already_selected(bool p_enable); + bool get_single_select_cell_editing_only_when_already_selected() const; + + void set_allow_rmb_select(bool p_allow); + bool get_allow_rmb_select() const; + void set_value_evaluator(ValueEvaluator *p_evaluator); Tree(); ~Tree(); diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index fc7cc0a362..26227d6389 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -131,7 +131,7 @@ void VideoPlayer::_notification(int p_notification) { if (!playback->is_playing()) return; - double audio_time = OS::get_singleton()->get_ticks_usec()/1000000.0; //AudioServer::get_singleton()->get_mix_time(); + double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec()); //AudioServer::get_singleton()->get_mix_time(); double delta = last_audio_time==0?0:audio_time-last_audio_time; last_audio_time=audio_time; @@ -360,8 +360,8 @@ bool VideoPlayer::has_autoplay() const { void VideoPlayer::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&VideoPlayer::set_stream); - ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&VideoPlayer::get_stream); + ObjectTypeDB::bind_method(_MD("set_stream","stream:VideoStream"),&VideoPlayer::set_stream); + ObjectTypeDB::bind_method(_MD("get_stream:VideoStream"),&VideoPlayer::get_stream); ObjectTypeDB::bind_method(_MD("play"),&VideoPlayer::play); ObjectTypeDB::bind_method(_MD("stop"),&VideoPlayer::stop); |