xref: /reactos/base/applications/sndvol32/dialog.c (revision 11345aed)
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 
11 VOID
12 ConvertRect(LPRECT lpRect, UINT xBaseUnit, UINT yBaseUnit)
13 {
14     lpRect->left = MulDiv(lpRect->left, xBaseUnit, 4);
15     lpRect->right = MulDiv(lpRect->right, xBaseUnit, 4);
16     lpRect->top = MulDiv(lpRect->top, yBaseUnit, 8);
17     lpRect->bottom = MulDiv(lpRect->bottom, yBaseUnit, 8);
18 }
19 
20 LPVOID
21 LoadDialogResource(
22     IN HMODULE hModule,
23     IN LPCWSTR ResourceName,
24     OUT LPDWORD ResourceLength)
25 {
26     HRSRC hSrc;
27     HGLOBAL hRes;
28     PVOID Result;
29 
30     /* find resource */
31     hSrc = FindResourceW(hModule, ResourceName, (LPCWSTR)RT_DIALOG);
32 
33     if (!hSrc)
34     {
35         /* failed to find resource */
36         return NULL;
37     }
38 
39     /* now load the resource */
40     hRes = LoadResource(hAppInstance, hSrc);
41     if (!hRes)
42     {
43         /* failed to load resource */
44         return NULL;
45     }
46 
47     /* now lock the resource */
48     Result = LockResource(hRes);
49 
50     if (!Result)
51     {
52         /* failed to lock resource */
53         return NULL;
54     }
55 
56     if (ResourceLength)
57     {
58         /* store output length */
59         *ResourceLength = SizeofResource(hAppInstance, hSrc);
60     }
61 
62     /* done */
63     return Result;
64 }
65 
66 LPWORD
67 AddDialogControl(
68     IN HWND hwndDialog,
69     OUT HWND *OutWnd,
70     IN LPRECT DialogOffset,
71     IN PDLGITEMTEMPLATE DialogItem,
72     IN DWORD DialogIdMultiplier,
73     IN HFONT hFont,
74     IN UINT xBaseUnit,
75     IN UINT yBaseUnit,
76     IN UINT MixerId)
77 {
78     RECT rect;
79     LPWORD Offset;
80     LPWSTR ClassName, WindowName;
81     WCHAR WindowIdBuf[sizeof("#65535")];
82     HWND hwnd;
83     DWORD wID;
84     INT nSteps, i;
85 
86     /* initialize client rectangle */
87     rect.left = DialogItem->x;
88     rect.top = DialogItem->y;
89     rect.right = DialogItem->x + DialogItem->cx;
90     rect.bottom = DialogItem->y + DialogItem->cy;
91 
92     /* Convert Dialog units to pixes */
93     ConvertRect(&rect, xBaseUnit, yBaseUnit);
94 
95     rect.left += DialogOffset->left;
96     rect.right += DialogOffset->left;
97     rect.top += DialogOffset->top;
98     rect.bottom += DialogOffset->top;
99 
100     /* move offset after dialog item */
101     Offset = (LPWORD)(DialogItem + 1);
102 
103     if (*Offset == 0xFFFF)
104     {
105         /* class is encoded as type */
106         Offset++;
107 
108         /* get control type */
109         switch(*Offset)
110         {
111             case 0x80:
112                 ClassName = L"button";
113                 break ;
114             case 0x82:
115                 ClassName = L"static";
116                 break;
117             default:
118                /* FIXME */
119                assert(0);
120                ClassName = NULL;
121         }
122         Offset++;
123     }
124     else
125     {
126         /* class name is encoded as string */
127         ClassName = (LPWSTR)(Offset);
128 
129         /* move offset to the end of class string */
130         Offset += wcslen(ClassName) + 1;
131     }
132 
133     if (*Offset == 0xFFFF)
134     {
135         /* Window name is encoded as ordinal */
136         Offset++;
137         wsprintf(WindowIdBuf, L"#%u", (DWORD)*Offset);
138         WindowName = WindowIdBuf;
139         Offset++;
140     }
141     else
142     {
143         /* window name is encoded as string */
144         WindowName = (LPWSTR)(Offset);
145 
146         /* move offset to the end of class string */
147         Offset += wcslen(WindowName) + 1;
148     }
149 
150     if (DialogItem->id == MAXWORD)
151     {
152         /* id is not important */
153         wID = DialogItem->id;
154     }
155     else
156     {
157         /* calculate id */
158         wID = DialogItem->id * (DialogIdMultiplier + 1);
159 
160     }
161 
162     /* now create the window */
163     hwnd = CreateWindowExW(DialogItem->dwExtendedStyle,
164                            ClassName,
165                            WindowName,
166                            DialogItem->style,
167                            rect.left,
168                            rect.top,
169                            rect.right - rect.left,
170                            rect.bottom - rect.top,
171                            hwndDialog,
172                            UlongToPtr(wID),
173                            hAppInstance,
174                            NULL);
175 
176     /* sanity check */
177     assert(hwnd);
178 
179     /* store window */
180     *OutWnd = hwnd;
181 
182     /* check if this the track bar */
183     if (!wcsicmp(ClassName, L"msctls_trackbar32"))
184     {
185         if (DialogItem->style & TBS_VERT)
186         {
187             /* Vertical trackbar: Volume */
188 
189             /* Disable the volume trackbar by default */
190             EnableWindow(hwnd, FALSE);
191 
192             /* set up range */
193             SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
194 
195             /* set up page size */
196             SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
197 
198             /* set position */
199             SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
200 
201             /* Calculate and set ticks */
202             nSteps = (VOLUME_MAX / (VOLUME_TICKS + 1));
203             if (VOLUME_MAX % (VOLUME_TICKS + 1) != 0)
204                 nSteps++;
205             for (i = nSteps; i < VOLUME_MAX; i += nSteps)
206                 SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
207         }
208         else
209         {
210             /* Horizontal trackbar: Balance */
211 
212             /* Disable the balance trackbar by default */
213             EnableWindow(hwnd, FALSE);
214 
215             /* set up range */
216             SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, BALANCE_STEPS));
217 
218             /* set up page size */
219             SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)BALANCE_PAGE_SIZE);
220 
221             /* set position */
222             SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)BALANCE_STEPS / 2);
223 
224             /* Calculate and set ticks */
225             nSteps = (BALANCE_STEPS / (BALANCE_TICKS + 1));
226             if (BALANCE_STEPS % (BALANCE_TICKS + 1) != 0)
227                 nSteps++;
228             for (i = nSteps; i < BALANCE_STEPS; i += nSteps)
229                 SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
230         }
231     }
232     else if (!wcsicmp(ClassName, L"static"))
233     {
234         /* Set font */
235         SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
236     }
237     else if (!wcsicmp(ClassName, L"button"))
238     {
239         if (DialogItem->id == IDC_LINE_SWITCH)
240         {
241             if (MixerId == PLAY_MIXER)
242             {
243                 /* Disable checkboxes by default, if we are in play mode */
244                 EnableWindow(hwnd, FALSE);
245             }
246         }
247         else if (DialogItem->id == IDC_LINE_ADVANCED)
248         {
249             ShowWindow(hwnd, SW_HIDE);
250         }
251 
252         /* Set font */
253         SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
254     }
255 
256 
257     /* check if there is additional data */
258     if (*Offset == 0)
259     {
260         /* no additional data */
261         Offset++;
262     }
263     else
264     {
265         /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
266         /* skip past additional data */
267         Offset += *Offset;
268     }
269 
270     /* make sure next template is word-aligned */
271     Offset = (LPWORD)(((ULONG_PTR)Offset + 3) & ~3);
272 
273     /* done */
274     return Offset;
275 }
276 
277 VOID
278 LoadDialogControls(
279     IN PMIXER_WINDOW MixerWindow,
280     LPRECT DialogOffset,
281     WORD ItemCount,
282     PDLGITEMTEMPLATE DialogItem,
283     DWORD DialogIdMultiplier,
284     UINT xBaseUnit,
285     UINT yBaseUnit)
286 {
287     LPWORD Offset;
288     WORD Index;
289 
290     /* sanity check */
291     assert(ItemCount);
292 
293     if (MixerWindow->Window)
294         MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + ItemCount) * sizeof(HWND));
295     else
296         MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ItemCount * sizeof(HWND));
297     if (!MixerWindow->Window)
298     {
299         /* no memory */
300         return;
301     }
302 
303     /* enumerate now all controls */
304     for (Index = 0; Index < ItemCount; Index++)
305     {
306         /* add controls */
307         Offset = AddDialogControl(MixerWindow->hWnd,
308                                   &MixerWindow->Window[MixerWindow->WindowCount],
309                                   DialogOffset,
310                                   DialogItem,
311                                   DialogIdMultiplier,
312                                   MixerWindow->hFont,
313                                   xBaseUnit,
314                                   yBaseUnit,
315                                   MixerWindow->MixerId);
316 
317         /* sanity check */
318         assert(Offset);
319 
320         /* move dialog item to new offset */
321         DialogItem =(PDLGITEMTEMPLATE)Offset;
322 
323         /* increment window count */
324         MixerWindow->WindowCount++;
325     }
326 }
327 
328 VOID
329 LoadDialog(
330     IN HMODULE hModule,
331     IN PMIXER_WINDOW MixerWindow,
332     IN LPCWSTR DialogResId,
333     IN DWORD Index)
334 {
335     LPDLGTEMPLATE DlgTemplate;
336     PDLGITEMTEMPLATE DlgItem;
337     RECT dialogRect;
338     LPWORD Offset;
339     WORD FontSize;
340     WCHAR FontName[100];
341     WORD Length;
342     int width;
343 
344     DWORD units = GetDialogBaseUnits();
345     UINT xBaseUnit = LOWORD(units);
346     UINT yBaseUnit = HIWORD(units);
347 
348     /* first load the dialog resource */
349     DlgTemplate = (LPDLGTEMPLATE)LoadDialogResource(hModule, DialogResId, NULL);
350     if (!DlgTemplate)
351     {
352         /* failed to load resource */
353         return;
354     }
355 
356     /* Now walk past the dialog header */
357     Offset = (LPWORD)(DlgTemplate + 1);
358 
359     /* FIXME: support menu */
360     assert(*Offset == 0);
361     Offset++;
362 
363     /* FIXME: support classes */
364     assert(*Offset == 0);
365     Offset++;
366 
367     /* FIXME: support titles */
368     assert(*Offset == 0);
369     Offset++;
370 
371     /* get font size */
372     FontSize = *Offset;
373     Offset++;
374 
375     /* calculate font length */
376     Length = wcslen((LPWSTR)Offset) + 1;
377     assert(Length < (sizeof(FontName) / sizeof(WCHAR)));
378 
379     /* copy font */
380     wcscpy(FontName, (LPWSTR)Offset);
381 
382     if (DlgTemplate->style & DS_SETFONT)
383     {
384         HDC hDC;
385 
386         hDC = GetDC(0);
387 
388         if (!MixerWindow->hFont)
389         {
390             int pixels = MulDiv(FontSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
391             MixerWindow->hFont = CreateFontW(-pixels, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, FontName);
392         }
393 
394         if (MixerWindow->hFont)
395         {
396             SIZE charSize;
397             HFONT hOldFont;
398 
399             hOldFont = SelectObject(hDC, MixerWindow->hFont);
400             charSize.cx = GdiGetCharDimensions(hDC, NULL, &charSize.cy);
401             if (charSize.cx)
402             {
403                 xBaseUnit = charSize.cx;
404                 yBaseUnit = charSize.cy;
405             }
406             SelectObject(hDC, hOldFont);
407 
408             MixerWindow->baseUnit.cx = charSize.cx;
409             MixerWindow->baseUnit.cy = charSize.cy;
410         }
411 
412         ReleaseDC(NULL, hDC);
413     }
414 
415 //    assert(MixerWindow->hFont);
416 
417     /* move offset after font name */
418     Offset += Length;
419 
420     /* offset is now at first dialog item control */
421     DlgItem = (PDLGITEMTEMPLATE)Offset;
422 
423     dialogRect.left = 0;
424     dialogRect.right = DlgTemplate->cx;
425     dialogRect.top = 0;
426     dialogRect.bottom = DlgTemplate->cy;
427 
428     ConvertRect(&dialogRect, xBaseUnit, yBaseUnit);
429 
430     width = dialogRect.right - dialogRect.left;
431 
432     dialogRect.left += MixerWindow->rect.right;
433     dialogRect.right += MixerWindow->rect.right;
434     dialogRect.top += MixerWindow->rect.top;
435     dialogRect.bottom += MixerWindow->rect.top;
436 
437     MixerWindow->rect.right += width;
438     if ((dialogRect.bottom - dialogRect.top) > (MixerWindow->rect.bottom - MixerWindow->rect.top))
439         MixerWindow->rect.bottom = MixerWindow->rect.top + dialogRect.bottom - dialogRect.top;
440 
441     /* now add the controls */
442     LoadDialogControls(MixerWindow, &dialogRect, DlgTemplate->cdit, DlgItem, Index, xBaseUnit, yBaseUnit);
443 }
444 
445 BOOL
446 CALLBACK
447 EnumConnectionsCallback(
448     PSND_MIXER Mixer,
449     DWORD LineID,
450     LPMIXERLINE Line,
451     PVOID Context)
452 {
453     WCHAR LineName[MIXER_LONG_NAME_CHARS];
454     DWORD Flags;
455     DWORD wID;
456     UINT ControlCount = 0, Index;
457     LPMIXERCONTROL Control = NULL;
458     HWND hDlgCtrl;
459     PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails = NULL;
460     PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
461 
462     if (Line->cControls == 0)
463         return TRUE;
464 
465     /* get line name */
466     if (SndMixerGetLineName(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
467     {
468         /* failed to get line name */
469         LineName[0] = L'\0';
470     }
471 
472     pVolumeDetails = HeapAlloc(GetProcessHeap(),
473                                0,
474                                Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
475     if (pVolumeDetails == NULL)
476         goto done;
477 
478     /* check if line is found in registry settings */
479     if (ReadLineConfig(PrefContext->DeviceName,
480                        LineName,
481                        Line->szName,
482                        &Flags))
483     {
484           /* is it selected */
485           if (Flags != 0x4)
486           {
487               int dlgId;
488 
489               if ((Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) ||
490                   (Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_HEADPHONES))
491                   dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_MASTER : IDD_NORMAL_MASTER;
492               else
493                   dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_LINE : IDD_NORMAL_LINE;
494 
495               /* load dialog resource */
496               LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(dlgId), PrefContext->MixerWindow->DialogCount);
497 
498               /* get id */
499               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_NAME;
500 
501               /* set line name */
502               SetDlgItemTextW(PrefContext->MixerWindow->hWnd, wID, Line->szName);
503 
504               /* query controls */
505               if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) != FALSE)
506               {
507                   /* now go through all controls and update their states */
508                   for (Index = 0; Index < Line->cControls; Index++)
509                   {
510                       if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
511                       {
512                           MIXERCONTROLDETAILS_BOOLEAN Details;
513 
514                           /* get volume control details */
515                           if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
516                           {
517                               /* update dialog control */
518                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SWITCH;
519 
520                               /* get dialog control */
521                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
522 
523                               if (hDlgCtrl != NULL)
524                               {
525                                   /* Enable the 'Mute' checkbox, if we are in play mode */
526                                   if (Mixer->MixerId == PLAY_MIXER)
527                                       EnableWindow(hDlgCtrl, TRUE);
528 
529                                   /* check state */
530                                   if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != Details.fValue)
531                                   {
532                                       /* update control state */
533                                       SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)Details.fValue, 0);
534                                   }
535                               }
536                           }
537                       }
538                       else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
539                       {
540                           /* get volume control details */
541                           if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)pVolumeDetails) != -1)
542                           {
543                               /* update dialog control */
544                               DWORD volumePosition, volumeStep, maxVolume, i;
545                               DWORD balancePosition, balanceStep;
546 
547                               volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
548 
549                               maxVolume = 0;
550                               for (i = 0; i < Line->cChannels; i++)
551                               {
552                                   if (pVolumeDetails[i].dwValue > maxVolume)
553                                       maxVolume = pVolumeDetails[i].dwValue;
554                               }
555 
556                               volumePosition = (maxVolume - Control[Index].Bounds.dwMinimum) / volumeStep;
557 
558                               if (Line->cChannels == 1)
559                               {
560                                   balancePosition = BALANCE_CENTER;
561                               }
562                               else if (Line->cChannels == 2)
563                               {
564                                   if (pVolumeDetails[0].dwValue == pVolumeDetails[1].dwValue)
565                                   {
566                                       balancePosition = BALANCE_CENTER;
567                                   }
568                                   else if (pVolumeDetails[0].dwValue == Control[Index].Bounds.dwMinimum)
569                                   {
570                                       balancePosition = BALANCE_RIGHT;
571                                   }
572                                   else if (pVolumeDetails[1].dwValue == Control[Index].Bounds.dwMinimum)
573                                   {
574                                       balancePosition = BALANCE_LEFT;
575                                   }
576                                   else
577                                   {
578                                       balanceStep = (maxVolume - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
579 
580                                       if (pVolumeDetails[0].dwValue < pVolumeDetails[1].dwValue)
581                                       {
582                                           balancePosition = (pVolumeDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
583                                           balancePosition = BALANCE_RIGHT - balancePosition;
584                                       }
585                                       else if (pVolumeDetails[1].dwValue < pVolumeDetails[0].dwValue)
586                                       {
587                                           balancePosition = (pVolumeDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
588                                           balancePosition = BALANCE_LEFT + balancePosition;
589                                       }
590                                   }
591                               }
592 
593                               /* Set the volume trackbar */
594                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_VERT;
595 
596                               /* get dialog control */
597                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
598 
599                               if (hDlgCtrl != NULL)
600                               {
601                                   /* check state */
602                                   LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
603 
604                                   /* Enable the volume trackbar */
605                                   EnableWindow(hDlgCtrl, TRUE);
606 
607                                   if (OldPosition != (VOLUME_MAX - volumePosition))
608                                   {
609                                       /* update control state */
610                                       SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, VOLUME_MAX - volumePosition);
611                                   }
612                               }
613 
614                               if (Line->cChannels == 2)
615                               {
616                                   /* Set the balance trackbar */
617                                   wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_HORZ;
618 
619                                   /* get dialog control */
620                                   hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
621 
622                                   if (hDlgCtrl != NULL)
623                                   {
624                                       /* check state */
625                                       LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
626 
627                                       /* Enable the balance trackbar */
628                                       EnableWindow(hDlgCtrl, TRUE);
629 
630                                       if (OldPosition != balancePosition)
631                                       {
632                                           /* update control state */
633                                           SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, balancePosition);
634                                       }
635                                   }
636                               }
637                           }
638                       }
639                       else
640                       {
641                           if (PrefContext->MixerWindow->Mode == NORMAL_MODE)
642                           {
643                               PrefContext->MixerWindow->bHasExtendedControls = TRUE;
644 
645                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_ADVANCED;
646 
647                               /* get dialog control */
648                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
649                               if (hDlgCtrl != NULL)
650                               {
651                                   ShowWindow(hDlgCtrl,
652                                              PrefContext->MixerWindow->bShowExtendedControls ? SW_SHOWNORMAL : SW_HIDE);
653                               }
654                           }
655                       }
656                   }
657 
658                   /* free controls */
659                   HeapFree(GetProcessHeap(), 0, Control);
660               }
661 
662               /* increment dialog count */
663               PrefContext->MixerWindow->DialogCount++;
664           }
665     }
666 
667 done:
668     /* Free the volume details */
669     if (pVolumeDetails)
670         HeapFree(GetProcessHeap(), 0, pVolumeDetails);
671 
672     return TRUE;
673 }
674 
675 VOID
676 LoadDialogCtrls(
677     PPREFERENCES_CONTEXT PrefContext)
678 {
679     WCHAR szBuffer[64];
680     HWND hDlgCtrl;
681     RECT statusRect;
682     UINT i;
683     LONG dy;
684 
685     /* set dialog count to zero */
686     PrefContext->MixerWindow->DialogCount = 0;
687     PrefContext->MixerWindow->bHasExtendedControls = FALSE;
688     SetRectEmpty(&PrefContext->MixerWindow->rect);
689 
690     /* enumerate controls */
691     SndMixerEnumConnections(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, EnumConnectionsCallback, (PVOID)PrefContext);
692 
693     /* Update the 'Advanced Controls' menu item */
694     EnableMenuItem(GetMenu(PrefContext->MixerWindow->hWnd),
695                    IDM_ADVANCED_CONTROLS,
696                    MF_BYCOMMAND | (PrefContext->MixerWindow->bHasExtendedControls ? MF_ENABLED : MF_GRAYED));
697 
698     /* Add some height for the status bar */
699     if (PrefContext->MixerWindow->hStatusBar)
700     {
701         GetWindowRect(PrefContext->MixerWindow->hStatusBar, &statusRect);
702         PrefContext->MixerWindow->rect.bottom += (statusRect.bottom - statusRect.top);
703     }
704 
705     /* Add height of the 'Advanced' button */
706     dy = MulDiv(ADVANCED_BUTTON_HEIGHT, PrefContext->MixerWindow->baseUnit.cy, 8);
707     if (PrefContext->MixerWindow->bShowExtendedControls && PrefContext->MixerWindow->bHasExtendedControls)
708         PrefContext->MixerWindow->rect.bottom += dy;
709 
710     /* now move the window */
711     AdjustWindowRect(&PrefContext->MixerWindow->rect, WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, TRUE);
712     SetWindowPos(PrefContext->MixerWindow->hWnd, HWND_TOP, PrefContext->MixerWindow->rect.left, PrefContext->MixerWindow->rect.top, PrefContext->MixerWindow->rect.right - PrefContext->MixerWindow->rect.left, PrefContext->MixerWindow->rect.bottom - PrefContext->MixerWindow->rect.top, SWP_NOMOVE | SWP_NOZORDER);
713 
714     /* Move the status bar */
715     if (PrefContext->MixerWindow->hStatusBar)
716     {
717         SetWindowPos(PrefContext->MixerWindow->hStatusBar,
718                      HWND_TOP,
719                      statusRect.left,
720                      PrefContext->MixerWindow->rect.bottom - (statusRect.bottom - statusRect.top),
721                      PrefContext->MixerWindow->rect.right - PrefContext->MixerWindow->rect.left,
722                      statusRect.bottom - statusRect.top,
723                      SWP_NOZORDER);
724     }
725 
726     if (PrefContext->MixerWindow->MixerId == RECORD_MIXER)
727         LoadStringW(hAppInstance, IDS_SELECT, szBuffer, ARRAYSIZE(szBuffer));
728 
729     for (i = 0; i < PrefContext->MixerWindow->DialogCount; i++)
730     {
731         if (PrefContext->MixerWindow->MixerId == RECORD_MIXER)
732         {
733             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, (i + 1) * IDC_LINE_SWITCH);
734 
735             /* Turn the autocheckbox into a checkbox */
736             SetWindowLongPtr(hDlgCtrl, GWL_STYLE, (GetWindowLongPtr(hDlgCtrl, GWL_STYLE) & ~BS_AUTOCHECKBOX) | BS_CHECKBOX);
737 
738             /* Change text from 'Mute' to 'Select' */
739             SetWindowTextW(hDlgCtrl, szBuffer);
740         }
741 
742         /* Resize the vertical line separator */
743         hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, (i + 1) * IDC_LINE_SEP);
744         if (hDlgCtrl != NULL)
745         {
746             GetWindowRect(hDlgCtrl, &statusRect);
747             if (PrefContext->MixerWindow->bShowExtendedControls && PrefContext->MixerWindow->bHasExtendedControls)
748                 statusRect.bottom += dy;
749 
750             SetWindowPos(hDlgCtrl,
751                          HWND_TOP,
752                          0,
753                          0,
754                          statusRect.right - statusRect.left,
755                          statusRect.bottom - statusRect.top,
756                          SWP_NOMOVE | SWP_NOZORDER);
757         }
758     }
759 
760     /* Hide the last line separator */
761     hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, IDC_LINE_SEP * PrefContext->MixerWindow->DialogCount);
762     if (hDlgCtrl != NULL)
763     {
764         ShowWindow(hDlgCtrl, SW_HIDE);
765     }
766 }
767 
768 VOID
769 UpdateDialogLineSwitchControl(
770     PPREFERENCES_CONTEXT PrefContext,
771     LPMIXERLINE Line,
772     LONG fValue)
773 {
774     DWORD Index;
775     DWORD wID;
776     HWND hDlgCtrl;
777     WCHAR LineName[MIXER_LONG_NAME_CHARS];
778 
779     /* find the index of this line */
780     for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
781     {
782         /* get id */
783         wID = (Index + 1) * IDC_LINE_NAME;
784 
785         if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
786         {
787             /* failed to retrieve id */
788             continue;
789         }
790 
791         /* check if the line name matches */
792         if (!wcsicmp(LineName, Line->szName))
793         {
794             /* found matching line name */
795             wID = (Index + 1) * IDC_LINE_SWITCH;
796 
797             /* get dialog control */
798             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
799 
800             if (hDlgCtrl != NULL)
801             {
802                 /* check state */
803                 if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != fValue)
804                 {
805                     /* update control state */
806                     SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)fValue, 0);
807                 }
808             }
809             break;
810         }
811     }
812 }
813 
814 VOID
815 UpdateDialogLineSliderControl(
816     PPREFERENCES_CONTEXT PrefContext,
817     LPMIXERLINE Line,
818     DWORD dwDialogID,
819     DWORD Position)
820 {
821     DWORD Index;
822     DWORD wID;
823     HWND hDlgCtrl;
824     WCHAR LineName[MIXER_LONG_NAME_CHARS];
825 
826     /* find the index of this line */
827     for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
828     {
829         /* get id */
830         wID = (Index + 1) * IDC_LINE_NAME;
831 
832         if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
833         {
834             /* failed to retrieve id */
835             continue;
836         }
837 
838         /* check if the line name matches */
839         if (!wcsicmp(LineName, Line->szName))
840         {
841             /* found matching line name */
842             wID = (Index + 1) * dwDialogID;
843 
844             /* get dialog control */
845             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
846 
847             if (hDlgCtrl != NULL)
848             {
849                 /* check state */
850                 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
851                 if (OldPosition != Position)
852                 {
853                     /* update control state */
854                     SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position);
855                 }
856             }
857             break;
858         }
859     }
860 }
861