Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the Container children selection but don't allow them to move #23059

Merged
merged 2 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
127 changes: 100 additions & 27 deletions editor/plugins/canvas_item_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,14 @@ bool CanvasItemEditor::_is_node_locked(const Node *p_node) {
return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
}

bool CanvasItemEditor::_is_node_movable(const Node *p_node) {
bool CanvasItemEditor::_is_node_movable(const Node *p_node, bool p_popup_warning) {
if (_is_node_locked(p_node)) {
return false;
}
if (Object::cast_to<Control>(p_node) && Object::cast_to<Container>(p_node->get_parent())) {
if (p_popup_warning) {
_popup_warning_temporarily(warning_child_of_container, 3.0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit weird to pass a reference to a Label IMO, and it means that if we want other warnings we'll have to create labels for each of them. I think it's simpler to reuse the same design as for the warning dialog, where you popup the dialog directly with the arbitrary string you want to display (and thus reuse the same Label for all warnings).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that I need the ability to check whether or not the warning is already displayed, so that it does not popup twice if it is already there. Using a string comparison is not really safe : as I want to expose this to plugins, they might not understand why their two warnings with the same text does do not popup.

So a solution could be to change the API to something like that:

int create_popup_warning("Warning: blablabla") // returns an ID
void popup_warning(int id, float time)

If you think this is cleaner I can change the API to that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use draw_string directly on the viewport, like in the other implementations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, depending on what you have behind it might be more or less easier to read (on white background for example). Also, this allow for several messages to be displayed, so we can reuse the system for other plugins.
So in the end, it's easier using containers + labels instead of drawing a string.

}
return false;
}
return true;
Expand Down Expand Up @@ -1295,26 +1298,28 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
// Start rotation
if (drag_type == DRAG_NONE) {
if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if ((b->get_control() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
List<CanvasItem *> selection = _get_edited_canvas_items();

// Remove not movable nodes
for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
if (!_is_node_movable(E->get()))
selection.erase(E);
}
// Remove not movable nodes
for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
if (!_is_node_movable(E->get(), true))
selection.erase(E);
}

drag_selection = selection;
if (drag_selection.size() > 0 && ((b->get_control() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE)) {
drag_type = DRAG_ROTATE;
drag_from = transform.affine_inverse().xform(b->get_position());
CanvasItem *canvas_item = drag_selection[0];
if (canvas_item->_edit_use_pivot()) {
drag_rotation_center = canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_pivot());
} else {
drag_rotation_center = canvas_item->get_global_transform_with_canvas().get_origin();
drag_selection = selection;
if (drag_selection.size() > 0) {
drag_type = DRAG_ROTATE;
drag_from = transform.affine_inverse().xform(b->get_position());
CanvasItem *canvas_item = drag_selection[0];
if (canvas_item->_edit_use_pivot()) {
drag_rotation_center = canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_pivot());
} else {
drag_rotation_center = canvas_item->get_global_transform_with_canvas().get_origin();
}
_save_canvas_item_state(drag_selection);
return true;
}
_save_canvas_item_state(drag_selection);
return true;
}
}
}
Expand Down Expand Up @@ -1772,16 +1777,16 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
//Start moving the nodes
if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();

// Remove not movable nodes
for (int i = 0; i < selection.size(); i++) {
if (!_is_node_movable(selection[i])) {
selection.erase(selection[i]);
// Remove not movable nodes
for (int i = 0; i < selection.size(); i++) {
if (!_is_node_movable(selection[i], true)) {
selection.erase(selection[i]);
}
}
}

if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) {
if (selection.size() > 0) {
drag_type = DRAG_MOVE;
drag_from = transform.affine_inverse().xform(b->get_position());
Expand Down Expand Up @@ -2067,7 +2072,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {

// Remove not movable nodes
for (int i = 0; i < selection.size(); i++) {
if (!_is_node_movable(selection[i])) {
if (!_is_node_movable(selection[i], true)) {
selection.erase(selection[i]);
}
}
Expand Down Expand Up @@ -3174,6 +3179,8 @@ void CanvasItemEditor::_draw_viewport() {
group_button->set_disabled(selection.empty());
ungroup_button->set_visible(all_group);

info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);

_draw_grid();
_draw_selection();
_draw_axis();
Expand Down Expand Up @@ -3541,6 +3548,35 @@ void CanvasItemEditor::_update_scrollbars() {
updating_scroll = false;
}

void CanvasItemEditor::_popup_warning_depop(Control *p_control) {
ERR_FAIL_COND(!popup_temporarily_timers.has(p_control));

Timer *timer = popup_temporarily_timers[p_control];
p_control->hide();
remove_child(timer);
popup_temporarily_timers.erase(p_control);
memdelete(timer);
info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
}

void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const float p_duration) {
Timer *timer;
if (!popup_temporarily_timers.has(p_control)) {
timer = memnew(Timer);
timer->connect("timeout", this, "_popup_warning_depop", varray(p_control));
timer->set_one_shot(true);
add_child(timer);

popup_temporarily_timers[p_control] = timer;
} else {
timer = popup_temporarily_timers[p_control];
}

timer->start(p_duration);
p_control->show();
info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
}

void CanvasItemEditor::_update_scroll(float) {

if (updating_scroll)
Expand Down Expand Up @@ -4247,7 +4283,7 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed);
ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list);
ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed);

ClassDB::bind_method("_popup_warning_depop", &CanvasItemEditor::_popup_warning_depop);
ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed);
ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
Expand Down Expand Up @@ -4433,7 +4469,22 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
viewport->update();
}

void CanvasItemEditor::add_control_to_info_overlay(Control *p_control) {
ERR_FAIL_COND(!p_control);

p_control->set_h_size_flags(p_control->get_h_size_flags() & ~Control::SIZE_EXPAND_FILL);
info_overlay->add_child(p_control);
info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
}

void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) {

info_overlay->remove_child(p_control);
info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
}

