tuxanci2-game
Game code/assets for tuxanci2
Log | Files | Refs | README | LICENSE

button.c (4727B)


      1 #include "button.h"
      2 #include <tuxanci2/text.h>
      3 #include <tuxanci2/display.h>
      4 #include <tuxanci2/keyboard.h>
      5 #include <stdint.h>
      6 #include <stdlib.h>
      7 #include <stddef.h>
      8 
      9 #define TA_BUTTON_FONT_SIZE 32
     10 #define TA_BUTTON_FONT_SIZE_MAX 255
     11 #define TA_BUTTON_SPACING 48
     12 #define TA_BUTTON_COLOR_IDLE 118
     13 #define TA_BUTTON_COLOR_SELECTED 255
     14 #define TA_BUTTON_REFERENCE_WIDTH 800
     15 #define TA_BUTTON_REFERENCE_HEIGHT 600
     16 
     17 static uint32_t scale_to_display(uint32_t value) {
     18 	uint32_t display_width = ta_display_width();
     19 	uint32_t display_height = ta_display_height();
     20 	uint32_t numerator = display_width;
     21 	uint32_t denominator = TA_BUTTON_REFERENCE_WIDTH;
     22 
     23 	if ((uint32_t)display_width * TA_BUTTON_REFERENCE_HEIGHT >= (uint32_t)display_height * TA_BUTTON_REFERENCE_WIDTH) {
     24 		numerator = display_height;
     25 		denominator = TA_BUTTON_REFERENCE_HEIGHT;
     26 	}
     27 
     28 	uint32_t scaled = (value * numerator * 2 + denominator) / (denominator * 2);
     29 
     30 	return scaled == 0 ? 1 : scaled;
     31 }
     32 
     33 void ta_button_lists_init(ta_button_lists *list) {
     34 	if (list == NULL) {
     35 		return;
     36 	}
     37 
     38     list->buttons = NULL;
     39     list->buttons_size = 0;
     40 	list->size = 0;
     41 	list->selected = 0;
     42 	list->up_was_down = false;
     43 	list->down_was_down = false;
     44 	list->enter_was_down = false;
     45 }
     46 
     47 bool ta_button_lists_add(ta_button_lists *list, const char *label, ta_button_callback callback) {
     48 	if (list == NULL || label == NULL) {
     49 		return false;
     50 	}
     51 
     52     if (list->size >= list->buttons_size) {
     53         size_t new_capacity = list->buttons_size + 1;
     54         
     55         ta_button *temp = (ta_button *)realloc(list->buttons, new_capacity * sizeof(ta_button));
     56         
     57         if (temp == NULL) {
     58             return false;
     59         }
     60         
     61         list->buttons = temp;
     62         list->buttons_size = new_capacity;
     63     }
     64 
     65 	uint32_t font_size = scale_to_display(TA_BUTTON_FONT_SIZE);
     66 
     67 	if (font_size > TA_BUTTON_FONT_SIZE_MAX) {
     68 		font_size = TA_BUTTON_FONT_SIZE_MAX;
     69 	}
     70 
     71 	ta_text text_idle = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE), 1, TA_DISPLAY_RGB(0, 0, 0));
     72 	ta_text text_selected = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED), 1, TA_DISPLAY_RGB(0, 0, 0));
     73 
     74 	if (text_idle == 0 || text_selected == 0) {
     75 		ta_text_destroy(text_idle);
     76 		ta_text_destroy(text_selected);
     77 		return false;
     78 	}
     79 
     80 	ta_button *button = &list->buttons[list->size];
     81 
     82 	button->label = label;
     83 	button->callback = callback;
     84 	button->text_idle = text_idle;
     85 	button->text_selected = text_selected;
     86 	button->text_width = ta_text_width(text_idle);
     87 	button->text_height = ta_text_height(text_idle);
     88 	
     89 	list->size++;
     90 
     91 	return true;
     92 }
     93 
     94 void ta_button_lists_update(ta_button_lists *list) {
     95 	if (list == NULL || list->size == 0) {
     96 		return;
     97 	}
     98 
     99 	bool up_down = ta_keyboard_is_down(KEY_UP);
    100 	bool down_down = ta_keyboard_is_down(KEY_DOWN);
    101 	bool enter_down = ta_keyboard_is_down(KEY_ENTER);
    102 	bool up_pressed = up_down && !list->up_was_down;
    103 	bool down_pressed = down_down && !list->down_was_down;
    104 	bool enter_pressed = enter_down && !list->enter_was_down;
    105 
    106 	list->up_was_down = up_down;
    107 	list->down_was_down = down_down;
    108 	list->enter_was_down = enter_down;
    109 
    110 	if (down_pressed || up_pressed) {
    111 		if (down_pressed) {
    112 			list->selected = (list->selected + 1) % list->size;
    113 		} else {
    114 			list->selected = list->selected == 0 ? list->size - 1 : list->selected - 1;
    115 		}
    116 	}
    117 
    118 	if (enter_pressed && list->buttons[list->selected].callback != NULL) {
    119 		list->buttons[list->selected].callback();
    120 	}
    121 }
    122 
    123 void ta_button_lists_draw(const ta_button_lists *list) {
    124 	if (list == NULL || list->size == 0) {
    125 		return;
    126 	}
    127 
    128 	uint32_t display_width = ta_display_width();
    129 	uint32_t display_height = ta_display_height();
    130 	int32_t spacing = (int32_t)scale_to_display(TA_BUTTON_SPACING);
    131 	int32_t center_y = (int32_t)(display_height / 2);
    132 	int32_t total_span = (int32_t)(list->size - 1) * spacing;
    133 	int32_t start_y = center_y - (total_span / 2);
    134 
    135 	for (size_t i = 0; i < list->size; i++) {
    136 		const ta_button *button = &list->buttons[i];
    137 		ta_text text = i == list->selected ? button->text_selected : button->text_idle;
    138 		int32_t y = start_y + (int32_t)i * spacing - (int32_t)(button->text_height / 2);
    139 
    140 		if (y < 0 || (size_t)y >= display_height || button->text_width > display_width) {
    141 			continue;
    142 		}
    143 
    144 		ta_text_draw(text, (display_width - button->text_width) / 2, (uint32_t)y);
    145 	}
    146 }
    147 
    148 void ta_button_lists_destroy(ta_button_lists *list) {
    149 	if (list == NULL) {
    150 		return;
    151 	}
    152 
    153 	for (size_t i = 0; i < list->size; i++) {
    154 		ta_text_destroy(list->buttons[i].text_idle);
    155 		ta_text_destroy(list->buttons[i].text_selected);
    156 	}
    157 
    158 	if (list->buttons != NULL) {
    159 		free(list->buttons);
    160 	}
    161 
    162 	ta_button_lists_init(list);
    163 }