GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
selection_grid.c
1#include "selection_grid.h"
2
3static void selection_grid_process_directional_input(SelectionGrid* selection_grid)
4{
5 int horz_tri_input = bit_tribool(key_hit(KEY_ANY), KI_RIGHT, KI_LEFT);
6
7 if (horz_tri_input != 0)
8 {
9 selection_grid_move_selection_horz(selection_grid, horz_tri_input);
10 /* Avoid handling both vertical and horizontal input at the same time,
11 * it creates all sorts of difficult edge cases.
12 */
13 return;
14 }
15
16 int vert_tri_input = bit_tribool(key_hit(KEY_ANY), KI_DOWN, KI_UP);
17
18 if (vert_tri_input != 0)
19 {
20 selection_grid_move_selection_vert(selection_grid, vert_tri_input);
21 }
22}
23
24void selection_grid_move_selection_horz(SelectionGrid* selection_grid, int direction_tribool)
25{
26 if (selection_grid == NULL || selection_grid->selection.y < 0 ||
27 selection_grid->selection.y >= selection_grid->num_rows)
28 {
29 return;
30 }
31
32 SelectionGridRow current_row = selection_grid->rows[selection_grid->selection.y];
33
34 // Choose the horizontal exit index if it exists
35 Selection new_selection =
36 current_row.attributes.has_h_exit_idx
37 ? (Selection){selection_grid->selection.x, current_row.attributes.h_exit_idx}
38 : selection_grid->selection;
39
40 new_selection.x += direction_tribool;
41 int row_size = selection_grid->rows[new_selection.y].get_size();
42 bool wrap_enabled = selection_grid->rows[new_selection.y].attributes.wrap;
43
44 if (wrap_enabled)
45 {
46 new_selection.x = wrap(new_selection.x, 0, row_size);
47 }
48
49 if (wrap_enabled || (new_selection.x >= 0 && new_selection.x < row_size))
50 {
51 bool proceed_selection =
52 selection_grid->rows[selection_grid->selection.y].on_selection_changed(
53 selection_grid,
54 current_row.row_idx,
55 &selection_grid->selection,
56 &new_selection
57 );
58
59 if (proceed_selection)
60 {
61 selection_grid->selection = new_selection;
62 }
63 }
64}
65
66void selection_grid_move_selection_vert(SelectionGrid* selection_grid, int direction_tribool)
67{
68 if (selection_grid == NULL)
69 return;
70
71 Selection selection = selection_grid->selection;
72 Selection new_selection = selection;
73 new_selection.y += direction_tribool;
74
75 if (new_selection.y >= 0 && new_selection.y < selection_grid->num_rows)
76 {
77 int new_row_size = selection_grid->rows[new_selection.y].get_size();
78 if (new_row_size <= 0)
79 return;
80
81 int old_row_size = selection_grid->rows[selection.y].get_size();
82
83 // Branchless set to 1 if 0 to avoid division by 0
84 old_row_size += (old_row_size == 0);
85
86 // Maintain relative horizontal position
87 // The operations are equivalent to fixed point if all the numbers were converted
88 new_selection.x = fx2int(selection.x * ((int2fx(new_row_size) / old_row_size)));
89
90 bool proceed_selection = true;
91
92 if (selection.y >= 0 && selection.y < selection_grid->num_rows)
93 {
94 proceed_selection =
95 selection_grid->rows[selection.y]
96 .on_selection_changed(selection_grid, selection.y, &selection, &new_selection);
97 }
98
99 if (proceed_selection)
100 {
101 proceed_selection = selection_grid->rows[new_selection.y].on_selection_changed(
102 selection_grid,
103 new_selection.y,
104 &selection,
105 &new_selection
106 );
107 }
108
109 if (proceed_selection)
110 {
111 selection_grid->selection = new_selection;
112 }
113 }
114}
115
117{
118 if (selection_grid == NULL || selection_grid->rows == NULL)
119 return;
120
121 selection_grid_process_directional_input(selection_grid);
122
123 u32 non_directional_key = KEY_ANY & ~KEY_DIR;
124 if (key_transit(non_directional_key))
125 {
126 // To make the next line shorter and more readable
127 Selection* selection = &selection_grid->selection;
128 if (selection_grid->rows[selection->y].on_key_transit != NULL)
129 {
130 selection_grid->rows[selection->y].on_key_transit(selection_grid, selection);
131 }
132 }
133}
An implementation for a selection grid that handles directional selection.
void selection_grid_move_selection_vert(SelectionGrid *selection_grid, int direction_tribool)
Moves the selection vertically within the selection grid.
void selection_grid_move_selection_horz(SelectionGrid *selection_grid, int direction_tribool)
Moves the selection horizontally within the selection grid.
void selection_grid_process_input(SelectionGrid *selection_grid)
Processes user input for the selection grid.
bool has_h_exit_idx
Whether this row have a horizontal exit index (a row to process horizontal inputs from).
u8 h_exit_idx
The index of the row to exit from when a horizontal input is received.
bool wrap
Whether to wrap selection when it passes the end of the row.
The core selection grid struct, represents the grid itself and its state.