void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
ERR_FAIL_COND(!p_control);

hb->add_child(p_control);
}
Expand Down Expand Up @@ -4502,6 +4553,28 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->connect("draw", this, "_draw_viewport");
viewport->connect("gui_input", this, "_gui_input_viewport");

info_overlay = memnew(VBoxContainer);
info_overlay->set_anchors_and_margins_preset(Control::PRESET_BOTTOM_LEFT);
info_overlay->set_margin(MARGIN_LEFT, 10);
info_overlay->set_margin(MARGIN_BOTTOM, -15);
info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN);
info_overlay->add_constant_override("separation", 10);
viewport_scrollable->add_child(info_overlay);

Theme *info_overlay_theme = memnew(Theme);
info_overlay_theme->copy_default_theme();
info_overlay->set_theme(info_overlay_theme);

StyleBoxFlat *info_overlay_label_stylebox = memnew(StyleBoxFlat);
info_overlay_label_stylebox->set_bg_color(Color(0.0, 0.0, 0.0, 0.2));
info_overlay_label_stylebox->set_expand_margin_size_all(4);
info_overlay_theme->set_stylebox("normal", "Label", info_overlay_label_stylebox);

warning_child_of_container = memnew(Label);
warning_child_of_container->hide();
warning_child_of_container->set_text("Warning: Children of a container get their position and size determined only by their parent");
add_control_to_info_overlay(warning_child_of_container);

h_scroll = memnew(HScrollBar);
viewport->add_child(h_scroll);
h_scroll->connect("value_changed", this, "_update_scroll");
Expand Down
13 changes: 12 additions & 1 deletion editor/plugins/canvas_item_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ class CanvasItemEditor : public VBoxContainer {
ToolButton *zoom_reset;
ToolButton *zoom_plus;

Map<Control *, Timer *> popup_temporarily_timers;

Label *warning_child_of_container;
VBoxContainer *info_overlay;

Transform2D transform;
bool show_grid;
bool show_rulers;
Expand Down Expand Up @@ -370,7 +375,7 @@ class CanvasItemEditor : public VBoxContainer {
Ref<ShortCut> divide_grid_step_shortcut;

bool _is_node_locked(const Node *p_node);
bool _is_node_movable(const Node *p_node);
bool _is_node_movable(const Node *p_node, bool p_popup_warning = false);
void _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());
void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items);
void _get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items);
Expand Down Expand Up @@ -478,6 +483,9 @@ class CanvasItemEditor : public VBoxContainer {
void _update_bone_list();
void _tree_changed(Node *);

void _popup_warning_temporarily(Control *p_control, const float p_duration);
void _popup_warning_depop(Control *p_control);

friend class CanvasItemEditorPlugin;

protected:
Expand Down Expand Up @@ -543,6 +551,9 @@ class CanvasItemEditor : public VBoxContainer {
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);

void add_control_to_info_overlay(Control *p_control);
void remove_control_from_info_overlay(Control *p_control);

HSplitContainer *get_palette_split();
VSplitContainer *get_bottom_split();

Expand Down