]> git.sesse.net Git - vlc/blob - modules/gui/wince/preferences.cpp
* modules/gui/wince/*: New Windows CE interface by Cedric Marodon <cedric_marodon...
[vlc] / modules / gui / wince / preferences.cpp
1 /*****************************************************************************
2  * preferences.cpp : WinCE gui plugin for VLC
3  *****************************************************************************
4  * Copyright (C) 2000-2004 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29 #include <vlc/intf.h>
30 #include <string.h>
31
32 #include <string>
33 #include <stdio.h>
34 using namespace std; 
35
36 #include <winuser.h>
37 #include <windows.h>
38 #include <windowsx.h>
39 #include <commctrl.h>
40 #include <aygshell.h>
41
42 #include <commdlg.h>
43
44 #include <vlc_config_cat.h>
45
46 #include "wince.h"
47 #include "preferences_widgets.h"
48
49 #define GENERAL_ID 1242
50 #define PLUGIN_ID 1243
51 #define CAPABILITY_ID 1244
52
53 /*****************************************************************************
54  * Event Table.
55  *****************************************************************************/
56
57 /* IDs for the controls and the menu commands */
58 enum
59 {
60     Notebook_Event,
61     MRL_Event,
62     ResetAll_Event,
63     Advanced_Event
64 };
65
66 /*****************************************************************************
67  * Classes declarations.
68  *****************************************************************************/
69 class ConfigTreeData;
70 class PrefsTreeCtrl
71 {
72 public:
73
74     PrefsTreeCtrl() { }
75     PrefsTreeCtrl( intf_thread_t *_p_intf, PrefsDialog *p_prefs_dialog, 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     vlc_bool_t b_advanced;
91
92     HTREEITEM root_item;
93     HTREEITEM general_item;
94     HTREEITEM plugins_item;
95 };
96
97 class PrefsPanel
98 {
99 public:
100
101     PrefsPanel() { }
102     PrefsPanel( HWND parent, HINSTANCE hInst, intf_thread_t *_p_intf,
103                 PrefsDialog *, int i_object_id, char *, char * );
104     virtual ~PrefsPanel() {}
105
106     void Hide();
107     void Show();
108
109     HWND config_window;
110
111     int oldvalue;
112     int maxvalue;
113
114     void ApplyChanges();
115
116 private:
117     intf_thread_t *p_intf;
118     PrefsDialog *p_prefs_dialog;
119
120     vlc_bool_t b_advanced;
121
122     HWND label;
123
124     vector<ConfigControl *> config_array;
125 };
126
127 class ConfigTreeData
128 {
129 public:
130
131     ConfigTreeData() { b_submodule = 0; panel = NULL; psz_section = NULL;
132                        psz_help = NULL; }
133     virtual ~ConfigTreeData() { if( panel ) delete panel;
134                                 if( psz_section) free(psz_section);
135                                 if( psz_help) free(psz_help); }
136
137     vlc_bool_t b_submodule;
138
139     PrefsPanel *panel;
140     int i_object_id;
141     char *psz_section;
142     char *psz_help;
143 };
144
145 /*****************************************************************************
146  * Constructor.
147  *****************************************************************************/
148 PrefsDialog::PrefsDialog( intf_thread_t *_p_intf, HINSTANCE _hInst )
149 {
150     /* Initializations */
151     p_intf = _p_intf;
152     hInst = _hInst;
153     prefs_tree = NULL;
154 }
155
156 /***********************************************************************
157
158 FUNCTION: 
159   WndProc
160
161 PURPOSE: 
162   Processes messages sent to the main window.
163   
164 ***********************************************************************/
165 LRESULT PrefsDialog::WndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
166                               PBOOL pbProcessed  )
167 {
168     SHINITDLGINFO shidi;
169     SHMENUBARINFO mbi;
170     RECT rcClient;
171
172     LRESULT lResult = CBaseWindow::WndProc( hwnd, msg, wp, lp, pbProcessed );
173     BOOL bWasProcessed = *pbProcessed;
174     *pbProcessed = TRUE;
175
176     switch( msg )
177     {
178     case WM_INITDIALOG: 
179         shidi.dwMask = SHIDIM_FLAGS;
180         shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN |
181             SHIDIF_FULLSCREENNOMENUBAR;//SHIDIF_SIZEDLGFULLSCREEN;
182         shidi.hDlg = hwnd;
183         SHInitDialog( &shidi );
184
185         //Create the menubar
186         memset( &mbi, 0, sizeof (SHMENUBARINFO) );
187         mbi.cbSize     = sizeof (SHMENUBARINFO);
188         mbi.hwndParent = hwnd;
189         mbi.nToolBarId = IDR_DUMMYMENU;
190         mbi.hInstRes   = hInst;
191         mbi.nBmpId     = 0;
192         mbi.cBmpImages = 0;  
193
194         if( !SHCreateMenuBar(&mbi) )
195         {
196             MessageBox(hwnd, L"SHCreateMenuBar Failed", L"Error", MB_OK);
197             //return -1;
198         }
199
200         hwndCB = mbi.hwndMB;
201
202         // Get the client area rect to put the panels in
203         GetClientRect(hwnd, &rcClient);
204
205         /* Create the buttons */                
206         advanced_checkbox =
207             CreateWindow( _T("BUTTON"), _T("Advanced options"),
208                         WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
209                         5, 10, 15, 15, hwnd, NULL, hInst, NULL );
210         SendMessage( advanced_checkbox, BM_SETCHECK, BST_UNCHECKED, 0 );
211
212         advanced_label = CreateWindow( _T("STATIC"), _T("Advanced options"),
213                         WS_CHILD | WS_VISIBLE | SS_LEFT,
214                         5 + 15 + 5, 10, 110, 15,
215                         hwnd, NULL, hInst, NULL);
216
217         if( config_GetInt( p_intf, "advanced" ) )
218         {
219             SendMessage( advanced_checkbox, BM_SETCHECK, BST_CHECKED, 0 );
220             /*dummy_event.SetInt(TRUE);
221               OnAdvanced( dummy_event );*/
222         }
223
224         reset_button = CreateWindow( _T("BUTTON"), _T("Reset All"),
225                         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
226                         rcClient.right - 5 - 80, 10 - 3, 80, 15 + 6,
227                         hwnd, NULL, hInst, NULL );
228
229         /* Create the preferences tree control */
230         prefs_tree = new PrefsTreeCtrl( p_intf, this, hwnd, hInst );
231
232         UpdateWindow( hwnd );
233         return lResult;
234
235     case WM_COMMAND:
236         if( LOWORD(wp) == IDOK )
237         {
238             OnOk();
239             EndDialog( hwnd, LOWORD( wp ) );
240             return TRUE;
241         }
242         *pbProcessed = bWasProcessed;
243         lResult = FALSE;
244         return lResult;
245
246     case WM_NOTIFY:
247
248         if ( ( ((LPNMHDR)lp)->hwndFrom == prefs_tree->hwndTV ) &&
249              ( ((LPNMHDR)lp)->code == TVN_SELCHANGED  ) )
250         {
251             prefs_tree->OnSelectTreeItem( (NM_TREEVIEW FAR *)(LPNMHDR)lp,
252                                           hwnd, hInst );
253             return TRUE;
254         }
255
256         *pbProcessed = bWasProcessed;
257         lResult = FALSE;
258         return lResult;
259
260     case WM_VSCROLL:
261     {
262         TVITEM tvi = {0};
263         tvi.mask = TVIF_PARAM;
264         tvi.hItem = TreeView_GetSelection( prefs_tree->hwndTV );
265         TreeView_GetItem( prefs_tree->hwndTV, &tvi );
266         ConfigTreeData *config_data = prefs_tree->FindModuleConfig( (ConfigTreeData *)tvi.lParam );
267         if ( hwnd == config_data->panel->config_window ) 
268         {
269             int dy;
270             RECT rc;
271             GetWindowRect( hwnd, &rc);
272             int newvalue = config_data->panel->oldvalue;
273             switch ( GET_WM_VSCROLL_CODE(wp,lp) ) 
274             {
275             case SB_BOTTOM       : newvalue = 0; break;
276             case SB_TOP          : newvalue = config_data->panel->maxvalue; break;
277             case SB_LINEDOWN     : newvalue += 10; break;
278             case SB_PAGEDOWN     : newvalue += rc.bottom - rc.top - 25; break; // faux ! une page c'est la longueur réelle de notebook
279             case SB_LINEUP       : newvalue -= 10; break;
280             case SB_PAGEUP       : newvalue -= rc.bottom - rc.top - 25; break;
281             case SB_THUMBPOSITION:
282             case SB_THUMBTRACK   : newvalue = GET_WM_VSCROLL_POS(wp,lp); break;
283             }
284             newvalue = max(0,min(config_data->panel->maxvalue,newvalue));
285             SetScrollPos( hwnd,SB_VERT,newvalue,TRUE);//SB_CTL si hwnd=hwndScrollBar, SB_VERT si window
286             dy = config_data->panel->oldvalue - newvalue;
287
288             ScrollWindowEx( hwnd, 0, dy, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN );
289             UpdateWindow ( hwnd);
290
291             config_data->panel->oldvalue = newvalue;                                
292         }
293     }
294     *pbProcessed = bWasProcessed;
295     lResult = FALSE;
296     return lResult;
297
298     default:
299         // the message was not processed
300         // indicate if the base class handled it
301         *pbProcessed = bWasProcessed;
302         lResult = FALSE;
303         return lResult;
304     }
305
306     return lResult;
307 }
308
309 /*****************************************************************************
310  * Private methods.
311  *****************************************************************************/
312
313 /*****************************************************************************
314  * Events methods.
315  *****************************************************************************/
316 void PrefsDialog::OnOk( void )
317 {
318     prefs_tree->ApplyChanges();
319     config_SaveConfigFile( p_intf, NULL );
320 }
321
322 /*****************************************************************************
323  * PrefsTreeCtrl class definition.
324  *****************************************************************************/
325 PrefsTreeCtrl::PrefsTreeCtrl( intf_thread_t *_p_intf,
326                               PrefsDialog *_p_prefs_dialog, HWND hwnd,
327                               HINSTANCE hInst )
328 {
329     vlc_list_t      *p_list;
330     module_t        *p_module;
331     module_config_t *p_item;
332     int i_index;
333
334     INITCOMMONCONTROLSEX iccex;
335     RECT rcClient;
336
337     int size;
338     char *szAnsi;
339     LPWSTR wUnicode;
340     BOOL bTemp;
341     TVITEM tvi = {0}; 
342     TVINSERTSTRUCT tvins = {0}; 
343     HTREEITEM hPrev;
344
345     size_t i_capability_count = 0;
346     size_t i_child_index;
347
348     HTREEITEM capability_item;
349
350     /* Initializations */
351     p_intf = _p_intf;
352     p_prefs_dialog = _p_prefs_dialog;
353     b_advanced = VLC_FALSE;
354
355     /* Create a tree view */
356     // Initialize the INITCOMMONCONTROLSEX structure.
357     iccex.dwSize = sizeof( INITCOMMONCONTROLSEX );
358     iccex.dwICC = ICC_TREEVIEW_CLASSES;
359
360     // Registers Statusbar control classes from the common control dll
361     InitCommonControlsEx( &iccex );
362
363     // Get the client area rect to put the tv in
364     GetClientRect(hwnd, &rcClient);
365
366     // Create the tree-view control.
367     hwndTV = CreateWindowEx( 0, WC_TREEVIEW, NULL,
368         WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES |
369         TVS_LINESATROOT | TVS_HASBUTTONS,
370         5, 10 + 2*(15 + 10) + 105 + 5, rcClient.right - 5 - 5, 6*15,
371         hwnd, NULL, hInst, NULL );
372
373     tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; 
374     tvi.pszText = _T("root");
375     tvi.cchTextMax = lstrlen(_T("root"));
376     tvi.lParam = (LPARAM) 1; // root level
377     tvins.item = tvi;
378     tvins.hInsertAfter = TVI_FIRST; 
379     tvins.hParent = TVI_ROOT; 
380
381     // Add the item to the tree-view control. 
382     hPrev = (HTREEITEM) TreeView_InsertItem( hwndTV, &tvins );
383     root_item = hPrev;
384
385     /* List the plugins */
386     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
387     if( !p_list ) return;
388
389     /*
390      * Build a tree of the main options
391      */
392     ConfigTreeData *config_data = new ConfigTreeData;
393     config_data->i_object_id = GENERAL_ID;
394     config_data->psz_help = strdup("nothing");//strdup( GENERAL_HELP );
395     config_data->psz_section = strdup( GENERAL_TITLE );
396     tvi.pszText = _T("General settings");
397     tvi.cchTextMax = lstrlen(_T("General settings"));
398     tvi.lParam = (long) config_data;
399     tvins.item = tvi;
400     tvins.hInsertAfter = hPrev;
401     tvins.hParent = root_item; //level 2
402
403     // Add the item to the tree-view control.
404     hPrev = (HTREEITEM) TreeView_InsertItem( hwndTV, &tvins);
405     general_item = hPrev;
406
407     for( i_index = 0; i_index < p_list->i_count; i_index++ )
408     {
409         p_module = (module_t *)p_list->p_values[i_index].p_object;
410         if( !strcmp( p_module->psz_object_name, "main" ) )
411             break;
412     }
413     if( i_index < p_list->i_count )
414     {
415         /* We found the main module */
416
417         /* Enumerate config categories and store a reference so we can
418          * generate their config panel them when it is asked by the user. */
419         p_item = p_module->p_config;
420
421         if( p_item ) do
422         {
423             switch( p_item->i_type )
424             {
425             case CONFIG_HINT_CATEGORY:
426                 ConfigTreeData *config_data = new ConfigTreeData;
427                 config_data->psz_section = strdup( p_item->psz_text );
428                 if( p_item->psz_longtext )
429                 {
430                     config_data->psz_help =
431                         strdup( p_item->psz_longtext );
432                 }
433                 else
434                 {
435                     config_data->psz_help = NULL;
436                 }
437                 config_data->i_object_id = p_module->i_object_id;
438
439                 /* Add the category to the tree */
440                 // Set the text of the item. 
441                 tvi.pszText = _FROMMB(p_item->psz_text); 
442                 tvi.cchTextMax = _tcslen(tvi.pszText);
443                 tvi.lParam = (long)config_data;
444                 tvins.item = tvi;
445                 tvins.hInsertAfter = hPrev; 
446                 tvins.hParent = general_item; //level 3
447     
448                 // Add the item to the tree-view control. 
449                 hPrev = (HTREEITEM)TreeView_InsertItem( hwndTV, &tvins );
450
451                 break;
452             }
453         }
454         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
455
456         TreeView_SortChildren( hwndTV, general_item, 0 );
457     }
458         
459     /*
460      * Build a tree of all the plugins
461      */
462     config_data = new ConfigTreeData;
463     config_data->i_object_id = PLUGIN_ID;
464     config_data->psz_help = strdup("nothing");//strdup( PLUGIN_HELP );
465     config_data->psz_section = strdup("nothing");//strdup( PLUGIN_TITLE );
466     tvi.pszText = _T("Modules");
467     tvi.cchTextMax = lstrlen(_T("Modules"));
468     tvi.lParam = (long) config_data;
469     tvins.item = tvi;
470     tvins.hInsertAfter = hPrev;
471     tvins.hParent = root_item;// level 2
472
473     // Add the item to the tree-view control.
474     hPrev = (HTREEITEM) TreeView_InsertItem( hwndTV, &tvins);
475     plugins_item = hPrev;
476
477     i_capability_count = 0;
478     for( i_index = 0; i_index < p_list->i_count; i_index++ )
479     {
480         i_child_index = 0;
481
482         p_module = (module_t *)p_list->p_values[i_index].p_object;
483
484         /* Exclude the main module */
485         if( !strcmp( p_module->psz_object_name, "main" ) )
486             continue;
487
488         /* Exclude empty plugins (submodules don't have config options, they
489          * are stored in the parent module) */
490         if( p_module->b_submodule )
491             p_item = ((module_t *)p_module->p_parent)->p_config;
492         else
493             p_item = p_module->p_config;
494
495         if( !p_item ) continue;
496         do
497         {
498             if( p_item->i_type & CONFIG_ITEM )
499                 break;
500         }
501         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
502         if( p_item->i_type == CONFIG_HINT_END ) continue;
503
504         /* Find the capability child item */
505         /*long cookie; size_t i_child_index;*/
506         capability_item = TreeView_GetChild( hwndTV, plugins_item );
507         while( capability_item != 0 )
508         {
509             TVITEM capability_tvi = {0};
510
511             i_child_index++;
512
513             capability_tvi.mask = TVIF_TEXT;
514             capability_tvi.pszText = new WCHAR[200];
515             capability_tvi.cchTextMax = 200;
516             capability_tvi.hItem = capability_item;
517             TreeView_GetItem( hwndTV, &capability_tvi );
518             size = WideCharToMultiByte( CP_ACP, 0, capability_tvi.pszText, -1, NULL, 0, NULL, &bTemp );
519             szAnsi = new char[size];
520             WideCharToMultiByte( CP_ACP, 0, capability_tvi.pszText, -1, szAnsi, size, NULL, &bTemp );       
521             if( !strcmp( szAnsi, p_module->psz_capability ) )
522             {
523                 free( szAnsi );
524                 free( capability_tvi.pszText );
525                 break;
526             }
527             free( szAnsi );
528             free( capability_tvi.pszText );
529
530             capability_item = TreeView_GetNextSibling( hwndTV, capability_item );
531         }
532
533         if( i_child_index == i_capability_count &&
534             p_module->psz_capability && *p_module->psz_capability )
535         {
536             /* We didn't find it, add it */
537             ConfigTreeData *config_data = new ConfigTreeData;
538             config_data->psz_section =
539                 strdup( GetCapabilityHelp( p_module->psz_capability , 1 ) );
540             config_data->psz_help =
541                 strdup( GetCapabilityHelp( p_module->psz_capability , 2 ) );
542             config_data->i_object_id = CAPABILITY_ID;
543             tvi.pszText = _FROMMB(p_module->psz_capability);
544             tvi.cchTextMax = _tcslen(tvi.pszText);
545             tvi.lParam = (long) config_data;
546             tvins.item = tvi;
547             tvins.hInsertAfter = plugins_item; 
548             tvins.hParent = plugins_item;// level 3
549
550             // Add the item to the tree-view control. 
551             capability_item = (HTREEITEM) TreeView_InsertItem( hwndTV, &tvins);
552
553             i_capability_count++;
554         }
555
556         /* Add the plugin to the tree */
557         ConfigTreeData *config_data = new ConfigTreeData;
558         config_data->b_submodule = p_module->b_submodule;
559         config_data->i_object_id = p_module->b_submodule ?
560             ((module_t *)p_module->p_parent)->i_object_id :
561             p_module->i_object_id;
562         config_data->psz_help = NULL;
563         tvi.pszText = _FROMMB(p_module->psz_object_name);
564         tvi.cchTextMax = _tcslen(tvi.pszText);
565         tvi.lParam = (long) config_data;
566         tvins.item = tvi;
567         tvins.hInsertAfter = capability_item; 
568         tvins.hParent = capability_item;// level 4
569
570         // Add the item to the tree-view control. 
571         TreeView_InsertItem( hwndTV, &tvins);
572     }
573
574     /* Sort all this mess */
575     /*long cookie; size_t i_child_index;*/
576     TreeView_SortChildren( hwndTV, plugins_item, 0 );
577     capability_item = TreeView_GetChild( hwndTV, plugins_item );
578     while( capability_item != 0 )
579     {
580         TreeView_SortChildren( hwndTV, capability_item, 0 );
581         capability_item = TreeView_GetNextSibling( hwndTV, capability_item );
582     }
583
584     /* Clean-up everything */
585     vlc_list_release( p_list );
586
587     TreeView_Expand( hwndTV, root_item, TVE_EXPANDPARTIAL |TVE_EXPAND );
588     TreeView_Expand( hwndTV, general_item, TVE_EXPANDPARTIAL |TVE_EXPAND );
589 }
590
591 PrefsTreeCtrl::~PrefsTreeCtrl()
592 {
593 }
594
595 void PrefsTreeCtrl::ApplyChanges()
596 {
597     /*long cookie, cookie2;*/
598     ConfigTreeData *config_data;
599
600     /* Apply changes to the main module */
601     HTREEITEM item = TreeView_GetChild( hwndTV, general_item );
602     while( item != 0 )
603     {
604         TVITEM tvi = {0};
605         tvi.mask = TVIF_PARAM;
606         tvi.hItem = item;
607         TreeView_GetItem( hwndTV, &tvi );
608         config_data = (ConfigTreeData *)tvi.lParam;
609         if( config_data && config_data->panel )
610         {
611             config_data->panel->ApplyChanges();
612         }
613
614         item = TreeView_GetNextSibling( hwndTV, item );
615     }
616
617     /* Apply changes to the plugins */
618     item = TreeView_GetChild( hwndTV, plugins_item );
619     while( item != 0 )
620     {
621         HTREEITEM item2 = TreeView_GetChild( hwndTV, item );
622         while( item2 != 0 )
623         {       
624             TVITEM tvi = {0};
625             tvi.mask = TVIF_PARAM;
626             tvi.hItem = item2;
627             TreeView_GetItem( hwndTV, &tvi );
628             config_data = (ConfigTreeData *)tvi.lParam;
629             if( config_data && config_data->panel )
630             {
631                 config_data->panel->ApplyChanges();
632             }
633             item2 = TreeView_GetNextSibling( hwndTV, item2 );
634         }
635         item = TreeView_GetNextSibling( hwndTV, item );
636     }
637 }
638
639 ConfigTreeData *PrefsTreeCtrl::FindModuleConfig( ConfigTreeData *config_data )
640 {
641     /* We need this complexity because submodules don't have their own config
642      * options. They use the parent module ones. */
643
644     if( !config_data || !config_data->b_submodule )
645     {
646         return config_data;
647     }
648
649     /*long cookie, cookie2;*/
650     ConfigTreeData *config_new;
651     HTREEITEM item = TreeView_GetChild( hwndTV, plugins_item );
652     while( item != 0 )
653     {
654         HTREEITEM item2 = TreeView_GetChild( hwndTV, item );
655         while( item2 != 0 )
656         {       
657             TVITEM tvi = {0};
658             tvi.mask = TVIF_PARAM;
659             tvi.hItem = item2;
660             TreeView_GetItem( hwndTV, &tvi );
661             config_new = (ConfigTreeData *)tvi.lParam;
662             if( config_new && !config_new->b_submodule &&
663                 config_new->i_object_id == config_data->i_object_id )
664             {
665                 return config_new;
666             }
667             item2 = TreeView_GetNextSibling( hwndTV, item2 );
668         }
669         item = TreeView_GetNextSibling( hwndTV, item );
670     }
671
672     /* Found nothing */
673     return NULL;
674 }
675
676 void PrefsTreeCtrl::OnSelectTreeItem( LPNM_TREEVIEW pnmtv, HWND parent,
677                                       HINSTANCE hInst )
678 {
679     ConfigTreeData *config_data = NULL;
680
681     if( pnmtv->itemOld.hItem )
682         config_data = FindModuleConfig( (ConfigTreeData *)pnmtv->itemOld.lParam );
683
684     if( config_data && config_data->panel )
685     {
686         config_data->panel->Hide();
687     }
688
689     /* Don't use event.GetItem() because we also send fake events */
690     TVITEM tvi = {0};
691     tvi.mask = TVIF_PARAM;
692     tvi.hItem = TreeView_GetSelection( hwndTV );
693     TreeView_GetItem( hwndTV, &tvi );
694     config_data = FindModuleConfig( (ConfigTreeData *)tvi.lParam );
695     if( config_data )
696     {
697         if( !config_data->panel )
698         {
699             /* The panel hasn't been created yet. Let's do it. */
700             config_data->panel =
701                 new PrefsPanel( parent, hInst, p_intf, p_prefs_dialog,
702                                 config_data->i_object_id,
703                                 config_data->psz_section,
704                                 config_data->psz_help );
705         }
706         else
707         {
708             config_data->panel->Show();
709         }
710     }
711 }
712
713 /*****************************************************************************
714  * PrefsPanel class definition.
715  *****************************************************************************/
716 PrefsPanel::PrefsPanel( HWND parent, HINSTANCE hInst, intf_thread_t *_p_intf,
717                         PrefsDialog *_p_prefs_dialog,
718                         int i_object_id, char *psz_section, char *psz_help )
719 {
720     module_config_t *p_item;
721     module_t *p_module = NULL;
722
723     /* Initializations */
724     p_intf = _p_intf;
725     p_prefs_dialog = _p_prefs_dialog;
726
727     b_advanced = VLC_TRUE;
728
729     if( i_object_id == PLUGIN_ID || i_object_id == GENERAL_ID ||
730         i_object_id == CAPABILITY_ID )
731     {
732         label = CreateWindow( _T("STATIC"), _FROMMB(psz_section),
733                               WS_CHILD | WS_VISIBLE | SS_LEFT,
734                               5, 10 + (15 + 10), 200, 15,
735                               parent, NULL, hInst, NULL );
736         config_window = NULL;
737     }
738     else
739     {
740         /* Get a pointer to the module */
741         p_module = (module_t *)vlc_object_get( p_intf,  i_object_id );
742         if( p_module->i_object_type != VLC_OBJECT_MODULE )
743         {
744             /* 0OOoo something went really bad */
745             return;
746         }
747
748         /* Enumerate config options and add corresponding config boxes
749          * (submodules don't have config options, they are stored in the
750          *  parent module) */
751         if( p_module->b_submodule )
752             p_item = ((module_t *)p_module->p_parent)->p_config;
753         else
754             p_item = p_module->p_config;
755
756         /* Find the category if it has been specified */
757         if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY )
758         {
759             while( !p_item->i_type == CONFIG_HINT_CATEGORY ||
760                    strcmp( psz_section, p_item->psz_text ) )
761             {
762                 if( p_item->i_type == CONFIG_HINT_END )
763                     break;
764                 p_item++;
765             }
766         }
767
768         /* Add a head title to the panel */
769         label = CreateWindow( _T("STATIC"), _FROMMB(psz_section ?
770                         p_item->psz_text : p_module->psz_longname),
771                         WS_CHILD | WS_VISIBLE | SS_LEFT,
772                         5, 10 + (15 + 10), 250, 15,
773                         parent, NULL, hInst, NULL );
774
775         WNDCLASS wc;
776         memset( &wc, 0, sizeof(wc) );
777         wc.style          = CS_HREDRAW | CS_VREDRAW;
778         wc.lpfnWndProc    = (WNDPROC) _p_prefs_dialog->BaseWndProc;
779         wc.cbClsExtra     = 0;
780         wc.cbWndExtra     = 0;
781         wc.hInstance      = hInst;
782         wc.hIcon          = 0;
783         wc.hCursor        = 0;
784         wc.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
785         wc.lpszMenuName   = 0;
786         wc.lpszClassName  = _T("PrefsPanelClass");
787         RegisterClass(&wc);
788
789         RECT rc;
790         GetWindowRect( parent, &rc);
791         config_window = CreateWindow( _T("PrefsPanelClass"),
792                         _T("config_window"),
793                         WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER,
794                         5, 10 + 2*(15 + 10), rc.right - 5 - 7, 105,
795                         parent, NULL, hInst, (void *) _p_prefs_dialog );
796
797         int y_pos = 5;
798         if( p_item ) do
799         {
800             /* If a category has been specified, check we finished the job */
801             if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY &&
802                 strcmp( psz_section, p_item->psz_text ) )
803                 break;
804
805             ConfigControl *control =
806                 CreateConfigControl( VLC_OBJECT(p_intf),
807                                      p_item, config_window,
808                                      hInst, &y_pos );
809
810             /* Don't add items that were not recognized */
811             if( control == NULL ) continue;
812
813             /* Add the config data to our array so we can keep a trace of it */
814             config_array.push_back( control );
815         }
816         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
817                 
818         GetWindowRect( config_window, &rc);
819         maxvalue = y_pos - (rc.bottom - rc.top) + 5;
820         oldvalue = 0;
821         SetScrollRange( config_window, SB_VERT, 0, maxvalue, TRUE );
822     }
823 }
824
825 void PrefsPanel::Hide()
826 {
827     ShowWindow( label, SW_HIDE );
828     if( config_window ) ShowWindow( config_window, SW_HIDE );
829 }
830
831 void PrefsPanel::Show()
832 {
833     ShowWindow( label, SW_SHOW );
834     if( config_window ) ShowWindow( config_window, SW_SHOW );
835 }
836
837 void PrefsPanel::ApplyChanges()
838 {
839     vlc_value_t val;
840
841     for( size_t i = 0; i < config_array.size(); i++ )
842     {
843         ConfigControl *control = config_array[i];
844
845         switch( control->GetType() )
846         {
847         case CONFIG_ITEM_STRING:
848         case CONFIG_ITEM_FILE:
849         case CONFIG_ITEM_DIRECTORY:
850         case CONFIG_ITEM_MODULE:
851             config_PutPsz( p_intf, control->GetName(),
852                            control->GetPszValue() );
853             break;
854         case CONFIG_ITEM_KEY:
855             /* So you don't need to restart to have the changes take effect */
856             val.i_int = control->GetIntValue();
857             var_Set( p_intf->p_vlc, control->GetName(), val );
858         case CONFIG_ITEM_INTEGER:
859         case CONFIG_ITEM_BOOL:
860             config_PutInt( p_intf, control->GetName(),
861                            control->GetIntValue() );
862             break;
863         case CONFIG_ITEM_FLOAT:
864             config_PutFloat( p_intf, control->GetName(),
865                              control->GetFloatValue() );
866             break;
867         }
868     }
869 }