diff options
author | albeu <albeu@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-11-14 23:47:11 +0000 |
---|---|---|
committer | albeu <albeu@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-11-14 23:47:11 +0000 |
commit | c83ebc0b7df94135390661a0d7a1a7b9bda57462 (patch) | |
tree | 5c1a489baddf23a95de12d1a678599f0da04f399 /libmenu/menu.c | |
parent | 54e31581a3cc8cd5501baa8553ab0a1cf2a75bee (diff) | |
download | mpv-c83ebc0b7df94135390661a0d7a1a7b9bda57462.tar.bz2 mpv-c83ebc0b7df94135390661a0d7a1a7b9bda57462.tar.xz |
OSD menus initial version
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8198 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmenu/menu.c')
-rw-r--r-- | libmenu/menu.c | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/libmenu/menu.c b/libmenu/menu.c new file mode 100644 index 0000000000..89842f5c6e --- /dev/null +++ b/libmenu/menu.c @@ -0,0 +1,515 @@ + +#include "../config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../libvo/osd.h" +#include "../libvo/font_load.h" +#include "../linux/keycodes.h" +#include "../asxparser.h" +#include "../libmpdemux/stream.h" + +#include "img_format.h" +#include "mp_image.h" +#include "../m_option.h" +#include "../m_struct.h" +#include "menu.h" + +extern menu_info_t menu_info_cmdlist; +extern menu_info_t menu_info_pt; +extern menu_info_t menu_info_filesel; +extern menu_info_t menu_info_txt; +extern menu_info_t menu_info_console; +extern menu_info_t menu_info_pref; + +menu_info_t* menu_info_list[] = { + &menu_info_pt, + &menu_info_cmdlist, + &menu_info_filesel, + &menu_info_txt, + &menu_info_console, + &menu_info_pref, + NULL +}; + +typedef struct menu_def_st { + char* name; + menu_info_t* type; + void* cfg; + char* args; +} menu_def_t; + +static menu_def_t* menu_list = NULL; +static int mcount = 0; + + +static int menu_parse_config(char* buffer) { + char *element,*body, **attribs, *name; + menu_info_t* minfo = NULL; + int r,i; + ASX_Parser_t* parser = asx_parser_new(); + + while(1) { + r = asx_get_element(parser,&buffer,&element,&body,&attribs); + if(r < 0) { + printf("Syntax error at line %d\n",parser->line); + asx_parser_free(parser); + return 0; + } else if(r == 0) { + asx_parser_free(parser); + return 1; + } + // Has it a name ? + name = asx_get_attrib("name",attribs); + if(!name) { + printf("Menu definitions need a name attrib (line %d)\n",parser->line); + free(element); + if(body) free(body); + asx_free_attribs(attribs); + continue; + } + + // Try to find this menu type in our list + for(i = 0, minfo = NULL ; menu_info_list[i] ; i++) { + if(strcasecmp(element,menu_info_list[i]->name) == 0) { + minfo = menu_info_list[i]; + break; + } + } + // Got it : add this to our list + if(minfo) { + menu_list = realloc(menu_list,(mcount+2)*sizeof(menu_def_t)); + menu_list[mcount].name = name; + menu_list[mcount].type = minfo; + menu_list[mcount].cfg = m_struct_alloc(&minfo->priv_st); + menu_list[mcount].args = body; + // Setup the attribs + for(i = 0 ; attribs[2*i] ; i++) { + if(strcasecmp(attribs[2*i],"name") == 0) continue; + if(!m_struct_set(&minfo->priv_st,menu_list[mcount].cfg,attribs[2*i], attribs[2*i+1])) + printf("Bad attrib %s=%s in menu %s at line %d\n",attribs[2*i],attribs[2*i+1], + name,parser->line); + } + mcount++; + memset(&menu_list[mcount],0,sizeof(menu_def_t)); + } else { + printf("Unknow menu type %s at line %d\n",element,parser->line); + free(name); + if(body) free(body); + } + + free(element); + asx_free_attribs(attribs); + } + +} + + +/// This will build the menu_defs list from the cfg file +#define BUF_STEP 1024 +#define BUF_MIN 128 +#define BUF_MAX BUF_STEP*1024 +int menu_init(char* cfg_file) { + char* buffer = NULL; + int bl = BUF_STEP, br = 0; + int f; + stream_t* stream = open_stream(cfg_file,0,&f); + if(!stream) { + printf("Can't open menu config file: %s\n",cfg_file); + return 0; + } + buffer = malloc(bl); + while(1) { + int r; + if(bl - br < BUF_MIN) { + if(bl >= BUF_MAX) { + printf("Menu config file is too big (> %d KB)\n",BUF_MAX/1024); + free_stream(stream); + free(buffer); + return 0; + } + bl += BUF_STEP; + buffer = realloc(buffer,bl); + } + r = stream_read(stream,buffer+br,bl-br); + if(r == 0) break; + br += r; + } + if(!br) { + printf("Menu config file is empty\n"); + return 0; + } + buffer[br-1] = '\0'; + + f = menu_parse_config(buffer); + free(buffer); + return f; +} + +// Destroy all this stuff +void menu_unint(void) { + int i; + for(i = 0 ; menu_list && menu_list[i].name ; i++) { + free(menu_list[i].name); + m_struct_free(&menu_list[i].type->priv_st,menu_list[i].cfg); + if(menu_list[i].args) free(menu_list[i].args); + } + free(menu_list); + mcount = 0; +} + +/// Default read_key function +void menu_dflt_read_key(menu_t* menu,int cmd) { + switch(cmd) { + case KEY_UP: + menu->read_cmd(menu,MENU_CMD_UP); + break; + case KEY_DOWN: + menu->read_cmd(menu,MENU_CMD_DOWN); + break; + case KEY_LEFT: + case KEY_ESC: + menu->read_cmd(menu,MENU_CMD_CANCEL); + break; + case KEY_RIGHT: + case KEY_ENTER: + menu->read_cmd(menu,MENU_CMD_OK); + break; + } +} + +menu_t* menu_open(char *name) { + menu_t* m; + int i; + + for(i = 0 ; menu_list[i].name != NULL ; i++) { + if(strcmp(name,menu_list[i].name) == 0) + break; + } + if(menu_list[i].name == NULL) { + printf("Menu %s not found\n",name); + return NULL; + } + m = calloc(1,sizeof(menu_t)); + m->priv_st = &(menu_list[i].type->priv_st); + m->priv = m_struct_copy(m->priv_st,menu_list[i].cfg); + if(menu_list[i].type->open(m,menu_list[i].args)) + return m; + if(m->priv) + m_struct_free(m->priv_st,m->priv); + free(m); + printf("Menu %s: init failed\n",name); + return NULL; +} + +void menu_draw(menu_t* menu,mp_image_t* mpi) { + if(menu->show && menu->draw) + menu->draw(menu,mpi); +} + +void menu_read_cmd(menu_t* menu,int cmd) { + if(menu->read_cmd) + menu->read_cmd(menu,cmd); +} + +void menu_close(menu_t* menu) { + if(menu->close) + menu->close(menu); + if(menu->priv) + m_struct_free(menu->priv_st,menu->priv); + free(menu); +} + +void menu_read_key(menu_t* menu,int cmd) { + if(menu->read_key) + menu->read_key(menu,cmd); + else + menu_dflt_read_key(menu,cmd); +} + +///////////////////////////// Helpers //////////////////////////////////// + +typedef void (*draw_alpha_f)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride); + +inline static draw_alpha_f get_draw_alpha(uint32_t fmt) { + switch(fmt) { + case IMGFMT_BGR15: + case IMGFMT_RGB15: + return vo_draw_alpha_rgb15; + case IMGFMT_BGR16: + case IMGFMT_RGB16: + return vo_draw_alpha_rgb16; + case IMGFMT_BGR24: + case IMGFMT_RGB24: + return vo_draw_alpha_rgb24; + case IMGFMT_BGR32: + case IMGFMT_RGB32: + return vo_draw_alpha_rgb32; + case IMGFMT_YV12: + case IMGFMT_I420: + case IMGFMT_IYUV: + case IMGFMT_YVU9: + case IMGFMT_IF09: + case IMGFMT_Y800: + case IMGFMT_Y8: + return vo_draw_alpha_yv12; + case IMGFMT_YUY2: + return vo_draw_alpha_yuy2; + } + + return NULL; +} + + +void menu_draw_text(mp_image_t* mpi,char* txt, int x, int y) { + draw_alpha_f draw_alpha = get_draw_alpha(mpi->imgfmt); + int font; + + if(!draw_alpha) { + printf("Unsupported outformat !!!!\n"); + return; + } + + while (*txt) { + unsigned char c=*txt++; + if ((font=vo_font->font[c])>=0 && (x + vo_font->width[c] <= mpi->w) && (y + vo_font->pic_a[font]->h <= mpi->h)) + draw_alpha(vo_font->width[c], vo_font->pic_a[font]->h, + vo_font->pic_b[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->w, + mpi->planes[0] + y * mpi->stride[0] + x * (mpi->bpp>>3), + mpi->stride[0]); + x+=vo_font->width[c]+vo_font->charspace; + } + +} + +void menu_draw_text_full(mp_image_t* mpi,char* txt, + int x, int y,int w, int h, + int vspace, int warp, int align, int anchor) { + int need_w,need_h; + int sy, ymin, ymax; + int sx, xmin, xmax, xmid, xrmin; + int ll = 0; + int font; + draw_alpha_f draw_alpha = get_draw_alpha(mpi->imgfmt); + + if(!draw_alpha) { + printf("Unsupported outformat !!!!\n"); + return; + } + + if(x > mpi->w || y > mpi->h) + return; + + if(anchor & MENU_TEXT_VCENTER) { + if(h <= 0) h = mpi->h; + ymin = y - h/2; + ymax = y + h/2; + } else if(anchor & MENU_TEXT_BOT) { + if(h <= 0) h = mpi->h - y; + ymin = y - h; + ymax = y; + } else { + if(h <= 0) h = mpi->h - y; + ymin = y; + ymax = y + h; + } + + if(anchor & MENU_TEXT_HCENTER) { + if(w <= 0) w = mpi->w; + xmin = x - w/2; + xmax = x + w/2; + } else if(anchor & MENU_TEXT_RIGHT) { + if(w <= 0) w = mpi->w -x; + xmin = x - w; + xmax = x; + } else { + if(w <= 0) w = mpi->w -x; + xmin = x; + xmax = x + w; + } + + // How many space do we need to draw this ? + menu_text_size(txt,w,vspace,warp,&need_w,&need_h); + + // Find the first line + if(align & MENU_TEXT_VCENTER) + sy = ymin + ((h - need_h)/2); + else if(align & MENU_TEXT_BOT) + sy = ymax - need_h; + else + sy = y; + +#if 0 + // Find the first col + if(align & MENU_TEXT_HCENTER) + sx = xmin + ((w - need_w)/2); + else if(align & MENU_TEXT_RIGHT) + sx = xmax - need_w; +#endif + + xmid = xmin + (xmax - xmin) / 2; + xrmin = xmin; + // Clamp the bb to the mpi size + if(ymin < 0) ymin = 0; + if(xmin < 0) xmin = 0; + if(ymax > mpi->h) ymax = mpi->h; + if(xmax > mpi->w) xmax = mpi->w; + + // Jump some the beginnig text if needed + while(sy < ymin && *txt) { + unsigned char c=*txt++; + if(c == '\n' || (warp && ll + vo_font->width[c] > w)) { + ll = 0; + sy += vo_font->height + vspace; + if(c == '\n') continue; + } + ll += vo_font->width[c]+vo_font->charspace; + } + if(*txt == '\0') // Nothing left to draw + return; + + while(sy < ymax && *txt) { + char* line_end = NULL; + int n; + + if(txt[0] == '\n') { // New line + sy += vo_font->height + vspace; + txt++; + continue; + } + + // Get the length and end of this line + for(n = 0, ll = 0 ; txt[n] != '\0' && txt[n] != '\n' ; n++) { + unsigned char c = txt[n]; + if(warp && ll + vo_font->width[c] > w) break; + ll += vo_font->width[c]+vo_font->charspace; + } + line_end = &txt[n]; + ll -= vo_font->charspace; + + + if(align & (MENU_TEXT_HCENTER|MENU_TEXT_RIGHT)) { + // Too long line + if(ll > xmax-xmin) { + if(align & MENU_TEXT_HCENTER) { + int mid = ll/2; + // Find the middle point + for(n--, ll = 0 ; n <= 0 ; n--) { + ll += vo_font->width[(int)txt[n]]+vo_font->charspace; + if(ll - vo_font->charspace > mid) break; + } + ll -= vo_font->charspace; + sx = xmid + mid - ll; + } else// MENU_TEXT_RIGHT) + sx = xmax + vo_font->charspace; + + // We are after the start point -> go back + if(sx > xmin) { + for(n-- ; n <= 0 ; n--) { + unsigned char c = txt[n]; + if(sx - vo_font->width[c] - vo_font->charspace < xmin) break; + sx -= vo_font->width[c]+vo_font->charspace; + } + } else { // We are before the start point -> go forward + for( ; sx < xmin && (&txt[n]) != line_end ; n++) { + unsigned char c = txt[n]; + sx += vo_font->width[c]+vo_font->charspace; + } + } + txt = &txt[n]; // Jump to the new start char + } else { + if(align & MENU_TEXT_HCENTER) + sx = xmid - ll/2; + else + sx = xmax - ll; + } + } else { + for(sx = xrmin ; sx < xmin && txt != line_end ; txt++) { + unsigned char c = txt[n]; + sx += vo_font->width[c]+vo_font->charspace; + } + } + + while(sx < xmax && txt != line_end) { + unsigned char c = *txt++; + font = vo_font->font[c]; + if ( (font >= 0) && (sx + vo_font->width[c] <= xmax) /*&& (sy + vo_font->pic_a[font]->h <= ymax)*/) + draw_alpha(vo_font->width[c], vo_font->pic_a[font]->h, + vo_font->pic_b[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->bmp+vo_font->start[c], + vo_font->pic_a[font]->w, + mpi->planes[0] + sy * mpi->stride[0] + sx * (mpi->bpp>>3), + mpi->stride[0]); +/* else */ +/* printf("Can't draw '%c'\n",c); */ + sx+=vo_font->width[c]+vo_font->charspace; + } + txt = line_end; + if(txt[0] == '\0') break; + sy += vo_font->height + vspace; + } +} + +int menu_text_length(char* txt) { + int l = 0; + while (*txt) { + unsigned char c=*txt++; + l += vo_font->width[c]+vo_font->charspace; + } + return l - vo_font->charspace; +} + +void menu_text_size(char* txt,int max_width, int vspace, int warp, int* _w, int* _h) { + int l = 1, i = 0; + int w = 0; + + while (*txt) { + unsigned char c=*txt++; + if(c == '\n' || (warp && i + vo_font->width[c] >= max_width)) { + if(*txt) + l++; + i = 0; + if(c == '\n') continue; + } + i += vo_font->width[c]+vo_font->charspace; + if(i > w) w = i; + } + + *_w = w; + *_h = (l-1) * (vo_font->height + vspace) + vo_font->height; +} + + +int menu_text_num_lines(char* txt, int max_width) { + int l = 1, i = 0; + while (*txt) { + unsigned char c=*txt++; + if(c == '\n' || i + vo_font->width[c] > max_width) { + l++; + i = 0; + if(c == '\n') continue; + } + i += vo_font->width[c]+vo_font->charspace; + } + return l; +} + +char* menu_text_get_next_line(char* txt, int max_width) { + int i = 0; + while (*txt) { + unsigned char c=*txt; + if(c == '\n') { + txt++; + break; + } + i += vo_font->width[c]; + if(i >= max_width) + break; + i += vo_font->charspace; + } + return txt; +} |