[SNDVOL32] Fix controls' offset (#280)
[reactos.git] / base / applications / sndvol32 / dialog.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Sound Volume Control
4 * FILE: base/applications/sndvol32/dialog.c
5 * PROGRAMMERS: Johannes Anderwald
6 */
7
8 #include "sndvol32.h"
9
10 #include <wingdi.h>
11
12 #define XLEFT (30)
13 #define XTOP (20)
14 #define DIALOG_VOLUME_SIZE (150)
15
16 LPVOID
17 LoadDialogResource(
18 IN HMODULE hModule,
19 IN LPCWSTR ResourceName,
20 OUT LPDWORD ResourceLength)
21 {
22 HRSRC hSrc;
23 HGLOBAL hRes;
24 PVOID Result;
25
26 /* find resource */
27 hSrc = FindResourceW(hModule, ResourceName, (LPCWSTR)RT_DIALOG);
28
29 if (!hSrc)
30 {
31 /* failed to find resource */
32 return NULL;
33 }
34
35 /* now load the resource */
36 hRes = LoadResource(hAppInstance, hSrc);
37 if (!hRes)
38 {
39 /* failed to load resource */
40 return NULL;
41 }
42
43 /* now lock the resource */
44 Result = LockResource(hRes);
45
46 if (!Result)
47 {
48 /* failed to lock resource */
49 return NULL;
50 }
51
52 if (ResourceLength)
53 {
54 /* store output length */
55 *ResourceLength = SizeofResource(hAppInstance, hSrc);
56 }
57
58 /* done */
59 return Result;
60 }
61
62 LPWORD
63 AddDialogControl(
64 IN HWND hwndDialog,
65 IN HWND * OutWnd,
66 IN LPRECT DialogOffset,
67 IN PDLGITEMTEMPLATE DialogItem,
68 IN DWORD DialogIdMultiplier,
69 IN HFONT hFont)
70 {
71 RECT rect;
72 LPWORD Offset;
73 LPWSTR ClassName, WindowName = NULL;
74 HWND hwnd;
75 DWORD wID;
76
77 /* initialize client rectangle */
78 rect.left = DialogItem->x + DialogOffset->left;
79 rect.top = DialogItem->y + DialogOffset->top;
80 rect.right = DialogItem->cx;
81 rect.bottom = DialogItem->cy;
82
83 //MapDialogRect(hwndDialog, &rect);
84
85 /* move offset after dialog item */
86 Offset = (LPWORD)(DialogItem + 1);
87
88 if (*Offset == 0xFFFF)
89 {
90 /* class is encoded as type */
91 Offset++;
92
93 /* get control type */
94 switch(*Offset)
95 {
96 case 0x80:
97 ClassName = L"button";
98 WindowName = (LPWSTR)(Offset + 1);
99 break ;
100 case 0x82:
101 ClassName = L"static";
102 WindowName = (LPWSTR)(Offset + 1);
103 break;
104 default:
105 /* FIXME */
106 assert(0);
107 ClassName = NULL;
108 }
109 }
110 else
111 {
112 /* class name is encoded as string */
113 ClassName = (LPWSTR)Offset;
114
115 /* move offset to the end of class string */
116 Offset += wcslen(ClassName);
117
118 /* get window name */
119 WindowName = (LPWSTR)(Offset + 1);
120 }
121
122 /* move offset past class type/string */
123 Offset++;
124
125 if (DialogItem->id == MAXWORD)
126 {
127 /* id is not important */
128 wID = DialogItem->id;
129 }
130 else
131 {
132 /* calculate id */
133 wID = DialogItem->id * (DialogIdMultiplier + 1);
134
135 }
136 /* now create the window */
137 hwnd = CreateWindowExW(DialogItem->dwExtendedStyle,
138 ClassName,
139 WindowName,
140 DialogItem->style,
141 rect.left,
142 rect.top,
143 rect.right,
144 rect.bottom,
145 hwndDialog,
146 (HMENU)(wID),
147 hAppInstance,
148 NULL);
149
150 /* sanity check */
151 assert(hwnd);
152
153 /* store window */
154 *OutWnd = hwnd;
155
156 /* check if this the track bar */
157 if (!wcsicmp(ClassName, L"msctls_trackbar32"))
158 {
159 /* set up range */
160 SendMessage(hwnd, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG(0, 5));
161
162 /* set up page size */
163 SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM) 1);
164
165 /* set available range */
166 //SendMessage(hwnd, TBM_SETSEL, (WPARAM) FALSE, (LPARAM) MAKELONG(0, 5));
167
168 /* set position */
169 SendMessage(hwnd, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) 0);
170
171 }
172 else if (!wcsicmp(ClassName, L"static") || !wcsicmp(ClassName, L"button"))
173 {
174 /* set font */
175 SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
176 }
177
178 //ShowWindow(hwnd, SW_SHOWNORMAL);
179
180 if (WindowName != NULL)
181 {
182 /* move offset past window name */
183 Offset += wcslen(WindowName) + 1;
184 }
185
186 /* check if there is additional data */
187 if (*Offset == 0)
188 {
189 /* no additional data */
190 Offset++;
191 }
192 else
193 {
194 /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
195 /* skip past additional data */
196 Offset += *Offset;
197 }
198
199 /* make sure next template is word-aligned */
200 Offset = (LPWORD)(((ULONG_PTR)Offset + 3) & ~3);
201
202 /* done */
203 return Offset;
204 }
205
206 VOID
207 LoadDialogControls(
208 IN PMIXER_WINDOW MixerWindow,
209 LPRECT DialogOffset,
210 LPVOID DlgResource,
211 DWORD DialogIdMultiplier)
212 {
213 LPDLGTEMPLATE DialogHeader;
214 PDLGITEMTEMPLATE DialogItem;
215 LPWORD Offset;
216 WORD FontSize;
217 WCHAR FontName[100];
218 WORD Length, Index;
219 HFONT Font;
220
221 /* get dialog header */
222 DialogHeader = (LPDLGTEMPLATE)DlgResource;
223
224 /* sanity check */
225 assert(DialogHeader->cdit);
226
227 if (MixerWindow->Window)
228 MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + DialogHeader->cdit) * sizeof(HWND));
229 else
230 MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DialogHeader->cdit * sizeof(HWND));
231 if (!MixerWindow->Window)
232 {
233 /* no memory */
234 return;
235 }
236
237 /* now walk past the dialog header */
238 Offset = (LPWORD)(DialogHeader + 1);
239
240 /* FIXME: support menu */
241 assert(*Offset == 0);
242 Offset++;
243
244 /* FIXME: support classes */
245 assert(*Offset == 0);
246 Offset++;
247
248 /* FIXME: support titles */
249 assert(*Offset == 0);
250 Offset++;
251
252 /* get font size */
253 FontSize = *Offset;
254 Offset++;
255
256 /* calculate font length */
257 Length = wcslen((LPWSTR)Offset) + 1;
258 assert(Length < (sizeof(FontName) / sizeof(WCHAR)));
259
260 /* copy font */
261 wcscpy(FontName, (LPWSTR)Offset);
262
263 Font = CreateFontW(FontSize+8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, FontName);
264 assert(Font);
265
266 /* move offset after font name */
267 Offset += Length;
268
269 /* offset is now at first dialog item control */
270 DialogItem = (PDLGITEMTEMPLATE)Offset;
271
272 /* enumerate now all controls */
273 for(Index = 0; Index < DialogHeader->cdit; Index++)
274 {
275 /* add controls */
276 Offset = AddDialogControl(MixerWindow->hWnd, &MixerWindow->Window[MixerWindow->WindowCount], DialogOffset, DialogItem, DialogIdMultiplier, Font);
277
278 /* sanity check */
279 assert(Offset);
280
281 /* move dialog item to new offset */
282 DialogItem =(PDLGITEMTEMPLATE)Offset;
283
284 /* increment window count */
285 MixerWindow->WindowCount++;
286 }
287 }
288
289 VOID
290 LoadDialog(
291 IN HMODULE hModule,
292 IN PMIXER_WINDOW MixerWindow,
293 IN LPCWSTR DialogResId,
294 IN DWORD Index)
295 {
296 LPVOID DlgResource;
297 RECT rect;
298
299 /* first load the dialog resource */
300 DlgResource = LoadDialogResource(hModule, DialogResId, NULL);
301
302 if (!DlgResource)
303 {
304 /* failed to load resource */
305 return;
306 }
307
308 /* get window size */
309 GetClientRect(MixerWindow->hWnd, &rect);
310
311 /* adjust client position */
312 rect.left += (Index * DIALOG_VOLUME_SIZE);
313
314
315 /* now add the controls */
316 LoadDialogControls(MixerWindow, &rect, DlgResource, Index);
317
318 }
319
320 BOOL
321 CALLBACK
322 EnumConnectionsCallback(
323 PSND_MIXER Mixer,
324 DWORD LineID,
325 LPMIXERLINE Line,
326 PVOID Context)
327 {
328 WCHAR LineName[MIXER_LONG_NAME_CHARS];
329 DWORD Flags;
330 DWORD wID;
331 RECT rect;
332 UINT ControlCount = 0, Index;
333 LPMIXERCONTROL Control = NULL;
334 HWND hDlgCtrl;
335 PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
336
337 if (Line->cControls != 0)
338 {
339 /* get line name */
340 if (SndMixerGetLineName(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
341 {
342 /* failed to get line name */
343 LineName[0] = L'\0';
344 }
345
346 /* check if line is found in registry settings */
347 if (ReadLineConfig(PrefContext->DeviceName,
348 LineName,
349 Line->szName,
350 &Flags))
351 {
352 /* is it selected */
353 if (Flags != 0x4)
354 {
355 /* load dialog resource */
356 LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(IDD_VOLUME_CTRL), PrefContext->Count);
357
358 /* get id */
359 wID = (PrefContext->Count + 1) * IDC_LINE_NAME;
360
361 /* set line name */
362 SetDlgItemTextW(PrefContext->MixerWindow->hWnd, wID, Line->szName);
363
364 /* query controls */
365 if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) != FALSE)
366 {
367 /* now go through all controls and update their states */
368 for(Index = 0; Index < ControlCount; Index++)
369 {
370 if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_SWITCH)
371 {
372 MIXERCONTROLDETAILS_BOOLEAN Details;
373
374 /* get volume control details */
375 if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
376 {
377 /* update dialog control */
378 wID = (PrefContext->Count + 1) * IDC_LINE_SWITCH;
379
380 /* get dialog control */
381 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
382
383 if (hDlgCtrl != NULL)
384 {
385 /* check state */
386 if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != Details.fValue)
387 {
388 /* update control state */
389 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)Details.fValue, 0);
390 }
391 }
392 }
393 }
394 else if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_FADER)
395 {
396 MIXERCONTROLDETAILS_UNSIGNED Details;
397
398 /* get volume control details */
399 if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&Details) != -1)
400 {
401 /* update dialog control */
402 DWORD Position;
403 DWORD Step = 0x10000 / 5;
404
405 /* FIXME: give me granularity */
406 Position = 5 - (Details.dwValue / Step);
407
408 /* FIXME support left - right slider */
409 wID = (PrefContext->Count + 1) * IDC_LINE_SLIDER_VERT;
410
411 /* get dialog control */
412 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
413
414 if (hDlgCtrl != NULL)
415 {
416 /* check state */
417 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
418 if (OldPosition != Position)
419 {
420 /* update control state */
421 SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position + Index);
422 }
423 }
424 }
425 }
426 }
427
428 /* free controls */
429 HeapFree(GetProcessHeap(), 0, Control);
430 }
431
432 /* increment dialog count */
433 PrefContext->Count++;
434
435 /* get application rectangle */
436 GetWindowRect(PrefContext->MixerWindow->hWnd, &rect);
437
438 /* now move the window */
439 MoveWindow(PrefContext->MixerWindow->hWnd, rect.left, rect.top, (PrefContext->Count * DIALOG_VOLUME_SIZE), rect.bottom - rect.top, TRUE);
440 }
441 }
442 }
443 return TRUE;
444 }
445
446 VOID
447 LoadDialogCtrls(
448 PPREFERENCES_CONTEXT PrefContext)
449 {
450 HWND hDlgCtrl;
451
452 /* set dialog count to zero */
453 PrefContext->Count = 0;
454
455 /* enumerate controls */
456 SndMixerEnumConnections(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, EnumConnectionsCallback, (PVOID)PrefContext);
457
458 /* get last line separator */
459 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, IDC_LINE_SEP * PrefContext->Count);
460
461 if (hDlgCtrl != NULL)
462 {
463 /* hide last separator */
464 ShowWindow(hDlgCtrl, SW_HIDE);
465 }
466
467 }
468
469 VOID
470 UpdateDialogLineSwitchControl(
471 PPREFERENCES_CONTEXT PrefContext,
472 LPMIXERLINE Line,
473 LONG fValue)
474 {
475 DWORD Index;
476 DWORD wID;
477 HWND hDlgCtrl;
478 WCHAR LineName[MIXER_LONG_NAME_CHARS];
479
480 /* find the index of this line */
481 for(Index = 0; Index < PrefContext->Count; Index++)
482 {
483 /* get id */
484 wID = (Index + 1) * IDC_LINE_NAME;
485
486 if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
487 {
488 /* failed to retrieve id */
489 continue;
490 }
491
492 /* check if the line name matches */
493 if (!wcsicmp(LineName, Line->szName))
494 {
495 /* found matching line name */
496 wID = (Index + 1) * IDC_LINE_SWITCH;
497
498 /* get dialog control */
499 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
500
501 if (hDlgCtrl != NULL)
502 {
503 /* check state */
504 if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != fValue)
505 {
506 /* update control state */
507 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)fValue, 0);
508 }
509 }
510 break;
511 }
512 }
513 }
514
515 VOID
516 UpdateDialogLineSliderControl(
517 PPREFERENCES_CONTEXT PrefContext,
518 LPMIXERLINE Line,
519 DWORD dwControlID,
520 DWORD dwDialogID,
521 DWORD Position)
522 {
523 DWORD Index;
524 DWORD wID;
525 HWND hDlgCtrl;
526 WCHAR LineName[MIXER_LONG_NAME_CHARS];
527
528 /* find the index of this line */
529 for(Index = 0; Index < PrefContext->Count; Index++)
530 {
531 /* get id */
532 wID = (Index + 1) * IDC_LINE_NAME;
533
534 if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
535 {
536 /* failed to retrieve id */
537 continue;
538 }
539
540 /* check if the line name matches */
541 if (!wcsicmp(LineName, Line->szName))
542 {
543 /* found matching line name */
544 wID = (Index + 1) * dwDialogID;
545
546 /* get dialog control */
547 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
548
549 if (hDlgCtrl != NULL)
550 {
551 /* check state */
552 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
553 if (OldPosition != Position)
554 {
555 /* update control state */
556 SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position + Index);
557 }
558 }
559 break;
560 }
561 }
562 }