pebble/tests/fw/ui/test_scroll_layer.c
2025-01-27 11:38:16 -08:00

214 lines
8.6 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applib/ui/scroll_layer.h"
#include "clar.h"
// Stubs
////////////////////////////////////
#include "stubs_app_state.h"
#include "stubs_compiled_with_legacy2_sdk.h"
#include "stubs_content_indicator.h"
#include "stubs_graphics_context.h"
#include "stubs_heap.h"
#include "stubs_logging.h"
#include "stubs_passert.h"
#include "stubs_pbl_malloc.h"
#include "stubs_pebble_tasks.h"
#include "stubs_resources.h"
#include "stubs_syscalls.h"
#include "stubs_unobstructed_area.h"
#define DEFAULT_SCROLL_HEIGHT 32
// Stubs
////////////////////////////////////
static GRect s_graphics_draw_bitmap_in_rect__rect = GRectZero;
void graphics_draw_bitmap_in_rect(GContext* ctx, const GBitmap *src_bitmap, const GRect *rect) {
s_graphics_draw_bitmap_in_rect__rect = *rect;
}
bool graphics_release_frame_buffer(GContext *ctx, GBitmap *buffer) {return false;}
void window_schedule_render(struct Window *window) {}
void window_set_click_config_provider_with_context(
struct Window *window, ClickConfigProvider click_config_provider, void *context) {}
void window_set_click_context(ButtonId button_id, void *context) {}
void window_single_repeating_click_subscribe(
ButtonId button_id, uint16_t repeat_interval_ms, ClickHandler handler) {}
// Internal definitions
////////////////////////////////////
extern bool prv_scroll_layer_is_paging_enabled(ScrollLayer *scroll_layer);
extern void prv_scroll_layer_set_content_offset_internal(ScrollLayer *scroll_layer, GPoint offset);
extern uint16_t prv_scroll_layer_get_paging_height(ScrollLayer *scroll_layer);
// Setup
////////////////////////////////////
void test_scroll_layer__initialize(void) {}
void test_scroll_layer__cleanup(void) {}
// Tests
////////////////////////////////////
void test_scroll_layer__enable_paging(void) {
GRect scroll_bounds = GRect(0,0,180,180);
ScrollLayer *scroll_layer = scroll_layer_create(scroll_bounds);
// Verify paging is disabled by default
cl_assert_equal_b(false, prv_scroll_layer_is_paging_enabled(scroll_layer));
// Verify shadow_layer is not hidden when paging disabled
cl_assert_equal_b(false, scroll_layer_get_shadow_hidden(scroll_layer));
scroll_layer_set_paging(scroll_layer, true);
// Verify paging is enabled
cl_assert_equal_b(true, prv_scroll_layer_is_paging_enabled(scroll_layer));
// Verify shadow_layer is hidden now that paging enabled
cl_assert_equal_b(true, scroll_layer_get_shadow_hidden(scroll_layer));
// verify disable paging works
scroll_layer_set_paging(scroll_layer, false);
cl_assert_equal_b(false, prv_scroll_layer_is_paging_enabled(scroll_layer));
// verify shadow layer is hidden on paging disabled
cl_assert_equal_b(true, scroll_layer_get_shadow_hidden(scroll_layer));
}
void test_scroll_layer__paging_vs_shadow_bits(void) {
ScrollLayer *scroll_layer = scroll_layer_create(GRect(0,0,180,180));
// Validate that paging_disabled is same position as shadow clips
scroll_layer->shadow_sublayer.clips = true;
cl_assert_equal_b(true, scroll_layer->paging.paging_disabled);
cl_assert_equal_b(false, scroll_layer->paging.shadow_hidden);
scroll_layer->shadow_sublayer.clips = false;
cl_assert_equal_b(false, scroll_layer->paging.paging_disabled);
cl_assert_equal_b(false, scroll_layer->paging.shadow_hidden);
// Validate that shadow_hidden is same position as layer hidden in shadow sublayer
scroll_layer->shadow_sublayer.hidden = true;
cl_assert_equal_b(false, scroll_layer->paging.paging_disabled);
cl_assert_equal_b(true, scroll_layer->paging.shadow_hidden);
scroll_layer->shadow_sublayer.hidden = false;
cl_assert_equal_b(false, scroll_layer->paging.paging_disabled);
cl_assert_equal_b(false, scroll_layer->paging.shadow_hidden);
}
void test_scroll_layer__scrolling(void) {
GRect scroll_bounds = GRect(0,0,180,180);
ScrollLayer *scroll_layer = scroll_layer_create(scroll_bounds);
GSize content_size = GSize(180, 2000);
scroll_layer_set_content_size(scroll_layer, content_size);
int32_t scroll_height = DEFAULT_SCROLL_HEIGHT;
int32_t offset = 0;
for (offset = 0; offset < content_size.h - scroll_bounds.size.h; offset += scroll_height) {
// scroll offset for scroll down is negative, so invert offset.y
cl_assert_equal_i(offset, -((int32_t)scroll_layer_get_content_offset(scroll_layer).y));
scroll_layer_scroll(scroll_layer, ScrollDirectionDown, false);
}
// can only scroll to content offset == content_size.h - bounds.size.h
// so the last scroll from the above loop is expected to have stopped short
cl_assert(offset > -((int32_t)scroll_layer_get_content_offset(scroll_layer).y));
}
void test_scroll_layer__paging_with_scroll(void) {
ScrollLayer *scroll_layer = scroll_layer_create(GRect(0,0,180,180));
int16_t page_height = 0;
page_height = scroll_layer->layer.frame.size.h;
scroll_layer_set_paging(scroll_layer, true);
cl_assert_equal_i(page_height, prv_scroll_layer_get_paging_height(scroll_layer));
// paging should force < page_height offsets to ceil of modulo page height
scroll_layer_set_content_size(scroll_layer, GSize(180, 2000));
scroll_layer_scroll(scroll_layer, ScrollDirectionDown, false);
// scroll offset for scroll down is negative, so invert offset.y
cl_assert_equal_i(page_height, -((int32_t)scroll_layer_get_content_offset(scroll_layer).y));
}
void test_scroll_layer__paging_last_pages_content(void) {
uint16_t page_height = 86;
ScrollLayer *scroll_layer = scroll_layer_create(GRect(0,0,180,page_height));
// validate enable paging works for paging height
scroll_layer_set_paging(scroll_layer, true);
cl_assert_equal_i(page_height, prv_scroll_layer_get_paging_height(scroll_layer));
int pages = 2;
int offset = 0;
// setup content size to be slightly more than 2 pages
GSize content_size = GSize(180, page_height * pages + 10);
scroll_layer_set_content_size(scroll_layer, content_size);
// paging should force full contents of last page to show
// so content size rounded up to the next modulo of page_height
cl_assert_equal_i(offset, -scroll_layer_get_content_offset(scroll_layer).y);
scroll_layer_scroll(scroll_layer, ScrollDirectionDown, false);
offset += page_height;
cl_assert_equal_i(offset, -scroll_layer_get_content_offset(scroll_layer).y);
// we expect to scroll to the end of content padded to the last full page
scroll_layer_scroll(scroll_layer, ScrollDirectionDown, false);
offset += page_height;
cl_assert_equal_i(offset, -scroll_layer_get_content_offset(scroll_layer).y);
cl_assert_equal_i(page_height * pages, -scroll_layer_get_content_offset(scroll_layer).y);
// once the last full page of content has been displayed
// another scroll down shouldn't advance the offset
scroll_layer_scroll(scroll_layer, ScrollDirectionDown, false);
cl_assert_equal_i(page_height * pages, -scroll_layer_get_content_offset(scroll_layer).y);
}
void test_scroll_layer__fullscreen_paging(void) {
GRect scroll_bounds = GRect(0,0,180,180);
ScrollLayer *scroll_layer = scroll_layer_create(scroll_bounds);
int16_t page_height = scroll_bounds.size.h;
scroll_layer_set_paging(scroll_layer, true);
cl_assert_equal_i(page_height, prv_scroll_layer_get_paging_height(scroll_layer));
int pages = 22;
int offset = 0;
// setup content size to be slightly more than the pages
GSize content_size = GSize(scroll_bounds.size.w, page_height * pages + 24);
scroll_layer_set_content_size(scroll_layer, content_size);
// paging should force full contents of last page to show
// so content size rounded up to the next modulo of page_height
cl_assert_equal_i(offset, -scroll_layer_get_content_offset(scroll_layer).y);
// we expect to scroll to the end of content padded to the last full page
for (int i = 0; i < pages; i++) {
scroll_layer_scroll(scroll_layer, ScrollDirectionDown, false);
offset += page_height;
cl_assert_equal_i(offset, -scroll_layer_get_content_offset(scroll_layer).y);
}
// once the last full page of content has been displayed
// another scroll down shouldn't advance the offset
scroll_layer_scroll(scroll_layer, ScrollDirectionDown, false);
cl_assert_equal_i(page_height * pages, -scroll_layer_get_content_offset(scroll_layer).y);
}