Path: blob/master/editor/scene/2d/camera_2d_editor_plugin.cpp
9904 views
/**************************************************************************/1/* camera_2d_editor_plugin.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "camera_2d_editor_plugin.h"3132#include "core/config/project_settings.h"33#include "editor/editor_node.h"34#include "editor/editor_undo_redo_manager.h"35#include "editor/scene/canvas_item_editor_plugin.h"36#include "editor/themes/editor_scale.h"37#include "scene/2d/camera_2d.h"38#include "scene/gui/label.h"39#include "scene/gui/menu_button.h"4041void Camera2DEditor::edit(Camera2D *p_camera) {42if (p_camera == selected_camera) {43return;44}45const Callable update_overlays = callable_mp(plugin, &EditorPlugin::update_overlays);4647if (selected_camera) {48selected_camera->disconnect(SceneStringName(draw), update_overlays);49if (drag_type != Drag::NONE) {50selected_camera->set_limit_rect(drag_revert);51}52drag_type = Drag::NONE;53hover_type = Drag::NONE;54CanvasItemEditor::get_singleton()->set_cursor_shape_override(CURSOR_ARROW);55}56selected_camera = p_camera;5758if (selected_camera) {59selected_camera->connect(SceneStringName(draw), update_overlays);60}61plugin->update_overlays();62}6364bool Camera2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {65if (!selected_camera || !selected_camera->is_limit_enabled()) {66return false;67}6869Ref<InputEventMouseButton> mb = p_event;70if (mb.is_valid()) {71if (mb->get_button_index() == MouseButton::LEFT) {72if (mb->is_pressed()) {73if (hover_type != Drag::NONE) {74Vector2 pos = CanvasItemEditor::get_singleton()->get_canvas_transform().affine_inverse().xform(mb->get_position());75const Rect2 limit_rect = selected_camera->get_limit_rect();7677drag_type = hover_type;78drag_revert = selected_camera->get_limit_rect();79center_drag_point = pos - limit_rect.position;80return true;81}82} else if (drag_type != Drag::NONE) {83EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();84ur->create_action(TTR("Edit Camera2D Limits"));85ur->add_do_method(selected_camera, "_set_limit_rect", selected_camera->get_limit_rect());86ur->add_do_method(this, "_update_overlays_if_needed", selected_camera);87ur->add_undo_method(selected_camera, "_set_limit_rect", drag_revert);88ur->add_undo_method(this, "_update_overlays_if_needed", selected_camera);89ur->commit_action(false);9091drag_type = Drag::NONE;92return true;93}94} else if (drag_type != Drag::NONE && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {95selected_camera->set_limit_rect(drag_revert);96drag_type = Drag::NONE;97plugin->update_overlays();98_update_hover(mb->get_position());99return true;100}101return false;102}103104Ref<InputEventMouseMotion> mm = p_event;105if (mm.is_valid()) {106Vector2 pos = mm->get_position();107if (drag_type == Drag::NONE) {108_update_hover(pos);109return false;110}111112pos = CanvasItemEditor::get_singleton()->get_canvas_transform().affine_inverse().xform(pos);113pos = CanvasItemEditor::get_singleton()->snap_point(pos);114115switch (drag_type) {116case Drag::LEFT: {117selected_camera->set_limit(SIDE_LEFT, MIN(selected_camera->get_limit(SIDE_RIGHT), pos.x));118plugin->update_overlays();119} break;120121case Drag::RIGHT: {122selected_camera->set_limit(SIDE_RIGHT, MAX(selected_camera->get_limit(SIDE_LEFT), pos.x));123plugin->update_overlays();124} break;125126case Drag::TOP: {127selected_camera->set_limit(SIDE_TOP, MIN(selected_camera->get_limit(SIDE_BOTTOM), pos.y));128plugin->update_overlays();129} break;130131case Drag::BOTTOM: {132selected_camera->set_limit(SIDE_BOTTOM, MAX(selected_camera->get_limit(SIDE_TOP), pos.y));133plugin->update_overlays();134} break;135136case Drag::TOP_LEFT: {137selected_camera->set_limit(SIDE_LEFT, MIN(selected_camera->get_limit(SIDE_RIGHT), pos.x));138selected_camera->set_limit(SIDE_TOP, MIN(selected_camera->get_limit(SIDE_BOTTOM), pos.y));139plugin->update_overlays();140} break;141142case Drag::TOP_RIGHT: {143selected_camera->set_limit(SIDE_RIGHT, MAX(selected_camera->get_limit(SIDE_LEFT), pos.x));144selected_camera->set_limit(SIDE_TOP, MIN(selected_camera->get_limit(SIDE_BOTTOM), pos.y));145plugin->update_overlays();146} break;147148case Drag::BOTTOM_LEFT: {149selected_camera->set_limit(SIDE_LEFT, MIN(selected_camera->get_limit(SIDE_RIGHT), pos.x));150selected_camera->set_limit(SIDE_BOTTOM, MAX(selected_camera->get_limit(SIDE_TOP), pos.y));151plugin->update_overlays();152} break;153154case Drag::BOTTOM_RIGHT: {155selected_camera->set_limit(SIDE_RIGHT, MAX(selected_camera->get_limit(SIDE_LEFT), pos.x));156selected_camera->set_limit(SIDE_BOTTOM, MAX(selected_camera->get_limit(SIDE_TOP), pos.y));157plugin->update_overlays();158} break;159160case Drag::CENTER: {161Rect2 target_rect = selected_camera->get_limit_rect();162target_rect.position = pos - center_drag_point;163selected_camera->set_limit_rect(target_rect);164plugin->update_overlays();165} break;166167case Drag::NONE: {168} break;169}170return true;171}172173return false;174}175176void Camera2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {177if (!selected_camera || !selected_camera->is_limit_enabled()) {178return;179}180Rect2 limit_rect = selected_camera->get_limit_rect();181limit_rect = CanvasItemEditor::get_singleton()->get_canvas_transform().xform(limit_rect);182p_overlay->draw_rect(limit_rect, Color(1, 1, 0.25, 0.63), false, 3);183}184185void Camera2DEditor::_menu_option(int p_option) {186switch (p_option) {187case MENU_SNAP_LIMITS_TO_VIEWPORT: {188EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();189ur->create_action(TTR("Snap Camera2D Limits to the Viewport"), UndoRedo::MERGE_DISABLE, selected_camera);190ur->add_do_method(this, "_snap_limits_to_viewport", selected_camera);191ur->add_undo_method(selected_camera, "_set_limit_rect", selected_camera->get_limit_rect());192ur->add_undo_method(this, "_update_overlays_if_needed", selected_camera);193ur->commit_action();194} break;195}196}197198void Camera2DEditor::_snap_limits_to_viewport(Camera2D *p_camera) {199p_camera->set_limit(SIDE_LEFT, 0);200p_camera->set_limit(SIDE_TOP, 0);201p_camera->set_limit(SIDE_RIGHT, GLOBAL_GET("display/window/size/viewport_width"));202p_camera->set_limit(SIDE_BOTTOM, GLOBAL_GET("display/window/size/viewport_height"));203_update_overlays_if_needed(p_camera);204}205206void Camera2DEditor::_update_overlays_if_needed(Camera2D *p_camera) {207if (p_camera == selected_camera) {208plugin->update_overlays();209}210}211212void Camera2DEditor::_update_hover(const Vector2 &p_mouse_pos) {213if (CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) {214hover_type = Drag::NONE;215CanvasItemEditor::get_singleton()->set_cursor_shape_override();216return;217}218219const Rect2 limit_rect = CanvasItemEditor::get_singleton()->get_canvas_transform().xform(selected_camera->get_limit_rect());220const float drag_tolerance = 8.0;221const Vector2 tolerance_vector = Vector2(1, 1) * drag_tolerance;222223hover_type = Drag::NONE;224if (Rect2(limit_rect.position - tolerance_vector, tolerance_vector * 2).has_point(p_mouse_pos)) {225hover_type = Drag::TOP_LEFT;226} else if (Rect2(Vector2(limit_rect.get_end().x, limit_rect.position.y) - tolerance_vector, tolerance_vector * 2).has_point(p_mouse_pos)) {227hover_type = Drag::TOP_RIGHT;228} else if (Rect2(Vector2(limit_rect.position.x, limit_rect.get_end().y) - tolerance_vector, tolerance_vector * 2).has_point(p_mouse_pos)) {229hover_type = Drag::BOTTOM_LEFT;230} else if (Rect2(limit_rect.get_end() - tolerance_vector, tolerance_vector * 2).has_point(p_mouse_pos)) {231hover_type = Drag::BOTTOM_RIGHT;232} else if (p_mouse_pos.y > limit_rect.position.y && p_mouse_pos.y < limit_rect.get_end().y) {233if (Math::abs(p_mouse_pos.x - limit_rect.position.x) < drag_tolerance) {234hover_type = Drag::LEFT;235} else if (Math::abs(p_mouse_pos.x - limit_rect.get_end().x) < drag_tolerance) {236hover_type = Drag::RIGHT;237}238} else if (p_mouse_pos.x > limit_rect.position.x && p_mouse_pos.x < limit_rect.get_end().x) {239if (Math::abs(p_mouse_pos.y - limit_rect.position.y) < drag_tolerance) {240hover_type = Drag::TOP;241} else if (Math::abs(p_mouse_pos.y - limit_rect.get_end().y) < drag_tolerance) {242hover_type = Drag::BOTTOM;243}244}245246if (hover_type == Drag::NONE && limit_rect.has_point(p_mouse_pos)) {247const Rect2 editor_rect = Rect2(Vector2(), CanvasItemEditor::get_singleton()->get_viewport_control()->get_size());248const Rect2 transformed_rect = selected_camera->get_viewport()->get_canvas_transform().xform_inv(limit_rect);249250// Only allow center drag if any limit edge is visible on screen.251bool edge_visible = false;252edge_visible = edge_visible || (transformed_rect.get_end().y > editor_rect.position.y && transformed_rect.position.y < editor_rect.get_end().y && transformed_rect.position.x > editor_rect.position.x && transformed_rect.position.x < editor_rect.get_end().x);253edge_visible = edge_visible || (transformed_rect.get_end().y > editor_rect.position.y && transformed_rect.position.y < editor_rect.get_end().y && transformed_rect.get_end().x > editor_rect.position.x && transformed_rect.get_end().x < editor_rect.get_end().x);254edge_visible = edge_visible || (transformed_rect.get_end().x > editor_rect.position.x && transformed_rect.position.x < editor_rect.get_end().x && transformed_rect.position.y > editor_rect.position.y && transformed_rect.position.y < editor_rect.get_end().y);255edge_visible = edge_visible || (transformed_rect.get_end().x > editor_rect.position.x && transformed_rect.position.x < editor_rect.get_end().x && transformed_rect.get_end().y > editor_rect.position.y && transformed_rect.get_end().y < editor_rect.get_end().y);256257if (edge_visible) {258hover_type = Drag::CENTER;259}260}261262switch (hover_type) {263case Drag::NONE: {264CanvasItemEditor::get_singleton()->set_cursor_shape_override();265} break;266case Drag::LEFT:267case Drag::RIGHT: {268CanvasItemEditor::get_singleton()->set_cursor_shape_override(CURSOR_HSIZE);269} break;270case Drag::TOP:271case Drag::BOTTOM: {272CanvasItemEditor::get_singleton()->set_cursor_shape_override(CURSOR_VSIZE);273} break;274case Drag::TOP_LEFT:275case Drag::BOTTOM_RIGHT: {276CanvasItemEditor::get_singleton()->set_cursor_shape_override(CURSOR_FDIAGSIZE);277} break;278case Drag::TOP_RIGHT:279case Drag::BOTTOM_LEFT: {280CanvasItemEditor::get_singleton()->set_cursor_shape_override(CURSOR_BDIAGSIZE);281} break;282case Drag::CENTER: {283CanvasItemEditor::get_singleton()->set_cursor_shape_override(CURSOR_MOVE);284} break;285}286}287288void Camera2DEditor::_notification(int p_what) {289switch (p_what) {290case NOTIFICATION_THEME_CHANGED: {291options->set_button_icon(get_editor_theme_icon(SNAME("Camera2D")));292} break;293}294}295296void Camera2DEditor::_bind_methods() {297ClassDB::bind_method(D_METHOD("_snap_limits_to_viewport", "camera"), &Camera2DEditor::_snap_limits_to_viewport);298ClassDB::bind_method(D_METHOD("_update_overlays_if_needed", "camera"), &Camera2DEditor::_update_overlays_if_needed);299}300301Camera2DEditor::Camera2DEditor(EditorPlugin *p_plugin) {302plugin = p_plugin;303304options = memnew(MenuButton);305options->set_text(TTRC("Camera2D"));306options->get_popup()->add_item(TTRC("Snap the Limits to the Viewport"), MENU_SNAP_LIMITS_TO_VIEWPORT);307options->set_switch_on_hover(true);308options->hide();309CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);310options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &Camera2DEditor::_menu_option));311}312313void Camera2DEditorPlugin::edit(Object *p_object) {314camera_2d_editor->edit(Object::cast_to<Camera2D>(p_object));315}316317bool Camera2DEditorPlugin::handles(Object *p_object) const {318return p_object->is_class("Camera2D");319}320321void Camera2DEditorPlugin::make_visible(bool p_visible) {322if (p_visible) {323camera_2d_editor->options->show();324} else {325camera_2d_editor->options->hide();326}327}328329Camera2DEditorPlugin::Camera2DEditorPlugin() {330camera_2d_editor = memnew(Camera2DEditor(this));331EditorNode::get_singleton()->get_gui_base()->add_child(camera_2d_editor);332}333334335