/*
	2004.02.01
		first released source code for IOMP
*/

#include "../config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.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 1
	if(strcasecmp(attribs[2*i],"ptr") == 0) {
			char *ptr = attribs[2*i+1];
			if ((strlen(ptr) == 1) && (*ptr == '>')) {
					char temp[2];
					temp[0] = 1; temp[1] = 0;
					attribs[2*i+1] = strdup(temp);
					free(ptr);
			}
	}
#endif	
	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, fd;
#ifndef HAVE_FREETYPE
  if(vo_font == NULL)
    return 0;
#endif
  fd = open(cfg_file, O_RDONLY);
  if(fd < 0) {
    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);
	close(fd);
	free(buffer);
	return 0;
      }
      bl += BUF_STEP;
      buffer = realloc(buffer,bl);
    }
    r = read(fd,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';

  close(fd);

  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;
}

char *menu_find_name_by_title(char *ttt)
{
  int i,j;
  m_struct_t *st;

  for(j = 0 ; menu_list[j].name != NULL ; j++) {
  	st = &(menu_list[j].type->priv_st);
   	for(i = 0 ; st->fields[i].name ; i++) {
		if (strcmp(st->fields[i].name,"title") == 0) {
			char *newstr;
			m_option_copy(&st->fields[i],&newstr,
				M_ST_MB_P(menu_list[j].cfg,st->fields[i].p));
			if (strcmp(newstr,ttt) == 0)
				return menu_list[j].name;
		}
  	}
  }
  return NULL;
}

void menu_change_title(char *name,char *newtitle) {
  int i,j;
  m_struct_t *st;

  for(j = 0 ; menu_list[j].name != NULL ; j++) {
    if(strcmp(name,menu_list[j].name) == 0)
      break;
  }
  if(menu_list[j].name == NULL) {
    printf("Menu %s not found\n",name);
    return ;
  }
  st = &(menu_list[j].type->priv_st);
   for(i = 0 ; st->fields[i].name ; i++) {
	if (strcmp(st->fields[i].name,"title") == 0) {
		char *newstr;
		char *tempstr;
		m_option_copy(&st->fields[i],&newstr,
			M_ST_MB_P(menu_list[j].cfg,st->fields[i].p));
		tempstr = newstr;
		newstr = strdup(newtitle);
		m_option_set(&st->fields[i],
			M_ST_MB_P(menu_list[j].cfg,st->fields[i].p)
			,&newstr);
		free(tempstr);
		break;
	}
  }
}


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;
}

// return the real height of a char:
static inline int get_height(int c,int h){
    int font;
    if ((font=vo_font->font[c])>=0)
	if(h<vo_font->pic_a[font]->h) h=vo_font->pic_a[font]->h;
    return h;
}

#ifdef HAVE_FREETYPE
//#define render_txt(t)  { char* p = t;  while(*p) render_one_glyph(vo_font,*p++); }
#define render_txt(t)  { char* p = t;  while(*p) render_one_glyph(vo_font,(unsigned short) *p++); }
#else
#define render_txt(t)
#endif
    
#ifdef HAVE_FREETYPE
#include <iconv.h>
char *MyConvertText(char *txt)
{
	char *ip,*op,*ot;
    int ileft;
    int oleft;
    char icbuffer[512];
    ip = txt;
    op = icbuffer;
    ileft = strlen(ip);
    oleft = 511;

	if (avamax_var->my_icdsc == NULL)
		return strdup(txt);

	memset(icbuffer,0,512);

    if (iconv(avamax_var->my_icdsc, &ip, 
		&ileft, &op, &oleft) == (size_t)(-1)) {
		return strdup(txt);
    }
    if (!(ot = (char *)malloc(op - icbuffer + 1))){
		return strdup(txt);
    }
    *op='\0' ;
    strcpy (ot, icbuffer);
   	return ot; 
}
#endif

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;
int mybuf[256];
int k1=0,k2=0;
int flag = 0;
unsigned char *cp;
unsigned char *tcp;

memset(mybuf,0,1024);

  if(!draw_alpha) {
    printf("Unsupported outformat !!!!\n");
    return;
  }
  
#ifdef HAVE_FREETYPE
	cp = MyConvertText(txt);
	tcp = cp;
#else
	cp = txt;
#endif

 	while (*cp){
        int c=*cp++;
#ifdef HAVE_FREETYPE
		if ((c & 0xe0) == 0xc0) {   /* 2 bytes U+00080..U+0007FF*/
        	c = (c & 0x1f)<<6 | (*cp++ & 0x3f);
			flag = 1;
		} else if((c & 0xf0) == 0xe0){ /* 3 bytes U+00800..U+00FFFF*/
        	c = (((c & 0x0f)<<6) | (*cp++ & 0x3f))<<6;
            c |= (*cp++ & 0x3f);
			flag = 1;
        }
#else
        if (c>=0x80) {
            c = (c<<8) + *cp++;
            flag = 1;
        }
#endif
        mybuf[k1++] = c;

#ifdef HAVE_FREETYPE
	render_one_glyph(vo_font,c);
#endif
    }

    if (!flag) {
	    render_txt(txt);
    }
	avamax_var->my_osdcolor = 1;
 
 if (flag) {
 	k2 = 0;
 	while (mybuf[k2]) {
 		int c = mybuf[k2];
 		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;
    	k2++;
    }   
} else {

  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;
  }
	avamax_var->my_osdcolor = 0;
}
}

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);

