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