summaryrefslogtreecommitdiff
path: root/src/sdlutils.h
blob: 9a9d56e003b0516b119255eb2ea2bac7b2b0b8b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
// __-prefixed functions, structs, etc. are not advised to be used by other files
#include <stdlib.h>
#include <math.h>

#include <SDL.h>
#include <SDL_ttf.h>
#include "colors.h"

#define FONT_WIDTH_FACTOR 0.585 // Width of text / letter / font size
#define FONT_HEIGHT_FACTOR 1.2 // Height of text / font size

#define FONT_SIZE 12
#define CHAR_WIDTH FONT_WIDTH_FACTOR * FONT_SIZE
#define CHAR_HEIGHT FONT_HEIGHT_FACTOR * FONT_SIZE

#define MAX_OPTIONS 1000

#define ENTRY_SUBMIT 1 << 14

SDL_Window* window;
SDL_Surface* window_surface;
SDL_Renderer* renderer;
TTF_Font* font;
char* editor;
char* __sdlutils_clear;
int __sdlutils_entry_capacity;
int __sdlutils_entry_enabled;

typedef struct
{
    char* text;
    int xpos;
    int ypos;
    int action_id;
    SDL_Color fg;
    SDL_Color bg;
    SDL_Color hl; // BG When highlighted
} __sdlutils_option;

__sdlutils_option** __sdlutils_options;
int __sdlutils_selected = 0;
int __sdlutils_option_count = 0;
int __sdlutils_entry_x, __sdlutils_entry_y;
char* __sdlutils_entry_contents;
int __sdlutils_entry_contents_sz; // Length of string in entry

char* int_to_str(int i)
{
    char* buffer = malloc((int)(log((double)i)/log(10))+3);
    sprintf(buffer, "%d", i);
    return buffer;
}

char* double_to_str(double d)
{
    char* buffer = malloc(32);
    sprintf(buffer, "%f", d);
    return buffer;
}


void write_text(char* text, int x, int y, SDL_Color fg, SDL_Color bg)
{
    if (!(text && text[0])) return;
    SDL_Surface* text_surface = TTF_RenderText_Solid(font, text, fg);
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, text_surface);
    SDL_Rect rect = {x, y, text_surface->w, text_surface->h};
    SDL_SetRenderDrawColor(renderer, bg.r, bg.g, bg.b, bg.a);
    SDL_RenderFillRect(renderer, &rect);
    SDL_RenderCopy(renderer, texture, NULL, &rect);
    SDL_FreeSurface(text_surface);
    SDL_DestroyTexture(texture);

}

void write_str(char* s, int xpos, int ypos, SDL_Color fg, SDL_Color bg)
{
    // For grid-like letter placement (for text-based applications1)
    // Same as write_text, but writes in terms of the letter positions
    write_text(s, xpos * CHAR_WIDTH, ypos * CHAR_HEIGHT, fg, bg);
}

void hcenter_str(char* s, int cols, int ypos, SDL_Color fg, SDL_Color bg)
{
    // Center string horizontally
    write_str(s, cols / 2 - strlen(s) / 2, ypos, fg, bg);
}

void write_char(char c, int xpos, int ypos, SDL_Color fg, SDL_Color bg)
{
    char* s = malloc(2);
    s[0] = c;
    s[1] = 0;
    write_str(s, xpos, ypos, fg, bg);
}

void create_option(char* text, int action_id, int x, int y, SDL_Color fg, SDL_Color bg, SDL_Color highlighted)
{
    __sdlutils_option* opt = malloc(sizeof(__sdlutils_option));
    opt->text = text;
    opt->action_id = action_id;
    opt->xpos = x;
    opt->ypos = y;
    opt->fg = fg;
    opt->bg = bg;
    opt->hl = highlighted;
    __sdlutils_options[__sdlutils_option_count++] = opt;
}

void draw_options()
{
    int i;
    __sdlutils_option* opt;
    for (i = 0; opt = __sdlutils_options[i]; i++)
    {
        write_str(opt->text, opt->xpos, opt->ypos, opt->fg, __sdlutils_selected == i ? opt->hl : opt->bg);
    }
}

