xref: /reactos/base/applications/sndvol32/dialog.c (revision c2c66aff)
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