⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gui.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
		    MOUSE_LEFT
# endif
				)
	{
	    clip_start_selection(button, x, y, repeated_click, modifiers);
	    did_clip = TRUE;
	}
# ifdef RISCOS
	else if (button == MOUSE_LEFT)
	{
	    clip_clear_selection();
	    did_clip = TRUE;
	}
# endif

	/* Always allow pasting */
	if (button != MOUSE_MIDDLE)
	{
	    if (!mouse_has(checkfor) || button == MOUSE_RELEASE)
		return;
	    button = MOUSE_LEFT;
	}
	repeated_click = FALSE;
    }

    if (clipboard.state != SELECT_CLEARED && !did_clip)
	clip_clear_selection();
#endif

    /*
     * Don't put mouse events in the input queue while executing an external
     * command.
     */
    if (!termcap_active)
	return;

    row = check_row(Y_2_ROW(y));
    col = check_col(X_2_COL(x));

    /*
     * If we are dragging and the mouse hasn't moved far enough to be on a
     * different character, then don't send an event to vim.
     */
    if (button == MOUSE_DRAG && row == prev_row && col == prev_col)
	return;

    /*
     * If topline has changed (window scrolled) since the last click, reset
     * repeated_click, because we don't want starting Visual mode when
     * clicking on a different character in the text.
     */
    if (curwin->w_topline != gui_prev_topline)
	repeated_click = FALSE;

    string[0] = CSI;	/* this sequence is recognized by check_termcode() */
    string[1] = KS_MOUSE;
    string[2] = K_FILLER;
    if (button != MOUSE_DRAG && button != MOUSE_RELEASE)
    {
	if (repeated_click)
	{
	    /*
	     * Handle multiple clicks.	They only count if the mouse is still
	     * pointing at the same character.
	     */
	    if (button != prev_button || row != prev_row || col != prev_col)
		num_clicks = 1;
	    else if (++num_clicks > 4)
		num_clicks = 1;
	}
	else
	    num_clicks = 1;
	prev_button = button;
	gui_prev_topline = curwin->w_topline;

	string[3] = (char_u)(button | 0x20);
	SET_NUM_MOUSE_CLICKS(string[3], num_clicks);
    }
    else
	string[3] = (char_u)button;

    string[3] |= modifiers;
    string[4] = (char_u)(col + ' ' + 1);
    string[5] = (char_u)(row + ' ' + 1);
    add_to_input_buf(string, 6);

    prev_row = row;
    prev_col = col;
}

/*
 * Menu stuff.
 */

    void
gui_menu_cb(menu)
    GuiMenu *menu;
{
    char_u  bytes[3 + sizeof(long_u)];

    bytes[0] = CSI;
    bytes[1] = KS_MENU;
    bytes[2] = K_FILLER;
    add_long_to_buf((long_u)menu, bytes + 3);
    add_to_input_buf(bytes, 3 + sizeof(long_u));
}

/*
 * Return the index into the menu->strings or menu->noremap arrays for the
 * current state.  Returns MENU_INDEX_INVALID if there is no mapping for the
 * given menu in the current mode.
 */
    int
gui_get_menu_index(menu, state)
    GuiMenu *menu;
    int	    state;
{
    int	    idx;

    if (VIsual_active)
	idx = MENU_INDEX_VISUAL;
    else if ((state & INSERT))
	idx = MENU_INDEX_INSERT;
    else if ((state & CMDLINE))
	idx = MENU_INDEX_CMDLINE;
    else if (finish_op)
	idx = MENU_INDEX_OP_PENDING;
    else if ((state & NORMAL))
	idx = MENU_INDEX_NORMAL;
    else
	idx = MENU_INDEX_INVALID;

    if (idx != MENU_INDEX_INVALID && menu->strings[idx] == NULL)
	idx = MENU_INDEX_INVALID;
    return idx;
}

/*
 * Return the modes specified by the given menu command (eg :menu! returns
 * MENU_CMDLINE_MODE | MENU_INSERT_MODE).  If noremap is not NULL, then the
 * flag it points to is set according to whether the command is a "nore"
 * command.  If unmenu is not NULL, then the flag it points to is set
 * according to whether the command is an "unmenu" command.
 */
    static int
