diff options
Diffstat (limited to 'scene')
39 files changed, 491 insertions, 246 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index b605be47df..fc5e5cbba2 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -641,6 +641,9 @@ void CanvasItem::update() { void CanvasItem::set_modulate(const Color &p_modulate) { + if (modulate == p_modulate) + return; + modulate = p_modulate; VisualServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate); } @@ -679,6 +682,9 @@ CanvasItem *CanvasItem::get_parent_item() const { void CanvasItem::set_self_modulate(const Color &p_self_modulate) { + if (self_modulate == p_self_modulate) + return; + self_modulate = p_self_modulate; VisualServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate); } @@ -689,6 +695,9 @@ Color CanvasItem::get_self_modulate() const { void CanvasItem::set_light_mask(int p_light_mask) { + if (light_mask == p_light_mask) + return; + light_mask = p_light_mask; VS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask); } diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 202c7c9cf2..228b67990c 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -376,11 +376,12 @@ void CollisionObject2D::set_only_update_transform_changes(bool p_enable) { void CollisionObject2D::_update_pickable() { if (!is_inside_tree()) return; - bool pickable = this->pickable && is_inside_tree() && is_visible_in_tree(); + + bool is_pickable = pickable && is_visible_in_tree(); if (area) - Physics2DServer::get_singleton()->area_set_pickable(rid, pickable); + Physics2DServer::get_singleton()->area_set_pickable(rid, is_pickable); else - Physics2DServer::get_singleton()->body_set_pickable(rid, pickable); + Physics2DServer::get_singleton()->body_set_pickable(rid, is_pickable); } String CollisionObject2D::get_configuration_warning() const { diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 7cc937a64a..9b6020e0fd 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1446,6 +1446,14 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) { void KinematicBody2D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { last_valid_transform = get_global_transform(); + + // Reset move_and_slide() data. + on_floor = false; + on_floor_body = RID(); + on_ceiling = false; + on_wall = false; + colliders.clear(); + floor_velocity = Vector2(); } if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 2cd05b5c50..15423f8c5e 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1944,6 +1944,7 @@ TileMap::TileMap() { quadrant_order_dirty = false; quadrant_size = 16; cell_size = Size2(64, 64); + custom_transform = Transform2D(64, 0, 0, 64, 0, 0); collision_layer = 1; collision_mask = 1; friction = 1; diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 63301fc226..735b393171 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -105,7 +105,8 @@ void CollisionObject::_mouse_exit() { void CollisionObject::_update_pickable() { if (!is_inside_tree()) return; - bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree(); + + bool pickable = ray_pickable && is_visible_in_tree(); if (area) PhysicsServer::get_singleton()->area_set_ray_pickable(rid, pickable); else diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index ebac968cb4..0756be5fc8 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1387,6 +1387,18 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) { return slide_colliders[p_bounce]; } +void KinematicBody::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE) { + // Reset move_and_slide() data. + on_floor = false; + on_floor_body = RID(); + on_ceiling = false; + on_wall = false; + colliders.clear(); + floor_velocity = Vector3(); + } +} + void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index aa6030d44e..0967cb9cd5 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -162,6 +162,7 @@ protected: ShapePair(int p_bs, int p_ls) { body_shape = p_bs; local_shape = p_ls; + tagged = false; } }; struct RigidBody_RemoveAction { @@ -314,6 +315,7 @@ private: Ref<KinematicCollision> _get_slide_collision(int p_bounce); protected: + void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index fc5523633d..a9dacc442c 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -286,6 +286,18 @@ SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const { return alpha_cut; } +void SpriteBase3D::set_billboard_mode(SpatialMaterial::BillboardMode p_mode) { + + ERR_FAIL_INDEX(p_mode, 3); + billboard_mode = p_mode; + _queue_update(); +} + +SpatialMaterial::BillboardMode SpriteBase3D::get_billboard_mode() const { + + return billboard_mode; +} + void SpriteBase3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_centered", "centered"), &SpriteBase3D::set_centered); @@ -318,6 +330,9 @@ void SpriteBase3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_alpha_cut_mode", "mode"), &SpriteBase3D::set_alpha_cut_mode); ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode); + ClassDB::bind_method(D_METHOD("set_billboard_mode", "mode"), &SpriteBase3D::set_billboard_mode); + ClassDB::bind_method(D_METHOD("get_billboard_mode"), &SpriteBase3D::get_billboard_mode); + ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect); ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh); @@ -333,6 +348,7 @@ void SpriteBase3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001"), "set_pixel_size", "get_pixel_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis", PROPERTY_HINT_ENUM, "X-Axis,Y-Axis,Z-Axis"), "set_axis", "get_axis"); ADD_GROUP("Flags", ""); + ADD_PROPERTY(PropertyInfo(Variant::INT, "billboard", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard"), "set_billboard_mode", "get_billboard_mode"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_draw_flag", "get_draw_flag", FLAG_TRANSPARENT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "shaded"), "set_draw_flag", "get_draw_flag", FLAG_SHADED); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "double_sided"), "set_draw_flag", "get_draw_flag", FLAG_DOUBLE_SIDED); @@ -361,6 +377,7 @@ SpriteBase3D::SpriteBase3D() { flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED; alpha_cut = ALPHA_CUT_DISABLED; + billboard_mode = SpatialMaterial::BILLBOARD_DISABLED; axis = Vector3::AXIS_Z; pixel_size = 0.01; modulate = Color(1, 1, 1, 1); @@ -463,7 +480,7 @@ void Sprite3D::_draw() { tangent = Plane(1, 0, 0, 1); } - RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS); + RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); VS::get_singleton()->immediate_set_material(immediate, mat); VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); @@ -788,7 +805,7 @@ void AnimatedSprite3D::_draw() { tangent = Plane(1, 0, 0, -1); } - RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS); + RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y); VS::get_singleton()->immediate_set_material(immediate, mat); diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 97a426b5b9..065931de84 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -80,6 +80,7 @@ private: bool flags[FLAG_MAX]; AlphaCutMode alpha_cut; + SpatialMaterial::BillboardMode billboard_mode; bool pending_update; void _im_update(); @@ -130,6 +131,8 @@ public: void set_alpha_cut_mode(AlphaCutMode p_mode); AlphaCutMode get_alpha_cut_mode() const; + void set_billboard_mode(SpatialMaterial::BillboardMode p_mode); + SpatialMaterial::BillboardMode get_billboard_mode() const; virtual Rect2 get_item_rect() const = 0; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 6745b57cff..bb7c400cfe 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -1412,6 +1412,7 @@ void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<A Vector<Activity> activity; for (int i = 0; i < node->get_input_count(); i++) { Activity a; + a.activity = 0; a.last_pass = 0; activity.push_back(a); } diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 65e9cccd05..6b3e89af6c 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -39,158 +39,191 @@ Size2 Button::get_minimum_size() const { if (clip_text) minsize.width = 0; - Ref<Texture> _icon; - if (icon.is_null() && has_icon("icon")) - _icon = Control::get_icon("icon"); - else - _icon = icon; - - if (!_icon.is_null()) { - - minsize.height = MAX(minsize.height, _icon->get_height()); - minsize.width += _icon->get_width(); - if (xl_text != "") - minsize.width += get_constant("hseparation"); + if (!expand_icon) { + Ref<Texture> _icon; + if (icon.is_null() && has_icon("icon")) + _icon = Control::get_icon("icon"); + else + _icon = icon; + + if (!_icon.is_null()) { + + minsize.height = MAX(minsize.height, _icon->get_height()); + minsize.width += _icon->get_width(); + if (xl_text != "") + minsize.width += get_constant("hseparation"); + } } return get_stylebox("normal")->get_minimum_size() + minsize; } void Button::_set_internal_margin(Margin p_margin, float p_value) { + _internal_margin[p_margin] = p_value; } void Button::_notification(int p_what) { - if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { + switch (p_what) { + case NOTIFICATION_TRANSLATION_CHANGED: { - xl_text = tr(text); - minimum_size_changed(); - update(); - } + xl_text = tr(text); + minimum_size_changed(); + update(); + } break; + case NOTIFICATION_DRAW: { - if (p_what == NOTIFICATION_DRAW) { + RID ci = get_canvas_item(); + Size2 size = get_size(); + Color color; + Color color_icon(1, 1, 1, 1); - RID ci = get_canvas_item(); - Size2 size = get_size(); - Color color; - Color color_icon(1, 1, 1, 1); + Ref<StyleBox> style = get_stylebox("normal"); - Ref<StyleBox> style = get_stylebox("normal"); + switch (get_draw_mode()) { + case DRAW_NORMAL: { - switch (get_draw_mode()) { - - case DRAW_NORMAL: { + style = get_stylebox("normal"); + if (!flat) + style->draw(ci, Rect2(Point2(0, 0), size)); + color = get_color("font_color"); + if (has_color("icon_color_normal")) + color_icon = get_color("icon_color_normal"); + } break; + case DRAW_HOVER_PRESSED: { + + if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) { + style = get_stylebox("hover_pressed"); + if (!flat) + style->draw(ci, Rect2(Point2(0, 0), size)); + if (has_color("font_color_hover_pressed")) + color = get_color("font_color_hover_pressed"); + else + color = get_color("font_color"); + if (has_color("icon_color_hover_pressed")) + color_icon = get_color("icon_color_hover_pressed"); + + break; + } + FALLTHROUGH; + } + case DRAW_PRESSED: { - style = get_stylebox("normal"); - if (!flat) - style->draw(ci, Rect2(Point2(0, 0), size)); - color = get_color("font_color"); - if (has_color("icon_color_normal")) - color_icon = get_color("icon_color_normal"); - } break; - case DRAW_HOVER_PRESSED: { - if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) { - style = get_stylebox("hover_pressed"); + style = get_stylebox("pressed"); if (!flat) style->draw(ci, Rect2(Point2(0, 0), size)); - if (has_color("font_color_hover_pressed")) - color = get_color("font_color_hover_pressed"); + if (has_color("font_color_pressed")) + color = get_color("font_color_pressed"); else color = get_color("font_color"); - if (has_color("icon_color_hover_pressed")) - color_icon = get_color("icon_color_hover_pressed"); + if (has_color("icon_color_pressed")) + color_icon = get_color("icon_color_pressed"); - break; - } - FALLTHROUGH; + } break; + case DRAW_HOVER: { + + style = get_stylebox("hover"); + if (!flat) + style->draw(ci, Rect2(Point2(0, 0), size)); + color = get_color("font_color_hover"); + if (has_color("icon_color_hover")) + color_icon = get_color("icon_color_hover"); + + } break; + case DRAW_DISABLED: { + + style = get_stylebox("disabled"); + if (!flat) + style->draw(ci, Rect2(Point2(0, 0), size)); + color = get_color("font_color_disabled"); + if (has_color("icon_color_disabled")) + color_icon = get_color("icon_color_disabled"); + + } break; } - case DRAW_PRESSED: { - - style = get_stylebox("pressed"); - if (!flat) - style->draw(ci, Rect2(Point2(0, 0), size)); - if (has_color("font_color_pressed")) - color = get_color("font_color_pressed"); - else - color = get_color("font_color"); - if (has_color("icon_color_pressed")) - color_icon = get_color("icon_color_pressed"); - - } break; - case DRAW_HOVER: { - - style = get_stylebox("hover"); - if (!flat) - style->draw(ci, Rect2(Point2(0, 0), size)); - color = get_color("font_color_hover"); - if (has_color("icon_color_hover")) - color_icon = get_color("icon_color_hover"); - - } break; - case DRAW_DISABLED: { - - style = get_stylebox("disabled"); - if (!flat) - style->draw(ci, Rect2(Point2(0, 0), size)); - color = get_color("font_color_disabled"); - if (has_color("icon_color_disabled")) - color_icon = get_color("icon_color_disabled"); - - } break; - } - if (has_focus()) { + if (has_focus()) { - Ref<StyleBox> style2 = get_stylebox("focus"); - style2->draw(ci, Rect2(Point2(), size)); - } + Ref<StyleBox> style2 = get_stylebox("focus"); + style2->draw(ci, Rect2(Point2(), size)); + } - Ref<Font> font = get_font("font"); - Ref<Texture> _icon; - if (icon.is_null() && has_icon("icon")) - _icon = Control::get_icon("icon"); - else - _icon = icon; + Ref<Font> font = get_font("font"); + Ref<Texture> _icon; + if (icon.is_null() && has_icon("icon")) + _icon = Control::get_icon("icon"); + else + _icon = icon; + + Rect2 icon_region = Rect2(); + if (!_icon.is_null()) { - Point2 icon_ofs = (!_icon.is_null()) ? Point2(_icon->get_width() + get_constant("hseparation"), 0) : Point2(); - int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; - Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0; - - switch (align) { - case ALIGN_LEFT: { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation"); - text_ofs.y += style->get_offset().y; - } break; - case ALIGN_CENTER: { - if (text_ofs.x < 0) - text_ofs.x = 0; - text_ofs += icon_ofs; - text_ofs += style->get_offset(); - } break; - case ALIGN_RIGHT: { - if (_internal_margin[MARGIN_RIGHT] > 0) { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation"); + int valign = size.height - style->get_minimum_size().y; + if (is_disabled()) { + color_icon.a = 0.4; + } + + float icon_ofs_region = 0; + if (_internal_margin[MARGIN_LEFT] > 0) { + icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_constant("hseparation"); + } + + if (expand_icon) { + Size2 _size = get_size() - style->get_offset() * 2; + _size.width -= get_constant("hseparation") + icon_ofs_region; + if (!clip_text) + _size.width -= get_font("font")->get_string_size(xl_text).width; + float icon_width = icon->get_width() * _size.height / icon->get_height(); + float icon_height = _size.height; + + if (icon_width > _size.width) { + icon_width = _size.width; + icon_height = icon->get_height() * icon_width / icon->get_width(); + } + + icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); } else { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x; + icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), icon->get_size()); } - text_ofs.y += style->get_offset().y; - } break; - } + } - text_ofs.y += font->get_ascent(); - font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1); - if (!_icon.is_null()) { + Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_constant("hseparation"), 0) : Point2(); + int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; + Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0; + + switch (align) { + case ALIGN_LEFT: { + if (_internal_margin[MARGIN_LEFT] > 0) { + text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation"); + } else { + text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x; + } + text_ofs.y += style->get_offset().y; + } break; + case ALIGN_CENTER: { + if (text_ofs.x < 0) + text_ofs.x = 0; + text_ofs += icon_ofs; + text_ofs += style->get_offset(); + } break; + case ALIGN_RIGHT: { + if (_internal_margin[MARGIN_RIGHT] > 0) { + text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation"); + } else { + text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x; + } + text_ofs.y += style->get_offset().y; + } break; + } + + text_ofs.y += font->get_ascent(); + font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1); - int valign = size.height - style->get_minimum_size().y; - if (is_disabled()) - color_icon.a = 0.4; - if (_internal_margin[MARGIN_LEFT] > 0) { - _icon->draw(ci, style->get_offset() + Point2(_internal_margin[MARGIN_LEFT] + get_constant("hseparation"), Math::floor((valign - _icon->get_height()) / 2.0)), color_icon); - } else { - _icon->draw(ci, style->get_offset() + Point2(0, Math::floor((valign - _icon->get_height()) / 2.0)), color_icon); + if (!_icon.is_null() && icon_region.size.width > 0) { + draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), icon->get_size()), color_icon); } - } + } break; } } @@ -224,6 +257,18 @@ Ref<Texture> Button::get_icon() const { return icon; } +void Button::set_expand_icon(bool p_expand_icon) { + + expand_icon = p_expand_icon; + update(); + minimum_size_changed(); +} + +bool Button::is_expand_icon() const { + + return expand_icon; +} + void Button::set_flat(bool p_flat) { flat = p_flat; @@ -265,6 +310,8 @@ void Button::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text"), &Button::get_text); ClassDB::bind_method(D_METHOD("set_button_icon", "texture"), &Button::set_icon); ClassDB::bind_method(D_METHOD("get_button_icon"), &Button::get_icon); + ClassDB::bind_method(D_METHOD("set_expand_icon"), &Button::set_expand_icon); + ClassDB::bind_method(D_METHOD("is_expand_icon"), &Button::is_expand_icon); ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &Button::set_flat); ClassDB::bind_method(D_METHOD("set_clip_text", "enabled"), &Button::set_clip_text); ClassDB::bind_method(D_METHOD("get_clip_text"), &Button::get_clip_text); @@ -281,12 +328,14 @@ void Button::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon"), "set_expand_icon", "is_expand_icon"); } Button::Button(const String &p_text) { flat = false; clip_text = false; + expand_icon = false; set_mouse_filter(MOUSE_FILTER_STOP); set_text(p_text); align = ALIGN_CENTER; diff --git a/scene/gui/button.h b/scene/gui/button.h index 370809060e..1fff2cfda7 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -49,6 +49,7 @@ private: String text; String xl_text; Ref<Texture> icon; + bool expand_icon; bool clip_text; TextAlign align; float _internal_margin[4]; @@ -59,8 +60,6 @@ protected: static void _bind_methods(); public: - // - virtual Size2 get_minimum_size() const; void set_text(const String &p_text); @@ -69,6 +68,9 @@ public: void set_icon(const Ref<Texture> &p_icon); Ref<Texture> get_icon() const; + void set_expand_icon(bool p_expand_icon); + bool is_expand_icon() const; + void set_flat(bool p_flat); bool is_flat() const; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 1d529f4e72..6dd9e401f6 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -964,6 +964,7 @@ void ColorPickerButton::_update_picker() { popup->connect("popup_hide", this, "set_pressed", varray(false)); picker->set_pick_color(color); picker->set_edit_alpha(edit_alpha); + emit_signal("picker_created"); } } @@ -980,6 +981,7 @@ void ColorPickerButton::_bind_methods() { ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color"))); ADD_SIGNAL(MethodInfo("popup_closed")); + ADD_SIGNAL(MethodInfo("picker_created")); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index b655feecbe..034e9266f6 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2918,7 +2918,11 @@ void Control::_bind_methods() { BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size")); - BIND_VMETHOD(MethodInfo(Variant::OBJECT, "get_drag_data", PropertyInfo(Variant::VECTOR2, "position"))); + + MethodInfo get_drag_data = MethodInfo("get_drag_data", PropertyInfo(Variant::VECTOR2, "position")); + get_drag_data.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + BIND_VMETHOD(get_drag_data); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text"))); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 0c096f0d97..9bc593ea3b 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -430,7 +430,7 @@ void FileDialog::update_file_list() { TreeItem *ti = tree->create_item(root); ti->set_text(0, dir_name); ti->set_icon(0, folder); - ti->set_icon_color(0, folder_color); + ti->set_icon_modulate(0, folder_color); Dictionary d; d["name"] = dir_name; diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index 75f5f79873..09ef6f26bf 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -241,9 +241,13 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) { float newofs = CLAMP(x / float(total_w), 0, 1); - //Snap to nearest point if holding shift - if (mm->get_shift()) { - float snap_threshold = 0.03; + // Snap to "round" coordinates if holding Ctrl. + // Be more precise if holding Shift as well + if (mm->get_control()) { + newofs = Math::stepify(newofs, mm->get_shift() ? 0.025 : 0.1); + } else if (mm->get_shift()) { + // Snap to nearest point if holding just Shift + const float snap_threshold = 0.03; float smallest_ofs = snap_threshold; bool found = false; int nearest_point = 0; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index fdffb26cb5..7827c66841 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -276,6 +276,11 @@ void GraphEdit::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal"); port_grab_distance_vertical = get_constant("port_grab_distance_vertical"); + + zoom_minus->set_icon(get_icon("minus")); + zoom_reset->set_icon(get_icon("reset")); + zoom_plus->set_icon(get_icon("more")); + snap_button->set_icon(get_icon("snap")); } if (p_what == NOTIFICATION_READY) { Size2 hmin = h_scroll->get_combined_minimum_size(); @@ -290,11 +295,6 @@ void GraphEdit::_notification(int p_what) { h_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); h_scroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -hmin.height); h_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); - - zoom_minus->set_icon(get_icon("minus")); - zoom_reset->set_icon(get_icon("reset")); - zoom_plus->set_icon(get_icon("more")); - snap_button->set_icon(get_icon("snap")); } if (p_what == NOTIFICATION_DRAW) { diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index f7bef4ed39..5b2f8812d5 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -210,6 +210,7 @@ void GraphNode::_notification(int p_what) { int close_offset = get_constant("close_offset"); int close_h_offset = get_constant("close_h_offset"); Color close_color = get_color("close_color"); + Color resizer_color = get_color("resizer_color"); Ref<Font> title_font = get_font("title_font"); int title_offset = get_constant("title_offset"); int title_h_offset = get_constant("title_h_offset"); @@ -274,7 +275,7 @@ void GraphNode::_notification(int p_what) { } if (resizable) { - draw_texture(resizer, get_size() - resizer->get_size()); + draw_texture(resizer, get_size() - resizer->get_size(), resizer_color); } } break; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 8223ea6d1e..1aed858c94 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -916,9 +916,12 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const { - if (!underline_meta || selection.click) + if (!underline_meta) return CURSOR_ARROW; + if (selection.click) + return CURSOR_IBEAM; + if (main->first_invalid_line < main->lines.size()) return CURSOR_ARROW; //invalid diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 461281a4ed..a840e3fec1 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -382,7 +382,10 @@ void ScrollContainer::update_scrollbars() { Size2 min = child_max_size; - if (!scroll_v || min.height <= size.height - hmin.height) { + bool hide_scroll_v = !scroll_v || min.height <= size.height - hmin.height; + bool hide_scroll_h = !scroll_h || min.width <= size.width - vmin.width; + + if (hide_scroll_v) { v_scroll->hide(); v_scroll->set_max(0); @@ -391,11 +394,16 @@ void ScrollContainer::update_scrollbars() { v_scroll->show(); v_scroll->set_max(min.height); - v_scroll->set_page(size.height - hmin.height); + if (hide_scroll_h) { + v_scroll->set_page(size.height); + } else { + v_scroll->set_page(size.height - hmin.height); + } + scroll.y = v_scroll->get_value(); } - if (!scroll_h || min.width <= size.width - vmin.width) { + if (hide_scroll_h) { h_scroll->hide(); h_scroll->set_max(0); @@ -404,7 +412,12 @@ void ScrollContainer::update_scrollbars() { h_scroll->show(); h_scroll->set_max(min.width); - h_scroll->set_page(size.width - vmin.width); + if (hide_scroll_v) { + h_scroll->set_page(size.width); + } else { + h_scroll->set_page(size.width - vmin.width); + } + scroll.x = h_scroll->get_value(); } } diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 6ada0cba97..172c366c41 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "spin_box.h" +#include "core/math/expression.h" #include "core/os/input.h" Size2 SpinBox::get_minimum_size() const { @@ -50,15 +51,19 @@ void SpinBox::_value_changed(double) { void SpinBox::_text_entered(const String &p_string) { - /* - if (!p_string.is_numeric()) + Ref<Expression> expr; + expr.instance(); + // Ignore the prefix and suffix in the expression + Error err = expr->parse(p_string.trim_prefix(prefix + " ").trim_suffix(" " + suffix)); + if (err != OK) { return; - */ - String value = p_string; - if (prefix != "" && p_string.begins_with(prefix)) - value = p_string.substr(prefix.length(), p_string.length() - prefix.length()); - set_value(value.to_double()); - _value_changed(0); + } + + Variant value = expr->execute(Array(), NULL, false); + if (value.get_type() != Variant::NIL) { + set_value(value); + _value_changed(0); + } } LineEdit *SpinBox::get_line_edit() { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index be8f1cf36e..292d80be9d 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -840,7 +840,7 @@ Size2 TabContainer::get_minimum_size() const { Control *c = tabs[i]; - if (!c->is_visible_in_tree()) + if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size) continue; Size2 cms = c->get_combined_minimum_size(); @@ -887,6 +887,13 @@ int TabContainer::get_tabs_rearrange_group() const { return tabs_rearrange_group; } +void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { + use_hidden_tabs_for_min_size = p_use_hidden_tabs; +} + +bool TabContainer::get_use_hidden_tabs_for_min_size() const { + return use_hidden_tabs_for_min_size; +} void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input); @@ -913,6 +920,9 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group); ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group); + ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size); + ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size); + ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback); ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed); ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab); @@ -925,6 +935,7 @@ void TabContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size"); BIND_ENUM_CONSTANT(ALIGN_LEFT); BIND_ENUM_CONSTANT(ALIGN_CENTER); @@ -945,4 +956,5 @@ TabContainer::TabContainer() { popup = NULL; drag_to_rearrange_enabled = false; tabs_rearrange_group = -1; + use_hidden_tabs_for_min_size = false; } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index f7a9fb64fd..0314f86837 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -59,6 +59,7 @@ private: int _get_top_margin() const; Popup *popup; bool drag_to_rearrange_enabled; + bool use_hidden_tabs_for_min_size; int tabs_rearrange_group; Vector<Control *> _get_tabs() const; @@ -118,6 +119,8 @@ public: bool get_drag_to_rearrange_enabled() const; void set_tabs_rearrange_group(int p_group_id); int get_tabs_rearrange_group() const; + void set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs); + bool get_use_hidden_tabs_for_min_size() const; TabContainer(); }; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index f8c31121be..0464cc1ac8 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -559,7 +559,7 @@ void TextEdit::_update_selection_mode_line() { click_select_held->start(); } -void TextEdit::_update_minimap_scroll() { +void TextEdit::_update_minimap_click() { Point2 mp = get_local_mouse_position(); int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); @@ -573,6 +573,13 @@ void TextEdit::_update_minimap_scroll() { int row; _get_minimap_mouse_row(Point2i(mp.x, mp.y), row); + if (row >= get_first_visible_line() && (row < get_last_visible_line() || row >= (text.size() - 1))) { + minimap_scroll_ratio = v_scroll->get_as_ratio(); + minimap_scroll_click_pos = mp.y; + can_drag_minimap = true; + return; + } + int wi; int first_line = row - num_lines_from_rows(row, 0, -get_visible_rows() / 2, wi) + 1; double delta = get_scroll_pos_for_line(first_line, wi) - get_v_scroll(); @@ -583,11 +590,27 @@ void TextEdit::_update_minimap_scroll() { } } +void TextEdit::_update_minimap_drag() { + + if (!can_drag_minimap) { + return; + } + + int control_height = _get_control_height(); + int scroll_height = v_scroll->get_max() * (minimap_char_size.y + minimap_line_spacing); + if (control_height > scroll_height) { + control_height = scroll_height; + } + + Point2 mp = get_local_mouse_position(); + double diff = (mp.y - minimap_scroll_click_pos) / control_height; + v_scroll->set_as_ratio(minimap_scroll_ratio + diff); +} + void TextEdit::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - _update_caches(); if (cursor_changed_dirty) MessageQueue::get_singleton()->push_call(this, "_cursor_changed_emit"); @@ -596,12 +619,16 @@ void TextEdit::_notification(int p_what) { _update_wrap_at(); } break; case NOTIFICATION_RESIZED: { - _update_scrollbars(); - call_deferred("_update_wrap_at"); + _update_wrap_at(); + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible()) { + call_deferred("_update_scrollbars"); + call_deferred("_update_wrap_at"); + } } break; case NOTIFICATION_THEME_CHANGED: { - _update_caches(); _update_wrap_at(); syntax_highlighting_cache.clear(); @@ -899,12 +926,7 @@ void TextEdit::_notification(int p_what) { // calculate viewport size and y offset int viewport_height = (draw_amount - 1) * minimap_line_height; - int control_height = size.height; - control_height -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) { - control_height -= h_scroll->get_size().height; - } - control_height -= viewport_height; + int control_height = _get_control_height() - viewport_height; int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount)); // calculate the first line. @@ -918,8 +940,7 @@ void TextEdit::_notification(int p_what) { int minimap_draw_amount = minimap_visible_lines + times_line_wraps(minimap_line + 1); // draw the minimap - Color viewport_color = cache.current_line_color; - viewport_color.a /= 2; + Color viewport_color = (cache.background_color.get_v() < 0.5) ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1); VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, cache.minimap_width, viewport_height), viewport_color); for (int i = 0; i < minimap_draw_amount; i++) { @@ -2071,12 +2092,7 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const // calculate viewport size and y offset int viewport_height = (draw_amount - 1) * minimap_line_height; - int control_height = get_size().height; - control_height -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) { - control_height -= h_scroll->get_size().height; - } - control_height -= viewport_height; + int control_height = _get_control_height() - viewport_height; int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount)); // calculate the first line. @@ -2187,12 +2203,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int row, col; _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); - if (mb->get_command() && highlighted_word != String()) { - - emit_signal("symbol_lookup", highlighted_word, row, col); - return; - } - // Toggle breakpoint on gutter click. if (draw_breakpoint_gutter) { int gutter = cache.style_normal->get_margin(MARGIN_LEFT); @@ -2240,7 +2250,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { // minimap if (draw_minimap) { - _update_minimap_scroll(); + _update_minimap_click(); if (dragging_minimap) { return; } @@ -2361,8 +2371,17 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_command() && highlighted_word != String()) { + int row, col; + _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); + + emit_signal("symbol_lookup", highlighted_word, row, col); + return; + } + dragging_minimap = false; dragging_selection = false; + can_drag_minimap = false; click_select_held->stop(); } @@ -2411,7 +2430,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _reset_caret_blink_timer(); if (draw_minimap && !dragging_selection) { - _update_minimap_scroll(); + _update_minimap_drag(); } if (!dragging_minimap) { @@ -3506,6 +3525,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; case KEY_Z: { + if (readonly) { + break; + } + if (!k->get_command()) { scancode_handled = false; break; @@ -3518,6 +3541,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; case KEY_Y: { + if (readonly) { + break; + } + if (!k->get_command()) { scancode_handled = false; break; @@ -3992,7 +4019,7 @@ void TextEdit::_line_edited_from(int p_line) { if (syntax_highlighting_cache.size() > 0) { cache_size = syntax_highlighting_cache.back()->key(); - for (int i = p_line - 1; i < cache_size; i++) { + for (int i = p_line - 1; i <= cache_size; i++) { if (syntax_highlighting_cache.has(i)) { syntax_highlighting_cache.erase(i); } @@ -4019,23 +4046,21 @@ Size2 TextEdit::get_minimum_size() const { return cache.style_normal->get_minimum_size(); } -int TextEdit::get_visible_rows() const { +int TextEdit::_get_control_height() const { + int control_height = get_size().height; + control_height -= cache.style_normal->get_minimum_size().height; + if (h_scroll->is_visible_in_tree()) { + control_height -= h_scroll->get_size().height; + } + return control_height; +} - int total = get_size().height; - total -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) - total -= h_scroll->get_size().height; - total /= get_row_height(); - return total; +int TextEdit::get_visible_rows() const { + return _get_control_height() / get_row_height(); } int TextEdit::_get_minimap_visible_rows() const { - int total = get_size().height; - total -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) - total -= h_scroll->get_size().height; - total /= (minimap_char_size.y + minimap_line_spacing); - return total; + return _get_control_height() / (minimap_char_size.y + minimap_line_spacing); } int TextEdit::get_total_visible_rows() const { @@ -4599,7 +4624,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { return CURSOR_ARROW; } else { int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); - if (p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { + if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { return CURSOR_ARROW; } @@ -5340,6 +5365,9 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l break; } pos_from = last_pos - p_key.length(); + if (pos_from < 0) { + break; + } } } else { while ((last_pos = (p_search_flags & SEARCH_MATCH_CASE) ? text_line.find(p_key, pos_from) : text_line.findn(p_key, pos_from)) != -1) { @@ -6126,10 +6154,7 @@ int TextEdit::get_last_visible_line_wrap_index() const { double TextEdit::get_visible_rows_offset() const { - double total = get_size().height; - total -= cache.style_normal->get_minimum_size().height; - if (h_scroll->is_visible_in_tree()) - total -= h_scroll->get_size().height; + double total = _get_control_height(); total /= (double)get_row_height(); total = total - floor(total); total = -CLAMP(total, 0.001, 1) + 1; @@ -6539,9 +6564,21 @@ void TextEdit::set_line(int line, String new_text) { } void TextEdit::insert_at(const String &p_text, int at) { - cursor_set_column(0); - cursor_set_line(at, false, true); _insert_text(at, 0, p_text + "\n"); + if (cursor.line >= at) { + // offset cursor when located after inserted line + ++cursor.line; + } + if (is_selection_active()) { + if (selection.from_line >= at) { + // offset selection when located after inserted line + ++selection.from_line; + ++selection.to_line; + } else if (selection.to_line >= at) { + // extend selection that includes inserted line + ++selection.to_line; + } + } } void TextEdit::set_show_line_numbers(bool p_show) { @@ -7019,6 +7056,9 @@ TextEdit::TextEdit() { scrolling = false; minimap_clicked = false; dragging_minimap = false; + can_drag_minimap = false; + minimap_scroll_ratio = 0; + minimap_scroll_click_pos = 0; dragging_selection = false; target_v_scroll = 0; v_scroll_speed = 80; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 889be3eaa5..9c568acd93 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -334,7 +334,10 @@ private: bool scrolling; bool dragging_selection; bool dragging_minimap; + bool can_drag_minimap; bool minimap_clicked; + double minimap_scroll_ratio; + double minimap_scroll_click_pos; float target_v_scroll; float v_scroll_speed; @@ -406,7 +409,8 @@ private: void _update_selection_mode_word(); void _update_selection_mode_line(); - void _update_minimap_scroll(); + void _update_minimap_click(); + void _update_minimap_drag(); void _scroll_up(real_t p_delta); void _scroll_down(real_t p_delta); @@ -418,6 +422,7 @@ private: //void mouse_motion(const Point& p_pos, const Point& p_rel, int p_button_mask); Size2 get_minimum_size() const; + int _get_control_height() const; int get_row_height() const; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index b5f949aeb7..e9b0bd8f38 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -205,24 +205,26 @@ void TextureButton::_notification(int p_what) { case STRETCH_KEEP_ASPECT_COVERED: { size = get_size(); Size2 tex_size = texdraw->get_size(); - Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height); - float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height; - Size2 scaledTexSize = tex_size * scale; - Point2 ofs2 = ((scaledTexSize - size) / scale).abs() / 2.0f; + Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height); + float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height; + Size2 scaled_tex_size = tex_size * scale; + Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f; _texture_region = Rect2(ofs2, size / scale); } break; } } + _position_rect = Rect2(ofs, size); - if (_tile) + if (_tile) { draw_texture_rect(texdraw, _position_rect, _tile); - else + } else { draw_texture_rect_region(texdraw, _position_rect, _texture_region); + } } else { _position_rect = Rect2(); } - if (has_focus() && focused.is_valid()) { + if (has_focus() && focused.is_valid()) { draw_texture_rect(focused, _position_rect, false); }; } break; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 6c8aa35e3c..b7451faad3 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -224,14 +224,14 @@ Rect2 TreeItem::get_icon_region(int p_column) const { return cells[p_column].icon_region; } -void TreeItem::set_icon_color(int p_column, const Color &p_icon_color) { +void TreeItem::set_icon_modulate(int p_column, const Color &p_modulate) { ERR_FAIL_INDEX(p_column, cells.size()); - cells.write[p_column].icon_color = p_icon_color; + cells.write[p_column].icon_color = p_modulate; _changed_notify(p_column); } -Color TreeItem::get_icon_color(int p_column) const { +Color TreeItem::get_icon_modulate(int p_column) const { ERR_FAIL_INDEX_V(p_column, cells.size(), Color()); return cells[p_column].icon_color; @@ -744,6 +744,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_icon_max_width", "column", "width"), &TreeItem::set_icon_max_width); ClassDB::bind_method(D_METHOD("get_icon_max_width", "column"), &TreeItem::get_icon_max_width); + ClassDB::bind_method(D_METHOD("set_icon_modulate", "column", "modulate"), &TreeItem::set_icon_modulate); + ClassDB::bind_method(D_METHOD("get_icon_modulate", "column"), &TreeItem::get_icon_modulate); + ClassDB::bind_method(D_METHOD("set_range", "column", "value"), &TreeItem::set_range); ClassDB::bind_method(D_METHOD("get_range", "column"), &TreeItem::get_range); ClassDB::bind_method(D_METHOD("set_range_config", "column", "min", "max", "step", "expr"), &TreeItem::set_range_config, DEFVAL(false)); @@ -1259,10 +1262,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 check_ofs.y += Math::floor((real_t)(item_rect.size.y - checked->get_height()) / 2); if (p_item->cells[i].checked) { - - checked->draw(ci, check_ofs, icon_col); + checked->draw(ci, check_ofs); } else { - unchecked->draw(ci, check_ofs, icon_col); + unchecked->draw(ci, check_ofs); } int check_w = checked->get_width() + cache.hseparation; @@ -1274,8 +1276,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 draw_item_rect(p_item->cells[i], item_rect, col, icon_col); - //font->draw( ci, text_pos, p_item->cells[i].text, col,item_rect.size.x-check_w ); - } break; case TreeItem::CELL_MODE_RANGE: { if (p_item->cells[i].text != "") { @@ -1305,18 +1305,16 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 font->draw(ci, text_pos, s, col, item_rect.size.x - downarrow->get_width()); - //? Point2i arrow_pos = item_rect.position; arrow_pos.x += item_rect.size.x - downarrow->get_width(); arrow_pos.y += Math::floor(((item_rect.size.y - downarrow->get_height())) / 2.0); - downarrow->draw(ci, arrow_pos, icon_col); + downarrow->draw(ci, arrow_pos); } else { Ref<Texture> updown = cache.updown; String valtext = String::num(p_item->cells[i].val, Math::range_step_decimals(p_item->cells[i].step)); - //String valtext = rtos( p_item->cells[i].val ); if (p_item->cells[i].suffix != String()) valtext += " " + p_item->cells[i].suffix; @@ -1330,7 +1328,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 updown_pos.x += item_rect.size.x - updown->get_width(); updown_pos.y += Math::floor(((item_rect.size.y - updown->get_height())) / 2.0); - updown->draw(ci, updown_pos, icon_col); + updown->draw(ci, updown_pos); } } break; @@ -1348,13 +1346,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 icon_ofs += item_rect.position; draw_texture_rect(p_item->cells[i].icon, Rect2(icon_ofs, icon_size), false, icon_col); - //p_item->cells[i].icon->draw(ci, icon_ofs); } break; case TreeItem::CELL_MODE_CUSTOM: { - //int option = (int)p_item->cells[i].val; - if (p_item->cells[i].custom_draw_obj) { Object *cdo = ObjectDB::get_instance(p_item->cells[i].custom_draw_obj); @@ -1429,10 +1424,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 arrow->draw(ci, p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset); } - //separator - //get_painter()->draw_fill_rect( Point2i(0,pos.y),Size2i(get_size().width,1),color( COLOR_TREE_GRID) ); - - //pos=p_pos; //reset pos } Point2 children_pos = p_pos; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index b57923e24b..fdc6da5055 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -193,8 +193,8 @@ public: void set_icon_region(int p_column, const Rect2 &p_icon_region); Rect2 get_icon_region(int p_column) const; - void set_icon_color(int p_column, const Color &p_icon_color); - Color get_icon_color(int p_column) const; + void set_icon_modulate(int p_column, const Color &p_modulate); + Color get_icon_modulate(int p_column) const; void set_icon_max_width(int p_column, int p_max); int get_icon_max_width(int p_column) const; diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp index 3f7a110c1b..35696a0459 100644 --- a/scene/gui/viewport_container.cpp +++ b/scene/gui/viewport_container.cpp @@ -211,4 +211,5 @@ ViewportContainer::ViewportContainer() { stretch = false; shrink = 1; set_process_input(true); + set_process_unhandled_input(true); } diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index e21e47f8a8..6c922adbd2 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -60,10 +60,10 @@ Error HTTPRequest::_parse_url(const String &p_url) { use_ssl = true; port = 443; } else { - ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL."); + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL: " + url + "."); } - ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short."); + ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + "."); int slash_pos = url.find("/"); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 98d63650d3..6c89016ea3 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -33,6 +33,7 @@ #include "core/io/marshalls.h" #include "core/io/resource_loader.h" #include "core/message_queue.h" +#include "core/os/dir_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/print_string.h" @@ -1673,6 +1674,12 @@ void SceneTree::drop_files(const Vector<String> &p_files, int p_from_screen) { MainLoop::drop_files(p_files, p_from_screen); } +void SceneTree::global_menu_action(const Variant &p_id, const Variant &p_meta) { + + emit_signal("global_menu_action", p_id, p_meta); + MainLoop::global_menu_action(p_id, p_meta); +} + Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) { Ref<SceneTreeTimer> stt; @@ -1894,6 +1901,7 @@ void SceneTree::_bind_methods() { ADD_SIGNAL(MethodInfo("physics_frame")); ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); + ADD_SIGNAL(MethodInfo("global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta"))); ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("connected_to_server")); @@ -1946,6 +1954,38 @@ bool SceneTree::is_using_font_oversampling() const { return use_font_oversampling; } +void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + + if (p_function == "change_scene") { + DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); + List<String> directories; + directories.push_back(dir_access->get_current_dir()); + + while (!directories.empty()) { + dir_access->change_dir(directories.back()->get()); + directories.pop_back(); + + dir_access->list_dir_begin(); + String filename = dir_access->get_next(); + + while (filename != "") { + if (filename == "." || filename == "..") { + filename = dir_access->get_next(); + continue; + } + + if (dir_access->dir_exists(filename)) { + directories.push_back(dir_access->get_current_dir().plus_file(filename)); + } else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) { + r_options->push_back("\"" + dir_access->get_current_dir().plus_file(filename) + "\""); + } + + filename = dir_access->get_next(); + } + } + } +} + SceneTree::SceneTree() { if (singleton == NULL) singleton = this; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index afb653e242..d387886d61 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -407,6 +407,8 @@ public: static SceneTree *get_singleton() { return singleton; } void drop_files(const Vector<String> &p_files, int p_from_screen = 0); + void global_menu_action(const Variant &p_id, const Variant &p_meta); + void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; //network API diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 93eea2ad0b..b5c82ce4e3 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2289,32 +2289,34 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (from && p_event->is_pressed()) { Control *next = NULL; - if (p_event->is_action_pressed("ui_focus_next")) { + Input *input = Input::get_singleton(); + + if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) { next = from->find_next_valid_focus(); } - if (p_event->is_action_pressed("ui_focus_prev")) { + if (p_event->is_action_pressed("ui_focus_prev") && input->is_action_just_pressed("ui_focus_prev")) { next = from->find_prev_valid_focus(); } - if (!mods && p_event->is_action_pressed("ui_up")) { + if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) { next = from->_get_focus_neighbour(MARGIN_TOP); } - if (!mods && p_event->is_action_pressed("ui_left")) { + if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) { next = from->_get_focus_neighbour(MARGIN_LEFT); } - if (!mods && p_event->is_action_pressed("ui_right")) { + if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) { next = from->_get_focus_neighbour(MARGIN_RIGHT); } - if (!mods && p_event->is_action_pressed("ui_down")) { + if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) { next = from->_get_focus_neighbour(MARGIN_BOTTOM); } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 53bdb4145f..06d84302a3 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -304,6 +304,7 @@ void register_scene_types() { ClassDB::register_class<TextureRect>(); ClassDB::register_class<ColorRect>(); ClassDB::register_class<NinePatchRect>(); + ClassDB::register_class<ReferenceRect>(); ClassDB::register_class<TabContainer>(); ClassDB::register_class<Tabs>(); ClassDB::register_virtual_class<Separator>(); @@ -339,7 +340,6 @@ void register_scene_types() { ClassDB::register_virtual_class<TreeItem>(); ClassDB::register_class<OptionButton>(); ClassDB::register_class<SpinBox>(); - ClassDB::register_class<ReferenceRect>(); ClassDB::register_class<ColorPicker>(); ClassDB::register_class<ColorPickerButton>(); ClassDB::register_class<RichTextLabel>(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 1a5f57ce48..d761eb01fe 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -611,6 +611,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("title_font", "GraphNode", default_font); theme->set_color("title_color", "GraphNode", Color(0, 0, 0, 1)); theme->set_color("close_color", "GraphNode", Color(0, 0, 0, 1)); + theme->set_color("resizer_color", "GraphNode", Color(0, 0, 0, 1)); theme->set_constant("title_offset", "GraphNode", 20 * scale); theme->set_constant("close_offset", "GraphNode", 18 * scale); theme->set_constant("port_offset", "GraphNode", 3 * scale); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 0f0974114f..afb7f1102b 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1399,7 +1399,7 @@ Environment::Environment() : fog_depth_enabled = true; fog_depth_begin = 10; - fog_depth_end = 0; + fog_depth_end = 100; fog_depth_curve = 1; fog_transmit_enabled = false; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index daa51aabd7..0de462d616 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1772,7 +1772,7 @@ SpatialMaterial::TextureChannel SpatialMaterial::get_refraction_texture_channel( return refraction_texture_channel; } -RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass) { +RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y) { int version = 0; if (p_shaded) @@ -1785,6 +1785,10 @@ RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent, version |= 8; if (p_double_sided) version |= 16; + if (p_billboard) + version |= 32; + if (p_billboard_y) + version |= 64; if (materials_for_2d[version].is_valid()) { return materials_for_2d[version]->get_rid(); @@ -1800,6 +1804,11 @@ RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent, material->set_flag(FLAG_SRGB_VERTEX_COLOR, true); material->set_flag(FLAG_ALBEDO_FROM_VERTEX_COLOR, true); material->set_flag(FLAG_USE_ALPHA_SCISSOR, p_cut_alpha); + if (p_billboard) { + material->set_billboard_mode(BILLBOARD_ENABLED); + } else if (p_billboard_y) { + material->set_billboard_mode(BILLBOARD_FIXED_Y); + } materials_for_2d[version] = material; diff --git a/scene/resources/material.h b/scene/resources/material.h index 4c368b3f8b..2423d6d48b 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -437,9 +437,7 @@ private: _FORCE_INLINE_ void _validate_feature(const String &text, Feature feature, PropertyInfo &property) const; - enum { - MAX_MATERIALS_FOR_2D = 32 - }; + static const int MAX_MATERIALS_FOR_2D = 128; static Ref<SpatialMaterial> materials_for_2d[MAX_MATERIALS_FOR_2D]; //used by Sprite3D and other stuff @@ -626,7 +624,7 @@ public: static void finish_shaders(); static void flush_changes(); - static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass); + static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false); RID get_shader_rid() const; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 699410719c..e85609468b 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -2463,6 +2463,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad if (pre_symbols.empty()) { pre_symbols.push_back("\t"); pre_symbols.push_back(","); + pre_symbols.push_back(";"); pre_symbols.push_back("{"); pre_symbols.push_back("["); pre_symbols.push_back("("); @@ -2479,9 +2480,9 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad static Vector<String> post_symbols; if (post_symbols.empty()) { - post_symbols.push_back("\0"); post_symbols.push_back("\t"); post_symbols.push_back("\n"); + post_symbols.push_back(","); post_symbols.push_back(";"); post_symbols.push_back("}"); post_symbols.push_back("]"); |