From 5ca70d88a7a038e148ea87c97f1c10e22d97c54c Mon Sep 17 00:00:00 2001
From: Lazy-Rabbit-2001 <2733679597@qq.com>
Date: Wed, 12 Mar 2025 09:57:31 +0800
Subject: [PATCH] Improve usability of Camera2D
---
doc/classes/Camera2D.xml | 3 +
editor/plugins/camera_2d_editor_plugin.cpp | 167 +++++++++++++++++++++
editor/plugins/camera_2d_editor_plugin.h | 80 ++++++++++
editor/register_editor_types.cpp | 2 +
scene/2d/camera_2d.cpp | 105 ++++++++++++-
scene/2d/camera_2d.h | 26 ++++
6 files changed, 378 insertions(+), 5 deletions(-)
create mode 100644 editor/plugins/camera_2d_editor_plugin.cpp
create mode 100644 editor/plugins/camera_2d_editor_plugin.h
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index da98e6c26a0..714288de845 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -142,6 +142,9 @@
Bottom scroll limit in pixels. The camera stops moving when reaching this value, but [member offset] can push the view past the limit.
+
+ If [code]true[/code], the limits will be enabled. Disabling this will allow the camera to focus anywhere, when the four [code]limit_*[/code] properties will not work.
+
Left scroll limit in pixels. The camera stops moving when reaching this value, but [member offset] can push the view past the limit.
diff --git a/editor/plugins/camera_2d_editor_plugin.cpp b/editor/plugins/camera_2d_editor_plugin.cpp
new file mode 100644
index 00000000000..fc075f62217
--- /dev/null
+++ b/editor/plugins/camera_2d_editor_plugin.cpp
@@ -0,0 +1,167 @@
+/**************************************************************************/
+/* camera_2d_editor_plugin.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "camera_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "core/config/project_settings.h"
+#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "editor/themes/editor_scale.h"
+#include "scene/2d/camera_2d.h"
+#include "scene/gui/label.h"
+#include "scene/gui/menu_button.h"
+
+void Camera2DEditor::edit(Camera2D *p_camera) {
+ if (p_camera == selected_camera) {
+ return;
+ }
+ selected_camera = p_camera;
+}
+
+void Camera2DEditor::_menu_option(int p_option) {
+ switch (p_option) {
+ case MENU_SNAP_LIMITS_TO_VIEWPORT: {
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
+ Rect2 prev_rect = selected_camera->get_limit_rect();
+ ur->create_action(TTR("Snap the Limits to the Viewport"), UndoRedo::MERGE_DISABLE, selected_camera);
+ ur->add_do_method(this, "_snap_limits_to_viewport");
+ ur->add_do_reference(selected_camera);
+ ur->add_undo_method(this, "_undo_snap_limits_to_viewport", prev_rect);
+ ur->commit_action();
+ } break;
+ }
+}
+
+void Camera2DEditor::_snap_limits_to_viewport() {
+ selected_camera->set_limit(SIDE_LEFT, 0);
+ selected_camera->set_limit(SIDE_TOP, 0);
+ selected_camera->set_limit(SIDE_RIGHT, GLOBAL_GET("display/window/size/viewport_width"));
+ selected_camera->set_limit(SIDE_BOTTOM, GLOBAL_GET("display/window/size/viewport_height"));
+}
+
+void Camera2DEditor::_undo_snap_limits_to_viewport(const Rect2 &p_prev_rect) {
+ Point2 end = p_prev_rect.get_end();
+ selected_camera->set_limit(SIDE_LEFT, p_prev_rect.position.x);
+ selected_camera->set_limit(SIDE_TOP, p_prev_rect.position.y);
+ selected_camera->set_limit(SIDE_RIGHT, end.x);
+ selected_camera->set_limit(SIDE_BOTTOM, end.y);
+}
+
+void Camera2DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ options->set_button_icon(get_editor_theme_icon(SNAME("Camera2D")));
+ } break;
+ }
+}
+
+void Camera2DEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_snap_limits_to_viewport"), &Camera2DEditor::_snap_limits_to_viewport);
+ ClassDB::bind_method(D_METHOD("_undo_snap_limits_to_viewport", "prev_rect"), &Camera2DEditor::_undo_snap_limits_to_viewport);
+}
+
+Camera2DEditor::Camera2DEditor() {
+ options = memnew(MenuButton);
+
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
+
+ options->set_text(TTRC("Camera2D"));
+
+ options->get_popup()->add_item(TTRC("Snap the Limits to the Viewport"), MENU_SNAP_LIMITS_TO_VIEWPORT);
+ options->set_switch_on_hover(true);
+
+ options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &Camera2DEditor::_menu_option));
+
+#ifdef TOOLS_ENABLED
+ add_user_signal(MethodInfo("_editor_theme_changed"));
+#endif
+}
+
+void Camera2DEditorPlugin::_update_approach_text_visibility() {
+ if (camera_2d_editor->selected_camera == nullptr) {
+ return;
+ }
+ approach_to_move_rect->set_visible(camera_2d_editor->selected_camera->is_limit_enabled());
+}
+
+void Camera2DEditorPlugin::_editor_theme_changed() {
+ approach_to_move_rect->remove_theme_color_override(SceneStringName(font_color));
+ approach_to_move_rect->add_theme_color_override(SceneStringName(font_color), Color(0.6f, 0.6f, 0.6f, 1));
+ approach_to_move_rect->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1));
+ approach_to_move_rect->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE);
+ approach_to_move_rect->add_theme_constant_override("line_spacing", 0);
+}
+
+void Camera2DEditorPlugin::edit(Object *p_object) {
+ Callable update_text = callable_mp(this, &Camera2DEditorPlugin::_update_approach_text_visibility);
+ StringName update_signal = SNAME("_camera_limit_enabled_updated");
+
+ Camera2D *prev_cam = camera_2d_editor->selected_camera;
+ if (prev_cam != nullptr && prev_cam->is_connected(update_signal, update_text)) {
+ prev_cam->disconnect(update_signal, update_text);
+ }
+ Camera2D *cam = Object::cast_to(p_object);
+ if (cam != nullptr) {
+ camera_2d_editor->edit(cam);
+ _update_approach_text_visibility();
+ if (!cam->is_connected(update_signal, update_text)) {
+ cam->connect(update_signal, update_text);
+ }
+ }
+}
+
+bool Camera2DEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("Camera2D");
+}
+
+void Camera2DEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ camera_2d_editor->options->show();
+ approach_to_move_rect->show();
+ } else {
+ camera_2d_editor->options->hide();
+ approach_to_move_rect->hide();
+ }
+}
+
+Camera2DEditorPlugin::Camera2DEditorPlugin() {
+ camera_2d_editor = memnew(Camera2DEditor);
+ EditorNode::get_singleton()->get_gui_base()->add_child(camera_2d_editor);
+ camera_2d_editor->connect(SNAME("_editor_theme_changed"), callable_mp(this, &Camera2DEditorPlugin::_editor_theme_changed));
+
+ approach_to_move_rect = memnew(Label);
+ approach_to_move_rect->set_text(TTRC("In Move Mode: \nHold Ctrl + left mouse button to move the limit rectangle.\nHold left mouse button to move the camera only."));
+ approach_to_move_rect->hide();
+ _editor_theme_changed();
+ CanvasItemEditor::get_singleton()->get_controls_container()->add_child(approach_to_move_rect);
+
+ make_visible(false);
+}
diff --git a/editor/plugins/camera_2d_editor_plugin.h b/editor/plugins/camera_2d_editor_plugin.h
new file mode 100644
index 00000000000..3e72329a285
--- /dev/null
+++ b/editor/plugins/camera_2d_editor_plugin.h
@@ -0,0 +1,80 @@
+/**************************************************************************/
+/* camera_2d_editor_plugin.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#pragma once
+
+#include "editor/plugins/editor_plugin.h"
+
+class Camera2D;
+class Label;
+class MenuButton;
+
+class Camera2DEditor : public Control {
+ GDCLASS(Camera2DEditor, Control);
+
+ enum Menu {
+ MENU_SNAP_LIMITS_TO_VIEWPORT,
+ };
+
+ Camera2D *selected_camera = nullptr;
+
+ friend class Camera2DEditorPlugin;
+ MenuButton *options = nullptr;
+
+ void _menu_option(int p_option);
+ void _snap_limits_to_viewport();
+ void _undo_snap_limits_to_viewport(const Rect2 &p_prev_rect);
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void edit(Camera2D *p_camera);
+ Camera2DEditor();
+};
+
+class Camera2DEditorPlugin : public EditorPlugin {
+ GDCLASS(Camera2DEditorPlugin, EditorPlugin);
+
+ Camera2DEditor *camera_2d_editor = nullptr;
+
+ Label *approach_to_move_rect = nullptr;
+
+ void _editor_theme_changed();
+ void _update_approach_text_visibility();
+
+public:
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ Camera2DEditorPlugin();
+};
diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp
index 1dfe399a24a..2edba72e79e 100644
--- a/editor/register_editor_types.cpp
+++ b/editor/register_editor_types.cpp
@@ -73,6 +73,7 @@
#include "editor/plugins/audio_stream_randomizer_editor_plugin.h"
#include "editor/plugins/bit_map_editor_plugin.h"
#include "editor/plugins/bone_map_editor_plugin.h"
+#include "editor/plugins/camera_2d_editor_plugin.h"
#include "editor/plugins/camera_3d_editor_plugin.h"
#include "editor/plugins/cast_2d_editor_plugin.h"
#include "editor/plugins/collision_polygon_2d_editor_plugin.h"
@@ -252,6 +253,7 @@ void register_editor_types() {
EditorPlugins::add_by_type();
// 2D
+ EditorPlugins::add_by_type();
EditorPlugins::add_by_type();
EditorPlugins::add_by_type();
EditorPlugins::add_by_type();
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index cad9e41c1c5..25a7f8900fd 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -31,8 +31,61 @@
#include "camera_2d.h"
#include "core/config/project_settings.h"
+#include "core/input/input.h"
#include "scene/main/viewport.h"
+#ifdef TOOLS_ENABLED
+Dictionary Camera2D::_edit_get_state() const {
+ Dictionary state = Node2D::_edit_get_state();
+ state["limit_rect"] = get_limit_rect();
+ return state;
+}
+
+void Camera2D::_edit_set_state(const Dictionary &p_state) {
+ if (p_state.has("limit_rect")) {
+ _set_limit_rect(p_state["limit_rect"]);
+ }
+ Node2D::_edit_set_state(p_state);
+}
+
+void Camera2D::_edit_set_position(const Point2 &p_position) {
+ if (_is_dragging_limit_rect()) {
+ Rect2 rect = get_limit_rect();
+ rect.position = p_position;
+ _set_limit_rect(rect);
+ } else {
+ Node2D::_edit_set_position(p_position);
+ }
+}
+
+Point2 Camera2D::_edit_get_position() const {
+ return _is_dragging_limit_rect() ? get_limit_rect().position : Node2D::_edit_get_position();
+}
+
+void Camera2D::_edit_set_rect(const Rect2 &p_rect) {
+ ERR_FAIL_COND(limit_enabled && !_edit_use_rect());
+ Rect2 rect = p_rect;
+ Vector2 scl = get_global_scale().abs();
+ rect.size *= scl;
+ rect.position = (rect.position + get_global_position()) * scl;
+ _set_limit_rect(rect);
+}
+#endif // TOOLS_ENABLED
+
+#ifdef DEBUG_ENABLED
+Rect2 Camera2D::_edit_get_rect() const {
+ Rect2 rect = get_limit_rect();
+ Vector2 scl = get_global_scale().abs();
+ rect.size /= scl;
+ rect.position = (rect.position - get_global_position()) / scl;
+ return rect;
+}
+
+bool Camera2D::_edit_use_rect() const {
+ return limit_enabled;
+}
+#endif // DEBUG_ENABLED
+
bool Camera2D::_is_editing_in_editor() const {
#ifdef TOOLS_ENABLED
return is_part_of_edited_scene();
@@ -75,6 +128,10 @@ void Camera2D::_update_scroll() {
}
#ifdef TOOLS_ENABLED
+bool Camera2D::_is_dragging_limit_rect() const {
+ return _edit_use_rect() && Input::get_singleton()->is_key_pressed(Key::CTRL);
+}
+
void Camera2D::_project_settings_changed() {
if (screen_drawing_enabled) {
queue_redraw();
@@ -169,7 +226,7 @@ Transform2D Camera2D::get_camera_transform() {
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom_scale) : Point2());
Rect2 screen_rect(-screen_offset + camera_pos, screen_size * zoom_scale);
- if (limit_smoothing_enabled) {
+ if (limit_enabled && limit_smoothing_enabled) {
if (screen_rect.position.x < limit[SIDE_LEFT]) {
camera_pos.x -= screen_rect.position.x - limit[SIDE_LEFT];
}
@@ -222,7 +279,7 @@ Transform2D Camera2D::get_camera_transform() {
Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom_scale);
- if (!position_smoothing_enabled || !limit_smoothing_enabled) {
+ if (limit_enabled && (!position_smoothing_enabled || !limit_smoothing_enabled)) {
if (screen_rect.position.x < limit[SIDE_LEFT]) {
screen_rect.position.x = limit[SIDE_LEFT];
}
@@ -398,8 +455,7 @@ void Camera2D::_notification(int p_what) {
}
}
- if (limit_drawing_enabled) {
- Color limit_drawing_color(1, 1, 0.25, 0.63);
+ if (limit_enabled && limit_drawing_enabled) {
real_t limit_drawing_width = -1;
if (is_current()) {
limit_drawing_width = 3;
@@ -415,7 +471,7 @@ void Camera2D::_notification(int p_what) {
};
for (int i = 0; i < 4; i++) {
- draw_line(limit_points[i], limit_points[(i + 1) % 4], limit_drawing_color, limit_drawing_width);
+ draw_line(limit_points[i], limit_points[(i + 1) % 4], Color(1, 1, 0.25, 0.63), limit_drawing_width);
}
}
@@ -484,6 +540,22 @@ bool Camera2D::is_ignoring_rotation() const {
return ignore_rotation;
}
+void Camera2D::set_limit_enabled(bool p_limit_enabled) {
+ if (p_limit_enabled == limit_enabled) {
+ return;
+ }
+ limit_enabled = p_limit_enabled;
+ _update_scroll();
+#ifdef TOOLS_ENABLED
+ emit_signal("_camera_limit_enabled_updated"); // Used for Camera2DEditorPlugin
+#endif
+ notify_property_list_changed();
+}
+
+bool Camera2D::is_limit_enabled() const {
+ return limit_enabled;
+}
+
void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) {
if (process_callback == p_mode) {
return;
@@ -548,6 +620,18 @@ void Camera2D::_update_process_internal_for_smoothing() {
set_process_internal(enable);
}
+void Camera2D::_set_limit_rect(const Rect2 &p_limit_rect) {
+ Point2 limit_rect_end = p_limit_rect.get_end();
+ set_limit(SIDE_LEFT, p_limit_rect.position.x);
+ set_limit(SIDE_TOP, p_limit_rect.position.y);
+ set_limit(SIDE_RIGHT, limit_rect_end.x);
+ set_limit(SIDE_BOTTOM, limit_rect_end.y);
+}
+
+Rect2 Camera2D::get_limit_rect() const {
+ return Rect2(limit[SIDE_LEFT], limit[SIDE_TOP], limit[SIDE_RIGHT] - limit[SIDE_LEFT], limit[SIDE_BOTTOM] - limit[SIDE_TOP]);
+}
+
void Camera2D::make_current() {
ERR_FAIL_COND(!enabled || !is_inside_tree());
get_tree()->call_group(group_name, "_make_current", this);
@@ -817,6 +901,9 @@ bool Camera2D::is_margin_drawing_enabled() const {
}
void Camera2D::_validate_property(PropertyInfo &p_property) const {
+ if (!limit_enabled && (p_property.name == "limit_smoothed" || p_property.name == "limit_left" || p_property.name == "limit_top" || p_property.name == "limit_right" || p_property.name == "limit_bottom")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
if (!position_smoothing_enabled && p_property.name == "position_smoothing_speed") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
@@ -847,6 +934,9 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_current"), &Camera2D::is_current);
ClassDB::bind_method(D_METHOD("_make_current"), &Camera2D::_make_current);
+ ClassDB::bind_method(D_METHOD("set_limit_enabled", "limit_enabled"), &Camera2D::set_limit_enabled);
+ ClassDB::bind_method(D_METHOD("is_limit_enabled"), &Camera2D::is_limit_enabled);
+
ClassDB::bind_method(D_METHOD("set_limit", "margin", "limit"), &Camera2D::set_limit);
ClassDB::bind_method(D_METHOD("get_limit", "margin"), &Camera2D::get_limit);
@@ -913,6 +1003,7 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
ADD_GROUP("Limit", "limit_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "limit_enabled"), "set_limit_enabled", "is_limit_enabled");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_top", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_right", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_RIGHT);
@@ -961,4 +1052,8 @@ Camera2D::Camera2D() {
set_notify_transform(true);
set_hide_clip_children(true);
+
+#ifdef TOOLS_ENABLED
+ add_user_signal(MethodInfo("_camera_limit_enabled_updated")); // Camera2DEditorPlugin listens to this
+#endif
}
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 2b5cc281d41..b3f90b211b1 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -72,6 +72,7 @@ protected:
real_t rotation_smoothing_speed = 5.0;
bool rotation_smoothing_enabled = false;
+ bool limit_enabled = true;
int limit[4];
bool limit_smoothing_enabled = false;
@@ -87,7 +88,9 @@ protected:
bool _is_editing_in_editor() const;
void _update_process_callback();
void _update_scroll();
+
#ifdef TOOLS_ENABLED
+ bool _is_dragging_limit_rect() const;
void _project_settings_changed();
#endif
@@ -98,6 +101,8 @@ protected:
void _update_process_internal_for_smoothing();
+ void _set_limit_rect(const Rect2 &p_limit_rect);
+
bool screen_drawing_enabled = true;
bool limit_drawing_enabled = false;
bool margin_drawing_enabled = false;
@@ -122,6 +127,24 @@ protected:
void _validate_property(PropertyInfo &p_property) const;
public:
+#ifdef TOOLS_ENABLED
+ virtual Dictionary _edit_get_state() const override;
+ virtual void _edit_set_state(const Dictionary &p_state) override;
+
+ virtual void _edit_set_position(const Point2 &p_position) override;
+ virtual Point2 _edit_get_position() const override;
+
+ virtual void _edit_set_rect(const Rect2 &p_rect) override;
+ virtual Size2 _edit_get_minimum_size() const override { return Size2(); }
+#endif // TOOLS_ENABLED
+
+#ifdef DEBUG_ENABLED
+ virtual Rect2 _edit_get_rect() const override;
+ virtual bool _edit_use_rect() const override;
+#endif // DEBUG_ENABLED
+
+ Rect2 get_limit_rect() const;
+
void set_offset(const Vector2 &p_offset);
Vector2 get_offset() const;
@@ -131,6 +154,9 @@ public:
void set_ignore_rotation(bool p_ignore);
bool is_ignoring_rotation() const;
+ void set_limit_enabled(bool p_limit_enabled);
+ bool is_limit_enabled() const;
+
void set_limit(Side p_side, int p_limit);
int get_limit(Side p_side) const;