-
-
Notifications
You must be signed in to change notification settings - Fork 21.8k
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
Add drag and drop to TextEdit #55294
Add drag and drop to TextEdit #55294
Conversation
3e901a5
to
bdddf2d
Compare
This commit should solve godotengine/godot-proposals#3488 |
Nice! This wasn't apparent with the previous PRs, but it would be useful if holding Ctrl would make the text being copied instead of moved. |
bdddf2d
to
48e652e
Compare
I've added support for copy when CTRL is pressed in both TextEdit and LineEdit |
When moving a text within one TextEdit, it's registered as 2 operations (remove -> add), so you need to undo twice to revert moving. This should be merged into one undo step (check "complex operation" stuff in TextEdit). |
48e652e
to
314d091
Compare
Fixed |
I can try to fix it, but I suspect that this is tricky to implement.
Yes, TextEdit has many problems when you run the project, but it is not caused by my changes. |
Well, if it's too difficult then it's not worth it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested and it works fine (except the runtime bug, but it's unrelated issue). The code is similar to LineEdit changes, so it's likely good to, but @Paulb23 might want to take a look too.
314d091
to
b351576
Compare
I've done some small changes to handle the copy-drop at the beginning and at the end of selection. |
b351576
to
31892eb
Compare
scene/gui/text_edit.cpp
Outdated
if (!text_changed_dirty) { | ||
if (is_inside_tree()) { | ||
MessageQueue::get_singleton()->push_call(this, "_text_changed"); | ||
} | ||
text_changed_dirty = true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to call the MessageQueue
in TextEdit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.cpp
Outdated
@@ -5691,6 +5825,43 @@ void TextEdit::_post_shift_selection() { | |||
selection.selecting_text = true; | |||
} | |||
|
|||
bool TextEdit::_is_caret_inside_selection(bool p_edge) const { | |||
Point2i pos = get_line_column_at_pos(get_local_mouse_pos()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check the selection here rather then in external ifs
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.cpp
Outdated
@@ -5691,6 +5825,43 @@ void TextEdit::_post_shift_selection() { | |||
selection.selecting_text = true; | |||
} | |||
|
|||
bool TextEdit::_is_caret_inside_selection(bool p_edge) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This checks the mouse not not the caret, would be better called is_mouse_over_selection
or is_cursor_over_selection
, also would be nice to expose to the API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.cpp
Outdated
@@ -1538,6 +1564,9 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { | |||
|
|||
update(); | |||
} | |||
} else if (is_editable() && has_selection() && _is_caret_inside_selection()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should allow dragging from a TextEdit
even if it's not editable
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.cpp
Outdated
if (is_editable() && has_selection() && _is_caret_inside_selection()) { | ||
selection.drag_attempt = true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure on the use case this is solving, as it should be caught in the above statement, should be safe to remove this?
Testing, locally, it seems to prevent word and line selection modes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed when you do a double or triple click and you keep the left mouse button pressed on your last click to start dragging.
The code here is really tricky, but I've added the drag and drop feature trying to avoid dangerous refactoring of the actual code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed when you do a double or triple click and you keep the left mouse button pressed on your last click to start dragging.
We should't start dragging in this use case, it should continue to select text in the given mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior has been kept from original LineEdit before my changes, this is the discussion #54339 (review)
I can change it in both LineEdit and TextEdit (and perhaps also in my commit for RichTextLabel), I've implemented it only because of KoBeWi comment.
Let me know what should be the expected behavior in these cases in Godot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking around most editors have text dragging as a separate action, so I would expect Godot to do the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only hope that users do not complain about that change in the previous behavior (I'm referring to LineEdit)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the drag start in case of double or triple click from TextEdit and LineEdit
scene/gui/text_edit.cpp
Outdated
@@ -2406,6 +2460,86 @@ bool TextEdit::is_text_field() const { | |||
return true; | |||
} | |||
|
|||
Variant TextEdit::get_drag_data(const Point2 &p_point) { | |||
if (selection.drag_attempt && selection.active) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Can invert this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
void TextEdit::drop_data(const Point2 &p_point, const Variant &p_data) { | ||
Control::drop_data(p_point, p_data); | ||
|
||
if (p_data.get_type() == Variant::STRING && is_editable()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can invert this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.h
Outdated
virtual String get_tooltip(const Point2 &p_pos) const override; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accidental new line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.cpp
Outdated
} | ||
text_changed_dirty = true; | ||
} | ||
update(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to call update here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.cpp
Outdated
} | ||
} | ||
} | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems overly complex, would something like the following work?
if (p_edge) {
if ((row == selection.from_line && col == selection.from_column) || (row == selection.to_line && col == selection.to_column)) {
return true
}
}
return (row > selection.from_line && row <= selection.to_line && (row > selection.from_line || col >= selection.from_column) && (row < selection.to_line || col < selection.to_column))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've used the first part of your code to simplify the current code.
But the second part
return (row > selection.from_line && row <= selection.to_line && (row > selection.from_line || col >= selection.from_column) && (row < selection.to_line || col < selection.to_column))
is not correct, it does not handle all the possible cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What use cases are missing from that statement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest I didn't thoroughly analyze that line of code, I stopped at
row > selection.from_line &&
that exclude the first line of selection, so I assumed you misunderstood the meaning of the p_edge parameter and used my code.
Looking back at your code I now understand what you wanted to do, but to make it work some changes are needed:
row > selection.from_line --> row >= selection.from_line
and
col >= selection.from_column --> col > selection.from_column
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
31892eb
to
ec142a2
Compare
ec142a2
to
6fddac9
Compare
@Paulb23 as we discussed here #54339 (comment) |
e3085c0
to
b7ad3dd
Compare
scene/gui/text_edit.cpp
Outdated
if (pos.y <= get_first_visible_line()) { | ||
_scroll_lines_up(); | ||
} else if (pos.y >= get_last_full_visible_line()) { | ||
_scroll_lines_down(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need to do this, set_caret_column
should adjust the viewport for us.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in theory it shouldn't be necessary, but in practice the scroll won't work without this code.
I have the possibility to test only on Linux, so I don't know if the problem is limited to this platform, but without the code I added the scroll only works if you move the selection from top to bottom, if you move from the bottom upward the scroll does not work.
I can add a comment at the beginning of the code to indicate that this is a temporary workaround, if you remove that code the drag functionality would be almost unusable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would still remove it for this PR, not a keen on adding temporary workarounds as they quickly become permanent. The base issue should be fixed instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
scene/gui/text_edit.cpp
Outdated
void TextEdit::drop_data(const Point2 &p_point, const Variant &p_data) { | ||
Control::drop_data(p_point, p_data); | ||
|
||
if (is_editable() && p_data.get_type() == Variant::STRING) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
: Can invert this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
set_caret_line(caret_row_tmp, true, false); | ||
set_caret_column(caret_column_tmp); | ||
insert_text_at_caret(p_data); | ||
end_complex_operation(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need to call delete_selection
here as insert_text_at_caret
will handle that. This should also remove the need to make this a complex operation. Similar for the else if
below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the second delete_selection
after the else if
The first one instead is needed, because is true that insert_text_at_caret
call delete_selection
, but delete_selection
reset the caret position at the beginning of the selection and this break the code for the drag and drop.
b7ad3dd
to
0699941
Compare
Thanks! |
I've implemented the drag and drop operation on TextEdit.
Update: I've added support for copy when CTRL is pressed in both TextEdit and LineEdit as suggested by @KoBeWi