Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions doc/classes/ScrollContainer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
<member name="scroll_deadzone" type="int" setter="set_deadzone" getter="get_deadzone" default="0">
Deadzone for touch scrolling. Lower deadzone makes the scrolling more sensitive.
</member>
<member name="scroll_hint_mode" type="int" setter="set_scroll_hint_mode" getter="get_scroll_hint_mode" enum="ScrollContainer.ScrollHintMode" default="0">
The way which scroll hints (indicators that show that the content can still be scrolled in a certain direction) will be shown.
[b]Note:[/b] Hints won't be shown if the content can be scrolled both vertically and horizontally.
</member>
<member name="scroll_horizontal" type="int" setter="set_h_scroll" getter="get_h_scroll" default="0">
The current horizontal scroll value.
[b]Note:[/b] If you are setting this value in the [method Node._ready] function or earlier, it needs to be wrapped with [method Object.set_deferred], since scroll bar's [member Range.max_value] is not initialized yet.
Expand All @@ -74,6 +78,9 @@
<member name="scroll_vertical_custom_step" type="float" setter="set_vertical_custom_step" getter="get_vertical_custom_step" default="-1.0">
Overrides the [member ScrollBar.custom_step] used when clicking the internal scroll bar's vertical increment and decrement buttons or when using arrow keys when the [ScrollBar] is focused.
</member>
<member name="tile_scroll_hint" type="bool" setter="set_tile_scroll_hint" getter="is_scroll_hint_tiled" default="false">
If [code]true[/code], the scroll hint texture will be tiled instead of stretched. See [member scroll_hint_mode].
</member>
<member name="vertical_scroll_mode" type="int" setter="set_vertical_scroll_mode" getter="get_vertical_scroll_mode" enum="ScrollContainer.ScrollMode" default="1">
Controls whether vertical scrollbar can be used and when it should be visible.
</member>
Expand Down Expand Up @@ -108,6 +115,18 @@
<constant name="SCROLL_MODE_RESERVE" value="4" enum="ScrollMode">
Combines [constant SCROLL_MODE_AUTO] and [constant SCROLL_MODE_SHOW_ALWAYS]. The scrollbar is only visible if necessary, but the content size is adjusted as if it was always visible. It's useful for ensuring that content size stays the same regardless if the scrollbar is visible.
</constant>
<constant name="SCROLL_HINT_MODE_DISABLED" value="0" enum="ScrollHintMode">
Scroll hints will never be shown.
</constant>
<constant name="SCROLL_HINT_MODE_ALL" value="1" enum="ScrollHintMode">
Scroll hints will be shown at the top and bottom (if vertical), or left and right (if horizontal).
</constant>
<constant name="SCROLL_HINT_MODE_TOP_AND_LEFT" value="2" enum="ScrollHintMode">
Scroll hints will be shown at the top (if vertical), or the left (if horizontal).
</constant>
<constant name="SCROLL_HINT_MODE_BOTTOM_AND_RIGHT" value="3" enum="ScrollHintMode">
Scroll hints will be shown at the bottom (if horizontal), or the right (if horizontal).
</constant>
</constants>
<theme_items>
<theme_item name="scrollbar_h_separation" data_type="constant" type="int" default="0">
Expand All @@ -116,6 +135,12 @@
<theme_item name="scrollbar_v_separation" data_type="constant" type="int" default="0">
The space between the ScrollContainer's horizontal scroll bar and its content, in pixels. No space will be added when the content's minimum size is larger than the ScrollContainer's size.
</theme_item>
<theme_item name="scroll_hint_horizontal" data_type="icon" type="Texture2D">
The indicator that will be shown when the content can still be scrolled horizontally. See [member scroll_hint_mode].
</theme_item>
<theme_item name="scroll_hint_vertical" data_type="icon" type="Texture2D">
The indicator that will be shown when the content can still be scrolled vertically. See [member scroll_hint_mode].
</theme_item>
<theme_item name="focus" data_type="style" type="StyleBox">
The focus border [StyleBox] of the [ScrollContainer]. Only used if [member draw_focus_border] is [code]true[/code].
</theme_item>
Expand Down
21 changes: 21 additions & 0 deletions doc/classes/Tree.xml
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,9 @@
<member name="hide_root" type="bool" setter="set_hide_root" getter="is_root_hidden" default="false">
If [code]true[/code], the tree's root is hidden.
</member>
<member name="scroll_hint_mode" type="int" setter="set_scroll_hint_mode" getter="get_scroll_hint_mode" enum="Tree.ScrollHintMode" default="0">
The way which scroll hints (indicators that show that the content can still be scrolled in a certain direction) will be shown.
</member>
<member name="scroll_horizontal_enabled" type="bool" setter="set_h_scroll_enabled" getter="is_h_scroll_enabled" default="true">
If [code]true[/code], enables horizontal scrolling.
</member>
Expand All @@ -392,6 +395,9 @@
<member name="select_mode" type="int" setter="set_select_mode" getter="get_select_mode" enum="Tree.SelectMode" default="0">
Allows single or multiple selection. See the [enum SelectMode] constants.
</member>
<member name="tile_scroll_hint" type="bool" setter="set_tile_scroll_hint" getter="is_scroll_hint_tiled" default="false">
If [code]true[/code], the scroll hint texture will be tiled instead of stretched. See [member scroll_hint_mode].
</member>
</members>
<signals>
<signal name="button_clicked">
Expand Down Expand Up @@ -514,6 +520,18 @@
Enables "above item" and "below item" drop sections. The "above item" drop section covers the top half of the item, and the "below item" drop section covers the bottom half.
When combined with [constant DROP_MODE_ON_ITEM], these drop sections halves the height and stays on top / bottom accordingly.
</constant>
<constant name="SCROLL_HINT_MODE_DISABLED" value="0" enum="ScrollHintMode">
Scroll hints will never be shown.
</constant>
<constant name="SCROLL_HINT_MODE_BOTH" value="1" enum="ScrollHintMode">
Scroll hints will be shown at the top and bottom.
</constant>
<constant name="SCROLL_HINT_MODE_TOP" value="2" enum="ScrollHintMode">
Only the top scroll hint will be shown.
</constant>
<constant name="SCROLL_HINT_MODE_BOTTOM" value="3" enum="ScrollHintMode">
Only the bottom scroll hint will be shown.
</constant>
</constants>
<theme_items>
<theme_item name="children_hl_line_color" data_type="color" type="Color" default="Color(0.27, 0.27, 0.27, 1)">
Expand Down Expand Up @@ -667,6 +685,9 @@
<theme_item name="indeterminate_disabled" data_type="icon" type="Texture2D">
The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode cell is indeterminate and non-editable (see [method TreeItem.set_editable]).
</theme_item>
<theme_item name="scroll_hint" data_type="icon" type="Texture2D">
The indicator that will be shown when the content can still be scrolled. See [member scroll_hint_mode].
</theme_item>
<theme_item name="select_arrow" data_type="icon" type="Texture2D">
The arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] mode cell.
</theme_item>
Expand Down
1 change: 1 addition & 0 deletions editor/docks/inspector_dock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
inspector->set_property_name_style(property_name_style);
inspector->set_use_folding(!bool(EDITOR_GET("interface/inspector/disable_folding")));
inspector->register_text_enter(search);
inspector->set_scroll_hint_mode(ScrollContainer::SCROLL_HINT_MODE_TOP_AND_LEFT);

