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

📄 gui.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* check if tearoff already exists */
		if (STRCMP(menu->children->name, TEAR_STRING) != 0)
		{
		    gui_add_tearoff(newpname, pri_tab, pri_idx - 1);
		    *d = NUL;			/* remove TEAR_STRING */
		}

		STRCAT(newpname, ".");
		gui_create_tearoffs_recurse(menu->children, newpname,
							    pri_tab, pri_idx);
		vim_free(newpname);
	    }
	}
	menu = menu->next;
    }
}

/*
 * Add tear-off menu item for a submenu.
 * "tearpath" is the menu path, and must have room to add TEAR_STRING.
 */
    static void
gui_add_tearoff(tearpath, pri_tab, pri_idx)
    char_u	*tearpath;
    int		*pri_tab;
    int		pri_idx;
{
    char_u	*tbuf;
    int		t;

    tbuf = alloc(5 + STRLEN(tearpath));
    if (tbuf != NULL)
    {
	tbuf[0] = K_SPECIAL;
	tbuf[1] = K_SECOND(K_TEAROFF);
	tbuf[2] = K_THIRD(K_TEAROFF);
	STRCPY(tbuf + 3, tearpath);
	STRCAT(tbuf + 3, "\r");

	STRCAT(tearpath, ".");
	STRCAT(tearpath, TEAR_STRING);

	/* Priority of tear-off is always 1 */
	t = pri_tab[pri_idx + 1];
	pri_tab[pri_idx + 1] = 1;

	gui_add_menu_path(tearpath, MENU_ALL_MODES, pri_tab,
		gui_menu_cb, tbuf, TRUE, FALSE);

	gui_add_menu_path(tearpath, MENU_TIP_MODE, pri_tab,
		gui_menu_cb, (char_u *)"Tear off this menu", TRUE, FALSE);

	pri_tab[pri_idx + 1] = t;
	vim_free(tbuf);
    }
}

/*
 * Recursively destroy tearoff items
 */
    static void
gui_destroy_tearoffs_recurse(menu)
    GuiMenu *menu;
{
    GuiMenu *oldmenu;

    while (menu)
    {
	if (menu->children)
	{
	    /* check if tearoff exists */
	    if ( STRCMP(menu->children->name, TEAR_STRING) == 0)
	    {
		/* Disconnect the item */
		oldmenu = menu->children;
		menu->children = oldmenu->next;
		/* Free the memory */
		gui_free_menu(oldmenu);
	    }
	    if (menu->children != NULL) /* might have been last one */
		gui_destroy_tearoffs_recurse(menu->children);
	}
	menu = menu->next;
    }
}

#endif /*USE_GUI_WIN32*/

/*
 * Add the menu with the given name to the menu hierarchy
 */
    static int
gui_add_menu_path(menu_path, modes, pri_tab, call_back, call_data, noremap
#ifdef USE_GUI_WIN32
	, addtearoff
#endif
	)
    char_u	*menu_path;
    int		modes;
    int		*pri_tab;
    void	(*call_back)();
    char_u	*call_data;
    int		noremap;
#ifdef USE_GUI_WIN32
    int		addtearoff;	/* may add tearoff item */
