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