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
,
79 LPWSTR ClassName
, WindowName
= NULL
;
84 /* initialize client rectangle */
85 rect
.left
= DialogItem
->x
;
86 rect
.top
= DialogItem
->y
;
87 rect
.right
= DialogItem
->x
+ DialogItem
->cx
;
88 rect
.bottom
= DialogItem
->y
+ DialogItem
->cy
;
90 /* Convert Dialog units to pixes */
91 ConvertRect(&rect
, xBaseUnit
, yBaseUnit
);
93 rect
.left
+= DialogOffset
->left
;
94 rect
.right
+= DialogOffset
->left
;
95 rect
.top
+= DialogOffset
->top
;
96 rect
.bottom
+= DialogOffset
->top
;
98 /* move offset after dialog item */
99 Offset
= (LPWORD
)(DialogItem
+ 1);
101 if (*Offset
== 0xFFFF)
103 /* class is encoded as type */
106 /* get control type */
110 ClassName
= L
"button";
111 WindowName
= (LPWSTR
)(Offset
+ 1);
114 ClassName
= L
"static";
115 WindowName
= (LPWSTR
)(Offset
+ 1);
125 /* class name is encoded as string */
126 ClassName
= (LPWSTR
)Offset
;
128 /* move offset to the end of class string */
129 Offset
+= wcslen(ClassName
);
131 /* get window name */
132 WindowName
= (LPWSTR
)(Offset
+ 1);
135 /* move offset past class type/string */
138 if (DialogItem
->id
== MAXWORD
)
140 /* id is not important */
141 wID
= DialogItem
->id
;
146 wID
= DialogItem
->id
* (DialogIdMultiplier
+ 1);
150 /* now create the window */
151 hwnd
= CreateWindowExW(DialogItem
->dwExtendedStyle
,
157 rect
.right
- rect
.left
,
158 rect
.bottom
- rect
.top
,
170 /* check if this the track bar */
171 if (!wcsicmp(ClassName
, L
"msctls_trackbar32"))
173 if (DialogItem
->style
& TBS_VERT
)
175 /* Vertical trackbar: Volume */
178 SendMessage(hwnd
, TBM_SETRANGE
, (WPARAM
)TRUE
, (LPARAM
)MAKELONG(VOLUME_MIN
, VOLUME_MAX
));
180 /* set up page size */
181 SendMessage(hwnd
, TBM_SETPAGESIZE
, 0, (LPARAM
)VOLUME_PAGE_SIZE
);
184 SendMessage(hwnd
, TBM_SETPOS
, (WPARAM
)TRUE
, (LPARAM
)0);
186 /* Calculate and set ticks */
187 nSteps
= (VOLUME_MAX
/ (VOLUME_TICKS
+ 1));
188 if (VOLUME_MAX
% (VOLUME_TICKS
+ 1) != 0)
190 for (i
= nSteps
; i
< VOLUME_MAX
; i
+= nSteps
)
191 SendMessage(hwnd
, TBM_SETTIC
, 0, (LPARAM
)i
);
195 /* Horizontal trackbar: Balance */
198 SendMessage(hwnd
, TBM_SETRANGE
, (WPARAM
)TRUE
, (LPARAM
)MAKELONG(0, BALANCE_STEPS
));
200 /* set up page size */
201 SendMessage(hwnd
, TBM_SETPAGESIZE
, 0, (LPARAM
)BALANCE_PAGE_SIZE
);
204 SendMessage(hwnd
, TBM_SETPOS
, (WPARAM
)TRUE
, (LPARAM
)BALANCE_STEPS
/ 2);
206 /* Calculate and set ticks */
207 nSteps
= (BALANCE_STEPS
/ (BALANCE_TICKS
+ 1));
208 if (BALANCE_STEPS
% (BALANCE_TICKS
+ 1) != 0)
210 for (i
= nSteps
; i
< BALANCE_STEPS
; i
+= nSteps
)
211 SendMessage(hwnd
, TBM_SETTIC
, 0, (LPARAM
)i
);
214 else if (!wcsicmp(ClassName
, L
"static") || !wcsicmp(ClassName
, L
"button"))
217 SendMessageW(hwnd
, WM_SETFONT
, (WPARAM
)hFont
, TRUE
);
220 //ShowWindow(hwnd, SW_SHOWNORMAL);
222 if (WindowName
!= NULL
)
224 /* move offset past window name */
225 Offset
+= wcslen(WindowName
) + 1;
228 /* check if there is additional data */
231 /* no additional data */
236 /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
237 /* skip past additional data */
241 /* make sure next template is word-aligned */
242 Offset
= (LPWORD
)(((ULONG_PTR
)Offset
+ 3) & ~3);
250 IN PMIXER_WINDOW MixerWindow
,
253 PDLGITEMTEMPLATE DialogItem
,
254 DWORD DialogIdMultiplier
,
264 if (MixerWindow
->Window
)
265 MixerWindow
->Window
= (HWND
*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MixerWindow
->Window
, (MixerWindow
->WindowCount
+ ItemCount
) * sizeof(HWND
));
267 MixerWindow
->Window
= (HWND
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ItemCount
* sizeof(HWND
));
268 if (!MixerWindow
->Window
)
274 /* enumerate now all controls */
275 for (Index
= 0; Index
< ItemCount
; Index
++)
278 Offset
= AddDialogControl(MixerWindow
->hWnd
, &MixerWindow
->Window
[MixerWindow
->WindowCount
], DialogOffset
, DialogItem
, DialogIdMultiplier
, MixerWindow
->hFont
, xBaseUnit
, yBaseUnit
);
283 /* move dialog item to new offset */
284 DialogItem
=(PDLGITEMTEMPLATE
)Offset
;
286 /* increment window count */
287 MixerWindow
->WindowCount
++;
294 IN PMIXER_WINDOW MixerWindow
,
295 IN LPCWSTR DialogResId
,
298 LPDLGTEMPLATE DlgTemplate
;
299 PDLGITEMTEMPLATE DlgItem
;
307 DWORD units
= GetDialogBaseUnits();
308 UINT xBaseUnit
= LOWORD(units
);
309 UINT yBaseUnit
= HIWORD(units
);
311 /* first load the dialog resource */
312 DlgTemplate
= (LPDLGTEMPLATE
)LoadDialogResource(hModule
, DialogResId
, NULL
);
315 /* failed to load resource */
319 /* Now walk past the dialog header */
320 Offset
= (LPWORD
)(DlgTemplate
+ 1);
322 /* FIXME: support menu */
323 assert(*Offset
== 0);
326 /* FIXME: support classes */
327 assert(*Offset
== 0);
330 /* FIXME: support titles */
331 assert(*Offset
== 0);
338 /* calculate font length */
339 Length
= wcslen((LPWSTR
)Offset
) + 1;
340 assert(Length
< (sizeof(FontName
) / sizeof(WCHAR
)));
343 wcscpy(FontName
, (LPWSTR
)Offset
);
345 if (DlgTemplate
->style
& DS_SETFONT
)
351 if (!MixerWindow
->hFont
)
353 int pixels
= MulDiv(FontSize
, GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
354 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
);
357 if (MixerWindow
->hFont
)
362 hOldFont
= SelectObject(hDC
, MixerWindow
->hFont
);
363 charSize
.cx
= GdiGetCharDimensions(hDC
, NULL
, &charSize
.cy
);
366 xBaseUnit
= charSize
.cx
;
367 yBaseUnit
= charSize
.cy
;
369 SelectObject(hDC
, hOldFont
);
373 // assert(MixerWindow->hFont);
375 /* move offset after font name */
378 /* offset is now at first dialog item control */
379 DlgItem
= (PDLGITEMTEMPLATE
)Offset
;
382 dialogRect
.right
= DlgTemplate
->cx
;
384 dialogRect
.bottom
= DlgTemplate
->cy
;
386 ConvertRect(&dialogRect
, xBaseUnit
, yBaseUnit
);
388 width
= dialogRect
.right
- dialogRect
.left
;
390 dialogRect
.left
+= MixerWindow
->rect
.right
;
391 dialogRect
.right
+= MixerWindow
->rect
.right
;
392 dialogRect
.top
+= MixerWindow
->rect
.top
;
393 dialogRect
.bottom
+= MixerWindow
->rect
.top
;
395 MixerWindow
->rect
.right
+= width
;
396 if ((dialogRect
.bottom
- dialogRect
.top
) > (MixerWindow
->rect
.bottom
- MixerWindow
->rect
.top
))
397 MixerWindow
->rect
.bottom
= MixerWindow
->rect
.top
+ dialogRect
.bottom
- dialogRect
.top
;
399 /* now add the controls */
400 LoadDialogControls(MixerWindow
, &dialogRect
, DlgTemplate
->cdit
, DlgItem
, Index
, xBaseUnit
, yBaseUnit
);
405 EnumConnectionsCallback(
411 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
414 UINT ControlCount
= 0, Index
;
415 LPMIXERCONTROL Control
= NULL
;
417 PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails
= NULL
;
418 PPREFERENCES_CONTEXT PrefContext
= (PPREFERENCES_CONTEXT
)Context
;
420 if (Line
->cControls
== 0)
424 if (SndMixerGetLineName(PrefContext
->MixerWindow
->Mixer
, PrefContext
->SelectedLine
, LineName
, MIXER_LONG_NAME_CHARS
, TRUE
) == -1)
426 /* failed to get line name */
430 pVolumeDetails
= HeapAlloc(GetProcessHeap(),
432 Line
->cChannels
* sizeof(MIXERCONTROLDETAILS_UNSIGNED
));
433 if (pVolumeDetails
== NULL
)
436 /* check if line is found in registry settings */
437 if (ReadLineConfig(PrefContext
->DeviceName
,
447 if ((Line
->dwComponentType
== MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
) ||
448 (Line
->dwComponentType
== MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
))
449 dlgId
= (PrefContext
->MixerWindow
->Mode
== SMALL_MODE
) ? IDD_SMALL_MASTER
: IDD_NORMAL_MASTER
;
451 dlgId
= (PrefContext
->MixerWindow
->Mode
== SMALL_MODE
) ? IDD_SMALL_LINE
: IDD_NORMAL_LINE
;
453 /* load dialog resource */
454 LoadDialog(hAppInstance
, PrefContext
->MixerWindow
, MAKEINTRESOURCE(dlgId
), PrefContext
->Count
);
457 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_NAME
;
460 SetDlgItemTextW(PrefContext
->MixerWindow
->hWnd
, wID
, Line
->szName
);
463 if (SndMixerQueryControls(Mixer
, &ControlCount
, Line
, &Control
) != FALSE
)
465 /* now go through all controls and update their states */
466 for (Index
= 0; Index
< Line
->cControls
; Index
++)
468 if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_SWITCH
)
470 MIXERCONTROLDETAILS_BOOLEAN Details
;
472 /* get volume control details */
473 if (SndMixerGetVolumeControlDetails(Mixer
, Control
[Index
].dwControlID
, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN
), (LPVOID
)&Details
) != -1)
475 /* update dialog control */
476 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SWITCH
;
478 /* get dialog control */
479 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
481 if (hDlgCtrl
!= NULL
)
484 if (SendMessageW(hDlgCtrl
, BM_GETCHECK
, 0, 0) != Details
.fValue
)
486 /* update control state */
487 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)Details
.fValue
, 0);
492 else if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_FADER
)
494 /* get volume control details */
495 if (SndMixerGetVolumeControlDetails(Mixer
, Control
[Index
].dwControlID
, Line
->cChannels
, sizeof(MIXERCONTROLDETAILS_UNSIGNED
), (LPVOID
)pVolumeDetails
) != -1)
497 /* update dialog control */
498 DWORD volumePosition
, volumeStep
, maxVolume
, i
;
499 DWORD balancePosition
, balanceStep
;
501 volumeStep
= (Control
[Index
].Bounds
.dwMaximum
- Control
[Index
].Bounds
.dwMinimum
) / (VOLUME_MAX
- VOLUME_MIN
);
504 for (i
= 0; i
< Line
->cChannels
; i
++)
506 if (pVolumeDetails
[i
].dwValue
> maxVolume
)
507 maxVolume
= pVolumeDetails
[i
].dwValue
;
510 volumePosition
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / volumeStep
;
512 if (Line
->cChannels
== 1)
514 balancePosition
= BALANCE_CENTER
;
516 else if (Line
->cChannels
== 2)
518 if (pVolumeDetails
[0].dwValue
== pVolumeDetails
[1].dwValue
)
520 balancePosition
= BALANCE_CENTER
;
522 else if (pVolumeDetails
[0].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
524 balancePosition
= BALANCE_RIGHT
;
526 else if (pVolumeDetails
[1].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
528 balancePosition
= BALANCE_LEFT
;
532 balanceStep
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / (BALANCE_STEPS
/ 2);
534 if (pVolumeDetails
[0].dwValue
< pVolumeDetails
[1].dwValue
)
536 balancePosition
= (pVolumeDetails
[0].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
537 balancePosition
= BALANCE_RIGHT
- balancePosition
;
539 else if (pVolumeDetails
[1].dwValue
< pVolumeDetails
[0].dwValue
)
541 balancePosition
= (pVolumeDetails
[1].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
542 balancePosition
= BALANCE_LEFT
+ balancePosition
;
547 /* Set the volume trackbar */
548 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SLIDER_VERT
;
550 /* get dialog control */
551 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
553 if (hDlgCtrl
!= NULL
)
556 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
558 if (OldPosition
!= (VOLUME_MAX
- volumePosition
))
560 /* update control state */
561 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, VOLUME_MAX
- volumePosition
);
565 if (Line
->cChannels
== 1)
567 /* Disable the balance trackbar for mono channels */
568 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SLIDER_HORZ
;
570 /* get dialog control */
571 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
572 if (hDlgCtrl
!= NULL
)
574 EnableWindow(hDlgCtrl
, FALSE
);
577 else if (Line
->cChannels
== 2)
579 /* Set the balance trackbar */
580 wID
= (PrefContext
->Count
+ 1) * IDC_LINE_SLIDER_HORZ
;
582 /* get dialog control */
583 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
585 if (hDlgCtrl
!= NULL
)
588 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
590 if (OldPosition
!= balancePosition
)
592 /* update control state */
593 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, balancePosition
);
602 HeapFree(GetProcessHeap(), 0, Control
);
605 /* increment dialog count */
606 PrefContext
->Count
++;
611 /* Free the volume details */
613 HeapFree(GetProcessHeap(), 0, pVolumeDetails
);
620 PPREFERENCES_CONTEXT PrefContext
)
625 /* set dialog count to zero */
626 PrefContext
->Count
= 0;
628 SetRectEmpty(&PrefContext
->MixerWindow
->rect
);
630 /* enumerate controls */
631 SndMixerEnumConnections(PrefContext
->MixerWindow
->Mixer
, PrefContext
->SelectedLine
, EnumConnectionsCallback
, (PVOID
)PrefContext
);
633 if (PrefContext
->MixerWindow
->hStatusBar
)
635 GetWindowRect(PrefContext
->MixerWindow
->hStatusBar
, &statusRect
);
636 PrefContext
->MixerWindow
->rect
.bottom
+= (statusRect
.bottom
- statusRect
.top
);
639 /* now move the window */
640 AdjustWindowRect(&PrefContext
->MixerWindow
->rect
, WS_DLGFRAME
| WS_CAPTION
| WS_MINIMIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_VISIBLE
, TRUE
);
641 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
);
643 /* get last line separator */
644 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, IDC_LINE_SEP
* PrefContext
->Count
);
646 if (hDlgCtrl
!= NULL
)
648 /* hide last separator */
649 ShowWindow(hDlgCtrl
, SW_HIDE
);
654 UpdateDialogLineSwitchControl(
655 PPREFERENCES_CONTEXT PrefContext
,
662 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
664 /* find the index of this line */
665 for (Index
= 0; Index
< PrefContext
->Count
; Index
++)
668 wID
= (Index
+ 1) * IDC_LINE_NAME
;
670 if (GetDlgItemText(PrefContext
->MixerWindow
->hWnd
, wID
, LineName
, MIXER_LONG_NAME_CHARS
) == 0)
672 /* failed to retrieve id */
676 /* check if the line name matches */
677 if (!wcsicmp(LineName
, Line
->szName
))
679 /* found matching line name */
680 wID
= (Index
+ 1) * IDC_LINE_SWITCH
;
682 /* get dialog control */
683 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
685 if (hDlgCtrl
!= NULL
)
688 if (SendMessageW(hDlgCtrl
, BM_GETCHECK
, 0, 0) != fValue
)
690 /* update control state */
691 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)fValue
, 0);
700 UpdateDialogLineSliderControl(
701 PPREFERENCES_CONTEXT PrefContext
,
709 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
711 /* find the index of this line */
712 for (Index
= 0; Index
< PrefContext
->Count
; Index
++)
715 wID
= (Index
+ 1) * IDC_LINE_NAME
;
717 if (GetDlgItemText(PrefContext
->MixerWindow
->hWnd
, wID
, LineName
, MIXER_LONG_NAME_CHARS
) == 0)
719 /* failed to retrieve id */
723 /* check if the line name matches */
724 if (!wcsicmp(LineName
, Line
->szName
))
726 /* found matching line name */
727 wID
= (Index
+ 1) * dwDialogID
;
729 /* get dialog control */
730 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
732 if (hDlgCtrl
!= NULL
)
735 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
736 if (OldPosition
!= Position
)
738 /* update control state */
739 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, Position
);