]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/pluginmenu.cpp
iqmmodel: better format description
[xonotic/netradiant.git] / radiant / pluginmenu.cpp
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "pluginmenu.h"
23
24 #include <gtk/gtk.h>
25
26 #include "stream/textstream.h"
27
28 #include "gtkutil/pointer.h"
29 #include "gtkutil/menu.h"
30
31 #include "pluginmanager.h"
32 #include "mainframe.h"
33 #include "preferences.h"
34
35
36 int m_nNextPlugInID = 0;
37
38 void plugin_activated(ui::Widget widget, gpointer data)
39 {
40     const char *str = (const char *) g_object_get_data(G_OBJECT(widget), "command");
41     GetPlugInMgr().Dispatch(gpointer_to_int(data), str);
42 }
43
44 #include <stack>
45
46 void PlugInMenu_Add(ui::Menu plugin_menu, IPlugIn *pPlugIn)
47 {
48     ui::Widget item{ui::null}, parent{ui::null};
49     ui::Menu menu{ui::null}, subMenu{ui::null};
50     const char *menuText, *menuCommand;
51     std::stack<ui::Menu> menuStack;
52
53     parent = ui::MenuItem(pPlugIn->getMenuName());
54     parent.show();
55     plugin_menu.add(parent);
56
57     std::size_t nCount = pPlugIn->getCommandCount();
58     if (nCount > 0) {
59         menu = ui::Menu(ui::New);
60         if (g_Layout_enableDetachableMenus.m_value) {
61             menu_tearoff(menu);
62         }
63         while (nCount > 0) {
64             menuText = pPlugIn->getCommandTitle(--nCount);
65             menuCommand = pPlugIn->getCommand(nCount);
66
67             if (menuText != 0 && strlen(menuText) > 0) {
68                 if (!strcmp(menuText, "-")) {
69                     item = ui::Widget::from(gtk_menu_item_new());
70                     gtk_widget_set_sensitive(item, FALSE);
71                 } else if (!strcmp(menuText, ">")) {
72                     menuText = pPlugIn->getCommandTitle(--nCount);
73                     menuCommand = pPlugIn->getCommand(nCount);
74                     if (!strcmp(menuText, "-") || !strcmp(menuText, ">") || !strcmp(menuText, "<")) {
75                         globalErrorStream() << pPlugIn->getMenuName() << " Invalid title (" << menuText
76                                             << ") for submenu.\n";
77                         continue;
78                     }
79
80                     item = ui::MenuItem(menuText);
81                     item.show();
82                     menu.add(item);
83
84                     subMenu = ui::Menu(ui::New);
85                     gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), subMenu);
86                     menuStack.push(menu);
87                     menu = subMenu;
88                     continue;
89                 } else if (!strcmp(menuText, "<")) {
90                     if (!menuStack.empty()) {
91                         menu = menuStack.top();
92                         menuStack.pop();
93                     } else {
94                         globalErrorStream() << pPlugIn->getMenuName()
95                                             << ": Attempt to end non-existent submenu ignored.\n";
96                     }
97                     continue;
98                 } else {
99                     item = ui::MenuItem(menuText);
100                     g_object_set_data(G_OBJECT(item), "command",
101                                       const_cast<gpointer>( static_cast<const void *>( menuCommand )));
102                     item.connect("activate", G_CALLBACK(plugin_activated), gint_to_pointer(m_nNextPlugInID));
103                 }
104                 item.show();
105                 menu.add(item);
106                 pPlugIn->addMenuID(m_nNextPlugInID++);
107             }
108         }
109         if (!menuStack.empty()) {
110             std::size_t size = menuStack.size();
111             if (size != 0) {
112                 globalErrorStream() << pPlugIn->getMenuName() << " mismatched > <. " << Unsigned(size)
113                                     << " submenu(s) not closed.\n";
114             }
115             for (std::size_t i = 0; i < (size - 1); i++) {
116                 menuStack.pop();
117             }
118             menu = menuStack.top();
119             menuStack.pop();
120         }
121         gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent), menu);
122     }
123 }
124
125 ui::Menu g_plugins_menu{ui::null};
126 ui::MenuItem g_plugins_menu_separator{ui::null};
127
128 void PluginsMenu_populate()
129 {
130     class PluginsMenuConstructor : public PluginsVisitor {
131         ui::Menu m_menu;
132     public:
133         PluginsMenuConstructor(ui::Menu menu) : m_menu(menu)
134         {
135         }
136
137         void visit(IPlugIn &plugin)
138         {
139             PlugInMenu_Add(m_menu, &plugin);
140         }
141     };
142
143     PluginsMenuConstructor constructor(g_plugins_menu);
144     GetPlugInMgr().constructMenu(constructor);
145 }
146
147 void PluginsMenu_clear()
148 {
149     m_nNextPlugInID = 0;
150
151     GList *lst = g_list_find(gtk_container_get_children(GTK_CONTAINER(g_plugins_menu)),
152                              g_plugins_menu_separator._handle);
153     while (lst->next) {
154         g_plugins_menu.remove(ui::Widget::from(lst->next->data));
155         lst = g_list_find(gtk_container_get_children(GTK_CONTAINER(g_plugins_menu)), g_plugins_menu_separator._handle);
156     }
157 }
158
159 ui::MenuItem create_plugins_menu()
160 {
161     // Plugins menu
162     auto plugins_menu_item = new_sub_menu_item_with_mnemonic("_Plugins");
163     auto menu = ui::Menu::from(gtk_menu_item_get_submenu(plugins_menu_item));
164     if (g_Layout_enableDetachableMenus.m_value) {
165         menu_tearoff(menu);
166     }
167
168     g_plugins_menu = menu;
169
170     //TODO: some modules/plugins do not yet support refresh
171 #if 0
172     create_menu_item_with_mnemonic( menu, "Refresh", makeCallbackF(Restart) );
173
174     // NOTE: the seperator is used when doing a refresh of the list, everything past the seperator is removed
175     g_plugins_menu_separator = menu_separator( menu );
176 #endif
177
178     PluginsMenu_populate();
179
180     return plugins_menu_item;
181 }