1 // This is core/vgui/vgui_soview.cxx
2 //:
3 // \file
4 // \author Philip C. Pritchett, RRG, University of Oxford
5 // \date   24 Mar 1999
6 // \brief  See vgui_soview.h for a description of this file.
7 //
8 // \date Modified 14 Nov 2006, by B. McCane. Set AWF_USE_MAP to 1 so the
9 // map is used by default and added a destructor that removes the id
10 // from the map and therefore prevents a memory leak.
11 
12 #include <iostream>
13 #include <map>
14 #include "vgui_soview.h"
15 
16 #ifdef _MSC_VER
17 #  include "vcl_msvc_warnings.h"
18 #endif
19 
20 #include "vgui/vgui_gl.h"
21 #include "vgui/vgui_observer.h"
22 #include "vgui/vgui_style.h"
23 
24 #define VGUI_STATIC_OBJECT(T, var)                                                                                     \
25   static T & var()                                                                                                     \
26   {                                                                                                                    \
27     static T * t = 0;                                                                                                  \
28     if (t == 0)                                                                                                        \
29       t = new T();                                                                                                     \
30     return *t;                                                                                                         \
31   }
32 
33 #define AWF_USE_MAP 1
34 
35 unsigned vgui_soview::current_id = 1;
36 
37 #if AWF_USE_MAP
38 typedef std::map<unsigned, void *, std::less<unsigned>> Map_soview;
39 VGUI_STATIC_OBJECT(Map_soview, object_map);
40 #else
41 typedef std::vector<void *> Map_soview;
42 VGUI_STATIC_OBJECT(Map_soview, object_map);
43 #endif
44 
45 //: Destructor - delete this soview.
46 // Modified to erase the id from the map - otherwise we get a memory leak
~vgui_soview()47 vgui_soview::~vgui_soview()
48 {
49 #if AWF_USE_MAP
50   object_map().erase(id);
51 #endif
52 }
53 
54 unsigned
create_id()55 vgui_soview::create_id()
56 {
57   unsigned nid = current_id;
58   current_id++;
59   return nid;
60 }
61 
62 void
add_id()63 vgui_soview::add_id()
64 {
65   id = create_id();
66 #if AWF_USE_MAP
67   object_map().insert(Map_soview::value_type(id, this));
68 #else
69   object_map().resize(id * 2);
70   object_map()[id] = this;
71 #endif
72 }
73 
74 vgui_soview *
id_to_object(unsigned id)75 vgui_soview::id_to_object(unsigned id)
76 {
77 #if AWF_USE_MAP
78   Map_soview::iterator i = object_map().find(id);
79   if (i != object_map().end())
80   {
81     return static_cast<vgui_soview *>((*i).second);
82   }
83 #else
84   if (id < object_map().size())
85   {
86     return static_cast<vgui_soview *>(object_map()[id]);
87   }
88 #endif
89 
90   return nullptr;
91 }
92 
93 
94 std::ostream &
print(std::ostream & s) const95 vgui_soview::print(std::ostream & s) const
96 {
97   return s << "id " << id;
98 }
99 
100 
101 void
draw_select() const102 vgui_soview::draw_select() const
103 {
104   // default is to draw as normal. Complex objects may override
105   // this behaviour.
106   //
107   this->draw();
108 }
109 
110 
111 void
load_name() const112 vgui_soview::load_name() const
113 {
114   glLoadName(id);
115 }
116 
117 
118 void
set_colour(float r,float g,float b)119 vgui_soview::set_colour(float r, float g, float b)
120 {
121   vgui_style_sptr newstyle = vgui_style::new_style();
122 
123   newstyle->rgba[0] = r;
124   newstyle->rgba[1] = g;
125   newstyle->rgba[2] = b;
126 
127   if (style)
128   {
129     newstyle->point_size = style->point_size;
130     newstyle->line_width = style->line_width;
131   }
132 
133   style = newstyle;
134 }
135 
136 void
set_point_size(float s)137 vgui_soview::set_point_size(float s)
138 {
139   vgui_style_sptr newstyle = vgui_style::new_style();
140 
141   newstyle->point_size = s;
142 
143   if (style)
144   {
145     newstyle->rgba[0] = style->rgba[0];
146     newstyle->rgba[1] = style->rgba[1];
147     newstyle->rgba[2] = style->rgba[2];
148     newstyle->line_width = style->line_width;
149   }
150 
151   style = newstyle;
152 }
153 
154 void
set_line_width(float w)155 vgui_soview::set_line_width(float w)
156 {
157   vgui_style_sptr newstyle = vgui_style::new_style();
158 
159   newstyle->line_width = w;
160 
161   if (style)
162   {
163     newstyle->rgba[0] = style->rgba[0];
164     newstyle->rgba[1] = style->rgba[1];
165     newstyle->rgba[2] = style->rgba[2];
166     newstyle->point_size = style->point_size;
167   }
168 
169   style = newstyle;
170 }
171 
172 
173 //
174 const void * const vgui_soview::msg_select = "select";
175 const void * const vgui_soview::msg_deselect = "deselect";
176 const void * const vgui_soview::msg_highlight = "highlight";
177 const void * const vgui_soview::msg_unhighlight = "unhighlight";
178 
179 
180 //--------------------------------------------------------------------------------
181 
182 // Observers. Rather than storing a std::list/std::vector/whatever of observers on each
183 // soview, we maintain a static multimap from soviews to observers. This makes
184 // the soviews smaller and optimizes the common case of soviews with no
185 // observers.
186 // fsm: I have not tested this code yet -- where is it used?
187 
188 // vc++ static data members have some peculiarities, so
189 // we use this traditional work-around instead :
190 typedef std::multimap<void *, void *, std::less<void *>> mmap_Pv_Pv;
191 static mmap_Pv_Pv &
the_map()192 the_map()
193 {
194   static mmap_Pv_Pv * ptr = nullptr;
195   if (!ptr)
196     ptr = new mmap_Pv_Pv;
197   return *ptr;
198 }
199 
200 void
attach(vgui_observer * o)201 vgui_soview::attach(vgui_observer * o)
202 {
203   the_map().insert(mmap_Pv_Pv::value_type(this, o));
204 }
205 
206 void
detach(vgui_observer * o)207 vgui_soview::detach(vgui_observer * o)
208 {
209   mmap_Pv_Pv::iterator lo = the_map().lower_bound(this);
210   mmap_Pv_Pv::iterator hi = the_map().upper_bound(this);
211   for (mmap_Pv_Pv::iterator i = lo; i != hi; ++i)
212     if ((*i).second == o)
213     {
214       the_map().erase(i);
215       return;
216     }
217 
218   // not found :
219   std::cerr << __FILE__ " : no such observer on this soview\n";
220 }
221 
222 void
get_observers(std::vector<vgui_observer * > & vobs) const223 vgui_soview::get_observers(std::vector<vgui_observer *> & vobs) const
224 {
225   mmap_Pv_Pv::const_iterator lo = the_map().lower_bound(const_cast<vgui_soview *>(this));
226   mmap_Pv_Pv::const_iterator hi = the_map().upper_bound(const_cast<vgui_soview *>(this));
227   for (mmap_Pv_Pv::const_iterator i = lo; i != hi; ++i)
228     vobs.push_back(static_cast<vgui_observer *>((*i).second));
229 }
230 
231 // These two method could be optimized a bit.
232 void
notify() const233 vgui_soview::notify() const
234 {
235   std::vector<vgui_observer *> vobs;
236   get_observers(vobs);
237   for (unsigned i = 0; i < vobs.size(); ++i)
238     vobs[i]->update();
239 }
240 
241 void
notify(vgui_message const & msg) const242 vgui_soview::notify(vgui_message const & msg) const
243 {
244   std::vector<vgui_observer *> vobs;
245   get_observers(vobs);
246   for (unsigned i = 0; i < vobs.size(); ++i)
247     vobs[i]->update(msg);
248 }
249