Merge pull request #90743 from timothyqiu/empty-selection-clipboard

Add TextEdit option to prevent copying without a selection
This commit is contained in:
Rémi Verschelde 2024-09-23 12:27:35 +02:00
commit 720c236fc0
No known key found for this signature in database
GPG Key ID: C3336907360768E1
9 changed files with 112 additions and 0 deletions

View File

@ -1200,6 +1200,9 @@
<member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter=""> <member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter="">
If [code]true[/code], trims trailing whitespace when saving a script. Trailing whitespace refers to tab and space characters placed at the end of lines. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy. If [code]true[/code], trims trailing whitespace when saving a script. Trailing whitespace refers to tab and space characters placed at the end of lines. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy.
</member> </member>
<member name="text_editor/behavior/general/empty_selection_clipboard" type="bool" setter="" getter="">
If [code]true[/code], copying or cutting without a selection is performed on all lines with a caret. Otherwise, copy and cut require a selection.
</member>
<member name="text_editor/behavior/indent/auto_indent" type="bool" setter="" getter=""> <member name="text_editor/behavior/indent/auto_indent" type="bool" setter="" getter="">
If [code]true[/code], automatically indents code when pressing the [kbd]Enter[/kbd] key based on blocks above the new line. If [code]true[/code], automatically indents code when pressing the [kbd]Enter[/kbd] key based on blocks above the new line.
</member> </member>

View File

@ -1299,6 +1299,9 @@
<member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled"> <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true" keywords="readonly, disabled, enabled">
If [code]false[/code], existing text cannot be modified and new text cannot be added. If [code]false[/code], existing text cannot be modified and new text cannot be added.
</member> </member>
<member name="empty_selection_clipboard_enabled" type="bool" setter="set_empty_selection_clipboard_enabled" getter="is_empty_selection_clipboard_enabled" default="true">
If [code]true[/code], copying or cutting without a selection is performed on all lines with a caret. Otherwise, copy and cut require a selection.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
<member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled" default="false"> <member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled" default="false">
If [code]true[/code], all occurrences of the selected text will be highlighted. If [code]true[/code], all occurrences of the selected text will be highlighted.

View File

@ -1090,6 +1090,9 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_draw_spaces(EDITOR_GET("text_editor/appearance/whitespace/draw_spaces")); text_editor->set_draw_spaces(EDITOR_GET("text_editor/appearance/whitespace/draw_spaces"));
text_editor->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing")); text_editor->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing"));
// Behavior: General
text_editor->set_empty_selection_clipboard_enabled(EDITOR_GET("text_editor/behavior/general/empty_selection_clipboard"));
// Behavior: Navigation // Behavior: Navigation
text_editor->set_scroll_past_end_of_file_enabled(EDITOR_GET("text_editor/behavior/navigation/scroll_past_end_of_file")); text_editor->set_scroll_past_end_of_file_enabled(EDITOR_GET("text_editor/behavior/navigation/scroll_past_end_of_file"));
text_editor->set_smooth_scroll_enabled(EDITOR_GET("text_editor/behavior/navigation/smooth_scrolling")); text_editor->set_smooth_scroll_enabled(EDITOR_GET("text_editor/behavior/navigation/smooth_scrolling"));

View File

@ -668,6 +668,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/whitespace/line_spacing", 4, "0,50,1") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/whitespace/line_spacing", 4, "0,50,1")
// Behavior // Behavior
// Behavior: General
_initial_set("text_editor/behavior/general/empty_selection_clipboard", true);
// Behavior: Navigation // Behavior: Navigation
_initial_set("text_editor/behavior/navigation/move_caret_on_right_click", true, true); _initial_set("text_editor/behavior/navigation/move_caret_on_right_click", true, true);
_initial_set("text_editor/behavior/navigation/scroll_past_end_of_file", false, true); _initial_set("text_editor/behavior/navigation/scroll_past_end_of_file", false, true);

View File

