gui_w32.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:132k
源码类别:
编辑器/阅读器
开发平台:
DOS
- FILE *fd;
- char line[LINE_LEN];
- char_u *fname;
- fname = expand_env_save((char_u *)"$VIM/rgb.txt");
- if (fname == NULL)
- return (GuiColor)-1;
- fd = fopen((char *)fname, "rt");
- vim_free(fname);
- if (fd == NULL)
- return (GuiColor)-1;
- while (!feof(fd))
- {
- int len;
- int pos;
- char *color;
- fgets(line, LINE_LEN, fd);
- len = strlen(line);
- if (len <= 1 || line[len-1] != 'n')
- continue;
- line[len-1] = ' ';
- i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
- if (i != 3)
- continue;
- color = line + pos;
- if (STRICMP(color, name) == 0)
- {
- fclose(fd);
- return (GuiColor) RGB(r,g,b);
- }
- }
- fclose(fd);
- }
- return (GuiColor)-1;
- }
- /*
- * Set the current text foreground color.
- */
- void
- gui_mch_set_fg_color(GuiColor color)
- {
- gui.currFgColor = color;
- }
- /*
- * Set the current text background color.
- */
- void
- gui_mch_set_bg_color(GuiColor color)
- {
- gui.currBgColor = color;
- }
- #if defined(MULTI_BYTE) || defined(PROTO)
- /*
- * Multi-byte handling, by Sung-Hoon Baek
- */
- static void
- HanExtTextOut(HDC hdc,int X, int Y, UINT fuOption, const RECT *lprc,
- LPCTSTR lpString, UINT cbCount, const int *lpDx, BOOL bOpaque)
- {
- LPCTSTR pszTemp;
- int i;
- HPEN hpen, old_pen;
- POINT point;
- if (gui.char_width == sysfixed_width && gui.char_height == sysfixed_height)
- {
- hpen = CreatePen(PS_SOLID, 2, gui.currFgColor);
- old_pen = SelectObject(hdc, hpen);
- pszTemp = lpString;
- i = 0;
- while (cbCount > 0)
- {
- if (cbCount > 1 && IsLeadByte(*pszTemp))
- {
- cbCount -= 2;
- pszTemp += 2;
- i += 2;
- }
- else if (*pszTemp == '\')
- {
- if (i > 0)
- ExtTextOut(hdc, X+((pszTemp-i)-lpString)*gui.char_width, Y,
- fuOption, lprc, pszTemp-i, i, lpDx);
- MoveToEx(hdc, (int)(X+(pszTemp-lpString)*gui.char_width
- + gui.char_width*0.2),
- (int)(Y + gui.char_height*0.2), &point);
- LineTo(hdc, (int)(X+(pszTemp-lpString)*gui.char_width
- + gui.char_width*0.8),
- (int)(Y + gui.char_height*0.75));
- pszTemp++;
- cbCount--;
- i = 0;
- }
- else
- {
- pszTemp++;
- cbCount--;
- i++;
- }
- }
- if (i > 0)
- {
- int OldBkMode;
- if (bOpaque)
- {
- OldBkMode = GetBkMode(hdc);
- SetBkMode(hdc, OPAQUE);
- }
- ExtTextOut(hdc,X+((pszTemp-i)-lpString)*gui.char_width,Y,
- fuOption,lprc,pszTemp-i,i,lpDx);
- if (bOpaque)
- SetBkMode(hdc, OldBkMode);
- }
- DeleteObject(SelectObject(hdc, old_pen));
- }
- else
- ExtTextOut(hdc,X,Y,fuOption,lprc,lpString,cbCount,lpDx);
- }
- # if defined(MULTI_BYTE_IME) || defined(PROTO)
- #include <imm.h>
- static BOOL bKoreanMode = FALSE;
- static char lpCompStr[100]; // Pointer to composition str.
- static BOOL bInComposition=FALSE;
- static BOOL bCommandMode=TRUE;
- static BOOL bImeKorean=FALSE;
- /*
- * display composition string(korean)
- */
- static void
- DisplayCompStringOpaque(char_u *s, int len)
- {
- int OldBkMode = GetBkMode(s_hdc);
- SetBkMode(s_hdc,OPAQUE);
- gui_outstr_nowrap(s,len,GUI_MON_TRS_CURSOR , (GuiColor)0, (GuiColor)0 ,0);
- SetBkMode(s_hdc,OldBkMode);
- }
- /*
- * When enter to insert mode, set IME to previous language mode
- */
- void
- ImeSetOriginMode(void)
- {
- HIMC hImc;
- DWORD dwConvMode, dwSentMode;
- if ((hImc = ImmGetContext(s_hwnd)))
- {
- ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
- if (!(dwConvMode & IME_CMODE_NATIVE) && bKoreanMode == TRUE)
- {
- ImmSimulateHotKey(s_hwnd, IME_KHOTKEY_ENGLISH);
- }
- else
- bKoreanMode = FALSE;
- }
- bCommandMode = FALSE;
- }
- /* When enter to command mode, set IME to english mode */
- void
- ImeSetEnglishMode(void)
- {
- HIMC hImc;
- DWORD dwConvMode, dwSentMode;
- if ((hImc = ImmGetContext(s_hwnd)))
- {
- ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
- if (dwConvMode & IME_CMODE_NATIVE)
- {
- ImmSimulateHotKey(s_hwnd, IME_KHOTKEY_ENGLISH);
- bKoreanMode = TRUE;
- }
- else
- bKoreanMode = FALSE;
- }
- bCommandMode = TRUE;
- }
- /* get composition string from WIN_IME */
- static void
- GetCompositionStr(HWND hwnd, LPARAM CompFlag)
- {
- DWORD dwBufLen; // Stogare for len. of composition str
- HIMC hIMC; // Input context handle.
- // If fail to get input context handle then do nothing.
- // Applications should call ImmGetContext API to get
- // input context handle.
- if (!(hIMC = ImmGetContext(hwnd)))
- return;
- // Determines how much memory space to store the composition string.
- // Applications should call ImmGetCompositionString with
- // GCS_COMPSTR flag on, buffer length zero, to get the bullfer
- // length.
- if ((dwBufLen = ImmGetCompositionString( hIMC, GCS_COMPSTR,
- (void FAR*)NULL, 0l)) < 0)
- goto exit2;
- if (dwBufLen > 99)
- goto exit2;
- // Reads in the composition string.
- if ( dwBufLen != 0 )
- {
- ImmGetCompositionString(hIMC, GCS_COMPSTR, lpCompStr, dwBufLen);
- lpCompStr[dwBufLen] = 0;
- }
- else
- {
- strcpy(lpCompStr," ");
- dwBufLen = 2;
- }
- // Display new composition chars.
- DisplayCompStringOpaque(lpCompStr, dwBufLen);
- exit2:
- ImmReleaseContext(hwnd, hIMC);
- }
- // void GetResultStr()
- //
- // This handles WM_IME_COMPOSITION with GCS_RESULTSTR flag on.
- //
- // get complete composition string
- static void
- GetResultStr(HWND hwnd)
- {
- DWORD dwBufLen; // Storage for length of result str.
- HIMC hIMC; // Input context handle.
- // If fail to get input context handle then do nothing.
- if (!(hIMC = ImmGetContext(hwnd)))
- return;
- // Determines how much memory space to store the result string.
- // Applications should call ImmGetCompositionString with
- // GCS_RESULTSTR flag on, buffer length zero, to get the bullfer
- // length.
- if ((dwBufLen = ImmGetCompositionString( hIMC, GCS_RESULTSTR,
- (void FAR *)NULL, (DWORD) 0)) <= 0)
- goto exit2;
- if (dwBufLen > 99)
- goto exit2;
- // Reads in the result string.
- ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpCompStr, dwBufLen);
- // Displays the result string.
- DisplayCompStringOpaque(lpCompStr, dwBufLen);
- exit2:
- ImmReleaseContext(hwnd, hIMC);
- }
- /* this handles WM_IME_STARTCOMPOSITION */
- static void
- ImeUIStartComposition(HWND hwnd)
- {
- bInComposition = TRUE;
- //GetResultStr( hwnd );
- }
- /* WM_IME_COMPOSITION */
- static void
- ImeUIComposition(HWND hwnd, WPARAM wParam,LPARAM CompFlag)
- {
- if (CompFlag & GCS_RESULTSTR)
- GetResultStr( hwnd );
- else if (CompFlag & GCS_COMPSTR)
- GetCompositionStr( hwnd, CompFlag );
- }
- /* WM_IME_COMPOSITION */
- static void
- ImeUIEndComposition(HWND hwnd)
- {
- bInComposition = FALSE;
- //GetResultStr( hwnd );
- }
- static char *
- ImeGetTempComposition(void)
- {
- if ( bInComposition == TRUE /* && bCommandMode == FALSE */)
- {
- HIMC hImc;
- DWORD dwConvMode, dwSentMode;
- if ((hImc = ImmGetContext(s_hwnd)))
- {
- ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
- if ((dwConvMode & IME_CMODE_NATIVE))
- return lpCompStr;
- }
- }
- return NULL;
- }
- static void
- ImeNotify(WPARAM w, LPARAM l)
- {
- HIMC hImc;
- DWORD dwConvMode, dwSentMode;
- if ((hImc = ImmGetContext(s_hwnd)))
- {
- ImmGetConversionStatus(hImc, &dwConvMode, &dwSentMode);
- if (dwConvMode & IME_CMODE_NATIVE)
- bImeKorean = TRUE;
- else
- bImeKorean = FALSE;
- }
- }
- # if 0 // This is not used !?
- void
- ImeOpenClose(HWND hWnd, BOOL fFlag)
- {
- HIMC hIMC;
- //
- // If fFlag is true then open IME; otherwise close it.
- //
- if (!(hIMC = ImmGetContext(hWnd)))
- return;
- ImmSetOpenStatus(hIMC, fFlag);
- ImmReleaseContext(hWnd, hIMC);
- }
- /*
- * IsDBCSTrailByte - returns TRUE if the given byte is a DBCS trail byte
- *
- * The algorithm searchs backward in the string, to some known
- * character boundary, counting consecutive bytes in the lead
- * byte range. An odd number indicates the current byte is part
- * of a two byte character code.
- *
- * INPUT: PCHAR - pointer to a preceding known character boundary.
- * PCHAR - pointer to the character to test.
- *
- * OUTPUT:BOOL - indicating truth of p==trailbyte.
- *
- */
- int
- IsDBCSTrailByte(char *base, char *p)
- {
- int lbc = 0; // lead byte count
- if (base > p)
- return 0;
- if (strlen(base) <= (size_t)(p-base))
- return 0;
- while (p > base)
- {
- if (!IsLeadByte(*(--p)))
- break;
- lbc++;
- }
- return (lbc & 1);
- }
- # endif /* not used */
- # endif /* MULTI_BYTE_IME */
- #endif /* MULTI_BYTE */
- #define UNIBUFSIZE 2000 /* a big buffer */
- void
- gui_mch_draw_string(
- int row,
- int col,
- char_u *s,
- int len,
- int flags)
- {
- static int *padding = NULL;
- static int pad_size = 0;
- #ifdef MULTI_BYTE
- static WCHAR *unicodebuf = NULL;
- #endif
- HPEN hpen, old_pen;
- int y;
- int i;
- #if 1
- /*
- * 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;
- #ifdef MULTI_BYTE_IME
- char *szComp;
- #endif
- #ifdef MULTI_BYTE
- int OrgLen;
- if (is_dbcs)
- {
- OrgLen = len;
- if (IsLeadByte(s[len-1]))
- {
- if (s[len] > 30)
- len++;
- }
- }
- #endif
- 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);
- rc.right = FILL_X(col + len); /* Add +1 to erase fake bold? */
- rc.bottom = FILL_Y(row + 1);
- hbr = CreateSolidBrush(gui.currBgColor);
- FillRect(s_hdc, &rc, hbr);
- DeleteBrush(hbr);
- SetBkMode(s_hdc, TRANSPARENT);
- }
- #else
- /*
- * The alternative would be to write the characters in opaque mode, but
- * when the text is not exactly the same proportions as normal text, too
- * big or too little a rectangle gets drawn for the background.
- */
- SetBkMode(s_hdc, OPAQUE);
- SetBkColor(s_hdc, gui.currBgColor);
- #endif
- SetTextColor(s_hdc, gui.currFgColor);
- SelectFont(s_hdc, gui.currFont);
- 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;
- }
- /*
- * 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.
- */
- #ifdef MULTI_BYTE_IME
- if (is_dbcs)
- {
- /* draw an incomplete composition character(korean) */
- if (OrgLen == 1 && blink_state == BLINK_ON
- && (szComp = ImeGetTempComposition()) != NULL) // hangul
- HanExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL, szComp,
- 2, padding, TRUE);
- else
- HanExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL, (char *)s,
- len, padding, FALSE);
- }
- else
- #endif
- {
- #ifdef MULTI_BYTE
- /* if we want to display DBCS, and the current CP is not the DBCS one,
- * we need to go via Unicode */
- if (is_funky_dbcs)
- {
- /* check if our output buffer exists, if not create it */
- if (unicodebuf == NULL)
- unicodebuf = (WCHAR *)alloc(UNIBUFSIZE);
- if (unicodebuf != NULL)
- {
- if (len = MultiByteToWideChar(is_dbcs,
- MB_PRECOMPOSED,
- (char *)s, len,
- (LPWSTR)unicodebuf, UNIBUFSIZE))
- ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL,
- unicodebuf, len, NULL);
- }
- }
- else
- #endif
- ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL,
- (char *)s, len, padding);
- }
- if (flags & DRAW_UNDERL)
- {
- hpen = CreatePen(PS_SOLID, 1, gui.currFgColor);
- old_pen = SelectObject(s_hdc, hpen);
- y = FILL_Y(row + 1) - 1;
- 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));
- }
- }
- /*
- * Return OK if the key with the termcap name "name" is supported.
- */
- int
- gui_mch_haskey(char_u *name)
- {
- int i;
- for (i = 0; special_keys[i].vim_code1 != NUL; i++)
- if (name[0] == special_keys[i].vim_code0 &&
- name[1] == special_keys[i].vim_code1)
- return OK;
- return FAIL;
- }
- void
- gui_mch_beep(void)
- {
- MessageBeep(MB_OK);
- }
- void
- gui_mch_flash(void)
- {
- RECT rc;
- /*
- * Note: InvertRect() excludes right and bottom of rectangle.
- */
- rc.left = 0;
- rc.top = 0;
- rc.right = gui.num_cols * gui.char_width;
- rc.bottom = gui.num_rows * gui.char_height;
- InvertRect(s_hdc, &rc);
- ui_delay(20L, TRUE); /* wait 1/50 of a second */
- InvertRect(s_hdc, &rc);
- }
- /*
- * Invert a rectangle from row r, column c, for nr rows and nc columns.
- */
- void
- gui_mch_invert_rectangle(
- int r,
- int c,
- int nr,
- int nc)
- {
- RECT rc;
- /*
- * Note: InvertRect() excludes right and bottom of rectangle.
- */
- rc.left = FILL_X(c);
- rc.top = FILL_Y(r);
- rc.right = rc.left + nc * gui.char_width;
- rc.bottom = rc.top + nr * gui.char_height;
- InvertRect(s_hdc, &rc);
- }
- /*
- * Iconify the GUI window.
- */
- void
- gui_mch_iconify(void)
- {
- ShowWindow(s_hwnd, SW_MINIMIZE);
- }
- #if defined(HAVE_OLE) || defined(PROTO)
- /*
- * Make the GUI window come to the foreground.
- */
- void
- gui_mch_set_foreground(void)
- {
- SetForegroundWindow(s_hwnd);
- }
- #endif
- /*
- * Set the window title
- */
- void
- gui_mch_settitle(
- char_u *title,
- char_u *icon)
- {
- if (title != NULL)
- SetWindowText(s_hwnd, (LPCSTR)title);
- }
- /*
- * Draw a cursor without focus.
- */
- void
- gui_mch_draw_hollow_cursor(GuiColor color)
- {
- HBRUSH hbr;
- RECT rc;
- /*
- * Note: FrameRect() excludes right and bottom of rectangle.
- */
- rc.left = FILL_X(gui.col);
- rc.top = FILL_Y(gui.row);
- rc.right = rc.left + gui.char_width;
- rc.bottom = rc.top + gui.char_height;
- hbr = CreateSolidBrush(color);
- FrameRect(s_hdc, &rc, hbr);
- DeleteBrush(hbr);
- }
- /*
- * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
- * color "color".
- */
- void
- gui_mch_draw_part_cursor(
- int w,
- int h,
- GuiColor color)
- {
- HBRUSH hbr;
- RECT rc;
- /*
- * Note: FillRect() excludes right and bottom of rectangle.
- */
- rc.left =
- #ifdef RIGHTLEFT
- /* vertical line should be on the right of current point */
- State != CMDLINE && curwin->w_p_rl ? FILL_X(gui.col + 1) - w :
- #endif
- FILL_X(gui.col);
- rc.top = FILL_Y(gui.row) + gui.char_height - h;
- rc.right = rc.left + w;
- rc.bottom = rc.top + h;
- hbr = CreateSolidBrush(color);
- FillRect(s_hdc, &rc, hbr);
- DeleteBrush(hbr);
- }
- /*
- * Process a single Windows message.
- * If one is not available we hang until one is.
- */
- static void
- process_message(void)
- {
- MSG msg;
- UINT vk; /* Virtual key */
- char_u string[3];
- int i;
- int modifiers = 0;
- int key;
- GetMessage(&msg, NULL, 0, 0);
- #ifdef HAVE_OLE
- /* Look after OLE Automation commands */
- if (msg.message == WM_OLE)
- {
- char_u *str = (char_u *)msg.lParam;
- add_to_input_buf(str, strlen(str));
- vim_free(str);
- return;
- }
- #endif
- #ifdef WIN32_FIND_REPLACE
- /* Don't process messages used by the dialog */
- if ((s_findrep_hwnd) && (IsDialogMessage(s_findrep_hwnd, &msg)))
- return;
- #endif
- /*
- * Check if it's a special key that we recognise. If not, call
- * TranslateMessage().
- */
- if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
- {
- vk = (int) msg.wParam;
- /* handle key after dead key, but ignore shift, alt and control */
- if (dead_key && vk != VK_SHIFT && vk != VK_MENU && vk != VK_CONTROL)
- {
- dead_key = 0;
- /* handle non-alphabetic keys (ones that hopefully cannot generate
- * umlaut-characters), unless when control is down */
- if (vk < 'A' || vk > 'Z' || (GetKeyState(VK_CONTROL) & 0x8000))
- {
- MSG dm;
- dm.message = msg.message;
- dm.hwnd = msg.hwnd;
- dm.wParam = VK_SPACE;
- TranslateMessage(&dm); /* generate dead character */
- if (vk != VK_SPACE) /* and send current character once more */
- PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
- return;
- }
- }
- /* Check for CTRL-BREAK */
- if (vk == VK_CANCEL)
- {
- trash_input_buf();
- got_int = TRUE;
- string[0] = Ctrl('C');
- add_to_input_buf(string, 1);
- }
- for (i = 0; special_keys[i].key_sym != 0; i++)
- {
- /* ignore VK_SPACE when ALT key pressed: system menu */
- if (special_keys[i].key_sym == vk
- && (vk != VK_SPACE || !(GetKeyState(VK_MENU) & 0x8000)))
- {
- if (GetKeyState(VK_SHIFT) & 0x8000)
- modifiers |= MOD_MASK_SHIFT;
- /*
- * Don't use caps-lock as shift, because these are special keys
- * being considered here, and we only want letters to get
- * shifted -- webb
- */
- /*
- if (GetKeyState(VK_CAPITAL) & 0x0001)
- modifiers ^= MOD_MASK_SHIFT;
- */
- if (GetKeyState(VK_CONTROL) & 0x8000)
- modifiers |= MOD_MASK_CTRL;
- if (GetKeyState(VK_MENU) & 0x8000)
- modifiers |= MOD_MASK_ALT;
- if (special_keys[i].vim_code1 == NUL)
- key = special_keys[i].vim_code0;
- else
- key = TO_SPECIAL(special_keys[i].vim_code0,
- special_keys[i].vim_code1);
- key = simplify_key(key, &modifiers);
- if (modifiers)
- {
- string[0] = CSI;
- string[1] = KS_MODIFIER;
- string[2] = modifiers;
- add_to_input_buf(string, 3);
- }
- if (IS_SPECIAL(key))
- {
- string[0] = CSI;
- string[1] = K_SECOND(key);
- string[2] = K_THIRD(key);
- add_to_input_buf(string, 3);
- }
- else
- {
- string[0] = key;
- add_to_input_buf(string, 1);
- }
- break;
- }
- }
- if (special_keys[i].key_sym == 0)
- {
- /* Some keys need C-S- where they should only need C- */
- if ((GetKeyState(VK_CONTROL) & 0x8000)
- && !(GetKeyState(VK_SHIFT) & 0x8000)
- && !(GetKeyState(VK_MENU) & 0x8000))
- {
- if (vk == '6')
- {
- string[0] = Ctrl('^');
- add_to_input_buf(string, 1);
- }
- /* vk == 0xDB AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
- else if (vk == 0xBD) /* QWERTY for CTRL-'-' */
- {
- string[0] = Ctrl('_');
- add_to_input_buf(string, 1);
- }
- else
- TranslateMessage(&msg);
- }
- else
- TranslateMessage(&msg);
- }
- }
- #ifdef MULTI_BYTE_IME
- else if (msg.message == WM_IME_STARTCOMPOSITION)
- ImeUIStartComposition(s_hwnd);
- else if (msg.message == WM_IME_COMPOSITION)
- ImeUIComposition(s_hwnd, msg.wParam, msg.lParam);
- else if (msg.message == WM_IME_ENDCOMPOSITION)
- ImeUIEndComposition(s_hwnd);
- else if (msg.message == WM_IME_COMPOSITIONFULL)
- ImeUIEndComposition(s_hwnd);
- else if (msg.message == WM_IME_NOTIFY)
- ImeNotify(msg.wParam, msg.lParam);
- #endif
- DispatchMessage(&msg);
- }
- /*
- * Catch up with any queued events. This may put keyboard input into the
- * input buffer, call resize call-backs, trigger timers etc. If there is
- * nothing in the event queue (& no timers pending), then we return
- * immediately.
- */
- void
- gui_mch_update(void)
- {
- MSG msg;
- while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)
- && !vim_is_input_buf_full())
- process_message();
- }
- /*
- * GUI input routine called by gui_wait_for_chars(). Waits for a character
- * from the keyboard.
- * wtime == -1 Wait forever.
- * wtime == 0 This should never happen.
- * wtime > 0 Wait wtime milliseconds for a character.
- * Returns OK if a character was found to be available within the given time,
- * or FAIL otherwise.
- */
- int
- gui_mch_wait_for_chars(int wtime)
- {
- MSG msg;
- int focus;
- s_timed_out = FALSE;
- if (wtime > 0)
- s_wait_timer = SetTimer(NULL, 0, (UINT)wtime, (TIMERPROC)_OnTimer);
- focus = gui.in_focus;
- while (!s_timed_out)
- {
- /* Stop or start blinking when focus changes */
- if (gui.in_focus != focus)
- {
- if (gui.in_focus)
- gui_mch_start_blink();
- else
- gui_mch_stop_blink();
- focus = gui.in_focus;
- }
- /*
- * Don't use gui_mch_update() because then we will spin-lock until a
- * char arrives, instead we use GetMessage() to hang until an
- * event arrives. No need to check for input_buf_full because we are
- * returning as soon as it contains a single char -- webb
- */
- process_message();
- if (!vim_is_input_buf_empty())
- {
- if (s_wait_timer != 0 && !s_timed_out)
- {
- KillTimer(NULL, s_wait_timer);
- /* Eat spurious WM_TIMER messages */
- while (PeekMessage(&msg, s_hwnd,
- WM_TIMER, WM_TIMER, PM_REMOVE));
- s_wait_timer = 0;
- }
- return OK;
- }
- }
- return FAIL;
- }
- /*
- * Output routines.
- */
- /* Flush any output to the screen */
- void
- gui_mch_flush(void)
- {
- /* Is anything needed here? */
- }
- static void
- clear_rect(RECT *rcp)
- {
- HBRUSH hbr;
- hbr = CreateSolidBrush(gui.back_pixel);
- FillRect(s_hdc, rcp, hbr);
- DeleteBrush(hbr);
- }
- /*
- * Clear a rectangular region of the screen from text pos (row1, col1) to
- * (row2, col2) inclusive.
- */
- void
- gui_mch_clear_block(
- int row1,
- int col1,
- int row2,
- int col2)
- {
- RECT rc;
- /*
- * Clear one extra pixel at the right, for when bold characters have
- * spilled over to the next column. Note: FillRect() excludes right and
- * bottom of rectangle.
- * Can this ever erase part of the next character? - webb
- */
- rc.left = FILL_X(col1);
- rc.top = FILL_Y(row1);
- rc.right = FILL_X(col2 + 1) + 1;
- rc.bottom = FILL_Y(row2 + 1);
- clear_rect(&rc);
- }
- /*
- * Clear the whole text window.
- */
- void
- gui_mch_clear_all(void)
- {
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.right = Columns * gui.char_width + 2 * gui.border_width;
- rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
- clear_rect(&rc);
- }
- /*
- * Delete the given number of lines from the given row, scrolling up any
- * text further down within the scroll region.
- */
- void
- gui_mch_delete_lines(
- int row,
- int num_lines)
- {
- if (num_lines <= 0)
- return;
- if (row + num_lines > gui.scroll_region_bot)
- {
- /* Scrolled out of region, just blank the lines out */
- gui_clear_block(row, 0, gui.scroll_region_bot, Columns - 1);
- }
- else
- {
- RECT rc;
- rc.left = FILL_X(0);
- rc.right = FILL_X(Columns);
- rc.top = FILL_Y(row);
- rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
- /* The SW_INVALIDATE is required when part of the window is covered or
- * off-screen. How do we avoid it when it's not needed? */
- ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height,
- &rc, &rc, NULL, NULL, SW_INVALIDATE);
- /* Update gui.cursor_row if the cursor scrolled or copied over */
- if (gui.cursor_row >= row)
- {
- if (gui.cursor_row < row + num_lines)
- gui.cursor_is_valid = FALSE;
- else if (gui.cursor_row <= gui.scroll_region_bot)
- gui.cursor_row -= num_lines;
- }
- gui_undraw_cursor();
- UpdateWindow(s_textArea);
- gui_clear_block(gui.scroll_region_bot - num_lines + 1, 0,
- gui.scroll_region_bot, Columns - 1);
- }
- }
- /*
- * Insert the given number of lines before the given row, scrolling down any
- * following text within the scroll region.
- */
- void
- gui_mch_insert_lines(
- int row,
- int num_lines)
- {
- if (num_lines <= 0)
- return;
- if (row + num_lines > gui.scroll_region_bot)
- {
- /* Scrolled out of region, just blank the lines out */
- gui_clear_block(row, 0, gui.scroll_region_bot, Columns - 1);
- }
- else
- {
- RECT rc;
- rc.left = FILL_X(0);
- rc.right = FILL_X(Columns);
- rc.top = FILL_Y(row);
- rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
- /* The SW_INVALIDATE is required when part of the window is covered or
- * off-screen. How do we avoid it when it's not needed? */
- ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height,
- &rc, &rc, NULL, NULL, SW_INVALIDATE);
- /* Update gui.cursor_row if the cursor scrolled or copied over */
- if (gui.cursor_row >= gui.row)
- {
- if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
- gui.cursor_row += num_lines;
- else if (gui.cursor_row <= gui.scroll_region_bot)
- gui.cursor_is_valid = FALSE;
- }
- gui_undraw_cursor();
- UpdateWindow(s_textArea);
- gui_clear_block(row, 0, row + num_lines - 1, Columns - 1);
- }
- }
- /*
- * Menu stuff.
- */
- void
- gui_mch_enable_menu(int flag)
- {
- SetMenu(s_hwnd, flag ? s_menuBar : NULL);
- }
- void
- gui_mch_set_menu_pos(
- int x,
- int y,
- int w,
- int h)
- {
- /* It will be in the right place anyway */
- }
- /*
- * Add a sub menu to the menu bar.
- */
- void
- gui_mch_add_menu(
- GuiMenu *menu,
- GuiMenu *parent,
- int pos)
- {
- menu->submenu_id = CreatePopupMenu();
- menu->id = s_menu_id++;
- menu->parent = parent;
- if (gui_menubar_menu(menu->name))
- {
- if (is_winnt_3())
- {
- InsertMenu((parent == NULL) ? s_menuBar : parent->submenu_id,
- (UINT)pos, MF_POPUP | MF_STRING | MF_BYPOSITION,
- (UINT)menu->submenu_id, (LPCTSTR) menu->name);
- }
- else
- {
- MENUITEMINFO info;
- info.cbSize = sizeof(info);
- info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID | MIIM_SUBMENU;
- info.dwItemData = (DWORD)menu;
- info.wID = menu->id;
- info.fType = MFT_STRING;
- info.dwTypeData = (LPTSTR)menu->name;
- info.cch = STRLEN(menu->name);
- info.hSubMenu = menu->submenu_id;
- InsertMenuItem((parent == NULL) ? s_menuBar : parent->submenu_id,
- (UINT)pos, TRUE, &info);
- }
- }
- /* Fix window size if menu may have wrapped */
- if (parent == NULL)
- gui_w32_get_menu_height(!gui.starting);
- }
- void
- gui_mch_show_popupmenu(GuiMenu *menu)
- {
- POINT mp;
- if (GetCursorPos((LPPOINT)&mp))
- {
- (void)TrackPopupMenu(
- (HMENU)menu->submenu_id,
- TPM_LEFTALIGN | TPM_LEFTBUTTON,
- (int)mp.x,
- (int)mp.y,
- (int)0, /*reserved param*/
- s_hwnd,
- NULL);
- /*
- * NOTE: The pop-up menu can eat the mouse up event.
- * We deal with this in normal.c.
- */
- }
- }
- /*
- * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
- * create it as a pseudo-"tearoff menu".
- */
- void
- gui_make_tearoff(char_u *path_name)
- {
- GuiMenu **menup;
- GuiMenu *menu = NULL;
- GuiMenu *parent = NULL;
- char_u *name;
- char_u *saved_name;
- char_u *p;
- menup = &gui.root_menu;
- saved_name = vim_strsave(path_name);
- if (saved_name == NULL)
- return;
- name = saved_name;
- while (*name)
- {
- /* Find in the menu hierarchy */
- p = gui_menu_name_skip(name);
- menu = *menup;
- while (menu != NULL)
- {
- if (STRCMP(name, menu->name) == 0 || STRCMP(name, menu->dname) == 0)
- {
- if (*p == NUL && menu->children == NULL)
- {
- /* not allowed to tear off one item*/
- EMSG("Menu path must lead to a sub-menu");
- vim_free(saved_name);
- return;
- }
- else if (*p != NUL && menu->children == NULL)
- {
- EMSG("Part of menu-item path is not sub-menu");
- vim_free(saved_name);
- return;
- }
- break;
- }
- menup = &menu->next;
- menu = menu->next;
- }
- menup = &menu->children;
- parent = menu;
- name = p;
- }
- vim_free(saved_name);
- if (menu == NULL)
- {
- EMSG("Menu not found - check menu names");
- return;
- }
- /* Found the menu, so tear it off. */
- gui_mch_tearoff(menu->dname, menu, 0xffffL, 0xffffL);
- }
- /*
- * Add a menu item to a menu
- */
- void
- gui_mch_add_menu_item(
- GuiMenu *menu,
- GuiMenu *parent,
- int idx)
- {
- menu->id = s_menu_id++;
- menu->submenu_id = NULL;
- menu->parent = parent;
- if (STRNCMP(menu->name, TEAR_STRING, TEAR_LEN) == 0)
- {
- InsertMenu(parent->submenu_id, (UINT)idx, MF_BITMAP|MF_BYPOSITION,
- (UINT)menu->id, (LPCTSTR) s_htearbitmap);
- }
- #ifdef USE_GUI_WIN32_TOOLBAR
- else if (STRCMP(parent->name, "ToolBar") == 0)
- {
- TBBUTTON newtb;
- vim_memset(&newtb, 0, sizeof(newtb));
- newtb.iBitmap = get_toolbar_bitmap(menu->name);
- newtb.idCommand = menu->id;
- newtb.fsStyle = TBSTYLE_BUTTON;
- newtb.fsState = TBSTATE_ENABLED;
- newtb.iString = 0;
- SendMessage(s_toolbarhwnd, TB_ADDBUTTONS, (WPARAM)1, (LPARAM) &newtb);
- menu->submenu_id = (HMENU)-1;
- }
- #endif
- else
- {
- InsertMenu(parent->submenu_id, (UINT)idx, MF_STRING|MF_BYPOSITION,
- (UINT)menu->id, (LPCTSTR) menu->name);
- if (IsWindow(parent->tearoff_handle))
- rebuild_tearoff(parent);
- }
- }
- /*
- * Destroy the machine specific menu widget.
- */
- void
- gui_mch_destroy_menu(GuiMenu *menu)
- {
- #ifdef USE_GUI_WIN32_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
- {
- RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND);
- if (menu->submenu_id != NULL)
- DestroyMenu(menu->submenu_id);
- if (IsWindow(menu->tearoff_handle))
- DestroyWindow(menu->tearoff_handle);
- if ((menu->parent != NULL) && (IsWindow(menu->parent->tearoff_handle)))
- rebuild_tearoff(menu->parent);
- }
- }
- static void
- rebuild_tearoff(GuiMenu *menu)
- {
- /*hackish*/
- char_u tbuf[128];
- RECT trect;
- RECT rct;
- RECT roct;
- int x, y;
- HWND thwnd = menu->tearoff_handle;
- GetWindowText(thwnd, tbuf, 127);
- if (GetWindowRect(thwnd, &trect) &&
- GetWindowRect(s_hwnd, &rct) &&
- GetClientRect(s_hwnd, &roct))
- {
- x = trect.left - rct.left;
- y = (trect.top - rct.bottom + roct.bottom);
- }
- else
- {
- x = y = 0xffffL;
- }
- DestroyWindow(thwnd);
- gui_mch_tearoff(tbuf, menu, x, y);
- if (IsWindow(menu->tearoff_handle))
- (void) SetWindowPos(menu->tearoff_handle,
- NULL,
- (int) trect.left,
- (int) trect.top,
- 0, 0,
- SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
- }
- /*
- * Make a menu either grey or not grey.
- */
- void
- gui_mch_menu_grey(
- GuiMenu *menu,
- int grey)
- {
- #ifdef USE_GUI_WIN32_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);
- #if 1
- if ((menu->parent != NULL) && (IsWindow(menu->parent->tearoff_handle)))
- {
- WORD menuID;
- HWND menuHandle;
- /*
- * A tearoff button has changed state.
- */
- if (menu->children == NULL)
- menuID = (WORD)(menu->id);
- else
- menuID = (WORD)((WORD)(menu->submenu_id) | (WORD)0x8000);
- menuHandle = GetDlgItem(menu->parent->tearoff_handle, menuID);
- if (menuHandle)
- EnableWindow(menuHandle, !grey);
- }
- #endif
- }
- /*
- * Make menu item hidden or not hidden
- */
- void
- gui_mch_menu_hidden(
- GuiMenu *menu,
- int hidden)
- {
- /*
- * This doesn't do what we want. Hmm, just grey the menu items for now.
- */
- /*
- if (hidden)
- EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
- else
- EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
- */
- gui_mch_menu_grey(menu, hidden);
- }
- /*
- * This is called after setting all the menus to grey/hidden or not.
- */
- void
- gui_mch_draw_menubar(void)
- {
- DrawMenuBar(s_hwnd);
- }
- /* cproto doesn't create a prototype for main() */
- int main __ARGS((int argc, char **argv));
- #ifndef PROTO
- void
- #ifdef VIMDLL
- _export
- #endif
- _cdecl
- SaveInst(HINSTANCE hInst)
- {
- s_hinst = hInst;
- }
- #endif
- /*
- * Return the lightness of a pixel. White is 255.
- */
- int
- gui_mch_get_lightness(pixel)
- GuiColor pixel;
- {
- return (GetRValue(pixel)*3 + GetGValue(pixel)*6 + GetBValue(pixel)) / 10;
- }
- /*
- * Return the RGB value of a pixel as "#RRGGBB".
- */
- char_u *
- gui_mch_get_rgb(
- GuiColor pixel)
- {
- static char_u retval[10];
- sprintf((char *)retval, "#%02x%02x%02x",
- GetRValue(pixel), GetGValue(pixel), GetBValue(pixel));
- return retval;
- }
- #ifdef USE_BROWSE
- /*
- * Pop open a file browser and return the file selected, in allocated memory,
- * or NULL if Cancel is hit.
- * saving - TRUE if the file will be saved to, FALSE if it will be opened.
- * title - Title message for the file browser dialog.
- * dflt - Default name of file.
- * ext - Default extension to be added to files without extensions.
- * initdir - directory in which to open the browser (NULL = current dir)
- * filter - Filter for matched files to choose from.
- * Has a format like this:
- * "C Files (*.c) *.c "
- * "All Files *.* "
- * If these two strings were concatenated, then a choice of two file
- * filters will be selectable to the user. Then only matching files will
- * be shown in the browser. If NULL, the default allows all files.
- *
- * *NOTE* - the filter string must be terminated with TWO nulls.
- */
- char_u *
- gui_mch_browse(
- int saving,
- char_u *title,
- char_u *dflt,
- char_u *ext,
- char_u *initdir,
- char_u *filter)
- {
- OPENFILENAME fileStruct;
- char_u fileBuf[MAX_PATH], *p;
- if (dflt == NULL)
- fileBuf[0] = ' ';
- else
- {
- STRNCPY(fileBuf, dflt, MAX_PATH - 1);
- fileBuf[MAX_PATH - 1] = NUL;
- }
- /*
- * The default filter. NOTE: should we perhaps put this in
- * feature.h?
- */
- if (filter == NULL)
- filter =
- "All Files (*.*) *.* "
- "C source (*.c, *.h) *.c;*.h "
- "C++ source (*.cpp, *.hpp) *.cpp;*.hpp "
- "VB code (*.bas, *.frm) *.bas;*.frm "
- "Vim files (*.vim, _vimrc, _gvimrc) *.vim;_vimrc;_gvimrc ";
- memset(&fileStruct, 0, sizeof(OPENFILENAME));
- fileStruct.lStructSize = sizeof(OPENFILENAME);
- fileStruct.lpstrFilter = filter;
- fileStruct.lpstrFile = fileBuf;
- fileStruct.nMaxFile = MAX_PATH;
- fileStruct.lpstrTitle = title;
- fileStruct.lpstrDefExt = ext;
- fileStruct.hwndOwner = s_hwnd; /* main Vim window is owner*/
- /* has an initial dir been specified? */
- if (initdir != NULL && *initdir != NUL)
- fileStruct.lpstrInitialDir = initdir;
- /*
- * TODO: Allow selection of multiple files. Needs another arg to this
- * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
- * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
- * files that don't exist yet, so I haven't put it in. What about
- * OFN_PATHMUSTEXIST?
- */
- fileStruct.Flags = (OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT
- | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY);
- if (saving)
- {
- if (!GetSaveFileName(&fileStruct))
- return NULL;
- }
- else
- {
- if (!GetOpenFileName(&fileStruct))
- return NULL;
- }
- /* Shorten the file name if possible */
- mch_dirname(IObuff, IOSIZE);
- p = shorten_fname(fileBuf, IObuff);
- if (p == NULL)
- p = fileBuf;
- return vim_strsave(p);
- }
- #endif /* USE_BROWSE */
- /* Convert pixels in X to dialog units */
- static WORD
- PixelToDialogX(int numPixels)
- {
- return (WORD)((numPixels * 4) / s_dlgfntwidth);
- }
- /* Convert pixels in Y to dialog units */
- static WORD
- PixelToDialogY(int numPixels)
- {
- return (WORD)((numPixels * 8) / s_dlgfntheight);
- }
- /* Return the width in pixels of the given text in the given DC. */
- static int
- GetTextWidth(HDC hdc, char_u *str, int len)
- {
- SIZE size;
- GetTextExtentPoint(hdc, str, len, &size);
- return size.cx;
- }
- #if defined(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 returns that button's ID - 2, which is the button's number.
- */
- static LRESULT CALLBACK
- dialog_callback(
- HWND hwnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam)
- {
- if (message == WM_INITDIALOG)
- {
- CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER));
- return (TRUE);
- }
- if (message == WM_COMMAND)
- {
- EndDialog (hwnd, (LOWORD(wParam) - 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)
- {
- WORD *p, *pdlgtemplate, *pnumitems;
- int numButtons;
- int *buttonWidths, *buttonPositions;
- char *dflt_text;
- int nchar, i;
- DWORD lStyle;
- int dlgwidth = 0;
- int horizWidth;
- int msgheight;
- char_u *pstart;
- char_u *pend;
- char_u *tbuffer;
- RECT rect;
- HWND hwnd;
- HDC hdc;
- HFONT font, oldFont;
- TEXTMETRIC fontInfo;
- int fontHeight;
- int textWidth, minButtonWidth, messageWidth;
- int maxDialogWidth;
- int vertical;
- int dlgPaddingX;
- int dlgPaddingY;
- #ifndef NO_CONSOLE
- /* Don't output anything in silent mode ("ex -s") */
- if (silent_mode)
- return dfltbutton; /* return default option */
- #endif
- if ((type < 0) || (type > VIM_LAST_TYPE))
- type = 0;
- /* allocate some memory for dialog template */
- /* TODO should compute this really*/
- pdlgtemplate = p = (PWORD) LocalAlloc(LPTR, DLG_ALLOC_SIZE);
- 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, and find default button text */
- pstart = tbuffer;
- numButtons = 1;
- dflt_text = NULL;
- for (i = 0; tbuffer[i] != ' '; i++)
- {
- if (tbuffer[i] == DLG_BUTTON_SEP)
- {
- if (numButtons++ == dfltbutton)
- dflt_text = &tbuffer[i + 1];
- }
- }
- if (dflt_text == NULL)
- {
- dflt_text = tbuffer;
- 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);
- font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- VARIABLE_PITCH , DLG_FONT_NAME);
- if (s_usenewlook)
- {
- oldFont = SelectFont(hdc, font);
- dlgPaddingX = DLG_PADDING_X;
- dlgPaddingY = DLG_PADDING_Y;
- }
- else
- {
- 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_CXSIZEFRAME) * 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_guioptions, 'v') != 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 */
- if (s_usenewlook)
- lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE |DS_SETFONT;
- else
- lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE;
- *p++ = LOWORD(lStyle);
- *p++ = HIWORD(lStyle);
- *p++ = 0; // LOWORD (lExtendedStyle)
- *p++ = 0; // HIWORD (lExtendedStyle)
- pnumitems = p; /*save where the number of items must be stored*/
- *p++ = 0; // NumberOfItems(will change later)
- *p++ = 10; // x
- *p++ = 10; // y
- *p++ = PixelToDialogX(dlgwidth); // cx
- // Dialog height.
- if (vertical)
- *p++ = PixelToDialogY(msgheight + 2 * dlgPaddingY +
- DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons);
- else
- *p++ = PixelToDialogY(msgheight + 3 * dlgPaddingY + 2 * fontHeight);
- *p++ = 0; // Menu
- *p++ = 0; // Class
- /* copy the title of the dialog */
- nchar = nCopyAnsiToWideChar(p, (title ?
- (LPSTR)title :
- (LPSTR)("Vim "VIM_VERSION_MEDIUM)));
- p += nchar;
- if (s_usenewlook)
- {
- /* do the font, since DS_3DLOOK doesn't work properly */
- *p++ = DLG_FONT_POINT_SIZE; //point size
- nchar = nCopyAnsiToWideChar (p, TEXT(DLG_FONT_NAME));
- p += nchar;
- }
- pstart = dflt_text;
- horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */
- i = dfltbutton; /* Start with default button */
- do
- {
- /* get end of this button. */
- for ( pend = pstart;
- *pend && (*pend != DLG_BUTTON_SEP);
- pend++)
- ;
- if (*pend)
- *pend = ' ';
- /*
- * 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.
- */
- if (vertical)
- {
- p = add_dialog_element(p,
- BS_PUSHBUTTON | WS_TABSTOP,
- PixelToDialogX(DLG_VERT_PADDING_X),
- PixelToDialogY(msgheight + 2 * dlgPaddingY
- + 2 * fontHeight * i),
- PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X),
- (WORD)(PixelToDialogY(2 * fontHeight) - 1),
- (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, pstart);
- }
- else
- {
- p = add_dialog_element(p,
- BS_PUSHBUTTON | WS_TABSTOP,
- PixelToDialogX(horizWidth + buttonPositions[i]),
- PixelToDialogY(msgheight + 2 * dlgPaddingY),
- PixelToDialogX(buttonWidths[i]),
- (WORD)(PixelToDialogY(2 * fontHeight) - 1),
- (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, pstart);
- }
- if (++i >= numButtons)
- {
- i = 0;
- pstart = tbuffer;
- }
- else
- pstart = pend + 1; /*next button*/
- } while (i != dfltbutton);
- *pnumitems += numButtons;
- /* Vim icon */
- p = add_dialog_element(p, SS_ICON,
- PixelToDialogX(dlgPaddingX),
- PixelToDialogY(dlgPaddingY),
- PixelToDialogX(DLG_ICON_WIDTH),
- PixelToDialogY(DLG_ICON_HEIGHT),
- 0, (WORD)0x0082, dlg_icons[type]);
- /* Dialog message */
- p = add_dialog_element(p, SS_LEFT,//SS_CENTER,
- PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
- PixelToDialogY(dlgPaddingY),
- (WORD)(PixelToDialogX(messageWidth) + 1),
- PixelToDialogY(msgheight),
- 1, (WORD)0x0082, message);
- *pnumitems += 2;
- SelectFont(hdc, oldFont);
- DeleteObject(font);
- ReleaseDC(hwnd, hdc);
- /*show the dialog box modally and get a return value*/
- nchar = DialogBoxIndirect(
- s_hinst,
- (LPDLGTEMPLATE)pdlgtemplate,
- s_hwnd,
- (DLGPROC)dialog_callback);
- LocalFree (LocalHandle (pdlgtemplate));
- vim_free(tbuffer);
- vim_free(buttonWidths);
- vim_free(buttonPositions);
- return nchar;
- }
- #endif /* GUI_DIALOG */
- /*
- * Put a simple element (basic class) onto a dialog template in memory.
- * return a pointer to where the next item shoudl be added.
- *
- * parameters:
- * lStyle = additional style flags
- * (be careful, NT3.51 & Win32s will ignore the new ones)
- * 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 0x0080 for a button, 0x0082 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 PWORD
- add_dialog_element(
- PWORD p,
- DWORD lStyle,
- WORD x,
- WORD y,
- WORD w,
- WORD h,
- WORD Id,
- WORD clss,
- const char *caption)
- {
- int nchar;
- p = lpwAlign(p); /* Align to dword boundary*/
- lStyle = lStyle | WS_VISIBLE | WS_CHILD;
- *p++ = LOWORD(lStyle);
- *p++ = HIWORD(lStyle);
- *p++ = 0; // LOWORD (lExtendedStyle)
- *p++ = 0; // HIWORD (lExtendedStyle)
- *p++ = x;
- *p++ = y;
- *p++ = w;
- *p++ = h;
- *p++ = Id; //9 or 10 words in all
- *p++ = (WORD)0xffff;
- *p++ = clss; //2 more here
- nchar = nCopyAnsiToWideChar(p, (LPSTR)caption); //strlen(caption)+1
- p += nchar;
- *p++ = 0; // advance pointer over nExtraStuff WORD - 2 more
- return p; //total = 15+ (strlen(caption)) words
- // = 30 + 2(strlen(caption) bytes reqd
- }
- /*
- * Helper routine. Take an input pointer, return closest pointer that is
- * aligned on a DWORD (4 byte) boundary. Taken from the Win32SDK samples.
- */
- static LPWORD
- lpwAlign(
- LPWORD lpIn)
- {
- ULONG ul;
- ul = (ULONG)lpIn;
- ul += 3;
- ul >>= 2;
- ul <<= 2;
- return (LPWORD)ul;
- }
- /*
- * Helper routine. Takes second parameter as Ansi string, copies it to first
- * parameter as wide character (16-bits / char) string, and returns integer
- * number of wide characters (words) in string (including the trailing wide
- * char NULL). Partly taken from the Win32SDK samples.
- */
- static int
- nCopyAnsiToWideChar(
- LPWORD lpWCStr,
- LPSTR lpAnsiIn)
- {
- int nChar = 0;
- do
- {
- if (*lpAnsiIn == 't')
- *lpWCStr++ = (WORD)' ';
- else
- *lpWCStr++ = (WORD)*lpAnsiIn;
- nChar++;
- } while (*lpAnsiIn++);
- return nChar;
- }
- /*
- * A quick little routine that will center one window over another, handy for
- * dialog boxes. Taken from the Win32SDK samples.
- */
- static BOOL
- CenterWindow(
- HWND hwndChild,
- HWND hwndParent)
- {
- RECT rChild, rParent;
- int wChild, hChild, wParent, hParent;
- int wScreen, hScreen, xNew, yNew;
- HDC hdc;
- GetWindowRect(hwndChild, &rChild);
- wChild = rChild.right - rChild.left;
- hChild = rChild.bottom - rChild.top;
- GetWindowRect(hwndParent, &rParent);
- wParent = rParent.right - rParent.left;
- hParent = rParent.bottom - rParent.top;
- hdc = GetDC(hwndChild);
- wScreen = GetDeviceCaps (hdc, HORZRES);
- hScreen = GetDeviceCaps (hdc, VERTRES);
- ReleaseDC(hwndChild, hdc);
- xNew = rParent.left + ((wParent - wChild) /2);
- if (xNew < 0)
- {
- xNew = 0;
- }
- else if ((xNew+wChild) > wScreen)
- {
- xNew = wScreen - wChild;
- }
- yNew = rParent.top + ((hParent - hChild) /2);
- if (yNew < 0)
- yNew = 0;
- else if ((yNew+hChild) > hScreen)
- yNew = hScreen - hChild;
- return SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0,
- SWP_NOSIZE | SWP_NOZORDER);
- }
- /*
- * The callback function for all the modeless dialogs that make up the
- * "tearoff menus" Very simple - forward button presses (to fool Vim into
- * thinking its menus have been clicked), and go away when closed.
- */
- static LRESULT CALLBACK
- tearoff_callback(
- HWND hwnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam)
- {
- if (message == WM_INITDIALOG)
- return (TRUE);
- if (message == WM_COMMAND)
- {
- if ((WORD)(LOWORD(wParam)) & 0x8000)
- {
- POINT mp;
- RECT rect;
- if (GetCursorPos(&mp) && GetWindowRect(hwnd, &rect));
- {
- (void)TrackPopupMenu(
- (HMENU)(LOWORD(wParam) ^ 0x8000),
- TPM_LEFTALIGN | TPM_LEFTBUTTON,
- (int)rect.right - 8,
- (int)mp.y,
- (int)0, /*reserved param*/
- s_hwnd,
- NULL);
- /*
- * NOTE: The pop-up menu can eat the mouse up event.
- * We deal with this in normal.c.
- */
- }
- }
- else
- /* Pass on messages to the main Vim window */
- PostMessage (s_hwnd, WM_COMMAND, LOWORD(wParam), 0);
- /*
- * Give main window the focus back: this is so after
- * choosing a tearoff button you can start typing again
- * straight away.
- */
- (void)SetFocus(s_hwnd);
- return TRUE;
- }
- if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
- {
- DestroyWindow(hwnd);
- return TRUE;
- }
- /* When moved around, give main window the focus back. */
- if (message == WM_EXITSIZEMOVE)
- (void)SetActiveWindow(s_hwnd);
- return FALSE;
- }
- /*
- * Create a pseudo-"tearoff menu" based on the child
- * items of a given menu pointer.
- */
- static void
- gui_mch_tearoff(
- char_u *title,
- GuiMenu *menu,
- int initX,
- int initY)
- {
- WORD *p, *pdlgtemplate, *pnumitems, *ptrueheight;
- int nchar, textWidth, submenuWidth;
- DWORD lStyle;
- DWORD lExtendedStyle;
- WORD dlgwidth;
- WORD menuID;
- GuiMenu *pmenu;
- GuiMenu *the_menu = menu;
- HWND hwnd;
- HDC hdc;
- HFONT font, oldFont;
- int col, spaceWidth, len;
- int columnWidths[2];
- char_u *label, *text, *end, *acEnd;
- int padding0, padding1, padding2;
- /*
- * If this menu is already torn off, then don't
- * tear it off again, but move the existing tearoff
- * to the mouse position.
- */
- if (IsWindow(menu->tearoff_handle))
- {
- POINT mp;
- if (GetCursorPos((LPPOINT)&mp))
- {
- SetWindowPos(menu->tearoff_handle, NULL, mp.x, mp.y, 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
- }
- return;
- }
- /*
- * Otherwise, create a new tearoff
- */
- if (*title == MNU_HIDDEN_CHAR)
- title++;
- /* allocate some memory to play with */
- /* TODO should compute this really */
- pdlgtemplate = p = (PWORD)LocalAlloc(LPTR, DLG_ALLOC_SIZE);
- if (p == NULL)
- return;
- hwnd = GetDesktopWindow();
- hdc = GetWindowDC(hwnd);
- font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- VARIABLE_PITCH , DLG_FONT_NAME);
- if (s_usenewlook)
- oldFont = SelectFont(hdc, font);
- else
- oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
- /*
- * Calculate width of a single space. Used for padding columns to the
- * right width.
- */
- spaceWidth = GetTextWidth(hdc, " ", 1);
- submenuWidth = 0;
- /* Figure out widths for each column. */
- for (col = 0; col < 2; col++)
- {
- columnWidths[col] = 0;
- for (pmenu = menu->children; pmenu != NULL; pmenu = pmenu->next)
- {
- text = (col == 0) ? pmenu->dname : pmenu->actext;
- if (pmenu->children != NULL)
- submenuWidth = TEAROFF_COLUMN_PADDING * spaceWidth;
- if (text != NULL && *text != NUL)
- {
- end = text + strlen(text);
- textWidth = GetTextWidth(hdc, text, end - text);
- if (textWidth > columnWidths[col])
- columnWidths[col] = textWidth;
- }
- }
- }
- if (columnWidths[1] == 0)
- {
- if (submenuWidth != 0)
- columnWidths[0] += submenuWidth;
- else
- columnWidths[0] += spaceWidth;
- }
- else
- {
- columnWidths[0] += TEAROFF_COLUMN_PADDING * spaceWidth;
- columnWidths[1] += submenuWidth;
- }
- /*
- * Now find the width of our 'menu'.
- */
- textWidth = 0;
- for (col = 0; col < 2; col++)
- textWidth += columnWidths[col];
- if (submenuWidth != 0)
- {
- submenuWidth = GetTextWidth(hdc, TEAROFF_SUBMENU_LABEL,
- STRLEN(TEAROFF_SUBMENU_LABEL));
- textWidth += submenuWidth;
- }
- dlgwidth = GetTextWidth(hdc, title, strlen(title));
- if (textWidth > dlgwidth)
- dlgwidth = textWidth;
- dlgwidth += 2 * TEAROFF_PADDING_X + TEAROFF_BUTTON_PAD_X;
- /* W95 can't do thin dialogs, they look v. weird! */
- if (mch_windows95() && dlgwidth < TEAROFF_MIN_WIDTH)
- dlgwidth = TEAROFF_MIN_WIDTH;
- /* start to fill in the dlgtemplate information. addressing by WORDs */
- if (s_usenewlook)
- lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU |DS_SETFONT| WS_VISIBLE;
- else
- lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU | WS_VISIBLE;
- lExtendedStyle = WS_EX_TOOLWINDOW|WS_EX_STATICEDGE;
- *p++ = LOWORD(lStyle);
- *p++ = HIWORD(lStyle);
- *p++ = LOWORD (lExtendedStyle);
- *p++ = HIWORD (lExtendedStyle);
- pnumitems = p; /* save where the number of items must be stored */
- *p++ = 0; // NumberOfItems(will change later)
- if (initX == 0xffffL)
- *p++ = PixelToDialogX(gui_mch_get_mouse_x()); // x
- else
- *p++ = PixelToDialogX(initX); // x
- if (initY == 0xffffL)
- *p++ = PixelToDialogY(gui_mch_get_mouse_y()); // y
- else
- *p++ = PixelToDialogY(initY); // y
- *p++ = PixelToDialogX(dlgwidth); // cx
- ptrueheight =p;
- *p++ = 0; // dialog height: changed later anyway
- *p++ = 0; // Menu
- *p++ = 0; // Class
- /* copy the title of the dialog */
- nchar = nCopyAnsiToWideChar(p, ((*title) ?
- (LPSTR)title :
- (LPSTR)("Vim "VIM_VERSION_MEDIUM)));
- p += nchar;
- if (s_usenewlook)
- {
- /* do the font, since DS_3DLOOK doesn't work properly */
- *p++ = DLG_FONT_POINT_SIZE; //point size
- nchar = nCopyAnsiToWideChar (p, TEXT(DLG_FONT_NAME));
- p += nchar;
- }
- /* Don't include tearbar in tearoff menu */
- if (STRCMP(menu->children->name, TEAR_STRING) == 0)
- menu = menu->children->next;
- else
- menu = menu->children;
- while (menu != NULL)
- {
- /* Figure out length of this menu label */
- len = STRLEN(menu->dname);
- end = menu->dname + STRLEN(menu->dname);
- padding0 = (columnWidths[0] - GetTextWidth(hdc, menu->dname,
- end - menu->dname)) / spaceWidth;
- len += padding0;
- if (menu->actext != NULL)
- {
- len += STRLEN(menu->actext);
- acEnd = menu->actext + STRLEN(menu->actext);
- }
- if (menu->actext != NULL)
- textWidth = GetTextWidth(hdc, menu->actext,
- acEnd - menu->actext);
- else
- textWidth = 0;
- padding1 = (columnWidths[1] - textWidth) / spaceWidth;
- len += padding1;
- if (menu->children == NULL)
- {
- padding2 = submenuWidth / spaceWidth;
- len += padding2;
- menuID = (WORD)(menu->id);
- }
- else
- {
- len += STRLEN(TEAROFF_SUBMENU_LABEL);
- menuID = (WORD)((WORD)(menu->submenu_id) | (WORD)0x8000);
- }
- /* Allocate menu label and fill it in */
- text = label = alloc((unsigned)len + 1);
- if (label == NULL)
- break;
- STRNCPY(text, menu->dname, end - menu->dname);
- text += end - menu->dname;
- while (padding0-- > 0)
- *text++ = ' ';
- if (menu->actext != NULL)
- {
- STRNCPY(text, menu->actext, acEnd - menu->actext);
- text += acEnd - menu->actext;
- }
- while (padding1-- > 0)
- *text++ = ' ';
- if (menu->children != NULL)
- {
- STRCPY(text, TEAROFF_SUBMENU_LABEL);
- text += STRLEN(TEAROFF_SUBMENU_LABEL);
- }
- else
- {
- while (padding2-- > 0)
- *text++ = ' ';
- }
- *text = NUL;
- *end = NUL;
- /*
- * BS_LEFT will just be ignored on Win32s/NT3.5x - on
- * W95/NT4 it makes the tear-off look more like a menu.
- */
- p = add_dialog_element(p,
- BS_PUSHBUTTON|BS_LEFT,
- (WORD)PixelToDialogX(TEAROFF_PADDING_X),
- (WORD)(1 + 13 * (*pnumitems)),
- (WORD)PixelToDialogX(dlgwidth - 2 * TEAROFF_PADDING_X),
- (WORD)12,
- menuID, (WORD)0x0080, label);
- vim_free(label);
- (*pnumitems)++;
- menu = menu->next;
- }
- *ptrueheight = (WORD)(1 + 13 * (*pnumitems));
- /* show modelessly */
- the_menu->tearoff_handle = CreateDialogIndirect(
- s_hinst,
- (LPDLGTEMPLATE)pdlgtemplate,
- s_hwnd,
- (DLGPROC)tearoff_callback);
- LocalFree(LocalHandle(pdlgtemplate));
- SelectFont(hdc, oldFont);
- DeleteObject(font);
- ReleaseDC(hwnd, hdc);
- /*
- * Reassert ourselves as the active window. This is so that after creating
- * a tearoff, the user doesn't have to click with the mouse just to start
- * typing agin!
- */
- SetActiveWindow(s_hwnd);
- /* make sure the right buttons are enabled*/
- force_menu_update = TRUE;
- }
- /*
- * Decide whether to use the "new look" (small, non-bold font) or the "old
- * look" (big, clanky font) for dialogs, and work out a few values for use
- * later accordingly.
- */
- static void
- get_dialog_font_metrics(void)
- {
- HDC hdc;
- HFONT hfontTools = 0;
- DWORD dlgFontSize;
- SIZE size;
- s_usenewlook = FALSE;
- /*
- * For NT3.51 and Win32s, we stick with the old look
- * because it matches everything else.
- */
- if (!is_winnt_3())
- {
- hfontTools = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, VARIABLE_PITCH , DLG_FONT_NAME);
- if (hfontTools)
- {
- hdc = GetDC (s_hwnd);
- SelectObject (hdc, hfontTools);
- /*
- * GetTextMetrics() doesn't return the right value in
- * tmAveCharWidth, so we have to figure out the dialog base units
- * ourselves.
- */
- GetTextExtentPoint(hdc,
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
- 52, &size);
- ReleaseDC (s_hwnd, hdc);
- s_dlgfntwidth = (WORD)((size.cx / 26 + 1) / 2);
- s_dlgfntheight = (WORD)size.cy;
- s_usenewlook = TRUE;
- }
- }
- if (!s_usenewlook)
- {
- dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/
- s_dlgfntwidth = LOWORD(dlgFontSize);
- s_dlgfntheight = HIWORD(dlgFontSize);
- }
- }
- #if defined(USE_GUI_WIN32_TOOLBAR) || defined(PROTO)
- #include "gui_w32_rc.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)
- {
- InitCommonControls();
- s_toolbarhwnd = CreateToolbarEx(
- s_hwnd,
- WS_CHILD | TBSTYLE_TOOLTIPS,
- 4000, //any old big number
- 28, //number of images in inital bitmap
- s_hinst,
- IDR_TOOLBAR1, // id of initial bitmap
- NULL,
- 0, // initial number of buttons
- TOOLBAR_BUTTON_WIDTH, //api guide is wrong!
- TOOLBAR_BUTTON_HEIGHT,
- TOOLBAR_BUTTON_WIDTH,
- TOOLBAR_BUTTON_HEIGHT,
- sizeof(TBBUTTON)
- );
- gui_mch_show_toolbar(vim_strchr(p_guioptions, GO_TOOLBAR) != NULL);
- }
- void
- gui_mch_show_toolbar(int showit)
- {
- if (s_toolbarhwnd == NULL)
- return;
- if (showit)
- ShowWindow(s_toolbarhwnd, SW_SHOW);
- else
- ShowWindow(s_toolbarhwnd, SW_HIDE);
- }
- /*
- * Find a bitmap by name.
- * If the name is one of the built-in bitmaps, return the index to that bitmap.
- * Otherwise, look for $vim/bitmaps/<name>.bmp, load it, add it to the toolbar
- * bitmap list and return the resulting index on failure return -1, which will
- * result in a blank (but still functional) button
- */
- static const char_u *BuiltInBitmaps[] =
- {
- "New", //0
- "Open", //1
- "Save", //2
- "Undo", //3
- "Redo", //4
- "Cut", //5
- "Copy", //6
- "Paste", //7
- "Print", //8
- "Help", //9
- "Find", //10
- "SaveAll", //11
- "SaveSession", //12
- "NewSession", //13
- "LoadSession", //14
- "RunMacro", //15
- "Replace", //16
- "WinClose", //17
- "WinZoom", //18
- "WinMin", //19
- "WinSplit", //20
- "Shell", //21
- "FindPrev", //22
- "FindNext", //23
- "FindHelp", //24
- "Make", //25
- "TagsJump", //26
- "TagsBuild", //27
- NULL
- };
- static int
- get_toolbar_bitmap(char_u *name)
- {
- int i;
- if (STRNCMP(name, "BuiltIn", 7) == 0)
- {
- char_u *dummy;
- /*
- * reference by index
- */
- i = strtol(name + 7, &dummy, 0);
- return i;
- }
- /*
- * Check user bitmaps next
- */
- i = -1;
- if (!is_winnt_3())
- {
- char_u *fname;
- char_u *ffname;
- HANDLE hbitmap;
- fname = alloc(_MAX_PATH);
- STRCPY(fname, "$VIM\bitmaps\");
- strcat(fname, name);
- strcat(fname, ".bmp");
- ffname = expand_env_save(fname);
- hbitmap = LoadImage(
- NULL,
- ffname,
- IMAGE_BITMAP,
- TOOLBAR_BUTTON_WIDTH,
- TOOLBAR_BUTTON_HEIGHT,
- LR_LOADFROMFILE |
- LR_LOADMAP3DCOLORS
- );
- if (hbitmap != NULL)
- {
- TBADDBITMAP tbAddBitmap;
- tbAddBitmap.hInst = NULL;
- tbAddBitmap.nID = (UINT)hbitmap;
- i = SendMessage(s_toolbarhwnd, TB_ADDBITMAP,
- (WPARAM)1, (LPARAM)&tbAddBitmap);
- /* i will be set to -1 if it fails */
- }
- vim_free(fname);
- vim_free(ffname);
- }
- if (i != -1)
- return i;
- for (i = 0; BuiltInBitmaps[i]; i++)
- {
- if (STRCMP(name, BuiltInBitmaps[i]) == 0)
- return i;
- }
- return i;
- }
- #endif
- void
- gui_simulate_alt_key(char_u *keys)
- {
- PostMessage(s_hwnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)0);
- while (*keys)
- {
- if (*keys == '~')
- *keys = ' '; /* for showing system menu */
- PostMessage(s_hwnd, WM_CHAR, (WPARAM)*keys, (LPARAM)0);
- keys++;
- }
- }
- /*
- * Create the find & replace dialogs
- * You can't have both at once: ":find" when replace is showing, destroys
- * the replace dialog first.
- */
- void
- gui_mch_find_dialog(char_u *arg)
- {
- #ifdef WIN32_FIND_REPLACE
- if (s_findrep_msg != 0)
- {
- if (IsWindow(s_findrep_hwnd) && (s_findrep_is_find == FALSE))
- DestroyWindow(s_findrep_hwnd);
- if (!IsWindow(s_findrep_hwnd))
- {
- initialise_findrep(arg);
- s_findrep_hwnd = FindText((LPFINDREPLACE) &s_findrep_struct);
- }
- (void)SetWindowText(s_findrep_hwnd,
- (LPCSTR) "Find string (use '\\' to find a '\')");
- (void)SetFocus(s_findrep_hwnd);
- s_findrep_is_find = TRUE;
- }
- #endif
- }
- void
- gui_mch_replace_dialog(char_u *arg)
- {
- #ifdef WIN32_FIND_REPLACE
- if (s_findrep_msg != 0)
- {
- if (IsWindow(s_findrep_hwnd) && (s_findrep_is_find == TRUE))
- DestroyWindow(s_findrep_hwnd);
- if (!IsWindow(s_findrep_hwnd))
- {
- initialise_findrep(arg);
- s_findrep_hwnd = ReplaceText((LPFINDREPLACE) &s_findrep_struct);
- }
- (void)SetWindowText(s_findrep_hwnd,
- (LPCSTR) "Find & Replace (use '\\' to find a '\')");
- (void)SetFocus(s_findrep_hwnd);
- s_findrep_is_find = FALSE;
- }
- #endif
- }
- #ifdef WIN32_FIND_REPLACE
- static void
- initialise_findrep(char_u *initial_string)
- {
- s_findrep_struct.hwndOwner = s_hwnd;
- s_findrep_struct.Flags = FR_HIDEMATCHCASE | FR_DOWN;
- if (initial_string != NULL && *initial_string != NUL)
- {
- STRCPY(s_findrep_struct.lpstrFindWhat, initial_string);
- s_findrep_struct.lpstrReplaceWith[0] = NUL;
- }
- }
- #endif
- /*
- * Set visibility of the pointer.
- */
- void
- gui_mch_mousehide(int hide)
- {
- if (hide != gui.pointer_hidden)
- {
- ShowCursor(!hide);
- gui.pointer_hidden = hide;
- }
- }