1 // This is core/vgui/vgui_tableau.cxx
2 //:
3 // \file
4 // \author Philip C. Pritchett, Robotics Research Group, University of Oxford
5 // \date   11 Sep 99
6 // \brief  See vgui_tableau.h for a description of this file.
7 //
8 // \verbatim
9 //  Modifications
10 //   11-SEP-1999 P.Pritchett - Initial version.
11 //   08-OCT-2002 K.Y.McGaul - Removed unused adopt and disown functions.
12 // \endverbatim
13 
14 #include <iostream>
15 #include <vector>
16 #include <algorithm>
17 #include "vgui_tableau.h"
18 
19 #include <cassert>
20 #ifdef _MSC_VER
21 #  include "vcl_msvc_warnings.h"
22 #endif
23 
24 #include "vgui/vgui_macro.h"
25 #include "vgui/vgui_event.h"
26 #include "vgui/vgui_parent_child_link.h"
27 #include "vgui/vgui_menu.h"
28 #include "vgui/vgui_popup_params.h"
29 #include "vgui/vgui_tableau_sptr.h"
30 
31 // static data
32 //------------
33 // Every tableau is on this array.
34 // It must be a ptr as must live longer than any vgui_tableau_sptr
35 static vgui_DLLDATA std::vector<vgui_tableau *> * all = nullptr;
36 
37 //-----------------------------------------------------------------------------
38 //: Constructor.
39 //  Don't use the constructor for a tableau, use vgui_tableau_sptr to get
40 //  a smart-pointer to your tableau.
vgui_tableau()41 vgui_tableau::vgui_tableau()
42   : references(0)
43 {
44 #ifdef DEBUG
45   std::cerr << "vgui_tableau constructor: this = " << (void *)this << '\n';
46 #endif
47   // register :
48   if (all == nullptr)
49   {
50     all = new std::vector<vgui_tableau *>;
51   }
52   all->push_back(this);
53 }
54 
55 //-----------------------------------------------------------------------------
56 //: Destructor - called by vgui_tableau_sptr when ref count is zero.
~vgui_tableau()57 vgui_tableau::~vgui_tableau()
58 {
59 #ifdef DEBUG
60   std::cerr << "vgui_tableau destructor : this = " << (void *)this << '\n';
61 #endif
62 
63   if (references != 0)
64     vgui_macro_warning << "there are still " << references << " references. this=" << (void *)this << std::endl;
65 
66   // deregister :
67   std::vector<vgui_tableau *>::iterator i = std::find(all->begin(), all->end(), this);
68   assert(i != all->end());
69   all->erase(i);
70   if (all->size() == 0)
71   {
72     delete all;
73     all = nullptr;
74   }
75 }
76 
77 //-----------------------------------------------------------------------------
78 //: Increase the reference count by one (for smart-pointers).
79 void
ref() const80 vgui_tableau::ref() const
81 {
82   ++const_cast<int &>(references);
83 }
84 
85 //-----------------------------------------------------------------------------
86 //: Decrease the reference count by one (for smart-pointers).
87 //  If the reference count reaches zero then delete the object.
88 void
unref() const89 vgui_tableau::unref() const
90 {
91   assert(references > 0); // fatal if not
92 
93   if (--const_cast<int &>(references) == 0)
94   {
95     delete const_cast<vgui_tableau *>(this);
96   }
97 }
98 
99 //-----------------------------------------------------------------------------
100 //: Handle all events sent to this tableau.
101 //  Override in subclasses to give the tableau some appearance and behaviour.
102 bool
handle(vgui_event const & event)103 vgui_tableau::handle(vgui_event const & event)
104 {
105   vgui_macro_report_errors;
106 
107   switch (event.type)
108   {
109     case vgui_DRAW:
110       return draw();
111     case vgui_BUTTON_DOWN:
112       return mouse_down(event.wx, event.wy, event.button, event.modifier);
113     case vgui_MOTION:
114       return motion(event.wx, event.wy);
115     case vgui_BUTTON_UP:
116       return mouse_up(event.wx, event.wy, event.button, event.modifier);
117     case vgui_KEY_PRESS:
118       if (event.key == '?' || event.key == '/')
119         return help();
120       else
121         return key_press(event.wx, event.wy, event.key, event.modifier);
122     case vgui_IDLE:
123       return idle();
124     default:
125       return false;
126   }
127 }
128 
129 //-----------------------------------------------------------------------------
130 //: Called by default handle when it receives a mouse down event.
131 bool
mouse_down(int,int,vgui_button,vgui_modifier)132 vgui_tableau::mouse_down(int, int, vgui_button, vgui_modifier)
133 {
134 #ifdef DEBUG
135   std::cerr << "vgui_tableau::mouse_down\n";
136 #endif
137   return false;
138 }
139 
140 //-----------------------------------------------------------------------------
141 //: Called by default handle when it receives a mouse up event.
142 bool
mouse_up(int,int,vgui_button,vgui_modifier)143 vgui_tableau::mouse_up(int, int, vgui_button, vgui_modifier)
144 {
145 #ifdef DEBUG
146   std::cerr << "vgui_tableau::mouse_up\n";
147 #endif
148   return false;
149 }
150 
151 //-----------------------------------------------------------------------------
152 //: Called by default handle when it receives a mouse motion event.
153 bool
motion(int,int)154 vgui_tableau::motion(int, int)
155 {
156 #ifdef DEBUG
157   std::cerr << "vgui_tableau::motion\n";
158 #endif
159   return false;
160 }
161 
162 //-----------------------------------------------------------------------------
163 //: Caled by default handle when it receives a key press event.
164 bool
key_press(int,int,vgui_key,vgui_modifier)165 vgui_tableau::key_press(int, int, vgui_key, vgui_modifier)
166 {
167 #ifdef DEBUG
168   std::cerr << "vgui_tableau::key_press\n";
169 #endif
170   return false;
171 }
172 
173 //-----------------------------------------------------------------------------
174 //: Called by default handle when it receives a '?' pressed event.
175 bool
help()176 vgui_tableau::help()
177 {
178 #ifdef DEBUG
179   std::cerr << "vgui_tableau::help\n";
180 #endif
181   return false;
182 }
183 
184 //-----------------------------------------------------------------------------
185 //: Called by default handle when it receives a draw event.
186 bool
draw()187 vgui_tableau::draw()
188 {
189 #ifdef DEBUG
190   std::cerr << "vgui_tableau::draw\n";
191 #endif
192   return false;
193 }
194 
195 
196 bool
idle()197 vgui_tableau::idle()
198 {
199 #ifdef DEBUG
200   std::cerr << "vgui_tableau::idle\n";
201 #endif
202   return false; // no idle processing
203 }
204 
205 
206 //-----------------------------------------------------------------------------
207 //: Return the bounding box of this tableau.
208 //  If infinite in extent, or nothing is drawn, or you can't be bothered to
209 //  implement it, return false.
210 bool
get_bounding_box(float[3],float[3]) const211 vgui_tableau::get_bounding_box(float /*low*/[3], float /*high*/[3]) const
212 {
213   return false;
214 }
215 
216 //-----------------------------------------------------------------------------
217 //: Post a message event.
218 void
post_message(char const * msg,void const * data)219 vgui_tableau::post_message(char const * msg, void const * data)
220 {
221   std::vector<vgui_tableau_sptr> ps;
222   get_parents(&ps);
223   for (unsigned i = 0; i < ps.size(); ++i)
224     ps[i]->post_message(msg, data);
225 }
226 
227 //-----------------------------------------------------------------------------
228 //: Post a draw event.
229 void
post_redraw()230 vgui_tableau::post_redraw()
231 {
232   std::vector<vgui_tableau_sptr> ps;
233   get_parents(&ps);
234   for (unsigned i = 0; i < ps.size(); ++i)
235     ps[i]->post_redraw();
236 }
237 
238 //-----------------------------------------------------------------------------
239 //: Post an overlay redraw event.
240 void
post_overlay_redraw()241 vgui_tableau::post_overlay_redraw()
242 {
243   std::vector<vgui_tableau_sptr> ps;
244   get_parents(&ps);
245   for (unsigned i = 0; i < ps.size(); ++i)
246     ps[i]->post_overlay_redraw();
247 }
248 
249 
250 //-----------------------------------------------------------------------------
251 void
post_idle_request()252 vgui_tableau::post_idle_request()
253 {
254   std::vector<vgui_tableau_sptr> ps;
255   get_parents(&ps);
256   for (unsigned i = 0; i < ps.size(); ++i)
257     ps[i]->post_idle_request();
258 }
259 
260 
261 //-----------------------------------------------------------------------------
262 //: Return the name of the most derived (tableau) class.
263 //  Virtual. This ought never to be called as derived classes should
264 //  implement type_name().
265 std::string
type_name() const266 vgui_tableau::type_name() const
267 {
268   static bool warned = false;
269   if (!warned)
270   {
271     vgui_macro_warning << "WARNING: vgui_tableau::type_name() called\n";
272     warned = true;
273   }
274   return "vgui_tableau";
275 }
276 
277 //-----------------------------------------------------------------------------
278 //: Push parents onto the given std::vector.
279 void
get_parents(std::vector<vgui_tableau_sptr> * v) const280 vgui_tableau::get_parents(std::vector<vgui_tableau_sptr> * v) const
281 {
282   vgui_parent_child_link::get_parents_of(const_cast<vgui_tableau *>(this), v);
283 }
284 
285 //-----------------------------------------------------------------------------
286 //: Push children onto the given std::vector.
287 void
get_children(std::vector<vgui_tableau_sptr> * v) const288 vgui_tableau::get_children(std::vector<vgui_tableau_sptr> * v) const
289 {
290   vgui_parent_child_link::get_children_of(const_cast<vgui_tableau *>(this), v);
291 }
292 
293 //-----------------------------------------------------------------------------
294 //: Get the ith child, or return 0.
295 vgui_tableau_sptr
get_child(unsigned i) const296 vgui_tableau::get_child(unsigned i) const
297 {
298   std::vector<vgui_tableau_sptr> children;
299   get_children(&children);
300   return i < children.size() ? children[i] : vgui_tableau_sptr();
301 }
302 
303 //-----------------------------------------------------------------------------
304 //: Add the given tableau to the list of child tableaux.
305 //  Virtual overridden by consenting parents.
306 bool
add_child(vgui_tableau_sptr const &)307 vgui_tableau::add_child(vgui_tableau_sptr const &)
308 {
309   return false;
310 }
311 
312 //-----------------------------------------------------------------------------
313 //: Remove the given tableau from the list of child tableaux.
314 bool
remove_child(vgui_tableau_sptr const &)315 vgui_tableau::remove_child(vgui_tableau_sptr const &)
316 {
317   return false;
318 }
319 
320 //-----------------------------------------------------------------------------
321 //: Called when a child of this tableau is forcibly replaced.
322 //  This method is called when some part of the program (typically the
323 //  parent_child_link mechanism) is about to forcibly replace a child of this
324 //  tableau.
325 //  The canonical reason to override this is in order to invalidate caches.
326 bool
notify_replaced_child(vgui_tableau_sptr const &,vgui_tableau_sptr const &)327 vgui_tableau::notify_replaced_child(vgui_tableau_sptr const & /*old_child*/, vgui_tableau_sptr const & /*new_child*/)
328 {
329   return true;
330 }
331 
332 //-----------------------------------------------------------------------------
333 //: Add given menu to the tableau popup menu.
334 //  This method is for tableaux to implement if they want to _add_ some items to
335 //  the popup menu. They can assign to or clear 'menu', but that is not
336 //  recommended as it would remove what other tableaux put there.
337 //  The recommended usage is to .add() items or to .include() another menu.
338 //
339 //  ** This is an interface method. it abstracts a behaviour. **
340 void
add_popup(vgui_menu &)341 vgui_tableau::add_popup(vgui_menu & /*menu*/)
342 {
343   // do nothing by default.
344 }
345 
346 //-----------------------------------------------------------------------------
347 //: Gets popup menu for this tableau.
348 // If recurse is, true, recursively add the popup menus for children and
349 // children's children etc.
350 //
351 // ** this is a mixin method. it does some work for you. **
352 void
get_popup(vgui_popup_params const & params,vgui_menu & menu)353 vgui_tableau::get_popup(vgui_popup_params const & params, vgui_menu & menu)
354 {
355   // extract this tableau's popup menu into 'submenu'.
356   vgui_menu submenu;
357   add_popup(submenu);
358 
359   if (params.nested)
360   { // nested menu style.
361     // get list of children of this tableau.
362     std::vector<vgui_tableau_sptr> children;
363     get_children(&children);
364 
365     if (params.defaults && !children.empty())
366       submenu.separator();
367 
368     for (unsigned i = 0; i < children.size(); ++i)
369       if (children[i])
370         children[i]->get_popup(params, submenu);
371 
372     menu.add(type_name(), submenu);
373   }
374   else
375   {
376     // not nested.
377     if (submenu.size() > 0) // do not add empty submenus.
378       menu.include(submenu);
379 
380     if (params.recurse)
381     {
382       std::vector<vgui_tableau_sptr> children;
383       get_children(&children);
384 
385       for (unsigned i = 0; i < children.size(); ++i)
386         if (children[i])
387           children[i]->get_popup(params, menu);
388     }
389   }
390 }
391 
392 //-----------------------------------------------------------------------------
393 //: Prints pretty name and address of tableau.
394 //  eg : pig.jpg[vgui_composite:0xeffff728]
395 std::ostream &
operator <<(std::ostream & os,vgui_tableau_sptr const & t)396 operator<<(std::ostream & os, vgui_tableau_sptr const & t)
397 {
398   if (t)
399     return os << t->pretty_name() << '[' << t->type_name() << ':' << static_cast<const void *>(t.operator->()) << ']';
400   else
401     return os << "(empty vgui_tableau_sptr)" << std::flush;
402 }
403 
404 //-----------------------------------------------------------------------------
405 //: Push all tableaux onto the given vector.
406 void
get_all(std::vector<vgui_tableau_sptr> * v)407 vgui_tableau::get_all(std::vector<vgui_tableau_sptr> * v)
408 {
409   // v->insert(v->begin(), all->begin(), all->end());
410   for (unsigned i = 0; i < all->size(); ++i)
411     v->push_back((*all)[i]);
412 }
413 
414 //-----------------------------------------------------------------------------
415 //: Returns true if the given address points to a valid tableau.
416 bool
exists(vgui_tableau_sptr const & ptr)417 vgui_tableau::exists(vgui_tableau_sptr const & ptr)
418 {
419   return std::find(all->begin(), all->end(), ptr.operator->()) != all->end();
420 }
421