merge down from merged-API-layer branch: cvs -q up -dP -j API_LAYER_MERGING_BASELINE...
[flac.git] / src / plugin_winamp2 / configure.c
1 /* in_flac - Winamp2 FLAC input plugin\r
2  * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson\r
3  *\r
4  * This library is free software; you can redistribute it and/or\r
5  * modify it under the terms of the GNU Lesser General Public\r
6  * License as published by the Free Software Foundation; either\r
7  * version 2.1 of the License, or (at your option) any later version.\r
8  *\r
9  * This library is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
12  * Lesser General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU Lesser General Public\r
15  * License along with this library; if not, write to the Free Software\r
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
17  */\r
18 \r
19 #if HAVE_CONFIG_H\r
20 #  include <config.h>\r
21 #endif\r
22 \r
23 #include <windows.h>\r
24 #include <commctrl.h>\r
25 #include <stdio.h>\r
26 #include "configure.h"\r
27 #include "tagz.h"\r
28 #include "resource.h"\r
29 \r
30 \r
31 static char buffer[256];\r
32 static char ini_name[MAX_PATH];\r
33 \r
34 /*\r
35  *  Read/write config\r
36  */\r
37 \r
38 #define RI(x, def)          (x = GetPrivateProfileInt("FLAC", #x, def, ini_name))\r
39 #define WI(x)               WritePrivateProfileString("FLAC", #x, itoa(x, buffer, 10), ini_name)\r
40 #define RS(x, n, def)       GetPrivateProfileString("FLAC", #x, def, x, n, ini_name)\r
41 #define WS(x)               WritePrivateProfileString("FLAC", #x, x, ini_name)\r
42 \r
43 static const char default_format[] = "[%artist% - ]$if2(%title%,%filename%)";\r
44 static const char default_sep[] = ", ";\r
45 \r
46 static wchar_t *convert_ansi_to_wide_(const char *src)\r
47 {\r
48         int len;\r
49         wchar_t *dest;\r
50 \r
51         FLAC__ASSERT(0 != src);\r
52 \r
53         len = strlen(src) + 1;\r
54         /* copy */\r
55         dest = malloc(len*sizeof(wchar_t));\r
56         if (dest) mbstowcs(dest, src, len);\r
57         return dest;\r
58 }\r
59 \r
60 void InitConfig()\r
61 {\r
62         char *p;\r
63 \r
64         GetModuleFileName(NULL, ini_name, sizeof(ini_name));\r
65         p = strrchr(ini_name, '.');\r
66         if (!p) p = ini_name + strlen(ini_name);\r
67         strcpy(p, ".ini");\r
68 \r
69         flac_cfg.title.tag_format_w = NULL;\r
70 }\r
71 \r
72 void ReadConfig()\r
73 {\r
74         RS(flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format), default_format);\r
75         if (flac_cfg.title.tag_format_w)\r
76                 free(flac_cfg.title.tag_format_w);\r
77         flac_cfg.title.tag_format_w = convert_ansi_to_wide_(flac_cfg.title.tag_format);\r
78         /* @@@ FIXME: trailing spaces */\r
79         RS(flac_cfg.title.sep, sizeof(flac_cfg.title.sep), default_sep);\r
80         RI(flac_cfg.tag.reserve_space, 1);\r
81 \r
82         RI(flac_cfg.display.show_bps, 1);\r
83         RI(flac_cfg.output.misc.stop_err, 0);\r
84         RI(flac_cfg.output.replaygain.enable, 1);\r
85         RI(flac_cfg.output.replaygain.album_mode, 0);\r
86         RI(flac_cfg.output.replaygain.hard_limit, 0);\r
87         RI(flac_cfg.output.replaygain.preamp, 0);\r
88         RI(flac_cfg.output.resolution.normal.dither_24_to_16, 0);\r
89         RI(flac_cfg.output.resolution.replaygain.dither, 0);\r
90         RI(flac_cfg.output.resolution.replaygain.noise_shaping, 1);\r
91         RI(flac_cfg.output.resolution.replaygain.bps_out, 16);\r
92 }\r
93 \r
94 void WriteConfig()\r
95 {\r
96         WS(flac_cfg.title.tag_format);\r
97         WI(flac_cfg.tag.reserve_space);\r
98         WS(flac_cfg.title.sep);\r
99 \r
100         WI(flac_cfg.display.show_bps);\r
101         WI(flac_cfg.output.misc.stop_err);\r
102         WI(flac_cfg.output.replaygain.enable);\r
103         WI(flac_cfg.output.replaygain.album_mode);\r
104         WI(flac_cfg.output.replaygain.hard_limit);\r
105         WI(flac_cfg.output.replaygain.preamp);\r
106         WI(flac_cfg.output.resolution.normal.dither_24_to_16);\r
107         WI(flac_cfg.output.resolution.replaygain.dither);\r
108         WI(flac_cfg.output.resolution.replaygain.noise_shaping);\r
109         WI(flac_cfg.output.resolution.replaygain.bps_out);\r
110 }\r
111 \r
112 /*\r
113  *  Dialog\r
114  */\r
115 \r
116 #define PREAMP_RANGE            24\r
117 \r
118 #define Check(x,y)              CheckDlgButton(hwnd, x, y ? BST_CHECKED : BST_UNCHECKED)\r
119 #define GetCheck(x)             (IsDlgButtonChecked(hwnd, x)==BST_CHECKED)\r
120 #define GetSel(x)               SendDlgItemMessage(hwnd, x, CB_GETCURSEL, 0, 0)\r
121 #define GetPos(x)               SendDlgItemMessage(hwnd, x, TBM_GETPOS, 0, 0)\r
122 #define Enable(x,y)             EnableWindow(GetDlgItem(hwnd, x), y)\r
123 \r
124 static INT_PTR CALLBACK GeneralProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
125 {\r
126         switch (msg)\r
127         {\r
128         /* init */\r
129         case WM_INITDIALOG:\r
130                 SendDlgItemMessage(hwnd, IDC_TITLE, EM_LIMITTEXT, 255, 0);\r
131                 SendDlgItemMessage(hwnd, IDC_SEP, EM_LIMITTEXT, 15, 0);\r
132 \r
133                 SetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format);\r
134                 SetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep);\r
135                 Check(IDC_ID3V1, 0);\r
136 /*!             Check(IDC_RESERVE, flac_cfg.tag.reserve_space); */\r
137                 Check(IDC_BPS, flac_cfg.display.show_bps);\r
138                 Check(IDC_ERRORS, flac_cfg.output.misc.stop_err);\r
139                 return TRUE;\r
140         /* commands */\r
141         case WM_COMMAND:\r
142                 switch (LOWORD(wParam))\r
143                 {\r
144                 /* ok */\r
145                 case IDOK:\r
146                         GetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format));\r
147                         if (flac_cfg.title.tag_format_w)\r
148                                 free(flac_cfg.title.tag_format_w);\r
149                         GetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep, sizeof(flac_cfg.title.sep));\r
150                         flac_cfg.title.tag_format_w = convert_ansi_to_wide_(flac_cfg.title.tag_format);\r
151 \r
152 /*!                     flac_cfg.tag.reserve_space = GetCheck(IDC_RESERVE); */\r
153                         flac_cfg.display.show_bps = GetCheck(IDC_BPS);\r
154                         flac_cfg.output.misc.stop_err = GetCheck(IDC_ERRORS);\r
155                         break;\r
156                 /* reset */\r
157                 case IDC_RESET:\r
158                         Check(IDC_ID3V1, 0);\r
159                         Check(IDC_RESERVE, 1);\r
160                         Check(IDC_BPS, 1);\r
161                         Check(IDC_ERRORS, 0);\r
162                         /* fall throught */\r
163                 /* default */\r
164                 case IDC_TAGZ_DEFAULT:\r
165                         SetDlgItemText(hwnd, IDC_TITLE, default_format);\r
166                         break;\r
167                 /* help */\r
168                 case IDC_TAGZ_HELP:\r
169                         MessageBox(hwnd, tagz_manual, "Help", 0);\r
170                         break;\r
171                 }\r
172                 break;\r
173         }\r
174 \r
175         return 0;\r
176 }\r
177 \r
178 \r
179 static void UpdatePreamp(HWND hwnd, HWND hamp)\r
180 {\r
181         int pos = SendMessage(hamp, TBM_GETPOS, 0, 0) - PREAMP_RANGE;\r
182         sprintf(buffer, "%d dB", pos);\r
183         SetDlgItemText(hwnd, IDC_PA, buffer);\r
184 }\r
185 \r
186 static void UpdateRG(HWND hwnd)\r
187 {\r
188         int on = GetCheck(IDC_ENABLE);\r
189         Enable(IDC_ALBUM, on);\r
190         Enable(IDC_LIMITER, on);\r
191         Enable(IDC_PREAMP, on);\r
192         Enable(IDC_PA, on);\r
193 }\r
194 \r
195 static void UpdateDither(HWND hwnd)\r
196 {\r
197         int on = GetCheck(IDC_DITHERRG);\r
198         Enable(IDC_SHAPE, on);\r
199 }\r
200 \r
201 static INT_PTR CALLBACK OutputProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
202 {\r
203         switch (msg)\r
204         {\r
205         /* init */\r
206         case WM_INITDIALOG:\r
207                 Check(IDC_ENABLE, flac_cfg.output.replaygain.enable);\r
208                 Check(IDC_ALBUM, flac_cfg.output.replaygain.album_mode);\r
209                 Check(IDC_LIMITER, flac_cfg.output.replaygain.hard_limit);\r
210                 Check(IDC_DITHER, flac_cfg.output.resolution.normal.dither_24_to_16);\r
211                 Check(IDC_DITHERRG, flac_cfg.output.resolution.replaygain.dither);\r
212                 /* prepare preamp slider */\r
213                 {\r
214                         HWND hamp = GetDlgItem(hwnd, IDC_PREAMP);\r
215                         SendMessage(hamp, TBM_SETRANGE, 1, MAKELONG(0, PREAMP_RANGE*2));\r
216                         SendMessage(hamp, TBM_SETPOS, 1, flac_cfg.output.replaygain.preamp+PREAMP_RANGE);\r
217                         UpdatePreamp(hwnd, hamp);\r
218                 }\r
219                 /* fill comboboxes */\r
220                 {\r
221                         HWND hlist = GetDlgItem(hwnd, IDC_TO);\r
222                         SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"16 bps");\r
223                         SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"24 bps");\r
224                         SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.bps_out/8 - 2, 0);\r
225 \r
226                         hlist = GetDlgItem(hwnd, IDC_SHAPE);\r
227                         SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"None");\r
228                         SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Low");\r
229                         SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Medium");\r
230                         SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"High");\r
231                         SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.noise_shaping, 0);\r
232                 }\r
233                 UpdateRG(hwnd);\r
234                 UpdateDither(hwnd);\r
235                 return TRUE;\r
236         /* commands */\r
237         case WM_COMMAND:\r
238                 switch (LOWORD(wParam))\r
239                 {\r
240                 /* ok */\r
241                 case IDOK:\r
242                         flac_cfg.output.replaygain.enable = GetCheck(IDC_ENABLE);\r
243                         flac_cfg.output.replaygain.album_mode = GetCheck(IDC_ALBUM);\r
244                         flac_cfg.output.replaygain.hard_limit = GetCheck(IDC_LIMITER);\r
245                         flac_cfg.output.replaygain.preamp = GetPos(IDC_PREAMP) - PREAMP_RANGE;\r
246                         flac_cfg.output.resolution.normal.dither_24_to_16 = GetCheck(IDC_DITHER);\r
247                         flac_cfg.output.resolution.replaygain.dither = GetCheck(IDC_DITHERRG);\r
248                         flac_cfg.output.resolution.replaygain.noise_shaping = GetSel(IDC_SHAPE);\r
249                         flac_cfg.output.resolution.replaygain.bps_out = (GetSel(IDC_TO)+2)*8;\r
250                         break;\r
251                 /* reset */\r
252                 case IDC_RESET:\r
253                         Check(IDC_ENABLE, 1);\r
254                         Check(IDC_ALBUM, 0);\r
255                         Check(IDC_LIMITER, 0);\r
256                         Check(IDC_DITHER, 0);\r
257                         Check(IDC_DITHERRG, 0);\r
258 \r
259                         SendDlgItemMessage(hwnd, IDC_PREAMP, TBM_SETPOS, 1, PREAMP_RANGE);\r
260                         SendDlgItemMessage(hwnd, IDC_TO, CB_SETCURSEL, 0, 0);\r
261                         SendDlgItemMessage(hwnd, IDC_SHAPE, CB_SETCURSEL, 1, 0);\r
262 \r
263                         UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP));\r
264                         UpdateRG(hwnd);\r
265                         UpdateDither(hwnd);\r
266                         break;\r
267                 /* active check-boxes */\r
268                 case IDC_ENABLE:\r
269                         UpdateRG(hwnd);\r
270                         break;\r
271                 case IDC_DITHERRG:\r
272                         UpdateDither(hwnd);\r
273                         break;\r
274                 }\r
275                 break;\r
276         /* scroller */\r
277         case WM_HSCROLL:\r
278                 if (GetDlgCtrlID((HWND)lParam)==IDC_PREAMP)\r
279                         UpdatePreamp(hwnd, (HWND)lParam);\r
280                 return 0;\r
281         }\r
282 \r
283         return 0;\r
284 }\r
285 \r
286 #define NUM_PAGES       2\r
287 \r
288 typedef struct\r
289 {\r
290         HWND htab;\r
291         HWND hdlg;\r
292         RECT r;\r
293         HWND all[NUM_PAGES];\r
294 } LOCALDATA;\r
295 \r
296 static void ScreenToClientRect(HWND hwnd, RECT *rect)\r
297 {\r
298         POINT pt = { rect->left, rect->top };\r
299         ScreenToClient(hwnd, &pt);\r
300         rect->left = pt.x;\r
301         rect->top  = pt.y;\r
302 \r
303         pt.x = rect->right;\r
304         pt.y = rect->bottom;\r
305         ScreenToClient(hwnd, &pt);\r
306         rect->right  = pt.x;\r
307         rect->bottom = pt.y;\r
308 }\r
309 \r
310 static void SendCommand(HWND hwnd, int command)\r
311 {\r
312         LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
313         SendMessage(data->hdlg, WM_COMMAND, command, 0);\r
314 }\r
315 \r
316 static void BroadcastCommand(HWND hwnd, int command)\r
317 {\r
318         LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
319         int i;\r
320 \r
321         for (i=0; i<NUM_PAGES; i++)\r
322                 SendMessage(data->all[i], WM_COMMAND, command, 0);\r
323 }\r
324 \r
325 static void OnSelChange(HWND hwnd)\r
326 {\r
327         LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
328         int index = TabCtrl_GetCurSel(data->htab);\r
329         if (index < 0) return;\r
330         /* hide previous */\r
331         if (data->hdlg)\r
332                 ShowWindow(data->hdlg, SW_HIDE);\r
333         /* display */\r
334         data->hdlg = data->all[index];\r
335         SetWindowPos(data->hdlg, HWND_TOP, data->r.left, data->r.top, data->r.right-data->r.left, data->r.bottom-data->r.top, SWP_SHOWWINDOW);\r
336         SetFocus(hwnd);\r
337 }\r
338 \r
339 static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
340 {\r
341         static activePage = 0;\r
342 \r
343         switch (msg)\r
344         {\r
345         /* init */\r
346         case WM_INITDIALOG:\r
347                 {\r
348                         LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));\r
349                         HINSTANCE inst = (HINSTANCE)lParam;\r
350                         TCITEM item;\r
351 \r
352                         /* init */\r
353                         SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);\r
354                         data->htab = GetDlgItem(hwnd, IDC_TABS);\r
355                         data->hdlg = NULL;\r
356                         /* add pages */\r
357                         item.mask = TCIF_TEXT;\r
358                         data->all[0] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_GENERAL), hwnd, GeneralProc);\r
359                         item.pszText = "General";\r
360                         TabCtrl_InsertItem(data->htab, 0, &item);\r
361 \r
362                         data->all[1] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_OUTPUT), hwnd, OutputProc);\r
363                         item.pszText = "Output";\r
364                         TabCtrl_InsertItem(data->htab, 1, &item);\r
365                         /* get rect (after adding pages) */\r
366                         GetWindowRect(data->htab, &data->r);\r
367                         ScreenToClientRect(hwnd, &data->r);\r
368                         TabCtrl_AdjustRect(data->htab, 0, &data->r);\r
369                         /* simulate item change */\r
370                         TabCtrl_SetCurSel(data->htab, activePage);\r
371                         OnSelChange(hwnd);\r
372                 }\r
373                 return TRUE;\r
374         /* destory */\r
375         case WM_DESTROY:\r
376                 {\r
377                         LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
378                         int i;\r
379 \r
380                         activePage = TabCtrl_GetCurSel(data->htab);\r
381 \r
382                         for (i=0; i<NUM_PAGES; i++)\r
383                                 DestroyWindow(data->all[i]);\r
384 \r
385                         LocalFree(data);\r
386                 }\r
387                 break;\r
388         /* commands */\r
389         case WM_COMMAND:\r
390                 switch (LOWORD(wParam))\r
391                 {\r
392                 /* ok/cancel */\r
393                 case IDOK:\r
394                         BroadcastCommand(hwnd, IDOK);\r
395                         /* fall through */\r
396                 case IDCANCEL:\r
397                         EndDialog(hwnd, LOWORD(wParam));\r
398                         return TRUE;\r
399                 case IDC_RESET:\r
400                         SendCommand(hwnd, IDC_RESET);\r
401                         break;\r
402                 }\r
403                 break;\r
404         /* notification */\r
405         case WM_NOTIFY:\r
406                 if (LOWORD(wParam) == IDC_TABS)\r
407                 {\r
408                         NMHDR *hdr = (NMHDR*)lParam;\r
409 \r
410                         switch (hdr->code)\r
411                         {\r
412                         case TCN_SELCHANGE:\r
413                                 OnSelChange(hwnd);\r
414                                 break;\r
415                         }\r
416                 }\r
417                 break;\r
418         }\r
419 \r
420         return 0;\r
421 }\r
422 \r
423 \r
424 int DoConfig(HINSTANCE inst, HWND parent)\r
425 {\r
426         return DialogBoxParam(inst, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc, (LONG)inst) == IDOK;\r
427 }\r