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