=== Overview ===
[xuni.git] / src / widget / label.c
blob3b2c2af7fea03488b9021d77b8e262d4eae2b6e8
1 /*! \file label.c
3 */
5 #include <string.h>
7 #include "SDL_gfxPrimitives.h"
9 #include "../graphics.h"
10 #include "../memory.h"
11 #include "font.h"
12 #include "widgets.h"
13 #include "label.h"
14 #include "theme.h"
16 static void free_label(struct xuni_t *xuni, struct widget_t *widget);
17 static void reposition_label(struct xuni_t *xuni, struct widget_t *widget);
18 static void rescale_label(struct xuni_t *xuni, struct widget_t *widget);
19 static void paint_label(struct xuni_t *xuni, struct widget_t *widget);
20 static void update_text_label(struct xuni_t *xuni, struct widget_t *widget);
22 static void get_label_image_pos(enum label_type_t type, const SDL_Rect *real,
23 const SDL_Surface *image, int *x, int *y);
24 static int label_pos_to_width(struct widget_edit_t *edit,
25 struct widget_t *font);
26 static void paint_label_clip(SDL_Surface *image, SDL_Surface *screen,
27 int x, int y, struct clip_pos_t *clip);
28 static void paint_edit_label(struct smode_t *smode,
29 struct widget_edit_t *edit, struct widget_t *font, int x, int y);
31 void label_widget_event(struct xuni_t *xuni, struct widget_t *widget,
32 enum widget_event_t event) {
34 static void (*function[])(struct xuni_t *xuni, struct widget_t *widget)
35 = {
37 free_label,
38 update_text_label,
39 paint_label,
40 reposition_label,
41 rescale_label
44 call_widget_event_func(xuni, widget, event, function,
45 sizeof(function) / sizeof(*function));
48 void init_label(struct widget_t *widget, size_t font, const char *data,
49 enum label_type_t type, Uint8 r, Uint8 g, Uint8 b) {
51 widget->type = WIDGET_LABEL;
52 widget->p.label = xuni_memory_allocate(sizeof(*widget->p.label));
54 widget->p.label->type = type;
55 xuni_memory_increment((void *)data);
56 widget->p.label->text = data;
57 widget->p.label->font = font;
58 widget->p.label->label = 0;
59 widget->p.label->scroll = 0;
61 widget->p.label->col.r = r;
62 widget->p.label->col.g = g;
63 widget->p.label->col.b = b;
66 static void free_label(struct xuni_t *xuni, struct widget_t *widget) {
67 if(xuni_memory_decrement(widget->p.label)) {
68 free_surface(widget->p.label->label);
70 xuni_memory_free((void *)widget->p.label->text);
72 free(widget->p.label);
76 static void get_label_image_pos(enum label_type_t type, const SDL_Rect *real,
77 const SDL_Surface *image, int *x, int *y) {
79 switch(type) {
80 case LABEL_ALIGN_LEFT:
81 *y += (real->h - image->h) / 2;
82 break;
83 case LABEL_ALIGN_CENTRE:
84 *x += (real->w - image->w) / 2;
85 *y += (real->h - image->h) / 2;
86 break;
87 case LABEL_ALIGN_RIGHT:
88 *x += real->w - image->w;
89 *y += (real->h - image->h) / 2;
90 break;
91 default:
92 printf("*** Unknown label type: %i\n", (int)type);
93 break;
97 static void paint_label_clip(SDL_Surface *image, SDL_Surface *screen,
98 int x, int y, struct clip_pos_t *clip) {
100 if(!clip) {
101 blit_surface(screen, image, x, y);
103 else {
104 blit_surface_area(screen, image,
105 x + clip->xoff,
106 y + clip->yoff,
107 clip->xclip,
108 clip->yclip,
109 clip->wclip,
110 clip->hclip);
114 static int label_pos_to_width(struct widget_edit_t *edit,
115 struct widget_t *font) {
117 int w, swap;
118 char temp;
120 if(!edit->data->text || !*edit->data->text) return 0;
122 if(edit->pos != edit->len) swap = 1;
124 if(swap) {
125 temp = edit->data->text[edit->pos];
126 ((char *)edit->data->text)[edit->pos] = 0;
129 /* !!! if pos->real.w is set by reposition_label(), it could be used here
130 when edit->pos == edit->len
132 w = font_string_width(font, edit->data->text);
134 if(swap) {
135 ((char *)edit->data->text)[edit->pos] = temp;
138 return w;
141 /* !!! very inefficient */
142 size_t width_to_label_pos(int pos, struct widget_t *font, char *data) {
143 int w = 0, prevw;
144 char temp;
145 size_t len = strlen(data), x = len + 1;
147 do {
148 x --;
149 temp = data[x];
150 data[x] = 0;
152 prevw = w;
153 w = font_string_width(font, data);
155 /*printf("is %i>%i for \"%s\"?\n", w, pos, data);*/
157 data[x] = temp;
158 } while(w > pos && x);
160 /*printf("%i<=%i<=%i: %i %i (%i)\n", prevw, pos, w,
161 abs(pos - prevw), abs(pos - w), (int)x);*/
163 /* Because <= is used instead of <, it opts to move the cursor to the
164 right when the exact centre of a character is clicked on. This only
165 matters for characters that are an odd number of pixels wide. */
166 if(prevw - pos <= pos - w) x ++;
168 if(x == len + 1) x --;
170 return x;
173 static void paint_edit_label(struct smode_t *smode,
174 struct widget_edit_t *edit, struct widget_t *font, int x, int y) {
176 int height, width;
178 width = label_pos_to_width(edit, font);
179 height = font_height(font);
180 /*vlineRGBA(smode->screen, x + widget->pos->real.w + 1,
181 y, y + widget->pos->real.h, 255, 255, 255, 255);*/
182 /*printf("width=%i, height=%i, pos=(%i,%i)\n", width, height, x, y);*/
183 vlineRGBA(smode->screen, x + width,
184 y, y + height, 255, 255, 255, 255);
187 static void paint_label(struct xuni_t *xuni, struct widget_t *widget) {
188 int x = 0, y = 0;
190 if(!widget->p.label->label) {
191 return;
194 /*if(widget->sel) {
195 SDL_FillRect(xuni->smode->screen, &widget->pos->real,
196 SDL_MapRGB(xuni->smode->screen->format, 0, 0, 128));
199 get_label_image_pos(widget->p.label->type, &widget->pos->real,
200 widget->p.label->label, &x, &y);
202 x += widget->pos->real.x;
203 y += widget->pos->real.y;
205 paint_label_clip(widget->p.label->label, xuni->smode->screen,
206 x, y, widget->pos->clip);
208 /* use xuni->gui->edit.datawidget instead of xuni->gui->active.widget? */
209 if(widget->base && widget->base->type == WIDGET_TEXTBOX
210 && xuni->gui->active.widget == widget->base) {
212 if(widget->pos->clip) {
213 x -= widget->pos->clip->xclip;
214 x += widget->pos->clip->xoff;
215 y += widget->pos->clip->yoff;
218 paint_edit_label(xuni->smode, &xuni->gui->edit,
219 get_theme_widget(xuni, widget->p.label->font), x, y);
223 void reposition_label_data(struct xuni_t *xuni, struct label_t *label,
224 struct widget_edit_t *edit, size_t pos) {
226 int poswidth = label_pos_to_width(edit,
227 get_theme_widget(xuni, label->font));
228 double boxwidth = get_box_width(xuni, xuni->theme->current) / 100.0
229 * xuni->smode->width;
230 int labelw, offset, newleft, basewidth;
232 /* !!! would use widget->p.label->label->w, but the label is not resized, nor pos->real.w set */
233 if(label->text) {
234 labelw = font_string_width(
235 get_theme_widget(xuni, label->font), label->text);
237 else labelw = 0;
239 offset = labelw - edit->datawidget->base->pos->real.w + boxwidth * 2;
241 /*printf("reposition_label_data() offset=%i, poswidth=%i, labelw=%i\n",
242 offset, poswidth, labelw);*/
244 if(offset > 0) {
245 if(poswidth < offset) newleft = poswidth;
246 else newleft = offset;
248 else {
249 /* all of the text in the textbox fits into one view */
250 newleft = 0;
253 basewidth = edit->datawidget->base->pos->real.w - boxwidth * 2;
255 /* If the new left position is out of range of the displayed one, set the
256 displayed left position so that newleft is visible.
258 if(poswidth < edit->datawidget->base->p.textbox->leftpos) {
259 edit->datawidget->base->p.textbox->leftpos = poswidth;
261 else if(poswidth > edit->datawidget->base->p.textbox->leftpos
262 + basewidth) {
264 edit->datawidget->base->p.textbox->leftpos = poswidth - basewidth;
267 /*poswidth = edit->leftpos;*/
269 if(offset > edit->datawidget->base->p.textbox->leftpos) {
270 /*printf("offset by %i\n", offset - poswidth);*/
271 add_widget_clip(xuni, edit->datawidget, 0, 0,
272 -(offset - edit->datawidget->base->p.textbox->leftpos), 0, 0, 0);
275 /*if(offset > 0) {
276 add_widget_clip(xuni, edit->datawidget, 0, 0, offset, 0, 0, 0);
279 /*add_widget_clip(widget, width, 0, 0, 0, -width * 2, 0);*/
282 static void reposition_label(struct xuni_t *xuni, struct widget_t *widget) {
283 int offset;
285 /* !!! hack to allow textbox scrolling */
286 if(/*widget->p.label->label &&*/ widget->base && widget->base->pos
287 && (widget->base->type == WIDGET_TEXTBOX
288 || widget->base->type == WIDGET_PANEL)) {
290 double width = get_box_width(xuni, xuni->theme->current) / 100.0
291 * xuni->smode->width;
292 int labelw;
294 /* !!! would use widget->p.label->label->w, but the label is not resized, nor pos->real.w set */
295 if(widget->p.label->text) {
296 labelw = font_string_width(
297 get_theme_widget(xuni, widget->p.label->font),
298 widget->p.label->text);
300 else labelw = 0;
302 offset = labelw - widget->base->pos->real.w + width * 2;
303 /*printf("base width: %i\n", widget->base->pos->real.w);
304 print_inline_widget_backtrace(widget);*/
305 if(widget->base->type == WIDGET_TEXTBOX) {
306 if(offset > 0) {
307 add_widget_clip(xuni, widget, 0, 0, offset, 0, 0, 0);
310 add_widget_clip(xuni, widget, width, 0, 0, 0, -width * 2, 0);
313 if(offset < 0) widget->pos->real.w = labelw;
314 else {
315 widget->pos->real.w = widget->base->pos->real.w - width * 2;
318 /*if(widget->base->type == WIDGET_TEXTBOX) {*/
319 if(widget == xuni->gui->edit.datawidget) {
320 reposition_label_data(xuni, xuni->gui->edit.data,
321 &xuni->gui->edit, xuni->gui->edit.pos);
323 /*else {
324 add_widget_clip(xuni, widget, 0, 0,
325 -widget->base->p.textbox->leftpos, 0, 0, 0);
329 /* !!! too small most likely */
330 /*widget->pos->real.h = font_height(widget->p.label->font);*/
334 static void rescale_label(struct xuni_t *xuni, struct widget_t *widget) {
336 static int count = 0;
338 printf("rescale_label() #%3i \"%s\"\n", ++count,
339 widget->p.label->text);
342 /*if(widget->p.label->font) {*/
344 free_surface(widget->p.label->label);
345 widget->p.label->label
346 = render_text(get_theme_widget(xuni, widget->p.label->font),
347 widget->p.label->text,
348 widget->p.label->col.r,
349 widget->p.label->col.g,
350 widget->p.label->col.b);
352 /*widget->pos->scale.w
353 = widget->p.label->label->w * 100.0 / smode->width;
354 widget->pos->scale.h
355 = widget->p.label->label->h * 100.0 / smode->height;*/
357 if(!widget->pos->scale.w && !widget->pos->scale.h
358 && widget->p.label->label) {
360 widget->pos->real.w = widget->p.label->label->w;
361 widget->pos->real.h = widget->p.label->label->h;
365 static void update_text_label(struct xuni_t *xuni, struct widget_t *widget) {
366 rescale_label(xuni, widget);