diff --git a/editor/docks/scene_tree_dock.cpp b/editor/docks/scene_tree_dock.cpp
index 438924f14318..a786e46851ac 100644
--- a/editor/docks/scene_tree_dock.cpp
+++ b/editor/docks/scene_tree_dock.cpp
@@ -5072,7 +5072,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
tree_menu->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
button_panel = memnew(PanelContainer);
- button_panel->set_theme_type_variation("PanelContainerTabbarInner");
+ button_panel->set_theme_type_variation("PanelContainerButtonGroup");
main_vbox->add_child(button_panel);
HBoxContainer *button_hb = memnew(HBoxContainer);
diff --git a/editor/icons/EmbedDisabled.svg b/editor/icons/EmbedDisabled.svg
new file mode 100644
index 000000000000..c94b44e2a395
--- /dev/null
+++ b/editor/icons/EmbedDisabled.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/EmbedFloating.svg b/editor/icons/EmbedFloating.svg
new file mode 100644
index 000000000000..9e2d8b75bf24
--- /dev/null
+++ b/editor/icons/EmbedFloating.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/EmbedFused.svg b/editor/icons/EmbedFused.svg
new file mode 100644
index 000000000000..ade21a8f9641
--- /dev/null
+++ b/editor/icons/EmbedFused.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/Suspend.svg b/editor/icons/Suspend.svg
index daba9c27d22a..6dedba642771 100644
--- a/editor/icons/Suspend.svg
+++ b/editor/icons/Suspend.svg
@@ -1 +1 @@
-
+
diff --git a/editor/run/game_view_plugin.cpp b/editor/run/game_view_plugin.cpp
index 9c137bdfd271..e6ce82e57733 100644
--- a/editor/run/game_view_plugin.cpp
+++ b/editor/run/game_view_plugin.cpp
@@ -49,6 +49,7 @@
#include "editor/settings/editor_feature_profile.h"
#include "editor/settings/editor_settings.h"
#include "editor/themes/editor_scale.h"
+#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
#include "scene/gui/menu_button.h"
@@ -429,7 +430,7 @@ bool GameViewDebugger::has_capture(const String &p_capture) const {
GameViewDebugger::GameViewDebugger() {
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &GameViewDebugger::_feature_profile_changed));
- ED_SHORTCUT("editor/suspend_resume_embedded_project", TTRC("Suspend/Resume Embedded Project"), Key::F9);
+ ED_SHORTCUT("editor/suspend_resume_embedded_project", TTRC("Suspend/Resume Embedded Game"), Key::F9);
ED_SHORTCUT_OVERRIDE("editor/suspend_resume_embedded_project", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::B);
ED_SHORTCUT("editor/next_frame_embedded_project", TTRC("Next Frame"), Key::F10);
@@ -648,10 +649,6 @@ void GameView::_update_debugger_buttons() {
camera_override_button->set_disabled(empty);
speed_state_button->set_disabled(empty);
game_size_label->set_visible(!empty);
- game_size_placeholder->set_visible(empty);
- bool disabled = time_scale_index == DEFAULT_TIME_SCALE_INDEX;
-
- reset_speed_button->set_disabled(empty || disabled);
PopupMenu *menu = camera_override_menu->get_popup();
@@ -752,6 +749,11 @@ void GameView::_select_mode_pressed(int p_option) {
void GameView::_selection_options_menu_id_pressed(int p_id) {
switch (p_id) {
+ case SELECTION_HIDE: {
+ selection_hide = !selection_hide;
+ debugger->set_selection_visible(selection_hide);
+ EditorSettings::get_singleton()->set_project_metadata("game_view", "hide_selection", selection_hide);
+ } break;
case SELECTION_AVOID_LOCKED: {
selection_avoid_locked = !selection_avoid_locked;
debugger->set_selection_avoid_locked(selection_avoid_locked);
@@ -765,26 +767,40 @@ void GameView::_selection_options_menu_id_pressed(int p_id) {
}
PopupMenu *menu = selection_options_menu->get_popup();
+ menu->set_item_checked(menu->get_item_index(SELECTION_HIDE), selection_hide);
menu->set_item_checked(menu->get_item_index(SELECTION_AVOID_LOCKED), selection_avoid_locked);
menu->set_item_checked(menu->get_item_index(SELECTION_PREFER_GROUP), selection_prefer_group);
}
-void GameView::_game_window_options_menu_menu_id_pressed(int p_id) {
- switch (p_id) {
- case WINDOW_RUN_GAME_EMBEDDED: {
- embed_on_play = !embed_on_play;
- int game_mode = EDITOR_GET("run/window_placement/game_embed_mode");
- if (game_mode == 0) { // Save only if not overridden by editor.
- EditorSettings::get_singleton()->set_project_metadata("game_view", "embed_on_play", embed_on_play);
- }
+void GameView::_game_embed_mode_pressed(int p_option) {
+ switch ((EmbedMode)p_option) {
+ case EMBED_TYPE_DISABLED: {
+ embed_on_play = false;
+ make_floating_on_play = false;
+ game_embed_mode_menu->set_button_icon(get_editor_theme_icon(SNAME("EmbedDisabled")));
} break;
- case WINDOW_MAKE_FLOATING_ON_PLAY: {
- make_floating_on_play = !make_floating_on_play;
- int game_mode = EDITOR_GET("run/window_placement/game_embed_mode");
- if (game_mode == 0) { // Save only if not overridden by editor.
- EditorSettings::get_singleton()->set_project_metadata("game_view", "make_floating_on_play", make_floating_on_play);
- }
+ case EMBED_TYPE_FLOATING: {
+ embed_on_play = true;
+ make_floating_on_play = true;
+ game_embed_mode_menu->set_button_icon(get_editor_theme_icon(SNAME("EmbedFloating")));
} break;
+ case EMBED_TYPE_EDITOR: {
+ embed_on_play = true;
+ make_floating_on_play = false;
+ game_embed_mode_menu->set_button_icon(get_editor_theme_icon(SNAME("EmbedFused")));
+ } break;
+ case EMBED_TYPE_MAX:
+ break;
+ }
+ EditorSettings::get_singleton()->set_project_metadata("game_view", "embed_on_play", embed_on_play);
+ EditorSettings::get_singleton()->set_project_metadata("game_view", "make_floating_on_play", make_floating_on_play);
+
+ _update_embed_buttons();
+ _update_ui();
+}
+
+void GameView::_game_window_options_menu_menu_id_pressed(int p_id) {
+ switch (p_id) {
case WINDOW_SIZE_MODE_FIXED:
case WINDOW_SIZE_MODE_KEEP_ASPECT:
case WINDOW_SIZE_MODE_STRETCH: {
@@ -815,6 +831,7 @@ void GameView::_reset_time_scales() {
time_scale_index = DEFAULT_TIME_SCALE_INDEX;
debugger->reset_time_scale();
if (is_inside_tree()) {
+ _update_speed_state_icon(DEFAULT_TIME_SCALE_INDEX);
_update_speed_buttons();
}
}
@@ -822,12 +839,35 @@ void GameView::_reset_time_scales() {
void GameView::_speed_state_menu_pressed(int p_id) {
time_scale_index = p_id;
debugger->set_time_scale(time_scale_range[time_scale_index]);
+ _update_speed_state_icon(p_id);
_update_speed_buttons();
}
+void GameView::_update_speed_state_icon(int p_id) {
+ PopupMenu *menu = speed_state_button->get_popup();
+ for (int i = 0; i < speed_state_button->get_item_count(); i++) {
+ if (i == DEFAULT_TIME_SCALE_INDEX) {
+ continue;
+ }
+
+ menu->set_item_icon(i, nullptr);
+ }
+
+ menu->set_item_icon(p_id, get_editor_theme_icon(SNAME("KeyValue")));
+ if (p_id == DEFAULT_TIME_SCALE_INDEX) {
+ menu->set_item_icon_modulate(p_id, get_theme_color(SNAME("mono_color"), EditorStringName(Editor)));
+ } else {
+ menu->set_item_icon(DEFAULT_TIME_SCALE_INDEX, get_editor_theme_icon(SNAME("KeyBezierHandle")));
+
+ if (p_id > DEFAULT_TIME_SCALE_INDEX) {
+ menu->set_item_icon_modulate(p_id, get_theme_color(SNAME("success_color"), EditorStringName(Editor)));
+ } else {
+ menu->set_item_icon_modulate(p_id, get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
+ }
+ }
+}
+
void GameView::_update_speed_buttons() {
- bool disabled = time_scale_index == DEFAULT_TIME_SCALE_INDEX;
- reset_speed_button->set_disabled(disabled);
speed_state_button->set_text(vformat(U"%s×", time_scale_label[time_scale_index]));
_update_speed_state_color();
}
@@ -842,6 +882,9 @@ void GameView::_update_speed_state_color() {
text_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
}
speed_state_button->add_theme_color_override(SceneStringName(font_color), text_color);
+ speed_state_button->add_theme_color_override(SNAME("font_hover_color"), text_color);
+ speed_state_button->add_theme_color_override(SNAME("font_hover_pressed_color"), text_color);
+ speed_state_button->add_theme_color_override(SNAME("font_pressed_color"), text_color);
}
void GameView::_update_speed_state_size() {
@@ -909,9 +952,13 @@ void GameView::_update_ui() {
} else if (EditorRunBar::get_singleton()->is_playing()) {
state_label->set_text(TTRC("Game running not embedded."));
} else if (embed_on_play) {
- state_label->set_text(TTRC("Press play to start the game."));
+ if (make_floating_on_play) {
+ state_label->set_text(TTRC("The game will run in a floating window with an attached toolbar."));
+ } else {
+ state_label->set_text(TTRC("The game will run here within the Game workspace."));
+ }
} else {
- state_label->set_text(TTRC("Embedding is disabled."));
+ state_label->set_text(TTRC("The game will run in a floating window without the toolbar."));
}
break;
case EMBED_NOT_AVAILABLE_FEATURE_NOT_SUPPORTED:
@@ -930,7 +977,7 @@ void GameView::_update_ui() {
state_label->set_text(TTR("Game embedding not available when the game starts in fullscreen.") + "\n" + TTR("Consider overriding the window mode project setting with the editor feature tag to Windowed to use game embedding while leaving the exported project intact."));
break;
case EMBED_NOT_AVAILABLE_SINGLE_WINDOW_MODE:
- state_label->set_text(TTRC("Game embedding not available in single window mode."));
+ state_label->set_text(TTRC("Game embedding not available in single-window mode."));
break;
case EMBED_NOT_AVAILABLE_HEADLESS:
state_label->set_text(TTRC("Game embedding not available when the game starts in headless mode."));
@@ -947,16 +994,17 @@ void GameView::_update_ui() {
}
void GameView::_update_embed_menu_options() {
- bool is_multi_window = window_wrapper->is_window_available();
PopupMenu *menu = game_window_options_menu->get_popup();
- menu->set_item_checked(menu->get_item_index(WINDOW_RUN_GAME_EMBEDDED), embed_on_play);
- menu->set_item_checked(menu->get_item_index(WINDOW_MAKE_FLOATING_ON_PLAY), make_floating_on_play && is_multi_window);
-
menu->set_item_checked(menu->get_item_index(WINDOW_SIZE_MODE_FIXED), embed_size_mode == SIZE_MODE_FIXED);
menu->set_item_checked(menu->get_item_index(WINDOW_SIZE_MODE_KEEP_ASPECT), embed_size_mode == SIZE_MODE_KEEP_ASPECT);
menu->set_item_checked(menu->get_item_index(WINDOW_SIZE_MODE_STRETCH), embed_size_mode == SIZE_MODE_STRETCH);
+}
- menu->set_item_disabled(menu->get_item_index(WINDOW_MAKE_FLOATING_ON_PLAY), !embed_on_play || !is_multi_window);
+void GameView::_update_embed_buttons() {
+ PopupMenu *menu = game_embed_mode_menu->get_popup();
+ menu->set_item_checked(menu->get_item_index(EMBED_TYPE_EDITOR), embed_on_play && !make_floating_on_play);
+ menu->set_item_checked(menu->get_item_index(EMBED_TYPE_FLOATING), make_floating_on_play && window_wrapper->is_window_available());
+ menu->set_item_checked(menu->get_item_index(EMBED_TYPE_DISABLED), !embed_on_play && !make_floating_on_play);
}
void GameView::_update_game_window_size_label() {
@@ -997,14 +1045,6 @@ void GameView::_update_embed_window_size() {
}
}
-void GameView::_hide_selection_toggled(bool p_pressed) {
- hide_selection->set_button_icon(get_editor_theme_icon(p_pressed ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
-
- debugger->set_selection_visible(!p_pressed);
-
- EditorSettings::get_singleton()->set_project_metadata("game_view", "hide_selection", p_pressed);
-}
-
void GameView::_debug_mute_audio_button_pressed() {
debug_mute_audio = !debug_mute_audio;
debug_mute_audio_button->set_button_icon(get_editor_theme_icon(debug_mute_audio ? SNAME("AudioMute") : SNAME("AudioStreamPlayer")));
@@ -1132,7 +1172,6 @@ void GameView::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
suspend_button->set_button_icon(get_editor_theme_icon(SNAME("Suspend")));
next_frame_button->set_button_icon(get_editor_theme_icon(SNAME("NextFrame")));
- reset_speed_button->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_button_icon(get_editor_theme_icon(SNAME("InputEventJoypadMotion")));
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_button_icon(get_editor_theme_icon(SNAME("2DNodes")));
@@ -1141,16 +1180,22 @@ void GameView::_notification(int p_what) {
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_button_icon(get_editor_theme_icon(SNAME("ListSelect")));
- hide_selection->set_button_icon(get_editor_theme_icon(hide_selection->is_pressed() ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
- selection_options_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ selection_options_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiDropdown")));
debug_mute_audio_button->set_button_icon(get_editor_theme_icon(debug_mute_audio ? SNAME("AudioMute") : SNAME("AudioStreamPlayer")));
camera_override_button->set_button_icon(get_editor_theme_icon(SNAME("Camera")));
- camera_override_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ camera_override_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiDropdown")));
- game_window_options_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ game_embed_mode_menu->set_button_icon(get_editor_theme_icon(SNAME("EmbedFused")));
+ PopupMenu *game_embed_menu = game_embed_mode_menu->get_popup();
+ game_embed_menu->set_item_icon(game_embed_menu->get_item_index(EMBED_TYPE_EDITOR), get_editor_theme_icon(SNAME("EmbedFused")));
+ game_embed_menu->set_item_icon(game_embed_menu->get_item_index(EMBED_TYPE_FLOATING), get_editor_theme_icon(SNAME("EmbedFloating")));
+ game_embed_menu->set_item_icon(game_embed_menu->get_item_index(EMBED_TYPE_DISABLED), get_editor_theme_icon(SNAME("EmbedDisabled")));
+ game_window_options_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiDropdown")));
+
+ _update_speed_state_icon(time_scale_index);
_update_speed_state_size();
_update_speed_state_color();
} break;
@@ -1163,14 +1208,17 @@ void GameView::_notification(int p_what) {
case -1: { // Disabled.
embed_on_play = false;
make_floating_on_play = false;
+ game_embed_mode_menu->set_button_icon(get_editor_theme_icon(SNAME("EmbedDisabled")));
} break;
case 1: { // Embed.
embed_on_play = true;
make_floating_on_play = false;
+ game_embed_mode_menu->set_button_icon(get_editor_theme_icon(SNAME("EmbedFused")));
} break;
case 2: { // Floating.
embed_on_play = true;
make_floating_on_play = true;
+ game_embed_mode_menu->set_button_icon(get_editor_theme_icon(SNAME("EmbedFloating")));
} break;
default: {
embed_on_play = EditorSettings::get_singleton()->get_project_metadata("game_view", "embed_on_play", true);
@@ -1178,6 +1226,7 @@ void GameView::_notification(int p_what) {
} break;
}
embed_size_mode = (EmbedSizeMode)(int)EditorSettings::get_singleton()->get_project_metadata("game_view", "embed_size_mode", SIZE_MODE_FIXED);
+ _update_embed_buttons();
_update_embed_menu_options();
EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &GameView::_play_pressed));
@@ -1440,6 +1489,9 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
MarginContainer *toolbar_margin = memnew(MarginContainer);
toolbar_margin->set_theme_type_variation("MainToolBarMargin");
+ toolbar_margin->add_theme_constant_override("margin_top", 1 * EDSCALE);
+ toolbar_margin->add_theme_constant_override("margin_bottom", 1 * EDSCALE);
+ toolbar_margin->set_custom_maximum_size(Size2(-1, 36 * EDSCALE));
add_child(toolbar_margin);
// FIXME: Turn this back into a FlowContainer once GH-115523 is fixed.
@@ -1447,6 +1499,7 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
toolbar_margin->add_child(main_menu_fc);
HBoxContainer *process_hb = memnew(HBoxContainer);
+
main_menu_fc->add_child(process_hb);
suspend_button = memnew(Button);
process_hb->add_child(suspend_button);
@@ -1455,7 +1508,7 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
suspend_button->connect(SceneStringName(toggled), callable_mp(this, &GameView::_suspend_button_toggled));
suspend_button->set_accessibility_name(TTRC("Suspend"));
suspend_button->set_shortcut(ED_GET_SHORTCUT("editor/suspend_resume_embedded_project"));
- suspend_button->set_tooltip_text(TTRC("Force pause at SceneTree level. Stops all processing, but you can still interact with the project."));
+ suspend_button->set_tooltip_text(TTRC("Force pause at SceneTree level. Stops all processing, but you can still interact with the game."));
next_frame_button = memnew(Button);
process_hb->add_child(next_frame_button);
@@ -1464,6 +1517,8 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
next_frame_button->set_accessibility_name(TTRC("Next Frame"));
next_frame_button->set_shortcut(ED_GET_SHORTCUT("editor/next_frame_embedded_project"));
+ process_hb->add_child(memnew(VSeparator));
+
speed_state_button = memnew(MenuButton);
process_hb->add_child(speed_state_button);
speed_state_button->set_text(U"1.0×");
@@ -1478,17 +1533,14 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
menu->add_item(vformat(U"%s×", lbl));
}
- reset_speed_button = memnew(Button);
- process_hb->add_child(reset_speed_button);
- reset_speed_button->set_theme_type_variation(SceneStringName(FlatButton));
- reset_speed_button->set_tooltip_text(TTRC("Reset the game speed."));
- reset_speed_button->set_accessibility_name(TTRC("Reset Speed"));
- reset_speed_button->connect(SceneStringName(pressed), callable_mp(this, &GameView::_reset_time_scales));
-
process_hb->add_child(memnew(VSeparator));
+ PanelContainer *input_panel = memnew(PanelContainer);
+ input_panel->set_theme_type_variation("PanelContainerButtonGroup");
+ main_menu_fc->add_child(input_panel);
+
HBoxContainer *input_hb = memnew(HBoxContainer);
- main_menu_fc->add_child(input_hb);
+ input_panel->add_child(input_hb);
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE] = memnew(Button);
input_hb->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]);
@@ -1497,7 +1549,7 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_pressed(true);
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_theme_type_variation("FlatButtonNoIconTint");
node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_NONE));
- node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_tooltip_text(TTRC("Allow game input."));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_tooltip_text(TTRC("Allow game input as usual."));
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D] = memnew(Button);
input_hb->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]);
@@ -1505,7 +1557,7 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_toggle_mode(true);
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_theme_type_variation("FlatButtonNoIconTint");
node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_2D));
- node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_tooltip_text(TTRC("Disable game input and allow to select Node2Ds, Controls, and manipulate the 2D camera."));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_tooltip_text(TTRC("Disable game input to allow selecting Node2Ds and Controls, as well as manipulate the 2D camera."));
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D] = memnew(Button);
input_hb->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]);
@@ -1513,12 +1565,16 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_toggle_mode(true);
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_theme_type_variation("FlatButtonNoIconTint");
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_3D));
- node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_tooltip_text(TTRC("Disable game input and allow to select Node3Ds and manipulate the 3D camera."));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_tooltip_text(TTRC("Disable game input to allow selecting Node3Ds and manipulating the 3D camera."));
- input_hb->add_child(memnew(VSeparator));
+ main_menu_fc->add_child(memnew(VSeparator));
+
+ PanelContainer *selection_panel = memnew(PanelContainer);
+ selection_panel->set_theme_type_variation("PanelContainerButtonGroup");
+ main_menu_fc->add_child(selection_panel);
HBoxContainer *selection_hb = memnew(HBoxContainer);
- main_menu_fc->add_child(selection_hb);
+ selection_panel->add_child(selection_hb);
select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE] = memnew(Button);
selection_hb->add_child(select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]);
@@ -1538,52 +1594,38 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
_select_mode_pressed(EditorSettings::get_singleton()->get_project_metadata("game_view", "select_mode", 0));
- hide_selection = memnew(Button);
- selection_hb->add_child(hide_selection);
- hide_selection->set_toggle_mode(true);
- hide_selection->set_theme_type_variation(SceneStringName(FlatButton));
- hide_selection->set_tooltip_text(TTRC("Toggle Selection Visibility"));
- hide_selection->set_pressed(EditorSettings::get_singleton()->get_project_metadata("game_view", "hide_selection", false));
- if (hide_selection->is_pressed()) {
- debugger->set_selection_visible(false);
- }
- hide_selection->connect(SceneStringName(toggled), callable_mp(this, &GameView::_hide_selection_toggled));
-
selection_options_menu = memnew(MenuButton);
selection_hb->add_child(selection_options_menu);
selection_options_menu->set_flat(false);
- selection_options_menu->set_theme_type_variation("FlatMenuButton");
+ selection_options_menu->set_theme_type_variation("FlatMenuButtonNoIconTint");
selection_options_menu->set_h_size_flags(SIZE_SHRINK_END);
- selection_options_menu->set_tooltip_text(TTRC("Selection Options"));
+ selection_options_menu->set_tooltip_text(TTRC("Selection options."));
PopupMenu *selection_menu = selection_options_menu->get_popup();
selection_menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_selection_options_menu_id_pressed));
+ selection_menu->add_check_item(TTRC("Show Selection Visibility"), SELECTION_HIDE);
selection_menu->add_check_item(TTRC("Don't Select Locked Nodes"), SELECTION_AVOID_LOCKED);
selection_menu->add_check_item(TTRC("Select Group Over Children"), SELECTION_PREFER_GROUP);
+ selection_hide = EditorSettings::get_singleton()->get_project_metadata("game_view", "hide_selection", true);
selection_avoid_locked = EditorSettings::get_singleton()->get_project_metadata("game_view", "selection_avoid_locked", false);
selection_prefer_group = EditorSettings::get_singleton()->get_project_metadata("game_view", "selection_prefer_group", false);
+ selection_menu->set_item_checked(selection_menu->get_item_index(SELECTION_HIDE), selection_hide);
selection_menu->set_item_checked(selection_menu->get_item_index(SELECTION_AVOID_LOCKED), selection_avoid_locked);
selection_menu->set_item_checked(selection_menu->get_item_index(SELECTION_PREFER_GROUP), selection_prefer_group);
+ debugger->set_selection_visible(selection_hide);
debugger->set_selection_avoid_locked(selection_avoid_locked);
debugger->set_selection_prefer_group(selection_prefer_group);
- selection_hb->add_child(memnew(VSeparator));
+ main_menu_fc->add_child(memnew(VSeparator));
- HBoxContainer *audio_hb = memnew(HBoxContainer);
- main_menu_fc->add_child(audio_hb);
-
- debug_mute_audio_button = memnew(Button);
- audio_hb->add_child(debug_mute_audio_button);
- debug_mute_audio_button->set_theme_type_variation("FlatButton");
- debug_mute_audio_button->connect(SceneStringName(pressed), callable_mp(this, &GameView::_debug_mute_audio_button_pressed));
- debug_mute_audio_button->set_tooltip_text(debug_mute_audio ? TTRC("Unmute game audio.") : TTRC("Mute game audio."));
-
- audio_hb->add_child(memnew(VSeparator));
+ PanelContainer *camera_panel = memnew(PanelContainer);
+ camera_panel->set_theme_type_variation("PanelContainerButtonGroup");
+ main_menu_fc->add_child(camera_panel);
HBoxContainer *camera_hb = memnew(HBoxContainer);
- main_menu_fc->add_child(camera_hb);
+ camera_panel->add_child(camera_hb);
camera_override_button = memnew(Button);
camera_hb->add_child(camera_override_button);
@@ -1595,9 +1637,9 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
camera_override_menu = memnew(MenuButton);
camera_hb->add_child(camera_override_menu);
camera_override_menu->set_flat(false);
- camera_override_menu->set_theme_type_variation("FlatMenuButton");
+ camera_override_menu->set_theme_type_variation("FlatMenuButtonNoIconTint");
camera_override_menu->set_h_size_flags(SIZE_SHRINK_END);
- camera_override_menu->set_tooltip_text(TTRC("Camera Override Options"));
+ camera_override_menu->set_tooltip_text(TTRC("Camera override options."));
menu = camera_override_menu->get_popup();
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_camera_override_menu_id_pressed));
@@ -1607,14 +1649,32 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
menu->add_radio_check_item(TTRC("Manipulate In-Game"), CAMERA_MODE_INGAME);
menu->set_item_checked(menu->get_item_index(CAMERA_MODE_INGAME), true);
menu->add_radio_check_item(TTRC("Manipulate From Editors"), CAMERA_MODE_EDITORS);
- camera_hb->add_child(memnew(VSeparator));
+
+ main_menu_fc->add_child(memnew(VSeparator));
+
+ HBoxContainer *audio_hb = memnew(HBoxContainer);
+ main_menu_fc->add_child(audio_hb);
+
+ debug_mute_audio_button = memnew(Button);
+ audio_hb->add_child(debug_mute_audio_button);
+ debug_mute_audio_button->set_theme_type_variation(SceneStringName(FlatButton));
+ debug_mute_audio_button->connect(SceneStringName(pressed), callable_mp(this, &GameView::_debug_mute_audio_button_pressed));
+ debug_mute_audio_button->set_tooltip_text(debug_mute_audio ? TTRC("Unmute game audio.") : TTRC("Mute game audio."));
embedding_hb = memnew(HBoxContainer);
embedding_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ embedding_hb->set_alignment(ALIGNMENT_END);
main_menu_fc->add_child(embedding_hb);
+ PanelContainer *embed_panel = memnew(PanelContainer);
+ embed_panel->set_theme_type_variation("PanelContainerButtonGroup");
+
game_size_label = memnew(Label());
+ game_hb = memnew(HBoxContainer);
+
embedding_hb->add_child(game_size_label);
+ embedding_hb->add_child(embed_panel);
+ embed_panel->add_child(game_hb);
game_size_label->hide();
// Setting the minimum size prevents the game workspace from resizing indefinitely
// due to the label size oscillating by a few pixels when the game is in stretch mode
@@ -1624,29 +1684,38 @@ GameView::GameView(Ref p_debugger, EmbeddedProcessBase *p_embe
game_size_label->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_RIGHT);
game_size_label->set_mouse_filter(MouseFilter::MOUSE_FILTER_PASS);
- game_size_placeholder = memnew(Control());
- embedding_hb->add_child(game_size_placeholder);
- game_size_placeholder->set_h_size_flags(game_size_label->get_h_size_flags());
+ game_embed_mode_menu = memnew(MenuButton);
+ game_hb->add_child(game_embed_mode_menu);
+ game_embed_mode_menu->set_flat(false);
+ game_embed_mode_menu->set_theme_type_variation("FlatMenuButtonNoIconTint");
+ game_embed_mode_menu->set_h_size_flags(SIZE_SHRINK_END);
+ game_embed_mode_menu->set_tooltip_text(TTRC("Game embed modes."));
+
+ PopupMenu *game_embed_menu = game_embed_mode_menu->get_popup();
+ game_embed_menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_game_embed_mode_pressed));
+ game_embed_menu->add_radio_check_item(TTRC("Embed in editor"), EMBED_TYPE_EDITOR);
+ game_embed_menu->add_radio_check_item(TTRC("Float window with toolbar"), EMBED_TYPE_FLOATING);
+ game_embed_menu->add_radio_check_item(TTRC("Float window without toolbar"), EMBED_TYPE_DISABLED);
+ game_embed_menu->set_item_checked(game_embed_menu->get_item_index(EMBED_TYPE_EDITOR), embed_on_play && !make_floating_on_play);
+ game_embed_menu->set_item_checked(game_embed_menu->get_item_index(EMBED_TYPE_FLOATING), make_floating_on_play && window_wrapper->is_window_available());
+ game_embed_menu->set_item_checked(game_embed_menu->get_item_index(EMBED_TYPE_DISABLED), !embed_on_play && !make_floating_on_play);
game_window_options_menu = memnew(MenuButton);
- embedding_hb->add_child(game_window_options_menu);
+ game_hb->add_child(game_window_options_menu);
game_window_options_menu->set_flat(false);
- game_window_options_menu->set_theme_type_variation("FlatMenuButton");
+ game_window_options_menu->set_theme_type_variation("FlatMenuButtonNoIconTint");
game_window_options_menu->set_h_size_flags(SIZE_SHRINK_END);
- game_window_options_menu->set_tooltip_text(TTRC("Game Window Options"));
+ game_window_options_menu->set_tooltip_text(TTRC("Game window options."));
menu = game_window_options_menu->get_popup();
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_game_window_options_menu_menu_id_pressed));
- menu->add_check_item(TTRC("Embed Game on Next Play"), WINDOW_RUN_GAME_EMBEDDED);
- menu->add_check_item(TTRC("Make Game Workspace Floating on Next Play"), WINDOW_MAKE_FLOATING_ON_PLAY);
-
menu->add_separator(TTRC("Embedded Window Sizing"));
menu->add_radio_check_item(TTRC("Fixed Size"), WINDOW_SIZE_MODE_FIXED);
- menu->set_item_tooltip(menu->get_item_index(WINDOW_SIZE_MODE_FIXED), TTRC("Embedded game size is based on project settings.\nThe 'Keep Aspect' mode is used when the Game Workspace is smaller than the desired size."));
+ menu->set_item_tooltip(menu->get_item_index(WINDOW_SIZE_MODE_FIXED), TTRC("Embedded game size is based on project settings.\nThe 'Keep Aspect' mode is used when the Game workspace is smaller than the desired size."));
menu->add_radio_check_item(TTRC("Keep Aspect Ratio"), WINDOW_SIZE_MODE_KEEP_ASPECT);
menu->set_item_tooltip(menu->get_item_index(WINDOW_SIZE_MODE_KEEP_ASPECT), TTRC("Keep the aspect ratio of the embedded game."));
menu->add_radio_check_item(TTRC("Stretch to Fit"), WINDOW_SIZE_MODE_STRETCH);
- menu->set_item_tooltip(menu->get_item_index(WINDOW_SIZE_MODE_STRETCH), TTRC("Embedded game size stretches to fit the Game Workspace."));
+ menu->set_item_tooltip(menu->get_item_index(WINDOW_SIZE_MODE_STRETCH), TTRC("Embedded game size stretches to fit the Game workspace."));
panel = memnew(Panel);
add_child(panel);
diff --git a/editor/run/game_view_plugin.h b/editor/run/game_view_plugin.h
index ddcc21dd9dab..2121495d22d2 100644
--- a/editor/run/game_view_plugin.h
+++ b/editor/run/game_view_plugin.h
@@ -36,6 +36,7 @@
#include "editor/plugins/editor_plugin.h"
#include "scene/debugger/runtime_node_select.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/menu_button.h"
class EmbeddedProcessBase;
class VSeparator;
@@ -124,10 +125,9 @@ class GameView : public VBoxContainer {
CAMERA_RESET_3D,
CAMERA_MODE_INGAME,
CAMERA_MODE_EDITORS,
+ SELECTION_HIDE,
SELECTION_AVOID_LOCKED,
SELECTION_PREFER_GROUP,
- WINDOW_RUN_GAME_EMBEDDED,
- WINDOW_MAKE_FLOATING_ON_PLAY,
WINDOW_SIZE_MODE_FIXED,
WINDOW_SIZE_MODE_KEEP_ASPECT,
WINDOW_SIZE_MODE_STRETCH,
@@ -153,6 +153,13 @@ class GameView : public VBoxContainer {
EMBED_NOT_AVAILABLE_HEADLESS,
};
+ enum EmbedMode {
+ EMBED_TYPE_DISABLED,
+ EMBED_TYPE_FLOATING,
+ EMBED_TYPE_EDITOR,
+ EMBED_TYPE_MAX,
+ };
+
inline static GameView *singleton = nullptr;
Ref debugger;
@@ -174,6 +181,7 @@ class GameView : public VBoxContainer {
bool debug_mute_audio = false;
+ bool selection_hide = true;
bool selection_avoid_locked = false;
bool selection_prefer_group = false;
@@ -183,18 +191,19 @@ class GameView : public VBoxContainer {
Button *node_type_button[RuntimeNodeSelect::NODE_TYPE_MAX];
Button *select_mode_button[RuntimeNodeSelect::SELECT_MODE_MAX];
- Button *hide_selection = nullptr;
MenuButton *selection_options_menu = nullptr;
- Button *debug_mute_audio_button = nullptr;
-
Button *camera_override_button = nullptr;
MenuButton *camera_override_menu = nullptr;
+ Button *debug_mute_audio_button = nullptr;
+
HBoxContainer *embedding_hb = nullptr;
MenuButton *game_window_options_menu = nullptr;
Label *game_size_label = nullptr;
- Control *game_size_placeholder = nullptr;
+ HBoxContainer *game_hb = nullptr;
+ MenuButton *game_embed_mode_menu = nullptr;
+ Button *game_embed_mode_button[EmbedMode::EMBED_TYPE_MAX];
Panel *panel = nullptr;
EmbeddedProcessBase *embedded_process = nullptr;
Label *state_label = nullptr;
@@ -213,7 +222,6 @@ class GameView : public VBoxContainer {
bool renderer_supports_hdr_output = false;
MenuButton *speed_state_button = nullptr;
- Button *reset_speed_button = nullptr;
void _sessions_changed();
@@ -225,12 +233,14 @@ class GameView : public VBoxContainer {
void _node_type_pressed(int p_option);
void _select_mode_pressed(int p_option);
+ void _game_embed_mode_pressed(int p_option);
void _selection_options_menu_id_pressed(int p_id);
void _game_window_options_menu_menu_id_pressed(int p_id);
void _reset_time_scales();
void _speed_state_menu_pressed(int p_id);
void _update_speed_buttons();
+ void _update_speed_state_icon(int p_id);
void _update_speed_state_color();
void _update_speed_state_size();
@@ -248,13 +258,12 @@ class GameView : public VBoxContainer {
EmbedAvailability _get_embed_available();
void _update_ui();
void _update_embed_menu_options();
+ void _update_embed_buttons();
void _update_game_window_size_label();
void _update_embed_window_size();
void _update_arguments_for_instance(int p_idx, List &r_arguments);
void _show_update_window_wrapper();
- void _hide_selection_toggled(bool p_pressed);
-
void _debug_mute_audio_button_pressed();
void _setup_complete();
void _game_window_size_received(const Array &p_state);
diff --git a/editor/themes/theme_classic.cpp b/editor/themes/theme_classic.cpp
index f8b7632b7bbf..c9b2a87ee77b 100644
--- a/editor/themes/theme_classic.cpp
+++ b/editor/themes/theme_classic.cpp
@@ -1887,8 +1887,8 @@ void ThemeClassic::populate_editor_styles(const Ref &p_theme, Edito
p_theme->set_type_variation("FlatButtonNoIconTint", "FlatButton");
p_theme->set_color("icon_pressed_color", "FlatButtonNoIconTint", p_config.icon_normal_color);
- p_theme->set_color("icon_hover_color", "FlatButtonNoIconTint", p_config.mono_color);
- p_theme->set_color("icon_hover_pressed_color", "FlatButtonNoIconTint", p_config.mono_color);
+ p_theme->set_color("icon_hover_color", "FlatButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color.inverted());
+ p_theme->set_color("icon_hover_pressed_color", "FlatButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color.inverted());
// Variation for the AssetLib thumbnails.
@@ -1901,8 +1901,8 @@ void ThemeClassic::populate_editor_styles(const Ref &p_theme, Edito
p_theme->set_type_variation("FlatMenuButtonNoIconTint", "FlatMenuButton");
p_theme->set_color("icon_pressed_color", "FlatMenuButtonNoIconTint", p_config.icon_normal_color);
- p_theme->set_color("icon_hover_color", "FlatMenuButtonNoIconTint", p_config.mono_color);
- p_theme->set_color("icon_hover_pressed_color", "FlatMenuButtonNoIconTint", p_config.mono_color);
+ p_theme->set_color("icon_hover_color", "FlatMenuButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color.inverted());
+ p_theme->set_color("icon_hover_pressed_color", "FlatMenuButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color.inverted());
// Variation for Editor Log filter buttons.
p_theme->set_type_variation("EditorLogFilterButton", "Button");
@@ -1933,8 +1933,8 @@ void ThemeClassic::populate_editor_styles(const Ref &p_theme, Edito
{
p_theme->set_type_variation("CheckBoxNoIconTint", "CheckBox");
p_theme->set_color("icon_pressed_color", "CheckBoxNoIconTint", p_config.icon_normal_color);
- p_theme->set_color("icon_hover_color", "CheckBoxNoIconTint", p_config.mono_color);
- p_theme->set_color("icon_hover_pressed_color", "CheckBoxNoIconTint", p_config.mono_color);
+ p_theme->set_color("icon_hover_color", "CheckBoxNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color.inverted());
+ p_theme->set_color("icon_hover_pressed_color", "CheckBoxNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color.inverted());
}
// Buttons styles that stand out against the panel background (e.g. AssetLib).
@@ -2062,6 +2062,18 @@ void ThemeClassic::populate_editor_styles(const Ref &p_theme, Edito
p_theme->set_stylebox(SceneStringName(panel), "PanelContainerTabbarInner", EditorThemeManager::make_empty_stylebox(0, 0, 0, 0));
}
+ // PanelContainerButtonGroup.
+ {
+ p_theme->set_type_variation("PanelContainerButtonGroup", "PanelContainer");
+
+ Ref style_button_group = p_theme->get_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))->duplicate();
+ style_button_group->set_content_margin_all(p_config.base_margin * EDSCALE);
+ style_button_group->set_corner_radius_all(p_config.corner_radius);
+ style_button_group->set_bg_color(p_config.dark_color_1.lerp(p_config.mono_color, 0.15));
+
+ p_theme->set_stylebox(SceneStringName(panel), "PanelContainerButtonGroup", style_button_group);
+ }
+
// TreeLineEdit.
{
Ref tree_line_edit_style = p_theme->get_stylebox(CoreStringName(normal), SNAME("LineEdit"))->duplicate();
diff --git a/editor/themes/theme_modern.cpp b/editor/themes/theme_modern.cpp
index cc030f772498..b0c7763d6dc6 100644
--- a/editor/themes/theme_modern.cpp
+++ b/editor/themes/theme_modern.cpp
@@ -1947,13 +1947,13 @@ void ThemeModern::populate_editor_styles(const Ref &p_theme, Editor
p_theme->set_type_variation("FlatButtonNoIconTint", "FlatButton");
p_theme->set_color("icon_pressed_color", "FlatButtonNoIconTint", p_config.icon_normal_color);
- p_theme->set_color("icon_hover_color", "FlatButtonNoIconTint", p_config.mono_color);
- p_theme->set_color("icon_hover_pressed_color", "FlatButtonNoIconTint", p_config.mono_color);
+ p_theme->set_color("icon_hover_color", "FlatButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color_inv);
+ p_theme->set_color("icon_hover_pressed_color", "FlatButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color_inv);
p_theme->set_type_variation("FlatMenuButtonNoIconTint", "FlatMenuButton");
p_theme->set_color("icon_pressed_color", "FlatMenuButtonNoIconTint", p_config.icon_normal_color);
- p_theme->set_color("icon_hover_color", "FlatMenuButtonNoIconTint", p_config.mono_color);
- p_theme->set_color("icon_hover_pressed_color", "FlatMenuButtonNoIconTint", p_config.mono_color);
+ p_theme->set_color("icon_hover_color", "FlatMenuButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color_inv);
+ p_theme->set_color("icon_hover_pressed_color", "FlatMenuButtonNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color_inv);
// Variation for the AssetLib thumbnails.
@@ -1985,8 +1985,8 @@ void ThemeModern::populate_editor_styles(const Ref &p_theme, Editor
{
p_theme->set_type_variation("CheckBoxNoIconTint", "CheckBox");
p_theme->set_color("icon_pressed_color", "CheckBoxNoIconTint", p_config.icon_normal_color);
- p_theme->set_color("icon_hover_color", "CheckBoxNoIconTint", p_config.mono_color);
- p_theme->set_color("icon_hover_pressed_color", "CheckBoxNoIconTint", p_config.mono_color);
+ p_theme->set_color("icon_hover_color", "CheckBoxNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color_inv);
+ p_theme->set_color("icon_hover_pressed_color", "CheckBoxNoIconTint", p_config.dark_icon_and_font ? p_config.mono_color : p_config.mono_color_inv);
}
// Buttons styles that stand out against the panel background (e.g. AssetLib).
@@ -2175,6 +2175,18 @@ void ThemeModern::populate_editor_styles(const Ref &p_theme, Editor
p_theme->set_stylebox(SceneStringName(panel), "PanelContainerTabbarInner", style_tabbar_background_inner);
}
+ // PanelContainerButtonGroup.
+ {
+ p_theme->set_type_variation("PanelContainerButtonGroup", "PanelContainer");
+
+ Ref style_button_group = p_theme->get_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))->duplicate();
+ style_button_group->set_content_margin_all(p_config.base_margin * EDSCALE);
+ style_button_group->set_corner_radius_all(p_config.corner_radius > 0 ? (p_config.corner_radius + p_config.base_margin) * EDSCALE : 0);
+ style_button_group->set_bg_color(p_config.surface_lower_color.lerp(p_config.mono_color_inv, 0.15).lightened(0.02));
+
+ p_theme->set_stylebox(SceneStringName(panel), "PanelContainerButtonGroup", style_button_group);
+ }
+
// TreeLineEdit.
{
Ref tree_line_edit_style = p_theme->get_stylebox(CoreStringName(normal), SNAME("LineEdit"))->duplicate();