| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321 |
- /**************************************************************************/
- /* split_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 "split_container.h"
- #include "split_container.compat.inc"
- #include "scene/gui/texture_rect.h"
- #include "scene/main/viewport.h"
- #include "scene/theme/theme_db.h"
- void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND(p_event.is_null());
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->collapsed || sc->valid_children.size() < 2u || !sc->dragging_enabled) {
- return;
- }
- Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::LEFT) {
- if (mb->is_pressed()) {
- // To match the visual position, clamp on the first split.
- sc->_update_dragger_positions(0);
- dragging = true;
- sc->emit_signal(SNAME("drag_started"));
- start_drag_split_offset = sc->get_split_offset(dragger_index);
- if (sc->vertical) {
- drag_from = (int)get_transform().xform(mb->get_position()).y;
- } else {
- drag_from = (int)get_transform().xform(mb->get_position()).x;
- }
- } else {
- dragging = false;
- queue_redraw();
- sc->emit_signal(SNAME("drag_ended"));
- }
- }
- }
- Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid()) {
- if (!dragging) {
- return;
- }
- Vector2i in_parent_pos = get_transform().xform(mm->get_position());
- int new_drag_offset;
- if (!sc->vertical && is_layout_rtl()) {
- new_drag_offset = start_drag_split_offset - (in_parent_pos.x - drag_from);
- } else {
- new_drag_offset = start_drag_split_offset + ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from);
- }
- sc->set_split_offset(new_drag_offset, dragger_index);
- sc->_update_dragger_positions(dragger_index);
- sc->queue_sort();
- sc->emit_signal(SNAME("dragged"), sc->get_split_offset(dragger_index));
- }
- }
- Control::CursorShape SplitContainerDragger::get_cursor_shape(const Point2 &p_pos) const {
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (!sc->collapsed && sc->dragging_enabled) {
- return (sc->vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
- }
- return Control::get_cursor_shape(p_pos);
- }
- void SplitContainerDragger::_accessibility_action_inc(const Variant &p_data) {
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->collapsed || sc->valid_children.size() < 2u || !sc->dragging_enabled) {
- return;
- }
- sc->set_split_offset(sc->get_split_offset(dragger_index) - 10, dragger_index);
- sc->clamp_split_offset(dragger_index);
- }
- void SplitContainerDragger::_accessibility_action_dec(const Variant &p_data) {
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->collapsed || sc->valid_children.size() < 2u || !sc->dragging_enabled) {
- return;
- }
- sc->set_split_offset(sc->get_split_offset(dragger_index) + 10, dragger_index);
- sc->clamp_split_offset(dragger_index);
- }
- void SplitContainerDragger::_accessibility_action_set_value(const Variant &p_data) {
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->collapsed || sc->valid_children.size() < 2u || !sc->dragging_enabled) {
- return;
- }
- sc->set_split_offset(p_data, dragger_index);
- sc->clamp_split_offset(dragger_index);
- }
- void SplitContainerDragger::_touch_dragger_mouse_exited() {
- if (!dragging) {
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- touch_dragger->set_modulate(sc->theme_cache.touch_dragger_color);
- }
- }
- void SplitContainerDragger::_touch_dragger_gui_input(const Ref<InputEvent> &p_event) {
- if (!touch_dragger) {
- return;
- }
- Ref<InputEventMouseMotion> mm = p_event;
- Ref<InputEventMouseButton> mb = p_event;
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
- if (mb->is_pressed()) {
- touch_dragger->set_modulate(sc->theme_cache.touch_dragger_pressed_color);
- } else {
- touch_dragger->set_modulate(sc->theme_cache.touch_dragger_color);
- }
- }
- if (mm.is_valid() && !dragging) {
- touch_dragger->set_modulate(sc->theme_cache.touch_dragger_hover_color);
- }
- }
- void SplitContainerDragger::set_touch_dragger_enabled(bool p_enabled) {
- if (p_enabled) {
- touch_dragger = memnew(TextureRect);
- update_touch_dragger();
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- touch_dragger->set_modulate(sc->theme_cache.touch_dragger_color);
- touch_dragger->connect(SceneStringName(gui_input), callable_mp(this, &SplitContainerDragger::_touch_dragger_gui_input));
- touch_dragger->connect(SceneStringName(mouse_exited), callable_mp(this, &SplitContainerDragger::_touch_dragger_mouse_exited));
- add_child(touch_dragger, false, Node::INTERNAL_MODE_FRONT);
- } else {
- if (touch_dragger) {
- touch_dragger->queue_free();
- touch_dragger = nullptr;
- }
- }
- queue_redraw();
- }
- void SplitContainerDragger::update_touch_dragger() {
- if (!touch_dragger) {
- return;
- }
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- touch_dragger->set_texture(sc->_get_touch_dragger_icon());
- touch_dragger->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
- touch_dragger->set_default_cursor_shape(sc->vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
- }
- void SplitContainerDragger::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ACCESSIBILITY_UPDATE: {
- RID ae = get_accessibility_element();
- ERR_FAIL_COND(ae.is_null());
- DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_SPLITTER);
- DisplayServer::get_singleton()->accessibility_update_set_name(ae, RTR("Drag to resize"));
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->collapsed || sc->valid_children.size() < 2u || !sc->dragging_enabled) {
- return;
- }
- sc->clamp_split_offset(dragger_index);
- DisplayServer::get_singleton()->accessibility_update_set_num_value(ae, sc->get_split_offset(dragger_index));
- DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_DECREMENT, callable_mp(this, &SplitContainerDragger::_accessibility_action_dec));
- DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_INCREMENT, callable_mp(this, &SplitContainerDragger::_accessibility_action_inc));
- DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SET_VALUE, callable_mp(this, &SplitContainerDragger::_accessibility_action_set_value));
- } break;
- case NOTIFICATION_THEME_CHANGED: {
- if (touch_dragger) {
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- touch_dragger->set_modulate(sc->theme_cache.touch_dragger_color);
- touch_dragger->set_texture(sc->_get_touch_dragger_icon());
- }
- } break;
- case NOTIFICATION_MOUSE_ENTER: {
- mouse_inside = true;
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->theme_cache.autohide) {
- queue_redraw();
- }
- } break;
- case NOTIFICATION_MOUSE_EXIT: {
- mouse_inside = false;
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->theme_cache.autohide) {
- queue_redraw();
- }
- } break;
- case NOTIFICATION_FOCUS_EXIT: {
- if (dragging) {
- dragging = false;
- queue_redraw();
- }
- } break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
- if (dragging && !is_visible_in_tree()) {
- dragging = false;
- }
- } break;
- case NOTIFICATION_DRAW: {
- SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- draw_style_box(sc->theme_cache.split_bar_background, split_bar_rect);
- if (sc->dragger_visibility == SplitContainer::DRAGGER_VISIBLE && (dragging || mouse_inside || !sc->theme_cache.autohide) && !sc->touch_dragger_enabled) {
- Ref<Texture2D> tex = sc->_get_grabber_icon();
- float available_size = sc->vertical ? (sc->get_size().x - tex->get_size().x) : (sc->get_size().y - tex->get_size().y);
- if (available_size - sc->drag_area_margin_begin - sc->drag_area_margin_end > 0) { // Draw the grabber only if it fits.
- draw_texture(tex, (split_bar_rect.get_position() + (split_bar_rect.get_size() - tex->get_size()) * 0.5));
- }
- }
- if (sc->show_drag_area && Engine::get_singleton()->is_editor_hint()) {
- draw_rect(Rect2(Vector2(0, 0), get_size()), sc->dragging_enabled ? Color(1, 1, 0, 0.3) : Color(1, 0, 0, 0.3));
- }
- } break;
- }
- }
- SplitContainerDragger::SplitContainerDragger() {
- set_focus_mode(FOCUS_ACCESSIBILITY);
- }
- Ref<Texture2D> SplitContainer::_get_grabber_icon() const {
- if (is_fixed) {
- return theme_cache.grabber_icon;
- } else {
- if (vertical) {
- return theme_cache.grabber_icon_v;
- } else {
- return theme_cache.grabber_icon_h;
- }
- }
- }
- Ref<Texture2D> SplitContainer::_get_touch_dragger_icon() const {
- if (is_fixed) {
- return theme_cache.touch_dragger_icon;
- } else {
- if (vertical) {
- return theme_cache.touch_dragger_icon_v;
- } else {
- return theme_cache.touch_dragger_icon_h;
- }
- }
- }
- int SplitContainer::_get_separation() const {
- if (dragger_visibility == DRAGGER_HIDDEN_COLLAPSED) {
- return 0;
- }
- if (touch_dragger_enabled) {
- return theme_cache.separation;
- }
- // DRAGGER_VISIBLE or DRAGGER_HIDDEN.
- Ref<Texture2D> g = _get_grabber_icon();
- return MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width());
- }
- Point2i SplitContainer::_get_valid_range(int p_dragger_index) const {
- ERR_FAIL_INDEX_V(p_dragger_index, (int)dragger_positions.size(), Point2i());
- const int axis = vertical ? 1 : 0;
- const int sep = _get_separation();
- // Sum the minimum sizes on the left and right sides of the dragger.
- Point2i position_range = Point2i(0, (int)get_size()[axis]);
- position_range.x += sep * p_dragger_index;
- position_range.y -= sep * ((int)dragger_positions.size() - p_dragger_index);
- for (int i = 0; i < (int)valid_children.size(); i++) {
- Control *child = valid_children[i];
- ERR_FAIL_NULL_V(child, Point2i());
- if (i <= p_dragger_index) {
- position_range.x += (int)child->get_combined_minimum_size()[axis];
- } else if (i > p_dragger_index) {
- position_range.y -= (int)child->get_combined_minimum_size()[axis];
- }
- }
- return position_range;
- }
- PackedInt32Array SplitContainer::_get_desired_sizes() const {
- ERR_FAIL_COND_V((int)default_dragger_positions.size() != split_offsets.size() || (int)valid_children.size() - 1 != split_offsets.size(), PackedInt32Array());
- PackedInt32Array desired_sizes;
- desired_sizes.resize_uninitialized((int)valid_children.size());
- const int sep = _get_separation();
- const int axis = vertical ? 1 : 0;
- int desired_start_pos = 0;
- for (int i = 0; i < (int)valid_children.size() - 1; i++) {
- const int desired_end_pos = default_dragger_positions[i] + split_offsets[i];
- desired_sizes.write[i] = desired_end_pos - desired_start_pos;
- desired_start_pos = desired_end_pos + sep;
- }
- desired_sizes.write[(int)valid_children.size() - 1] = (int)get_size()[axis] - desired_start_pos;
- return desired_sizes;
- }
- void SplitContainer::_set_desired_sizes(const PackedInt32Array &p_desired_sizes, int p_priority_index) {
- const int sep = _get_separation();
- const int axis = vertical ? 1 : 0;
- const real_t size = get_size()[axis];
- real_t total_desired_size = 0;
- if (!p_desired_sizes.is_empty()) {
- ERR_FAIL_COND((int)valid_children.size() != p_desired_sizes.size());
- total_desired_size += sep * (p_desired_sizes.size() - 1);
- }
- struct StretchData {
- real_t min_size = 0;
- real_t stretch_ratio = 0.0;
- real_t final_size = 0;
- bool priority = false;
- };
- // First pass, determine the total stretch amount.
- real_t stretch_total = 0;
- LocalVector<StretchData> stretch_data;
- for (int i = 0; i < (int)valid_children.size(); i++) {
- Control *child = valid_children[i];
- StretchData sdata;
- sdata.min_size = child->get_combined_minimum_size()[axis];
- sdata.final_size = MAX(sdata.min_size, p_desired_sizes.is_empty() ? 0 : p_desired_sizes[i]);
- total_desired_size += sdata.final_size;
- sdata.priority = i == p_priority_index;
- // Treat the priority child as not expanded, so it doesn't shrink with other expanded children.
- if (i != p_priority_index && child->get_stretch_ratio() > 0 && (vertical ? child->get_v_size_flags() : child->get_h_size_flags()).has_flag(SIZE_EXPAND)) {
- sdata.stretch_ratio = child->get_stretch_ratio();
- stretch_total += sdata.stretch_ratio;
- }
- stretch_data.push_back(sdata);
- }
- real_t available_space = size - total_desired_size;
- // Grow expanding children.
- if (available_space > 0) {
- const real_t grow_amount = available_space / stretch_total;
- for (StretchData &sdata : stretch_data) {
- if (sdata.stretch_ratio <= 0) {
- continue;
- }
- const real_t prev_size = sdata.final_size;
- sdata.final_size = prev_size + grow_amount * sdata.stretch_ratio;
- const real_t size_diff = prev_size - sdata.final_size;
- available_space += size_diff;
- }
- }
- // Shrink expanding children.
- while (available_space < 0) {
- real_t shrinkable_stretch_ratio = 0.0;
- real_t shrinkable_amount = 0.0;
- for (const StretchData &sdata : stretch_data) {
- if (sdata.stretch_ratio <= 0 || sdata.final_size <= sdata.min_size) {
- continue;
- }
- shrinkable_stretch_ratio += sdata.stretch_ratio;
- shrinkable_amount += sdata.final_size - sdata.min_size;
- }
- if (shrinkable_stretch_ratio == 0) {
- break;
- }
- const real_t shrink_amount = MIN(-available_space, shrinkable_amount) / shrinkable_stretch_ratio;
- if (Math::is_zero_approx(shrink_amount)) {
- break;
- }
- const real_t prev_available_space = available_space;
- for (StretchData &sdata : stretch_data) {
- if (sdata.stretch_ratio <= 0 || sdata.final_size <= sdata.min_size) {
- continue;
- }
- const real_t prev_size = sdata.final_size;
- sdata.final_size = CLAMP(prev_size - shrink_amount * sdata.stretch_ratio, sdata.min_size, sdata.final_size);
- const real_t size_diff = prev_size - sdata.final_size;
- available_space += size_diff;
- }
- if (Math::is_equal_approx(available_space, prev_available_space)) {
- // Shrinking can fail due to values being too small to have an effect but too large for `is_zero_approx`.
- break;
- }
- }
- // Shrink non-expanding children.
- bool skip_priority_child = true;
- while (available_space < 0) {
- // Get largest and target sizes. The target size is the second largest size.
- real_t largest_size = 0;
- real_t target_size = 0;
- int largest_count = 0;
- for (const StretchData &sdata : stretch_data) {
- if (sdata.final_size <= sdata.min_size || (skip_priority_child && sdata.priority)) {
- continue;
- }
- if (sdata.final_size > largest_size) {
- target_size = largest_size;
- largest_size = sdata.final_size;
- largest_count = 1;
- } else if (sdata.final_size == largest_size) {
- largest_count++;
- } else if (sdata.final_size < largest_size && sdata.final_size > target_size) {
- target_size = sdata.final_size;
- }
- }
- if (largest_size <= 0) {
- if (skip_priority_child) {
- // Retry with priority child.
- skip_priority_child = false;
- continue;
- } else {
- // No more children to shrink.
- break;
- }
- }
- // Don't shrink smaller than needed.
- target_size = MAX(target_size, largest_size + available_space / largest_count);
- const real_t prev_available_space = available_space;
- for (StretchData &sdata : stretch_data) {
- if (sdata.final_size <= sdata.min_size || (skip_priority_child && sdata.priority)) {
- continue;
- }
- // Shrink all largest elements.
- if (sdata.final_size == largest_size) {
- sdata.final_size = CLAMP(target_size, sdata.min_size, sdata.final_size);
- const real_t size_diff = largest_size - sdata.final_size;
- available_space += size_diff;
- }
- }
- if (Math::is_zero_approx(available_space) || Math::is_equal_approx(available_space, prev_available_space)) {
- break;
- }
- }
- ERR_FAIL_COND((int)default_dragger_positions.size() != (int)stretch_data.size() - 1);
- // Update the split offsets to match the desired sizes.
- split_offsets.resize(MAX(1, (int)default_dragger_positions.size()));
- int pos = 0;
- real_t error_accumulator = 0.0;
- for (int i = 0; i < (int)default_dragger_positions.size(); i++) {
- int final_size = (int)stretch_data[i].final_size;
- if (final_size == stretch_data[i].final_size) {
- error_accumulator += stretch_data[i].final_size - final_size;
- if (error_accumulator > 1.0) {
- error_accumulator -= 1.0;
- final_size += 1;
- }
- }
- pos += final_size;
- split_offsets.write[i] = pos - default_dragger_positions[i];
- pos += sep;
- }
- }
- void SplitContainer::_update_default_dragger_positions() {
- if (valid_children.size() <= 1u) {
- default_dragger_positions.clear();
- return;
- }
- default_dragger_positions.resize((int)valid_children.size() - 1);
- const int sep = _get_separation();
- const int axis = vertical ? 1 : 0;
- const int size = (int)get_size()[axis];
- struct StretchData {
- int min_size = 0;
- real_t stretch_ratio = 0.0;
- int final_size = 0;
- bool expand_flag = false;
- bool will_stretch = false;
- };
- // First pass, determine the total stretch amount.
- real_t stretchable_space = size - sep * ((int)valid_children.size() - 1);
- real_t stretch_total = 0;
- int expand_count = 0;
- LocalVector<StretchData> stretch_data;
- for (const Control *child : valid_children) {
- StretchData sdata;
- sdata.min_size = (int)child->get_combined_minimum_size()[axis];
- sdata.final_size = sdata.min_size;
- if ((vertical ? child->get_v_size_flags() : child->get_h_size_flags()).has_flag(SIZE_EXPAND) && child->get_stretch_ratio() > 0) {
- sdata.stretch_ratio = child->get_stretch_ratio();
- stretch_total += sdata.stretch_ratio;
- sdata.expand_flag = true;
- sdata.will_stretch = true;
- expand_count++;
- } else {
- stretchable_space -= sdata.min_size;
- }
- stretch_data.push_back(sdata);
- }
- #ifndef DISABLE_DEPRECATED
- if (expand_count == 2 && valid_children.size() == 2u) {
- // Special case when there are 2 expanded children, ignore minimum sizes.
- const real_t ratio = stretch_data[0].stretch_ratio / (stretch_data[0].stretch_ratio + stretch_data[1].stretch_ratio);
- default_dragger_positions[0] = (int)(size * ratio - sep * 0.5);
- return;
- }
- #endif // DISABLE_DEPRECATED
- // Determine final sizes if stretching.
- while (stretch_total > 0.0 && stretchable_space > 0.0) {
- bool refit_successful = true;
- // Keep track of accumulated error in pixels.
- float error = 0.0;
- for (StretchData &sdata : stretch_data) {
- if (!sdata.will_stretch) {
- continue;
- }
- // Check if it reaches its minimum size.
- const float desired_stretch_size = sdata.stretch_ratio / stretch_total * stretchable_space;
- error += desired_stretch_size - (int)desired_stretch_size;
- if (desired_stretch_size < sdata.min_size) {
- // Will not be stretched, remove and retry.
- stretch_total -= sdata.stretch_ratio;
- stretchable_space -= sdata.min_size;
- sdata.will_stretch = false;
- sdata.final_size = sdata.min_size;
- refit_successful = false;
- break;
- } else {
- sdata.final_size = (int)desired_stretch_size;
- // Dump accumulated error if one pixel or more.
- if (error >= 1.0) {
- sdata.final_size += 1;
- error -= 1;
- }
- }
- }
- if (refit_successful) {
- break;
- }
- }
- // Set the default positions.
- int pos = 0;
- int expands_seen = 0;
- for (int i = 0; i < (int)default_dragger_positions.size(); i++) {
- pos += stretch_data[i].final_size;
- if (stretch_data[i].expand_flag) {
- expands_seen += 1;
- }
- if (expands_seen == 0) {
- // Before all expand flags.
- default_dragger_positions[i] = 0;
- } else if (expands_seen >= expand_count) {
- // After all expand flags.
- default_dragger_positions[i] = size - sep;
- } else {
- default_dragger_positions[i] = pos;
- }
- pos += sep;
- }
- }
- void SplitContainer::_update_dragger_positions(int p_clamp_index) {
- if (p_clamp_index != -1) {
- ERR_FAIL_INDEX(p_clamp_index, (int)dragger_positions.size());
- }
- const int sep = _get_separation();
- const int axis = vertical ? 1 : 0;
- const int size = (int)get_size()[axis];
- dragger_positions.resize(default_dragger_positions.size());
- if (split_offsets.size() < (int)default_dragger_positions.size() || split_offsets.is_empty()) {
- split_offsets.resize_initialized(MAX(1, (int)default_dragger_positions.size()));
- }
- if (collapsed) {
- for (int i = 0; i < (int)dragger_positions.size(); i++) {
- dragger_positions[i] = default_dragger_positions[i];
- const Point2i valid_range = _get_valid_range(i);
- dragger_positions[i] = CLAMP(dragger_positions[i], valid_range.x, valid_range.y);
- if (p_clamp_index != -1) {
- split_offsets.write[i] = dragger_positions[i] - default_dragger_positions[i];
- }
- if (!vertical && is_layout_rtl()) {
- dragger_positions[i] = size - dragger_positions[i] - sep;
- }
- }
- return;
- }
- // Use split_offsets to find the desired dragger positions.
- for (int i = 0; i < (int)dragger_positions.size(); i++) {
- // Clamp the desired position to acceptable values.
- const Point2i valid_range = _get_valid_range(i);
- dragger_positions[i] = CLAMP(default_dragger_positions[i] + split_offsets[i], valid_range.x, valid_range.y);
- }
- // Prevent overlaps.
- if (p_clamp_index == -1) {
- // Check each dragger with the one to the right of it.
- for (int i = 0; i < (int)dragger_positions.size() - 1; i++) {
- const int check_min_size = (int)valid_children[i + 1]->get_combined_minimum_size()[axis];
- const int push_pos = dragger_positions[i] + sep + check_min_size;
- if (dragger_positions[i + 1] < push_pos) {
- dragger_positions[i + 1] = push_pos;
- const Point2i valid_range = _get_valid_range(i);
- dragger_positions[i] = CLAMP(dragger_positions[i], valid_range.x, valid_range.y);
- }
- }
- } else {
- // Prioritize the active dragger.
- const int dragging_position = dragger_positions[p_clamp_index];
- // Push overlapping draggers to the left.
- int accumulated_min_size = (int)valid_children[p_clamp_index]->get_combined_minimum_size()[axis];
- for (int i = p_clamp_index - 1; i >= 0; i--) {
- const int push_pos = dragging_position - sep * (p_clamp_index - i) - accumulated_min_size;
- if (dragger_positions[i] > push_pos) {
- dragger_positions[i] = push_pos;
- }
- accumulated_min_size += (int)valid_children[i]->get_combined_minimum_size()[axis];
- }
- // Push overlapping draggers to the right.
- accumulated_min_size = 0;
- for (int i = p_clamp_index + 1; i < (int)dragger_positions.size(); i++) {
- accumulated_min_size += (int)valid_children[i]->get_combined_minimum_size()[axis];
- const int push_pos = dragging_position + sep * (i - p_clamp_index) + accumulated_min_size;
- if (dragger_positions[i] < push_pos) {
- dragger_positions[i] = push_pos;
- }
- }
- }
- // Clamp the split_offset if requested.
- if (p_clamp_index != -1) {
- for (int i = 0; i < (int)dragger_positions.size(); i++) {
- split_offsets.write[i] = dragger_positions[i] - default_dragger_positions[i];
- }
- }
- // Invert if rtl.
- if (!vertical && is_layout_rtl()) {
- for (int i = 0; i < (int)dragger_positions.size(); i++) {
- dragger_positions[i] = size - dragger_positions[i] - sep;
- }
- }
- }
- void SplitContainer::_resort() {
- if (!is_visible_in_tree()) {
- return;
- }
- if (valid_children.size() < 2u) {
- if (valid_children.size() == 1u) {
- // Only one valid child.
- Control *child = valid_children[0];
- fit_child_in_rect(child, Rect2(Point2(), get_size()));
- }
- for (SplitContainerDragger *dragger : dragging_area_controls) {
- dragger->hide();
- }
- return;
- }
- for (SplitContainerDragger *dragger : dragging_area_controls) {
- dragger->set_visible(!collapsed);
- if (touch_dragger_enabled) {
- dragger->touch_dragger->set_visible(dragging_enabled);
- }
- }
- _update_default_dragger_positions();
- _update_dragger_positions();
- const int sep = _get_separation();
- const int axis = vertical ? 1 : 0;
- const Size2i new_size = get_size();
- const bool rtl = is_layout_rtl();
- // Move the children.
- for (int i = 0; i < (int)valid_children.size(); i++) {
- Control *child = valid_children[i];
- int start_pos;
- int end_pos;
- if (!vertical && rtl) {
- start_pos = i >= (int)dragger_positions.size() ? 0 : dragger_positions[i] + sep;
- end_pos = i == 0 ? new_size[axis] : dragger_positions[i - 1];
- } else {
- start_pos = i == 0 ? 0 : dragger_positions[i - 1] + sep;
- end_pos = i >= (int)dragger_positions.size() ? new_size[axis] : dragger_positions[i];
- }
- int size = end_pos - start_pos;
- if (vertical) {
- fit_child_in_rect(child, Rect2(Point2(0, start_pos), Size2(new_size.width, size)));
- } else {
- fit_child_in_rect(child, Rect2(Point2(start_pos, 0), Size2(size, new_size.height)));
- }
- }
- _update_draggers();
- // Update dragger positions.
- const int dragger_ctrl_size = MAX(sep, theme_cache.minimum_grab_thickness);
- const float split_bar_offset = (dragger_ctrl_size - sep) * 0.5;
- ERR_FAIL_COND(dragging_area_controls.size() != dragger_positions.size());
- for (int i = 0; i < (int)dragger_positions.size(); i++) {
- dragging_area_controls[i]->set_mouse_filter(dragging_enabled ? MOUSE_FILTER_STOP : MOUSE_FILTER_IGNORE);
- if (vertical) {
- const Rect2 split_bar_rect = Rect2(rtl ? drag_area_margin_end : drag_area_margin_begin, dragger_positions[i], new_size.width - drag_area_margin_begin - drag_area_margin_end, sep);
- dragging_area_controls[i]->set_rect(Rect2(split_bar_rect.position.x, split_bar_rect.position.y - split_bar_offset + drag_area_offset, split_bar_rect.size.x, dragger_ctrl_size));
- dragging_area_controls[i]->split_bar_rect = Rect2(Vector2(0.0, int(split_bar_offset) - drag_area_offset), split_bar_rect.size);
- } else {
- const Rect2 split_bar_rect = Rect2(dragger_positions[i], drag_area_margin_begin, sep, new_size.height - drag_area_margin_begin - drag_area_margin_end);
- dragging_area_controls[i]->set_rect(Rect2(split_bar_rect.position.x - split_bar_offset + drag_area_offset * (rtl ? -1 : 1), split_bar_rect.position.y, dragger_ctrl_size, split_bar_rect.size.y));
- dragging_area_controls[i]->split_bar_rect = Rect2(Vector2(int(split_bar_offset) - drag_area_offset * (rtl ? -1 : 1), 0.0), split_bar_rect.size);
- }
- dragging_area_controls[i]->queue_redraw();
- }
- queue_redraw();
- }
- void SplitContainer::_update_draggers() {
- const int valid_child_count = (int)valid_children.size();
- const int dragger_count = MAX(valid_child_count - 1, 1);
- const int draggers_size_diff = dragger_count - (int)dragging_area_controls.size();
- // Add new draggers.
- for (int i = 0; i < draggers_size_diff; i++) {
- SplitContainerDragger *dragger = memnew(SplitContainerDragger);
- dragging_area_controls.push_back(dragger);
- add_child(dragger, false, Node::INTERNAL_MODE_BACK);
- if (touch_dragger_enabled) {
- dragger->set_touch_dragger_enabled(true);
- }
- }
- // Remove extra draggers.
- for (int i = 0; i < -draggers_size_diff; i++) {
- const int remove_at = (int)dragging_area_controls.size() - 1;
- SplitContainerDragger *dragger = dragging_area_controls[remove_at];
- dragging_area_controls.remove_at(remove_at);
- // replace_by removes all children, so make sure it is a child before removing.
- if (dragger->get_parent() == this) {
- remove_child(dragger);
- }
- memdelete(dragger);
- }
- // Make sure draggers have the correct index.
- for (int i = 0; i < (int)dragging_area_controls.size(); i++) {
- dragging_area_controls[i]->dragger_index = i;
- }
- }
- Size2 SplitContainer::get_minimum_size() const {
- const int sep = _get_separation();
- const int axis = vertical ? 1 : 0;
- const int other_axis = vertical ? 0 : 1;
- Size2i minimum;
- if (valid_children.size() >= 2u) {
- minimum[axis] += sep * ((int)valid_children.size() - 1);
- }
- for (const Control *child : valid_children) {
- const Size2 min_size = child->get_combined_minimum_size();
- minimum[axis] += (int)min_size[axis];
- minimum[other_axis] = (int)MAX(minimum[other_axis], min_size[other_axis]);
- }
- return minimum;
- }
- void SplitContainer::_validate_property(PropertyInfo &p_property) const {
- if (is_fixed && p_property.name == "vertical") {
- p_property.usage = PROPERTY_USAGE_NONE;
- }
- }
- void SplitContainer::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_TRANSLATION_CHANGED:
- case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- queue_sort();
- } break;
- case NOTIFICATION_POSTINITIALIZE: {
- initialized = true;
- } break;
- case NOTIFICATION_SORT_CHILDREN: {
- _resort();
- } break;
- case NOTIFICATION_THEME_CHANGED: {
- update_minimum_size();
- } break;
- case NOTIFICATION_PREDELETE: {
- valid_children.clear();
- dragging_area_controls.clear();
- } break;
- }
- }
- void SplitContainer::add_child_notify(Node *p_child) {
- Container::add_child_notify(p_child);
- if (p_child->is_internal()) {
- return;
- }
- Control *child = as_sortable_control(p_child, SortableVisibilityMode::IGNORE);
- if (!child) {
- return;
- }
- child->connect(SceneStringName(visibility_changed), callable_mp(this, &SplitContainer::_on_child_visibility_changed).bind(child));
- if (child->is_visible()) {
- _add_valid_child(child);
- }
- }
- void SplitContainer::remove_child_notify(Node *p_child) {
- Container::remove_child_notify(p_child);
- if (p_child->is_internal()) {
- return;
- }
- Control *child = as_sortable_control(p_child, SortableVisibilityMode::IGNORE);
- if (!child) {
- return;
- }
- child->disconnect(SceneStringName(visibility_changed), callable_mp(this, &SplitContainer::_on_child_visibility_changed));
- if (child->is_visible()) {
- _remove_valid_child(child);
- }
- }
- void SplitContainer::move_child_notify(Node *p_child) {
- Container::move_child_notify(p_child);
- Control *moved_child = as_sortable_control(p_child, SortableVisibilityMode::IGNORE);
- const int prev_index = valid_children.find(moved_child);
- if (prev_index == -1) {
- return;
- }
- PackedInt32Array desired_sizes;
- if (initialized && !split_offset_pending && valid_children.size() > 2u && split_offsets.size() == (int)default_dragger_positions.size()) {
- desired_sizes = _get_desired_sizes();
- }
- valid_children.remove_at(prev_index);
- // Get new index.
- int index = 0;
- for (int i = 0; i < get_child_count(false); i++) {
- Control *child = as_sortable_control(get_child(i, false), SortableVisibilityMode::IGNORE);
- if (!child) {
- continue;
- }
- if (child == moved_child) {
- break;
- }
- if (valid_children.has(child)) {
- index++;
- }
- }
- valid_children.insert(index, moved_child);
- if (desired_sizes.is_empty()) {
- return;
- }
- const int prev_desired_size = desired_sizes[prev_index];
- desired_sizes.remove_at(prev_index);
- desired_sizes.insert(index, prev_desired_size);
- _set_desired_sizes(desired_sizes, index);
- }
- void SplitContainer::_on_child_visibility_changed(Control *p_control) {
- if (p_control->is_visible()) {
- _add_valid_child(p_control);
- } else {
- _remove_valid_child(p_control);
- }
- }
- void SplitContainer::_add_valid_child(Control *p_control) {
- if (valid_children.has(p_control)) {
- return;
- }
- // Get index to insert.
- bool child_is_valid = false;
- int index = 0;
- for (int i = 0; i < get_child_count(false); i++) {
- Control *child = as_sortable_control(get_child(i, false), SortableVisibilityMode::IGNORE);
- if (!child) {
- continue;
- }
- if (child == p_control) {
- if (child->is_visible()) {
- child_is_valid = true;
- }
- break;
- }
- if (valid_children.has(child)) {
- index++;
- }
- }
- if (!child_is_valid) {
- return;
- }
- PackedInt32Array desired_sizes;
- if (initialized && can_use_desired_sizes && !split_offset_pending && valid_children.size() >= 2u && split_offsets.size() == (int)default_dragger_positions.size()) {
- desired_sizes = _get_desired_sizes();
- }
- valid_children.insert(index, p_control);
- if (!initialized) {
- // If not initialized, the theme cache isn't ready yet so return early.
- return;
- }
- _update_default_dragger_positions();
- queue_sort();
- if (valid_children.size() <= 2u) {
- // Already have first dragger.
- return;
- }
- // Call deferred in case already adding or removing children.
- callable_mp(this, &SplitContainer::_update_draggers).call_deferred();
- if (split_offset_pending && split_offsets.size() == (int)valid_children.size() - 1) {
- split_offset_pending = false;
- }
- if (desired_sizes.is_empty()) {
- return;
- }
- // Use the child's existing size as it's desired size.
- const int axis = vertical ? 1 : 0;
- desired_sizes.insert(index, (int)p_control->get_size()[axis]);
- _set_desired_sizes(desired_sizes, index);
- }
- void SplitContainer::_remove_valid_child(Control *p_control) {
- const int index = valid_children.find(p_control);
- if (index == -1) {
- return;
- }
- PackedInt32Array desired_sizes;
- if (initialized && !split_offset_pending && valid_children.size() > 2u && split_offsets.size() == (int)default_dragger_positions.size()) {
- desired_sizes = _get_desired_sizes();
- }
- valid_children.remove_at(index);
- if (!initialized) {
- return;
- }
- // Only use desired sizes to change the split offset after the first time a child is removed.
- // This allows adding children to not affect the split offsets when creating.
- can_use_desired_sizes = true;
- _update_default_dragger_positions();
- queue_sort();
- if (valid_children.size() <= 1u) {
- // Don't remove last dragger.
- return;
- }
- // Call deferred in case already adding or removing children.
- callable_mp(this, &SplitContainer::_update_draggers).call_deferred();
- if (split_offset_pending && split_offsets.size() == (int)valid_children.size() - 2) {
- split_offset_pending = false;
- }
- if (desired_sizes.is_empty()) {
- return;
- }
- desired_sizes.remove_at(index);
- _set_desired_sizes(desired_sizes);
- }
- void SplitContainer::set_split_offset(int p_offset, int p_index) {
- ERR_FAIL_INDEX(p_index, split_offsets.size());
- if (split_offsets[p_index] == p_offset) {
- return;
- }
- split_offsets.write[p_index] = p_offset;
- queue_sort();
- }
- int SplitContainer::get_split_offset(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, split_offsets.size(), 0);
- return split_offsets[p_index];
- }
- void SplitContainer::set_split_offsets(const PackedInt32Array &p_offsets) {
- if (split_offsets == p_offsets) {
- return;
- }
- split_offsets = p_offsets;
- split_offset_pending = split_offsets.size() > 1 && (int)valid_children.size() - 1 != split_offsets.size();
- queue_sort();
- }
- PackedInt32Array SplitContainer::get_split_offsets() const {
- return split_offsets;
- }
- void SplitContainer::clamp_split_offset(int p_priority_index) {
- ERR_FAIL_INDEX(p_priority_index, split_offsets.size());
- if (valid_children.size() < 2u) {
- // Needs at least two children.
- return;
- }
- _update_dragger_positions(p_priority_index);
- queue_sort();
- }
- void SplitContainer::set_collapsed(bool p_collapsed) {
- if (collapsed == p_collapsed) {
- return;
- }
- collapsed = p_collapsed;
- queue_sort();
- }
- void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) {
- if (dragger_visibility == p_visibility) {
- return;
- }
- dragger_visibility = p_visibility;
- queue_sort();
- }
- SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const {
- return dragger_visibility;
- }
- bool SplitContainer::is_collapsed() const {
- return collapsed;
- }
- void SplitContainer::set_vertical(bool p_vertical) {
- ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
- if (vertical == p_vertical) {
- return;
- }
- vertical = p_vertical;
- for (SplitContainerDragger *dragger : dragging_area_controls) {
- dragger->update_touch_dragger();
- }
- update_minimum_size();
- _resort();
- }
- bool SplitContainer::is_vertical() const {
- return vertical;
- }
- void SplitContainer::set_dragging_enabled(bool p_enabled) {
- if (dragging_enabled == p_enabled) {
- return;
- }
- dragging_enabled = p_enabled;
- if (!dragging_enabled) {
- bool was_dragging = false;
- for (SplitContainerDragger *dragger : dragging_area_controls) {
- was_dragging |= dragger->dragging;
- dragger->dragging = false;
- }
- if (was_dragging) {
- emit_signal(SNAME("drag_ended"));
- }
- }
- if (get_viewport()) {
- get_viewport()->update_mouse_cursor_state();
- }
- _resort();
- }
- bool SplitContainer::is_dragging_enabled() const {
- return dragging_enabled;
- }
- Vector<int> SplitContainer::get_allowed_size_flags_horizontal() const {
- Vector<int> flags;
- flags.append(SIZE_FILL);
- if (!vertical) {
- flags.append(SIZE_EXPAND);
- }
- flags.append(SIZE_SHRINK_BEGIN);
- flags.append(SIZE_SHRINK_CENTER);
- flags.append(SIZE_SHRINK_END);
- return flags;
- }
- Vector<int> SplitContainer::get_allowed_size_flags_vertical() const {
- Vector<int> flags;
- flags.append(SIZE_FILL);
- if (vertical) {
- flags.append(SIZE_EXPAND);
- }
- flags.append(SIZE_SHRINK_BEGIN);
- flags.append(SIZE_SHRINK_CENTER);
- flags.append(SIZE_SHRINK_END);
- return flags;
- }
- void SplitContainer::set_drag_area_margin_begin(int p_margin) {
- if (drag_area_margin_begin == p_margin) {
- return;
- }
- drag_area_margin_begin = p_margin;
- queue_sort();
- }
- int SplitContainer::get_drag_area_margin_begin() const {
- return drag_area_margin_begin;
- }
- void SplitContainer::set_drag_area_margin_end(int p_margin) {
- if (drag_area_margin_end == p_margin) {
- return;
- }
- drag_area_margin_end = p_margin;
- queue_sort();
- }
- int SplitContainer::get_drag_area_margin_end() const {
- return drag_area_margin_end;
- }
- void SplitContainer::set_drag_area_offset(int p_offset) {
- if (drag_area_offset == p_offset) {
- return;
- }
- drag_area_offset = p_offset;
- queue_sort();
- }
- int SplitContainer::get_drag_area_offset() const {
- return drag_area_offset;
- }
- void SplitContainer::set_show_drag_area_enabled(bool p_enabled) {
- show_drag_area = p_enabled;
- for (SplitContainerDragger *dragger : dragging_area_controls) {
- dragger->queue_redraw();
- }
- }
- bool SplitContainer::is_show_drag_area_enabled() const {
- return show_drag_area;
- }
- TypedArray<Control> SplitContainer::get_drag_area_controls() {
- TypedArray<Control> controls;
- controls.resize((int)dragging_area_controls.size());
- for (int i = 0; i < (int)dragging_area_controls.size(); i++) {
- controls[i] = dragging_area_controls[i];
- }
- return controls;
- }
- void SplitContainer::set_touch_dragger_enabled(bool p_enabled) {
- if (touch_dragger_enabled == p_enabled) {
- return;
- }
- touch_dragger_enabled = p_enabled;
- for (SplitContainerDragger *dragger : dragging_area_controls) {
- dragger->set_touch_dragger_enabled(p_enabled);
- }
- }
- bool SplitContainer::is_touch_dragger_enabled() const {
- return touch_dragger_enabled;
- }
- void SplitContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_split_offsets", "offsets"), &SplitContainer::set_split_offsets);
- ClassDB::bind_method(D_METHOD("get_split_offsets"), &SplitContainer::get_split_offsets);
- ClassDB::bind_method(D_METHOD("clamp_split_offset", "priority_index"), &SplitContainer::clamp_split_offset, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("set_collapsed", "collapsed"), &SplitContainer::set_collapsed);
- ClassDB::bind_method(D_METHOD("is_collapsed"), &SplitContainer::is_collapsed);
- ClassDB::bind_method(D_METHOD("set_dragger_visibility", "mode"), &SplitContainer::set_dragger_visibility);
- ClassDB::bind_method(D_METHOD("get_dragger_visibility"), &SplitContainer::get_dragger_visibility);
- ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &SplitContainer::set_vertical);
- ClassDB::bind_method(D_METHOD("is_vertical"), &SplitContainer::is_vertical);
- ClassDB::bind_method(D_METHOD("set_dragging_enabled", "dragging_enabled"), &SplitContainer::set_dragging_enabled);
- ClassDB::bind_method(D_METHOD("is_dragging_enabled"), &SplitContainer::is_dragging_enabled);
- ClassDB::bind_method(D_METHOD("set_drag_area_margin_begin", "margin"), &SplitContainer::set_drag_area_margin_begin);
- ClassDB::bind_method(D_METHOD("get_drag_area_margin_begin"), &SplitContainer::get_drag_area_margin_begin);
- ClassDB::bind_method(D_METHOD("set_drag_area_margin_end", "margin"), &SplitContainer::set_drag_area_margin_end);
- ClassDB::bind_method(D_METHOD("get_drag_area_margin_end"), &SplitContainer::get_drag_area_margin_end);
- ClassDB::bind_method(D_METHOD("set_drag_area_offset", "offset"), &SplitContainer::set_drag_area_offset);
- ClassDB::bind_method(D_METHOD("get_drag_area_offset"), &SplitContainer::get_drag_area_offset);
- ClassDB::bind_method(D_METHOD("set_drag_area_highlight_in_editor", "drag_area_highlight_in_editor"), &SplitContainer::set_show_drag_area_enabled);
- ClassDB::bind_method(D_METHOD("is_drag_area_highlight_in_editor_enabled"), &SplitContainer::is_show_drag_area_enabled);
- ClassDB::bind_method(D_METHOD("get_drag_area_controls"), &SplitContainer::get_drag_area_controls);
- ClassDB::bind_method(D_METHOD("set_touch_dragger_enabled", "enabled"), &SplitContainer::set_touch_dragger_enabled);
- ClassDB::bind_method(D_METHOD("is_touch_dragger_enabled"), &SplitContainer::is_touch_dragger_enabled);
- ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::INT, "offset")));
- ADD_SIGNAL(MethodInfo("drag_started"));
- ADD_SIGNAL(MethodInfo("drag_ended"));
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "split_offsets", PROPERTY_HINT_NONE, "suffix:px"), "set_split_offsets", "get_split_offsets");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dragging_enabled"), "set_dragging_enabled", "is_dragging_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden and Collapsed"), "set_dragger_visibility", "get_dragger_visibility");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "touch_dragger_enabled"), "set_touch_dragger_enabled", "is_touch_dragger_enabled");
- ADD_GROUP("Drag Area", "drag_area_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "drag_area_margin_begin", PROPERTY_HINT_NONE, "suffix:px"), "set_drag_area_margin_begin", "get_drag_area_margin_begin");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "drag_area_margin_end", PROPERTY_HINT_NONE, "suffix:px"), "set_drag_area_margin_end", "get_drag_area_margin_end");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "drag_area_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_drag_area_offset", "get_drag_area_offset");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_area_highlight_in_editor"), "set_drag_area_highlight_in_editor", "is_drag_area_highlight_in_editor_enabled");
- BIND_ENUM_CONSTANT(DRAGGER_VISIBLE);
- BIND_ENUM_CONSTANT(DRAGGER_HIDDEN);
- BIND_ENUM_CONSTANT(DRAGGER_HIDDEN_COLLAPSED);
- BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, SplitContainer, touch_dragger_color);
- BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, SplitContainer, touch_dragger_pressed_color);
- BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, SplitContainer, touch_dragger_hover_color);
- BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, separation);
- BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, minimum_grab_thickness);
- BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, autohide);
- BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, touch_dragger_icon, "touch_dragger");
- BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, touch_dragger_icon_h, "h_touch_dragger");
- BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, touch_dragger_icon_v, "v_touch_dragger");
- BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon, "grabber");
- BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_h, "h_grabber");
- BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_v, "v_grabber");
- BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, SplitContainer, split_bar_background, "split_bar_background");
- #ifndef DISABLE_DEPRECATED
- ClassDB::bind_method(D_METHOD("get_drag_area_control"), &SplitContainer::get_drag_area_control);
- ClassDB::bind_method(D_METHOD("set_split_offset", "offset"), &SplitContainer::_set_split_offset_first);
- ClassDB::bind_method(D_METHOD("get_split_offset"), &SplitContainer::_get_split_offset_first);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "split_offset", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_NO_EDITOR), "set_split_offset", "get_split_offset");
- #endif // DISABLE_DEPRECATED
- }
- SplitContainer::SplitContainer(bool p_vertical) {
- vertical = p_vertical;
- split_offsets.push_back(0);
- SplitContainerDragger *dragger = memnew(SplitContainerDragger);
- dragging_area_controls.push_back(dragger);
- add_child(dragger, false, Node::INTERNAL_MODE_BACK);
- }
|