graphics updates
[voxelands-alt.git] / src / ui / ui.c
blob7f2d09fa7bcaabdfd159e689039cb77626daa7c6
1 /************************************************************************
2 * ui.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #include "graphics.h"
22 #include "ui.h"
24 #include <stdarg.h>
26 /* TODO: ui scaling based off scale and autoscale settings */
27 static struct {
28 widget_t *containers;
29 widget_t *elements;
30 float scale;
31 uint8_t autoscale;
32 } ui_data = {
33 NULL,
34 NULL,
35 1.0,
39 int ui_scale_setter(char* value)
41 float v;
42 if (!value)
43 return 0;
45 v = strtof(value,NULL);
46 if (v < 0.0)
47 return 0;
49 ui_data.scale = v;
51 return 0;
53 int ui_autoscale_setter(char* value)
55 ui_data.autoscale = parse_bool(value);
57 return 0;
60 /* find an empty container, or create a new one */
61 widget_t *ui_widget_container()
63 widget_t *w = ui_data.containers;
65 while (w) {
66 if (!w->style.visible && !w->child && !w->x)
67 return w;
68 w = w->next;
71 w = ui_widget_create(UI_WIDGET_CONTAINER,NULL);
73 return w;
76 /* initialise the ui */
77 int ui_init()
79 char* fontname = "font.ttf";
80 if (config_get_bool("ui.font.unifont"))
81 fontname = "unifont.ttf";
82 return font_load(fontname,"default");
85 /* draw the ui */
86 void ui_render()
88 widget_t *w;
89 widget_t *wc;
90 int mouse[2];
91 int pos[2];
92 int size[2];
93 int bx;
94 int by;
95 int bw;
96 int bh;
98 w = ui_data.containers;
99 while (w) {
100 /* TODO: uncomment this
101 if (w->style.visible)
102 ui_widget_draw(w); */
103 w = w->next;
106 wc = ui_data.containers;
107 while (wc) {
108 if (wc->style.visible) {
109 w = wc->child;
110 while (w) {
111 if (w->hover && w->parent && w->parent->hover && w->htext.length) {
112 events_get_mouse(pos);
113 textbuffer_get_dimensions(&w->htext,size);
114 mouse[0] = pos[0];
115 mouse[1] = pos[1];
116 pos[0] += 10;
117 if (mouse[1] > w->style.ttfont_size) {
118 pos[1] -= w->style.ttfont_size;
119 if (mouse[0] > (wm_data.size.width-size[0]))
120 pos[0] -= size[0]+10;
121 }else{
122 pos[0] -= size[0]+10;
125 bx = pos[0]-1;
126 by = pos[1];
127 bw = size[0]+2;
128 bh = size[1];
130 if (w->style.has_ttbg)
131 draw2d_rect(&w->style.ttbg,bx,by,bw,bh);
133 if (w->style.has_ttborder) {
134 draw2d_line(&w->style.ttborder,bx,by,bx+bw,by);
135 draw2d_line(&w->style.ttborder,bx,by,bx,by+bh );
136 draw2d_line(&w->style.ttborder,bx+bw,by,bx+bw,by+bh);
137 draw2d_line(&w->style.ttborder,bx,by+bh,bx+bw,by+bh);
141 w->htext.x = pos[0];
142 w->htext.y = pos[1];
143 render2d_textbuffer(&w->htext);
145 w = w->next;
148 wc = wc->next;
152 /* event handler for the msgbox */
153 static int ui_msg_event(widget_t *w)
155 msgbox_data_t *wd = &w->parent->data->msg;
156 if (w->id == wd->btn1->id) {
157 if (wd->btn1_func)
158 wd->btn1_func(w);
159 }else if (w->id == wd->btn2->id) {
160 if (wd->btn2_func)
161 wd->btn2_func(w);
162 }else{
163 return EVENT_UNHANDLED;
166 ui_widget_free(w->parent);
168 return EVENT_HANDLED;
171 /* create a popup message box */
172 void ui_msg(uint8_t type, char* txt, int (*func)(), ...)
174 va_list ap;
175 widget_t *con;
177 if (!(type == UIMSG_OC || type == UIMSG_OK || type == UIMSG_YN) || !txt) {
178 vlprintf(CN_WARN, "Invalid message type: %d",type);
179 return;
182 con = ui_widget_container();
184 con->style.w = 300;
185 con->style.h = 120;
186 con->style.x = UI_ALIGN_CENTRE;
187 con->style.y = UI_ALIGN_MIDDLE;
189 con->style.visible = 1;
190 con->data = malloc(sizeof(widget_data_t));
191 con->data->msg.container = con;
192 con->data->msg.btn1_func = func;
193 con->data->msg.btn2_func = NULL;
195 con->data->msg.txt = ui_widget_create(UI_WIDGET_LABEL,con);
196 */ con->data->msg.txt->style.w = 300;
197 con->data->msg.txt->style.x = 0;
198 con->data->msg.txt->style.text_align = UI_ALIGN_CENTRE;
199 con->data->msg.txt->style.y = 20;
201 ui_widget_value(con->data->msg.txt,txt);
203 /* con->data->msg.btn1 = ui_widget_create(UI_WIDGET_BUTTON,con);
204 */ con->data->msg.btn1->events->mclick = &ui_msg_event;
206 /* con->data->msg.btn2 = ui_widget_create(UI_WIDGET_BUTTON,con);
207 */ con->data->msg.btn2->events->mclick = &ui_msg_event;
209 con->data->msg.btn1->style.x = 290-con->data->msg.btn1->style.w;
210 con->data->msg.btn1->style.y = 65;
211 con->data->msg.btn2->style.x = con->data->msg.btn1->style.x-10-con->data->msg.btn2->style.w;
212 con->data->msg.btn2->style.y = 65;
214 if (type == UIMSG_OC) {
215 va_start(ap,func);
216 *(void**)(&con->data->msg.btn2_func) = va_arg(ap,int (*));
217 va_end(ap);
218 /* ui_widget_value(con->data->msg.btn1,"OK");
219 ui_widget_value(con->data->msg.btn2,"Cancel");
220 */ }else if (type == UIMSG_OK) {
221 con->data->msg.btn2->style.visible = 0;
222 /* ui_widget_value(con->data->msg.btn1,"OK");
223 */ }else if (type == UIMSG_YN) {
224 va_start(ap,func);
225 *(void**)(&con->data->msg.btn2_func) = va_arg(ap,int (*));
226 va_end(ap);
227 /* ui_widget_value(con->data->msg.btn1,"Yes");
228 ui_widget_value(con->data->msg.btn2,"No");
229 */ }
232 /* event handler for the optbox */
233 static int ui_opt_event(widget_t *w)
235 optbox_data_t *wd = &w->parent->data->opb;
236 optbox_btn_t *btn = wd->buttons;
238 while (btn) {
239 if (btn->btn->id == w->id)
240 break;
241 btn = btn->next;
244 if (!btn) {
245 return EVENT_UNHANDLED;
248 btn->func(w);
250 ui_widget_free(w->parent);
252 return EVENT_HANDLED;
255 /* create an option select popup box */
256 void ui_opt(char* txt, ...)
258 va_list ap;
259 widget_t *con;
260 int (*f)(widget_t*);
261 char* t;
262 optbox_btn_t *b;
263 int y = 95;
265 if (!txt || !txt[0])
266 return;
267 va_start(ap,txt);
268 t = (char*)va_arg(ap,char*);
269 if (!t)
270 return;
271 *(void**)(&f) = va_arg(ap,int (*));
272 if (!f)
273 return;
275 con = ui_widget_container();
276 con->data = malloc(sizeof(widget_data_t));
277 con->style.w = 200;
278 con->style.x = UI_ALIGN_CENTRE;
279 con->style.y = UI_ALIGN_MIDDLE;
280 con->style.visible = 1;
282 con->data->opb.container = con;
283 /* con->data->opb.txt = ui_widget_create(UI_WIDGET_LABEL,con);
284 con->data->opb.txt->style.x = 100-((print_length(1,SML_FONT,txt))/2);
285 */ if (con->data->opb.txt->style.x < 0)
286 con->data->opb.txt->style.x = 0;
287 con->data->msg.txt->style.y = 20;
288 /* ui_widget_value(con->data->opb.txt,txt);
290 con->data->opb.buttons = malloc(sizeof(optbox_btn_t));
291 con->data->opb.buttons->func = f;
292 /* con->data->opb.buttons->btn = ui_widget_create(UI_WIDGET_BUTTON,con);
293 */ con->data->opb.buttons->btn->style.x = 63;
294 con->data->opb.buttons->btn->style.y = 65;
295 con->data->opb.buttons->btn->events->mclick = &ui_opt_event;
296 /* ui_widget_value(con->data->opb.buttons->btn,t);
297 */ b = con->data->opb.buttons;
299 con->data->opb.buttons->next = NULL;
301 while ((t = (char*)va_arg(ap,char*)) != NULL && (*(void**)(&f) = va_arg(ap,int (*))) != NULL) {
302 b->next = malloc(sizeof(optbox_btn_t));
303 b->next->func = f;
304 /* b->next->btn = ui_widget_create(UI_WIDGET_BUTTON,con);
305 */ b->next->btn->style.x = 63;
306 b->next->btn->style.y = y;
307 b->next->btn->events->mclick = &ui_opt_event;
308 /* ui_widget_value(b->next->btn,t);
309 */ b = b->next;
310 b->next = NULL;
311 y += 30;
314 va_end(ap);
315 con->style.h = y;