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