[SNDVOL32] In record mode, rename the 'Mute' autocheckbox to 'Select', turn it into...
[reactos.git] / base / applications / sndvol32 / dialog.c
index 1c83b61..5a52272 100644 (file)
@@ -1,17 +1,21 @@
 /*
  * COPYRIGHT:   See COPYING in the top level directory
  * PROJECT:     ReactOS Sound Volume Control
- * FILE:        subsys/system/sndvol32/dialog.c
+ * FILE:        base/applications/sndvol32/dialog.c
  * PROGRAMMERS: Johannes Anderwald
  */
 
 #include "sndvol32.h"
 
-#include <wingdi.h>
 
-#define XLEFT (30)
-#define XTOP (20)
-#define DIALOG_VOLUME_SIZE (150)
+VOID
+ConvertRect(LPRECT lpRect, UINT xBaseUnit, UINT yBaseUnit)
+{
+    lpRect->left = MulDiv(lpRect->left, xBaseUnit, 4);
+    lpRect->right = MulDiv(lpRect->right, xBaseUnit, 4);
+    lpRect->top = MulDiv(lpRect->top, yBaseUnit, 8);
+    lpRect->bottom = MulDiv(lpRect->bottom, yBaseUnit, 8);
+}
 
 LPVOID
 LoadDialogResource(
@@ -62,25 +66,36 @@ LoadDialogResource(
 LPWORD
 AddDialogControl(
     IN HWND hwndDialog,
-    IN HWND * OutWnd,
+    OUT HWND *OutWnd,
     IN LPRECT DialogOffset,
     IN PDLGITEMTEMPLATE DialogItem,
     IN DWORD DialogIdMultiplier,
-    IN HFONT hFont)
+    IN HFONT hFont,
+    IN UINT xBaseUnit,
+    IN UINT yBaseUnit,
+    IN UINT MixerId)
 {
     RECT rect;
     LPWORD Offset;
-    LPWSTR ClassName, WindowName = NULL;
+    LPWSTR ClassName, WindowName;
+    WCHAR WindowIdBuf[sizeof("#65535")];
     HWND hwnd;
     DWORD wID;
+    INT nSteps, i;
 
     /* initialize client rectangle */
-    rect.left = DialogItem->x + DialogOffset->left;
-    rect.top = DialogItem->y + DialogOffset->top;
-    rect.right = DialogItem->cx;
-    rect.bottom = DialogItem->cy;
+    rect.left = DialogItem->x;
+    rect.top = DialogItem->y;
+    rect.right = DialogItem->x + DialogItem->cx;
+    rect.bottom = DialogItem->y + DialogItem->cy;
 
-    //MapDialogRect(hwndDialog, &rect);
+    /* Convert Dialog units to pixes */
+    ConvertRect(&rect, xBaseUnit, yBaseUnit);
+
+    rect.left += DialogOffset->left;
+    rect.right += DialogOffset->left;
+    rect.top += DialogOffset->top;
+    rect.bottom += DialogOffset->top;
 
     /* move offset after dialog item */
     Offset = (LPWORD)(DialogItem + 1);
@@ -95,28 +110,41 @@ AddDialogControl(
         {
             case 0x80:
                 ClassName = L"button";
-                WindowName = (LPWSTR)(Offset + 1);
                 break ;
             case 0x82:
                 ClassName = L"static";
-                WindowName = (LPWSTR)(Offset + 1);
                 break;
             default:
                /* FIXME */
                assert(0);
-               ClassName = 0;
+               ClassName = NULL;
         }
+        Offset++;
     }
     else
     {
         /* class name is encoded as string */
-        ClassName = (LPWSTR)Offset;
+        ClassName = (LPWSTR)(Offset);
 
-        /* adjust offset */
+        /* move offset to the end of class string */
         Offset += wcslen(ClassName) + 1;
+    }
 
-        /* get offset */
-        WindowName = (LPWSTR)(Offset + 1);
+    if (*Offset == 0xFFFF)
+    {
+        /* Window name is encoded as ordinal */
+        Offset++;
+        wsprintf(WindowIdBuf, L"#%u", (DWORD)*Offset);
+        WindowName = WindowIdBuf;
+        Offset++;
+    }
+    else
+    {
+        /* window name is encoded as string */
+        WindowName = (LPWSTR)(Offset);
+
+        /* move offset to the end of class string */
+        Offset += wcslen(WindowName) + 1;
     }
 
     if (DialogItem->id == MAXWORD)
@@ -130,6 +158,7 @@ AddDialogControl(
         wID = DialogItem->id * (DialogIdMultiplier + 1);
 
     }
+
     /* now create the window */
     hwnd = CreateWindowExW(DialogItem->dwExtendedStyle,
                            ClassName,
@@ -137,10 +166,10 @@ AddDialogControl(
                            DialogItem->style,
                            rect.left,
                            rect.top,
-                           rect.right,
-                           rect.bottom,
+                           rect.right - rect.left,
+                           rect.bottom - rect.top,
                            hwndDialog,
-                           (HMENU)(wID),
+                           UlongToPtr(wID),
                            hAppInstance,
                            NULL);
 
@@ -153,41 +182,78 @@ AddDialogControl(
     /* check if this the track bar */
     if (!wcsicmp(ClassName, L"msctls_trackbar32"))
     {
-        /* set up range */
-        SendMessage(hwnd, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG(0, 5));
+        if (DialogItem->style & TBS_VERT)
+        {
+            /* Vertical trackbar: Volume */
+
+            /* Disable the volume trackbar by default */
+            EnableWindow(hwnd, FALSE);
 
-        /* set up page size */
-        SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM) 1);
+            /* set up range */
+            SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
 
-        /* set available range */
-        //SendMessage(hwnd, TBM_SETSEL, (WPARAM) FALSE, (LPARAM) MAKELONG(0, 5));
+            /* set up page size */
+            SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
 
-        /* set position */
-        SendMessage(hwnd, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) 0);
+            /* set position */
+            SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
 
+            /* Calculate and set ticks */
+            nSteps = (VOLUME_MAX / (VOLUME_TICKS + 1));
+            if (VOLUME_MAX % (VOLUME_TICKS + 1) != 0)
+                nSteps++;
+            for (i = nSteps; i < VOLUME_MAX; i += nSteps)
+                SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
+        }
+        else
+        {
+            /* Horizontal trackbar: Balance */
+
+            /* Disable the balance trackbar by default */
+            EnableWindow(hwnd, FALSE);
+
+            /* set up range */
+            SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, BALANCE_STEPS));
+
+            /* set up page size */
+            SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)BALANCE_PAGE_SIZE);
+
+            /* set position */
+            SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)BALANCE_STEPS / 2);
+
+            /* Calculate and set ticks */
+            nSteps = (BALANCE_STEPS / (BALANCE_TICKS + 1));
+            if (BALANCE_STEPS % (BALANCE_TICKS + 1) != 0)
+                nSteps++;
+            for (i = nSteps; i < BALANCE_STEPS; i += nSteps)
+                SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
+        }
     }