#endif
{
    char_u	*path_name;
    GuiMenu	**menup;
    GuiMenu	*menu = NULL;
    GuiMenu	*parent;
    GuiMenu	**lower_pri;
    char_u	*p;
    char_u	*name;
    char_u	*dname;
    char_u	*next_name;
    int		i;
    int		c;
    int		idx, new_idx;
    int		pri_idx = 0;
    int		old_modes = 0;
    int		amenu;

    /* Make a copy so we can stuff around with it, since it could be const */
    path_name = vim_strsave(menu_path);
    if (path_name == NULL)
	return FAIL;
    menup = &gui.root_menu;
    parent = NULL;
    name = path_name;
    while (*name)
    {
	/* Get name of this element in the menu hierarchy, and the simplified
	 * name (without mnemonic and accelerator text). */
	next_name = gui_menu_name_skip(name);
	dname = gui_menu_text(name, NULL, NULL);

	/* See if it's already there */
	lower_pri = menup;
	idx = 0;
	new_idx = 0;
	menu = *menup;
	while (menu != NULL)
	{
	    if (menu_name_equal(name, menu) || menu_name_equal(dname, menu))
	    {
		if (*next_name == NUL && menu->children != NULL)
		{
		    if (!gui_sys_menu)
			EMSG("Menu path must not lead to a sub-menu");
		    vim_free(path_name);
		    vim_free(dname);
		    return FAIL;
		}
		if (*next_name != NUL && menu->children == NULL
#ifdef USE_GUI_WIN32
			&& addtearoff
#endif
			)
		{
		    if (!gui_sys_menu)
			EMSG("Part of menu-item path is not sub-menu");
		    vim_free(path_name);
		    vim_free(dname);
		    return FAIL;
		}
		break;
	    }
	    menup = &menu->next;

	    /* Count menus, to find where this one needs to be inserted.
	     * Ignore menus that are not in the menubar (PopUp and Toolbar) */
	    if (parent != NULL || gui_menubar_menu(menu->name))
	    {
		++idx;
		if (menu->priority <= pri_tab[pri_idx])
		{
		    lower_pri = menup;
		    new_idx = idx;
		}
	    }
	    menu = menu->next;
	}

	if (menu == NULL)
	{
	    if (*next_name == NUL && parent == NULL)
	    {
		EMSG("Must not add menu items directly to menu bar");
		vim_free(path_name);
		vim_free(dname);
		return FAIL;
	    }

	    /* Not already there, so lets add it */
	    menu = (GuiMenu *)alloc_clear(sizeof(GuiMenu));
	    if (menu == NULL)
	    {
		vim_free(path_name);
		vim_free(dname);
		return FAIL;
	    }
	    menu->modes = modes;
	    menu->name = vim_strsave(name);
	    /* separate mnemonic and accelerator text from actual menu name */
	    menu->dname = gui_menu_text(name, &menu->mnemonic, &menu->actext);
	    menu->priority = pri_tab[pri_idx];

	    /*
	     * Add after menu that has lower priority.
	     */
	    menu->next = *lower_pri;
	    *lower_pri = menu;

	    if (gui.in_use)  /* Otherwise it will be added when GUI starts */
	    {
		if (*next_name == NUL)
		{
		    /* Real menu item, not sub-menu */
		    gui_mch_add_menu_item(menu, parent, new_idx);

		    /* Want to update menus now even if mode not changed */
		    force_menu_update = TRUE;
		}
		else
		{
		    /* Sub-menu (not at end of path yet) */
		    gui_mch_add_menu(menu, parent, new_idx);
		}
	    }

#ifdef USE_GUI_WIN32
	    /* When adding a new submenu, may add a tearoff item */
	    if (	addtearoff
		    && *next_name
		    && vim_strchr(p_guioptions, GO_TEAROFF) != NULL
		    && gui_menubar_menu(name))
	    {
		char_u		*tearpath;

		/*
		 * The pointers next_name & path_name refer to a string with
		 * \'s and ^V's stripped out. But menu_path is a "raw"
		 * string, so we must correct for special characters.
		 */
		tearpath = alloc(STRLEN(menu_path) + TEAR_LEN + 2);
		if (tearpath != NULL)
		{
		    char_u  *s;
		    int	    idx;

		    STRCPY(tearpath, menu_path);
		    idx = next_name - path_name - 1;
		    for (s = tearpath; *s && s < tearpath + idx; ++s)
			if ((*s == '\\' || *s == Ctrl('V')) && s[1])
			{
			    ++idx;
			    ++s;
			}
		    tearpath[idx] = NUL;
		    gui_add_tearoff(tearpath, pri_tab, pri_idx);
		    vim_free(tearpath);
		}
	    }
#endif
	    old_modes = 0;
	}
	else
	{
	    old_modes = menu->modes;

	    /*
	     * If this menu option was previously only available in other
	     * modes, then make sure it's available for this one now
	     */
#ifdef USE_GUI_WIN32
	    /* If adding a tearbar (addtearoff == FALSE) don't update modes */
	    if (addtearoff)
#endif
		menu->modes |= modes;
	}

	menup = &menu->children;
	parent = menu;
	name = next_name;
	vim_free(dname);
	if (pri_tab[pri_idx + 1] != -1)
	    ++pri_idx;
    }
    vim_free(path_name);

    /*
     * Only add system menu items which have not been defined yet.
     * First check if this was an ":amenu".
     */
    amenu = ((modes & (MENU_NORMAL_MODE | MENU_INSERT_MODE)) ==
				       (MENU_NORMAL_MODE | MENU_INSERT_MODE));
    if (gui_sys_menu)
	modes &= ~old_modes;

    if (menu != NULL && modes)
    {
	menu->cb = call_back;
	p = (call_data == NULL) ? NULL : vim_strsave(call_data);

	/* loop over all modes, may add more than one */
	for (i = 0; i < MENU_MODES; ++i)
	{
	    if (modes & (1 << i))
	    {
		/* free any old menu */
		gui_free_menu_string(menu, i);

		/* For "amenu", may insert an extra character */
		/* Don't do this if adding a tearbar (addtearoff == FALSE) */
		c = 0;
		if (amenu
#ifdef USE_GUI_WIN32
		       && addtearoff
#endif
				       )
		{
		    switch (1 << i)
		    {
			case MENU_VISUAL_MODE:
			case MENU_OP_PENDING_MODE:
			case MENU_CMDLINE_MODE:
			    c = Ctrl('C');
			    break;
			case MENU_INSERT_MODE:
			    c = Ctrl('O');
			    break;
		    }
		}

		if (c)
		{
		    menu->strings[i] = alloc((unsigned)(STRLEN(call_data) + 2));
		    if (menu->strings[i] != NULL)
		    {
			menu->strings[i][0] = c;
			STRCPY(menu->strings[i] + 1, call_data);
		    }
		}
		else
		    menu->strings[i] = p;
		menu->noremap[i] = noremap;
	    }
	}
    }
    return OK;
}

