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