]> git.sesse.net Git - vlc/blobdiff - modules/gui/win32/menu.cpp
* src/misc/variables.c, ALL: improvements to the object variables api.
[vlc] / modules / gui / win32 / menu.cpp
index 1de6140c6c9703aa70cec7f238792022c26738d5..08c741bdd821715a171ac8c94111b0f6af563f0d 100644 (file)
@@ -1,7 +1,8 @@
 /*****************************************************************************\r
  * menu.cpp: functions to handle menu items\r
  *****************************************************************************\r
- * Copyright (C) 2002 VideoLAN\r
+ * Copyright (C) 2002-2003 VideoLAN\r
+ * $Id: menu.cpp,v 1.15 2003/05/04 22:42:16 gbazin Exp $\r
  *\r
  * Authors: Olivier Teuliere <ipkiss@via.ecp.fr>\r
  *\r
@@ -9,7 +10,7 @@
  * it under the terms of the GNU General Public License as published by\r
  * the Free Software Foundation; either version 2 of the License, or\r
  * (at your option) any later version.\r
- * \r
+ *\r
  * This program is distributed in the hope that it will be useful,\r
  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
@@ -21,7 +22,6 @@
  *****************************************************************************/\r
 \r
 #include <vcl.h>\r
-//#pragma hdrstop\r
 \r
 #include <vlc/vlc.h>\r
 #include <vlc/intf.h>\r
 #include "menu.h"\r
 #include "win32_common.h"\r
 \r
-\r
-/****************************************************************************\r
- * Local Prototypes\r
+/*****************************************************************************\r
+ * TMenusGen::*Click: callbacks for the menuitems\r
  ****************************************************************************/\r
-extern  intf_thread_t *p_intfGlobal;\r
-\r
-static TMenuItem *Index2Item( TMenuItem *, int, bool );\r
-static int Item2Index( TMenuItem *, TMenuItem * );\r
-static void __fastcall LangChange( TMenuItem *, TMenuItem *, TMenuItem *, int );\r
-static void __fastcall ProgramChange( TMenuItem *, TMenuItem * );\r
-\r
-static void __fastcall RadioMenu( TMenuItem *, AnsiString,\r
-                                  int, int, TNotifyEvent );\r
-static void __fastcall ProgramMenu( TMenuItem *, pgrm_descriptor_t *,\r
-                                    TNotifyEvent );\r
-static void __fastcall LanguageMenu( TMenuItem *t, es_descriptor_t *,\r
-                                     int, TNotifyEvent );\r
-static void __fastcall NavigationMenu( TMenuItem *, TNotifyEvent );\r
 \r
+/*\r
+ * Variables\r
+ */\r
 \r
-static TMenuItem *Index2Item( TMenuItem *Root, int i_index, bool SingleColumn )\r
+/* variables of the audio output */\r
+void __fastcall TMenusGen::AoutVarClick( TObject *Sender )\r
 {\r
-    if( SingleColumn || ( i_index < 20 ) )\r
-    {\r
-        return Root->Items[i_index];\r
-    }\r
-    else\r
+    TMenuItem * Item = (TMenuItem *)Sender;\r
+\r
+    vlc_object_t * p_aout;\r
+    p_aout = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,\r
+                                              FIND_ANYWHERE );\r
+    if( p_aout == NULL )\r
     {\r
-        return Root->Items[i_index / 10]->Items[i_index % 10];\r
+        msg_Warn( p_intf, "cannot set variable (%s)", Item->Caption.c_str() );\r
+        return;\r
     }\r
-}\r
 \r
-static int Item2Index( TMenuItem *Root, TMenuItem *Item )\r
-{\r
-    if( Item->Parent == Root )\r
+#error fixme! look at rc.c line 823\r
+    if( Item->Parent == MenuADevice || Item->Parent == PopupADevice )\r
     {\r
-        return Item->MenuIndex;\r
+        VarChange( p_aout, "audio-device", MenuADevice, PopupADevice, Item );\r
     }\r
-    else\r
+    else if( Item->Parent == MenuChannel || Item->Parent == PopupChannel )\r
     {\r
-        return( 10 * Item->Parent->MenuIndex + Item->MenuIndex );\r
+        VarChange( p_aout, "audio-channels", MenuChannel, PopupChannel, Item );\r
     }\r
-}\r
 \r
+    vlc_object_release( p_aout );\r
+}\r
 \r
-/****************************************************************************\r
- * LangChange: change audio or subtitles languages\r
- ****************************************************************************\r
- * Toggle the language, and update the selected menuitems.\r
- ****************************************************************************/\r
-static void __fastcall LangChange( TMenuItem *RootCurrent, TMenuItem *Item,\r
-                                   TMenuItem *RootOther, int i_cat )\r
+/* variables of the video output */\r
+void __fastcall TMenusGen::VoutVarClick( TObject *Sender )\r
 {\r
-    intf_thread_t         * p_intf = p_intfGlobal;\r
-    es_descriptor_t       * p_es;\r
-    es_descriptor_t       * p_es_old;\r
-    int                     i_index;\r
-    int                     i_es;\r
+    TMenuItem * Item = (TMenuItem *)Sender;\r
 \r
-    /* find the selected ES */\r
-    i_es = Item->Tag;\r
-\r
-    /* find selected menu item */\r
-    i_index = Item2Index( RootCurrent, Item ) - 1;\r
-    if( i_index < 0 )\r
-    {\r
-        /* 'None' was selected */\r
-        p_es = NULL;\r
-    }\r
-    else\r
+    vlc_object_t * p_vout;\r
+    p_vout = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,\r
+                                              FIND_ANYWHERE );\r
+    if( p_vout == NULL )\r
     {\r
-        vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-        p_es = p_intfGlobal->p_sys->p_input->stream.pp_es[i_es];\r
-        vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
+        msg_Warn( p_intf, "cannot set variable (%s)", Item->Caption.c_str() );\r
+        return;\r
     }\r
 \r
-    /* find the current ES */\r
-    if( i_cat == AUDIO_ES )\r
-    {\r
-        p_es_old = p_intf->p_sys->p_audio_es_old;\r
-        p_intf->p_sys->p_audio_es_old = p_es;\r
-    }\r
-    else\r
+    if( Item->Parent == MenuVDevice || Item->Parent == PopupVDevice )\r
     {\r
-        p_es_old = p_intf->p_sys->p_spu_es_old;\r
-        p_intf->p_sys->p_spu_es_old = p_es;\r
+        VarChange( p_vout, "video-device", MenuVDevice, PopupVDevice, Item );\r
     }\r
 \r
-    /* exchange them */\r
-    input_ToggleES( p_intfGlobal->p_sys->p_input, p_es_old, false );\r
-    input_ToggleES( p_intfGlobal->p_sys->p_input, p_es, true );\r
-\r
-    Item->Checked = true;\r
-    Index2Item( RootOther, i_index + 1, true )->Checked = true;\r
+    vlc_object_release( p_vout );\r
 }\r
 \r
+/*\r
+ * Modules\r
+ */\r
 \r
-/****************************************************************************\r
- * ProgramChange: change the program\r
- ****************************************************************************\r
- * Toggle the program, and update the selected menuitems.\r
- ****************************************************************************/\r
-static void __fastcall ProgramChange( TMenuItem *Item, TMenuItem *RootOther )\r
+/* Interface modules: we spawn a new interface */\r
+void __fastcall TMenusGen::InterfaceModuleClick( TObject *Sender )\r
 {\r
-    intf_thread_t * p_intf = p_intfGlobal;\r
-    int             i_program = Item->Tag;\r
-\r
-    /* toggle the program */\r
-    input_ChangeProgram( p_intfGlobal->p_sys->p_input, (u16)i_program );\r
+    TMenuItem * Item = (TMenuItem *)Sender;\r
 \r
-    /* check selected menu items */\r
-    Item->Checked = true;\r
-    Index2Item( RootOther, i_program - 1, true )->Checked = true;\r
+    AnsiString IntfName = CleanCaption( Item->Caption );\r
 \r
-    /* update audio/subtitles menus */\r
-    p_intf->p_sys->b_audio_update = 1;\r
-    p_intf->p_sys->b_spu_update = 1;\r
-    vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-    SetupMenus( p_intf );\r
-    vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-    p_intf->p_sys->b_audio_update = 0;\r
-    p_intf->p_sys->b_spu_update = 0;\r
-\r
-    input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY );\r
-}\r
+    intf_thread_t *p_newintf;\r
 \r
+    p_newintf = intf_Create( p_intf->p_vlc, IntfName.c_str() );\r
 \r
-/****************************************************************************\r
- * TMainFrameDlg::*Click: callbacks for the menuitems\r
- ****************************************************************************\r
- * These functions need to be in a class, or we won't be able to pass them\r
- * as arguments (since TNotifyEvent uses __closure)\r
- ****************************************************************************/\r
+    if( p_newintf )\r
+    {\r
+        p_newintf->b_block = VLC_FALSE;\r
+        if( intf_RunThread( p_newintf ) )\r
+        {\r
+            vlc_object_detach( p_newintf );\r
+            intf_Destroy( p_newintf );\r
+        }\r
+    }\r
+}\r
 \r
- /*\r
+/*\r
  * Audio\r
  */\r
 \r
-void __fastcall TMainFrameDlg::MenuAudioClick( TObject *Sender )\r
+void __fastcall TMenusGen::MenuLanguageClick( TObject *Sender )\r
 {\r
-    LangChange( MenuAudio, (TMenuItem *)Sender, PopupAudio, AUDIO_ES );\r
+    LangChange( MenuLanguage, (TMenuItem *)Sender, PopupLanguage, AUDIO_ES );\r
 }\r
 \r
-void __fastcall TMainFrameDlg::PopupAudioClick( TObject *Sender )\r
+void __fastcall TMenusGen::PopupLanguageClick( TObject *Sender )\r
 {\r
-    LangChange( PopupAudio, (TMenuItem *)Sender, MenuAudio, AUDIO_ES );\r
+    LangChange( PopupLanguage, (TMenuItem *)Sender, MenuLanguage, AUDIO_ES );\r
 }\r
 \r
 /*\r
  * Subtitles\r
  */\r
 \r
-void __fastcall TMainFrameDlg::MenuSubtitleClick( TObject *Sender )\r
+void __fastcall TMenusGen::MenuSubtitleClick( TObject *Sender )\r
 {\r
     LangChange( MenuSubtitles, (TMenuItem *)Sender, PopupSubtitles, SPU_ES );\r
 }\r
 \r
-void __fastcall TMainFrameDlg::PopupSubtitleClick( TObject *Sender )\r
+void __fastcall TMenusGen::PopupSubtitleClick( TObject *Sender )\r
 {\r
     LangChange( PopupSubtitles, (TMenuItem *)Sender, MenuSubtitles, SPU_ES );\r
 }\r
@@ -195,220 +144,584 @@ void __fastcall TMainFrameDlg::PopupSubtitleClick( TObject *Sender )
  * Program\r
  */\r
 \r
-void __fastcall TMainFrameDlg::MenuProgramClick( TObject *Sender )\r
+void __fastcall TMenusGen::MenuProgramClick( TObject *Sender )\r
 {\r
-    ProgramChange( (TMenuItem *)Sender, PopupProgram );\r
+   ProgramChange( (TMenuItem *)Sender, PopupProgram );\r
 }\r
 \r
-void __fastcall TMainFrameDlg::PopupProgramClick( TObject *Sender )\r
+void __fastcall TMenusGen::PopupProgramClick( TObject *Sender )\r
 {\r
     ProgramChange( (TMenuItem *)Sender, MenuProgram );\r
 }\r
 \r
 /*\r
- * Navigation\r
+ * Title\r
  */\r
 \r
-void __fastcall TMainFrameDlg::PopupNavigationClick( TObject *Sender )\r
+void __fastcall TMenusGen::MenuTitleClick( TObject *Sender )\r
 {\r
     TMenuItem     * Item = (TMenuItem *)Sender;\r
     TMenuItem     * ItemTitle;\r
     input_area_t  * p_area;\r
-    int             i_title   = DATA2TITLE( Item->Tag );\r
-    int             i_chapter = DATA2CHAPTER( Item->Tag );\r
+    unsigned int    i_title = Item->Tag;\r
 \r
-    p_area = p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title];\r
-    p_area->i_part = i_chapter;\r
+    vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    i_title = __MIN( i_title,\r
+                     p_intf->p_sys->p_input->stream.i_area_nb - 1 );\r
+    i_title = __MAX( i_title, 1 );\r
+    p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];\r
+    vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
 \r
-    input_ChangeArea( p_intfGlobal->p_sys->p_input, (input_area_t*)p_area );\r
+    input_ChangeArea( p_intf->p_sys->p_input, p_area );\r
 \r
     Item->Checked = true;\r
-    ItemTitle = Index2Item( MenuTitle, i_title - 1, false );\r
-    if( ItemTitle->Checked )\r
-    {\r
-        /* same title, new chapter */\r
-        Index2Item( MenuChapter, i_chapter - 1, false )->Checked = true;\r
-    }\r
-    else\r
-    {\r
-        /* new title => we must rebuild the chapter menu */\r
-        vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-        RadioMenu( MenuChapter, "Chapter",\r
-                   p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part_nb,\r
-                   i_chapter, MenuChapterClick );\r
-        vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-    }\r
+    ItemTitle = Index2Item( PopupNavigation, i_title - 1, false );\r
+    Index2Item( ItemTitle, 0, false )->Checked = true;\r
 \r
-    input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY );\r
+    input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
 }\r
 \r
 /*\r
- * Title\r
+ * Chapter\r
  */\r
 \r
-void __fastcall TMainFrameDlg::MenuTitleClick( TObject *Sender )\r
+void __fastcall TMenusGen::MenuChapterClick( TObject *Sender )\r
 {\r
     TMenuItem     * Item = (TMenuItem *)Sender;\r
     TMenuItem     * ItemTitle;\r
-    int             i_title = Item->Tag;\r
+    input_area_t  * p_area;\r
+    unsigned int    i_title;\r
+    unsigned int    i_chapter = Item->Tag;\r
 \r
-    input_ChangeArea( p_intfGlobal->p_sys->p_input,\r
-                      p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title] );\r
-    Item->Checked = true;\r
-    ItemTitle = Index2Item( PopupNavigation, i_title - 1, false );\r
-    Index2Item( ItemTitle, 0, false )->Checked = true;\r
+    vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    p_area = p_intf->p_sys->p_input->stream.p_selected_area;\r
+    i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );\r
+    i_chapter = __MAX( i_chapter, 1 );\r
+    p_area->i_part = i_chapter;\r
+    vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
 \r
-    input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY );\r
+    input_ChangeArea( p_intf->p_sys->p_input, p_area );\r
+\r
+    vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    i_title = p_intf->p_sys->p_input->stream.p_selected_area->i_id;\r
+    vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+\r
+    ItemTitle = Index2Item( PopupNavigation, i_title, false );\r
+    Index2Item( ItemTitle, i_chapter, false )->Checked = true;\r
+\r
+    input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
 }\r
 \r
 /*\r
- * Chapter\r
+ * Navigation\r
  */\r
 \r
-void __fastcall TMainFrameDlg::MenuChapterClick( TObject *Sender )\r
+void __fastcall TMenusGen::PopupNavigationClick( TObject *Sender )\r
 {\r
     TMenuItem     * Item = (TMenuItem *)Sender;\r
     TMenuItem     * ItemTitle;\r
     input_area_t  * p_area;\r
-    int             i_title;\r
-    int             i_chapter = Item->Tag;\r
-\r
-    p_area = p_intfGlobal->p_sys->p_input->stream.p_selected_area;\r
+    unsigned int    i_title   = Data2Title( Item->Tag );\r
+    unsigned int    i_chapter = Data2Chapter( Item->Tag );\r
+\r
+    vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    i_title = __MIN( i_title,\r
+                     p_intf->p_sys->p_input->stream.i_area_nb - 1 );\r
+    i_title = __MAX( i_title, 1 );\r
+    p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title];\r
+    i_chapter = __MIN( i_chapter, p_area->i_part_nb - 1 );\r
+    i_chapter = __MAX( i_chapter, 1 );\r
     p_area->i_part = i_chapter;\r
+    vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
 \r
-    input_ChangeArea( p_intfGlobal->p_sys->p_input, (input_area_t*)p_area );\r
+    input_ChangeArea( p_intf->p_sys->p_input, p_area );\r
 \r
-    i_title = p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_id;\r
-    ItemTitle = Index2Item( PopupNavigation, i_title - 1, false );\r
-    Index2Item( ItemTitle, i_chapter - 1, false )->Checked = true;\r
+    Item->Checked = true;\r
+    ItemTitle = Index2Item( MenuTitle, i_title, false );\r
+    if( ItemTitle->Checked )\r
+    {\r
+        /* same title, new chapter */\r
+        Index2Item( MenuChapter, i_chapter, false )->Checked = true;\r
+    }\r
+    else\r
+    {\r
+        /* new title => we must rebuild the chapter menu */\r
+        vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+        RadioMenu(\r
+            MenuChapter, "Chapter",\r
+            p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb,\r
+            i_chapter, MenuChapterClick );\r
+        vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    }\r
 \r
-    input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY );\r
+    input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
 }\r
 \r
 \r
-/****************************************************************************\r
- * Functions to generate menus\r
- ****************************************************************************/\r
+__fastcall TMenusGen::TMenusGen( intf_thread_t *_p_intf ) : TObject()\r
+{\r
+    p_intf = _p_intf;\r
+\r
+    /* Initialize local pointers to menu items of the main window */\r
+    TMainFrameDlg * p_window = p_intf->p_sys->p_window;\r
+    if( p_window == NULL )\r
+    {\r
+        msg_Warn( p_intf, "Main window wasn't created, expect problems..." );\r
+        return;\r
+    }\r
+\r
+    MenuChannel = p_window->MenuChannel;\r
+    PopupChannel = p_window->PopupChannel;\r
+    MenuADevice = p_window->MenuADevice;\r
+    PopupADevice = p_window->PopupADevice;\r
+    MenuVDevice = p_window->MenuVDevice;\r
+    PopupVDevice = p_window->PopupVDevice;\r
+    MenuLanguage = p_window->MenuLanguage;\r
+    PopupLanguage = p_window->PopupLanguage;\r
+    MenuSubtitles = p_window->MenuSubtitles;\r
+    PopupSubtitles = p_window->PopupSubtitles;\r
+    MenuProgram = p_window->MenuProgram;\r
+    PopupProgram = p_window->PopupProgram;\r
+    MenuTitle = p_window->MenuTitle;\r
+    MenuChapter = p_window->MenuChapter;\r
+    PopupNavigation = p_window->PopupNavigation;\r
+    MenuAddInterface = p_window->MenuAddInterface;\r
+\r
+    /* Create the "Add interface" menu */\r
+    SetupModuleMenu( "interface", MenuAddInterface, InterfaceModuleClick );\r
+}\r
+\r
 \r
 /*****************************************************************************\r
- * RadioMenu: update interactive menus of the interface\r
+ * SetupMenus: This function dynamically generates some menus\r
  *****************************************************************************\r
- * Sets up menus with information from input\r
- * Warning: since this function is designed to be called by management\r
- * function, the interface lock has to be taken\r
+ * The lock on p_input->stream must be taken before you call this function\r
  *****************************************************************************/\r
-static void __fastcall RadioMenu( TMenuItem * Root, AnsiString ItemName,\r
-                                  int i_nb, int i_selected,\r
-                                  TNotifyEvent MenuItemClick )\r
+void __fastcall TMenusGen::SetupMenus()\r
 {\r
-    TMenuItem     * ItemGroup;\r
-    TMenuItem     * Item;\r
-    TMenuItem     * ItemActive;\r
-    AnsiString      Name;\r
-    int             i_item;\r
-\r
-    /* remove previous menu */\r
-    Root->Enabled = false;\r
-    Root->Clear();\r
+    TMainFrameDlg  * p_window = p_intf->p_sys->p_window;\r
+    input_thread_t * p_input  = p_intf->p_sys->p_input;\r
+    es_descriptor_t   * p_audio_es;\r
+    es_descriptor_t   * p_spu_es;\r
 \r
-    ItemActive = NULL;\r
+    p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;\r
+    p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_program_update |\r
+                                     p_intf->p_sys->b_title_update;\r
+    p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_program_update |\r
+                                   p_intf->p_sys->b_title_update;\r
 \r
-    for( i_item = 0; i_item < i_nb; i_item++ )\r
+    if( p_intf->p_sys->b_program_update )\r
     {\r
-        /* we group titles/chapters in packets of ten for small screens */\r
-        if( ( i_item % 10 == 0 ) && ( i_nb > 20 ) )\r
+        pgrm_descriptor_t * p_pgrm;\r
+\r
+        if( p_input->stream.p_new_program )\r
         {\r
-            if( i_item != 0 )\r
-            {\r
-                Root->Add( ItemGroup );\r
-            }\r
+            p_pgrm = p_input->stream.p_new_program;\r
+        }\r
+        else\r
+        {\r
+            p_pgrm = p_input->stream.p_selected_program;\r
+        }\r
 \r
-            Name.sprintf( "%ss %d to %d", ItemName, i_item + 1, i_item + 10 );\r
-            ItemGroup = new TMenuItem( Root );\r
-            ItemGroup->Hint = Name;\r
+        ProgramMenu( MenuProgram, p_pgrm, MenuProgramClick );\r
+        ProgramMenu( PopupProgram, p_pgrm, PopupProgramClick );\r
 \r
-            /* set the accelerator character */\r
-            Name.Insert( "&", Name.Length() - 1 );\r
-            ItemGroup->Caption = Name;\r
-        }\r
+        p_intf->p_sys->b_program_update = VLC_FALSE;\r
+    }\r
 \r
-        Name.sprintf( "%s %d", ItemName, i_item + 1 );\r
-        Item = new TMenuItem( Root );\r
-        Item->RadioItem = true;\r
-        Item->Hint = Name;\r
+    if( p_intf->p_sys->b_title_update )\r
+    {\r
+// why "-1" ?\r
+// because if the titles go from 1 to X-1, there are X-1 titles\r
+        RadioMenu( MenuTitle, "Title",\r
+                   p_input->stream.i_area_nb - 1,\r
+                   p_input->stream.p_selected_area->i_id,\r
+                   MenuTitleClick );\r
 \r
-        /* set the accelerator character */\r
-        Name.Insert( "&", Name.Length() );\r
-        Item->Caption = Name;\r
+        AnsiString CurrentTitle;\r
+        CurrentTitle.sprintf( "%d", p_input->stream.p_selected_area->i_id );\r
+        p_window->LabelTitleCurrent->Caption = CurrentTitle;\r
 \r
-        /* FIXME: temporary hack to save i_item with the Item\r
-         * It will be used in the callback. */\r
-        Item->Tag = i_item + 1;\r
+        p_intf->p_sys->b_title_update = VLC_FALSE;\r
+    }\r
+\r
+    if( p_intf->p_sys->b_chapter_update )\r
+    {\r
+        RadioMenu( MenuChapter, "Chapter",\r
+                   p_input->stream.p_selected_area->i_part_nb - 1,\r
+                   p_input->stream.p_selected_area->i_part,\r
+                   MenuChapterClick );\r
+\r
+        NavigationMenu( PopupNavigation, PopupNavigationClick );\r
+\r
+        AnsiString CurrentChapter;\r
+        CurrentChapter.sprintf( "%d", p_input->stream.p_selected_area->i_part );\r
+        p_window->LabelChapterCurrent->Caption = CurrentChapter;\r
+\r
+        p_intf->p_sys->i_part = p_input->stream.p_selected_area->i_part;\r
+\r
+        p_intf->p_sys->b_chapter_update = VLC_FALSE;\r
+    }\r
+\r
+    /* look for selected ES */\r
+    p_audio_es = NULL;\r
+    p_spu_es = NULL;\r
 \r
-        if( i_selected == i_item + 1 )\r
+    for( unsigned int i = 0; i < p_input->stream.i_selected_es_number; i++ )\r
+    {\r
+        if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )\r
         {\r
-            ItemActive = Item;\r
+            p_audio_es = p_input->stream.pp_selected_es[i];\r
         }\r
-        \r
-        /* setup signal handling */\r
-        Item->OnClick = MenuItemClick;\r
 \r
-        if( i_nb > 20 )\r
+        if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )\r
         {\r
-            ItemGroup->Add( Item );\r
+            p_spu_es = p_input->stream.pp_selected_es[i];\r
         }\r
-        else\r
+    }\r
+    this->p_audio_es_old = p_audio_es;\r
+    this->p_spu_es_old = p_spu_es;\r
+\r
+    vlc_mutex_unlock( &p_input->stream.stream_lock );\r
+\r
+    /* audio menus */\r
+    if( p_intf->p_sys->b_audio_update )\r
+    {\r
+        LanguageMenu( MenuLanguage, p_audio_es, AUDIO_ES, MenuLanguageClick );\r
+        LanguageMenu( PopupLanguage, p_audio_es, AUDIO_ES, PopupLanguageClick );\r
+\r
+        p_intf->p_sys->b_audio_update = VLC_FALSE;\r
+    }\r
+\r
+    /* sub picture menus */\r
+    if( p_intf->p_sys->b_spu_update )\r
+    {\r
+        LanguageMenu( PopupSubtitles, p_spu_es, SPU_ES, PopupSubtitleClick );\r
+        LanguageMenu( MenuSubtitles, p_spu_es, SPU_ES, MenuSubtitleClick );\r
+\r
+        p_intf->p_sys->b_spu_update = VLC_FALSE;\r
+    }\r
+\r
+    if( p_intf->p_sys->b_aout_update )\r
+    {\r
+        aout_instance_t * p_aout;\r
+        p_aout = (aout_instance_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,\r
+                                                     FIND_ANYWHERE );\r
+\r
+        if( p_aout != NULL )\r
         {\r
-            Root->Add( Item );\r
+            vlc_value_t val;\r
+            val.b_bool = VLC_FALSE;\r
+\r
+            var_Set( (vlc_object_t *)p_aout, "intf-change", val );\r
+\r
+#error fixme! look at rc.c line 823\r
+            SetupVarMenu( (vlc_object_t *)p_aout, "audio-channels",\r
+                          MenuChannel, AoutVarClick );\r
+            SetupVarMenu( (vlc_object_t *)p_aout, "audio-channels",\r
+                          PopupChannel, AoutVarClick );\r
+\r
+            SetupVarMenu( (vlc_object_t *)p_aout, "audio-device",\r
+                          MenuADevice, AoutVarClick );\r
+            SetupVarMenu( (vlc_object_t *)p_aout, "audio-device",\r
+                          PopupADevice, AoutVarClick );\r
+\r
+            vlc_object_release( (vlc_object_t *)p_aout );\r
         }\r
+\r
+        p_intf->p_sys->b_aout_update = VLC_FALSE;\r
     }\r
 \r
-//  if( ( i_nb > 20 ) && ( i_item % 10 ) )  ?\r
-    if( i_nb > 20 )\r
+    if( p_intf->p_sys->b_vout_update )\r
     {\r
-        Root->Add( ItemGroup );\r
+        vout_thread_t * p_vout;\r
+        p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,\r
+                                                   FIND_ANYWHERE );\r
+\r
+        if( p_vout != NULL )\r
+        {\r
+            vlc_value_t val;\r
+            val.b_bool = VLC_FALSE;\r
+\r
+            var_Set( (vlc_object_t *)p_vout, "intf-change", val );\r
+\r
+            SetupVarMenu( (vlc_object_t *)p_vout, "video-device",\r
+                          MenuVDevice, VoutVarClick );\r
+            SetupVarMenu( (vlc_object_t *)p_vout, "video-device",\r
+                          PopupVDevice, VoutVarClick );\r
+\r
+            vlc_object_release( (vlc_object_t *)p_vout );\r
+        }\r
+\r
+        p_intf->p_sys->b_vout_update = VLC_FALSE;\r
     }\r
 \r
-    /* check currently selected chapter */\r
-    if( ItemActive != NULL )\r
+    vlc_mutex_lock( &p_input->stream.stream_lock );\r
+}\r
+\r
+\r
+/*****************************************************************************\r
+ * Private functions\r
+ *****************************************************************************/\r
+TMenuItem * TMenusGen::Index2Item( TMenuItem *Root, int i_index,\r
+                                   bool SingleColumn )\r
+{\r
+    if( SingleColumn || ( i_index < 20 ) )\r
+        return Root->Items[i_index];\r
+    else\r
+        return Root->Items[i_index / 10]->Items[i_index % 10];\r
+}\r
+\r
+int TMenusGen::Item2Index( TMenuItem *Root, TMenuItem *Item )\r
+{\r
+    if( Item->Parent == Root )\r
+        return Item->MenuIndex;\r
+    else\r
+        return( 10 * Item->Parent->MenuIndex + Item->MenuIndex );\r
+}\r
+\r
+int __fastcall TMenusGen::Data2Title( int data )\r
+{\r
+    return (int) (data >> 16 );\r
+}\r
+\r
+int __fastcall TMenusGen::Data2Chapter( int data )\r
+{\r
+    return (int) (data & 0xffff);\r
+}\r
+\r
+int __fastcall TMenusGen::Pos2Data( int title, int chapter )\r
+{\r
+    return (int) (( title << 16 ) | ( chapter & 0xffff ));\r
+}\r
+\r
+/* This function deletes all the '&' characters in the caption string,\r
+ * because Borland automatically adds one when (and only when!) you click on\r
+ * the menuitem. Grrrrr... */\r
+AnsiString __fastcall TMenusGen::CleanCaption( AnsiString Caption )\r
+{\r
+    while( Caption.LastDelimiter( "&" ) != 0 )\r
     {\r
-        ItemActive->Checked = true;\r
+        Caption.Delete( Caption.LastDelimiter( "&" ), 1 );\r
     }\r
 \r
-    /* be sure that menu is enabled, if there are several items */\r
-    if( i_nb > 1 )\r
+    return Caption;\r
+}\r
+\r
+/****************************************************************************\r
+ * VarChange: change a variable in a vlc_object_t\r
+ ****************************************************************************\r
+ * Change the variable and update the menuitems.\r
+ ****************************************************************************/\r
+void __fastcall TMenusGen::VarChange( vlc_object_t *p_object,\r
+        const char *psz_variable, TMenuItem *RootMenu, TMenuItem *RootPopup,\r
+        TMenuItem *Item )\r
+{\r
+    vlc_value_t val;\r
+    int i_index;\r
+\r
+    AnsiString Caption = CleanCaption( Item->Caption );\r
+    val.psz_string = Caption.c_str();\r
+\r
+    /* set the new value */\r
+    if( var_Set( p_object, psz_variable, val ) < 0 )\r
     {\r
-        Root->Enabled = true;\r
+        msg_Warn( p_object, "cannot set variable (%s)", val.psz_string );\r
     }\r
+\r
+    i_index = Item->MenuIndex;\r
+    RootMenu->Items[i_index]->Checked = true;\r
+    RootPopup->Items[i_index]->Checked = true;\r
 }\r
 \r
+/****************************************************************************\r
+ * LangChange: change audio or subtitles languages\r
+ ****************************************************************************\r
+ * Toggle the language, and update the selected menuitems.\r
+ ****************************************************************************/\r
+void __fastcall TMenusGen::LangChange( TMenuItem *RootCurrent, TMenuItem *Item,\r
+    TMenuItem *RootOther, int i_cat )\r
+{\r
+    es_descriptor_t * p_es;\r
+    es_descriptor_t * p_es_old;\r
+    int i_index;\r
+    int i_es;\r
+\r
+    /* find the selected ES */\r
+    i_es = Item->Tag;\r
+\r
+    /* find selected menu item */\r
+    i_index = Item2Index( RootCurrent, Item ) - 1;\r
+    if( i_index < 0 )\r
+    {\r
+        /* 'None' was selected */\r
+        p_es = NULL;\r
+    }\r
+    else\r
+    {\r
+        vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+        p_es = p_intf->p_sys->p_input->stream.pp_es[i_es];\r
+        vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    }\r
+\r
+    /* find the current ES */\r
+    if( i_cat == AUDIO_ES )\r
+    {\r
+        p_es_old = this->p_audio_es_old;\r
+        this->p_audio_es_old = p_es;\r
+    }\r
+    else\r
+    {\r
+        p_es_old = this->p_spu_es_old;\r
+        this->p_spu_es_old = p_es;\r
+    }\r
+\r
+    /* exchange them */\r
+    input_ToggleES( p_intf->p_sys->p_input, p_es_old, false );\r
+    input_ToggleES( p_intf->p_sys->p_input, p_es, true );\r
+\r
+    Item->Checked = true;\r
+    Index2Item( RootOther, i_index + 1, true )->Checked = true;\r
+}\r
+\r
+/****************************************************************************\r
+ * ProgramChange: change the program\r
+ ****************************************************************************\r
+ * Toggle the program, and update the selected menuitems.\r
+ ****************************************************************************/\r
+void __fastcall TMenusGen::ProgramChange( TMenuItem *Item,\r
+                                          TMenuItem *RootOther )\r
+{\r
+    int i_program = Item->Tag;\r
+\r
+    /* toggle the program */\r
+    input_ChangeProgram( p_intf->p_sys->p_input, (uint16_t)i_program );\r
+\r
+    /* check selected menu items */\r
+    Item->Checked = true;\r
+    Index2Item( RootOther, i_program - 1, true )->Checked = true;\r
+\r
+    /* update audio/subtitles menus */\r
+    p_intf->p_sys->b_audio_update = VLC_TRUE;\r
+    p_intf->p_sys->b_spu_update = VLC_TRUE;\r
+    vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    SetupMenus();\r
+    vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
+    p_intf->p_sys->b_audio_update = VLC_FALSE;\r
+    p_intf->p_sys->b_spu_update = VLC_FALSE;\r
+\r
+    input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );\r
+}\r
+\r
+/*****************************************************************************\r
+ * SetupVarMenu: build a menu allowing to change a variable\r
+ *****************************************************************************/\r
+void __fastcall TMenusGen::SetupVarMenu( vlc_object_t *p_object,\r
+        const char *psz_variable, TMenuItem *Root, TNotifyEvent MenuItemClick )\r
+{\r
+    TMenuItem * Item;\r
+    vlc_value_t val;\r
+    char * psz_value = NULL;\r
+    int i;\r
+\r
+    /* remove previous menu */\r
+    Root->Clear();\r
+\r
+    /* get the current value */\r
+    if( var_Get( p_object, psz_variable, &val ) < 0 )\r
+    {\r
+        return;\r
+    }\r
+    psz_value = val.psz_string;\r
+\r
+    if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST, &val, NULL ) < 0 )\r
+    {\r
+        free( psz_value );\r
+        return;\r
+    }\r
+\r
+    /* append a menuitem for each option */\r
+    for( i = 0; i < val.p_list->i_count; i++ )\r
+    {\r
+        Item = new TMenuItem( Root );\r
+        Item->Caption = val.p_list->p_values[i].psz_string;\r
+        Item->Hint = val.p_list->p_values[i].psz_string;\r
+        Item->RadioItem = true;\r
+        Item->OnClick = MenuItemClick;\r
+        if( !strcmp( psz_value, val.p_list->p_values[i].psz_string ) )\r
+            Item->Checked = true;\r
+\r
+        /* Add the item to the submenu */\r
+        Root->Add( Item );\r
+    }\r
+\r
+    /* enable the menu if there is at least 1 item */\r
+    Root->Enabled = ( val.p_list->i_count > 0 );\r
+\r
+    /* clean up everything */\r
+    var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val, NULL );\r
+//    free( psz_value );\r
+}\r
+\r
+/*****************************************************************************\r
+ * SetupModuleMenu: build a menu listing all the modules of a given\r
+                    capability\r
+ *****************************************************************************/\r
+void __fastcall TMenusGen::SetupModuleMenu( const char *psz_capability,\r
+        TMenuItem *Root, TNotifyEvent MenuItemClick )\r
+{\r
+    module_t * p_parser;\r
+    vlc_list_t *p_list;\r
+    int i_index;\r
+\r
+    /* remove previous menu */\r
+    Root->Clear();\r
+    Root->Enabled = false;\r
+\r
+    p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );\r
+    for( i_index = 0; i_index < p_list->i_count; i_index++ )\r
+    {\r
+        p_parser = (module_t *)p_list->p_values[i_index].p_object ;\r
+\r
+        if( !strcmp( p_parser->psz_capability, psz_capability ) )\r
+        {\r
+            TMenuItem *Item = new TMenuItem( Root );\r
+            Item->Caption = p_parser->psz_object_name;\r
+            Item->Hint = Item->Caption;\r
+            Item->OnClick = MenuItemClick;\r
+            Root->Add( Item );\r
+        }\r
+    }\r
+\r
+    vlc_list_release( p_list );\r
+\r
+    /* be sure that menu is enabled, if there is at least one item */\r
+    if( i_index > 0 )\r
+        Root->Enabled = true;\r
+}\r
 \r
 /*****************************************************************************\r
  * ProgramMenu: update the programs menu of the interface\r
  *****************************************************************************\r
- * Builds the program menu according to what have been found in the PAT \r
+ * Builds the program menu according to what have been found in the PAT\r
  * by the input. Useful for multi-programs streams such as DVB ones.\r
  *****************************************************************************/\r
-static void __fastcall ProgramMenu( TMenuItem * Root,\r
-                                    pgrm_descriptor_t * p_pgrm,\r
-                                    TNotifyEvent MenuItemClick )\r
+void __fastcall TMenusGen::ProgramMenu( TMenuItem *Root,\r
+    pgrm_descriptor_t *p_pgrm, TNotifyEvent MenuItemClick )\r
 {\r
-    TMenuItem     * Item;\r
-    TMenuItem     * ItemActive;\r
-    AnsiString      Name;\r
-    int             i;\r
+    TMenuItem * Item;\r
 \r
     /* remove previous menu */\r
     Root->Clear();\r
     Root->Enabled = false;\r
 \r
-    ItemActive = NULL;\r
-\r
     /* create a set of program buttons and append them to the container */\r
-    for( i = 0; i < p_intfGlobal->p_sys->p_input->stream.i_pgrm_number; i++ )\r
+    for( unsigned int i = 0; i < p_intf->p_sys->p_input->stream.i_pgrm_number;\r
+         i++ )\r
     {\r
+        AnsiString Name;\r
         Name.sprintf( "id %d",\r
-            p_intfGlobal->p_sys->p_input->stream.pp_programs[i]->i_number );\r
+            p_intf->p_sys->p_input->stream.pp_programs[i]->i_number );\r
 \r
         Item = new TMenuItem( Root );\r
         Item->Caption = Name;\r
@@ -420,30 +733,90 @@ static void __fastcall ProgramMenu( TMenuItem * Root,
          * It will be used in the callback. */\r
         Item->Tag = i + 1;\r
 \r
-        if( p_pgrm == p_intfGlobal->p_sys->p_input->stream.pp_programs[i] )\r
-        {\r
-            /* don't lose Item when we append into menu */\r
-            ItemActive = Item;\r
-        }\r
+        /* check the currently selected program */\r
+        if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] )\r
+            Item->Checked = true;\r
 \r
-        /* Add the item to the submenu */\r
+        /* add the item to the submenu */\r
         Root->Add( Item );\r
     }\r
 \r
-    /* check currently selected program */\r
-    if( ItemActive != NULL )\r
+    /* be sure that menu is enabled if more than 1 program */\r
+    if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 )\r
+        Root->Enabled = true;\r
+}\r
+\r
+/*****************************************************************************\r
+ * RadioMenu: update interactive menus of the interface\r
+ *****************************************************************************\r
+ * Sets up menus with information from input\r
+ * Warning: since this function is designed to be called by management\r
+ * function, the interface lock has to be taken\r
+ *****************************************************************************/\r
+void __fastcall TMenusGen::RadioMenu( TMenuItem *Root, AnsiString ItemName,\r
+     int i_nb, int i_selected, TNotifyEvent MenuItemClick )\r
+{\r
+    TMenuItem  * ItemGroup;\r
+    TMenuItem  * Item;\r
+    AnsiString   Name;\r
+\r
+    /* remove previous menu */\r
+    Root->Enabled = false;\r
+    Root->Clear();\r
+\r
+    for( int i_item = 1; i_item <= i_nb; i_item++ )\r
     {\r
-        ItemActive->Checked = true;\r
+        /* we group titles/chapters in packets of ten for small screens */\r
+        if( ( i_item % 10 == 1 ) && ( i_nb > 20 ) )\r
+        {\r
+            if( i_item != 1 )\r
+                Root->Add( ItemGroup );\r
+\r
+            Name.sprintf( "%ss %d to %d", ItemName, i_item, i_item + 9 );\r
+            ItemGroup = new TMenuItem( Root );\r
+            ItemGroup->Hint = Name;\r
+            ItemGroup->RadioItem = true;\r
+\r
+            /* set the accelerator character */\r
+            Name.Insert( "&", Name.Length() - 1 );\r
+            ItemGroup->Caption = Name;\r
+        }\r
+\r
+        Name.sprintf( "%s %d", ItemName, i_item );\r
+        Item = new TMenuItem( Root );\r
+        Item->RadioItem = true;\r
+        Item->Hint = Name;\r
+\r
+        /* set the accelerator character */\r
+        Name.Insert( "&", Name.Length() );\r
+        Item->Caption = Name;\r
+\r
+        /* FIXME: temporary hack to save i_item with the Item\r
+         * It will be used in the callback. */\r
+        Item->Tag = i_item;\r
+\r
+        /* check the currently selected chapter */\r
+        if( i_selected == i_item )\r
+            Item->Checked = true;\r
+\r
+        /* setup signal handling */\r
+        Item->OnClick = MenuItemClick;\r
+\r
+        if( i_nb > 20 )\r
+            ItemGroup->Add( Item );\r
+        else\r
+            Root->Add( Item );\r
     }\r
 \r
-    /* be sure that menu is enabled if more than 1 program */\r
-    if( p_intfGlobal->p_sys->p_input->stream.i_pgrm_number > 1 )\r
-    {\r
+//  if( ( i_nb > 20 ) && ( i_item % 10 ) )  ?\r
+    if( i_nb > 20 )\r
+        Root->Add( ItemGroup );\r
+\r
+    /* be sure that menu is enabled, if there are several items */\r
+    if( i_nb > 1 )\r
         Root->Enabled = true;\r
-    }\r
 }\r
 \r
-\r
 /*****************************************************************************\r
  * LanguageMenus: update interactive menus of the interface\r
  *****************************************************************************\r
@@ -453,15 +826,12 @@ static void __fastcall ProgramMenu( TMenuItem * Root,
  * Warning: since this function is designed to be called by management\r
  * function, the interface lock has to be taken\r
  *****************************************************************************/\r
-static void __fastcall LanguageMenu( TMenuItem * Root, es_descriptor_t * p_es,\r
-                                      int i_cat, TNotifyEvent MenuItemClick )\r
+void __fastcall TMenusGen::LanguageMenu( TMenuItem *Root, es_descriptor_t *p_es,\r
+    int i_cat, TNotifyEvent MenuItemClick )\r
 {\r
     TMenuItem     * Separator;\r
     TMenuItem     * Item;\r
-    TMenuItem     * ItemActive;\r
     AnsiString      Name;\r
-    int             i_item;\r
-    int             i;\r
 \r
     /* remove previous menu */\r
     Root->Clear();\r
@@ -482,26 +852,24 @@ static void __fastcall LanguageMenu( TMenuItem * Root, es_descriptor_t * p_es,
     Separator->Caption = "-";\r
     Root->Add( Separator );\r
 \r
-    ItemActive = NULL;\r
-    i_item = 0;\r
+    int i_item = 0;\r
 \r
-    vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
+    vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );\r
 \r
-#define ES p_intfGlobal->p_sys->p_input->stream.pp_es[i]\r
+#define ES p_intf->p_sys->p_input->stream.pp_es[i]\r
     /* create a set of language buttons and append them to the Root */\r
-    for( i = 0; i < p_intfGlobal->p_sys->p_input->stream.i_es_number; i++ )\r
+    for( unsigned int i = 0; i < p_intf->p_sys->p_input->stream.i_es_number;\r
+         i++ )\r
     {\r
         if( ( ES->i_cat == i_cat ) &&\r
             ( !ES->p_pgrm ||\r
               ES->p_pgrm ==\r
-                 p_intfGlobal->p_sys->p_input->stream.p_selected_program ) )\r
+                p_intf->p_sys->p_input->stream.p_selected_program ) )\r
         {\r
             i_item++;\r
-            Name = p_intfGlobal->p_sys->p_input->stream.pp_es[i]->psz_desc;\r
+            Name = p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc;\r
             if( Name.IsEmpty() )\r
-            {\r
                 Name.sprintf( "Language %d", i_item );\r
-            }\r
 \r
             Item = new TMenuItem( Root );\r
             Item->RadioItem = true;\r
@@ -509,11 +877,9 @@ static void __fastcall LanguageMenu( TMenuItem * Root, es_descriptor_t * p_es,
             Item->Caption = Name;\r
             Item->Tag = i;\r
 \r
-            if( p_es == p_intfGlobal->p_sys->p_input->stream.pp_es[i] )\r
-            {\r
-                /* don't lose Item when we append into menu */\r
-                ItemActive = Item;\r
-            }\r
+            /* check the currently selected item */\r
+            if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )\r
+                Item->Checked = true;\r
 \r
             /* setup signal hanling */\r
             Item->OnClick = MenuItemClick;\r
@@ -522,22 +888,13 @@ static void __fastcall LanguageMenu( TMenuItem * Root, es_descriptor_t * p_es,
     }\r
 #undef ES\r
 \r
-    vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-\r
-    /* check currently selected item */\r
-    if( ItemActive != NULL )\r
-    {\r
-        ItemActive->Checked = true;\r
-    }\r
+    vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );\r
 \r
     /* be sure that menu is enabled if non empty */\r
     if( i_item > 0 )\r
-    {\r
         Root->Enabled = true;\r
-    }\r
 }\r
 \r
-\r
 /*****************************************************************************\r
  * NavigationMenu: sets menus for titles and chapters selection\r
  *****************************************************************************\r
@@ -545,38 +902,32 @@ static void __fastcall LanguageMenu( TMenuItem * Root, es_descriptor_t * p_es,
  *  -simple list of titles\r
  *  -cascaded lists of chapters for each title\r
  *****************************************************************************/\r
-static void __fastcall NavigationMenu( TMenuItem * Root,\r
-                                       TNotifyEvent MenuItemClick )\r
+void __fastcall TMenusGen::NavigationMenu( TMenuItem *Root,\r
+    TNotifyEvent MenuItemClick )\r
 {\r
     TMenuItem     * TitleGroup;\r
     TMenuItem     * TitleItem;\r
-    TMenuItem     * ItemActive;\r
     TMenuItem     * ChapterGroup;\r
     TMenuItem     * ChapterItem;\r
     AnsiString      Name;\r
-    int             i_title;\r
-    int             i_chapter;\r
-    int             i_title_nb;\r
-    int             i_chapter_nb;\r
+    unsigned int    i_title_nb;\r
+    unsigned int    i_chapter_nb;\r
 \r
 \r
     /* remove previous menu */\r
     Root->Enabled = false;\r
     Root->Clear();\r
 \r
-    ItemActive = NULL;\r
-    i_title_nb = p_intfGlobal->p_sys->p_input->stream.i_area_nb;\r
-    \r
+    i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb - 1;\r
+\r
     /* loop on titles */\r
-    for( i_title = 1; i_title < i_title_nb; i_title++ )\r
+    for( unsigned int i_title = 1; i_title <= i_title_nb; i_title++ )\r
     {\r
         /* we group titles in packets of ten for small screens */\r
         if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) )\r
         {\r
             if( i_title != 1 )\r
-            {\r
                 Root->Add( TitleGroup );\r
-            }\r
 \r
             Name.sprintf( "%d - %d", i_title, i_title + 9 );\r
             TitleGroup = new TMenuItem( Root );\r
@@ -586,8 +937,7 @@ static void __fastcall NavigationMenu( TMenuItem * Root,
         }\r
 \r
         Name.sprintf( "Title %d (%d)", i_title,\r
-            p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb );\r
-\r
+            p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1 );\r
         {\r
             TitleItem = new TMenuItem( Root );\r
             TitleItem->RadioItem = true;\r
@@ -595,27 +945,26 @@ static void __fastcall NavigationMenu( TMenuItem * Root,
             TitleItem->Caption = Name;\r
 \r
             i_chapter_nb =\r
-                p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb;\r
+                p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb - 1;\r
 \r
             /* loop on chapters */\r
-            for( i_chapter = 0; i_chapter < i_chapter_nb; i_chapter++ )\r
+            for( unsigned int i_chapter = 1; i_chapter <= i_chapter_nb;\r
+                 i_chapter++ )\r
             {\r
                 /* we group chapters in packets of ten for small screens */\r
-                if( ( i_chapter % 10 == 0 ) && ( i_chapter_nb > 20 ) )\r
+                if( ( i_chapter % 10 == 1 ) && ( i_chapter_nb > 20 ) )\r
                 {\r
-                    if( i_chapter != 0 )\r
-                    {\r
+                    if( i_chapter != 1 )\r
                         TitleItem->Add( ChapterGroup );\r
-                    }\r
 \r
-                    Name.sprintf( "%d - %d", i_chapter + 1, i_chapter + 10 );\r
+                    Name.sprintf( "%d - %d", i_chapter, i_chapter + 9 );\r
                     ChapterGroup = new TMenuItem( TitleItem );\r
                     ChapterGroup->RadioItem = true;\r
                     ChapterGroup->Hint = Name;\r
                     ChapterGroup->Caption = Name;\r
                 }\r
 \r
-                Name.sprintf( "Chapter %d", i_chapter + 1 );\r
+                Name.sprintf( "Chapter %d", i_chapter );\r
 \r
                 ChapterItem = new TMenuItem( TitleItem );\r
                 ChapterItem->RadioItem = true;\r
@@ -624,28 +973,25 @@ static void __fastcall NavigationMenu( TMenuItem * Root,
 \r
                 /* FIXME: temporary hack to save i_title and i_chapter with\r
                  * ChapterItem, since we will need them in the callback */\r
-                 ChapterItem->Tag = (int)POS2DATA( i_title, i_chapter + 1 );\r
+                ChapterItem->Tag = Pos2Data( i_title, i_chapter );\r
 \r
-#define p_area p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]\r
+#define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title]\r
+                /* check the currently selected chapter */\r
                 if( ( p_area ==\r
-                        p_intfGlobal->p_sys->p_input->stream.p_selected_area ) &&\r
-                    ( p_area->i_part == i_chapter + 1 ) )\r
+                        p_intf->p_sys->p_input->stream.p_selected_area ) &&\r
+                    ( p_area->i_part == i_chapter ) )\r
                 {\r
-                    ItemActive = ChapterItem;\r
+                    ChapterItem->Checked = true;\r
                 }\r
 #undef p_area\r
 \r
-                /* setup signal hanling */\r
+                /* setup signal handling */\r
                 ChapterItem->OnClick = MenuItemClick;\r
 \r
                 if( i_chapter_nb > 20 )\r
-                {\r
                     ChapterGroup->Add( ChapterItem );\r
-                }\r
                 else\r
-                {\r
                     TitleItem->Add( ChapterItem );\r
-                }\r
             }\r
 \r
             if( i_chapter_nb > 20 )\r
@@ -653,7 +999,7 @@ static void __fastcall NavigationMenu( TMenuItem * Root,
                 TitleItem->Add( ChapterGroup );\r
             }\r
 \r
-            if( p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb\r
+            if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb\r
                 > 1 )\r
             {\r
                 /* be sure that menu is sensitive */\r
@@ -662,155 +1008,15 @@ static void __fastcall NavigationMenu( TMenuItem * Root,
         }\r
 \r
         if( i_title_nb > 20 )\r
-        {\r
             TitleGroup->Add( TitleItem );\r
-        }\r
         else\r
-        {\r
             Root->Add( TitleItem );\r
-        }\r
     }\r
 \r
     if( i_title_nb > 20 )\r
-    {\r
         Root->Add( TitleGroup );\r
-    }\r
-\r
-    /* Default selected chapter */\r
-    if( ItemActive != NULL )\r
-    {\r
-        ItemActive->Checked = true;\r
-    }\r
 \r
     /* be sure that menu is sensitive */\r
     Root->Enabled = true;\r
 }\r
 \r
