1 // This is core/vgui/vgui_displaybase_tableau.cxx
2 //:
3 // \file
4 // \author Philip C. Pritchett, RRG, University of Oxford
5 // \date   14 Sep 1999
6 // \brief  See vgui_displaybase_tableau.h for a description of this file.
7 
8 #include <iostream>
9 #include <vector>
10 #include <algorithm>
11 #include <utility>
12 #include "vgui_displaybase_tableau.h"
13 #include "vgui_macro.h"
14 
15 #ifdef _MSC_VER
16 #  include "vcl_msvc_warnings.h"
17 #endif
18 
19 #include "vgui/vgui_gl.h"
20 #include "vgui/vgui_glu.h"
21 #include "vgui/vgui_event.h"
22 #include "vgui/vgui_message.h"
23 #include "vgui/vgui_style.h"
24 #include "vgui/vgui_soview.h"
25 
26 bool
select(unsigned)27 vgui_displaybase_tableau_selection_callback::select(unsigned)
28 {
29   return false;
30 }
31 
32 bool
deselect(unsigned)33 vgui_displaybase_tableau_selection_callback::deselect(unsigned)
34 {
35   return false;
36 }
37 
38 bool
deselect_all()39 vgui_displaybase_tableau_selection_callback::deselect_all()
40 {
41   return false;
42 }
43 
vgui_displaybase_tableau()44 vgui_displaybase_tableau::vgui_displaybase_tableau()
45 {
46   id = vgui_soview::create_id();
47 
48   gl_mode = GL_RENDER;
49   highlighted = 0;
50   gl_display_list = GL_INVALID_VALUE;
51 
52   cb_ = nullptr;
53 
54   current_grouping = "default";
55   groupings.clear();
56 }
57 
~vgui_displaybase_tableau()58 vgui_displaybase_tableau::~vgui_displaybase_tableau() {}
59 
60 void
set_selection_callback(vgui_displaybase_tableau_selection_callback * cb)61 vgui_displaybase_tableau::set_selection_callback(vgui_displaybase_tableau_selection_callback * cb)
62 {
63   cb_ = cb;
64 }
65 
66 void
add(vgui_soview * object)67 vgui_displaybase_tableau::add(vgui_soview * object)
68 {
69 #ifndef NDEBUG
70   std::vector<vgui_soview *>::iterator i = std::find(objects.begin(), objects.end(), object);
71   if (i == objects.end())
72   {
73 #endif
74     objects.push_back(object);
75     std::map<std::string, vgui_displaybase_tableau_grouping>::iterator it = groupings.find(current_grouping);
76     if (it == groupings.end())
77     {
78       vgui_displaybase_tableau_grouping temp;
79       temp.style = nullptr;
80       temp.hide = false;
81       temp.color_override = false;
82       temp.line_width_override = false;
83       temp.point_size_override = false;
84       temp.objects.push_back(object);
85       groupings.insert(std::pair<std::string, vgui_displaybase_tableau_grouping>(current_grouping, temp));
86     }
87     else
88       it->second.objects.push_back(object);
89 #ifndef NDEBUG
90   }
91   else
92     std::cerr << "Warning: attempt to add an soview twice.\n";
93 #endif
94 }
95 
96 void
remove(vgui_soview * & object)97 vgui_displaybase_tableau::remove(vgui_soview *& object)
98 {
99   if (object->get_id() == highlighted)
100   {
101     // if the point to be removed is the currently highlighted
102     // one, zero out the 'highlighted' field. otherwise the
103     // point will still be rendered when the pointer moves.
104     highlighted = 0;
105   }
106 
107   // must first unselect the object, if it's selected
108   deselect(object->get_id());
109 
110   std::vector<vgui_soview *>::iterator i = std::find(objects.begin(), objects.end(), object);
111   if (i != objects.end())
112   {
113     objects.erase(i);
114   }
115 
116   for (std::map<std::string, vgui_displaybase_tableau_grouping>::iterator it = groupings.begin(); it != groupings.end();
117        it++)
118   {
119     std::vector<vgui_soview *>::iterator a = std::find(it->second.objects.begin(), it->second.objects.end(), object);
120     if (a != it->second.objects.end())
121     {
122       it->second.objects.erase(a);
123       if (it->second.objects.size() == 0)
124       {
125         groupings.erase(it);
126       }
127       delete object;
128       break; // found obj, stop iterating
129     }
130   }
131 }
132 
133 //: clear all soviews from the display.
134 //  The soviews must be deleted otherwise we have a big memory leak.
135 //  It is not clear that the design intended that the creator of the
136 //  soview is responsible for deleting it.  In any case, such management
137 //  would be impossible without reference counting.  If users are going
138 //  to keep soviews for personal use, then the whole soview scheme
139 //  should be changed to smart pointers. JLM
140 //
141 void
clear()142 vgui_displaybase_tableau::clear()
143 {
144   highlighted = 0;
145   deselect_all();
146 
147   // destroy the objects
148   for (std::vector<vgui_soview *>::iterator so_iter = objects.begin(); so_iter != objects.end(); ++so_iter)
149   {
150     delete *so_iter;
151   }
152 
153   objects.clear();
154 
155   for (std::map<std::string, vgui_displaybase_tableau_grouping>::iterator it = groupings.begin(); it != groupings.end();
156        it++)
157   {
158     it->second.objects.clear();
159   }
160 
161   groupings.clear();
162 }
163 
164 void
draw_soviews_render()165 vgui_displaybase_tableau::draw_soviews_render()
166 {
167   vgui_macro_report_errors;
168   {
169     for (std::map<std::string, vgui_displaybase_tableau_grouping>::iterator it = groupings.begin();
170          it != groupings.end();
171          it++)
172     {
173       if (!it->second.hide)
174       {
175         for (std::vector<vgui_soview *>::iterator so_iter = it->second.objects.begin();
176              so_iter != it->second.objects.end();
177              ++so_iter)
178         {
179           vgui_soview * so = *so_iter;
180           vgui_style_sptr style = so->get_style();
181 
182           if (!it->second.style && style)
183             style->apply_all();
184           else if (!style && it->second.style)
185             it->second.style->apply_all();
186           else if (style && it->second.style)
187           {
188             if (it->second.color_override)
189               it->second.style->apply_color();
190             else
191               style->apply_color();
192 
193             if (it->second.line_width_override)
194               it->second.style->apply_line_width();
195             else
196               style->apply_line_width();
197 
198             if (it->second.point_size_override)
199               it->second.style->apply_point_size();
200             else
201               style->apply_point_size();
202           }
203 
204           if (is_selected(so->get_id()))
205             glColor3f(1.0f, 0.0f, 0.0f);
206 
207           so->draw();
208         } //  for all soviews
209       }
210     }
211   }
212   vgui_macro_report_errors;
213 }
214 
215 
216 void
draw_soviews_select()217 vgui_displaybase_tableau::draw_soviews_select()
218 {
219   // push the name of this displaylist onto the name stack
220   glPushName(id);
221 
222   glPushName(0); // will be replaced by the id of each object
223 
224   for (std::map<std::string, vgui_displaybase_tableau_grouping>::iterator it = groupings.begin(); it != groupings.end();
225        it++)
226   {
227     if (!it->second.hide)
228     {
229       for (std::vector<vgui_soview *>::iterator so_iter = it->second.objects.begin();
230            so_iter != it->second.objects.end();
231            ++so_iter)
232       {
233         // only highlight if the so is selectable
234         vgui_soview * so = *so_iter;
235         if (so->get_selectable())
236         {
237           so->load_name();
238           so->draw_select();
239         }
240       } //  for all soviews
241     }
242   }
243 
244   // remove name of last object
245   glPopName();
246 
247   // remove the name of the displaylist from the name stack
248   glPopName();
249 }
250 
251 
252 bool
handle(const vgui_event & e)253 vgui_displaybase_tableau::handle(const vgui_event & e)
254 {
255   if (e.type == vgui_DRAW)
256   {
257     if (gl_mode == GL_SELECT)
258       draw_soviews_select();
259     else
260       draw_soviews_render();
261 
262     return true;
263   }
264   else
265     return vgui_tableau::handle(e);
266 }
267 
268 bool
is_selected(unsigned iden)269 vgui_displaybase_tableau::is_selected(unsigned iden)
270 {
271   std::vector<unsigned>::iterator result = std::find(selections.begin(), selections.end(), iden);
272   return result != selections.end();
273 }
274 
275 std::vector<vgui_soview *>
get_selected_soviews() const276 vgui_displaybase_tableau::get_selected_soviews() const
277 {
278   std::vector<vgui_soview *> svs;
279   for (unsigned i = 0; i < selections.size(); ++i)
280   {
281     svs.push_back(vgui_soview::id_to_object(selections[i]));
282   }
283   return svs;
284 }
285 
286 std::vector<unsigned>
get_all_ids() const287 vgui_displaybase_tableau::get_all_ids() const
288 {
289   std::vector<unsigned> ids;
290   for (unsigned int i = 0; i < objects.size(); ++i)
291     ids.push_back(objects[i]->get_id());
292 
293   return ids;
294 }
295 
296 bool
select(unsigned iden)297 vgui_displaybase_tableau::select(unsigned iden)
298 {
299   std::vector<unsigned>::iterator result = std::find(selections.begin(), selections.end(), iden);
300   if (result == selections.end())
301   {
302     // add selection to std::list
303     selections.push_back(iden);
304 
305     // notify so's observers
306     vgui_soview * so = vgui_soview::id_to_object(iden);
307 
308     if (so->get_selectable())
309     {
310       vgui_message msg;
311 #if 0
312       msg.text = "soview select";
313 #endif // 0
314       msg.user = (void const *)&vgui_soview::msg_select;
315       so->notify(msg);
316 
317       if (cb_)
318         cb_->select(iden);
319     }
320   }
321 
322   return true;
323 }
324 
325 bool
deselect(unsigned iden)326 vgui_displaybase_tableau::deselect(unsigned iden)
327 {
328   std::vector<unsigned>::iterator result = std::find(selections.begin(), selections.end(), iden);
329   if (result != selections.end())
330   {
331     // remove selection from std::list
332     selections.erase(result);
333 
334     // notify so's observers
335     vgui_soview * so = vgui_soview::id_to_object(iden);
336     vgui_message msg;
337 #if 0
338     msg.text = "soview deselect";
339 #endif // 0
340     msg.user = (void const *)&vgui_soview::msg_deselect;
341     so->notify(msg);
342 
343     if (cb_)
344       cb_->deselect(iden);
345   }
346 
347   return true;
348 }
349 
350 bool
deselect_all()351 vgui_displaybase_tableau::deselect_all()
352 {
353   // this is a bit inelegant but you have to make a copy
354   // of the selections std::list as sending the deselect message
355   // may actually change the selections
356 
357   std::vector<unsigned> oldselections = selections;
358 
359   for (std::vector<unsigned>::iterator s_iter = oldselections.begin(); s_iter != oldselections.end(); ++s_iter)
360   {
361     unsigned iden = *s_iter;
362 
363     // notify so's observers
364     vgui_soview * so = vgui_soview::id_to_object(iden);
365     vgui_message msg;
366     msg.user = (void const *)&vgui_soview::msg_deselect;
367     so->notify(msg);
368 
369     if (cb_)
370       cb_->deselect(iden);
371   }
372 
373   selections.clear();
374   this->post_redraw();
375 
376   return true;
377 }
378 
379 
380 vgui_soview *
get_highlighted_soview()381 vgui_displaybase_tableau::get_highlighted_soview()
382 {
383   return vgui_soview::id_to_object(highlighted);
384 }
385 
386 vgui_soview *
contains_hit(std::vector<unsigned> names)387 vgui_displaybase_tableau::contains_hit(std::vector<unsigned> names)
388 {
389   for (std::vector<vgui_soview *>::iterator i = objects.begin(); i != objects.end(); ++i)
390   {
391     // get id of soview
392     unsigned soview_id = (*i)->get_id();
393 #ifdef DEBUG
394     std::cerr << "vgui_displaybase_tableau::contains_hit soview_id=" << soview_id << '\n';
395 #endif
396     std::vector<unsigned>::iterator ni = std::find(names.begin(), names.end(), soview_id);
397     if (ni != names.end())
398       return *i;
399   }
400 
401   return nullptr;
402 }
403 
404 vgui_displaybase_tableau_grouping *
get_grouping_ptr(std::string t_name)405 vgui_displaybase_tableau::get_grouping_ptr(std::string t_name)
406 {
407   std::map<std::string, vgui_displaybase_tableau_grouping>::iterator it = groupings.find(t_name);
408   if (it != groupings.end())
409     return &it->second;
410   else
411     return nullptr;
412 }
413 
414 std::vector<std::string>
get_grouping_names()415 vgui_displaybase_tableau::get_grouping_names()
416 {
417   std::vector<std::string> to_return;
418 
419   for (std::map<std::string, vgui_displaybase_tableau_grouping>::iterator it = groupings.begin(); it != groupings.end();
420        it++)
421   {
422     to_return.push_back(it->first);
423   }
424 
425   return to_return;
426 }
427