GTK: wrap GTK_WIDGET
[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         const char* str = (const char*)g_object_get_data( G_OBJECT( widget ),"command" );
40         GetPlugInMgr().Dispatch( gpointer_to_int( data ), str );
41 }
42
43 #include <stack>
44
45 void PlugInMenu_Add( ui::Menu plugin_menu, IPlugIn* pPlugIn ){
46         ui::Widget item{ui::null}, parent{ui::null};
47         ui::Menu menu{ui::null}, subMenu{ui::null};
48         const char *menuText, *menuCommand;
49         std::stack<ui::Menu> menuStack;
50
51         parent = ui::MenuItem( pPlugIn->getMenuName() );
52         parent.show();
53         plugin_menu.add(parent);
54
55         std::size_t nCount = pPlugIn->getCommandCount();
56         if ( nCount > 0 ) {
57                 menu = ui::Menu(ui::New);
58                 if ( g_Layout_enableDetachableMenus.m_value ) {
59                         menu_tearoff( menu );
60                 }
61                 while ( nCount > 0 )
62                 {
63                         menuText = pPlugIn->getCommandTitle( --nCount );
64                         menuCommand = pPlugIn->getCommand( nCount );
65
66                         if ( menuText != 0 && strlen( menuText ) > 0 ) {
67                                 if ( !strcmp( menuText, "-" ) ) {
68                                         item = ui::Widget(gtk_menu_item_new());
69                                         gtk_widget_set_sensitive( item, FALSE );
70                                 }
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 << ") for submenu.\n";
76                                                 continue;
77                                         }
78
79                                         item = ui::MenuItem( menuText );
80                                         item.show();
81                                         menu.add(item);
82
83                                         subMenu = ui::Menu(ui::New);
84                                         gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), subMenu );
85                                         menuStack.push( menu );
86                                         menu = subMenu;
87                                         continue;
88                                 }
89                                 else if ( !strcmp( menuText, "<" ) ) {
90                                         if ( !menuStack.empty() ) {
91                                                 menu = menuStack.top();
92                                                 menuStack.pop();
93                                         }
94                                         else
95                                         {
96                                                 globalErrorStream() << pPlugIn->getMenuName() << ": Attempt to end non-existent submenu ignored.\n";
97                                         }
98                                         continue;
99                                 }
100                                 else
101                                 {
102                                         item = ui::MenuItem( menuText );
103                                         g_object_set_data( G_OBJECT( item ),"command", const_cast<gpointer>( static_cast<const void*>( menuCommand ) ) );
104                                         item.connect( "activate", G_CALLBACK( plugin_activated ), gint_to_pointer( m_nNextPlugInID ) );
105                                 }
106                                 item.show();
107                                 menu.add(item);
108                                 pPlugIn->addMenuID( m_nNextPlugInID++ );
109                         }
110                 }
111                 if ( !menuStack.empty() ) {
112                         std::size_t size = menuStack.size();
113                         if ( size != 0 ) {
114                                 globalErrorStream() << pPlugIn->getMenuName() << " mismatched > <. " << Unsigned( size ) << " submenu(s) not closed.\n";
115                         }
116                         for ( std::size_t i = 0; i < ( size - 1 ); i++ )
117                         {
118                                 menuStack.pop();
119                         }
120                         menu = menuStack.top();
121                         menuStack.pop();
122                 }
123                 gtk_menu_item_set_submenu( GTK_MENU_ITEM( parent ), menu );
124         }
125 }
126
127 ui::Menu g_plugins_menu{ui::null};
128 GtkMenuItem* g_plugins_menu_separator = 0;
129
130 void PluginsMenu_populate(){
131         class PluginsMenuConstructor : public PluginsVisitor
132         {
133         ui::Menu m_menu;
134 public:
135         PluginsMenuConstructor( ui::Menu menu ) : m_menu( menu ){
136         }
137         void visit( IPlugIn& plugin ){
138                 PlugInMenu_Add( m_menu, &plugin );
139         }
140         };
141
142         PluginsMenuConstructor constructor( g_plugins_menu );
143         GetPlugInMgr().constructMenu( constructor );
144 }
145
146 void PluginsMenu_clear(){
147         m_nNextPlugInID = 0;
148
149         GList* lst = g_list_find( gtk_container_get_children( GTK_CONTAINER( g_plugins_menu ) ), g_plugins_menu_separator  );
150         while ( lst->next )
151         {
152                 g_plugins_menu.remove(ui::Widget::from(lst->next->data));
153                 lst = g_list_find( gtk_container_get_children( GTK_CONTAINER( g_plugins_menu ) ),  g_plugins_menu_separator  );
154         }
155 }
156
157 ui::MenuItem create_plugins_menu(){
158         // Plugins menu
159         auto plugins_menu_item = new_sub_menu_item_with_mnemonic( "_Plugins" );
160         auto menu = ui::Menu(GTK_MENU( gtk_menu_item_get_submenu( plugins_menu_item ) ));
161         if ( g_Layout_enableDetachableMenus.m_value ) {
162                 menu_tearoff( menu );
163         }
164
165         g_plugins_menu = menu;
166
167         //TODO: some modules/plugins do not yet support refresh
168 #if 0
169         create_menu_item_with_mnemonic( menu, "Refresh", FreeCaller<Restart>() );
170
171         // NOTE: the seperator is used when doing a refresh of the list, everything past the seperator is removed
172         g_plugins_menu_separator = menu_separator( menu );
173 #endif
174
175         PluginsMenu_populate();
176
177         return plugins_menu_item;
178 }