2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 /*---------------------------------------------------------------------------
20 * Networks and Distributed Computing
21 * Computing and Communications
22 * University of Washington
23 * Administration Builiding, AG-44
24 * Seattle, Washington, 98195, USA
25 * Internet: tunger@cac.washington.edu
28 * Pine and Pico are registered trademarks of the University of Washington.
29 * No commercial use of these trademarks may be made without prior written
30 * permission of the University of Washington.
32 * Pine, Pico, and Pilot software and its included text are Copyright
33 * 1989-1998 by the University of Washington.
35 * The full text of our legal notices is contained in the file called
36 * CPYRIGHT, included with this distribution.
38 *--------------------------------------------------------------------------*/
53 #include "../estruct.h"
56 #include "../keydefs.h"
59 #include "../utf8stub.h"
60 #include "../../pith/charconv/filesys.h"
64 extern HINSTANCE ghInstance
;
65 extern BOOL gfUseDialogs
;
66 extern FILE *mswin_debugfile
;
67 extern int mswin_debug
;
68 extern TCHAR gszAppName
[45];
72 #define BTN_FIRSTID 200
74 #define BWIDTH_MIN 120
78 LPTSTR prompt
; /* Prompt. */
79 LPTSTR string
; /* Resulting string. */
80 int strlen
; /* Length of buffer. */
81 int append
; /* Append to existing string. */
82 int passwd
; /* Passwd, don't echo (1 use asterisk, 10 space). */
83 unsigned flags
; /* other flags. */
86 int button_count
; /* Number of additional buttons. */
87 MDlgButton
*button_list
; /* List of other buttons. */
88 char **helptext
; /* Help text. */
94 static OEInfo gOEInfo
;
95 static BOOL gDoHelpFirst
;
96 static WNDPROC gpOldEditProc
; /* Old Edit window proc. */
97 static WNDPROC gpEditProc
;
98 static WNDPROC gpOldBtnProc
; /* Old Edit window proc. */
99 static WNDPROC gpBtnProc
;
105 * Forward function declaratins.
107 LONG FAR PASCAL __export
EditProc(HWND hBtn
, UINT msg
, WPARAM wParam
,
109 LONG FAR PASCAL __export
ButtonProc(HWND hBtn
, UINT msg
, WPARAM wParam
,
111 BOOL CALLBACK __export
mswin_dialog_proc (HWND hDlg
, UINT uMsg
,
112 WPARAM wParam
, LPARAM lParam
);
113 BOOL CALLBACK __export
mswin_select_proc (HWND hDlg
, UINT uMsg
,
114 WPARAM wParam
, LPARAM lParam
);
115 LONG FAR PASCAL __export
KBCProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
,
119 static void BuildButtonList (HWND
, MDlgButton
*, int, MDlgButton
*);
120 static BOOL
ProcessChar (HWND
, WPARAM
, OEInfo
*, long *);
121 static void GetBtnPos (HWND
, HWND
, RECT
*);
123 int mswin_yesno_lptstr (LPTSTR
);
127 mswin_usedialog (void)
129 return (gfUseDialogs
);
134 /*----------------------------------------------------------------------
137 Generic text entry. Prompt user for a string.
141 prompt -- The string to prompt with
142 string -- the buffer result is returned in, and original string (if
144 field_len -- Maximum length of string to accept
145 append_current -- flag indicating string should not be truncated before
147 passwd -- a pass word is being fetch. Don't echo on screen
148 button_list -- pointer to array of mDlgButton's. input chars matching
149 those in list return value from list. Nearly identical
150 to Pine's ESCKEY structure.
151 help -- Array of strings for help text in bottom screen lines
154 Result: editing input string
155 returns -1 unexpected errors
156 returns 0 typed CR or pressed "OK"
157 returns 1 typed ESC or pressed "Cancel"
158 returns 3 typed ^G or PF1 (help)
159 returns 4 typed ^L for a screen redraw
160 or one of the other return values defined in button_list.
162 WARNING: Care is required with regard to the escape_list processing.
163 The passed array is terminated with an entry that has ch = -1.
164 Function key labels and key strokes need to be setup externally!
165 Traditionally, a return value of 2 is used for ^T escapes.
168 Note About Help: We don't get the help text on the first call. If we
169 want help text we have to return 3. We'll get called again
170 with help text. To make it look good, we want to display
171 this the second time we're called. But we don't want to
172 display the help text every time we're called with help
173 text. To know the difference we set gDoHelpFirst when
174 exiting to request help text. If this is set then we
175 display help. If not, then no help.
178 ----------------------------------------------------------------------*/
182 * xxx implement flags.
183 * xxx display.d uses flags QFFILE, QDEFLT, and QBOBUF
187 mswin_dialog(UCS
*prompt
, UCS
*buf
, int nbuf
, int append_current
,
188 int passwd
, MDlgButton
*button_list
, char **help
, unsigned flags
)
192 LPTSTR promptlpt
, buflpt
, b
;
197 promptlpt
= ucs4_to_lptstr(prompt
);
198 buflpt
= (LPTSTR
) fs_get(nbuf
* sizeof(TCHAR
));
199 b
= ucs4_to_lptstr(buf
);
203 for(i
= 0; i
< nbuf
&& b
[i
]; i
++)
210 fs_give((void **) &b
);
213 gOEInfo
.prompt
= promptlpt
;
214 gOEInfo
.string
= buflpt
;
215 gOEInfo
.strlen
= nbuf
;
216 gOEInfo
.append
= append_current
;
217 gOEInfo
.passwd
= passwd
;
218 gOEInfo
.helptext
= help
;
219 gOEInfo
.helpkey
= 0x07; /* ^G */
220 gOEInfo
.flags
= flags
;
221 gOEInfo
.button_list
= button_list
;
224 for (c
= 0; button_list
&& button_list
[c
].ch
!= -1; ++c
)
227 gOEInfo
.button_count
= c
;
229 gpEditProc
= (WNDPROC
) MakeProcInstance((FARPROC
) EditProc
, ghInstance
);
230 gpBtnProc
= (WNDPROC
) MakeProcInstance((FARPROC
) ButtonProc
, ghInstance
);
231 dlgprc
= (DLGPROC
) MakeProcInstance((FARPROC
) mswin_dialog_proc
, ghInstance
);
233 DialogBox(ghInstance
, MAKEINTRESOURCE (IDD_OPTIONALYENTER
), ghTTYWnd
, dlgprc
);
235 FreeProcInstance((FARPROC
) dlgprc
);
236 FreeProcInstance((FARPROC
) gpBtnProc
);
237 FreeProcInstance((FARPROC
) gpEditProc
);
240 fs_give((void **) &promptlpt
);
242 ucs
= lptstr_to_ucs4(buflpt
);
246 for(i
= 0; i
< nbuf
&& ucs
[i
]; i
++)
253 fs_give((void **) &ucs
);
256 return(gOEInfo
.result
);
263 * Dialog procedure for the generic text entry dialog box.
265 BOOL CALLBACK __export
266 mswin_dialog_proc (HWND hDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
272 MDlgButton built_in
[3];
279 * Set the prompt text.
281 SetDlgItemText(hDlg
, IDC_PROMPT
, gOEInfo
.prompt
);
284 * Set the initial edit text and configure the edit control
287 *gOEInfo
.string
= '\0';
289 SetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
);
291 SendDlgItemMessage (hDlg
, IDC_RESPONCE
, EM_SETPASSWORDCHAR
,
292 (gOEInfo
.passwd
== 1) ? '*' : gOEInfo
.passwd
? ' ' : 0, 0L);
293 SendDlgItemMessage (hDlg
, IDC_RESPONCE
, EM_LIMITTEXT
,
294 gOEInfo
.strlen
- 1, 0L);
295 l
= (long) lstrlen(gOEInfo
.string
);
296 SendDlgItemMessage(hDlg
, IDC_RESPONCE
, EM_SETSEL
, 0, l
);
297 hEdit
= GetDlgItem (hDlg
, IDC_RESPONCE
);
299 gpOldEditProc
= (WNDPROC
) GetWindowLong (hEdit
, GWL_WNDPROC
);
300 SetWindowLong (hEdit
, GWL_WNDPROC
, (DWORD
)(FARPROC
)gpEditProc
);
304 * Subclass the standard buttons and build buttons for each item
305 * in the button_list.
307 gpOldBtnProc
= (WNDPROC
) GetWindowLong (GetDlgItem (hDlg
, IDOK
), GWL_WNDPROC
);
308 SetWindowLong (GetDlgItem (hDlg
, IDOK
), GWL_WNDPROC
,
309 (DWORD
)(FARPROC
)gpBtnProc
);
310 SetWindowLong (GetDlgItem (hDlg
, IDCANCEL
), GWL_WNDPROC
,
311 (DWORD
)(FARPROC
)gpBtnProc
);
313 memset (&built_in
, 0, sizeof (built_in
));
314 built_in
[0].id
= IDOK
;
315 built_in
[1].id
= IDCANCEL
;
317 built_in
[2].id
= IDC_GETHELP
;
321 DestroyWindow (GetDlgItem (hDlg
, IDC_GETHELP
));
324 BuildButtonList (hDlg
, built_in
, biCount
, gOEInfo
.button_list
);
327 if (gOEInfo
.helptext
&& gDoHelpFirst
) {
328 mswin_showhelpmsg ((WINHAND
)hDlg
, gOEInfo
.helptext
);
329 gDoHelpFirst
= FALSE
;
336 * Keep focus on the edit item so key strokes are always
339 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
347 * Normal exit. Accept the new text.
349 GetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
, gOEInfo
.strlen
);
352 EndDialog (hDlg
, gOEInfo
.result
);
358 * Cancel operation. Don't retrieve new text.
361 EndDialog (hDlg
, gOEInfo
.result
);
367 * Get help. If we have help text display it. If not,
368 * return value 3, which tells the caller to provide us
371 if (gOEInfo
.helptext
!= NULL
) {
372 mswin_showhelpmsg ((WINHAND
)hDlg
, gOEInfo
.helptext
);
375 GetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
, gOEInfo
.strlen
);
378 EndDialog (hDlg
, gOEInfo
.result
);
385 * Search button list for button with this ID. If found
386 * return it's result code. Retrieve text.
388 if ( wParam
>= BTN_FIRSTID
&&
389 wParam
< BTN_FIRSTID
+ (WPARAM
) gOEInfo
.button_count
) {
390 GetDlgItemText(hDlg
, IDC_RESPONCE
, gOEInfo
.string
, gOEInfo
.strlen
);
391 i
= wParam
- BTN_FIRSTID
;
392 gOEInfo
.result
= gOEInfo
.button_list
[i
].rval
;
393 EndDialog (hDlg
, gOEInfo
.result
);
406 * Subclassed window procedure for Edit control on generic text
409 LONG FAR PASCAL __export
410 EditProc (HWND hEdit
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
415 hDlg
= GetParent (hEdit
);
417 if (msg
== WM_GETDLGCODE
) {
419 * Tell windows that we want to receive ALL keystrokes.
421 ret
= CallWindowProc (gpOldEditProc
, hEdit
, msg
, wParam
, lParam
);
422 ret
|= DLGC_WANTALLKEYS
;
427 if (msg
== WM_CHAR
) {
429 * See if the character typed is a shortcut for any of the
432 if (ProcessChar (hDlg
, wParam
, &gOEInfo
, &ret
))
435 /* No... Fall through for default processing. */
438 return (CallWindowProc (gpOldEditProc
, hEdit
, msg
, wParam
, lParam
));
445 * Subclass button windows.
447 * These buttons will automatically return the input focus to
448 * a control with id IDC_RESPONCE.
450 LONG FAR PASCAL __export
451 ButtonProc (HWND hBtn
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
457 if (uMsg
== WM_LBUTTONUP
|| uMsg
== WM_MBUTTONUP
|| uMsg
== WM_RBUTTONUP
) {
459 * On mouse button up restore input focus to IDC_RESPONCE, which
460 * processes keyboard input.
462 ret
= CallWindowProc (gpOldBtnProc
, hBtn
, uMsg
, wParam
, lParam
);
463 hDlg
= GetParent (hBtn
);
464 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
468 return (CallWindowProc (gpOldBtnProc
, hBtn
, uMsg
, wParam
, lParam
));
474 mswin_yesno(UCS
*prompt_ucs4
)
477 LPTSTR prompt_lptstr
;
479 prompt_lptstr
= ucs4_to_lptstr(prompt_ucs4
);
480 ret
= mswin_yesno_lptstr(prompt_lptstr
);
481 fs_give((void **) &prompt_lptstr
);
488 mswin_yesno_utf8(char *prompt_utf8
)
491 LPTSTR prompt_lptstr
;
493 prompt_lptstr
= utf8_to_lptstr(prompt_utf8
);
494 ret
= mswin_yesno_lptstr(prompt_lptstr
);
495 fs_give((void **) &prompt_lptstr
);
501 * Ask a yes/no question with the MessageBox procedure.
504 * 0 - Cancel operation.
505 * 1 - "Yes" was selected.
506 * 2 - "No" was selected.
509 mswin_yesno_lptstr(LPTSTR prompt
)
517 ret
= MessageBox (ghTTYWnd
, prompt
, gszAppName
,
518 MB_APPLMODAL
| MB_ICONQUESTION
| MB_YESNOCANCEL
);
521 case IDYES
: ret
= 1; break;
522 case IDNO
: ret
= 2; break;
524 case IDCANCEL
: ret
= 0; break;
530 /*----------------------------------------------------------------------
533 Generic selection routine. Display a prompt and a set of buttons for
534 each possible answer.
539 prompt -- The string to prompt with.
540 button_list -- pointer to array of mDlgButton's. input chars
541 matching those in list return value from
542 mlist. Nearly identical to Pine's ESCKEY
544 dflt -- Value returned when "Enter" is pressed.
545 on_ctrl_C -- Value returned to cancel dialog (ESC).
546 help -- Array of strings for help text in bottom screen
551 dflt -- Default option selected.
552 on_ctrl_C -- Calcel operation.
553 or one of the other return values defined in button_list.
556 Note: To process keyboard input we use a custom dialog control
557 which is invisible but always has the input focus.
559 ----------------------------------------------------------------------*/
562 mswin_select(char *utf8prompt
, MDlgButton
*button_list
, int dflt
, int on_ctrl_C
,
563 char **help
, unsigned flags
)
573 promptlpt
= utf8_to_lptstr(utf8prompt
);
576 * Setup dialog config structure.
578 gOEInfo
.prompt
= promptlpt
;
579 gOEInfo
.string
= NULL
;
583 gOEInfo
.helptext
= help
;
584 gOEInfo
.helpkey
= 'g';
586 gOEInfo
.cancel
= on_ctrl_C
;
587 gOEInfo
.flags
= flags
;
588 gOEInfo
.button_list
= button_list
;
594 for(c
= 0; button_list
&& button_list
[c
].ch
!= -1; ++c
)
597 gOEInfo
.button_count
= c
;
600 * Register the class for the user control which will receive keyboard
603 kbcProc
= (WNDPROC
) MakeProcInstance((FARPROC
) KBCProc
, ghInstance
);
605 wndclass
.lpfnWndProc
= kbcProc
;
606 wndclass
.cbClsExtra
= 0;
607 wndclass
.cbWndExtra
= 0;
608 wndclass
.hInstance
= ghInstance
;
609 wndclass
.hIcon
= NULL
;
610 wndclass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
611 wndclass
.hbrBackground
= 0;
612 wndclass
.lpszMenuName
= NULL
;
613 wndclass
.lpszClassName
= TEXT("KeyboardCapture");
615 if(RegisterClass (&wndclass
) == 0){
617 * There is no good return value to indicate an error.
618 * Cancel the operation.
624 * Make other procedure instances.
626 dlgprc
= (DLGPROC
) MakeProcInstance((FARPROC
) mswin_select_proc
, ghInstance
);
627 gpBtnProc
= (WNDPROC
) MakeProcInstance((FARPROC
) ButtonProc
, ghInstance
);
630 * Bring up the dialog box.
632 DialogBox(ghInstance
, MAKEINTRESOURCE(IDD_SELECT
), ghTTYWnd
, dlgprc
);
635 * Free the proc instances and window class.
637 FreeProcInstance((FARPROC
) dlgprc
);
638 FreeProcInstance((FARPROC
) gpBtnProc
);
639 UnregisterClass (TEXT("KeyboardCapture"), ghInstance
);
640 FreeProcInstance((FARPROC
) kbcProc
);
643 fs_give((void **) &promptlpt
);
645 return(gOEInfo
.result
);
652 * Dialog procedure for the button selection dialog box.
654 BOOL CALLBACK __export
655 mswin_select_proc (HWND hDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
660 MDlgButton built_in
[3];
662 if (mswin_debug
>= 1)
663 fprintf (mswin_debugfile
, "Select: uMsg x%x (%d), wParam x%x, lParam x%lx\n",
664 uMsg
, uMsg
, wParam
, lParam
);
672 SetDlgItemText(hDlg
, IDC_PROMPT
, gOEInfo
.prompt
);
675 * Set focus to the invisible custom control
677 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
680 * Subclass the standard buttons and build buttons for each item
681 * in the button_list.
683 gpOldBtnProc
= (WNDPROC
) GetWindowLong (GetDlgItem (hDlg
, IDCANCEL
), GWL_WNDPROC
);
684 SetWindowLong (GetDlgItem (hDlg
, IDC_GETHELP
), GWL_WNDPROC
,
685 (DWORD
)(FARPROC
)gpBtnProc
);
686 SetWindowLong (GetDlgItem (hDlg
, IDCANCEL
), GWL_WNDPROC
,
687 (DWORD
)(FARPROC
)gpBtnProc
);
689 memset (&built_in
, 0, sizeof (built_in
));
690 built_in
[0].id
= IDCANCEL
;
691 if (gOEInfo
.helptext
!= NULL
) {
692 built_in
[1].id
= IDC_GETHELP
;
696 DestroyWindow (GetDlgItem (hDlg
, IDC_GETHELP
));
700 BuildButtonList (hDlg
, built_in
, biCount
, gOEInfo
.button_list
);
701 gDoHelpFirst
= FALSE
;
707 * Keep focus on the custom control item so key strokes are always
710 SetFocus (GetDlgItem (hDlg
, IDC_RESPONCE
));
717 gOEInfo
.result
= gOEInfo
.dflt
;
718 EndDialog (hDlg
, gOEInfo
.result
);
723 gOEInfo
.result
= gOEInfo
.cancel
;
724 EndDialog (hDlg
, gOEInfo
.result
);
730 * Get help. If we have help text display it. If not,
731 * return value 3, which tells the caller to provide us
734 if (gOEInfo
.helptext
!= NULL
) {
735 mswin_showhelpmsg ((WINHAND
) hDlg
, gOEInfo
.helptext
);
741 if ( wParam
>= BTN_FIRSTID
&&
742 wParam
< BTN_FIRSTID
+ (WPARAM
) gOEInfo
.button_count
) {
743 i
= wParam
- BTN_FIRSTID
;
744 gOEInfo
.result
= gOEInfo
.button_list
[i
].rval
;
745 EndDialog (hDlg
, gOEInfo
.result
);
757 * Window procedure for the hidden custom control.
759 LONG FAR PASCAL __export
760 KBCProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
765 if (uMsg
== WM_GETDLGCODE
) {
767 * Tell windows that we want all the character messages.
769 ret
= DefWindowProc (hWnd
, uMsg
, wParam
, lParam
);
770 ret
|= DLGC_WANTALLKEYS
;
775 if (uMsg
== WM_CHAR
) {
777 * See if the character typed is a shortcut for any of the
780 if (ProcessChar (GetParent (hWnd
), wParam
, &gOEInfo
, &ret
))
783 /* Fall through for default processing. */
786 return (DefWindowProc (hWnd
, uMsg
, wParam
, lParam
));
795 * Check if character activates any button. If it does, send WM_COMMAND
799 * hWnd - Window to send message to.
800 * wParam - character typed.
801 * oeinfo - dialog config structure. Contains button list.
802 * ret - value to return to windows.
805 * TRUE - Found a match. Exit from Window Procedure returning
808 * FALSE - No match. Continue with default processing of character
813 ProcessChar (HWND hWnd
, WPARAM wParam
, OEInfo
*oeinfo
, long *ret
)
820 if (wParam
== 0x0d) {
822 * "Enter" is same as clicking on OK button.
824 PostMessage (hWnd
, WM_COMMAND
, IDOK
,
825 MAKELONG (GetDlgItem (hWnd
, IDOK
), 1));
828 if (wParam
== 0x1b || wParam
== 0x03) {
830 * Esc is same as clicking on Cancel button.
832 PostMessage (hWnd
, WM_COMMAND
, IDCANCEL
,
833 MAKELONG (GetDlgItem (hWnd
, IDCANCEL
), 1));
838 * Any of the custom buttons respond to this key?
840 for (i
= 0; i
< oeinfo
->button_count
; ++i
) {
841 if (wParam
== oeinfo
->button_list
[i
].ch
) {
842 id
= oeinfo
->button_list
[i
].id
;
843 PostMessage (hWnd
, WM_COMMAND
, id
,
844 MAKELONG (GetDlgItem (hWnd
, id
), 1));
850 * Lastly, is it the help key?
852 if (oeinfo
->helpkey
!= 0 && wParam
== oeinfo
->helpkey
) {
854 PostMessage (hWnd
, WM_COMMAND
, id
,
855 MAKELONG (GetDlgItem (hWnd
, id
), 1));
861 * Nothing we understand.
871 * Get a button position in the parent's coordinate space.
874 GetBtnPos (HWND hPrnt
, HWND hWnd
, RECT
*r
)
876 GetWindowRect (hWnd
, r
);
877 ScreenToClient (hPrnt
, (POINT
*) r
);
878 ScreenToClient (hPrnt
, (POINT
*) &r
->right
);
885 * Add buttons to the dialog box.
888 BuildButtonList(HWND hDlg
, MDlgButton
*built_in
, int biCount
, MDlgButton
*button_list
)
890 RECT rDlg
, rb1
, rb2
, r
;
892 MDlgButton
*pB
; /* pointer to button struct*/
893 HWND hBtn
, hBtn1
, hBtn2
; /* handle to buttons */
894 int btnCount
; /* extra button count */
895 int rows
, cols
; /* button rows and columns */
896 int bpos
; /* button position */
898 int maxstrIdx
, maxstrLen
; /* button w/ longest caption*/
899 DWORD textExtent
; /* width of button caption */
900 int margine
; /* left and right margines */
901 int btop
, bleft
; /* button position */
902 int bwidth
, bheight
, w
; /* button size */
903 int bMinWidth
; /* minimum buttonwidth */
904 int bvertSpace
, bhorzSpace
; /* button spacing */
905 int newWHeight
, delta
; /* window resizing */
912 * Are there any buttons to add?
914 if(button_list
== NULL
)
918 for(btnCount
= 0; button_list
[btnCount
].ch
!= -1; ++btnCount
){
919 if(lstrlen(button_list
[btnCount
].label
) >
920 lstrlen(button_list
[maxstrIdx
].label
))
921 maxstrIdx
= btnCount
;
929 * Get the size of the dialog box and the positions of the
930 * first and, if there is one, the second button. Calculate or
931 * default button offsets and positions.
933 GetClientRect(hDlg
, &rDlg
);
934 hBtn1
= GetDlgItem(hDlg
, built_in
[0].id
);
935 GetBtnPos(hDlg
, hBtn1
, &rb1
);
936 margine
= rb1
.left
; /* left and right margine */
937 bheight
= rb1
.bottom
- rb1
.top
; /* button width */
938 bwidth
= rb1
.right
- rb1
.left
; /* button height. */
940 hBtn2
= GetDlgItem(hDlg
, built_in
[1].id
);
941 GetBtnPos(hDlg
, hBtn2
, &rb2
);
942 bvertSpace
= rb2
.top
- rb1
.top
; /* vertical spacing */
945 bvertSpace
= bheight
+ BSPACE
; /* vertical spacing */
950 * Get the button font.
952 btnFont
= (HFONT
) SendMessage (hBtn1
, WM_GETFONT
, 0, 0);
955 * Get the screen extent of the longest button label. min width
956 * is the extent, plus the average width of 5 extra characters for
957 * key stroke, plus margine.
960 ncaption
= sizeof(caption
)/sizeof(TCHAR
);
961 _sntprintf(caption
, ncaption
, TEXT("%s '%s'"), button_list
[maxstrIdx
].label
,
962 button_list
[maxstrIdx
].name
);
964 maxstrLen
= lstrlen(caption
);
965 GetTextExtentPoint32(hdc
, caption
, maxstrLen
, &size
);
967 textExtent
= size
.cx
;
969 ReleaseDC(hBtn1
, hdc
);
970 bMinWidth
= LOWORD (textExtent
) + (2 * (LOWORD(textExtent
) / maxstrLen
));
971 if(bwidth
< bMinWidth
)
975 * Calculate button positions. If the buttons are going to extend
976 * past the right edge of the dialog box, shrink their width. But
977 * if they get narrower than the min width calculated above then
978 * increase the number of rows.
982 ++rows
; /* More rows. */
983 w
= bwidth
; /* Original button width. */
984 cols
= 1 + ((biCount
+ btnCount
) - 1) / rows
; /* Calc num cols. */
986 /* Need to shrink button width? */
987 if (2 * margine
+ bwidth
* cols
+ BSPACE
* (cols
- 1) > rDlg
.right
) {
988 w
= ((rDlg
.right
- (2 * margine
)) - (BSPACE
* (cols
-1))) / cols
;
990 /* Did buttons get too narrow? */
991 } while (w
< bMinWidth
&& cols
> 1);
994 bhorzSpace
= bwidth
+ BSPACE
; /* horizontal spacing */
1000 newWHeight
= rb1
.top
+ (rows
* bvertSpace
);
1001 delta
= newWHeight
- rDlg
.bottom
;
1003 GetWindowRect (hDlg
, &r
);
1004 MoveWindow (hDlg
, r
.left
, r
.top
, r
.right
- r
.left
,
1005 (r
.bottom
- r
.top
) + delta
, FALSE
);
1011 * Create new buttons.
1013 for(bpos
= 0; bpos
< biCount
+ btnCount
; ++bpos
) {
1015 * Calculate position for this button.
1017 btop
= rb1
.top
+ (bpos
% rows
) * bvertSpace
;
1018 bleft
= rb1
.left
+ (bpos
/ rows
) * bhorzSpace
;
1022 * Resize existing buttons.
1024 MoveWindow(GetDlgItem(hDlg
, built_in
[bpos
].id
),
1025 bleft
, btop
, bwidth
, bheight
, FALSE
);
1029 pB
= &button_list
[i
];
1031 _sntprintf(caption
, ncaption
, TEXT("%s '%s'"), pB
->label
, pB
->name
);
1032 hBtn
= CreateWindow(TEXT("BUTTON"), caption
,
1033 WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
,
1034 bleft
, btop
, bwidth
, bheight
,
1035 hDlg
, NULL
, ghInstance
, NULL
);
1037 pB
->id
= BTN_FIRSTID
+ i
;
1038 SetWindowLong(hBtn
, GWL_ID
, pB
->id
);
1039 SendMessage(hBtn
, WM_SETFONT
, (WPARAM
)btnFont
, MAKELPARAM (0, 0));
1041 /* Subclass button. */
1042 SetWindowLong(hBtn
, GWL_WNDPROC
, (DWORD
)(FARPROC
)gpBtnProc
);
1043 EnableWindow(hBtn
, TRUE
);