1 // This is core/vgui/impl/glut/vgui_glut_popup_impl.cxx
2 //:
3 // \file
4 // \author fsm
5 
6 #include <iostream>
7 #include "vgui_glut_popup_impl.h"
8 #include "vgui_glut_adaptor.h"
9 #ifdef _MSC_VER
10 #  include "vcl_msvc_warnings.h"
11 #endif
12 #include "vgui/vgui_macro.h"
13 #include "vgui/vgui_command.h"
14 #include "vgui/vgui_glut.h"
15 
vgui_glut_popup_impl()16 vgui_glut_popup_impl::vgui_glut_popup_impl()
17 {
18 #ifdef DEBUG
19   std::cerr << "popup_impl ctor\n";
20 #endif
21   int old_id = glutGetMenu();
22   menu_id = glutCreateMenu(command_func);
23 #ifdef DEBUG
24   std::cerr << "created menu_id = " << menu_id << '\n';
25 #endif
26 
27   // vgui_macro_warning << "before\n";
28   if (old_id)
29     glutSetMenu(old_id);
30   // vgui_macro_warning << "after\n";
31 }
32 
33 
34 void
clear()35 vgui_glut_popup_impl::clear()
36 {
37   int old_id = glutGetMenu();
38   glutSetMenu(menu_id);
39 
40   //
41   unsigned n = glutGet(GLenum(GLUT_MENU_NUM_ITEMS));
42 #ifdef DEBUG
43   std::cerr << "removing " << n << " items in menu\n";
44 #endif
45   for (int i = n; i >= 1; --i)
46     glutRemoveMenuItem(i);
47 
48   //
49   // vgui_macro_warning << "before\n";
50   if (old_id)
51     glutSetMenu(old_id);
52   // vgui_macro_warning << "after\n";
53 
54   //
55   for (unsigned i = 0; i < subs.size(); ++i)
56     delete static_cast<vgui_glut_popup_impl *>(subs[i]);
57   subs.clear();
58 }
59 
~vgui_glut_popup_impl()60 vgui_glut_popup_impl::~vgui_glut_popup_impl()
61 {
62 #ifdef DEBUG
63   std::cerr << "popup_impl dtor\n";
64 #endif
65   clear();
66   glutDestroyMenu(menu_id);
67   menu_id = 0;
68 }
69 
70 void
build(vgui_menu const & m)71 vgui_glut_popup_impl::build(vgui_menu const & m)
72 {
73   // clear();
74 
75   // FIXME - this line here is to make sure the commands in the
76   // given menu stay alive while the popup menu is active :
77   tmp_menu = m;
78 
79 #ifdef DEBUG
80   std::cerr << "popup_impl::build : m =\n" << m << '\n';
81 #endif
82   this->build_internal(m);
83 }
84 
85 void
build_internal(vgui_menu const & m)86 vgui_glut_popup_impl::build_internal(vgui_menu const & m)
87 {
88   int old_id = glutGetMenu();
89   // vgui_macro_warning << "before\n";
90   glutSetMenu(menu_id);
91   // vgui_macro_warning << "after\n";
92 
93   for (unsigned i = 0; i < m.size(); ++i)
94   {
95     if (m[i].is_command())
96       glutAddMenuEntry(m[i].name.c_str(), reinterpret_cast<long>(m[i].cmnd.as_pointer()));
97 
98     else if (m[i].is_submenu())
99     {
100       vgui_glut_popup_impl * sub = new vgui_glut_popup_impl;
101       sub->build_internal(*m[i].menu);
102       glutAddSubMenu(m[i].name.c_str(), sub->menu_id);
103       subs.push_back(sub);
104     }
105 
106     else if (m[i].is_toggle_button())
107     {
108       vgui_command_toggle * c = static_cast<vgui_command_toggle *>(m[i].cmnd.as_pointer());
109       glutAddMenuEntry((m[i].name + (c->state ? " (on)" : " (off)")).c_str(),
110                        reinterpret_cast<long>(m[i].cmnd.as_pointer()));
111     }
112 
113     else if (m[i].is_separator())
114     {
115       // do glut menus have real separators?
116       if (0 < i && i < m.size() - 1) // ignore separators at start and end.
117         glutAddMenuEntry("----------------", 1);
118     }
119 
120     else
121     {
122       vgui_macro_warning << "unknown menu item\n"
123                          << "menu =\n"
124                          << m << std::endl;
125     }
126   }
127 
128   // vgui_macro_warning << "before\n";
129   if (old_id)
130     glutSetMenu(old_id); // restore
131   // vgui_macro_warning << "after\n";
132 }
133 
134 // When a menu item is selected, glut may have upset its internal
135 // state considerably and so it is advisable to wait for the next
136 // idle event before invoking the vgui_command. E.g. if the command
137 // were to start run_one_event()ing, heap corruption often results.
138 // To accomplish that, the action of selecting a menu item just
139 // queues the command for later execution.
140 
141 #include "vgui_glut_impl.h"
142 
143 void
command_func(int value)144 vgui_glut_popup_impl::command_func(int value)
145 {
146   if (value == 0)
147     vgui_macro_warning << "null command\n";
148   else if (value == 1)
149     std::cerr << "[that's a separator]\n";
150   else
151   {
152     int win = glutGetWindow();
153     vgui_glut_adaptor * a = vgui_glut_adaptor::get_adaptor(win);
154     vgui_command * c = reinterpret_cast<vgui_command *>(value);
155     vgui_glut_impl_queue_command(a, c);
156   }
157 }
158