Allow selecting SpinBox & LineEdit text when focus enters

This commit is contained in:
Haoyu Qiu 2022-10-16 20:37:35 +08:00
parent 11e1bac768
commit 3aed3edc06
10 changed files with 81 additions and 41 deletions

View file

@ -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>

View file

@ -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>

View file

@ -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);
}

View file

@ -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]);
}

View file

@ -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);

View file

@ -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();

View file

@ -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");

View file

@ -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();

View file

@ -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() {

View file

@ -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;