mirror of https://github.com/godotengine/godot
Replace DockSlot with DockTabContainer
This commit is contained in:
parent
5ad8b27d8d
commit
4274f8b543
|
|
@ -0,0 +1,270 @@
|
|||
/**************************************************************************/
|
||||
/* dock_tab_container.cpp */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "dock_tab_container.h"
|
||||
|
||||
#include "editor/docks/editor_dock.h"
|
||||
#include "editor/docks/editor_dock_manager.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/resources/style_box_flat.h"
|
||||
|
||||
bool EditorDockDragHint::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
|
||||
return can_drop_dock;
|
||||
}
|
||||
|
||||
void EditorDockDragHint::drop_data(const Point2 &p_point, const Variant &p_data) {
|
||||
// Drop dock into last spot if not over tabbar.
|
||||
if (drop_tabbar->get_rect().has_point(p_point)) {
|
||||
drop_tabbar->_handle_drop_data("tab_container_tab", p_point, p_data, callable_mp(this, &EditorDockDragHint::_drag_move_tab), callable_mp(this, &EditorDockDragHint::_drag_move_tab_from));
|
||||
} else {
|
||||
EditorDockManager *dock_manager = EditorDockManager::get_singleton();
|
||||
dock_manager->_move_dock(dock_manager->_get_dock_tab_dragged(), dock_container, drop_tabbar->get_tab_count());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDockDragHint::_drag_move_tab(int p_from_index, int p_to_index) {
|
||||
dock_container->get_dock(p_from_index)->set_tab_index(p_to_index, true);
|
||||
}
|
||||
|
||||
void EditorDockDragHint::_drag_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index) {
|
||||
EditorDockManager *dock_manager = EditorDockManager::get_singleton();
|
||||
dock_manager->_move_dock(dock_manager->_get_dock_tab_dragged(), dock_container, p_to_index);
|
||||
}
|
||||
|
||||
void EditorDockDragHint::gui_input(const Ref<InputEvent> &p_event) {
|
||||
ERR_FAIL_COND(p_event.is_null());
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (mm.is_valid()) {
|
||||
Point2 pos = mm->get_position();
|
||||
|
||||
// Redraw when inside the tabbar and just exited.
|
||||
if (mouse_inside_tabbar) {
|
||||
queue_redraw();
|
||||
}
|
||||
mouse_inside_tabbar = drop_tabbar->get_rect().has_point(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDockDragHint::set_slot(DockTabContainer *p_slot) {
|
||||
dock_container = p_slot;
|
||||
drop_tabbar = p_slot->get_tab_bar();
|
||||
}
|
||||
|
||||
void EditorDockDragHint::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
||||
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/theme")) {
|
||||
dock_drop_highlight->set_corner_radius_all(EDSCALE * EDITOR_GET("interface/theme/corner_radius").operator int());
|
||||
if (mouse_inside) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
valid_drop_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_MOUSE_ENTER:
|
||||
case NOTIFICATION_MOUSE_EXIT: {
|
||||
mouse_inside = p_what == NOTIFICATION_MOUSE_ENTER;
|
||||
queue_redraw();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAG_BEGIN: {
|
||||
EditorDock *dragged_dock = EditorDockManager::get_singleton()->_get_dock_tab_dragged();
|
||||
if (!dragged_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
can_drop_dock = dragged_dock->get_available_layouts() & dock_container->layout;
|
||||
|
||||
dock_drop_highlight->set_border_color(valid_drop_color);
|
||||
dock_drop_highlight->set_bg_color(valid_drop_color * Color(1, 1, 1, 0.1));
|
||||
} break;
|
||||
case NOTIFICATION_DRAG_END: {
|
||||
EditorDockManager::get_singleton()->_dock_drag_stopped();
|
||||
can_drop_dock = false;
|
||||
mouse_inside = false;
|
||||
hide();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (!mouse_inside || !can_drop_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw highlights around docks that can be dropped.
|
||||
Rect2 dock_rect = Rect2(Point2(), get_size()).grow(2 * EDSCALE);
|
||||
draw_style_box(dock_drop_highlight, dock_rect);
|
||||
|
||||
// Only display tabbar hint if the mouse is over the tabbar.
|
||||
if (drop_tabbar->get_global_rect().has_point(get_global_mouse_position())) {
|
||||
draw_set_transform(drop_tabbar->get_position()); // The TabBar isn't always on top.
|
||||
drop_tabbar->_draw_tab_drop(get_canvas_item());
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorDockDragHint::EditorDockDragHint() {
|
||||
set_as_top_level(true);
|
||||
hide();
|
||||
|
||||
dock_drop_highlight.instantiate();
|
||||
dock_drop_highlight->set_corner_radius_all(EDSCALE * EDITOR_GET("interface/theme/corner_radius").operator int());
|
||||
dock_drop_highlight->set_border_width_all(Math::round(2 * EDSCALE));
|
||||
}
|
||||
|
||||
void DockTabContainer::_pre_popup() {
|
||||
dock_context_popup->set_dock(get_dock(get_current_tab()));
|
||||
}
|
||||
|
||||
void DockTabContainer::_tab_rmb_clicked(int p_tab_idx) {
|
||||
EditorDock *hovered_dock = get_dock(p_tab_idx);
|
||||
if (!hovered_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Right click context menu.
|
||||
dock_context_popup->set_dock(hovered_dock);
|
||||
dock_context_popup->set_position(get_tab_bar()->get_screen_position() + get_tab_bar()->get_local_mouse_position());
|
||||
dock_context_popup->popup();
|
||||
}
|
||||
|
||||
void DockTabContainer::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_POSTINITIALIZE) {
|
||||
connect("pre_popup_pressed", callable_mp(this, &DockTabContainer::_pre_popup));
|
||||
connect("child_order_changed", callable_mp(this, &DockTabContainer::update_visibility));
|
||||
}
|
||||
}
|
||||
|
||||
void DockTabContainer::update_visibility() {
|
||||
// Hide the dock container if there are no tabs.
|
||||
set_visible(EditorDockManager::get_singleton()->are_docks_visible() && get_tab_count() > 0);
|
||||
}
|
||||
|
||||
DockTabContainer::TabStyle DockTabContainer::get_tab_style() const {
|
||||
return (TabStyle)EDITOR_GET("interface/editor/dock_tab_style").operator int();
|
||||
}
|
||||
|
||||
bool DockTabContainer::can_switch_dock() const {
|
||||
return EditorDockManager::get_singleton()->are_docks_visible();
|
||||
}
|
||||
|
||||
void DockTabContainer::save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) {
|
||||
PackedStringArray names;
|
||||
names.reserve_exact(get_tab_count());
|
||||
for (int i = 0; i < get_tab_count(); i++) {
|
||||
const String name = get_dock(i)->get_effective_layout_key();
|
||||
names.append(name);
|
||||
}
|
||||
|
||||
const String config_key = DockTabContainer::get_config_key(dock_slot);
|
||||
if (!names.is_empty()) {
|
||||
p_layout->set_value(p_section, config_key, String(",").join(names));
|
||||
} else if (p_layout->has_section_key(p_section, config_key)) {
|
||||
p_layout->erase_section_key(p_section, config_key);
|
||||
}
|
||||
|
||||
const String tab_key = config_key + "_selected_tab_idx";
|
||||
int selected_tab_idx = get_current_tab();
|
||||
if (selected_tab_idx >= 0) {
|
||||
p_layout->set_value(p_section, tab_key, selected_tab_idx);
|
||||
} else if (p_layout->has_section_key(p_section, tab_key)) {
|
||||
p_layout->erase_section_key(p_section, tab_key);
|
||||
}
|
||||
}
|
||||
|
||||
void DockTabContainer::load_selected_tab(int p_idx) {
|
||||
EditorDock *selected_dock = get_dock(p_idx);
|
||||
if (!selected_dock) {
|
||||
return;
|
||||
}
|
||||
set_block_signals(true);
|
||||
set_current_tab(p_idx);
|
||||
set_block_signals(false);
|
||||
}
|
||||
|
||||
void DockTabContainer::set_dock_context_popup(DockContextPopup *p_popup) {
|
||||
dock_context_popup = p_popup;
|
||||
set_popup(dock_context_popup);
|
||||
}
|
||||
|
||||
void DockTabContainer::move_dock_index(EditorDock *p_dock, int p_to_index, bool p_set_current) {
|
||||
set_block_signals(true);
|
||||
int target_index = CLAMP(p_to_index, 0, get_tab_count() - 1);
|
||||
move_child(p_dock, get_dock(target_index)->get_index(false));
|
||||
|
||||
if (p_set_current) {
|
||||
set_current_tab(target_index);
|
||||
}
|
||||
set_block_signals(false);
|
||||
}
|
||||
|
||||
EditorDock *DockTabContainer::get_dock(int p_idx) const {
|
||||
return Object::cast_to<EditorDock>(get_tab_control(p_idx));
|
||||
}
|
||||
|
||||
void DockTabContainer::show_drag_hint() {
|
||||
if (!is_visible_in_tree()) {
|
||||
return;
|
||||
}
|
||||
drag_hint->set_rect(get_global_rect());
|
||||
drag_hint->show();
|
||||
}
|
||||
|
||||
DockTabContainer::DockTabContainer(EditorDock::DockSlot p_slot) {
|
||||
ERR_FAIL_INDEX(p_slot, EditorDock::DOCK_SLOT_MAX);
|
||||
dock_slot = p_slot;
|
||||
|
||||
set_drag_to_rearrange_enabled(true);
|
||||
set_tabs_rearrange_group(1);
|
||||
hide();
|
||||
|
||||
drag_hint = memnew(EditorDockDragHint);
|
||||
drag_hint->set_slot(this);
|
||||
drag_hint->hide();
|
||||
EditorNode::get_singleton()->get_gui_base()->add_child(drag_hint);
|
||||
|
||||
get_tab_bar()->set_switch_on_release(true);
|
||||
get_tab_bar()->connect("tab_rmb_clicked", callable_mp(this, &DockTabContainer::_tab_rmb_clicked));
|
||||
}
|
||||
|
||||
SideDockTabContainer::SideDockTabContainer(EditorDock::DockSlot p_slot) :
|
||||
DockTabContainer(p_slot) {
|
||||
set_custom_minimum_size(Size2(170 * EDSCALE, 0));
|
||||
set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
set_use_hidden_tabs_for_min_size(true);
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/**************************************************************************/
|
||||
/* dock_tab_container.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "editor/docks/editor_dock.h"
|
||||
#include "scene/gui/tab_container.h"
|
||||
|
||||
class ConfigFile;
|
||||
class DockContextPopup;
|
||||
class DockTabContainer;
|
||||
class EditorDockManager;
|
||||
class StyleBoxFlat;
|
||||
|
||||
class EditorDockDragHint : public Control {
|
||||
GDCLASS(EditorDockDragHint, Control);
|
||||
|
||||
DockTabContainer *dock_container = nullptr;
|
||||
TabBar *drop_tabbar = nullptr;
|
||||
|
||||
Color valid_drop_color;
|
||||
Ref<StyleBoxFlat> dock_drop_highlight;
|
||||
bool can_drop_dock = false;
|
||||
bool mouse_inside = false;
|
||||
bool mouse_inside_tabbar = false;
|
||||
|
||||
void _drag_move_tab(int p_from_index, int p_to_index);
|
||||
void _drag_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index);
|
||||
|
||||
protected:
|
||||
virtual void gui_input(const Ref<InputEvent> &p_event) override;
|
||||
|
||||
void _notification(int p_what);
|
||||
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
|
||||
virtual void drop_data(const Point2 &p_point, const Variant &p_data) override;
|
||||
|
||||
public:
|
||||
void set_slot(DockTabContainer *p_slot);
|
||||
|
||||
EditorDockDragHint();
|
||||
};
|
||||
|
||||
class DockTabContainer : public TabContainer {
|
||||
GDCLASS(DockTabContainer, TabContainer);
|
||||
|
||||
EditorDockDragHint *drag_hint = nullptr;
|
||||
|
||||
void _pre_popup();
|
||||
void _tab_rmb_clicked(int p_tab_idx);
|
||||
|
||||
protected:
|
||||
DockContextPopup *dock_context_popup = nullptr;
|
||||
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
enum class TabStyle {
|
||||
TEXT_ONLY,
|
||||
ICON_ONLY,
|
||||
TEXT_AND_ICON,
|
||||
};
|
||||
|
||||
EditorDock::DockSlot dock_slot = EditorDock::DOCK_SLOT_NONE;
|
||||
EditorDock::DockLayout layout = EditorDock::DOCK_LAYOUT_VERTICAL;
|
||||
|
||||
static String get_config_key(int p_idx) { return "dock_" + itos(p_idx + 1); }
|
||||
|
||||
virtual void dock_closed(EditorDock *p_dock) {}
|
||||
virtual void dock_focused(EditorDock *p_dock, bool p_was_visible) {}
|
||||
virtual void update_visibility();
|
||||
virtual TabStyle get_tab_style() const;
|
||||
virtual bool can_switch_dock() const;
|
||||
|
||||
// There is no equivalent load method, because loading needs to handle floating and closing.
|
||||
void save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section);
|
||||
virtual void load_selected_tab(int p_idx);
|
||||
|
||||
// This method should only be called by EditorDock.
|
||||
void move_dock_index(EditorDock *p_dock, int p_to_index, bool p_set_current);
|
||||
|
||||
void set_dock_context_popup(DockContextPopup *p_popup);
|
||||
EditorDock *get_dock(int p_idx) const;
|
||||
void show_drag_hint();
|
||||
|
||||
DockTabContainer(EditorDock::DockSlot p_slot);
|
||||
};
|
||||
|
||||
class SideDockTabContainer : public DockTabContainer {
|
||||
GDCLASS(SideDockTabContainer, DockTabContainer);
|
||||
|
||||
public:
|
||||
SideDockTabContainer(EditorDock::DockSlot p_slot);
|
||||
};
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/input/shortcut.h"
|
||||
#include "core/io/config_file.h"
|
||||
#include "editor/docks/dock_tab_container.h"
|
||||
#include "editor/docks/editor_dock_manager.h"
|
||||
|
||||
void EditorDock::_set_default_slot_bind(DockSlot p_slot) {
|
||||
|
|
@ -49,6 +50,14 @@ void EditorDock::_notification(int p_what) {
|
|||
set_accessibility_region(true);
|
||||
set_accessibility_name(get_display_title());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PARENTED: {
|
||||
parent_dock_container = Object::cast_to<DockTabContainer>(get_parent());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNPARENTED: {
|
||||
parent_dock_container = nullptr;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +149,10 @@ void EditorDock::make_visible() {
|
|||
EditorDockManager::get_singleton()->open_dock(this, true);
|
||||
}
|
||||
|
||||
void EditorDock::make_floating() {
|
||||
EditorDockManager::get_singleton()->make_dock_floating(this);
|
||||
}
|
||||
|
||||
void EditorDock::close() {
|
||||
if (is_open) {
|
||||
EditorDockManager::get_singleton()->close_dock(this);
|
||||
|
|
@ -242,3 +255,62 @@ String EditorDock::get_display_title() const {
|
|||
String EditorDock::get_effective_layout_key() const {
|
||||
return layout_key.is_empty() ? get_display_title() : layout_key;
|
||||
}
|
||||
|
||||
void EditorDock::set_tab_index(int p_index, bool p_set_current) {
|
||||
parent_dock_container->move_dock_index(this, p_index, p_set_current);
|
||||
previous_tab_index = parent_dock_container->get_tab_idx_from_control(this);
|
||||
}
|
||||
|
||||
void EditorDock::update_tab_style() {
|
||||
if (!enabled || !is_open) {
|
||||
return; // Disabled by feature profile or manually closed by user.
|
||||
}
|
||||
if (dock_window) {
|
||||
return; // Floating.
|
||||
}
|
||||
|
||||
ERR_FAIL_NULL(parent_dock_container);
|
||||
|
||||
int index = parent_dock_container->get_tab_idx_from_control(this);
|
||||
ERR_FAIL_COND(index == -1);
|
||||
|
||||
parent_dock_container->get_tab_bar()->set_font_color_override_all(index, title_color);
|
||||
|
||||
const Ref<Texture2D> icon = get_effective_icon(callable_mp((Control *)this, &Control::get_editor_theme_icon));
|
||||
bool assign_icon = force_show_icon;
|
||||
String tooltip;
|
||||
switch (parent_dock_container->get_tab_style()) {
|
||||
case DockTabContainer::TabStyle::TEXT_ONLY: {
|
||||
parent_dock_container->set_tab_title(index, get_display_title());
|
||||
} break;
|
||||
case DockTabContainer::TabStyle::ICON_ONLY: {
|
||||
parent_dock_container->set_tab_title(index, icon.is_valid() ? String() : get_display_title());
|
||||
tooltip = TTR(get_display_title());
|
||||
assign_icon = true;
|
||||
} break;
|
||||
case DockTabContainer::TabStyle::TEXT_AND_ICON: {
|
||||
parent_dock_container->set_tab_title(index, get_display_title());
|
||||
parent_dock_container->set_tab_tooltip(index, String());
|
||||
assign_icon = true;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (shortcut.is_valid() && shortcut->has_valid_event()) {
|
||||
tooltip += (tooltip.is_empty() ? "" : "\n") + TTR(shortcut->get_name()) + " (" + shortcut->get_as_text() + ")";
|
||||
}
|
||||
parent_dock_container->set_tab_tooltip(index, tooltip);
|
||||
|
||||
if (assign_icon) {
|
||||
parent_dock_container->set_tab_icon(index, icon);
|
||||
} else {
|
||||
parent_dock_container->set_tab_icon(index, Ref<Texture2D>());
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Texture2D> EditorDock::get_effective_icon(const Callable &p_icon_fetch) {
|
||||
Ref<Texture2D> icon = dock_icon;
|
||||
if (icon.is_null() && !icon_name.is_empty()) {
|
||||
icon = p_icon_fetch.call(icon_name);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "core/io/config_file.h"
|
||||
#include "scene/gui/margin_container.h"
|
||||
|
||||
class DockTabContainer;
|
||||
class Shortcut;
|
||||
class WindowWrapper;
|
||||
|
||||
|
|
@ -85,6 +86,7 @@ private:
|
|||
bool enabled = true;
|
||||
int previous_tab_index = -1;
|
||||
WindowWrapper *dock_window = nullptr;
|
||||
DockTabContainer *parent_dock_container = nullptr;
|
||||
int dock_slot_index = DOCK_SLOT_NONE;
|
||||
|
||||
void _set_default_slot_bind(DockSlot p_slot);
|
||||
|
|
@ -103,6 +105,7 @@ protected:
|
|||
public:
|
||||
void open();
|
||||
void make_visible();
|
||||
void make_floating();
|
||||
void close();
|
||||
|
||||
void set_title(const String &p_title);
|
||||
|
|
@ -144,6 +147,11 @@ public:
|
|||
String get_display_title() const;
|
||||
String get_effective_layout_key() const;
|
||||
|
||||
DockTabContainer *get_parent_container() const { return parent_dock_container; }
|
||||
void set_tab_index(int p_index, bool p_set_current);
|
||||
void update_tab_style();
|
||||
Ref<Texture2D> get_effective_icon(const Callable &p_icon_fetch);
|
||||
|
||||
virtual void update_layout(DockLayout p_layout) { GDVIRTUAL_CALL(_update_layout, p_layout); }
|
||||
DockLayout get_current_layout() const { return current_layout; }
|
||||
|
||||
|
|
|
|||
|
|
@ -37,135 +37,13 @@
|
|||
#include "scene/gui/tab_container.h"
|
||||
#include "scene/main/window.h"
|
||||
|
||||
#include "editor/docks/dock_tab_container.h"
|
||||
#include "editor/docks/editor_dock.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/gui/editor_bottom_panel.h"
|
||||
#include "editor/gui/window_wrapper.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/resources/style_box_flat.h"
|
||||
|
||||
enum class TabStyle {
|
||||
TEXT_ONLY,
|
||||
ICON_ONLY,
|
||||
TEXT_AND_ICON,
|
||||
};
|
||||
|
||||
static inline Ref<Texture2D> _get_dock_icon(const EditorDock *p_dock, const Callable &p_icon_fetch) {
|
||||
Ref<Texture2D> icon = p_dock->get_dock_icon();
|
||||
if (icon.is_null() && !p_dock->get_icon_name().is_empty()) {
|
||||
icon = p_icon_fetch.call(p_dock->get_icon_name());
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
bool EditorDockDragHint::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
|
||||
return can_drop_dock;
|
||||
}
|
||||
|
||||
void EditorDockDragHint::drop_data(const Point2 &p_point, const Variant &p_data) {
|
||||
// Drop dock into last spot if not over tabbar.
|
||||
if (drop_tabbar->get_rect().has_point(p_point)) {
|
||||
drop_tabbar->_handle_drop_data("tab_container_tab", p_point, p_data, callable_mp(this, &EditorDockDragHint::_drag_move_tab), callable_mp(this, &EditorDockDragHint::_drag_move_tab_from));
|
||||
} else {
|
||||
dock_manager->_move_dock(dock_manager->_get_dock_tab_dragged(), dock_manager->dock_slots[occupied_slot].container, drop_tabbar->get_tab_count());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDockDragHint::_drag_move_tab(int p_from_index, int p_to_index) {
|
||||
dock_manager->_move_dock_tab_index(dock_manager->_get_dock_tab_dragged(), p_to_index, true);
|
||||
}
|
||||
|
||||
void EditorDockDragHint::_drag_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index) {
|
||||
dock_manager->_move_dock(dock_manager->_get_dock_tab_dragged(), dock_manager->dock_slots[occupied_slot].container, p_to_index);
|
||||
}
|
||||
|
||||
void EditorDockDragHint::gui_input(const Ref<InputEvent> &p_event) {
|
||||
ERR_FAIL_COND(p_event.is_null());
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (mm.is_valid()) {
|
||||
Point2 pos = mm->get_position();
|
||||
|
||||
// Redraw when inside the tabbar and just exited.
|
||||
if (mouse_inside_tabbar) {
|
||||
queue_redraw();
|
||||
}
|
||||
mouse_inside_tabbar = drop_tabbar->get_rect().has_point(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDockDragHint::set_slot(EditorDock::DockSlot p_slot) {
|
||||
occupied_slot = p_slot;
|
||||
drop_tabbar = dock_manager->dock_slots[occupied_slot].container->get_tab_bar();
|
||||
}
|
||||
|
||||
void EditorDockDragHint::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
||||
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/theme")) {
|
||||
dock_drop_highlight->set_corner_radius_all(EDSCALE * EDITOR_GET("interface/theme/corner_radius").operator int());
|
||||
if (mouse_inside) {
|
||||
queue_redraw();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
valid_drop_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_MOUSE_ENTER:
|
||||
case NOTIFICATION_MOUSE_EXIT: {
|
||||
mouse_inside = p_what == NOTIFICATION_MOUSE_ENTER;
|
||||
queue_redraw();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAG_BEGIN: {
|
||||
EditorDock *dragged_dock = dock_manager->_get_dock_tab_dragged();
|
||||
if (!dragged_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
can_drop_dock = dragged_dock->get_available_layouts() & EditorDockManager::get_singleton()->dock_slots[occupied_slot].layout;
|
||||
|
||||
dock_drop_highlight->set_border_color(valid_drop_color);
|
||||
dock_drop_highlight->set_bg_color(valid_drop_color * Color(1, 1, 1, 0.1));
|
||||
} break;
|
||||
case NOTIFICATION_DRAG_END: {
|
||||
dock_manager->_dock_drag_stopped();
|
||||
can_drop_dock = false;
|
||||
mouse_inside = false;
|
||||
hide();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (!mouse_inside || !can_drop_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw highlights around docks that can be dropped.
|
||||
Rect2 dock_rect = Rect2(Point2(), get_size()).grow(2 * EDSCALE);
|
||||
draw_style_box(dock_drop_highlight, dock_rect);
|
||||
|
||||
// Only display tabbar hint if the mouse is over the tabbar.
|
||||
if (drop_tabbar->get_global_rect().has_point(get_global_mouse_position())) {
|
||||
draw_set_transform(drop_tabbar->get_position()); // The TabBar isn't always on top.
|
||||
drop_tabbar->_draw_tab_drop(get_canvas_item());
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorDockDragHint::EditorDockDragHint() {
|
||||
dock_manager = EditorDockManager::get_singleton();
|
||||
|
||||
set_as_top_level(true);
|
||||
dock_drop_highlight.instantiate();
|
||||
dock_drop_highlight->set_corner_radius_all(EDSCALE * EDITOR_GET("interface/theme/corner_radius").operator int());
|
||||
dock_drop_highlight->set_border_width_all(Math::round(2 * EDSCALE));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////
|
||||
|
|
@ -246,7 +124,7 @@ EditorDock *EditorDockManager::_get_dock_tab_dragged() {
|
|||
return dock_tab_dragged;
|
||||
}
|
||||
|
||||
Dictionary dock_drop_data = dock_slots[EditorDock::DOCK_SLOT_LEFT_BL].container->get_viewport()->gui_get_drag_data();
|
||||
Dictionary dock_drop_data = EditorNode::get_singleton()->get_viewport()->gui_get_drag_data();
|
||||
|
||||
// Check if we are dragging a dock.
|
||||
if (dock_drop_data.get("type", "").operator String() != "tab") {
|
||||
|
|
@ -260,21 +138,18 @@ EditorDock *EditorDockManager::_get_dock_tab_dragged() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
TabContainer *source_tab_container = Object::cast_to<TabContainer>(source_tab_bar->get_parent());
|
||||
DockTabContainer *source_tab_container = Object::cast_to<DockTabContainer>(source_tab_bar->get_parent());
|
||||
if (!source_tab_container) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dock_tab_dragged = Object::cast_to<EditorDock>(source_tab_container->get_tab_control(dock_drop_data["tab_index"]));
|
||||
dock_tab_dragged = source_tab_container->get_dock(dock_drop_data["tab_index"]);
|
||||
if (!dock_tab_dragged) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_MAX; i++) {
|
||||
if (dock_slots[i].container->is_visible_in_tree()) {
|
||||
dock_slots[i].drag_hint->set_rect(dock_slots[i].container->get_global_rect());
|
||||
dock_slots[i].drag_hint->show();
|
||||
}
|
||||
dock_slots[i]->show_drag_hint();
|
||||
}
|
||||
|
||||
return dock_tab_dragged;
|
||||
|
|
@ -290,26 +165,6 @@ void EditorDockManager::_dock_split_dragged(int p_offset) {
|
|||
EditorNode::get_singleton()->save_editor_layout_delayed();
|
||||
}
|
||||
|
||||
void EditorDockManager::_dock_container_popup(int p_tab_idx, TabContainer *p_dock_container) {
|
||||
EditorDock *hovered_dock = Object::cast_to<EditorDock>(p_dock_container->get_tab_control(p_tab_idx));
|
||||
if (hovered_dock == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Right click context menu.
|
||||
dock_context_popup->set_dock(hovered_dock);
|
||||
dock_context_popup->set_position(p_dock_container->get_tab_bar()->get_screen_position() + p_dock_container->get_tab_bar()->get_local_mouse_position());
|
||||
dock_context_popup->popup();
|
||||
}
|
||||
|
||||
void EditorDockManager::_dock_container_update_visibility(TabContainer *p_dock_container) {
|
||||
if (!docks_visible) {
|
||||
return;
|
||||
}
|
||||
// Hide the dock container if there are no tabs.
|
||||
p_dock_container->set_visible(p_dock_container->get_tab_count() > 0);
|
||||
}
|
||||
|
||||
void EditorDockManager::_update_layout() {
|
||||
if (!dock_context_popup->is_inside_tree() || EditorNode::get_singleton()->is_exiting()) {
|
||||
return;
|
||||
|
|
@ -346,7 +201,7 @@ void EditorDockManager::update_docks_menu() {
|
|||
}
|
||||
docks_menu->set_item_icon_max_width(id, icon_max_width);
|
||||
|
||||
const Ref<Texture2D> icon = _get_dock_icon(dock, icon_fetch);
|
||||
const Ref<Texture2D> icon = dock->get_effective_icon(icon_fetch);
|
||||
docks_menu->set_item_icon(id, icon.is_valid() ? icon : default_icon);
|
||||
if (!dock->is_open) {
|
||||
docks_menu->set_item_icon_modulate(id, closed_icon_color_mod);
|
||||
|
|
@ -378,7 +233,6 @@ void EditorDockManager::_window_close_request(WindowWrapper *p_wrapper) {
|
|||
|
||||
if (dock->dock_slot_index != EditorDock::DOCK_SLOT_NONE) {
|
||||
dock->is_open = false;
|
||||
open_dock(dock);
|
||||
focus_dock(dock);
|
||||
} else {
|
||||
close_dock(dock);
|
||||
|
|
@ -447,23 +301,6 @@ void EditorDockManager::_restore_dock_to_saved_window(EditorDock *p_dock, const
|
|||
p_window_dump.get("window_screen_rect", Rect2i()));
|
||||
}
|
||||
|
||||
void EditorDockManager::_move_dock_tab_index(EditorDock *p_dock, int p_tab_index, bool p_set_current) {
|
||||
TabContainer *dock_tab_container = Object::cast_to<TabContainer>(p_dock->get_parent());
|
||||
if (!dock_tab_container) {
|
||||
return;
|
||||
}
|
||||
|
||||
dock_tab_container->set_block_signals(true);
|
||||
int target_index = CLAMP(p_tab_index, 0, dock_tab_container->get_tab_count() - 1);
|
||||
dock_tab_container->move_child(p_dock, dock_tab_container->get_tab_control(target_index)->get_index(false));
|
||||
p_dock->previous_tab_index = target_index;
|
||||
|
||||
if (p_set_current) {
|
||||
dock_tab_container->set_current_tab(target_index);
|
||||
}
|
||||
dock_tab_container->set_block_signals(false);
|
||||
}
|
||||
|
||||
void EditorDockManager::_move_dock(EditorDock *p_dock, Control *p_target, int p_tab_index, bool p_set_current) {
|
||||
ERR_FAIL_NULL(p_dock);
|
||||
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot move unknown dock '%s'.", p_dock->get_display_title()));
|
||||
|
|
@ -472,7 +309,7 @@ void EditorDockManager::_move_dock(EditorDock *p_dock, Control *p_target, int p_
|
|||
if (parent == p_target) {
|
||||
if (parent && p_tab_index >= 0) {
|
||||
// Only change the tab index.
|
||||
_move_dock_tab_index(p_dock, p_tab_index, p_set_current);
|
||||
p_dock->set_tab_index(p_tab_index, p_set_current);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -482,7 +319,7 @@ void EditorDockManager::_move_dock(EditorDock *p_dock, Control *p_target, int p_
|
|||
if (p_dock->dock_window) {
|
||||
_close_window(p_dock->dock_window);
|
||||
} else {
|
||||
TabContainer *parent_tabs = Object::cast_to<TabContainer>(parent);
|
||||
DockTabContainer *parent_tabs = Object::cast_to<DockTabContainer>(parent);
|
||||
if (parent_tabs) {
|
||||
p_dock->previous_tab_index = parent_tabs->get_tab_idx_from_control(p_dock);
|
||||
}
|
||||
|
|
@ -490,7 +327,7 @@ void EditorDockManager::_move_dock(EditorDock *p_dock, Control *p_target, int p_
|
|||
parent->remove_child(p_dock);
|
||||
parent->set_block_signals(false);
|
||||
if (parent_tabs) {
|
||||
_dock_container_update_visibility(parent_tabs);
|
||||
parent_tabs->update_visibility();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -499,13 +336,13 @@ void EditorDockManager::_move_dock(EditorDock *p_dock, Control *p_target, int p_
|
|||
return;
|
||||
}
|
||||
|
||||
DockTabContainer *dock_tab_container = Object::cast_to<DockTabContainer>(p_target);
|
||||
if (p_target != closed_dock_parent) {
|
||||
EditorDock::DockLayout layout = p_target->get_meta("dock_layout");
|
||||
if (layout != p_dock->current_layout) {
|
||||
p_dock->update_layout(layout);
|
||||
p_dock->current_layout = layout;
|
||||
if (dock_tab_container->layout != p_dock->current_layout) {
|
||||
p_dock->update_layout(dock_tab_container->layout);
|
||||
p_dock->current_layout = dock_tab_container->layout;
|
||||
}
|
||||
p_dock->dock_slot_index = p_target->get_meta("dock_slot");
|
||||
p_dock->dock_slot_index = dock_tab_container->dock_slot;
|
||||
}
|
||||
|
||||
// Add dock to its new parent, at the given tab index.
|
||||
|
|
@ -513,15 +350,14 @@ void EditorDockManager::_move_dock(EditorDock *p_dock, Control *p_target, int p_
|
|||
p_target->add_child(p_dock);
|
||||
p_target->set_block_signals(false);
|
||||
|
||||
TabContainer *dock_tab_container = Object::cast_to<TabContainer>(p_target);
|
||||
if (dock_tab_container) {
|
||||
if (dock_tab_container->is_inside_tree()) {
|
||||
_update_tab_style(p_dock);
|
||||
p_dock->update_tab_style();
|
||||
}
|
||||
if (p_tab_index >= 0) {
|
||||
_move_dock_tab_index(p_dock, p_tab_index, p_set_current);
|
||||
p_dock->set_tab_index(p_tab_index, p_set_current);
|
||||
}
|
||||
_dock_container_update_visibility(dock_tab_container);
|
||||
dock_tab_container->update_visibility();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -536,7 +372,7 @@ void EditorDockManager::_update_dirty_dock_tabs() {
|
|||
bool update_menu = false;
|
||||
for (EditorDock *dock : dirty_docks) {
|
||||
update_menu = update_menu || dock->global;
|
||||
_update_tab_style(dock);
|
||||
dock->update_tab_style();
|
||||
}
|
||||
dirty_docks.clear();
|
||||
|
||||
|
|
@ -545,85 +381,10 @@ void EditorDockManager::_update_dirty_dock_tabs() {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorDockManager::_update_tab_style(EditorDock *p_dock) {
|
||||
if (!p_dock->enabled || !p_dock->is_open) {
|
||||
return; // Disabled by feature profile or manually closed by user.
|
||||
}
|
||||
if (p_dock->dock_window) {
|
||||
return; // Floating.
|
||||
}
|
||||
|
||||
TabContainer *tab_container = get_dock_tab_container(p_dock);
|
||||
ERR_FAIL_NULL(tab_container);
|
||||
|
||||
int index = tab_container->get_tab_idx_from_control(p_dock);
|
||||
ERR_FAIL_COND(index == -1);
|
||||
|
||||
tab_container->get_tab_bar()->set_font_color_override_all(index, p_dock->title_color);
|
||||
|
||||
const TabStyle style = (tab_container == EditorNode::get_bottom_panel())
|
||||
? (TabStyle)EDITOR_GET("interface/editor/bottom_dock_tab_style").operator int()
|
||||
: (TabStyle)EDITOR_GET("interface/editor/dock_tab_style").operator int();
|
||||
|
||||
const Ref<Texture2D> icon = _get_dock_icon(p_dock, callable_mp((Control *)tab_container, &Control::get_editor_theme_icon));
|
||||
bool assign_icon = p_dock->force_show_icon;
|
||||
String tooltip;
|
||||
switch (style) {
|
||||
case TabStyle::TEXT_ONLY: {
|
||||
tab_container->set_tab_title(index, p_dock->get_display_title());
|
||||
} break;
|
||||
case TabStyle::ICON_ONLY: {
|
||||
tab_container->set_tab_title(index, icon.is_valid() ? String() : p_dock->get_display_title());
|
||||
tooltip = TTR(p_dock->get_display_title());
|
||||
assign_icon = true;
|
||||
} break;
|
||||
case TabStyle::TEXT_AND_ICON: {
|
||||
tab_container->set_tab_title(index, p_dock->get_display_title());
|
||||
assign_icon = true;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (p_dock->shortcut.is_valid() && p_dock->shortcut->has_valid_event()) {
|
||||
tooltip += (tooltip.is_empty() ? "" : "\n") + TTR(p_dock->shortcut->get_name()) + " (" + p_dock->shortcut->get_as_text() + ")";
|
||||
}
|
||||
tab_container->set_tab_tooltip(index, tooltip);
|
||||
|
||||
if (assign_icon) {
|
||||
tab_container->set_tab_icon(index, icon);
|
||||
} else {
|
||||
tab_container->set_tab_icon(index, Ref<Texture2D>());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) const {
|
||||
// Save docks by dock slot.
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_MAX; i++) {
|
||||
const DockSlot &dock_slot = dock_slots[i];
|
||||
|
||||
PackedStringArray names;
|
||||
names.reserve_exact(dock_slot.container->get_tab_count());
|
||||
for (int j = 0; j < dock_slot.container->get_tab_count(); j++) {
|
||||
const String name = Object::cast_to<EditorDock>(dock_slot.container->get_tab_control(j))->get_effective_layout_key();
|
||||
names.append(name);
|
||||
}
|
||||
|
||||
const String config_key = "dock_" + itos(i + 1);
|
||||
if (p_layout->has_section_key(p_section, config_key)) {
|
||||
p_layout->erase_section_key(p_section, config_key);
|
||||
}
|
||||
|
||||
if (!names.is_empty()) {
|
||||
p_layout->set_value(p_section, config_key, String(",").join(names));
|
||||
}
|
||||
|
||||
const String tab_key = config_key + "_selected_tab_idx";
|
||||
|
||||
int selected_tab_idx = dock_slots[i].container->get_current_tab();
|
||||
if (selected_tab_idx >= 0) {
|
||||
p_layout->set_value(p_section, tab_key, selected_tab_idx);
|
||||
} else if (p_layout->has_section_key(p_section, tab_key)) {
|
||||
p_layout->erase_section_key(p_section, tab_key);
|
||||
}
|
||||
dock_slots[i]->save_docks_to_config(p_layout, p_section);
|
||||
}
|
||||
|
||||
// Clear the special dock slot for docks without default slots (index -1 = dock_0).
|
||||
|
|
@ -652,7 +413,7 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
|
|||
|
||||
// Append to regular dock section so we know where to restore it to.
|
||||
int dock_slot_id = dock->dock_slot_index;
|
||||
String config_key = "dock_" + itos(dock_slot_id + 1);
|
||||
String config_key = DockTabContainer::get_config_key(dock_slot_id);
|
||||
|
||||
String names = p_layout->get_value(p_section, config_key, "");
|
||||
if (names.is_empty()) {
|
||||
|
|
@ -664,7 +425,6 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
|
|||
}
|
||||
p_layout->set_value(p_section, "dock_floating", floating_docks_dump);
|
||||
|
||||
// Save closed docks.
|
||||
Array closed_docks_dump;
|
||||
for (const EditorDock *dock : all_docks) {
|
||||
const String section_name = p_section + "/" + dock->get_effective_layout_key();
|
||||
|
|
@ -674,13 +434,14 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
|
|||
continue;
|
||||
}
|
||||
|
||||
// Save closed docks.
|
||||
const String name = dock->get_effective_layout_key();
|
||||
if (!dock->is_open && !dock->transient) {
|
||||
if (!dock->transient) {
|
||||
closed_docks_dump.push_back(name);
|
||||
}
|
||||
|
||||
int dock_slot_id = dock->dock_slot_index;
|
||||
String config_key = "dock_" + itos(dock_slot_id + 1);
|
||||
String config_key = DockTabContainer::get_config_key(dock_slot_id);
|
||||
|
||||
String names = p_layout->get_value(p_section, config_key, "");
|
||||
if (names.is_empty()) {
|
||||
|
|
@ -725,12 +486,12 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
|
|||
|
||||
// Load docks by slot. Index -1 is for docks that have no slot.
|
||||
for (int i = -1; i < EditorDock::DOCK_SLOT_MAX; i++) {
|
||||
if (!p_layout->has_section_key(p_section, "dock_" + itos(i + 1))) {
|
||||
const String key = DockTabContainer::get_config_key(i);
|
||||
if (!p_layout->has_section_key(p_section, key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<String> names = String(p_layout->get_value(p_section, "dock_" + itos(i + 1))).split(",");
|
||||
|
||||
Vector<String> names = String(p_layout->get_value(p_section, key)).split(",");
|
||||
for (int j = names.size() - 1; j >= 0; j--) {
|
||||
const String &name = names[j];
|
||||
const String section_name = p_section + "/" + name;
|
||||
|
|
@ -741,7 +502,7 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
|
|||
EditorDock *dock = dock_map[name];
|
||||
|
||||
if (!dock->enabled) {
|
||||
// Don't is_open disabled docks.
|
||||
// Don't open disabled docks.
|
||||
dock->load_layout_from_config(p_layout, section_name);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -756,7 +517,7 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
|
|||
_move_dock(dock, closed_dock_parent);
|
||||
} else {
|
||||
dock->is_open = true;
|
||||
_move_dock(dock, dock_slots[i].container, 0);
|
||||
_move_dock(dock, dock_slots[i], 0);
|
||||
}
|
||||
}
|
||||
dock->load_layout_from_config(p_layout, section_name);
|
||||
|
|
@ -768,23 +529,8 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
|
|||
|
||||
// Set the selected tabs.
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_MAX; i++) {
|
||||
const DockSlot &dock_slot = dock_slots[i];
|
||||
|
||||
int selected_tab_idx = p_layout->get_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx", -1);
|
||||
if (selected_tab_idx <= 0 || selected_tab_idx >= dock_slot.container->get_tab_count()) {
|
||||
if (i == EditorDock::DOCK_SLOT_BOTTOM) {
|
||||
dock_slot.container->set_current_tab(-1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
EditorDock *selected_dock = Object::cast_to<EditorDock>(dock_slot.container->get_tab_control(selected_tab_idx));
|
||||
if (!selected_dock) {
|
||||
continue;
|
||||
}
|
||||
dock_slot.container->set_block_signals(true);
|
||||
dock_slot.container->set_current_tab(selected_tab_idx);
|
||||
dock_slot.container->set_block_signals(false);
|
||||
int selected_tab_idx = p_layout->get_value(p_section, DockTabContainer::get_config_key(i) + "_selected_tab_idx", -1);
|
||||
dock_slots[i]->load_selected_tab(selected_tab_idx);
|
||||
}
|
||||
|
||||
// Load SplitContainer offsets.
|
||||
|
|
@ -832,11 +578,8 @@ void EditorDockManager::close_dock(EditorDock *p_dock) {
|
|||
}
|
||||
|
||||
p_dock->is_open = false;
|
||||
p_dock->get_parent_container()->dock_closed(p_dock);
|
||||
|
||||
EditorBottomPanel *bottom_panel = EditorNode::get_bottom_panel();
|
||||
if (get_dock_tab_container(p_dock) == bottom_panel && bottom_panel->get_current_tab_control() == p_dock) {
|
||||
bottom_panel->hide_bottom_panel();
|
||||
}
|
||||
// Hide before moving to remove inconsistent signals.
|
||||
p_dock->hide();
|
||||
_move_dock(p_dock, closed_dock_parent);
|
||||
|
|
@ -860,7 +603,7 @@ void EditorDockManager::open_dock(EditorDock *p_dock, bool p_set_current) {
|
|||
|
||||
// Open dock to its previous location.
|
||||
if (p_dock->dock_slot_index != EditorDock::DOCK_SLOT_NONE) {
|
||||
TabContainer *slot = dock_slots[p_dock->dock_slot_index].container;
|
||||
TabContainer *slot = dock_slots[p_dock->dock_slot_index];
|
||||
int tab_index = p_dock->previous_tab_index;
|
||||
if (tab_index < 0) {
|
||||
tab_index = slot->get_tab_count();
|
||||
|
|
@ -883,10 +626,6 @@ void EditorDockManager::make_dock_floating(EditorDock *p_dock) {
|
|||
}
|
||||
}
|
||||
|
||||
TabContainer *EditorDockManager::get_dock_tab_container(Control *p_dock) const {
|
||||
return Object::cast_to<TabContainer>(p_dock->get_parent());
|
||||
}
|
||||
|
||||
void EditorDockManager::_make_dock_visible(EditorDock *p_dock, bool p_grab_focus) {
|
||||
if (p_dock->dock_window) {
|
||||
if (p_grab_focus) {
|
||||
|
|
@ -895,23 +634,17 @@ void EditorDockManager::_make_dock_visible(EditorDock *p_dock, bool p_grab_focus
|
|||
return;
|
||||
}
|
||||
|
||||
if (p_dock->get_parent() == EditorNode::get_bottom_panel()) {
|
||||
if (EditorNode::get_bottom_panel()->is_locked()) {
|
||||
return;
|
||||
}
|
||||
} else if (!docks_visible) {
|
||||
DockTabContainer *tab_container = p_dock->get_parent_container();
|
||||
if (!tab_container || !tab_container->can_switch_dock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TabContainer *tab_container = get_dock_tab_container(p_dock);
|
||||
if (tab_container) {
|
||||
if (p_grab_focus) {
|
||||
tab_container->get_tab_bar()->grab_focus();
|
||||
}
|
||||
|
||||
int tab_index = tab_container->get_tab_idx_from_control(p_dock);
|
||||
tab_container->set_current_tab(tab_index);
|
||||
if (p_grab_focus) {
|
||||
tab_container->get_tab_bar()->grab_focus();
|
||||
}
|
||||
|
||||
int tab_index = tab_container->get_tab_idx_from_control(p_dock);
|
||||
tab_container->set_current_tab(tab_index);
|
||||
}
|
||||
|
||||
void EditorDockManager::focus_dock(EditorDock *p_dock) {
|
||||
|
|
@ -964,10 +697,9 @@ void EditorDockManager::set_docks_visible(bool p_show) {
|
|||
return;
|
||||
}
|
||||
docks_visible = p_show;
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_BOTTOM; i++) {
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_MAX; i++) {
|
||||
// Show and hide in reverse order due to the SplitContainer prioritizing the last split offset.
|
||||
TabContainer *container = dock_slots[docks_visible ? i : EditorDock::DOCK_SLOT_BOTTOM - i - 1].container;
|
||||
container->set_visible(docks_visible && container->get_tab_count() > 0);
|
||||
dock_slots[docks_visible ? i : EditorDock::DOCK_SLOT_MAX - i - 1]->update_visibility();
|
||||
}
|
||||
_update_layout();
|
||||
}
|
||||
|
|
@ -978,14 +710,13 @@ bool EditorDockManager::are_docks_visible() const {
|
|||
|
||||
void EditorDockManager::update_tab_styles() {
|
||||
for (EditorDock *dock : all_docks) {
|
||||
_update_tab_style(dock);
|
||||
dock->update_tab_style();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDockManager::set_tab_icon_max_width(int p_max_width) {
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_MAX; i++) {
|
||||
TabContainer *tab_container = dock_slots[i].container;
|
||||
tab_container->add_theme_constant_override(SNAME("icon_max_width"), p_max_width);
|
||||
dock_slots[i]->add_theme_constant_override(SNAME("icon_max_width"), p_max_width);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -999,40 +730,13 @@ void EditorDockManager::set_hsplit(DockSplitContainer *p_split) {
|
|||
p_split->connect("dragged", callable_mp(this, &EditorDockManager::_dock_split_dragged));
|
||||
}
|
||||
|
||||
void EditorDockManager::register_dock_slot(EditorDock::DockSlot p_dock_slot, TabContainer *p_tab_container, EditorDock::DockLayout p_layout) {
|
||||
void EditorDockManager::register_dock_slot(DockTabContainer *p_tab_container) {
|
||||
ERR_FAIL_NULL(p_tab_container);
|
||||
ERR_FAIL_INDEX(p_dock_slot, EditorDock::DOCK_SLOT_MAX);
|
||||
dock_slots[p_tab_container->dock_slot] = p_tab_container;
|
||||
|
||||
DockSlot slot;
|
||||
slot.layout = p_layout;
|
||||
|
||||
slot.container = p_tab_container;
|
||||
p_tab_container->set_popup(dock_context_popup);
|
||||
p_tab_container->connect("pre_popup_pressed", callable_mp(dock_context_popup, &DockContextPopup::select_current_dock_in_dock_slot).bind(p_dock_slot));
|
||||
p_tab_container->get_tab_bar()->set_switch_on_release(true);
|
||||
p_tab_container->get_tab_bar()->connect("tab_rmb_clicked", callable_mp(this, &EditorDockManager::_dock_container_popup).bind(p_tab_container));
|
||||
p_tab_container->set_drag_to_rearrange_enabled(true);
|
||||
p_tab_container->set_tabs_rearrange_group(1);
|
||||
p_tab_container->set_dock_context_popup(dock_context_popup);
|
||||
p_tab_container->connect("tab_changed", callable_mp(this, &EditorDockManager::_update_layout).unbind(1));
|
||||
p_tab_container->connect("active_tab_rearranged", callable_mp(this, &EditorDockManager::_update_layout).unbind(1));
|
||||
p_tab_container->connect("child_order_changed", callable_mp(this, &EditorDockManager::_dock_container_update_visibility).bind(p_tab_container));
|
||||
p_tab_container->hide();
|
||||
p_tab_container->set_meta("dock_slot", p_dock_slot);
|
||||
p_tab_container->set_meta("dock_layout", p_layout);
|
||||
|
||||
if (p_layout == EditorDock::DOCK_LAYOUT_VERTICAL) {
|
||||
p_tab_container->set_custom_minimum_size(Size2(170, 0) * EDSCALE);
|
||||
p_tab_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
p_tab_container->set_use_hidden_tabs_for_min_size(true);
|
||||
}
|
||||
|
||||
// Create dock dragging hint.
|
||||
slot.drag_hint = memnew(EditorDockDragHint);
|
||||
slot.drag_hint->hide();
|
||||
EditorNode::get_singleton()->get_gui_base()->add_child(slot.drag_hint);
|
||||
|
||||
dock_slots[p_dock_slot] = slot;
|
||||
slot.drag_hint->set_slot(p_dock_slot);
|
||||
}
|
||||
|
||||
int EditorDockManager::get_vsplit_count() const {
|
||||
|
|
@ -1088,23 +792,23 @@ void DockContextPopup::_notification(int p_what) {
|
|||
}
|
||||
|
||||
void DockContextPopup::_tab_move_left() {
|
||||
TabContainer *tab_container = dock_manager->get_dock_tab_container(context_dock);
|
||||
TabContainer *tab_container = context_dock->get_parent_container();
|
||||
if (!tab_container) {
|
||||
return;
|
||||
}
|
||||
int new_index = tab_container->get_tab_idx_from_control(context_dock) - 1;
|
||||
dock_manager->_move_dock(context_dock, tab_container, new_index);
|
||||
context_dock->set_tab_index(new_index, true);
|
||||
dock_manager->_update_layout();
|
||||
dock_select->queue_redraw();
|
||||
}
|
||||
|
||||
void DockContextPopup::_tab_move_right() {
|
||||
TabContainer *tab_container = dock_manager->get_dock_tab_container(context_dock);
|
||||
TabContainer *tab_container = context_dock->get_parent_container();
|
||||
if (!tab_container) {
|
||||
return;
|
||||
}
|
||||
int new_index = tab_container->get_tab_idx_from_control(context_dock) + 1;
|
||||
dock_manager->_move_dock(context_dock, tab_container, new_index);
|
||||
context_dock->set_tab_index(new_index, true);
|
||||
dock_manager->_update_layout();
|
||||
dock_select->queue_redraw();
|
||||
}
|
||||
|
|
@ -1120,10 +824,6 @@ void DockContextPopup::_float_dock() {
|
|||
dock_manager->_open_dock_in_window(context_dock);
|
||||
}
|
||||
|
||||
bool DockContextPopup::_is_slot_available(int p_slot) const {
|
||||
return context_dock->available_layouts & EditorDockManager::get_singleton()->dock_slots[p_slot].layout;
|
||||
}
|
||||
|
||||
void DockContextPopup::_dock_select_input(const Ref<InputEvent> &p_input) {
|
||||
Ref<InputEventMouse> me = p_input;
|
||||
|
||||
|
|
@ -1148,14 +848,19 @@ void DockContextPopup::_dock_select_input(const Ref<InputEvent> &p_input) {
|
|||
}
|
||||
|
||||
Ref<InputEventMouseButton> mb = me;
|
||||
TabContainer *target_tab_container = dock_manager->dock_slots[over_dock_slot].container;
|
||||
DockTabContainer *target_tab_container = dock_manager->dock_slots[over_dock_slot];
|
||||
if (context_dock->get_parent_container() == target_tab_container) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(context_dock->available_layouts & target_tab_container->layout)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
|
||||
if (dock_manager->get_dock_tab_container(context_dock) != target_tab_container && _is_slot_available(over_dock_slot)) {
|
||||
dock_manager->_move_dock(context_dock, target_tab_container, target_tab_container->get_tab_count());
|
||||
dock_manager->_update_layout();
|
||||
hide();
|
||||
}
|
||||
dock_manager->_move_dock(context_dock, target_tab_container, target_tab_container->get_tab_count());
|
||||
dock_manager->_update_layout();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1210,7 +915,7 @@ void DockContextPopup::_dock_select_draw() {
|
|||
real_t dock_spacing = 2.0 * EDSCALE;
|
||||
real_t dock_top_spacing = tab_height + dock_spacing;
|
||||
|
||||
TabContainer *context_tab_container = dock_manager->get_dock_tab_container(context_dock);
|
||||
TabContainer *context_tab_container = context_dock->get_parent_container();
|
||||
int context_tab_index = -1;
|
||||
if (context_tab_container && context_tab_container->get_tab_count() > 0) {
|
||||
context_tab_index = context_tab_container->get_tab_idx_from_control(context_dock);
|
||||
|
|
@ -1223,7 +928,7 @@ void DockContextPopup::_dock_select_draw() {
|
|||
// Draw all dock slots.
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_MAX; i++) {
|
||||
int max_tabs = (i == EditorDock::DOCK_SLOT_BOTTOM) ? 6 : 3;
|
||||
const EditorDockManager::DockSlot &dock_slot = dock_manager->dock_slots[i];
|
||||
const DockTabContainer *dock_slot = dock_manager->dock_slots[i];
|
||||
|
||||
Rect2 dock_slot_draw_rect = dock_select_rects[i].grow_individual(-dock_spacing, -dock_top_spacing, -dock_spacing, -dock_spacing);
|
||||
real_t tab_width = Math::round(dock_slot_draw_rect.size.width / max_tabs);
|
||||
|
|
@ -1238,11 +943,11 @@ void DockContextPopup::_dock_select_draw() {
|
|||
tab_draw_rect.position.x += dock_slot_draw_rect.size.x - tab_draw_rect.size.x;
|
||||
}
|
||||
|
||||
int tabs_to_draw = MIN(max_tabs, dock_slot.container->get_tab_count());
|
||||
bool is_context_dock = context_tab_container == dock_slot.container;
|
||||
int tabs_to_draw = MIN(max_tabs, dock_slot->get_tab_count());
|
||||
bool is_context_dock = context_tab_container == dock_slot;
|
||||
if (i == context_dock->dock_slot_index) {
|
||||
dock_select->draw_rect(dock_slot_draw_rect, tab_selected_color);
|
||||
} else if (!_is_slot_available(i)) {
|
||||
} else if (!(context_dock->available_layouts & dock_slot->layout)) {
|
||||
dock_select->draw_rect(dock_slot_draw_rect, unusable_dock_color);
|
||||
} else if (i == dock_select_rect_over_idx) {
|
||||
dock_select->draw_rect(dock_slot_draw_rect, hovered_dock_color);
|
||||
|
|
@ -1266,7 +971,6 @@ void DockContextPopup::_dock_select_draw() {
|
|||
}
|
||||
|
||||
void DockContextPopup::_update_buttons() {
|
||||
TabContainer *context_tab_container = dock_manager->get_dock_tab_container(context_dock);
|
||||
if (context_dock->global || context_dock->closable) {
|
||||
close_button->set_tooltip_text(TTRC("Close this dock."));
|
||||
close_button->set_disabled(false);
|
||||
|
|
@ -1287,6 +991,7 @@ void DockContextPopup::_update_buttons() {
|
|||
// Update tab move buttons.
|
||||
tab_move_left_button->set_disabled(true);
|
||||
tab_move_right_button->set_disabled(true);
|
||||
TabContainer *context_tab_container = context_dock->get_parent_container();
|
||||
if (context_tab_container && context_tab_container->get_tab_count() > 0) {
|
||||
int context_tab_index = context_tab_container->get_tab_idx_from_control(context_dock);
|
||||
tab_move_left_button->set_disabled(context_tab_index == 0);
|
||||
|
|
@ -1295,20 +1000,11 @@ void DockContextPopup::_update_buttons() {
|
|||
reset_size();
|
||||
}
|
||||
|
||||
void DockContextPopup::select_current_dock_in_dock_slot(int p_dock_slot) {
|
||||
context_dock = Object::cast_to<EditorDock>(dock_manager->dock_slots[p_dock_slot].container->get_current_tab_control());
|
||||
_update_buttons();
|
||||
}
|
||||
|
||||
void DockContextPopup::set_dock(EditorDock *p_dock) {
|
||||
context_dock = p_dock;
|
||||
_update_buttons();
|
||||
}
|
||||
|
||||
EditorDock *DockContextPopup::get_dock() const {
|
||||
return context_dock;
|
||||
}
|
||||
|
||||
void DockContextPopup::docks_updated() {
|
||||
if (!is_visible()) {
|
||||
return;
|
||||
|
|
@ -1380,11 +1076,14 @@ void DockShortcutHandler::shortcut_input(const Ref<InputEvent> &p_event) {
|
|||
for (EditorDock *dock : EditorDockManager::get_singleton()->all_docks) {
|
||||
const Ref<Shortcut> &dock_shortcut = dock->get_dock_shortcut();
|
||||
if (dock_shortcut.is_valid() && dock_shortcut->matches_event(p_event)) {
|
||||
if (dock->is_visible() && dock->get_parent() == EditorNode::get_bottom_panel()) {
|
||||
EditorNode::get_bottom_panel()->hide_bottom_panel();
|
||||
} else if (!dock->transient || dock->is_open) {
|
||||
bool was_visible = dock->is_visible();
|
||||
if (!dock->transient || dock->is_open) {
|
||||
EditorDockManager::get_singleton()->focus_dock(dock);
|
||||
}
|
||||
DockTabContainer *dock_container = dock->get_parent_container();
|
||||
if (dock_container) {
|
||||
dock_container->dock_focused(dock, was_visible);
|
||||
}
|
||||
get_viewport()->set_input_as_handled();
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ public:
|
|||
|
||||
class DockContextPopup;
|
||||
class EditorDockDragHint;
|
||||
class DockTabContainer;
|
||||
|
||||
class EditorDockManager : public Object {
|
||||
GDCLASS(EditorDockManager, Object);
|
||||
|
|
@ -88,13 +89,7 @@ private:
|
|||
Vector<DockSplitContainer *> vsplits;
|
||||
DockSplitContainer *main_hsplit = nullptr;
|
||||
|
||||
struct DockSlot {
|
||||
TabContainer *container = nullptr;
|
||||
EditorDockDragHint *drag_hint = nullptr;
|
||||
EditorDock::DockLayout layout = EditorDock::DOCK_LAYOUT_VERTICAL;
|
||||
};
|
||||
|
||||
DockSlot dock_slots[EditorDock::DOCK_SLOT_MAX];
|
||||
DockTabContainer *dock_slots[EditorDock::DOCK_SLOT_MAX];
|
||||
Vector<WindowWrapper *> dock_windows;
|
||||
LocalVector<EditorDock *> all_docks;
|
||||
HashSet<EditorDock *> dirty_docks;
|
||||
|
|
@ -110,8 +105,6 @@ private:
|
|||
EditorDock *_get_dock_tab_dragged();
|
||||
void _dock_drag_stopped();
|
||||
void _dock_split_dragged(int p_offset);
|
||||
void _dock_container_popup(int p_tab_idx, TabContainer *p_dock_container);
|
||||
void _dock_container_update_visibility(TabContainer *p_dock_container);
|
||||
void _update_layout();
|
||||
|
||||
void _docks_menu_option(int p_id);
|
||||
|
|
@ -122,12 +115,10 @@ private:
|
|||
void _restore_dock_to_saved_window(EditorDock *p_dock, const Dictionary &p_window_dump);
|
||||
|
||||
void _make_dock_visible(EditorDock *p_dock, bool p_grab_focus);
|
||||
void _move_dock_tab_index(EditorDock *p_dock, int p_tab_index, bool p_set_current);
|
||||
void _move_dock(EditorDock *p_dock, Control *p_target, int p_tab_index = -1, bool p_set_current = true);
|
||||
|
||||
void _queue_update_tab_style(EditorDock *p_dock);
|
||||
void _update_dirty_dock_tabs();
|
||||
void _update_tab_style(EditorDock *p_dock);
|
||||
|
||||
public:
|
||||
static EditorDockManager *get_singleton() { return singleton; }
|
||||
|
|
@ -138,7 +129,7 @@ public:
|
|||
|
||||
void add_vsplit(DockSplitContainer *p_split);
|
||||
void set_hsplit(DockSplitContainer *p_split);
|
||||
void register_dock_slot(EditorDock::DockSlot p_dock_slot, TabContainer *p_tab_container, EditorDock::DockLayout p_layout);
|
||||
void register_dock_slot(DockTabContainer *p_tab_container);
|
||||
int get_vsplit_count() const;
|
||||
PopupMenu *get_docks_menu();
|
||||
|
||||
|
|
@ -151,8 +142,6 @@ public:
|
|||
void focus_dock(EditorDock *p_dock);
|
||||
void make_dock_floating(EditorDock *p_dock);
|
||||
|
||||
TabContainer *get_dock_tab_container(Control *p_dock) const;
|
||||
|
||||
void set_docks_visible(bool p_show);
|
||||
bool are_docks_visible() const;
|
||||
|
||||
|
|
@ -162,36 +151,6 @@ public:
|
|||
EditorDockManager();
|
||||
};
|
||||
|
||||
class EditorDockDragHint : public Control {
|
||||
GDCLASS(EditorDockDragHint, Control);
|
||||
|
||||
private:
|
||||
EditorDockManager *dock_manager = nullptr;
|
||||
EditorDock::DockSlot occupied_slot = EditorDock::DOCK_SLOT_MAX;
|
||||
TabBar *drop_tabbar = nullptr;
|
||||
|
||||
Color valid_drop_color;
|
||||
Ref<StyleBoxFlat> dock_drop_highlight;
|
||||
bool can_drop_dock = false;
|
||||
bool mouse_inside = false;
|
||||
bool mouse_inside_tabbar = false;
|
||||
|
||||
void _drag_move_tab(int p_from_index, int p_to_index);
|
||||
void _drag_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index);
|
||||
|
||||
protected:
|
||||
virtual void gui_input(const Ref<InputEvent> &p_event) override;
|
||||
|
||||
void _notification(int p_what);
|
||||
bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
|
||||
void drop_data(const Point2 &p_point, const Variant &p_data) override;
|
||||
|
||||
public:
|
||||
void set_slot(EditorDock::DockSlot p_slot);
|
||||
|
||||
EditorDockDragHint();
|
||||
};
|
||||
|
||||
class DockContextPopup : public PopupPanel {
|
||||
GDCLASS(DockContextPopup, PopupPanel);
|
||||
|
||||
|
|
@ -215,7 +174,6 @@ private:
|
|||
void _tab_move_right();
|
||||
void _close_dock();
|
||||
void _float_dock();
|
||||
bool _is_slot_available(int p_slot) const;
|
||||
|
||||
void _dock_select_input(const Ref<InputEvent> &p_input);
|
||||
void _dock_select_mouse_exited();
|
||||
|
|
@ -227,9 +185,7 @@ protected:
|
|||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void select_current_dock_in_dock_slot(int p_dock_slot);
|
||||
void set_dock(EditorDock *p_dock);
|
||||
EditorDock *get_dock() const;
|
||||
void docks_updated();
|
||||
|
||||
DockContextPopup();
|
||||
|
|
|
|||
|
|
@ -1460,7 +1460,7 @@ void EditorNode::_sources_changed(bool p_exist) {
|
|||
if (SceneTreeDock::get_singleton()->is_visible_in_tree()) {
|
||||
SceneTreeDock::get_singleton()->get_tree_editor()->get_scene_tree()->grab_focus();
|
||||
} else {
|
||||
TabContainer *tab_container = EditorDockManager::get_singleton()->get_dock_tab_container(SceneTreeDock::get_singleton());
|
||||
TabContainer *tab_container = SceneTreeDock::get_singleton()->get_parent_container();
|
||||
if (tab_container) {
|
||||
// Another tab is active (e.g., Import) - focus the tab bar so user can switch.
|
||||
tab_container->get_tab_bar()->grab_focus();
|
||||
|
|
@ -8518,24 +8518,36 @@ EditorNode::EditorNode() {
|
|||
left_l_vsplit->set_vertical(true);
|
||||
main_hsplit->add_child(left_l_vsplit);
|
||||
|
||||
TabContainer *dock_slot[EditorDock::DOCK_SLOT_MAX];
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_UL] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_UL]->set_name("DockSlotLeftUL");
|
||||
left_l_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_LEFT_UL]);
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_BL] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_BL]->set_name("DockSlotLeftBL");
|
||||
left_l_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_LEFT_BL]);
|
||||
DockTabContainer *dock_slots[EditorDock::DOCK_SLOT_MAX];
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_LEFT_UL));
|
||||
dock_container->set_name("DockSlotLeftUL");
|
||||
left_l_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_LEFT_BL));
|
||||
dock_container->set_name("DockSlotLeftBL");
|
||||
left_l_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
|
||||
left_r_vsplit = memnew(DockSplitContainer);
|
||||
left_r_vsplit->set_name("DockVSplitLeftR");
|
||||
left_r_vsplit->set_vertical(true);
|
||||
main_hsplit->add_child(left_r_vsplit);
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_UR] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_UR]->set_name("DockSlotLeftUR");
|
||||
left_r_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_LEFT_UR]);
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_BR] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_LEFT_BR]->set_name("DockSlotLeftBR");
|
||||
left_r_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_LEFT_BR]);
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_LEFT_UR));
|
||||
dock_container->set_name("DockSlotLeftUR");
|
||||
left_r_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_LEFT_BR));
|
||||
dock_container->set_name("DockSlotLeftBR");
|
||||
left_r_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
|
||||
VBoxContainer *center_vb = memnew(VBoxContainer);
|
||||
center_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
|
@ -8553,23 +8565,35 @@ EditorNode::EditorNode() {
|
|||
right_l_vsplit->set_name("DockVSplitRightL");
|
||||
right_l_vsplit->set_vertical(true);
|
||||
main_hsplit->add_child(right_l_vsplit);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_UL] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_UL]->set_name("DockSlotRightUL");
|
||||
right_l_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_RIGHT_UL]);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_BL] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_BL]->set_name("DockSlotRightBL");
|
||||
right_l_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_RIGHT_BL]);
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_RIGHT_UL));
|
||||
dock_container->set_name("DockSlotRightUL");
|
||||
right_l_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_RIGHT_BL));
|
||||
dock_container->set_name("DockSlotRightBL");
|
||||
right_l_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
|
||||
right_r_vsplit = memnew(DockSplitContainer);
|
||||
right_r_vsplit->set_name("DockVSplitRightR");
|
||||
right_r_vsplit->set_vertical(true);
|
||||
main_hsplit->add_child(right_r_vsplit);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_UR] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_UR]->set_name("DockSlotRightUR");
|
||||
right_r_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_RIGHT_UR]);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_BR] = memnew(TabContainer);
|
||||
dock_slot[EditorDock::DOCK_SLOT_RIGHT_BR]->set_name("DockSlotRightBR");
|
||||
right_r_vsplit->add_child(dock_slot[EditorDock::DOCK_SLOT_RIGHT_BR]);
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_RIGHT_UR));
|
||||
dock_container->set_name("DockSlotRightUR");
|
||||
right_r_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
{
|
||||
DockTabContainer *dock_container = memnew(SideDockTabContainer(EditorDock::DOCK_SLOT_RIGHT_BR));
|
||||
dock_container->set_name("DockSlotRightBR");
|
||||
right_r_vsplit->add_child(dock_container);
|
||||
dock_slots[dock_container->dock_slot] = dock_container;
|
||||
}
|
||||
|
||||
editor_dock_manager = memnew(EditorDockManager);
|
||||
|
||||
|
|
@ -8582,7 +8606,7 @@ EditorNode::EditorNode() {
|
|||
editor_dock_manager->set_hsplit(main_hsplit);
|
||||
|
||||
for (int i = 0; i < EditorDock::DOCK_SLOT_BOTTOM; i++) {
|
||||
editor_dock_manager->register_dock_slot((EditorDock::DockSlot)i, dock_slot[i], EditorDock::DOCK_LAYOUT_VERTICAL);
|
||||
editor_dock_manager->register_dock_slot(dock_slots[i]);
|
||||
}
|
||||
|
||||
editor_layout_save_delay_timer = memnew(Timer);
|
||||
|
|
@ -8988,8 +9012,7 @@ EditorNode::EditorNode() {
|
|||
// Bottom panels.
|
||||
|
||||
bottom_panel = memnew(EditorBottomPanel);
|
||||
editor_dock_manager->register_dock_slot(EditorDock::DOCK_SLOT_BOTTOM, bottom_panel, EditorDock::DOCK_LAYOUT_HORIZONTAL);
|
||||
bottom_panel->set_theme_type_variation("BottomPanel");
|
||||
editor_dock_manager->register_dock_slot(bottom_panel);
|
||||
center_split->add_child(bottom_panel);
|
||||
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "editor/gui/editor_version_button.h"
|
||||
#include "editor/scene/editor_scene_tabs.h"
|
||||
#include "editor/settings/editor_command_palette.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/separator.h"
|
||||
|
|
@ -48,7 +49,6 @@ void EditorBottomPanel::_notification(int p_what) {
|
|||
switch (p_what) {
|
||||
case NOTIFICATION_READY: {
|
||||
set_accessibility_region(true);
|
||||
layout_popup = get_popup();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
|
|
@ -110,7 +110,7 @@ void EditorBottomPanel::_repaint() {
|
|||
if (panel_collapsed && get_popup()) {
|
||||
set_popup(nullptr);
|
||||
} else if (!panel_collapsed && !get_popup()) {
|
||||
set_popup(layout_popup);
|
||||
set_popup(dock_context_popup);
|
||||
}
|
||||
if (!panel_collapsed && (previous_tab != -1)) {
|
||||
return;
|
||||
|
|
@ -132,6 +132,36 @@ void EditorBottomPanel::_repaint() {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorBottomPanel::dock_closed(EditorDock *p_dock) {
|
||||
if (p_dock == get_current_tab_control()) {
|
||||
hide_bottom_panel();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorBottomPanel::dock_focused(EditorDock *p_dock, bool p_was_visible) {
|
||||
if (p_was_visible && p_dock->is_visible()) {
|
||||
hide_bottom_panel();
|
||||
}
|
||||
}
|
||||
|
||||
DockTabContainer::TabStyle EditorBottomPanel::get_tab_style() const {
|
||||
return (TabStyle)EDITOR_GET("interface/editor/bottom_dock_tab_style").operator int();
|
||||
}
|
||||
|
||||
bool EditorBottomPanel::can_switch_dock() const {
|
||||
return !is_locked();
|
||||
}
|
||||
|
||||
void EditorBottomPanel::load_selected_tab(int p_idx) {
|
||||
EditorDock *selected_dock = get_dock(p_idx);
|
||||
if (!selected_dock) {
|
||||
p_idx = -1;
|
||||
}
|
||||
set_block_signals(true);
|
||||
set_current_tab(p_idx);
|
||||
set_block_signals(false);
|
||||
}
|
||||
|
||||
void EditorBottomPanel::save_layout_to_config(Ref<ConfigFile> p_config_file, const String &p_section) const {
|
||||
Dictionary offsets;
|
||||
for (const KeyValue<String, int> &E : dock_offsets) {
|
||||
|
|
@ -251,10 +281,14 @@ void EditorBottomPanel::_on_button_visibility_changed(Button *p_button, EditorDo
|
|||
}
|
||||
}
|
||||
|
||||
EditorBottomPanel::EditorBottomPanel() {
|
||||
EditorBottomPanel::EditorBottomPanel() :
|
||||
DockTabContainer(EditorDock::DOCK_SLOT_BOTTOM) {
|
||||
layout = EditorDock::DOCK_LAYOUT_HORIZONTAL;
|
||||
|
||||
get_tab_bar()->connect("tab_changed", callable_mp(this, &EditorBottomPanel::_on_tab_changed));
|
||||
set_tabs_position(TabPosition::POSITION_BOTTOM);
|
||||
set_deselect_enabled(true);
|
||||
set_theme_type_variation("BottomPanel");
|
||||
|
||||
bottom_hbox = memnew(HBoxContainer);
|
||||
bottom_hbox->set_mouse_filter(MOUSE_FILTER_IGNORE);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/tab_container.h"
|
||||
#include "editor/docks/dock_tab_container.h"
|
||||
|
||||
class Button;
|
||||
class ConfigFile;
|
||||
|
|
@ -38,15 +38,14 @@ class EditorDock;
|
|||
class EditorToaster;
|
||||
class HBoxContainer;
|
||||
|
||||
class EditorBottomPanel : public TabContainer {
|
||||
GDCLASS(EditorBottomPanel, TabContainer);
|
||||
class EditorBottomPanel : public DockTabContainer {
|
||||
GDCLASS(EditorBottomPanel, DockTabContainer);
|
||||
|
||||
HBoxContainer *bottom_hbox = nullptr;
|
||||
Control *icon_spacer = nullptr;
|
||||
EditorToaster *editor_toaster = nullptr;
|
||||
Button *pin_button = nullptr;
|
||||
Button *expand_button = nullptr;
|
||||
Popup *layout_popup = nullptr;
|
||||
|
||||
int previous_tab = -1;
|
||||
bool lock_panel_switching = false;
|
||||
|
|
@ -67,6 +66,13 @@ protected:
|
|||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
virtual void dock_closed(EditorDock *p_dock) override;
|
||||
virtual void dock_focused(EditorDock *p_dock, bool p_was_visible) override;
|
||||
virtual void update_visibility() override { show(); } // Never hide bottom panel.
|
||||
virtual TabStyle get_tab_style() const override;
|
||||
virtual bool can_switch_dock() const override;
|
||||
virtual void load_selected_tab(int p_idx) override;
|
||||
|
||||
void save_layout_to_config(Ref<ConfigFile> p_config_file, const String &p_section) const;
|
||||
void load_layout_from_config(Ref<ConfigFile> p_config_file, const String &p_section);
|
||||
|
||||
|
|
|
|||
|
|
@ -849,7 +849,7 @@ void ShaderEditorPlugin::shortcut_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
|
||||
if (make_floating_shortcut.is_valid() && make_floating_shortcut->matches_event(p_event)) {
|
||||
EditorDockManager::get_singleton()->make_dock_floating(shader_dock);
|
||||
shader_dock->make_floating();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue