You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Add dock dragging area and highlight
This commit is contained in:
@@ -43,6 +43,7 @@
|
|||||||
#include "editor/gui/editor_bottom_panel.h"
|
#include "editor/gui/editor_bottom_panel.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
#include "editor/window_wrapper.h"
|
#include "editor/window_wrapper.h"
|
||||||
|
#include "scene/resources/style_box_flat.h"
|
||||||
|
|
||||||
enum class TabStyle {
|
enum class TabStyle {
|
||||||
TEXT_ONLY,
|
TEXT_ONLY,
|
||||||
@@ -52,6 +53,115 @@ enum class TabStyle {
|
|||||||
|
|
||||||
EditorDockManager *EditorDockManager::singleton = nullptr;
|
EditorDockManager *EditorDockManager::singleton = nullptr;
|
||||||
|
|
||||||
|
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_slot[occupied_slot], 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_slot[occupied_slot], 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(EditorDockManager::DockSlot p_slot) {
|
||||||
|
occupied_slot = p_slot;
|
||||||
|
drop_tabbar = dock_manager->dock_slot[occupied_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: {
|
||||||
|
Control *dragged_dock = dock_manager->_get_dock_tab_dragged();
|
||||||
|
if (!dragged_dock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
can_drop_dock = true;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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())) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
void DockSplitContainer::_update_visibility() {
|
void DockSplitContainer::_update_visibility() {
|
||||||
if (is_updating) {
|
if (is_updating) {
|
||||||
return;
|
return;
|
||||||
@@ -120,6 +230,56 @@ DockSplitContainer::DockSplitContainer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Control *EditorDockManager::_get_dock_tab_dragged() {
|
||||||
|
if (dock_tab_dragged) {
|
||||||
|
return dock_tab_dragged;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary dock_drop_data = dock_slot[DOCK_SLOT_LEFT_BL]->get_viewport()->gui_get_drag_data();
|
||||||
|
|
||||||
|
// Check if we are dragging a dock.
|
||||||
|
const String type = dock_drop_data.get("type", "");
|
||||||
|
if (type == "tab_container_tab") {
|
||||||
|
Node *from_node = dock_slot[DOCK_SLOT_LEFT_BL]->get_node(dock_drop_data["from_path"]);
|
||||||
|
if (!from_node) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TabContainer *parent = Object::cast_to<TabContainer>(from_node->get_parent());
|
||||||
|
if (!parent) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Update logic when GH-106503 is merged to cast directly to EditorDock instead of the below check.
|
||||||
|
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
|
||||||
|
if (dock_slot[i] == parent) {
|
||||||
|
dock_tab_dragged = parent->get_tab_control(dock_drop_data["tab_index"]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dock_tab_dragged) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
|
||||||
|
if (dock_slot[i]->is_visible_in_tree()) {
|
||||||
|
dock_drag_rects[i]->set_rect(dock_slot[i]->get_global_rect());
|
||||||
|
dock_drag_rects[i]->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dock_tab_dragged;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDockManager::_dock_drag_stopped() {
|
||||||
|
dock_tab_dragged = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void EditorDockManager::_dock_split_dragged(int p_offset) {
|
void EditorDockManager::_dock_split_dragged(int p_offset) {
|
||||||
EditorNode::get_singleton()->save_editor_layout_delayed();
|
EditorNode::get_singleton()->save_editor_layout_delayed();
|
||||||
}
|
}
|
||||||
@@ -836,6 +996,12 @@ void EditorDockManager::register_dock_slot(DockSlot p_dock_slot, TabContainer *p
|
|||||||
p_tab_container->set_use_hidden_tabs_for_min_size(true);
|
p_tab_container->set_use_hidden_tabs_for_min_size(true);
|
||||||
p_tab_container->get_tab_bar()->connect(SceneStringName(gui_input), callable_mp(this, &EditorDockManager::_dock_container_gui_input).bind(p_tab_container));
|
p_tab_container->get_tab_bar()->connect(SceneStringName(gui_input), callable_mp(this, &EditorDockManager::_dock_container_gui_input).bind(p_tab_container));
|
||||||
p_tab_container->hide();
|
p_tab_container->hide();
|
||||||
|
|
||||||
|
// Create dock dragging hint.
|
||||||
|
dock_drag_rects[p_dock_slot] = memnew(EditorDockDragHint);
|
||||||
|
dock_drag_rects[p_dock_slot]->set_slot(p_dock_slot);
|
||||||
|
dock_drag_rects[p_dock_slot]->hide();
|
||||||
|
EditorNode::get_singleton()->get_gui_base()->add_child(dock_drag_rects[p_dock_slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EditorDockManager::get_vsplit_count() const {
|
int EditorDockManager::get_vsplit_count() const {
|
||||||
@@ -860,6 +1026,9 @@ EditorDockManager::EditorDockManager() {
|
|||||||
EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorDockManager::update_docks_menu));
|
EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorDockManager::update_docks_menu));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
void DockContextPopup::_notification(int p_what) {
|
void DockContextPopup::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
|
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
|
||||||
|
|||||||
@@ -37,9 +37,11 @@ class Button;
|
|||||||
class ConfigFile;
|
class ConfigFile;
|
||||||
class Control;
|
class Control;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
class TabBar;
|
||||||
class TabContainer;
|
class TabContainer;
|
||||||
class VBoxContainer;
|
class VBoxContainer;
|
||||||
class WindowWrapper;
|
class WindowWrapper;
|
||||||
|
class StyleBoxFlat;
|
||||||
|
|
||||||
class DockSplitContainer : public SplitContainer {
|
class DockSplitContainer : public SplitContainer {
|
||||||
GDCLASS(DockSplitContainer, SplitContainer);
|
GDCLASS(DockSplitContainer, SplitContainer);
|
||||||
@@ -58,6 +60,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class DockContextPopup;
|
class DockContextPopup;
|
||||||
|
class EditorDockDragHint;
|
||||||
|
|
||||||
class EditorDockManager : public Object {
|
class EditorDockManager : public Object {
|
||||||
GDCLASS(EditorDockManager, Object);
|
GDCLASS(EditorDockManager, Object);
|
||||||
@@ -78,6 +81,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DockContextPopup;
|
friend class DockContextPopup;
|
||||||
|
friend class EditorDockDragHint;
|
||||||
|
|
||||||
struct DockInfo {
|
struct DockInfo {
|
||||||
String title;
|
String title;
|
||||||
@@ -101,7 +105,9 @@ private:
|
|||||||
|
|
||||||
Vector<WindowWrapper *> dock_windows;
|
Vector<WindowWrapper *> dock_windows;
|
||||||
TabContainer *dock_slot[DOCK_SLOT_MAX];
|
TabContainer *dock_slot[DOCK_SLOT_MAX];
|
||||||
|
EditorDockDragHint *dock_drag_rects[DOCK_SLOT_MAX];
|
||||||
HashMap<Control *, DockInfo> all_docks;
|
HashMap<Control *, DockInfo> all_docks;
|
||||||
|
Control *dock_tab_dragged = nullptr;
|
||||||
bool docks_visible = true;
|
bool docks_visible = true;
|
||||||
|
|
||||||
DockContextPopup *dock_context_popup = nullptr;
|
DockContextPopup *dock_context_popup = nullptr;
|
||||||
@@ -109,6 +115,8 @@ private:
|
|||||||
Vector<Control *> docks_menu_docks;
|
Vector<Control *> docks_menu_docks;
|
||||||
Control *closed_dock_parent = nullptr;
|
Control *closed_dock_parent = nullptr;
|
||||||
|
|
||||||
|
Control *_get_dock_tab_dragged();
|
||||||
|
void _dock_drag_stopped();
|
||||||
void _dock_split_dragged(int p_offset);
|
void _dock_split_dragged(int p_offset);
|
||||||
void _dock_container_gui_input(const Ref<InputEvent> &p_input, TabContainer *p_dock_container);
|
void _dock_container_gui_input(const Ref<InputEvent> &p_input, TabContainer *p_dock_container);
|
||||||
void _bottom_dock_button_gui_input(const Ref<InputEvent> &p_input, Control *p_dock, Button *p_bottom_button);
|
void _bottom_dock_button_gui_input(const Ref<InputEvent> &p_input, Control *p_dock, Button *p_bottom_button);
|
||||||
@@ -167,9 +175,40 @@ public:
|
|||||||
EditorDockManager();
|
EditorDockManager();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EditorDockDragHint : public Control {
|
||||||
|
GDCLASS(EditorDockDragHint, Control);
|
||||||
|
|
||||||
|
private:
|
||||||
|
EditorDockManager *dock_manager = nullptr;
|
||||||
|
EditorDockManager::DockSlot occupied_slot = EditorDockManager::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(EditorDockManager::DockSlot p_slot);
|
||||||
|
|
||||||
|
EditorDockDragHint();
|
||||||
|
};
|
||||||
|
|
||||||
class DockContextPopup : public PopupPanel {
|
class DockContextPopup : public PopupPanel {
|
||||||
GDCLASS(DockContextPopup, PopupPanel);
|
GDCLASS(DockContextPopup, PopupPanel);
|
||||||
|
|
||||||
|
private:
|
||||||
VBoxContainer *dock_select_popup_vb = nullptr;
|
VBoxContainer *dock_select_popup_vb = nullptr;
|
||||||
|
|
||||||
Button *make_float_button = nullptr;
|
Button *make_float_button = nullptr;
|
||||||
|
|||||||
@@ -572,48 +572,54 @@ void TabBar::_notification(int p_what) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dragging_valid_tab) {
|
if (dragging_valid_tab) {
|
||||||
int x;
|
_draw_tab_drop(get_canvas_item());
|
||||||
|
|
||||||
int closest_tab = get_closest_tab_idx_to_point(get_local_mouse_position());
|
|
||||||
if (closest_tab != -1) {
|
|
||||||
Rect2 tab_rect = get_tab_rect(closest_tab);
|
|
||||||
x = tab_rect.position.x;
|
|
||||||
|
|
||||||
// Only add the tab_separation if closest tab is not on the edge.
|
|
||||||
bool not_leftmost_tab = -1 != (rtl ? get_next_available(closest_tab) : get_previous_available(closest_tab));
|
|
||||||
bool not_rightmost_tab = -1 != (rtl ? get_previous_available(closest_tab) : get_next_available(closest_tab));
|
|
||||||
|
|
||||||
// Calculate midpoint between tabs.
|
|
||||||
if (get_local_mouse_position().x > tab_rect.get_center().x) {
|
|
||||||
x += tab_rect.size.x;
|
|
||||||
if (not_rightmost_tab) {
|
|
||||||
x += Math::ceil(0.5f * theme_cache.tab_separation);
|
|
||||||
}
|
|
||||||
} else if (not_leftmost_tab) {
|
|
||||||
x -= Math::floor(0.5f * theme_cache.tab_separation);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (rtl ^ (get_local_mouse_position().x < get_tab_rect(0).position.x)) {
|
|
||||||
x = get_tab_rect(0).position.x;
|
|
||||||
if (rtl) {
|
|
||||||
x += get_tab_rect(0).size.width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Rect2 tab_rect = get_tab_rect(get_tab_count() - 1);
|
|
||||||
|
|
||||||
x = tab_rect.position.x;
|
|
||||||
if (!rtl) {
|
|
||||||
x += tab_rect.size.width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
theme_cache.drop_mark_icon->draw(get_canvas_item(), Point2(x - theme_cache.drop_mark_icon->get_width() / 2, (size.height - theme_cache.drop_mark_icon->get_height()) / 2), theme_cache.drop_mark_color);
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabBar::_draw_tab_drop(RID p_canvas_item) {
|
||||||
|
Vector2 size = get_size();
|
||||||
|
int x;
|
||||||
|
bool rtl = is_layout_rtl();
|
||||||
|
|
||||||
|
int closest_tab = get_closest_tab_idx_to_point(get_local_mouse_position());
|
||||||
|
if (closest_tab != -1) {
|
||||||
|
Rect2 tab_rect = get_tab_rect(closest_tab);
|
||||||
|
x = tab_rect.position.x;
|
||||||
|
|
||||||
|
// Only add the tab_separation if closest tab is not on the edge.
|
||||||
|
bool not_leftmost_tab = -1 != (rtl ? get_next_available(closest_tab) : get_previous_available(closest_tab));
|
||||||
|
bool not_rightmost_tab = -1 != (rtl ? get_previous_available(closest_tab) : get_next_available(closest_tab));
|
||||||
|
|
||||||
|
// Calculate midpoint between tabs.
|
||||||
|
if (get_local_mouse_position().x > tab_rect.get_center().x) {
|
||||||
|
x += tab_rect.size.x;
|
||||||
|
if (not_rightmost_tab) {
|
||||||
|
x += Math::ceil(0.5f * theme_cache.tab_separation);
|
||||||
|
}
|
||||||
|
} else if (not_leftmost_tab) {
|
||||||
|
x -= Math::floor(0.5f * theme_cache.tab_separation);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rtl ^ (get_local_mouse_position().x < get_tab_rect(0).position.x)) {
|
||||||
|
x = get_tab_rect(0).position.x;
|
||||||
|
if (rtl) {
|
||||||
|
x += get_tab_rect(0).size.width;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Rect2 tab_rect = get_tab_rect(get_tab_count() - 1);
|
||||||
|
|
||||||
|
x = tab_rect.position.x;
|
||||||
|
if (!rtl) {
|
||||||
|
x += tab_rect.size.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
theme_cache.drop_mark_icon->draw(p_canvas_item, Point2(x - theme_cache.drop_mark_icon->get_width() / 2, (size.height - theme_cache.drop_mark_icon->get_height()) / 2), theme_cache.drop_mark_color);
|
||||||
|
}
|
||||||
|
|
||||||
void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x, bool p_focus) {
|
void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x, bool p_focus) {
|
||||||
RID ci = get_canvas_item();
|
RID ci = get_canvas_item();
|
||||||
bool rtl = is_layout_rtl();
|
bool rtl = is_layout_rtl();
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ public:
|
|||||||
Variant _handle_get_drag_data(const String &p_type, const Point2 &p_point);
|
Variant _handle_get_drag_data(const String &p_type, const Point2 &p_point);
|
||||||
bool _handle_can_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data) const;
|
bool _handle_can_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data) const;
|
||||||
void _handle_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data, const Callable &p_move_tab_callback, const Callable &p_move_tab_from_other_callback);
|
void _handle_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data, const Callable &p_move_tab_callback, const Callable &p_move_tab_from_other_callback);
|
||||||
|
void _draw_tab_drop(RID p_canvas_item);
|
||||||
|
|
||||||
void add_tab(const String &p_str = "", const Ref<Texture2D> &p_icon = Ref<Texture2D>());
|
void add_tab(const String &p_str = "", const Ref<Texture2D> &p_icon = Ref<Texture2D>());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user