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