]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/gtkutil/menu.cpp
-DGTK_DISABLE_DEPRECATED
[xonotic/netradiant.git] / libs / gtkutil / menu.cpp
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
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 "menu.h"
23
24 #include <ctype.h>
25 #include <gtk/gtk.h>
26 #include <uilib/uilib.h>
27 #include <debugging/debugging.h>
28
29 #include "generic/callback.h"
30
31 #include "accelerator.h"
32 #include "closure.h"
33 #include "container.h"
34 #include "pointer.h"
35
36 void menu_add_item( GtkMenu* menu, GtkMenuItem* item ){
37         gtk_container_add( GTK_CONTAINER( menu ), GTK_WIDGET( item ) );
38 }
39
40 GtkMenuItem* menu_separator( GtkMenu* menu ){
41         GtkMenuItem* menu_item = GTK_MENU_ITEM( gtk_menu_item_new() );
42         container_add_widget( GTK_CONTAINER( menu ), GTK_WIDGET( menu_item ) );
43         gtk_widget_set_sensitive( GTK_WIDGET( menu_item ), FALSE );
44         gtk_widget_show( GTK_WIDGET( menu_item ) );
45         return menu_item;
46 }
47
48 GtkTearoffMenuItem* menu_tearoff( GtkMenu* menu ){
49         GtkTearoffMenuItem* menu_item = GTK_TEAROFF_MENU_ITEM( gtk_tearoff_menu_item_new() );
50         container_add_widget( GTK_CONTAINER( menu ), GTK_WIDGET( menu_item ) );
51 // gtk_widget_set_sensitive(GTK_WIDGET(menu_item), FALSE); -- controls whether menu is detachable
52         gtk_widget_show( GTK_WIDGET( menu_item ) );
53         return menu_item;
54 }
55
56 GtkMenuItem* new_sub_menu_item_with_mnemonic( const char* mnemonic ){
57         GtkMenuItem* item = ui::MenuItem( mnemonic, true );
58         gtk_widget_show( GTK_WIDGET( item ) );
59
60         GtkWidget* sub_menu = ui::Menu();
61         gtk_menu_item_set_submenu( item, sub_menu );
62
63         return item;
64 }
65
66 GtkMenu* create_sub_menu_with_mnemonic( GtkMenuShell* parent, const char* mnemonic ){
67         GtkMenuItem* item = new_sub_menu_item_with_mnemonic( mnemonic );
68         container_add_widget( GTK_CONTAINER( parent ), GTK_WIDGET( item ) );
69         return GTK_MENU( gtk_menu_item_get_submenu( item ) );
70 }
71
72 GtkMenu* create_sub_menu_with_mnemonic( GtkMenuBar* bar, const char* mnemonic ){
73         return create_sub_menu_with_mnemonic( GTK_MENU_SHELL( bar ), mnemonic );
74 }
75
76 GtkMenu* create_sub_menu_with_mnemonic( GtkMenu* parent, const char* mnemonic ){
77         return create_sub_menu_with_mnemonic( GTK_MENU_SHELL( parent ), mnemonic );
78 }
79
80 void activate_closure_callback( GtkWidget* widget, gpointer data ){
81         ( *reinterpret_cast<Callback*>( data ) )( );
82 }
83
84 guint menu_item_connect_callback( GtkMenuItem* item, const Callback& callback ){
85 #if 1
86         return g_signal_connect_swapped( G_OBJECT( item ), "activate", G_CALLBACK( callback.getThunk() ), callback.getEnvironment() );
87 #else
88         return g_signal_connect_closure( G_OBJECT( item ), "activate", create_cclosure( G_CALLBACK( activate_closure_callback ), callback ), FALSE );
89 #endif
90 }
91
92 guint check_menu_item_connect_callback( GtkCheckMenuItem* item, const Callback& callback ){
93 #if 1
94         guint handler = g_signal_connect_swapped( G_OBJECT( item ), "toggled", G_CALLBACK( callback.getThunk() ), callback.getEnvironment() );
95 #else
96         guint handler = g_signal_connect_closure( G_OBJECT( item ), "toggled", create_cclosure( G_CALLBACK( activate_closure_callback ), callback ), TRUE );
97 #endif
98         g_object_set_data( G_OBJECT( item ), "handler", gint_to_pointer( handler ) );
99         return handler;
100 }
101
102 GtkMenuItem* new_menu_item_with_mnemonic( const char *mnemonic, const Callback& callback ){
103         GtkMenuItem* item = ui::MenuItem( mnemonic, true );
104         gtk_widget_show( GTK_WIDGET( item ) );
105         menu_item_connect_callback( item, callback );
106         return item;
107 }
108
109 GtkMenuItem* create_menu_item_with_mnemonic( GtkMenu* menu, const char *mnemonic, const Callback& callback ){
110         GtkMenuItem* item = new_menu_item_with_mnemonic( mnemonic, callback );
111         container_add_widget( GTK_CONTAINER( menu ), GTK_WIDGET( item ) );
112         return item;
113 }
114
115 GtkCheckMenuItem* new_check_menu_item_with_mnemonic( const char* mnemonic, const Callback& callback ){
116         GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM( gtk_check_menu_item_new_with_mnemonic( mnemonic ) );
117         gtk_widget_show( GTK_WIDGET( item ) );
118         check_menu_item_connect_callback( item, callback );
119         return item;
120 }
121
122 GtkCheckMenuItem* create_check_menu_item_with_mnemonic( GtkMenu* menu, const char* mnemonic, const Callback& callback ){
123         GtkCheckMenuItem* item = new_check_menu_item_with_mnemonic( mnemonic, callback );
124         container_add_widget( GTK_CONTAINER( menu ), GTK_WIDGET( item ) );
125         return item;
126 }
127
128 GtkRadioMenuItem* new_radio_menu_item_with_mnemonic( GSList** group, const char* mnemonic, const Callback& callback ){
129         GtkRadioMenuItem* item = GTK_RADIO_MENU_ITEM( gtk_radio_menu_item_new_with_mnemonic( *group, mnemonic ) );
130         if ( *group == 0 ) {
131                 gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( item ), TRUE );
132         }
133         *group = gtk_radio_menu_item_get_group( item );
134         gtk_widget_show( GTK_WIDGET( item ) );
135         check_menu_item_connect_callback( GTK_CHECK_MENU_ITEM( item ), callback );
136         return item;
137 }
138
139 GtkRadioMenuItem* create_radio_menu_item_with_mnemonic( GtkMenu* menu, GSList** group, const char* mnemonic, const Callback& callback ){
140         GtkRadioMenuItem* item = new_radio_menu_item_with_mnemonic( group, mnemonic, callback );
141         container_add_widget( GTK_CONTAINER( menu ), GTK_WIDGET( item ) );
142         return item;
143 }
144
145 void check_menu_item_set_active_no_signal( GtkCheckMenuItem* item, gboolean active ){
146         guint handler_id = gpointer_to_int( g_object_get_data( G_OBJECT( item ), "handler" ) );
147         g_signal_handler_block( G_OBJECT( item ), handler_id );
148         gtk_check_menu_item_set_active( item, active );
149         g_signal_handler_unblock( G_OBJECT( item ), handler_id );
150 }
151
152
153
154 void radio_menu_item_set_active_no_signal( GtkRadioMenuItem* item, gboolean active ){
155         {
156                 for ( GSList* l = gtk_radio_menu_item_get_group( item ); l != 0; l = g_slist_next( l ) )
157                 {
158                         g_signal_handler_block( G_OBJECT( l->data ), gpointer_to_int( g_object_get_data( G_OBJECT( l->data ), "handler" ) ) );
159                 }
160         }
161         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( item ), active );
162         {
163                 for ( GSList* l = gtk_radio_menu_item_get_group( item ); l != 0; l = g_slist_next( l ) )
164                 {
165                         g_signal_handler_unblock( G_OBJECT( l->data ), gpointer_to_int( g_object_get_data( G_OBJECT( l->data ), "handler" ) ) );
166                 }
167         }
168 }
169
170
171 void menu_item_set_accelerator( GtkMenuItem* item, GClosure* closure ){
172         GtkAccelLabel* accel_label = GTK_ACCEL_LABEL( gtk_bin_get_child( GTK_BIN( item ) ) );
173         gtk_accel_label_set_accel_closure( accel_label, closure );
174 }
175
176 void accelerator_name( const Accelerator& accelerator, GString* gstring ){
177         gboolean had_mod = FALSE;
178         if ( accelerator.modifiers & GDK_SHIFT_MASK ) {
179                 g_string_append( gstring, "Shift" );
180                 had_mod = TRUE;
181         }
182         if ( accelerator.modifiers & GDK_CONTROL_MASK ) {
183                 if ( had_mod ) {
184                         g_string_append( gstring, "+" );
185                 }
186                 g_string_append( gstring, "Ctrl" );
187                 had_mod = TRUE;
188         }
189         if ( accelerator.modifiers & GDK_MOD1_MASK ) {
190                 if ( had_mod ) {
191                         g_string_append( gstring, "+" );
192                 }
193                 g_string_append( gstring, "Alt" );
194                 had_mod = TRUE;
195         }
196
197         if ( had_mod ) {
198                 g_string_append( gstring, "+" );
199         }
200         if ( accelerator.key < 0x80 || ( accelerator.key > 0x80 && accelerator.key <= 0xff ) ) {
201                 switch ( accelerator.key )
202                 {
203                 case ' ':
204                         g_string_append( gstring, "Space" );
205                         break;
206                 case '\\':
207                         g_string_append( gstring, "Backslash" );
208                         break;
209                 default:
210                         g_string_append_c( gstring, gchar( toupper( accelerator.key ) ) );
211                         break;
212                 }
213         }
214         else
215         {
216                 gchar *tmp;
217
218                 tmp = gtk_accelerator_name( accelerator.key, (GdkModifierType)0 );
219                 if ( tmp[0] != 0 && tmp[1] == 0 ) {
220                         tmp[0] = gchar( toupper( tmp[0] ) );
221                 }
222                 g_string_append( gstring, tmp );
223                 g_free( tmp );
224         }
225 }
226
227 void menu_item_add_accelerator( GtkMenuItem* item, Accelerator accelerator ){
228         if ( accelerator.key != 0 ) {
229                 GClosure* closure = global_accel_group_find( accelerator );
230                 ASSERT_NOTNULL(closure);
231                 menu_item_set_accelerator( item, closure );
232         }
233 }
234
235 GtkMenuItem* create_menu_item_with_mnemonic( GtkMenu* menu, const char* mnemonic, const Command& command ){
236         GtkMenuItem* item = create_menu_item_with_mnemonic( menu, mnemonic, command.m_callback );
237         menu_item_add_accelerator( item, command.m_accelerator );
238         return item;
239 }
240
241 void check_menu_item_set_active_callback( GtkCheckMenuItem& item, bool enabled ){
242         check_menu_item_set_active_no_signal( &item, enabled );
243 }
244 typedef ReferenceCaller1<GtkCheckMenuItem, bool, check_menu_item_set_active_callback> CheckMenuItemSetActiveCaller;
245
246 GtkCheckMenuItem* create_check_menu_item_with_mnemonic( GtkMenu* menu, const char* mnemonic, const Toggle& toggle ){
247         GtkCheckMenuItem* item = create_check_menu_item_with_mnemonic( menu, mnemonic, toggle.m_command.m_callback );
248         menu_item_add_accelerator( GTK_MENU_ITEM( item ), toggle.m_command.m_accelerator );
249         toggle.m_exportCallback( CheckMenuItemSetActiveCaller( *item ) );
250         return item;
251 }