From c83ebc0b7df94135390661a0d7a1a7b9bda57462 Mon Sep 17 00:00:00 2001 From: albeu Date: Thu, 14 Nov 2002 23:47:11 +0000 Subject: OSD menus initial version git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8198 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libmenu/Makefile | 38 ++++ libmenu/menu.c | 515 +++++++++++++++++++++++++++++++++++++++++++++++++ libmenu/menu.h | 72 +++++++ libmenu/menu_cmdlist.c | 155 +++++++++++++++ libmenu/menu_console.c | 234 ++++++++++++++++++++++ libmenu/menu_filesel.c | 283 +++++++++++++++++++++++++++ libmenu/menu_list.c | 225 +++++++++++++++++++++ libmenu/menu_list.h | 66 +++++++ libmenu/menu_param.c | 159 +++++++++++++++ libmenu/menu_pt.c | 151 +++++++++++++++ libmenu/menu_txt.c | 194 +++++++++++++++++++ libmenu/vf_menu.c | 251 ++++++++++++++++++++++++ 12 files changed, 2343 insertions(+) create mode 100644 libmenu/Makefile create mode 100644 libmenu/menu.c create mode 100644 libmenu/menu.h create mode 100644 libmenu/menu_cmdlist.c create mode 100644 libmenu/menu_console.c create mode 100644 libmenu/menu_filesel.c create mode 100644 libmenu/menu_list.c create mode 100644 libmenu/menu_list.h create mode 100644 libmenu/menu_param.c create mode 100644 libmenu/menu_pt.c create mode 100644 libmenu/menu_txt.c create mode 100644 libmenu/vf_menu.c (limited to 'libmenu') diff --git a/libmenu/Makefile b/libmenu/Makefile new file mode 100644 index 0000000000..7886c13679 --- /dev/null +++ b/libmenu/Makefile @@ -0,0 +1,38 @@ + +include ../config.mak + +LIBNAME = libmenu.a + +SRCS= menu.c vf_menu.c menu_cmdlist.c menu_pt.c menu_list.c menu_filesel.c menu_txt.c menu_console.c menu_param.c +OBJS=$(SRCS:.c=.o) + +CFLAGS = $(OPTFLAGS) -I. -I.. -I../libmpcodecs $(EXTRA_INC) -Wall + +.SUFFIXES: .c .o + + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< + +$(LIBNAME): $(OBJS) + $(AR) r $(LIBNAME) $(OBJS) + +all: $(LIBNAME) + +clean: + rm -f *.o *.a *~ + +distclean: + rm -f Makefile.bak *.o *.a *~ .depend + +dep: depend + +depend: + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +# +# include dependency files if they exist +# +ifneq ($(wildcard .depend),) +include .depend +endif 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 +#include +#include + +#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; +} diff --git a/libmenu/menu.h b/libmenu/menu.h new file mode 100644 index 0000000000..225326a40b --- /dev/null +++ b/libmenu/menu.h @@ -0,0 +1,72 @@ + +struct menu_priv_s; +typedef struct menu_s menu_t; + +struct menu_s { + void (*draw)(menu_t* menu,mp_image_t* mpi); + void (*read_cmd)(menu_t* menu,int cmd); + void (*read_key)(menu_t* menu,int cmd); + void (*close)(menu_t* menu); + m_struct_t* priv_st; + struct menu_priv_s* priv; + int show; // Draw it ? + int cl; // Close request (user sent a close cmd or + menu_t* parent; +}; + +typedef struct menu_info_s { + const char *info; + const char *name; + const char *author; + const char *comment; + m_struct_t priv_st; // Config struct definition + // cfg is a config struct as defined in cfg_st, it may be used as a priv struct + // cfg is filled from the attributs found in the cfg file + // the args param hold the content of the balise in the cfg file (if any) + int (*open)(menu_t* menu, char* args); +} menu_info_t; + + +#define MENU_CMD_UP 0 +#define MENU_CMD_DOWN 1 +#define MENU_CMD_OK 2 +#define MENU_CMD_CANCEL 3 + +/// Global init/uninit +int menu_init(char* cfg_file); +void menu_unint(void); + +/// Open a menu defined in the config file +menu_t* menu_open(char *name); + +void menu_draw(menu_t* menu,mp_image_t* mpi); +void menu_read_cmd(menu_t* menu,int cmd); +void menu_close(menu_t* menu); +void menu_read_key(menu_t* menu,int cmd); + +//// Default implementation +void menu_dflt_read_key(menu_t* menu,int cmd); + +/////////// Helpers + +#define MENU_TEXT_TOP (1<<0) +#define MENU_TEXT_VCENTER (1<<1) +#define MENU_TEXT_BOT (1<<2) +#define MENU_TEXT_VMASK (MENU_TEXT_TOP|MENU_TEXT_VCENTER|MENU_TEXT_BOT) +#define MENU_TEXT_LEFT (1<<3) +#define MENU_TEXT_HCENTER (1<<4) +#define MENU_TEXT_RIGHT (1<<5) +#define MENU_TEXT_HMASK (MENU_TEXT_LEFT|MENU_TEXT_HCENTER|MENU_TEXT_RIGHT) +#define MENU_TEXT_CENTER (MENU_TEXT_VCENTER|MENU_TEXT_HCENTER) + +void menu_draw_text(mp_image_t* mpi, char* txt, int x, int y); +int menu_text_length(char* txt); +int menu_text_num_lines(char* txt, int max_width); + +void menu_text_size(char* txt,int max_width, + int vspace, int warp, + int* _w, int* _h); + +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); diff --git a/libmenu/menu_cmdlist.c b/libmenu/menu_cmdlist.c new file mode 100644 index 0000000000..44e12364cd --- /dev/null +++ b/libmenu/menu_cmdlist.c @@ -0,0 +1,155 @@ + +#include "../config.h" + +#include +#include +#include + +#include "img_format.h" +#include "mp_image.h" + +#include "../m_option.h" +#include "../m_struct.h" +#include "../asxparser.h" +#include "menu.h" +#include "menu_list.h" + +#include "../libvo/font_load.h" + +#include "../input/input.h" +#include "../version.h" + + + +struct list_entry_s { + struct list_entry p; + + char* ok; + char* cancel; +}; + +struct menu_priv_s { + menu_list_priv_t p; +}; + +static struct menu_priv_s cfg_dflt = { + MENU_LIST_PRIV_DFLT +}; + +static m_option_t cfg_fields[] = { + MENU_LIST_PRIV_FIELDS, + { "title",M_ST_OFF(struct menu_priv_s,p.title), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { NULL, NULL, NULL, 0,0,0,NULL } +}; + +#define mpriv (menu->priv) + +static void read_cmd(menu_t* menu,int cmd) { + switch(cmd) { + case MENU_CMD_OK: { + if(mpriv->p.current->ok) { + mp_cmd_t* c = mp_input_parse_cmd(mpriv->p.current->ok); + if(c) + mp_input_queue_cmd(c); + } + } break; + case MENU_CMD_CANCEL: + if(mpriv->p.current->cancel) { + mp_cmd_t* c = mp_input_parse_cmd(mpriv->p.current->cancel); + if(c) + mp_input_queue_cmd(c); + break; + } + default: + menu_list_read_cmd(menu,cmd); + } +} + +static void read_key(menu_t* menu,int c){ + menu_list_read_key(menu,c,0); +} + +static void free_entry(list_entry_t* entry) { + if(entry->ok) + free(entry->ok); + if(entry->cancel) + free(entry->cancel); + free(entry->p.txt); + free(entry); +} + +static void close(menu_t* menu) { + menu_list_uninit(menu,free_entry); +} + +static int parse_args(menu_t* menu,char* args) { + char *element,*body, **attribs, *name, *ok, *cancel; + list_entry_t* m = NULL; + int r; + ASX_Parser_t* parser = asx_parser_new(); + + while(1) { + r = asx_get_element(parser,&args,&element,&body,&attribs); + if(r < 0) { + printf("Syntax error at line %d\n",parser->line); + asx_parser_free(parser); + return -1; + } else if(r == 0) { + asx_parser_free(parser); + if(!m) + printf("No entry found in the menu definition\n"); + return m ? 1 : 0; + } + // Has it a name ? + name = asx_get_attrib("name",attribs); + if(!name) { + printf("List menu entry definitions need a name (line %d)\n",parser->line); + free(element); + if(body) free(body); + asx_free_attribs(attribs); + continue; + } + ok = asx_get_attrib("ok",attribs); + cancel = asx_get_attrib("cancel",attribs); + m = calloc(1,sizeof(struct list_entry_s)); + m->p.txt = name; + m->ok = ok; + m->cancel = cancel; + menu_list_add_entry(menu,m); + + free(element); + if(body) free(body); + asx_free_attribs(attribs); + } +} + +static int open(menu_t* menu, char* args) { + menu->draw = menu_list_draw; + menu->read_cmd = read_cmd; + menu->read_key = read_key; + menu->close = close; + + if(!args) { + printf("List menu need an argument\n"); + return 0; + } + + menu_list_init(menu); + if(!parse_args(menu,args)) + return 0; + return 1; +} + +const menu_info_t menu_info_cmdlist = { + "Command list menu", + "cmdlist", + "Albeu", + "", + { + "cmdlist_cfg", + sizeof(struct menu_priv_s), + &cfg_dflt, + cfg_fields + }, + open +}; diff --git a/libmenu/menu_console.c b/libmenu/menu_console.c new file mode 100644 index 0000000000..cc30568338 --- /dev/null +++ b/libmenu/menu_console.c @@ -0,0 +1,234 @@ + +#include "../config.h" + +#include +#include +#include +#include + +#include "img_format.h" +#include "mp_image.h" + +#include "../m_struct.h" +#include "../m_option.h" +#include "menu.h" + +#include "../libvo/font_load.h" +#include "../linux/keycodes.h" +#include "../input/input.h" +#include "../linux/timer.h" + +struct menu_priv_s { + char** lines; // Our buffer + int last_line; + int num_lines; + char* input; // input buffer + int input_size; // size of the input buffer in lines + unsigned int hide_ts; + unsigned int show_ts; + + //int max_lines; // Max number of lines with the last mpi + + char* prompt; + int buf_lines; // Buffer size (in line) + int height; // Display size in % + int minb; + int vspace; + unsigned int hide_time; + unsigned int show_time; +}; + +static struct menu_priv_s cfg_dflt = { + NULL, + 0, + 0, + NULL, + 0, + 0, + 0, + + "# ", + 50, // lines + 33, // % + 3, + 3, + 500, + 500, +}; + +#define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m) + +static m_option_t cfg_fields[] = { + { "prompt", ST_OFF(prompt), CONF_TYPE_STRING, M_OPT_MIN, 1, 0, NULL }, + { "buffer-lines", ST_OFF(buf_lines), CONF_TYPE_INT, M_OPT_MIN, 5, 0, NULL }, + { "height", ST_OFF(height), CONF_TYPE_INT, M_OPT_RANGE, 1, 100, NULL }, + { "minbor", ST_OFF(minb), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, + { "vspace", ST_OFF(vspace), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, + { "show-time",ST_OFF(show_time), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, + { "hide-time",ST_OFF(hide_time), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, + { NULL, NULL, NULL, 0,0,0,NULL } +}; + +#define mpriv (menu->priv) + +static void add_line(struct menu_priv_s* priv, char* l) { + + if(priv->num_lines >= priv->buf_lines && priv->lines[priv->last_line]) + free(priv->lines[priv->last_line]); + else + priv->num_lines++; + + priv->lines[priv->last_line] = strdup(l); + priv->last_line = (priv->last_line + 1) % priv->buf_lines; +} + +static void draw(menu_t* menu, mp_image_t* mpi) { + int h = mpi->h*mpriv->height/100; + int w = mpi->w - 2* mpriv->minb; + int x = mpriv->minb, y; + int lw,lh,i, ll = mpriv->last_line - 1; + + if(mpriv->hide_ts) { + unsigned int t = GetTimerMS() - mpriv->hide_ts; + if(t >= mpriv->hide_time) { + mpriv->hide_ts = 0; + menu->show = 0; + return; + } + h = mpi->h*(mpriv->height - (mpriv->height * t /mpriv->hide_time))/100; + } else if(mpriv->show_time && mpriv->show_ts == 0) { + mpriv->show_ts = GetTimerMS(); + return; + } else if(mpriv->show_ts > 0) { + unsigned int t = GetTimerMS() - mpriv->show_ts; + if(t > mpriv->show_time) + mpriv->show_ts = -1; + else + h = mpi->h*(mpriv->height * t /mpriv->hide_time)/100; + } + + y = h - mpriv->vspace; + + if(x < 0 || y < 0 || w <= 0 || h <= 0 ) + return; + + menu_text_size(mpriv->input,w,mpriv->vspace,1,&lw,&lh); + menu_draw_text_full(mpi,mpriv->input,x,y,w,h,mpriv->vspace,1, + MENU_TEXT_BOT|MENU_TEXT_LEFT, + MENU_TEXT_BOT|MENU_TEXT_LEFT); + y -= lh + mpriv->vspace; + + for( i = 0 ; y > mpriv->minb && i < mpriv->num_lines ; i++){ + int c = (ll - i) >= 0 ? ll - i : mpriv->buf_lines + ll - i; + menu_text_size(mpriv->lines[c],w,mpriv->vspace,1,&lw,&lh); + menu_draw_text_full(mpi,mpriv->lines[c],x,y,w,h,mpriv->vspace,1, + MENU_TEXT_BOT|MENU_TEXT_LEFT, + MENU_TEXT_BOT|MENU_TEXT_LEFT); + y -= lh + mpriv->vspace; + } + return; +} + +static void read_cmd(menu_t* menu,int cmd) { + switch(cmd) { + case MENU_CMD_UP: + break; + case MENU_CMD_DOWN: + case MENU_CMD_OK: + break; + case MENU_CMD_CANCEL: + menu->show = 0; + menu->cl = 1; + break; + } +} + +static void read_key(menu_t* menu,int c) { + switch(c) { + case KEY_ESC: + if(mpriv->hide_time) + mpriv->hide_ts = GetTimerMS(); + else + menu->show = 0; + mpriv->show_ts = 0; + return; + case KEY_ENTER: { + mp_cmd_t* c = mp_input_parse_cmd(&mpriv->input[strlen(mpriv->prompt)]); + add_line(mpriv,mpriv->input); + if(!c) + add_line(mpriv,"Invalid command try help"); + else { + switch(c->id) { + case MP_CMD_CHELP: + add_line(mpriv,"Mplayer console 0.01"); + add_line(mpriv,"TODO: Write some mainful help msg ;)"); + add_line(mpriv,"Enter any mplayer command"); + add_line(mpriv,"exit close this console"); + break; + case MP_CMD_CEXIT: + menu->show = 0; + menu->cl = 1; + break; + case MP_CMD_CHIDE: + if(mpriv->hide_time) + mpriv->hide_ts = GetTimerMS(); + else + menu->show = 0; + mpriv->show_ts = 0; + break; + default: // Send the other commands to mplayer + mp_input_queue_cmd(c); + } + } + mpriv->input[strlen(mpriv->prompt)] = '\0'; + return; + } + case KEY_DELETE: + case KEY_BS: { + unsigned int i = strlen(mpriv->input); + if(i > strlen(mpriv->prompt)) + mpriv->input[i-1] = '\0'; + return; + } + } + + if(isascii(c)) { + int l = strlen(mpriv->input); + mpriv->input[l] = (char)c; + mpriv->input[l+1] = '\0'; + } + +} + + +static int open(menu_t* menu, char* args) { + + + menu->draw = draw; + menu->read_cmd = read_cmd; + menu->read_key = read_key; + + mpriv->lines = calloc(mpriv->buf_lines,sizeof(char*)); + mpriv->input_size = 1024; + mpriv->input = calloc(mpriv->input_size,sizeof(char)); + strcpy(mpriv->input,mpriv->prompt); + + if(args) + add_line(mpriv,args); + + return 1; +} + +const menu_info_t menu_info_console = { + "MPlayer console", + "console", + "Albeu", + "", + { + "console_cfg", + sizeof(struct menu_priv_s), + &cfg_dflt, + cfg_fields + }, + open, +}; diff --git a/libmenu/menu_filesel.c b/libmenu/menu_filesel.c new file mode 100644 index 0000000000..83eaa34881 --- /dev/null +++ b/libmenu/menu_filesel.c @@ -0,0 +1,283 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../config.h" + +#include "../m_struct.h" +#include "../m_option.h" + +#include "img_format.h" +#include "mp_image.h" + +#include "menu.h" +#include "menu_list.h" +#include "../input/input.h" +#include "../linux/keycodes.h" + +struct list_entry_s { + struct list_entry p; + int d; +}; + +struct menu_priv_s { + menu_list_priv_t p; + char* dir; // current dir + /// Cfg fields + char* path; + char* title; + char* file_action; + char* dir_action; + int auto_close; +}; + +static struct menu_priv_s cfg_dflt = { + MENU_LIST_PRIV_DFLT, + NULL, + + NULL, + "Select a file: %p", + "loadfile %p", + NULL, + 0 +}; + +#define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m) + +static m_option_t cfg_fields[] = { + MENU_LIST_PRIV_FIELDS, + { "path", ST_OFF(path), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "title", ST_OFF(title), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "file-action", ST_OFF(file_action), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "dir-action", ST_OFF(dir_action), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "auto-close", ST_OFF(auto_close), CONF_TYPE_FLAG, 0, 0, 1, NULL }, + { NULL, NULL, NULL, 0,0,0,NULL } +}; + +#define mpriv (menu->priv) + +static void free_entry(list_entry_t* entry) { + free(entry->p.txt); + free(entry); +} + +static char* replace_path(char* title , char* dir) { + char *p = strstr(title,"%p"); + if(p) { + int tl = strlen(title); + int dl = strlen(dir); + int t1l = p-title; + int l = tl - 2 + dl; + char*r = malloc(l + 1); + memcpy(r,title,t1l); + memcpy(r+t1l,dir,dl); + if(tl - t1l - 2 > 0) + memcpy(r+t1l+dl,p+2,tl - t1l - 2); + r[l] = '\0'; + return r; + } else + return title; +} + +typedef int (*kill_warn)(const void*, const void*); + +static int open_dir(menu_t* menu,char* args) { + struct dirent **namelist; + struct stat st; + int n; + char* p = NULL; + list_entry_t* e; + + int mylstat(char *dir, char *file,struct stat* st) { + int l = strlen(dir) + strlen(file); + char s[l+1]; + sprintf(s,"%s%s",args,file); + return lstat(s,st); + } + + int compare(struct dirent **a,struct dirent **b) { + struct stat as,bs; + mylstat(args,(*a)->d_name,&as); + mylstat(args,(*b)->d_name,&bs); + if(S_ISDIR(as.st_mode)) { + if(S_ISDIR(bs.st_mode)) + return alphasort(b,a); + else + return 1; + } else { + if(S_ISDIR(bs.st_mode)) + return -1; + else + return alphasort(b,a); + } + } + + int select_f(const struct dirent *d) { + if(d->d_name[0] != '.' || strcmp(d->d_name,"..") == 0) + return 1; + return 0; + } + + menu_list_init(menu); + + if(mpriv->dir) + free(mpriv->dir); + mpriv->dir = strdup(args); + if(mpriv->p.title && mpriv->p.title != mpriv->title && mpriv->p.title != cfg_dflt.p.title) + free(mpriv->p.title); + p = strstr(mpriv->title,"%p"); + + mpriv->p.title = replace_path(mpriv->title,mpriv->dir); + + n = scandir(mpriv->dir, &namelist, select_f, (kill_warn)compare); + if (n < 0) { + printf("scandir error: %s\n",strerror(errno)); + return 0; + } + while(n--) { + e = calloc(1,sizeof(list_entry_t)); + mylstat(args,namelist[n]->d_name,&st); + + if(S_ISDIR(st.st_mode)) { + int sl =strlen(namelist[n]->d_name); + e->p.txt = malloc(sl + 2); + strncpy(e->p.txt,namelist[n]->d_name,sl); + e->p.txt[sl] = '/'; + e->p.txt[sl+1] = '\0'; + e->d = 1; + menu_list_add_entry(menu,e); + } else if(strcmp(namelist[n]->d_name,"..") == 0 || namelist[n]->d_name[0] != '.') { + e->p.txt = strdup(namelist[n]->d_name); + menu_list_add_entry(menu,e); + } + free(namelist[n]); + } + free(namelist); + + return 1; +} + + +static void read_cmd(menu_t* menu,int cmd) { + mp_cmd_t* c = NULL; + switch(cmd) { + case MENU_CMD_OK: { + // Directory + if(mpriv->p.current->d) { + if(mpriv->dir_action) { + int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1; + char filename[fname_len]; + char* str; + sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt); + str = replace_path(mpriv->dir_action,filename); + c = mp_input_parse_cmd(str); + if(str != mpriv->dir_action) + free(str); + } else { // Default action : open this dirctory ourself + int l = strlen(mpriv->dir); + char *slash = NULL, *p = NULL; + if(strcmp(mpriv->p.current->p.txt,"../") == 0) { + if(l <= 1) break; + mpriv->dir[l-1] = '\0'; + slash = strrchr(mpriv->dir,'/'); + if(!slash) break; + slash[1] = '\0'; + p = strdup(mpriv->dir); + } else { + p = malloc(l + strlen(mpriv->p.current->p.txt) + 1); + sprintf(p,"%s%s",mpriv->dir,mpriv->p.current->p.txt); + } + menu_list_uninit(menu,free_entry); + if(!open_dir(menu,p)) { + printf("Can't open directory %s\n",p); + menu->cl = 1; + } + free(p); + } + } else { // Files + int fname_len = strlen(mpriv->dir) + strlen(mpriv->p.current->p.txt) + 1; + char filename[fname_len]; + char *str; + sprintf(filename,"%s%s",mpriv->dir,mpriv->p.current->p.txt); + str = replace_path(mpriv->file_action,filename); + c = mp_input_parse_cmd(str); + if(str != mpriv->file_action) + free(str); + } + if(c) { + mp_input_queue_cmd(c); + if(mpriv->auto_close) + menu->cl = 1; + } + } break; + default: + menu_list_read_cmd(menu,cmd); + } +} + +static void read_key(menu_t* menu,int c){ + if(c == KEY_BS) { + mpriv->p.current = mpriv->p.menu; // Hack : we consider that the first entry is ../ + read_cmd(menu,MENU_CMD_OK); + } else + menu_list_read_key(menu,c,1); +} + +static void clos(menu_t* menu) { + menu_list_uninit(menu,free_entry); + free(mpriv->dir); +} + +static int open_fs(menu_t* menu, char* args) { + char *path = mpriv->path; + int r = 0; + char wd[PATH_MAX+1]; + args = NULL; // Warning kill + + menu->draw = menu_list_draw; + menu->read_cmd = read_cmd; + menu->read_key = read_key; + menu->close = clos; + + getcwd(wd,PATH_MAX); + if(!path || path[0] == '\0') { + int l = strlen(wd) + 2; + char b[l]; + sprintf(b,"%s/",wd); + r = open_dir(menu,b); + } else if(path[0] != '/') { + int al = strlen(path); + int l = strlen(wd) + al + 3; + char b[l]; + if(b[al-1] != '/') + sprintf(b,"%s/%s/",wd,path); + else + sprintf(b,"%s/%s",wd,path); + r = open_dir(menu,b); + } else + r = open_dir(menu,path); + + return r; +} + +const menu_info_t menu_info_filesel = { + "File seletor menu", + "filesel", + "Albeu", + "", + { + "fs_cfg", + sizeof(struct menu_priv_s), + &cfg_dflt, + cfg_fields + }, + open_fs +}; diff --git a/libmenu/menu_list.c b/libmenu/menu_list.c new file mode 100644 index 0000000000..ffcd4921fd --- /dev/null +++ b/libmenu/menu_list.c @@ -0,0 +1,225 @@ + +#include +#include +#include + +#include "../config.h" + +#include "img_format.h" +#include "mp_image.h" + +#include "m_struct.h" +#include "menu.h" + +#include "../libvo/font_load.h" +#include "../linux/keycodes.h" + +#define IMPL 1 +#include "menu_list.h" + +#define mpriv (menu->priv) + +void menu_list_draw(menu_t* menu,mp_image_t* mpi) { + int x = mpriv->x; + int y = mpriv->y; + int i; + int h = mpriv->h; + int w = mpriv->w; + int dh = 0,dw = 0; + int dy = 0; + int need_h = 0,need_w = 0,ptr_l = menu_text_length(mpriv->ptr) + 10,sidx = 0; + int th; + list_entry_t* m; + + if(mpriv->count < 1) + return; + + if(h <= 0) h = mpi->height; + if(w <= 0) w = mpi->width; + dh = h - 2*mpriv->minb; + dw = w - 2*mpriv->minb; + ptr_l = menu_text_length(mpriv->ptr); + // mpi is too small + if(h - vo_font->height <= 0 || w - ptr_l <= 0 || dw <= 0 || dh <= 0) + return; + + th = menu_text_num_lines(mpriv->title,dw) * (mpriv->vspace + vo_font->height) + mpriv->vspace; + + for(i = 0, m = mpriv->menu ; m ; m = m->next, i++) { + int ll = menu_text_length(m->txt); + if(ptr_l + ll > need_w) need_w = ptr_l + ll; + if(m == mpriv->current) sidx = i; + } + if(need_w > dw) need_w = dw; + if(x > 0) + x += mpriv->minb; + if(y > 0) + y += mpriv->minb; + else + y = mpriv->minb; + + need_h = mpriv->count * (mpriv->vspace + vo_font->height) - mpriv->vspace; + if( need_h + th > dh) { + int start,end; + int maxl = (dh + mpriv->vspace - th) / (mpriv->vspace + vo_font->height); + if(maxl < 4) { + th = 0; + maxl = (dh + mpriv->vspace) / ( vo_font->height + mpriv->vspace); + } + // Too smoll + if(maxl < 1) return; + need_h = maxl*(mpriv->vspace + vo_font->height) - mpriv->vspace; + + start = sidx - (maxl/2); + if(start < 0) start = 0; + end = start + maxl; + if(end > mpriv->count) { + end = mpriv->count; + if(end - start < maxl) + start = end - maxl < 0 ? 0 : end - maxl; + } + m = mpriv->menu; + for(i = 0 ; m->next && i < start ; i++) + m = m->next; + } else + m = mpriv->menu; + + if(th > 0) { + menu_draw_text_full(mpi,mpriv->title, + x < 0 ? mpi->w / 2 : x, + dy+y,dw,0, + mpriv->vspace,1, + MENU_TEXT_TOP|MENU_TEXT_HCENTER, + MENU_TEXT_TOP|(x < 0 ? MENU_TEXT_HCENTER :MENU_TEXT_LEFT)); + dy += th; + } + + for( ; m != NULL && dy + vo_font->height < dh ; m = m->next ) { + if(m == mpriv->current) + menu_draw_text_full(mpi,mpriv->ptr, + x < 0 ? (mpi->w - need_w) / 2 + ptr_l : x, + dy+y,dw,dh - dy, + mpriv->vspace,0, + MENU_TEXT_TOP|(x < 0 ? MENU_TEXT_RIGHT :MENU_TEXT_LEFT) , + MENU_TEXT_TOP|(x < 0 ? MENU_TEXT_RIGHT :MENU_TEXT_LEFT)); + menu_draw_text_full(mpi,m->txt, + x < 0 ? (mpi->w - need_w) / 2 + ptr_l : x + ptr_l, + dy+y,dw-ptr_l,dh - dy, + mpriv->vspace,0, + MENU_TEXT_TOP|MENU_TEXT_LEFT, + MENU_TEXT_TOP|MENU_TEXT_LEFT); + dy += vo_font->height + mpriv->vspace; + } + +} + +void menu_list_read_cmd(menu_t* menu,int cmd) { + switch(cmd) { + case MENU_CMD_UP: + if(mpriv->current->prev) { + mpriv->current = mpriv->current->prev; + } else { + for( ; mpriv->current->next != NULL ; mpriv->current = mpriv->current->next) + /* NOTHING */; + } break; + case MENU_CMD_DOWN: + if(mpriv->current->next) { + mpriv->current = mpriv->current->next; + } else { + mpriv->current = mpriv->menu; + } break; + case MENU_CMD_CANCEL: + menu->show = 0; + menu->cl = 1; + break; + } +} + +void menu_list_jump_to_key(menu_t* menu,int c) { + if(isalnum(c)) { + list_entry_t* e = mpriv->current; + if(e->txt[0] == c) e = e->next; + for( ; e ; e = e->next) { + if(e->txt[0] == c) { + mpriv->current = e; + return; + } + } + for(e = mpriv->menu ; e ; e = e->next) { + if(e->txt[0] == c) { + mpriv->current = e; + return; + } + } + } else + menu_dflt_read_key(menu,c); +} + +void menu_list_read_key(menu_t* menu,int c,int jump_to) { + list_entry_t* m; + int i; + switch(c) { + case KEY_HOME: + mpriv->current = mpriv->menu; + break; + case KEY_END: + for(m = mpriv->current ; m && m->next ; m = m->next) + /**/; + if(m) + mpriv->current = m; + break; + case KEY_PAGE_UP: + for(i = 0, m = mpriv->current ; m && m->prev && i < 10 ; m = m->prev, i++) + /**/; + if(m) + mpriv->current = m; + break; + case KEY_PAGE_DOWN: + for(i = 0, m = mpriv->current ; m && m->next && i < 10 ; m = m->next, i++) + /**/; + if(m) + mpriv->current = m; + break; + default: + if(jump_to) + menu_list_jump_to_key(menu,c); + else + menu_dflt_read_key(menu,c); + } +} + +void menu_list_add_entry(menu_t* menu,list_entry_t* entry) { + list_entry_t* l; + mpriv->count++; + + if(mpriv->menu == NULL) { + mpriv->menu = mpriv->current = entry; + return; + } + + for(l = mpriv->menu ; l->next != NULL ; l = l->next) + /* NOP */; + l->next = entry; + entry->prev = l; +} + +void menu_list_init(menu_t* menu) { + if(!mpriv) + mpriv = calloc(1,sizeof(struct menu_priv_s)); + +} + +void menu_list_uninit(menu_t* menu,free_entry_t free_func) { + list_entry_t *i,*j; + + if(!free_func) free_func = (free_entry_t)free; + + for(i = mpriv->menu ; i != NULL ; ) { + j = i->next; + free_func(i); + i = j; + } + + mpriv->menu = mpriv->current = NULL; + +} diff --git a/libmenu/menu_list.h b/libmenu/menu_list.h new file mode 100644 index 0000000000..74219753fa --- /dev/null +++ b/libmenu/menu_list.h @@ -0,0 +1,66 @@ + +typedef struct list_entry_s list_entry_t; + + +#ifdef IMPL +struct list_entry_s { +#else +struct list_entry { +#endif + list_entry_t* prev; + list_entry_t* next; + + char* txt; +}; + + +#ifndef IMPL +typedef struct menu_list_priv_s { +#else +typedef struct menu_priv_s { +#endif + list_entry_t* menu; + list_entry_t* current; + int count; + + char* title; + int x,y; + int w,h; + int vspace, minb; + char* ptr; +} menu_list_priv_t; + +typedef void (*free_entry_t)(list_entry_t* entry); + +void menu_list_read_cmd(menu_t* menu,int cmd); +void menu_list_read_key(menu_t* menu,int c,int jump_to); +void menu_list_draw(menu_t* menu,mp_image_t* mpi); +void menu_list_add_entry(menu_t* menu,list_entry_t* entry); +void menu_list_init(menu_t* menu); +void menu_list_uninit(menu_t* menu,free_entry_t free_func); +void menu_list_jump_to_key(menu_t* menu,int c); + +extern const menu_list_priv_t menu_list_priv_dflt; + +#define MENU_LIST_PRIV_DFLT { \ + NULL, \ + NULL, \ + 0, \ +\ + "MPlayer", \ + -1,-1, \ + 0,0, \ + 5, 3, \ + ">" \ +} + + +#define MENU_LIST_PRIV_FIELDS \ + { "minbor", M_ST_OFF(menu_list_priv_t,minb), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, \ + { "vspace", M_ST_OFF(menu_list_priv_t,vspace), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, \ + { "x", M_ST_OFF(menu_list_priv_t,x), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, \ + { "y", M_ST_OFF(menu_list_priv_t,y), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, \ + { "w", M_ST_OFF(menu_list_priv_t,w), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, \ + { "h", M_ST_OFF(menu_list_priv_t,h), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, \ + { "ptr", M_ST_OFF(menu_list_priv_t,ptr), CONF_TYPE_STRING, 0, 0, 0, NULL } + diff --git a/libmenu/menu_param.c b/libmenu/menu_param.c new file mode 100644 index 0000000000..36c2150c5c --- /dev/null +++ b/libmenu/menu_param.c @@ -0,0 +1,159 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../config.h" + +#include "../m_struct.h" +#include "../m_option.h" +#include "../m_config.h" +#include "../asxparser.h" + +#include "img_format.h" +#include "mp_image.h" + +#include "menu.h" +#include "menu_list.h" +#include "../input/input.h" +#include "../linux/keycodes.h" + +struct list_entry_s { + struct list_entry p; + m_option_t* opt; +}; + +struct menu_priv_s { + menu_list_priv_t p; + char* edit; + int edit_len; + /// Cfg fields +}; + +static struct menu_priv_s cfg_dflt = { + MENU_LIST_PRIV_DFLT, + NULL, + 0 +}; + +static m_option_t cfg_fields[] = { + MENU_LIST_PRIV_FIELDS, + { "title", M_ST_OFF(menu_list_priv_t,title), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { NULL, NULL, NULL, 0,0,0,NULL } +}; + +#define mpriv (menu->priv) + +extern m_config_t* mconfig; + +static int parse_args(menu_t* menu,char* args) { + char *element,*body, **attribs, *name, *ok, *cancel; + list_entry_t* m = NULL; + int r; + m_option_t* opt; + ASX_Parser_t* parser = asx_parser_new(); + + + while(1) { + r = asx_get_element(parser,&args,&element,&body,&attribs); + if(r < 0) { + printf("Syntax error at line %d\n",parser->line); + asx_parser_free(parser); + return -1; + } else if(r == 0) { + asx_parser_free(parser); + if(!m) + printf("No entry found in the menu definition\n"); + return m ? 1 : 0; + } + // Has it a name ? + name = asx_get_attrib("name",attribs); + opt = name ? m_config_get_option(mconfig,name) : NULL; + if(!opt) { + printf("Pref menu entry definitions need a valid name attribut (line %d)\n",parser->line); + free(element); + if(name) free(name); + if(body) free(body); + asx_free_attribs(attribs); + continue; + } + m = calloc(1,sizeof(struct list_entry_s)); + m->p.txt = name; + m->opt = opt; + menu_list_add_entry(menu,m); + + free(element); + if(body) free(body); + asx_free_attribs(attribs); + } +} + +static void read_key(menu_t* menu,int c) { + menu_list_read_key(menu,c,0); +} + +static void free_entry(list_entry_t* entry) { + free(entry->p.txt); + free(entry); +} + +static void close(menu_t* menu) { + menu_list_uninit(menu,free_entry); + if(mpriv->edit) + free(mpriv->edit); +} + +static int open(menu_t* menu, char* args) { + list_entry_t* e; + + menu->draw = menu_list_draw; + menu->read_cmd = menu_list_read_cmd; + menu->read_key = read_key; + menu->close = close; + + + if(!args) { + printf("Pref menu need an argument\n"); + return 0; + } + + menu_list_init(menu); + if(!parse_args(menu,args)) + return 0; + + for(e = mpriv->p.menu ; e ; e = e->p.next) { + int l; + char* val = m_option_print(e->opt,e->opt->p); + if((int)val == -1) { + printf("Can't get value of option %s\n",e->opt->name); + continue; + } else if(!val) + val = strdup("NULL"); + l = strlen(e->opt->name) + 2 + strlen(val) + 1; + e->p.txt = malloc(l); + sprintf(e->p.txt,"%s: %s",e->opt->name,val); + free(val); + } + + return 1; +} + +const menu_info_t menu_info_pref = { + "Preferences menu", + "pref", + "Albeu", + "", + { + "pref_cfg", + sizeof(struct menu_priv_s), + &cfg_dflt, + cfg_fields + }, + open +}; diff --git a/libmenu/menu_pt.c b/libmenu/menu_pt.c new file mode 100644 index 0000000000..bd63afae2e --- /dev/null +++ b/libmenu/menu_pt.c @@ -0,0 +1,151 @@ + +#include +#include +#include + +#include "../config.h" + +#include "img_format.h" +#include "mp_image.h" + +#include "../m_struct.h" +#include "../m_option.h" +#include "menu.h" +#include "menu_list.h" + + +#include "../playtree.h" +#include "../input/input.h" + + + +extern play_tree_iter_t* playtree_iter; + +struct list_entry_s { + struct list_entry p; + play_tree_t* pt; +}; + + +struct menu_priv_s { + menu_list_priv_t p; + char* title; +}; + +static struct menu_priv_s cfg_dflt = { + MENU_LIST_PRIV_DFLT, + "Jump to" +}; + +#define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m) + +static m_option_t cfg_fields[] = { + MENU_LIST_PRIV_FIELDS, + { "title", ST_OFF(title), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { NULL, NULL, NULL, 0,0,0,NULL } +}; + +#define mpriv (menu->priv) + +static void read_cmd(menu_t* menu,int cmd) { + switch(cmd) { + case MENU_CMD_OK: { + int d = 1; + char str[15]; + play_tree_t* i; + mp_cmd_t* c; + + + if(playtree_iter->tree == mpriv->p.current->pt) + break; + + if(playtree_iter->tree->parent && mpriv->p.current->pt == playtree_iter->tree->parent) + snprintf(str,15,"pt_up_step 1"); + else { + for(i = playtree_iter->tree->next; i != NULL ; i = i->next) { + if(i == mpriv->p.current->pt) + break; + d++; + } + if(i == NULL) { + d = -1; + for(i = playtree_iter->tree->prev; i != NULL ; i = i->prev) { + if(i == mpriv->p.current->pt) + break; + d--; + } + if(i == NULL) { + printf("Can't find the target item ????\n"); + break; + } + } + snprintf(str,15,"pt_step %d",d); + } + c = mp_input_parse_cmd(str); + if(c) + mp_input_queue_cmd(c); + else + printf("Failed to build command %s\n",str); + } break; + default: + menu_list_read_cmd(menu,cmd); + } +} + +static void read_key(menu_t* menu,int c){ + menu_list_read_key(menu,c,1); +} + +static void close(menu_t* menu) { + menu_list_uninit(menu,NULL); +} + +static int op(menu_t* menu, char* args) { + play_tree_t* i; + list_entry_t* e; + args = NULL; // Warning kill + + menu->draw = menu_list_draw; + menu->read_cmd = read_cmd; + menu->read_key = read_key; + menu->close = close; + + menu_list_init(menu); + + mpriv->p.title = mpriv->title; + + if(playtree_iter->tree->parent != playtree_iter->root) { + e = calloc(1,sizeof(list_entry_t)); + e->p.txt = ".."; + e->pt = playtree_iter->tree->parent; + menu_list_add_entry(menu,e); + } + + for(i = playtree_iter->tree ; i->prev != NULL ; i = i->prev) + /* NOP */; + for( ; i != NULL ; i = i->next ) { + e = calloc(1,sizeof(list_entry_t)); + if(i->files) + e->p.txt = basename(i->files[0]); + else + e->p.txt = "Group ..."; + e->pt = i; + menu_list_add_entry(menu,e); + } + + return 1; +} + +const menu_info_t menu_info_pt = { + "Playtree menu", + "pt", + "Albeu", + "", + { + "pt_cfg", + sizeof(struct menu_priv_s), + &cfg_dflt, + cfg_fields + }, + op +}; diff --git a/libmenu/menu_txt.c b/libmenu/menu_txt.c new file mode 100644 index 0000000000..305167c940 --- /dev/null +++ b/libmenu/menu_txt.c @@ -0,0 +1,194 @@ + +#include "../config.h" + +#include +#include +#include + +#include "img_format.h" +#include "mp_image.h" + +#include "../m_struct.h" +#include "../m_option.h" +#include "menu.h" + +#include "../libvo/font_load.h" +#include "../linux/keycodes.h" + +struct menu_priv_s { + char** lines; + int num_lines; + int cur_line; + int disp_lines; + int minb; + int hspace; + char* file; +}; + +static struct menu_priv_s cfg_dflt = { + NULL, + 0, + 0, + 0, + 0, + 3, + NULL +}; + +#define ST_OFF(m) M_ST_OFF(struct menu_priv_s,m) + +static m_option_t cfg_fields[] = { + { "minbor", ST_OFF(minb), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, + { "hspace", ST_OFF(hspace), CONF_TYPE_INT, M_OPT_MIN, 0, 0, NULL }, + { "file", ST_OFF(file), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { NULL, NULL, NULL, 0,0,0,NULL } +}; + +#define mpriv (menu->priv) + +static void read_cmd(menu_t* menu,int cmd) { + switch(cmd) { + case MENU_CMD_UP: + mpriv->cur_line -= mpriv->disp_lines / 2; + if(mpriv->cur_line < 0) + mpriv->cur_line = 0; + break; + case MENU_CMD_DOWN: + case MENU_CMD_OK: + mpriv->cur_line += mpriv->disp_lines / 2; + if(mpriv->cur_line >= mpriv->num_lines) + mpriv->cur_line = mpriv->num_lines - 1; + break; + case MENU_CMD_CANCEL: + menu->show = 0; + menu->cl = 1; + break; + } +} + +static void read_key(menu_t* menu,int c) { + switch (c) { + case KEY_HOME: + mpriv->cur_line = 0; + break; + case KEY_END: + mpriv->cur_line = mpriv->num_lines - 1; + break; + case KEY_PAGE_UP: + mpriv->cur_line = mpriv->cur_line > mpriv->disp_lines ? + mpriv->cur_line - mpriv->disp_lines : 0; + break; + case KEY_PAGE_DOWN: + mpriv->cur_line = mpriv->cur_line + mpriv->disp_lines > mpriv->num_lines - 1 ? mpriv->num_lines - 1 : mpriv->cur_line + mpriv->disp_lines; + break; + default: + menu_dflt_read_key(menu,c); + } +} + + +static void draw(menu_t* menu,mp_image_t* mpi) { + int x = mpriv->minb; + int y = mpriv->minb; + //int th = 2*mpriv->hspace + vo_font->height; + int i,end; + + if(x < 0) x = 8; + if(y < 0) y = 8; + + mpriv->disp_lines = (mpi->h + mpriv->hspace - 2*mpriv->minb) / ( vo_font->height + mpriv->hspace); + if(mpriv->num_lines - mpriv->cur_line < mpriv->disp_lines) { + i = mpriv->num_lines - 1 - mpriv->disp_lines; + if(i < 0) i = 0; + end = mpriv->num_lines - 1; + } else { + i = mpriv->cur_line; + end = i + mpriv->disp_lines; + if(end >= mpriv->num_lines) end = mpriv->num_lines - 1; + } + + for( ; i < end ; i++) { + menu_draw_text(mpi,mpriv->lines[i],x,y); + y += vo_font->height + mpriv->hspace; + } + +} + +#define BUF_SIZE 1024 + +static int open(menu_t* menu, char* args) { + FILE* fd; + char buf[BUF_SIZE]; + char *l; + int s; + int pos = 0, r = 0; + args = NULL; // Warning kill + + menu->draw = draw; + menu->read_cmd = read_cmd; + menu->read_key = read_key; + + if(!mpriv->file) { + printf("Menu txt need a txt file name (param file)\n"); + return 0; + } + + fd = fopen(mpriv->file,"r"); + if(!fd) { + printf("Menu txt can't open: %s\n",mpriv->file); + return 0; + } + + while(1) { + r = fread(buf+pos,1,BUF_SIZE-pos-1,fd); + if(r <= 0) { + if(pos > 0) { + mpriv->lines = realloc(mpriv->lines,(mpriv->num_lines + 1)*sizeof(char*)); + mpriv->lines[mpriv->num_lines] = strdup(buf); + mpriv->num_lines++; + } + fclose(fd); + break; + } + pos += r; + buf[pos] = '\0'; + + while((l = strchr(buf,'\n')) != NULL) { + s = l-buf; + mpriv->lines = realloc(mpriv->lines,(mpriv->num_lines + 1)*sizeof(char*)); + mpriv->lines[mpriv->num_lines] = malloc(s+1); + memcpy(mpriv->lines[mpriv->num_lines],buf,s); + mpriv->lines[mpriv->num_lines][s] = '\0'; + pos -= s + 1; + if(pos > 0) + memmove(buf,l+1,pos); + buf[pos] = '\0'; + mpriv->num_lines++; + } + if(pos >= BUF_SIZE-1) { + printf("Warning too long line, splitting it\n"); + mpriv->lines = realloc(mpriv->lines,(mpriv->num_lines + 1)*sizeof(char*)); + mpriv->lines[mpriv->num_lines] = strdup(buf); + mpriv->num_lines++; + pos = 0; + } + } + + printf("Parsed %d lines\n",mpriv->num_lines); + + return 1; +} + +const menu_info_t menu_info_txt = { + "Text file viewer", + "txt", + "Albeu", + "", + { + "txt_cfg", + sizeof(struct menu_priv_s), + &cfg_dflt, + cfg_fields + }, + open, +}; diff --git a/libmenu/vf_menu.c b/libmenu/vf_menu.c new file mode 100644 index 0000000000..5d84b55191 --- /dev/null +++ b/libmenu/vf_menu.c @@ -0,0 +1,251 @@ + +#include "../config.h" + +#include +#include +#include + + +#include "../mp_msg.h" + +#include "../libmpcodecs/img_format.h" +#include "../libmpcodecs/mp_image.h" +#include "../libmpcodecs/vf.h" + +#include "../libvo/fastmemcpy.h" +#include "../libvo/video_out.h" +#include "../input/input.h" +#include "../m_struct.h" +#include "menu.h" + +extern vo_functions_t* video_out; + + +static struct vf_priv_s* st_priv = NULL; + +static mp_image_t* pause_mpi = NULL; +static int go2pause = 0; + +struct vf_priv_s { + menu_t* root; + menu_t* current; +}; + +static int put_image(struct vf_instance_s* vf, mp_image_t *mpi); + +static mp_image_t* alloc_mpi(int w, int h, uint32_t fmt) { + mp_image_t* mpi = new_mp_image(w,h); + + mp_image_setfmt(mpi,fmt); + // IF09 - allocate space for 4. plane delta info - unused + if (mpi->imgfmt == IMGFMT_IF09) + { + mpi->planes[0]=memalign(64, mpi->bpp*mpi->width*(mpi->height+2)/8+ + mpi->chroma_width*mpi->chroma_height); + /* delta table, just for fun ;) */ + mpi->planes[3]=mpi->planes[0]+2*(mpi->chroma_width*mpi->chroma_height); + } + else + mpi->planes[0]=memalign(64, mpi->bpp*mpi->width*(mpi->height+2)/8); + if(mpi->flags&MP_IMGFLAG_PLANAR){ + // YV12/I420/YVU9/IF09. feel free to add other planar formats here... + if(!mpi->stride[0]) mpi->stride[0]=mpi->width; + if(!mpi->stride[1]) mpi->stride[1]=mpi->stride[2]=mpi->chroma_width; + if(mpi->flags&MP_IMGFLAG_SWAPPED){ + // I420/IYUV (Y,U,V) + mpi->planes[1]=mpi->planes[0]+mpi->width*mpi->height; + mpi->planes[2]=mpi->planes[1]+mpi->chroma_width*mpi->chroma_height; + } else { + // YV12,YVU9,IF09 (Y,V,U) + mpi->planes[2]=mpi->planes[0]+mpi->width*mpi->height; + mpi->planes[1]=mpi->planes[2]+mpi->chroma_width*mpi->chroma_height; + } + } else { + if(!mpi->stride[0]) mpi->stride[0]=mpi->width*mpi->bpp/8; + } + mpi->flags|=MP_IMGFLAG_ALLOCATED; + + return mpi; +} + +void vf_menu_pause_update(struct vf_instance_s* vf) { + if(pause_mpi) { + put_image(vf,pause_mpi); + // Don't draw the osd atm + //vf->control(vf,VFCTRL_DRAW_OSD,NULL); + video_out->flip_page(); + } +} + +static int cmd_filter(mp_cmd_t* cmd, int paused, struct vf_priv_s * priv) { + + switch(cmd->id) { + case MP_CMD_PAUSE : + if(!paused && !go2pause) { // Initial pause cmd -> wait the next put_image + go2pause = 1; + return 1; + } + if(go2pause == 2) // Msg resent by put_image after saving the image + go2pause = 0; + break; + case MP_CMD_MENU : { // Convert txt cmd from the users into libmenu stuff + char* arg = cmd->args[0].v.s; + + if(!priv->current->show) + priv->current->show = 1; + else if(strcmp(arg,"up") == 0) + menu_read_cmd(priv->current,MENU_CMD_UP); + else if(strcmp(arg,"down") == 0) + menu_read_cmd(priv->current,MENU_CMD_DOWN); + else if(strcmp(arg,"ok") == 0) + menu_read_cmd(priv->current,MENU_CMD_OK); + else if(strcmp(arg,"cancel") == 0) + menu_read_cmd(priv->current,MENU_CMD_CANCEL); + else if(strcmp(arg,"hide") == 0) + priv->current->show = 0; + else + printf("Unknow menu command: '%s'\n",arg); + return 1; + } + case MP_CMD_SET_MENU : { + char* menu = cmd->args[0].v.s; + menu_t* l = priv->current; + priv->current = menu_open(menu); + if(!priv->current) { + printf("Failed to open menu '%s'\n",menu); + priv->current = l; + priv->current->show = 0; + } else { + priv->current->show = 1; + priv->current->parent = l; + } + return 1; + } + } + return 0; +} + +static void get_image(struct vf_instance_s* vf, mp_image_t *mpi){ + mp_image_t *dmpi; + + if(mpi->type == MP_IMGTYPE_TEMP && (!(mpi->flags&MP_IMGFLAG_PRESERVE)) ) { + dmpi = vf_get_image(vf->next,mpi->imgfmt,mpi->type, mpi->flags, mpi->w, mpi->h); + memcpy(mpi->planes,dmpi->planes,MP_MAX_PLANES*sizeof(unsigned char*)); + memcpy(mpi->stride,dmpi->stride,MP_MAX_PLANES*sizeof(unsigned int)); + mpi->flags|=MP_IMGFLAG_DIRECT; + mpi->priv=(void*)dmpi; + return; + } +} + +static void key_cb(int code) { + menu_read_key(st_priv->current,code); +} + + + +inline static void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi) { + if(mpi->flags&MP_IMGFLAG_PLANAR){ + memcpy_pic(dmpi->planes[0],mpi->planes[0], mpi->w, mpi->h, + dmpi->stride[0],mpi->stride[0]); + memcpy_pic(dmpi->planes[1],mpi->planes[1], mpi->chroma_width, mpi->chroma_height, + dmpi->stride[1],mpi->stride[1]); + memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->chroma_width, mpi->chroma_height, + dmpi->stride[2],mpi->stride[2]); + } else { + memcpy_pic(dmpi->planes[0],mpi->planes[0], + mpi->w*(dmpi->bpp/8), mpi->h, + dmpi->stride[0],mpi->stride[0]); + } +} + + + +static int put_image(struct vf_instance_s* vf, mp_image_t *mpi){ + mp_image_t *dmpi = NULL; + + // Close all menu who requested it + while(vf->priv->current->cl && vf->priv->current != vf->priv->root) { + menu_t* m = vf->priv->current; + vf->priv->current = m->parent ? m->parent : vf->priv->root; + menu_close(m); + } + + // Step 1 : save the picture + while(go2pause == 1) { + static char delay = 0; // Hack : wait the 2 frame to be sure to show the right picture + delay ^= 1; // after a seek + if(!delay) break; + + if(pause_mpi && (mpi->w != pause_mpi->w || mpi->h != pause_mpi->h || + mpi->imgfmt != pause_mpi->imgfmt)) { + free_mp_image(pause_mpi); + pause_mpi = NULL; + } + if(!pause_mpi) + pause_mpi = alloc_mpi(mpi->w,mpi->h,mpi->imgfmt); + copy_mpi(pause_mpi,mpi); + mp_input_queue_cmd(mp_input_parse_cmd("pause")); + go2pause = 2; + break; + } + + // Grab // Ungrab the keys + if(!mp_input_key_cb && vf->priv->current->show) + mp_input_key_cb = key_cb; + if(mp_input_key_cb && !vf->priv->current->show) + mp_input_key_cb = NULL; + + if(mpi->flags&MP_IMGFLAG_DIRECT) + dmpi = mpi->priv; + else { + dmpi = vf_get_image(vf->next,mpi->imgfmt, + MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, + mpi->w,mpi->h); + copy_mpi(dmpi,mpi); + } + menu_draw(vf->priv->current,dmpi); + + return vf_next_put_image(vf,dmpi); +} + +static void uninit(vf_instance_t *vf) { + vf->priv=NULL; + if(pause_mpi) { + free_mp_image(pause_mpi); + pause_mpi = NULL; + } +} + +static int open(vf_instance_t *vf, char* args){ + if(!st_priv) { + st_priv = calloc(1,sizeof(struct vf_priv_s)); + st_priv->root = st_priv->current = menu_open(args); + if(!st_priv->current) { + free(st_priv); + st_priv = NULL; + return 0; + } + mp_input_add_cmd_filter((mp_input_cmd_filter)cmd_filter,st_priv); + } + + vf->put_image = put_image; + vf->get_image = get_image; + vf->uninit=uninit; + vf->priv=st_priv; + go2pause=0; + + return 1; +} + + +vf_info_t vf_info_menu = { + "Internal filter for libmenu", + "menu", + "Albeu", + "", + open +}; + + + -- cgit v1.2.3