Created Makefiles for the dist/ subdirectory and put dist/ under subversion control.
[xuni.git] / src / graphics.c
blob552355efaa251f25ca3ff4af362cb61ab146f0ed
1 /*! \file graphics.c
3 */
5 #include <stdlib.h>
6 #include <string.h>
7 #include <ctype.h>
8 #include "SDL_image.h"
9 #include "SDL_rotozoom.h"
10 #include "font.h"
11 #include "graphics.h"
12 #include "gui.h"
13 #include "settings.h"
14 #include "xuni.h"
16 static Uint32 get_flags(struct smode_t *smode);
17 static SDL_Surface *set_graphics_mode(struct smode_t *smode);
18 static int try_resizing_screen(struct smode_t *smode);
19 static void allocate_widget_p(struct widget_t *widget);
21 void clear_gui(struct gui_t *gui, enum panel_type_t panel) {
22 clear_sel(&gui->sel);
24 clear_active(&gui->active);
26 clear_tab(&gui->tab, panel);
28 /*smode->button.button = 0;
29 smode->button.xp = -1;
30 smode->button.yp = -1;*/
32 /*smode->lastclick.button = 0;
33 smode->lastclick.xp = -1;
34 smode->lastclick.yp = -1;*/
37 void clear_sel(struct widget_sel_t *sel) {
38 sel->wasin = 0;
39 sel->clickin = 0;
40 sel->p.widget = 0;
41 /*sel->p.panelid = (size_t)-1;*/
44 void clear_active(struct widget_p_t *wp) {
45 wp->widget = 0;
46 /*wp->panelid = (size_t)-1;*/
48 if(SDL_EnableUNICODE(-1)) SDL_EnableUNICODE(0);
51 void clear_tab(struct widget_tab_t *tab, enum panel_type_t panel) {
52 tab->panel = panel;
53 tab->sel = (size_t)-1;
56 /*! Initializes the SDL and SDL_ttf. Also sets the screen mode, sets the
57 caption to "Loading", disables SDL UNICODE translation, sets the focus,
58 enables key repeating, loads the icon for the window, etc.
59 \param smode The screen mode structure to read the screen mode from
61 void init_sdl(struct smode_t *smode) {
62 if(SDL_Init(SDL_INIT_VIDEO /*| SDL_INIT_AUDIO*/) < 0) {
63 fatal_error("Can't init SDL", __FILE__, __LINE__);
66 load_icon();
68 smode->screen = set_graphics_mode(smode);
69 if(!smode->screen) {
70 fatal_error("Can't set graphics mode", __FILE__, __LINE__);
73 set_caption("Loading");
75 smode->restrictfocus = set_focus(smode->restrictfocus);
77 SDL_EnableUNICODE(0);
79 if(TTF_Init() < 0) fatal_error("Can't init SDL_ttf", __FILE__, __LINE__);
81 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
82 SDL_DEFAULT_REPEAT_INTERVAL);
85 /*! Tries to set the input grab mode ("focus") to \a mode, but only if the
86 current grab mode differs from the requested grab mode. If the modes are
87 the same, it does nothing. Regardless, it returns the new grab mode.
88 \param mode The mode to set the grab mode ("focus") to.
89 \return The new grab mode. This could differ from \a mode if the function
90 failed to set the grab mode.
92 SDL_GrabMode set_focus(SDL_GrabMode mode) {
93 if(SDL_WM_GrabInput(SDL_GRAB_QUERY) != mode) {
94 return SDL_WM_GrabInput(mode);
97 return mode;
100 /*! Uninitializes the SDL and SDL_ttf libraries; the other SDL libraries
101 require no such de-initialization.
103 void quit_sdl(void) {
104 TTF_Quit();
105 SDL_Quit();
108 /*! Frees the memory allocated for a resize_image_t structure: that is, the
109 SDL_Surface representing the original image, and another SDL_Surface for
110 the resized image.
111 \param image The resize_image_t structure to free the contents of.
113 void free_resize_image(struct resize_image_t *image) {
114 if(image->original) SDL_FreeSurface(image->original);
115 if(image->image) SDL_FreeSurface(image->image);
118 /*! Frees the memory allocated for a theme_t structure.
119 \param theme The theme_t structure to free the contents of.
121 void free_theme(struct theme_t *theme) {
122 enum boxtype_t x;
124 for(x = 0; x < BOXTYPES; x ++) {
125 free_resize_image(&theme->box[x].corners);
128 free_resize_image(&theme->check);
129 free_resize_image(&theme->cursor);
131 if(theme->scrollbar.original) SDL_FreeSurface(theme->scrollbar.original);
132 if(theme->scrollbar.up) SDL_FreeSurface(theme->scrollbar.up);
133 if(theme->scrollbar.down) SDL_FreeSurface(theme->scrollbar.down);
134 if(theme->scrollbar.left) SDL_FreeSurface(theme->scrollbar.left);
135 if(theme->scrollbar.right) SDL_FreeSurface(theme->scrollbar.right);
137 free_string(&theme->name);
140 /*! Loads and sets an icon for the SDL window. If the icon could not be
141 opened, prints a warning instead.
143 void load_icon(void) {
144 SDL_Surface *icon = SDL_LoadBMP(ICON_FILE);
146 if(icon) {
147 SDL_WM_SetIcon(icon, NULL);
148 SDL_FreeSurface(icon); /* !!! ??? */
150 else {
151 print_warning("Can't open icon \"" ICON_FILE "\"",
152 __FILE__, __LINE__);
156 void load_theme(struct theme_t *theme) {
157 enum boxtype_t x;
158 size_t len = theme->name.len + GUI_PATH_LEN;
159 /* gui/path/boxtype/8.3\0 */
160 char *filename = malloc(len + 1 + 8+1 + 8+1+3 + 1);
161 /* !!! load from settings file? */
162 static char *btstr[] = {"out", "out_hov", "out_act", "in", "in_hov",
163 "in_act"};
164 size_t btlen[] = {3, 7, 7, 2, 6, 6};
166 strcpy(filename, GUI_PATH);
167 strcpy(filename + GUI_PATH_LEN, theme->name.data);
168 filename[len++] = '/';
170 for(x = 0; x < BOXTYPES; x ++) {
171 strcpy(filename + len, btstr[x]);
172 filename[len + btlen[x]] = '/';
173 strcpy(filename + len + btlen[x] + 1, "corners.png");
175 load_resize_image(&theme->box[x].corners, filename);
178 strcpy(filename + len, "check.png");
180 load_resize_image(&theme->check, filename);
182 /* !!! */
183 load_resize_image(&theme->cursor, "gui/alienglow/cursor.png");
184 theme->scrollbar.original = load_image("gui/alienglow/scrollbar.png");
185 theme->scrollbar.up = 0;
186 theme->scrollbar.down = 0;
187 theme->scrollbar.left = 0;
188 theme->scrollbar.right = 0;
190 free(filename);
192 theme->boxw_th = 30.0;
193 theme->boxh_th = 30.0;
196 /*! Opens the image \a filename as an SDL_Surface. Calls \c print_warning() if
197 the file could not be opened.
198 \param filename The image to open (in any format supported by SDL_image).
199 \return The opened image (as an SDL_Surface) or NULL on error.
201 SDL_Surface *load_image(const char *filename) {
202 SDL_Surface *image = IMG_Load(filename);
204 if(!image) print_warning("Can't open image", __FILE__, __LINE__);
206 return image;
209 void load_resize_image(struct resize_image_t *image, const char *filename) {
210 image->original = load_image(filename);
211 image->image = 0;
214 int resize_screen(struct smode_t *smode, SDL_ResizeEvent *resize) {
215 int x = smode->width;
216 int y = smode->height;
218 smode->width = resize->w;
219 smode->height = resize->h;
221 if(try_resizing_screen(smode)) {
222 smode->width = x;
223 smode->height = y;
225 return 1;
228 return 0;
231 /*! Toggles fullscreen mode for the xuni window.
233 First tries SDL_WM_ToggleFullScreen(); if that fails, it then tries
234 try_resizing_screen().
236 \param smode The current screen mode that the xuni window is in.
237 \return Zero on success, nonzero on failure.
239 int toggle_fullscreen(struct smode_t *smode) {
240 smode->fullscreen = !smode->fullscreen;
242 if(SDL_WM_ToggleFullScreen(smode->screen)) return 0;
244 if(!try_resizing_screen(smode)) return 0;
246 smode->fullscreen = !smode->fullscreen; /* undo previous toggling */
247 print_warning("Can't toggle fullscreen", __FILE__, __LINE__);
249 return 1;
252 /*! Changes the title of the xuni window to \a s, prefixed by TITLE_PREFIX.
253 \param s The string to change the title of the xuni window to.
255 void set_caption(const char *s) {
256 char wt[BUFSIZ] = TITLE_PREFIX; /* !!! this function shouldn't do this */
258 strcat(wt, s);
260 SDL_WM_SetCaption(wt, NULL);
263 void resize_theme(struct theme_t *theme, struct smode_t *smode,
264 struct font_t *font) {
266 enum boxtype_t x;
268 theme->boxw = smode->width / theme->boxw_th / 2;
269 theme->boxh = smode->height / theme->boxh_th / 2;
271 for(x = 0; x < BOXTYPES; x ++) {
272 zoom_resize_image(&theme->box[x].corners,
273 smode->width / theme->boxw_th,
274 smode->height / theme->boxh_th);
277 zoom_resize_image(&theme->check,
278 /*smode->width / 30.0 / theme->check.original->w,
279 smode->height / 30.0 / theme->check.original->h,*/
280 font->point * 1.2, /* !!! */
281 font->point);
283 zoom_resize_image(&theme->cursor,
284 smode->width / 20.0 * 3 / 4,
285 smode->height / 20.0);
287 if(theme->scrollbar.original) { /* !!! */
288 if(theme->scrollbar.up) {
289 SDL_FreeSurface(theme->scrollbar.up);
292 theme->scrollbar.up = zoomSurface(theme->scrollbar.original,
293 font->point * 1.2 / theme->cursor.original->w,
294 font->point / (double)theme->cursor.original->h,
295 SMOOTHING_ON);
297 if(theme->scrollbar.down) {
298 SDL_FreeSurface(theme->scrollbar.down);
301 theme->scrollbar.down = rotozoomSurfaceXY(theme->scrollbar.original,
302 180.0,
303 font->point * 1.2 / theme->cursor.original->w,
304 font->point / (double)theme->cursor.original->h,
305 SMOOTHING_ON);
307 if(theme->scrollbar.left) {
308 SDL_FreeSurface(theme->scrollbar.left);
311 theme->scrollbar.left = rotozoomSurfaceXY(theme->scrollbar.original,
312 270.0,
313 font->point * 1.2 / theme->cursor.original->w,
314 font->point / (double)theme->cursor.original->h,
315 SMOOTHING_ON);
317 if(theme->scrollbar.right) {
318 SDL_FreeSurface(theme->scrollbar.right);
321 theme->scrollbar.right = rotozoomSurfaceXY(theme->scrollbar.original,
322 90.0,
323 font->point * 1.2 / theme->cursor.original->w,
324 font->point / (double)theme->cursor.original->h,
325 SMOOTHING_ON);
329 void zoom_resize_image(struct resize_image_t *image, double w, double h) {
330 if(!image->original) return;
332 if(image->image) SDL_FreeSurface(image->image);
334 image->image = zoomSurface(image->original,
335 w / image->original->w, h / image->original->h, SMOOTHING_ON);
338 static Uint32 get_flags(struct smode_t *smode) {
339 Uint32 flags = SDL_SWSURFACE | SDL_RESIZABLE;
340 if(smode->fullscreen) flags |= SDL_FULLSCREEN;
342 return flags;
345 static SDL_Surface *set_graphics_mode(struct smode_t *smode) {
346 return SDL_SetVideoMode(smode->width, smode->height, smode->depth,
347 get_flags(smode));
350 SDL_Rect **list_graphics_modes(struct smode_t *smode) {
351 return SDL_ListModes(NULL, get_flags(smode));
354 static int try_resizing_screen(struct smode_t *smode) {
355 SDL_Surface *nscreen = set_graphics_mode(smode);
357 if(nscreen) smode->screen = nscreen;
359 return nscreen == 0;
362 void lock_screen(SDL_Surface *screen) {
363 if(SDL_MUSTLOCK(screen)) {
364 if(SDL_LockSurface(screen) < 0) {
365 print_warning("Can't lock screen", __FILE__, __LINE__);
370 void unlock_screen(SDL_Surface *screen) {
371 if(SDL_MUSTLOCK(screen)) {
372 SDL_UnlockSurface(screen);
376 void blit_surface(SDL_Surface *screen, SDL_Surface *image, int xp, int yp) {
377 SDL_Rect rect;
379 rect.x = xp;
380 rect.y = yp;
382 if(SDL_BlitSurface(image, NULL, screen, &rect) < 0) {
383 print_warning("Can't blit surface", __FILE__, __LINE__);
387 void blit_surface_area(SDL_Surface *screen, SDL_Surface *image,
388 int tx, int ty, int fx, int fy, int fw, int fh) {
390 SDL_Rect from, to;
392 from.x = fx;
393 from.y = fy;
394 from.w = fw;
395 from.h = fh;
396 to.x = tx;
397 to.y = ty;
399 if(SDL_BlitSurface(image, &from, screen, &to) < 0) {
400 print_warning("Can't blit surface", __FILE__, __LINE__);
404 void blit_surface_repeat(SDL_Surface *screen, SDL_Surface *image,
405 int xp, int yp, int w, int h) {
407 int x, y;
408 SDL_Rect srect, drect;
410 srect.x = 0;
411 srect.y = 0;
413 for(x = 0; x < w; x += image->w) {
414 for(y = 0; y < h; y += image->h) {
415 drect.x = xp + x;
416 drect.y = yp + y;
418 if(x + image->w > w) srect.w = w - x;
419 else srect.w = image->w;
420 if(y + image->h > h) srect.h = h - y;
421 else srect.h = image->h;
423 if(SDL_BlitSurface(image, &srect, screen, &drect) < 0) {
424 print_warning("Can't blit surface", __FILE__, __LINE__);
430 void blit_surface_repeat_area(SDL_Surface *screen, SDL_Surface *image,
431 int tx, int ty, int tw, int th, int fx, int fy, int fw, int fh) {
433 int x, y;
434 SDL_Rect srect, drect;
436 srect.x = fx;
437 srect.y = fy;
439 for(x = 0; x < tw; x += fw) {
440 for(y = 0; y < th; y += fh) {
441 drect.x = tx + x;
442 drect.y = ty + y;
444 if(x + fw > tw) srect.w = tw - x;
445 else srect.w = fw;
446 if(y + fh > th) srect.h = th - y;
447 else srect.h = fh;
449 if(SDL_BlitSurface(image, &srect, screen, &drect) < 0) {
450 print_warning("Can't blit surface", __FILE__, __LINE__);
456 void blit_surface_fill_from(SDL_Surface *screen, SDL_Surface *image,
457 int tx, int ty, int tw, int th, int fx1, int fy1) {
459 int x, y;
460 SDL_Rect srect, drect;
462 /*x = image->w - fx1 < tw ? image->w - fx1 : tw;
463 y = image->h - fy1 < th ? image->h - fy1 : th;
464 blit_surface_area(screen, image,
465 tx, ty, fx1, fy1, x, y);*/
467 for(x = fx1 - image->w; x < tw; x += image->w) {
468 for(y = fy1 - image->h; y < th; y += image->h) {
469 if(x < 0) {
470 drect.x = tx;
471 srect.x = -x;
472 srect.w = image->w - -x;
474 else {
475 drect.x = tx + x;
477 srect.x = 0;
478 if(x + image->w > tw) srect.w = tw - x;
479 else srect.w = image->w;
482 if(y < 0) {
483 drect.y = ty;
484 srect.y = -y;
485 srect.h = image->h - -y;
487 else {
488 drect.y = ty + y;
490 srect.y = 0;
491 if(y + image->h > th) srect.h = th - y;
492 else srect.h = image->h;
495 if(SDL_BlitSurface(image, &srect, screen, &drect) < 0) {
496 print_warning("Can't blit surface", __FILE__, __LINE__);
502 /*! Returns true if the position (\a xp, \a yp) is inside the rectangle
503 between (\a x, \a y) and (\c x+w, \c y+h).
504 \param xp The x coordinate of the position to check.
505 \param yp The y coordinate as the position to check.
506 \param x The x coordinate of the upper-left corner of the rectangle.
507 \param y The y coordinate of the upper-left corner of the rectangle.
508 \param w The width of the rectangle.
509 \param h The height of the rectangle.
510 \return True if the position is inside the rectangle.
512 int in_rect(int xp, int yp, int x, int y, int w, int h) {
513 return xp >= x && xp < x + w && yp >= y && yp < y + h;
516 /*! Returns true if the position (\a xp, \a yp) is inside the rectangle
517 delimited by the SDL_Rect \a r.
518 \param xp The x-coordinate of the position to check.
519 \param yp The y-coordinate of the position to check.
520 \param r The rectangle to look for a position inside.
521 \return True if the position is inside the rectangle.
523 int in_sdl_rect(int xp, int yp, SDL_Rect *r) {
524 return xp >= r->x && xp < r->x + r->w && yp >= r->y && yp < r->y + r->h;
527 /*int two_in_rect(int x1, int y1, int x2, int y2, int x, int y, int w, int h) {
528 return in_rect(x1, y1, x, y, w, h) && in_rect(x2, y2, x, y, w, h);
531 struct widget_t *allocate_widget(size_t id, enum widget_type_t type) {
532 struct widget_t *widget = malloc(sizeof(*widget));
534 /*widget->p.all = malloc(sizeof_widget_structure(type));*/
535 /*widget->p.all = 0;*/
537 widget->id = id;
538 widget->type = type;
540 widget->repaint = 0;
542 widget->enabled = 1;
544 widget->compose.widget = 0;
545 widget->compose.widgets = 0;
547 allocate_widget_p(widget);
549 return widget;
552 static void allocate_widget_p(struct widget_t *widget) {
553 switch(widget->type) {
554 case WIDGET_BUTTON:
555 widget->p.button = malloc(sizeof(*widget->p.button));
557 widget->p.button->text = 0;
558 break;
559 case WIDGET_CHECKBOX:
560 widget->p.checkbox = malloc(sizeof(*widget->p.checkbox));
562 widget->p.checkbox->text = 0;
563 break;
564 case WIDGET_TEXTBOX:
565 widget->p.textbox = malloc(sizeof(*widget->p.textbox));
567 widget->p.textbox->data.scroll.string.data = malloc(1);
568 *widget->p.textbox->data.scroll.string.data = 0;
569 widget->p.textbox->data.scroll.string.len = 0;
571 widget->p.textbox->data.scroll.text = 0;
572 break;
573 case WIDGET_LISTBOX:
574 widget->p.listbox = malloc(sizeof(*widget->p.listbox));
576 widget->p.listbox->vscroll = allocate_widget(1000, WIDGET_SCROLLBAR);
577 add_widget(&widget->compose, widget->p.listbox->vscroll);
578 /*widget->p.listbox->vscroll = 0;*/
580 widget->p.listbox->data = 0;
581 widget->p.listbox->n = 0;
582 widget->p.listbox->first = 0;
583 widget->p.listbox->selected = 0;
584 break;
585 case WIDGET_SCROLLBAR:
586 widget->p.scrollbar = malloc(sizeof(*widget->p.scrollbar));
588 add_widget(&widget->compose, allocate_widget(1000, WIDGET_BUTTON));
589 add_widget(&widget->compose, allocate_widget(1000, WIDGET_BUTTON));
590 add_widget(&widget->compose, allocate_widget(1000, WIDGET_BUTTON));
592 widget->p.scrollbar->pos = 0;
593 widget->p.scrollbar->max = 0;
594 break;
595 default:
596 break;
600 void set_widget(struct widget_t *widget, int x, int y, int w, int h) {
601 if(widget->p.button) free_widget(widget, 0); /* !!! */
603 widget->pos.x = x;
604 widget->pos.y = y;
605 widget->pos.w = w;
606 widget->pos.h = h;
609 #if 0
610 static size_t sizeof_widget_structure(enum widget_type_t type) {
611 switch(type) {
612 case WIDGET_BUTTON:
613 return sizeof(struct button_t);
614 case WIDGET_CHECKBOX:
615 return sizeof(struct checkbox_t);
616 case WIDGET_TEXTBOX:
617 return sizeof(struct textbox_t);
618 case WIDGET_LISTBOX:
619 return sizeof(struct listbox_t);
620 default:
621 print_warning("Unknown widget type", __FILE__, __LINE__);
622 return 0;
625 #endif
627 void set_button(struct widget_t *widget, TTF_Font *font, const char *text,
628 int x, int y, int w, int h) {
630 set_widget(widget, x, y, w, h);
632 /*if(!widget->p.all) {
633 widget->p.button = malloc(sizeof(*widget->p.button));
636 widget->p.button->text = render_white_text(font, text);
639 void set_button_image(struct widget_t *widget, SDL_Surface *image,
640 int x, int y, int w, int h) {
642 set_widget(widget, x, y, w, h);
644 widget->p.button->text = image;
647 void set_checkbox(struct widget_t *widget, TTF_Font *font, const char *text,
648 int checked, int x, int y, int w, int h, int bw) {
650 set_widget(widget, x, y, w, h);
652 /*if(!widget->p.all) {
653 widget->p.checkbox = malloc(sizeof(*widget->p.checkbox));
656 widget->p.checkbox->text = render_white_text(font, text);
657 widget->p.checkbox->checked = checked;
658 widget->p.checkbox->bw = bw;
661 void set_textbox(struct widget_t *widget, TTF_Font *font, int x, int y,
662 int w, int h) {
664 set_widget(widget, x, y, w, h);
666 /*if(!widget->p.all) {
667 widget->p.textbox = malloc(sizeof(*widget->p.textbox));
669 widget->p.textbox->data.scroll.string.data = malloc(1);
670 *widget->p.textbox->data.scroll.string.data = 0;
671 widget->p.textbox->data.scroll.string.len = 0;
674 /*widget->p.textbox->data.scroll.string.data = duplicate_string(data, len);
675 widget->p.textbox->data.scroll.string.len = len;*/
676 widget->p.textbox->data.scroll.first = render_restricted_text(
677 &widget->p.textbox->data.scroll.text,
678 widget->p.textbox->data.scroll.string.data, font, w);
679 /*widget->p.textbox->data.prev = widget->p.textbox->data.scroll;*/
680 /*widget->p.textbox->data.scrollalloc
681 = widget->p.textbox->data.scroll.string.len + 1;
682 widget->p.textbox->data.cursor
683 = widget->p.textbox->data.scroll.string.len;*/
686 void set_scrollbar(struct widget_t *widget, struct theme_t *theme, int max,
687 int x, int y, int w, int h) {
689 set_widget(widget, x, y, w, h);
691 set_button_image(widget->compose.widget[0], theme->scrollbar.up,
692 x, y, w, w);
693 set_button_image(widget->compose.widget[1], 0,
694 x, y + w, w, w);
695 set_button_image(widget->compose.widget[2], theme->scrollbar.down,
696 x, y + h - w, w, w);
698 /* !!! */
699 theme->scrollbar.up->refcount ++;
700 theme->scrollbar.down->refcount ++;
702 widget->p.scrollbar->max = max;
705 void set_listbox(struct widget_t *widget, struct theme_t *theme,
706 int x, int y, int w, int h) {
708 set_widget(widget, x, y, w, h);
710 set_scrollbar(widget->p.listbox->vscroll, theme, h, x + w - 30, y, 30, h);
712 /*if(!widget->p.all) {
713 widget->p.listbox = malloc(sizeof(*widget->p.listbox));
717 void set_textbox_data(struct widget_t *widget, const char *data, size_t len) {
718 free(widget->p.textbox->data.scroll.string.data);
719 widget->p.textbox->data.scroll.string.data = duplicate_string(data, len);
720 widget->p.textbox->data.scroll.string.len = len;
722 widget->p.textbox->data.scrollalloc = len + 1;
723 widget->p.textbox->data.cursor = len;
726 void add_listbox_item(struct widget_t *widget, const char *data, size_t len) {
727 widget->p.listbox->data = realloc(widget->p.listbox->data,
728 (widget->p.listbox->n + 1) * sizeof(*widget->p.listbox->data));
729 allocate_scroll_string_t(&widget->p.listbox->data[widget->p.listbox->n],
730 data, len);
731 widget->p.listbox->n ++;
734 void allocate_scroll_string_t(struct scroll_string_t *scroll,
735 const char *data, size_t len) {
737 scroll->string.data = duplicate_string(data, len);
738 scroll->string.len = len;
739 scroll->text = 0;
740 scroll->first = 0;
743 struct widget_t *widget_in_panel(int xp, int yp, struct panel_t *panel) {
744 size_t x;
745 struct widget_t *w;
747 if(!panel->widgets) return 0;
749 for(x = 0; x < panel->widgets; x ++) {
750 if(in_sdl_rect(xp, yp, &panel->widget[x]->pos)) {
751 w = widget_in_panel(xp, yp, &panel->widget[x]->compose);
752 if(w) return w;
754 return panel->widget[x];
758 return 0;
761 int set_widget_sel_repaint(struct widget_sel_t *sel, int xp, int yp,
762 int click, struct panel_t *panel) {
764 return set_widget_repaint(sel, xp, yp, click)
765 | set_widget_sel(sel, xp, yp, click, panel);
768 int set_widget_sel(struct widget_sel_t *sel, int xp, int yp, int click,
769 struct panel_t *panel) {
771 struct widget_t *w;
773 if(!panel->widgets) return 0;
775 if(sel->p.widget && !sel->clickin && !sel->wasin) clear_sel(sel);
777 if(!sel->p.widget) {
778 w = widget_in_panel(xp, yp, panel);
780 if(w) {
781 sel->wasin = 1;
782 sel->clickin = click;
783 sel->p.widget = w;
785 return 1;
789 return 0;
792 int set_widget_repaint(struct widget_sel_t *sel, int xp, int yp, int click) {
793 int r, v = 0;
795 if(sel->p.widget) {
796 v = set_compose_sel(sel, xp, yp);
798 r = in_sdl_rect(xp, yp, &sel->p.widget->pos);
800 /* the mouse focus in the widget was toggled */
801 if(sel->wasin != r) {
802 sel->wasin = r;
803 v = 1;
806 /* the mouse button was clicked or released inside the widget */
807 if(sel->clickin != click) {
808 sel->clickin = click;
809 v = 1;
812 if(v) sel->p.widget->repaint = 1;
815 return v;
818 int set_compose_sel(struct widget_sel_t *sel, int xp, int yp) {
819 struct widget_t *widget = 0;
821 if(sel->p.widget && !sel->clickin) {
822 widget = widget_in_panel(xp, yp, &sel->p.widget->compose);
823 if(widget) sel->p.widget = widget;
826 return widget != 0;
829 void perform_widget_click(struct widget_t *widget) {
830 switch(widget->type) {
831 case WIDGET_CHECKBOX:
832 widget->p.checkbox->checked = !widget->p.checkbox->checked;
833 break;
834 default:
835 break;
839 int render_restricted_text(SDL_Surface **text, const char *data,
840 TTF_Font *font, int w) {
842 const char *p = data;
844 int tw;
846 if(*p) {
847 do {
848 TTF_SizeText(font, p ++, &tw, NULL);
849 } while(tw > w && *p);
851 p --;
852 if(p != data) {
853 *text = render_white_text(font, p - 1);
855 return p - data;
859 *text = render_white_text(font, p);
861 return 0;
864 void add_char_string_alloc(struct string_t *data, size_t *alloc, char c) {
865 if(data->len + 1 >= *alloc) {
866 if(!*alloc) *alloc = 1;
867 else *alloc *= 2;
869 data->data = realloc(data->data, *alloc);
872 data->data[data->len] = c;
873 data->data[++data->len] = 0;
876 void delete_char_string_alloc(struct string_t *data) {
877 data->data[--data->len] = 0;
880 int widget_process_character(struct widget_t *widget, SDL_keysym *sym,
881 struct font_t *font, struct theme_t *theme, struct gui_t *gui) {
883 if(!(sym->unicode >> 7)) {
884 if(isprint(sym->unicode)) {
885 switch(widget->type) {
886 case WIDGET_TEXTBOX:
887 add_char_string_alloc(&widget->p.textbox->data.scroll.string,
888 &widget->p.textbox->data.scrollalloc, sym->unicode);
890 /*if(widget->p.textbox->data.scroll.text
891 != widget->p.textbox->data.prev.text) {*/
893 SDL_FreeSurface(widget->p.textbox->data.scroll.text);
894 /*}*/
896 widget->p.textbox->data.scroll.first = render_restricted_text(
897 &widget->p.textbox->data.scroll.text,
898 widget->p.textbox->data.scroll.string.data,
899 font->sans, widget->pos.w - theme->boxw * 2);
900 break;
901 default:
902 break;
905 return 1;
907 else if(sym->unicode == '\b') {
908 switch(widget->type) {
909 case WIDGET_TEXTBOX:
910 if(widget->p.textbox->data.scroll.string.len) {
911 delete_char_string_alloc(
912 &widget->p.textbox->data.scroll.string);
914 /*if(widget->p.textbox->data.scroll.text
915 != widget->p.textbox->data.prev.text) {*/
917 SDL_FreeSurface(widget->p.textbox->data.scroll.text);
918 /*}*/
920 widget->p.textbox->data.scroll.first
921 = render_restricted_text(
922 &widget->p.textbox->data.scroll.text,
923 widget->p.textbox->data.scroll.string.data,
924 font->sans, widget->pos.w - theme->boxw * 2);
926 /*widget->p.textbox->data.scroll.string.data
927 = realloc(widget->p.textbox->data.scroll.string.data,
928 widget->p.textbox->data.scroll.string.len + 1);
929 widget->p.textbox->data.scroll.string.data[
930 --widget->p.textbox->data.scroll.string.len] = 0;
931 widget->p.textbox->data.scroll.first
932 = render_restricted_text(
933 &widget->p.textbox->data.scroll.text,
934 widget->p.textbox->data.scroll.string.data,
935 font->sans, widget->pos.w - theme->boxw * 2);*/
937 else return 0;
939 break;
940 default:
941 break;
944 return 1;
946 else if(sym->unicode == '\r') {
947 switch(widget->type) {
948 case WIDGET_TEXTBOX:
949 /*free_textbox_half(&widget->p.textbox->data.prev,
950 &widget->p.textbox->data.scroll);*/
952 clear_active(&gui->active);
953 break;
954 default:
955 break;
958 return 1;
962 return 0;
965 void free_textbox_half(struct scroll_string_t *del,
966 struct scroll_string_t *ref) { /* !!! really needed? */
968 if(del->text != ref->text) SDL_FreeSurface(del->text);
970 free(del->string.data);
973 int widget_can_be_active(enum widget_type_t wt) {
974 return wt == WIDGET_TEXTBOX;
977 void enable_unicode(enum widget_type_t wt) {
978 int v = 0;
980 if(wt == WIDGET_TEXTBOX) {
981 v = 1;
984 if(SDL_EnableUNICODE(-1) != v) SDL_EnableUNICODE(v);
987 void activate_widget(struct widget_t *widget) {
988 switch(widget->type) {
989 case WIDGET_TEXTBOX:
990 /*copy_string(&widget->p.textbox->data.prev.string,
991 &widget->p.textbox->data.scroll.string);
992 widget->p.textbox->data.prev.text
993 = widget->p.textbox->data.scroll.text;
994 widget->p.textbox->data.prev.first
995 = widget->p.textbox->data.scroll.first;*/
996 break;
997 default:
998 break;
1002 void revert_widget(struct widget_t *widget) {
1003 switch(widget->type) {
1004 case WIDGET_TEXTBOX:
1005 /*if(widget->p.textbox->data.scroll.text
1006 != widget->p.textbox->data.prev.text) {
1008 SDL_FreeSurface(widget->p.textbox->data.scroll.text);
1009 widget->p.textbox->data.scroll.text =
1010 widget->p.textbox->data.prev.text;
1013 free(widget->p.textbox->data.scroll.string.data);
1015 widget->p.textbox->data.scroll = widget->p.textbox->data.prev;*/
1016 break;
1017 default:
1018 break;
1022 void deactivate_widget(struct widget_t *widget) {
1023 switch(widget->type) {
1024 case WIDGET_TEXTBOX:
1025 /*free_textbox_half(&widget->p.textbox->data.prev,
1026 &widget->p.textbox->data.scroll);*/
1027 break;
1028 default:
1029 break;
1033 void paint_widget_array(struct smode_t *smode, struct font_t *font,
1034 struct theme_t *theme, struct gui_t *gui, struct widget_t **widget,
1035 size_t n) {
1037 size_t x;
1039 if(!widget) return;
1041 for(x = 0; x < n; x ++) {
1042 paint_widget(smode, font, theme, gui, widget[x]);
1046 /*void fill_area(SDL_Surface *screen, int x, int y, int w, int h, Uint32 col) {
1047 SDL_Rect r;
1049 r.x = x;
1050 r.y = y;
1051 r.w = w;
1052 r.h = h;
1054 SDL_FillRect(screen, &r, col);
1057 void fill_area(SDL_Surface *screen, int x, int y, int w, int h,
1058 SDL_Surface *image, int ix, int iy) {
1060 Uint8 r, g, b, a;
1061 SDL_Rect rect;
1063 SDL_GetRGBA(get_pixel(image, ix, iy), image->format, &r, &g, &b, &a);
1065 if(a == 255) {
1066 rect.x = x;
1067 rect.y = y;
1068 rect.w = w;
1069 rect.h = h;
1071 SDL_FillRect(screen, &rect, SDL_MapRGBA(screen->format, r, g, b, a));
1073 else {
1074 blit_surface_repeat_area(screen, image, x, y, w, h, ix, iy, 1, 1);
1078 Uint32 get_pixel(SDL_Surface *surface, int x, int y) {
1079 int bpp = surface->format->BytesPerPixel;
1080 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
1082 if(x < 0 || y < 0 || x >= surface->w || y >= surface->h) return 0;
1084 switch(bpp) {
1085 case 1:
1086 return *p;
1087 case 2:
1088 return *(Uint16 *)p;
1089 case 3:
1090 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1091 return p[0] << 16 | p[1] << 8 | p[2];
1093 else return p[0] | p[1] << 8 | p[2] << 16;
1094 case 4:
1095 return *(Uint32 *)p;
1096 default:
1097 return 0;