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