core/vgui/impl/gtk2/vgui_gtk2_utils.cxx
Go to the documentation of this file.
00001 // This is core/vgui/impl/gtk2/vgui_gtk2_utils.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Philip C. Pritchett, RRG, University of Oxford
00008 // \date   19 Dec 99
00009 // \brief  See vgui_gtk2_utils.h for a description of this file.
00010 
00011 #include "vgui_gtk2_utils.h"
00012 
00013 #include <vcl_iostream.h>
00014 #include <vcl_cstdlib.h> // for vcl_abort()
00015 
00016 #include <vgui/vgui_gl.h>
00017 #include <gdk/gdkkeysyms.h>
00018 #include <gtk/gtk.h>
00019 
00020 #include <vgui/vgui_command.h>
00021 #include <vgui/vgui_menu.h>
00022 
00023 static bool debug = false;
00024 GtkAccelGroup *vgui_gtk2_utils::accel_group = NULL;
00025 
00026 vgui_button vgui_gtk2_utils::translate_button(int button)
00027 {
00028   if (button == 1)
00029     return vgui_LEFT;
00030   else if (button == 2)
00031     return vgui_MIDDLE;
00032   else if (button == 3)
00033     return vgui_RIGHT;
00034 #if 1
00035   // spinning the wheel generates button events no 4 and 5 -- fsm
00036   else if (button == 4)
00037     return vgui_MIDDLE;
00038   else if (button == 5)
00039     return vgui_MIDDLE;
00040 #endif
00041   else
00042     vcl_abort();
00043   return vgui_BUTTON_NULL;
00044 }
00045 
00046 vgui_key vgui_gtk2_utils::translate_key(GdkEventKey const *gev)
00047 {
00048   if (gev->length == 1)
00049     return vgui_key( *(gev->string) );
00050 
00051   switch (gev->keyval)
00052   {
00053    case GDK_Page_Up:
00054     return vgui_PAGE_UP;
00055    case GDK_Page_Down:
00056     return vgui_PAGE_DOWN;
00057    case GDK_Home:
00058     return vgui_HOME;
00059    case GDK_End:
00060     return vgui_END;
00061    case GDK_Delete:
00062     return vgui_DELETE;
00063    case GDK_Insert:
00064     return vgui_INSERT;
00065    case GDK_Up:
00066     return vgui_CURSOR_UP;
00067    case GDK_Down:
00068     return vgui_CURSOR_DOWN;
00069    case GDK_Left:
00070     return vgui_CURSOR_LEFT;
00071    case GDK_Right:
00072     return vgui_CURSOR_RIGHT;
00073    default:
00074     return vgui_KEY_NULL;
00075   }
00076 }
00077 
00078 guint vgui_gtk2_utils::translate_key_reverse(vgui_key key)
00079 {
00080   guint gdk_key;
00081 
00082   if ( key >= 'A' && key <= 'Z' )
00083     return char(key);
00084 
00085   if ( key >= 'a' && key <= 'z' )
00086     return char(key+'A'-'a'); 
00087 
00088   switch ( key ) 
00089   {
00090     // Function keys
00091     case vgui_F1:
00092     case vgui_F2:
00093     case vgui_F3:
00094     case vgui_F4:
00095     case vgui_F5:
00096     case vgui_F6:
00097     case vgui_F7:
00098     case vgui_F8:
00099     case vgui_F9:
00100     case vgui_F10:
00101     case vgui_F11:
00102     case vgui_F12:
00103       gdk_key = GDK_F1+key-vgui_F1;
00104       break;
00105     case vgui_CURSOR_LEFT:
00106     case vgui_CURSOR_UP:
00107     case vgui_CURSOR_RIGHT:
00108     case vgui_CURSOR_DOWN:
00109     case vgui_PAGE_UP:
00110     case vgui_PAGE_DOWN:
00111       gdk_key = GDK_Left+key-vgui_CURSOR_LEFT;
00112       break;
00113     case vgui_HOME:
00114       gdk_key = GDK_Home;
00115       break;
00116     case vgui_END:
00117       gdk_key = GDK_End;
00118       break;
00119     case vgui_DELETE:
00120       gdk_key = GDK_Delete;
00121       break;
00122     case vgui_INSERT:
00123       gdk_key = GDK_Insert;
00124       break;
00125     default: // undefined
00126       gdk_key = GDK_VoidSymbol; 
00127       break;
00128   }
00129 
00130   return gdk_key;
00131 }
00132 
00133 void vgui_gtk2_utils::set_coordinates(vgui_event &e, const gdouble x, const gdouble y)
00134 {
00135   GLint vp[4];
00136   glGetIntegerv(GL_VIEWPORT, vp);
00137   // FIXME : the size of the current glViewport settings is not
00138   // really what we want -- we want the size of the _window_.
00139   e.wx = (int)x;
00140   e.wy = vp[3]-1-(int)y;
00141 }
00142 
00143 void vgui_gtk2_utils::set_modifiers(vgui_event &e, const guint state)
00144 {
00145   e.modifier = vgui_modifier( ((state & 4)?vgui_CTRL:0) |
00146                               ((state & 8)?vgui_ALT:0) |
00147                               ((state & 1)?vgui_SHIFT:0) );
00148 }
00149 
00150 
00151 bool vgui_gtk2_utils::is_modifier(GdkEvent const *gev)
00152 {
00153   if (gev->type != GDK_KEY_PRESS &&
00154       gev->type != GDK_KEY_RELEASE)
00155     return false;
00156 
00157   GdkEventKey *e = (GdkEventKey*)(const_cast<GdkEvent*>(gev));
00158   // cannot use static_cast<> here since GdkEventKey and GdkEvent are unrelated
00159 
00160 #if 0
00161   // This code would only return 'true' if any of the modifier keys is solely
00162   // pressed. However we want to return 'true' so long as any of the modifier
00163   // keys is pressed simultaneously with some other key. This is a must
00164   // if we want to allow menu accelerator keys. - u97mb
00165 
00166   return e->keyval & GDK_Shift_L ||
00167          e->keyval & GDK_Shift_R ||
00168          e->keyval & GDK_Control_L ||
00169          e->keyval & GDK_Control_R ||
00170          e->keyval & GDK_Meta_L ||
00171          e->keyval & GDK_Meta_R ||
00172          e->keyval & GDK_Alt_L ||
00173          e->keyval & GDK_Alt_R;
00174 #endif // 0
00175   // - u97mb
00176   // GDK_MOD1_MASK corresponds to META key(at least on Sun Solaris)
00177   return e->state & GDK_CONTROL_MASK ||
00178          e->state & GDK_SHIFT_MASK ||
00179          e->state & GDK_MOD1_MASK;
00180 }
00181 
00182 
00183 static void execute_command(GtkWidget*, gpointer c)
00184 {
00185   vgui_command *cmnd = static_cast<vgui_command*>(c);
00186   cmnd->execute();
00187 }
00188 
00189 
00190 void vgui_gtk2_utils::add_submenu(GtkWidget *widget, const vgui_menu& menu)
00191 {
00192   for (unsigned i=0;i<menu.size();i++)
00193   {
00194     if (menu[i].is_separator())
00195     {
00196       if (debug) vcl_cerr << " <separator>\n";
00197       GtkWidget* item = gtk_menu_item_new();
00198       gtk_menu_append(GTK_MENU(widget), item);
00199       gtk_widget_show(item);
00200     }
00201 
00202     else if (menu[i].is_command())
00203     {
00204       if (debug) vcl_cerr << " <command>\n";
00205       GtkWidget* item = gtk_menu_item_new_with_label(menu[i].name.c_str());
00206       gtk_signal_connect(GTK_OBJECT(item), "activate",
00207                          GTK_SIGNAL_FUNC(execute_command),
00208                          (void*)menu[i].cmnd.as_pointer());
00209 
00210       gtk_menu_append(GTK_MENU(widget), item);
00211 
00212       gtk_widget_show(item);
00213       if (menu[i].short_cut.mod!=vgui_MODIFIER_NULL ||
00214           menu[i].short_cut.key!=vgui_KEY_NULL)
00215       {
00216         GdkModifierType mask = GdkModifierType(0);
00217         // Health warning - It seems that GDK_MOD1_MASK corresponds
00218         // to META on Solaris and ALT has no correspondance
00219         if (menu[i].short_cut.mod & vgui_CTRL)
00220           mask = GdkModifierType(mask | GDK_CONTROL_MASK);
00221         if (menu[i].short_cut.mod & vgui_META)
00222           mask = GdkModifierType(mask | GDK_MOD1_MASK);
00223         if (menu[i].short_cut.mod & vgui_SHIFT)
00224           mask = GdkModifierType(mask | GDK_SHIFT_MASK);
00225         if (menu[i].short_cut.mod & vgui_ALT)
00226           mask = GdkModifierType(mask | GDK_MOD1_MASK);
00227         gtk_widget_add_accelerator (item,
00228                                     "activate",
00229                                     accel_group,
00230                                     translate_key_reverse(menu[i].short_cut.key),
00231                                     mask,
00232                                     GtkAccelFlags(GTK_ACCEL_VISIBLE|GTK_ACCEL_LOCKED));
00233       }
00234     }
00235     else if (menu[i].is_submenu())
00236     {
00237       if (debug) vcl_cerr << " <submenu>\n";
00238       GtkWidget* item = gtk_menu_item_new_with_label(menu[i].name.c_str());
00239       GtkWidget* submenu = gtk_menu_new();
00240 
00241       gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
00242       gtk_menu_append(GTK_MENU(widget), item);
00243       gtk_widget_show(item);
00244 
00245       add_submenu(submenu, *menu[i].menu);
00246       
00247       GtkWidget *tearoffitem= gtk_tearoff_menu_item_new();
00248       gtk_menu_prepend(GTK_MENU(submenu), tearoffitem);
00249       gtk_widget_show(tearoffitem);
00250     }
00251   }
00252 }
00253 
00254 void vgui_gtk2_utils::set_menu(GtkWidget *widget, const vgui_menu& menu, bool is_menubar)
00255 {
00256   for (unsigned i=0;i<menu.size();i++)
00257   {
00258     if (menu[i].is_separator())
00259     {
00260       if (debug) vcl_cerr << " <separator>\n";
00261       GtkWidget* item = gtk_menu_item_new();
00262       if (!is_menubar)
00263         gtk_menu_append(GTK_MENU(widget), item);
00264       gtk_widget_show(item);
00265     }
00266     else if (menu[i].is_command())
00267     {
00268       if (debug) vcl_cerr << " <command> " << menu[i].name << vcl_endl;
00269       GtkWidget* item = gtk_menu_item_new_with_label(menu[i].name.c_str());
00270 
00271       if (is_menubar)
00272         gtk_menu_bar_append(GTK_MENU_BAR(widget), item);
00273       else
00274       {
00275         if (menu[i].short_cut.mod!=vgui_MODIFIER_NULL ||
00276             menu[i].short_cut.key!=vgui_KEY_NULL)
00277         {
00278           GdkModifierType mask = GdkModifierType(0);
00279           // Health warning - It seems that GDK_MOD1_MASK corresponds
00280           // to META on Solaris and ALT has no correspondance
00281           if (menu[i].short_cut.mod & vgui_CTRL)
00282             mask = GdkModifierType(mask | GDK_CONTROL_MASK);
00283           if (menu[i].short_cut.mod & vgui_META)
00284             mask = GdkModifierType(mask | GDK_MOD1_MASK);
00285           if (menu[i].short_cut.mod & vgui_SHIFT)
00286             mask = GdkModifierType(mask | GDK_SHIFT_MASK);
00287           if (menu[i].short_cut.mod & vgui_ALT)
00288             mask = GdkModifierType(mask | GDK_MOD1_MASK);
00289           gtk_widget_add_accelerator (item,
00290                                       "activate",
00291                                       accel_group,
00292                                       translate_key_reverse(menu[i].short_cut.key),
00293                                       mask,
00294                                       GtkAccelFlags(GTK_ACCEL_VISIBLE|GTK_ACCEL_LOCKED));
00295         }
00296         gtk_menu_append(GTK_MENU(widget), item);
00297       }
00298 
00299       gtk_signal_connect(GTK_OBJECT(item), "activate",
00300                          GTK_SIGNAL_FUNC(execute_command),
00301                          (void*)menu[i].cmnd.as_pointer());
00302 
00303       gtk_widget_show(item);
00304     }
00305     else if (menu[i].is_submenu())
00306     {
00307       if (debug) vcl_cerr << " <submenu> " << menu[i].name << vcl_endl;
00308 
00309       GtkWidget* item = gtk_menu_item_new_with_label(menu[i].name.c_str());
00310       GtkWidget* submenu = gtk_menu_new();
00311 
00312       gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
00313 
00314       if (is_menubar)
00315         gtk_menu_bar_append(GTK_MENU_BAR(widget), item);
00316       else
00317         gtk_menu_append(GTK_MENU(widget), item);
00318 
00319       gtk_widget_show(item);
00320 
00321       add_submenu(submenu, *menu[i].menu);
00322 
00323       GtkWidget *tearoffitem= gtk_tearoff_menu_item_new();
00324       gtk_menu_prepend(GTK_MENU(submenu), tearoffitem);
00325       gtk_widget_show(tearoffitem);
00326     }
00327 
00328     
00329   }
00330 
00331 }