From 496db167337e246cc12beb1ace2bdec35b916479 Mon Sep 17 00:00:00 2001 From: quou Date: Sat, 3 Aug 2024 16:15:02 +1000 Subject: scrollbars --- editor.c | 8 +++- gui.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gui.h | 23 +++++++++- 3 files changed, 186 insertions(+), 3 deletions(-) diff --git a/editor.c b/editor.c index 0aae694..b59ce32 100644 --- a/editor.c +++ b/editor.c @@ -12,18 +12,22 @@ void draw_map_scrollable( const Rect* rect, const GUI_Scroll_State* ss ) { + Rect re = { 0, 0, 500, 500 }; + re.x = rect->x - ss->x; + re.y = rect->y - ss->y; (void)g; (void)ss; - ren_texture(r, rect, get_texture(asset_id_floorboards_texture)); + ren_texture(r, &re, get_texture(asset_id_floorboards_texture)); } void edit_map(Editor* e, GUI* g, Map* m) { Rect b = gui_viewport(g); Rect t = gui_cut_up(&b, gui_text_height() + 4); + int mcs[] = { 500, 500 }; (void)e; (void)m; gui_btn(g, gui_cut_left(&t, gui_text_width("Load", 4) + 4), "Save"); gui_btn(g, gui_cut_left(&t, gui_text_width("Save", 4) + 4), "Load"); - gui_scrollable(g, b, &map_ss, draw_map_scrollable); + gui_scrollable(g, b, mcs, &map_ss, draw_map_scrollable); } diff --git a/gui.c b/gui.c index 0fe1f69..366e420 100644 --- a/gui.c +++ b/gui.c @@ -1,4 +1,5 @@ #include "gui.h" +#include "maths.h" #include "memory.h" #include "plat.h" #include "render.h" @@ -103,14 +104,109 @@ int gui_btn(GUI* g, Rect r, const char* text) { void gui_scrollable( GUI* g, Rect r, + const int* cs, GUI_Scroll_State* state, GUI_Scrollable_Draw_Fn fn ) { GUI_Scrollable* e = gui_alloc(g, sizeof *e); + Rect srx, sry; + int nx, ny, h = mouse_over(g->app, &r); + int size = 15; e->el.type = gui_el_type_scrollable; e->el.r = r; + e->cs[0] = cs[0]; + e->cs[1] = cs[1]; e->ss = state; e->draw = fn; + e->vp[0] = r.w - 2; + e->vp[1] = r.h - 2; + if ((nx = cs[0] - r.w) > 0) { + srx.h = size; + srx.w = r.w; + srx.x = r.x; + srx.y = r.y + r.h - srx.h; + e->vp[1] -= srx.h; + if (h) + state->x -= g->app->scrollx; + } + if ((ny = cs[1] - r.h) > 0) { + sry.w = size; + sry.h = r.h; + sry.x = r.x + r.w - sry.w; + sry.y = r.y; + e->vp[0] -= sry.w; + if (h) + state->y -= g->app->scrolly; + } + if (nx > 0 && ny > 0) { + srx.w -= size; + sry.h -= size; + nx = cs[0] - (r.w - size); + ny = cs[1] - (r.h - size); + } + if (nx > 0) { + state->x = clamp(state->x, 0, nx); + gui_scrollbar(g, state, srx, nx, 1); + } + if (ny > 0) { + state->y = clamp(state->y, 0, ny); + gui_scrollbar(g, state, sry, ny, 0); + } +} + +void gui_scrollbar( + GUI* g, + GUI_Scroll_State* state, + Rect r, + int diff, + int horizontal +) { + GUI_Scrollbar* e = gui_alloc(g, sizeof *e); + int ls = g->app->mbtn_states[mbtn_left]; + int mh = 30; + e->el.type = gui_el_type_scrollbar; + e->el.r = r; + if (horizontal) { + e->handle.x = r.x + state->x * (r.w - e->handle.w) / diff; + e->handle.y = r.y; + e->handle.w = r.w * r.w / (r.w + diff); + e->handle.w = maxi(e->handle.w, mh); + e->handle.h = r.h; + } else { + e->handle.x = r.x; + e->handle.y = r.y + state->y * (r.h - e->handle.h) / diff; + e->handle.w = r.w; + e->handle.h = r.h * r.h / (r.h + diff); + e->handle.h = maxi(e->handle.h, mh); + } + e->s = state; + e->h = horizontal; + e->hover = 0; + e->active = 0; + if ( + mouse_over(g->app, &e->handle) && + ls & key_state_just_pressed + ) { + state->grabbed[horizontal] = 1; + state->graboff[horizontal] = + (e->handle.x - g->app->mx); + } +#define doscroll(a, ad) \ + int scroll = state->a + g->app->dm ## a; \ + scroll = clamp(scroll, 0, diff); \ + state->a = scroll; \ + e->handle.a = scroll * (r.ad - e->handle.ad) / diff + r.a; + if (state->grabbed[horizontal]) { + if (horizontal) { + doscroll(x, w) + } else { + doscroll(y, h) + } + if (ls & key_state_just_released) + state->grabbed[horizontal] = 0; + if (ls & key_state_just_released) + state->grabbed[horizontal] = 0; + } } void rect_cfit(Rect* r) { @@ -177,11 +273,70 @@ void draw_scrollable( Rect rect = s->el.r; draw_container(r, &s->el.r, 0); rect_cfit(&rect); + rect.w = s->vp[0]; + rect.h = s->vp[1]; ren_clip(r, &rect); s->draw(g, r, &rect, s->ss); ren_clipr(r); } +void draw_scrollbar( + GUI* g, + Renderer* r, + const GUI_Scrollbar* s +) { + int a = s->s->grabbed[s->h]; + Colour out1 = make_colour(0xffffff, 0xff); + Colour out2 = make_colour(0x000000, 0xff); + Rect rect, h = s->handle; + (void)g; + if (a) { + Colour t = out1; + out1 = out2; + out2 = t; + } + draw_container(r, &s->el.r, 0); + if (s->h) { + int i; + h.x++; + h.w -= 2; + rect.w = 1; + rect.h = 7; + rect.x = s->handle.x + s->handle.w / 2 - 7; + rect.y = s->handle.y + s->handle.h / 2 - rect.h / 2; + if (a) { + rect.x++; + rect.y++; + } + draw_container(r, &h, a); + for (i = 0; i < 3; i++) { + ren_rect(r, out1, &rect); + rect.x++; + ren_rect(r, out2, &rect); + rect.x += 4; + } + } else { + int i; + h.y++; + h.h -= 2; + rect.w = 7; + rect.h = 1; + rect.x = s->handle.x + s->handle.w / 2 - rect.w / 2; + rect.y = s->handle.y + s->handle.h / 2 - 7; + if (a) { + rect.x++; + rect.y++; + } + draw_container(r, &h, a); + for (i = 0; i < 3; i++) { + ren_rect(r, out1, &rect); + rect.y++; + ren_rect(r, out2, &rect); + rect.y += 4; + } + } +} + void gui_end(GUI* g, Renderer* r) { GUI_El* el = g->first; while (el) { @@ -192,6 +347,9 @@ void gui_end(GUI* g, Renderer* r) { case gui_el_type_scrollable: draw_scrollable(g, r, (GUI_Scrollable*)el); break; + case gui_el_type_scrollbar: + draw_scrollbar(g, r, (GUI_Scrollbar*)el); + break; } el = el->next; } diff --git a/gui.h b/gui.h index 50927f4..5b3063b 100644 --- a/gui.h +++ b/gui.h @@ -10,7 +10,8 @@ struct Renderer; typedef enum { gui_el_type_btn, - gui_el_type_scrollable + gui_el_type_scrollable, + gui_el_type_scrollbar } GUI_El_Type; typedef struct GUI_El { @@ -27,8 +28,18 @@ typedef struct { typedef struct { int x, y; + short grabbed[2]; + short graboff[2]; } GUI_Scroll_State; +typedef struct { + GUI_El el; + GUI_Scroll_State* s; + Rect handle; + int h; + int hover, active; +} GUI_Scrollbar; + typedef void (*GUI_Scrollable_Draw_Fn)( struct GUI*, struct Renderer*, @@ -40,6 +51,8 @@ typedef struct { GUI_El el; GUI_Scrollable_Draw_Fn draw; GUI_Scroll_State* ss; + int cs[2]; + int vp[2]; } GUI_Scrollable; typedef struct GUI { @@ -63,8 +76,16 @@ int gui_btn(GUI* g, Rect r, const char* text); void gui_scrollable( GUI* g, Rect r, + const int* cs, GUI_Scroll_State* state, GUI_Scrollable_Draw_Fn fn ); +void gui_scrollbar( + GUI* g, + GUI_Scroll_State* state, + Rect r, + int diff, + int horizontal +); #endif -- cgit v1.2.3-54-g00ecf