gui_get_menu_cmd_modes(cmd, forceit, noremap, unmenu)
    char_u  *cmd;
    int	    forceit;	    /* Was there a "!" after the command? */
    int	    *noremap;
    int	    *unmenu;
{
    int	    modes;

    switch (*cmd++)
    {
	case 'v':			/* vmenu, vunmenu, vnoremenu */
	    modes = MENU_VISUAL_MODE;
	    break;
	case 'o':			/* omenu */
	    modes = MENU_OP_PENDING_MODE;
	    break;
	case 'i':			/* imenu */
	    modes = MENU_INSERT_MODE;
	    break;
	case 't':
	    modes = MENU_TIP_MODE;	/* tmenu */
	    break;
	case 'c':			/* cmenu */
	    modes = MENU_CMDLINE_MODE;
	    break;
	case 'a':			/* amenu */
	    modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE | MENU_NORMAL_MODE
				    | MENU_VISUAL_MODE | MENU_OP_PENDING_MODE;
	    break;
	case 'n':
	    if (cmd[1] != 'o')		/* nmenu */
	    {
		modes = MENU_NORMAL_MODE;
		break;
	    }
	    /* FALLTHROUGH */
	default:
	    --cmd;
	    if (forceit)		/* menu!! */
		modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE;
	    else			/* menu */
		modes = MENU_NORMAL_MODE | MENU_VISUAL_MODE
						       | MENU_OP_PENDING_MODE;
    }

    if (noremap != NULL)
	*noremap = (*cmd == 'n');
    if (unmenu != NULL)
	*unmenu = (*cmd == 'u');
    return modes;
}

#define MENUDEPTH   10		/* maximum depth of menus */

/*
 * Do the :menu commands.
 */
    void
do_menu(eap)
    EXARG	*eap;		    /* Ex command arguments */
{
    char_u	*menu_path;
    int		modes;
    char_u	*map_to;
    int		noremap;
    int		unmenu;
    char_u	*map_buf;
    char_u	*arg;
    char_u	*p;
    int		i;
    int		old_menu_height;
    int		pri_tab[MENUDEPTH + 1];

    modes = gui_get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);
    arg = eap->arg;

    /* fill in the priority table */
    for (p = arg; *p; ++p)
	if (!isdigit(*p) && *p != '.')
	    break;
    if (vim_iswhite(*p))
    {
	for (i = 0; i < MENUDEPTH && !vim_iswhite(*arg); ++i)
	{
	    pri_tab[i] = getdigits(&arg);
	    if (pri_tab[i] == 0)
		pri_tab[i] = 500;
	    if (*arg == '.')
		++arg;
	}
	arg = skipwhite(arg);
    }
    else if (eap->addr_count)
    {
	pri_tab[0] = eap->line2;
	i = 1;
    }
    else
	i = 0;
    while (i < MENUDEPTH)
	pri_tab[i++] = 500;
    pri_tab[MENUDEPTH] = -1;		/* mark end of the table */

    menu_path = arg;
    if (*menu_path == NUL)
    {
	gui_show_menus(menu_path, modes);
	return;
    }

    /* skip the menu name, and translate <Tab> into a real TAB */
    while (*arg && !vim_iswhite(*arg))
    {
	if ((*arg == '\\' || *arg == Ctrl('V')) && arg[1] != NUL)
	    arg++;
	else if (STRNICMP(arg, "<TAB>", 5) == 0)
	{
	    *arg = TAB;
	    mch_memmove(arg + 1, arg + 5, STRLEN(arg + 4));
	}
	arg++;
    }
    if (*arg != NUL)
	*arg++ = NUL;
    arg = skipwhite(arg);
    map_to = arg;
    if (*map_to == NUL && !unmenu)
    {
	gui_show_menus(menu_path, modes);
	return;
    }
    else if (*map_to != NUL && unmenu)
    {
	EMSG("Trailing characters");
	return;
    }

    old_menu_height = gui.menu_height;
    if (unmenu)
    {
	if (STRCMP(menu_path, "*") == 0)	/* meaning: remove all menus */
	    menu_path = (char_u *)"";
	gui_remove_menu(&gui.root_menu, menu_path, modes, FALSE);

	/*
	 * For the PopUp menu, remove a menu for each mode separately.
	 */
	if (STRNCMP(menu_path, "PopUp", 5) == 0)
	{
	    for (i = 0; i < MENU_INDEX_TIP; ++i)
		if (modes & (1 << i))
		{
		    p = popup_mode_name(menu_path, i);
		    if (p != NULL)
		    {
			gui_remove_menu(&gui.root_menu, p, 1 << i, TRUE);
			vim_free(p);
		    }
		}
	}
    }
    else
    {
	/* Replace special key codes */
	map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE);
	gui_add_menu_path(menu_path, modes,
		pri_tab, gui_menu_cb, map_to, noremap
#ifdef USE_GUI_WIN32
		, TRUE
#endif
		);

	/*
	 * For the PopUp menu, add a menu for each mode separately.
	 */
	if (STRNCMP(menu_path, "PopUp", 5) == 0)
	{
	    for (i = 0; i < MENU_INDEX_TIP; ++i)
		if (modes & (1 << i))
		{
		    p = popup_mode_name(menu_path, i);
		    if (p != NULL)
		    {
			/* Include all modes, to make ":amenu" work */
			gui_add_menu_path(p, modes,
				pri_tab, gui_menu_cb, map_to, noremap
#ifdef USE_GUI_WIN32
				, TRUE
#endif
					 );
			vim_free(p);
		    }
		}
	}

	vim_free(map_buf);
    }

    /* If the menubar height changed, resize the window */
    if (gui.menu_height != old_menu_height)
	gui_set_winsize(FALSE);
}

