| /* vi:set ts=8 sts=4 sw=4: |
| * |
| * VIM - Vi IMproved by Bram Moolenaar |
| * GUI support by Robert Webb |
| * |
| * Do ":help uganda" in Vim to read copying and usage conditions. |
| * Do ":help credits" in Vim to see a list of people who contributed. |
| * See README.txt for an overview of the Vim source code. |
| */ |
| /* |
| * gui_w16.c |
| * |
| * GUI support for Microsoft Windows 3.1x |
| * |
| * George V. Reilly <george@reilly.org> wrote the original Win32 GUI. |
| * Robert Webb reworked it to use the existing GUI stuff and added menu, |
| * scrollbars, etc. |
| * |
| * Vince Negri then butchered the code to get it compiling for |
| * 16-bit windows. |
| * |
| */ |
| |
| /* Win16 doesn't use the "W" methods. */ |
| #define pDispatchMessage DispatchMessage |
| #define pGetMessage GetMessage |
| #define pIsDialogMessage IsDialogMessage |
| #define pPeekMessage PeekMessage |
| |
| /* |
| * Include the common stuff for MS-Windows GUI. |
| */ |
| #include "gui_w48.c" |
| |
| #include "guiw16rc.h" |
| |
| /* Undocumented Windows Message - not even defined in some SDK headers */ |
| #define WM_EXITSIZEMOVE 0x0232 |
| |
| |
| #ifdef FEAT_TOOLBAR |
| # define CMD_TB_BASE (99) |
| # include <vimtbar.h> |
| #endif |
| |
| #ifdef PROTO |
| # define WINAPI |
| #endif |
| |
| #define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \ |
| ((fn)((hwnd), (HDROP)(wParam)), 0L) |
| |
| |
| /* Local variables: */ |
| |
| #ifdef FEAT_MENU |
| static UINT s_menu_id = 100; |
| #endif |
| |
| |
| #define VIM_NAME "vim" |
| #define VIM_CLASS "Vim" |
| |
| #define DLG_ALLOC_SIZE 16 * 1024 |
| |
| /* |
| * stuff for dialogs, menus, tearoffs etc. |
| */ |
| #if defined(FEAT_GUI_DIALOG) || defined(PROTO) |
| static BOOL CALLBACK dialog_callback(HWND, UINT, WPARAM, LPARAM); |
| |
| static LPWORD |
| add_dialog_element( |
| LPWORD p, |
| DWORD lStyle, |
| WORD x, |
| WORD y, |
| WORD w, |
| WORD h, |
| WORD Id, |
| BYTE clss, |
| const char *caption); |
| |
| static int dialog_default_button = -1; |
| #endif |
| |
| static void get_dialog_font_metrics(void); |
| |
| #ifdef FEAT_TOOLBAR |
| static void initialise_toolbar(void); |
| #endif |
| |
| |
| #ifdef FEAT_MENU |
| /* |
| * Figure out how high the menu bar is at the moment. |
| */ |
| static int |
| gui_mswin_get_menu_height( |
| int fix_window) /* If TRUE, resize window if menu height changed */ |
| { |
| static int old_menu_height = -1; |
| |
| int num; |
| int menu_height; |
| |
| if (gui.menu_is_active) |
| num = GetMenuItemCount(s_menuBar); |
| else |
| num = 0; |
| |
| if (num == 0) |
| menu_height = 0; |
| else if (gui.starting) |
| menu_height = GetSystemMetrics(SM_CYMENU); |
| else |
| { |
| RECT r1, r2; |
| int frameht = GetSystemMetrics(SM_CYFRAME); |
| int capht = GetSystemMetrics(SM_CYCAPTION); |
| |
| /* get window rect of s_hwnd |
| * get client rect of s_hwnd |
| * get cap height |
| * subtract from window rect, the sum of client height, |
| * (if not maximized)frame thickness, and caption height. |
| */ |
| GetWindowRect(s_hwnd, &r1); |
| GetClientRect(s_hwnd, &r2); |
| menu_height = r1.bottom - r1.top - (r2.bottom-r2.top + |
| 2 * frameht * (!IsZoomed(s_hwnd)) + capht); |
| } |
| |
| if (fix_window && menu_height != old_menu_height) |
| { |
| old_menu_height = menu_height; |
| gui_set_shellsize(FALSE, FALSE, RESIZE_VERT); |
| } |
| |
| return menu_height; |
| } |
| #endif /*FEAT_MENU*/ |
| |
| |
| /* |
| * Even though we have _DuringSizing() which makes the rubber band a valid |
| * size, we need this for when the user maximises the window. |
| * TODO: Doesn't seem to adjust the width though for some reason. |
| */ |
| static BOOL |
| _OnWindowPosChanging( |
| HWND hwnd, |
| LPWINDOWPOS lpwpos) |
| { |
| |
| if (!IsIconic(hwnd) && !(lpwpos->flags & SWP_NOSIZE)) |
| { |
| gui_mswin_get_valid_dimensions(lpwpos->cx, lpwpos->cy, |
| &lpwpos->cx, &lpwpos->cy); |
| } |
| return 0; |
| } |
| |
| |
| |
| |
| |
| static LRESULT CALLBACK |
| _WndProc( |
| HWND hwnd, |
| UINT uMsg, |
| WPARAM wParam, |
| LPARAM lParam) |
| { |
| /* |
| TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n", |
| hwnd, uMsg, wParam, lParam); |
| */ |
| |
| HandleMouseHide(uMsg, lParam); |
| |
| s_uMsg = uMsg; |
| s_wParam = wParam; |
| s_lParam = lParam; |
| |
| switch (uMsg) |
| { |
| HANDLE_MSG(hwnd, WM_DEADCHAR, _OnDeadChar); |
| HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar); |
| /* HANDLE_MSG(hwnd, WM_ACTIVATE, _OnActivate); */ |
| HANDLE_MSG(hwnd, WM_CHAR, _OnChar); |
| HANDLE_MSG(hwnd, WM_CLOSE, _OnClose); |
| /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */ |
| HANDLE_MSG(hwnd, WM_DESTROY, _OnDestroy); |
| HANDLE_MSG(hwnd, WM_DROPFILES, _OnDropFiles); |
| HANDLE_MSG(hwnd, WM_HSCROLL, _OnScroll); |
| HANDLE_MSG(hwnd, WM_KILLFOCUS, _OnKillFocus); |
| #ifdef FEAT_MENU |
| HANDLE_MSG(hwnd, WM_COMMAND, _OnMenu); |
| #endif |
| /* HANDLE_MSG(hwnd, WM_MOVE, _OnMove); */ |
| /* HANDLE_MSG(hwnd, WM_NCACTIVATE, _OnNCActivate); */ |
| HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus); |
| HANDLE_MSG(hwnd, WM_SIZE, _OnSize); |
| /* HANDLE_MSG(hwnd, WM_SYSCOMMAND, _OnSysCommand); */ |
| /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN, _OnAltKey); */ |
| HANDLE_MSG(hwnd, WM_VSCROLL, _OnScroll); |
| HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging); |
| HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp); |
| |
| case WM_QUERYENDSESSION: /* System wants to go down. */ |
| gui_shell_closed(); /* Will exit when no changed buffers. */ |
| return FALSE; /* Do NOT allow system to go down. */ |
| |
| case WM_ENDSESSION: |
| if (wParam) /* system only really goes down when wParam is TRUE */ |
| _OnEndSession(); |
| break; |
| |
| case WM_SYSCHAR: |
| /* |
| * if 'winaltkeys' is "no", or it's "menu" and it's not a menu |
| * shortcut key, handle like a typed ALT key, otherwise call Windows |
| * ALT key handling. |
| */ |
| #ifdef FEAT_MENU |
| if ( !gui.menu_is_active |
| || p_wak[0] == 'n' |
| || (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam)) |
| ) |
| #endif |
| return HANDLE_WM_SYSCHAR((hwnd), (wParam), (lParam), (_OnSysChar)); |
| #ifdef FEAT_MENU |
| else |
| return MyWindowProc(hwnd, uMsg, wParam, lParam); |
| #endif |
| |
| case WM_SYSKEYUP: |
| #ifdef FEAT_MENU |
| /* Only when menu is active, ALT key is used for that. */ |
| if (gui.menu_is_active) |
| { |
| return MyWindowProc(hwnd, uMsg, wParam, lParam); |
| } |
| else |
| #endif |
| return 0; |
| |
| #if defined(MENUHINTS) && defined(FEAT_MENU) |
| case WM_MENUSELECT: |
| if (((UINT) LOWORD(lParam) |
| & (0xffff ^ (MF_MOUSESELECT + MF_BITMAP + MF_POPUP))) |
| == MF_HILITE |
| && (State & CMDLINE) == 0) |
| { |
| UINT idButton; |
| int idx; |
| vimmenu_T *pMenu; |
| |
| idButton = (UINT)LOWORD(wParam); |
| pMenu = gui_mswin_find_menu(root_menu, idButton); |
| if (pMenu) |
| { |
| idx = MENU_INDEX_TIP; |
| msg_clr_cmdline(); |
| if (pMenu->strings[idx]) |
| msg(pMenu->strings[idx]); |
| else |
| msg(""); |
| setcursor(); |
| out_flush(); |
| } |
| } |
| break; |
| #endif |
| case WM_NCHITTEST: |
| { |
| LRESULT result; |
| int x, y; |
| int xPos = GET_X_LPARAM(lParam); |
| |
| result = MyWindowProc(hwnd, uMsg, wParam, lParam); |
| if (result == HTCLIENT) |
| { |
| gui_mch_get_winpos(&x, &y); |
| xPos -= x; |
| |
| if (xPos < 48) /*<VN> TODO should use system metric?*/ |
| return HTBOTTOMLEFT; |
| else |
| return HTBOTTOMRIGHT; |
| } |
| else |
| return result; |
| } |
| /* break; */ |
| default: |
| #ifdef MSWIN_FIND_REPLACE |
| if (uMsg == s_findrep_msg && s_findrep_msg != 0) |
| { |
| _OnFindRepl(); |
| } |
| #endif |
| return MyWindowProc(hwnd, uMsg, wParam, lParam); |
| } |
| |
| return 1; |
| } |
| |
| |
| |
| /* |
| * End of call-back routines |
| */ |
| |
| |
| /* |
| * Parse the GUI related command-line arguments. Any arguments used are |
| * deleted from argv, and *argc is decremented accordingly. This is called |
| * when vim is started, whether or not the GUI has been started. |
| */ |
| void |
| gui_mch_prepare(int *argc, char **argv) |
| { |
| /* No special args for win16 GUI at the moment. */ |
| |
| } |
| |
| /* |
| * Initialise the GUI. Create all the windows, set up all the call-backs |
| * etc. |
| */ |
| int |
| gui_mch_init(void) |
| { |
| const char szVimWndClass[] = VIM_CLASS; |
| const char szTextAreaClass[] = "VimTextArea"; |
| WNDCLASS wndclass; |
| |
| #ifdef WIN16_3DLOOK |
| Ctl3dRegister(s_hinst); |
| Ctl3dAutoSubclass(s_hinst); |
| #endif |
| |
| /* Display any pending error messages */ |
| display_errors(); |
| |
| gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL); |
| gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL); |
| #ifdef FEAT_MENU |
| gui.menu_height = 0; /* Windows takes care of this */ |
| #endif |
| gui.border_width = 0; |
| |
| gui.currBgColor = INVALCOLOR; |
| |
| s_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); |
| |
| if (GetClassInfo(s_hinst, szVimWndClass, &wndclass) == 0) { |
| wndclass.style = 0; |
| wndclass.lpfnWndProc = _WndProc; |
| wndclass.cbClsExtra = 0; |
| wndclass.cbWndExtra = 0; |
| wndclass.hInstance = s_hinst; |
| wndclass.hIcon = LoadIcon(wndclass.hInstance, MAKEINTRESOURCE(IDR_VIM)); |
| wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); |
| wndclass.hbrBackground = s_brush; |
| wndclass.lpszMenuName = NULL; |
| wndclass.lpszClassName = szVimWndClass; |
| |
| if (( |
| #ifdef GLOBAL_IME |
| atom = |
| #endif |
| RegisterClass(&wndclass)) == 0) |
| return FAIL; |
| } |
| |
| s_hwnd = CreateWindow( |
| szVimWndClass, "Vim MSWindows GUI", |
| WS_OVERLAPPEDWINDOW, |
| gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x, |
| gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y, |
| 100, /* Any value will do */ |
| 100, /* Any value will do */ |
| NULL, NULL, |
| s_hinst, NULL); |
| |
| if (s_hwnd == NULL) |
| return FAIL; |
| |
| #ifdef GLOBAL_IME |
| global_ime_init(atom, s_hwnd); |
| #endif |
| |
| /* Create the text area window */ |
| if (GetClassInfo(s_hinst, szTextAreaClass, &wndclass) == 0) { |
| wndclass.style = CS_OWNDC; |
| wndclass.lpfnWndProc = _TextAreaWndProc; |
| wndclass.cbClsExtra = 0; |
| wndclass.cbWndExtra = 0; |
| wndclass.hInstance = s_hinst; |
| wndclass.hIcon = NULL; |
| wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); |
| wndclass.hbrBackground = NULL; |
| wndclass.lpszMenuName = NULL; |
| wndclass.lpszClassName = szTextAreaClass; |
| |
| if (RegisterClass(&wndclass) == 0) |
| return FAIL; |
| } |
| s_textArea = CreateWindow( |
| szTextAreaClass, "Vim text area", |
| WS_CHILD | WS_VISIBLE, 0, 0, |
| 100, /* Any value will do for now */ |
| 100, /* Any value will do for now */ |
| s_hwnd, NULL, |
| s_hinst, NULL); |
| |
| if (s_textArea == NULL) |
| return FAIL; |
| |
| #ifdef FEAT_MENU |
| s_menuBar = CreateMenu(); |
| #endif |
| s_hdc = GetDC(s_textArea); |
| |
| #ifdef MSWIN16_FASTTEXT |
| SetBkMode(s_hdc, OPAQUE); |
| #endif |
| |
| DragAcceptFiles(s_hwnd, TRUE); |
| |
| /* Do we need to bother with this? */ |
| /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */ |
| |
| /* Get background/foreground colors from the system */ |
| gui_mch_def_colors(); |
| |
| /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc |
| * file) */ |
| set_normal_colors(); |
| |
| /* |
| * Check that none of the colors are the same as the background color. |
| * Then store the current values as the defaults. |
| */ |
| gui_check_colors(); |
| gui.def_norm_pixel = gui.norm_pixel; |
| gui.def_back_pixel = gui.back_pixel; |
| |
| /* Get the colors for the highlight groups (gui_check_colors() might have |
| * changed them) */ |
| highlight_gui_started(); |
| |
| /* |
| * Start out by adding the configured border width into the border offset |
| */ |
| gui.border_offset = gui.border_width; |
| |
| |
| /* |
| * compute a couple of metrics used for the dialogs |
| */ |
| get_dialog_font_metrics(); |
| #ifdef FEAT_TOOLBAR |
| /* |
| * Create the toolbar |
| */ |
| initialise_toolbar(); |
| #endif |
| #ifdef MSWIN_FIND_REPLACE |
| /* |
| * Initialise the dialog box stuff |
| */ |
| s_findrep_msg = RegisterWindowMessage(FINDMSGSTRING); |
| |
| /* Initialise the struct */ |
| s_findrep_struct.lStructSize = sizeof(s_findrep_struct); |
| s_findrep_struct.lpstrFindWhat = alloc(MSWIN_FR_BUFSIZE); |
| s_findrep_struct.lpstrFindWhat[0] = NUL; |
| s_findrep_struct.lpstrReplaceWith = alloc(MSWIN_FR_BUFSIZE); |
| s_findrep_struct.lpstrReplaceWith[0] = NUL; |
| s_findrep_struct.wFindWhatLen = MSWIN_FR_BUFSIZE; |
| s_findrep_struct.wReplaceWithLen = MSWIN_FR_BUFSIZE; |
| #endif |
| |
| return OK; |
| } |
| |
| |
| /* |
| * Set the size of the window to the given width and height in pixels. |
| */ |
| void |
| gui_mch_set_shellsize(int width, int height, |
| int min_width, int min_height, int base_width, int base_height, |
| int direction) |
| { |
| RECT workarea_rect; |
| int win_width, win_height; |
| int win_xpos, win_ypos; |
| WINDOWPLACEMENT wndpl; |
| |
| /* try to keep window completely on screen */ |
| /* get size of the screen work area - use SM_CYFULLSCREEN |
| * instead of SM_CYSCREEN so that we don't overlap the |
| * taskbar if someone fires us up on Win95/NT */ |
| workarea_rect.left = 0; |
| workarea_rect.top = 0; |
| workarea_rect.right = GetSystemMetrics(SM_CXSCREEN); |
| workarea_rect.bottom = GetSystemMetrics(SM_CYFULLSCREEN); |
| |
| /* get current posision of our window */ |
| wndpl.length = sizeof(WINDOWPLACEMENT); |
| GetWindowPlacement(s_hwnd, &wndpl); |
| if (wndpl.showCmd == SW_SHOWNORMAL) |
| { |
| win_xpos = wndpl.rcNormalPosition.left; |
| win_ypos = wndpl.rcNormalPosition.top; |
| } |
| else |
| { |
| win_xpos = workarea_rect.left; |
| win_ypos = workarea_rect.top; |
| } |
| |
| /* compute the size of the outside of the window */ |
| win_width = width + GetSystemMetrics(SM_CXFRAME) * 2; |
| win_height = height + GetSystemMetrics(SM_CYFRAME) * 2 |
| + GetSystemMetrics(SM_CYCAPTION) |
| #ifdef FEAT_MENU |
| + gui_mswin_get_menu_height(FALSE) |
| #endif |
| ; |
| |
| /* if the window is going off the screen, move it on to the screen */ |
| if ((direction & RESIZE_HOR) && win_xpos + win_width > workarea_rect.right) |
| win_xpos = workarea_rect.right - win_width; |
| |
| if ((direction & RESIZE_HOR) && win_xpos < workarea_rect.left) |
| win_xpos = workarea_rect.left; |
| |
| if ((direction & RESIZE_VERT) |
| && win_ypos + win_height > workarea_rect.bottom) |
| win_ypos = workarea_rect.bottom - win_height; |
| |
| if ((direction & RESIZE_VERT) && win_ypos < workarea_rect.top) |
| win_ypos = workarea_rect.top; |
| |
| /* set window position */ |
| SetWindowPos(s_hwnd, NULL, win_xpos, win_ypos, win_width, win_height, |
| SWP_NOZORDER | SWP_NOACTIVATE); |
| |
| #ifdef FEAT_MENU |
| /* Menu may wrap differently now */ |
| gui_mswin_get_menu_height(!gui.starting); |
| #endif |
| } |
| |
| void |
| gui_mch_set_scrollbar_thumb( |
| scrollbar_T *sb, |
| long val, |
| long size, |
| long max) |
| { |
| sb->scroll_shift = 0; |
| while (max > 32767) |
| { |
| max = (max + 1) >> 1; |
| val >>= 1; |
| size >>= 1; |
| ++sb->scroll_shift; |
| } |
| |
| if (sb->scroll_shift > 0) |
| ++size; |
| |
| SetScrollRange(sb->id, SB_CTL, 0, (int) max, FALSE); |
| SetScrollPos(sb->id, SB_CTL, (int) val, TRUE); |
| } |
| |
| |
| /* |
| * Set the current text font. |
| */ |
| void |
| gui_mch_set_font(GuiFont font) |
| { |
| gui.currFont = font; |
| SelectFont(s_hdc, gui.currFont); |
| } |
| |
| /* |
| * Set the current text foreground color. |
| */ |
| void |
| gui_mch_set_fg_color(guicolor_T color) |
| { |
| gui.currFgColor = color; |
| SetTextColor(s_hdc, gui.currFgColor); |
| } |
| |
| /* |
| * Set the current text background color. |
| */ |
| void |
| gui_mch_set_bg_color(guicolor_T color) |
| { |
| if (gui.currBgColor == color) |
| return; |
| |
| gui.currBgColor = color; |
| SetBkColor(s_hdc, gui.currBgColor); |
| } |
| |
| /* |
| * Set the current text special color. |
| */ |
| void |
| gui_mch_set_sp_color(guicolor_T color) |
| { |
| /* TODO */ |
| } |
| |
| |
| |
| void |
| gui_mch_draw_string( |
| int row, |
| int col, |
| char_u *text, |
| int len, |
| int flags) |
| { |
| #ifndef MSWIN16_FASTTEXT |
| static int *padding = NULL; |
| static int pad_size = 0; |
| int i; |
| #endif |
| HPEN hpen, old_pen; |
| int y; |
| |
| #ifndef MSWIN16_FASTTEXT |
| /* |
| * Italic and bold text seems to have an extra row of pixels at the bottom |
| * (below where the bottom of the character should be). If we draw the |
| * characters with a solid background, the top row of pixels in the |
| * character below will be overwritten. We can fix this by filling in the |
| * background ourselves, to the correct character proportions, and then |
| * writing the character in transparent mode. Still have a problem when |
| * the character is "_", which gets written on to the character below. |
| * New fix: set gui.char_ascent to -1. This shifts all characters up one |
| * pixel in their slots, which fixes the problem with the bottom row of |
| * pixels. We still need this code because otherwise the top row of pixels |
| * becomes a problem. - webb. |
| */ |
| HBRUSH hbr; |
| RECT rc; |
| |
| if (!(flags & DRAW_TRANSP)) |
| { |
| /* |
| * Clear background first. |
| * Note: FillRect() excludes right and bottom of rectangle. |
| */ |
| rc.left = FILL_X(col); |
| rc.top = FILL_Y(row); |
| #ifdef FEAT_MBYTE |
| if (has_mbyte) |
| { |
| /* Compute the length in display cells. */ |
| rc.right = FILL_X(col + mb_string2cells(text, len)); |
| } |
| else |
| #endif |
| rc.right = FILL_X(col + len); |
| rc.bottom = FILL_Y(row + 1); |
| hbr = CreateSolidBrush(gui.currBgColor); |
| FillRect(s_hdc, &rc, hbr); |
| DeleteBrush(hbr); |
| |
| SetBkMode(s_hdc, TRANSPARENT); |
| |
| /* |
| * When drawing block cursor, prevent inverted character spilling |
| * over character cell (can happen with bold/italic) |
| */ |
| if (flags & DRAW_CURSOR) |
| { |
| pcliprect = &rc; |
| foptions = ETO_CLIPPED; |
| } |
| } |
| #else |
| /* |
| * Alternative: write the characters in opaque mode, since we have blocked |
| * bold or italic fonts. |
| */ |
| /* The OPAQUE mode and backcolour have already been set */ |
| #endif |
| /* The forecolor and font have already been set */ |
| |
| #ifndef MSWIN16_FASTTEXT |
| |
| if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width) |
| { |
| vim_free(padding); |
| pad_size = Columns; |
| |
| padding = (int *)alloc(pad_size * sizeof(int)); |
| if (padding != NULL) |
| for (i = 0; i < pad_size; i++) |
| padding[i] = gui.char_width; |
| } |
| #endif |
| |
| /* |
| * We have to provide the padding argument because italic and bold versions |
| * of fixed-width fonts are often one pixel or so wider than their normal |
| * versions. |
| * No check for DRAW_BOLD, Windows will have done it already. |
| */ |
| #ifndef MSWIN16_FASTTEXT |
| ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL, |
| (char *)text, len, padding); |
| #else |
| TextOut(s_hdc, TEXT_X(col), TEXT_Y(row), (char *)text, len); |
| #endif |
| |
| if (flags & DRAW_UNDERL) |
| { |
| hpen = CreatePen(PS_SOLID, 1, gui.currFgColor); |
| old_pen = SelectObject(s_hdc, hpen); |
| /* When p_linespace is 0, overwrite the bottom row of pixels. |
| * Otherwise put the line just below the character. */ |
| y = FILL_Y(row + 1) - 1; |
| #ifndef MSWIN16_FASTTEXT |
| if (p_linespace > 1) |
| y -= p_linespace - 1; |
| #endif |
| MoveToEx(s_hdc, FILL_X(col), y, NULL); |
| /* Note: LineTo() excludes the last pixel in the line. */ |
| LineTo(s_hdc, FILL_X(col + len), y); |
| DeleteObject(SelectObject(s_hdc, old_pen)); |
| } |
| } |
| |
| |
| /* |
| * Output routines. |
| */ |
| |
| /* Flush any output to the screen */ |
| void |
| gui_mch_flush(void) |
| { |
| /* Is anything needed here? */ |
| } |
| |
| static void |
| clear_rect(RECT *rcp) |
| { |
| /* Use trick for fast rect clear */ |
| gui_mch_set_bg_color(gui.back_pixel); |
| ExtTextOut(s_hdc, 0, 0, ETO_CLIPPED | ETO_OPAQUE, rcp, NULL, 0, NULL); |
| } |
| |
| |
| void |
| gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) |
| { |
| |
| *screen_w = GetSystemMetrics(SM_CXFULLSCREEN) |
| - GetSystemMetrics(SM_CXFRAME) * 2; |
| /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include |
| * the menubar for MSwin, we subtract it from the screen height, so that |
| * the window size can be made to fit on the screen. */ |
| *screen_h = GetSystemMetrics(SM_CYFULLSCREEN) |
| - GetSystemMetrics(SM_CYFRAME) * 2 |
| #ifdef FEAT_MENU |
| - gui_mswin_get_menu_height(FALSE) |
| #endif |
| ; |
| } |
| |
| |
| #if defined(FEAT_MENU) || defined(PROTO) |
| /* |
| * Add a sub menu to the menu bar. |
| */ |
| void |
| gui_mch_add_menu( |
| vimmenu_T *menu, |
| int pos) |
| { |
| vimmenu_T *parent = menu->parent; |
| |
| menu->submenu_id = CreatePopupMenu(); |
| menu->id = s_menu_id++; |
| |
| if (menu_is_menubar(menu->name)) |
| { |
| InsertMenu((parent == NULL) ? s_menuBar : parent->submenu_id, |
| (UINT)pos, MF_POPUP | MF_STRING | MF_BYPOSITION, |
| (UINT)menu->submenu_id, menu->name); |
| } |
| |
| /* Fix window size if menu may have wrapped */ |
| if (parent == NULL) |
| gui_mswin_get_menu_height(!gui.starting); |
| } |
| |
| void |
| gui_mch_show_popupmenu(vimmenu_T *menu) |
| { |
| POINT mp; |
| |
| (void)GetCursorPos((LPPOINT)&mp); |
| gui_mch_show_popupmenu_at(menu, (int)mp.x, (int)mp.y); |
| } |
| |
| void |
| gui_make_popup(char_u *path_name, int mouse_pos) |
| { |
| vimmenu_T *menu = gui_find_menu(path_name); |
| |
| if (menu != NULL) |
| { |
| /* Find the position of the current cursor */ |
| DWORD temp_p; |
| POINT p; |
| temp_p = GetDCOrg(s_hdc); |
| p.x = LOWORD(temp_p); |
| p.y = HIWORD(temp_p); |
| if (mouse_pos) |
| { |
| int mx, my; |
| |
| gui_mch_getmouse(&mx, &my); |
| p.x += mx; |
| p.y += my; |
| } |
| else if (curwin != NULL) |
| { |
| p.x += TEXT_X(W_WINCOL(curwin) + curwin->w_wcol + 1); |
| p.y += TEXT_Y(W_WINROW(curwin) + curwin->w_wrow + 1); |
| } |
| msg_scroll = FALSE; |
| gui_mch_show_popupmenu_at(menu, (int)p.x, (int)p.y); |
| } |
| } |
| |
| /* |
| * Add a menu item to a menu |
| */ |
| void |
| gui_mch_add_menu_item( |
| vimmenu_T *menu, |
| int idx) |
| { |
| vimmenu_T *parent = menu->parent; |
| |
| menu->id = s_menu_id++; |
| menu->submenu_id = NULL; |
| |
| #ifdef FEAT_TOOLBAR |
| if (menu_is_toolbar(parent->name)) |
| { |
| TBBUTTON newtb; |
| |
| vim_memset(&newtb, 0, sizeof(newtb)); |
| if (menu_is_separator(menu->name)) |
| { |
| newtb.iBitmap = 0; |
| newtb.fsStyle = TBSTYLE_SEP; |
| } |
| else |
| { |
| if (menu->iconidx >= TOOLBAR_BITMAP_COUNT) |
| newtb.iBitmap = -1; |
| else |
| newtb.iBitmap = menu->iconidx; |
| newtb.fsStyle = TBSTYLE_BUTTON; |
| } |
| newtb.idCommand = menu->id; |
| newtb.fsState = TBSTATE_ENABLED; |
| SendMessage(s_toolbarhwnd, TB_INSERTBUTTON, (WPARAM)idx, |
| (LPARAM)&newtb); |
| menu->submenu_id = (HMENU)-1; |
| } |
| else |
| #endif |
| { |
| InsertMenu(parent->submenu_id, (UINT)idx, |
| (menu_is_separator(menu->name) ? MF_SEPARATOR : MF_STRING) |
| | MF_BYPOSITION, |
| (UINT)menu->id, menu->name); |
| } |
| } |
| |
| /* |
| * Destroy the machine specific menu widget. |
| */ |
| void |
| gui_mch_destroy_menu(vimmenu_T *menu) |
| { |
| UINT i, j; |
| char pants[80]; /*<VN> hack*/ |
| #ifdef FEAT_TOOLBAR |
| /* |
| * is this a toolbar button? |
| */ |
| if (menu->submenu_id == (HMENU)-1) |
| { |
| int iButton; |
| |
| iButton = SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX, (WPARAM)menu->id, 0); |
| SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0); |
| } |
| else |
| #endif |
| { |
| /* |
| * negri: horrible API bug when running 16-bit programs under Win9x or |
| * NT means that we can't use MF_BYCOMMAND for menu items which have |
| * submenus, including the top-level headings. We have to find the menu |
| * item and use MF_BYPOSITION instead. :-p |
| */ |
| if (menu->parent != NULL |
| && menu_is_popup(menu->parent->dname) |
| && menu->parent->submenu_id != NULL) |
| RemoveMenu(menu->parent->submenu_id, menu->id, MF_BYCOMMAND); |
| else if (menu->submenu_id == NULL) |
| RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND); |
| else if (menu->parent != NULL) |
| { |
| i = GetMenuItemCount(menu->parent->submenu_id); |
| for (j = 0; j < i; ++j) |
| { |
| GetMenuString(menu->parent->submenu_id, j, |
| pants, 80, MF_BYPOSITION); |
| if (strcmp(pants, menu->name) == 0) |
| { |
| RemoveMenu(menu->parent->submenu_id, j, MF_BYPOSITION); |
| break; |
| } |
| } |
| } |
| else |
| { |
| i = GetMenuItemCount(s_menuBar); |
| for (j = 0; j < i; ++j) |
| { |
| GetMenuString(s_menuBar, j, pants, 80, MF_BYPOSITION); |
| if (strcmp(pants, menu->name) == 0) |
| { |
| RemoveMenu(s_menuBar, j, MF_BYPOSITION); |
| break; |
| } |
| } |
| } |
| |
| if (menu->submenu_id != NULL) |
| DestroyMenu(menu->submenu_id); |
| } |
| DrawMenuBar(s_hwnd); |
| } |
| |
| |
| /* |
| * Make a menu either grey or not grey. |
| */ |
| void |
| gui_mch_menu_grey( |
| vimmenu_T *menu, |
| int grey) |
| { |
| #ifdef FEAT_TOOLBAR |
| /* |
| * is this a toolbar button? |
| */ |
| if (menu->submenu_id == (HMENU)-1) |
| { |
| SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON, |
| (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) ); |
| } |
| else |
| #endif |
| if (grey) |
| EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_GRAYED); |
| else |
| EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED); |
| |
| } |
| |
| |
| #endif /*FEAT_MENU*/ |
| |
| |
| /* define some macros used to make the dialogue creation more readable */ |
| |
| #define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1) |
| #define add_word(x) *p++ = (x) |
| #define add_byte(x) *((LPSTR)p)++ = (x) |
| #define add_long(x) *((LPDWORD)p)++ = (x) |
| |
| #if defined(FEAT_GUI_DIALOG) || defined(PROTO) |
| /* |
| * stuff for dialogs |
| */ |
| |
| /* |
| * The callback routine used by all the dialogs. Very simple. First, |
| * acknowledges the INITDIALOG message so that Windows knows to do standard |
| * dialog stuff (Return = default, Esc = cancel....) Second, if a button is |
| * pressed, return that button's ID - IDCANCEL (2), which is the button's |
| * number. |
| */ |
| static BOOL CALLBACK |
| dialog_callback( |
| HWND hwnd, |
| UINT message, |
| WPARAM wParam, |
| LPARAM lParam) |
| { |
| if (message == WM_INITDIALOG) |
| { |
| CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER)); |
| /* Set focus to the dialog. Set the default button, if specified. */ |
| (void)SetFocus(hwnd); |
| if (dialog_default_button > IDCANCEL) |
| (void)SetFocus(GetDlgItem(hwnd, dialog_default_button)); |
| // if (dialog_default_button > 0) |
| // (void)SetFocus(GetDlgItem(hwnd, dialog_default_button + IDCANCEL)); |
| return FALSE; |
| } |
| |
| if (message == WM_COMMAND) |
| { |
| int button = LOWORD(wParam); |
| |
| /* Don't end the dialog if something was selected that was |
| * not a button. |
| */ |
| if (button >= DLG_NONBUTTON_CONTROL) |
| return TRUE; |
| |
| /* If the edit box exists, copy the string. */ |
| if (s_textfield != NULL) |
| GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2, |
| s_textfield, IOSIZE); |
| |
| /* |
| * Need to check for IDOK because if the user just hits Return to |
| * accept the default value, some reason this is what we get. |
| */ |
| if (button == IDOK) |
| EndDialog(hwnd, dialog_default_button); |
| else |
| EndDialog(hwnd, button - IDCANCEL); |
| return TRUE; |
| } |
| |
| if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE)) |
| { |
| EndDialog(hwnd, 0); |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| /* |
| * Create a dialog dynamically from the parameter strings. |
| * type = type of dialog (question, alert, etc.) |
| * title = dialog title. may be NULL for default title. |
| * message = text to display. Dialog sizes to accommodate it. |
| * buttons = '\n' separated list of button captions, default first. |
| * dfltbutton = number of default button. |
| * |
| * This routine returns 1 if the first button is pressed, |
| * 2 for the second, etc. |
| * |
| * 0 indicates Esc was pressed. |
| * -1 for unexpected error |
| * |
| * If stubbing out this fn, return 1. |
| */ |
| |
| static const char_u dlg_icons[] = /* must match names in resource file */ |
| { |
| IDR_VIM, |
| IDR_VIM_ERROR, |
| IDR_VIM_ALERT, |
| IDR_VIM_INFO, |
| IDR_VIM_QUESTION |
| }; |
| |
| int |
| gui_mch_dialog( |
| int type, |
| char_u *title, |
| char_u *message, |
| char_u *buttons, |
| int dfltbutton, |
| char_u *textfield, |
| int ex_cmd) |
| { |
| FARPROC dp; |
| LPWORD p, pnumitems; |
| int numButtons; |
| int *buttonWidths, *buttonPositions; |
| int buttonYpos; |
| int nchar, i; |
| DWORD lStyle; |
| int dlgwidth = 0; |
| int dlgheight; |
| int editboxheight; |
| int horizWidth; |
| int msgheight; |
| char_u *pstart; |
| char_u *pend; |
| char_u *tbuffer; |
| RECT rect; |
| HWND hwnd; |
| HDC hdc; |
| HFONT oldFont; |
| TEXTMETRIC fontInfo; |
| int fontHeight; |
| int textWidth, minButtonWidth, messageWidth; |
| int maxDialogWidth; |
| int vertical; |
| int dlgPaddingX; |
| int dlgPaddingY; |
| HGLOBAL hglbDlgTemp; |
| |
| #ifndef NO_CONSOLE |
| /* Don't output anything in silent mode ("ex -s") */ |
| if (silent_mode) |
| return dfltbutton; /* return default option */ |
| #endif |
| |
| /* If there is no window yet, open it. */ |
| if (s_hwnd == NULL && gui_mch_init() == FAIL) |
| return dfltbutton; |
| |
| if ((type < 0) || (type > VIM_LAST_TYPE)) |
| type = 0; |
| |
| /* allocate some memory for dialog template */ |
| /* TODO should compute this really*/ |
| |
| hglbDlgTemp = GlobalAlloc(GHND, DLG_ALLOC_SIZE); |
| if (hglbDlgTemp == NULL) |
| return -1; |
| |
| p = (LPWORD) GlobalLock(hglbDlgTemp); |
| |
| if (p == NULL) |
| return -1; |
| |
| /* |
| * make a copy of 'buttons' to fiddle with it. complier grizzles because |
| * vim_strsave() doesn't take a const arg (why not?), so cast away the |
| * const. |
| */ |
| tbuffer = vim_strsave(buttons); |
| if (tbuffer == NULL) |
| return -1; |
| |
| --dfltbutton; /* Change from one-based to zero-based */ |
| |
| /* Count buttons */ |
| numButtons = 1; |
| for (i = 0; tbuffer[i] != '\0'; i++) |
| { |
| if (tbuffer[i] == DLG_BUTTON_SEP) |
| numButtons++; |
| } |
| if (dfltbutton >= numButtons) |
| dfltbutton = 0; |
| |
| /* Allocate array to hold the width of each button */ |
| buttonWidths = (int *) lalloc(numButtons * sizeof(int), TRUE); |
| if (buttonWidths == NULL) |
| return -1; |
| |
| /* Allocate array to hold the X position of each button */ |
| buttonPositions = (int *) lalloc(numButtons * sizeof(int), TRUE); |
| if (buttonPositions == NULL) |
| return -1; |
| |
| /* |
| * Calculate how big the dialog must be. |
| */ |
| hwnd = GetDesktopWindow(); |
| hdc = GetWindowDC(hwnd); |
| oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT)); |
| dlgPaddingX = DLG_OLD_STYLE_PADDING_X; |
| dlgPaddingY = DLG_OLD_STYLE_PADDING_Y; |
| |
| GetTextMetrics(hdc, &fontInfo); |
| fontHeight = fontInfo.tmHeight; |
| |
| /* Minimum width for horizontal button */ |
| minButtonWidth = GetTextWidth(hdc, "Cancel", 6); |
| |
| /* Maximum width of a dialog, if possible */ |
| GetWindowRect(s_hwnd, &rect); |
| maxDialogWidth = rect.right - rect.left |
| - GetSystemMetrics(SM_CXFRAME) * 2; |
| if (maxDialogWidth < DLG_MIN_MAX_WIDTH) |
| maxDialogWidth = DLG_MIN_MAX_WIDTH; |
| |
| /* Set dlgwidth to width of message */ |
| pstart = message; |
| messageWidth = 0; |
| msgheight = 0; |
| do |
| { |
| pend = vim_strchr(pstart, DLG_BUTTON_SEP); |
| if (pend == NULL) |
| pend = pstart + STRLEN(pstart); /* Last line of message. */ |
| msgheight += fontHeight; |
| textWidth = GetTextWidth(hdc, pstart, pend - pstart); |
| if (textWidth > messageWidth) |
| messageWidth = textWidth; |
| pstart = pend + 1; |
| } while (*pend != NUL); |
| dlgwidth = messageWidth; |
| |
| /* Add width of icon to dlgwidth, and some space */ |
| dlgwidth += DLG_ICON_WIDTH + 3 * dlgPaddingX; |
| |
| if (msgheight < DLG_ICON_HEIGHT) |
| msgheight = DLG_ICON_HEIGHT; |
| |
| /* |
| * Check button names. A long one will make the dialog wider. |
| */ |
| vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); |
| if (!vertical) |
| { |
| // Place buttons horizontally if they fit. |
| horizWidth = dlgPaddingX; |
| pstart = tbuffer; |
| i = 0; |
| do |
| { |
| pend = vim_strchr(pstart, DLG_BUTTON_SEP); |
| if (pend == NULL) |
| pend = pstart + STRLEN(pstart); // Last button name. |
| textWidth = GetTextWidth(hdc, pstart, pend - pstart); |
| if (textWidth < minButtonWidth) |
| textWidth = minButtonWidth; |
| textWidth += dlgPaddingX; /* Padding within button */ |
| buttonWidths[i] = textWidth; |
| buttonPositions[i++] = horizWidth; |
| horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */ |
| pstart = pend + 1; |
| } while (*pend != NUL); |
| |
| if (horizWidth > maxDialogWidth) |
| vertical = TRUE; // Too wide to fit on the screen. |
| else if (horizWidth > dlgwidth) |
| dlgwidth = horizWidth; |
| } |
| |
| if (vertical) |
| { |
| // Stack buttons vertically. |
| pstart = tbuffer; |
| do |
| { |
| pend = vim_strchr(pstart, DLG_BUTTON_SEP); |
| if (pend == NULL) |
| pend = pstart + STRLEN(pstart); // Last button name. |
| textWidth = GetTextWidth(hdc, pstart, pend - pstart); |
| textWidth += dlgPaddingX; /* Padding within button */ |
| textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */ |
| if (textWidth > dlgwidth) |
| dlgwidth = textWidth; |
| pstart = pend + 1; |
| } while (*pend != NUL); |
| } |
| |
| if (dlgwidth < DLG_MIN_WIDTH) |
| dlgwidth = DLG_MIN_WIDTH; /* Don't allow a really thin dialog!*/ |
| |
| /* start to fill in the dlgtemplate information. addressing by WORDs */ |
| lStyle = DS_MODALFRAME | WS_CAPTION | WS_VISIBLE ; |
| |
| add_long(lStyle); |
| pnumitems = p; /*save where the number of items must be stored*/ |
| add_byte(0); // NumberOfItems(will change later) |
| add_word(10); // x |
| add_word(10); // y |
| add_word(PixelToDialogX(dlgwidth)); |
| |
| // Dialog height. |
| if (vertical) |
| dlgheight = msgheight + 2 * dlgPaddingY + |
| DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons; |
| else |
| dlgheight = msgheight + 3 * dlgPaddingY + 2 * fontHeight; |
| |
| // Dialog needs to be taller if contains an edit box. |
| editboxheight = fontHeight + dlgPaddingY + 4 * DLG_VERT_PADDING_Y; |
| if (textfield != NULL) |
| dlgheight += editboxheight; |
| |
| add_word(PixelToDialogY(dlgheight)); |
| |
| add_byte(0); //menu |
| add_byte(0); //class |
| |
| /* copy the title of the dialog */ |
| add_string(title ? title : ("Vim"VIM_VERSION_MEDIUM)); |
| |
| buttonYpos = msgheight + 2 * dlgPaddingY; |
| |
| if (textfield != NULL) |
| buttonYpos += editboxheight; |
| |
| pstart = tbuffer; //dflt_text |
| horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */ |
| for (i = 0; i < numButtons; i++) |
| { |
| /* get end of this button. */ |
| for ( pend = pstart; |
| *pend && (*pend != DLG_BUTTON_SEP); |
| pend++) |
| ; |
| |
| if (*pend) |
| *pend = '\0'; |
| |
| /* |
| * NOTE: |
| * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets |
| * the focus to the first tab-able button and in so doing makes that |
| * the default!! Grrr. Workaround: Make the default button the only |
| * one with WS_TABSTOP style. Means user can't tab between buttons, but |
| * he/she can use arrow keys. |
| * |
| * NOTE (Thore): Setting BS_DEFPUSHBUTTON works fine when it's the |
| * first one, so I changed the correct button to be this style. This |
| * is necessary because when an edit box is added, we need a button to |
| * be default. The edit box will be the default control, and when the |
| * user presses enter from the edit box we want the default button to |
| * be pressed. |
| */ |
| if (vertical) |
| { |
| p = add_dialog_element(p, |
| ((i == dfltbutton || dfltbutton < 0) && textfield != NULL |
| ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP, |
| PixelToDialogX(DLG_VERT_PADDING_X), |
| PixelToDialogY(buttonYpos /* TBK */ |
| + 2 * fontHeight * i), |
| PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X), |
| (WORD)(PixelToDialogY(2 * fontHeight) - 1), |
| (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart); |
| } |
| else |
| { |
| p = add_dialog_element(p, |
| ((i == dfltbutton || dfltbutton < 0) && textfield != NULL |
| ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP, |
| PixelToDialogX(horizWidth + buttonPositions[i]), |
| PixelToDialogY(buttonYpos), /* TBK */ |
| PixelToDialogX(buttonWidths[i]), |
| (WORD)(PixelToDialogY(2 * fontHeight) - 1), |
| (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart); |
| } |
| |
| pstart = pend + 1; /*next button*/ |
| |
| } |
| *pnumitems += numButtons; |
| |
| /* Vim icon */ |
| p = add_dialog_element(p, SS_ICON, |
| PixelToDialogX(dlgPaddingX), |
| PixelToDialogY(dlgPaddingY), |
| PixelToDialogX(DLG_ICON_WIDTH), |
| PixelToDialogY(DLG_ICON_HEIGHT), |
| DLG_NONBUTTON_CONTROL + 0, (BYTE)0x82, |
| &dlg_icons[type]); |
| |
| |
| /* Dialog message */ |
| p = add_dialog_element(p, SS_LEFT, |
| PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH), |
| PixelToDialogY(dlgPaddingY), |
| (WORD)(PixelToDialogX(messageWidth) + 1), |
| PixelToDialogY(msgheight), |
| DLG_NONBUTTON_CONTROL + 1, (BYTE)0x82, message); |
| |
| /* Edit box */ |
| if (textfield != NULL) |
| { |
| p = add_dialog_element(p, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP | WS_BORDER, |
| PixelToDialogX(2 * dlgPaddingX), |
| PixelToDialogY(2 * dlgPaddingY + msgheight), |
| PixelToDialogX(dlgwidth - 4 * dlgPaddingX), |
| PixelToDialogY(fontHeight + dlgPaddingY), |
| DLG_NONBUTTON_CONTROL + 2, (BYTE)0x81, textfield); |
| *pnumitems += 1; |
| } |
| |
| *pnumitems += 2; |
| |
| SelectFont(hdc, oldFont); |
| ReleaseDC(hwnd, hdc); |
| dp = MakeProcInstance((FARPROC)dialog_callback, s_hinst); |
| |
| |
| /* Let the dialog_callback() function know which button to make default |
| * If we have an edit box, make that the default. We also need to tell |
| * dialog_callback() if this dialog contains an edit box or not. We do |
| * this by setting s_textfield if it does. |
| */ |
| if (textfield != NULL) |
| { |
| dialog_default_button = DLG_NONBUTTON_CONTROL + 2; |
| s_textfield = textfield; |
| } |
| else |
| { |
| dialog_default_button = IDCANCEL + 1 + dfltbutton; |
| s_textfield = NULL; |
| } |
| |
| /*show the dialog box modally and get a return value*/ |
| nchar = DialogBoxIndirect( |
| s_hinst, |
| (HGLOBAL) hglbDlgTemp, |
| s_hwnd, |
| (DLGPROC)dp); |
| |
| FreeProcInstance( dp ); |
| GlobalUnlock(hglbDlgTemp); |
| GlobalFree(hglbDlgTemp); |
| vim_free(tbuffer); |
| vim_free(buttonWidths); |
| vim_free(buttonPositions); |
| |
| |
| return nchar; |
| } |
| |
| /* |
| * Put a simple element (basic class) onto a dialog template in memory. |
| * return a pointer to where the next item should be added. |
| * |
| * parameters: |
| * lStyle = additional style flags |
| * x,y = x & y positions IN DIALOG UNITS |
| * w,h = width and height IN DIALOG UNITS |
| * Id = ID used in messages |
| * clss = class ID, e.g 0x80 for a button, 0x82 for a static |
| * caption = usually text or resource name |
| * |
| * TODO: use the length information noted here to enable the dialog creation |
| * routines to work out more exactly how much memory they need to alloc. |
| */ |
| static LPWORD |
| add_dialog_element( |
| LPWORD p, |
| DWORD lStyle, |
| WORD x, |
| WORD y, |
| WORD w, |
| WORD h, |
| WORD Id, |
| BYTE clss, |
| const char *caption) |
| { |
| |
| lStyle = lStyle | WS_VISIBLE | WS_CHILD; |
| |
| add_word(x); |
| add_word(y); |
| add_word(w); |
| add_word(h); |
| add_word(Id); |
| add_long(lStyle); |
| add_byte(clss); |
| if (((lStyle & SS_ICON) != 0) && (clss == 0x82)) |
| { |
| /* Use resource ID */ |
| add_byte(0xff); |
| add_byte(*caption); |
| } |
| else |
| add_string(caption); |
| |
| add_byte(0); //# of extra bytes following |
| |
| |
| return p; |
| } |
| |
| #undef add_byte |
| #undef add_string |
| #undef add_long |
| #undef add_word |
| |
| #endif /* FEAT_GUI_DIALOG */ |
| |
| static void |
| get_dialog_font_metrics(void) |
| { |
| DWORD dlgFontSize; |
| dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/ |
| s_dlgfntwidth = LOWORD(dlgFontSize); |
| s_dlgfntheight = HIWORD(dlgFontSize); |
| } |
| |
| |
| #if defined(FEAT_TOOLBAR) || defined(PROTO) |
| #include "gui_w3~1.h" |
| /* |
| * Create the toolbar, initially unpopulated. |
| * (just like the menu, there are no defaults, it's all |
| * set up through menu.vim) |
| */ |
| static void |
| initialise_toolbar(void) |
| { |
| s_toolbarhwnd = CreateToolbar( |
| s_hwnd, |
| WS_CHILD | WS_VISIBLE, |
| CMD_TB_BASE, /*<vn>*/ |
| 31, //number of images in initial bitmap |
| s_hinst, |
| IDR_TOOLBAR1, // id of initial bitmap |
| NULL, |
| 0 // initial number of buttons |
| ); |
| |
| gui_mch_show_toolbar(vim_strchr(p_go, GO_TOOLBAR) != NULL); |
| } |
| #endif |
| |
| #if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO) |
| /* |
| * Make the GUI window come to the foreground. |
| */ |
| void |
| gui_mch_set_foreground(void) |
| { |
| if (IsIconic(s_hwnd)) |
| SendMessage(s_hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); |
| SetActiveWindow(s_hwnd); |
| } |
| #endif |