1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Sound Volume Control
4 * FILE: base/applications/sndvol32/advanced.c
5 * PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org>
6 */
7
8 #include "sndvol32.h"
9
10 typedef struct _ADVANCED_DATA
11 {
12 PADVANCED_CONTEXT Context;
13
14 BOOL bEnabled[4];
15 DWORD dwControlId[4];
16
17 /* Bass and Treble */
18 DWORD dwMaximum[2];
19 DWORD dwMinimum[2];
20
21 } ADVANCED_DATA, *PADVANCED_DATA;
22
23 static
24 VOID
OnInitDialog(HWND hwndDlg,PADVANCED_DATA pData)25 OnInitDialog(
26 HWND hwndDlg,
27 PADVANCED_DATA pData)
28 {
29 MIXERCONTROLDETAILS_UNSIGNED UnsignedDetails;
30 MIXERCONTROLDETAILS_BOOLEAN BooleanDetails;
31 WCHAR szRawBuffer[256], szCookedBuffer[256];
32 LPMIXERCONTROL Control = NULL;
33 UINT ControlCount = 0, Index;
34 DWORD i, dwStep, dwPosition;
35 DWORD dwOtherControls = 0;
36 RECT rect;
37 LONG dy;
38
39 /* Set the dialog title */
40 LoadStringW(hAppInstance, IDS_ADVANCED_CONTROLS, szRawBuffer, ARRAYSIZE(szRawBuffer));
41 StringCchPrintfW(szCookedBuffer, ARRAYSIZE(szCookedBuffer), szRawBuffer, pData->Context->LineName);
42 SetWindowTextW(hwndDlg, szCookedBuffer);
43
44 /* Disable the tone controls */
45 for (i = IDC_ADV_BASS_LOW; i<= IDC_ADV_TREBLE_SLIDER; i++)
46 EnableWindow(GetDlgItem(hwndDlg, i), FALSE);
47
48 /* Initialize the bass and treble trackbars */
49 SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
50 SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
51 SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
52 SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
53 SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
54 SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
55
56 /* Calculate and set ticks */
57 dwStep = (VOLUME_MAX / (VOLUME_TICKS + 1));
58 if (VOLUME_MAX % (VOLUME_TICKS + 1) != 0)
59 dwStep++;
60 for (i = dwStep; i < VOLUME_MAX; i += dwStep)
61 {
62 SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETTIC, 0, (LPARAM)i);
63 SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETTIC, 0, (LPARAM)i);
64 }
65
66 /* Hide the other controls */
67 for (i = IDC_ADV_OTHER_CONTROLS; i<= IDC_ADV_OTHER_CHECK2; i++)
68 ShowWindow(GetDlgItem(hwndDlg, i), SW_HIDE);
69
70 if (SndMixerQueryControls(pData->Context->Mixer, &ControlCount, pData->Context->Line, &Control))
71 {
72 for (Index = 0; Index < ControlCount; Index++)
73 {
74 if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_BASS)
75 {
76 /* Bass control */
77
78 if (SndMixerGetVolumeControlDetails(pData->Context->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&UnsignedDetails) != -1)
79 {
80 for (i = IDC_ADV_BASS_LOW; i<= IDC_ADV_BASS_SLIDER; i++)
81 EnableWindow(GetDlgItem(hwndDlg, i), TRUE);
82
83 dwStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
84 dwPosition = (UnsignedDetails.dwValue - Control[Index].Bounds.dwMinimum) / dwStep;
85 SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETPOS, (WPARAM)TRUE, dwPosition);
86
87 pData->bEnabled[0] = TRUE;
88 pData->dwControlId[0] = Control[Index].dwControlID;
89 pData->dwMaximum[0] = Control[Index].Bounds.dwMaximum;
90 pData->dwMinimum[0] = Control[Index].Bounds.dwMinimum;
91 }
92 }
93 else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_TREBLE)
94 {
95 /* Treble control */
96
97 if (SndMixerGetVolumeControlDetails(pData->Context->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&UnsignedDetails) != -1)
98 {
99 for (i = IDC_ADV_TREBLE_LOW; i<= IDC_ADV_TREBLE_SLIDER; i++)
100 EnableWindow(GetDlgItem(hwndDlg, i), TRUE);
101
102 dwStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
103 dwPosition = (UnsignedDetails.dwValue - Control[Index].Bounds.dwMinimum) / dwStep;
104 SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETPOS, (WPARAM)TRUE, dwPosition);
105
106 pData->bEnabled[1] = TRUE;
107 pData->dwControlId[1] = Control[Index].dwControlID;
108 pData->dwMaximum[1] = Control[Index].Bounds.dwMaximum;
109 pData->dwMinimum[1] = Control[Index].Bounds.dwMinimum;
110 }
111 }
112 else if (((Control[Index].dwControlType & (MIXERCONTROL_CT_CLASS_MASK | MIXERCONTROL_CT_SUBCLASS_MASK | MIXERCONTROL_CT_UNITS_MASK)) == MIXERCONTROL_CONTROLTYPE_BOOLEAN) &&
113 (Control[Index].dwControlType != MIXERCONTROL_CONTROLTYPE_MUTE))
114 {
115 /* All boolean controls but the Mute control (Maximum of 2) */
116
117 if (dwOtherControls < 2)
118 {
119 if (SndMixerGetVolumeControlDetails(pData->Context->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&BooleanDetails) != -1)
120 {
121 LoadStringW(hAppInstance, IDS_OTHER_CONTROLS1 + dwOtherControls, szRawBuffer, ARRAYSIZE(szRawBuffer));
122 StringCchPrintfW(szCookedBuffer, ARRAYSIZE(szCookedBuffer), szRawBuffer, Control[Index].szName);
123 SetWindowTextW(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CHECK1 + dwOtherControls), szCookedBuffer);
124
125 ShowWindow(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CHECK1 + dwOtherControls), SW_SHOWNORMAL);
126
127 SendDlgItemMessageW(hwndDlg, IDC_ADV_OTHER_CHECK1 + dwOtherControls, BM_SETCHECK, (WPARAM)BooleanDetails.fValue, 0);
128
129 pData->bEnabled[dwOtherControls + 2] = TRUE;
130 pData->dwControlId[dwOtherControls + 2] = Control[Index].dwControlID;
131
132 dwOtherControls++;
133 }
134 }
135 }
136 }
137
138 /* Free controls */
139 HeapFree(GetProcessHeap(), 0, Control);
140 }
141
142 if (dwOtherControls != 0)
143 {
144 /* Show the 'Other controls' groupbox and text */
145 ShowWindow(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CONTROLS), SW_SHOWNORMAL);
146 ShowWindow(GetDlgItem(hwndDlg, IDC_ADV_OTHER_TEXT), SW_SHOWNORMAL);
147
148 /* Resize the dialog */
149 GetWindowRect(hwndDlg, &rect);
150
151 dy = MulDiv((dwOtherControls == 1) ? 73 : (73 + 15), pData->Context->MixerWindow->baseUnit.cy, 8);
152 rect.bottom += dy;
153
154 SetWindowPos(hwndDlg, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
155
156 /* Move the 'Close' button down */
157 GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rect);
158 MapWindowPoints(HWND_DESKTOP, hwndDlg, (LPPOINT)&rect, 2);
159
160 rect.top += dy;
161 rect.bottom += dy;
162
163 SetWindowPos(GetDlgItem(hwndDlg, IDOK), HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOSIZE | SWP_NOZORDER);
164
165 if (dwOtherControls == 2)
166 {
167 /* Resize the 'Other Controls' groupbox */
168 GetWindowRect(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CONTROLS), &rect);
169 MapWindowPoints(HWND_DESKTOP, hwndDlg, (LPPOINT)&rect, 2);
170
171 dy = MulDiv(15, pData->Context->MixerWindow->baseUnit.cy, 8);
172 rect.bottom += dy;
173
174 SetWindowPos(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CONTROLS), HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
175 }
176 }
177 }
178
179
180 static
181 VOID
OnHScroll(HWND hwndDlg,PADVANCED_DATA pData,DWORD dwCtrlID)182 OnHScroll(
183 HWND hwndDlg,
184 PADVANCED_DATA pData,
185 DWORD dwCtrlID)
186 {
187 MIXERCONTROLDETAILS_UNSIGNED Details;
188 DWORD dwControlID = 0, dwStep, dwPosition;
189 DWORD dwMaximum, dwMinimum;
190
191 if (dwCtrlID != IDC_ADV_BASS_SLIDER &&
192 dwCtrlID != IDC_ADV_TREBLE_SLIDER)
193 return;
194
195 if (dwCtrlID == IDC_ADV_BASS_SLIDER)
196 {
197 if (pData->bEnabled[0] == FALSE)
198 return;
199
200 dwControlID = pData->dwControlId[0];
201 dwMaximum = pData->dwMaximum[0];
202 dwMinimum = pData->dwMinimum[0];
203 }
204 else if (dwCtrlID == IDC_ADV_TREBLE_SLIDER)
205 {
206 if (pData->bEnabled[1] == FALSE)
207 return;
208
209 dwControlID = pData->dwControlId[1];
210 dwMaximum = pData->dwMaximum[1];
211 dwMinimum = pData->dwMinimum[1];
212 }
213
214 dwPosition = (DWORD)SendDlgItemMessage(hwndDlg, dwCtrlID, TBM_GETPOS, 0, 0);
215 dwStep = (dwMaximum - dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
216
217 Details.dwValue = (dwPosition * dwStep) + dwMinimum;
218
219 SndMixerSetVolumeControlDetails(pData->Context->Mixer, dwControlID, 1, sizeof(MIXERCONTROLDETAILS_UNSIGNED), &Details);
220 }
221
222
223 INT_PTR
224 CALLBACK
AdvancedDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)225 AdvancedDlgProc(
226 HWND hwndDlg,
227 UINT uMsg,
228 WPARAM wParam,
229 LPARAM lParam)
230 {
231 PADVANCED_DATA pData;
232
233 pData = (PADVANCED_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
234
235 switch (uMsg)
236 {
237 case WM_INITDIALOG:
238 pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ADVANCED_DATA));
239 if (pData != NULL)
240 {
241 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
242 pData->Context = (PADVANCED_CONTEXT)((LONG_PTR)lParam);
243 OnInitDialog(hwndDlg, pData);
244 }
245 return TRUE;
246
247 case WM_COMMAND:
248 switch (LOWORD(wParam))
249 {
250 case IDOK:
251 EndDialog(hwndDlg, IDOK);
252 break;
253 }
254 break;
255
256 case WM_HSCROLL:
257 if (pData != NULL)
258 {
259 if (LOWORD(wParam) == TB_THUMBTRACK)
260 OnHScroll(hwndDlg, pData, GetDlgCtrlID((HWND)lParam));
261 }
262 break;
263
264 case WM_CLOSE:
265 EndDialog(hwndDlg, IDCANCEL);
266 break;
267
268 case WM_DESTROY:
269 if (pData != NULL)
270 {
271 HeapFree(GetProcessHeap(), 0, pData);
272 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)NULL);
273 }
274 break;
275 }
276
277 return FALSE;
278 }
279
280 /* EOF */
281