]> git.sesse.net Git - vlc/blob - modules/gui/win32/menu.cpp
* src/misc/variables.c, ALL: improvements to the object variables api.
[vlc] / modules / gui / win32 / menu.cpp
1 /*****************************************************************************\r
2  * menu.cpp: functions to handle menu items\r
3  *****************************************************************************\r
4  * Copyright (C) 2002-2003 VideoLAN\r
5  * $Id: menu.cpp,v 1.15 2003/05/04 22:42:16 gbazin Exp $\r
6  *\r
7  * Authors: Olivier Teuliere <ipkiss@via.ecp.fr>\r
8  *\r
9  * This program is free software; you can redistribute it and/or modify\r
10  * it under the terms of the GNU General Public License as published by\r
11  * the Free Software Foundation; either version 2 of the License, or\r
12  * (at your option) any later version.\r
13  *\r
14  * This program is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU General Public License for more details.\r
18  *\r
19  * You should have received a copy of the GNU General Public License\r
20  * along with this program; if not, write to the Free Software\r
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.\r
22  *****************************************************************************/\r
23 \r
24 #include <vcl.h>\r
25 \r
26 #include <vlc/vlc.h>\r
27 #include <vlc/intf.h>\r
28 \r
29 #include "menu.h"\r
30 #include "win32_common.h"\r
31 \r
32 /*****************************************************************************\r
33  * TMenusGen::*Click: callbacks for the menuitems\r
34  ****************************************************************************/\r
35 \r
36 /*\r
37  * Variables\r
38  */\r
39 \r
40 /* variables of the audio output */\r
41 void __fastcall TMenusGen::AoutVarClick( TObject *Sender )\r
42 {\r
43     TMenuItem * Item = (TMenuItem *)Sender;\r
44 \r
45     vlc_object_t * p_aout;\r
46     p_aout = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,\r
47                                               FIND_ANYWHERE );\r
48     if( p_aout == NULL )\r
49     {\r
50         msg_Warn( p_intf, "cannot set variable (%s)", Item->Caption.c_str() );\r
51         return;\r
52     }\r
53 \r
54 #error fixme! look at rc.c line 823\r
55     if( Item->Parent == MenuADevice || Item->Parent == PopupADevice )\r
56     {\r
57         VarChange( p_aout, "audio-device", MenuADevice, PopupADevice, Item );\r
58     }\r
59     else if( Item->Parent == MenuChannel || Item->Parent == PopupChannel )\r
60     {\r
61         VarChange( p_aout, "audio-channels", MenuChannel, PopupChannel, Item );\r
62     }\r
63 \r
64     vlc_object_release( p_aout );\r
65 }\r
66 \r
67 /* variables of the video output */\r
68 void __fastcall TMenusGen::VoutVarClick( TObject *Sender )\r
69 {\r
70     TMenuItem * Item = (TMenuItem *)Sender;\r
71 \r
72     vlc_object_t * p_vout;\r
73     p_vout = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,\r
74                                               FIND_ANYWHERE );\r
75     if( p_vout == NULL )\r
76     {\r
77         msg_Warn( p_intf, "cannot set variable (%s)", Item->Caption.c_str() );\r
78         return;\r
79     }\r
80 \r
81     if( Item->Parent == MenuVDevice || Item->Parent == PopupVDevice )\r
82     {\r
83         VarChange( p_vout, "video-device", MenuVDevice, PopupVDevice, Item );\r
84     }\r
85 \r
86     vlc_object_release( p_vout );\r
87 }\r
88 \r
89 /*\r
90  * Modules\r
91  */\r
92 \r
93 /* Interface modules: we spawn a new interface */\r
94 void __fastcall TMenusGen::InterfaceModuleClick( TObject *Sender )\r
95 {\r
96     TMenuItem * Item = (TMenuItem *)Sender;\r
97 \r
98     AnsiString IntfName = CleanCaption( Item->Caption );\r
99 \r
100     intf_thread_t *p_newintf;\r
101 \r
102     p_newintf = intf_Create( p_intf->p_vlc, IntfName.c_str() );\r
103 \r
104     if( p_newintf )\r
105     {\r
106         p_newintf->b_block = VLC_FALSE;\r
107         if( intf_RunThread( p_newintf ) )\r
108         {\r
109             vlc_object_detach( p_newintf );\r
110             intf_Destroy( p_newintf );\r
111         }\r
112     }\r
113 }\r
114 \r
115 /*\r
116  * Audio\r
117  */\r
118 \r
119 void __fastcall TMenusGen::MenuLanguageClick( TObject *Sender )\r
120 {\r
121     LangChange( MenuLanguage, (TMenuItem *)Sender, PopupLanguage, AUDIO_ES );\r
122 }\r
123 \r
124 void __fastcall TMenusGen::PopupLanguageClick( TObject *Sender )\r
125 {\r
126     LangChange( PopupLanguage, (TMenuItem *)Sender, MenuLanguage, AUDIO_ES );\r
127 }\r
128 \r
129 /*\r
130  * Subtitles\r
131  */\r
132 \r
133 void __fastcall TMenusGen::MenuSubtitleClick( TObject *Sender )\r
134 {\r
135     LangChange( MenuSubtitles, (TMenuItem *)Sender, PopupSubtitles, SPU_ES );\r
136 }\r
137 \r
138 void __fastcall TMenusGen::PopupSubtitleClick( TObject *Sender )\r
139 {\r
140     LangChange( PopupSubtitles, (TMenuItem *)Sender, MenuSubtitles, SPU_ES );\r
141 }\r
142 \r
143 /*\r
144  * Program\r
145  */\r
146 \r
147 void __fastcall TMenusGen::MenuProgramClick( TObject *Sender )\r
148 {\r
149    ProgramChange( (TMenuItem *)Sender, PopupProgram );\r
150 }\r
151 \r
152 void __fastcall TMenusGen::PopupProgramClick( TObject *Sender )\r
153 {\r
154     ProgramChange( (TMenuItem *)Sender, MenuProgram );\r
155 }\r
156 \r
157 /*\r
158  * Title\r
159  */\r
160 \r
161 void __fastcall TMenusGen::MenuTitleClick( TObject *Sender )\r
162 {\r
163     TMenuItem     * Item = (TMenuItem *)Sender;\r
164     TMenuItem     * ItemTitle;\r
165     input_area_t  * p_area;\r
166     unsigned int    i_title = Item->Tag;\r
167 \r
168     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
169     i_title = __MIN( i_title,\r
170                      p_intf->p_sys->p_input->stream.i_area_nb - 1 );\r
171     i_title = __MAX( i_title, 1 );\r
172     p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];\r
173     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
174 \r
175     input_ChangeArea( p_intf->p_sys->p_input, p_area );\r
176 \r
177     Item->Checked = true;\r
178     ItemTitle = Index2Item( PopupNavigation, i_title - 1, false );\r
179     Index2Item( ItemTitle, 0, false )->Checked = true;\r
180 \r
181     input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
182 }\r
183 \r
184 /*\r
185  * Chapter\r
186  */\r
187 \r
188 void __fastcall TMenusGen::MenuChapterClick( TObject *Sender )\r
189 {\r
190     TMenuItem     * Item = (TMenuItem *)Sender;\r
191     TMenuItem     * ItemTitle;\r
192     input_area_t  * p_area;\r
193     unsigned int    i_title;\r
194     unsigned int    i_chapter = Item->Tag;\r
195 \r
196     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
197     p_area = p_intf->p_sys->p_input->stream.p_selected_area;\r
198     i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );\r
199     i_chapter = __MAX( i_chapter, 1 );\r
200     p_area->i_part = i_chapter;\r
201     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
202 \r
203     input_ChangeArea( p_intf->p_sys->p_input, p_area );\r
204 \r
205     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
206     i_title = p_intf->p_sys->p_input->stream.p_selected_area->i_id;\r
207     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
208 \r
209     ItemTitle = Index2Item( PopupNavigation, i_title, false );\r
210     Index2Item( ItemTitle, i_chapter, false )->Checked = true;\r
211 \r
212     input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
213 }\r
214 \r
215 /*\r
216  * Navigation\r
217  */\r
218 \r
219 void __fastcall TMenusGen::PopupNavigationClick( TObject *Sender )\r
220 {\r
221     TMenuItem     * Item = (TMenuItem *)Sender;\r
222     TMenuItem     * ItemTitle;\r
223     input_area_t  * p_area;\r
224     unsigned int    i_title   = Data2Title( Item->Tag );\r
225     unsigned int    i_chapter = Data2Chapter( Item->Tag );\r
226 \r
227     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
228     i_title = __MIN( i_title,\r
229                      p_intf->p_sys->p_input->stream.i_area_nb - 1 );\r
230     i_title = __MAX( i_title, 1 );\r
231     p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];\r
232     i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );\r
233     i_chapter = __MAX( i_chapter, 1 );\r
234     p_area->i_part = i_chapter;\r
235     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
236 \r
237     input_ChangeArea( p_intf->p_sys->p_input, p_area );\r
238 \r
239     Item->Checked = true;\r
240     ItemTitle = Index2Item( MenuTitle, i_title, false );\r
241     if( ItemTitle->Checked )\r
242     {\r
243         /* same title, new chapter */\r
244         Index2Item( MenuChapter, i_chapter, false )->Checked = true;\r
245     }\r
246     else\r
247     {\r
248         /* new title => we must rebuild the chapter menu */\r
249         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
250         RadioMenu(\r
251             MenuChapter, "Chapter",\r
252             p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb,\r
253             i_chapter, MenuChapterClick );\r
254         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
255     }\r
256 \r
257     input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
258 }\r
259 \r
260 \r
261 __fastcall TMenusGen::TMenusGen( intf_thread_t *_p_intf ) : TObject()\r
262 {\r
263     p_intf = _p_intf;\r
264 \r
265     /* Initialize local pointers to menu items of the main window */\r
266     TMainFrameDlg * p_window = p_intf->p_sys->p_window;\r
267     if( p_window == NULL )\r
268     {\r
269         msg_Warn( p_intf, "Main window wasn't created, expect problems..." );\r
270         return;\r
271     }\r
272 \r
273     MenuChannel = p_window->MenuChannel;\r
274     PopupChannel = p_window->PopupChannel;\r
275     MenuADevice = p_window->MenuADevice;\r
276     PopupADevice = p_window->PopupADevice;\r
277     MenuVDevice = p_window->MenuVDevice;\r
278     PopupVDevice = p_window->PopupVDevice;\r
279     MenuLanguage = p_window->MenuLanguage;\r
280     PopupLanguage = p_window->PopupLanguage;\r
281     MenuSubtitles = p_window->MenuSubtitles;\r
282     PopupSubtitles = p_window->PopupSubtitles;\r
283     MenuProgram = p_window->MenuProgram;\r
284     PopupProgram = p_window->PopupProgram;\r
285     MenuTitle = p_window->MenuTitle;\r
286     MenuChapter = p_window->MenuChapter;\r
287     PopupNavigation = p_window->PopupNavigation;\r
288     MenuAddInterface = p_window->MenuAddInterface;\r
289 \r
290     /* Create the "Add interface" menu */\r
291     SetupModuleMenu( "interface", MenuAddInterface, InterfaceModuleClick );\r
292 }\r
293 \r
294 \r
295 /*****************************************************************************\r
296  * SetupMenus: This function dynamically generates some menus\r
297  *****************************************************************************\r
298  * The lock on p_input->stream must be taken before you call this function\r
299  *****************************************************************************/\r
300 void __fastcall TMenusGen::SetupMenus()\r
301 {\r
302     TMainFrameDlg  * p_window = p_intf->p_sys->p_window;\r
303     input_thread_t * p_input  = p_intf->p_sys->p_input;\r
304     es_descriptor_t   * p_audio_es;\r
305     es_descriptor_t   * p_spu_es;\r
306 \r
307     p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;\r
308     p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_program_update |\r
309                                      p_intf->p_sys->b_title_update;\r
310     p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_program_update |\r
311                                    p_intf->p_sys->b_title_update;\r
312 \r
313     if( p_intf->p_sys->b_program_update )\r
314     {\r
315         pgrm_descriptor_t * p_pgrm;\r
316 \r
317         if( p_input->stream.p_new_program )\r
318         {\r
319             p_pgrm = p_input->stream.p_new_program;\r
320         }\r
321         else\r
322         {\r
323             p_pgrm = p_input->stream.p_selected_program;\r
324         }\r
325 \r
326         ProgramMenu( MenuProgram, p_pgrm, MenuProgramClick );\r
327         ProgramMenu( PopupProgram, p_pgrm, PopupProgramClick );\r
328 \r
329         p_intf->p_sys->b_program_update = VLC_FALSE;\r
330     }\r
331 \r
332     if( p_intf->p_sys->b_title_update )\r
333     {\r
334 // why "-1" ?\r
335 // because if the titles go from 1 to X-1, there are X-1 titles\r
336         RadioMenu( MenuTitle, "Title",\r
337                    p_input->stream.i_area_nb - 1,\r
338                    p_input->stream.p_selected_area->i_id,\r
339                    MenuTitleClick );\r
340 \r
341         AnsiString CurrentTitle;\r
342         CurrentTitle.sprintf( "%d", p_input->stream.p_selected_area->i_id );\r
343         p_window->LabelTitleCurrent->Caption = CurrentTitle;\r
344 \r
345         p_intf->p_sys->b_title_update = VLC_FALSE;\r
346     }\r
347 \r
348     if( p_intf->p_sys->b_chapter_update )\r
349     {\r
350         RadioMenu( MenuChapter, "Chapter",\r
351                    p_input->stream.p_selected_area->i_part_nb - 1,\r
352                    p_input->stream.p_selected_area->i_part,\r
353                    MenuChapterClick );\r
354 \r
355         NavigationMenu( PopupNavigation, PopupNavigationClick );\r
356 \r
357         AnsiString CurrentChapter;\r
358         CurrentChapter.sprintf( "%d", p_input->stream.p_selected_area->i_part );\r
359         p_window->LabelChapterCurrent->Caption = CurrentChapter;\r
360 \r
361         p_intf->p_sys->i_part = p_input->stream.p_selected_area->i_part;\r
362 \r
363         p_intf->p_sys->b_chapter_update = VLC_FALSE;\r
364     }\r
365 \r
366     /* look for selected ES */\r
367     p_audio_es = NULL;\r
368     p_spu_es = NULL;\r
369 \r
370     for( unsigned int i = 0; i < p_input->stream.i_selected_es_number; i++ )\r
371     {\r
372         if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )\r
373         {\r
374             p_audio_es = p_input->stream.pp_selected_es[i];\r
375         }\r
376 \r
377         if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )\r
378         {\r
379             p_spu_es = p_input->stream.pp_selected_es[i];\r
380         }\r
381     }\r
382     this->p_audio_es_old = p_audio_es;\r
383     this->p_spu_es_old = p_spu_es;\r
384 \r
385     vlc_mutex_unlock( &p_input->stream.stream_lock );\r
386 \r
387     /* audio menus */\r
388     if( p_intf->p_sys->b_audio_update )\r
389     {\r
390         LanguageMenu( MenuLanguage, p_audio_es, AUDIO_ES, MenuLanguageClick );\r
391         LanguageMenu( PopupLanguage, p_audio_es, AUDIO_ES, PopupLanguageClick );\r
392 \r
393         p_intf->p_sys->b_audio_update = VLC_FALSE;\r
394     }\r
395 \r
396     /* sub picture menus */\r
397     if( p_intf->p_sys->b_spu_update )\r
398     {\r
399         LanguageMenu( PopupSubtitles, p_spu_es, SPU_ES, PopupSubtitleClick );\r
400         LanguageMenu( MenuSubtitles, p_spu_es, SPU_ES, MenuSubtitleClick );\r
401 \r
402         p_intf->p_sys->b_spu_update = VLC_FALSE;\r
403     }\r
404 \r
405     if( p_intf->p_sys->b_aout_update )\r
406     {\r
407         aout_instance_t * p_aout;\r
408         p_aout = (aout_instance_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,\r
409                                                      FIND_ANYWHERE );\r
410 \r
411         if( p_aout != NULL )\r
412         {\r
413             vlc_value_t val;\r
414             val.b_bool = VLC_FALSE;\r
415 \r
416             var_Set( (vlc_object_t *)p_aout, "intf-change", val );\r
417 \r
418 #error fixme! look at rc.c line 823\r
419             SetupVarMenu( (vlc_object_t *)p_aout, "audio-channels",\r
420                           MenuChannel, AoutVarClick );\r
421             SetupVarMenu( (vlc_object_t *)p_aout, "audio-channels",\r
422                           PopupChannel, AoutVarClick );\r
423 \r
424             SetupVarMenu( (vlc_object_t *)p_aout, "audio-device",\r
425                           MenuADevice, AoutVarClick );\r
426             SetupVarMenu( (vlc_object_t *)p_aout, "audio-device",\r
427                           PopupADevice, AoutVarClick );\r
428 \r
429             vlc_object_release( (vlc_object_t *)p_aout );\r
430         }\r
431 \r
432         p_intf->p_sys->b_aout_update = VLC_FALSE;\r
433     }\r
434 \r
435     if( p_intf->p_sys->b_vout_update )\r
436     {\r
437         vout_thread_t * p_vout;\r
438         p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,\r
439                                                    FIND_ANYWHERE );\r
440 \r
441         if( p_vout != NULL )\r
442         {\r
443             vlc_value_t val;\r
444             val.b_bool = VLC_FALSE;\r
445 \r
446             var_Set( (vlc_object_t *)p_vout, "intf-change", val );\r
447 \r
448             SetupVarMenu( (vlc_object_t *)p_vout, "video-device",\r
449                           MenuVDevice, VoutVarClick );\r
450             SetupVarMenu( (vlc_object_t *)p_vout, "video-device",\r
451                           PopupVDevice, VoutVarClick );\r
452 \r
453             vlc_object_release( (vlc_object_t *)p_vout );\r
454         }\r
455 \r
456         p_intf->p_sys->b_vout_update = VLC_FALSE;\r
457     }\r
458 \r
459     vlc_mutex_lock( &p_input->stream.stream_lock );\r
460 }\r
461 \r
462 \r
463 /*****************************************************************************\r
464  * Private functions\r
465  *****************************************************************************/\r
466 TMenuItem * TMenusGen::Index2Item( TMenuItem *Root, int i_index,\r
467                                    bool SingleColumn )\r
468 {\r
469     if( SingleColumn || ( i_index < 20 ) )\r
470         return Root->Items[i_index];\r
471     else\r
472         return Root->Items[i_index / 10]->Items[i_index % 10];\r
473 }\r
474 \r
475 int TMenusGen::Item2Index( TMenuItem *Root, TMenuItem *Item )\r
476 {\r
477     if( Item->Parent == Root )\r
478         return Item->MenuIndex;\r
479     else\r
480         return( 10 * Item->Parent->MenuIndex + Item->MenuIndex );\r
481 }\r
482 \r
483 int __fastcall TMenusGen::Data2Title( int data )\r
484 {\r
485     return (int) (data >> 16 );\r
486 }\r
487 \r
488 int __fastcall TMenusGen::Data2Chapter( int data )\r
489 {\r
490     return (int) (data & 0xffff);\r
491 }\r
492 \r
493 int __fastcall TMenusGen::Pos2Data( int title, int chapter )\r
494 {\r
495     return (int) (( title << 16 ) | ( chapter & 0xffff ));\r
496 }\r
497 \r
498 /* This function deletes all the '&' characters in the caption string,\r
499  * because Borland automatically adds one when (and only when!) you click on\r
500  * the menuitem. Grrrrr... */\r
501 AnsiString __fastcall TMenusGen::CleanCaption( AnsiString Caption )\r
502 {\r
503     while( Caption.LastDelimiter( "&" ) != 0 )\r
504     {\r
505         Caption.Delete( Caption.LastDelimiter( "&" ), 1 );\r
506     }\r
507 \r
508     return Caption;\r
509 }\r
510 \r
511 /****************************************************************************\r
512  * VarChange: change a variable in a vlc_object_t\r
513  ****************************************************************************\r
514  * Change the variable and update the menuitems.\r
515  ****************************************************************************/\r
516 void __fastcall TMenusGen::VarChange( vlc_object_t *p_object,\r
517         const char *psz_variable, TMenuItem *RootMenu, TMenuItem *RootPopup,\r
518         TMenuItem *Item )\r
519 {\r
520     vlc_value_t val;\r
521     int i_index;\r
522 \r
523     AnsiString Caption = CleanCaption( Item->Caption );\r
524     val.psz_string = Caption.c_str();\r
525 \r
526     /* set the new value */\r
527     if( var_Set( p_object, psz_variable, val ) < 0 )\r
528     {\r
529         msg_Warn( p_object, "cannot set variable (%s)", val.psz_string );\r
530     }\r
531 \r
532     i_index = Item->MenuIndex;\r
533     RootMenu->Items[i_index]->Checked = true;\r
534     RootPopup->Items[i_index]->Checked = true;\r
535 }\r
536 \r
537 /****************************************************************************\r
538  * LangChange: change audio or subtitles languages\r
539  ****************************************************************************\r
540  * Toggle the language, and update the selected menuitems.\r
541  ****************************************************************************/\r
542 void __fastcall TMenusGen::LangChange( TMenuItem *RootCurrent, TMenuItem *Item,\r
543     TMenuItem *RootOther, int i_cat )\r
544 {\r
545     es_descriptor_t * p_es;\r
546     es_descriptor_t * p_es_old;\r
547     int i_index;\r
548     int i_es;\r
549 \r
550     /* find the selected ES */\r
551     i_es = Item->Tag;\r
552 \r
553     /* find selected menu item */\r
554     i_index = Item2Index( RootCurrent, Item ) - 1;\r
555     if( i_index < 0 )\r
556     {\r
557         /* 'None' was selected */\r
558         p_es = NULL;\r
559     }\r
560     else\r
561     {\r
562         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
563         p_es = p_intf->p_sys->p_input->stream.pp_es[i_es];\r
564         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
565     }\r
566 \r
567     /* find the current ES */\r
568     if( i_cat == AUDIO_ES )\r
569     {\r
570         p_es_old = this->p_audio_es_old;\r
571         this->p_audio_es_old = p_es;\r
572     }\r
573     else\r
574     {\r
575         p_es_old = this->p_spu_es_old;\r
576         this->p_spu_es_old = p_es;\r
577     }\r
578 \r
579     /* exchange them */\r
580     input_ToggleES( p_intf->p_sys->p_input, p_es_old, false );\r
581     input_ToggleES( p_intf->p_sys->p_input, p_es, true );\r
582 \r
583     Item->Checked = true;\r
584     Index2Item( RootOther, i_index + 1, true )->Checked = true;\r
585 }\r
586 \r
587 /****************************************************************************\r
588  * ProgramChange: change the program\r
589  ****************************************************************************\r
590  * Toggle the program, and update the selected menuitems.\r
591  ****************************************************************************/\r
592 void __fastcall TMenusGen::ProgramChange( TMenuItem *Item,\r
593                                           TMenuItem *RootOther )\r
594 {\r
595     int i_program = Item->Tag;\r
596 \r
597     /* toggle the program */\r
598     input_ChangeProgram( p_intf->p_sys->p_input, (uint16_t)i_program );\r
599 \r
600     /* check selected menu items */\r
601     Item->Checked = true;\r
602     Index2Item( RootOther, i_program - 1, true )->Checked = true;\r
603 \r
604     /* update audio/subtitles menus */\r
605     p_intf->p_sys->b_audio_update = VLC_TRUE;\r
606     p_intf->p_sys->b_spu_update = VLC_TRUE;\r
607     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
608     SetupMenus();\r
609     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
610     p_intf->p_sys->b_audio_update = VLC_FALSE;\r
611     p_intf->p_sys->b_spu_update = VLC_FALSE;\r
612 \r
613     input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
614 }\r
615 \r
616 /*****************************************************************************\r
617  * SetupVarMenu: build a menu allowing to change a variable\r
618  *****************************************************************************/\r
619 void __fastcall TMenusGen::SetupVarMenu( vlc_object_t *p_object,\r
620         const char *psz_variable, TMenuItem *Root, TNotifyEvent MenuItemClick )\r
621 {\r
622     TMenuItem * Item;\r
623     vlc_value_t val;\r
624     char * psz_value = NULL;\r
625     int i;\r
626 \r
627     /* remove previous menu */\r
628     Root->Clear();\r
629 \r
630     /* get the current value */\r
631     if( var_Get( p_object, psz_variable, &val ) < 0 )\r
632     {\r
633         return;\r
634     }\r
635     psz_value = val.psz_string;\r
636 \r
637     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST, &val, NULL ) < 0 )\r
638     {\r
639         free( psz_value );\r
640         return;\r
641     }\r
642 \r
643     /* append a menuitem for each option */\r
644     for( i = 0; i < val.p_list->i_count; i++ )\r
645     {\r
646         Item = new TMenuItem( Root );\r
647         Item->Caption = val.p_list->p_values[i].psz_string;\r
648         Item->Hint = val.p_list->p_values[i].psz_string;\r
649         Item->RadioItem = true;\r
650         Item->OnClick = MenuItemClick;\r
651         if( !strcmp( psz_value, val.p_list->p_values[i].psz_string ) )\r
652             Item->Checked = true;\r
653 \r
654         /* Add the item to the submenu */\r
655         Root->Add( Item );\r
656     }\r
657 \r
658     /* enable the menu if there is at least 1 item */\r
659     Root->Enabled = ( val.p_list->i_count > 0 );\r
660 \r
661     /* clean up everything */\r
662     var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val, NULL );\r
663 //    free( psz_value );\r
664 }\r
665 \r
666 /*****************************************************************************\r
667  * SetupModuleMenu: build a menu listing all the modules of a given\r
668                     capability\r
669  *****************************************************************************/\r
670 void __fastcall TMenusGen::SetupModuleMenu( const char *psz_capability,\r
671         TMenuItem *Root, TNotifyEvent MenuItemClick )\r
672 {\r
673     module_t * p_parser;\r
674     vlc_list_t *p_list;\r
675     int i_index;\r
676 \r
677     /* remove previous menu */\r
678     Root->Clear();\r
679     Root->Enabled = false;\r
680 \r
681     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );\r
682     for( i_index = 0; i_index < p_list->i_count; i_index++ )\r
683     {\r
684         p_parser = (module_t *)p_list->p_values[i_index].p_object ;\r
685 \r
686         if( !strcmp( p_parser->psz_capability, psz_capability ) )\r
687         {\r
688             TMenuItem *Item = new TMenuItem( Root );\r
689             Item->Caption = p_parser->psz_object_name;\r
690             Item->Hint = Item->Caption;\r
691             Item->OnClick = MenuItemClick;\r
692             Root->Add( Item );\r
693         }\r
694     }\r
695 \r
696     vlc_list_release( p_list );\r
697 \r
698     /* be sure that menu is enabled, if there is at least one item */\r
699     if( i_index > 0 )\r
700         Root->Enabled = true;\r
701 }\r
702 \r
703 /*****************************************************************************\r
704  * ProgramMenu: update the programs menu of the interface\r
705  *****************************************************************************\r
706  * Builds the program menu according to what have been found in the PAT\r
707  * by the input. Useful for multi-programs streams such as DVB ones.\r
708  *****************************************************************************/\r
709 void __fastcall TMenusGen::ProgramMenu( TMenuItem *Root,\r
710     pgrm_descriptor_t *p_pgrm, TNotifyEvent MenuItemClick )\r
711 {\r
712     TMenuItem * Item;\r
713 \r
714     /* remove previous menu */\r
715     Root->Clear();\r
716     Root->Enabled = false;\r
717 \r
718     /* create a set of program buttons and append them to the container */\r
719     for( unsigned int i = 0; i < p_intf->p_sys->p_input->stream.i_pgrm_number;\r
720          i++ )\r
721     {\r
722         AnsiString Name;\r
723         Name.sprintf( "id %d",\r
724             p_intf->p_sys->p_input->stream.pp_programs[i]->i_number );\r
725 \r
726         Item = new TMenuItem( Root );\r
727         Item->Caption = Name;\r
728         Item->Hint = Name;\r
729         Item->RadioItem = true;\r
730         Item->OnClick = MenuItemClick;\r
731 \r
732         /* FIXME: temporary hack to save the program id with the Item\r
733          * It will be used in the callback. */\r
734         Item->Tag = i + 1;\r
735 \r
736         /* check the currently selected program */\r
737         if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] )\r
738             Item->Checked = true;\r
739 \r
740         /* add the item to the submenu */\r
741         Root->Add( Item );\r
742     }\r
743 \r
744     /* be sure that menu is enabled if more than 1 program */\r
745     if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 )\r
746         Root->Enabled = true;\r
747 }\r
748 \r
749 /*****************************************************************************\r
750  * RadioMenu: update interactive menus of the interface\r
751  *****************************************************************************\r
752  * Sets up menus with information from input\r
753  * Warning: since this function is designed to be called by management\r
754  * function, the interface lock has to be taken\r
755  *****************************************************************************/\r
756 void __fastcall TMenusGen::RadioMenu( TMenuItem *Root, AnsiString ItemName,\r
757      int i_nb, int i_selected, TNotifyEvent MenuItemClick )\r
758 {\r
759     TMenuItem  * ItemGroup;\r
760     TMenuItem  * Item;\r
761     AnsiString   Name;\r
762 \r
763     /* remove previous menu */\r
764     Root->Enabled = false;\r
765     Root->Clear();\r
766 \r
767     for( int i_item = 1; i_item <= i_nb; i_item++ )\r
768     {\r
769         /* we group titles/chapters in packets of ten for small screens */\r
770         if( ( i_item % 10 == 1 ) && ( i_nb > 20 ) )\r
771         {\r
772             if( i_item != 1 )\r
773                 Root->Add( ItemGroup );\r
774 \r
775             Name.sprintf( "%ss %d to %d", ItemName, i_item, i_item + 9 );\r
776             ItemGroup = new TMenuItem( Root );\r
777             ItemGroup->Hint = Name;\r
778             ItemGroup->RadioItem = true;\r
779 \r
780             /* set the accelerator character */\r
781             Name.Insert( "&", Name.Length() - 1 );\r
782             ItemGroup->Caption = Name;\r
783         }\r
784 \r
785         Name.sprintf( "%s %d", ItemName, i_item );\r
786         Item = new TMenuItem( Root );\r
787         Item->RadioItem = true;\r
788         Item->Hint = Name;\r
789 \r
790         /* set the accelerator character */\r
791         Name.Insert( "&", Name.Length() );\r
792         Item->Caption = Name;\r
793 \r
794         /* FIXME: temporary hack to save i_item with the Item\r
795          * It will be used in the callback. */\r
796         Item->Tag = i_item;\r
797 \r
798         /* check the currently selected chapter */\r
799         if( i_selected == i_item )\r
800             Item->Checked = true;\r
801 \r
802         /* setup signal handling */\r
803         Item->OnClick = MenuItemClick;\r
804 \r
805         if( i_nb > 20 )\r
806             ItemGroup->Add( Item );\r
807         else\r
808             Root->Add( Item );\r
809     }\r
810 \r
811 //  if( ( i_nb > 20 ) && ( i_item % 10 ) )  ?\r
812     if( i_nb > 20 )\r
813         Root->Add( ItemGroup );\r
814 \r
815     /* be sure that menu is enabled, if there are several items */\r
816     if( i_nb > 1 )\r
817         Root->Enabled = true;\r
818 }\r
819 \r
820 /*****************************************************************************\r
821  * LanguageMenus: update interactive menus of the interface\r
822  *****************************************************************************\r
823  * Sets up menus with information from input:\r
824  *  - languages\r
825  *  - sub-pictures\r
826  * Warning: since this function is designed to be called by management\r
827  * function, the interface lock has to be taken\r
828  *****************************************************************************/\r
829 void __fastcall TMenusGen::LanguageMenu( TMenuItem *Root, es_descriptor_t *p_es,\r
830     int i_cat, TNotifyEvent MenuItemClick )\r
831 {\r
832     TMenuItem     * Separator;\r
833     TMenuItem     * Item;\r
834     AnsiString      Name;\r
835 \r
836     /* remove previous menu */\r
837     Root->Clear();\r
838     Root->Enabled = false;\r
839 \r
840     /* special case for "off" item */\r
841     Name = "None";\r
842     Item = new TMenuItem( Root );\r
843     Item->RadioItem = true;\r
844     Item->Hint = Name;\r
845     Item->Caption = Name;\r
846     Item->OnClick = MenuItemClick;\r
847     Item->Tag = -1;\r
848     Root->Add( Item );\r
849 \r
850     /* separator item */\r
851     Separator = new TMenuItem( Root );\r
852     Separator->Caption = "-";\r
853     Root->Add( Separator );\r
854 \r
855     int i_item = 0;\r
856 \r
857     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
858 \r
859 #define ES p_intf->p_sys->p_input->stream.pp_es[i]\r
860     /* create a set of language buttons and append them to the Root */\r
861     for( unsigned int i = 0; i < p_intf->p_sys->p_input->stream.i_es_number;\r
862          i++ )\r
863     {\r
864         if( ( ES->i_cat == i_cat ) &&\r
865             ( !ES->p_pgrm ||\r
866               ES->p_pgrm ==\r
867                 p_intf->p_sys->p_input->stream.p_selected_program ) )\r
868         {\r
869             i_item++;\r
870             Name = p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc;\r
871             if( Name.IsEmpty() )\r
872                 Name.sprintf( "Language %d", i_item );\r
873 \r
874             Item = new TMenuItem( Root );\r
875             Item->RadioItem = true;\r
876             Item->Hint = Name;\r
877             Item->Caption = Name;\r
878             Item->Tag = i;\r
879 \r
880             /* check the currently selected item */\r
881             if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )\r
882                 Item->Checked = true;\r
883 \r
884             /* setup signal hanling */\r
885             Item->OnClick = MenuItemClick;\r
886             Root->Add( Item );\r
887         }\r
888     }\r
889 #undef ES\r
890 \r
891     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
892 \r
893     /* be sure that menu is enabled if non empty */\r
894     if( i_item > 0 )\r
895         Root->Enabled = true;\r
896 }\r
897 \r
898 /*****************************************************************************\r
899  * NavigationMenu: sets menus for titles and chapters selection\r
900  *****************************************************************************\r
901  * Generates two types of menus:\r
902  *  -simple list of titles\r
903  *  -cascaded lists of chapters for each title\r
904  *****************************************************************************/\r
905 void __fastcall TMenusGen::NavigationMenu( TMenuItem *Root,\r
906     TNotifyEvent MenuItemClick )\r
907 {\r
908     TMenuItem     * TitleGroup;\r
909     TMenuItem     * TitleItem;\r
910     TMenuItem     * ChapterGroup;\r
911     TMenuItem     * ChapterItem;\r
912     AnsiString      Name;\r
913     unsigned int    i_title_nb;\r
914     unsigned int    i_chapter_nb;\r
915 \r
916 \r
917     /* remove previous menu */\r
918     Root->Enabled = false;\r
919     Root->Clear();\r
920 \r
921     i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb - 1;\r
922 \r
923     /* loop on titles */\r
924     for( unsigned int i_title = 1; i_title <= i_title_nb; i_title++ )\r
925     {\r
926         /* we group titles in packets of ten for small screens */\r
927         if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )\r
928         {\r
929             if( i_title != 1 )\r
930                 Root->Add( TitleGroup );\r
931 \r
932             Name.sprintf( "%d - %d", i_title, i_title + 9 );\r
933             TitleGroup = new TMenuItem( Root );\r
934             TitleGroup->RadioItem = true;\r
935             TitleGroup->Hint = Name;\r
936             TitleGroup->Caption = Name;\r
937         }\r
938 \r
939         Name.sprintf( "Title %d (%d)", i_title,\r
940             p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1 );\r
941         {\r
942             TitleItem = new TMenuItem( Root );\r
943             TitleItem->RadioItem = true;\r
944             TitleItem->Hint = Name;\r
945             TitleItem->Caption = Name;\r
946 \r
947             i_chapter_nb =\r
948                 p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1;\r
949 \r
950             /* loop on chapters */\r
951             for( unsigned int i_chapter = 1; i_chapter <= i_chapter_nb;\r
952                  i_chapter++ )\r
953             {\r
954                 /* we group chapters in packets of ten for small screens */\r
955                 if( ( i_chapter % 10 == 1 ) && ( i_chapter_nb > 20 ) )\r
956                 {\r
957                     if( i_chapter != 1 )\r
958                         TitleItem->Add( ChapterGroup );\r
959 \r
960                     Name.sprintf( "%d - %d", i_chapter, i_chapter + 9 );\r
961                     ChapterGroup = new TMenuItem( TitleItem );\r
962                     ChapterGroup->RadioItem = true;\r
963                     ChapterGroup->Hint = Name;\r
964                     ChapterGroup->Caption = Name;\r
965                 }\r
966 \r
967                 Name.sprintf( "Chapter %d", i_chapter );\r
968 \r
969                 ChapterItem = new TMenuItem( TitleItem );\r
970                 ChapterItem->RadioItem = true;\r
971                 ChapterItem->Hint = Name;\r
972                 ChapterItem->Caption = Name;\r
973 \r
974                 /* FIXME: temporary hack to save i_title and i_chapter with\r
975                  * ChapterItem, since we will need them in the callback */\r
976                 ChapterItem->Tag = Pos2Data( i_title, i_chapter );\r
977 \r
978 #define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]\r
979                 /* check the currently selected chapter */\r
980                 if( ( p_area ==\r
981                         p_intf->p_sys->p_input->stream.p_selected_area ) &&\r
982                     ( p_area->i_part == i_chapter ) )\r
983                 {\r
984                     ChapterItem->Checked = true;\r
985                 }\r
986 #undef p_area\r
987 \r
988                 /* setup signal handling */\r
989                 ChapterItem->OnClick = MenuItemClick;\r
990 \r
991                 if( i_chapter_nb > 20 )\r
992                     ChapterGroup->Add( ChapterItem );\r
993                 else\r
994                     TitleItem->Add( ChapterItem );\r
995             }\r
996 \r
997             if( i_chapter_nb > 20 )\r
998             {\r
999                 TitleItem->Add( ChapterGroup );\r
1000             }\r
1001 \r
1002             if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb\r
1003                 > 1 )\r
1004             {\r
1005                 /* be sure that menu is sensitive */\r
1006                 Root->Enabled = true;\r
1007             }\r
1008         }\r
1009 \r
1010         if( i_title_nb > 20 )\r
1011             TitleGroup->Add( TitleItem );\r
1012         else\r
1013             Root->Add( TitleItem );\r
1014     }\r
1015 \r
1016     if( i_title_nb > 20 )\r
1017         Root->Add( TitleGroup );\r
1018 \r
1019     /* be sure that menu is sensitive */\r
1020     Root->Enabled = true;\r
1021 }\r
1022 \r