7
|
1 /* 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
|
|
51 static 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)
|
|
64 static BOOL CALLBACK dialog_callback(HWND, UINT, WPARAM, LPARAM);
|
|
65
|
|
66 static LPWORD
|
|
67 add_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
|
|
78 static int dialog_default_button = -1;
|
|
79 #endif
|
|
80
|
|
81 static void get_dialog_font_metrics(void);
|
|
82
|
|
83 #ifdef FEAT_TOOLBAR
|
|
84 static 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
|
|
93 gui_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;
|
811
|
131 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
|
7
|
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
|
|
317 gui_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
|
|
328 gui_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
|
|
490 gui_mch_set_shellsize(int width, int height,
|
811
|
491 int min_width, int min_height, int base_width, int base_height,
|
|
492 int direction)
|
7
|
493 {
|
|
494 RECT workarea_rect;
|
|
495 int win_width, win_height;
|
|
496 int win_xpos, win_ypos;
|
|
497 WINDOWPLACEMENT wndpl;
|
|
498
|
|
499 /* try to keep window completely on screen */
|
|
500 /* get size of the screen work area - use SM_CYFULLSCREEN
|
|
501 * instead of SM_CYSCREEN so that we don't overlap the
|
|
502 * taskbar if someone fires us up on Win95/NT */
|
|
503 workarea_rect.left = 0;
|
|
504 workarea_rect.top = 0;
|
|
505 workarea_rect.right = GetSystemMetrics(SM_CXSCREEN);
|
|
506 workarea_rect.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
|
|
507
|
|
508 /* get current posision of our window */
|
|
509 wndpl.length = sizeof(WINDOWPLACEMENT);
|
|
510 GetWindowPlacement(s_hwnd, &wndpl);
|
|
511 if (wndpl.showCmd == SW_SHOWNORMAL)
|
|
512 {
|
|
513 win_xpos = wndpl.rcNormalPosition.left;
|
|
514 win_ypos = wndpl.rcNormalPosition.top;
|
|
515 }
|
|
516 else
|
|
517 {
|
|
518 win_xpos = workarea_rect.left;
|
|
519 win_ypos = workarea_rect.top;
|
|
520 }
|
|
521
|
|
522 /* compute the size of the outside of the window */
|
|
523 win_width = width + GetSystemMetrics(SM_CXFRAME) * 2;
|
|
524 win_height = height + GetSystemMetrics(SM_CYFRAME) * 2
|
|
525 + GetSystemMetrics(SM_CYCAPTION)
|
|
526 #ifdef FEAT_MENU
|
|
527 + gui_mswin_get_menu_height(FALSE)
|
|
528 #endif
|
|
529 ;
|
|
530
|
|
531 /* if the window is going off the screen, move it on to the screen */
|
811
|
532 if ((direction & RESIZE_HOR) && win_xpos + win_width > workarea_rect.right)
|
7
|
533 win_xpos = workarea_rect.right - win_width;
|
|
534
|
811
|
535 if ((direction & RESIZE_HOR) && win_xpos < workarea_rect.left)
|
7
|
536 win_xpos = workarea_rect.left;
|
|
537
|
811
|
538 if ((direction & RESIZE_VERT)
|
|
539 && win_ypos + win_height > workarea_rect.bottom)
|
7
|
540 win_ypos = workarea_rect.bottom - win_height;
|
|
541
|
811
|
542 if ((direction & RESIZE_VERT) && win_ypos < workarea_rect.top)
|
7
|
543 win_ypos = workarea_rect.top;
|
|
544
|
|
545 /* set window position */
|
|
546 SetWindowPos(s_hwnd, NULL, win_xpos, win_ypos, win_width, win_height,
|
|
547 SWP_NOZORDER | SWP_NOACTIVATE);
|
|
548
|
|
549 #ifdef FEAT_MENU
|
|
550 /* Menu may wrap differently now */
|
|
551 gui_mswin_get_menu_height(!gui.starting);
|
|
552 #endif
|
|
553 }
|
|
554
|
|
555 void
|
|
556 gui_mch_set_scrollbar_thumb(
|
|
557 scrollbar_T *sb,
|
|
558 long val,
|
|
559 long size,
|
|
560 long max)
|
|
561 {
|
|
562 sb->scroll_shift = 0;
|
|
563 while (max > 32767)
|
|
564 {
|
|
565 max = (max + 1) >> 1;
|
|
566 val >>= 1;
|
|
567 size >>= 1;
|
|
568 ++sb->scroll_shift;
|
|
569 }
|
|
570
|
|
571 if (sb->scroll_shift > 0)
|
|
572 ++size;
|
|
573
|
|
574 SetScrollRange(sb->id, SB_CTL, 0, (int) max, FALSE);
|
|
575 SetScrollPos(sb->id, SB_CTL, (int) val, TRUE);
|
|
576 }
|
|
577
|
|
578
|
|
579 /*
|
|
580 * Set the current text font.
|
|
581 */
|
|
582 void
|
|
583 gui_mch_set_font(GuiFont font)
|
|
584 {
|
|
585 gui.currFont = font;
|
|
586 SelectFont(s_hdc, gui.currFont);
|
|
587 }
|
|
588
|
|
589 /*
|
|
590 * Set the current text foreground color.
|
|
591 */
|
|
592 void
|
|
593 gui_mch_set_fg_color(guicolor_T color)
|
|
594 {
|
|
595 gui.currFgColor = color;
|
|
596 SetTextColor(s_hdc, gui.currFgColor);
|
|
597 }
|
|
598
|
|
599 /*
|
|
600 * Set the current text background color.
|
|
601 */
|
|
602 void
|
|
603 gui_mch_set_bg_color(guicolor_T color)
|
|
604 {
|
|
605 if (gui.currBgColor == color)
|
|
606 return;
|
|
607
|
|
608 gui.currBgColor = color;
|
|
609 SetBkColor(s_hdc, gui.currBgColor);
|
|
610 }
|
|
611
|
203
|
612 /*
|
|
613 * Set the current text special color.
|
|
614 */
|
|
615 void
|
|
616 gui_mch_set_sp_color(guicolor_T color)
|
|
617 {
|
|
618 /* TODO */
|
|
619 }
|
|
620
|
7
|
621
|
|
622
|
|
623 void
|
|
624 gui_mch_draw_string(
|
|
625 int row,
|
|
626 int col,
|
|
627 char_u *text,
|
|
628 int len,
|
|
629 int flags)
|
|
630 {
|
|
631 #ifndef MSWIN16_FASTTEXT
|
|
632 static int *padding = NULL;
|
|
633 static int pad_size = 0;
|
|
634 int i;
|
|
635 #endif
|
|
636 HPEN hpen, old_pen;
|
|
637 int y;
|
|
638
|
|
639 #ifndef MSWIN16_FASTTEXT
|
|
640 /*
|
|
641 * Italic and bold text seems to have an extra row of pixels at the bottom
|
|
642 * (below where the bottom of the character should be). If we draw the
|
|
643 * characters with a solid background, the top row of pixels in the
|
|
644 * character below will be overwritten. We can fix this by filling in the
|
|
645 * background ourselves, to the correct character proportions, and then
|
|
646 * writing the character in transparent mode. Still have a problem when
|
|
647 * the character is "_", which gets written on to the character below.
|
|
648 * New fix: set gui.char_ascent to -1. This shifts all characters up one
|
|
649 * pixel in their slots, which fixes the problem with the bottom row of
|
|
650 * pixels. We still need this code because otherwise the top row of pixels
|
|
651 * becomes a problem. - webb.
|
|
652 */
|
|
653 HBRUSH hbr;
|
|
654 RECT rc;
|
|
655
|
|
656 if (!(flags & DRAW_TRANSP))
|
|
657 {
|
|
658 /*
|
|
659 * Clear background first.
|
|
660 * Note: FillRect() excludes right and bottom of rectangle.
|
|
661 */
|
|
662 rc.left = FILL_X(col);
|
|
663 rc.top = FILL_Y(row);
|
|
664 #ifdef FEAT_MBYTE
|
|
665 if (has_mbyte)
|
|
666 {
|
|
667 int cell_len = 0;
|
|
668
|
|
669 /* Compute the length in display cells. */
|
|
670 for (n = 0; n < len; n += MB_BYTE2LEN(text[n]))
|
|
671 cell_len += (*mb_ptr2cells)(text + n);
|
|
672 rc.right = FILL_X(col + cell_len);
|
|
673 }
|
|
674 else
|
|
675 #endif
|
|
676 rc.right = FILL_X(col + len);
|
|
677 rc.bottom = FILL_Y(row + 1);
|
|
678 hbr = CreateSolidBrush(gui.currBgColor);
|
|
679 FillRect(s_hdc, &rc, hbr);
|
|
680 DeleteBrush(hbr);
|
|
681
|
|
682 SetBkMode(s_hdc, TRANSPARENT);
|
|
683
|
|
684 /*
|
|
685 * When drawing block cursor, prevent inverted character spilling
|
|
686 * over character cell (can happen with bold/italic)
|
|
687 */
|
|
688 if (flags & DRAW_CURSOR)
|
|
689 {
|
|
690 pcliprect = &rc;
|
|
691 foptions = ETO_CLIPPED;
|
|
692 }
|
|
693 }
|
|
694 #else
|
|
695 /*
|
|
696 * Alternative: write the characters in opaque mode, since we have blocked
|
|
697 * bold or italic fonts.
|
|
698 */
|
|
699 /* The OPAQUE mode and backcolour have already been set */
|
|
700 #endif
|
|
701 /* The forecolor and font have already been set */
|
|
702
|
|
703 #ifndef MSWIN16_FASTTEXT
|
|
704
|
|
705 if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
|
|
706 {
|
|
707 vim_free(padding);
|
|
708 pad_size = Columns;
|
|
709
|
|
710 padding = (int *)alloc(pad_size * sizeof(int));
|
|
711 if (padding != NULL)
|
|
712 for (i = 0; i < pad_size; i++)
|
|
713 padding[i] = gui.char_width;
|
|
714 }
|
|
715 #endif
|
|
716
|
|
717 /*
|
|
718 * We have to provide the padding argument because italic and bold versions
|
|
719 * of fixed-width fonts are often one pixel or so wider than their normal
|
|
720 * versions.
|
|
721 * No check for DRAW_BOLD, Windows will have done it already.
|
|
722 */
|
|
723 #ifndef MSWIN16_FASTTEXT
|
|
724 ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL,
|
|
725 (char *)text, len, padding);
|
|
726 #else
|
|
727 TextOut(s_hdc, TEXT_X(col), TEXT_Y(row), (char *)text, len);
|
|
728 #endif
|
|
729
|
|
730 if (flags & DRAW_UNDERL)
|
|
731 {
|
|
732 hpen = CreatePen(PS_SOLID, 1, gui.currFgColor);
|
|
733 old_pen = SelectObject(s_hdc, hpen);
|
|
734 /* When p_linespace is 0, overwrite the bottom row of pixels.
|
|
735 * Otherwise put the line just below the character. */
|
|
736 y = FILL_Y(row + 1) - 1;
|
|
737 #ifndef MSWIN16_FASTTEXT
|
|
738 if (p_linespace > 1)
|
|
739 y -= p_linespace - 1;
|
|
740 #endif
|
|
741 MoveToEx(s_hdc, FILL_X(col), y, NULL);
|
|
742 /* Note: LineTo() excludes the last pixel in the line. */
|
|
743 LineTo(s_hdc, FILL_X(col + len), y);
|
|
744 DeleteObject(SelectObject(s_hdc, old_pen));
|
|
745 }
|
|
746 }
|
|
747
|
|
748
|
|
749 /*
|
|
750 * Output routines.
|
|
751 */
|
|
752
|
|
753 /* Flush any output to the screen */
|
|
754 void
|
|
755 gui_mch_flush(void)
|
|
756 {
|
|
757 /* Is anything needed here? */
|
|
758 }
|
|
759
|
|
760 static void
|
|
761 clear_rect(RECT *rcp)
|
|
762 {
|
|
763 /* Use trick for fast rect clear */
|
|
764 gui_mch_set_bg_color(gui.back_pixel);
|
|
765 ExtTextOut(s_hdc, 0, 0, ETO_CLIPPED | ETO_OPAQUE, rcp, NULL, 0, NULL);
|
|
766 }
|
|
767
|
|
768
|
635
|
769 void
|
|
770 gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
|
|
771 {
|
|
772
|
|
773 *screen_w = GetSystemMetrics(SM_CXFULLSCREEN)
|
|
774 - GetSystemMetrics(SM_CXFRAME) * 2;
|
|
775 /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include
|
|
776 * the menubar for MSwin, we subtract it from the screen height, so that
|
|
777 * the window size can be made to fit on the screen. */
|
|
778 *screen_h = GetSystemMetrics(SM_CYFULLSCREEN)
|
|
779 - GetSystemMetrics(SM_CYFRAME) * 2
|
|
780 #ifdef FEAT_MENU
|
|
781 - gui_mswin_get_menu_height(FALSE)
|
|
782 #endif
|
|
783 ;
|
|
784 }
|
7
|
785
|
|
786
|
|
787 #if defined(FEAT_MENU) || defined(PROTO)
|
|
788 /*
|
|
789 * Add a sub menu to the menu bar.
|
|
790 */
|
|
791 void
|
|
792 gui_mch_add_menu(
|
|
793 vimmenu_T *menu,
|
|
794 int pos)
|
|
795 {
|
|
796 vimmenu_T *parent = menu->parent;
|
|
797
|
|
798 menu->submenu_id = CreatePopupMenu();
|
|
799 menu->id = s_menu_id++;
|
|
800
|
|
801 if (menu_is_menubar(menu->name))
|
|
802 {
|
|
803 InsertMenu((parent == NULL) ? s_menuBar : parent->submenu_id,
|
|
804 (UINT)pos, MF_POPUP | MF_STRING | MF_BYPOSITION,
|
|
805 (UINT)menu->submenu_id, menu->name);
|
|
806 }
|
|
807
|
|
808 /* Fix window size if menu may have wrapped */
|
|
809 if (parent == NULL)
|
|
810 gui_mswin_get_menu_height(!gui.starting);
|
|
811 }
|
|
812
|
|
813 void
|
|
814 gui_mch_show_popupmenu(vimmenu_T *menu)
|
|
815 {
|
|
816 POINT mp;
|
|
817
|
|
818 (void)GetCursorPos((LPPOINT)&mp);
|
|
819 gui_mch_show_popupmenu_at(menu, (int)mp.x, (int)mp.y);
|
|
820 }
|
|
821
|
|
822 void
|
399
|
823 gui_make_popup(char_u *path_name, int mouse_pos)
|
7
|
824 {
|
|
825 vimmenu_T *menu = gui_find_menu(path_name);
|
|
826
|
|
827 if (menu != NULL)
|
|
828 {
|
|
829 /* Find the position of the current cursor */
|
|
830 DWORD temp_p;
|
|
831 POINT p;
|
|
832 temp_p = GetDCOrg(s_hdc);
|
|
833 p.x = LOWORD(temp_p);
|
|
834 p.y = HIWORD(temp_p);
|
399
|
835 if (mouse_pos)
|
7
|
836 {
|
399
|
837 int mx, my;
|
|
838
|
|
839 gui_mch_getmouse(&mx, &my);
|
|
840 p.x += mx;
|
|
841 p.y += my;
|
|
842 }
|
|
843 else if (curwin != NULL)
|
|
844 {
|
|
845 p.x += TEXT_X(W_WINCOL(curwin) + curwin->w_wcol + 1);
|
|
846 p.y += TEXT_Y(W_WINROW(curwin) + curwin->w_wrow + 1);
|
7
|
847 }
|
|
848 msg_scroll = FALSE;
|
|
849 gui_mch_show_popupmenu_at(menu, (int)p.x, (int)p.y);
|
|
850 }
|
|
851 }
|
|
852
|
|
853 /*
|
|
854 * Add a menu item to a menu
|
|
855 */
|
|
856 void
|
|
857 gui_mch_add_menu_item(
|
|
858 vimmenu_T *menu,
|
|
859 int idx)
|
|
860 {
|
|
861 vimmenu_T *parent = menu->parent;
|
|
862
|
|
863 menu->id = s_menu_id++;
|
|
864 menu->submenu_id = NULL;
|
|
865
|
|
866 #ifdef FEAT_TOOLBAR
|
|
867 if (menu_is_toolbar(parent->name))
|
|
868 {
|
|
869 TBBUTTON newtb;
|
|
870
|
|
871 vim_memset(&newtb, 0, sizeof(newtb));
|
|
872 if (menu_is_separator(menu->name))
|
|
873 {
|
|
874 newtb.iBitmap = 0;
|
|
875 newtb.fsStyle = TBSTYLE_SEP;
|
|
876 }
|
|
877 else
|
|
878 {
|
|
879 if (menu->iconidx >= TOOLBAR_BITMAP_COUNT)
|
|
880 newtb.iBitmap = -1;
|
|
881 else
|
|
882 newtb.iBitmap = menu->iconidx;
|
|
883 newtb.fsStyle = TBSTYLE_BUTTON;
|
|
884 }
|
|
885 newtb.idCommand = menu->id;
|
|
886 newtb.fsState = TBSTATE_ENABLED;
|
|
887 SendMessage(s_toolbarhwnd, TB_INSERTBUTTON, (WPARAM)idx,
|
|
888 (LPARAM)&newtb);
|
|
889 menu->submenu_id = (HMENU)-1;
|
|
890 }
|
|
891 else
|
|
892 #endif
|
|
893 {
|
|
894 InsertMenu(parent->submenu_id, (UINT)idx,
|
|
895 (menu_is_separator(menu->name) ? MF_SEPARATOR : MF_STRING)
|
|
896 | MF_BYPOSITION,
|
|
897 (UINT)menu->id, menu->name);
|
|
898 }
|
|
899 }
|
|
900
|
|
901 /*
|
|
902 * Destroy the machine specific menu widget.
|
|
903 */
|
|
904 void
|
|
905 gui_mch_destroy_menu(vimmenu_T *menu)
|
|
906 {
|
|
907 UINT i, j;
|
|
908 char pants[80]; /*<VN> hack*/
|
|
909 #ifdef FEAT_TOOLBAR
|
|
910 /*
|
|
911 * is this a toolbar button?
|
|
912 */
|
|
913 if (menu->submenu_id == (HMENU)-1)
|
|
914 {
|
|
915 int iButton;
|
|
916
|
|
917 iButton = SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX, (WPARAM)menu->id, 0);
|
|
918 SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0);
|
|
919 }
|
|
920 else
|
|
921 #endif
|
|
922 {
|
|
923 /*
|
|
924 * negri: horrible API bug when running 16-bit programs under Win9x or
|
|
925 * NT means that we can't use MF_BYCOMMAND for menu items which have
|
|
926 * submenus, including the top-level headings. We have to find the menu
|
|
927 * item and use MF_BYPOSITION instead. :-p
|
|
928 */
|
|
929 if (menu->parent != NULL
|
|
930 && menu_is_popup(menu->parent->dname)
|
|
931 && menu->parent->submenu_id != NULL)
|
|
932 RemoveMenu(menu->parent->submenu_id, menu->id, MF_BYCOMMAND);
|
|
933 else if (menu->submenu_id == NULL)
|
|
934 RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND);
|
|
935 else if (menu->parent != NULL)
|
|
936 {
|
|
937 i = GetMenuItemCount(menu->parent->submenu_id);
|
|
938 for (j = 0; j < i; ++j)
|
|
939 {
|
|
940 GetMenuString(menu->parent->submenu_id, j,
|
|
941 pants, 80, MF_BYPOSITION);
|
|
942 if (strcmp(pants, menu->name) == 0)
|
|
943 {
|
|
944 RemoveMenu(menu->parent->submenu_id, j, MF_BYPOSITION);
|
|
945 break;
|
|
946 }
|
|
947 }
|
|
948 }
|
|
949 else
|
|
950 {
|
|
951 i = GetMenuItemCount(s_menuBar);
|
|
952 for (j = 0; j < i; ++j)
|
|
953 {
|
|
954 GetMenuString(s_menuBar, j, pants, 80, MF_BYPOSITION);
|
|
955 if (strcmp(pants, menu->name) == 0)
|
|
956 {
|
|
957 RemoveMenu(s_menuBar, j, MF_BYPOSITION);
|
|
958 break;
|
|
959 }
|
|
960 }
|
|
961 }
|
|
962
|
|
963 if (menu->submenu_id != NULL)
|
|
964 DestroyMenu(menu->submenu_id);
|
|
965 }
|
|
966 DrawMenuBar(s_hwnd);
|
|
967 }
|
|
968
|
|
969
|
|
970 /*
|
|
971 * Make a menu either grey or not grey.
|
|
972 */
|
|
973 void
|
|
974 gui_mch_menu_grey(
|
|
975 vimmenu_T *menu,
|
|
976 int grey)
|
|
977 {
|
|
978 #ifdef FEAT_TOOLBAR
|
|
979 /*
|
|
980 * is this a toolbar button?
|
|
981 */
|
|
982 if (menu->submenu_id == (HMENU)-1)
|
|
983 {
|
|
984 SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON,
|
|
985 (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) );
|
|
986 }
|
|
987 else
|
|
988 #endif
|
|
989 if (grey)
|
|
990 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_GRAYED);
|
|
991 else
|
|
992 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
|
|
993
|
|
994 }
|
|
995
|
|
996
|
|
997 #endif /*FEAT_MENU*/
|
|
998
|
|
999
|
|
1000 /* define some macros used to make the dialogue creation more readable */
|
|
1001
|
|
1002 #define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1)
|
|
1003 #define add_word(x) *p++ = (x)
|
|
1004 #define add_byte(x) *((LPSTR)p)++ = (x)
|
|
1005 #define add_long(x) *((LPDWORD)p)++ = (x)
|
|
1006
|
|
1007 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
|
|
1008 /*
|
|
1009 * stuff for dialogs
|
|
1010 */
|
|
1011
|
|
1012 /*
|
|
1013 * The callback routine used by all the dialogs. Very simple. First,
|
|
1014 * acknowledges the INITDIALOG message so that Windows knows to do standard
|
|
1015 * dialog stuff (Return = default, Esc = cancel....) Second, if a button is
|
|
1016 * pressed, return that button's ID - IDCANCEL (2), which is the button's
|
|
1017 * number.
|
|
1018 */
|
|
1019 static BOOL CALLBACK
|
|
1020 dialog_callback(
|
|
1021 HWND hwnd,
|
|
1022 UINT message,
|
|
1023 WPARAM wParam,
|
|
1024 LPARAM lParam)
|
|
1025 {
|
|
1026 if (message == WM_INITDIALOG)
|
|
1027 {
|
|
1028 CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER));
|
|
1029 /* Set focus to the dialog. Set the default button, if specified. */
|
|
1030 (void)SetFocus(hwnd);
|
|
1031 if (dialog_default_button > IDCANCEL)
|
|
1032 (void)SetFocus(GetDlgItem(hwnd, dialog_default_button));
|
|
1033 // if (dialog_default_button > 0)
|
|
1034 // (void)SetFocus(GetDlgItem(hwnd, dialog_default_button + IDCANCEL));
|
|
1035 return FALSE;
|
|
1036 }
|
|
1037
|
|
1038 if (message == WM_COMMAND)
|
|
1039 {
|
|
1040 int button = LOWORD(wParam);
|
|
1041
|
|
1042 /* Don't end the dialog if something was selected that was
|
|
1043 * not a button.
|
|
1044 */
|
|
1045 if (button >= DLG_NONBUTTON_CONTROL)
|
|
1046 return TRUE;
|
|
1047
|
|
1048 /* If the edit box exists, copy the string. */
|
|
1049 if (s_textfield != NULL)
|
|
1050 GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2,
|
|
1051 s_textfield, IOSIZE);
|
|
1052
|
|
1053 /*
|
|
1054 * Need to check for IDOK because if the user just hits Return to
|
|
1055 * accept the default value, some reason this is what we get.
|
|
1056 */
|
|
1057 if (button == IDOK)
|
|
1058 EndDialog(hwnd, dialog_default_button);
|
|
1059 else
|
|
1060 EndDialog(hwnd, button - IDCANCEL);
|
|
1061 return TRUE;
|
|
1062 }
|
|
1063
|
|
1064 if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
|
|
1065 {
|
|
1066 EndDialog(hwnd, 0);
|
|
1067 return TRUE;
|
|
1068 }
|
|
1069 return FALSE;
|
|
1070 }
|
|
1071
|
|
1072 /*
|
|
1073 * Create a dialog dynamically from the parameter strings.
|
|
1074 * type = type of dialog (question, alert, etc.)
|
|
1075 * title = dialog title. may be NULL for default title.
|
|
1076 * message = text to display. Dialog sizes to accommodate it.
|
|
1077 * buttons = '\n' separated list of button captions, default first.
|
|
1078 * dfltbutton = number of default button.
|
|
1079 *
|
|
1080 * This routine returns 1 if the first button is pressed,
|
|
1081 * 2 for the second, etc.
|
|
1082 *
|
|
1083 * 0 indicates Esc was pressed.
|
|
1084 * -1 for unexpected error
|
|
1085 *
|
|
1086 * If stubbing out this fn, return 1.
|
|
1087 */
|
|
1088
|
|
1089 static const char_u dlg_icons[] = /* must match names in resource file */
|
|
1090 {
|
|
1091 IDR_VIM,
|
|
1092 IDR_VIM_ERROR,
|
|
1093 IDR_VIM_ALERT,
|
|
1094 IDR_VIM_INFO,
|
|
1095 IDR_VIM_QUESTION
|
|
1096 };
|
|
1097
|
|
1098 int
|
|
1099 gui_mch_dialog(
|
|
1100 int type,
|
|
1101 char_u *title,
|
|
1102 char_u *message,
|
|
1103 char_u *buttons,
|
|
1104 int dfltbutton,
|
|
1105 char_u *textfield)
|
|
1106 {
|
|
1107 FARPROC dp;
|
|
1108 LPWORD p, pnumitems;
|
|
1109 int numButtons;
|
|
1110 int *buttonWidths, *buttonPositions;
|
|
1111 int buttonYpos;
|
|
1112 int nchar, i;
|
|
1113 DWORD lStyle;
|
|
1114 int dlgwidth = 0;
|
|
1115 int dlgheight;
|
|
1116 int editboxheight;
|
|
1117 int horizWidth;
|
|
1118 int msgheight;
|
|
1119 char_u *pstart;
|
|
1120 char_u *pend;
|
|
1121 char_u *tbuffer;
|
|
1122 RECT rect;
|
|
1123 HWND hwnd;
|
|
1124 HDC hdc;
|
|
1125 HFONT oldFont;
|
|
1126 TEXTMETRIC fontInfo;
|
|
1127 int fontHeight;
|
|
1128 int textWidth, minButtonWidth, messageWidth;
|
|
1129 int maxDialogWidth;
|
|
1130 int vertical;
|
|
1131 int dlgPaddingX;
|
|
1132 int dlgPaddingY;
|
|
1133 HGLOBAL hglbDlgTemp;
|
|
1134
|
|
1135 #ifndef NO_CONSOLE
|
|
1136 /* Don't output anything in silent mode ("ex -s") */
|
|
1137 if (silent_mode)
|
|
1138 return dfltbutton; /* return default option */
|
|
1139 #endif
|
|
1140
|
|
1141 /* If there is no window yet, open it. */
|
|
1142 if (s_hwnd == NULL && gui_mch_init() == FAIL)
|
|
1143 return dfltbutton;
|
|
1144
|
|
1145 if ((type < 0) || (type > VIM_LAST_TYPE))
|
|
1146 type = 0;
|
|
1147
|
|
1148 /* allocate some memory for dialog template */
|
|
1149 /* TODO should compute this really*/
|
|
1150
|
|
1151 hglbDlgTemp = GlobalAlloc(GHND, DLG_ALLOC_SIZE);
|
|
1152 if (hglbDlgTemp == NULL)
|
|
1153 return -1;
|
|
1154
|
|
1155 p = (LPWORD) GlobalLock(hglbDlgTemp);
|
|
1156
|
|
1157 if (p == NULL)
|
|
1158 return -1;
|
|
1159
|
|
1160 /*
|
|
1161 * make a copy of 'buttons' to fiddle with it. complier grizzles because
|
|
1162 * vim_strsave() doesn't take a const arg (why not?), so cast away the
|
|
1163 * const.
|
|
1164 */
|
|
1165 tbuffer = vim_strsave(buttons);
|
|
1166 if (tbuffer == NULL)
|
|
1167 return -1;
|
|
1168
|
|
1169 --dfltbutton; /* Change from one-based to zero-based */
|
|
1170
|
|
1171 /* Count buttons */
|
|
1172 numButtons = 1;
|
|
1173 for (i = 0; tbuffer[i] != '\0'; i++)
|
|
1174 {
|
|
1175 if (tbuffer[i] == DLG_BUTTON_SEP)
|
|
1176 numButtons++;
|
|
1177 }
|
|
1178 if (dfltbutton >= numButtons)
|
|
1179 dfltbutton = 0;
|
|
1180
|
|
1181 /* Allocate array to hold the width of each button */
|
|
1182 buttonWidths = (int *) lalloc(numButtons * sizeof(int), TRUE);
|
|
1183 if (buttonWidths == NULL)
|
|
1184 return -1;
|
|
1185
|
|
1186 /* Allocate array to hold the X position of each button */
|
|
1187 buttonPositions = (int *) lalloc(numButtons * sizeof(int), TRUE);
|
|
1188 if (buttonPositions == NULL)
|
|
1189 return -1;
|
|
1190
|
|
1191 /*
|
|
1192 * Calculate how big the dialog must be.
|
|
1193 */
|
|
1194 hwnd = GetDesktopWindow();
|
|
1195 hdc = GetWindowDC(hwnd);
|
|
1196 oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
|
|
1197 dlgPaddingX = DLG_OLD_STYLE_PADDING_X;
|
|
1198 dlgPaddingY = DLG_OLD_STYLE_PADDING_Y;
|
|
1199
|
|
1200 GetTextMetrics(hdc, &fontInfo);
|
|
1201 fontHeight = fontInfo.tmHeight;
|
|
1202
|
|
1203 /* Minimum width for horizontal button */
|
|
1204 minButtonWidth = GetTextWidth(hdc, "Cancel", 6);
|
|
1205
|
|
1206 /* Maximum width of a dialog, if possible */
|
|
1207 GetWindowRect(s_hwnd, &rect);
|
|
1208 maxDialogWidth = rect.right - rect.left
|
|
1209 - GetSystemMetrics(SM_CXFRAME) * 2;
|
|
1210 if (maxDialogWidth < DLG_MIN_MAX_WIDTH)
|
|
1211 maxDialogWidth = DLG_MIN_MAX_WIDTH;
|
|
1212
|
|
1213 /* Set dlgwidth to width of message */
|
|
1214 pstart = message;
|
|
1215 messageWidth = 0;
|
|
1216 msgheight = 0;
|
|
1217 do
|
|
1218 {
|
|
1219 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
|
|
1220 if (pend == NULL)
|
|
1221 pend = pstart + STRLEN(pstart); /* Last line of message. */
|
|
1222 msgheight += fontHeight;
|
|
1223 textWidth = GetTextWidth(hdc, pstart, pend - pstart);
|
|
1224 if (textWidth > messageWidth)
|
|
1225 messageWidth = textWidth;
|
|
1226 pstart = pend + 1;
|
|
1227 } while (*pend != NUL);
|
|
1228 dlgwidth = messageWidth;
|
|
1229
|
|
1230 /* Add width of icon to dlgwidth, and some space */
|
|
1231 dlgwidth += DLG_ICON_WIDTH + 3 * dlgPaddingX;
|
|
1232
|
|
1233 if (msgheight < DLG_ICON_HEIGHT)
|
|
1234 msgheight = DLG_ICON_HEIGHT;
|
|
1235
|
|
1236 /*
|
|
1237 * Check button names. A long one will make the dialog wider.
|
|
1238 */
|
|
1239 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
|
|
1240 if (!vertical)
|
|
1241 {
|
|
1242 // Place buttons horizontally if they fit.
|
|
1243 horizWidth = dlgPaddingX;
|
|
1244 pstart = tbuffer;
|
|
1245 i = 0;
|
|
1246 do
|
|
1247 {
|
|
1248 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
|
|
1249 if (pend == NULL)
|
|
1250 pend = pstart + STRLEN(pstart); // Last button name.
|
|
1251 textWidth = GetTextWidth(hdc, pstart, pend - pstart);
|
|
1252 if (textWidth < minButtonWidth)
|
|
1253 textWidth = minButtonWidth;
|
|
1254 textWidth += dlgPaddingX; /* Padding within button */
|
|
1255 buttonWidths[i] = textWidth;
|
|
1256 buttonPositions[i++] = horizWidth;
|
|
1257 horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */
|
|
1258 pstart = pend + 1;
|
|
1259 } while (*pend != NUL);
|
|
1260
|
|
1261 if (horizWidth > maxDialogWidth)
|
|
1262 vertical = TRUE; // Too wide to fit on the screen.
|
|
1263 else if (horizWidth > dlgwidth)
|
|
1264 dlgwidth = horizWidth;
|
|
1265 }
|
|
1266
|
|
1267 if (vertical)
|
|
1268 {
|
|
1269 // Stack buttons vertically.
|
|
1270 pstart = tbuffer;
|
|
1271 do
|
|
1272 {
|
|
1273 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
|
|
1274 if (pend == NULL)
|
|
1275 pend = pstart + STRLEN(pstart); // Last button name.
|
|
1276 textWidth = GetTextWidth(hdc, pstart, pend - pstart);
|
|
1277 textWidth += dlgPaddingX; /* Padding within button */
|
|
1278 textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */
|
|
1279 if (textWidth > dlgwidth)
|
|
1280 dlgwidth = textWidth;
|
|
1281 pstart = pend + 1;
|
|
1282 } while (*pend != NUL);
|
|
1283 }
|
|
1284
|
|
1285 if (dlgwidth < DLG_MIN_WIDTH)
|
|
1286 dlgwidth = DLG_MIN_WIDTH; /* Don't allow a really thin dialog!*/
|
|
1287
|
|
1288 /* start to fill in the dlgtemplate information. addressing by WORDs */
|
|
1289 lStyle = DS_MODALFRAME | WS_CAPTION | WS_VISIBLE ;
|
|
1290
|
|
1291 add_long(lStyle);
|
|
1292 pnumitems = p; /*save where the number of items must be stored*/
|
|
1293 add_byte(0); // NumberOfItems(will change later)
|
|
1294 add_word(10); // x
|
|
1295 add_word(10); // y
|
|
1296 add_word(PixelToDialogX(dlgwidth));
|
|
1297
|
|
1298 // Dialog height.
|
|
1299 if (vertical)
|
|
1300 dlgheight = msgheight + 2 * dlgPaddingY +
|
|
1301 DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons;
|
|
1302 else
|
|
1303 dlgheight = msgheight + 3 * dlgPaddingY + 2 * fontHeight;
|
|
1304
|
|
1305 // Dialog needs to be taller if contains an edit box.
|
|
1306 editboxheight = fontHeight + dlgPaddingY + 4 * DLG_VERT_PADDING_Y;
|
|
1307 if (textfield != NULL)
|
|
1308 dlgheight += editboxheight;
|
|
1309
|
|
1310 add_word(PixelToDialogY(dlgheight));
|
|
1311
|
|
1312 add_byte(0); //menu
|
|
1313 add_byte(0); //class
|
|
1314
|
|
1315 /* copy the title of the dialog */
|
|
1316 add_string(title ? title : ("Vim"VIM_VERSION_MEDIUM));
|
|
1317
|
|
1318 buttonYpos = msgheight + 2 * dlgPaddingY;
|
|
1319
|
|
1320 if (textfield != NULL)
|
|
1321 buttonYpos += editboxheight;
|
|
1322
|
|
1323 pstart = tbuffer; //dflt_text
|
|
1324 horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */
|
|
1325 for (i = 0; i < numButtons; i++)
|
|
1326 {
|
|
1327 /* get end of this button. */
|
|
1328 for ( pend = pstart;
|
|
1329 *pend && (*pend != DLG_BUTTON_SEP);
|
|
1330 pend++)
|
|
1331 ;
|
|
1332
|
|
1333 if (*pend)
|
|
1334 *pend = '\0';
|
|
1335
|
|
1336 /*
|
|
1337 * NOTE:
|
|
1338 * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets
|
|
1339 * the focus to the first tab-able button and in so doing makes that
|
|
1340 * the default!! Grrr. Workaround: Make the default button the only
|
|
1341 * one with WS_TABSTOP style. Means user can't tab between buttons, but
|
|
1342 * he/she can use arrow keys.
|
|
1343 *
|
|
1344 * NOTE (Thore): Setting BS_DEFPUSHBUTTON works fine when it's the
|
|
1345 * first one, so I changed the correct button to be this style. This
|
|
1346 * is necessary because when an edit box is added, we need a button to
|
|
1347 * be default. The edit box will be the default control, and when the
|
|
1348 * user presses enter from the edit box we want the default button to
|
|
1349 * be pressed.
|
|
1350 */
|
|
1351 if (vertical)
|
|
1352 {
|
|
1353 p = add_dialog_element(p,
|
|
1354 ((i == dfltbutton || dfltbutton < 0) && textfield != NULL
|
|
1355 ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
|
|
1356 PixelToDialogX(DLG_VERT_PADDING_X),
|
|
1357 PixelToDialogY(buttonYpos /* TBK */
|
|
1358 + 2 * fontHeight * i),
|
|
1359 PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X),
|
|
1360 (WORD)(PixelToDialogY(2 * fontHeight) - 1),
|
|
1361 (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart);
|
|
1362 }
|
|
1363 else
|
|
1364 {
|
|
1365 p = add_dialog_element(p,
|
|
1366 ((i == dfltbutton || dfltbutton < 0) && textfield != NULL
|
|
1367 ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
|
|
1368 PixelToDialogX(horizWidth + buttonPositions[i]),
|
|
1369 PixelToDialogY(buttonYpos), /* TBK */
|
|
1370 PixelToDialogX(buttonWidths[i]),
|
|
1371 (WORD)(PixelToDialogY(2 * fontHeight) - 1),
|
|
1372 (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart);
|
|
1373 }
|
|
1374
|
|
1375 pstart = pend + 1; /*next button*/
|
|
1376
|
|
1377 }
|
|
1378 *pnumitems += numButtons;
|
|
1379
|
|
1380 /* Vim icon */
|
|
1381 p = add_dialog_element(p, SS_ICON,
|
|
1382 PixelToDialogX(dlgPaddingX),
|
|
1383 PixelToDialogY(dlgPaddingY),
|
|
1384 PixelToDialogX(DLG_ICON_WIDTH),
|
|
1385 PixelToDialogY(DLG_ICON_HEIGHT),
|
|
1386 DLG_NONBUTTON_CONTROL + 0, (BYTE)0x82,
|
|
1387 &dlg_icons[type]);
|
|
1388
|
|
1389
|
|
1390 /* Dialog message */
|
|
1391 p = add_dialog_element(p, SS_LEFT,
|
|
1392 PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
|
|
1393 PixelToDialogY(dlgPaddingY),
|
|
1394 (WORD)(PixelToDialogX(messageWidth) + 1),
|
|
1395 PixelToDialogY(msgheight),
|
|
1396 DLG_NONBUTTON_CONTROL + 1, (BYTE)0x82, message);
|
|
1397
|
|
1398 /* Edit box */
|
|
1399 if (textfield != NULL)
|
|
1400 {
|
|
1401 p = add_dialog_element(p, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP | WS_BORDER,
|
|
1402 PixelToDialogX(2 * dlgPaddingX),
|
|
1403 PixelToDialogY(2 * dlgPaddingY + msgheight),
|
|
1404 PixelToDialogX(dlgwidth - 4 * dlgPaddingX),
|
|
1405 PixelToDialogY(fontHeight + dlgPaddingY),
|
|
1406 DLG_NONBUTTON_CONTROL + 2, (BYTE)0x81, textfield);
|
|
1407 *pnumitems += 1;
|
|
1408 }
|
|
1409
|
|
1410 *pnumitems += 2;
|
|
1411
|
|
1412 SelectFont(hdc, oldFont);
|
|
1413 ReleaseDC(hwnd, hdc);
|
|
1414 dp = MakeProcInstance((FARPROC)dialog_callback, s_hinst);
|
|
1415
|
|
1416
|
|
1417 /* Let the dialog_callback() function know which button to make default
|
|
1418 * If we have an edit box, make that the default. We also need to tell
|
|
1419 * dialog_callback() if this dialog contains an edit box or not. We do
|
|
1420 * this by setting s_textfield if it does.
|
|
1421 */
|
|
1422 if (textfield != NULL)
|
|
1423 {
|
|
1424 dialog_default_button = DLG_NONBUTTON_CONTROL + 2;
|
|
1425 s_textfield = textfield;
|
|
1426 }
|
|
1427 else
|
|
1428 {
|
|
1429 dialog_default_button = IDCANCEL + 1 + dfltbutton;
|
|
1430 s_textfield = NULL;
|
|
1431 }
|
|
1432
|
|
1433 /*show the dialog box modally and get a return value*/
|
|
1434 nchar = DialogBoxIndirect(
|
|
1435 s_hinst,
|
|
1436 (HGLOBAL) hglbDlgTemp,
|
|
1437 s_hwnd,
|
|
1438 (DLGPROC)dp);
|
|
1439
|
|
1440 FreeProcInstance( dp );
|
|
1441 GlobalUnlock(hglbDlgTemp);
|
|
1442 GlobalFree(hglbDlgTemp);
|
|
1443 vim_free(tbuffer);
|
|
1444 vim_free(buttonWidths);
|
|
1445 vim_free(buttonPositions);
|
|
1446
|
|
1447
|
|
1448 return nchar;
|
|
1449 }
|
|
1450
|
|
1451 /*
|
|
1452 * Put a simple element (basic class) onto a dialog template in memory.
|
|
1453 * return a pointer to where the next item should be added.
|
|
1454 *
|
|
1455 * parameters:
|
|
1456 * lStyle = additional style flags
|
|
1457 * x,y = x & y positions IN DIALOG UNITS
|
|
1458 * w,h = width and height IN DIALOG UNITS
|
|
1459 * Id = ID used in messages
|
|
1460 * clss = class ID, e.g 0x80 for a button, 0x82 for a static
|
|
1461 * caption = usually text or resource name
|
|
1462 *
|
|
1463 * TODO: use the length information noted here to enable the dialog creation
|
|
1464 * routines to work out more exactly how much memory they need to alloc.
|
|
1465 */
|
|
1466 static LPWORD
|
|
1467 add_dialog_element(
|
|
1468 LPWORD p,
|
|
1469 DWORD lStyle,
|
|
1470 WORD x,
|
|
1471 WORD y,
|
|
1472 WORD w,
|
|
1473 WORD h,
|
|
1474 WORD Id,
|
|
1475 BYTE clss,
|
|
1476 const char *caption)
|
|
1477 {
|
|
1478
|
|
1479 lStyle = lStyle | WS_VISIBLE | WS_CHILD;
|
|
1480
|
|
1481 add_word(x);
|
|
1482 add_word(y);
|
|
1483 add_word(w);
|
|
1484 add_word(h);
|
|
1485 add_word(Id);
|
|
1486 add_long(lStyle);
|
|
1487 add_byte(clss);
|
|
1488 if (((lStyle & SS_ICON) != 0) && (clss == 0x82))
|
|
1489 {
|
|
1490 /* Use resource ID */
|
|
1491 add_byte(0xff);
|
|
1492 add_byte(*caption);
|
|
1493 }
|
|
1494 else
|
|
1495 add_string(caption);
|
|
1496
|
|
1497 add_byte(0); //# of extra bytes following
|
|
1498
|
|
1499
|
|
1500 return p;
|
|
1501 }
|
|
1502
|
|
1503 #undef add_byte
|
|
1504 #undef add_string
|
|
1505 #undef add_long
|
|
1506 #undef add_word
|
|
1507
|
|
1508 #endif /* FEAT_GUI_DIALOG */
|
|
1509
|
|
1510 static void
|
|
1511 get_dialog_font_metrics(void)
|
|
1512 {
|
|
1513 DWORD dlgFontSize;
|
|
1514 dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/
|
|
1515 s_dlgfntwidth = LOWORD(dlgFontSize);
|
|
1516 s_dlgfntheight = HIWORD(dlgFontSize);
|
|
1517 }
|
|
1518
|
|
1519
|
|
1520 #if defined(FEAT_TOOLBAR) || defined(PROTO)
|
|
1521 #include "gui_w3~1.h"
|
|
1522 /*
|
|
1523 * Create the toolbar, initially unpopulated.
|
|
1524 * (just like the menu, there are no defaults, it's all
|
|
1525 * set up through menu.vim)
|
|
1526 */
|
|
1527 static void
|
|
1528 initialise_toolbar(void)
|
|
1529 {
|
|
1530 s_toolbarhwnd = CreateToolbar(
|
|
1531 s_hwnd,
|
|
1532 WS_CHILD | WS_VISIBLE,
|
|
1533 CMD_TB_BASE, /*<vn>*/
|
1201
|
1534 31, //number of images in initial bitmap
|
7
|
1535 s_hinst,
|
|
1536 IDR_TOOLBAR1, // id of initial bitmap
|
|
1537 NULL,
|
|
1538 0 // initial number of buttons
|
|
1539 );
|
|
1540
|
|
1541 gui_mch_show_toolbar(vim_strchr(p_go, GO_TOOLBAR) != NULL);
|
|
1542 }
|
|
1543 #endif
|
|
1544
|
|
1545 #if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO)
|
|
1546 /*
|
|
1547 * Make the GUI window come to the foreground.
|
|
1548 */
|
|
1549 void
|
|
1550 gui_mch_set_foreground(void)
|
|
1551 {
|
|
1552 if (IsIconic(s_hwnd))
|
|
1553 SendMessage(s_hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
|
|
1554 SetActiveWindow(s_hwnd);
|
|
1555 }
|
|
1556 #endif
|