inspector->set_use_filter(true);

Expand Down
8 changes: 8 additions & 0 deletions editor/themes/theme_classic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "editor/themes/editor_scale.h"
#include "editor/themes/editor_theme_manager.h"
#include "scene/gui/graph_edit.h"
#include "scene/resources/compressed_texture.h"
#include "scene/resources/dpi_texture.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/style_box_flat.h"
Expand Down Expand Up @@ -1551,6 +1552,13 @@ void ThemeClassic::populate_editor_styles(const Ref<EditorTheme> &p_theme, Edito
Ref<StyleBoxFlat> style_widget_scroll_container = p_config.button_style_focus->duplicate();
p_theme->set_stylebox("focus", "ScrollContainer", style_widget_scroll_container);

// Hide scroll hints.
Ref<CompressedTexture2D> empty_texture;
empty_texture.instantiate();
p_theme->set_icon("scroll_hint_vertical", "ScrollContainer", empty_texture);
p_theme->set_icon("scroll_hint_horizontal", "ScrollContainer", empty_texture);
p_theme->set_icon("scroll_hint", "Tree", empty_texture);

// This stylebox is used in 3d and 2d viewports (no borders).
Ref<StyleBoxFlat> style_content_panel_vp = p_config.content_panel_style->duplicate();
style_content_panel_vp->set_content_margin_individual(p_config.border_width * 2, p_config.base_margin * EDSCALE, p_config.border_width * 2, p_config.border_width * 2);
Expand Down
115 changes: 105 additions & 10 deletions scene/gui/scroll_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include "core/config/project_settings.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/main/window.h"
#include "scene/theme/theme_db.h"

Expand Down Expand Up @@ -343,6 +344,7 @@ void ScrollContainer::ensure_control_visible(Control *p_control) {

void ScrollContainer::_reposition_children() {
update_scrollbars();
update_scroll_hints();

Rect2 margins = _get_margins();
Size2 size = get_size();
Expand All @@ -362,10 +364,7 @@ void ScrollContainer::_reposition_children() {

for (int i = 0; i < get_child_count(); i++) {
Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
if (c == h_scroll || c == v_scroll || c == focus_panel) {
if (!c || c->is_internal()) {
continue;
}
Size2 minsize = c->get_combined_minimum_size();
Expand Down Expand Up @@ -445,7 +444,10 @@ void ScrollContainer::_notification(int p_what) {
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SET_SCROLL_OFFSET, callable_mp(this, &ScrollContainer::_accessibility_action_scroll_set));
} break;

case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
update_scroll_hints();
[[fallthrough]];
}
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
_updating_scrollbars = true;
Expand Down Expand Up @@ -602,6 +604,48 @@ void ScrollContainer::update_scrollbars() {
callable_mp(this, &ScrollContainer::_update_scrollbar_position).call_deferred();
}

void ScrollContainer::update_scroll_hints() {
Size2 size = get_size();
Rect2 margins = _get_margins();
Size2 scroll_size = size - margins.position + margins.size;

float v_scroll_value = v_scroll->get_value();
bool v_scroll_below_max = v_scroll_value < (largest_child_min_size.height - scroll_size.height - 1);
bool show_vertical_hints = v_scroll_value > 1 || v_scroll_below_max;

float h_scroll_value = h_scroll->get_value();
bool h_scroll_below_max = h_scroll_value < (largest_child_min_size.width - scroll_size.width - 1);
bool show_horizontal_hints = h_scroll_value > 1 || h_scroll_below_max;

if (show_vertical_hints) {
scroll_hint_top_left->set_texture(theme_cache.scroll_hint_vertical);
scroll_hint_top_left->set_visible(!show_horizontal_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || scroll_hint_mode == SCROLL_HINT_MODE_TOP_AND_LEFT) && v_scroll_value > 1);
scroll_hint_top_left->set_offsets_preset(PRESET_TOP_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);

scroll_hint_bottom_right->set_flip_h(false);
scroll_hint_bottom_right->set_flip_v(true);
scroll_hint_bottom_right->set_texture(theme_cache.scroll_hint_vertical);
scroll_hint_bottom_right->set_visible(!show_horizontal_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || scroll_hint_mode == SCROLL_HINT_MODE_BOTTOM_AND_RIGHT) && v_scroll_below_max);
scroll_hint_bottom_right->set_offsets_preset(PRESET_BOTTOM_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);
} else {
bool rtl = is_layout_rtl();

scroll_hint_top_left->set_texture(theme_cache.scroll_hint_horizontal);
scroll_hint_top_left->set_visible(!show_vertical_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || (rtl ? scroll_hint_mode == SCROLL_HINT_MODE_BOTTOM_AND_RIGHT : scroll_hint_mode == SCROLL_HINT_MODE_TOP_AND_LEFT)) && h_scroll_value > 1);
scroll_hint_top_left->set_offsets_preset(rtl ? PRESET_RIGHT_WIDE : PRESET_LEFT_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);
if (rtl) {
// TODO: Find out why this is even necessary.
scroll_hint_top_left->set_position(Point2(0, scroll_hint_top_left->get_position().y));
}
Comment on lines +636 to +639
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no clue why, but this is necessary for this hint to be positioned properly.


scroll_hint_bottom_right->set_flip_h(true);
scroll_hint_bottom_right->set_flip_v(false);
scroll_hint_bottom_right->set_texture(theme_cache.scroll_hint_horizontal);
scroll_hint_bottom_right->set_visible(!show_vertical_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || (rtl ? scroll_hint_mode == SCROLL_HINT_MODE_TOP_AND_LEFT : scroll_hint_mode == SCROLL_HINT_MODE_BOTTOM_AND_RIGHT)) && h_scroll_below_max);
scroll_hint_bottom_right->set_offsets_preset(rtl ? PRESET_LEFT_WIDE : PRESET_RIGHT_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);
}
}

