1  /*
2   * COPYRIGHT:   See COPYING in the top level directory
3   * PROJECT:     ReactOS Sound Volume Control
4   * FILE:        base/applications/sndvol32/advanced.c
5   * PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org>
6   */
7  
8  #include "sndvol32.h"
9  
10  typedef struct _ADVANCED_DATA
11  {
12      PADVANCED_CONTEXT Context;
13  
14      BOOL bEnabled[4];
15      DWORD dwControlId[4];
16  
17      /* Bass and Treble */
18      DWORD dwMaximum[2];
19      DWORD dwMinimum[2];
20  
21  } ADVANCED_DATA, *PADVANCED_DATA;
22  
23  static
24  VOID
25  OnInitDialog(
26      HWND hwndDlg,
27      PADVANCED_DATA pData)
28  {
29      MIXERCONTROLDETAILS_UNSIGNED UnsignedDetails;
30      MIXERCONTROLDETAILS_BOOLEAN BooleanDetails;
31      WCHAR szRawBuffer[256], szCookedBuffer[256];
32      LPMIXERCONTROL Control = NULL;
33      UINT ControlCount = 0, Index;
34      DWORD i, dwStep, dwPosition;
35      DWORD dwOtherControls = 0;
36      RECT rect;
37      LONG dy;
38  
39      /* Set the dialog title */
40      LoadStringW(hAppInstance, IDS_ADVANCED_CONTROLS, szRawBuffer, ARRAYSIZE(szRawBuffer));
41      StringCchPrintfW(szCookedBuffer, ARRAYSIZE(szCookedBuffer), szRawBuffer, pData->Context->LineName);
42      SetWindowTextW(hwndDlg, szCookedBuffer);
43  
44      /* Disable the tone controls */
45      for (i = IDC_ADV_BASS_LOW; i<= IDC_ADV_TREBLE_SLIDER; i++)
46          EnableWindow(GetDlgItem(hwndDlg, i), FALSE);
47  
48      /* Initialize the bass and treble trackbars */
49      SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
50      SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
51      SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
52      SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
53      SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
54      SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
55  
56      /* Calculate and set ticks */
57      dwStep = (VOLUME_MAX / (VOLUME_TICKS + 1));
58      if (VOLUME_MAX % (VOLUME_TICKS + 1) != 0)
59          dwStep++;
60      for (i = dwStep; i < VOLUME_MAX; i += dwStep)
61      {
62          SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETTIC, 0, (LPARAM)i);
63          SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETTIC, 0, (LPARAM)i);
64      }
65  
66      /* Hide the other controls */
67      for (i = IDC_ADV_OTHER_CONTROLS; i<= IDC_ADV_OTHER_CHECK2; i++)
68          ShowWindow(GetDlgItem(hwndDlg, i), SW_HIDE);
69  
70      if (SndMixerQueryControls(pData->Context->Mixer, &ControlCount, pData->Context->Line, &Control))
71      {
72          for (Index = 0; Index < ControlCount; Index++)
73          {
74              if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_BASS)
75              {
76                  /* Bass control */
77  
78                  if (SndMixerGetVolumeControlDetails(pData->Context->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&UnsignedDetails) != -1)
79                  {
80                      for (i = IDC_ADV_BASS_LOW; i<= IDC_ADV_BASS_SLIDER; i++)
81                          EnableWindow(GetDlgItem(hwndDlg, i), TRUE);
82  
83                      dwStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
84                      dwPosition = (UnsignedDetails.dwValue - Control[Index].Bounds.dwMinimum) / dwStep;
85                      SendDlgItemMessageW(hwndDlg, IDC_ADV_BASS_SLIDER, TBM_SETPOS, (WPARAM)TRUE, dwPosition);
86  
87                      pData->bEnabled[0] = TRUE;
88                      pData->dwControlId[0] = Control[Index].dwControlID;
89                      pData->dwMaximum[0] = Control[Index].Bounds.dwMaximum;
90                      pData->dwMinimum[0] = Control[Index].Bounds.dwMinimum;
91                  }
92              }
93              else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_TREBLE)
94              {
95                  /* Treble control */
96  
97                  if (SndMixerGetVolumeControlDetails(pData->Context->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&UnsignedDetails) != -1)
98                  {
99                      for (i = IDC_ADV_TREBLE_LOW; i<= IDC_ADV_TREBLE_SLIDER; i++)
100                          EnableWindow(GetDlgItem(hwndDlg, i), TRUE);
101  
102                      dwStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
103                      dwPosition = (UnsignedDetails.dwValue - Control[Index].Bounds.dwMinimum) / dwStep;
104                      SendDlgItemMessageW(hwndDlg, IDC_ADV_TREBLE_SLIDER, TBM_SETPOS, (WPARAM)TRUE, dwPosition);
105  
106                      pData->bEnabled[1] = TRUE;
107                      pData->dwControlId[1] = Control[Index].dwControlID;
108                      pData->dwMaximum[1] = Control[Index].Bounds.dwMaximum;
109                      pData->dwMinimum[1] = Control[Index].Bounds.dwMinimum;
110                  }
111              }
112              else if (((Control[Index].dwControlType & (MIXERCONTROL_CT_CLASS_MASK | MIXERCONTROL_CT_SUBCLASS_MASK | MIXERCONTROL_CT_UNITS_MASK)) == MIXERCONTROL_CONTROLTYPE_BOOLEAN) &&
113                       (Control[Index].dwControlType != MIXERCONTROL_CONTROLTYPE_MUTE))
114              {
115                  /* All boolean controls but the Mute control (Maximum of 2) */
116  
117                  if (dwOtherControls < 2)
118                  {
119                      if (SndMixerGetVolumeControlDetails(pData->Context->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&BooleanDetails) != -1)
120                      {
121                          LoadStringW(hAppInstance, IDS_OTHER_CONTROLS1 + dwOtherControls, szRawBuffer, ARRAYSIZE(szRawBuffer));
122                          StringCchPrintfW(szCookedBuffer, ARRAYSIZE(szCookedBuffer), szRawBuffer, Control[Index].szName);
123                          SetWindowTextW(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CHECK1 + dwOtherControls), szCookedBuffer);
124  
125                          ShowWindow(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CHECK1 + dwOtherControls), SW_SHOWNORMAL);
126  
127                          SendDlgItemMessageW(hwndDlg, IDC_ADV_OTHER_CHECK1 + dwOtherControls, BM_SETCHECK, (WPARAM)BooleanDetails.fValue, 0);
128  
129                          pData->bEnabled[dwOtherControls + 2] = TRUE;
130                          pData->dwControlId[dwOtherControls + 2] = Control[Index].dwControlID;
131  
132                          dwOtherControls++;
133                      }
134                  }
135              }
136          }
137  
138          /* Free controls */
139          HeapFree(GetProcessHeap(), 0, Control);
140      }
141  
142      if (dwOtherControls != 0)
143      {
144          /* Show the 'Other controls' groupbox and text */
145          ShowWindow(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CONTROLS), SW_SHOWNORMAL);
146          ShowWindow(GetDlgItem(hwndDlg, IDC_ADV_OTHER_TEXT), SW_SHOWNORMAL);
147  
148          /* Resize the dialog */
149          GetWindowRect(hwndDlg, &rect);
150  
151          dy = MulDiv((dwOtherControls == 1) ? 73 : (73 + 15), pData->Context->MixerWindow->baseUnit.cy, 8);
152          rect.bottom += dy;
153  
154          SetWindowPos(hwndDlg, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
155  
156          /* Move the 'Close' button down */
157          GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rect);
158          MapWindowPoints(HWND_DESKTOP, hwndDlg, (LPPOINT)&rect, 2);
159  
160          rect.top += dy;
161          rect.bottom += dy;
162  
163          SetWindowPos(GetDlgItem(hwndDlg, IDOK), HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOSIZE | SWP_NOZORDER);
164  
165          if (dwOtherControls == 2)
166          {
167              /* Resize the 'Other Controls' groupbox */
168              GetWindowRect(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CONTROLS), &rect);
169              MapWindowPoints(HWND_DESKTOP, hwndDlg, (LPPOINT)&rect, 2);
170  
171              dy = MulDiv(15, pData->Context->MixerWindow->baseUnit.cy, 8);
172              rect.bottom += dy;
173  
174              SetWindowPos(GetDlgItem(hwndDlg, IDC_ADV_OTHER_CONTROLS), HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
175          }
176      }
177  }
178  
179  
180  static
181  VOID
182  OnHScroll(
183      HWND hwndDlg,
184      PADVANCED_DATA pData,
185      DWORD dwCtrlID)
186  {
187      MIXERCONTROLDETAILS_UNSIGNED Details;
188      DWORD dwControlID = 0, dwStep, dwPosition;
189      DWORD dwMaximum, dwMinimum;
190  
191      if (dwCtrlID != IDC_ADV_BASS_SLIDER &&
192          dwCtrlID != IDC_ADV_TREBLE_SLIDER)
193          return;
194  
195      if (dwCtrlID == IDC_ADV_BASS_SLIDER)
196      {
197          if (pData->bEnabled[0] == FALSE)
198              return;
199  
200          dwControlID = pData->dwControlId[0];
201          dwMaximum = pData->dwMaximum[0];
202          dwMinimum = pData->dwMinimum[0];
203      }
204      else if (dwCtrlID == IDC_ADV_TREBLE_SLIDER)
205      {
206          if (pData->bEnabled[1] == FALSE)
207              return;
208  
209          dwControlID = pData->dwControlId[1];
210          dwMaximum = pData->dwMaximum[1];
211          dwMinimum = pData->dwMinimum[1];
212      }
213  
214      dwPosition = (DWORD)SendDlgItemMessage(hwndDlg, dwCtrlID, TBM_GETPOS, 0, 0);
215      dwStep = (dwMaximum - dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
216  
217      Details.dwValue = (dwPosition * dwStep) + dwMinimum;
218  
219      SndMixerSetVolumeControlDetails(pData->Context->Mixer, dwControlID, 1, sizeof(MIXERCONTROLDETAILS_UNSIGNED), &Details);
220  }
221  
222  
223  INT_PTR
224  CALLBACK
225  AdvancedDlgProc(
226      HWND hwndDlg,
227      UINT uMsg,
228      WPARAM wParam,
229      LPARAM lParam)
230  {
231      PADVANCED_DATA pData;
232  
233      pData = (PADVANCED_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
234  
235      switch (uMsg)
236      {
237          case WM_INITDIALOG:
238              pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ADVANCED_DATA));
239              if (pData != NULL)
240              {
241                  SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
242                  pData->Context = (PADVANCED_CONTEXT)((LONG_PTR)lParam);
243                  OnInitDialog(hwndDlg, pData);
244              }
245              return TRUE;
246  
247          case WM_COMMAND:
248              switch (LOWORD(wParam))
249              {
250                  case IDOK:
251                      EndDialog(hwndDlg, IDOK);
252                      break;
253              }
254              break;
255  
256          case WM_HSCROLL:
257              if (pData != NULL)
258              {
259                   if (LOWORD(wParam) == TB_THUMBTRACK)
260                      OnHScroll(hwndDlg, pData, GetDlgCtrlID((HWND)lParam));
261              }
262              break;
263  
264          case WM_CLOSE:
265              EndDialog(hwndDlg, IDCANCEL);
266              break;
267  
268          case WM_DESTROY:
269              if (pData != NULL)
270              {
271                  HeapFree(GetProcessHeap(), 0, pData);
272                  SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)NULL);
273              }
274              break;
275      }
276  
277      return FALSE;
278  }
279  
280  /* EOF */
281