WinCE intf: don't use old preferences macros
[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     module_t        *p_module = NULL;
325     module_config_t *p_item;
326
327     INITCOMMONCONTROLSEX iccex;
328     RECT rcClient;
329     TVITEM tvi = {0};
330     TVINSERTSTRUCT tvins = {0};
331     HTREEITEM hPrev;
332
333     size_t i_capability_count = 0;
334     size_t i_child_index;
335
336     HTREEITEM category_item, subcategory_item;
337
338     /* Initializations */
339     p_intf = _p_intf;
340     p_prefs_dialog = _p_prefs_dialog;
341     b_advanced = false;
342
343     /* Create a tree view */
344     // Initialize the INITCOMMONCONTROLSEX structure.
345     iccex.dwSize = sizeof( INITCOMMONCONTROLSEX );
346     iccex.dwICC = ICC_TREEVIEW_CLASSES;
347
348     // Registers Statusbar control classes from the common control dll
349     InitCommonControlsEx( &iccex );
350
351     // Get the client area rect to put the tv in
352     GetClientRect(hwnd, &rcClient);
353
354     // Create the tree-view control.
355     hwndTV = CreateWindowEx( 0, WC_TREEVIEW, NULL,
356         WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES |
357         TVS_LINESATROOT | TVS_HASBUTTONS,
358         5, 10 + 2*(15 + 10) + 105 + 5, rcClient.right - 5 - 5, 6*15,
359         hwnd, NULL, hInst, NULL );
360
361     tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
362
363     /*
364      * Build a tree of the main options
365      */
366     ConfigTreeData *config_data = new ConfigTreeData;
367     config_data->i_object_id = TYPE_CATEGORY;
368     config_data->psz_help = strdup(MAIN_HELP);
369     config_data->psz_name = strdup( "General" );
370     tvi.pszText = _T("General settings");
371     tvi.cchTextMax = lstrlen(_T("General settings"));
372     tvi.lParam = (long)config_data;
373     tvins.item = tvi;
374     tvins.hInsertAfter = TVI_FIRST;
375     tvins.hParent = TVI_ROOT;
376
377     // Add the item to the tree-view control.
378     hPrev = (HTREEITEM) TreeView_InsertItem( hwndTV, &tvins);
379     general_item = hPrev;
380
381     /* Build the categories list */
382     p_module = module_get_main();
383
384     unsigned int confsize;
385     const char *psz_help;
386     module_config_t * p_config;
387
388     /* Enumerate config categories and store a reference so we can
389      * generate their config panel when it is asked by the user. */
390     p_config = module_config_get (p_module, &confsize);
391
392     for( size_t i = 0; i < confsize; i++ )
393     {
394     /* Work on a new item */
395         module_config_t *p_item = p_config + i;
396
397             switch( p_item->i_type )
398             {
399                 case CONFIG_CATEGORY:
400                     if( p_item->value.i == -1 )   break; // Don't display it
401                     config_data = new ConfigTreeData;
402                     config_data->psz_name = strdup( config_CategoryNameGet(p_item->value.i ) );
403                     psz_help = config_CategoryHelpGet( p_item->value.i );
404                     if( psz_help )
405                     {
406                         config_data->psz_help = wraptext( strdup( psz_help ), 72 );
407                     }
408                     else
409                     {
410                         config_data->psz_help = NULL;
411                     }
412
413                     config_data->i_type = TYPE_CATEGORY;
414                     config_data->i_object_id = p_item->value.i;
415                     config_data->p_module =  p_module;
416                     tvi.pszText = _FROMMB(config_data->psz_name);
417                     tvi.cchTextMax = _tcslen(tvi.pszText);
418
419                     /* Add the category to the tree */
420                     tvi.lParam = (long)config_data;
421                     tvins.item = tvi;
422                     tvins.hInsertAfter = hPrev;
423                     tvins.hParent = general_item; //level 3
424
425                     // Add the item to the tree-view control.
426                     hPrev = (HTREEITEM)TreeView_InsertItem( hwndTV, &tvins );
427                     break;
428
429                 case CONFIG_SUBCATEGORY:
430                     if( p_item->value.i == -1 ) break; // Don't display it
431                     /* Special case: move the "general" subcategories to their parent category */
432                     if(config_data && p_item->value.i == SUBCAT_VIDEO_GENERAL ||
433                         p_item->value.i == SUBCAT_ADVANCED_MISC ||
434                         p_item->value.i == SUBCAT_INPUT_GENERAL ||
435                         p_item->value.i == SUBCAT_INTERFACE_GENERAL ||
436                         p_item->value.i == SUBCAT_SOUT_GENERAL||
437                         p_item->value.i == SUBCAT_PLAYLIST_GENERAL||
438                         p_item->value.i == SUBCAT_AUDIO_GENERAL )
439                     {
440
441                         config_data->i_type = TYPE_CATSUBCAT;
442                         config_data->i_subcat_id = p_item->value.i;
443                         free( config_data->psz_name );
444                         config_data->psz_name = strdup( config_CategoryNameGet( p_item->value.i ) );
445
446                         free( config_data->psz_help );
447                         const char *psz_help = config_CategoryHelpGet( p_item->value.i );
448                         if( psz_help )
449                         {
450                             config_data->psz_help = wraptext( strdup( psz_help ), 72 );
451                         }
452                         else
453                         {
454                             config_data->psz_help = NULL;
455                         }
456                         continue;
457                     }
458
459                     config_data = new ConfigTreeData;
460
461                     config_data->psz_name = strdup(  config_CategoryNameGet( p_item->value.i ) );
462                     psz_help = config_CategoryHelpGet( p_item->value.i );
463                     if( psz_help )
464                     {
465                         config_data->psz_help = wraptext( strdup( psz_help ), 72 );
466                     }
467                     else
468                     {
469                         config_data->psz_help = NULL;
470                     }
471                     config_data->i_type = TYPE_SUBCATEGORY;
472                     config_data->i_object_id = p_item->value.i;
473
474                     tvi.pszText = _FROMMB(config_data->psz_name);
475                     tvi.cchTextMax = _tcslen(tvi.pszText);
476
477                     tvi.lParam = (long)config_data;
478                     tvins.item = tvi;
479                     tvins.hInsertAfter = hPrev;
480                     tvins.hParent = hPrev;
481
482                     // Add the item to the tree-view control.
483                     TreeView_InsertItem( hwndTV, &tvins );
484                     break;
485
486             }
487         }
488     TreeView_SortChildren( hwndTV, general_item, 0 );
489     module_config_free( p_config );
490
491     /* List the plugins */
492     module_t **p_list = module_list_get( NULL );
493
494     /*
495     * Build a tree of all the plugins
496     */
497     for( size_t i_index = 0; p_list[i_index]; i_index++ )
498     {
499         /* Take every module */
500         p_module = p_list[i_index];
501
502         /* Exclude the main module */
503         if( module_is_main( p_module ) )
504             continue;
505
506         /* Exclude empty plugins (submodules don't have config options, they
507          * are stored in the parent module) */
508
509         unsigned int confsize;
510         i_child_index = 0;
511         int i_category = 0, i_subcategory = 0, i_options = 0;
512         bool b_options = false;
513
514         p_config = module_config_get( (module_t *) p_module,&confsize);
515
516         /* Loop through the configurations items */
517         for( size_t i = 0; i < confsize; i++ )
518         {
519             module_config_t *p_item = p_config + i;
520             if( p_item->i_type == CONFIG_CATEGORY )
521                 i_category = p_item->value.i;
522             else if( p_item->i_type == CONFIG_SUBCATEGORY )
523                 i_subcategory = p_item->value.i;
524
525             if( p_item->i_type & CONFIG_ITEM )
526                 b_options = true;
527
528             if( b_options && i_category && i_subcategory )
529                 break;
530         }
531         module_config_free (p_config);
532
533         /* Dummy item, please proceed */
534         if( !b_options || i_category == 0 || i_subcategory == 0 ) continue;
535
536         category_item = TreeView_GetChild( hwndTV, general_item );
537         while(category_item != 0)
538         {
539             TVITEM category_tvi = {0};
540
541             category_tvi.mask = TVIF_PARAM;
542             category_tvi.lParam = NULL;
543             category_tvi.hItem = category_item;
544             TreeView_GetItem( hwndTV, &category_tvi );
545
546             ConfigTreeData * data = (ConfigTreeData *)category_tvi.lParam;
547
548             if( data->i_object_id == i_category )
549             {
550                 subcategory_item = TreeView_GetChild( hwndTV, category_item );
551
552                 while(subcategory_item != 0)
553                 {
554                     TVITEM subcategory_tvi = {0};
555
556                     subcategory_tvi.mask = TVIF_PARAM;
557                     subcategory_tvi.lParam = NULL;
558                     subcategory_tvi.hItem = subcategory_item;
559                     TreeView_GetItem( hwndTV, &subcategory_tvi );
560
561                     ConfigTreeData * subdata = (ConfigTreeData *)subcategory_tvi.lParam;
562
563                     if( subdata->i_object_id == i_subcategory )
564                     {
565                         config_data = new ConfigTreeData;
566
567                         config_data->psz_name = strdup( module_get_object( p_module ) );
568                         config_data->psz_help = NULL;
569                         config_data->i_type = TYPE_MODULE;
570                         config_data->i_object_id = p_item->value.i;
571                         config_data->p_module = p_module;
572
573                         tvi.pszText = _FROMMB(module_get_name( p_module, false ));
574                         tvi.cchTextMax = _tcslen(tvi.pszText);
575
576                         tvi.lParam = (long)config_data;
577                         tvins.item = tvi;
578                         tvins.hInsertAfter = subcategory_item;
579                         tvins.hParent = subcategory_item;
580
581                 // Add the item to the tree-view control.
582                         hPrev = (HTREEITEM)TreeView_InsertItem( hwndTV, &tvins );
583                         break;
584                     }
585                     subcategory_item = TreeView_GetNextSibling( hwndTV, subcategory_item );
586                 }
587
588                 break;
589             }
590
591             category_item = TreeView_GetNextSibling( hwndTV, category_item );
592         }
593
594     }
595
596     /* Sort all this mess */
597     TreeView_SortChildren( hwndTV, general_item, 0 );
598     category_item = TreeView_GetChild( hwndTV, general_item );
599     while( category_item != 0 )
600     {
601         TreeView_SortChildren( hwndTV, category_item, 0 );
602         category_item = TreeView_GetNextSibling( hwndTV, category_item );
603     }
604
605     /* Clean-up everything */
606     module_list_free( p_list );
607
608     TreeView_Expand( hwndTV, general_item, TVE_EXPANDPARTIAL |TVE_EXPAND );
609 }
610
611 PrefsTreeCtrl::~PrefsTreeCtrl()
612 {
613 }
614
615 void PrefsTreeCtrl::ApplyChanges()
616 {
617     ConfigTreeData *config_data;
618
619     /* Apply changes to the main module */
620     HTREEITEM item = TreeView_GetChild( hwndTV, general_item );
621     while( item != 0 )
622     {
623         TVITEM tvi = {0};
624         tvi.mask = TVIF_PARAM;
625         tvi.hItem = item;
626         TreeView_GetItem( hwndTV, &tvi );
627         config_data = (ConfigTreeData *)tvi.lParam;
628         if( config_data && config_data->panel )
629         {
630             config_data->panel->ApplyChanges();
631         }
632
633         item = TreeView_GetNextSibling( hwndTV, item );
634     }
635
636     /* Apply changes to the plugins */
637     item = TreeView_GetChild( hwndTV, general_item );
638     while( item != 0 )
639     {
640         HTREEITEM item2 = TreeView_GetChild( hwndTV, item );
641         while( item2 != 0 )
642         {
643             HTREEITEM item3 = TreeView_GetChild( hwndTV, item2 );
644             while(item3 !=0)
645             {
646                 TVITEM tvi = {0};
647                 tvi.mask = TVIF_PARAM;
648                 tvi.hItem = item3;
649                 TreeView_GetItem( hwndTV, &tvi );
650                 config_data = (ConfigTreeData *)tvi.lParam;
651                 if( config_data && config_data->panel )
652                 {
653                     config_data->panel->ApplyChanges();
654                 }
655                 item3 = TreeView_GetNextSibling( hwndTV, item3 );
656             }
657             item2 = TreeView_GetNextSibling( hwndTV, item2 );
658         }
659         item = TreeView_GetNextSibling( hwndTV, item );
660     }
661 }
662
663 ConfigTreeData *PrefsTreeCtrl::FindModuleConfig( ConfigTreeData *config_data )
664 {
665     if( !config_data || !config_data->p_module )
666     {
667         return config_data;
668     }
669
670     ConfigTreeData *config_new;
671     HTREEITEM item = TreeView_GetChild( hwndTV, general_item );
672     while( item != 0 )
673     {
674         HTREEITEM item2 = TreeView_GetChild( hwndTV, item );
675         while( item2 != 0 )
676         {
677             HTREEITEM item3 = TreeView_GetChild( hwndTV, item2 );
678             while( item3 != 0 )
679             {
680                 TVITEM tvi = {0};
681                 tvi.mask = TVIF_PARAM;
682                 tvi.hItem = item3;
683                 TreeView_GetItem( hwndTV, &tvi );
684                 config_new = (ConfigTreeData *)tvi.lParam;
685                 if( config_new && config_new->p_module == config_data->p_module )
686                 {
687                     return config_new;
688                 }
689                 item3 = TreeView_GetNextSibling( hwndTV, item3 );
690             }
691             item2 = TreeView_GetNextSibling( hwndTV, item2 );
692         }
693         item = TreeView_GetNextSibling( hwndTV, item );
694     }
695
696     /* Found nothing */
697     return NULL;
698 }
699
700 void PrefsTreeCtrl::OnSelectTreeItem( LPNM_TREEVIEW pnmtv, HWND parent,
701                                       HINSTANCE hInst )
702 {
703     ConfigTreeData *config_data = NULL;
704
705     if( pnmtv->itemOld.hItem )
706         config_data = FindModuleConfig( (ConfigTreeData *)pnmtv->itemOld.lParam );
707
708     if( config_data && config_data->panel )
709     {
710         config_data->panel->Hide();
711     }
712
713     /* Don't use event.GetItem() because we also send fake events */
714     TVITEM tvi = {0};
715     tvi.mask = TVIF_PARAM;
716     tvi.hItem = TreeView_GetSelection( hwndTV );
717     TreeView_GetItem( hwndTV, &tvi );
718     config_data = FindModuleConfig( (ConfigTreeData *)tvi.lParam );
719     if( config_data )
720     {
721         if( !config_data->panel )
722         {
723             /* The panel hasn't been created yet. Let's do it. */
724             config_data->panel =
725                 new PrefsPanel( parent, hInst, p_intf, p_prefs_dialog,
726                                 config_data->p_module,
727                                 config_data->psz_name,
728                                 config_data->psz_help, config_data );
729         }
730         else
731         {
732             config_data->panel->Show();
733         }
734     }
735 }
736
737 /*****************************************************************************
738  * PrefsPanel class definition.
739  *****************************************************************************/
740 PrefsPanel::PrefsPanel( HWND parent, HINSTANCE hInst, intf_thread_t *_p_intf,
741                         PrefsDialog *_p_prefs_dialog,
742                         module_t *p_module, char *psz_name, char *psz_help, ConfigTreeData * config_data )
743 {
744     module_config_t *p_item, *p_config, *p_end;
745
746     /* Initializations */
747     p_intf = _p_intf;
748     p_prefs_dialog = _p_prefs_dialog;
749     module_t **p_list;
750
751     b_advanced = true;
752
753     if( config_data->i_type == TYPE_CATEGORY )
754     {
755         label = CreateWindow( _T("STATIC"), _FROMMB(psz_name),
756                               WS_CHILD | WS_VISIBLE | SS_LEFT,
757                               5, 10 + (15 + 10), 200, 15,
758                               parent, NULL, hInst, NULL );
759         config_window = NULL;
760     }
761     else
762     {
763         /* Get a pointer to the module */
764         if( config_data->i_type == TYPE_MODULE )
765         {
766             p_module = config_data->p_module;
767         }
768         else
769         {
770             /* List the plugins */
771             size_t i_index;
772             bool b_found = false;
773             p_list = module_list_get( NULL );
774
775             for( i_index = 0; p_list[i_index]; i_index++ )
776             {
777                 p_module = p_list[i_index];
778                 if( !strcmp( module_get_object(p_module), "main" ) )
779                 {
780                     b_found = true;
781                     break;
782                 }
783             }
784             if( !p_module && !b_found )
785             {
786                 msg_Warn( p_intf, "unable to create preferences "
787                         "(main module not found)" );
788                 return;
789             }
790         }
791
792         /* Enumerate config options and add corresponding config boxes
793          * (submodules don't have config options, they are stored in the
794          *  parent module) */
795         unsigned confsize;
796         p_config = module_config_get( (module_t *) p_module,&confsize);
797
798         p_item = p_config;
799         p_end = p_config + confsize;
800
801         /* Find the category if it has been specified */
802         if( config_data->i_type == TYPE_SUBCATEGORY ||
803             config_data->i_type == TYPE_CATSUBCAT )
804         {
805             for( ; p_item && p_item < p_end ; p_item++ )
806             {
807                 if( p_item->i_type == CONFIG_SUBCATEGORY &&
808                     ( config_data->i_type == TYPE_SUBCATEGORY &&
809                     p_item->value.i == config_data->i_object_id ) ||
810                     ( config_data->i_type == TYPE_CATSUBCAT &&
811                     p_item->value.i == config_data->i_subcat_id ) )
812                 {
813                     break;
814                 }
815             }
816         }
817
818         /* Add a head title to the panel */
819         const char *psz_head;
820         if( config_data->i_type == TYPE_SUBCATEGORY ||
821             config_data->i_type == TYPE_CATSUBCAT )
822         {
823             psz_head = config_data->psz_name;
824             p_item++;
825         }
826         else
827         {
828             psz_head = module_GetLongName(p_module);
829         }
830
831         label = CreateWindow( _T("STATIC"), _FROMMB(psz_head ?
832                 psz_head : _("Unknown")),
833                         WS_CHILD | WS_VISIBLE | SS_LEFT,
834                         5, 10 + (15 + 10), 250, 15,
835                                  parent, NULL, hInst, NULL );
836
837         WNDCLASS wc;
838         memset( &wc, 0, sizeof(wc) );
839         wc.style          = CS_HREDRAW | CS_VREDRAW;
840         wc.lpfnWndProc    = (WNDPROC) _p_prefs_dialog->BaseWndProc;
841         wc.cbClsExtra     = 0;
842         wc.cbWndExtra     = 0;
843         wc.hInstance      = hInst;
844         wc.hIcon          = 0;
845         wc.hCursor        = 0;
846         wc.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
847         wc.lpszMenuName   = 0;
848         wc.lpszClassName  = _T("PrefsPanelClass");
849         RegisterClass(&wc);
850
851         RECT rc;
852         GetWindowRect( parent, &rc);
853         config_window = CreateWindow( _T("PrefsPanelClass"),
854                         _T("config_window"),
855                         WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER,
856                         5, 10 + 2*(15 + 10), rc.right - 5 - 7, 105,
857                         parent, NULL, hInst, (void *) _p_prefs_dialog );
858
859         int y_pos = 5;
860         for( ; p_item && p_item < p_end ; p_item++ )
861         {
862             /* If a category has been specified, check we finished the job */
863             if( ( ( config_data->i_type == TYPE_SUBCATEGORY &&
864                     p_item->value.i != config_data->i_object_id ) ||
865                     ( config_data->i_type == TYPE_CATSUBCAT  &&
866                     p_item->value.i != config_data->i_subcat_id ) ) &&
867                     (p_item->i_type == CONFIG_CATEGORY ||
868                     p_item->i_type == CONFIG_SUBCATEGORY ) )
869                 break;
870
871             ConfigControl *control = NULL;
872
873             control = CreateConfigControl( VLC_OBJECT(p_intf),
874                                      p_item, config_window,
875                                      hInst, &y_pos );
876
877             /* Don't add items that were not recognized */
878             if( control == NULL ) continue;
879
880             /* Add the config data to our array so we can keep a trace of it */
881             config_array.push_back( control );
882         }
883         GetWindowRect( config_window, &rc);
884         maxvalue = y_pos - (rc.bottom - rc.top) + 5;
885         oldvalue = 0;
886         SetScrollRange( config_window, SB_VERT, 0, maxvalue, TRUE );
887     }
888 }
889
890 void PrefsPanel::Hide()
891 {
892     ShowWindow( label, SW_HIDE );
893     if( config_window ) ShowWindow( config_window, SW_HIDE );
894 }
895
896 void PrefsPanel::Show()
897 {
898     ShowWindow( label, SW_SHOW );
899     if( config_window ) ShowWindow( config_window, SW_SHOW );
900 }
901
902 void PrefsPanel::ApplyChanges()
903 {
904     vlc_value_t val;
905     for( size_t i = 0; i < config_array.size(); i++ )
906     {
907         ConfigControl *control = config_array[i];
908
909         switch( control->GetType() )
910         {
911         case CONFIG_ITEM_STRING:
912         case CONFIG_ITEM_FILE:
913         case CONFIG_ITEM_DIRECTORY:
914         case CONFIG_ITEM_MODULE:
915             config_PutPsz( p_intf, control->GetName(),
916                            control->GetPszValue() );
917             break;
918         case CONFIG_ITEM_KEY:
919             /* So you don't need to restart to have the changes take effect */
920             val.i_int = control->GetIntValue();
921             var_Set( p_intf->p_libvlc, control->GetName(), val );
922         case CONFIG_ITEM_INTEGER:
923         case CONFIG_ITEM_BOOL:
924             config_PutInt( p_intf, control->GetName(),
925                            control->GetIntValue() );
926             break;
927         case CONFIG_ITEM_FLOAT:
928             config_PutFloat( p_intf, control->GetName(),
929                              control->GetFloatValue() );
930             break;
931         }
932     }
933 }