37
37
#include " editor/gui/editor_toaster.h"
38
38
#include " editor/gui/editor_version_button.h"
39
39
#include " editor/themes/editor_scale.h"
40
+ #include " editor/themes/editor_theme_manager.h"
40
41
#include " scene/gui/box_container.h"
41
42
#include " scene/gui/button.h"
43
+ #include " scene/gui/menu_button.h"
42
44
#include " scene/gui/split_container.h"
45
+ #include " scene/resources/style_box_flat.h"
43
46
44
47
void EditorBottomPanel::_notification (int p_what) {
45
48
switch (p_what) {
46
49
case NOTIFICATION_THEME_CHANGED: {
47
50
pin_button->set_button_icon (get_editor_theme_icon (SNAME (" Pin" )));
48
51
expand_button->set_button_icon (get_editor_theme_icon (SNAME (" ExpandBottomDock" )));
52
+ button_menu->set_button_icon (get_editor_theme_icon (SNAME (" GuiTabMenuHl" )));
53
+
54
+ if (get_theme_color (SNAME (" base_color" ), EditorStringName (Editor)) != Color (0 , 0 , 0 )) {
55
+ stylebox_shadow_left->set_border_color (get_theme_color (SNAME (" dark_color_1" )) * Color (1 , 1 , 1 , EditorThemeManager::is_dark_theme () ? 0.4 : 0.3 ));
56
+ stylebox_shadow_right->set_border_color (get_theme_color (SNAME (" dark_color_1" )) * Color (1 , 1 , 1 , EditorThemeManager::is_dark_theme () ? 0.4 : 0.3 ));
57
+ } else {
58
+ stylebox_shadow_left->set_border_color (Color (0.3 , 0.3 , 0.3 , 0.45 ));
59
+ stylebox_shadow_right->set_border_color (Color (0.3 , 0.3 , 0.3 , 0.45 ));
60
+ }
49
61
} break ;
50
62
}
51
63
}
52
64
53
65
void EditorBottomPanel::_switch_by_control (bool p_visible, Control *p_control, bool p_ignore_lock) {
54
66
for (int i = 0 ; i < items.size (); i++) {
55
67
if (items[i].control == p_control) {
56
- _switch_to_item (p_visible, i, p_ignore_lock);
68
+ callable_mp ( this , &EditorBottomPanel:: _switch_to_item). call_deferred (p_visible, i, p_ignore_lock);
57
69
return ;
58
70
}
59
71
}
@@ -62,7 +74,12 @@ void EditorBottomPanel::_switch_by_control(bool p_visible, Control *p_control, b
62
74
void EditorBottomPanel::_switch_to_item (bool p_visible, int p_idx, bool p_ignore_lock) {
63
75
ERR_FAIL_INDEX (p_idx, items.size ());
64
76
77
+ if (get_tree ()->is_connected (" process_frame" , callable_mp (this , &EditorBottomPanel::_focus_pressed_button))) {
78
+ get_tree ()->disconnect (" process_frame" , callable_mp (this , &EditorBottomPanel::_focus_pressed_button));
79
+ }
80
+
65
81
if (items[p_idx].control ->is_visible () == p_visible) {
82
+ get_tree ()->connect (" process_frame" , callable_mp (this , &EditorBottomPanel::_focus_pressed_button).bind (items[p_idx].button ->get_instance_id ()), CONNECT_ONE_SHOT);
66
83
return ;
67
84
}
68
85
@@ -84,7 +101,7 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx, bool p_ignore
84
101
} else {
85
102
add_theme_style_override (SceneStringName (panel), get_theme_stylebox (SNAME (" BottomPanel" ), EditorStringName (EditorStyles)));
86
103
}
87
-
104
+ get_tree ()-> connect ( " process_frame " , callable_mp ( this , &EditorBottomPanel::_focus_pressed_button). bind (items[p_idx]. button -> get_instance_id ()), CONNECT_ONE_SHOT);
88
105
center_split->set_dragger_visibility (SplitContainer::DRAGGER_VISIBLE);
89
106
center_split->set_collapsed (false );
90
107
pin_button->show ();
@@ -125,6 +142,92 @@ bool EditorBottomPanel::_button_drag_hover(const Vector2 &, const Variant &, But
125
142
return false ;
126
143
}
127
144
145
+ void EditorBottomPanel::_focus_pressed_button (ObjectID btn_id) {
146
+ Object *btn_instance = ObjectDB::get_instance (btn_id);
147
+ if (!btn_instance) {
148
+ return ;
149
+ }
150
+ button_sc->ensure_control_visible (Object::cast_to<Button >(btn_instance));
151
+ }
152
+
153
+ void EditorBottomPanel::_add_item_to_popup () {
154
+ button_popup_menu->clear ();
155
+ for (int i = 0 ; i < button_hbox->get_child_count (); i++) {
156
+ Button *btn = Object::cast_to<Button >(button_hbox->get_child (i));
157
+ if (!btn->is_visible ()) {
158
+ continue ;
159
+ }
160
+ button_popup_menu->add_item (btn->get_text ());
161
+ button_popup_menu->set_item_metadata (button_popup_menu->get_item_count () - 1 , btn->get_index ());
162
+ }
163
+ }
164
+
165
+ void EditorBottomPanel::_popup_position () {
166
+ if (button_popup_menu->is_visible ()) {
167
+ button_popup_menu->hide ();
168
+ return ;
169
+ }
170
+ button_popup_menu->reset_size ();
171
+ Vector2 popup_pos = button_menu->get_screen_rect ().position - Vector2 (0 , button_popup_menu->get_size ().y );
172
+ if (is_layout_rtl ()) {
173
+ popup_pos.x -= button_popup_menu->get_size ().x - button_menu->get_size ().x ;
174
+ }
175
+ button_popup_menu->set_position (popup_pos);
176
+ button_popup_menu->popup ();
177
+ }
178
+
179
+ void EditorBottomPanel::_popup_item_pressed (int p_idx) {
180
+ Button *btn = Object::cast_to<Button >(button_hbox->get_child (button_popup_menu->get_item_metadata (p_idx)));
181
+ btn->emit_signal (SceneStringName (toggled), true );
182
+ }
183
+
184
+ void EditorBottomPanel::_set_button_sc_controls () {
185
+ if (button_hbox->get_size ().x < button_sc->get_size ().x ) {
186
+ button_menu->set_visible (false );
187
+ shadow_spacer->set_visible (false );
188
+ shadow_panel_left->add_theme_style_override (SceneStringName (panel), stylebox_shadow_empty);
189
+ shadow_panel_right->add_theme_style_override (SceneStringName (panel), stylebox_shadow_empty);
190
+ } else {
191
+ button_menu->set_visible (true );
192
+ shadow_spacer->set_visible (true );
193
+ if (is_layout_rtl ()) {
194
+ if (button_sc->get_h_scroll_bar ()->get_value () + 3 >= button_sc->get_h_scroll_bar ()->get_max () - button_sc->get_size ().x ) {
195
+ shadow_panel_left->add_theme_style_override (SceneStringName (panel), stylebox_shadow_empty);
196
+ } else {
197
+ shadow_panel_left->add_theme_style_override (SceneStringName (panel), stylebox_shadow_left);
198
+ }
199
+ if (button_sc->get_h_scroll_bar ()->get_value () == 0 ) {
200
+ shadow_panel_right->add_theme_style_override (SceneStringName (panel), stylebox_shadow_empty);
201
+ } else {
202
+ shadow_panel_right->add_theme_style_override (SceneStringName (panel), stylebox_shadow_right);
203
+ }
204
+ } else {
205
+ if (button_sc->get_h_scroll_bar ()->get_value () == 0 ) {
206
+ shadow_panel_left->add_theme_style_override (SceneStringName (panel), stylebox_shadow_empty);
207
+ } else {
208
+ shadow_panel_left->add_theme_style_override (SceneStringName (panel), stylebox_shadow_left);
209
+ }
210
+ if (button_sc->get_h_scroll_bar ()->get_value () + 3 >= button_sc->get_h_scroll_bar ()->get_max () - button_sc->get_size ().x ) {
211
+ shadow_panel_right->add_theme_style_override (SceneStringName (panel), stylebox_shadow_empty);
212
+ } else {
213
+ shadow_panel_right->add_theme_style_override (SceneStringName (panel), stylebox_shadow_right);
214
+ }
215
+ }
216
+ }
217
+ }
218
+
219
+ void EditorBottomPanel::_sc_input (const Ref<InputEvent> &p_gui_input) {
220
+ Ref<InputEventMouseButton> mb = p_gui_input;
221
+
222
+ if (mb.is_valid ()) {
223
+ if (mb->is_pressed ()) {
224
+ if ((mb->get_button_index () == MouseButton::WHEEL_UP && mb->is_alt_pressed ()) || (mb->get_button_index () == MouseButton::WHEEL_DOWN && mb->is_alt_pressed ())) {
225
+ mb->set_factor (mb->get_factor () * 7 );
226
+ }
227
+ }
228
+ }
229
+ }
230
+
128
231
void EditorBottomPanel::save_layout_to_config (Ref<ConfigFile> p_config_file, const String &p_section) const {
129
232
int selected_item_idx = -1 ;
130
233
for (int i = 0 ; i < items.size (); i++) {
@@ -162,7 +265,7 @@ void EditorBottomPanel::load_layout_from_config(Ref<ConfigFile> p_config_file, c
162
265
Button *EditorBottomPanel::add_item (String p_text, Control *p_item, const Ref<Shortcut> &p_shortcut, bool p_at_front) {
163
266
Button *tb = memnew (Button );
164
267
tb->set_theme_type_variation (" BottomPanelButton" );
165
- tb->connect (SceneStringName (toggled), callable_mp (this , &EditorBottomPanel::_switch_by_control).bind (p_item, true ));
268
+ tb->connect (SceneStringName (toggled), callable_mp (this , &EditorBottomPanel::_switch_by_control).bind (p_item, true ), CONNECT_DEFERRED );
166
269
tb->set_drag_forwarding (Callable (), callable_mp (this , &EditorBottomPanel::_button_drag_hover).bind (tb, p_item), Callable ());
167
270
tb->set_text (p_text);
168
271
tb->set_shortcut (p_shortcut);
@@ -259,9 +362,62 @@ EditorBottomPanel::EditorBottomPanel() {
259
362
bottom_hbox->set_custom_minimum_size (Size2 (0 , 24 * EDSCALE)); // Adjust for the height of the "Expand Bottom Dock" icon.
260
363
item_vbox->add_child (bottom_hbox);
261
364
365
+ button_tab_bar_hbox = memnew (HBoxContainer);
366
+ button_tab_bar_hbox->set_h_size_flags (Control::SIZE_EXPAND_FILL);
367
+ button_tab_bar_hbox->add_theme_constant_override (" separation" , 0 );
368
+ bottom_hbox->add_child (button_tab_bar_hbox);
369
+
370
+ button_menu = memnew (Button );
371
+ button_menu->set_theme_type_variation (" FlatMenuButton" );
372
+ button_menu->set_toggle_mode (true );
373
+ button_menu->set_action_mode (BaseButton::ACTION_MODE_BUTTON_PRESS);
374
+ button_menu->set_tooltip_text (TTR (" List all options." ));
375
+ button_menu->connect (SceneStringName (pressed), callable_mp (this , &EditorBottomPanel::_popup_position));
376
+ button_tab_bar_hbox->add_child (button_menu);
377
+
378
+ button_popup_menu = memnew (PopupMenu);
379
+ add_child (button_popup_menu);
380
+ button_popup_menu->connect (SceneStringName (id_pressed), callable_mp (this , &EditorBottomPanel::_popup_item_pressed));
381
+ button_popup_menu->connect (" popup_hide" , callable_mp ((BaseButton *)button_menu, &BaseButton::set_pressed).bind (false ));
382
+ button_popup_menu->connect (" about_to_popup" , callable_mp ((BaseButton *)button_menu, &BaseButton::set_pressed).bind (true ));
383
+
384
+ shadow_spacer = memnew (Control);
385
+ shadow_spacer->set_custom_minimum_size (Size2 (2 * EDSCALE, 0 ));
386
+ button_tab_bar_hbox->add_child (shadow_spacer);
387
+
388
+ stylebox_shadow_empty.instantiate ();
389
+ stylebox_shadow_left.instantiate ();
390
+ stylebox_shadow_left->set_draw_center (false );
391
+ stylebox_shadow_left->set_border_blend (true );
392
+ stylebox_shadow_left->set_border_width_all (0 );
393
+ stylebox_shadow_right = stylebox_shadow_left->duplicate ();
394
+ stylebox_shadow_left->set_border_width (Side::SIDE_LEFT, 3 * EDSCALE);
395
+ stylebox_shadow_left->set_expand_margin (Side::SIDE_LEFT, 1 );
396
+ stylebox_shadow_right->set_border_width (Side::SIDE_RIGHT, 3 * EDSCALE);
397
+ stylebox_shadow_right->set_expand_margin (Side::SIDE_RIGHT, 1 );
398
+
399
+ shadow_panel_left = memnew (Panel);
400
+ shadow_panel_left->set_custom_minimum_size (Size2 (4 * EDSCALE, 0 ));
401
+ shadow_panel_left->add_theme_style_override (SceneStringName (panel), stylebox_shadow_left);
402
+ button_tab_bar_hbox->add_child (shadow_panel_left);
403
+
404
+ button_sc = memnew (ScrollContainer);
405
+ button_sc->set_h_size_flags (Control::SIZE_EXPAND_FILL);
406
+ button_sc->set_follow_focus (true );
407
+ button_sc->set_horizontal_scroll_mode (ScrollContainer::SCROLL_MODE_SHOW_NEVER);
408
+ button_sc->set_vertical_scroll_mode (ScrollContainer::SCROLL_MODE_DISABLED);
409
+ button_sc->connect (SceneStringName (draw), callable_mp (this , &EditorBottomPanel::_set_button_sc_controls));
410
+ button_sc->connect (SceneStringName (gui_input), callable_mp (this , &EditorBottomPanel::_sc_input));
411
+ button_tab_bar_hbox->add_child (button_sc);
412
+
262
413
button_hbox = memnew (HBoxContainer);
263
- button_hbox->set_h_size_flags (Control::SIZE_EXPAND_FILL);
264
- bottom_hbox->add_child (button_hbox);
414
+ button_sc->add_child (button_hbox);
415
+ button_hbox->connect (SceneStringName (resized), callable_mp (this , &EditorBottomPanel::_add_item_to_popup));
416
+
417
+ shadow_panel_right = memnew (Panel);
418
+ shadow_panel_right->set_custom_minimum_size (Size2 (4 * EDSCALE, 0 ));
419
+ shadow_panel_right->add_theme_style_override (SceneStringName (panel), stylebox_shadow_right);
420
+ button_tab_bar_hbox->add_child (shadow_panel_right);
265
421
266
422
editor_toaster = memnew (EditorToaster);
267
423
bottom_hbox->add_child (editor_toaster);
0 commit comments