/*
 * Remove the (sub)menu with the given name from the menu hierarchy
 * Called recursively.
 */
    static int
gui_remove_menu(menup, name, modes, silent)
    GuiMenu	**menup;
    char_u	*name;
    int		modes;
    int		silent;		/* don't give error messages */
{
    GuiMenu	*menu;
    GuiMenu	*child;
    char_u	*p;

    if (*menup == NULL)
	return OK;		/* Got to bottom of hierarchy */

    /* Get name of this element in the menu hierarchy */
    p = gui_menu_name_skip(name);

    /* Find the menu */
    menu = *menup;
    while (menu != NULL)
    {
	if (*name == NUL || menu_name_equal(name, menu))
	{
	    if (*p != NUL && menu->children == NULL)
	    {
		if (!silent)
		    EMSG("Part of menu-item path is not sub-menu");
		return FAIL;
	    }
	    if ((menu->modes & modes) != 0x0)
	    {
		if (gui_remove_menu(&menu->children, p, modes, silent) == FAIL)
		    return FAIL;
	    }
	    else if (*name != NUL)
	    {
		if (!silent)
		    EMSG("Menu only exists in another mode");
		return FAIL;
	    }

	    /*
	     * When name is empty, we are removing all menu items for the given
	     * modes, so keep looping, otherwise we are just removing the named
	     * menu item (which has been found) so break here.
	     */
	    if (*name != NUL)
		break;

	    /* Remove the menu item for the given mode[s] */
	    menu->modes &= ~modes;
	    if (modes & MENU_TIP_MODE)
		gui_free_menu_string(menu, MENU_INDEX_TIP);
	    if ((menu->modes & MENU_ALL_MODES) == 0)
	    {
		/* The menu item is no longer valid in ANY mode, so delete it */
		*menup = menu->next;
		gui_free_menu(menu);
	    }
	    else
		menup = &menu->next;
	}
	else
	    menup = &menu->next;
	menu = *menup;
    }
    if (*name != NUL)
    {
	if (menu == NULL)
	{
	    if (!silent)
		EMSG("No menu of that name");
	    return FAIL;
	}


	/* Recalculate modes for menu based on the new updated children */
	menu->modes &= ~modes;
#ifdef USE_GUI_WIN32
	if ((s_tearoffs) && (menu->children != NULL)) /* there's a tear bar.. */
	    child = menu->children->next; /* don't count tearoff bar */
	else
#endif
	    child = menu->children;
	for ( ; child != NULL; child = child->next)
	    menu->modes |= child->modes;
	if (modes & MENU_TIP_MODE)
	    gui_free_menu_string(menu, MENU_INDEX_TIP);
	if ((menu->modes & MENU_ALL_MODES) == 0)
	{
	    /* The menu item is no longer valid in ANY mode, so delete it */
#ifdef USE_GUI_WIN32
	    if ((s_tearoffs) && (menu->children != NULL)) /* there's a tear bar.. */
		gui_free_menu(menu->children);
#endif
	    *menup = menu->next;
	    gui_free_menu(menu);
	}
    }

    return OK;
}

/*
 * Free the given menu structure
 */
    static void
gui_free_menu(menu)
    GuiMenu *menu;
{
    int	    i;

    /* Free machine specific menu structures (only when already created) */
    if (gui.in_use)
	gui_mch_destroy_menu(menu);
    vim_free(menu->name);
    vim_free(menu->dname);
    vim_free(menu->actext);
    for (i = 0; i < MENU_MODES; i++)
	gui_free_menu_string(menu, i);
    vim_free(menu);

    /* Want to update menus now even if mode not changed */
    force_menu_update = TRUE;
}

/*
 * Free the menu->string with the given index.
 */
    static void
gui_free_menu_string(menu, idx)
    GuiMenu *menu;
    int	    idx;
{
    int	    count = 0;
    int	    i;

    for (i = 0; i < MENU_MODES; i++)
	if (menu->strings[i] == menu->strings[idx])
	    count++;
    if (count == 1)
	vim_free(menu->strings[idx]);
    menu->strings[idx] = NULL;
}

/*
 * Show the mapping associated with a menu item or hierarchy in a sub-menu.
 */
    static int
gui_show_menus(path_name, modes)
    char_u  *path_name;
    int	    modes;
{
    char_u  *p;
    char_u  *name;
    GuiMenu *menu;
    GuiMenu *parent = NULL;

    menu = gui.root_menu;
    name = path_name = vim_strsave(path_name);
    if (path_name == NULL)
	return FAIL;

    /* Fir

⌨️ 快捷键说明

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