void clear_options()
{
    int i;
    for (i = __sdlutils_option_count = 0; i < MAX_OPTIONS; i++)
    {
        __sdlutils_options[i] = NULL;
    }
    __sdlutils_selected = 0;
    for (i = 0; i < __sdlutils_entry_capacity; i++) __sdlutils_entry_contents[i] = 0;
    __sdlutils_entry_enabled = 0;
    SDL_StopTextInput();
}

int mod(int a, int b)
{
    a %= b;
    while (a < 0) a += b;
    return a;
}

void draw_entry()
{
    if (__sdlutils_entry_enabled)
    {
        write_str(__sdlutils_clear, __sdlutils_entry_x, __sdlutils_entry_y, BLACK, BLACK);
        write_str(__sdlutils_entry_contents, __sdlutils_entry_x, __sdlutils_entry_y, WHITE, BLACK);
    }
}

void setup_entry(char* contents, int x, int y)
{
    memcpy(__sdlutils_entry_contents, contents, strlen(contents)+1);
    __sdlutils_entry_x = x;
    __sdlutils_entry_y = y;
    __sdlutils_entry_enabled = 1;
    SDL_StartTextInput();
    draw_entry();
}

char* get_entry_contents()
{
    return __sdlutils_entry_contents;
}



int sdlutils_process_key(SDL_Keycode kc)
{
    int len;
    switch (kc)
    {
    case SDLK_UP:
        if (__sdlutils_options[0])
        {
            __sdlutils_selected--;
            __sdlutils_selected = mod(__sdlutils_selected, __sdlutils_option_count);
            draw_options();
        }
        break;
    case SDLK_DOWN:
        if (__sdlutils_options[0])
        {
            __sdlutils_selected++;
            __sdlutils_selected = mod(__sdlutils_selected, __sdlutils_option_count);
            draw_options();
        }
        break;
    case SDLK_RETURN:
        if (__sdlutils_entry_enabled) return ENTRY_SUBMIT;
        if (__sdlutils_options[0]) return __sdlutils_options[__sdlutils_selected]->action_id;
        break;
    case SDLK_BACKSPACE:
        if (!__sdlutils_entry_enabled) break;
        len = strlen(__sdlutils_entry_contents);
        __sdlutils_entry_contents[(len ? len : 1)-1] = 0;
        break;
    }
    if (__sdlutils_options[0]) __sdlutils_selected = mod(__sdlutils_selected, __sdlutils_option_count);
    draw_entry();
    return 0;
}

void handle_text(char* text)
{
    if (!__sdlutils_entry_enabled) return;
    strcat(__sdlutils_entry_contents, text);
    draw_entry();
}

void quit()
{
    SDL_DestroyWindow(window);
    TTF_CloseFont(font);
    TTF_Quit();
    SDL_Quit();
    exit(0);
}

void sdlutils_set_capacity(int capacity)
{
    __sdlutils_entry_contents = malloc((__sdlutils_entry_capacity = capacity)+1);
    __sdlutils_clear = malloc(__sdlutils_entry_capacity+1);
    int i;
    for (i = 0; i < __sdlutils_entry_capacity; i++)
    {
        __sdlutils_clear[i] = 'M'; // Wide letter for non-monospace fonts (although most of this wouldn't work for non-monospace fonts)
    }
    __sdlutils_clear[i] = 0;
}

void sdlutils_init(int width, int height)
{
    __sdlutils_options = malloc(MAX_OPTIONS*sizeof(__sdlutils_option*));

    clear_options();

    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        fprintf(stderr, "SDL Error: %s\n", SDL_GetError());
        exit(1);
    }
    if (TTF_Init() == -1)
    {
        fprintf(stderr, "SDL_ttf could not initialize! SDL_ttf Error: %s\n", TTF_GetError());
    }

    window = SDL_CreateWindow("A framework for genetic algorithms", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);
    if (window == NULL)
    {
        fprintf(stderr, "SDL Error: %s\n", SDL_GetError());
        exit(1);
    }

    window_surface = SDL_GetWindowSurface(window);
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    // Font
    font = TTF_OpenFont("fonts/DejaVuSansMono.ttf", FONT_SIZE);
}