Переглянути джерело

Allow selecting SpinBox & LineEdit text when focus enters

Haoyu Qiu 2 роки тому
батько
коміт
3aed3edc06

+ 3 - 0
doc/classes/LineEdit.xml

@@ -224,6 +224,9 @@
 		<member name="secret_character" type="String" setter="set_secret_character" getter="get_secret_character" default="&quot;•&quot;">
 			The character to use to mask secret input (defaults to "•"). Only a single character can be used as the secret character.
 		</member>
+		<member name="select_all_on_focus" type="bool" setter="set_select_all_on_focus" getter="is_select_all_on_focus" default="false">
+			If [code]true[/code], the [LineEdit] will select the whole text when it gains focus.
+		</member>
 		<member name="selecting_enabled" type="bool" setter="set_selecting_enabled" getter="is_selecting_enabled" default="true">
 			If [code]false[/code], it's impossible to select the text using mouse nor keyboard.
 		</member>

+ 3 - 0
doc/classes/SpinBox.xml

@@ -56,6 +56,9 @@
 		<member name="prefix" type="String" setter="set_prefix" getter="get_prefix" default="&quot;&quot;">
 			Adds the specified [code]prefix[/code] string before the numerical value of the [SpinBox].
 		</member>
+		<member name="select_all_on_focus" type="bool" setter="set_select_all_on_focus" getter="is_select_all_on_focus" default="false">
+			If [code]true[/code], the [SpinBox] will select the whole text when the [LineEdit] gains focus. Clicking the up and down arrows won't trigger this behavior.
+		</member>
 		<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
 			Adds the specified [code]suffix[/code] string after the numerical value of the [SpinBox].
 		</member>

+ 8 - 0
editor/plugins/canvas_item_editor_plugin.cpp

@@ -116,6 +116,7 @@ public:
 		grid_offset_x->set_allow_greater(true);
 		grid_offset_x->set_suffix("px");
 		grid_offset_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		grid_offset_x->set_select_all_on_focus(true);
 		child_container->add_child(grid_offset_x);
 
 		grid_offset_y = memnew(SpinBox);
@@ -125,6 +126,7 @@ public:
 		grid_offset_y->set_allow_greater(true);
 		grid_offset_y->set_suffix("px");
 		grid_offset_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		grid_offset_y->set_select_all_on_focus(true);
 		child_container->add_child(grid_offset_y);
 
 		label = memnew(Label);
@@ -138,6 +140,7 @@ public:
 		grid_step_x->set_allow_greater(true);
 		grid_step_x->set_suffix("px");
 		grid_step_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		grid_step_x->set_select_all_on_focus(true);
 		child_container->add_child(grid_step_x);
 
 		grid_step_y = memnew(SpinBox);
@@ -146,6 +149,7 @@ public:
 		grid_step_y->set_allow_greater(true);
 		grid_step_y->set_suffix("px");
 		grid_step_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		grid_step_y->set_select_all_on_focus(true);
 		child_container->add_child(grid_step_y);
 
 		child_container = memnew(GridContainer);
@@ -164,6 +168,7 @@ public:
 		primary_grid_steps->set_allow_greater(true);
 		primary_grid_steps->set_suffix(TTR("steps"));
 		primary_grid_steps->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		primary_grid_steps->set_select_all_on_focus(true);
 		child_container->add_child(primary_grid_steps);
 
 		container->add_child(memnew(HSeparator));
@@ -184,6 +189,7 @@ public:
 		rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE);
 		rotation_offset->set_suffix("deg");
 		rotation_offset->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		rotation_offset->set_select_all_on_focus(true);
 		child_container->add_child(rotation_offset);
 
 		label = memnew(Label);
@@ -196,6 +202,7 @@ public:
 		rotation_step->set_max(SPIN_BOX_ROTATION_RANGE);
 		rotation_step->set_suffix("deg");
 		rotation_step->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		rotation_step->set_select_all_on_focus(true);
 		child_container->add_child(rotation_step);
 
 		container->add_child(memnew(HSeparator));
