comparison libmenu/menu.c @ 8197:b31caec933e9

OSD menus initial version
author albeu
date Thu, 14 Nov 2002 23:47:11 +0000
parents
children fefc56153615
comparison
equal deleted inserted replaced
8196:419bdbfdb660 8197:b31caec933e9
1
2 #include "../config.h"
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "../libvo/osd.h"
9 #include "../libvo/font_load.h"
10 #include "../linux/keycodes.h"
11 #include "../asxparser.h"
12 #include "../libmpdemux/stream.h"
13
14 #include "img_format.h"
15 #include "mp_image.h"
16 #include "../m_option.h"
17 #include "../m_struct.h"
18 #include "menu.h"
19
20 extern menu_info_t menu_info_cmdlist;
21 extern menu_info_t menu_info_pt;
22 extern menu_info_t menu_info_filesel;
23 extern menu_info_t menu_info_txt;
24 extern menu_info_t menu_info_console;
25 extern menu_info_t menu_info_pref;
26
27 menu_info_t* menu_info_list[] = {
28 &menu_info_pt,
29 &menu_info_cmdlist,
30 &menu_info_filesel,
31 &menu_info_txt,
32 &menu_info_console,
33 &menu_info_pref,
34 NULL
35 };
36
37 typedef struct menu_def_st {
38 char* name;
39 menu_info_t* type;
40 void* cfg;
41 char* args;
42 } menu_def_t;
43
44 static menu_def_t* menu_list = NULL;
45 static int mcount = 0;
46
47
48 static int menu_parse_config(char* buffer) {
49 char *element,*body, **attribs, *name;
50 menu_info_t* minfo = NULL;
51 int r,i;
52 ASX_Parser_t* parser = asx_parser_new();
53
54 while(1) {
55 r = asx_get_element(parser,&buffer,&element,&body,&attribs);
56 if(r < 0) {
57 printf("Syntax error at line %d\n",parser->line);
58 asx_parser_free(parser);
59 return 0;
60 } else if(r == 0) {
61 asx_parser_free(parser);
62 return 1;
63 }
64 // Has it a name ?
65 name = asx_get_attrib("name",attribs);
66 if(!name) {
67 printf("Menu definitions need a name attrib (line %d)\n",parser->line);
68 free(element);
69 if(body) free(body);
70 asx_free_attribs(attribs);
71 continue;
72 }
73
74 // Try to find this menu type in our list
75 for(i = 0, minfo = NULL ; menu_info_list[i] ; i++) {
76 if(strcasecmp(element,menu_info_list[i]->name) == 0) {
77 minfo = menu_info_list[i];
78 break;
79 }
80 }
81 // Got it : add this to our list
82 if(minfo) {
83 menu_list = realloc(menu_list,(mcount+2)*sizeof(menu_def_t));
84 menu_list[mcount].name = name;
85 menu_list[mcount].type = minfo;
86 menu_list[mcount].cfg = m_struct_alloc(&minfo->priv_st);
87 menu_list[mcount].args = body;
88 // Setup the attribs
89 for(i = 0 ; attribs[2*i] ; i++) {
90 if(strcasecmp(attribs[2*i],"name") == 0) continue;
91 if(!m_struct_set(&minfo->priv_st,menu_list[mcount].cfg,attribs[2*i], attribs[2*i+1]))
92 printf("Bad attrib %s=%s in menu %s at line %d\n",attribs[2*i],attribs[2*i+1],
93 name,parser->line);
94 }
95 mcount++;
96 memset(&menu_list[mcount],0,sizeof(menu_def_t));
97 } else {
98 printf("Unknow menu type %s at line %d\n",element,parser->line);
99 free(name);
100 if(body) free(body);
101 }
102
103 free(element);
104 asx_free_attribs(attribs);
105 }
106
107 }
108
109
110 /// This will build the menu_defs list from the cfg file
111 #define BUF_STEP 1024
112 #define BUF_MIN 128
113 #define BUF_MAX BUF_STEP*1024
114 int menu_init(char* cfg_file) {
115 char* buffer = NULL;
116 int bl = BUF_STEP, br = 0;
117 int f;
118 stream_t* stream = open_stream(cfg_file,0,&f);
119 if(!stream) {
120 printf("Can't open menu config file: %s\n",cfg_file);
121 return 0;
122 }
123 buffer = malloc(bl);
124 while(1) {
125 int r;
126 if(bl - br < BUF_MIN) {
127 if(bl >= BUF_MAX) {
128 printf("Menu config file is too big (> %d KB)\n",BUF_MAX/1024);
129 free_stream(stream);
130 free(buffer);
131 return 0;
132 }
133 bl += BUF_STEP;
134 buffer = realloc(buffer,bl);
135 }
136 r = stream_read(stream,buffer+br,bl-br);
137 if(r == 0) break;
138 br += r;
139 }
140 if(!br) {
141 printf("Menu config file is empty\n");
142 return 0;
143 }
144 buffer[br-1] = '\0';
145
146 f = menu_parse_config(buffer);
147 free(buffer);
148 return f;
149 }
150
151 // Destroy all this stuff
152 void menu_unint(void) {
153 int i;
154 for(i = 0 ; menu_list && menu_list[i].name ; i++) {
155 free(menu_list[i].name);
156 m_struct_free(&menu_list[i].type->priv_st,menu_list[i].cfg);
157 if(menu_list[i].args) free(menu_list[i].args);
158 }
159 free(menu_list);
160 mcount = 0;
161 }
162
163 /// Default read_key function
164 void menu_dflt_read_key(menu_t* menu,int cmd) {
165 switch(cmd) {
166 case KEY_UP:
167 menu->read_cmd(menu,MENU_CMD_UP);
168 break;
169 case KEY_DOWN:
170 menu->read_cmd(menu,MENU_CMD_DOWN);
171 break;
172 case KEY_LEFT:
173 case KEY_ESC:
174 menu->read_cmd(menu,MENU_CMD_CANCEL);
175 break;
176 case KEY_RIGHT:
177 case KEY_ENTER:
178 menu->read_cmd(menu,MENU_CMD_OK);
179 break;
180 }
181 }
182
183 menu_t* menu_open(char *name) {
184 menu_t* m;
185 int i;
186
187 for(i = 0 ; menu_list[i].name != NULL ; i++) {
188 if(strcmp(name,menu_list[i].name) == 0)
189 break;
190 }
191 if(menu_list[i].name == NULL) {
192 printf("Menu %s not found\n",name);
193 return NULL;
194 }
195 m = calloc(1,sizeof(menu_t));
196 m->priv_st = &(menu_list[i].type->priv_st);
197 m->priv = m_struct_copy(m->priv_st,menu_list[i].cfg);
198 if(menu_list[i].type->open(m,menu_list[i].args))
199 return m;
200 if(m->priv)
201 m_struct_free(m->priv_st,m->priv);
202 free(m);
203 printf("Menu %s: init failed\n",name);
204 return NULL;
205 }
206
207 void menu_draw(menu_t* menu,mp_image_t* mpi) {
208 if(menu->show && menu->draw)
209 menu->draw(menu,mpi);
210 }
211
212 void menu_read_cmd(menu_t* menu,int cmd) {
213 if(menu->read_cmd)
214 menu->read_cmd(menu,cmd);
215 }
216
217 void menu_close(menu_t* menu) {
218 if(menu->close)
219 menu->close(menu);
220 if(menu->priv)
221 m_struct_free(menu->priv_st,menu->priv);
222 free(menu);
223 }
224
225 void menu_read_key(menu_t* menu,int cmd) {
226 if(menu->read_key)
227 menu->read_key(menu,cmd);
228 else
229 menu_dflt_read_key(menu,cmd);
230 }
231
232 ///////////////////////////// Helpers ////////////////////////////////////
233
234 typedef void (*draw_alpha_f)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
235
236 inline static draw_alpha_f get_draw_alpha(uint32_t fmt) {
237 switch(fmt) {
238 case IMGFMT_BGR15:
239 case IMGFMT_RGB15:
240 return vo_draw_alpha_rgb15;
241 case IMGFMT_BGR16:
242 case IMGFMT_RGB16:
243 return vo_draw_alpha_rgb16;
244 case IMGFMT_BGR24:
245 case IMGFMT_RGB24:
246 return vo_draw_alpha_rgb24;
247 case IMGFMT_BGR32:
248 case IMGFMT_RGB32:
249 return vo_draw_alpha_rgb32;
250 case IMGFMT_YV12:
251 case IMGFMT_I420:
252 case IMGFMT_IYUV:
253 case IMGFMT_YVU9:
254 case IMGFMT_IF09:
255 case IMGFMT_Y800:
256 case IMGFMT_Y8:
257 return vo_draw_alpha_yv12;
258 case IMGFMT_YUY2:
259 return vo_draw_alpha_yuy2;
260 }
261
262 return NULL;
263 }
264
265
266 void menu_draw_text(mp_image_t* mpi,char* txt, int x, int y) {
267 draw_alpha_f draw_alpha = get_draw_alpha(mpi->imgfmt);
268 int font;
269
270 if(!draw_alpha) {
271 printf("Unsupported outformat !!!!\n");
272 return;
273 }
274
275 while (*txt) {
276 unsigned char c=*txt++;
277 if ((font=vo_font->font[c])>=0 && (x + vo_font->width[c] <= mpi->w) && (y + vo_font->pic_a[font]->h <= mpi->h))
278 draw_alpha(vo_font->width[c], vo_font->pic_a[font]->h,
279 vo_font->pic_b[font]->bmp+vo_font->start[c],
280 vo_font->pic_a[font]->bmp+vo_font->start[c],
281 vo_font->pic_a[font]->w,
282 mpi->planes[0] + y * mpi->stride[0] + x * (mpi->bpp>>3),
283 mpi->stride[0]);
284 x+=vo_font->width[c]+vo_font->charspace;
285 }
286
287 }
288
289 void menu_draw_text_full(mp_image_t* mpi,char* txt,
290 int x, int y,int w, int h,
291 int vspace, int warp, int align, int anchor) {
292 int need_w,need_h;
293 int sy, ymin, ymax;
294 int sx, xmin, xmax, xmid, xrmin;
295 int ll = 0;
296 int font;
297 draw_alpha_f draw_alpha = get_draw_alpha(mpi->imgfmt);
298
299 if(!draw_alpha) {
300 printf("Unsupported outformat !!!!\n");
301 return;
302 }
303
304 if(x > mpi->w || y > mpi->h)
305 return;
306
307 if(anchor & MENU_TEXT_VCENTER) {
308 if(h <= 0) h = mpi->h;
309 ymin = y - h/2;
310 ymax = y + h/2;
311 } else if(anchor & MENU_TEXT_BOT) {
312 if(h <= 0) h = mpi->h - y;
313 ymin = y - h;
314 ymax = y;
315 } else {
316 if(h <= 0) h = mpi->h - y;
317 ymin = y;
318 ymax = y + h;
319 }
320
321 if(anchor & MENU_TEXT_HCENTER) {
322 if(w <= 0) w = mpi->w;
323 xmin = x - w/2;
324 xmax = x + w/2;
325 } else if(anchor & MENU_TEXT_RIGHT) {
326 if(w <= 0) w = mpi->w -x;
327 xmin = x - w;
328 xmax = x;
329 } else {
330 if(w <= 0) w = mpi->w -x;
331 xmin = x;
332 xmax = x + w;
333 }
334
335 // How many space do we need to draw this ?
336 menu_text_size(txt,w,vspace,warp,&need_w,&need_h);
337
338 // Find the first line
339 if(align & MENU_TEXT_VCENTER)
340 sy = ymin + ((h - need_h)/2);
341 else if(align & MENU_TEXT_BOT)
342 sy = ymax - need_h;
343 else
344 sy = y;
345
346 #if 0
347 // Find the first col
348 if(align & MENU_TEXT_HCENTER)
349 sx = xmin + ((w - need_w)/2);
350 else if(align & MENU_TEXT_RIGHT)
351 sx = xmax - need_w;
352 #endif
353
354 xmid = xmin + (xmax - xmin) / 2;
355 xrmin = xmin;
356 // Clamp the bb to the mpi size
357 if(ymin < 0) ymin = 0;
358 if(xmin < 0) xmin = 0;
359 if(ymax > mpi->h) ymax = mpi->h;
360 if(xmax > mpi->w) xmax = mpi->w;
361
362 // Jump some the beginnig text if needed
363 while(sy < ymin && *txt) {
364 unsigned char c=*txt++;
365 if(c == '\n' || (warp && ll + vo_font->width[c] > w)) {
366 ll = 0;
367 sy += vo_font->height + vspace;
368 if(c == '\n') continue;
369 }
370 ll += vo_font->width[c]+vo_font->charspace;
371 }
372 if(*txt == '\0') // Nothing left to draw
373 return;
374
375 while(sy < ymax && *txt) {
376 char* line_end = NULL;
377 int n;
378
379 if(txt[0] == '\n') { // New line
380 sy += vo_font->height + vspace;
381 txt++;
382 continue;
383 }
384
385 // Get the length and end of this line
386 for(n = 0, ll = 0 ; txt[n] != '\0' && txt[n] != '\n' ; n++) {
387 unsigned char c = txt[n];
388 if(warp && ll + vo_font->width[c] > w) break;
389 ll += vo_font->width[c]+vo_font->charspace;
390 }
391 line_end = &txt[n];
392 ll -= vo_font->charspace;
393
394
395 if(align & (MENU_TEXT_HCENTER|MENU_TEXT_RIGHT)) {
396 // Too long line
397 if(ll > xmax-xmin) {
398 if(align & MENU_TEXT_HCENTER) {
399 int mid = ll/2;
400 // Find the middle point
401 for(n--, ll = 0 ; n <= 0 ; n--) {
402 ll += vo_font->width[(int)txt[n]]+vo_font->charspace;
403 if(ll - vo_font->charspace > mid) break;
404 }
405 ll -= vo_font->charspace;
406 sx = xmid + mid - ll;
407 } else// MENU_TEXT_RIGHT)
408 sx = xmax + vo_font->charspace;
409
410 // We are after the start point -> go back
411 if(sx > xmin) {
412 for(n-- ; n <= 0 ; n--) {
413 unsigned char c = txt[n];
414 if(sx - vo_font->width[c] - vo_font->charspace < xmin) break;
415 sx -= vo_font->width[c]+vo_font->charspace;
416 }
417 } else { // We are before the start point -> go forward
418 for( ; sx < xmin && (&txt[n]) != line_end ; n++) {
419 unsigned char c = txt[n];
420 sx += vo_font->width[c]+vo_font->charspace;
421 }
422 }
423 txt = &txt[n]; // Jump to the new start char
424 } else {
425 if(align & MENU_TEXT_HCENTER)
426 sx = xmid - ll/2;
427 else
428 sx = xmax - ll;
429 }
430 } else {
431 for(sx = xrmin ; sx < xmin && txt != line_end ; txt++) {
432 unsigned char c = txt[n];
433 sx += vo_font->width[c]+vo_font->charspace;
434 }
435 }
436
437 while(sx < xmax && txt != line_end) {
438 unsigned char c = *txt++;
439 font = vo_font->font[c];
440 if ( (font >= 0) && (sx + vo_font->width[c] <= xmax) /*&& (sy + vo_font->pic_a[font]->h <= ymax)*/)
441 draw_alpha(vo_font->width[c], vo_font->pic_a[font]->h,
442 vo_font->pic_b[font]->bmp+vo_font->start[c],
443 vo_font->pic_a[font]->bmp+vo_font->start[c],
444 vo_font->pic_a[font]->w,
445 mpi->planes[0] + sy * mpi->stride[0] + sx * (mpi->bpp>>3),
446 mpi->stride[0]);
447 /* else */
448 /* printf("Can't draw '%c'\n",c); */
449 sx+=vo_font->width[c]+vo_font->charspace;
450 }
451 txt = line_end;
452 if(txt[0] == '\0') break;
453 sy += vo_font->height + vspace;
454 }
455 }
456
457 int menu_text_length(char* txt) {
458 int l = 0;
459 while (*txt) {
460 unsigned char c=*txt++;
461 l += vo_font->width[c]+vo_font->charspace;
462 }
463 return l - vo_font->charspace;
464 }
465
466 void menu_text_size(char* txt,int max_width, int vspace, int warp, int* _w, int* _h) {
467 int l = 1, i = 0;
468 int w = 0;
469
470 while (*txt) {
471 unsigned char c=*txt++;
472 if(c == '\n' || (warp && i + vo_font->width[c] >= max_width)) {
473 if(*txt)
474 l++;
475 i = 0;
476 if(c == '\n') continue;
477 }
478 i += vo_font->width[c]+vo_font->charspace;
479 if(i > w) w = i;
480 }
481
482 *_w = w;
483 *_h = (l-1) * (vo_font->height + vspace) + vo_font->height;
484 }
485
486
487 int menu_text_num_lines(char* txt, int max_width) {
488 int l = 1, i = 0;
489 while (*txt) {
490 unsigned char c=*txt++;
491 if(c == '\n' || i + vo_font->width[c] > max_width) {
492 l++;
493 i = 0;
494 if(c == '\n') continue;
495 }
496 i += vo_font->width[c]+vo_font->charspace;
497 }
498 return l;
499 }
500
501 char* menu_text_get_next_line(char* txt, int max_width) {
502 int i = 0;
503 while (*txt) {
504 unsigned char c=*txt;
505 if(c == '\n') {
506 txt++;
507 break;
508 }
509 i += vo_font->width[c];
510 if(i >= max_width)
511 break;
512 i += vo_font->charspace;
513 }
514 return txt;
515 }