Small bugfixes.
[xuni.git] / src / widget / label.c
blob3ff4f48850613268e0ec1d47e1cdc07b881f38c7
1 /*! \file label.c
3 */
5 #include <string.h>
6 #include <stdlib.h>
8 #include "SDL_gfxPrimitives.h"
10 #include "../graphics.h"
11 #include "../memory.h"
12 #include "font.h"
13 #include "widgets.h"
14 #include "label.h"
15 #include "theme.h"
17 static void free_label(struct xuni_t *xuni, struct widget_t *widget);
18 static void reposition_label(struct xuni_t *xuni, struct widget_t *widget);
19 static void rescale_label(struct xuni_t *xuni, struct widget_t *widget);
20 static void paint_label(struct xuni_t *xuni, struct widget_t *widget);
21 static void update_text_label(struct xuni_t *xuni, struct widget_t *widget);
23 static void get_label_image_pos(struct xuni_t *xuni, struct widget_t *widget,
24 int *x, int *y);
25 static int label_pos_to_width(struct xuni_t *xuni, struct widget_edit_t *edit,
26 struct widget_t *font);
27 static void paint_label_clip(SDL_Surface *image, SDL_Surface *screen,
28 int x, int y, struct clip_pos_t *clip);
29 static void paint_edit_label(struct xuni_t *xuni, struct widget_edit_t *edit,
30 struct widget_t *font, int x, int y);
32 void label_widget_event(struct xuni_t *xuni, struct widget_t *widget,
33 enum widget_event_t event) {
35 static void (*function[])(struct xuni_t *xuni, struct widget_t *widget)
36 = {
38 free_label,
39 update_text_label,
40 paint_label,
41 reposition_label,
42 rescale_label
45 call_widget_event_func(xuni, widget, event, function,
46 sizeof(function) / sizeof(*function));
49 void init_label(struct widget_t *widget, size_t font, const char *data,
50 enum label_type_t type, Uint8 r, Uint8 g, Uint8 b) {
52 widget->type = WIDGET_LABEL;
53 widget->p.label = xuni_memory_allocate(sizeof(*widget->p.label));
55 widget->p.label->type = type;
56 xuni_memory_increment((void *)data);
57 widget->p.label->text = data;
58 widget->p.label->font = font;
59 widget->p.label->label = 0;
60 widget->p.label->scroll = 0;
62 widget->p.label->col.r = r;
63 widget->p.label->col.g = g;
64 widget->p.label->col.b = b;
67 static void free_label(struct xuni_t *xuni, struct widget_t *widget) {
68 if(xuni_memory_decrement(widget->p.label)) {
69 free_surface(widget->p.label->label);
71 xuni_memory_free((void *)widget->p.label->text);
73 free(widget->p.label);
77 static void get_label_image_pos(struct xuni_t *xuni, struct widget_t *widget,
78 int *x, int *y) {
80 const SDL_Rect *real = &widget->pos->real;
81 int height
82 = font_height(xuni, get_theme_widget(xuni, widget->p.label->font));
83 int width = 0;
85 if(widget->p.label->label) {
86 width = widget->p.label->label->w;
89 switch(widget->p.label->type) {
90 case LABEL_ALIGN_LEFT:
91 *y += (real->h - height) / 2;
92 break;
93 case LABEL_ALIGN_CENTRE:
94 *x += (real->w - width) / 2;
95 *y += (real->h - height) / 2;
96 break;
97 case LABEL_ALIGN_RIGHT:
98 *x += real->w - width;
99 *y += (real->h - height) / 2;
100 break;
101 default:
102 printf("*** Unknown label type: %i\n", (int)widget->p.label->type);
103 break;
107 static void paint_label_clip(SDL_Surface *image, SDL_Surface *screen,
108 int x, int y, struct clip_pos_t *clip) {
110 if(!image) return;
112 if(!clip) {
113 blit_surface(screen, image, x, y);
115 else {
116 blit_surface_area(screen, image,
117 x + clip->xoff,
118 y + clip->yoff,
119 clip->xclip,
120 clip->yclip,
121 clip->wclip,
122 clip->hclip);
126 static int label_pos_to_width(struct xuni_t *xuni, struct widget_edit_t *edit,
127 struct widget_t *font) {
129 int w, swap;
130 char temp;
132 if(!edit->data->text || !*edit->data->text) return 0;
134 if(edit->pos != edit->len) swap = 1;
136 if(swap) {
137 temp = edit->data->text[edit->pos];
138 ((char *)edit->data->text)[edit->pos] = 0;
141 /* !!! if pos->real.w is set by reposition_label(), it could be used here
142 when edit->pos == edit->len
144 w = font_string_width(xuni, font, edit->data->text);
146 if(swap) {
147 ((char *)edit->data->text)[edit->pos] = temp;
150 return w;
153 /* !!! very inefficient */
154 size_t width_to_label_pos(struct xuni_t *xuni, int pos, struct widget_t *font,
155 char *data) {
157 int w = 0, prevw;
158 char temp;
159 size_t len = strlen(data), x = len + 1;
161 do {
162 x --;
163 temp = data[x];
164 data[x] = 0;
166 prevw = w;
167 w = font_string_width(xuni, font, data);
169 /*printf("is %i>%i for \"%s\"?\n", w, pos, data);*/
171 data[x] = temp;
172 } while(w > pos && x);
174 /*printf("%i<=%i<=%i: %i %i (%i)\n", prevw, pos, w,
175 abs(pos - prevw), abs(pos - w), (int)x);*/
177 /* Because <= is used instead of <, it opts to move the cursor to the
178 right when the exact centre of a character is clicked on. This only
179 matters for characters that are an odd number of pixels wide. */
180 if(prevw - pos <= pos - w) x ++;
182 if(x == len + 1) x --;
184 return x;
187 static void paint_edit_label(struct xuni_t *xuni, struct widget_edit_t *edit,
188 struct widget_t *font, int x, int y) {
190 int height, width;
192 width = label_pos_to_width(xuni, edit, font);
193 height = font_height(xuni, font);
194 /*vlineRGBA(smode->screen, x + widget->pos->real.w + 1,
195 y, y + widget->pos->real.h, 255, 255, 255, 255);*/
196 /*printf("width=%i, height=%i, pos=(%i,%i)\n", width, height, x, y);*/
197 vlineRGBA(xuni->smode->screen, x + width, y, y + height,
198 255, 255, 255, 255);
201 static void paint_label(struct xuni_t *xuni, struct widget_t *widget) {
202 int x = 0, y = 0;
204 /*if(widget->sel) {
205 SDL_FillRect(xuni->smode->screen, &widget->pos->real,
206 SDL_MapRGB(xuni->smode->screen->format, 0, 0, 128));
209 /*if(widget->p.label->label->h !=
210 font_height(xuni, get_theme_widget(xuni, widget->p.label->font))) {
212 printf("Not equal!\n");
215 get_label_image_pos(xuni, widget, &x, &y);
217 x += widget->pos->real.x;
218 y += widget->pos->real.y;
220 paint_label_clip(widget->p.label->label, xuni->smode->screen,
221 x, y, widget->pos->clip);
223 /* use xuni->gui->edit.datawidget instead of xuni->gui->active.widget? */
224 if(widget->base && widget->base->type == WIDGET_TEXTBOX
225 && xuni->gui->active.widget == widget->base) {
227 if(widget->pos->clip) {
228 x -= widget->pos->clip->xclip;
229 x += widget->pos->clip->xoff;
230 y += widget->pos->clip->yoff;
233 paint_edit_label(xuni, &xuni->gui->edit,
234 get_theme_widget(xuni, widget->p.label->font), x, y);
238 void reposition_label_data(struct xuni_t *xuni, struct label_t *label,
239 struct widget_edit_t *edit, size_t pos) {
241 int poswidth = label_pos_to_width(xuni, edit,
242 get_theme_widget(xuni, label->font));
243 double boxwidth = get_box_width(xuni, xuni->theme->current) / 100.0
244 * xuni->smode->width;
245 int labelw, offset, newleft, basewidth;
247 /* !!! would use widget->p.label->label->w, but the label is not resized, nor pos->real.w set */
248 if(label->text) {
249 labelw = font_string_width(xuni,
250 get_theme_widget(xuni, label->font), label->text);
252 else labelw = 0;
254 offset = labelw - edit->datawidget->base->pos->real.w + boxwidth * 2;
256 /*printf("reposition_label_data() offset=%i, poswidth=%i, labelw=%i\n",
257 offset, poswidth, labelw);*/
259 if(offset > 0) {
260 if(poswidth < offset) newleft = poswidth;
261 else newleft = offset;
263 else {
264 /* all of the text in the textbox fits into one view */
265 newleft = 0;
268 basewidth = edit->datawidget->base->pos->real.w - boxwidth * 2;
270 /* If the new left position is out of range of the displayed one, set the
271 displayed left position so that newleft is visible.
273 if(poswidth < edit->datawidget->base->p.textbox->leftpos) {
274 edit->datawidget->base->p.textbox->leftpos = poswidth;
276 else if(poswidth > edit->datawidget->base->p.textbox->leftpos
277 + basewidth) {
279 edit->datawidget->base->p.textbox->leftpos = poswidth - basewidth;
282 /*poswidth = edit->leftpos;*/
284 if(offset > edit->datawidget->base->p.textbox->leftpos) {
285 /*printf("offset by %i\n", offset - poswidth);*/
286 add_widget_clip(xuni, edit->datawidget, 0, 0,
287 -(offset - edit->datawidget->base->p.textbox->leftpos), 0, 0, 0);
290 /*if(offset > 0) {
291 add_widget_clip(xuni, edit->datawidget, 0, 0, offset, 0, 0, 0);
294 /*add_widget_clip(widget, width, 0, 0, 0, -width * 2, 0);*/
297 static void reposition_label(struct xuni_t *xuni, struct widget_t *widget) {
298 int offset;
299 int scroll = 0;
301 /* !!! hack to allow textbox scrolling */
302 if(/*widget->p.label->label &&*/ widget->base && widget->base->pos) {
303 if(widget->base->type == WIDGET_TEXTBOX) scroll = 1;
305 if(widget->base->type == WIDGET_PANEL && widget->base->base
306 && widget->base->base->type == WIDGET_LISTBOX) {
308 /*scroll = 1;*/
312 if(scroll) {
313 double width = get_box_width(xuni, xuni->theme->current) / 100.0
314 * xuni->smode->width;
315 int labelw;
317 /* !!! would use widget->p.label->label->w, but the label is not resized, nor pos->real.w set */
318 if(widget->p.label->text) {
319 labelw = font_string_width(xuni,
320 get_theme_widget(xuni, widget->p.label->font),
321 widget->p.label->text);
323 else labelw = 0;
325 offset = labelw - widget->base->pos->real.w + width * 2;
326 /*printf("base width: %i\n", widget->base->pos->real.w);
327 print_inline_widget_backtrace(widget);*/
329 if(offset > 0) {
330 add_widget_clip(xuni, widget, 0, 0, offset, 0, 0, 0);
333 add_widget_clip(xuni, widget, width, 0, 0, 0, -width * 2, 0);
335 if(offset < 0) widget->pos->real.w = labelw;
336 else {
337 widget->pos->real.w = widget->base->pos->real.w - width * 2;
340 if(widget == xuni->gui->edit.datawidget) {
341 reposition_label_data(xuni, xuni->gui->edit.data,
342 &xuni->gui->edit, xuni->gui->edit.pos);
344 /*else {
345 add_widget_clip(xuni, widget, 0, 0,
346 -widget->base->p.textbox->leftpos, 0, 0, 0);
349 /* !!! too small most likely */
350 /*widget->pos->real.h = font_height(widget->p.label->font);*/
354 static void rescale_label(struct xuni_t *xuni, struct widget_t *widget) {
356 static int count = 0;
358 printf("rescale_label() #%3i \"%s\"\n", ++count,
359 widget->p.label->text);
362 /*if(widget->p.label->font) {*/
364 free_surface(widget->p.label->label);
365 widget->p.label->label
366 = render_text(xuni,
367 get_theme_widget(xuni, widget->p.label->font),
368 widget->p.label->text,
369 widget->p.label->col.r,
370 widget->p.label->col.g,
371 widget->p.label->col.b);
373 #if !1
374 /* it's better to do this in font.c */
375 if(widget->p.label->label) {
376 SDL_Surface *temp = widget->p.label->label;
377 double ratio, xratio, yratio;
379 ratio = (xuni->smode->screen->w / (double)xuni->smode->screen->h)
380 / get_font_ratio(xuni);
381 xratio = (ratio > 1.0) ? ratio : 1.0;
382 yratio = (ratio < 1.0) ? 1.0 / ratio : 1.0;
384 widget->p.label->label = zoomSurface(temp,
385 /*widget->pos->scale.w / 100.0
386 / ((double)xuni->smode->screen->w / widget->base->pos->real.w)
387 * xuni->smode->screen->w / temp->w*/ xratio,
388 /*widget->pos->scale.h / 100.0
389 / ((double)xuni->smode->screen->h / widget->base->pos->real.h)
390 * xuni->smode->screen->h / temp->h*/ yratio,
391 SMOOTHING_ON);
393 SDL_FreeSurface(temp);
395 #endif
397 /*widget->pos->scale.w
398 = widget->p.label->label->w * 100.0 / smode->width;
399 widget->pos->scale.h
400 = widget->p.label->label->h * 100.0 / smode->height;*/
402 if(!widget->pos->scale.w && !widget->pos->scale.h
403 && widget->p.label->label) {
405 widget->pos->real.w = widget->p.label->label->w;
406 widget->pos->real.h = widget->p.label->label->h;
410 static void update_text_label(struct xuni_t *xuni, struct widget_t *widget) {
411 rescale_label(xuni, widget);