@@ -214,6 +221,7 @@ public:
 		scale_step->set_allow_greater(true);
 		scale_step->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 		scale_step->set_step(0.01f);
+		scale_step->set_select_all_on_focus(true);
 		child_container->add_child(scale_step);
 	}
 

+ 9 - 0
editor/plugins/node_3d_editor_plugin.cpp

@@ -8046,12 +8046,15 @@ Node3DEditor::Node3DEditor() {
 	snap_dialog->add_child(snap_dialog_vbc);
 
 	snap_translate = memnew(LineEdit);
+	snap_translate->set_select_all_on_focus(true);
 	snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
 
 	snap_rotate = memnew(LineEdit);
+	snap_rotate->set_select_all_on_focus(true);
 	snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
 
 	snap_scale = memnew(LineEdit);
+	snap_scale->set_select_all_on_focus(true);
 	snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
 
 	_snap_update();
@@ -8070,6 +8073,7 @@ Node3DEditor::Node3DEditor() {
 	settings_fov->set_min(MIN_FOV);
 	settings_fov->set_step(0.1);
 	settings_fov->set_value(EDITOR_GET("editors/3d/default_fov"));
+	settings_fov->set_select_all_on_focus(true);
 	settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov);
 
 	settings_znear = memnew(SpinBox);
@@ -8077,6 +8081,7 @@ Node3DEditor::Node3DEditor() {
 	settings_znear->set_min(MIN_Z);
 	settings_znear->set_step(0.01);
 	settings_znear->set_value(EDITOR_GET("editors/3d/default_z_near"));
+	settings_znear->set_select_all_on_focus(true);
 	settings_vbc->add_margin_child(TTR("View Z-Near:"), settings_znear);
 
 	settings_zfar = memnew(SpinBox);
@@ -8084,6 +8089,7 @@ Node3DEditor::Node3DEditor() {
 	settings_zfar->set_min(MIN_Z);
 	settings_zfar->set_step(0.1);
 	settings_zfar->set_value(EDITOR_GET("editors/3d/default_z_far"));
+	settings_zfar->set_select_all_on_focus(true);
 	settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
 
 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; ++i) {
@@ -8109,6 +8115,7 @@ Node3DEditor::Node3DEditor() {
 	for (int i = 0; i < 3; i++) {
 		xform_translate[i] = memnew(LineEdit);
 		xform_translate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+		xform_translate[i]->set_select_all_on_focus(true);
 		xform_hbc->add_child(xform_translate[i]);
 	}
 
@@ -8122,6 +8129,7 @@ Node3DEditor::Node3DEditor() {
 	for (int i = 0; i < 3; i++) {
 		xform_rotate[i] = memnew(LineEdit);
 		xform_rotate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+		xform_rotate[i]->set_select_all_on_focus(true);
 		xform_hbc->add_child(xform_rotate[i]);
 	}
 
@@ -8135,6 +8143,7 @@ Node3DEditor::Node3DEditor() {
 	for (int i = 0; i < 3; i++) {
 		xform_scale[i] = memnew(LineEdit);
 		xform_scale[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+		xform_scale[i]->set_select_all_on_focus(true);
 		xform_hbc->add_child(xform_scale[i]);
 	}
 

+ 2 - 39
scene/gui/color_picker.cpp

@@ -368,11 +368,10 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) {
 
 	SpinBox *val = memnew(SpinBox);
 	slider->share(val);
+	val->set_select_all_on_focus(true);
 	gc->add_child(val);
 
 	LineEdit *vle = val->get_line_edit();
-	vle->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter), CONNECT_DEFERRED);
-	vle->connect("focus_exited", callable_mp(this, &ColorPicker::_focus_exit));
 	vle->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed));
 	vle->connect("gui_input", callable_mp(this, &ColorPicker::_line_edit_input));
 	vle->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
@@ -1407,47 +1406,11 @@ void ColorPicker::_screen_pick_pressed() {
 	//screen->show_modal();
 }
 
-void ColorPicker::_focus_enter() {
-	bool has_ctext_focus = c_text->has_focus();
-	if (has_ctext_focus) {
-		c_text->select_all();
-	} else {
-		c_text->select(0, 0);
-	}
-
-	for (int i = 0; i < current_slider_count; i++) {
-		if (values[i]->get_line_edit()->has_focus() && !has_ctext_focus) {
-			values[i]->get_line_edit()->select_all();
-		} else {
-			values[i]->get_line_edit()->select(0, 0);
-		}
-	}
-	if (alpha_value->get_line_edit()->has_focus() && !has_ctext_focus) {
-		alpha_value->get_line_edit()->select_all();
-	} else {
-		alpha_value->get_line_edit()->select(0, 0);
-	}
-}
-
-void ColorPicker::_focus_exit() {
-	for (int i = 0; i < current_slider_count; i++) {
-		if (!values[i]->get_line_edit()->get_menu()->is_visible()) {
-			values[i]->get_line_edit()->select(0, 0);
-		}
-	}
-	if (!alpha_value->get_line_edit()->get_menu()->is_visible()) {
-		alpha_value->get_line_edit()->select(0, 0);
-	}
-
-	c_text->select(0, 0);
-}
-
 void ColorPicker::_html_focus_exit() {
 	if (c_text->is_menu_visible()) {
 		return;
 	}
 	_html_submitted(c_text->get_text());
-	_focus_exit();
 }
 
 void ColorPicker::set_presets_enabled(bool p_enabled) {
@@ -1658,9 +1621,9 @@ ColorPicker::ColorPicker() :
 
 	c_text = memnew(LineEdit);
 	hhb->add_child(c_text);
+	c_text->set_select_all_on_focus(true);
 	c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted));
 	c_text->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed));