unsigned int mybuf[256];
int k1=0,k2=0;
int flag = 0;
unsigned char *cp;
unsigned char *tcp;

memset(mybuf,0,1024);

  if(!draw_alpha) {
    printf("Unsupported outformat !!!!\n");
    return;
  }
#ifdef HAVE_FREETYPE
	cp = MyConvertText(txt);
	tcp = cp;
#else
	cp = txt;
#endif

 	while (*cp){
        int c=*cp++;
#ifdef HAVE_FREETYPE
		if ((c & 0xe0) == 0xc0) {   /* 2 bytes U+00080..U+0007FF*/
        	c = (c & 0x1f)<<6 | (*cp++ & 0x3f);
			flag = 1;
		} else if((c & 0xf0) == 0xe0){ /* 3 bytes U+00800..U+00FFFF*/
        	c = (((c & 0x0f)<<6) | (*cp++ & 0x3f))<<6;
            c |= (*cp++ & 0x3f);
			flag = 1;
        }
#else
        if (c>=0x80) {
            c = (c<<8) + *cp++;
            flag = 1;
        }
#endif
        mybuf[k1++] = c;

#ifdef HAVE_FREETYPE
	render_one_glyph(vo_font,c);
#endif
    }

if (!flag) {
	render_txt(txt);
}

  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 - 1;
  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 - 1 - ll;
      }
    } else {
      for(sx = xrmin ;  sx < xmin && txt != line_end ; txt++) {
	unsigned char c = txt[n];
	sx += vo_font->width[c]+vo_font->charspace;
      }
    }

	avamax_var->my_osdcolor = 1;
   if (flag) {
        while(sx < xmax && txt != line_end) {
            int c = mybuf[k2++]; if (c == 0) break;
            font = vo_font->font[c];
            if(font >= 0) {
                int cs = (vo_font->pic_a[font]->h - vo_font->height) / 2;
                if ((sx + vo_font->width[c] < xmax)  &&
                    (sy + vo_font->height < ymax) )
                    draw_alpha(vo_font->width[c], vo_font->height,
                        vo_font->pic_b[font]->bmp+vo_font->start[c] +
                        cs * vo_font->pic_a[font]->w,
                        vo_font->pic_a[font]->bmp+vo_font->start[c] +
                        cs * vo_font->pic_a[font]->w,
                        vo_font->pic_a[font]->w,
                        mpi->planes[0] + sy * mpi->stride[0] +
                                sx * (mpi->bpp>>3),
                        mpi->stride[0]);
            }
            sx+=vo_font->width[c]+vo_font->charspace;
        }
        txt = line_end;
		if(txt[0] == '\0') break;
        sy += vo_font->height + vspace;
    } else {
        while(sx < xmax && txt != line_end) {
            unsigned char c = *txt++;
            font = vo_font->font[c];
            if(font >= 0) {
                int cs = (vo_font->pic_a[font]->h - vo_font->height) / 2;
                if ((sx + vo_font->width[c] < xmax)  &&
                    (sy + vo_font->height < ymax) )
                draw_alpha(vo_font->width[c], vo_font->height,
                    vo_font->pic_b[font]->bmp+vo_font->start[c] +
                    cs * vo_font->pic_a[font]->w,
                    vo_font->pic_a[font]->bmp+vo_font->start[c] +
                    cs * vo_font->pic_a[font]->w,
                    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;
    }
   }
#ifdef HAVE_FREETYPE
	free(tcp);
#endif
	avamax_var->my_osdcolor = 0;
}

#if 1
int menu_text_length(char* txt) {
  int l = 0;

int mybuf[256];
int k1=0,k2=0;
int flag = 0;
unsigned char *cp;
unsigned char *tcp;

memset(mybuf,0,1024);

#ifdef HAVE_FREETYPE
	cp = MyConvertText(txt);
	tcp = cp;
#else
	cp = txt;
#endif

 	while (*cp){
        int c=*cp++;
#ifdef HAVE_FREETYPE
		if ((c & 0xe0) == 0xc0) {   /* 2 bytes U+00080..U+0007FF*/
        	c = (c & 0x1f)<<6 | (*cp++ & 0x3f);
			flag = 1;
		} else if((c & 0xf0) == 0xe0){ /* 3 bytes U+00800..U+00FFFF*/
        	c = (((c & 0x0f)<<6) | (*cp++ & 0x3f))<<6;
            c |= (*cp++ & 0x3f);
			flag = 1;
        }
#else
        if (c>=0x80) {
            c = (c<<8) + *cp++;
            flag = 1;
        }
#endif
        mybuf[k1++] = c;

#ifdef HAVE_FREETYPE
	render_one_glyph(vo_font,c);
#endif
    }

	free(tcp);
	
	if (!flag) {
		render_txt(txt);
		while (*txt) {
	    	unsigned char c=*txt++;
	    	l += vo_font->width[c]+vo_font->charspace;
	  	}
	   	return l - vo_font->charspace;
	} else {
		while (mybuf[k2]) {
	    	l += vo_font->width[mybuf[k2]]+vo_font->charspace;
	    	k2++;
	  	}
	   	return l - vo_font->charspace;		
	} 	
 }
 	  
#else 	  
int menu_text_length(char* txt) {
  int l = 0;
  render_txt(txt);
  while (*txt) {
    unsigned char c=*txt++;
    l += vo_font->width[c]+vo_font->charspace;
  }
  return l - vo_font->charspace;
}
#endif

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;

  render_txt(txt);
  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;
  render_txt(txt);
  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;
  render_txt(txt);
  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;
}