void ScrollContainer::_scroll_moved(float) {
queue_sort();
}
Expand Down Expand Up @@ -676,6 +720,32 @@ void ScrollContainer::set_deadzone(int p_deadzone) {
deadzone = p_deadzone;
}

void ScrollContainer::set_scroll_hint_mode(ScrollHintMode p_mode) {
if (scroll_hint_mode == p_mode) {
return;
}

scroll_hint_mode = p_mode;
update_scroll_hints();
}

ScrollContainer::ScrollHintMode ScrollContainer::get_scroll_hint_mode() const {
return scroll_hint_mode;
}

void ScrollContainer::set_tile_scroll_hint(bool p_enable) {
if (tile_scroll_hint != p_enable) {
return;
}

tile_scroll_hint = p_enable;
update_scroll_hints();
}

bool ScrollContainer::is_scroll_hint_tiled() {
return tile_scroll_hint;
}

bool ScrollContainer::is_following_focus() const {
return follow_focus;
}
Expand All @@ -691,10 +761,7 @@ PackedStringArray ScrollContainer::get_configuration_warnings() const {

for (int i = 0; i < get_child_count(); i++) {
Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE);
if (!c) {
continue;
}
if (c == h_scroll || c == v_scroll || c == focus_panel) {
if (!c || c->is_internal()) {
continue;
}

Expand Down Expand Up @@ -742,6 +809,12 @@ void ScrollContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_deadzone", "deadzone"), &ScrollContainer::set_deadzone);
ClassDB::bind_method(D_METHOD("get_deadzone"), &ScrollContainer::get_deadzone);

ClassDB::bind_method(D_METHOD("set_scroll_hint_mode", "scroll_hint_mode"), &ScrollContainer::set_scroll_hint_mode);
ClassDB::bind_method(D_METHOD("get_scroll_hint_mode"), &ScrollContainer::get_scroll_hint_mode);

ClassDB::bind_method(D_METHOD("set_tile_scroll_hint", "tile_scroll_hint"), &ScrollContainer::set_tile_scroll_hint);
ClassDB::bind_method(D_METHOD("is_scroll_hint_tiled"), &ScrollContainer::is_scroll_hint_tiled);

ClassDB::bind_method(D_METHOD("set_follow_focus", "enabled"), &ScrollContainer::set_follow_focus);
ClassDB::bind_method(D_METHOD("is_following_focus"), &ScrollContainer::is_following_focus);

Expand All @@ -758,7 +831,7 @@ void ScrollContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_focus"), "set_follow_focus", "is_following_focus");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_focus_border"), "set_draw_focus_border", "get_draw_focus_border");