-	c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter), CONNECT_DEFERRED);
 	c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit));
 
 	wheel_edit = memnew(AspectRatioContainer);

+ 0 - 2
scene/gui/color_picker.h

@@ -202,8 +202,6 @@ private:
 	void _text_changed(const String &p_new_text);
 	void _add_preset_pressed();
 	void _screen_pick_pressed();
-	void _focus_enter();
-	void _focus_exit();
 	void _html_focus_exit();
 
 	inline int _get_preset_size();

+ 29 - 0
scene/gui/line_edit.cpp

@@ -372,6 +372,11 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
 				selection.drag_attempt = false;
 			}
 
+			if (pending_select_all_on_focus) {
+				select_all();
+				pending_select_all_on_focus = false;
+			}
+
 			show_virtual_keyboard();
 		}
 
@@ -1056,6 +1061,15 @@ void LineEdit::_notification(int p_what) {
 				}
 			}
 
+			if (select_all_on_focus) {
+				if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
+					// Select all when the mouse button is up.
+					pending_select_all_on_focus = true;
+				} else {
+					select_all();
+				}
+			}
+
 			if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
 				DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
 				Point2 column = Point2(get_caret_column(), 1) * get_minimum_size().height;
@@ -2164,6 +2178,18 @@ bool LineEdit::is_flat() const {
 	return flat;
 }
 
+void LineEdit::set_select_all_on_focus(bool p_enabled) {
+	select_all_on_focus = p_enabled;
+}
+
+bool LineEdit::is_select_all_on_focus() const {
+	return select_all_on_focus;
+}
+
+void LineEdit::clear_pending_select_all_on_focus() {
+	pending_select_all_on_focus = false;
+}
+
 void LineEdit::_text_changed() {
 	_emit_text_change();
 	_clear_redo();
@@ -2367,6 +2393,8 @@ void LineEdit::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon);
 	ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &LineEdit::set_flat);
 	ClassDB::bind_method(D_METHOD("is_flat"), &LineEdit::is_flat);
+	ClassDB::bind_method(D_METHOD("set_select_all_on_focus", "enabled"), &LineEdit::set_select_all_on_focus);
+	ClassDB::bind_method(D_METHOD("is_select_all_on_focus"), &LineEdit::is_select_all_on_focus);
 
 	ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text")));
 	ADD_SIGNAL(MethodInfo("text_change_rejected", PropertyInfo(Variant::STRING, "rejected_substring")));