-    else if (!wcsicmp(ClassName, L"static") || !wcsicmp(ClassName, L"button"))
+    else if (!wcsicmp(ClassName, L"static"))
     {
-        /* set font */
+        /* Set font */
         SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
     }
-
-    //ShowWindow(hwnd, SW_SHOWNORMAL);
-
-    if (WindowName != NULL)
+    else if (!wcsicmp(ClassName, L"button"))
     {
-        /* position offset to start of name */
-        Offset++;
+        if (DialogItem->id == IDC_LINE_SWITCH)
+        {
+            if (MixerId == PLAY_MIXER)
+            {
+                /* Disable checkboxes by default, if we are in play mode */
+                EnableWindow(hwnd, FALSE);
+            }
+        }
+        else if (DialogItem->id == IDC_LINE_ADVANCED)
+        {
+            ShowWindow(hwnd, SW_HIDE);
+        }
 
-        /* move offset past name */
-        Offset += wcslen((LPWSTR)Offset) + 1;
-    }
-    else
-    {
-        /* no name so just adjust offset */
-        Offset++;
+        /* Set font */
+        SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
     }
 
+
     /* check if there is additional data */
     if (*Offset == 0)
     {
@@ -196,7 +262,8 @@ AddDialogControl(
     }
     else
     {
-        /* add data offset */
+        /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
+        /* skip past additional data */
         Offset += *Offset;
     }
 
@@ -211,35 +278,83 @@ VOID
 LoadDialogControls(
     IN PMIXER_WINDOW MixerWindow,
     LPRECT DialogOffset,
-    LPVOID DlgResource,
-    DWORD DialogIdMultiplier)
+    WORD ItemCount,
+    PDLGITEMTEMPLATE DialogItem,
+    DWORD DialogIdMultiplier,
+    UINT xBaseUnit,
+    UINT yBaseUnit)
 {
-    LPDLGTEMPLATE DialogHeader;
-    PDLGITEMTEMPLATE DialogItem;
     LPWORD Offset;
-    WORD FontSize;
-    WCHAR FontName[100];
-    WORD Length, Index;
-    HFONT Font;
-
-    /* get dialog header */
-    DialogHeader = (LPDLGTEMPLATE)DlgResource;
+    WORD Index;
 
     /* sanity check */
-    assert(DialogHeader->cdit);
+    assert(ItemCount);
 
     if (MixerWindow->Window)
-        MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + DialogHeader->cdit) * sizeof(HWND));
+        MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + ItemCount) * sizeof(HWND));
     else
