repos/menu

A graphical menu within a window
Commits Files Refs
commit 93f11266062aa3c05a0154a95f5c8e2f689e4f6a
parent 06e5cceda9ca59e1a6c8d24d71e2ccedb7a6fa5a
Author: mjkloeckner <martin.cachari@gmail.com>
Date:   Mon, 17 Oct 2022 19:43:41 -0300

Introduced two new types: Set and Elem

This commit introduces this two data types as well as all their methods

The Set is all the Elem (previously entries) together

The Elem data type is a rename of the now deprecated Entry data type

Diffstat:
Mmain.c | 49++++++++++++++++++++++++-------------------------
Mmenu.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mmenu.h | 42+++++++++++++++++++++++++++---------------
3 files changed, 134 insertions(+), 84 deletions(-)
diff --git a/main.c b/main.c
@@ -13,7 +13,7 @@
 
 #define BG_COLOR    0x323232FF
 
-static char *entries_text[TOTAL_ENTRIES] = {
+static char *elements_text[TOTAL_ENTRIES] = {
     "Bubble sort",
     "Bubble sort (improved)",
     "Insertion sort",
@@ -40,11 +40,17 @@ TTF_Font *font;
 int x, y;
 Uint32 buttons;
 
-int main (void) {
+/* TODO: remove global variables */
+/* TODO: custom box size, margin, padding, pos, etc */
+/* TODO: linked list (?) */
+
+int main (void)
+{
     SDL_Window *win;
     SDL_Renderer *rend;
     int min_w, min_h;
     size_t i;
+    Set *set;
 
     SDL_Init(SDL_INIT_VIDEO);
 
@@ -73,18 +79,11 @@ int main (void) {
     win_w = WIN_DEFAULT_W;
     win_h = WIN_DEFAULT_H;
 
-    Entry entries[TOTAL_ENTRIES];
+    Set_new(&set, TOTAL_ENTRIES);
 
-    for(i = 0; i < TOTAL_ENTRIES; i++) {
-        entries[i] = (Entry) {
-            .text = entries_text[i],
-            .selected = false,
-            .hover = false,
-            .index = i,
-        };
-    }
+    for(i = 0; i < set->size; i++)
+        Elem_set_text(set->elements[i], elements_text[i]);
 
-    entries[0].selected = true;
     SDL_Keymod mod;
     size_t index = TOTAL_ENTRIES;
     while(run) {
@@ -103,30 +102,31 @@ int main (void) {
                         break;
                     case SDL_SCANCODE_J:
                     case SDL_SCANCODE_DOWN:
-                        if(mod == KMOD_NONE) select_next(entries);
+                        if(mod == KMOD_NONE) Set_select_next(set);
                         break;
                     case SDL_SCANCODE_K:
                     case SDL_SCANCODE_UP:
-                        if(mod == KMOD_NONE) select_prev(entries);
+                        if(mod == KMOD_NONE) Set_select_prev(set);
                         break;
                     case SDL_SCANCODE_RETURN:
                         for(i = 0; i < TOTAL_ENTRIES; i++)
-                            if(entries[i].selected)
-                                printf("%s\n", entries[i].text);
+                            if(set->elements[i]->selected)
+                                printf("%s\n", set->elements[i]->text);
                         break;
                     default: break;
                 }
                 break;
             case SDL_MOUSEBUTTONDOWN:
-                index = entry_at(entries, event.button.x, event.button.y);
+                index = Set_elem_at(set, event.button.x, event.button.y);
                 if(index != TOTAL_ENTRIES) {
-                    printf("%s\n", entries[index].text);
-                    select_index(entries, index);
+                    printf("%s\n", set->elements[index]->text);
+                    Set_select_index(set, index);
                 }
                 break;
             case SDL_WINDOWEVENT:
                 switch(event.window.event) {
                 case SDL_WINDOWEVENT_RESIZED:
+                    /* printf("INFO: window resized to: %dx%d\n", win_w, win_h); */
                     win_w = event.window.data1;
                     win_h = event.window.data2;
                     break;
@@ -136,18 +136,17 @@ int main (void) {
             }
         }
 
-        SDL_PumpEvents();  // make sure we have the latest mouse state.
+        SDL_PumpEvents();  /* make sure we have the latest mouse state. */
 
         buttons = SDL_GetMouseState(&x, &y);
-        hover_at(entries, x, y);
+        Set_hover_at(set, x, y);
 
         SDL_SetRenderDrawColor(rend, UNHEX(BG_COLOR));
         SDL_RenderClear(rend);
 
-        compute_entries_pos(entries, win_w, win_h);
-        for(i = 0; i < TOTAL_ENTRIES; i++) {
-            draw_entry(rend, font, win_w, win_h, entries[i]);
-        }
+        Set_compute_pos(set, win_w, win_h);
+        for(i = 0; i < TOTAL_ENTRIES; i++)
+            Elem_draw(rend, font, win_w, win_h, set->elements[i]);
 
         SDL_RenderPresent(rend);
         SDL_Delay(1);
diff --git a/menu.c b/menu.c
@@ -1,83 +1,83 @@
 #include "menu.h"
 
 /* Finds the selected entry then selects next */
-void select_next(Entry *entries) {
-    for(int i = 0; i < TOTAL_ENTRIES; i++) {
-        if(entries[i].selected == true) {
-            entries[i].selected = false;
-            if((i + 1) == TOTAL_ENTRIES) entries[0].selected = true;
-            else entries[i + 1].selected = true;
+void Set_select_next(Set *set) {
+    for(int i = 0; i < set->size; i++) {
+        if(set->elements[i]->selected == true) {
+            set->elements[i]->selected = false;
+            if((i + 1) == set->size) set->elements[0]->selected = true;
+            else set->elements[i + 1]->selected = true;
             i++;
             continue;
         }
-        entries[i].selected = false;
+        set->elements[i]->selected = false;
     }
 }
 
 /* Finds the selected entry then selects previous */
-void select_prev(Entry *entries) {
-    for(int i = 0; i < TOTAL_ENTRIES; i++) {
-        if(entries[i].selected == true) {
-            entries[i].selected = false;
+void Set_select_prev(Set *set) {
+    for(int i = 0; i < set->size; i++) {
+        if(set->elements[i]->selected == true) {
+            set->elements[i]->selected = false;
             if(i == 0) {
-                entries[TOTAL_ENTRIES - 1].selected = true;
+                set->elements[set->size - 1]->selected = true;
                 break;
             }
-            else entries[i - 1].selected = true;
+            else set->elements[i - 1]->selected = true;
         }
     }
 }
 
-void select_index(Entry *entries, size_t index) {
+void Set_select_index(Set *set, size_t index) {
     size_t i;
-    for(i = 0; i < TOTAL_ENTRIES; i++) {
-        if(entries[i].index == index) entries[i].selected = true;
-        else if(entries[i].selected == true) entries[i].selected = false;
+    for(i = 0; i < set->size; i++) {
+        if(set->elements[i]->index == index) set->elements[i]->selected = true;
+        else if(set->elements[i]->selected == true) set->elements[i]->selected = false;
     }
 }
 
-size_t entry_at(Entry *entries, int x, int y) {
+size_t Set_elem_at(Set *set, int x, int y) {
     size_t i;
 
-    for(i = 0; i < TOTAL_ENTRIES; i++)
-        if((y < entries[i].pos.y) && (y > (entries[i].pos.y - BAR_H)))
+    for(i = 0; i < set->size; i++)
+        if((y < set->elements[i]->pos.y) && (y > (set->elements[i]->pos.y - BAR_H)))
             return i;
 
-    return TOTAL_ENTRIES;
+    return set->size;
 }
 
-void compute_entries_pos(Entry *entries, int win_w, int win_h) {
+void Set_compute_pos(Set *set, int win_w, int win_h) {
     int first_entry_pos_y, win_center_y;
     size_t i;
 
     win_center_y = (win_h / 2);
     first_entry_pos_y = win_center_y -
-        ((((BAR_H + ELEMENTS_PADDING) * TOTAL_ENTRIES) - ELEMENTS_PADDING) / 2) + BAR_H;
+        ((((BAR_H + ELEMENTS_PADDING) * set->size) - ELEMENTS_PADDING) / 2) + BAR_H;
 
-    for(i = 0; i < TOTAL_ENTRIES; i++) {
-        entries[i].pos.x = BAR_BORDER;
-        entries[i].pos.y = (first_entry_pos_y + (entries[i].index * (ELEMENTS_PADDING + BAR_H)));
+    for(i = 0; i < set->size; i++) {
+        set->elements[i]->pos.x = BAR_BORDER;
+        set->elements[i]->pos.y = (first_entry_pos_y + (set->elements[i]->index * (ELEMENTS_PADDING + BAR_H)));
     }
 }
 
-void hover_entry(Entry *entries, size_t index) {
+void Set_hover_elem(Set *set, size_t index) {
     size_t i;
 
-    for(i = 0; i < TOTAL_ENTRIES; i++)
-        entries[i].hover = ((i == index) ? true : false);
+    for(i = 0; i < set->size; i++)
+        set->elements[i]->hover = ((i == index) ? true : false);
 }
 
-void hover_at(Entry *entries, int x, int y) {
+void Set_hover_at(Set *set, int x, int y) {
     size_t i;
 
-    for(i = 0; i < TOTAL_ENTRIES; i++) {
-        if((y < entries[i].pos.y) && (y > (entries[i].pos.y - BAR_H)))
-            entries[i].hover = true;
-        else entries[i].hover = false;
+    for(i = 0; i < set->size; i++) {
+        if((y < set->elements[i]->pos.y) && (y > (set->elements[i]->pos.y - BAR_H)))
+            set->elements[i]->hover = true;
+        else set->elements[i]->hover = false;
     }
 }
 
-void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, const Entry entry) {
+void Elem_draw(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, const Elem *elem) {
     SDL_Surface *text_surface;
     SDL_Texture *text_texture;
     SDL_Rect text_rect, box;
@@ -87,20 +87,20 @@ void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, const 
     text_color = mk_SDL_Color(UNHEX(FONT_COLOR));
     text_color_shadow = mk_SDL_Color(UNHEX(SHADOW_COLOR));
 
-    box = (SDL_Rect){ BAR_BORDER, entry.pos.y, win_w - (BAR_BORDER * 2), -BAR_H };
+    box = (SDL_Rect) { BAR_BORDER, elem->pos.y, win_w - (BAR_BORDER * 2), -BAR_H };
 
-    SDL_SetRenderDrawColor(rend, UNHEX(entry.selected ? SEL_COLOR : (entry.hover ? HOVER_COLOR : NORM_COLOR)));
+    SDL_SetRenderDrawColor(rend, UNHEX(elem->selected ? SEL_COLOR : (elem->hover ? HOVER_COLOR : NORM_COLOR)));
     SDL_RenderFillRect(rend, &box);
 
-    TTF_SizeText(font, entry.text, &text_w, &text_h);
+    TTF_SizeText(font, elem->text, &text_w, &text_h);
 
     /* Draw shadow */
-    if(entry.selected) {
-        text_surface = TTF_RenderText_Blended(font, entry.text, text_color_shadow);
+    if(elem->selected) {
+        text_surface = TTF_RenderText_Blended(font, elem->text, text_color_shadow);
         text_texture = SDL_CreateTextureFromSurface(rend, text_surface);
 
         text_rect.x = (win_w / 2) - (text_w / 2) + 2;
-        text_rect.y = entry.pos.y - (BAR_H + 1) + 2;
+        text_rect.y = elem->pos.y - (BAR_H + 1) + 2;
         text_rect.w = text_surface->w;
         text_rect.h = text_surface->h;
 
@@ -109,11 +109,10 @@ void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, const 
         SDL_FreeSurface(text_surface);
     }
 
-    text_surface = TTF_RenderText_Blended(font, entry.text, text_color);
+    text_surface = TTF_RenderText_Blended(font, elem->text, text_color);
     text_texture = SDL_CreateTextureFromSurface(rend, text_surface);
-
     text_rect.x = (win_w / 2) - (text_w / 2);
-    text_rect.y = entry.pos.y - (BAR_H + 1);
+    text_rect.y = elem->pos.y - (BAR_H + 1);
     text_rect.w = text_surface->w;
     text_rect.h = text_surface->h;
 
@@ -121,3 +120,43 @@ void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, const 
     SDL_DestroyTexture(text_texture);
     SDL_FreeSurface(text_surface);
 }
+
+void Set_new(Set **set, size_t size) {
+    if(size == 0) return;
+
+    (*set) = malloc(sizeof(Set));
+
+    if((*set) == NULL)
+        return;
+
+    if(((*set)->elements = malloc(sizeof(Elem) * size)) == NULL)
+        return;
+
+    for(size_t i = 0; i < size; i++)
+        if(((*set)->elements[i] = malloc(sizeof(Elem))) == NULL)
+            return;
+
+    /* Initialize elements */
+    (*set)->size = size;
+    for(size_t i = 0; i < size; i++) {
+        (*set)->elements[i]->text = NULL;
+        (*set)->elements[i]->selected = false;
+        (*set)->elements[i]->hover = false;
+        (*set)->elements[i]->index = i;
+    }
+
+    (*set)->elements[0]->selected = true;
+}
+
+void Set_destroy(Set *set) {
+    free(set->elements);
+    free(set);
+}
+
+void Elem_set_text(Elem *el, const char *src) {
+    size_t text_len = strlen(src);
+
+    el->text = calloc(text_len + 1, sizeof(char));
+
+    strcpy(el->text, src);
+}
diff --git a/menu.h b/menu.h
@@ -3,9 +3,7 @@
 
 #include <SDL2/SDL.h>
 #include <SDL2/SDL_ttf.h>
-
 #include <stdbool.h>
-#include <stdlib.h>
 
 #include "util.h"
 
@@ -31,23 +29,37 @@
     ((color) >> (8 * 1)) & 0xFF, \
     ((color) >> (8 * 0)) & 0xFF
 
-typedef struct Entry {
+typedef struct {
     char *text;
     bool selected, hover;
     size_t index;
     Coord pos;
-} Entry;
-
-void select_prev(Entry *);
-void select_next(Entry *);
-void select_index(Entry *, size_t i);
-void draw_entry(SDL_Renderer *, TTF_Font *, int, int, const Entry);
-
-void Entry_new(Entry *);
-size_t entry_at(Entry *, int, int);
-void hover_at(Entry *, int, int);
-void hover_entry(Entry *, size_t);
-void compute_entries_pos(Entry *, int, int);
+} Elem;
+
+typedef struct {
+    Elem **elements;
+    size_t size;
+} Set;
+
+void Set_new(Set **, size_t size);
+void Set_draw(Set *);
+void Set_destroy(Set *);
+
+void Set_select_prev(Set *);
+void Set_select_next(Set *);
+void Set_select_index(Set *, size_t i);
+void Set_hover_at(Set *, int, int);
+void Set_hover_elem(Set *, size_t);
+size_t Set_elem_at(Set *, int, int);
+void Set_compute_pos(Set *, int, int);
+
+
+/* void Elem_new(Elem **); */
+/* void Elem_destroy(Elem *); */
+
+void Elem_draw(SDL_Renderer *, TTF_Font *, int, int, const Elem *);
+void Elem_set_text(Elem *, const char *);
+
 
 
 #endif