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 */
178 /* Disable the volume trackbar by default */
179 EnableWindow(hwnd
, FALSE
);
182 SendMessage(hwnd
, TBM_SETRANGE
, (WPARAM
)TRUE
, (LPARAM
)MAKELONG(VOLUME_MIN
, VOLUME_MAX
));
184 /* set up page size */
185 SendMessage(hwnd
, TBM_SETPAGESIZE
, 0, (LPARAM
)VOLUME_PAGE_SIZE
);
188 SendMessage(hwnd
, TBM_SETPOS
, (WPARAM
)TRUE
, (LPARAM
)0);
190 /* Calculate and set ticks */
191 nSteps
= (VOLUME_MAX
/ (VOLUME_TICKS
+ 1));
192 if (VOLUME_MAX
% (VOLUME_TICKS
+ 1) != 0)
194 for (i
= nSteps
; i
< VOLUME_MAX
; i
+= nSteps
)
195 SendMessage(hwnd
, TBM_SETTIC
, 0, (LPARAM
)i
);
199 /* Horizontal trackbar: Balance */
201 /* Disable the balance trackbar by default */
202 EnableWindow(hwnd
, FALSE
);
205 SendMessage(hwnd
, TBM_SETRANGE
, (WPARAM
)TRUE
, (LPARAM
)MAKELONG(0, BALANCE_STEPS
));
207 /* set up page size */
208 SendMessage(hwnd
, TBM_SETPAGESIZE
, 0, (LPARAM
)BALANCE_PAGE_SIZE
);
211 SendMessage(hwnd
, TBM_SETPOS
, (WPARAM
)TRUE
, (LPARAM
)BALANCE_STEPS
/ 2);
213 /* Calculate and set ticks */
214 nSteps
= (BALANCE_STEPS
/ (BALANCE_TICKS
+ 1));
215 if (BALANCE_STEPS
% (BALANCE_TICKS
+ 1) != 0)
217 for (i
= nSteps
; i
< BALANCE_STEPS
; i
+= nSteps
)
218 SendMessage(hwnd
, TBM_SETTIC
, 0, (LPARAM
)i
);
221 else if (!wcsicmp(ClassName
, L
"static"))
224 SendMessageW(hwnd
, WM_SETFONT
, (WPARAM
)hFont
, TRUE
);
226 else if (!wcsicmp(ClassName
, L
"button"))
228 if (DialogItem
->id
== IDC_LINE_SWITCH
)
230 if (MixerId
== PLAY_MIXER
)
232 /* Disable checkboxes by default, if we are in play mode */
233 EnableWindow(hwnd
, FALSE
);
236 else if (DialogItem
->id
== IDC_LINE_ADVANCED
)
238 ShowWindow(hwnd
, SW_HIDE
);
242 SendMessageW(hwnd
, WM_SETFONT
, (WPARAM
)hFont
, TRUE
);
245 if (WindowName
!= NULL
)
247 /* move offset past window name */
248 Offset
+= wcslen(WindowName
) + 1;
251 /* check if there is additional data */
254 /* no additional data */
259 /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
260 /* skip past additional data */
264 /* make sure next template is word-aligned */
265 Offset
= (LPWORD
)(((ULONG_PTR
)Offset
+ 3) & ~3);
273 IN PMIXER_WINDOW MixerWindow
,
276 PDLGITEMTEMPLATE DialogItem
,
277 DWORD DialogIdMultiplier
,
287 if (MixerWindow
->Window
)
288 MixerWindow
->Window
= (HWND
*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MixerWindow
->Window
, (MixerWindow
->WindowCount
+ ItemCount
) * sizeof(HWND
));
290 MixerWindow
->Window
= (HWND
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ItemCount
* sizeof(HWND
));
291 if (!MixerWindow
->Window
)
297 /* enumerate now all controls */
298 for (Index
= 0; Index
< ItemCount
; Index
++)
301 Offset
= AddDialogControl(MixerWindow
->hWnd
,
302 &MixerWindow
->Window
[MixerWindow
->WindowCount
],
309 MixerWindow
->MixerId
);
314 /* move dialog item to new offset */
315 DialogItem
=(PDLGITEMTEMPLATE
)Offset
;
317 /* increment window count */
318 MixerWindow
->WindowCount
++;
325 IN PMIXER_WINDOW MixerWindow
,
326 IN LPCWSTR DialogResId
,
329 LPDLGTEMPLATE DlgTemplate
;
330 PDLGITEMTEMPLATE DlgItem
;
338 DWORD units
= GetDialogBaseUnits();
339 UINT xBaseUnit
= LOWORD(units
);
340 UINT yBaseUnit
= HIWORD(units
);
342 /* first load the dialog resource */
343 DlgTemplate
= (LPDLGTEMPLATE
)LoadDialogResource(hModule
, DialogResId
, NULL
);
346 /* failed to load resource */
350 /* Now walk past the dialog header */
351 Offset
= (LPWORD
)(DlgTemplate
+ 1);
353 /* FIXME: support menu */
354 assert(*Offset
== 0);
357 /* FIXME: support classes */
358 assert(*Offset
== 0);
361 /* FIXME: support titles */
362 assert(*Offset
== 0);
369 /* calculate font length */
370 Length
= wcslen((LPWSTR
)Offset
) + 1;
371 assert(Length
< (sizeof(FontName
) / sizeof(WCHAR
)));
374 wcscpy(FontName
, (LPWSTR
)Offset
);
376 if (DlgTemplate
->style
& DS_SETFONT
)
382 if (!MixerWindow
->hFont
)
384 int pixels
= MulDiv(FontSize
, GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
385 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
);
388 if (MixerWindow
->hFont
)
393 hOldFont
= SelectObject(hDC
, MixerWindow
->hFont
);
394 charSize
.cx
= GdiGetCharDimensions(hDC
, NULL
, &charSize
.cy
);
397 xBaseUnit
= charSize
.cx
;
398 yBaseUnit
= charSize
.cy
;
400 SelectObject(hDC
, hOldFont
);
402 MixerWindow
->baseUnit
.cx
= charSize
.cx
;
403 MixerWindow
->baseUnit
.cy
= charSize
.cy
;
407 // assert(MixerWindow->hFont);
409 /* move offset after font name */
412 /* offset is now at first dialog item control */
413 DlgItem
= (PDLGITEMTEMPLATE
)Offset
;
416 dialogRect
.right
= DlgTemplate
->cx
;
418 dialogRect
.bottom
= DlgTemplate
->cy
;
420 ConvertRect(&dialogRect
, xBaseUnit
, yBaseUnit
);
422 width
= dialogRect
.right
- dialogRect
.left
;
424 dialogRect
.left
+= MixerWindow
->rect
.right
;
425 dialogRect
.right
+= MixerWindow
->rect
.right
;
426 dialogRect
.top
+= MixerWindow
->rect
.top
;
427 dialogRect
.bottom
+= MixerWindow
->rect
.top
;
429 MixerWindow
->rect
.right
+= width
;
430 if ((dialogRect
.bottom
- dialogRect
.top
) > (MixerWindow
->rect
.bottom
- MixerWindow
->rect
.top
))
431 MixerWindow
->rect
.bottom
= MixerWindow
->rect
.top
+ dialogRect
.bottom
- dialogRect
.top
;
433 /* now add the controls */
434 LoadDialogControls(MixerWindow
, &dialogRect
, DlgTemplate
->cdit
, DlgItem
, Index
, xBaseUnit
, yBaseUnit
);
439 EnumConnectionsCallback(
445 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
448 UINT ControlCount
= 0, Index
;
449 LPMIXERCONTROL Control
= NULL
;
451 PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails
= NULL
;
452 PPREFERENCES_CONTEXT PrefContext
= (PPREFERENCES_CONTEXT
)Context
;
454 if (Line
->cControls
== 0)
458 if (SndMixerGetLineName(PrefContext
->MixerWindow
->Mixer
, PrefContext
->SelectedLine
, LineName
, MIXER_LONG_NAME_CHARS
, TRUE
) == -1)
460 /* failed to get line name */
464 pVolumeDetails
= HeapAlloc(GetProcessHeap(),
466 Line
->cChannels
* sizeof(MIXERCONTROLDETAILS_UNSIGNED
));
467 if (pVolumeDetails
== NULL
)
470 /* check if line is found in registry settings */
471 if (ReadLineConfig(PrefContext
->DeviceName
,
481 if ((Line
->dwComponentType
== MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
) ||
482 (Line
->dwComponentType
== MIXERLINE_COMPONENTTYPE_DST_HEADPHONES
))
483 dlgId
= (PrefContext
->MixerWindow
->Mode
== SMALL_MODE
) ? IDD_SMALL_MASTER
: IDD_NORMAL_MASTER
;
485 dlgId
= (PrefContext
->MixerWindow
->Mode
== SMALL_MODE
) ? IDD_SMALL_LINE
: IDD_NORMAL_LINE
;
487 /* load dialog resource */
488 LoadDialog(hAppInstance
, PrefContext
->MixerWindow
, MAKEINTRESOURCE(dlgId
), PrefContext
->MixerWindow
->DialogCount
);
491 wID
= (PrefContext
->MixerWindow
->DialogCount
+ 1) * IDC_LINE_NAME
;
494 SetDlgItemTextW(PrefContext
->MixerWindow
->hWnd
, wID
, Line
->szName
);
497 if (SndMixerQueryControls(Mixer
, &ControlCount
, Line
, &Control
) != FALSE
)
499 /* now go through all controls and update their states */
500 for (Index
= 0; Index
< Line
->cControls
; Index
++)
502 if (Control
[Index
].dwControlType
== MIXERCONTROL_CONTROLTYPE_MUTE
)
504 MIXERCONTROLDETAILS_BOOLEAN Details
;
506 /* get volume control details */
507 if (SndMixerGetVolumeControlDetails(Mixer
, Control
[Index
].dwControlID
, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN
), (LPVOID
)&Details
) != -1)
509 /* update dialog control */
510 wID
= (PrefContext
->MixerWindow
->DialogCount
+ 1) * IDC_LINE_SWITCH
;
512 /* get dialog control */
513 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
515 if (hDlgCtrl
!= NULL
)
517 /* Enable the 'Mute' checkbox, if we are in play mode */
518 if (Mixer
->MixerId
== PLAY_MIXER
)
519 EnableWindow(hDlgCtrl
, TRUE
);
522 if (SendMessageW(hDlgCtrl
, BM_GETCHECK
, 0, 0) != Details
.fValue
)
524 /* update control state */
525 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)Details
.fValue
, 0);
530 else if (Control
[Index
].dwControlType
== MIXERCONTROL_CONTROLTYPE_VOLUME
)
532 /* get volume control details */
533 if (SndMixerGetVolumeControlDetails(Mixer
, Control
[Index
].dwControlID
, Line
->cChannels
, sizeof(MIXERCONTROLDETAILS_UNSIGNED
), (LPVOID
)pVolumeDetails
) != -1)
535 /* update dialog control */
536 DWORD volumePosition
, volumeStep
, maxVolume
, i
;
537 DWORD balancePosition
, balanceStep
;
539 volumeStep
= (Control
[Index
].Bounds
.dwMaximum
- Control
[Index
].Bounds
.dwMinimum
) / (VOLUME_MAX
- VOLUME_MIN
);
542 for (i
= 0; i
< Line
->cChannels
; i
++)
544 if (pVolumeDetails
[i
].dwValue
> maxVolume
)
545 maxVolume
= pVolumeDetails
[i
].dwValue
;
548 volumePosition
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / volumeStep
;
550 if (Line
->cChannels
== 1)
552 balancePosition
= BALANCE_CENTER
;
554 else if (Line
->cChannels
== 2)
556 if (pVolumeDetails
[0].dwValue
== pVolumeDetails
[1].dwValue
)
558 balancePosition
= BALANCE_CENTER
;
560 else if (pVolumeDetails
[0].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
562 balancePosition
= BALANCE_RIGHT
;
564 else if (pVolumeDetails
[1].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
566 balancePosition
= BALANCE_LEFT
;
570 balanceStep
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / (BALANCE_STEPS
/ 2);
572 if (pVolumeDetails
[0].dwValue
< pVolumeDetails
[1].dwValue
)
574 balancePosition
= (pVolumeDetails
[0].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
575 balancePosition
= BALANCE_RIGHT
- balancePosition
;
577 else if (pVolumeDetails
[1].dwValue
< pVolumeDetails
[0].dwValue
)
579 balancePosition
= (pVolumeDetails
[1].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
580 balancePosition
= BALANCE_LEFT
+ balancePosition
;
585 /* Set the volume trackbar */
586 wID
= (PrefContext
->MixerWindow
->DialogCount
+ 1) * IDC_LINE_SLIDER_VERT
;
588 /* get dialog control */
589 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
591 if (hDlgCtrl
!= NULL
)
594 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
596 /* Enable the volume trackbar */
597 EnableWindow(hDlgCtrl
, TRUE
);
599 if (OldPosition
!= (VOLUME_MAX
- volumePosition
))
601 /* update control state */
602 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, VOLUME_MAX
- volumePosition
);
606 if (Line
->cChannels
== 2)
608 /* Set the balance trackbar */
609 wID
= (PrefContext
->MixerWindow
->DialogCount
+ 1) * IDC_LINE_SLIDER_HORZ
;
611 /* get dialog control */
612 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
614 if (hDlgCtrl
!= NULL
)
617 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
619 /* Enable the balance trackbar */
620 EnableWindow(hDlgCtrl
, TRUE
);
622 if (OldPosition
!= balancePosition
)
624 /* update control state */
625 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, balancePosition
);
633 if (PrefContext
->MixerWindow
->Mode
== NORMAL_MODE
)
634 PrefContext
->MixerWindow
->bHasExtendedControls
= TRUE
;
639 HeapFree(GetProcessHeap(), 0, Control
);
642 /* increment dialog count */
643 PrefContext
->MixerWindow
->DialogCount
++;
648 /* Free the volume details */
650 HeapFree(GetProcessHeap(), 0, pVolumeDetails
);
657 PPREFERENCES_CONTEXT PrefContext
)
662 /* set dialog count to zero */
663 PrefContext
->MixerWindow
->DialogCount
= 0;
665 SetRectEmpty(&PrefContext
->MixerWindow
->rect
);
667 /* enumerate controls */
668 SndMixerEnumConnections(PrefContext
->MixerWindow
->Mixer
, PrefContext
->SelectedLine
, EnumConnectionsCallback
, (PVOID
)PrefContext
);
670 if (PrefContext
->MixerWindow
->bHasExtendedControls
)
672 EnableMenuItem(GetMenu(PrefContext
->MixerWindow
->hWnd
), IDM_ADVANCED_CONTROLS
, MF_BYCOMMAND
| MF_ENABLED
);
675 if (PrefContext
->MixerWindow
->hStatusBar
)
677 GetWindowRect(PrefContext
->MixerWindow
->hStatusBar
, &statusRect
);
678 PrefContext
->MixerWindow
->rect
.bottom
+= (statusRect
.bottom
- statusRect
.top
);
681 /* now move the window */
682 AdjustWindowRect(&PrefContext
->MixerWindow
->rect
, WS_DLGFRAME
| WS_CAPTION
| WS_MINIMIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_VISIBLE
, TRUE
);
683 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
);
685 /* Move the status bar */
686 if (PrefContext
->MixerWindow
->hStatusBar
)
688 SetWindowPos(PrefContext
->MixerWindow
->hStatusBar
,
691 PrefContext
->MixerWindow
->rect
.bottom
- (statusRect
.bottom
- statusRect
.top
),
692 PrefContext
->MixerWindow
->rect
.right
- PrefContext
->MixerWindow
->rect
.left
,
693 statusRect
.bottom
- statusRect
.top
,
697 /* Hide the last line separator */
698 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, IDC_LINE_SEP
* PrefContext
->MixerWindow
->DialogCount
/*PrefContext->Count*/);
699 if (hDlgCtrl
!= NULL
)
701 ShowWindow(hDlgCtrl
, SW_HIDE
);
706 UpdateDialogLineSwitchControl(
707 PPREFERENCES_CONTEXT PrefContext
,
714 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
716 /* find the index of this line */
717 for (Index
= 0; Index
< PrefContext
->MixerWindow
->DialogCount
; Index
++)
720 wID
= (Index
+ 1) * IDC_LINE_NAME
;
722 if (GetDlgItemText(PrefContext
->MixerWindow
->hWnd
, wID
, LineName
, MIXER_LONG_NAME_CHARS
) == 0)
724 /* failed to retrieve id */
728 /* check if the line name matches */
729 if (!wcsicmp(LineName
, Line
->szName
))
731 /* found matching line name */
732 wID
= (Index
+ 1) * IDC_LINE_SWITCH
;
734 /* get dialog control */
735 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
737 if (hDlgCtrl
!= NULL
)
740 if (SendMessageW(hDlgCtrl
, BM_GETCHECK
, 0, 0) != fValue
)
742 /* update control state */
743 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)fValue
, 0);
752 UpdateDialogLineSliderControl(
753 PPREFERENCES_CONTEXT PrefContext
,
761 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
763 /* find the index of this line */
764 for (Index
= 0; Index
< PrefContext
->MixerWindow
->DialogCount
; Index
++)
767 wID
= (Index
+ 1) * IDC_LINE_NAME
;
769 if (GetDlgItemText(PrefContext
->MixerWindow
->hWnd
, wID
, LineName
, MIXER_LONG_NAME_CHARS
) == 0)
771 /* failed to retrieve id */
775 /* check if the line name matches */
776 if (!wcsicmp(LineName
, Line
->szName
))
778 /* found matching line name */
779 wID
= (Index
+ 1) * dwDialogID
;
781 /* get dialog control */
782 hDlgCtrl
= GetDlgItem(PrefContext
->MixerWindow
->hWnd
, wID
);
784 if (hDlgCtrl
!= NULL
)
787 LRESULT OldPosition
= SendMessageW(hDlgCtrl
, TBM_GETPOS
, 0, 0);
788 if (OldPosition
!= Position
)
790 /* update control state */
791 SendMessageW(hDlgCtrl
, TBM_SETPOS
, (WPARAM
)TRUE
, Position
);