core/vgui/impl/glut/vgui_glut_popup_impl.cxx
Go to the documentation of this file.
00001 // This is core/vgui/impl/glut/vgui_glut_popup_impl.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "vgui_glut_popup_impl.h"
00010 #include "vgui_glut_adaptor.h"
00011 #include <vcl_iostream.h>
00012 #include <vgui/vgui_macro.h>
00013 #include <vgui/vgui_command.h>
00014 #include <vgui/vgui_glut.h>
00015 
00016 vgui_glut_popup_impl::vgui_glut_popup_impl()
00017 {
00018 #ifdef DEBUG
00019   vcl_cerr << "popup_impl ctor\n";
00020 #endif
00021   int old_id = glutGetMenu();
00022   menu_id = glutCreateMenu(command_func);
00023 #ifdef DEBUG
00024   vcl_cerr << "created menu_id = " << menu_id << '\n';
00025 #endif
00026 
00027   //vgui_macro_warning << "before\n";
00028   if (old_id)
00029     glutSetMenu(old_id);
00030   //vgui_macro_warning << "after\n";
00031 }
00032 
00033 
00034 void vgui_glut_popup_impl::clear()
00035 {
00036   int old_id = glutGetMenu();
00037   glutSetMenu(menu_id);
00038 
00039   //
00040   unsigned n = glutGet(GLenum(GLUT_MENU_NUM_ITEMS));
00041 #ifdef DEBUG
00042   vcl_cerr << "removing " << n << " items in menu\n";
00043 #endif
00044   for (int i=n; i>=1; --i)
00045     glutRemoveMenuItem(i);
00046 
00047   //
00048   //vgui_macro_warning << "before\n";
00049   if (old_id)
00050     glutSetMenu(old_id);
00051   //vgui_macro_warning << "after\n";
00052 
00053   //
00054   for (unsigned i=0; i<subs.size(); ++i)
00055     delete static_cast<vgui_glut_popup_impl*>( subs[i] );
00056   subs.clear();
00057 }
00058 
00059 vgui_glut_popup_impl::~vgui_glut_popup_impl()
00060 {
00061 #ifdef DEBUG
00062   vcl_cerr << "popup_impl dtor\n";
00063 #endif
00064   clear();
00065   glutDestroyMenu( menu_id );
00066   menu_id = 0;
00067 }
00068 
00069 void vgui_glut_popup_impl::build(vgui_menu const &m)
00070 {
00071   //clear();
00072 
00073   // FIXME - this line here is to make sure the commands in the
00074   // given menu stay alive while the popup menu is active :
00075   tmp_menu = m;
00076 
00077 #ifdef DEBUG
00078   vcl_cerr << "popup_impl::build : m =\n" << m << '\n';
00079 #endif
00080   this->build_internal(m);
00081 }
00082 
00083 void vgui_glut_popup_impl::build_internal(vgui_menu const &m)
00084 {
00085   int old_id = glutGetMenu();
00086   //vgui_macro_warning << "before\n";
00087   glutSetMenu(menu_id);
00088   //vgui_macro_warning << "after\n";
00089 
00090   for (unsigned i=0; i<m.size(); ++i) {
00091     if (m[i].is_command())
00092       glutAddMenuEntry( m[i].name.c_str(),
00093                         reinterpret_cast<long>(m[i].cmnd.as_pointer()));
00094 
00095     else if (m[i].is_submenu()) {
00096       vgui_glut_popup_impl *sub = new vgui_glut_popup_impl;
00097       sub->build_internal( * m[i].menu );
00098       glutAddSubMenu  (m[i].name.c_str(), sub->menu_id);
00099       subs.push_back(sub);
00100     }
00101 
00102     else if (m[i].is_toggle_button()) {
00103       vgui_command_toggle *c = static_cast<vgui_command_toggle*>( m[i].cmnd.as_pointer() );
00104       glutAddMenuEntry( (m[i].name + (c->state ? " (on)" : " (off)")).c_str(),
00105                         reinterpret_cast<long>(m[i].cmnd.as_pointer()));
00106     }
00107 
00108     else if (m[i].is_separator()) {
00109       // do glut menus have real separators?
00110       if (0<i && i<m.size()-1) // ignore separators at start and end.
00111         glutAddMenuEntry( "----------------", 1);
00112     }
00113 
00114     else {
00115       vgui_macro_warning << "unknown menu item\n"
00116                          << "menu =\n" << m << vcl_endl;
00117     }
00118   }
00119 
00120   //vgui_macro_warning << "before\n";
00121   if (old_id)
00122     glutSetMenu(old_id); // restore
00123   //vgui_macro_warning << "after\n";
00124 }
00125 
00126 // When a menu item is selected, glut may have upset its internal
00127 // state considerably and so it is advisable to wait for the next
00128 // idle event before invoking the vgui_command. E.g. if the command
00129 // were to start run_one_event()ing, heap corruption often results.
00130 // To accomplish that, the action of selecting a menu item just
00131 // queues the command for later execution.
00132 
00133 #include "vgui_glut_impl.h"
00134 
00135 void vgui_glut_popup_impl::command_func(int value)
00136 {
00137   if (value == 0)
00138     vgui_macro_warning << "null command\n";
00139   else if (value == 1)
00140     vcl_cerr << "[that's a separator]\n";
00141   else {
00142     int win = glutGetWindow();
00143     vgui_glut_adaptor *a = vgui_glut_adaptor::get_adaptor(win);
00144     vgui_command      *c = reinterpret_cast<vgui_command *>(value);
00145     vgui_glut_impl_queue_command(a, c);
00146   }
00147 }