/* MikMod example player (c) 1999 Miodrag Vallat and others - see file AUTHORS for complete list. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*============================================================================== $Id: mmenu.c,v 1.2 2003/09/30 01:53:30 raph Exp $ Menu functions ==============================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "display.h" #include #include "player.h" #include "mmenu.h" #include "mwindow.h" #include "mdialog.h" static BOOL menu_is_sub(MENTRY *entry) { char *pos; return((entry->text[strlen(entry->text)-1]=='>')&& (!((pos=strchr(entry->text,'%'))&& (*(pos+1)!='%')))); } static BOOL menu_is_option(MENTRY *entry) { char *pos; return((pos=strchr(entry->text,'%'))&& (*(pos+1)=='o')); } static BOOL menu_is_toggle(MENTRY *entry) { char *pos; return((pos=strchr(entry->text,'%'))&& (*(pos+1)=='c')); } static BOOL menu_is_int(MENTRY *entry) { char *pos; return((pos=strchr(entry->text,'%'))&& (*(pos+1)=='d')); } static BOOL menu_is_str(MENTRY *entry) { char *pos; return((pos=strchr(entry->text,'%'))&& (*(pos+1)=='s')); } static BOOL menu_has_sub(MENTRY *entry) { return menu_is_str(entry)||menu_is_int(entry)|| menu_is_option(entry)||menu_is_sub(entry); } static char *get_text(MENTRY *entry,int width) { char help[50],sub[50],*start,*pos; int i; if (entry) { if ((pos=strchr(entry->text,'%'))) { if (*(pos+1)=='c') sprintf(storage,entry->text,(long)(entry->data)?'x':' '); else if ((*(pos+1)=='o')&&(start=strchr(entry->text,'|'))) { char *s_pos=NULL; int max=0; strncpy(help,entry->text,start-entry->text); help[start-entry->text]='\0'; help[1+pos-entry->text]='s'; start++; i=(long)(entry->data); pos=start; while (start) { if (!i) s_pos=pos; if ((start=strchr(pos,'|'))) { if (start-pos>max) max=start-pos; pos=start+1; } i--; } if (strlen(pos)>max) max=strlen(pos); i=0; while (s_pos&&(*s_pos)&&(*s_pos!='|')) sub[i++]=*s_pos++; while (itext,'|'))) { char *right=strrchr(start,'|') + 1; strncpy(help,entry->text,pos+1-entry->text); help[pos+1-entry->text]='\0'; if (*(pos+1)=='d') { sprintf(sub,"%d",(int)strlen(right)); strcat(help,sub); } else strcat(help,right); i=strlen(help); strncat(help,pos+1,start-pos-1); help[i+start-pos-1]='\0'; if (*(pos+1)=='d') sprintf(storage,help,(long)(entry->data)); else { char ch; sscanf(right,"%d",&i); pos=(char*)(entry->data); ch=pos[i]; pos[i]='\0'; sprintf(storage,help,pos); pos[i]=ch; } } else if (*(pos+1)=='%') { /* '...%%...' -> '...%...' */ strncpy(storage,entry->text,pos-entry->text); strcpy(&storage[pos-entry->text],&entry->text[pos-entry->text+1]); } else strcpy(storage,entry->text); } else strcpy(storage,entry->text); i=strlen(storage); while (idata; int height,t,hl_pos; char *pos,*txt,hl[2]; height=win->height; if (height>m->count) height=m->count; m->cur+=diff; if (m->cur<0) m->cur=m->count-1; else if (m->cur>=m->count) m->cur=0; while (m->entries[m->cur].text[0]=='-') m->cur+=diff>0?1:-1; if (m->curfirst) m->first=m->cur; else if (m->cur>=m->first+height) m->first=m->cur-height+1; hl[1]='\0'; win_attrset(A_REVERSE); for (t=m->first;tcount && t<(height+m->first);t++) { txt=get_text(&m->entries[t],win->width); hl_pos=-1; if ((pos=strchr(txt,'&'))) { if ((*(pos+1)!='&')) { hl_pos=pos-txt; hl[0]=*(pos+1); } for (++pos;*pos;pos++) *(pos-1)=*pos; *(pos-1)=' '; if (hl_pos>=0) txt[hl_pos]='\0'; } if (t==m->cur) { win_attrset(A_NORMAL); win_print(0,t-m->first,txt); if (hl_pos>=0) { win_attrset(A_REVERSE); win_print(hl_pos,t-m->first,hl); win_attrset(A_NORMAL); win_print(hl_pos+1,t-m->first,&txt[hl_pos+1]); } win_status(m->entries[t].help); win_attrset(A_REVERSE); } else if (m->entries[t].text[0]=='-') { win_line(0,win->width-1,t-m->first); } else { if (hl_pos>=0) { win_print(0,t-m->first,txt); win_attrset(A_NORMAL); win_print(hl_pos,t-m->first,hl); win_attrset(A_REVERSE); win_print(hl_pos+1,t-m->first,&txt[hl_pos+1]); } else win_print(0,t-m->first,txt); } } win_attrset(A_NORMAL); } static BOOL menu_repaint(MWINDOW *win) { menu_do_repaint(win,0); return 1; } static void handle_opt_menu(MMENU *menu) { int i; MENTRY *entry=menu->data; entry->data=(void*)(long)menu->cur; menu_close(menu); for (i=0;icount;i++) free(menu->entries[i].text); free(menu->entries); free(menu); } static void handle_input_str(int button,void *input,void *data) { if (!button) strcpy(*((char**)data),input); } static void handle_input_int(int button,void *input,void *data) { if (!button) *((int*)data)=atoi(input); } static BOOL menu_do_select(MWINDOW *win) { MMENU *m=win->data; MENTRY *entry=&m->entries[m->cur]; if (menu_is_toggle(entry)) { entry->data=(void*)(long)(!((long)(entry->data))); menu_do_repaint(win,0); return 1; } else if (menu_is_option(entry)) { char *pos,*start; MENTRY *sub; MMENU *new=malloc(sizeof(MMENU)); int cnt=1,i; start=strchr(entry->text,'|'); pos=++start; while ((pos=strchr(pos,'|'))) { pos++; cnt++; } new->cur=(long)(entry->data); new->first=0; new->count=cnt; new->key_left=1; new->entries=malloc(sizeof(MENTRY)*cnt); new->handle_select=handle_opt_menu; new->win=NULL; new->data=entry; sub=new->entries; for (i=0;itext=malloc(sizeof(char)*(pos-start+1)); strncpy(sub->text,start,pos-start); sub->text[pos-start]='\0'; sub->data=NULL; sub->help=entry->help; start=pos+1; sub++; } menu_open(new,win->x+win->width+1,win->y+m->cur-m->first); return 1; } else if (menu_is_str(entry)) { char *msg=NULL,*start,*pos; int length=0; start=strchr(entry->text,'|') + 1; pos=strchr(start,'|'); msg=malloc(sizeof(char)*(pos-start+1)); strncpy(msg,start,pos-start); msg[pos-start]='\0'; sscanf(pos+1,"%d",&length); dlg_input_str(msg,(char*)(entry->data),length, handle_input_str,&entry->data); free(msg); } else if (menu_is_int(entry)) { char *msg=NULL,*start,*pos; int min=0,max=0; start=strchr(entry->text,'|') + 1; pos=strchr(start,'|'); msg=malloc(sizeof(char)*(pos-start+1)); strncpy(msg,start,pos-start); msg[pos-start]='\0'; sscanf(pos+1,"%d|%d",&min,&max); dlg_input_int(msg,(long)(entry->data),min,max, handle_input_int,&entry->data); free(msg); } else if (menu_is_sub(entry)) { MMENU *sub=entry->data; sub->cur=sub->first=0; menu_open(sub,win->x+win->width+1,win->y+m->cur-m->first); return 1; } return 0; } void menu_close(MMENU *menu) { int i; for (i=0;icount;i++) if (menu_is_sub(&menu->entries[i])) menu_close(menu->entries[i].data); if (menu->win) { win_status(NULL); win_close_win(menu->win); menu->win=NULL; } } static BOOL menu_handle_key(MWINDOW *win,int ch) { MMENU *menu=win->data; char *pos; int i,key; if ((ch<256) &&(isalpha(ch))) ch=toupper(ch); switch (ch) { case KEY_DOWN: menu_do_repaint(win,1); break; case KEY_UP: menu_do_repaint(win,-1); break; case KEY_LEFT: if (menu->key_left) menu_close(menu); break; case KEY_RIGHT: if (menu_has_sub(&menu->entries[menu->cur])) menu_do_select(win); break; case KEY_ENTER: case '\r': if (!menu_do_select(win)) if (menu->handle_select) menu->handle_select(menu); break; default: for (i=0;icount;i++) { key=0; if ((pos=strchr(menu->entries[i].text,'&'))) key=toupper((int)(*(pos+1))); if (key==ch) { menu_do_repaint(win,i-menu->cur); if (!menu_do_select(win)) if (menu->handle_select) menu->handle_select(menu); return 1; } } return 0; } return 1; } static void menu_handle_resize(MWINDOW *win,int dx,int dy) { int m_y,m_width,m_height; MMENU *menu=win->data; win_get_size_max(&m_y,&m_width,&m_height); m_width-=2;m_height-=2; if (win->x+win->width>m_width) { win->x=m_width-win->width+1; if (win->x<1) win->x=1; } if (win->y+win->height-m_y>m_height || win->y+menu->count-m_y>m_height) { win->y=m_height-menu->count+m_y+1; if (win->y <= m_y) win->y=m_y+1; } if (win->heightcount) win->height=menu->count; if (win->height>m_height) win->height=m_height; if (menu->first+win->height>menu->count) menu->first=menu->count-win->height; if (menu->first<0) menu->first=0; } void menu_open(MMENU *menu,int x,int y) { MWINDOW *win; char *entry; int m_y,m_width,m_height,width=0; /* get max. width of entries */ for (m_y=0;m_ycount;m_y++) { entry=get_text(&menu->entries[m_y],0); m_width=strlen(entry); if (strchr(entry,'&')) m_width--; if (m_width>width) width=m_width; } win_get_size_max(&m_y,&m_width,&m_height); m_width-=2;m_height-=2; if (x+width-1>m_width) x=m_width-width+1; if (x<1) x=1; if (y+menu->count-m_y-1>m_height) y=m_height-menu->count+m_y+1; if (ywin=win_open(x,y,width,menu->count,1,NULL); win_set_repaint(menu_repaint); win_set_handle_key(menu_handle_key); win_set_resize(0,menu_handle_resize); win_set_data((void*)menu); win=win_get_window(); if (menu->first+win->height>menu->count) menu->first=menu->count-win->height; if (menu->first<0) menu->first=0; menu_repaint(win); } /* ex:set ts=4: */