core/vgui/vgui_soview.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_soview.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Philip C. Pritchett, RRG, University of Oxford
00008 // \date   24 Mar 1999
00009 // \brief  See vgui_soview.h for a description of this file.
00010 //
00011 // \date Modified 14 Nov 2006, by B. McCane. Set AWF_USE_MAP to 1 so the
00012 // map is used by default and added a destructor that removes the id
00013 // from the map and therefore prevents a memory leak.
00014 
00015 #include "vgui_soview.h"
00016 
00017 #include <vcl_iostream.h>
00018 #include <vcl_map.h>
00019 
00020 #include <vgui/vgui_gl.h>
00021 #include <vgui/vgui_observer.h>
00022 #include <vgui/vgui_style.h>
00023 
00024 #define VGUI_STATIC_OBJECT(T, var) \
00025 static T& var () { \
00026   static T * t = 0; \
00027   if (t == 0) t = new T(); \
00028   return *t; \
00029 }
00030 
00031 #define AWF_USE_MAP 1
00032 
00033 unsigned vgui_soview::current_id = 1;
00034 
00035 #if AWF_USE_MAP
00036 typedef vcl_map<unsigned, void*, vcl_less<unsigned> > Map_soview;
00037 VGUI_STATIC_OBJECT(Map_soview, object_map);
00038 #else
00039 typedef vcl_vector<void* > Map_soview;
00040 VGUI_STATIC_OBJECT(Map_soview, object_map);
00041 #endif
00042 
00043 //: Destructor - delete this soview.
00044 // Modified to erase the id from the map - otherwise we get a memory leak
00045 vgui_soview::~vgui_soview()
00046 {
00047 #if AWF_USE_MAP
00048     object_map().erase(id);
00049 #endif
00050 }
00051 
00052 unsigned vgui_soview::create_id()
00053 {
00054   unsigned nid = current_id;
00055   current_id++;
00056   return nid;
00057 }
00058 
00059 void vgui_soview::add_id()
00060 {
00061   id = create_id();
00062 #if AWF_USE_MAP
00063   object_map().insert(Map_soview::value_type(id, this));
00064 #else
00065   object_map().resize(id * 2);
00066   object_map()[id] = this;
00067 #endif
00068 }
00069 
00070 vgui_soview* vgui_soview::id_to_object(unsigned id)
00071 {
00072 #if AWF_USE_MAP
00073   Map_soview::iterator i = object_map().find(id);
00074   if (i != object_map().end()) {
00075     return static_cast<vgui_soview*>((*i).second);
00076   }
00077 #else
00078   if (id < object_map().size()) {
00079     return static_cast<vgui_soview*>(object_map()[id]);
00080   }
00081 #endif
00082 
00083   return 0;
00084 }
00085 
00086 
00087 vcl_ostream& vgui_soview::print(vcl_ostream& s) const
00088 {
00089   return s << "id " << id;
00090 }
00091 
00092 
00093 void vgui_soview::draw_select() const
00094 {
00095   // default is to draw as normal. Complex objects may override
00096   // this behaviour.
00097   //
00098   this->draw();
00099 }
00100 
00101 
00102 void vgui_soview::load_name() const
00103 {
00104   glLoadName(id);
00105 }
00106 
00107 
00108 void vgui_soview::set_colour(float r, float g, float b)
00109 {
00110   vgui_style_sptr newstyle = vgui_style::new_style();
00111 
00112   newstyle->rgba[0] = r;
00113   newstyle->rgba[1] = g;
00114   newstyle->rgba[2] = b;
00115 
00116   if (style) {
00117     newstyle->point_size = style->point_size;
00118     newstyle->line_width = style->line_width;
00119   }
00120 
00121   style = newstyle;
00122 }
00123 
00124 void vgui_soview::set_point_size(float s)
00125 {
00126   vgui_style_sptr newstyle = vgui_style::new_style();
00127 
00128   newstyle->point_size = s;
00129 
00130   if (style) {
00131     newstyle->rgba[0] = style->rgba[0];
00132     newstyle->rgba[1] = style->rgba[1];
00133     newstyle->rgba[2] = style->rgba[2];
00134     newstyle->line_width = style->line_width;
00135   }
00136 
00137   style = newstyle;
00138 }
00139 
00140 void vgui_soview::set_line_width(float w)
00141 {
00142   vgui_style_sptr newstyle = vgui_style::new_style();
00143 
00144   newstyle->line_width = w;
00145 
00146   if (style) {
00147     newstyle->rgba[0] = style->rgba[0];
00148     newstyle->rgba[1] = style->rgba[1];
00149     newstyle->rgba[2] = style->rgba[2];
00150     newstyle->point_size = style->point_size;
00151   }
00152 
00153   style = newstyle;
00154 }
00155 
00156 
00157 //
00158 const void * const vgui_soview::msg_select="select";
00159 const void * const vgui_soview::msg_deselect="deselect";
00160 const void * const vgui_soview::msg_highlight="highlight";
00161 const void * const vgui_soview::msg_unhighlight="unhighlight";
00162 
00163 
00164 //--------------------------------------------------------------------------------
00165 
00166 // Observers. Rather than storing a vcl_list/vcl_vector/whatever of observers on each
00167 // soview, we maintain a static multimap from soviews to observers. This makes
00168 // the soviews smaller and optimizes the common case of soviews with no
00169 // observers.
00170 // fsm: I have not tested this code yet -- where is it used?
00171 
00172 // vc++ static data members have some peculiarities, so
00173 // we use this traditional work-around instead :
00174 typedef vcl_multimap<void *, void *, vcl_less<void *> > mmap_Pv_Pv;
00175 static mmap_Pv_Pv &the_map()
00176 {
00177   static mmap_Pv_Pv *ptr = 0;
00178   if (!ptr)
00179     ptr = new mmap_Pv_Pv;
00180   return *ptr;
00181 }
00182 
00183 void vgui_soview::attach(vgui_observer* o)
00184 {
00185   the_map().insert(mmap_Pv_Pv::value_type(this, o));
00186 }
00187 
00188 void vgui_soview::detach(vgui_observer* o)
00189 {
00190   mmap_Pv_Pv::iterator lo = the_map().lower_bound(this);
00191   mmap_Pv_Pv::iterator hi = the_map().upper_bound(this);
00192   for (mmap_Pv_Pv::iterator i=lo; i!=hi; ++i)
00193     if (
00194         (*i).second == o
00195         ) {
00196       the_map().erase(i);
00197       return;
00198     }
00199 
00200   // not found :
00201   vcl_cerr << __FILE__ " : no such observer on this soview\n";
00202 }
00203 
00204 void vgui_soview::get_observers(vcl_vector<vgui_observer*>& vobs) const
00205 {
00206   mmap_Pv_Pv::const_iterator lo = the_map().lower_bound( const_cast<vgui_soview*>(this) );
00207   mmap_Pv_Pv::const_iterator hi = the_map().upper_bound( const_cast<vgui_soview*>(this) );
00208   for (mmap_Pv_Pv::const_iterator i=lo; i!=hi; ++i)
00209     vobs.push_back( static_cast<vgui_observer*>((*i).second) );
00210 }
00211 
00212 // These two method could be optimized a bit.
00213 void vgui_soview::notify() const
00214 {
00215   vcl_vector<vgui_observer*> vobs;
00216   get_observers(vobs);
00217   for (unsigned i=0; i<vobs.size(); ++i)
00218     vobs[i]->update();
00219 }
00220 
00221 void vgui_soview::notify(vgui_message const &msg) const
00222 {
00223   vcl_vector<vgui_observer*> vobs;
00224   get_observers(vobs);
00225   for (unsigned i=0; i<vobs.size(); ++i)
00226     vobs[i]->update(msg);
00227 }