mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
Merge pull request #110250 from YeldhamDev/i_just_cant_keep_focused
Hide `Control` focus when given via mouse input
This commit is contained in:
commit
be421bcdd4
53 changed files with 229 additions and 105 deletions
|
@ -1675,6 +1675,7 @@ ProjectSettings::ProjectSettings() {
|
|||
#endif
|
||||
|
||||
GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
|
||||
GLOBAL_DEF("gui/common/always_show_focus_state", false);
|
||||
GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true);
|
||||
|
||||
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/vsync/frame_queue_size", PROPERTY_HINT_RANGE, "2,3,1"), 2);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
Godot propagates input events via viewports. Each [Viewport] is responsible for propagating [InputEvent]s to their child nodes. As the [member SceneTree.root] is a [Window], this already happens automatically for all UI elements in your game.
|
||||
Input events are propagated through the [SceneTree] from the root node to all child nodes by calling [method Node._input]. For UI elements specifically, it makes more sense to override the virtual method [method _gui_input], which filters out unrelated input events, such as by checking z-order, [member mouse_filter], focus, or if the event was inside of the control's bounding box.
|
||||
Call [method accept_event] so no other node receives the event. Once you accept an input, it becomes handled so [method Node._unhandled_input] will not process it.
|
||||
Only one [Control] node can be in focus. Only the node in focus will receive events. To get the focus, call [method grab_focus]. [Control] nodes lose focus when another node grabs it, or if you hide the node in focus.
|
||||
Only one [Control] node can be in focus. Only the node in focus will receive events. To get the focus, call [method grab_focus]. [Control] nodes lose focus when another node grabs it, or if you hide the node in focus. Focus will not be represented visually if gained via mouse/touch input, only appearing with keyboard/gamepad input (for accessibility), or via [method grab_focus].
|
||||
Sets [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] to tell a [Control] node to ignore mouse or touch events. You'll need it if you place an icon on top of a button.
|
||||
[Theme] resources change the control's appearance. The [member theme] of a [Control] node affects all of its direct and indirect children (as long as a chain of controls is uninterrupted). To override some of the theme items, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can also override theme items in the Inspector.
|
||||
[b]Note:[/b] Theme items are [i]not[/i] [Object] properties. This means you can't access their values using [method Object.get] and [method Object.set]. Instead, use the [code]get_theme_*[/code] and [code]add_theme_*_override[/code] methods provided by this class.
|
||||
|
@ -618,15 +618,19 @@
|
|||
</method>
|
||||
<method name="grab_focus">
|
||||
<return type="void" />
|
||||
<param index="0" name="hide_focus" type="bool" default="false" />
|
||||
<description>
|
||||
Steal the focus from another control and become the focused control (see [member focus_mode]).
|
||||
If [param hide_focus] is [code]true[/code], the control will not visually show its focused state. Has no effect if [member ProjectSettings.gui/common/always_show_focus_state] is set to [code]true[/code].
|
||||
[b]Note:[/b] Using this method together with [method Callable.call_deferred] makes it more reliable, especially when called inside [method Node._ready].
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_focus" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="ignore_hidden_focus" type="bool" default="false" />
|
||||
<description>
|
||||
Returns [code]true[/code] if this is the current focused control. See [member focus_mode].
|
||||
If [param ignore_hidden_focus] is [code]true[/code], controls that have their focus hidden will always return [code]false[/code]. Hidden focus happens automatically when controls gain focus via mouse input, or manually using [method grab_focus] with [code]hide_focus[/code] set to [code]true[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_theme_color" qualifiers="const">
|
||||
|
|
|
@ -1177,6 +1177,9 @@
|
|||
<member name="filesystem/import/fbx2gltf/enabled.web" type="bool" setter="" getter="" default="false">
|
||||
Override for [member filesystem/import/fbx2gltf/enabled] on the Web where FBX2glTF can't easily be accessed from Godot.
|
||||
</member>
|
||||
<member name="gui/common/always_show_focus_state" type="bool" setter="" getter="" default="false">
|
||||
If [code]true[/code], [Control]s will always show if they're focused, even if said focus was gained via mouse/touch input.
|
||||
</member>
|
||||
<member name="gui/common/default_scroll_deadzone" type="int" setter="" getter="" default="0">
|
||||
Default value for [member ScrollContainer.scroll_deadzone], which will be used for all [ScrollContainer]s unless overridden.
|
||||
</member>
|
||||
|
|
|
@ -303,7 +303,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
const int h_separation = get_theme_constant(SNAME("h_separation"), SNAME("AnimationBezierTrackEdit"));
|
||||
const int v_separation = get_theme_constant(SNAME("h_separation"), SNAME("AnimationBezierTrackEdit"));
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
draw_rect(Rect2(Point2(), get_size()), focus_color, false, Math::round(EDSCALE));
|
||||
}
|
||||
|
||||
|
|
|
@ -448,7 +448,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
|
|||
|
||||
Size2 s = blend_space_draw->get_size();
|
||||
|
||||
if (blend_space_draw->has_focus()) {
|
||||
if (blend_space_draw->has_focus(true)) {
|
||||
Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
|
||||
blend_space_draw->draw_rect(Rect2(Point2(), s), color, false);
|
||||
}
|
||||
|
|
|
@ -952,7 +952,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
|
|||
travel_path = playback->get_travel_path();
|
||||
}
|
||||
|
||||
if (state_machine_draw->has_focus()) {
|
||||
if (state_machine_draw->has_focus(true)) {
|
||||
state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), theme_cache.focus_color, false);
|
||||
}
|
||||
int sep = 3 * EDSCALE;
|
||||
|
|
|
@ -775,13 +775,13 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa
|
|||
item = item->get_next();
|
||||
}
|
||||
if (p_grab_focus) {
|
||||
tree->grab_focus();
|
||||
tree->grab_focus(true);
|
||||
}
|
||||
} else {
|
||||
(*directory_ptr)->select(0);
|
||||
_update_file_list(false);
|
||||
if (p_grab_focus) {
|
||||
files->grab_focus();
|
||||
files->grab_focus(true);
|
||||
}
|
||||
}
|
||||
tree->ensure_cursor_is_visible();
|
||||
|
@ -1397,7 +1397,7 @@ void FileSystemDock::_update_history() {
|
|||
|
||||
if (tree->is_visible()) {
|
||||
_update_tree(get_uncollapsed_paths());
|
||||
tree->grab_focus();
|
||||
tree->grab_focus(true);
|
||||
}
|
||||
|
||||
if (file_list_vb->is_visible()) {
|
||||
|
@ -3537,7 +3537,7 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos, MouseButton p_button
|
|||
if (p_button != MouseButton::RIGHT) {
|
||||
return;
|
||||
}
|
||||
tree->grab_focus();
|
||||
tree->grab_focus(true);
|
||||
|
||||
// Right click is pressed in the tree.
|
||||
Vector<String> paths = _tree_get_selected(false);
|
||||
|
|
|
@ -1553,7 +1553,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||
editor_selection->clear();
|
||||
editor_selection->add_node(new_node);
|
||||
|
||||
scene_tree->get_scene_tree()->grab_focus();
|
||||
scene_tree->get_scene_tree()->grab_focus(true);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
|
@ -3146,7 +3146,7 @@ void SceneTreeDock::_create() {
|
|||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
scene_tree->get_scene_tree()->grab_focus();
|
||||
scene_tree->get_scene_tree()->grab_focus(true);
|
||||
}
|
||||
|
||||
void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node) {
|
||||
|
|
|
@ -599,10 +599,10 @@ void FindReplaceBar::_show_search(bool p_with_replace, bool p_show_only) {
|
|||
|
||||
if (focus_replace) {
|
||||
search_text->deselect();
|
||||
callable_mp((Control *)replace_text, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)replace_text, &Control::grab_focus).call_deferred(false);
|
||||
} else {
|
||||
replace_text->deselect();
|
||||
callable_mp((Control *)search_text, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)search_text, &Control::grab_focus).call_deferred(false);
|
||||
}
|
||||
|
||||
if (on_one_line) {
|
||||
|
|
|
@ -563,7 +563,7 @@ void CreateDialog::_notification(int p_what) {
|
|||
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
if (is_visible()) {
|
||||
callable_mp((Control *)search_box, &Control::grab_focus).call_deferred(); // Still not visible.
|
||||
callable_mp((Control *)search_box, &Control::grab_focus).call_deferred(false); // Still not visible.
|
||||
search_box->select_all();
|
||||
} else {
|
||||
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "create_new_node", Rect2(get_position(), get_size()));
|
||||
|
|
|
@ -483,9 +483,9 @@ void EditorFileDialog::_post_popup() {
|
|||
set_current_dir(current);
|
||||
|
||||
if (mode == FILE_MODE_SAVE_FILE) {
|
||||
file->grab_focus();
|
||||
file->grab_focus(true);
|
||||
} else {
|
||||
item_list->grab_focus();
|
||||
item_list->grab_focus(true);
|
||||
}
|
||||
|
||||
bool is_open_directory_mode = mode == FILE_MODE_OPEN_DIR;
|
||||
|
|
|
@ -162,7 +162,7 @@ void EditorSpinSlider::_grab_end() {
|
|||
grabbing_spinner = false;
|
||||
emit_signal("ungrabbed");
|
||||
} else {
|
||||
_focus_entered();
|
||||
_focus_entered(true);
|
||||
}
|
||||
|
||||
grabbing_spinner_attempt = false;
|
||||
|
@ -204,7 +204,7 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
|
|||
grabbing_ratio = get_as_ratio();
|
||||
grabbing_from = grabber->get_transform().xform(mb->get_position()).x;
|
||||
}
|
||||
grab_focus();
|
||||
grab_focus(true);
|
||||
emit_signal("grabbed");
|
||||
} else {
|
||||
grabbing_grabber = false;
|
||||
|
@ -340,7 +340,7 @@ void EditorSpinSlider::_draw_spin_slider() {
|
|||
}
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
Ref<StyleBox> focus = get_theme_stylebox(SNAME("focus"), SNAME("LineEdit"));
|
||||
draw_style_box(focus, Rect2(Vector2(), size));
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ bool EditorSpinSlider::is_grabbing() const {
|
|||
return grabbing_grabber || grabbing_spinner;
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_focus_entered() {
|
||||
void EditorSpinSlider::_focus_entered(bool p_hide_focus) {
|
||||
if (read_only) {
|
||||
return;
|
||||
}
|
||||
|
@ -683,7 +683,7 @@ void EditorSpinSlider::_focus_entered() {
|
|||
value_input->set_focus_next(find_next_valid_focus()->get_path());
|
||||
value_input->set_focus_previous(find_prev_valid_focus()->get_path());
|
||||
callable_mp((CanvasItem *)value_input_popup, &CanvasItem::show).call_deferred();
|
||||
callable_mp((Control *)value_input, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)value_input, &Control::grab_focus).call_deferred(p_hide_focus);
|
||||
callable_mp(value_input, &LineEdit ::select_all).call_deferred();
|
||||
emit_signal("value_focus_entered");
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ protected:
|
|||
static void _bind_methods();
|
||||
void _grabber_mouse_entered();
|
||||
void _grabber_mouse_exited();
|
||||
void _focus_entered();
|
||||
void _focus_entered(bool p_hide_focus = false);
|
||||
|
||||
public:
|
||||
String get_tooltip(const Point2 &p_pos) const override;
|
||||
|
|
|
@ -942,9 +942,9 @@ void EditorProperty::grab_focus(int p_focusable) {
|
|||
|
||||
if (p_focusable >= 0) {
|
||||
ERR_FAIL_INDEX(p_focusable, focusables.size());
|
||||
focusables[p_focusable]->grab_focus();
|
||||
focusables[p_focusable]->grab_focus(true);
|
||||
} else {
|
||||
focusables[0]->grab_focus();
|
||||
focusables[0]->grab_focus(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -956,7 +956,7 @@ void EditorProperty::select(int p_focusable) {
|
|||
|
||||
if (p_focusable >= 0) {
|
||||
ERR_FAIL_INDEX(p_focusable, focusables.size());
|
||||
focusables[p_focusable]->grab_focus();
|
||||
focusables[p_focusable]->grab_focus(true);
|
||||
} else {
|
||||
selected = true;
|
||||
queue_redraw();
|
||||
|
|
|
@ -2904,7 +2904,7 @@ void EditorPropertyNodePath::_menu_option(int p_idx) {
|
|||
const NodePath &np = _get_node_path();
|
||||
edit->set_text(String(np));
|
||||
edit->show();
|
||||
callable_mp((Control *)edit, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)edit, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
|
||||
case ACTION_SELECT: {
|
||||
|
|
|
@ -813,7 +813,7 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
|
|||
renderer_container->hide();
|
||||
default_files_container->hide();
|
||||
|
||||
callable_mp((Control *)project_name, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)project_name, &Control::grab_focus).call_deferred(false);
|
||||
callable_mp(project_name, &LineEdit::select_all).call_deferred();
|
||||
} else {
|
||||
if (p_reset_name) {
|
||||
|
@ -882,7 +882,7 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
|
|||
renderer_container->show();
|
||||
default_files_container->show();
|
||||
|
||||
callable_mp((Control *)project_name, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)project_name, &Control::grab_focus).call_deferred(false);
|
||||
callable_mp(project_name, &LineEdit::select_all).call_deferred();
|
||||
} else if (mode == MODE_INSTALL) {
|
||||
set_title(TTR("Install Project:") + " " + zip_title);
|
||||
|
@ -895,7 +895,7 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
|
|||
renderer_container->hide();
|
||||
default_files_container->hide();
|
||||
|
||||
callable_mp((Control *)project_path, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)project_path, &Control::grab_focus).call_deferred(false);
|
||||
} else if (mode == MODE_DUPLICATE) {
|
||||
set_title(TTRC("Duplicate Project"));
|
||||
set_ok_button_text(TTRC("Duplicate"));
|
||||
|
@ -908,7 +908,7 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
|
|||
edit_check_box->hide();
|
||||
}
|
||||
|
||||
callable_mp((Control *)project_name, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)project_name, &Control::grab_focus).call_deferred(false);
|
||||
callable_mp(project_name, &LineEdit::select_all).call_deferred();
|
||||
}
|
||||
|
||||
|
|
|
@ -363,7 +363,8 @@ void ProjectManager::_select_main_view(int p_id) {
|
|||
if (current_main_view == MAIN_VIEW_PROJECTS && search_box->is_inside_tree()) {
|
||||
// Automatically grab focus when the user moves from the Templates tab
|
||||
// back to the Projects tab.
|
||||
search_box->grab_focus();
|
||||
// Needs to be deferred, otherwise the focus outline is always drawn.
|
||||
callable_mp((Control *)search_box, &Control::grab_focus).call_deferred(true);
|
||||
}
|
||||
|
||||
// The Templates tab's search field is focused on display in the asset
|
||||
|
|
|
@ -415,7 +415,7 @@ void EmbeddedProcess::_check_focused_process_id() {
|
|||
if (modal_window->get_mode() == Window::MODE_MINIMIZED) {
|
||||
modal_window->set_mode(Window::MODE_WINDOWED);
|
||||
}
|
||||
callable_mp(modal_window, &Window::grab_focus).call_deferred();
|
||||
callable_mp(modal_window, &Window::grab_focus).call_deferred(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -997,7 +997,7 @@ void TileSourceInspectorPlugin::_show_id_edit_dialog(Object *p_for_source) {
|
|||
edited_source = p_for_source;
|
||||
id_input->set_value(p_for_source->get("id"));
|
||||
id_edit_dialog->popup_centered(Vector2i(400, 0) * EDSCALE);
|
||||
callable_mp((Control *)id_input->get_line_edit(), &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)id_input->get_line_edit(), &Control::grab_focus).call_deferred(false);
|
||||
}
|
||||
|
||||
void TileSourceInspectorPlugin::_confirm_change_id() {
|
||||
|
|
|
@ -2796,7 +2796,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
|
|||
|
||||
// Grab focus
|
||||
if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) {
|
||||
callable_mp((Control *)viewport, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)viewport, &Control::grab_focus).call_deferred(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -485,7 +485,7 @@ void ConnectDialog::_update_warning_label() {
|
|||
}
|
||||
|
||||
void ConnectDialog::_post_popup() {
|
||||
callable_mp((Control *)dst_method, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)dst_method, &Control::grab_focus).call_deferred(false);
|
||||
callable_mp(dst_method, &LineEdit::select_all).call_deferred();
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ void SceneCreateDialog::config(const String &p_dir) {
|
|||
directory = p_dir;
|
||||
root_name_edit->set_text("");
|
||||
scene_name_edit->set_text("");
|
||||
callable_mp((Control *)scene_name_edit, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)scene_name_edit, &Control::grab_focus).call_deferred(false);
|
||||
validation_panel->update();
|
||||
|
||||
Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();
|
||||
|
|
|
@ -2279,7 +2279,7 @@ void SceneTreeDialog::_notification(int p_what) {
|
|||
tree->update_tree();
|
||||
|
||||
// Select the search bar by default.
|
||||
callable_mp((Control *)filter, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)filter, &Control::grab_focus).call_deferred(false);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
|
@ -467,16 +467,16 @@ void FindInFilesDialog::set_search_text(const String &text) {
|
|||
_search_text_line_edit->set_text(text);
|
||||
_on_search_text_modified(text);
|
||||
}
|
||||
callable_mp((Control *)_search_text_line_edit, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)_search_text_line_edit, &Control::grab_focus).call_deferred(false);
|
||||
_search_text_line_edit->select_all();
|
||||
} else if (_mode == REPLACE_MODE) {
|
||||
if (!text.is_empty()) {
|
||||
_search_text_line_edit->set_text(text);
|
||||
callable_mp((Control *)_replace_text_line_edit, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)_replace_text_line_edit, &Control::grab_focus).call_deferred(false);
|
||||
_replace_text_line_edit->select_all();
|
||||
_on_search_text_modified(text);
|
||||
} else {
|
||||
callable_mp((Control *)_search_text_line_edit, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)_search_text_line_edit, &Control::grab_focus).call_deferred(false);
|
||||
_search_text_line_edit->select_all();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1728,27 +1728,27 @@ void ScriptTextEditor::_edit_option(int p_op) {
|
|||
switch (p_op) {
|
||||
case EDIT_UNDO: {
|
||||
tx->undo();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_REDO: {
|
||||
tx->redo();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_CUT: {
|
||||
tx->cut();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_COPY: {
|
||||
tx->copy();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_PASTE: {
|
||||
tx->paste();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_SELECT_ALL: {
|
||||
tx->select_all();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_MOVE_LINE_UP: {
|
||||
code_editor->get_text_editor()->move_lines_up();
|
||||
|
|
|
@ -362,27 +362,27 @@ void TextEditor::_edit_option(int p_op) {
|
|||
switch (p_op) {
|
||||
case EDIT_UNDO: {
|
||||
tx->undo();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_REDO: {
|
||||
tx->redo();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_CUT: {
|
||||
tx->cut();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_COPY: {
|
||||
tx->copy();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_PASTE: {
|
||||
tx->paste();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_SELECT_ALL: {
|
||||
tx->select_all();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)tx, &Control::grab_focus).call_deferred(false);
|
||||
} break;
|
||||
case EDIT_MOVE_LINE_UP: {
|
||||
code_editor->get_text_editor()->move_lines_up();
|
||||
|
|
|
@ -787,7 +787,7 @@ void TextShaderEditor::_menu_option(int p_option) {
|
|||
} break;
|
||||
}
|
||||
if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) {
|
||||
callable_mp((Control *)code_editor->get_text_editor(), &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)code_editor->get_text_editor(), &Control::grab_focus).call_deferred(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,3 +7,10 @@ should instead be used to justify these changes and describe how users should wo
|
|||
Add new entries at the end of the file.
|
||||
|
||||
## Changes between 4.5-stable and 4.6-stable
|
||||
|
||||
GH-110250
|
||||
---------
|
||||
Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/Control/methods/grab_focus': arguments
|
||||
Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/Control/methods/has_focus': arguments
|
||||
|
||||
Optional argument added. Compatibility methods registered.
|
||||
|
|
|
@ -251,7 +251,7 @@ void Button::_notification(int p_what) {
|
|||
style->draw(ci, Rect2(Point2(), size));
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.focus->draw(ci, Rect2(Point2(), size));
|
||||
}
|
||||
|
||||
|
@ -315,7 +315,7 @@ void Button::_notification(int p_what) {
|
|||
switch (get_draw_mode()) {
|
||||
case DRAW_NORMAL: {
|
||||
// Focus colors only take precedence over normal state.
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
font_color = theme_cache.font_focus_color;
|
||||
if (has_theme_color(SNAME("icon_focus_color"))) {
|
||||
icon_modulate_color = theme_cache.icon_focus_color;
|
||||
|
|
|
@ -364,7 +364,7 @@ void ColorPicker::finish_shaders() {
|
|||
}
|
||||
|
||||
void ColorPicker::set_focus_on_line_edit() {
|
||||
callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)c_text, &Control::grab_focus).call_deferred(false);
|
||||
}
|
||||
|
||||
void ColorPicker::set_focus_on_picker_shape() {
|
||||
|
@ -1491,7 +1491,7 @@ void ColorPicker::_sample_draw() {
|
|||
|
||||
sample->draw_rect(rect_new, color);
|
||||
|
||||
if (display_old_color && !old_color.is_equal_approx(color) && sample->has_focus()) {
|
||||
if (display_old_color && !old_color.is_equal_approx(color) && sample->has_focus(true)) {
|
||||
RID ci = sample->get_canvas_item();
|
||||
theme_cache.sample_focus->draw(ci, rect_old);
|
||||
}
|
||||
|
@ -2663,7 +2663,7 @@ void ColorPresetButton::_notification(int p_what) {
|
|||
WARN_PRINT("Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat or StyleBoxTexture instead.");
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
RID ci = get_canvas_item();
|
||||
theme_cache.focus_style->draw(ci, Rect2(Point2(), get_size()));
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ void ColorPickerShape::cancel_event() {
|
|||
}
|
||||
|
||||
void ColorPickerShape::draw_focus_rect(Control *p_control, const Rect2 &p_rect) {
|
||||
if (!p_control->has_focus()) {
|
||||
if (!p_control->has_focus(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ void ColorPickerShape::draw_focus_rect(Control *p_control, const Rect2 &p_rect)
|
|||
}
|
||||
|
||||
void ColorPickerShape::draw_focus_circle(Control *p_control) {
|
||||
if (!p_control->has_focus()) {
|
||||
if (!p_control->has_focus(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
46
scene/gui/control.compat.inc
Normal file
46
scene/gui/control.compat.inc
Normal file
|
@ -0,0 +1,46 @@
|
|||
/**************************************************************************/
|
||||
/* control.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
bool Control::_has_focus_bind_compat_110250() const {
|
||||
return has_focus(false);
|
||||
}
|
||||
|
||||
void Control::_grab_focus_bind_compat_110250() {
|
||||
return grab_focus(false);
|
||||
}
|
||||
|
||||
void Control::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("has_focus"), &Control::_has_focus_bind_compat_110250);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("grab_focus"), &Control::_grab_focus_bind_compat_110250);
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
|
@ -29,6 +29,7 @@
|
|||
/**************************************************************************/
|
||||
|
||||
#include "control.h"
|
||||
#include "control.compat.inc"
|
||||
|
||||
#include "container.h"
|
||||
#include "core/config/project_settings.h"
|
||||
|
@ -2315,12 +2316,12 @@ void Control::_propagate_focus_behavior_recursive_recursively(bool p_enabled, bo
|
|||
}
|
||||
}
|
||||
|
||||
bool Control::has_focus() const {
|
||||
bool Control::has_focus(bool p_ignore_hidden_focus) const {
|
||||
ERR_READ_THREAD_GUARD_V(false);
|
||||
return is_inside_tree() && get_viewport()->_gui_control_has_focus(this);
|
||||
return is_inside_tree() && get_viewport()->_gui_control_has_focus(this, p_ignore_hidden_focus);
|
||||
}
|
||||
|
||||
void Control::grab_focus() {
|
||||
void Control::grab_focus(bool p_hide_focus) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
ERR_FAIL_COND(!is_inside_tree());
|
||||
|
||||
|
@ -2329,7 +2330,7 @@ void Control::grab_focus() {
|
|||
return;
|
||||
}
|
||||
|
||||
get_viewport()->_gui_control_grab_focus(this);
|
||||
get_viewport()->_gui_control_grab_focus(this, p_hide_focus);
|
||||
}
|
||||
|
||||
void Control::grab_click_focus() {
|
||||
|
@ -4002,8 +4003,8 @@ void Control::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_focus_mode_with_override"), &Control::get_focus_mode_with_override);
|
||||
ClassDB::bind_method(D_METHOD("set_focus_behavior_recursive", "focus_behavior_recursive"), &Control::set_focus_behavior_recursive);
|
||||
ClassDB::bind_method(D_METHOD("get_focus_behavior_recursive"), &Control::get_focus_behavior_recursive);
|
||||
ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus);
|
||||
ClassDB::bind_method(D_METHOD("grab_focus"), &Control::grab_focus);
|
||||
ClassDB::bind_method(D_METHOD("has_focus", "ignore_hidden_focus"), &Control::has_focus, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("grab_focus", "hide_focus"), &Control::grab_focus, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("release_focus"), &Control::release_focus);
|
||||
ClassDB::bind_method(D_METHOD("find_prev_valid_focus"), &Control::find_prev_valid_focus);
|
||||
ClassDB::bind_method(D_METHOD("find_next_valid_focus"), &Control::find_next_valid_focus);
|
||||
|
|
|
@ -394,6 +394,12 @@ protected:
|
|||
void _accessibility_action_hide_tooltip(const Variant &p_data);
|
||||
void _accessibility_action_scroll_into_view(const Variant &p_data);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
bool _has_focus_bind_compat_110250() const;
|
||||
void _grab_focus_bind_compat_110250();
|
||||
static void _bind_compatibility_methods();
|
||||
#endif //DISABLE_DEPRECATED
|
||||
|
||||
// Exposed virtual methods.
|
||||
|
||||
GDVIRTUAL1RC(bool, _has_point, Vector2)
|
||||
|
@ -592,8 +598,8 @@ public:
|
|||
FocusMode get_focus_mode_with_override() const;
|
||||
void set_focus_behavior_recursive(FocusBehaviorRecursive p_focus_behavior_recursive);
|
||||
FocusBehaviorRecursive get_focus_behavior_recursive() const;
|
||||
bool has_focus() const;
|
||||
void grab_focus();
|
||||
bool has_focus(bool p_ignore_hidden_focus = false) const;
|
||||
void grab_focus(bool p_hide_focus = false);
|
||||
void grab_click_focus();
|
||||
void release_focus();
|
||||
|
||||
|
|
|
@ -421,9 +421,9 @@ void FileDialog::_save_confirm_pressed() {
|
|||
void FileDialog::_post_popup() {
|
||||
ConfirmationDialog::_post_popup();
|
||||
if (mode == FILE_MODE_SAVE_FILE) {
|
||||
filename_edit->grab_focus();
|
||||
filename_edit->grab_focus(true);
|
||||
} else {
|
||||
file_list->grab_focus();
|
||||
file_list->grab_focus(true);
|
||||
}
|
||||
|
||||
set_process_shortcut_input(true);
|
||||
|
@ -2035,7 +2035,7 @@ void FileDialog::set_show_filename_filter(bool p_show) {
|
|||
filename_filter->grab_focus();
|
||||
} else {
|
||||
if (filename_filter->has_focus()) {
|
||||
callable_mp((Control *)file_list, &Control::grab_focus).call_deferred();
|
||||
callable_mp((Control *)file_list, &Control::grab_focus).call_deferred(false);
|
||||
}
|
||||
}
|
||||
show_filename_filter = p_show;
|
||||
|
|
|
@ -317,7 +317,7 @@ void FoldableContainer::_notification(int p_what) {
|
|||
_draw_flippable_stylebox(theme_cache.panel_style, panel_rect);
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
Rect2 focus_rect = folded ? title_rect : Rect2(Point2(), size);
|
||||
_draw_flippable_stylebox(theme_cache.focus_style, focus_rect);
|
||||
}
|
||||
|
|
|
@ -861,7 +861,7 @@ void GraphEdit::_notification(int p_what) {
|
|||
// Draw background fill.
|
||||
draw_style_box(theme_cache.panel, Rect2(Point2(), get_size()));
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
draw_style_box(theme_cache.panel_focus, Rect2(Point2(), get_size()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1383,7 +1383,7 @@ void ItemList::_notification(int p_what) {
|
|||
Ref<StyleBox> sbsel;
|
||||
Ref<StyleBox> cursor;
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
sbsel = theme_cache.selected_focus_style;
|
||||
cursor = theme_cache.cursor_focus_style;
|
||||
} else {
|
||||
|
@ -1507,7 +1507,7 @@ void ItemList::_notification(int p_what) {
|
|||
draw_style_box(sbsel, r);
|
||||
}
|
||||
if (should_draw_hovered_selected_bg) {
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
draw_style_box(theme_cache.hovered_selected_focus_style, r);
|
||||
} else {
|
||||
draw_style_box(theme_cache.hovered_selected_style, r);
|
||||
|
@ -1695,7 +1695,7 @@ void ItemList::_notification(int p_what) {
|
|||
draw_style_box(cursor, cursor_rcache);
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
|
||||
size.x -= (scroll_bar_h->get_max() - scroll_bar_h->get_page());
|
||||
draw_style_box(theme_cache.focus_style, Rect2(Point2(), size));
|
||||
|
|
|
@ -762,7 +762,7 @@ void Label::_notification(int p_what) {
|
|||
Vector<LabelSettings::StackedShadowData> stacked_shadow_datas = has_settings ? settings->get_stacked_shadow_data() : Vector<LabelSettings::StackedShadowData>();
|
||||
bool rtl_layout = is_layout_rtl();
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.focus_style->draw(ci, Rect2(Point2(0, 0), get_size()));
|
||||
} else {
|
||||
theme_cache.normal_style->draw(ci, Rect2(Point2(0, 0), get_size()));
|
||||
|
|
|
@ -1343,7 +1343,7 @@ void LineEdit::_notification(int p_what) {
|
|||
style->draw(ci, Rect2(Point2(), size));
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.focus->draw(ci, Rect2(Point2(), size));
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ void LinkButton::_notification(int p_what) {
|
|||
|
||||
switch (get_draw_mode()) {
|
||||
case DRAW_NORMAL: {
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
color = theme_cache.font_focus_color;
|
||||
} else {
|
||||
color = theme_cache.font_color;
|
||||
|
@ -222,7 +222,7 @@ void LinkButton::_notification(int p_what) {
|
|||
} break;
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
Ref<StyleBox> style = theme_cache.focus;
|
||||
style->draw(ci, Rect2(Point2(), size));
|
||||
}
|
||||
|
|
|
@ -493,7 +493,7 @@ void MenuBar::_draw_menu_item(int p_index) {
|
|||
style->draw(ci, item_rect);
|
||||
}
|
||||
// Focus colors only take precedence over normal state.
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
color = theme_cache.font_focus_color;
|
||||
} else {
|
||||
color = theme_cache.font_color;
|
||||
|
|
|
@ -114,7 +114,7 @@ void OptionButton::_notification(int p_what) {
|
|||
clr = theme_cache.font_disabled_color;
|
||||
break;
|
||||
default:
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
clr = theme_cache.font_focus_color;
|
||||
} else {
|
||||
clr = theme_cache.font_color;
|
||||
|
|
|
@ -2469,7 +2469,7 @@ void RichTextLabel::_notification(int p_what) {
|
|||
|
||||
draw_style_box(theme_cache.normal_style, Rect2(Point2(), size));
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
|
||||
draw_style_box(theme_cache.focus_style, Rect2(Point2(), size));
|
||||
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
|
||||
|
|
|
@ -279,7 +279,7 @@ void ScrollBar::_notification(int p_what) {
|
|||
area.height -= incr->get_height() + decr->get_height();
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.scroll_focus_style->draw(ci, Rect2(ofs, area));
|
||||
} else {
|
||||
theme_cache.scroll_style->draw(ci, Rect2(ofs, area));
|
||||
|
|
|
@ -316,7 +316,7 @@ void ScrollContainer::_gui_focus_changed(Control *p_control) {
|
|||
ensure_control_visible(p_control);
|
||||
}
|
||||
if (draw_focus_border) {
|
||||
const bool _should_draw_focus_border = has_focus() || child_has_focus();
|
||||
const bool _should_draw_focus_border = has_focus(true) || child_has_focus();
|
||||
if (focus_border_is_drawn != _should_draw_focus_border) {
|
||||
queue_redraw();
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ void ScrollContainer::_notification(int p_what) {
|
|||
|
||||
case NOTIFICATION_DRAW: {
|
||||
draw_style_box(theme_cache.panel_style, Rect2(Vector2(), get_size()));
|
||||
focus_border_is_drawn = draw_focus_border && (has_focus() || child_has_focus());
|
||||
focus_border_is_drawn = draw_focus_border && (has_focus(true) || child_has_focus());
|
||||
focus_panel->set_visible(focus_border_is_drawn);
|
||||
} break;
|
||||
|
||||
|
@ -815,7 +815,7 @@ bool ScrollContainer::get_draw_focus_border() {
|
|||
|
||||
bool ScrollContainer::child_has_focus() {
|
||||
const Control *focus_owner = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
|
||||
return focus_owner && is_ancestor_of(focus_owner);
|
||||
return focus_owner && focus_owner->has_focus(true) && is_ancestor_of(focus_owner);
|
||||
}
|
||||
|
||||
ScrollContainer::ScrollContainer() {
|
||||
|
|
|
@ -56,7 +56,7 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
|
|||
if (mb->get_button_index() == MouseButton::LEFT) {
|
||||
if (mb->is_pressed()) {
|
||||
Ref<Texture2D> grabber;
|
||||
if (mouse_inside || has_focus()) {
|
||||
if (mouse_inside || has_focus(true)) {
|
||||
grabber = theme_cache.grabber_hl_icon;
|
||||
} else {
|
||||
grabber = theme_cache.grabber_icon;
|
||||
|
@ -275,7 +275,7 @@ void Slider::_notification(int p_what) {
|
|||
Ref<StyleBox> style = theme_cache.slider_style;
|
||||
Ref<Texture2D> tick = theme_cache.tick_icon;
|
||||
|
||||
bool highlighted = editable && (mouse_inside || has_focus());
|
||||
bool highlighted = editable && (mouse_inside || has_focus(true));
|
||||
Ref<Texture2D> grabber;
|
||||
if (editable) {
|
||||
if (highlighted) {
|
||||
|
|
|
@ -543,7 +543,7 @@ void TabBar::_notification(int p_what) {
|
|||
if (current >= offset && current <= max_drawn_tab && !tabs[current].hidden) {
|
||||
Ref<StyleBox> sb = tabs[current].disabled ? theme_cache.tab_disabled_style : theme_cache.tab_selected_style;
|
||||
|
||||
_draw_tab(sb, theme_cache.font_selected_color, current, rtl ? (size.width - tabs[current].ofs_cache - tabs[current].size_cache) : tabs[current].ofs_cache, has_focus());
|
||||
_draw_tab(sb, theme_cache.font_selected_color, current, rtl ? (size.width - tabs[current].ofs_cache - tabs[current].size_cache) : tabs[current].ofs_cache, has_focus(true));
|
||||
}
|
||||
|
||||
if (buttons_visible) {
|
||||
|
|
|
@ -945,7 +945,7 @@ void TextEdit::_notification(int p_what) {
|
|||
theme_cache.style_readonly->draw(ci, Rect2(Point2(), size));
|
||||
draw_caret = is_drawing_caret_when_editable_disabled();
|
||||
}
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.style_focus->draw(ci, Rect2(Point2(), size));
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ void TextureButton::_notification(int p_what) {
|
|||
|
||||
Point2 ofs;
|
||||
Size2 size;
|
||||
bool draw_focus = (has_focus() && focused.is_valid());
|
||||
bool draw_focus = (has_focus(true) && focused.is_valid());
|
||||
|
||||
// If no other texture is valid, try using focused texture.
|
||||
bool draw_focus_only = draw_focus && texdraw.is_null();
|
||||
|
|
|
@ -2327,13 +2327,13 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|||
|
||||
if (p_item->cells[0].selected) {
|
||||
if (is_row_hovered) {
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.hovered_selected_focus->draw(ci, row_rect);
|
||||
} else {
|
||||
theme_cache.hovered_selected->draw(ci, row_rect);
|
||||
}
|
||||
} else {
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.selected_focus->draw(ci, row_rect);
|
||||
} else {
|
||||
theme_cache.selected->draw(ci, row_rect);
|
||||
|
@ -2375,13 +2375,13 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|||
}
|
||||
if (p_item->cells[i].selected) {
|
||||
if (is_cell_hovered) {
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.hovered_selected_focus->draw(ci, r);
|
||||
} else {
|
||||
theme_cache.hovered_selected->draw(ci, r);
|
||||
}
|
||||
} else {
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.selected_focus->draw(ci, r);
|
||||
} else {
|
||||
theme_cache.selected->draw(ci, r);
|
||||
|
@ -2675,7 +2675,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|||
if (is_layout_rtl()) {
|
||||
cell_rect.position.x = get_size().width - cell_rect.position.x - cell_rect.size.x;
|
||||
}
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
theme_cache.cursor->draw(ci, cell_rect);
|
||||
} else {
|
||||
theme_cache.cursor_unfocus->draw(ci, cell_rect);
|
||||
|
@ -5080,7 +5080,7 @@ void Tree::_notification(int p_what) {
|
|||
|
||||
// Draw the focus outline last, so that it is drawn in front of the section headings.
|
||||
// Otherwise, section heading backgrounds can appear to be in front of the focus outline when scrolling.
|
||||
if (has_focus()) {
|
||||
if (has_focus(true)) {
|
||||
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
|
||||
theme_cache.focus_style->draw(ci, Rect2(Point2(), get_size()));
|
||||
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
|
||||
|
|
|
@ -531,6 +531,22 @@ void Viewport::_update_viewport_path() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Viewport::_can_hide_focus_state() {
|
||||
return Engine::get_singleton()->is_editor_hint() || !GLOBAL_GET_CACHED(bool, "gui/common/always_show_focus_state");
|
||||
}
|
||||
|
||||
void Viewport::_on_settings_changed() {
|
||||
if (!gui.hide_focus && _can_hide_focus_state()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gui.hide_focus = false;
|
||||
// Show previously hidden focus.
|
||||
if (gui.key_focus) {
|
||||
gui.key_focus->queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::_notification(int p_what) {
|
||||
ERR_MAIN_THREAD_GUARD;
|
||||
|
||||
|
@ -1914,6 +1930,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
gui.mouse_focus = gui_find_control(mpos);
|
||||
|
||||
if (!gui.mouse_focus) {
|
||||
// Focus should be hidden on click even if the focus holder didn't change.
|
||||
if (gui.key_focus && mb->get_button_index() == MouseButton::LEFT && _can_hide_focus_state()) {
|
||||
gui.hide_focus = true;
|
||||
gui.key_focus->queue_redraw();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1946,8 +1968,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
if (control->_is_focusable()) {
|
||||
// Grabbing unhovered focus can cause issues when mouse is dragged
|
||||
// with another button held down.
|
||||
if (control != gui.key_focus && gui.mouse_over_hierarchy.has(control)) {
|
||||
control->grab_focus();
|
||||
if (gui.mouse_over_hierarchy.has(control)) {
|
||||
// Hide the focus when it comes from a click.
|
||||
control->grab_focus(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2301,6 +2324,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
|
||||
if (from && p_event->is_pressed()) {
|
||||
Control *next = nullptr;
|
||||
bool show_focus = false;
|
||||
|
||||
Ref<InputEventJoypadMotion> joypadmotion_event = p_event;
|
||||
if (joypadmotion_event.is_valid()) {
|
||||
|
@ -2308,10 +2332,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
|
||||
if (p_event->is_action_pressed(SNAME("ui_focus_next")) && input->is_action_just_pressed_by_event(SNAME("ui_focus_next"), p_event)) {
|
||||
next = from->find_next_valid_focus();
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_focus_prev")) && input->is_action_just_pressed_by_event(SNAME("ui_focus_prev"), p_event)) {
|
||||
next = from->find_prev_valid_focus();
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_accessibility_drag_and_drop")) && input->is_action_just_pressed_by_event(SNAME("ui_accessibility_drag_and_drop"), p_event)) {
|
||||
|
@ -2324,26 +2350,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
|
||||
if (p_event->is_action_pressed(SNAME("ui_up")) && input->is_action_just_pressed_by_event(SNAME("ui_up"), p_event)) {
|
||||
next = from->_get_focus_neighbor(SIDE_TOP);
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_left")) && input->is_action_just_pressed_by_event(SNAME("ui_left"), p_event)) {
|
||||
next = from->_get_focus_neighbor(SIDE_LEFT);
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_right")) && input->is_action_just_pressed_by_event(SNAME("ui_right"), p_event)) {
|
||||
next = from->_get_focus_neighbor(SIDE_RIGHT);
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_down")) && input->is_action_just_pressed_by_event(SNAME("ui_down"), p_event)) {
|
||||
next = from->_get_focus_neighbor(SIDE_BOTTOM);
|
||||
show_focus = true;
|
||||
}
|
||||
} else {
|
||||
if (p_event->is_action_pressed(SNAME("ui_focus_next"), true, true)) {
|
||||
next = from->find_next_valid_focus();
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_focus_prev"), true, true)) {
|
||||
next = from->find_prev_valid_focus();
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_accessibility_drag_and_drop"), true, true)) {
|
||||
|
@ -2356,23 +2388,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
|
||||
if (p_event->is_action_pressed(SNAME("ui_up"), true, true)) {
|
||||
next = from->_get_focus_neighbor(SIDE_TOP);
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_left"), true, true)) {
|
||||
next = from->_get_focus_neighbor(SIDE_LEFT);
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_right"), true, true)) {
|
||||
next = from->_get_focus_neighbor(SIDE_RIGHT);
|
||||
show_focus = true;
|
||||
}
|
||||
|
||||
if (p_event->is_action_pressed(SNAME("ui_down"), true, true)) {
|
||||
next = from->_get_focus_neighbor(SIDE_BOTTOM);
|
||||
show_focus = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
next->grab_focus();
|
||||
set_input_as_handled();
|
||||
} else if (show_focus && gui.hide_focus && gui.key_focus) {
|
||||
// Show focus even it the holder didn't change, as visual feedback.
|
||||
gui.hide_focus = false;
|
||||
gui.key_focus->queue_redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2655,18 +2696,26 @@ void Viewport::_gui_remove_focus_for_window(Node *p_window) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Viewport::_gui_control_has_focus(const Control *p_control) {
|
||||
return gui.key_focus == p_control;
|
||||
bool Viewport::_gui_control_has_focus(const Control *p_control, bool p_ignore_hidden_focus) {
|
||||
return (!p_ignore_hidden_focus || !gui.hide_focus) && gui.key_focus == p_control;
|
||||
}
|
||||
|
||||
void Viewport::_gui_control_grab_focus(Control *p_control) {
|
||||
void Viewport::_gui_control_grab_focus(Control *p_control, bool p_hide_focus) {
|
||||
if (gui.key_focus && gui.key_focus == p_control) {
|
||||
// No need for change.
|
||||
// Only worry about the focus visibility change.
|
||||
if (p_hide_focus != gui.hide_focus && _can_hide_focus_state()) {
|
||||
gui.hide_focus = p_hide_focus;
|
||||
p_control->queue_redraw();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
get_tree()->call_group("_viewports", "_gui_remove_focus_for_window", get_base_window());
|
||||
if (p_control->is_inside_tree() && p_control->get_viewport() == this) {
|
||||
gui.key_focus = p_control;
|
||||
if (_can_hide_focus_state()) {
|
||||
gui.hide_focus = p_hide_focus;
|
||||
}
|
||||
emit_signal(SNAME("gui_focus_changed"), p_control);
|
||||
p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
|
||||
p_control->queue_redraw();
|
||||
|
@ -5386,6 +5435,8 @@ Viewport::Viewport() {
|
|||
// Viewports can thus inherit physics interpolation OFF, which is unexpected.
|
||||
// Setting to ON allows each viewport to have a fresh interpolation state.
|
||||
set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_ON);
|
||||
|
||||
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &Viewport::_on_settings_changed));
|
||||
}
|
||||
|
||||
Viewport::~Viewport() {
|
||||
|
|
|
@ -330,6 +330,9 @@ private:
|
|||
|
||||
void _update_viewport_path();
|
||||
|
||||
bool _can_hide_focus_state();
|
||||
void _on_settings_changed();
|
||||
|
||||
SDFOversize sdf_oversize = SDF_OVERSIZE_120_PERCENT;
|
||||
SDFScale sdf_scale = SDF_SCALE_50_PERCENT;
|
||||
|
||||
|
@ -374,6 +377,7 @@ private:
|
|||
Control *mouse_click_grabber = nullptr;
|
||||
BitField<MouseButtonMask> mouse_focus_mask = MouseButtonMask::NONE;
|
||||
Control *key_focus = nullptr;
|
||||
bool hide_focus = false;
|
||||
Control *mouse_over = nullptr;
|
||||
LocalVector<Control *> mouse_over_hierarchy;
|
||||
bool sending_mouse_enter_exit_notifications = false;
|
||||
|
@ -459,8 +463,8 @@ private:
|
|||
|
||||
void _gui_remove_focus_for_window(Node *p_window);
|
||||
void _gui_unfocus_control(Control *p_control);
|
||||
bool _gui_control_has_focus(const Control *p_control);
|
||||
void _gui_control_grab_focus(Control *p_control);
|
||||
bool _gui_control_has_focus(const Control *p_control, bool p_ignore_hidden_focus = false);
|
||||
void _gui_control_grab_focus(Control *p_control, bool p_hide_focus = false);
|
||||
void _gui_grab_click_focus(Control *p_control);
|
||||
void _post_gui_grab_click_focus();
|
||||
void _gui_accept_event();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue