WinCE: update the interface module
[vlc.git] / modules / gui / wince / preferences.cpp
1 /*****************************************************************************
2  * preferences.cpp : WinCE gui plugin for VLC
3  *****************************************************************************
4  * Copyright (C) 2000-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Marodon Cedric <cedric_marodon@yahoo.fr>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_interface.h>
34
35 #include "wince.h"
36
37 #include <winuser.h>
38 #include <windows.h>
39 #include <windowsx.h>
40 #include <commctrl.h>
41 #include <commdlg.h>
42
43 #include <vlc_config_cat.h>
44
45 #include "preferences_widgets.h"
46
47 #define TYPE_CATEGORY 0
48 #define TYPE_CATSUBCAT 1  /* Category with embedded subcategory */
49 #define TYPE_SUBCATEGORY 2
50 #define TYPE_MODULE 3
51
52 /*****************************************************************************
53  * Event Table.
54  *****************************************************************************/
55
56 /* IDs for the controls and the menu commands */
57 enum
58 {
59     Notebook_Event,
60     MRL_Event,
61     ResetAll_Event,
62     Advanced_Event
63 };
64
65 /*****************************************************************************
66  * Classes declarations.
67  *****************************************************************************/
68 class ConfigTreeData;
69 class PrefsTreeCtrl
70 {
71 public:
72
73     PrefsTreeCtrl() { }
74     PrefsTreeCtrl( intf_thread_t *_p_intf, PrefsDialog *p_prefs_dialog,
75                    HWND hwnd, HINSTANCE _hInst );
76     virtual ~PrefsTreeCtrl();
77
78     void ApplyChanges();
79     /*void CleanChanges();*/
80
81     void OnSelectTreeItem( LPNM_TREEVIEW pnmtv, HWND parent, HINSTANCE hInst );
82  
83     ConfigTreeData *FindModuleConfig( ConfigTreeData *config_data );
84
85     HWND hwndTV;
86
87 private:
88     intf_thread_t *p_intf;
89     PrefsDialog *p_prefs_dialog;
90     bool b_advanced;
91
92     HTREEITEM general_item;
93     HTREEITEM plugins_item;
94 };
95
96 class PrefsPanel
97 {
98 public:
99
100     PrefsPanel() { }
101     PrefsPanel( HWND parent, HINSTANCE hInst, intf_thread_t *_p_intf,
102                 PrefsDialog *, module_t *p_module, char *, char *, ConfigTreeData * );
103     virtual ~PrefsPanel() {}
104
105     void Hide();
106     void Show();
107
108     HWND config_window;
109
110     int oldvalue;
111     int maxvalue;
112
113     void ApplyChanges();
114
115 private:
116     intf_thread_t *p_intf;
117     PrefsDialog *p_prefs_dialog;
118
119     bool b_advanced;
120
121     HWND label;
122
123     vector<ConfigControl *> config_array;
124 };
125
126 class ConfigTreeData
127 {
128 public:
129
130     ConfigTreeData() { b_submodule = 0; panel = NULL; psz_name = NULL;
131                        psz_help = NULL; }
132     virtual ~ConfigTreeData() { delete panel;
133                                 free( psz_name );
134                                 free( psz_help ); }
135
136     bool b_submodule;
137
138     PrefsPanel *panel;
139     module_t *p_module;
140     int i_object_id;
141     int i_subcat_id;
142     int i_type;
143     char *psz_name;
144     char *psz_help;
145 };
146
147 /*****************************************************************************
148  * Constructor.
149  *****************************************************************************/
150 PrefsDialog::PrefsDialog( intf_thread_t *p_intf, CBaseWindow *p_parent,
151                           HINSTANCE h_inst )
152   :  CBaseWindow( p_intf, p_parent, h_inst )
153 {
154     /* Initializations */
155     prefs_tree = NULL;
156 }
157
158 /***********************************************************************
159
160 FUNCTION:
161   WndProc
162
163 PURPOSE:
164   Processes messages sent to the main window.
165
166 ***********************************************************************/
167 LRESULT PrefsDialog::WndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
168 {
169     SHINITDLGINFO shidi;
170     SHMENUBARINFO mbi;
171     RECT rcClient;
172
173     switch( msg )
174     {
175     case WM_INITDIALOG:
176         shidi.dwMask = SHIDIM_FLAGS;
177         shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN |
178             SHIDIF_FULLSCREENNOMENUBAR;//SHIDIF_SIZEDLGFULLSCREEN;
179         shidi.hDlg = hwnd;
180         SHInitDialog( &shidi );
181
182         //Create the menubar
183         memset( &mbi, 0, sizeof (SHMENUBARINFO) );
184         mbi.cbSize     = sizeof (SHMENUBARINFO);
185         mbi.hwndParent = hwnd;
186         mbi.dwFlags    = SHCMBF_EMPTYBAR;
187         mbi.hInstRes   = hInst;
188
189         if( !SHCreateMenuBar(&mbi) )
190         {
191             MessageBox(hwnd, _T("SHCreateMenuBar Failed"), _T("Error"), MB_OK);
192             //return -1;
193         }
194
195         hwndCB = mbi.hwndMB;
196
197         // Get the client area rect to put the panels in
198         GetClientRect(hwnd, &rcClient);
199
200         /* Create the buttons */
201         advanced_checkbox =
202             CreateWindow( _T("BUTTON"), _T("Advanced options"),
203                         WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
204                         5, 10, 15, 15, hwnd, NULL, hInst, NULL );
205         SendMessage( advanced_checkbox, BM_SETCHECK, BST_UNCHECKED, 0 );
206
207         advanced_label = CreateWindow( _T("STATIC"), _T("Advanced options"),
208                         WS_CHILD | WS_VISIBLE | SS_LEFT,
209                         5 + 15 + 5, 10, 110, 15,
210                         hwnd, NULL, hInst, NULL);
211
212         if( config_GetInt( p_intf, "advanced" ) )
213         {
214             SendMessage( advanced_checkbox, BM_SETCHECK, BST_CHECKED, 0 );
215             /*dummy_event.SetInt(TRUE);
216               OnAdvanced( dummy_event );*/
217         }
218
219         reset_button = CreateWindow( _T("BUTTON"), _T("Reset All"),
220                         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
221                         rcClient.right - 5 - 80, 10 - 3, 80, 15 + 6,
222                         hwnd, NULL, hInst, NULL );
223
224         /* Create the preferences tree control */
225         prefs_tree = new PrefsTreeCtrl( p_intf, this, hwnd, hInst );
226
227         UpdateWindow( hwnd );
228         break;
229
230     case WM_CLOSE:
231         EndDialog( hwnd, LOWORD( wp ) );
232         break;
233
234     case WM_SETFOCUS:
235         SHFullScreen( hwnd, SHFS_SHOWSIPBUTTON );
236         break;
237
238     case WM_COMMAND:
239         if( LOWORD(wp) == IDOK )
240         {
241             OnOk();
242             EndDialog( hwnd, LOWORD( wp ) );
243         }
244         break;
245
246     case WM_NOTIFY:
247
248         if( lp && prefs_tree &&
249             ((LPNMHDR)lp)->hwndFrom == prefs_tree->hwndTV &&
250             ((LPNMHDR)lp)->code == TVN_SELCHANGED )
251         {
252             prefs_tree->OnSelectTreeItem( (NM_TREEVIEW FAR *)(LPNMHDR)lp,
253                                           hwnd, hInst );
254         }
255         break;
256
257     case WM_VSCROLL:
258     {
259         TVITEM tvi = {0};
260         tvi.mask = TVIF_PARAM;
261         tvi.hItem = TreeView_GetSelection( prefs_tree->hwndTV );
262     if( !tvi.hItem ) break;
263
264         if( !TreeView_GetItem( prefs_tree->hwndTV, &tvi ) ) break;
265
266         ConfigTreeData *config_data =
267             prefs_tree->FindModuleConfig( (ConfigTreeData *)tvi.lParam );
268         if( config_data && hwnd == config_data->panel->config_window )
269         {
270             int dy;
271             RECT rc;
272             GetWindowRect( hwnd, &rc);
273             int newvalue = config_data->panel->oldvalue;
274             switch ( GET_WM_VSCROLL_CODE(wp,lp) )
275             {
276             case SB_BOTTOM       : newvalue = 0; break;
277             case SB_TOP          : newvalue = config_data->panel->maxvalue; break;
278             case SB_LINEDOWN     : newvalue += 10; break;
279             case SB_PAGEDOWN     : newvalue += rc.bottom - rc.top - 25; break; // wrong! one page is notebook actual length
280             case SB_LINEUP       : newvalue -= 10; break;
281             case SB_PAGEUP       : newvalue -= rc.bottom - rc.top - 25; break;
282             case SB_THUMBPOSITION:
283             case SB_THUMBTRACK   : newvalue = GET_WM_VSCROLL_POS(wp,lp); break;
284             }
285             newvalue = max(0,min(config_data->panel->maxvalue,newvalue));
286             SetScrollPos( hwnd,SB_VERT,newvalue,TRUE);//SB_CTL si hwnd=hwndScrollBar, SB_VERT si window
287             dy = config_data->panel->oldvalue - newvalue;
288
289             ScrollWindowEx( hwnd, 0, dy, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN );
290             UpdateWindow ( hwnd);
291
292             config_data->panel->oldvalue = newvalue;
293         }
294         break;
295     }
296
297     default:
298         break;
299     }
300
301     return FALSE;
302 }
303
304 /*****************************************************************************
305  * Private methods.
306  *****************************************************************************/
307
308 /*****************************************************************************
309  * Events methods.
310  *****************************************************************************/
311 void PrefsDialog::OnOk( void )
312 {
313     prefs_tree->ApplyChanges();
314     config_SaveConfigFile( p_intf, NULL );
315 }
316
317 /*****************************************************************************
318  * PrefsTreeCtrl class definition.
319  *****************************************************************************/
320 PrefsTreeCtrl::PrefsTreeCtrl( intf_thread_t *_p_intf,
321                               PrefsDialog *_p_prefs_dialog, HWND hwnd,
322                               HINSTANCE hInst )
323 {
324     vlc_list_t      *p_list;
325     module_t        *p_module = NULL;
326     module_config_t *p_item;
327     int i_index;
328
329     INITCOMMONCONTROLSEX iccex;
330     RECT rcClient;
331     TVITEM tvi = {0};
332     TVINSERTSTRUCT tvins = {0};
333     HTREEITEM hPrev;
334
335     size_t i_capability_count = 0;
336     size_t i_child_index;
337
338     HTREEITEM category_item, subcategory_item;
339
340     /* Initializations */
341     p_intf = _p_intf;
342     p_prefs_dialog = _p_prefs_dialog;
343     b_advanced = false;
344
345     /* Create a tree view */
346     // Initialize the INITCOMMONCONTROLSEX structure.
347     iccex.dwSize = sizeof( INITCOMMONCONTROLSEX );
348     iccex.dwICC = ICC_TREEVIEW_CLASSES;
349
350     // Registers Statusbar control classes from the common control dll
351     InitCommonControlsEx( &iccex );
352
353     // Get the client area rect to put the tv in
354     GetClientRect(hwnd, &rcClient);
355
356     // Create the tree-view control.
357     hwndTV = CreateWindowEx( 0, WC_TREEVIEW, NULL,
358         WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES |
359         TVS_LINESATROOT | TVS_HASBUTTONS,
360         5, 10 + 2*(15 + 10) + 105 + 5, rcClient.right - 5 - 5, 6*15,
361         hwnd, NULL, hInst, NULL );
362
363     tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
364
365     /* List the plugins */
366     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
367     if( !p_list ) return;
368
369     /*
370      * Build a tree of the main options
371      */
372     ConfigTreeData *config_data = new ConfigTreeData;
373     config_data->i_object_id = TYPE_CATEGORY;
374     config_data->psz_help = strdup(MAIN_HELP);
375     config_data->psz_name = strdup( GENERAL_TITLE );
376     tvi.pszText = _T("General settings");
377     tvi.cchTextMax = lstrlen(_T("General settings"));
378     tvi.lParam = (long)config_data;
379     tvins.item = tvi;
380     tvins.hInsertAfter = TVI_FIRST;
381     tvins.hParent = TVI_ROOT;
382
383     // Add the item to the tree-view control.
384     hPrev = (HTREEITEM) TreeView_InsertItem( hwndTV, &tvins);
385     general_item = hPrev;
386
387     /* Build the categories list */
388     for( i_index = 0; i_index < p_list->i_count; i_index++ )
389     {
390         p_module = (module_t *)p_list->p_values[i_index].p_object;
391         if( strcmp( module_GetObjName( p_module ), "main" ) == 0 )
392             break;
393     }
394     /* TODO replace by
395      * p_module = module_GetMainModule( p_intf );
396      */
397     if( i_index < p_list->i_count )
398     {
399         unsigned int confsize;
400         const char *psz_help;
401         module_config_t * p_config;
402
403         /* We found the main module */
404
405         /* Enumerate config categories and store a reference so we can
406          * generate their config panel them when it is asked by the user. */
407         p_config = module_GetConfig (p_module, &confsize);
408
409         for( size_t i = 0; i < confsize; i++ )
410         {
411         /* Work on a new item */
412             module_config_t *p_item = p_config + i;
413
414                 switch( p_item->i_type )
415                 {
416                     case CONFIG_CATEGORY:
417                         if( p_item->value.i == -1 )   break; // Don't display it
418                         config_data = new ConfigTreeData;
419                         config_data->psz_name = strdup( config_CategoryNameGet(p_item->value.i ) );
420                         psz_help = config_CategoryHelpGet( p_item->value.i );
421                         if( psz_help )
422                         {
423                             config_data->psz_help = wraptext( strdup( psz_help ), 72 );
424                         }
425                         else
426                         {
427                             config_data->psz_help = NULL;
428                         }
429
430                         config_data->i_type = TYPE_CATEGORY;
431                         config_data->i_object_id = p_item->value.i;
432                         config_data->p_module =  p_module;
433                         tvi.pszText = _FROMMB(config_data->psz_name);
434                         tvi.cchTextMax = _tcslen(tvi.pszText);
435
436                         /* Add the category to the tree */
437                         tvi.lParam = (long)config_data;
438                         tvins.item = tvi;
439                         tvins.hInsertAfter = hPrev;
440                         tvins.hParent = general_item; //level 3
441
442                         // Add the item to the tree-view control.
443                         hPrev = (HTREEITEM)TreeView_InsertItem( hwndTV, &tvins );
444                         break;
445
446                     case CONFIG_SUBCATEGORY:
447                         if( p_item->value.i == -1 ) break; // Don't display it
448                         /* Special case: move the "general" subcategories to their parent category */
449                         if(config_data && p_item->value.i == SUBCAT_VIDEO_GENERAL ||
450                             p_item->value.i == SUBCAT_ADVANCED_MISC ||
451                             p_item->value.i == SUBCAT_INPUT_GENERAL ||
452                             p_item->value.i == SUBCAT_INTERFACE_GENERAL ||
453                             p_item->value.i == SUBCAT_SOUT_GENERAL||
454                             p_item->value.i == SUBCAT_PLAYLIST_GENERAL||
455                             p_item->value.i == SUBCAT_AUDIO_GENERAL )
456                         {
457
458                             config_data->i_type = TYPE_CATSUBCAT;
459                             config_data->i_subcat_id = p_item->value.i;
460                             free( config_data->psz_name );
461                             config_data->psz_name = strdup( config_CategoryNameGet( p_item->value.i ) );
462
463                             free( config_data->psz_help );
464                             const char *psz_help = config_CategoryHelpGet( p_item->value.i );
465                             if( psz_help )
466                             {
467                                 config_data->psz_help = wraptext( strdup( psz_help ), 72 );
468                             }
469                             else
470                             {
471                                 config_data->psz_help = NULL;
472                             }
473                             continue;
474                         }
475
476                         config_data = new ConfigTreeData;
477
478                         config_data->psz_name = strdup(  config_CategoryNameGet( p_item->value.i ) );
479                         psz_help = config_CategoryHelpGet( p_item->value.i );
480                         if( psz_help )
481                         {
482                             config_data->psz_help = wraptext( strdup( psz_help ), 72 );
483                         }
484                         else
485                         {
486                             config_data->psz_help = NULL;
487                         }
488                         config_data->i_type = TYPE_SUBCATEGORY;
489                         config_data->i_object_id = p_item->value.i;
490
491                         tvi.pszText = _FROMMB(config_data->psz_name);
492                         tvi.cchTextMax = _tcslen(tvi.pszText);
493
494                         tvi.lParam = (long)config_data;
495                         tvins.item = tvi;
496                         tvins.hInsertAfter = hPrev;
497                         tvins.hParent = hPrev;
498
499                         // Add the item to the tree-view control.
500                         TreeView_InsertItem( hwndTV, &tvins );
501                         break;
502
503                 }
504          }
505         TreeView_SortChildren( hwndTV, general_item, 0 );
506         module_PutConfig( p_config );
507     }
508
509
510     module_config_t *p_config;
511     /*
512     * Build a tree of all the plugins
513     */
514     for( i_index = 0; i_index < p_list->i_count; i_index++ )
515     {
516         /* Take every module */
517         p_module = (module_t *)p_list->p_values[i_index].p_object;
518
519         /* Exclude the main module */
520         if( !strcmp( module_GetObjName( p_module ), "main" ) )
521             continue;
522
523         /* Exclude empty plugins (submodules don't have config options, they
524          * are stored in the parent module) */
525
526         unsigned int confsize;
527         i_child_index = 0;
528         int i_category = 0, i_subcategory = 0, i_options = 0;
529         bool b_options = false;
530
531         p_config = module_GetConfig( (module_t *) p_module,&confsize);
532
533         /* Loop through the configurations items */
534         for( size_t i = 0; i < confsize; i++ )
535         {
536             module_config_t *p_item = p_config + i;
537             if( p_item->i_type == CONFIG_CATEGORY )
538                 i_category = p_item->value.i;
539             else if( p_item->i_type == CONFIG_SUBCATEGORY )
540                 i_subcategory = p_item->value.i;
541
542             if( p_item->i_type & CONFIG_ITEM )
543                 b_options = true;
544
545             if( b_options && i_category && i_subcategory )
546                 break;
547         }
548         module_PutConfig (p_config);
549
550         //if( !i_options ) continue;
551         /* Dummy item, please proceed */
552         if( !b_options || i_category == 0 || i_subcategory == 0 ) continue;
553
554         category_item = TreeView_GetChild( hwndTV, general_item );
555         while(category_item != 0)
556         {
557             TVITEM category_tvi = {0};
558
559             category_tvi.mask = TVIF_PARAM;
560             category_tvi.lParam = NULL;
561             category_tvi.hItem = category_item;
562             TreeView_GetItem( hwndTV, &category_tvi );
563
564             ConfigTreeData * data = (ConfigTreeData *)category_tvi.lParam;
565
566             if( data->i_object_id == i_category )
567             {
568                 subcategory_item = TreeView_GetChild( hwndTV, category_item );
569
570                 while(subcategory_item != 0)
571                 {
572                     TVITEM subcategory_tvi = {0};
573
574                     subcategory_tvi.mask = TVIF_PARAM;
575                     subcategory_tvi.lParam = NULL;
576                     subcategory_tvi.hItem = subcategory_item;
577                     TreeView_GetItem( hwndTV, &subcategory_tvi );
578
579                     ConfigTreeData * subdata = (ConfigTreeData *)subcategory_tvi.lParam;
580
581                     if( subdata->i_object_id == i_subcategory )
582                     {
583                         config_data = new ConfigTreeData;
584
585                         config_data->psz_name = strdup( module_GetObjName( p_module ) );
586                         config_data->psz_help = NULL;
587                         config_data->i_type = TYPE_MODULE;
588                         config_data->i_object_id = p_item->value.i;
589                         config_data->p_module = p_module;
590
591                         tvi.pszText = _FROMMB(module_GetName( p_module, false ));
592                         tvi.cchTextMax = _tcslen(tvi.pszText);
593
594                         tvi.lParam = (long)config_data;
595                         tvins.item = tvi;
596                         tvins.hInsertAfter = subcategory_item;
597                         tvins.hParent = subcategory_item;
598
599                 // Add the item to the tree-view control.
600                         hPrev = (HTREEITEM)TreeView_InsertItem( hwndTV, &tvins );
601                         break;
602                     }
603                     subcategory_item = TreeView_GetNextSibling( hwndTV, subcategory_item );
604                 }
605
606                 break;
607             }
608
609             category_item = TreeView_GetNextSibling( hwndTV, category_item );
610         }
611
612     }
613
614     /* Sort all this mess */
615     TreeView_SortChildren( hwndTV, general_item, 0 );
616     category_item = TreeView_GetChild( hwndTV, general_item );
617     while( category_item != 0 )
618     {
619         TreeView_SortChildren( hwndTV, category_item, 0 );
620         category_item = TreeView_GetNextSibling( hwndTV, category_item );
621     }
622
623     /* Clean-up everything */
624     vlc_list_release( p_list );
625
626     TreeView_Expand( hwndTV, general_item, TVE_EXPANDPARTIAL |TVE_EXPAND );
627 }
628
629 PrefsTreeCtrl::~PrefsTreeCtrl()
630 {
631 }
632
633 void PrefsTreeCtrl::ApplyChanges()
634 {
635     ConfigTreeData *config_data;
636
637     /* Apply changes to the main module */
638     HTREEITEM item = TreeView_GetChild( hwndTV, general_item );
639     while( item != 0 )
640     {
641         TVITEM tvi = {0};
642         tvi.mask = TVIF_PARAM;
643         tvi.hItem = item;
644         TreeView_GetItem( hwndTV, &tvi );
645         config_data = (ConfigTreeData *)tvi.lParam;
646         if( config_data && config_data->panel )
647         {
648             config_data->panel->ApplyChanges();
649         }
650
651         item = TreeView_GetNextSibling( hwndTV, item );
652     }
653
654     /* Apply changes to the plugins */
655     item = TreeView_GetChild( hwndTV, general_item );
656     while( item != 0 )
657     {
658         HTREEITEM item2 = TreeView_GetChild( hwndTV, item );
659         while( item2 != 0 )
660         {
661             HTREEITEM item3 = TreeView_GetChild( hwndTV, item2 );
662             while(item3 !=0)
663             {
664                 TVITEM tvi = {0};
665                 tvi.mask = TVIF_PARAM;
666                 tvi.hItem = item3;
667                 TreeView_GetItem( hwndTV, &tvi );
668                 config_data = (ConfigTreeData *)tvi.lParam;
669                 if( config_data && config_data->panel )
670                 {
671                     config_data->panel->ApplyChanges();
672                 }
673                 item3 = TreeView_GetNextSibling( hwndTV, item3 );
674             }
675             item2 = TreeView_GetNextSibling( hwndTV, item2 );
676         }
677         item = TreeView_GetNextSibling( hwndTV, item );
678     }
679 }
680
681 ConfigTreeData *PrefsTreeCtrl::FindModuleConfig( ConfigTreeData *config_data )
682 {
683     if( !config_data || !config_data->p_module )
684     {
685         return config_data;
686     }
687
688     ConfigTreeData *config_new;
689     HTREEITEM item = TreeView_GetChild( hwndTV, general_item );
690     while( item != 0 )
691     {
692         HTREEITEM item2 = TreeView_GetChild( hwndTV, item );
693         while( item2 != 0 )
694         {
695             HTREEITEM item3 = TreeView_GetChild( hwndTV, item2 );
696             while( item3 != 0 )
697             {
698                 TVITEM tvi = {0};
699                 tvi.mask = TVIF_PARAM;
700                 tvi.hItem = item3;
701                 TreeView_GetItem( hwndTV, &tvi );
702                 config_new = (ConfigTreeData *)tvi.lParam;
703                 if( config_new && config_new->p_module == config_data->p_module )
704                 {
705                     return config_new;
706                 }
707                 item3 = TreeView_GetNextSibling( hwndTV, item3 );
708             }
709             item2 = TreeView_GetNextSibling( hwndTV, item2 );
710         }
711         item = TreeView_GetNextSibling( hwndTV, item );
712     }
713
714     /* Found nothing */
715     return NULL;
716 }
717
718 void PrefsTreeCtrl::OnSelectTreeItem( LPNM_TREEVIEW pnmtv, HWND parent,
719                                       HINSTANCE hInst )
720 {
721     ConfigTreeData *config_data = NULL;
722
723     if( pnmtv->itemOld.hItem )
724         config_data = FindModuleConfig( (ConfigTreeData *)pnmtv->itemOld.lParam );
725
726     if( config_data && config_data->panel )
727     {
728         config_data->panel->Hide();
729     }
730
731     /* Don't use event.GetItem() because we also send fake events */
732     TVITEM tvi = {0};
733     tvi.mask = TVIF_PARAM;
734     tvi.hItem = TreeView_GetSelection( hwndTV );
735     TreeView_GetItem( hwndTV, &tvi );
736     config_data = FindModuleConfig( (ConfigTreeData *)tvi.lParam );
737     if( config_data )
738     {
739         if( !config_data->panel )
740         {
741             /* The panel hasn't been created yet. Let's do it. */
742             config_data->panel =
743                 new PrefsPanel( parent, hInst, p_intf, p_prefs_dialog,
744                                 config_data->p_module,
745                                 config_data->psz_name,
746                                 config_data->psz_help, config_data );
747         }
748         else
749         {
750             config_data->panel->Show();
751         }
752     }
753 }
754
755 /*****************************************************************************
756  * PrefsPanel class definition.
757  *****************************************************************************/
758 PrefsPanel::PrefsPanel( HWND parent, HINSTANCE hInst, intf_thread_t *_p_intf,
759                         PrefsDialog *_p_prefs_dialog,
760                         module_t *p_module, char *psz_name, char *psz_help, ConfigTreeData * config_data )
761 {
762     module_config_t *p_item, *p_config, *p_end;
763
764     /* Initializations */
765     p_intf = _p_intf;
766     p_prefs_dialog = _p_prefs_dialog;
767     vlc_list_t *p_list = NULL;
768
769     b_advanced = true;
770
771     if( config_data->i_type == TYPE_CATEGORY )
772     {
773         label = CreateWindow( _T("STATIC"), _FROMMB(psz_name),
774                               WS_CHILD | WS_VISIBLE | SS_LEFT,
775                               5, 10 + (15 + 10), 200, 15,
776                               parent, NULL, hInst, NULL );
777         config_window = NULL;
778     }
779     else
780     {
781         /* Get a pointer to the module */
782         if( config_data->i_type == TYPE_MODULE )
783         {
784             p_module = config_data->p_module;
785         }
786         else
787         {
788             /* List the plugins */
789             int i_index;
790             bool b_found = false;
791             p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
792             if( !p_list ) return;
793
794             for( i_index = 0; i_index < p_list->i_count; i_index++ )
795             {
796                 p_module = (module_t *)p_list->p_values[i_index].p_object;
797                 if( !strcmp( module_GetObjName(p_module), "main" ) )
798                 {
799                     b_found = true;
800                     break;
801                 }
802             }
803             if( !p_module && !b_found )
804             {
805                 msg_Warn( p_intf, "unable to create preferences "
806                         "(main module not found)" );
807                 return;
808             }
809         }
810
811         /* Enumerate config options and add corresponding config boxes
812          * (submodules don't have config options, they are stored in the
813          *  parent module) */
814         unsigned confsize;
815         p_config = module_GetConfig( (module_t *) p_module,&confsize);
816
817         p_item = p_config;
818         p_end = p_config + confsize;
819
820         /* Find the category if it has been specified */
821         if( config_data->i_type == TYPE_SUBCATEGORY ||
822             config_data->i_type == TYPE_CATSUBCAT )
823         {
824             for( ; p_item && p_item < p_end ; p_item++ )
825             {
826                 if( p_item->i_type == CONFIG_SUBCATEGORY &&
827                     ( config_data->i_type == TYPE_SUBCATEGORY &&
828                     p_item->value.i == config_data->i_object_id ) ||
829                     ( config_data->i_type == TYPE_CATSUBCAT &&
830                     p_item->value.i == config_data->i_subcat_id ) )
831                 {
832                     break;
833                 }
834             }
835         }
836
837         /* Add a head title to the panel */
838         const char *psz_head;
839         if( config_data->i_type == TYPE_SUBCATEGORY ||
840             config_data->i_type == TYPE_CATSUBCAT )
841         {
842             psz_head = config_data->psz_name;
843             p_item++;
844         }
845         else
846         {
847             psz_head = module_GetLongName(p_module);
848         }
849
850         label = CreateWindow( _T("STATIC"), _FROMMB(psz_head ?
851                 psz_head : _("Unknown")),
852                         WS_CHILD | WS_VISIBLE | SS_LEFT,
853                         5, 10 + (15 + 10), 250, 15,
854                                  parent, NULL, hInst, NULL );
855
856         WNDCLASS wc;
857         memset( &wc, 0, sizeof(wc) );
858         wc.style          = CS_HREDRAW | CS_VREDRAW;
859         wc.lpfnWndProc    = (WNDPROC) _p_prefs_dialog->BaseWndProc;
860         wc.cbClsExtra     = 0;
861         wc.cbWndExtra     = 0;
862         wc.hInstance      = hInst;
863         wc.hIcon          = 0;
864         wc.hCursor        = 0;
865         wc.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
866         wc.lpszMenuName   = 0;
867         wc.lpszClassName  = _T("PrefsPanelClass");
868         RegisterClass(&wc);
869
870         RECT rc;
871         GetWindowRect( parent, &rc);
872         config_window = CreateWindow( _T("PrefsPanelClass"),
873                         _T("config_window"),
874                         WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER,
875                         5, 10 + 2*(15 + 10), rc.right - 5 - 7, 105,
876                         parent, NULL, hInst, (void *) _p_prefs_dialog );
877
878         int y_pos = 5;
879         for( ; p_item && p_item < p_end ; p_item++ )
880         {
881             /* If a category has been specified, check we finished the job */
882             if( ( ( config_data->i_type == TYPE_SUBCATEGORY &&
883                     p_item->value.i != config_data->i_object_id ) ||
884                     ( config_data->i_type == TYPE_CATSUBCAT  &&
885                     p_item->value.i != config_data->i_subcat_id ) ) &&
886                     (p_item->i_type == CONFIG_CATEGORY ||
887                     p_item->i_type == CONFIG_SUBCATEGORY ) )
888                 break;
889
890             ConfigControl *control = NULL;
891
892             control = CreateConfigControl( VLC_OBJECT(p_intf),
893                                      p_item, config_window,
894                                      hInst, &y_pos );
895
896             /* Don't add items that were not recognized */
897             if( control == NULL ) continue;
898
899             /* Add the config data to our array so we can keep a trace of it */
900             config_array.push_back( control );
901         }
902         GetWindowRect( config_window, &rc);
903         maxvalue = y_pos - (rc.bottom - rc.top) + 5;
904         oldvalue = 0;
905         SetScrollRange( config_window, SB_VERT, 0, maxvalue, TRUE );
906     }
907 }
908
909 void PrefsPanel::Hide()
910 {
911     ShowWindow( label, SW_HIDE );
912     if( config_window ) ShowWindow( config_window, SW_HIDE );
913 }
914
915 void PrefsPanel::Show()
916 {
917     ShowWindow( label, SW_SHOW );
918     if( config_window ) ShowWindow( config_window, SW_SHOW );
919 }
920
921 void PrefsPanel::ApplyChanges()
922 {
923     vlc_value_t val;
924     for( size_t i = 0; i < config_array.size(); i++ )
925     {
926         ConfigControl *control = config_array[i];
927
928         switch( control->GetType() )
929         {
930         case CONFIG_ITEM_STRING:
931         case CONFIG_ITEM_FILE:
932         case CONFIG_ITEM_DIRECTORY:
933         case CONFIG_ITEM_MODULE:
934             config_PutPsz( p_intf, control->GetName(),
935                            control->GetPszValue() );
936             break;
937         case CONFIG_ITEM_KEY:
938             /* So you don't need to restart to have the changes take effect */
939             val.i_int = control->GetIntValue();
940             var_Set( p_intf->p_libvlc, control->GetName(), val );
941         case CONFIG_ITEM_INTEGER:
942         case CONFIG_ITEM_BOOL:
943             config_PutInt( p_intf, control->GetName(),
944                            control->GetIntValue() );
945             break;
946         case CONFIG_ITEM_FLOAT:
947             config_PutFloat( p_intf, control->GetName(),
948                              control->GetFloatValue() );
949             break;
950         }
951     }
952 }