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
12 ConvertRect(LPRECT lpRect
, UINT xBaseUnit
, UINT yBaseUnit
)
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);
23 IN LPCWSTR ResourceName
,
24 OUT LPDWORD ResourceLength
)
31 hSrc
= FindResourceW(hModule
, ResourceName
, (LPCWSTR
)RT_DIALOG
);
35 /* failed to find resource */
39 /* now load the resource */
40 hRes
= LoadResource(hAppInstance
, hSrc
);
43 /* failed to load resource */
47 /* now lock the resource */
48 Result
= LockResource(hRes
);
52 /* failed to lock resource */
58 /* store output length */
59 *ResourceLength
= SizeofResource(hAppInstance
, hSrc
);
70 IN LPRECT DialogOffset
,
71 IN PDLGITEMTEMPLATE DialogItem
,
72 IN DWORD DialogIdMultiplier
,
80 LPWSTR ClassName
, WindowName
= NULL
;
85 /* initialize client rectangle */
86 rect
.left
= DialogItem
->x
;
87 rect
.top
= DialogItem
->y
;
88 rect
.right
= DialogItem
->x
+ DialogItem
->cx
;
89 rect
.bottom
= DialogItem
->y
+ DialogItem
->cy
;
91 /* Convert Dialog units to pixes */
92 ConvertRect(&rect
, xBaseUnit
, yBaseUnit
);
94 rect
.left
+= DialogOffset
->left
;
95 rect
.right
+= DialogOffset
->left
;
96 rect
.top
+= DialogOffset
->top
;
97 rect
.bottom
+= DialogOffset
->top
;
99 /* move offset after dialog item */
100 Offset
= (LPWORD
)(DialogItem
+ 1);
102 if (*Offset
== 0xFFFF)
104 /* class is encoded as type */
107 /* get control type */
111 ClassName
= L
"button";
112 WindowName
= (LPWSTR
)(Offset
+ 1);
115 ClassName
= L
"static";
116 WindowName
= (LPWSTR
)(Offset
+ 1);
126 /* class name is encoded as string */
127 ClassName
= (LPWSTR
)Offset
;
129 /* move offset to the end of class string */
130 Offset
+= wcslen(ClassName
);
132 /* get window name */
133 WindowName
= (LPWSTR
)(Offset
+ 1);
136 /* move offset past class type/string */
139 if (DialogItem
->id
== MAXWORD
)
141 /* id is not important */
142 wID
= DialogItem
->id
;
147 wID
= DialogItem
->id
* (DialogIdMultiplier
+ 1);
151 /* now create the window */
152 hwnd
= CreateWindowExW(DialogItem
->dwExtendedStyle
,
158 rect
.right
- rect
.left
,
159 rect
.bottom
- rect
.top
,
171 /* check if this the track bar */
172 if (!wcsicmp(ClassName
, L
"msctls_trackbar32"))
174 if (DialogItem
->style
& TBS_VERT
)
176 /* Vertical trackbar: Volume */
179 SendMessage(hwnd
, TBM_SETRANGE
, (WPARAM
)TRUE
, (LPARAM
)MAKELONG(VOLUME_MIN
, VOLUME_MAX
));
181 /* set up page size */
182 SendMessage(hwnd
, TBM_SETPAGESIZE
, 0, (LPARAM
)VOLUME_PAGE_SIZE
);
185 SendMessage(hwnd
, TBM_SETPOS
, (WPARAM
)TRUE
, (LPARAM
)0);
187 /* Calculate and set ticks */
188 nSteps
= (VOLUME_MAX
/ (VOLUME_TICKS
+ 1));
189 if (VOLUME_MAX
% (VOLUME_TICKS
+ 1) != 0)
191 for (i
= nSteps
; i
< VOLUME_MAX
; i
+= nSteps
)
192 SendMessage(hwnd
, TBM_SETTIC
, 0, (LPARAM
)i
);
196 /* Horizontal trackbar: Balance */
199 SendMessage(hwnd
, TBM_SETRANGE
, (WPARAM
)TRUE
, (LPARAM
)MAKELONG(0, BALANCE_STEPS
));
201 /* set up page size */
202 SendMessage(hwnd
, TBM_SETPAGESIZE
, 0, (LPARAM
)BALANCE_PAGE_SIZE
);
205 SendMessage(hwnd
, TBM_SETPOS
, (WPARAM
)TRUE
, (LPARAM
)BALANCE_STEPS
/ 2);
207 /* Calculate and set ticks */
208 nSteps
= (BALANCE_STEPS
/ (BALANCE_TICKS
+ 1));
209 if (BALANCE_STEPS
% (BALANCE_TICKS
+ 1) != 0)
211 for (i
= nSteps
; i
< BALANCE_STEPS
; i
+= nSteps
)
212 SendMessage(hwnd
, TBM_SETTIC
, 0, (LPARAM
)i
);
215 else if (!wcsicmp(ClassName
, L
"static"))
218 SendMessageW(hwnd
, WM_SETFONT
, (WPARAM
)hFont
, TRUE
);
220 else if (!wcsicmp(ClassName
, L
"button"))
222 if (DialogItem
->style
& BS_AUTOCHECKBOX
)
224 if (MixerId
== PLAY_MIXER
)
226 /* Disable checkboxes by default, if we are in play mode */
227 EnableWindow(hwnd
, FALSE
);
232 SendMessageW(hwnd
, WM_SETFONT
, (WPARAM
)hFont
, TRUE
);
235 //ShowWindow(hwnd, SW_SHOWNORMAL);
237 if (WindowName
!= NULL
)
239 /* move offset past window name */
240 Offset
+= wcslen(WindowName
) + 1;
243 /* check if there is additional data */
246 /* no additional data */
251 /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
252 /* skip past additional data */
256 /* make sure next template is word-aligned */
257 Offset
= (LPWORD
)(((ULONG_PTR
)Offset
+ 3) & ~3);
265 IN PMIXER_WINDOW MixerWindow
,
268 PDLGITEMTEMPLATE DialogItem
,
269 DWORD DialogIdMultiplier
,
279 if (MixerWindow
->Window
)
280 MixerWindow
->Window
= (HWND
*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MixerWindow
->Window
, (MixerWindow
->WindowCount
+ ItemCount
) * sizeof(HWND
));
282 MixerWindow
->Window
= (HWND
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ItemCount
* sizeof(HWND
));
283 if (!MixerWindow
->Window
)
289 /* enumerate now all controls */
290 for (Index
= 0; Index
< ItemCount
; Index
++)
293 Offset
= AddDialogControl(MixerWindow
->hWnd
,
294 &MixerWindow
->Window
[MixerWindow
->WindowCount
],
301 MixerWindow
->MixerId
);
306 /* move dialog item to new offset */
307 DialogItem
=(PDLGITEMTEMPLATE
)Offset
;
309 /* increment window count */
310 MixerWindow
->WindowCount
++;
317 IN PMIXER_WINDOW MixerWindow
,
318 IN LPCWSTR DialogResId
,
321 LPDLGTEMPLATE DlgTemplate
;
322 PDLGITEMTEMPLATE DlgItem
;
330 DWORD units
= GetDialogBaseUnits();
331 UINT xBaseUnit
= LOWORD(units
);
332 UINT yBaseUnit
= HIWORD(units
);
334 /* first load the dialog resource */
335 DlgTemplate
= (LPDLGTEMPLATE
)LoadDialogResource(hModule
, DialogResId
, NULL
);
338 /* failed to load resource */
342 /* Now walk past the dialog header */
343 Offset
= (LPWORD
)(DlgTemplate
+ 1);
345 /* FIXME: support menu */
346 assert(*Offset
== 0);
349 /* FIXME: support classes */
350 assert(*Offset
== 0);
353 /* FIXME: support titles */
354 assert(*Offset
== 0);
361 /* calculate font length */
362 Length
= wcslen((LPWSTR
)Offset
) + 1;
363 assert(Length
< (sizeof(FontName
) / sizeof(WCHAR
)));
366 wcscpy(FontName
, (LPWSTR
)Offset
);
368 if (DlgTemplate
->style
& DS_SETFONT
)
374 if (!MixerWindow
->hFont
)
376 int pixels
= MulDiv(FontSize
, GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
377 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
);
380 if (MixerWindow
->hFont
)
385 hOldFont
= SelectObject(hDC
, MixerWindow
->hFont
);
386 charSize
.cx
= GdiGetCharDimensions(hDC
, NULL
, &charSize
.cy
);
389 xBaseUnit
= charSize
.cx
;
390 yBaseUnit
= charSize
.cy
;
392 SelectObject(hDC
, hOldFont
);
396 // assert(MixerWindow->hFont);
398 /* move offset after font name */
401 /* offset is now at first dialog item control */
402 DlgItem
= (PDLGITEMTEMPLATE
)Offset
;
405 dialogRect
.right
= DlgTemplate
->cx
;
407 dialogRect
.bottom
= DlgTemplate
->cy
;
409 ConvertRect(&dialogRect
, xBaseUnit
, yBaseUnit
);
411 width
= dialogRect
.right
- dialogRect
.left
;
413 dialogRect
.left
+= MixerWindow
->rect
.right
;
414 dialogRect
.right
+= MixerWindow
->rect
.right
;
415 dialogRect
.top
+= MixerWindow
->rect
.top
;
416 dialogRect
.bottom
+= MixerWindow
->rect
.top
;
418 MixerWindow
->rect
.right
+= width
;
419 if ((dialogRect
.bottom
- dialogRect
.top
) > (MixerWindow
->rect
.bottom
- MixerWindow
->rect
.top
))
420 MixerWindow
->rect
.bottom
= MixerWindow
->rect
.top
+ dialogRect
.bottom
- dialogRect
.top
;
422 /* now add the controls */
423 LoadDialogControls(MixerWindow
, &dialogRect
, DlgTemplate
->cdit
, DlgItem
, Index
, xBaseUnit
, yBaseUnit
);
428 EnumConnectionsCallback(
434 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
437 UINT ControlCount
= 0, Index
;
438 LPMIXERCONTROL Control
= NULL
;
440 PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails
= NULL
;
441 PPREFERENCES_CONTEXT PrefContext
= (PPREFERENCES_CONTEXT
)Context
;
443 if (Line
->cControls
== 0)
447 if (SndMixerGetLineName(PrefContext
->MixerWindow
->Mixer
, PrefContext
->SelectedLine
, LineName
, MIXER_LONG_NAME_CHARS
, TRUE
) == -1)
449 /* failed to get line name */
453 pVolumeDetails
= HeapAlloc(GetProcessHeap(),
455 Line
->cChannels
* sizeof(MIXERCONTROLDETAILS_UNSIGNED
));
456 if (pVolumeDetails
== NULL
)
459 /* check if line is found in registry settings */
460 if (ReadLineConfig(PrefContext
->DeviceName
,
470 if ((Line
->dwComponentType
== MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
) ||
471 (Line
->dwComponentType
== MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
))
472 dlgId
= (PrefContext
->MixerWindow
->Mode
== SMALL_MODE
) ? IDD_SMALL_MASTER
: IDD_NORMAL_MASTER
;
474 dlgId
= (PrefContext
->MixerWindow
->Mode
== SMALL_MODE
) ? IDD_SMALL_LINE
: IDD_NORMAL_LINE
;
476 /* load dialog resource */
477 LoadDialog(hAppInstance
, PrefContext
->MixerWindow
, MAKEINTRESOURCE(dlgId
), PrefContext
->Count
);
480 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_NAME
;
483 SetDlgItemTextW(PrefContext
->MixerWindow
->hWnd
, wID
, Line
->szName
);
486 if (SndMixerQueryControls(Mixer
, &ControlCount
, Line
, &Control
) != FALSE
)
488 /* now go through all controls and update their states */
489 for (Index
= 0; Index
< Line
->cControls
; Index
++)
491 if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_SWITCH
)
493 MIXERCONTROLDETAILS_BOOLEAN Details
;
495 /* get volume control details */
496 if (SndMixerGetVolumeControlDetails(Mixer
, Control
[Index
].dwControlID
, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN
), (LPVOID
)&Details
) != -1)
498 /* update dialog control */
499 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SWITCH
;
501 /* get dialog control */
502 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
504 if (hDlgCtrl
!= NULL
)
506 /* Enable the 'Mute' checkbox, if we are in play mode */
507 if (Mixer
->MixerId
== PLAY_MIXER
)
508 EnableWindow(hDlgCtrl
, TRUE
);
511 if (SendMessageW(hDlgCtrl
, BM_GETCHECK
, 0, 0) != Details
.fValue
)
513 /* update control state */
514 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)Details
.fValue
, 0);
519 else if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_FADER
)
521 /* get volume control details */
522 if (SndMixerGetVolumeControlDetails(Mixer
, Control
[Index
].dwControlID
, Line
->cChannels
, sizeof(MIXERCONTROLDETAILS_UNSIGNED
), (LPVOID
)pVolumeDetails
) != -1)
524 /* update dialog control */
525 DWORD volumePosition
, volumeStep
, maxVolume
, i
;
526 DWORD balancePosition
, balanceStep
;
528 volumeStep
= (Control
[Index
].Bounds
.dwMaximum
- Control
[Index
].Bounds
.dwMinimum
) / (VOLUME_MAX
- VOLUME_MIN
);
531 for (i
= 0; i
< Line
->cChannels
; i
++)
533 if (pVolumeDetails
[i
].dwValue
> maxVolume
)
534 maxVolume
= pVolumeDetails
[i
].dwValue
;
537 volumePosition
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / volumeStep
;
539 if (Line
->cChannels
== 1)
541 balancePosition
= BALANCE_CENTER
;
543 else if (Line
->cChannels
== 2)
545 if (pVolumeDetails
[0].dwValue
== pVolumeDetails
[1].dwValue
)
547 balancePosition
= BALANCE_CENTER
;
549 else if (pVolumeDetails
[0].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
551 balancePosition
= BALANCE_RIGHT
;
553 else if (pVolumeDetails
[1].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
555 balancePosition
= BALANCE_LEFT
;
559 balanceStep
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / (BALANCE_STEPS
/ 2);
561 if (pVolumeDetails
[0].dwValue
< pVolumeDetails
[1].dwValue
)
563 balancePosition
= (pVolumeDetails
[0].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
564 balancePosition
= BALANCE_RIGHT
- balancePosition
;
566 else if (pVolumeDetails
[1].dwValue
< pVolumeDetails
[0].dwValue
)
568 balancePosition
= (pVolumeDetails
[1].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
569 balancePosition
= BALANCE_LEFT
+ balancePosition
;
574 /* Set the volume trackbar */
575 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SLIDER_VERT
;
577 /* get dialog control */
578 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
580 if (hDlgCtrl
!= NULL
)
583 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
585 if (OldPosition
!= (VOLUME_MAX
- volumePosition
))
587 /* update control state */
588 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, VOLUME_MAX
- volumePosition
);
592 if (Line
->cChannels
== 1)
594 /* Disable the balance trackbar for mono channels */
595 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SLIDER_HORZ
;
597 /* get dialog control */
598 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
599 if (hDlgCtrl
!= NULL
)
601 EnableWindow(hDlgCtrl
, FALSE
);
604 else if (Line
->cChannels
== 2)
606 /* Set the balance trackbar */
607 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SLIDER_HORZ
;
609 /* get dialog control */
610 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
612 if (hDlgCtrl
!= NULL
)
615 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
617 if (OldPosition
!= balancePosition
)
619 /* update control state */
620 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, balancePosition
);
629 HeapFree(GetProcessHeap(), 0, Control
);
632 /* increment dialog count */
633 PrefContext
->Count
++;
638 /* Free the volume details */
640 HeapFree(GetProcessHeap(), 0, pVolumeDetails
);
647 PPREFERENCES_CONTEXT PrefContext
)
652 /* set dialog count to zero */
653 PrefContext
->Count
= 0;
655 SetRectEmpty(&PrefContext
->MixerWindow
->rect
);
657 /* enumerate controls */
658 SndMixerEnumConnections(PrefContext
->MixerWindow
->Mixer
, PrefContext
->SelectedLine
, EnumConnectionsCallback
, (PVOID
)PrefContext
);
660 if (PrefContext
->MixerWindow
->hStatusBar
)
662 GetWindowRect(PrefContext
->MixerWindow
->hStatusBar
, &statusRect
);
663 PrefContext
->MixerWindow
->rect
.bottom
+= (statusRect
.bottom
- statusRect
.top
);
666 /* now move the window */
667 AdjustWindowRect(&PrefContext
->MixerWindow
->rect
, WS_DLGFRAME
| WS_CAPTION
| WS_MINIMIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_VISIBLE
, TRUE
);
668 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
);
670 /* get last line separator */
671 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, IDC_LINE_SEP
* PrefContext
->Count
);
673 if (hDlgCtrl
!= NULL
)
675 /* hide last separator */
676 ShowWindow(hDlgCtrl
, SW_HIDE
);
681 UpdateDialogLineSwitchControl(
682 PPREFERENCES_CONTEXT PrefContext
,
689 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
691 /* find the index of this line */
692 for (Index
= 0; Index
< PrefContext
->Count
; Index
++)
695 wID
= (Index
+ 1) * IDC_LINE_NAME
;
697 if (GetDlgItemText(PrefContext
->MixerWindow
->hWnd
, wID
, LineName
, MIXER_LONG_NAME_CHARS
) == 0)
699 /* failed to retrieve id */
703 /* check if the line name matches */
704 if (!wcsicmp(LineName
, Line
->szName
))
706 /* found matching line name */
707 wID
= (Index
+ 1) * IDC_LINE_SWITCH
;
709 /* get dialog control */
710 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
712 if (hDlgCtrl
!= NULL
)
715 if (SendMessageW(hDlgCtrl
, BM_GETCHECK
, 0, 0) != fValue
)
717 /* update control state */
718 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)fValue
, 0);
727 UpdateDialogLineSliderControl(
728 PPREFERENCES_CONTEXT PrefContext
,
736 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
738 /* find the index of this line */
739 for (Index
= 0; Index
< PrefContext
->Count
; Index
++)
742 wID
= (Index
+ 1) * IDC_LINE_NAME
;
744 if (GetDlgItemText(PrefContext
->MixerWindow
->hWnd
, wID
, LineName
, MIXER_LONG_NAME_CHARS
) == 0)
746 /* failed to retrieve id */
750 /* check if the line name matches */
751 if (!wcsicmp(LineName
, Line
->szName
))
753 /* found matching line name */
754 wID
= (Index
+ 1) * dwDialogID
;
756 /* get dialog control */
757 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
759 if (hDlgCtrl
!= NULL
)
762 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
763 if (OldPosition
!= Position
)
765 /* update control state */
766 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, Position
);