475 lines
19 KiB
C++
475 lines
19 KiB
C++
/**************************************************************************/
|
|
/* test_scroll_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 "tests/test_macros.h"
|
|
|
|
TEST_FORCE_LINK(test_scroll_container)
|
|
|
|
#include "scene/gui/control.h"
|
|
#include "scene/gui/scroll_container.h"
|
|
#include "scene/main/scene_tree.h"
|
|
#include "scene/main/window.h"
|
|
|
|
namespace TestScrollContainer {
|
|
|
|
TEST_CASE("[SceneTree][ScrollContainer] Default behavior") {
|
|
ScrollContainer *test_container = memnew(ScrollContainer);
|
|
Window *root = SceneTree::get_singleton()->get_root();
|
|
root->add_child(test_container);
|
|
|
|
Control *test_control = memnew(Control);
|
|
test_control->set_custom_minimum_size(Size2(20, 20));
|
|
test_container->add_child(test_control);
|
|
|
|
test_container->set_size(Size2(100, 100));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_horizontal_scroll_mode() == ScrollContainer::SCROLL_MODE_AUTO,
|
|
"Horizontal scroll mode is SCROLL_MODE_AUTO by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_vertical_scroll_mode() == ScrollContainer::SCROLL_MODE_AUTO,
|
|
"Vertical scroll mode is SCROLL_MODE_AUTO by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_scroll_hint_mode() == ScrollContainer::SCROLL_HINT_MODE_DISABLED,
|
|
"Scroll hint mode is SCROLL_HINT_MODE_DISABLED by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->is_scroll_hint_tiled(),
|
|
"tile_scroll_hint is disabled by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->is_following_focus(),
|
|
"follow_focus is disabled by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->is_scroll_horizontal_by_default(),
|
|
"scroll_horizontal_by_default is disabled by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_draw_focus_border(),
|
|
"draw_focus_border is disabled by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->is_clipping_contents(),
|
|
"clip_contents is enabled by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll() == 0,
|
|
"Horizontal scroll starts at 0 by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll() == 0,
|
|
"Vertical scroll starts at 0 by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll_bar() != nullptr,
|
|
"Horizontal scrollbar is created by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll_bar() != nullptr,
|
|
"Vertical scrollbar is created by default.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_h_scroll_bar()->is_visible(),
|
|
"Horizontal scrollbar is hidden in auto mode when content fits.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_v_scroll_bar()->is_visible(),
|
|
"Vertical scrollbar is hidden in auto mode when content fits.");
|
|
|
|
memdelete(test_control);
|
|
memdelete(test_container);
|
|
}
|
|
|
|
TEST_CASE("[SceneTree][ScrollContainer] Scroll modes") {
|
|
ScrollContainer *test_container = memnew(ScrollContainer);
|
|
Window *root = SceneTree::get_singleton()->get_root();
|
|
root->add_child(test_container);
|
|
Control *test_control = memnew(Control);
|
|
test_container->add_child(test_control);
|
|
test_control->set_custom_minimum_size(Size2(100, 100));
|
|
Control *target_control = memnew(Control);
|
|
target_control->set_custom_minimum_size(Size2(20, 20));
|
|
target_control->set_position(Point2(80, 80));
|
|
target_control->set_size(Size2(20, 20));
|
|
test_control->add_child(target_control);
|
|
|
|
test_container->set_size(Size2(50, 50));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar displays when ScrollContainer width is smaller than contents width with SCROLL_MODE_AUTO.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar displays when ScrollContainer height is smaller than contents height with SCROLL_MODE_AUTO.");
|
|
|
|
test_container->set_size(Size2(150, 150));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar does not display when ScrollContainer width is larger than contents width with SCROLL_MODE_AUTO.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar does not display when ScrollContainer height is larger than contents height with SCROLL_MODE_AUTO.");
|
|
|
|
test_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
|
|
test_container->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
|
|
|
|
test_container->set_size(Size2(50, 50));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar does not display when ScrollContainer width is smaller than contents width with SCROLL_MODE_DISABLED.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar does not display when ScrollContainer height is smaller than contents height with SCROLL_MODE_DISABLED.");
|
|
|
|
test_container->set_h_scroll(0);
|
|
test_container->set_v_scroll(0);
|
|
int disabled_h_scroll_before = test_container->get_h_scroll();
|
|
int disabled_v_scroll_before = test_container->get_v_scroll();
|
|
test_container->ensure_control_visible(target_control);
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll() == disabled_h_scroll_before,
|
|
"SCROLL_MODE_DISABLED does not change horizontal scroll when ensure_control_visible() targets an out-of-view descendant.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll() == disabled_v_scroll_before,
|
|
"SCROLL_MODE_DISABLED does not change vertical scroll when ensure_control_visible() targets an out-of-view descendant.");
|
|
|
|
test_container->set_h_scroll(0);
|
|
test_container->set_v_scroll(0);
|
|
|
|
test_container->set_size(Size2(150, 150));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar does not display when ScrollContainer width is larger than contents width with SCROLL_MODE_DISABLED.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar does not display when ScrollContainer height is larger than contents height with SCROLL_MODE_DISABLED.");
|
|
|
|
test_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_SHOW_ALWAYS);
|
|
test_container->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_SHOW_ALWAYS);
|
|
|
|
test_container->set_size(Size2(50, 50));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar displays when ScrollContainer width is smaller than contents width with SCROLL_MODE_SHOW_ALWAYS.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar displays when ScrollContainer height is smaller than contents height with SCROLL_MODE_SHOW_ALWAYS.");
|
|
|
|
test_container->set_size(Size2(150, 150));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar displays when ScrollContainer width is larger than contents width with SCROLL_MODE_SHOW_ALWAYS.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar displays when ScrollContainer height is larger than contents height with SCROLL_MODE_SHOW_ALWAYS.");
|
|
|
|
test_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_SHOW_NEVER);
|
|
test_container->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_SHOW_NEVER);
|
|
|
|
test_container->set_size(Size2(50, 50));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar does not display when ScrollContainer width is smaller than contents width with SCROLL_MODE_SHOW_NEVER.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar does not display when ScrollContainer height is smaller than contents height with SCROLL_MODE_SHOW_NEVER.");
|
|
|
|
test_container->set_h_scroll(0);
|
|
test_container->set_v_scroll(0);
|
|
int show_never_h_scroll_before = test_container->get_h_scroll();
|
|
int show_never_v_scroll_before = test_container->get_v_scroll();
|
|
test_container->ensure_control_visible(target_control);
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll() > show_never_h_scroll_before,
|
|
"SCROLL_MODE_SHOW_NEVER keeps horizontal scrollbar hidden while still allowing programmatic scrolling.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll() > show_never_v_scroll_before,
|
|
"SCROLL_MODE_SHOW_NEVER keeps vertical scrollbar hidden while still allowing programmatic scrolling.");
|
|
|
|
test_container->set_h_scroll(0);
|
|
test_container->set_v_scroll(0);
|
|
|
|
test_container->set_size(Size2(150, 150));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar does not display when ScrollContainer width is larger than contents width with SCROLL_MODE_SHOW_NEVER.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar does not display when ScrollContainer height is larger than contents height with SCROLL_MODE_SHOW_NEVER.");
|
|
|
|
test_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_RESERVE);
|
|
test_container->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_RESERVE);
|
|
|
|
test_container->set_size(Size2(50, 50));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar displays when ScrollContainer width is smaller than contents width with SCROLL_MODE_RESERVE.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar displays when ScrollContainer height is smaller than contents height with SCROLL_MODE_RESERVE.");
|
|
|
|
test_container->set_size(Size2(150, 150));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_h_scroll_bar()->is_visible(),
|
|
"H Scrollbar does not display when ScrollContainer width is larger than contents width with SCROLL_MODE_RESERVE.");
|
|
|
|
CHECK_MESSAGE(
|
|
!test_container->get_v_scroll_bar()->is_visible(),
|
|
"V Scrollbar does not display when ScrollContainer height is larger than contents height with SCROLL_MODE_RESERVE.");
|
|
|
|
memdelete(test_control);
|
|
memdelete(test_container);
|
|
}
|
|
|
|
TEST_CASE("[SceneTree][ScrollContainer] Scroll values and property setters") {
|
|
ScrollContainer *test_container = memnew(ScrollContainer);
|
|
Window *root = SceneTree::get_singleton()->get_root();
|
|
root->add_child(test_container);
|
|
|
|
Control *test_control = memnew(Control);
|
|
test_control->set_custom_minimum_size(Size2(300, 300));
|
|
test_container->add_child(test_control);
|
|
|
|
test_container->set_size(Size2(100, 100));
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
test_container->set_h_scroll(25);
|
|
test_container->set_v_scroll(35);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll() == 25,
|
|
"Horizontal scroll value is updated by set_h_scroll().");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll() == 35,
|
|
"Vertical scroll value is updated by set_v_scroll().");
|
|
|
|
test_container->set_horizontal_custom_step(7.0f);
|
|
test_container->set_vertical_custom_step(9.0f);
|
|
|
|
CHECK_MESSAGE(
|
|
Math::is_equal_approx(test_container->get_horizontal_custom_step(), 7.0f),
|
|
"Horizontal custom step is updated correctly.");
|
|
|
|
CHECK_MESSAGE(
|
|
Math::is_equal_approx(test_container->get_vertical_custom_step(), 9.0f),
|
|
"Vertical custom step is updated correctly.");
|
|
|
|
test_container->set_deadzone(13);
|
|
CHECK_MESSAGE(
|
|
test_container->get_deadzone() == 13,
|
|
"Deadzone value is updated correctly.");
|
|
|
|
test_container->set_scroll_horizontal_by_default(true);
|
|
CHECK_MESSAGE(
|
|
test_container->is_scroll_horizontal_by_default(),
|
|
"scroll_horizontal_by_default is enabled correctly.");
|
|
|
|
test_container->set_follow_focus(true);
|
|
CHECK_MESSAGE(
|
|
test_container->is_following_focus(),
|
|
"follow_focus is enabled correctly.");
|
|
|
|
test_container->set_scroll_hint_mode(ScrollContainer::SCROLL_HINT_MODE_ALL);
|
|
CHECK_MESSAGE(
|
|
test_container->get_scroll_hint_mode() == ScrollContainer::SCROLL_HINT_MODE_ALL,
|
|
"Scroll hint mode is updated correctly.");
|
|
|
|
test_container->set_tile_scroll_hint(true);
|
|
CHECK_MESSAGE(
|
|
test_container->is_scroll_hint_tiled(),
|
|
"Tiled scroll hint mode is enabled correctly.");
|
|
|
|
test_container->set_draw_focus_border(true);
|
|
CHECK_MESSAGE(
|
|
test_container->get_draw_focus_border(),
|
|
"draw_focus_border is enabled correctly.");
|
|
|
|
memdelete(test_control);
|
|
memdelete(test_container);
|
|
}
|
|
|
|
TEST_CASE("[SceneTree][ScrollContainer] ensure_control_visible and follow_focus") {
|
|
ScrollContainer *test_container = memnew(ScrollContainer);
|
|
Window *root = SceneTree::get_singleton()->get_root();
|
|
root->add_child(test_container);
|
|
|
|
Control *content_control = memnew(Control);
|
|
content_control->set_custom_minimum_size(Size2(300, 300));
|
|
test_container->add_child(content_control);
|
|
|
|
Control *target_control = memnew(Control);
|
|
target_control->set_focus_mode(Control::FOCUS_ALL);
|
|
target_control->set_custom_minimum_size(Size2(20, 20));
|
|
target_control->set_position(Point2(260, 250));
|
|
target_control->set_size(Size2(20, 20));
|
|
content_control->add_child(target_control);
|
|
|
|
test_container->set_size(Size2(100, 100));
|
|
test_container->set_h_scroll(0);
|
|
test_container->set_v_scroll(0);
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll() == 0,
|
|
"Horizontal scroll starts at 0 for this setup.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll() == 0,
|
|
"Vertical scroll starts at 0 for this setup.");
|
|
|
|
test_container->ensure_control_visible(target_control);
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll() > 0,
|
|
"ensure_control_visible() scrolls horizontally when target control is outside the visible area.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll() > 0,
|
|
"ensure_control_visible() scrolls vertically when target control is outside the visible area.");
|
|
|
|
Rect2 target_rect(target_control->get_position(), target_control->get_size());
|
|
real_t side_margin = test_container->get_v_scroll_bar()->is_visible() ? test_container->get_v_scroll_bar()->get_size().x : 0.0f;
|
|
real_t bottom_margin = test_container->get_h_scroll_bar()->is_visible() ? test_container->get_h_scroll_bar()->get_size().y : 0.0f;
|
|
real_t visible_left = test_container->get_h_scroll();
|
|
real_t visible_top = test_container->get_v_scroll();
|
|
real_t visible_right = visible_left + test_container->get_size().x - side_margin;
|
|
real_t visible_bottom = visible_top + test_container->get_size().y - bottom_margin;
|
|
|
|
CHECK_MESSAGE(
|
|
(target_rect.position.x >= visible_left && (target_rect.position.x + target_rect.size.x) <= visible_right),
|
|
"ensure_control_visible() fully reveals target control horizontally.");
|
|
|
|
CHECK_MESSAGE(
|
|
(target_rect.position.y >= visible_top && (target_rect.position.y + target_rect.size.y) <= visible_bottom),
|
|
"ensure_control_visible() fully reveals target control vertically.");
|
|
|
|
test_container->set_h_scroll(0);
|
|
test_container->set_v_scroll(0);
|
|
test_container->set_follow_focus(true);
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
target_control->grab_focus();
|
|
SceneTree::get_singleton()->process(0);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_h_scroll() > 0,
|
|
"follow_focus scrolls horizontally to focused descendants.");
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_v_scroll() > 0,
|
|
"follow_focus scrolls vertically to focused descendants.");
|
|
|
|
visible_left = test_container->get_h_scroll();
|
|
visible_top = test_container->get_v_scroll();
|
|
visible_right = visible_left + test_container->get_size().x - side_margin;
|
|
visible_bottom = visible_top + test_container->get_size().y - bottom_margin;
|
|
|
|
CHECK_MESSAGE(
|
|
(target_rect.position.x >= visible_left && (target_rect.position.x + target_rect.size.x) <= visible_right),
|
|
"follow_focus fully reveals focused target control horizontally.");
|
|
|
|
CHECK_MESSAGE(
|
|
(target_rect.position.y >= visible_top && (target_rect.position.y + target_rect.size.y) <= visible_bottom),
|
|
"follow_focus fully reveals focused target control vertically.");
|
|
|
|
memdelete(target_control);
|
|
memdelete(content_control);
|
|
memdelete(test_container);
|
|
}
|
|
|
|
TEST_CASE("[SceneTree][ScrollContainer] Configuration warnings") {
|
|
ScrollContainer *test_container = memnew(ScrollContainer);
|
|
Window *root = SceneTree::get_singleton()->get_root();
|
|
root->add_child(test_container);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_configuration_warnings().size() == 1,
|
|
"ScrollContainer reports one configuration warning when it has no content child.");
|
|
|
|
Control *child_control_1 = memnew(Control);
|
|
Control *child_control_2 = memnew(Control);
|
|
test_container->add_child(child_control_1);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_configuration_warnings().is_empty(),
|
|
"ScrollContainer reports no configuration warning when it has exactly one content child.");
|
|
|
|
test_container->add_child(child_control_2);
|
|
|
|
CHECK_MESSAGE(
|
|
test_container->get_configuration_warnings().size() == 1,
|
|
"ScrollContainer reports one configuration warning when it has more than one content child.");
|
|
|
|
memdelete(child_control_2);
|
|
memdelete(child_control_1);
|
|
memdelete(test_container);
|
|
}
|
|
|
|
} // namespace TestScrollContainer
|