@@ -2430,6 +2458,7 @@ void LineEdit::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus");
 
 	ADD_GROUP("Caret", "caret_");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");

+ 7 - 0
scene/gui/line_edit.h

@@ -174,6 +174,9 @@ private:
 	double caret_blink_timer = 0.0;
 	bool caret_blinking = false;
 
+	bool pending_select_all_on_focus = false;
+	bool select_all_on_focus = false;
+
 	struct ThemeCache {
 		Ref<StyleBox> normal;
 		Ref<StyleBox> read_only;
@@ -365,6 +368,10 @@ public:
 	void set_flat(bool p_enabled);
 	bool is_flat() const;
 
+	void set_select_all_on_focus(bool p_enabled);
+	bool is_select_all_on_focus() const;
+	void clear_pending_select_all_on_focus(); // For other controls, e.g. SpinBox.
+
 	virtual bool is_text_field() const override;
 
 	void show_virtual_keyboard();

+ 17 - 0
scene/gui/spin_box.cpp

@@ -168,6 +168,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
 		range_click_timer->stop();
 		_release_mouse();
 		drag.allowed = false;
+		line_edit->clear_pending_select_all_on_focus();
 	}
 
 	Ref<InputEventMouseMotion> mm = p_event;
@@ -190,6 +191,11 @@ void SpinBox::_line_edit_focus_enter() {
 	int col = line_edit->get_caret_column();
 	_value_changed(0); // Update the LineEdit's text.
 	line_edit->set_caret_column(col);
+
+	// LineEdit text might change and it clears any selection. Have to re-select here.
+	if (line_edit->is_select_all_on_focus() && !Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
+		line_edit->select_all();
+	}
 }
 
 void SpinBox::_line_edit_focus_exit() {
@@ -308,6 +314,14 @@ bool SpinBox::get_update_on_text_changed() const {
 	return update_on_text_changed;
 }
 
+void SpinBox::set_select_all_on_focus(bool p_enabled) {
+	line_edit->set_select_all_on_focus(p_enabled);
+}
+
+bool SpinBox::is_select_all_on_focus() const {
+	return line_edit->is_select_all_on_focus();
+}
+
 void SpinBox::set_editable(bool p_enabled) {
 	line_edit->set_editable(p_enabled);
 }
@@ -341,6 +355,8 @@ void SpinBox::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_editable"), &SpinBox::is_editable);
 	ClassDB::bind_method(D_METHOD("set_update_on_text_changed", "enabled"), &SpinBox::set_update_on_text_changed);
 	ClassDB::bind_method(D_METHOD("get_update_on_text_changed"), &SpinBox::get_update_on_text_changed);
+	ClassDB::bind_method(D_METHOD("set_select_all_on_focus", "enabled"), &SpinBox::set_select_all_on_focus);
+	ClassDB::bind_method(D_METHOD("is_select_all_on_focus"), &SpinBox::is_select_all_on_focus);
 	ClassDB::bind_method(D_METHOD("apply"), &SpinBox::apply);
 	ClassDB::bind_method(D_METHOD("get_line_edit"), &SpinBox::get_line_edit);
 
@@ -350,6 +366,7 @@ void SpinBox::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "prefix"), "set_prefix", "get_prefix");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_arrow_step"), "set_custom_arrow_step", "get_custom_arrow_step");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus");
 }
 
 SpinBox::SpinBox() {

+ 3 - 0
scene/gui/spin_box.h

@@ -101,6 +101,9 @@ public:
 	void set_update_on_text_changed(bool p_enabled);
 	bool get_update_on_text_changed() const;
 
+	void set_select_all_on_focus(bool p_enabled);
+	bool is_select_all_on_focus() const;
+
 	void apply();
 	void set_custom_arrow_step(const double p_custom_arrow_step);
 	double get_custom_arrow_step() const;