Release 950727
[wine] / windows / dialog.c
1 /*
2  * Dialog functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6 static char Copyright[] = "Copyright  Alexandre Julliard, 1993, 1994";
7 */
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "windows.h"
13 #include "dialog.h"
14 #include "win.h"
15 #include "ldt.h"
16 #include "stackframe.h"
17 #include "user.h"
18 #include "message.h"
19 #include "stddebug.h"
20 /* #define DEBUG_DIALOG */
21 #include "debug.h"
22
23   /* Dialog base units */
24 static WORD xBaseUnit = 0, yBaseUnit = 0;
25
26
27 /***********************************************************************
28  *           DIALOG_Init
29  *
30  * Initialisation of the dialog manager.
31  */
32 BOOL DIALOG_Init()
33 {
34     TEXTMETRIC tm;
35     HDC hdc;
36     
37       /* Calculate the dialog base units */
38
39     if (!(hdc = GetDC( 0 ))) return FALSE;
40     GetTextMetrics( hdc, &tm );
41     ReleaseDC( 0, hdc );
42     xBaseUnit = tm.tmAveCharWidth;
43     yBaseUnit = tm.tmHeight;
44
45       /* Dialog units are based on a proportional system font */
46       /* so we adjust them a bit for a fixed font. */
47     if (tm.tmPitchAndFamily & TMPF_FIXED_PITCH) xBaseUnit = xBaseUnit * 5 / 4;
48
49     dprintf_dialog( stddeb, "DIALOG_Init: base units = %d,%d\n",
50                     xBaseUnit, yBaseUnit );
51     return TRUE;
52 }
53
54
55 /***********************************************************************
56  *           DIALOG_GetFirstTabItem
57  *
58  * Return the first item of the dialog that has the WS_TABSTOP style.
59  */
60 HWND DIALOG_GetFirstTabItem( HWND hwndDlg )
61 {
62     HWND hwnd;
63     WND *wndPtr = WIN_FindWndPtr( hwndDlg );
64     hwnd = wndPtr->hwndChild;
65     while(hwnd)
66     {
67         wndPtr = WIN_FindWndPtr( hwnd );
68         if (wndPtr->dwStyle & WS_TABSTOP) break;
69         hwnd = wndPtr->hwndNext;
70     }
71     return hwnd;
72 }
73
74
75 /***********************************************************************
76  *           DIALOG_GetControl
77  *
78  * Return the class and text of the control pointed to by ptr,
79  * and return a pointer to the next control.
80  */
81 static DLGCONTROLHEADER * DIALOG_GetControl( DLGCONTROLHEADER * ptr,
82                                              char ** class, char ** text )
83 {
84     unsigned char * p = (unsigned char *)ptr;
85     p += 14;  /* size of control header */
86
87     if (*p & 0x80)
88     {
89         switch(*p++)
90         {
91         case 0x80: *class = "BUTTON"; break;
92         case 0x81: *class = "EDIT"; break;
93         case 0x82: *class = "STATIC"; break;
94         case 0x83: *class = "LISTBOX"; break;
95         case 0x84: *class = "SCROLLBAR"; break;
96         case 0x85: *class = "COMBOBOX"; break;
97         default:   *class = ""; break;
98         }
99     }
100     else 
101     {
102         *class = p;
103         p += strlen(p) + 1;
104     }
105     if (*p == 0xff)
106     {
107           /* Integer id, not documented (?). Only works for SS_ICON controls */
108         *text = (char *)MAKEINTRESOURCE( p[1] + 256*p[2] );
109         p += 4;
110     }
111     else
112     {
113         *text = p;
114         p += strlen(p) + 2;
115     }
116     return (DLGCONTROLHEADER *)p;
117 }
118
119
120 /***********************************************************************
121  *           DIALOG_ParseTemplate
122  *
123  * Fill a DLGTEMPLATE structure from the dialog template, and return
124  * a pointer to the first control.
125  */
126 static DLGCONTROLHEADER * DIALOG_ParseTemplate( LPCSTR template,
127                                                 DLGTEMPLATE * result )
128 {
129     unsigned char * p = (unsigned char *)template;
130  
131     result->header = (DLGTEMPLATEHEADER *)p;
132     p += 13;
133
134     result->menuName = p;
135     if (*p == 0xff) p += 3;
136     else p += strlen(p) + 1;
137
138     if (*p) result->className = p;
139     else result->className = DIALOG_CLASS_NAME;
140     p += strlen(p) + 1;
141
142     result->caption = p;
143     p += strlen(p) + 1;
144
145     if (result->header->style & DS_SETFONT)
146     {
147         result->pointSize = *(WORD *)p; p += sizeof(WORD);
148         result->faceName = p;           p += strlen(p) + 1;
149     }
150
151     return (DLGCONTROLHEADER *)p;
152 }
153
154
155 /***********************************************************************
156  *           DIALOG_DisplayTemplate
157  */
158 static void DIALOG_DisplayTemplate( DLGTEMPLATE * result )
159 {
160     dprintf_dialog(stddeb, "DIALOG %d, %d, %d, %d\n", result->header->x, result->header->y,
161             result->header->cx, result->header->cy );
162     dprintf_dialog(stddeb, " STYLE %08lx\n", result->header->style );
163     dprintf_dialog(stddeb, " CAPTION '%s'\n", result->caption );
164     dprintf_dialog(stddeb, " CLASS '%s'\n", result->className );
165     if (result->menuName[0] == 0xff)
166         dprintf_dialog(stddeb, " MENU %d\n", result->menuName[1] + 256*result->menuName[2] );
167     else 
168         dprintf_dialog(stddeb, " MENU '%s'\n", result->menuName );
169     if (result->header->style & DS_SETFONT)
170         dprintf_dialog(stddeb, " FONT %d,'%s'\n", result->pointSize, result->faceName );
171 }
172
173
174 /***********************************************************************
175  *           CreateDialog   (USER.89)
176  */
177 HWND CreateDialog( HINSTANCE hInst, SEGPTR dlgTemplate,
178                    HWND owner, WNDPROC dlgProc )
179 {
180     return CreateDialogParam( hInst, dlgTemplate, owner, dlgProc, 0 );
181 }
182
183
184 /***********************************************************************
185  *           CreateDialogParam   (USER.241)
186  */
187 HWND CreateDialogParam( HINSTANCE hInst, SEGPTR dlgTemplate,
188                         HWND owner, WNDPROC dlgProc, LPARAM param )
189 {
190     HWND hwnd = 0;
191     HRSRC hRsrc;
192     HGLOBAL hmem;
193     LPCSTR data;
194
195     dprintf_dialog(stddeb, "CreateDialogParam: %d,%08lx,%d,%08lx,%ld\n",
196             hInst, dlgTemplate, owner, (DWORD)dlgProc, param );
197      
198     if (!(hRsrc = FindResource( hInst, dlgTemplate, RT_DIALOG ))) return 0;
199     if (!(hmem = LoadResource( hInst, hRsrc ))) return 0;
200     if (!(data = LockResource( hmem ))) hwnd = 0;
201     else hwnd = CreateDialogIndirectParam(hInst, data, owner, dlgProc, param);
202     FreeResource( hmem );
203     return hwnd;
204 }
205
206
207 /***********************************************************************
208  *           CreateDialogIndirect   (USER.219)
209  */
210 HWND CreateDialogIndirect( HINSTANCE hInst, LPCSTR dlgTemplate,
211                            HWND owner, WNDPROC dlgProc )
212 {
213     return CreateDialogIndirectParam( hInst, dlgTemplate, owner, dlgProc, 0 );
214 }
215
216
217 /***********************************************************************
218  *           CreateDialogIndirectParam   (USER.242)
219  */
220 HWND CreateDialogIndirectParam( HINSTANCE hInst, LPCSTR dlgTemplate,
221                                 HWND owner, WNDPROC dlgProc, LPARAM param )
222 {
223     HMENU hMenu;
224     HFONT hFont = 0;
225     HWND hwnd, hwndCtrl;
226     RECT rect;
227     WND * wndPtr;
228     int i;
229     DLGTEMPLATE template;
230     DLGCONTROLHEADER * header;
231     DIALOGINFO * dlgInfo;
232     DWORD exStyle = 0;
233     WORD xUnit = xBaseUnit;
234     WORD yUnit = yBaseUnit;
235
236       /* Parse dialog template */
237
238     if (!dlgTemplate) return 0;
239     header = DIALOG_ParseTemplate( dlgTemplate, &template );
240     if(debugging_dialog)DIALOG_DisplayTemplate( &template );
241
242       /* Load menu */
243
244     switch (template.menuName[0])
245     {
246       case 0x00:
247           hMenu = 0;
248           break;
249       case 0xff:
250           hMenu = LoadMenu( hInst, MAKEINTRESOURCE( template.menuName[1] +
251                                                    256*template.menuName[2] ));
252           break;
253       default:
254           {
255                 /* Need to copy the menu name to a 16-bit accessible area */
256               char name[256];
257               strncpy( name, template.menuName, 255 );
258               name[255] = '\0';
259               hMenu = LoadMenu( hInst, MAKE_SEGPTR(name) );
260           }
261           break;
262     }
263
264       /* Create custom font if needed */
265
266     if (template.header->style & DS_SETFONT)
267     {
268           /* The font height must be negative as it is a point size */
269           /* (see CreateFont() documentation in the Windows SDK).   */
270         hFont = CreateFont( -template.pointSize, 0, 0, 0, FW_DONTCARE,
271                             FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
272                             DEFAULT_QUALITY, FF_DONTCARE, template.faceName );
273         if (hFont)
274         {
275             TEXTMETRIC tm;
276             HFONT oldFont;
277             HDC hdc;
278
279             hdc = GetDC(0);
280             oldFont = SelectObject( hdc, hFont );
281             GetTextMetrics( hdc, &tm );
282             SelectObject( hdc, oldFont );
283             ReleaseDC( 0, hdc );
284             xUnit = tm.tmAveCharWidth;
285             yUnit = tm.tmHeight;
286             if (tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
287                 xBaseUnit = xBaseUnit * 5 / 4;  /* See DIALOG_Init() */
288         }
289     }
290     
291       /* Create dialog main window */
292
293     rect.left = rect.top = 0;
294     if (!(template.header->style & DS_ABSALIGN))
295         ClientToScreen( owner, (POINT *)&rect );
296     rect.right = rect.left + template.header->cx * xUnit / 4;
297     rect.bottom = rect.top + template.header->cy * yUnit / 8;
298     if (template.header->style & DS_MODALFRAME) exStyle |= WS_EX_DLGMODALFRAME;
299     AdjustWindowRectEx( &rect, template.header->style, hMenu, exStyle );
300
301     hwnd = CreateWindowEx( exStyle, template.className, template.caption,
302                            template.header->style & ~WS_VISIBLE,
303                            rect.left + template.header->x * xUnit / 4,
304                            rect.top + template.header->y * yUnit / 8,
305                            rect.right - rect.left, rect.bottom - rect.top,
306                            owner, hMenu, hInst, (SEGPTR)0 );
307     if (!hwnd)
308     {
309         if (hFont) DeleteObject( hFont );
310         if (hMenu) DestroyMenu( hMenu );
311         return 0;
312     }
313
314       /* Create control windows */
315
316     dprintf_dialog(stddeb, " BEGIN\n" );
317
318     wndPtr = WIN_FindWndPtr( hwnd );
319     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
320     dlgInfo->msgResult = 0;  /* This is used to store the default button id */
321     dlgInfo->hDialogHeap = 0;
322
323     for (i = 0; i < template.header->nbItems; i++)
324     {
325         DLGCONTROLHEADER * next_header;
326         LPSTR class, text;
327         HWND hwndDefButton = 0;
328         next_header = DIALOG_GetControl( header, &class, &text );
329
330         dprintf_dialog(stddeb, "   %s ", class);
331         if ((int)text & 0xffff0000) 
332           dprintf_dialog(stddeb,"'%s'", text);
333         else 
334           dprintf_dialog(stddeb,"%4X", (int)text & 0xffff);
335         dprintf_dialog(stddeb," %d, %d, %d, %d, %d, %08lx\n", 
336                 header->id, header->x, header->y, 
337                 header->cx, header->cy, header->style );
338
339         if ((strcmp(class, "EDIT") == 0) &&
340                     ((header->style & DS_LOCALEDIT) != DS_LOCALEDIT)) {
341             if (!dlgInfo->hDialogHeap) {
342                 dlgInfo->hDialogHeap = GlobalAlloc(GMEM_FIXED, 0x10000);
343                 if (!dlgInfo->hDialogHeap) {
344                     fprintf(stderr,"CreateDialogIndirectParam: Insufficient memory to create heap for edit control\n");
345                     continue;
346                 }
347                 LocalInit(dlgInfo->hDialogHeap, 0, 0xffff);
348             }
349             header->style |= WS_CHILD;
350             hwndCtrl = CreateWindowEx( WS_EX_NOPARENTNOTIFY, 
351                            class, text, header->style,
352                            header->x * xUnit / 4, header->y * yUnit / 8,
353                            header->cx * xUnit / 4, header->cy * yUnit / 8,
354                            hwnd, header->id, dlgInfo->hDialogHeap, (SEGPTR)0 );
355         }
356         else
357         {
358             header->style |= WS_CHILD;
359             hwndCtrl = CreateWindowEx( WS_EX_NOPARENTNOTIFY, 
360                                 class, text, header->style,
361                                 header->x * xUnit / 4, header->y * yUnit / 8,
362                                 header->cx * xUnit / 4, header->cy * yUnit / 8,
363                                 hwnd, header->id, hInst, (SEGPTR)0 );
364         }
365         /* Make the control last one in Z-order, so that controls remain
366            in the order in which they were created */
367         SetWindowPos( hwndCtrl, HWND_BOTTOM, 0, 0, 0, 0,
368                       SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
369
370             /* Send initialisation messages to the control */
371         if (hFont) SendMessage( hwndCtrl, WM_SETFONT, hFont, 0 );
372         if (SendMessage( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_DEFPUSHBUTTON)
373         {
374               /* If there's already a default push-button, set it back */
375               /* to normal and use this one instead. */
376             if (hwndDefButton)
377                 SendMessage( hwndDefButton, BM_SETSTYLE, BS_PUSHBUTTON, FALSE);
378             hwndDefButton = hwndCtrl;
379             dlgInfo->msgResult = header->id;
380         }
381         header = next_header;
382     }    
383
384     dprintf_dialog(stddeb, " END\n" );
385     
386       /* Initialise dialog extra data */
387
388     dlgInfo->dlgProc   = dlgProc;
389     dlgInfo->hUserFont = hFont;
390     dlgInfo->hMenu     = hMenu;
391     dlgInfo->xBaseUnit = xUnit;
392     dlgInfo->yBaseUnit = yUnit;
393     dlgInfo->hwndFocus = DIALOG_GetFirstTabItem( hwnd );
394
395       /* Send initialisation messages and set focus */
396
397     if (dlgInfo->hUserFont)
398         SendMessage( hwnd, WM_SETFONT, dlgInfo->hUserFont, 0 );
399     if (SendMessage( hwnd, WM_INITDIALOG, dlgInfo->hwndFocus, param ))
400         SetFocus( dlgInfo->hwndFocus );
401     if (template.header->style & WS_VISIBLE) ShowWindow(hwnd, SW_SHOW);
402     return hwnd;
403 }
404
405
406 /***********************************************************************
407  *           DIALOG_DoDialogBox
408  */
409 static int DIALOG_DoDialogBox( HWND hwnd, HWND owner )
410 {
411     WND * wndPtr;
412     DIALOGINFO * dlgInfo;
413     HANDLE msgHandle;
414     MSG* lpmsg;
415     int retval;
416
417       /* Owner must be a top-level window */
418     owner = WIN_GetTopParent( owner );
419     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
420     if (!(msgHandle = USER_HEAP_ALLOC( sizeof(MSG) ))) return -1;
421     lpmsg = (MSG *) USER_HEAP_LIN_ADDR( msgHandle );
422     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
423     EnableWindow( owner, FALSE );
424     ShowWindow( hwnd, SW_SHOW );
425
426     while (MSG_InternalGetMessage( USER_HEAP_SEG_ADDR(msgHandle), hwnd, owner,
427                                    MSGF_DIALOGBOX, PM_REMOVE,
428                                    !(wndPtr->dwStyle & DS_NOIDLEMSG) ))
429     {
430         if (!IsDialogMessage( hwnd, lpmsg))
431         {
432             TranslateMessage( lpmsg );
433             DispatchMessage( lpmsg );
434         }
435         if (dlgInfo->fEnd) break;
436     }
437     retval = dlgInfo->msgResult;
438     DestroyWindow( hwnd );
439     USER_HEAP_FREE( msgHandle );
440     EnableWindow( owner, TRUE );
441     return retval;
442 }
443
444
445 /***********************************************************************
446  *           DialogBox   (USER.87)
447  */
448 int DialogBox( HINSTANCE hInst, SEGPTR dlgTemplate,
449                HWND owner, WNDPROC dlgProc )
450 {
451     return DialogBoxParam( hInst, dlgTemplate, owner, dlgProc, 0 );
452 }
453
454
455 /***********************************************************************
456  *           DialogBoxParam   (USER.239)
457  */
458 int DialogBoxParam( HINSTANCE hInst, SEGPTR dlgTemplate,
459                     HWND owner, WNDPROC dlgProc, LPARAM param )
460 {
461     HWND hwnd;
462     
463     dprintf_dialog(stddeb, "DialogBoxParam: %d,%08lx,%d,%08lx,%ld\n",
464             hInst, dlgTemplate, owner, (DWORD)dlgProc, param );
465     hwnd = CreateDialogParam( hInst, dlgTemplate, owner, dlgProc, param );
466     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
467     return -1;
468 }
469
470
471 /***********************************************************************
472  *           DialogBoxIndirect   (USER.218)
473  */
474 int DialogBoxIndirect( HINSTANCE hInst, HANDLE dlgTemplate,
475                        HWND owner, WNDPROC dlgProc )
476 {
477     return DialogBoxIndirectParam( hInst, dlgTemplate, owner, dlgProc, 0 );
478 }
479
480
481 /***********************************************************************
482  *           DialogBoxIndirectParam   (USER.240)
483  */
484 int DialogBoxIndirectParam( HINSTANCE hInst, HANDLE dlgTemplate,
485                             HWND owner, WNDPROC dlgProc, LPARAM param )
486 {
487     HWND hwnd;
488     LPCSTR ptr;
489
490     if (!(ptr = GlobalLock( dlgTemplate ))) return -1;
491     hwnd = CreateDialogIndirectParam( hInst, ptr, owner, dlgProc, param );
492     GlobalUnlock( dlgTemplate );
493     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
494     return -1;
495 }
496
497
498 /***********************************************************************
499  *           DialogBoxIndirectParamPtr
500  *  like DialogBoxIndirectParam, but expects pointer to template
501  */
502 int DialogBoxIndirectParamPtr(HINSTANCE hInst,LPCSTR dlgTemplate,
503                               HWND owner, WNDPROC dlgProc, LPARAM param)
504 {
505     HWND hwnd;
506     hwnd = CreateDialogIndirectParam( hInst, dlgTemplate, owner, dlgProc, param );
507     if (hwnd) return DIALOG_DoDialogBox( hwnd, owner );
508     return -1;
509 }
510
511 /***********************************************************************
512  *           DialogBoxIndirectPtr
513  *  like DialogBoxIndirect, but expects pointer to template
514  */
515 int DialogBoxIndirectPtr( HINSTANCE hInst, LPCSTR dlgTemplate,
516                           HWND owner, WNDPROC dlgProc)
517 {
518     return DialogBoxIndirectParamPtr(hInst, dlgTemplate, owner, dlgProc, 0);
519 }
520
521 /***********************************************************************
522  *           EndDialog   (USER.88)
523  */
524 void EndDialog( HWND hwnd, short retval )
525 {
526     WND * wndPtr = WIN_FindWndPtr( hwnd );
527     DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
528     dlgInfo->msgResult = retval;
529     dlgInfo->fEnd = TRUE;
530     dprintf_dialog(stddeb, "EndDialog: %d %d\n", hwnd, retval );
531 }
532
533
534 /***********************************************************************
535  *           IsDialogMessage   (USER.90)
536  */
537 BOOL IsDialogMessage( HWND hwndDlg, LPMSG msg )
538 {
539     WND * wndPtr;
540     int dlgCode;
541
542     if (!(wndPtr = WIN_FindWndPtr( hwndDlg ))) return FALSE;
543     if ((hwndDlg != msg->hwnd) && !IsChild( hwndDlg, msg->hwnd )) return FALSE;
544
545       /* Only the key messages get special processing */
546     if ((msg->message != WM_KEYDOWN) &&
547         (msg->message != WM_SYSCHAR) &&
548         (msg->message != WM_CHAR))
549         return FALSE;
550
551     dlgCode = SendMessage( msg->hwnd, WM_GETDLGCODE, 0, 0 );
552     if (dlgCode & DLGC_WANTMESSAGE)
553     {
554         DispatchMessage( msg );
555         return TRUE;
556     }
557
558     switch(msg->message)
559     {
560     case WM_KEYDOWN:
561         if (dlgCode & DLGC_WANTALLKEYS) break;
562         switch(msg->wParam)
563         {
564         case VK_TAB:
565             if (!(dlgCode & DLGC_WANTTAB))
566             {
567                 SendMessage( hwndDlg, WM_NEXTDLGCTL,
568                              (GetKeyState(VK_SHIFT) & 0x80), 0 );
569                 return TRUE;
570             }
571             break;
572             
573         case VK_RIGHT:
574         case VK_DOWN:
575             if (!(dlgCode & DLGC_WANTARROWS))
576             {
577                 SetFocus(GetNextDlgGroupItem(hwndDlg,GetFocus(),FALSE));
578                 return TRUE;
579             }
580             break;
581
582         case VK_LEFT:
583         case VK_UP:
584             if (!(dlgCode & DLGC_WANTARROWS))
585             {
586                 SetFocus(GetNextDlgGroupItem(hwndDlg,GetFocus(),TRUE));
587                 return TRUE;
588             }
589             break;
590
591         case VK_ESCAPE:
592             SendMessage( hwndDlg, WM_COMMAND, IDCANCEL,
593                          MAKELPARAM( GetDlgItem(hwndDlg,IDCANCEL), 0 ));
594             break;
595
596         case VK_RETURN:
597             {
598                 DWORD dw = SendMessage( hwndDlg, DM_GETDEFID, 0, 0 );
599                 if (HIWORD(dw) == DC_HASDEFID)
600                     SendMessage( hwndDlg, WM_COMMAND, LOWORD(dw),
601                                  MAKELPARAM( GetDlgItem( hwndDlg, LOWORD(dw) ),
602                                              BN_CLICKED ));
603                 else
604                     SendMessage( hwndDlg, WM_COMMAND, IDOK,
605                                  MAKELPARAM( GetDlgItem(hwndDlg,IDOK), 0 ));
606             }
607             break;
608         }
609         break;  /* case WM_KEYDOWN */
610
611         
612     case WM_CHAR:
613         if (dlgCode & (DLGC_WANTALLKEYS | DLGC_WANTCHARS)) break;
614         break;
615
616     case WM_SYSCHAR:
617         if (dlgCode & DLGC_WANTALLKEYS) break;
618         break;
619     }
620
621       /* If we get here, the message has not been treated specially */
622       /* and can be sent to its destination window. */
623     DispatchMessage( msg );
624     return TRUE;
625 }
626
627
628 /****************************************************************
629  *         GetDlgCtrlID           (USER.277)
630  */
631 int GetDlgCtrlID( HWND hwnd )
632 {
633     WND *wndPtr = WIN_FindWndPtr(hwnd);
634     if (wndPtr) return wndPtr->wIDmenu;
635     else return 0;
636 }
637  
638
639 /***********************************************************************
640  *           GetDlgItem   (USER.91)
641  */
642 HWND GetDlgItem( HWND hwndDlg, WORD id )
643 {
644     HWND curChild;
645     WND * childPtr;
646     WND * wndPtr;
647
648     if (!(wndPtr = WIN_FindWndPtr( hwndDlg ))) return 0;
649     curChild = wndPtr->hwndChild;
650     while(curChild)
651     {
652         childPtr = WIN_FindWndPtr( curChild );
653         if (childPtr->wIDmenu == id) return curChild;
654         curChild = childPtr->hwndNext;
655     }
656     return 0;
657 }
658
659
660 /*******************************************************************
661  *           SendDlgItemMessage   (USER.101)
662  */
663 LONG SendDlgItemMessage(HWND hwnd, WORD id, UINT msg, WORD wParam, LONG lParam)
664 {
665     HWND hwndCtrl = GetDlgItem( hwnd, id );
666     if (hwndCtrl) return SendMessage( hwndCtrl, msg, wParam, lParam );
667     else return 0;
668 }
669
670
671 /*******************************************************************
672  *           SetDlgItemText   (USER.92)
673  */
674 void SetDlgItemText( HWND hwnd, WORD id, SEGPTR lpString )
675 {
676     SendDlgItemMessage( hwnd, id, WM_SETTEXT, 0, (DWORD)lpString );
677 }
678
679
680 /***********************************************************************
681  *           GetDlgItemText   (USER.93)
682  */
683 int GetDlgItemText( HWND hwnd, WORD id, SEGPTR str, WORD max )
684 {
685     return (int)SendDlgItemMessage( hwnd, id, WM_GETTEXT, max, (DWORD)str );
686 }
687
688
689 /*******************************************************************
690  *           SetDlgItemInt   (USER.94)
691  */
692 void SetDlgItemInt( HWND hwnd, WORD id, WORD value, BOOL fSigned )
693 {
694     char str[20];
695
696     if (fSigned) sprintf( str, "%d", (int)value );
697     else sprintf( str, "%u", value );
698     SendDlgItemMessage( hwnd, id, WM_SETTEXT, 0, MAKE_SEGPTR(str) );
699 }
700
701
702 /***********************************************************************
703  *           GetDlgItemInt   (USER.95)
704  */
705 WORD GetDlgItemInt( HWND hwnd, WORD id, BOOL * translated, BOOL fSigned )
706 {
707     char str[30];
708     long result = 0;
709     
710     if (translated) *translated = FALSE;
711     if (SendDlgItemMessage( hwnd, id, WM_GETTEXT, 30, MAKE_SEGPTR(str) ))
712     {
713         char * endptr;
714         result = strtol( str, &endptr, 10 );
715         if (endptr && (endptr != str))  /* Conversion was successful */
716         {
717             if (fSigned)
718             {
719                 if ((result < -32767) || (result > 32767)) result = 0;
720                 else if (translated) *translated = TRUE;
721             }
722             else
723             {
724                 if ((result < 0) || (result > 65535)) result = 0;
725                 else if (translated) *translated = TRUE;
726             }
727         }
728     }
729     return (WORD)result;
730 }
731
732
733 /***********************************************************************
734  *           CheckDlgButton   (USER.97)
735  */
736 void CheckDlgButton( HWND hwnd, WORD id, WORD check )
737 {
738     SendDlgItemMessage( hwnd, id, BM_SETCHECK, check, 0 );
739 }
740
741
742 /***********************************************************************
743  *           IsDlgButtonChecked   (USER.98)
744  */
745 WORD IsDlgButtonChecked( HWND hwnd, WORD id )
746 {
747     return (WORD)SendDlgItemMessage( hwnd, id, BM_GETCHECK, 0, 0 );
748 }
749
750
751 /***********************************************************************
752  *           CheckRadioButton   (USER.96)
753  */
754 void CheckRadioButton( HWND hwndDlg, WORD firstID, WORD lastID, WORD checkID )
755 {
756     HWND button = GetWindow( hwndDlg, GW_CHILD );
757     WND *wndPtr;
758
759     while (button)
760     {
761         if (!(wndPtr = WIN_FindWndPtr( button ))) return;
762         if ((wndPtr->wIDmenu == firstID) || (wndPtr->wIDmenu == lastID)) break;
763         button = wndPtr->hwndNext;
764     }
765     if (!button) return;
766
767     if (wndPtr->wIDmenu == lastID)
768         lastID = firstID;  /* Buttons are in reverse order */
769     while (button)
770     {
771         if (!(wndPtr = WIN_FindWndPtr( button ))) return;
772         SendMessage( button, BM_SETCHECK, (wndPtr->wIDmenu == checkID), 0 );
773         if (wndPtr->wIDmenu == lastID) break;
774         button = wndPtr->hwndNext;
775     }
776 }
777
778
779 /***********************************************************************
780  *           GetDialogBaseUnits   (USER.243)
781  */
782 DWORD GetDialogBaseUnits()
783 {
784     return MAKELONG( xBaseUnit, yBaseUnit );
785 }
786
787
788 /***********************************************************************
789  *           MapDialogRect   (USER.103)
790  */
791 void MapDialogRect( HWND hwnd, LPRECT rect )
792 {
793     DIALOGINFO * dlgInfo;
794     WND * wndPtr = WIN_FindWndPtr( hwnd );
795     if (!wndPtr) return;
796     dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
797     rect->left   = (rect->left * dlgInfo->xBaseUnit) / 4;
798     rect->right  = (rect->right * dlgInfo->xBaseUnit) / 4;
799     rect->top    = (rect->top * dlgInfo->yBaseUnit) / 8;
800     rect->bottom = (rect->bottom * dlgInfo->yBaseUnit) / 8;
801 }
802
803
804 /***********************************************************************
805  *           GetNextDlgGroupItem   (USER.227)
806  */
807 HWND GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
808 {
809     HWND hwnd, hwndStart;
810     WND * dlgPtr, * ctrlPtr, * wndPtr;
811
812     if (!(dlgPtr = WIN_FindWndPtr( hwndDlg ))) return 0;
813     if (!(ctrlPtr = WIN_FindWndPtr( hwndCtrl ))) return 0;
814     if (ctrlPtr->hwndParent != hwndDlg) return 0;
815
816     if (!fPrevious && ctrlPtr->hwndNext)  /*Check if next control is in group*/
817     {
818         wndPtr = WIN_FindWndPtr( ctrlPtr->hwndNext );
819         if (!(wndPtr->dwStyle & WS_GROUP)) return ctrlPtr->hwndNext;
820     }
821
822     if (ctrlPtr->dwStyle & WS_GROUP)  /* Control is the first of the group */
823     {
824         if (!fPrevious) return hwndCtrl;  /* Control is alone in his group */
825         hwnd = ctrlPtr->hwndNext;
826         while(hwnd)  /* Find last control of the group */
827         {
828             wndPtr = WIN_FindWndPtr( hwnd );
829             if (wndPtr->dwStyle & WS_GROUP) break;
830             hwndCtrl = hwnd;
831             hwnd = wndPtr->hwndNext;
832         }
833         return hwndCtrl;
834     }
835     
836       /* Now we will have to find the start of the group */
837
838     hwndStart = hwnd = dlgPtr->hwndChild;
839     while (hwnd)
840     {
841         wndPtr = WIN_FindWndPtr( hwnd );
842         if (wndPtr->dwStyle & WS_GROUP) hwndStart = hwnd;  /*Start of a group*/
843         if (hwnd == hwndCtrl)
844         {
845             /* We found the control -> hwndStart is the first of the group */
846             if (!fPrevious) return hwndStart;
847
848             while(hwndStart)  /* Find the control placed before hwndCtrl */
849             {
850                 wndPtr = WIN_FindWndPtr( hwndStart );
851                 if (wndPtr->hwndNext == hwndCtrl) return hwndStart;
852                 hwndStart = wndPtr->hwndNext;
853             }
854             break;
855         }
856         hwnd = wndPtr->hwndNext;
857     }
858     return hwndCtrl;  /* Not found -> return original control */
859 }
860
861
862 /***********************************************************************
863  *           GetNextDlgTabItem   (USER.228)
864  */
865 HWND GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl, BOOL fPrevious )
866 {
867     HWND hwnd, hwndLast;
868     WND * dlgPtr, * ctrlPtr, * wndPtr;
869
870     if (!(dlgPtr = WIN_FindWndPtr( hwndDlg ))) return 0;
871     if (!(ctrlPtr = WIN_FindWndPtr( hwndCtrl ))) return 0;
872     if (ctrlPtr->hwndParent != hwndDlg) return 0;
873
874     hwndLast = hwndCtrl;
875     hwnd = ctrlPtr->hwndNext;
876     while (1)
877     {
878         if (!hwnd) hwnd = dlgPtr->hwndChild;
879         if (hwnd == hwndCtrl) break;
880         wndPtr = WIN_FindWndPtr( hwnd );
881         if ((wndPtr->dwStyle & WS_TABSTOP) && (wndPtr->dwStyle & WS_VISIBLE))
882         {
883             hwndLast = hwnd;
884             if (!fPrevious) break;
885         }
886         hwnd = wndPtr->hwndNext;
887     }
888     return hwndLast;
889 }