menu

a graphical menu within a window
Index Commits Files Refs
commit 0fa3d3718bd186f5b8632478f4fbab9de12e1ee3
parent 6aee8a426017cfa7cc538df906dc07e2e7e29504
Author: klewer-martin <martin.cachari@gmail.com>
Date:   Fri, 22 Apr 2022 18:34:14 -0300

Added Mouse support, new functions, added Coord

New functions introduced to make interacting with the entries easier,
select_next, select_prev, select_index;

Added mouse support; this was possible by using the previous functions
as well as new ones created specifically to resolve this problem, i.e.
entry_at or hover_at.

Diffstat:
Mmain.c | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mmenu.c | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mmenu.h | 22+++++++++++++++++-----
Autil.h | 8++++++++
4 files changed, 157 insertions(+), 49 deletions(-)
diff --git a/main.c b/main.c
@@ -6,13 +6,37 @@
 #include "menu.h"
 
 #define FONT_SIZE    12
-#define FONT_NAME    "/home/mk/.local/share/fonts/VictorMono-Bold.ttf"
+#define FONT_NAME    "./VictorMono-Bold.ttf"
 
 #define WIN_DEFAULT_W    800
 #define WIN_DEFAULT_H    600
 
+static char *entries_text[TOTAL_ENTRIES] = {
+    "Bubble sort",
+    "Bubble sort (improved)",
+    "Insertion sort",
+    "Binary insertion sort",
+    "Merge sort",
+    "Quick sort",
+    "Quick sort (dual pivots)",
+    "Quick sort (LR pointers)",
+    "Quick sort (LL pointers)",
+    "Shell sort",
+    "Radix sort",
+    "Heap sort",
+    "Cocktail shaker sort",
+    "Gnome sort",
+    "Odd-even sort",
+    "Tim sort",
+    "Bogo sort",
+    "Stooge sort",
+    "Spaghetti sort"
+};
+
 int win_w, win_h;
 TTF_Font *font;