-\r
-/*****************************************************************************\r
- * SetupMenus: function that generates title/chapter/audio/subpic\r
- * menus with help from preceding functions\r
- *****************************************************************************/\r
-int __fastcall SetupMenus( intf_thread_t * p_intf )\r
-{\r
-    TMainFrameDlg     * p_window = p_intf->p_sys->p_window;\r
-    es_descriptor_t   * p_audio_es;\r
-    es_descriptor_t   * p_spu_es;\r
-    int                 i;\r
-\r
-    p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;\r
-    p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update |\r
-                                     p_intf->p_sys->b_program_update;\r
-    p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |\r
-                                   p_intf->p_sys->b_program_update;\r
-\r
-    if( p_intf->p_sys->b_program_update )\r
-    { \r
-        pgrm_descriptor_t * p_pgrm;\r
-\r
-        if( p_intfGlobal->p_sys->p_input->stream.p_new_program )\r
-        {\r
-            p_pgrm = p_intfGlobal->p_sys->p_input->stream.p_new_program;\r
-        }\r
-        else\r
-        {\r
-            p_pgrm = p_intfGlobal->p_sys->p_input->stream.p_selected_program;\r
-        }\r
-\r
-        ProgramMenu( p_window->MenuProgram, p_pgrm,\r
-                     p_window->MenuProgramClick );\r
-        ProgramMenu( p_window->PopupProgram, p_pgrm,\r
-                     p_window->PopupProgramClick );\r
-\r
-        p_intf->p_sys->b_program_update = 0;\r
-    }\r
-\r
-    if( p_intf->p_sys->b_title_update )\r
-    {\r
-        RadioMenu( p_window->MenuTitle, "Title",\r
-//why "-1" ?\r
-                   p_intfGlobal->p_sys->p_input->stream.i_area_nb - 1,\r
-                   p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_id,\r
-                   p_window->MenuTitleClick );\r
-\r
-        AnsiString CurrentTitle;\r
-        CurrentTitle.sprintf( "%d",\r
-                    p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_id );\r
-        p_window->LabelTitleCurrent->Caption = CurrentTitle;\r
-\r
-        p_intf->p_sys->b_title_update = 0;\r
-    }\r
-\r
-    if( p_intf->p_sys->b_chapter_update )\r
-    {\r
-        RadioMenu( p_window->MenuChapter, "Chapter",\r
-                   p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part_nb,\r
-                   p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part,\r
-                   p_window->MenuChapterClick );\r
-\r
-        NavigationMenu( p_window->PopupNavigation,\r
-                        p_window->PopupNavigationClick );\r
-\r
-        AnsiString CurrentChapter;\r
-        CurrentChapter.sprintf( "%d",\r
-                    p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part );\r
-        p_window->LabelChapterCurrent->Caption = CurrentChapter;\r
-\r
-        p_intf->p_sys->i_part =\r
-                    p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part;\r
-\r
-        p_intf->p_sys->b_chapter_update = 0;\r
-    }\r
-\r
-    /* look for selected ES */\r
-    p_audio_es = NULL;\r
-    p_spu_es = NULL;\r
-\r
-     for( i = 0; i < p_intfGlobal->p_sys->p_input->stream.i_selected_es_number; i++ )\r
-    {\r
-        if( p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i]->i_cat\r
-            == AUDIO_ES )\r
-        {\r
-            p_audio_es = p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i];\r
-            p_intfGlobal->p_sys->p_audio_es_old = p_audio_es;\r
-        }\r
-\r
-        if( p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i]->i_cat\r
-            == SPU_ES )\r
-        {\r
-            p_spu_es = p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i];\r
-            p_intfGlobal->p_sys->p_spu_es_old = p_spu_es;\r
-        }\r
-    }\r
-\r
-    vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-\r
-    /* audio menus */\r
-    if( p_intf->p_sys->b_audio_update )\r
-    {\r
-        LanguageMenu( p_window->MenuAudio, p_audio_es, AUDIO_ES,\r
-                      p_window->MenuAudioClick );\r
-        LanguageMenu( p_window->PopupAudio, p_audio_es, AUDIO_ES,\r
-                      p_window->PopupAudioClick );\r
-\r
-        p_intf->p_sys->b_audio_update = 0;\r
-    }\r
-\r
-    /* sub picture menus */\r
-    if( p_intf->p_sys->b_spu_update )\r
-    {\r
-        LanguageMenu( p_window->PopupSubtitles, p_spu_es, SPU_ES,\r
-                      p_window->PopupSubtitleClick );\r
-        LanguageMenu( p_window->MenuSubtitles, p_spu_es, SPU_ES,\r
-                      p_window->MenuSubtitleClick );\r
-\r
-        p_intf->p_sys->b_spu_update = 0;\r
-    }\r
-\r
-    vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock );\r
-\r
-    return true;\r
-}\r
-\r
-\r
-\r