blob: aa287d9d7c126e13b18c100705a985341555ccbf [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI support by Robert Webb
5 *
6 * Do ":help uganda" in Vim to read copying and usage conditions.
7 * Do ":help credits" in Vim to see a list of people who contributed.
8 * See README.txt for an overview of the Vim source code.
9 */
10/*
11 * gui_w16.c
12 *
13 * GUI support for Microsoft Windows 3.1x
14 *
15 * George V. Reilly <george@reilly.org> wrote the original Win32 GUI.
16 * Robert Webb reworked it to use the existing GUI stuff and added menu,
17 * scrollbars, etc.
18 *
19 * Vince Negri then butchered the code to get it compiling for
20 * 16-bit windows.
21 *
22 */
23
Bram Moolenaarfbe323d2012-02-04 22:01:48 +010024/* Win16 doesn't use the "W" methods. */
25#define pDispatchMessage DispatchMessage
26#define pGetMessage GetMessage
27#define pIsDialogMessage IsDialogMessage
28#define pPeekMessage PeekMessage
29
Bram Moolenaar071d4272004-06-13 20:20:40 +000030/*
31 * Include the common stuff for MS-Windows GUI.
32 */
33#include "gui_w48.c"
34
35#include "guiw16rc.h"
36
37/* Undocumented Windows Message - not even defined in some SDK headers */
38#define WM_EXITSIZEMOVE 0x0232
39
40
41#ifdef FEAT_TOOLBAR
42# define CMD_TB_BASE (99)
43# include <vimtbar.h>
44#endif
45
46#ifdef PROTO
47# define WINAPI
48#endif
49
50#define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
51 ((fn)((hwnd), (HDROP)(wParam)), 0L)
52
53
54/* Local variables: */
55
56#ifdef FEAT_MENU
57static UINT s_menu_id = 100;
58#endif
59
60
61#define VIM_NAME "vim"
62#define VIM_CLASS "Vim"
63
64#define DLG_ALLOC_SIZE 16 * 1024
65
66/*
67 * stuff for dialogs, menus, tearoffs etc.
68 */
69#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
70static BOOL CALLBACK dialog_callback(HWND, UINT, WPARAM, LPARAM);
71
72static LPWORD
73add_dialog_element(
74 LPWORD p,
75 DWORD lStyle,
76 WORD x,
77 WORD y,
78 WORD w,
79 WORD h,
80 WORD Id,
81 BYTE clss,
82 const char *caption);
83
84static int dialog_default_button = -1;
85#endif
86
87static void get_dialog_font_metrics(void);
88
89#ifdef FEAT_TOOLBAR
90static void initialise_toolbar(void);
91#endif
92
93
94#ifdef FEAT_MENU
95/*
96 * Figure out how high the menu bar is at the moment.
97 */
98 static int
99gui_mswin_get_menu_height(
100 int fix_window) /* If TRUE, resize window if menu height changed */
101{
102 static int old_menu_height = -1;
103
104 int num;
105 int menu_height;
106
107 if (gui.menu_is_active)
108 num = GetMenuItemCount(s_menuBar);
109 else
110 num = 0;
111
112 if (num == 0)
113 menu_height = 0;
114 else if (gui.starting)
115 menu_height = GetSystemMetrics(SM_CYMENU);
116 else
117 {
118 RECT r1, r2;
119 int frameht = GetSystemMetrics(SM_CYFRAME);
120 int capht = GetSystemMetrics(SM_CYCAPTION);
121
122 /* get window rect of s_hwnd
123 * get client rect of s_hwnd
124 * get cap height
125 * subtract from window rect, the sum of client height,
126 * (if not maximized)frame thickness, and caption height.
127 */
128 GetWindowRect(s_hwnd, &r1);
129 GetClientRect(s_hwnd, &r2);
130 menu_height = r1.bottom - r1.top - (r2.bottom-r2.top +
131 2 * frameht * (!IsZoomed(s_hwnd)) + capht);
132 }
133
134 if (fix_window && menu_height != old_menu_height)
135 {
136 old_menu_height = menu_height;
Bram Moolenaar2e2a2812006-03-27 20:55:21 +0000137 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138 }
139
140 return menu_height;
141}
142#endif /*FEAT_MENU*/
143
144
145/*
146 * Even though we have _DuringSizing() which makes the rubber band a valid
147 * size, we need this for when the user maximises the window.
148 * TODO: Doesn't seem to adjust the width though for some reason.
149 */
150 static BOOL
151_OnWindowPosChanging(
152 HWND hwnd,
153 LPWINDOWPOS lpwpos)
154{
155
156 if (!IsIconic(hwnd) && !(lpwpos->flags & SWP_NOSIZE))
157 {
158 gui_mswin_get_valid_dimensions(lpwpos->cx, lpwpos->cy,
159 &lpwpos->cx, &lpwpos->cy);
160 }
161 return 0;
162}
163
164
165
166
167
168 static LRESULT CALLBACK
169_WndProc(
170 HWND hwnd,
171 UINT uMsg,
172 WPARAM wParam,
173 LPARAM lParam)
174{
175 /*
176 TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
177 hwnd, uMsg, wParam, lParam);
178 */
179
180 HandleMouseHide(uMsg, lParam);
181
182 s_uMsg = uMsg;
183 s_wParam = wParam;
184 s_lParam = lParam;
185
186 switch (uMsg)
187 {
188 HANDLE_MSG(hwnd, WM_DEADCHAR, _OnDeadChar);
189 HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar);
190 /* HANDLE_MSG(hwnd, WM_ACTIVATE, _OnActivate); */
191 HANDLE_MSG(hwnd, WM_CHAR, _OnChar);
192 HANDLE_MSG(hwnd, WM_CLOSE, _OnClose);
193 /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */
194 HANDLE_MSG(hwnd, WM_DESTROY, _OnDestroy);
195 HANDLE_MSG(hwnd, WM_DROPFILES, _OnDropFiles);
196 HANDLE_MSG(hwnd, WM_HSCROLL, _OnScroll);
197 HANDLE_MSG(hwnd, WM_KILLFOCUS, _OnKillFocus);
198#ifdef FEAT_MENU
199 HANDLE_MSG(hwnd, WM_COMMAND, _OnMenu);
200#endif
201 /* HANDLE_MSG(hwnd, WM_MOVE, _OnMove); */
202 /* HANDLE_MSG(hwnd, WM_NCACTIVATE, _OnNCActivate); */
203 HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus);
204 HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
205 /* HANDLE_MSG(hwnd, WM_SYSCOMMAND, _OnSysCommand); */
206 /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN, _OnAltKey); */
207 HANDLE_MSG(hwnd, WM_VSCROLL, _OnScroll);
208 HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging);
209 HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp);
210
211 case WM_QUERYENDSESSION: /* System wants to go down. */
212 gui_shell_closed(); /* Will exit when no changed buffers. */
213 return FALSE; /* Do NOT allow system to go down. */
214
215 case WM_ENDSESSION:
216 if (wParam) /* system only really goes down when wParam is TRUE */
217 _OnEndSession();
218 break;
219
220 case WM_SYSCHAR:
221 /*
222 * if 'winaltkeys' is "no", or it's "menu" and it's not a menu
223 * shortcut key, handle like a typed ALT key, otherwise call Windows
224 * ALT key handling.
225 */
226#ifdef FEAT_MENU
227 if ( !gui.menu_is_active
228 || p_wak[0] == 'n'
229 || (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam))
230 )
231#endif
232 return HANDLE_WM_SYSCHAR((hwnd), (wParam), (lParam), (_OnSysChar));
233#ifdef FEAT_MENU
234 else
235 return MyWindowProc(hwnd, uMsg, wParam, lParam);
236#endif
237
238 case WM_SYSKEYUP:
239#ifdef FEAT_MENU
240 /* Only when menu is active, ALT key is used for that. */
241 if (gui.menu_is_active)
242 {
243 return MyWindowProc(hwnd, uMsg, wParam, lParam);
244 }
245 else
246#endif
247 return 0;
248
249#if defined(MENUHINTS) && defined(FEAT_MENU)
250 case WM_MENUSELECT:
251 if (((UINT) LOWORD(lParam)
252 & (0xffff ^ (MF_MOUSESELECT + MF_BITMAP + MF_POPUP)))
253 == MF_HILITE
254 && (State & CMDLINE) == 0)
255 {
256 UINT idButton;
257 int idx;
258 vimmenu_T *pMenu;
259
260 idButton = (UINT)LOWORD(wParam);
261 pMenu = gui_mswin_find_menu(root_menu, idButton);
262 if (pMenu)
263 {
264 idx = MENU_INDEX_TIP;
265 msg_clr_cmdline();
266 if (pMenu->strings[idx])
267 msg(pMenu->strings[idx]);
268 else
269 msg("");
270 setcursor();
271 out_flush();
272 }
273 }
274 break;
275#endif
276 case WM_NCHITTEST:
277 {
278 LRESULT result;
279 int x, y;
280 int xPos = GET_X_LPARAM(lParam);
281
282 result = MyWindowProc(hwnd, uMsg, wParam, lParam);
283 if (result == HTCLIENT)
284 {
285 gui_mch_get_winpos(&x, &y);
286 xPos -= x;
287
288 if (xPos < 48) /*<VN> TODO should use system metric?*/
289 return HTBOTTOMLEFT;
290 else
291 return HTBOTTOMRIGHT;
292 }
293 else
294 return result;
295 }
296 /* break; */
297 default:
298#ifdef MSWIN_FIND_REPLACE
299 if (uMsg == s_findrep_msg && s_findrep_msg != 0)
300 {
301 _OnFindRepl();
302 }
303#endif
304 return MyWindowProc(hwnd, uMsg, wParam, lParam);
305 }
306
307 return 1;
308}
309
310
311
312/*
313 * End of call-back routines
314 */
315
316
317/*
318 * Parse the GUI related command-line arguments. Any arguments used are
319 * deleted from argv, and *argc is decremented accordingly. This is called
320 * when vim is started, whether or not the GUI has been started.
321 */
322 void
323gui_mch_prepare(int *argc, char **argv)
324{
325 /* No special args for win16 GUI at the moment. */
326
327}
328
329/*
330 * Initialise the GUI. Create all the windows, set up all the call-backs
331 * etc.
332 */
333 int
334gui_mch_init(void)
335{
336 const char szVimWndClass[] = VIM_CLASS;
337 const char szTextAreaClass[] = "VimTextArea";
338 WNDCLASS wndclass;
339
340#ifdef WIN16_3DLOOK
341 Ctl3dRegister(s_hinst);
342 Ctl3dAutoSubclass(s_hinst);
343#endif
344
345 /* Display any pending error messages */
346 display_errors();
347
348 gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL);
349 gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL);
350#ifdef FEAT_MENU
351 gui.menu_height = 0; /* Windows takes care of this */
352#endif
353 gui.border_width = 0;
354
355 gui.currBgColor = INVALCOLOR;
356
357 s_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
358
359 if (GetClassInfo(s_hinst, szVimWndClass, &wndclass) == 0) {
360 wndclass.style = 0;
361 wndclass.lpfnWndProc = _WndProc;
362 wndclass.cbClsExtra = 0;
363 wndclass.cbWndExtra = 0;
364 wndclass.hInstance = s_hinst;
365 wndclass.hIcon = LoadIcon(wndclass.hInstance, MAKEINTRESOURCE(IDR_VIM));
366 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
367 wndclass.hbrBackground = s_brush;
368 wndclass.lpszMenuName = NULL;
369 wndclass.lpszClassName = szVimWndClass;
370
371 if ((
372#ifdef GLOBAL_IME
373 atom =
374#endif
375 RegisterClass(&wndclass)) == 0)
376 return FAIL;
377 }
378
379 s_hwnd = CreateWindow(
380 szVimWndClass, "Vim MSWindows GUI",
381 WS_OVERLAPPEDWINDOW,
382 gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x,
383 gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y,
384 100, /* Any value will do */
385 100, /* Any value will do */
386 NULL, NULL,
387 s_hinst, NULL);
388
389 if (s_hwnd == NULL)
390 return FAIL;
391
392#ifdef GLOBAL_IME
393 global_ime_init(atom, s_hwnd);
394#endif
395
396 /* Create the text area window */
397 if (GetClassInfo(s_hinst, szTextAreaClass, &wndclass) == 0) {
398 wndclass.style = CS_OWNDC;
399 wndclass.lpfnWndProc = _TextAreaWndProc;
400 wndclass.cbClsExtra = 0;
401 wndclass.cbWndExtra = 0;
402 wndclass.hInstance = s_hinst;
403 wndclass.hIcon = NULL;
404 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
405 wndclass.hbrBackground = NULL;
406 wndclass.lpszMenuName = NULL;
407 wndclass.lpszClassName = szTextAreaClass;
408
409 if (RegisterClass(&wndclass) == 0)
410 return FAIL;
411 }
412 s_textArea = CreateWindow(
413 szTextAreaClass, "Vim text area",
414 WS_CHILD | WS_VISIBLE, 0, 0,
415 100, /* Any value will do for now */
416 100, /* Any value will do for now */
417 s_hwnd, NULL,
418 s_hinst, NULL);
419
420 if (s_textArea == NULL)
421 return FAIL;
422
423#ifdef FEAT_MENU
424 s_menuBar = CreateMenu();
425#endif
426 s_hdc = GetDC(s_textArea);
427
428#ifdef MSWIN16_FASTTEXT
429 SetBkMode(s_hdc, OPAQUE);
430#endif
431
432 DragAcceptFiles(s_hwnd, TRUE);
433
434 /* Do we need to bother with this? */
435 /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */
436
437 /* Get background/foreground colors from the system */
438 gui_mch_def_colors();
439
440 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
441 * file) */
442 set_normal_colors();
443
444 /*
445 * Check that none of the colors are the same as the background color.
446 * Then store the current values as the defaults.
447 */
448 gui_check_colors();
449 gui.def_norm_pixel = gui.norm_pixel;
450 gui.def_back_pixel = gui.back_pixel;
451
452 /* Get the colors for the highlight groups (gui_check_colors() might have
453 * changed them) */
454 highlight_gui_started();
455
456 /*
457 * Start out by adding the configured border width into the border offset
458 */
459 gui.border_offset = gui.border_width;
460
461
462 /*
463 * compute a couple of metrics used for the dialogs
464 */
465 get_dialog_font_metrics();
466#ifdef FEAT_TOOLBAR
467 /*
468 * Create the toolbar
469 */
470 initialise_toolbar();
471#endif
472#ifdef MSWIN_FIND_REPLACE
473 /*
474 * Initialise the dialog box stuff
475 */
476 s_findrep_msg = RegisterWindowMessage(FINDMSGSTRING);
477
478 /* Initialise the struct */
479 s_findrep_struct.lStructSize = sizeof(s_findrep_struct);
480 s_findrep_struct.lpstrFindWhat = alloc(MSWIN_FR_BUFSIZE);
481 s_findrep_struct.lpstrFindWhat[0] = NUL;
482 s_findrep_struct.lpstrReplaceWith = alloc(MSWIN_FR_BUFSIZE);
483 s_findrep_struct.lpstrReplaceWith[0] = NUL;
484 s_findrep_struct.wFindWhatLen = MSWIN_FR_BUFSIZE;
485 s_findrep_struct.wReplaceWithLen = MSWIN_FR_BUFSIZE;
486#endif
487
488 return OK;
489}
490
491
492/*
493 * Set the size of the window to the given width and height in pixels.
494 */
495 void
496gui_mch_set_shellsize(int width, int height,
Bram Moolenaar2e2a2812006-03-27 20:55:21 +0000497 int min_width, int min_height, int base_width, int base_height,
498 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000499{
500 RECT workarea_rect;
501 int win_width, win_height;
502 int win_xpos, win_ypos;
503 WINDOWPLACEMENT wndpl;
504
505 /* try to keep window completely on screen */
506 /* get size of the screen work area - use SM_CYFULLSCREEN
507 * instead of SM_CYSCREEN so that we don't overlap the
508 * taskbar if someone fires us up on Win95/NT */
509 workarea_rect.left = 0;
510 workarea_rect.top = 0;
511 workarea_rect.right = GetSystemMetrics(SM_CXSCREEN);
512 workarea_rect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
513
514 /* get current posision of our window */
515 wndpl.length = sizeof(WINDOWPLACEMENT);
516 GetWindowPlacement(s_hwnd, &wndpl);
517 if (wndpl.showCmd == SW_SHOWNORMAL)
518 {
519 win_xpos = wndpl.rcNormalPosition.left;
520 win_ypos = wndpl.rcNormalPosition.top;
521 }
522 else
523 {
524 win_xpos = workarea_rect.left;
525 win_ypos = workarea_rect.top;
526 }
527
528 /* compute the size of the outside of the window */
529 win_width = width + GetSystemMetrics(SM_CXFRAME) * 2;
530 win_height = height + GetSystemMetrics(SM_CYFRAME) * 2
531 + GetSystemMetrics(SM_CYCAPTION)
532#ifdef FEAT_MENU
533 + gui_mswin_get_menu_height(FALSE)
534#endif
535 ;
536
537 /* if the window is going off the screen, move it on to the screen */
Bram Moolenaar2e2a2812006-03-27 20:55:21 +0000538 if ((direction & RESIZE_HOR) && win_xpos + win_width > workarea_rect.right)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539 win_xpos = workarea_rect.right - win_width;
540
Bram Moolenaar2e2a2812006-03-27 20:55:21 +0000541 if ((direction & RESIZE_HOR) && win_xpos < workarea_rect.left)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 win_xpos = workarea_rect.left;
543
Bram Moolenaar2e2a2812006-03-27 20:55:21 +0000544 if ((direction & RESIZE_VERT)
545 && win_ypos + win_height > workarea_rect.bottom)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 win_ypos = workarea_rect.bottom - win_height;
547
Bram Moolenaar2e2a2812006-03-27 20:55:21 +0000548 if ((direction & RESIZE_VERT) && win_ypos < workarea_rect.top)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 win_ypos = workarea_rect.top;
550
551 /* set window position */
552 SetWindowPos(s_hwnd, NULL, win_xpos, win_ypos, win_width, win_height,
553 SWP_NOZORDER | SWP_NOACTIVATE);
554
555#ifdef FEAT_MENU
556 /* Menu may wrap differently now */
557 gui_mswin_get_menu_height(!gui.starting);
558#endif
559}
560
561 void
562gui_mch_set_scrollbar_thumb(
563 scrollbar_T *sb,
564 long val,
565 long size,
566 long max)
567{
568 sb->scroll_shift = 0;
569 while (max > 32767)
570 {
571 max = (max + 1) >> 1;
572 val >>= 1;
573 size >>= 1;
574 ++sb->scroll_shift;
575 }
576
577 if (sb->scroll_shift > 0)
578 ++size;
579
580 SetScrollRange(sb->id, SB_CTL, 0, (int) max, FALSE);
581 SetScrollPos(sb->id, SB_CTL, (int) val, TRUE);
582}
583
584
585/*
586 * Set the current text font.
587 */
588 void
589gui_mch_set_font(GuiFont font)
590{
591 gui.currFont = font;
592 SelectFont(s_hdc, gui.currFont);
593}
594
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595/*
596 * Set the current text foreground color.
597 */
598 void
599gui_mch_set_fg_color(guicolor_T color)
600{
601 gui.currFgColor = color;
602 SetTextColor(s_hdc, gui.currFgColor);
603}
604
605/*
606 * Set the current text background color.
607 */
608 void
609gui_mch_set_bg_color(guicolor_T color)
610{
611 if (gui.currBgColor == color)
612 return;
613
614 gui.currBgColor = color;
615 SetBkColor(s_hdc, gui.currBgColor);
616}
617
Bram Moolenaar3918c952005-03-15 22:34:55 +0000618/*
619 * Set the current text special color.
620 */
621 void
622gui_mch_set_sp_color(guicolor_T color)
623{
624 /* TODO */
625}
626
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627
628
629 void
630gui_mch_draw_string(
631 int row,
632 int col,
633 char_u *text,
634 int len,
635 int flags)
636{
637#ifndef MSWIN16_FASTTEXT
638 static int *padding = NULL;
639 static int pad_size = 0;
640 int i;
641#endif
642 HPEN hpen, old_pen;
643 int y;
644
645#ifndef MSWIN16_FASTTEXT
646 /*
647 * Italic and bold text seems to have an extra row of pixels at the bottom
648 * (below where the bottom of the character should be). If we draw the
649 * characters with a solid background, the top row of pixels in the
650 * character below will be overwritten. We can fix this by filling in the
651 * background ourselves, to the correct character proportions, and then
652 * writing the character in transparent mode. Still have a problem when
653 * the character is "_", which gets written on to the character below.
654 * New fix: set gui.char_ascent to -1. This shifts all characters up one
655 * pixel in their slots, which fixes the problem with the bottom row of
656 * pixels. We still need this code because otherwise the top row of pixels
657 * becomes a problem. - webb.
658 */
659 HBRUSH hbr;
660 RECT rc;
661
662 if (!(flags & DRAW_TRANSP))
663 {
664 /*
665 * Clear background first.
666 * Note: FillRect() excludes right and bottom of rectangle.
667 */
668 rc.left = FILL_X(col);
669 rc.top = FILL_Y(row);
670#ifdef FEAT_MBYTE
671 if (has_mbyte)
672 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +0200674 rc.right = FILL_X(col + mb_string2cells(text, len));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675 }
676 else
677#endif
678 rc.right = FILL_X(col + len);
679 rc.bottom = FILL_Y(row + 1);
680 hbr = CreateSolidBrush(gui.currBgColor);
681 FillRect(s_hdc, &rc, hbr);
682 DeleteBrush(hbr);
683
684 SetBkMode(s_hdc, TRANSPARENT);
685
686 /*
687 * When drawing block cursor, prevent inverted character spilling
688 * over character cell (can happen with bold/italic)
689 */
690 if (flags & DRAW_CURSOR)
691 {
692 pcliprect = &rc;
693 foptions = ETO_CLIPPED;
694 }
695 }
696#else
697 /*
698 * Alternative: write the characters in opaque mode, since we have blocked
699 * bold or italic fonts.
700 */
701 /* The OPAQUE mode and backcolour have already been set */
702#endif
703 /* The forecolor and font have already been set */
704
705#ifndef MSWIN16_FASTTEXT
706
707 if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
708 {
709 vim_free(padding);
710 pad_size = Columns;
711
712 padding = (int *)alloc(pad_size * sizeof(int));
713 if (padding != NULL)
714 for (i = 0; i < pad_size; i++)
715 padding[i] = gui.char_width;
716 }
717#endif
718
719 /*
720 * We have to provide the padding argument because italic and bold versions
721 * of fixed-width fonts are often one pixel or so wider than their normal
722 * versions.
723 * No check for DRAW_BOLD, Windows will have done it already.
724 */
725#ifndef MSWIN16_FASTTEXT
726 ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL,
727 (char *)text, len, padding);
728#else
729 TextOut(s_hdc, TEXT_X(col), TEXT_Y(row), (char *)text, len);
730#endif
731
732 if (flags & DRAW_UNDERL)
733 {
734 hpen = CreatePen(PS_SOLID, 1, gui.currFgColor);
735 old_pen = SelectObject(s_hdc, hpen);
736 /* When p_linespace is 0, overwrite the bottom row of pixels.
737 * Otherwise put the line just below the character. */
738 y = FILL_Y(row + 1) - 1;
739#ifndef MSWIN16_FASTTEXT
740 if (p_linespace > 1)
741 y -= p_linespace - 1;
742#endif
743 MoveToEx(s_hdc, FILL_X(col), y, NULL);
744 /* Note: LineTo() excludes the last pixel in the line. */
745 LineTo(s_hdc, FILL_X(col + len), y);
746 DeleteObject(SelectObject(s_hdc, old_pen));
747 }
748}
749
750
751/*
752 * Output routines.
753 */
754
755/* Flush any output to the screen */
756 void
757gui_mch_flush(void)
758{
759 /* Is anything needed here? */
760}
761
762 static void
763clear_rect(RECT *rcp)
764{
765 /* Use trick for fast rect clear */
766 gui_mch_set_bg_color(gui.back_pixel);
767 ExtTextOut(s_hdc, 0, 0, ETO_CLIPPED | ETO_OPAQUE, rcp, NULL, 0, NULL);
768}
769
770
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000771 void
772gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
773{
774
775 *screen_w = GetSystemMetrics(SM_CXFULLSCREEN)
776 - GetSystemMetrics(SM_CXFRAME) * 2;
777 /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include
778 * the menubar for MSwin, we subtract it from the screen height, so that
779 * the window size can be made to fit on the screen. */
780 *screen_h = GetSystemMetrics(SM_CYFULLSCREEN)
781 - GetSystemMetrics(SM_CYFRAME) * 2
782#ifdef FEAT_MENU
783 - gui_mswin_get_menu_height(FALSE)
784#endif
785 ;
786}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787
788
789#if defined(FEAT_MENU) || defined(PROTO)
790/*
791 * Add a sub menu to the menu bar.
792 */
793 void
794gui_mch_add_menu(
795 vimmenu_T *menu,
796 int pos)
797{
798 vimmenu_T *parent = menu->parent;
799
800 menu->submenu_id = CreatePopupMenu();
801 menu->id = s_menu_id++;
802
803 if (menu_is_menubar(menu->name))
804 {
805 InsertMenu((parent == NULL) ? s_menuBar : parent->submenu_id,
806 (UINT)pos, MF_POPUP | MF_STRING | MF_BYPOSITION,
807 (UINT)menu->submenu_id, menu->name);
808 }
809
810 /* Fix window size if menu may have wrapped */
811 if (parent == NULL)
812 gui_mswin_get_menu_height(!gui.starting);
813}
814
815 void
816gui_mch_show_popupmenu(vimmenu_T *menu)
817{
818 POINT mp;
819
820 (void)GetCursorPos((LPPOINT)&mp);
821 gui_mch_show_popupmenu_at(menu, (int)mp.x, (int)mp.y);
822}
823
824 void
Bram Moolenaarec8a10a2005-07-08 22:19:11 +0000825gui_make_popup(char_u *path_name, int mouse_pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826{
827 vimmenu_T *menu = gui_find_menu(path_name);
828
829 if (menu != NULL)
830 {
831 /* Find the position of the current cursor */
832 DWORD temp_p;
833 POINT p;
834 temp_p = GetDCOrg(s_hdc);
835 p.x = LOWORD(temp_p);
836 p.y = HIWORD(temp_p);
Bram Moolenaarec8a10a2005-07-08 22:19:11 +0000837 if (mouse_pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 {
Bram Moolenaarec8a10a2005-07-08 22:19:11 +0000839 int mx, my;
840
841 gui_mch_getmouse(&mx, &my);
842 p.x += mx;
843 p.y += my;
844 }
845 else if (curwin != NULL)
846 {
847 p.x += TEXT_X(W_WINCOL(curwin) + curwin->w_wcol + 1);
848 p.y += TEXT_Y(W_WINROW(curwin) + curwin->w_wrow + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 }
850 msg_scroll = FALSE;
851 gui_mch_show_popupmenu_at(menu, (int)p.x, (int)p.y);
852 }
853}
854
855/*
856 * Add a menu item to a menu
857 */
858 void
859gui_mch_add_menu_item(
860 vimmenu_T *menu,
861 int idx)
862{
863 vimmenu_T *parent = menu->parent;
864
865 menu->id = s_menu_id++;
866 menu->submenu_id = NULL;
867
868#ifdef FEAT_TOOLBAR
869 if (menu_is_toolbar(parent->name))
870 {
871 TBBUTTON newtb;
872
873 vim_memset(&newtb, 0, sizeof(newtb));
874 if (menu_is_separator(menu->name))
875 {
876 newtb.iBitmap = 0;
877 newtb.fsStyle = TBSTYLE_SEP;
878 }
879 else
880 {
881 if (menu->iconidx >= TOOLBAR_BITMAP_COUNT)
882 newtb.iBitmap = -1;
883 else
884 newtb.iBitmap = menu->iconidx;
885 newtb.fsStyle = TBSTYLE_BUTTON;
886 }
887 newtb.idCommand = menu->id;
888 newtb.fsState = TBSTATE_ENABLED;
889 SendMessage(s_toolbarhwnd, TB_INSERTBUTTON, (WPARAM)idx,
890 (LPARAM)&newtb);
891 menu->submenu_id = (HMENU)-1;
892 }
893 else
894#endif
895 {
896 InsertMenu(parent->submenu_id, (UINT)idx,
897 (menu_is_separator(menu->name) ? MF_SEPARATOR : MF_STRING)
898 | MF_BYPOSITION,
899 (UINT)menu->id, menu->name);
900 }
901}
902
903/*
904 * Destroy the machine specific menu widget.
905 */
906 void
907gui_mch_destroy_menu(vimmenu_T *menu)
908{
909 UINT i, j;
910 char pants[80]; /*<VN> hack*/
911#ifdef FEAT_TOOLBAR
912 /*
913 * is this a toolbar button?
914 */
915 if (menu->submenu_id == (HMENU)-1)
916 {
917 int iButton;
918
919 iButton = SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX, (WPARAM)menu->id, 0);
920 SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0);
921 }
922 else
923#endif
924 {
925 /*
926 * negri: horrible API bug when running 16-bit programs under Win9x or
927 * NT means that we can't use MF_BYCOMMAND for menu items which have
928 * submenus, including the top-level headings. We have to find the menu
929 * item and use MF_BYPOSITION instead. :-p
930 */
931 if (menu->parent != NULL
932 && menu_is_popup(menu->parent->dname)
933 && menu->parent->submenu_id != NULL)
934 RemoveMenu(menu->parent->submenu_id, menu->id, MF_BYCOMMAND);
935 else if (menu->submenu_id == NULL)
936 RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND);
937 else if (menu->parent != NULL)
938 {
939 i = GetMenuItemCount(menu->parent->submenu_id);
940 for (j = 0; j < i; ++j)
941 {
942 GetMenuString(menu->parent->submenu_id, j,
943 pants, 80, MF_BYPOSITION);
944 if (strcmp(pants, menu->name) == 0)
945 {
946 RemoveMenu(menu->parent->submenu_id, j, MF_BYPOSITION);
947 break;
948 }
949 }
950 }
951 else
952 {
953 i = GetMenuItemCount(s_menuBar);
954 for (j = 0; j < i; ++j)
955 {
956 GetMenuString(s_menuBar, j, pants, 80, MF_BYPOSITION);
957 if (strcmp(pants, menu->name) == 0)
958 {
959 RemoveMenu(s_menuBar, j, MF_BYPOSITION);
960 break;
961 }
962 }
963 }
964
965 if (menu->submenu_id != NULL)
966 DestroyMenu(menu->submenu_id);
967 }
968 DrawMenuBar(s_hwnd);
969}
970
971
972/*
973 * Make a menu either grey or not grey.
974 */
975 void
976gui_mch_menu_grey(
977 vimmenu_T *menu,
978 int grey)
979{
980#ifdef FEAT_TOOLBAR
981 /*
982 * is this a toolbar button?
983 */
984 if (menu->submenu_id == (HMENU)-1)
985 {
986 SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON,
987 (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) );
988 }
989 else
990#endif
991 if (grey)
992 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_GRAYED);
993 else
994 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
995
996}
997
998
999#endif /*FEAT_MENU*/
1000
1001
1002/* define some macros used to make the dialogue creation more readable */
1003
1004#define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1)
1005#define add_word(x) *p++ = (x)
1006#define add_byte(x) *((LPSTR)p)++ = (x)
1007#define add_long(x) *((LPDWORD)p)++ = (x)
1008
1009#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
1010/*
1011 * stuff for dialogs
1012 */
1013
1014/*
1015 * The callback routine used by all the dialogs. Very simple. First,
1016 * acknowledges the INITDIALOG message so that Windows knows to do standard
1017 * dialog stuff (Return = default, Esc = cancel....) Second, if a button is
1018 * pressed, return that button's ID - IDCANCEL (2), which is the button's
1019 * number.
1020 */
1021 static BOOL CALLBACK
1022dialog_callback(
1023 HWND hwnd,
1024 UINT message,
1025 WPARAM wParam,
1026 LPARAM lParam)
1027{
1028 if (message == WM_INITDIALOG)
1029 {
1030 CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER));
1031 /* Set focus to the dialog. Set the default button, if specified. */
1032 (void)SetFocus(hwnd);
1033 if (dialog_default_button > IDCANCEL)
1034 (void)SetFocus(GetDlgItem(hwnd, dialog_default_button));
1035// if (dialog_default_button > 0)
1036// (void)SetFocus(GetDlgItem(hwnd, dialog_default_button + IDCANCEL));
1037 return FALSE;
1038 }
1039
1040 if (message == WM_COMMAND)
1041 {
1042 int button = LOWORD(wParam);
1043
1044 /* Don't end the dialog if something was selected that was
1045 * not a button.
1046 */
1047 if (button >= DLG_NONBUTTON_CONTROL)
1048 return TRUE;
1049
1050 /* If the edit box exists, copy the string. */
1051 if (s_textfield != NULL)
1052 GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2,
1053 s_textfield, IOSIZE);
1054
1055 /*
1056 * Need to check for IDOK because if the user just hits Return to
1057 * accept the default value, some reason this is what we get.
1058 */
1059 if (button == IDOK)
1060 EndDialog(hwnd, dialog_default_button);
1061 else
1062 EndDialog(hwnd, button - IDCANCEL);
1063 return TRUE;
1064 }
1065
1066 if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
1067 {
1068 EndDialog(hwnd, 0);
1069 return TRUE;
1070 }
1071 return FALSE;
1072}
1073
1074/*
1075 * Create a dialog dynamically from the parameter strings.
1076 * type = type of dialog (question, alert, etc.)
1077 * title = dialog title. may be NULL for default title.
1078 * message = text to display. Dialog sizes to accommodate it.
1079 * buttons = '\n' separated list of button captions, default first.
1080 * dfltbutton = number of default button.
1081 *
1082 * This routine returns 1 if the first button is pressed,
1083 * 2 for the second, etc.
1084 *
1085 * 0 indicates Esc was pressed.
1086 * -1 for unexpected error
1087 *
1088 * If stubbing out this fn, return 1.
1089 */
1090
1091static const char_u dlg_icons[] = /* must match names in resource file */
1092{
1093 IDR_VIM,
1094 IDR_VIM_ERROR,
1095 IDR_VIM_ALERT,
1096 IDR_VIM_INFO,
1097 IDR_VIM_QUESTION
1098};
1099
1100 int
1101gui_mch_dialog(
1102 int type,
1103 char_u *title,
1104 char_u *message,
1105 char_u *buttons,
1106 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01001107 char_u *textfield,
1108 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109{
1110 FARPROC dp;
1111 LPWORD p, pnumitems;
1112 int numButtons;
1113 int *buttonWidths, *buttonPositions;
1114 int buttonYpos;
1115 int nchar, i;
1116 DWORD lStyle;
1117 int dlgwidth = 0;
1118 int dlgheight;
1119 int editboxheight;
1120 int horizWidth;
1121 int msgheight;
1122 char_u *pstart;
1123 char_u *pend;
1124 char_u *tbuffer;
1125 RECT rect;
1126 HWND hwnd;
1127 HDC hdc;
1128 HFONT oldFont;
1129 TEXTMETRIC fontInfo;
1130 int fontHeight;
1131 int textWidth, minButtonWidth, messageWidth;
1132 int maxDialogWidth;
1133 int vertical;
1134 int dlgPaddingX;
1135 int dlgPaddingY;
1136 HGLOBAL hglbDlgTemp;
1137
1138#ifndef NO_CONSOLE
1139 /* Don't output anything in silent mode ("ex -s") */
1140 if (silent_mode)
1141 return dfltbutton; /* return default option */
1142#endif
1143
1144 /* If there is no window yet, open it. */
1145 if (s_hwnd == NULL && gui_mch_init() == FAIL)
1146 return dfltbutton;
1147
1148 if ((type < 0) || (type > VIM_LAST_TYPE))
1149 type = 0;
1150
1151 /* allocate some memory for dialog template */
1152 /* TODO should compute this really*/
1153
1154 hglbDlgTemp = GlobalAlloc(GHND, DLG_ALLOC_SIZE);
1155 if (hglbDlgTemp == NULL)
1156 return -1;
1157
1158 p = (LPWORD) GlobalLock(hglbDlgTemp);
1159
1160 if (p == NULL)
1161 return -1;
1162
1163 /*
1164 * make a copy of 'buttons' to fiddle with it. complier grizzles because
1165 * vim_strsave() doesn't take a const arg (why not?), so cast away the
1166 * const.
1167 */
1168 tbuffer = vim_strsave(buttons);
1169 if (tbuffer == NULL)
1170 return -1;
1171
1172 --dfltbutton; /* Change from one-based to zero-based */
1173
1174 /* Count buttons */
1175 numButtons = 1;
1176 for (i = 0; tbuffer[i] != '\0'; i++)
1177 {
1178 if (tbuffer[i] == DLG_BUTTON_SEP)
1179 numButtons++;
1180 }
1181 if (dfltbutton >= numButtons)
1182 dfltbutton = 0;
1183
1184 /* Allocate array to hold the width of each button */
1185 buttonWidths = (int *) lalloc(numButtons * sizeof(int), TRUE);
1186 if (buttonWidths == NULL)
1187 return -1;
1188
1189 /* Allocate array to hold the X position of each button */
1190 buttonPositions = (int *) lalloc(numButtons * sizeof(int), TRUE);
1191 if (buttonPositions == NULL)
1192 return -1;
1193
1194 /*
1195 * Calculate how big the dialog must be.
1196 */
1197 hwnd = GetDesktopWindow();
1198 hdc = GetWindowDC(hwnd);
1199 oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
1200 dlgPaddingX = DLG_OLD_STYLE_PADDING_X;
1201 dlgPaddingY = DLG_OLD_STYLE_PADDING_Y;
1202
1203 GetTextMetrics(hdc, &fontInfo);
1204 fontHeight = fontInfo.tmHeight;
1205
1206 /* Minimum width for horizontal button */
1207 minButtonWidth = GetTextWidth(hdc, "Cancel", 6);
1208
1209 /* Maximum width of a dialog, if possible */
1210 GetWindowRect(s_hwnd, &rect);
1211 maxDialogWidth = rect.right - rect.left
1212 - GetSystemMetrics(SM_CXFRAME) * 2;
1213 if (maxDialogWidth < DLG_MIN_MAX_WIDTH)
1214 maxDialogWidth = DLG_MIN_MAX_WIDTH;
1215
1216 /* Set dlgwidth to width of message */
1217 pstart = message;
1218 messageWidth = 0;
1219 msgheight = 0;
1220 do
1221 {
1222 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
1223 if (pend == NULL)
1224 pend = pstart + STRLEN(pstart); /* Last line of message. */
1225 msgheight += fontHeight;
1226 textWidth = GetTextWidth(hdc, pstart, pend - pstart);
1227 if (textWidth > messageWidth)
1228 messageWidth = textWidth;
1229 pstart = pend + 1;
1230 } while (*pend != NUL);
1231 dlgwidth = messageWidth;
1232
1233 /* Add width of icon to dlgwidth, and some space */
1234 dlgwidth += DLG_ICON_WIDTH + 3 * dlgPaddingX;
1235
1236 if (msgheight < DLG_ICON_HEIGHT)
1237 msgheight = DLG_ICON_HEIGHT;
1238
1239 /*
1240 * Check button names. A long one will make the dialog wider.
1241 */
1242 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
1243 if (!vertical)
1244 {
1245 // Place buttons horizontally if they fit.
1246 horizWidth = dlgPaddingX;
1247 pstart = tbuffer;
1248 i = 0;
1249 do
1250 {
1251 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
1252 if (pend == NULL)
1253 pend = pstart + STRLEN(pstart); // Last button name.
1254 textWidth = GetTextWidth(hdc, pstart, pend - pstart);
1255 if (textWidth < minButtonWidth)
1256 textWidth = minButtonWidth;
1257 textWidth += dlgPaddingX; /* Padding within button */
1258 buttonWidths[i] = textWidth;
1259 buttonPositions[i++] = horizWidth;
1260 horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */
1261 pstart = pend + 1;
1262 } while (*pend != NUL);
1263
1264 if (horizWidth > maxDialogWidth)
1265 vertical = TRUE; // Too wide to fit on the screen.
1266 else if (horizWidth > dlgwidth)
1267 dlgwidth = horizWidth;
1268 }
1269
1270 if (vertical)
1271 {
1272 // Stack buttons vertically.
1273 pstart = tbuffer;
1274 do
1275 {
1276 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
1277 if (pend == NULL)
1278 pend = pstart + STRLEN(pstart); // Last button name.
1279 textWidth = GetTextWidth(hdc, pstart, pend - pstart);
1280 textWidth += dlgPaddingX; /* Padding within button */
1281 textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */
1282 if (textWidth > dlgwidth)
1283 dlgwidth = textWidth;
1284 pstart = pend + 1;
1285 } while (*pend != NUL);
1286 }
1287
1288 if (dlgwidth < DLG_MIN_WIDTH)
1289 dlgwidth = DLG_MIN_WIDTH; /* Don't allow a really thin dialog!*/
1290
1291 /* start to fill in the dlgtemplate information. addressing by WORDs */
1292 lStyle = DS_MODALFRAME | WS_CAPTION | WS_VISIBLE ;
1293
1294 add_long(lStyle);
1295 pnumitems = p; /*save where the number of items must be stored*/
1296 add_byte(0); // NumberOfItems(will change later)
1297 add_word(10); // x
1298 add_word(10); // y
1299 add_word(PixelToDialogX(dlgwidth));
1300
1301 // Dialog height.
1302 if (vertical)
1303 dlgheight = msgheight + 2 * dlgPaddingY +
1304 DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons;
1305 else
1306 dlgheight = msgheight + 3 * dlgPaddingY + 2 * fontHeight;
1307
1308 // Dialog needs to be taller if contains an edit box.
1309 editboxheight = fontHeight + dlgPaddingY + 4 * DLG_VERT_PADDING_Y;
1310 if (textfield != NULL)
1311 dlgheight += editboxheight;
1312
1313 add_word(PixelToDialogY(dlgheight));
1314
1315 add_byte(0); //menu
1316 add_byte(0); //class
1317
1318 /* copy the title of the dialog */
1319 add_string(title ? title : ("Vim"VIM_VERSION_MEDIUM));
1320
1321 buttonYpos = msgheight + 2 * dlgPaddingY;
1322
1323 if (textfield != NULL)
1324 buttonYpos += editboxheight;
1325
1326 pstart = tbuffer; //dflt_text
1327 horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */
1328 for (i = 0; i < numButtons; i++)
1329 {
1330 /* get end of this button. */
1331 for ( pend = pstart;
1332 *pend && (*pend != DLG_BUTTON_SEP);
1333 pend++)
1334 ;
1335
1336 if (*pend)
1337 *pend = '\0';
1338
1339 /*
1340 * NOTE:
1341 * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets
1342 * the focus to the first tab-able button and in so doing makes that
1343 * the default!! Grrr. Workaround: Make the default button the only
1344 * one with WS_TABSTOP style. Means user can't tab between buttons, but
1345 * he/she can use arrow keys.
1346 *
1347 * NOTE (Thore): Setting BS_DEFPUSHBUTTON works fine when it's the
1348 * first one, so I changed the correct button to be this style. This
1349 * is necessary because when an edit box is added, we need a button to
1350 * be default. The edit box will be the default control, and when the
1351 * user presses enter from the edit box we want the default button to
1352 * be pressed.
1353 */
1354 if (vertical)
1355 {
1356 p = add_dialog_element(p,
1357 ((i == dfltbutton || dfltbutton < 0) && textfield != NULL
1358 ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
1359 PixelToDialogX(DLG_VERT_PADDING_X),
1360 PixelToDialogY(buttonYpos /* TBK */
1361 + 2 * fontHeight * i),
1362 PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X),
1363 (WORD)(PixelToDialogY(2 * fontHeight) - 1),
1364 (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart);
1365 }
1366 else
1367 {
1368 p = add_dialog_element(p,
1369 ((i == dfltbutton || dfltbutton < 0) && textfield != NULL
1370 ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
1371 PixelToDialogX(horizWidth + buttonPositions[i]),
1372 PixelToDialogY(buttonYpos), /* TBK */
1373 PixelToDialogX(buttonWidths[i]),
1374 (WORD)(PixelToDialogY(2 * fontHeight) - 1),
1375 (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart);
1376 }
1377
1378 pstart = pend + 1; /*next button*/
1379
1380 }
1381 *pnumitems += numButtons;
1382
1383 /* Vim icon */
1384 p = add_dialog_element(p, SS_ICON,
1385 PixelToDialogX(dlgPaddingX),
1386 PixelToDialogY(dlgPaddingY),
1387 PixelToDialogX(DLG_ICON_WIDTH),
1388 PixelToDialogY(DLG_ICON_HEIGHT),
1389 DLG_NONBUTTON_CONTROL + 0, (BYTE)0x82,
1390 &dlg_icons[type]);
1391
1392
1393 /* Dialog message */
1394 p = add_dialog_element(p, SS_LEFT,
1395 PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
1396 PixelToDialogY(dlgPaddingY),
1397 (WORD)(PixelToDialogX(messageWidth) + 1),
1398 PixelToDialogY(msgheight),
1399 DLG_NONBUTTON_CONTROL + 1, (BYTE)0x82, message);
1400
1401 /* Edit box */
1402 if (textfield != NULL)
1403 {
1404 p = add_dialog_element(p, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP | WS_BORDER,
1405 PixelToDialogX(2 * dlgPaddingX),
1406 PixelToDialogY(2 * dlgPaddingY + msgheight),
1407 PixelToDialogX(dlgwidth - 4 * dlgPaddingX),
1408 PixelToDialogY(fontHeight + dlgPaddingY),
1409 DLG_NONBUTTON_CONTROL + 2, (BYTE)0x81, textfield);
1410 *pnumitems += 1;
1411 }
1412
1413 *pnumitems += 2;
1414
1415 SelectFont(hdc, oldFont);
1416 ReleaseDC(hwnd, hdc);
1417 dp = MakeProcInstance((FARPROC)dialog_callback, s_hinst);
1418
1419
1420 /* Let the dialog_callback() function know which button to make default
1421 * If we have an edit box, make that the default. We also need to tell
1422 * dialog_callback() if this dialog contains an edit box or not. We do
1423 * this by setting s_textfield if it does.
1424 */
1425 if (textfield != NULL)
1426 {
1427 dialog_default_button = DLG_NONBUTTON_CONTROL + 2;
1428 s_textfield = textfield;
1429 }
1430 else
1431 {
1432 dialog_default_button = IDCANCEL + 1 + dfltbutton;
1433 s_textfield = NULL;
1434 }
1435
1436 /*show the dialog box modally and get a return value*/
1437 nchar = DialogBoxIndirect(
1438 s_hinst,
1439 (HGLOBAL) hglbDlgTemp,
1440 s_hwnd,
1441 (DLGPROC)dp);
1442
1443 FreeProcInstance( dp );
1444 GlobalUnlock(hglbDlgTemp);
1445 GlobalFree(hglbDlgTemp);
1446 vim_free(tbuffer);
1447 vim_free(buttonWidths);
1448 vim_free(buttonPositions);
1449
1450
1451 return nchar;
1452}
1453
1454/*
1455 * Put a simple element (basic class) onto a dialog template in memory.
1456 * return a pointer to where the next item should be added.
1457 *
1458 * parameters:
1459 * lStyle = additional style flags
1460 * x,y = x & y positions IN DIALOG UNITS
1461 * w,h = width and height IN DIALOG UNITS
1462 * Id = ID used in messages
1463 * clss = class ID, e.g 0x80 for a button, 0x82 for a static
1464 * caption = usually text or resource name
1465 *
1466 * TODO: use the length information noted here to enable the dialog creation
1467 * routines to work out more exactly how much memory they need to alloc.
1468 */
1469 static LPWORD
1470add_dialog_element(
1471 LPWORD p,
1472 DWORD lStyle,
1473 WORD x,
1474 WORD y,
1475 WORD w,
1476 WORD h,
1477 WORD Id,
1478 BYTE clss,
1479 const char *caption)
1480{
1481
1482 lStyle = lStyle | WS_VISIBLE | WS_CHILD;
1483
1484 add_word(x);
1485 add_word(y);
1486 add_word(w);
1487 add_word(h);
1488 add_word(Id);
1489 add_long(lStyle);
1490 add_byte(clss);
1491 if (((lStyle & SS_ICON) != 0) && (clss == 0x82))
1492 {
1493 /* Use resource ID */
1494 add_byte(0xff);
1495 add_byte(*caption);
1496 }
1497 else
1498 add_string(caption);
1499
1500 add_byte(0); //# of extra bytes following
1501
1502
1503 return p;
1504}
1505
1506#undef add_byte
1507#undef add_string
1508#undef add_long
1509#undef add_word
1510
1511#endif /* FEAT_GUI_DIALOG */
1512
1513 static void
1514get_dialog_font_metrics(void)
1515{
1516 DWORD dlgFontSize;
1517 dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/
1518 s_dlgfntwidth = LOWORD(dlgFontSize);
1519 s_dlgfntheight = HIWORD(dlgFontSize);
1520}
1521
1522
1523#if defined(FEAT_TOOLBAR) || defined(PROTO)
1524#include "gui_w3~1.h"
1525/*
1526 * Create the toolbar, initially unpopulated.
1527 * (just like the menu, there are no defaults, it's all
1528 * set up through menu.vim)
1529 */
1530 static void
1531initialise_toolbar(void)
1532{
1533 s_toolbarhwnd = CreateToolbar(
1534 s_hwnd,
1535 WS_CHILD | WS_VISIBLE,
1536 CMD_TB_BASE, /*<vn>*/
Bram Moolenaar7263a772007-05-10 17:35:54 +00001537 31, //number of images in initial bitmap
Bram Moolenaar071d4272004-06-13 20:20:40 +00001538 s_hinst,
1539 IDR_TOOLBAR1, // id of initial bitmap
1540 NULL,
1541 0 // initial number of buttons
1542 );
1543
1544 gui_mch_show_toolbar(vim_strchr(p_go, GO_TOOLBAR) != NULL);
1545}
1546#endif
1547
1548#if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO)
1549/*
1550 * Make the GUI window come to the foreground.
1551 */
1552 void
1553gui_mch_set_foreground(void)
1554{
1555 if (IsIconic(s_hwnd))
1556 SendMessage(s_hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1557 SetActiveWindow(s_hwnd);
1558}
1559#endif