Sync to trunk revision 63922.
[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: subsys/system/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 = 0;
108 }
109 }
110 else
111 {
112 /* class name is encoded as string */
113 ClassName = (LPWSTR)Offset;
114
115 /* adjust offset */
116 Offset += wcslen(ClassName) + 1;
117
118 /* get offset */
119 WindowName = (LPWSTR)(Offset + 1);
120 }
121
122 if (DialogItem->id == MAXWORD)
123 {
124 /* id is not important */
125 wID = DialogItem->id;
126 }
127 else
128 {
129 /* calculate id */
130 wID = DialogItem->id * (DialogIdMultiplier + 1);
131
132 }
133 /* now create the window */
134 hwnd = CreateWindowExW(DialogItem->dwExtendedStyle,
135 ClassName,
136 WindowName,
137 DialogItem->style,
138 rect.left,
139 rect.top,
140 rect.right,
141 rect.bottom,
142 hwndDialog,
143 (HMENU)(wID),
144 hAppInstance,
145 NULL);
146
147 /* sanity check */
148 assert(hwnd);
149
150 /* store window */
151 *OutWnd = hwnd;
152
153 /* check if this the track bar */
154 if (!wcsicmp(ClassName, L"msctls_trackbar32"))
155 {
156 /* set up range */
157 SendMessage(hwnd, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG(0, 5));
158
159 /* set up page size */
160 SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM) 1);
161
162 /* set available range */
163 //SendMessage(hwnd, TBM_SETSEL, (WPARAM) FALSE, (LPARAM) MAKELONG(0, 5));
164
165 /* set position */
166 SendMessage(hwnd, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) 0);
167
168 }
169 else if (!wcsicmp(ClassName, L"static") || !wcsicmp(ClassName, L"button"))
170 {
171 /* set font */
172 SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
173 }
174
175 //ShowWindow(hwnd, SW_SHOWNORMAL);
176
177 if (WindowName != NULL)
178 {
179 /* position offset to start of name */
180 Offset++;
181
182 /* move offset past name */
183 Offset += wcslen((LPWSTR)Offset) + 1;
184 }
185 else
186 {
187 /* no name so just adjust offset */
188 Offset++;
189 }
190
191 /* check if there is additional data */
192 if (*Offset == 0)
193 {
194 /* no additional data */
195 Offset++;
196 }
197 else
198 {
199 /* add data offset */
200 Offset += *Offset;
201 }
202
203 /* make sure next template is word-aligned */
204 Offset = (LPWORD)(((ULONG_PTR)Offset + 3) & ~3);
205
206 /* done */
207 return Offset;
208 }
209
210 VOID
211 LoadDialogControls(
212 IN PMIXER_WINDOW MixerWindow,
213 LPRECT DialogOffset,
214 LPVOID DlgResource,
215 DWORD DialogIdMultiplier)
216 {
217 LPDLGTEMPLATE DialogHeader;
218 PDLGITEMTEMPLATE DialogItem;
219 LPWORD Offset;
220 WORD FontSize;
221 WCHAR FontName[100];
222 WORD Length, Index;
223 HFONT Font;
224
225 /* get dialog header */
226 DialogHeader = (LPDLGTEMPLATE)DlgResource;
227
228 /* sanity check */
229 assert(DialogHeader->cdit);
230
231 if (MixerWindow->Window)
232 MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + DialogHeader->cdit) * sizeof(HWND));
233 else
234 MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DialogHeader->cdit * sizeof(HWND));
235 if (!MixerWindow->Window)
236 {
237 /* no memory */
238 return;
239 }
240
241 /* now walk past the dialog header */
242 Offset = (LPWORD)(DialogHeader + 1);
243
244 /* FIXME: support menu */
245 assert(*Offset == 0);
246 Offset++;
247
248 /* FIXME: support classes */
249 assert(*Offset == 0);
250 Offset++;
251
252 /* FIXME: support titles */
253 assert(*Offset == 0);
254 Offset++;
255
256 /* get font size */
257 FontSize = *Offset;
258 Offset++;
259
260 /* calculate font length */
261 Length = wcslen((LPWSTR)Offset) + 1;
262 assert(Length < (sizeof(FontName) / sizeof(WCHAR)));
263
264 /* copy font */
265 wcscpy(FontName, (LPWSTR)Offset);
266
267 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);
268 assert(Font);
269
270 /* move offset after font name */
271 Offset += Length;
272
273 /* offset is now at first dialog item control */
274 DialogItem = (PDLGITEMTEMPLATE)Offset;
275
276 /* enumerate now all controls */
277 for(Index = 0; Index < DialogHeader->cdit; Index++)
278 {
279 /* add controls */
280 Offset = AddDialogControl(MixerWindow->hWnd, &MixerWindow->Window[MixerWindow->WindowCount], DialogOffset, DialogItem, DialogIdMultiplier, Font);
281
282 /* sanity check */
283 assert(Offset);
284
285 /* move dialog item to new offset */
286 DialogItem =(PDLGITEMTEMPLATE)Offset;
287
288 /* increment window count */
289 MixerWindow->WindowCount++;
290 }
291 }
292
293 VOID
294 LoadDialog(
295 IN HMODULE hModule,
296 IN PMIXER_WINDOW MixerWindow,
297 IN LPCWSTR DialogResId,
298 IN DWORD Index)
299 {
300 LPVOID DlgResource;
301 RECT rect;
302
303 /* first load the dialog resource */
304 DlgResource = LoadDialogResource(hModule, DialogResId, NULL);
305
306 if (!DlgResource)
307 {
308 /* failed to load resource */
309 return;
310 }
311
312 /* get window size */
313 GetClientRect(MixerWindow->hWnd, &rect);
314
315 /* adjust client position */
316 rect.left += (Index * DIALOG_VOLUME_SIZE);
317
318
319 /* now add the controls */
320 LoadDialogControls(MixerWindow, &rect, DlgResource, Index);
321
322 }
323
324 BOOL
325 CALLBACK
326 EnumConnectionsCallback(
327 PSND_MIXER Mixer,
328 DWORD LineID,
329 LPMIXERLINE Line,
330 PVOID Context)
331 {
332 WCHAR LineName[MIXER_LONG_NAME_CHARS];
333 DWORD Flags;
334 DWORD wID;
335 RECT rect;
336 UINT ControlCount = 0, Index;
337 LPMIXERCONTROL Control = NULL;
338 HWND hDlgCtrl;
339 PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
340
341 if (Line->cControls != 0)
342 {
343 /* get line name */
344 if (SndMixerGetLineName(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
345 {
346 /* failed to get line name */
347 LineName[0] = L'\0';
348 }
349
350 /* check if line is found in registry settings */
351 if (ReadLineConfig(PrefContext->DeviceName,
352 LineName,
353 Line->szName,
354 &Flags))
355 {
356 /* is it selected */
357 if (Flags != 0x4)
358 {
359 /* load dialog resource */
360 LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(IDD_VOLUME_CTRL), PrefContext->Count);
361
362 /* get id */
363 wID = (PrefContext->Count + 1) * IDC_LINE_NAME;
364
365 /* set line name */
366 SetDlgItemTextW(PrefContext->MixerWindow->hWnd, wID, Line->szName);
367
368 /* query controls */
369 if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) == TRUE)
370 {
371 /* now go through all controls and update their states */
372 for(Index = 0; Index < ControlCount; Index++)
373 {
374 if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_SWITCH)
375 {
376 MIXERCONTROLDETAILS_BOOLEAN Details;
377
378 /* get volume control details */
379 if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
380 {
381 /* update dialog control */
382 wID = (PrefContext->Count + 1) * IDC_LINE_SWITCH;
383
384 /* get dialog control */
385 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
386
387 if (hDlgCtrl != NULL)
388 {
389 /* check state */
390 if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != Details.fValue)
391 {
392 /* update control state */
393 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)Details.fValue, 0);
394 }
395 }
396 }
397 }
398 else if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_FADER)
399 {
400 MIXERCONTROLDETAILS_UNSIGNED Details;
401
402 /* get volume control details */
403 if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&Details) != -1)
404 {
405 /* update dialog control */
406 DWORD Position;
407 DWORD Step = 0x10000 / 5;
408
409 /* FIXME: give me granularity */
410 Position = 5 - (Details.dwValue / Step);
411
412 /* FIXME support left - right slider */
413 wID = (PrefContext->Count + 1) * IDC_LINE_SLIDER_VERT;
414
415 /* get dialog control */
416 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
417
418 if (hDlgCtrl != NULL)
419 {
420 /* check state */
421 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
422 if (OldPosition != Position)
423 {
424 /* update control state */
425 SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position + Index);
426 }
427 }
428 }
429 }
430 }
431
432 /* free controls */
433 HeapFree(GetProcessHeap(), 0, Control);
434 }
435
436 /* increment dialog count */
437 PrefContext->Count++;
438
439 /* get application rectangle */
440 GetWindowRect(PrefContext->MixerWindow->hWnd, &rect);
441
442 /* now move the window */
443 MoveWindow(PrefContext->MixerWindow->hWnd, rect.left, rect.top, (PrefContext->Count * DIALOG_VOLUME_SIZE), rect.bottom - rect.top, TRUE);
444 }
445 }
446 }
447 return TRUE;
448 }
449
450 VOID
451 LoadDialogCtrls(
452 PPREFERENCES_CONTEXT PrefContext)
453 {
454 HWND hDlgCtrl;
455
456 /* set dialog count to zero */
457 PrefContext->Count = 0;
458
459 /* enumerate controls */
460 SndMixerEnumConnections(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, EnumConnectionsCallback, (PVOID)PrefContext);
461
462 /* get last line seperator */
463 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, IDC_LINE_SEP * PrefContext->Count);
464
465 if (hDlgCtrl != NULL)
466 {
467 /* hide last seperator */
468 ShowWindow(hDlgCtrl, SW_HIDE);
469 }
470
471 }
472
473 VOID
474 UpdateDialogLineSwitchControl(
475 PPREFERENCES_CONTEXT PrefContext,
476 LPMIXERLINE Line,
477 LONG fValue)
478 {
479 DWORD Index;
480 DWORD wID;
481 HWND hDlgCtrl;
482 WCHAR LineName[MIXER_LONG_NAME_CHARS];
483
484 /* find the index of this line */
485 for(Index = 0; Index < PrefContext->Count; Index++)
486 {
487 /* get id */
488 wID = (Index + 1) * IDC_LINE_NAME;
489
490 if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
491 {
492 /* failed to retrieve id */
493 continue;
494 }
495
496 /* check if the line name matches */
497 if (!wcsicmp(LineName, Line->szName))
498 {
499 /* found matching line name */
500 wID = (Index + 1) * IDC_LINE_SWITCH;
501
502 /* get dialog control */
503 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
504
505 if (hDlgCtrl != NULL)
506 {
507 /* check state */
508 if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != fValue)
509 {
510 /* update control state */
511 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)fValue, 0);
512 }
513 }
514 break;
515 }
516 }
517 }
518
519 VOID
520 UpdateDialogLineSliderControl(
521 PPREFERENCES_CONTEXT PrefContext,
522 LPMIXERLINE Line,
523 DWORD dwControlID,
524 DWORD dwDialogID,
525 DWORD Position)
526 {
527 DWORD Index;
528 DWORD wID;
529 HWND hDlgCtrl;
530 WCHAR LineName[MIXER_LONG_NAME_CHARS];
531
532 /* find the index of this line */
533 for(Index = 0; Index < PrefContext->Count; Index++)
534 {
535 /* get id */
536 wID = (Index + 1) * IDC_LINE_NAME;
537
538 if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
539 {
540 /* failed to retrieve id */
541 continue;
542 }
543
544 /* check if the line name matches */
545 if (!wcsicmp(LineName, Line->szName))
546 {
547 /* found matching line name */
548 wID = (Index + 1) * dwDialogID;
549
550 /* get dialog control */
551 hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
552
553 if (hDlgCtrl != NULL)
554 {
555 /* check state */
556 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
557 if (OldPosition != Position)
558 {
559 /* update control state */
560 SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position + Index);
561 }
562 }
563 break;
564 }
565 }
566 }