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