ADD_GROUP("Scroll", "scroll_");
ADD_GROUP("Scrollbar", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal", PROPERTY_HINT_NONE, "suffix:px"), "set_h_scroll", "get_h_scroll");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical", PROPERTY_HINT_NONE, "suffix:px"), "set_v_scroll", "get_v_scroll");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_horizontal_custom_step", PROPERTY_HINT_RANGE, "-1,4096,suffix:px"), "set_horizontal_custom_step", "get_horizontal_custom_step");
Expand All @@ -767,18 +840,30 @@ void ScrollContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_scroll_mode", PROPERTY_HINT_ENUM, "Disabled,Auto,Always Show,Never Show,Reserve"), "set_vertical_scroll_mode", "get_vertical_scroll_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_deadzone"), "set_deadzone", "get_deadzone");

ADD_GROUP("Scroll Hint", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_hint_mode", PROPERTY_HINT_ENUM, "Disabled,All,Top and Left,Bottom and Right"), "set_scroll_hint_mode", "get_scroll_hint_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tile_scroll_hint"), "set_tile_scroll_hint", "is_scroll_hint_tiled");

BIND_ENUM_CONSTANT(SCROLL_MODE_DISABLED);
BIND_ENUM_CONSTANT(SCROLL_MODE_AUTO);
BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_ALWAYS);
BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_NEVER);
BIND_ENUM_CONSTANT(SCROLL_MODE_RESERVE);

BIND_ENUM_CONSTANT(SCROLL_HINT_MODE_DISABLED);
BIND_ENUM_CONSTANT(SCROLL_HINT_MODE_ALL);
BIND_ENUM_CONSTANT(SCROLL_HINT_MODE_TOP_AND_LEFT);
BIND_ENUM_CONSTANT(SCROLL_HINT_MODE_BOTTOM_AND_RIGHT);

BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ScrollContainer, scrollbar_h_separation);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ScrollContainer, scrollbar_v_separation);

BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollContainer, panel_style, "panel");
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollContainer, focus_style, "focus");

BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ScrollContainer, scroll_hint_vertical);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ScrollContainer, scroll_hint_horizontal);

GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
}

Expand All @@ -802,6 +887,16 @@ bool ScrollContainer::child_has_focus() {
}

ScrollContainer::ScrollContainer() {
scroll_hint_top_left = memnew(TextureRect);
scroll_hint_top_left->set_mouse_filter(MOUSE_FILTER_IGNORE);
scroll_hint_top_left->hide();
add_child(scroll_hint_top_left, false, INTERNAL_MODE_BACK);

scroll_hint_bottom_right = memnew(TextureRect);
scroll_hint_bottom_right->set_mouse_filter(MOUSE_FILTER_IGNORE);
scroll_hint_bottom_right->hide();
add_child(scroll_hint_bottom_right, false, INTERNAL_MODE_BACK);

h_scroll = memnew(HScrollBar);
h_scroll->set_name("_h_scroll");
add_child(h_scroll, false, INTERNAL_MODE_BACK);
Expand Down
Loading