Path: blob/master/editor/scene/canvas_item_editor_plugin.h
9896 views
/**************************************************************************/1/* canvas_item_editor_plugin.h */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#pragma once3132#include "editor/plugins/editor_plugin.h"33#include "scene/gui/box_container.h"3435class AcceptDialog;36class Button;37class ButtonGroup;38class CanvasItemEditorViewport;39class ConfirmationDialog;40class EditorData;41class EditorSelection;42class EditorZoomWidget;43class HScrollBar;44class HSplitContainer;45class MenuButton;46class PanelContainer;47class StyleBoxTexture;48class ViewPanner;49class VScrollBar;50class VSeparator;51class VSplitContainer;5253class CanvasItemEditorSelectedItem : public Object {54GDCLASS(CanvasItemEditorSelectedItem, Object);5556public:57Transform2D prev_xform;58Rect2 prev_rect;59Vector2 prev_pivot;60real_t prev_anchors[4] = { (real_t)0.0 };6162Transform2D pre_drag_xform;63Rect2 pre_drag_rect;6465List<real_t> pre_drag_bones_length;66List<Dictionary> pre_drag_bones_undo_state;6768Dictionary undo_state;69};7071class CanvasItemEditor : public VBoxContainer {72GDCLASS(CanvasItemEditor, VBoxContainer);7374public:75enum Tool {76TOOL_SELECT,77TOOL_LIST_SELECT,78TOOL_MOVE,79TOOL_SCALE,80TOOL_ROTATE,81TOOL_EDIT_PIVOT,82TOOL_PAN,83TOOL_RULER,84TOOL_MAX85};8687enum AddNodeOption {88ADD_NODE,89ADD_INSTANCE,90ADD_PASTE,91ADD_MOVE,92};9394private:95enum SnapTarget {96SNAP_TARGET_NONE = 0,97SNAP_TARGET_PARENT,98SNAP_TARGET_SELF_ANCHORS,99SNAP_TARGET_SELF,100SNAP_TARGET_OTHER_NODE,101SNAP_TARGET_GUIDE,102SNAP_TARGET_GRID,103SNAP_TARGET_PIXEL104};105106enum MenuOption {107SNAP_USE,108SNAP_USE_NODE_PARENT,109SNAP_USE_NODE_ANCHORS,110SNAP_USE_NODE_SIDES,111SNAP_USE_NODE_CENTER,112SNAP_USE_OTHER_NODES,113SNAP_USE_GRID,114SNAP_USE_GUIDES,115SNAP_USE_ROTATION,116SNAP_USE_SCALE,117SNAP_RELATIVE,118SNAP_CONFIGURE,119SNAP_USE_PIXEL,120SHOW_HELPERS,121SHOW_RULERS,122SHOW_GUIDES,123SHOW_ORIGIN,124SHOW_VIEWPORT,125SHOW_POSITION_GIZMOS,126SHOW_LOCK_GIZMOS,127SHOW_GROUP_GIZMOS,128SHOW_TRANSFORMATION_GIZMOS,129LOCK_SELECTED,130UNLOCK_SELECTED,131GROUP_SELECTED,132UNGROUP_SELECTED,133ANIM_INSERT_KEY,134ANIM_INSERT_KEY_EXISTING,135ANIM_INSERT_POS,136ANIM_INSERT_ROT,137ANIM_INSERT_SCALE,138ANIM_COPY_POSE,139ANIM_PASTE_POSE,140ANIM_CLEAR_POSE,141CLEAR_GUIDES,142VIEW_CENTER_TO_SELECTION,143VIEW_FRAME_TO_SELECTION,144PREVIEW_CANVAS_SCALE,145SKELETON_MAKE_BONES,146SKELETON_SHOW_BONES147};148149enum DragType {150DRAG_NONE,151DRAG_BOX_SELECTION,152DRAG_LEFT,153DRAG_TOP_LEFT,154DRAG_TOP,155DRAG_TOP_RIGHT,156DRAG_RIGHT,157DRAG_BOTTOM_RIGHT,158DRAG_BOTTOM,159DRAG_BOTTOM_LEFT,160DRAG_ANCHOR_TOP_LEFT,161DRAG_ANCHOR_TOP_RIGHT,162DRAG_ANCHOR_BOTTOM_RIGHT,163DRAG_ANCHOR_BOTTOM_LEFT,164DRAG_ANCHOR_ALL,165DRAG_QUEUED,166DRAG_MOVE,167DRAG_MOVE_X,168DRAG_MOVE_Y,169DRAG_SCALE_X,170DRAG_SCALE_Y,171DRAG_SCALE_BOTH,172DRAG_ROTATE,173DRAG_PIVOT,174DRAG_TEMP_PIVOT,175DRAG_V_GUIDE,176DRAG_H_GUIDE,177DRAG_DOUBLE_GUIDE,178DRAG_KEY_MOVE179};180181enum GridVisibility {182GRID_VISIBILITY_SHOW,183GRID_VISIBILITY_SHOW_WHEN_SNAPPING,184GRID_VISIBILITY_HIDE,185};186187const String locked_transform_warning = TTRC("All selected CanvasItems are either invisible or locked in some way and can't be transformed.");188189bool selection_menu_additive_selection = false;190191Tool tool = TOOL_SELECT;192Control *viewport = nullptr;193Control *viewport_scrollable = nullptr;194195HScrollBar *h_scroll = nullptr;196VScrollBar *v_scroll = nullptr;197198// Used for secondary menu items which are displayed depending on the currently selected node199// (such as MeshInstance's "Mesh" menu).200PanelContainer *context_toolbar_panel = nullptr;201HBoxContainer *context_toolbar_hbox = nullptr;202HashMap<Control *, VSeparator *> context_toolbar_separators;203204void _update_context_toolbar();205206Transform2D transform;207GridVisibility grid_visibility = GRID_VISIBILITY_SHOW_WHEN_SNAPPING;208bool show_rulers = true;209bool show_guides = true;210bool show_origin = true;211bool show_viewport = true;212bool show_helpers = false;213bool show_position_gizmos = true;214bool show_lock_gizmos = true;215bool show_group_gizmos = true;216bool show_transformation_gizmos = true;217218real_t zoom = 1.0;219Point2 view_offset;220Point2 previous_update_view_offset;221222bool selected_from_canvas = false;223224// Defaults are defined in clear().225Point2 grid_offset;226Point2 grid_step;227Vector2i primary_grid_step;228int grid_step_multiplier = 0;229230real_t snap_rotation_step = 0.0;231real_t snap_rotation_offset = 0.0;232real_t snap_scale_step = 0.0;233bool smart_snap_active = false;234bool grid_snap_active = false;235236bool snap_node_parent = true;237bool snap_node_anchors = true;238bool snap_node_sides = true;239bool snap_node_center = true;240bool snap_other_nodes = true;241bool snap_guides = true;242bool snap_rotation = false;243bool snap_scale = false;244bool snap_relative = false;245// Enable pixel snapping even if pixel snap rendering is disabled in the Project Settings.246// This results in crisper visuals by preventing 2D nodes from being placed at subpixel coordinates.247bool snap_pixel = true;248249bool key_pos = true;250bool key_rot = true;251bool key_scale = false;252253bool pan_pressed = false;254Vector2 temp_pivot = Vector2(Math::INF, Math::INF);255256bool ruler_tool_active = false;257Point2 ruler_tool_origin;258real_t ruler_width_scaled = 16.0;259int ruler_font_size = 8;260Point2 node_create_position;261262MenuOption last_option;263264struct _SelectResult {265CanvasItem *item = nullptr;266real_t z_index = 0;267bool has_z = true;268_FORCE_INLINE_ bool operator<(const _SelectResult &p_rr) const {269return has_z && p_rr.has_z ? p_rr.z_index < z_index : p_rr.has_z;270}271};272Vector<_SelectResult> selection_results;273Vector<_SelectResult> selection_results_menu;274275struct _HoverResult {276Point2 position;277Ref<Texture2D> icon;278String name;279};280Vector<_HoverResult> hovering_results;281282struct BoneList {283Transform2D xform;284real_t length = 0;285uint64_t last_pass = 0;286};287288uint64_t bone_last_frame = 0;289290struct BoneKey {291ObjectID from;292ObjectID to;293_FORCE_INLINE_ bool operator<(const BoneKey &p_key) const {294if (from == p_key.from) {295return to < p_key.to;296} else {297return from < p_key.from;298}299}300};301302HashMap<BoneKey, BoneList> bone_list;303MenuButton *skeleton_menu = nullptr;304305struct PoseClipboard {306Vector2 pos;307Vector2 scale;308real_t rot = 0;309ObjectID id;310};311List<PoseClipboard> pose_clipboard;312313Button *select_button = nullptr;314315Button *move_button = nullptr;316Button *scale_button = nullptr;317Button *rotate_button = nullptr;318319Button *list_select_button = nullptr;320Button *pivot_button = nullptr;321Button *pan_button = nullptr;322323Button *ruler_button = nullptr;324325Button *smart_snap_button = nullptr;326Button *grid_snap_button = nullptr;327MenuButton *snap_config_menu = nullptr;328PopupMenu *smartsnap_config_popup = nullptr;329330Button *lock_button = nullptr;331Button *unlock_button = nullptr;332333Button *group_button = nullptr;334Button *ungroup_button = nullptr;335336MenuButton *view_menu = nullptr;337PopupMenu *grid_menu = nullptr;338PopupMenu *theme_menu = nullptr;339PopupMenu *gizmos_menu = nullptr;340HBoxContainer *animation_hb = nullptr;341MenuButton *animation_menu = nullptr;342343Button *key_loc_button = nullptr;344Button *key_rot_button = nullptr;345Button *key_scale_button = nullptr;346Button *key_insert_button = nullptr;347Button *key_auto_insert_button = nullptr;348349PopupMenu *selection_menu = nullptr;350PopupMenu *add_node_menu = nullptr;351352Control *top_ruler = nullptr;353Control *left_ruler = nullptr;354355Point2 drag_start_origin;356DragType drag_type = DRAG_NONE;357Point2 drag_from;358Point2 drag_to;359Point2 drag_rotation_center;360List<CanvasItem *> drag_selection;361int dragged_guide_index = -1;362Point2 dragged_guide_pos;363bool is_hovering_h_guide = false;364bool is_hovering_v_guide = false;365366bool updating_value_dialog = false;367Transform2D original_transform;368369Point2 box_selecting_to;370CursorShape cursor_shape_override = CURSOR_ARROW;371372Ref<StyleBoxTexture> select_sb;373Ref<Texture2D> select_handle;374Ref<Texture2D> anchor_handle;375376Ref<Shortcut> drag_pivot_shortcut;377Ref<Shortcut> set_pivot_shortcut;378Ref<Shortcut> multiply_grid_step_shortcut;379Ref<Shortcut> divide_grid_step_shortcut;380381Ref<ViewPanner> panner;382void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);383void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);384385bool _is_node_locked(const Node *p_node) const;386bool _is_node_movable(const Node *p_node, bool p_popup_warning = false);387void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());388void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked = false);389390void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());391bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append);392393ConfirmationDialog *snap_dialog = nullptr;394395CanvasItem *ref_item = nullptr;396397void _save_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool save_bones = false);398void _restore_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool restore_bones = false);399void _commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, const String &action_name, bool commit_bones = false);400401Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor);402Vector2 _position_to_anchor(const Control *p_control, Vector2 position);403404void _prepare_view_menu();405void _popup_callback(int p_op);406bool updating_scroll = false;407void _update_scroll(real_t);408void _update_scrollbars();409void _snap_changed();410void _selection_result_pressed(int);411void _selection_menu_hide();412void _add_node_pressed(int p_result);413void _adjust_new_node_position(Node *p_node);414void _reset_create_position();415void _update_editor_settings();416bool _is_grid_visible() const;417void _prepare_grid_menu();418void _on_grid_menu_id_pressed(int p_id);419420public:421enum ThemePreviewMode {422THEME_PREVIEW_PROJECT,423THEME_PREVIEW_EDITOR,424THEME_PREVIEW_DEFAULT,425426THEME_PREVIEW_MAX // The number of options for enumerating.427};428429private:430ThemePreviewMode theme_preview = THEME_PREVIEW_PROJECT;431void _switch_theme_preview(int p_mode);432433List<CanvasItem *> _get_edited_canvas_items(bool p_retrieve_locked = false, bool p_remove_canvas_item_if_parent_in_selection = true, bool *r_has_locked_items = nullptr) const;434Rect2 _get_encompassing_rect_from_list(const List<CanvasItem *> &p_list);435void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true);436Rect2 _get_encompassing_rect(const Node *p_node);437438Object *_get_editor_data(Object *p_what);439440void _insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing);441442void _keying_changed();443444virtual void shortcut_input(const Ref<InputEvent> &p_ev) override;445446void _draw_text_at_position(Point2 p_position, const String &p_string, Side p_side);447void _draw_margin_at_position(int p_value, Point2 p_position, Side p_side);448void _draw_percentage_at_position(real_t p_value, Point2 p_position, Side p_side);449void _draw_straight_line(Point2 p_from, Point2 p_to, Color p_color);450451void _draw_smart_snapping();452void _draw_rulers();453void _draw_guides();454void _draw_focus();455void _draw_grid();456void _draw_ruler_tool();457void _draw_control_anchors(Control *control);458void _draw_control_helpers(Control *control);459void _draw_selection();460void _draw_axis();461void _draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());462void _draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());463void _draw_hover();464void _draw_message();465466void _draw_viewport();467468bool _gui_input_anchors(const Ref<InputEvent> &p_event);469bool _gui_input_move(const Ref<InputEvent> &p_event);470bool _gui_input_open_scene_on_double_click(const Ref<InputEvent> &p_event);471bool _gui_input_scale(const Ref<InputEvent> &p_event);472bool _gui_input_pivot(const Ref<InputEvent> &p_event);473bool _gui_input_resize(const Ref<InputEvent> &p_event);474bool _gui_input_rotate(const Ref<InputEvent> &p_event);475bool _gui_input_select(const Ref<InputEvent> &p_event);476bool _gui_input_ruler_tool(const Ref<InputEvent> &p_event);477bool _gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bool p_already_accepted);478bool _gui_input_rulers_and_guides(const Ref<InputEvent> &p_event);479bool _gui_input_hover(const Ref<InputEvent> &p_event);480481void _gui_input_viewport(const Ref<InputEvent> &p_event);482void _update_cursor();483void _update_lock_and_group_button();484485void _selection_changed();486void _focus_selection(int p_op);487void _reset_drag();488489void _project_settings_changed();490491SnapTarget snap_target[2];492Transform2D snap_transform;493void _snap_if_closer_float(494const real_t p_value,495real_t &r_current_snap, SnapTarget &r_current_snap_target,496const real_t p_target_value, const SnapTarget p_snap_target,497const real_t p_radius = 10.0);498void _snap_if_closer_point(499Point2 p_value,500Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2],501Point2 p_target_value, const SnapTarget p_snap_target,502const real_t rotation = 0.0,503const real_t p_radius = 10.0);504void _snap_other_nodes(505const Point2 p_value,506const Transform2D p_transform_to_snap,507Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2],508const SnapTarget p_snap_target, List<const CanvasItem *> p_exceptions,509const Node *p_current);510511VBoxContainer *controls_vb = nullptr;512Button *button_center_view = nullptr;513EditorZoomWidget *zoom_widget = nullptr;514void _update_zoom(real_t p_zoom);515void _shortcut_zoom_set(real_t p_zoom);516void _zoom_on_position(real_t p_zoom, Point2 p_position = Point2());517void _button_toggle_smart_snap(bool p_status);518void _button_toggle_grid_snap(bool p_status);519void _button_tool_select(int p_index);520521HSplitContainer *left_panel_split = nullptr;522HSplitContainer *right_panel_split = nullptr;523VSplitContainer *bottom_split = nullptr;524525void _set_owner_for_node_and_children(Node *p_node, Node *p_owner);526527friend class CanvasItemEditorPlugin;528529protected:530void _notification(int p_what);531532static void _bind_methods();533534static CanvasItemEditor *singleton;535536public:537enum SnapMode {538SNAP_GRID = 1 << 0,539SNAP_GUIDES = 1 << 1,540SNAP_PIXEL = 1 << 2,541SNAP_NODE_PARENT = 1 << 3,542SNAP_NODE_ANCHORS = 1 << 4,543SNAP_NODE_SIDES = 1 << 5,544SNAP_NODE_CENTER = 1 << 6,545SNAP_OTHER_NODES = 1 << 7,546547SNAP_DEFAULT = SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL,548};549550String message;551552Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, const List<CanvasItem *> &p_other_nodes_exceptions = List<CanvasItem *>());553real_t snap_angle(real_t p_target, real_t p_start = 0) const;554555Transform2D get_canvas_transform() const { return transform; }556557static CanvasItemEditor *get_singleton() { return singleton; }558Dictionary get_state() const;559void set_state(const Dictionary &p_state);560void clear();561562void add_control_to_menu_panel(Control *p_control);563void remove_control_from_menu_panel(Control *p_control);564565void add_control_to_left_panel(Control *p_control);566void remove_control_from_left_panel(Control *p_control);567568void add_control_to_right_panel(Control *p_control);569void remove_control_from_right_panel(Control *p_control);570571VSplitContainer *get_bottom_split();572573Control *get_viewport_control() { return viewport; }574575Control *get_controls_container() { return controls_vb; }576577void update_viewport();578579Tool get_current_tool() { return tool; }580void set_current_tool(Tool p_tool);581582void edit(CanvasItem *p_canvas_item);583584void focus_selection();585void center_at(const Point2 &p_pos);586587void set_cursor_shape_override(CursorShape p_shape = CURSOR_ARROW);588virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;589590ThemePreviewMode get_theme_preview() const { return theme_preview; }591592EditorSelection *editor_selection = nullptr;593594CanvasItemEditor();595};596597class CanvasItemEditorPlugin : public EditorPlugin {598GDCLASS(CanvasItemEditorPlugin, EditorPlugin);599600CanvasItemEditor *canvas_item_editor = nullptr;601602protected:603void _notification(int p_what);604605public:606virtual String get_plugin_name() const override { return TTRC("2D"); }607bool has_main_screen() const override { return true; }608virtual void edit(Object *p_object) override;609virtual bool handles(Object *p_object) const override;610virtual void make_visible(bool p_visible) override;611virtual Dictionary get_state() const override;612virtual void set_state(const Dictionary &p_state) override;613virtual void clear() override;614615CanvasItemEditor *get_canvas_item_editor() { return canvas_item_editor; }616617CanvasItemEditorPlugin();618};619620class CanvasItemEditorViewport : public Control {621GDCLASS(CanvasItemEditorViewport, Control);622623// The type of node that will be created when dropping texture into the viewport.624String default_texture_node_type;625// Node types that are available to select from when dropping texture into viewport.626Vector<String> texture_node_types;627628Vector<String> selected_files;629Node *target_node = nullptr;630Point2 drop_pos;631632CanvasItemEditor *canvas_item_editor = nullptr;633Control *preview_node = nullptr;634AcceptDialog *accept = nullptr;635AcceptDialog *texture_node_type_selector = nullptr;636Label *label = nullptr;637Label *label_desc = nullptr;638Ref<ButtonGroup> button_group;639640void _on_mouse_exit();641void _on_select_texture_node_type(Object *selected);642void _on_change_type_confirmed();643void _on_change_type_closed();644645void _create_preview(const Vector<String> &files) const;646void _remove_preview();647648bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) const;649bool _is_any_texture_selected() const;650void _create_texture_node(Node *p_parent, Node *p_child, const String &p_path, const Point2 &p_point);651void _create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point);652bool _create_instance(Node *p_parent, const String &p_path, const Point2 &p_point);653void _perform_drop_data();654void _show_texture_node_type_selector();655void _update_theme();656657protected:658void _notification(int p_what);659660public:661virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;662virtual void drop_data(const Point2 &p_point, const Variant &p_data) override;663664CanvasItemEditorViewport(CanvasItemEditor *p_canvas_item_editor);665~CanvasItemEditorViewport();666};667668669