2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <sys/types.h>
34 #include "m_property.h"
35 #include "asxparser.h"
37 #include "libmpcodecs/mp_image.h"
40 #include "menu_list.h"
41 #include "input/input.h"
63 static struct menu_priv_s cfg_dflt
= {
71 static const m_option_t cfg_fields
[] = {
72 MENU_LIST_PRIV_FIELDS
,
73 { "title", M_ST_OFF(menu_list_priv_t
,title
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
74 { "na", M_ST_OFF(struct menu_priv_s
,na
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
75 { "hide-na", M_ST_OFF(struct menu_priv_s
,hide_na
), CONF_TYPE_FLAG
, CONF_RANGE
, 0, 1, NULL
},
76 { NULL
, NULL
, NULL
, 0,0,0,NULL
}
79 #define mpriv (menu->priv)
81 static void entry_set_text(menu_t
* menu
, list_entry_t
* e
) {
82 char* val
= e
->txt
? property_expand_string(menu
->ctx
, e
->txt
) :
83 mp_property_print(e
->prop
, menu
->ctx
);
84 int l
,edit
= (mpriv
->edit
&& e
== mpriv
->p
.current
);
91 val
= strdup(mpriv
->na
);
92 } else if(mpriv
->hide_na
)
94 l
= strlen(e
->name
) + 2 + strlen(val
) + (edit
? 4 : 0) + 1;
95 if(e
->p
.txt
) free(e
->p
.txt
);
97 sprintf(e
->p
.txt
,"%s: %s%s%s",e
->name
,edit
? "> " : "",val
,edit
? " <" : "");
101 static void update_entries(menu_t
* menu
, int auto_update
) {
103 for(e
= mpriv
->p
.menu
; e
; e
= e
->p
.next
)
104 if ((e
->txt
|| e
->prop
) && (!auto_update
|| e
->auto_update
))
105 entry_set_text(menu
, e
);
108 static int parse_args(menu_t
* menu
,char* args
) {
109 char *element
,*body
, **attribs
, *name
, *txt
, *auto_update
;
110 list_entry_t
* m
= NULL
;
113 ASX_Parser_t
* parser
= asx_parser_new(menu
->mconfig
);
117 r
= asx_get_element(parser
,&args
,&element
,&body
,&attribs
);
119 mp_tmsg(MSGT_OSD_MENU
,MSGL_ERR
,"[MENU] syntax error at line: %d\n",parser
->line
);
120 asx_parser_free(parser
);
123 asx_parser_free(parser
);
125 mp_tmsg(MSGT_OSD_MENU
,MSGL_WARN
,"[MENU] No entry found in the menu definition.\n");
126 m
= calloc(1,sizeof(struct list_entry_s
));
127 m
->p
.txt
= strdup("Back");
128 menu_list_add_entry(menu
,m
);
131 if(!strcmp(element
,"menu")) {
132 name
= asx_get_attrib("menu",attribs
);
134 mp_tmsg(MSGT_OSD_MENU
,MSGL_WARN
,"[MENU] Submenu definition needs a 'menu' attribute.\n");
137 m
= calloc(1,sizeof(struct list_entry_s
));
139 name
= NULL
; // we want to keep it
140 m
->p
.txt
= asx_get_attrib("name",attribs
);
141 if(!m
->p
.txt
) m
->p
.txt
= strdup(m
->menu
);
142 menu_list_add_entry(menu
,m
);
146 name
= asx_get_attrib("property",attribs
);
148 if(name
&& mp_property_do(name
,M_PROPERTY_GET_TYPE
,&opt
,menu
->ctx
) <= 0) {
149 mp_tmsg(MSGT_OSD_MENU
,MSGL_WARN
,"[MENU] Invalid property '%s' in pref menu entry. (line %d).\n",
153 txt
= asx_get_attrib("txt",attribs
);
155 mp_tmsg(MSGT_OSD_MENU
,MSGL_WARN
,"[MENU] Pref menu entry definitions need a valid 'property' or 'txt' attribute (line %d).\n",parser
->line
);
156 if(txt
) free(txt
), txt
= NULL
;
159 m
= calloc(1,sizeof(struct list_entry_s
));
161 m
->txt
= txt
; txt
= NULL
;
162 m
->prop
= name
; name
= NULL
;
163 m
->name
= asx_get_attrib("name",attribs
);
164 if(!m
->name
) m
->name
= strdup(opt
? opt
->name
: "-");
165 auto_update
= asx_get_attrib("auto-update", attribs
);
167 if (!strcmp(auto_update
, "1") ||
168 !strcasecmp(auto_update
, "on") ||
169 !strcasecmp(auto_update
, "yes") ||
170 !strcasecmp(auto_update
, "true"))
174 entry_set_text(menu
,m
);
175 menu_list_add_entry(menu
,m
);
181 asx_free_attribs(attribs
);
185 static void read_cmd(menu_t
* menu
,int cmd
) {
186 list_entry_t
* e
= mpriv
->p
.current
;
191 if(!mpriv
->edit
) break;
193 if(mp_property_do(e
->prop
,M_PROPERTY_STEP_UP
,NULL
,menu
->ctx
) > 0)
194 update_entries(menu
, 0);
197 if(!mpriv
->edit
) break;
199 if(mp_property_do(e
->prop
,M_PROPERTY_STEP_DOWN
,NULL
,menu
->ctx
) > 0)
200 update_entries(menu
, 0);
204 // check that the property is writable
205 if(mp_property_do(e
->prop
,M_PROPERTY_SET
,NULL
,menu
->ctx
) < 0) return;
206 // shortcut for flags
207 if(e
->opt
->type
== CONF_TYPE_FLAG
) {
208 if(mp_property_do(e
->prop
,M_PROPERTY_STEP_UP
,NULL
,menu
->ctx
) > 0)
209 update_entries(menu
, 0);
213 mpriv
->edit
= !mpriv
->edit
;
215 update_entries(menu
, 0);
216 // switch the pointer
218 mpriv
->ptr
= mpriv
->p
.ptr
;
221 mpriv
->p
.ptr
= mpriv
->ptr
;
223 case MENU_CMD_CANCEL
:
224 if(!mpriv
->edit
) break;
226 update_entries(menu
, 0);
227 mpriv
->p
.ptr
= mpriv
->ptr
;
235 char* txt
= malloc(10 + strlen(e
->menu
) + 1);
236 sprintf(txt
,"set_menu %s",e
->menu
);
237 c
= mp_input_parse_cmd(txt
);
238 if(c
) mp_input_queue_cmd(menu
->input_ctx
, c
);
251 menu_list_read_cmd(menu
,cmd
);
254 static void free_entry(list_entry_t
* entry
) {
256 if(entry
->name
) free(entry
->name
);
257 if(entry
->txt
) free(entry
->txt
);
258 if(entry
->prop
) free(entry
->prop
);
259 if(entry
->menu
) free(entry
->menu
);
263 static void closeMenu(menu_t
* menu
) {
264 menu_list_uninit(menu
,free_entry
);
267 static void menu_pref_draw(menu_t
* menu
, mp_image_t
* mpi
) {
268 update_entries(menu
, 1);
269 menu_list_draw(menu
, mpi
);
272 static int openMenu(menu_t
* menu
, char* args
) {
274 menu
->draw
= menu_pref_draw
;
275 menu
->read_cmd
= read_cmd
;
276 menu
->close
= closeMenu
;
280 mp_tmsg(MSGT_OSD_MENU
,MSGL_ERR
,"[MENU] Pref menu needs an argument.\n");
284 menu_list_init(menu
);
285 return parse_args(menu
,args
);
288 const menu_info_t menu_info_pref
= {
295 sizeof(struct menu_priv_s
),