+int x, y;
+Uint32 buttons;
 
 int main (void) {
     SDL_Window *win;
@@ -42,35 +66,29 @@ int main (void) {
     win_w = WIN_DEFAULT_W;
     win_h = WIN_DEFAULT_H;
 
-    Entry entries[TOTAL_ENTRIES] = {0};
+    Entry entries[TOTAL_ENTRIES];
 
     for(i = 0; i < TOTAL_ENTRIES; i++) {
-        entries[i].selected = false;
-        entries[i].index = i;
+        entries[i] = (Entry) {
+            .text = entries_text[i],
+            .selected = false,
+            .hover = false,
+            .index = i,
+        };
     }
 
-    entries[0].text = "Bubble sort";
-    entries[1].text = "Bubble sort (improved)";
-    entries[2].text = "Insertion sort";
-    entries[3].text = "Binary insertion sort";
-    entries[4].text = "Merge sort";
-    entries[5].text = "Quick sort";
-    entries[6].text = "Quick sort (dual pivots)";
-    entries[7].text = "Quick sort (LR pointers)";
-    entries[8].text = "Quick sort (LL pointers)";
-    entries[9].text = "Shell sort";
-    entries[10].text = "Radix sort";
-    entries[11].text = "Heap sort";
-    entries[12].text = "Cocktail shaker sort";
-    entries[13].text = "Gnome sort";
-    entries[14].text = "Odd-even sort";
-    entries[15].text = "Tim sort";
-    entries[16].text = "Bogo sort";
-    entries[17].text = "Stooge sort";
-    entries[18].text = "Spaghetti sort";
+    /* size_t len, len_max; */
+    /* for(i = len = len_max = 0; i < TOTAL_ENTRIES; i++, len = strlen(entries_text[i])) */
+    /*     len_max = (len > len_max) ? len : len_max; */
+
+    /* for(i = 0; i < TOTAL_ENTRIES; i++) { */
+    /*     entries[i].selected = false; */
+    /*     strcpy(entries.text, entries_text[i]); */
+    /* } */
 
     entries[0].selected = true;
     SDL_Keymod mod;
+    size_t index = TOTAL_ENTRIES;
     while(run) {
         while(SDL_PollEvent(&event)) {
             switch(event.type) {
@@ -82,6 +100,9 @@ int main (void) {
                 /* printf("SDL_GetModState() == %X\n", SDL_GetModState()); */
                 mod = SDL_GetModState();
                 switch(event.key.keysym.scancode) {
+                    case SDL_SCANCODE_Q:
+                        run = false;
+                        break;
                     case SDL_SCANCODE_J:
                     case SDL_SCANCODE_DOWN:
                         if(mod == KMOD_NONE) select_next(entries);
@@ -98,6 +119,13 @@ int main (void) {
                     default: break;
                 }
                 break;
+            case SDL_MOUSEBUTTONDOWN:
+                index = entry_at(entries, event.button.x, event.button.y);
+                if(index != TOTAL_ENTRIES) {
+                    printf("%s\n", entries[index].text);
+                    select_index(entries, index);
+                }
+                break;
             case SDL_WINDOWEVENT:
                 switch(event.window.event) {
                 case SDL_WINDOWEVENT_RESIZED:
@@ -110,11 +138,18 @@ int main (void) {
             }
         }
 
+        SDL_PumpEvents();  // make sure we have the latest mouse state.
+
+        buttons = SDL_GetMouseState(&x, &y);
+        hover_at(entries, x, y);
+
         SDL_SetRenderDrawColor(rend, 32, 32, 32, 0);
         SDL_RenderClear(rend);
 
-        for(i = 0; i < TOTAL_ENTRIES; i++)
+        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]);
+        }
 
         SDL_RenderPresent(rend);
         SDL_Delay(1);
diff --git a/menu.c b/menu.c
@@ -1,42 +1,96 @@
 #include "menu.h"
 
+/* void Entry_new(Entry *entry, Entry values) { */
+/*     if(!(entry = (Entry)malloc(sizeof(struct _Entry)))) return; */
+
+/*     strcpy(entry->text, values.text); */
+/*     entry->selected = values.selected; */
+/* } */
+
 /* Finds the selected entry then selects next */
-void select_next(Entry entries[]) {
+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[i + 1].selected = true;
-            else entries[0].selected = true;
-            return;
+            if((i + 1) == TOTAL_ENTRIES) entries[0].selected = true;
+            else entries[i + 1].selected = true;
+            i++;
+            continue;
         }
+        entries[i].selected = false;
     }
 }
 
 /* Finds the selected entry then selects previous */
-void select_prev(Entry entries[]) {
+void select_prev(Entry *entries) {
     for(int i = 0; i < TOTAL_ENTRIES; i++) {
         if(entries[i].selected == true) {
             entries[i].selected = false;
-            if(i == 0) entries[TOTAL_ENTRIES - 1].selected = true;
+            if(i == 0) {
+                entries[TOTAL_ENTRIES - 1].selected = true;
+                break;
+            }
             else entries[i - 1].selected = true;
-            return;
         }
     }
 }
 
-void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, Entry entry) {
+void select_index(Entry *entries, 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;
+    }
+}
+
+size_t entry_at(Entry *entries, 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)))
+            return i;
+
+    return TOTAL_ENTRIES;
+}
+
+void compute_entries_pos(Entry *entries, 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;
+
+    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)));
+    }
+}
+
+void hover_entry(Entry *entries, size_t index) {
+    size_t i;
+
+    for(i = 0; i < TOTAL_ENTRIES; i++)
+        entries[i].hover = ((i == index) ? true : false);
+}
+
+void hover_at(Entry *entries, 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;
+    }
+}
+
+void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, const Entry entry) {
     SDL_Surface *text_surface;
     SDL_Texture *text_texture;
     SDL_Rect text_rect, box;
     SDL_Color text_color, text_color_shadow;
-    int first_entry_y_pos, win_center_y;
     int text_w, text_h;
 
-    win_center_y = (win_h / 2);
-    first_entry_y_pos = win_center_y -
-        ((((BAR_H + ELEMENTS_PADDING) * TOTAL_ENTRIES) - ELEMENTS_PADDING) / 2) +
-        BAR_H + (entry.index * (ELEMENTS_PADDING + BAR_H));
-
     text_color_shadow.r = (char)(SHADOW_COLOR >> 16) & 0xFF;
     text_color_shadow.g = (char)(SHADOW_COLOR >> 8) & 0xFF;
     text_color_shadow.b = (char)(SHADOW_COLOR) & 0xFF;
@@ -46,13 +100,13 @@ void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, Entry 
     text_color.b = (char)(FONT_COLOR) & 0xFF;
 
     box.x = BAR_BORDER;
-    box.y = first_entry_y_pos;
+    box.y = entry.pos.y;
     box.w = win_w - (BAR_BORDER * 2);
     box.h = -BAR_H;
 
-    SDL_SetRenderDrawColor(rend, UNHEX(entry.selected ? SEL_COLOR : NORM_COLOR));
-
+    SDL_SetRenderDrawColor(rend, UNHEX(entry.selected ? SEL_COLOR : entry.hover ? HOVER_COLOR : NORM_COLOR));
     SDL_RenderFillRect(rend, &box);
+
     TTF_SizeText(font, entry.text, &text_w, &text_h);
 
     /* Draw shadow */
@@ -61,7 +115,7 @@ void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, Entry 
         text_texture = SDL_CreateTextureFromSurface(rend, text_surface);
 
         text_rect.x = (win_w / 2) - (text_w / 2) + 2;
-        text_rect.y = first_entry_y_pos - (BAR_H + 1) + 2;
+        text_rect.y = entry.pos.y - (BAR_H + 1) + 2;
         text_rect.w = text_surface->w;
         text_rect.h = text_surface->h;
 
@@ -74,7 +128,7 @@ void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, Entry 
     text_texture = SDL_CreateTextureFromSurface(rend, text_surface);
 
     text_rect.x = (win_w / 2) - (text_w / 2);
-    text_rect.y = first_entry_y_pos - (BAR_H + 1);
+    text_rect.y = entry.pos.y - (BAR_H + 1);
     text_rect.w = text_surface->w;
     text_rect.h = text_surface->h;
 
@@ -82,4 +136,3 @@ void draw_entry(SDL_Renderer *rend, TTF_Font *font, int win_w, int win_h, Entry 
     SDL_DestroyTexture(text_texture);
     SDL_FreeSurface(text_surface);
 }
-
diff --git a/menu.h b/menu.h
@@ -7,6 +7,8 @@
 #include <stdbool.h>
 #include <stdlib.h>
 
+#include "util.h"
+
 #define FONT_COLOR        0xFFFCF9
 #define SHADOW_COLOR    0x000000
 
@@ -17,7 +19,8 @@
 #define ELEMENTS_PADDING 3
 
 #define NORM_COLOR 0x010101FF
-#define SEL_COLOR 0xCC0000FF
+#define SEL_COLOR 0xEE0000FF
+#define HOVER_COLOR 0x444444FF
 
 #define WIN_DEFAULT_W    800
 #define WIN_DEFAULT_H    600
@@ -30,12 +33,21 @@
 
 typedef struct Entry {
     char *text;
-    bool selected;
+    bool selected, hover;
     size_t index;
+    Coord pos;
 } Entry;
 
-void select_prev(Entry []);
-void select_next(Entry []);
-void draw_entry(SDL_Renderer *, TTF_Font *, int, int, 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);
+
 
 #endif
diff --git a/util.h b/util.h
@@ -0,0 +1,8 @@
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+typedef struct _Coord {
+    int x, y;
+} Coord;
+
+#endif