Expanded on same-loop-handler-signature code, added staticgen.pl.
[xuni.git] / src / editor / editor.c
blob35fb500739c47813dfa1e34cb8c9b7bed3de4677
1 /*! \file editor.c
3 */
5 #include <string.h>
7 #include "editor.h"
9 #include "xuni.h"
10 #include "error.h"
11 #include "graphics.h"
12 #include "loadso.h"
13 #include "loop.h"
14 #include "resource/resource.h"
15 #include "memory.h"
16 #include "utility.h"
17 #include "version.h"
19 #include "widget/dump.h"
20 #include "widget/widgets.h"
22 static void load_resource(struct resource_t *settings);
23 static void save_resource(struct resource_t *resource);
25 static void init_loop_data(struct gui_t *gui);
27 #ifdef VERSION_WIN32
28 #include <windows.h>
29 int STDCALL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) {
30 #else
31 int main(int argc, char *argv[]) {
32 #endif
33 struct resource_t settings;
34 struct xuni_t *xuni = allocate_xuni();
36 xuni_error_initialize();
37 xuni_error_add_stream(0, stderr);
38 xuni_error_add_stream("editor.log", 0);
40 load_resource(&settings);
42 init_xuni(xuni, &settings,
43 lookup_resource_string(&settings, 0, "xuni-resource", "icon", 0));
45 init_loop_data(xuni->gui);
47 call_init_funcs(xuni, xuni->gui->widget, &settings);
48 main_loop(xuni, 0, PANEL_EDITOR);
50 xuni_memory_keep_freed_blocks(1);
52 save_resource(&settings);
53 free_resource(&settings);
54 free_xuni(xuni);
56 quit_sdl_libraries();
57 xuni_error_quit();
58 xuni_memory_free_all();
60 return 0;
63 static void load_resource(struct resource_t *settings) {
64 init_resource(settings);
66 if(parse_resource(settings->data, SETTINGS_FILE)) {
67 log_message(ERROR_TYPE_FATAL, 0, __FILE__, __LINE__,
68 "Failed to load resource \"%s\"", SETTINGS_FILE);
72 static void save_resource(struct resource_t *resource) {
73 /*write_resource(resource, SETTINGS_FILE ".generated");*/
76 static int editor_init(struct xuni_t *xuni, struct panel_data_t *data);
77 static int editor_start(struct xuni_t *xuni, struct panel_data_t *data);
78 static int editor_event(struct xuni_t *xuni, struct panel_data_t *data);
79 static int editor_click(struct xuni_t *xuni, struct panel_data_t *data);
80 static int editor_deactivate(struct xuni_t *xuni, struct panel_data_t *data);
81 static int editor_paint(struct xuni_t *xuni, struct panel_data_t *data);
82 static int editor_free(struct xuni_t *xuni, struct panel_data_t *data);
84 static void handle_cancel_action(struct xuni_t *xuni,
85 struct editor_data_t *data);
86 static void set_editor_mode(struct xuni_t *xuni, struct editor_data_t *data,
87 enum editor_mode_t mode);
89 enum wid_t {
90 WID_QUIT,
91 WID_MODE_LABEL,
92 WID_POSITION_LABEL,
93 WID_MODE_TEST,
94 WID_CANCEL_ACTION,
95 WID_MODE_DELETE_WIDGET,
96 WID_MODE_ADD_BUTTON,
97 WID_AREA,
98 WID_AREA_BOX,
99 WID_AREA_CURSOR_BOX,
100 WIDS
103 static void init_loop_data(struct gui_t *gui) {
104 struct widget_t *panel;
105 void *data;
107 init_wid(gui->widget, gui->widget, PANEL_EDITOR, "editor");
109 panel = widget_nameid_access(gui->widget, PANEL_EDITOR);
111 data = xuni_memory_allocate(sizeof(struct editor_data_t));
112 set_panel_data(panel, data, 0);
113 set_panel_callback(panel, PANEL_EVENT_INIT, editor_init);
114 set_panel_callback(panel, PANEL_EVENT_START, editor_start);
115 set_panel_callback(panel, PANEL_EVENT_EVENT, editor_event);
116 set_panel_callback(panel, PANEL_EVENT_SEL, default_panel_sel);
117 set_panel_callback(panel, PANEL_EVENT_CLICK, editor_click);
118 set_panel_callback(panel, PANEL_EVENT_DEACTIVATE, editor_deactivate);
119 set_panel_callback(panel, PANEL_EVENT_PAINT, editor_paint);
120 set_panel_callback(panel, PANEL_EVENT_FREE, editor_free);
122 /*set_panel_callbacks(widget_nameid_access(gui->widget, PANEL_EDITOR),
123 data, 0, editor_init, editor_start, editor_event,
124 default_panel_sel, editor_click, editor_deactivate,
125 editor_paint, editor_free);*/
128 static const char *get_mode_name(enum editor_mode_t mode) {
129 static const char *name[] = {
130 "test",
131 "delete",
132 "button"
135 if((size_t)mode < sizeof(name)/sizeof(*name)) {
136 return name[mode];
138 else return "ERROR";
141 static int editor_init(struct xuni_t *xuni, struct panel_data_t *data) {
142 struct editor_data_t *edata = data->data;
143 struct widget_t *panel = data->event[PANEL_EVENT_INIT].p.init.panel;
145 init_wid(panel, panel, WID_QUIT, "quit");
146 init_wid(panel, panel, WID_MODE_LABEL, "mode label");
147 init_wid(panel, panel, WID_POSITION_LABEL, "position label");
148 init_wid(panel, panel, WID_MODE_TEST, "resource tab/test");
149 init_wid(panel, panel, WID_CANCEL_ACTION,
150 "resource tab/cancel action");
151 init_wid(panel, panel, WID_MODE_DELETE_WIDGET,
152 "resource tab/delete widget");
153 init_wid(panel, panel, WID_MODE_ADD_BUTTON,
154 "resource tab/add button");
155 init_wid(panel, panel, WID_AREA, "area");
156 init_wid(panel, panel, WID_AREA_BOX, "area/box");
157 init_wid(panel, panel, WID_AREA_CURSOR_BOX, "area/cursor box");
159 add_widget_accelerator(xuni, panel, panel, SDLK_SPACE, KMOD_NONE);
160 add_widget_accelerator(xuni, panel, widget_nameid_access(panel,
161 WID_CANCEL_ACTION), SDLK_ESCAPE, KMOD_NONE);
163 edata->mode = EDITOR_MODE_TEST;
165 return 0;
168 static int editor_start(struct xuni_t *xuni, struct panel_data_t *data) {
169 set_caption("xuni editor");
171 return 0;
174 static int editor_event(struct xuni_t *xuni, struct panel_data_t *data) {
175 struct editor_data_t *edata = data->data;
176 struct widget_t *cbox;
177 int repaint = 0;
178 panel_type_t *mode = data->event[PANEL_EVENT_EVENT].p.event.mode;
179 SDL_Event *event = data->event[PANEL_EVENT_EVENT].p.event.event;
181 switch(event->type) {
182 case SDL_QUIT:
183 *mode = (size_t)-1;
184 break;
185 case SDL_KEYDOWN:
186 switch(event->key.keysym.sym) {
187 case SDLK_F4:
188 dump_widget_tree(xuni, widget_nameid_follow(xuni->gui->widget,
189 PANEL_EDITOR, WID_AREA, (size_t)-1));
190 break;
191 case SDLK_F3:
192 dump_widget_tree_xml(xuni, widget_nameid_follow(xuni->gui->widget,
193 PANEL_EDITOR, WID_AREA, (size_t)-1), "editor-dump.xml");
194 break;
195 default:
196 break;
199 break;
200 case SDL_MOUSEMOTION:
201 if(widget_nameid_follow(xuni->gui->widget,
202 PANEL_EDITOR, WID_AREA_BOX, (size_t)-1)->sel) {
204 char buffer[BUFSIZ], **bdata;
205 struct widget_t *label;
206 struct widget_t *box = widget_nameid_follow(xuni->gui->widget,
207 PANEL_EDITOR, WID_AREA, (size_t)-1);
209 label = widget_nameid_follow(xuni->gui->widget,
210 PANEL_EDITOR, WID_POSITION_LABEL, (size_t)-1);
211 bdata = (char **)&label->p.label->text;
213 sprintf(buffer, "(%.2f,%.2f)",
214 (event->motion.x - box->pos->real.x)
215 / (xuni->smode->width * (box->pos->scale.w / 100.0))
216 * 100.0,
217 (event->motion.y - box->pos->real.y)
218 / (xuni->smode->height * (box->pos->scale.h / 100.0))
219 * 100.0);
221 xuni_memory_free(*bdata);
222 *bdata = xuni_memory_duplicate_string(buffer);
224 widget_event(xuni, label, WIDGET_EVENT_RESCALE);
226 repaint = 1;
229 if(edata->mode == EDITOR_MODE_ADD_BUTTON) {
230 cbox = widget_nameid_follow(xuni->gui->widget,
231 PANEL_EDITOR, WID_AREA_CURSOR_BOX, (size_t)-1);
232 if(cbox->visibility & WIDGET_VISIBILITY_VISIBLE) {
233 /* !!! this really needs to be simplified */
234 cbox->pos->scale.w = (event->motion.x - cbox->pos->real.x)
235 / ((xuni->smode->width / 100.0)
236 * (cbox->base->pos->scale.w / 100.0));
237 cbox->pos->scale.h = (event->motion.y - cbox->pos->real.y)
238 / ((xuni->smode->height / 100.0)
239 * (cbox->base->pos->scale.h / 100.0));
240 if(cbox->pos->scale.w < 0) cbox->pos->scale.w = 0;
241 if(cbox->pos->scale.h < 0) cbox->pos->scale.h = 0;
243 widget_event(xuni, cbox->base, WIDGET_EVENT_RESCALE);
245 repaint = 1;
249 break;
250 default:
251 break;
254 return repaint;
257 #if !1
258 static int set_editor_widget_sel(panel_type_t mode, int xp, int yp, int click,
259 void *vdata, struct xuni_t *xuni) {
261 struct editor_data_t *data = vdata;
262 struct widget_t *widget;
264 switch(data->mode) {
265 case EDITOR_MODE_ADD_BUTTON:
266 widget = widget_nameid_follow(xuni->gui->widget,
267 PANEL_EDITOR, WID_AREA_BOX, (size_t)-1);
269 clear_widget_sel(xuni->gui->widget);
271 if(pos_in_rect(xp, yp, widget->pos)) {
272 widget->sel = 1;
273 /*return 1;*/
276 break;
277 default:
278 break;
281 return set_widget_sel_repaint(&xuni->gui->sel, xp, yp, click,
282 widget_nameid_access(xuni->gui->widget, mode));
284 #endif
286 static void handle_cancel_action(struct xuni_t *xuni,
287 struct editor_data_t *data) {
289 if(data->mode == EDITOR_MODE_ADD_BUTTON) {
290 struct widget_t *panel = widget_nameid_follow(xuni->gui->widget,
291 PANEL_EDITOR, WID_AREA_CURSOR_BOX, (size_t)-1);
293 panel->visibility &= ~WIDGET_VISIBILITY_VISIBLE;
294 panel->visibility &= ~WIDGET_VISIBILITY_SELABLE;
298 static void set_editor_mode(struct xuni_t *xuni, struct editor_data_t *data,
299 enum editor_mode_t mode) {
301 struct widget_t *modelabel;
302 const char *text;
304 if(mode == data->mode) return;
306 data->mode = mode;
308 handle_cancel_action(xuni, data);
310 modelabel = widget_nameid_follow(xuni->gui->widget,
311 PANEL_EDITOR, WID_MODE_LABEL, (size_t)-1);
313 xuni_memory_free((void *)modelabel->p.label->text);
314 text = get_mode_name(data->mode);
315 text = xuni_memory_duplicate_string(text);
316 modelabel->p.label->text = text;
317 widget_event(xuni, modelabel, WIDGET_EVENT_RESCALE);
320 static void set_all_widget_visibilities(struct widget_t *widget,
321 enum widget_visibility_t visibility) {
323 size_t x;
325 widget->visibility &= ~visibility;
327 if(widget->compose) {
328 for(x = 0; x < widget->compose->widgets; x ++) {
329 set_all_widget_visibilities(widget->compose->widget[x],
330 visibility);
335 static int editor_click(struct xuni_t *xuni, struct panel_data_t *data) {
336 struct editor_data_t *edata = data->data;
337 panel_type_t *mode = data->event[PANEL_EVENT_CLICK].p.click.mode;
338 struct widget_t *widget = data->event[PANEL_EVENT_CLICK].p.click.widget;
339 struct widget_t *cbox;
340 int repaint = 0;
341 int xp, yp;
343 switch(widget->id) {
344 case WID_QUIT:
345 *mode = (size_t)-1;
346 break;
347 case WID_MODE_TEST:
348 widget_nameid_follow(xuni->gui->widget, PANEL_EDITOR, WID_AREA_BOX,
349 (size_t)-1)->visibility &= ~WIDGET_VISIBILITY_CLICKABLE;
351 set_editor_mode(xuni, edata, EDITOR_MODE_TEST);
353 break;
354 case WID_CANCEL_ACTION:
355 handle_cancel_action(xuni, edata);
357 repaint = 1;
358 break;
359 case WID_MODE_DELETE_WIDGET:
360 widget_nameid_follow(xuni->gui->widget, PANEL_EDITOR, WID_AREA_BOX,
361 (size_t)-1)->visibility &= ~WIDGET_VISIBILITY_CLICKABLE;
363 set_editor_mode(xuni, edata, EDITOR_MODE_DELETE_WIDGET);
365 break;
366 case WID_MODE_ADD_BUTTON:
367 widget_nameid_follow(xuni->gui->widget, PANEL_EDITOR, WID_AREA_BOX,
368 (size_t)-1)->visibility |= WIDGET_VISIBILITY_CLICKABLE;
370 /*set_all_widget_visibilities(widget_nameid_follow(xuni->gui->widget,
371 PANEL_EDITOR, WID_AREA_BOX, (size_t)-1),
372 WIDGET_VISIBILITY_SELABLE);*/
374 set_editor_mode(xuni, edata, EDITOR_MODE_ADD_BUTTON);
376 break;
377 case WID_AREA_BOX:
378 if(edata->mode == EDITOR_MODE_ADD_BUTTON) {
379 cbox = widget_nameid_access(widget->base->base,
380 WID_AREA_CURSOR_BOX);
382 if(cbox->visibility & WIDGET_VISIBILITY_VISIBLE) {
383 cbox->visibility &= ~WIDGET_VISIBILITY_VISIBLE;
385 /* Only add the button if its width and height are nonzero. */
386 if(cbox->pos->scale.w && cbox->pos->scale.h) {
387 add_allocate_widget_compose(widget->base, "button");
389 init_widget_pos(last_compose_widget(widget->base),
390 cbox->pos->scale.x, cbox->pos->scale.y,
391 cbox->pos->scale.w, cbox->pos->scale.h,
392 POS_PACK_NONE);
393 init_button(last_compose_widget(widget->base), 0);
395 widget_event(xuni, last_compose_widget(widget->base),
396 WIDGET_EVENT_RESCALE);
399 else {
400 cbox->visibility |= WIDGET_VISIBILITY_VISIBLE;
402 SDL_GetMouseState(&xp, &yp);
403 xp -= cbox->base->pos->real.x;
404 yp -= cbox->base->pos->real.y;
405 cbox->pos->scale.x = (double)xp / cbox->base->pos->real.w
406 * 100.0;
407 cbox->pos->scale.y = (double)yp / cbox->base->pos->real.h
408 * 100.0;
409 cbox->pos->scale.w = 0;
410 cbox->pos->scale.h = 0;
412 widget_event(xuni, cbox, WIDGET_EVENT_RESCALE);
416 repaint = 1;
417 break;
418 default:
419 if(widget_is_parent(widget_nameid_follow(xuni->gui->widget,
420 PANEL_EDITOR, WID_AREA, (size_t)-1), widget)) {
422 if(edata->mode == EDITOR_MODE_DELETE_WIDGET) {
423 delete_widget_pointer(xuni, widget);
427 break;
430 return repaint;
433 static int editor_deactivate(struct xuni_t *xuni, struct panel_data_t *data) {
434 return 0;
437 static int editor_paint(struct xuni_t *xuni, struct panel_data_t *data) {
438 /*struct widget_t *area = widget_nameid_follow(xuni->gui->widget,
439 PANEL_EDITOR, WID_AREA, (size_t)-1);*/
441 clear_screen(xuni->smode->screen);
443 widget_event(xuni, widget_nameid_access(xuni->gui->widget, PANEL_EDITOR),
444 WIDGET_EVENT_PAINT);
447 int x, y;
448 SDL_GetMouseState(&x, &y);
449 lineRGBA(xuni->smode->screen, area->pos->real.x, area->pos->real.y,
450 x, y, 255, 255, 255, 255);
453 update_screen(xuni);
455 return 0;
458 static int editor_free(struct xuni_t *xuni, struct panel_data_t *data) {
459 return 0;
462 #ifdef LOADSO_STATIC_VERSION
463 func_point_t xuni_loadso_load_function(loadso_t object, const char *func) {
464 struct string_function_t data[] = {
465 {0, (func_point_t)0}
467 func_point_t funcp
468 = string_to_function(data, sizeof(data) / sizeof(*data), func);
470 if(!funcp) {
471 log_message(ERROR_TYPE_RESOURCE, 0, __FILE__, __LINE__,
472 "Unknown function: \"%s\"", func);
475 return funcp;
477 #endif