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