]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/pluginmenu.cpp
Merge remote-tracking branch 'github/master'
[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 "stream/textstream.h"
25
26 #include <gtk/gtkmenu.h>
27 #include <gtk/gtkmenuitem.h>
28
29 #include "gtkutil/pointer.h"
30 #include "gtkutil/menu.h"
31
32 #include "pluginmanager.h"
33 #include "mainframe.h"
34 #include "preferences.h"
35
36
37 int m_nNextPlugInID = 0;
38
39 void plugin_activated( GtkWidget* widget, gpointer data ){
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 typedef std::stack<GtkWidget*> WidgetStack;
46
47 void PlugInMenu_Add( GtkMenu* plugin_menu, IPlugIn* pPlugIn ){
48         GtkWidget *menu, *item, *parent, *subMenu;
49         const char *menuText, *menuCommand;
50         WidgetStack menuStack;
51
52         parent = gtk_menu_item_new_with_label( pPlugIn->getMenuName() );
53         gtk_widget_show( parent );
54         gtk_container_add( GTK_CONTAINER( plugin_menu ), parent );
55
56         std::size_t nCount = pPlugIn->getCommandCount();
57         if ( nCount > 0 ) {
58                 menu = gtk_menu_new();
59                 if ( g_Layout_enableDetachableMenus.m_value ) {
60                         menu_tearoff( GTK_MENU( menu ) );
61                 }
62                 while ( nCount > 0 )
63                 {
64                         menuText = pPlugIn->getCommandTitle( --nCount );
65                         menuCommand = pPlugIn->getCommand( nCount );
66
67                         if ( menuText != 0 && strlen( menuText ) > 0 ) {
68                                 if ( !strcmp( menuText, "-" ) ) {
69                                         item = gtk_menu_item_new();
70                                         gtk_widget_set_sensitive( item, FALSE );
71                                 }
72                                 else if ( !strcmp( menuText, ">" ) ) {
73                                         menuText = pPlugIn->getCommandTitle( --nCount );
74                                         menuCommand = pPlugIn->getCommand( nCount );
75                                         if ( !strcmp( menuText, "-" ) || !strcmp( menuText, ">" ) || !strcmp( menuText, "<" ) ) {
76                                                 globalErrorStream() << pPlugIn->getMenuName() << " Invalid title (" << menuText << ") for submenu.\n";
77                                                 continue;
78                                         }
79
80                                         item = gtk_menu_item_new_with_label( menuText );
81                                         gtk_widget_show( item );
82                                         gtk_container_add( GTK_CONTAINER( menu ), item );
83
84                                         subMenu = gtk_menu_new();
85                                         gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), subMenu );
86                                         menuStack.push( menu );
87                                         menu = subMenu;
88                                         continue;
89                                 }
90                                 else if ( !strcmp( menuText, "<" ) ) {
91                                         if ( !menuStack.empty() ) {
92                                                 menu = menuStack.top();
93                                                 menuStack.pop();
94                                         }
95                                         else
96                                         {
97                                                 globalErrorStream() << pPlugIn->getMenuName() << ": Attempt to end non-existent submenu ignored.\n";
98                                         }
99                                         continue;
100                                 }
101                                 else
102                                 {
103                                         item = gtk_menu_item_new_with_label( menuText );
104                                         g_object_set_data( G_OBJECT( item ),"command", const_cast<gpointer>( static_cast<const void*>( menuCommand ) ) );
105                                         g_signal_connect( G_OBJECT( item ), "activate", G_CALLBACK( plugin_activated ), gint_to_pointer( m_nNextPlugInID ) );
106                                 }
107                                 gtk_widget_show( item );
108                                 gtk_container_add( GTK_CONTAINER( menu ), item );
109                                 pPlugIn->addMenuID( m_nNextPlugInID++ );
110                         }
111                 }
112                 if ( !menuStack.empty() ) {
113                         std::size_t size = menuStack.size();
114                         if ( size != 0 ) {
115                                 globalErrorStream() << pPlugIn->getMenuName() << " mismatched > <. " << Unsigned( size ) << " submenu(s) not closed.\n";
116                         }
117                         for ( std::size_t i = 0; i < ( size - 1 ); i++ )
118                         {
119                                 menuStack.pop();
120                         }
121                         menu = menuStack.top();
122                         menuStack.pop();
123                 }
124                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( parent ), menu );
125         }
126 }
127
128 GtkMenu* g_plugins_menu = 0;
129 GtkMenuItem* g_plugins_menu_separator = 0;
130
131 void PluginsMenu_populate(){
132         class PluginsMenuConstructor : public PluginsVisitor
133         {
134         GtkMenu* m_menu;
135 public:
136         PluginsMenuConstructor( GtkMenu* menu ) : m_menu( menu ){
137         }
138         void visit( IPlugIn& plugin ){
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         m_nNextPlugInID = 0;
149
150         GList* lst = g_list_find( gtk_container_children( GTK_CONTAINER( g_plugins_menu ) ), GTK_WIDGET( g_plugins_menu_separator ) );
151         while ( lst->next )
152         {
153                 gtk_container_remove( GTK_CONTAINER( g_plugins_menu ), GTK_WIDGET( lst->next->data ) );
154                 lst = g_list_find( gtk_container_children( GTK_CONTAINER( g_plugins_menu ) ),  GTK_WIDGET( g_plugins_menu_separator ) );
155         }
156 }
157
158 GtkMenuItem* create_plugins_menu(){
159         // Plugins menu
160         GtkMenuItem* plugins_menu_item = new_sub_menu_item_with_mnemonic( "_Plugins" );
161         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( plugins_menu_item ) );
162         if ( g_Layout_enableDetachableMenus.m_value ) {
163                 menu_tearoff( menu );
164         }
165
166         g_plugins_menu = menu;
167
168         //TODO: some modules/plugins do not yet support refresh
169 #if 0
170         create_menu_item_with_mnemonic( menu, "Refresh", FreeCaller<Restart>() );
171
172         // NOTE: the seperator is used when doing a refresh of the list, everything past the seperator is removed
173         g_plugins_menu_separator = menu_separator( menu );
174 #endif
175
176         PluginsMenu_populate();
177
178         return plugins_menu_item;
179 }