/*
 * Modify a menu name starting with "PopUp" to include the mode character.
 * Returns the name in allocated memory (NULL for failure).
 */
    static char_u *
popup_mode_name(name, idx)
    char_u	*name;
    int		idx;
{
    char_u	*p;
    int		len = STRLEN(name);

    p = vim_strnsave(name, len + 1);
    if (p != NULL)
    {
	mch_memmove(p + 6, p + 5, len - 4);
	p[5] = MENU_MODE_CHARS[idx];
    }
    return p;
}

/*
 * Used recursively by gui_update_menus (see below)
 */
    static void
gui_update_menus_recurse(menu, mode)
    GuiMenu *menu;
    int	    mode;
{
    int	    i;

    while (menu)
    {
	if (menu->modes & mode)
	    i = FALSE;
	else
	    i = TRUE;
	if (vim_strchr(p_guioptions, GO_GREY) != NULL)
	    gui_mch_menu_grey(menu, i);
	else
	    gui_mch_menu_hidden(menu, i);
	gui_update_menus_recurse(menu->children, mode);
	menu = menu->next;
    }
}

/*
 * Make sure only the valid menu items appear for this mode.  If
 * force_menu_update is not TRUE, then we only do this if the mode has changed
 * since last time.  If "modes" is not 0, then we use these modes instead.
 */
    void
gui_update_menus(modes)
    int	    modes;
{
    static int	    prev_mode = -1;
    int		    mode = 0;

    if (modes != 0x0)
	mode = modes;
    else
    {
	mode = get_menu_mode();
	if (mode == MENU_INDEX_INVALID)
	    mode = 0;
	else
	    mode = (1 << mode);
    }

    if (force_menu_update || mode != prev_mode)
    {
	gui_update_menus_recurse(gui.root_menu, mode);
	gui_mch_draw_menubar();
	prev_mode = mode;
	force_menu_update = FALSE;
    }
}

    static int
get_menu_mode()
{
    if (VIsual_active)
	return MENU_INDEX_VISUAL;
    if (State & INSERT)
	return MENU_INDEX_INSERT;
    if (State & CMDLINE)
	return MENU_INDEX_CMDLINE;
    if (finish_op)
	return MENU_INDEX_OP_PENDING;
    if (State & NORMAL)
	return MENU_INDEX_NORMAL;
    return MENU_INDEX_INVALID;
}

/*
 * Check if a key is used as a mnemonic for a toplevel menu.
 * Case of the key is ignored.
 */
    int
gui_is_menu_shortcut(key)
    int		key;
{
    GuiMenu	*menu;

    key = TO_LOWER(key);
    for (menu = gui.root_menu; menu != NULL; menu = menu->next)
	if (TO_LOWER(menu->mnemonic) == key)
	    return TRUE;
    return FALSE;
}

#if defined(USE_GUI_WIN32) || defined(PROTO)

/*
 * Deal with tearoff items that are added like a menu item.
 * Currently only for Win32 GUI.  Others may follow later.
 */

    void
gui_mch_toggle_tearoffs(int enable)
{
    int		pri_tab[MENUDEPTH + 1];
    int		i;

    if (enable)
    {
	for (i = 0; i < MENUDEPTH; ++i)
	    pri_tab[i] = 500;
	pri_tab[MENUDEPTH] = -1;
	gui_create_tearoffs_recurse(gui.root_menu, (char_u *)"", pri_tab, 0);
    }
    else
	gui_destroy_tearoffs_recurse(gui.root_menu);
    s_tearoffs = enable;
}

/*
 * Recursively add tearoff items
 */
    static void
gui_create_tearoffs_recurse(menu, pname, pri_tab, pri_idx)
    GuiMenu		*menu;
    const char_u	*pname;
    int			*pri_tab;
    int			pri_idx;
{
    char_u	*newpname = NULL;
    int		len;
    char_u	*s;
    char_u	*d;

    if (pri_tab[pri_idx + 1] != -1)
	++pri_idx;
    while (menu != NULL)
    {
	if (menu->children != NULL && gui_menubar_menu(menu->name))
	{
	    /* Add the menu name to the menu path.  Insert a backslash before
	     * dots (it's used to separate menu names). */
	    len = STRLEN(pname) + STRLEN(menu->name);
	    for (s = menu->name; *s; ++s)
		if (*s == '.' || *s == '\\')
		    ++len;
	    newpname = alloc(len + TEAR_LEN + 2);
	    if (newpname != NULL)
	    {
		STRCPY(newpname, pname);
		d = newpname + STRLEN(newpname);
		for (s = menu->name; *s; ++s)
		{
		    if (*s == '.' || *s == '\\')
			*d++ = '\\';
		    *d++ = *s;
		}
		*d = NUL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -