From 98b957a8ff1809281324478f31c71aa906a7ead9 Mon Sep 17 00:00:00 2001 From: En Yi Date: Mon, 8 Jul 2024 18:02:56 +0800 Subject: [PATCH] Encapsulate scroll area as UI component --- engine/gui.c | 76 +++++++++++++++++++++++++++++++++++++ engine/gui.h | 30 +++++++++++++++ scenes/level_select_scene.c | 67 ++++++++++++-------------------- scenes/scene_impl.h | 3 +- 4 files changed, 132 insertions(+), 44 deletions(-) diff --git a/engine/gui.c b/engine/gui.c index 24b4d86..cce1e09 100644 --- a/engine/gui.c +++ b/engine/gui.c @@ -623,6 +623,82 @@ float UI_slider(const UIComp_t* comp, const char *textLeft, const char *textRigh return GuiSliderPro(comp, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH)); } +void vert_scrollarea_init(VertScrollArea_t* scroll_area, Rectangle display_area, Vector2 canvas_dims) +{ + scroll_area->canvas = LoadRenderTexture(canvas_dims.x, canvas_dims.y); + scroll_area->scroll_pos = canvas_dims.y - display_area.height; + scroll_area->scroll_bounds = (Vector2){ + 0, scroll_area->scroll_pos + }; + + vert_scrollarea_set_item_dims(scroll_area, 12, 3); + scroll_area->curr_selection = 0; + + scroll_area->display_area = display_area; + scroll_area->scroll_bar.alpha = 1; + scroll_area->scroll_bar.bbox = (Rectangle){ + display_area.width + display_area.x, display_area.y, + 0.1f * display_area.width, display_area.height, + }; + scroll_area->scroll_bar.state = STATE_NORMAL; + + scroll_area->comp.alpha = 1; + scroll_area->comp.bbox = display_area; + scroll_area->comp.bbox.width *= 1.1f; + scroll_area->scroll_bar.state = STATE_NORMAL; + +} + +void vert_scrollarea_set_item_dims(VertScrollArea_t* scroll_area, unsigned int item_height, unsigned int item_padding) +{ + scroll_area->item_height = item_height; + scroll_area->item_padding = item_padding; + scroll_area->n_items = (scroll_area->canvas.texture.height - scroll_area->item_padding) / (scroll_area->item_height + scroll_area->item_padding); +} + +void vert_scrollarea_insert_item(VertScrollArea_t* scroll_area, char* str, unsigned int item_idx) +{ + if (item_idx >= scroll_area->n_items) return; + + DrawText(str, 0, scroll_area->item_padding + (scroll_area->item_height + scroll_area->item_padding) * item_idx, scroll_area->item_height, BLACK); +} + +void vert_scrollarea_render(VertScrollArea_t* scroll_area) +{ + BeginScissorMode(scroll_area->comp.bbox.x, scroll_area->comp.bbox.y, scroll_area->comp.bbox.width, scroll_area->comp.bbox.height); + UI_vert_slider(&scroll_area->scroll_bar, + NULL, + NULL, + &scroll_area->scroll_pos, + scroll_area->scroll_bounds.x, + scroll_area->scroll_bounds.y + ); + Rectangle draw_rec = (Rectangle){ + 0, scroll_area->scroll_pos, + scroll_area->display_area.width, + scroll_area->display_area.height + }; + float selection_y = scroll_area->curr_selection * (scroll_area->item_height + scroll_area->item_padding) + scroll_area->item_padding; + DrawRectangle( + scroll_area->display_area.x, scroll_area->display_area.y + selection_y - (scroll_area->scroll_bounds.y - scroll_area->scroll_pos), + scroll_area->canvas.texture.width, scroll_area->item_height, + Fade(BLUE, 0.7) + ); + Vector2 draw_pos = {scroll_area->display_area.x, scroll_area->display_area.y}; + draw_rec.height *= -1; + DrawTextureRec( + scroll_area->canvas.texture, + draw_rec, + draw_pos, + WHITE + ); + EndScissorMode(); +} + +void vert_scrollarea_free(VertScrollArea_t* scroll_area) +{ + UnloadRenderTexture(scroll_area->canvas); +} void init_UI(void) diff --git a/engine/gui.h b/engine/gui.h index f216e0e..2639352 100644 --- a/engine/gui.h +++ b/engine/gui.h @@ -3,6 +3,7 @@ #include "raylib.h" #include "raygui.h" +// Generic Component typedef struct UIComp { Rectangle bbox; GuiState state; @@ -10,7 +11,36 @@ typedef struct UIComp { bool pressed; } UIComp_t; +typedef struct VertScrollArea { + UIComp_t comp; // Display area + scrollbar + Rectangle display_area; // Display dimension + + RenderTexture2D canvas; // Complete canvas + + unsigned int n_items; + unsigned int curr_selection; + unsigned int item_height; + unsigned int item_padding; + + float scroll_pos; + Vector2 scroll_bounds; + UIComp_t scroll_bar; + +} VertScrollArea_t; + void init_UI(void); +void vert_scrollarea_init(VertScrollArea_t* scroll_area, Rectangle display_area, Vector2 canvas_dims); +void vert_scrollarea_set_item_dims(VertScrollArea_t* scroll_area, unsigned int item_height, unsigned int item_padding); +void vert_scrollarea_insert_item(VertScrollArea_t* scroll_area, char* str, unsigned int item_idx); +void vert_scrollarea_render(VertScrollArea_t* scroll_area); +void vert_scrollarea_free(VertScrollArea_t* scroll_area); + +static inline void ScrollAreaRenderBegin(VertScrollArea_t* scroll) +{ + BeginTextureMode(scroll->canvas); +} +#define ScrollAreaRenderEnd() EndTextureMode() + void UI_button(const UIComp_t* bbox, const char* text); float UI_slider(const UIComp_t* comp, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); float UI_vert_slider(const UIComp_t* comp, const char *textTop, const char *textBottom, float* value, float minValue, float maxValue); diff --git a/scenes/level_select_scene.c b/scenes/level_select_scene.c index d472291..e4fdaa3 100644 --- a/scenes/level_select_scene.c +++ b/scenes/level_select_scene.c @@ -13,35 +13,9 @@ static void level_select_render_func(Scene_t* scene) { LevelSelectSceneData_t* data = &(CONTAINER_OF(scene, LevelSelectScene_t, scene)->data); - UIComp_t test_comp = { - .bbox = {data->level_display.texture.width + 50, 50, 25, - scene->layers.render_layers[0].render_area.height - 50 - }, - .state = STATE_NORMAL, - .alpha = 1.0f, - }; - BeginTextureMode(scene->layers.render_layers[0].layer_tex); ClearBackground(BLANK); - UI_vert_slider(&test_comp, - NULL, - NULL, - &data->scroll, - 0, HIDDEN_AREA_HEIGHT - ); - Rectangle draw_rec = (Rectangle){ - 0, data->scroll, - data->level_display.texture.width, - scene->layers.render_layers[0].render_area.height - }; - Vector2 draw_pos = {50, 50}; - draw_rec.height *= -1; - DrawTextureRec( - data->level_display.texture, - draw_rec, - draw_pos, - WHITE - ); + vert_scrollarea_render(&data->scroll_area); EndTextureMode(); } @@ -53,15 +27,15 @@ static void level_select_do_action(Scene_t* scene, ActionType_t action, bool pre case ACTION_UP: if (pressed) { - data->scroll += 3; - data->scroll = Clamp(data->scroll, 0, 400); + data->scroll_area.scroll_pos += 3; + data->scroll_area.scroll_pos = Clamp(data->scroll_area.scroll_pos,data->scroll_area.scroll_bounds.x, data->scroll_area.scroll_bounds.y); } break; case ACTION_DOWN: if (pressed) { - data->scroll -= 3; - data->scroll = Clamp(data->scroll, 0, 400); + data->scroll_area.scroll_pos -= 3; + data->scroll_area.scroll_pos = Clamp(data->scroll_area.scroll_pos,data->scroll_area.scroll_bounds.x, data->scroll_area.scroll_bounds.y); } break; case ACTION_EXIT: @@ -70,6 +44,14 @@ static void level_select_do_action(Scene_t* scene, ActionType_t action, bool pre change_scene(scene->engine, MAIN_MENU_SCENE); } break; + case ACTION_CONFIRM: + if (data->level_pack != NULL && data->scroll_area.curr_selection < data->level_pack->n_levels) + { + // TODO: Need to load the current level + change_scene(scene->engine, LEVEL_SELECT_SCENE); + + } + break; default: break; } @@ -82,32 +64,31 @@ void init_level_select_scene(LevelSelectScene_t* scene) &scene->scene, 400, DISPLAY_AREA_HEIGHT, (Rectangle){0, 0, 400, DISPLAY_AREA_HEIGHT} ); - scene->data.level_display = LoadRenderTexture(200, SCROLL_TOTAL_HEIGHT); - scene->data.scroll = scene->data.level_display.texture.height - DISPLAY_AREA_HEIGHT; - const unsigned int n_elems = SCROLL_TOTAL_HEIGHT / TEXT_HEIGHT; + vert_scrollarea_init(&scene->data.scroll_area, (Rectangle){50, 50, 150, DISPLAY_AREA_HEIGHT - 50}, (Vector2){150, SCROLL_TOTAL_HEIGHT}); + vert_scrollarea_set_item_dims(&scene->data.scroll_area, FONT_SIZE, TEXT_PADDING); char buf[32]; - BeginTextureMode(scene->data.level_display); - ClearBackground(GRAY); + ScrollAreaRenderBegin(&scene->data.scroll_area); + ClearBackground(BLANK); if (scene->data.level_pack != NULL) { for (unsigned int i = 0; i < scene->data.level_pack->n_levels; ++i) { - DrawText(scene->data.level_pack->levels[i].level_name, 0, TEXT_HEIGHT * i, FONT_SIZE, BLACK); + vert_scrollarea_insert_item(&scene->data.scroll_area, scene->data.level_pack->levels[i].level_name, i); } - for (unsigned int i = scene->data.level_pack->n_levels; i < n_elems; ++i) + for (unsigned int i = scene->data.level_pack->n_levels; i < scene->data.scroll_area.n_items; ++i) { - DrawText("---", 0, TEXT_HEIGHT * i, FONT_SIZE, BLACK); + vert_scrollarea_insert_item(&scene->data.scroll_area, "---", i); } } else { - for (unsigned int i = 0; i < n_elems; ++i) + for (unsigned int i = 0; i < scene->data.scroll_area.n_items; ++i) { sprintf(buf, "Level %u", i); - DrawText(buf, 0, TEXT_HEIGHT * i, FONT_SIZE, BLACK); + vert_scrollarea_insert_item(&scene->data.scroll_area, buf, i); } } - EndTextureMode(); + ScrollAreaRenderEnd(); sc_array_add(&scene->scene.systems, &level_select_render_func); sc_map_put_64(&scene->scene.action_map, KEY_UP, ACTION_UP); @@ -116,5 +97,7 @@ void init_level_select_scene(LevelSelectScene_t* scene) } void free_level_select_scene(LevelSelectScene_t* scene) { + + vert_scrollarea_free(&scene->data.scroll_area); free_scene(&scene->scene); } diff --git a/scenes/scene_impl.h b/scenes/scene_impl.h index 40eb556..eb1c5d5 100644 --- a/scenes/scene_impl.h +++ b/scenes/scene_impl.h @@ -87,8 +87,7 @@ typedef struct MenuScene { } MenuScene_t; typedef struct LevelSelectSceneData { - RenderTexture2D level_display; - float scroll; + VertScrollArea_t scroll_area; LevelPack_t* level_pack; } LevelSelectSceneData_t;