@ -831,6 +831,9 @@ void CodeEdit::_cut_internal(int p_caret) {
delete_selection(p_caret); delete_selection(p_caret);
return; return;
} }
if (!is_empty_selection_clipboard_enabled()) {
return;
}
if (p_caret == -1) { if (p_caret == -1) {
delete_lines(); delete_lines();
} else { } else {

View File

@ -3367,6 +3367,14 @@ bool TextEdit::is_middle_mouse_paste_enabled() const {
return middle_mouse_paste_enabled; return middle_mouse_paste_enabled;
} }
void TextEdit::set_empty_selection_clipboard_enabled(bool p_enabled) {
empty_selection_clipboard_enabled = p_enabled;
}
bool TextEdit::is_empty_selection_clipboard_enabled() const {
return empty_selection_clipboard_enabled;
}
// Text manipulation // Text manipulation
void TextEdit::clear() { void TextEdit::clear() {
setting_text = true; setting_text = true;
@ -6569,6 +6577,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_middle_mouse_paste_enabled", "enabled"), &TextEdit::set_middle_mouse_paste_enabled); ClassDB::bind_method(D_METHOD("set_middle_mouse_paste_enabled", "enabled"), &TextEdit::set_middle_mouse_paste_enabled);
ClassDB::bind_method(D_METHOD("is_middle_mouse_paste_enabled"), &TextEdit::is_middle_mouse_paste_enabled); ClassDB::bind_method(D_METHOD("is_middle_mouse_paste_enabled"), &TextEdit::is_middle_mouse_paste_enabled);
ClassDB::bind_method(D_METHOD("set_empty_selection_clipboard_enabled", "enabled"), &TextEdit::set_empty_selection_clipboard_enabled);
ClassDB::bind_method(D_METHOD("is_empty_selection_clipboard_enabled"), &TextEdit::is_empty_selection_clipboard_enabled);
// Text manipulation // Text manipulation
ClassDB::bind_method(D_METHOD("clear"), &TextEdit::clear); ClassDB::bind_method(D_METHOD("clear"), &TextEdit::clear);
@ -6962,6 +6973,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_and_drop_selection_enabled"), "set_drag_and_drop_selection_enabled", "is_drag_and_drop_selection_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_and_drop_selection_enabled"), "set_drag_and_drop_selection_enabled", "is_drag_and_drop_selection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "empty_selection_clipboard_enabled"), "set_empty_selection_clipboard_enabled", "is_empty_selection_clipboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Arbitrary:1,Word:2,Word (Smart):3"), "set_autowrap_mode", "get_autowrap_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Arbitrary:1,Word:2,Word (Smart):3"), "set_autowrap_mode", "get_autowrap_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_wrapped_lines"), "set_indent_wrapped_lines", "is_indent_wrapped_lines"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_wrapped_lines"), "set_indent_wrapped_lines", "is_indent_wrapped_lines");
@ -7216,6 +7228,10 @@ void TextEdit::_cut_internal(int p_caret) {
return; return;
} }
if (!empty_selection_clipboard_enabled) {
return;
}
// Remove full lines. // Remove full lines.
begin_complex_operation(); begin_complex_operation();
begin_multicaret_edit(); begin_multicaret_edit();
@ -7246,6 +7262,10 @@ void TextEdit::_copy_internal(int p_caret) {
return; return;
} }
if (!empty_selection_clipboard_enabled) {
return;
}
// Copy full lines. // Copy full lines.
StringBuilder clipboard; StringBuilder clipboard;
Vector<Point2i> line_ranges; Vector<Point2i> line_ranges;

View File

@ -319,6 +319,7 @@ private:
bool shortcut_keys_enabled = true; bool shortcut_keys_enabled = true;
bool virtual_keyboard_enabled = true; bool virtual_keyboard_enabled = true;
bool middle_mouse_paste_enabled = true; bool middle_mouse_paste_enabled = true;
bool empty_selection_clipboard_enabled = true;
// Overridable actions. // Overridable actions.
String cut_copy_line = ""; String cut_copy_line = "";
@ -770,6 +771,9 @@ public:
void set_middle_mouse_paste_enabled(bool p_enabled); void set_middle_mouse_paste_enabled(bool p_enabled);
bool is_middle_mouse_paste_enabled() const; bool is_middle_mouse_paste_enabled() const;
void set_empty_selection_clipboard_enabled(bool p_enabled);
bool is_empty_selection_clipboard_enabled() const;
// Text manipulation // Text manipulation
void clear(); void clear();

View File

@ -4779,6 +4779,31 @@ TEST_CASE("[SceneTree][CodeEdit] text manipulation") {
CHECK(code_edit->get_caret_column(3) == 0); CHECK(code_edit->get_caret_column(3) == 0);
} }
SUBCASE("[SceneTree][CodeEdit] cut when empty selection clipboard disabled") {
DisplayServerMock *DS = (DisplayServerMock *)(DisplayServer::get_singleton());
code_edit->set_empty_selection_clipboard_enabled(false);
DS->clipboard_set("");
code_edit->set_text("this is\nsome\n");
code_edit->set_caret_line(0);
code_edit->set_caret_column(6);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
code_edit->cut();
MessageQueue::get_singleton()->flush();
CHECK(DS->clipboard_get() == "");
CHECK(code_edit->get_text() == "this is\nsome\n");
CHECK(code_edit->get_caret_line() == 0);
CHECK(code_edit->get_caret_column() == 6);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[SceneTree][CodeEdit] new line") { SUBCASE("[SceneTree][CodeEdit] new line") {
// Add a new line. // Add a new line.
code_edit->set_text("test new line"); code_edit->set_text("test new line");

View File

@ -3585,6 +3585,54 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("lines_edited_from"); SIGNAL_CHECK_FALSE("lines_edited_from");
} }
SUBCASE("[TextEdit] cut when empty selection clipboard disabled") {
text_edit->set_empty_selection_clipboard_enabled(false);
DS->clipboard_set("");
text_edit->set_text("this is\nsome\n");
text_edit->set_caret_line(0);
text_edit->set_caret_column(6);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
text_edit->cut();
MessageQueue::get_singleton()->flush();
CHECK(DS->clipboard_get() == "");
CHECK(text_edit->get_text() == "this is\nsome\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 6);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] copy when empty selection clipboard disabled") {
text_edit->set_empty_selection_clipboard_enabled(false);
DS->clipboard_set("");
text_edit->set_text("this is\nsome\n");
text_edit->set_caret_line(0);
text_edit->set_caret_column(6);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
text_edit->copy();
MessageQueue::get_singleton()->flush();
CHECK(DS->clipboard_get() == "");
CHECK(text_edit->get_text() == "this is\nsome\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 6);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SIGNAL_UNWATCH(text_edit, "text_set"); SIGNAL_UNWATCH(text_edit, "text_set");
SIGNAL_UNWATCH(text_edit, "text_changed"); SIGNAL_UNWATCH(text_edit, "text_changed");
SIGNAL_UNWATCH(text_edit, "lines_edited_from"); SIGNAL_UNWATCH(text_edit, "lines_edited_from");