-        MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DialogHeader->cdit * sizeof(HWND));
+        MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ItemCount * sizeof(HWND));
     if (!MixerWindow->Window)
     {
         /* no memory */
         return;
     }
 
-    /* now walk past the dialog header */
-    Offset = (LPWORD)(DialogHeader + 1);
+    /* enumerate now all controls */
+    for (Index = 0; Index < ItemCount; Index++)
+    {
+        /* add controls */
+        Offset = AddDialogControl(MixerWindow->hWnd,
+                                  &MixerWindow->Window[MixerWindow->WindowCount],
+                                  DialogOffset,
+                                  DialogItem,
+                                  DialogIdMultiplier,
+                                  MixerWindow->hFont,
+                                  xBaseUnit,
+                                  yBaseUnit,
+                                  MixerWindow->MixerId);
+
+        /* sanity check */
+        assert(Offset);
+
+        /* move dialog item to new offset */
+        DialogItem =(PDLGITEMTEMPLATE)Offset;
+
+        /* increment window count */
+        MixerWindow->WindowCount++;
+    }
+}
+
+VOID
+LoadDialog(
+    IN HMODULE hModule,
+    IN PMIXER_WINDOW MixerWindow,
+    IN LPCWSTR DialogResId,
+    IN DWORD Index)
+{
+    LPDLGTEMPLATE DlgTemplate;
+    PDLGITEMTEMPLATE DlgItem;
+    RECT dialogRect;
+    LPWORD Offset;
+    WORD FontSize;
+    WCHAR FontName[100];
+    WORD Length;
+    int width;
+
+    DWORD units = GetDialogBaseUnits();
+    UINT xBaseUnit = LOWORD(units);
+    UINT yBaseUnit = HIWORD(units);
+
+    /* first load the dialog resource */
+    DlgTemplate = (LPDLGTEMPLATE)LoadDialogResource(hModule, DialogResId, NULL);
+    if (!DlgTemplate)
+    {
+        /* failed to load resource */
+        return;
+    }
+
+    /* Now walk past the dialog header */
+    Offset = (LPWORD)(DlgTemplate + 1);
 
     /* FIXME: support menu */
     assert(*Offset == 0);
@@ -264,61 +379,65 @@ LoadDialogControls(
     /* copy font */
     wcscpy(FontName, (LPWSTR)Offset);
 
-    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);
-    assert(Font);
-
-    /* move offset after font name */
-    Offset += Length;
+    if (DlgTemplate->style & DS_SETFONT)
+    {
+        HDC hDC;
 
-    /* offset is now at first dialog item control */
-    DialogItem = (PDLGITEMTEMPLATE)Offset;
+        hDC = GetDC(0);
 
-    /* enumerate now all controls */
-    for(Index = 0; Index < DialogHeader->cdit; Index++)
-    {
-        /* add controls */
-        Offset = AddDialogControl(MixerWindow->hWnd, &MixerWindow->Window[MixerWindow->WindowCount], DialogOffset, DialogItem, DialogIdMultiplier, Font);
+        if (!MixerWindow->hFont)
+        {
+            int pixels = MulDiv(FontSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
+            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);
+        }
 
-        /* sanity check */
-        assert(Offset);
+        if (MixerWindow->hFont)
+        {
+            SIZE charSize;
+            HFONT hOldFont;
 
-        /* move dialog item to new offset */
-        DialogItem =(PDLGITEMTEMPLATE)Offset;
+            hOldFont = SelectObject(hDC, MixerWindow->hFont);
+            charSize.cx = GdiGetCharDimensions(hDC, NULL, &charSize.cy);
+            if (charSize.cx)
+            {
+                xBaseUnit = charSize.cx;
+                yBaseUnit = charSize.cy;
+            }
+            SelectObject(hDC, hOldFont);
 
-        /* increment window count */
-        MixerWindow->WindowCount++;
+            MixerWindow->baseUnit.cx = charSize.cx;
+            MixerWindow->baseUnit.cy = charSize.cy;
+        }
     }
-}
 
-VOID
-LoadDialog(
-    IN HMODULE hModule,
-    IN PMIXER_WINDOW MixerWindow,
-    IN LPCWSTR DialogResId,
-    IN DWORD Index)
-{
-    LPVOID DlgResource;
-    RECT rect;
+//    assert(MixerWindow->hFont);
 
-    /* first load the dialog resource */
-    DlgResource = LoadDialogResource(hModule, DialogResId, NULL);
+    /* move offset after font name */
+    Offset += Length;
 
-    if (!DlgResource)
-    {
-        /* failed to load resource */
-        return;
-    }
+    /* offset is now at first dialog item control */
+    DlgItem = (PDLGITEMTEMPLATE)Offset;
 
-    /* get window size */
-    GetClientRect(MixerWindow->hWnd, &rect);
+    dialogRect.left = 0;
+    dialogRect.right = DlgTemplate->cx;
+    dialogRect.top = 0;
+    dialogRect.bottom = DlgTemplate->cy;
 
-    /* adjust client position */
-    rect.left += (Index * DIALOG_VOLUME_SIZE);
+    ConvertRect(&dialogRect, xBaseUnit, yBaseUnit);
 
+    width = dialogRect.right - dialogRect.left;
 
-    /* now add the controls */
-    LoadDialogControls(MixerWindow, &rect, DlgResource, Index);
+    dialogRect.left += MixerWindow->rect.right;
+    dialogRect.right += MixerWindow->rect.right;
+    dialogRect.top += MixerWindow->rect.top;
+    dialogRect.bottom += MixerWindow->rect.top;
 
+    MixerWindow->rect.right += width;
+    if ((dialogRect.bottom - dialogRect.top) > (MixerWindow->rect.bottom - MixerWindow->rect.top))
+        MixerWindow->rect.bottom = MixerWindow->rect.top + dialogRect.bottom - dialogRect.top;
+
+    /* now add the controls */
+    LoadDialogControls(MixerWindow, &dialogRect, DlgTemplate->cdit, DlgItem, Index, xBaseUnit, yBaseUnit);
 }
 
 BOOL
@@ -332,101 +451,206 @@ EnumConnectionsCallback(
     WCHAR LineName[MIXER_LONG_NAME_CHARS];
     DWORD Flags;
     DWORD wID;
-    RECT rect;
     UINT ControlCount = 0, Index;
     LPMIXERCONTROL Control = NULL;
     HWND hDlgCtrl;
+    PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails = NULL;
     PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
 
-    if (Line->cControls != 0)
+    if (Line->cControls == 0)
+        return TRUE;
+
+    /* get line name */
+    if (SndMixerGetLineName(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
+    {
+        /* failed to get line name */
+        LineName[0] = L'\0';
+    }
+
+    pVolumeDetails = HeapAlloc(GetProcessHeap(),
+                               0,
+                               Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
+    if (pVolumeDetails == NULL)
+        goto done;
+
+    /* check if line is found in registry settings */
+    if (ReadLineConfig(PrefContext->DeviceName,
+                       LineName,
+                       Line->szName,
+                       &Flags))
     {
-      /* get line name */
-      if (SndMixerGetLineName(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
-      {
-          /* failed to get line name */
-          LineName[0] = L'\0';
-      }
-
-      /* check if line is found in registry settings */
-      if (ReadLineConfig(PrefContext->DeviceName,
-                         LineName,
-                         Line->szName,
-                         &Flags))
-      {
           /* is it selected */
           if (Flags != 0x4)
           {
+              int dlgId;
+
+              if ((Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) ||
+                  (Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_HEADPHONES))
+                  dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_MASTER : IDD_NORMAL_MASTER;
+              else
+                  dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_LINE : IDD_NORMAL_LINE;
+
               /* load dialog resource */
-              LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(IDD_VOLUME_CTRL), PrefContext->Count);
+              LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(dlgId), PrefContext->MixerWindow->DialogCount);
 
               /* get id */
-              wID = (PrefContext->Count + 1) * IDC_LINE_NAME;
+              wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_NAME;
 
               /* set line name */
               SetDlgItemTextW(PrefContext->MixerWindow->hWnd, wID, Line->szName);
 
               /* query controls */
-              if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) == TRUE)
+              if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) != FALSE)
               {
                   /* now go through all controls and update their states */
-                  for(Index = 0; Index < ControlCount; Index++)
+                  for (Index = 0; Index < Line->cControls; Index++)
                   {
-                     if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_SWITCH)
-                     {
-                         MIXERCONTROLDETAILS_BOOLEAN Details;
-
-                         /* get volume control details */
-                         if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
-                         {
-                             /* update dialog control */
-                             wID = (PrefContext->Count + 1) * IDC_LINE_SWITCH;
-
-                            /* get dialog control */
-                            hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
-
-                            if (hDlgCtrl != NULL)
-                            {
-                                /* check state */
-                                if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != Details.fValue)
-                                {
-                                    /* update control state */
-                                    SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)Details.fValue, 0);
-                                }
-                            }
-                         }
-                     }
-                     else if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_FADER)
-                     {
-                         MIXERCONTROLDETAILS_UNSIGNED Details;
-
-                         /* get volume control details */
-                         if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&Details) != -1)
-                         {
-                             /* update dialog control */
-                             DWORD Position;
-                             DWORD Step = 0x10000 / 5;
-
-                             /* FIXME: give me granularity */
-                             Position = 5 - (Details.dwValue / Step);
-
-                             /* FIXME support left - right slider */
-                             wID = (PrefContext->Count + 1) * IDC_LINE_SLIDER_VERT;
-
-                             /* get dialog control */
-                             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
-
-                             if (hDlgCtrl != NULL)
-                             {
-                                 /* check state */
-                                 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
-                                 if (OldPosition != Position)
-                                 {
-                                     /* update control state */
-                                     SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position + Index);
-                                 }
-                             }
-                        }
-                     }
+                      if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
+                      {
+                          MIXERCONTROLDETAILS_BOOLEAN Details;
+
+                          /* get volume control details */
+                          if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
+                          {
+                              /* update dialog control */
+                              wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SWITCH;
+
+                              /* get dialog control */
+                              hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
+
+                              if (hDlgCtrl != NULL)
+                              {
+                                  /* Enable the 'Mute' checkbox, if we are in play mode */
+                                  if (Mixer->MixerId == PLAY_MIXER)
+                                      EnableWindow(hDlgCtrl, TRUE);
+
+                                  /* check state */
+                                  if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != Details.fValue)
+                                  {
+                                      /* update control state */
+                                      SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)Details.fValue, 0);
+                                  }
+                              }
+                          }
+                      }
+                      else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
+                      {
+                          /* get volume control details */
+                          if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)pVolumeDetails) != -1)
+                          {
+                              /* update dialog control */
+                              DWORD volumePosition, volumeStep, maxVolume, i;
+                              DWORD balancePosition, balanceStep;
+
+                              volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
+
+                              maxVolume = 0;
+                              for (i = 0; i < Line->cChannels; i++)
+                              {
+                                  if (pVolumeDetails[i].dwValue > maxVolume)
+                                      maxVolume = pVolumeDetails[i].dwValue;
+                              }
+
+                              volumePosition = (maxVolume - Control[Index].Bounds.dwMinimum) / volumeStep;
+
+                              if (Line->cChannels == 1)
+                              {
+                                  balancePosition = BALANCE_CENTER;
+                              }
+                              else if (Line->cChannels == 2)
+                              {
+                                  if (pVolumeDetails[0].dwValue == pVolumeDetails[1].dwValue)
+                                  {
+                                      balancePosition = BALANCE_CENTER;
+                                  }
+                                  else if (pVolumeDetails[0].dwValue == Control[Index].Bounds.dwMinimum)
+                                  {
+                                      balancePosition = BALANCE_RIGHT;
+                                  }
+                                  else if (pVolumeDetails[1].dwValue == Control[Index].Bounds.dwMinimum)
+                                  {
+                                      balancePosition = BALANCE_LEFT;
+                                  }
+                                  else
+                                  {
+                                      balanceStep = (maxVolume - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
+
+                                      if (pVolumeDetails[0].dwValue < pVolumeDetails[1].dwValue)
+                                      {
+                                          balancePosition = (pVolumeDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
+                                          balancePosition = BALANCE_RIGHT - balancePosition;
+                                      }
+                                      else if (pVolumeDetails[1].dwValue < pVolumeDetails[0].dwValue)
+                                      {
+                                          balancePosition = (pVolumeDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
+                                          balancePosition = BALANCE_LEFT + balancePosition;
+                                      }
+                                  }
+                              }
+
+                              /* Set the volume trackbar */
+                              wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_VERT;
+
+                              /* get dialog control */
+                              hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
+
+                              if (hDlgCtrl != NULL)
+                              {
+                                  /* check state */
+                                  LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
+
+                                  /* Enable the volume trackbar */
+                                  EnableWindow(hDlgCtrl, TRUE);
+
+                                  if (OldPosition != (VOLUME_MAX - volumePosition))
+                                  {
+                                      /* update control state */
+                                      SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, VOLUME_MAX - volumePosition);
+                                  }
+                              }
+
+                              if (Line->cChannels == 2)
+                              {
+                                  /* Set the balance trackbar */
+                                  wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_HORZ;
+
+                                  /* get dialog control */
+                                  hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
+
+                                  if (hDlgCtrl != NULL)
+                                  {
+                                      /* check state */
+                                      LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
+
+                                      /* Enable the balance trackbar */
+                                      EnableWindow(hDlgCtrl, TRUE);
+
+                                      if (OldPosition != balancePosition)
+                                      {
+                                          /* update control state */
+                                          SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, balancePosition);
+                                      }
+                                  }
+                              }
+                          }
+                      }
+                      else
+                      {
+                          if (PrefContext->MixerWindow->Mode == NORMAL_MODE)
+                          {
+                              PrefContext->MixerWindow->bHasExtendedControls = TRUE;
+
+                              wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_ADVANCED;
+
+                              /* get dialog control */
+                              hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
+                              if (hDlgCtrl != NULL)
+                              {
+                                  ShowWindow(hDlgCtrl,
+                                             PrefContext->MixerWindow->bShowExtendedControls ? SW_SHOWNORMAL : SW_HIDE);
+                              }
+                          }
+                      }
                   }
 
                   /* free controls */
@@ -434,16 +658,15 @@ EnumConnectionsCallback(
               }
 
               /* increment dialog count */
-              PrefContext->Count++;
-
-              /* get application rectangle */
-              GetWindowRect(PrefContext->MixerWindow->hWnd, &rect);
-
-              /* now move the window */
-              MoveWindow(PrefContext->MixerWindow->hWnd, rect.left, rect.top, (PrefContext->Count * DIALOG_VOLUME_SIZE), rect.bottom - rect.top, TRUE);
+              PrefContext->MixerWindow->DialogCount++;
           }
-      }
     }
+
+done:
+    /* Free the volume details */
+    if (pVolumeDetails)
+        HeapFree(GetProcessHeap(), 0, pVolumeDetails);
+
     return TRUE;
 }
 
@@ -451,23 +674,93 @@ VOID
 LoadDialogCtrls(
     PPREFERENCES_CONTEXT PrefContext)
 {
+    WCHAR szBuffer[64];
     HWND hDlgCtrl;
+    RECT statusRect;
+    UINT i;
+    LONG dy;
 
     /* set dialog count to zero */
-    PrefContext->Count = 0;
+    PrefContext->MixerWindow->DialogCount = 0;
+    PrefContext->MixerWindow->bHasExtendedControls = FALSE;
+    SetRectEmpty(&PrefContext->MixerWindow->rect);
 
     /* enumerate controls */
     SndMixerEnumConnections(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, EnumConnectionsCallback, (PVOID)PrefContext);
 
-    /* get last line seperator */
-    hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, IDC_LINE_SEP * PrefContext->Count);
+    /* Update the 'Advanced Controls' menu item */
+    EnableMenuItem(GetMenu(PrefContext->MixerWindow->hWnd),
+                   IDM_ADVANCED_CONTROLS,
+                   MF_BYCOMMAND | (PrefContext->MixerWindow->bHasExtendedControls ? MF_ENABLED : MF_GRAYED));
+
+    /* Add some height for the status bar */
+    if (PrefContext->MixerWindow->hStatusBar)
+    {
+        GetWindowRect(PrefContext->MixerWindow->hStatusBar, &statusRect);
+        PrefContext->MixerWindow->rect.bottom += (statusRect.bottom - statusRect.top);
+    }
+
+    /* Add height of the 'Advanced' button */
+    dy = MulDiv(ADVANCED_BUTTON_HEIGHT, PrefContext->MixerWindow->baseUnit.cy, 8);
+    if (PrefContext->MixerWindow->bShowExtendedControls && PrefContext->MixerWindow->bHasExtendedControls)
+        PrefContext->MixerWindow->rect.bottom += dy;
+
+    /* now move the window */
+    AdjustWindowRect(&PrefContext->MixerWindow->rect, WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, TRUE);
+    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);
+
+    /* Move the status bar */
+    if (PrefContext->MixerWindow->hStatusBar)
+    {
+        SetWindowPos(PrefContext->MixerWindow->hStatusBar,
+                     HWND_TOP,
+                     statusRect.left,
+                     PrefContext->MixerWindow->rect.bottom - (statusRect.bottom - statusRect.top),
+                     PrefContext->MixerWindow->rect.right - PrefContext->MixerWindow->rect.left,
+                     statusRect.bottom - statusRect.top,
+                     SWP_NOZORDER);
+    }
+
+    if (PrefContext->MixerWindow->MixerId == RECORD_MIXER)
+        LoadStringW(hAppInstance, IDS_SELECT, szBuffer, ARRAYSIZE(szBuffer));
+
+    for (i = 0; i < PrefContext->MixerWindow->DialogCount; i++)
+    {
+        if (PrefContext->MixerWindow->MixerId == RECORD_MIXER)
+        {
+            hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, (i + 1) * IDC_LINE_SWITCH);
+
+            /* Turn the autocheckbox into a checkbox */
+            SetWindowLongPtr(hDlgCtrl, GWL_STYLE, (GetWindowLongPtr(hDlgCtrl, GWL_STYLE) & ~BS_AUTOCHECKBOX) | BS_CHECKBOX);
 
+            /* Change text from 'Mute' to 'Select' */
+            SetWindowTextW(hDlgCtrl, szBuffer);
+        }
+
+        /* Resize the vertical line separator */
+        hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, (i + 1) * IDC_LINE_SEP);
+        if (hDlgCtrl != NULL)
+        {
+            GetWindowRect(hDlgCtrl, &statusRect);
+            if (PrefContext->MixerWindow->bShowExtendedControls && PrefContext->MixerWindow->bHasExtendedControls)
+                statusRect.bottom += dy;
+
+            SetWindowPos(hDlgCtrl,
+                         HWND_TOP,
+                         0,
+                         0,
+                         statusRect.right - statusRect.left,
+                         statusRect.bottom - statusRect.top,
+                         SWP_NOMOVE | SWP_NOZORDER);
+        }
+    }
+
+    /* Hide the last line separator */
+    hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, IDC_LINE_SEP * PrefContext->MixerWindow->DialogCount);
     if (hDlgCtrl != NULL)
     {
-        /* hide last seperator */
         ShowWindow(hDlgCtrl, SW_HIDE);
     }
-
 }
 
 VOID
@@ -482,7 +775,7 @@ UpdateDialogLineSwitchControl(
     WCHAR LineName[MIXER_LONG_NAME_CHARS];
 
     /* find the index of this line */
-    for(Index = 0; Index < PrefContext->Count; Index++)
+    for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
     {
         /* get id */
         wID = (Index + 1) * IDC_LINE_NAME;
@@ -520,7 +813,6 @@ VOID
 UpdateDialogLineSliderControl(
     PPREFERENCES_CONTEXT PrefContext,
     LPMIXERLINE Line,
-    DWORD dwControlID,
     DWORD dwDialogID,
     DWORD Position)
 {
@@ -530,7 +822,7 @@ UpdateDialogLineSliderControl(
     WCHAR LineName[MIXER_LONG_NAME_CHARS];
 
     /* find the index of this line */
-    for(Index = 0; Index < PrefContext->Count; Index++)
+    for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
     {
         /* get id */
         wID = (Index + 1) * IDC_LINE_NAME;
@@ -557,7 +849,7 @@ UpdateDialogLineSliderControl(
                 if (OldPosition != Position)
                 {
                     /* update control state */
-                    SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position + Index);
+                    SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position);
                 }
             }
             break;