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