1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: msdlg.c 1025 2008-04-08 22:59:38Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 /*---------------------------------------------------------------------------
24 * Networks and Distributed Computing
25 * Computing and Communications
26 * University of Washington
27 * Administration Builiding, AG-44
28 * Seattle, Washington, 98195, USA
29 * Internet: tunger@cac.washington.edu
32 * Pine and Pico are registered trademarks of the University of Washington.
33 * No commercial use of these trademarks may be made without prior written
34 * permission of the University of Washington.
36 * Pine, Pico, and Pilot software and its included text are Copyright
37 * 1989-1998 by the University of Washington.
39 * The full text of our legal notices is contained in the file called
40 * CPYRIGHT, included with this distribution.
42 *--------------------------------------------------------------------------*/
57 #include "../estruct.h"
60 #include "../keydefs.h"
63 #include "../utf8stub.h"
64 #include "../../pith/charconv/filesys.h"
68 extern HINSTANCE ghInstance
;
69 extern BOOL gfUseDialogs
;
70 extern FILE *mswin_debugfile
;
71 extern int mswin_debug
;
72 extern TCHAR gszAppName
[45];
76 #define BTN_FIRSTID 200
78 #define BWIDTH_MIN 120
82 LPTSTR prompt
; /* Prompt. */
83 LPTSTR string
; /* Resulting string. */
84 int strlen
; /* Length of buffer. */
85 int append
; /* Append to existing string. */
86 int passwd
; /* Passwd, don't echo (1 use asterisk, 10 space). */
87 unsigned flags
; /* other flags. */
90 int button_count
; /* Number of additional buttons. */
91 MDlgButton
*button_list
; /* List of other buttons. */
92 char **helptext
; /* Help text. */
98 static OEInfo gOEInfo
;
99 static BOOL gDoHelpFirst
;
100 static WNDPROC gpOldEditProc
; /* Old Edit window proc. */
101 static WNDPROC gpEditProc
;
102 static WNDPROC gpOldBtnProc
; /* Old Edit window proc. */
103 static WNDPROC gpBtnProc
;
109 * Forward function declaratins.
111 LONG FAR PASCAL __export
EditProc(HWND hBtn
, UINT msg
, WPARAM wParam
,
113 LONG FAR PASCAL __export
ButtonProc(HWND hBtn
, UINT msg
, WPARAM wParam
,
115 BOOL CALLBACK __export
mswin_dialog_proc (HWND hDlg
, UINT uMsg
,
116 WPARAM wParam
, LPARAM lParam
);
117 BOOL CALLBACK __export
mswin_select_proc (HWND hDlg
, UINT uMsg
,
118 WPARAM wParam
, LPARAM lParam
);
119 LONG FAR PASCAL __export
KBCProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
,
123 static void BuildButtonList (HWND
, MDlgButton
*, int, MDlgButton
*);
124 static BOOL
ProcessChar (HWND
, WPARAM
, OEInfo
*, long *);
125 static void GetBtnPos (HWND
, HWND
, RECT
*);
127 int mswin_yesno_lptstr (LPTSTR
);
131 mswin_usedialog (void)
133 return (gfUseDialogs
);
138 /*----------------------------------------------------------------------
141 Generic text entry. Prompt user for a string.
145 prompt -- The string to prompt with
146 string -- the buffer result is returned in, and original string (if
148 field_len -- Maximum length of string to accept
149 append_current -- flag indicating string should not be truncated before
151 passwd -- a pass word is being fetch. Don't echo on screen
152 button_list -- pointer to array of mDlgButton's. input chars matching
153 those in list return value from list. Nearly identical
154 to Pine's ESCKEY structure.
155 help -- Arrary of strings for help text in bottom screen lines
158 Result: editing input string
159 returns -1 unexpected errors
160 returns 0 typed CR or pressed "OK"
161 returns 1 typed ESC or pressed "Cancel"
162 returns 3 typed ^G or PF1 (help)
163 returns 4 typed ^L for a screen redraw
164 or one of the other return values defined in button_list.
166 WARNING: Care is required with regard to the escape_list processing.
167 The passed array is terminated with an entry that has ch = -1.
168 Function key labels and key strokes need to be setup externally!
169 Traditionally, a return value of 2 is used for ^T escapes.
172 Note About Help: We don't get the help text on the first call. If we
173 want help text we have to return 3. We'll get called again
174 with help text. To make it look good, we want to display
175 this the second time we're called. But we don't want to
176 display the help text every time we're called with help
177 text. To know the difference we set gDoHelpFirst when
178 exiting to request help text. If this is set then we
179 display help. If not, then no help.
182 ----------------------------------------------------------------------*/
186 * xxx implement flags.
187 * xxx display.d uses flags QFFILE, QDEFLT, and QBOBUF
191 mswin_dialog(UCS
*prompt
, UCS
*buf
, int nbuf
, int append_current
,
192 int passwd
, MDlgButton
*button_list
, char **help
, unsigned flags
)
196 LPTSTR promptlpt
, buflpt
, b
;
201 promptlpt
= ucs4_to_lptstr(prompt
);
202 buflpt
= (LPTSTR
) fs_get(nbuf
* sizeof(TCHAR
));
203 b
= ucs4_to_lptstr(buf
);
207 for(i
= 0; i
< nbuf
&& b
[i
]; i
++)
214 fs_give((void **) &b
);
217 gOEInfo
.prompt
= promptlpt
;
218 gOEInfo
.string
= buflpt
;
219 gOEInfo
.strlen
= nbuf
;
220 gOEInfo
.append
= append_current
;
221 gOEInfo
.passwd
= passwd
;
222 gOEInfo
.helptext
= help
;
223 gOEInfo
.helpkey
= 0x07; /* ^G */
224 gOEInfo
.flags
= flags
;
225 gOEInfo
.button_list
= button_list
;
228 for (c
= 0; button_list
&& button_list
[c
].ch
!= -1; ++c
)
231 gOEInfo
.button_count
= c
;
233 gpEditProc
= (WNDPROC
) MakeProcInstance((FARPROC
) EditProc
, ghInstance
);
234 gpBtnProc
= (WNDPROC
) MakeProcInstance((FARPROC
) ButtonProc
, ghInstance
);
235 dlgprc
= (DLGPROC
) MakeProcInstance((FARPROC
) mswin_dialog_proc
, ghInstance
);
237 DialogBox(ghInstance
, MAKEINTRESOURCE (IDD_OPTIONALYENTER
), ghTTYWnd
, dlgprc
);
239 FreeProcInstance((FARPROC
) dlgprc
);
240 FreeProcInstance((FARPROC
) gpBtnProc
);
241 FreeProcInstance((FARPROC
) gpEditProc
);
244 fs_give((void **) &promptlpt
);
246 ucs
= lptstr_to_ucs4(buflpt
);
250 for(i
= 0; i
< nbuf
&& ucs
[i
]; i
++)
257 fs_give((void **) &ucs
);
260 return(gOEInfo
.result
);
267 * Dialog procedure for the generic text entry dialog box.
269 BOOL CALLBACK __export
270 mswin_dialog_proc (HWND hDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
276 MDlgButton built_in
[3];
283 * Set the prompt text.
285 SetDlgItemText(hDlg
, IDC_PROMPT
, gOEInfo
.prompt
);
288 * Set the initial edit text and configure the edit control
291 *gOEInfo
.string
= '\0';
293 SetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
);
295 SendDlgItemMessage (hDlg
, IDC_RESPONCE
, EM_SETPASSWORDCHAR
,
296 (gOEInfo
.passwd
== 1) ? '*' : gOEInfo
.passwd
? ' ' : 0, 0L);
297 SendDlgItemMessage (hDlg
, IDC_RESPONCE
, EM_LIMITTEXT
,
298 gOEInfo
.strlen
- 1, 0L);
299 l
= (long) lstrlen(gOEInfo
.string
);
300 SendDlgItemMessage(hDlg
, IDC_RESPONCE
, EM_SETSEL
, 0, l
);
301 hEdit
= GetDlgItem (hDlg
, IDC_RESPONCE
);
303 gpOldEditProc
= (WNDPROC
) GetWindowLong (hEdit
, GWL_WNDPROC
);
304 SetWindowLong (hEdit
, GWL_WNDPROC
, (DWORD
)(FARPROC
)gpEditProc
);
308 * Subclass the standard buttons and build buttons for each item
309 * in the button_list.
311 gpOldBtnProc
= (WNDPROC
) GetWindowLong (GetDlgItem (hDlg
, IDOK
), GWL_WNDPROC
);
312 SetWindowLong (GetDlgItem (hDlg
, IDOK
), GWL_WNDPROC
,
313 (DWORD
)(FARPROC
)gpBtnProc
);
314 SetWindowLong (GetDlgItem (hDlg
, IDCANCEL
), GWL_WNDPROC
,
315 (DWORD
)(FARPROC
)gpBtnProc
);
317 memset (&built_in
, 0, sizeof (built_in
));
318 built_in
[0].id
= IDOK
;
319 built_in
[1].id
= IDCANCEL
;
321 built_in
[2].id
= IDC_GETHELP
;
325 DestroyWindow (GetDlgItem (hDlg
, IDC_GETHELP
));
328 BuildButtonList (hDlg
, built_in
, biCount
, gOEInfo
.button_list
);
331 if (gOEInfo
.helptext
&& gDoHelpFirst
) {
332 mswin_showhelpmsg ((WINHAND
)hDlg
, gOEInfo
.helptext
);
333 gDoHelpFirst
= FALSE
;
340 * Keep focus on the edit item so key strokes are always
343 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
351 * Normal exit. Accept the new text.
353 GetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
, gOEInfo
.strlen
);
356 EndDialog (hDlg
, gOEInfo
.result
);
362 * Cancel operation. Don't retreive new text.
365 EndDialog (hDlg
, gOEInfo
.result
);
371 * Get help. If we have help text display it. If not,
372 * return value 3, which tells the caller to provide us
375 if (gOEInfo
.helptext
!= NULL
) {
376 mswin_showhelpmsg ((WINHAND
)hDlg
, gOEInfo
.helptext
);
379 GetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
, gOEInfo
.strlen
);
382 EndDialog (hDlg
, gOEInfo
.result
);
389 * Search button list for button with this ID. If found
390 * return it's result code. Retreive text.
392 if ( wParam
>= BTN_FIRSTID
&&
393 wParam
< BTN_FIRSTID
+ (WPARAM
) gOEInfo
.button_count
) {
394 GetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
, gOEInfo
.strlen
);
395 i
= wParam
- BTN_FIRSTID
;
396 gOEInfo
.result
= gOEInfo
.button_list
[i
].rval
;
397 EndDialog (hDlg
, gOEInfo
.result
);
410 * Subclassed window procedure for Edit control on generic text
413 LONG FAR PASCAL __export
414 EditProc (HWND hEdit
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
419 hDlg
= GetParent (hEdit
);
421 if (msg
== WM_GETDLGCODE
) {
423 * Tell windows that we want to receive ALL keystrokes.
425 ret
= CallWindowProc (gpOldEditProc
, hEdit
, msg
, wParam
, lParam
);
426 ret
|= DLGC_WANTALLKEYS
;
431 if (msg
== WM_CHAR
) {
433 * See if the character typed is a shortcut for any of the
436 if (ProcessChar (hDlg
, wParam
, &gOEInfo
, &ret
))
439 /* No... Fall through for deault processing. */
442 return (CallWindowProc (gpOldEditProc
, hEdit
, msg
, wParam
, lParam
));
449 * Subclass button windows.
451 * These buttons will automatically return the input focus to
452 * a control with id IDC_RESPONCE.
454 LONG FAR PASCAL __export
455 ButtonProc (HWND hBtn
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
461 if (uMsg
== WM_LBUTTONUP
|| uMsg
== WM_MBUTTONUP
|| uMsg
== WM_RBUTTONUP
) {
463 * On mouse button up restore input focus to IDC_RESPONCE, which
464 * processes keyboard input.
466 ret
= CallWindowProc (gpOldBtnProc
, hBtn
, uMsg
, wParam
, lParam
);
467 hDlg
= GetParent (hBtn
);
468 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
472 return (CallWindowProc (gpOldBtnProc
, hBtn
, uMsg
, wParam
, lParam
));
478 mswin_yesno(UCS
*prompt_ucs4
)
481 LPTSTR prompt_lptstr
;
483 prompt_lptstr
= ucs4_to_lptstr(prompt_ucs4
);
484 ret
= mswin_yesno_lptstr(prompt_lptstr
);
485 fs_give((void **) &prompt_lptstr
);
492 mswin_yesno_utf8(char *prompt_utf8
)
495 LPTSTR prompt_lptstr
;
497 prompt_lptstr
= utf8_to_lptstr(prompt_utf8
);
498 ret
= mswin_yesno_lptstr(prompt_lptstr
);
499 fs_give((void **) &prompt_lptstr
);
505 * Ask a yes/no question with the MessageBox procedure.
508 * 0 - Cancel operation.
509 * 1 - "Yes" was selected.
510 * 2 - "No" was selected.
513 mswin_yesno_lptstr(LPTSTR prompt
)
521 ret
= MessageBox (ghTTYWnd
, prompt
, gszAppName
,
522 MB_APPLMODAL
| MB_ICONQUESTION
| MB_YESNOCANCEL
);
525 case IDYES
: ret
= 1; break;
526 case IDNO
: ret
= 2; break;
528 case IDCANCEL
: ret
= 0; break;
534 /*----------------------------------------------------------------------
537 Generic selection routine. Display a prompt and a set of buttons for
538 each possible answer.
543 prompt -- The string to prompt with.
544 button_list -- pointer to array of mDlgButton's. input chars
545 matching those in list return value from
546 mlist. Nearly identical to Pine's ESCKEY
548 dflt -- Value returned when "Enter" is pressed.
549 on_ctrl_C -- Value returned to cancel dialog (ESC).
550 help -- Arrary of strings for help text in bottom screen
555 dflt -- Default option selected.
556 on_ctrl_C -- Calcel operation.
557 or one of the other return values defined in button_list.
560 Note: To prcess keyboard in put we use a custom dialog control
561 which is invisible but always has the input focus.
563 ----------------------------------------------------------------------*/
566 mswin_select(char *utf8prompt
, MDlgButton
*button_list
, int dflt
, int on_ctrl_C
,
567 char **help
, unsigned flags
)
577 promptlpt
= utf8_to_lptstr(utf8prompt
);
580 * Setup dialog config structure.
582 gOEInfo
.prompt
= promptlpt
;
583 gOEInfo
.string
= NULL
;
587 gOEInfo
.helptext
= help
;
588 gOEInfo
.helpkey
= 'g';
590 gOEInfo
.cancel
= on_ctrl_C
;
591 gOEInfo
.flags
= flags
;
592 gOEInfo
.button_list
= button_list
;
598 for(c
= 0; button_list
&& button_list
[c
].ch
!= -1; ++c
)
601 gOEInfo
.button_count
= c
;
604 * Register the class for the user control which will receive keyboard
607 kbcProc
= (WNDPROC
) MakeProcInstance((FARPROC
) KBCProc
, ghInstance
);
609 wndclass
.lpfnWndProc
= kbcProc
;
610 wndclass
.cbClsExtra
= 0;
611 wndclass
.cbWndExtra
= 0;
612 wndclass
.hInstance
= ghInstance
;
613 wndclass
.hIcon
= NULL
;
614 wndclass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
615 wndclass
.hbrBackground
= 0;
616 wndclass
.lpszMenuName
= NULL
;
617 wndclass
.lpszClassName
= TEXT("KeyboardCapture");
619 if(RegisterClass (&wndclass
) == 0){
621 * There is no good return value to indicate an error.
622 * Cancel the operation.
628 * Make other procedure instances.
630 dlgprc
= (DLGPROC
) MakeProcInstance((FARPROC
) mswin_select_proc
, ghInstance
);
631 gpBtnProc
= (WNDPROC
) MakeProcInstance((FARPROC
) ButtonProc
, ghInstance
);
634 * Bring up the dialog box.
636 DialogBox(ghInstance
, MAKEINTRESOURCE(IDD_SELECT
), ghTTYWnd
, dlgprc
);
639 * Free the proc instances and window class.
641 FreeProcInstance((FARPROC
) dlgprc
);
642 FreeProcInstance((FARPROC
) gpBtnProc
);
643 UnregisterClass (TEXT("KeyboardCapture"), ghInstance
);
644 FreeProcInstance((FARPROC
) kbcProc
);
647 fs_give((void **) &promptlpt
);
649 return(gOEInfo
.result
);
656 * Dialog procedure for the button selection dialog box.
658 BOOL CALLBACK __export
659 mswin_select_proc (HWND hDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
664 MDlgButton built_in
[3];
666 if (mswin_debug
>= 1)
667 fprintf (mswin_debugfile
, "Select: uMsg x%x (%d), wParam x%x, lParam x%lx\n",
668 uMsg
, uMsg
, wParam
, lParam
);
676 SetDlgItemText(hDlg
, IDC_PROMPT
, gOEInfo
.prompt
);
679 * Set focus to the invisible custom control
681 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
684 * Subclass the standard buttons and build buttons for each item
685 * in the button_list.
687 gpOldBtnProc
= (WNDPROC
) GetWindowLong (GetDlgItem (hDlg
, IDCANCEL
), GWL_WNDPROC
);
688 SetWindowLong (GetDlgItem (hDlg
, IDC_GETHELP
), GWL_WNDPROC
,
689 (DWORD
)(FARPROC
)gpBtnProc
);
690 SetWindowLong (GetDlgItem (hDlg
, IDCANCEL
), GWL_WNDPROC
,
691 (DWORD
)(FARPROC
)gpBtnProc
);
693 memset (&built_in
, 0, sizeof (built_in
));
694 built_in
[0].id
= IDCANCEL
;
695 if (gOEInfo
.helptext
!= NULL
) {
696 built_in
[1].id
= IDC_GETHELP
;
700 DestroyWindow (GetDlgItem (hDlg
, IDC_GETHELP
));
704 BuildButtonList (hDlg
, built_in
, biCount
, gOEInfo
.button_list
);
705 gDoHelpFirst
= FALSE
;
711 * Keep focus on the custom control item so key strokes are always
714 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
721 gOEInfo
.result
= gOEInfo
.dflt
;
722 EndDialog (hDlg
, gOEInfo
.result
);
727 gOEInfo
.result
= gOEInfo
.cancel
;
728 EndDialog (hDlg
, gOEInfo
.result
);
734 * Get help. If we have help text display it. If not,
735 * return value 3, which tells the caller to provide us
738 if (gOEInfo
.helptext
!= NULL
) {
739 mswin_showhelpmsg ((WINHAND
) hDlg
, gOEInfo
.helptext
);
745 if ( wParam
>= BTN_FIRSTID
&&
746 wParam
< BTN_FIRSTID
+ (WPARAM
) gOEInfo
.button_count
) {
747 i
= wParam
- BTN_FIRSTID
;
748 gOEInfo
.result
= gOEInfo
.button_list
[i
].rval
;
749 EndDialog (hDlg
, gOEInfo
.result
);
761 * Window procedure for the hidden custom control.
763 LONG FAR PASCAL __export
764 KBCProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
769 if (uMsg
== WM_GETDLGCODE
) {
771 * Tell windows that we want all the character messages.
773 ret
= DefWindowProc (hWnd
, uMsg
, wParam
, lParam
);
774 ret
|= DLGC_WANTALLKEYS
;
779 if (uMsg
== WM_CHAR
) {
781 * See if the character typed is a shortcut for any of the
784 if (ProcessChar (GetParent (hWnd
), wParam
, &gOEInfo
, &ret
))
787 /* Fall through for default processing. */
790 return (DefWindowProc (hWnd
, uMsg
, wParam
, lParam
));
799 * Check if character activates any button. If it does, send WM_COMMAND
803 * hWnd - Window to send message to.
804 * wParam - character typed.
805 * oeinfo - dialog config structure. Contains button list.
806 * ret - value to return to windows.
809 * TRUE - Found a match. Exit from Window Procedure returning
812 * FALSE - No match. Continue with default processing of character
817 ProcessChar (HWND hWnd
, WPARAM wParam
, OEInfo
*oeinfo
, long *ret
)
824 if (wParam
== 0x0d) {
826 * "Enter" is same as clicking on OK button.
828 PostMessage (hWnd
, WM_COMMAND
, IDOK
,
829 MAKELONG (GetDlgItem (hWnd
, IDOK
), 1));
832 if (wParam
== 0x1b || wParam
== 0x03) {
834 * Esc is same as clicking on Cancel button.
836 PostMessage (hWnd
, WM_COMMAND
, IDCANCEL
,
837 MAKELONG (GetDlgItem (hWnd
, IDCANCEL
), 1));
842 * Any of the custom buttons respond to this key?
844 for (i
= 0; i
< oeinfo
->button_count
; ++i
) {
845 if (wParam
== oeinfo
->button_list
[i
].ch
) {
846 id
= oeinfo
->button_list
[i
].id
;
847 PostMessage (hWnd
, WM_COMMAND
, id
,
848 MAKELONG (GetDlgItem (hWnd
, id
), 1));
854 * Lastly, is it the help key?
856 if (oeinfo
->helpkey
!= 0 && wParam
== oeinfo
->helpkey
) {
858 PostMessage (hWnd
, WM_COMMAND
, id
,
859 MAKELONG (GetDlgItem (hWnd
, id
), 1));
865 * Nothing we understand.
875 * Get a button position in the parent's coordinate space.
878 GetBtnPos (HWND hPrnt
, HWND hWnd
, RECT
*r
)
880 GetWindowRect (hWnd
, r
);
881 ScreenToClient (hPrnt
, (POINT
*) r
);
882 ScreenToClient (hPrnt
, (POINT
*) &r
->right
);
889 * Add buttons to the dialog box.
892 BuildButtonList(HWND hDlg
, MDlgButton
*built_in
, int biCount
, MDlgButton
*button_list
)
894 RECT rDlg
, rb1
, rb2
, r
;
896 MDlgButton
*pB
; /* pointer to button struct*/
897 HWND hBtn
, hBtn1
, hBtn2
; /* handle to buttons */
898 int btnCount
; /* extra button count */
899 int rows
, cols
; /* button rows and columns */
900 int bpos
; /* button position */
902 int maxstrIdx
, maxstrLen
; /* button w/ longest caption*/
903 DWORD textExtent
; /* width of button caption */
904 int margine
; /* left and right margines */
905 int btop
, bleft
; /* button position */
906 int bwidth
, bheight
, w
; /* button size */
907 int bMinWidth
; /* minimum buttonwidth */
908 int bvertSpace
, bhorzSpace
; /* button spacing */
909 int newWHeight
, delta
; /* window resizing */
916 * Are there any buttons to add?
918 if(button_list
== NULL
)
922 for(btnCount
= 0; button_list
[btnCount
].ch
!= -1; ++btnCount
){
923 if(lstrlen(button_list
[btnCount
].label
) >
924 lstrlen(button_list
[maxstrIdx
].label
))
925 maxstrIdx
= btnCount
;
933 * Get the size of the dialog box and the positions of the
934 * first and, if there is one, the second button. Calculate or
935 * default button offsets and positions.
937 GetClientRect(hDlg
, &rDlg
);
938 hBtn1
= GetDlgItem(hDlg
, built_in
[0].id
);
939 GetBtnPos(hDlg
, hBtn1
, &rb1
);
940 margine
= rb1
.left
; /* left and right margine */
941 bheight
= rb1
.bottom
- rb1
.top
; /* button width */
942 bwidth
= rb1
.right
- rb1
.left
; /* button height. */
944 hBtn2
= GetDlgItem(hDlg
, built_in
[1].id
);
945 GetBtnPos(hDlg
, hBtn2
, &rb2
);
946 bvertSpace
= rb2
.top
- rb1
.top
; /* vertical spacing */
949 bvertSpace
= bheight
+ BSPACE
; /* vertical spacing */
954 * Get the button font.
956 btnFont
= (HFONT
) SendMessage (hBtn1
, WM_GETFONT
, 0, 0);
959 * Get the screen extent of the longest button label. min width
960 * is the extent, plus the average width of 5 extra characters for
961 * key stroke, plus margine.
964 ncaption
= sizeof(caption
)/sizeof(TCHAR
);
965 _sntprintf(caption
, ncaption
, TEXT("%s '%s'"), button_list
[maxstrIdx
].label
,
966 button_list
[maxstrIdx
].name
);
968 maxstrLen
= lstrlen(caption
);
969 GetTextExtentPoint32(hdc
, caption
, maxstrLen
, &size
);
971 textExtent
= size
.cx
;
973 ReleaseDC(hBtn1
, hdc
);
974 bMinWidth
= LOWORD (textExtent
) + (2 * (LOWORD(textExtent
) / maxstrLen
));
975 if(bwidth
< bMinWidth
)
979 * Calculate button positions. If the buttons are going to extend
980 * past the right edge of the dialog box, shrink their width. But
981 * if they get narrower than the min width calculated above then
982 * increase the number of rows.
986 ++rows
; /* More rows. */
987 w
= bwidth
; /* Original button width. */
988 cols
= 1 + ((biCount
+ btnCount
) - 1) / rows
; /* Calc num cols. */
990 /* Need to srink button width? */
991 if (2 * margine
+ bwidth
* cols
+ BSPACE
* (cols
- 1) > rDlg
.right
) {
992 w
= ((rDlg
.right
- (2 * margine
)) - (BSPACE
* (cols
-1))) / cols
;
994 /* Did buttons get too narrow? */
995 } while (w
< bMinWidth
&& cols
> 1);
998 bhorzSpace
= bwidth
+ BSPACE
; /* horizontal spacing */
1004 newWHeight
= rb1
.top
+ (rows
* bvertSpace
);
1005 delta
= newWHeight
- rDlg
.bottom
;
1007 GetWindowRect (hDlg
, &r
);
1008 MoveWindow (hDlg
, r
.left
, r
.top
, r
.right
- r
.left
,
1009 (r
.bottom
- r
.top
) + delta
, FALSE
);
1015 * Create new buttons.
1017 for(bpos
= 0; bpos
< biCount
+ btnCount
; ++bpos
) {
1019 * Calculate position for this button.
1021 btop
= rb1
.top
+ (bpos
% rows
) * bvertSpace
;
1022 bleft
= rb1
.left
+ (bpos
/ rows
) * bhorzSpace
;
1026 * Resize existing buttons.
1028 MoveWindow(GetDlgItem(hDlg
, built_in
[bpos
].id
),
1029 bleft
, btop
, bwidth
, bheight
, FALSE
);
1033 pB
= &button_list
[i
];
1035 _sntprintf(caption
, ncaption
, TEXT("%s '%s'"), pB
->label
, pB
->name
);
1036 hBtn
= CreateWindow(TEXT("BUTTON"), caption
,
1037 WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
,
1038 bleft
, btop
, bwidth
, bheight
,
1039 hDlg
, NULL
, ghInstance
, NULL
);
1041 pB
->id
= BTN_FIRSTID
+ i
;
1042 SetWindowLong(hBtn
, GWL_ID
, pB
->id
);
1043 SendMessage(hBtn
, WM_SETFONT
, (WPARAM
)btnFont
, MAKELPARAM (0, 0));
1045 /* Subclass button. */
1046 SetWindowLong(hBtn
, GWL_WNDPROC
, (DWORD
)(FARPROC
)gpBtnProc
);
1047 EnableWindow(hBtn
, TRUE
);