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