core/vgui/vgui_listmanager2D_tableau.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_listmanager2D_tableau.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   21 Oct 1999
00009 // \brief  See vgui_listmanager2D_tableau.h for a description of this file.
00010 
00011 #include "vgui_listmanager2D_tableau.h"
00012 
00013 #include <vcl_iostream.h>
00014 #include <vcl_vector.h>
00015 #include <vcl_algorithm.h>
00016 
00017 #include <vgui/vgui_gl.h>
00018 #include <vgui/vgui_parent_child_link.h>
00019 #include <vgui/vgui_event.h>
00020 #include <vgui/vgui_matrix_state.h>
00021 #include <vgui/vgui_projection_inspector.h>
00022 #include <vgui/vgui_utils.h>
00023 #include <vgui/vgui_soview.h>
00024 #include <vgui/vgui_soview2D.h>
00025 #include <vgui/vgui_displaylist2D_tableau.h>
00026 #include <vgui/vgui_style.h>
00027 
00028 
00029 vgui_listmanager2D_tableau::vgui_listmanager2D_tableau():
00030 #if 0
00031   highlight_list(0),
00032 #endif // 0
00033   highlight_so(0)
00034 {
00035 }
00036 
00037 vgui_listmanager2D_tableau::~vgui_listmanager2D_tableau()
00038 {
00039 }
00040 
00041 vcl_string vgui_listmanager2D_tableau::type_name() const
00042 {
00043   return "vgui_listmanager2D_tableau";
00044 }
00045 
00046 //: Add a child to the end of the vcl_list
00047 void vgui_listmanager2D_tableau::add(vgui_displaylist2D_tableau_sptr const& dl)
00048 {
00049   children.push_back( vgui_parent_child_link(this,dl) );
00050   active.push_back(true);
00051   visible.push_back(true);
00052   observers.notify();
00053 }
00054 
00055 //: Remove the given child from the vcl_list.
00056 void vgui_listmanager2D_tableau::remove(vgui_displaylist2D_tableau_sptr const& t)
00057 {
00058   vcl_vector<bool>::iterator ia = active.begin();
00059   vcl_vector<bool>::iterator iv = visible.begin();
00060   for (vcl_vector<vgui_parent_child_link>::iterator i=children.begin() ; i!=children.end() ; ++i, ++ia, ++iv)
00061     if ( *i == t )
00062     {
00063       children.erase(i);
00064       active.erase(ia);
00065       visible.erase(iv);
00066       observers.notify();
00067       return;
00068     }
00069 }
00070 
00071 void vgui_listmanager2D_tableau::set_active(int v, bool b)
00072 {
00073   if (!index_ok(v)) return;
00074   active[v] = b;
00075 }
00076 
00077 bool vgui_listmanager2D_tableau::is_active(int v)
00078 {
00079   if (!index_ok(v)) return false;
00080   return active[v];
00081 }
00082 
00083 void vgui_listmanager2D_tableau::set_visible(int v, bool b)
00084 {
00085   if (!index_ok(v)) return;
00086   visible[v] = b;
00087 }
00088 
00089 bool vgui_listmanager2D_tableau::is_visible(int v)
00090 {
00091   if (!index_ok(v)) return false;
00092   return visible[v];
00093 }
00094 
00095 bool vgui_listmanager2D_tableau::index_ok(int v)
00096 {
00097   return v >= 0 && v < int(children.size());
00098 }
00099 
00100 bool vgui_listmanager2D_tableau::help()
00101 {
00102   vcl_cerr << '\n'
00103            << "+- vgui_listmanager2D_tableau keys -+\n"
00104            << "|                                   |\n"
00105            << "| `1' to `9'  toggle child `n'      |\n"
00106            << "+-----------------------------------+\n\n";
00107   return false;
00108 }
00109 
00110 vgui_displaylist2D_tableau_sptr vgui_listmanager2D_tableau::contains_hit(vcl_vector<unsigned> const& names)
00111 {
00112   for (vcl_vector<vgui_parent_child_link>::iterator i=this->children.begin() ;
00113        i!=this->children.end() ; ++i)
00114   {
00115     // get id of vcl_list
00116     vgui_displaylist2D_tableau_sptr list;
00117     list.vgui_tableau_sptr::operator=(i->child());
00118     unsigned list_id = list->get_id();
00119 
00120     vcl_vector<unsigned>::const_iterator ni = vcl_find(names.begin(), names.end(), list_id);
00121     if (ni != names.end())
00122       return list;
00123   }
00124 
00125   return vgui_displaylist2D_tableau_sptr();
00126 }
00127 
00128 void vgui_listmanager2D_tableau::get_hits(float x, float y, vcl_vector<vcl_vector<unsigned> >* hits)
00129 {
00130   GLuint *ptr = vgui_utils::enter_pick_mode(x,y,100);
00131 
00132   int count=0;
00133   for (vcl_vector<vgui_parent_child_link>::iterator i=this->children.begin() ;
00134        i!=this->children.end() ; ++i, ++count)
00135   {
00136     vgui_displaylist2D_tableau_sptr display;
00137     display.vgui_tableau_sptr::operator=(i->child());
00138 
00139     if (this->active[count] && this->visible[count])
00140     {
00141       display->gl_mode = GL_SELECT;
00142       display->handle(vgui_event(vgui_DRAW));
00143       display->gl_mode = GL_RENDER;
00144     }
00145   }
00146 
00147   int num_hits = vgui_utils::leave_pick_mode();
00148 
00149   // get hits
00150   vgui_utils::process_hits(num_hits, ptr, *hits);
00151 }
00152 
00153 void vgui_listmanager2D_tableau::find_closest(float x, float y, vcl_vector<vcl_vector<unsigned> >* hits,
00154                                               vgui_soview2D** closest_so, vgui_displaylist2D_tableau_sptr* closest_display)
00155 {
00156   float closest_dist = -1; // vnl_numeric_traits<float>::maxval;
00157   vcl_vector<unsigned> closest_hit;
00158   vgui_displaylist2D_tableau_sptr display;
00159   closest_display = 0;
00160   closest_so = 0;
00161 
00162 #ifdef DEBUG
00163   vcl_cerr << "vgui_listmanager2D_tableau::find_closest: hits->size() = " << hits->size() << '\n';
00164 #endif
00165   for (vcl_vector<vcl_vector<unsigned> >::iterator h_iter = hits->begin();
00166        h_iter != hits->end(); ++h_iter)
00167   {
00168     vcl_vector<unsigned> names = *h_iter;
00169 #ifdef DEBUG
00170     vcl_cerr << "vgui_listmanager2D_tableau::find_closest: names.size() " << names.size() << '\n';
00171 #endif
00172 
00173     // first see if this hit is in a displaylist managed by this listmanager2D
00174     display = contains_hit(names);
00175     if (display)
00176     {
00177 #ifdef DEBUG
00178       vcl_cerr << "vgui_listmanager2D_tableau::find_closest: hit in display " << display->get_id() << '\n';
00179 #endif
00180       vgui_soview2D *so = static_cast<vgui_soview2D*>(display->contains_hit(names));
00181       if (so)
00182       {
00183         float dist = so->distance_squared(x,y);
00184         if (closest_dist<0 || dist<closest_dist)
00185         {
00186           closest_dist = dist;
00187           *closest_display = display;
00188           closest_hit = *h_iter;
00189         }
00190       }
00191     }// end if vcl_list valid
00192   }// end for hits
00193 
00194   if (*closest_display)
00195   {
00196     // get the soview out of the closest_hit name vcl_list
00197     *closest_so = static_cast<vgui_soview2D*>((*closest_display)->contains_hit(closest_hit));
00198   }
00199 }
00200 
00201 
00202 //: vgui_listmanager2D_tableau events are send to the child displaylist which holds the closest soview2d.
00203 bool vgui_listmanager2D_tableau::handle(const vgui_event& event)
00204 {
00205   // save current matrix state :
00206   vgui_matrix_state PM;
00207 
00208   // "draw" events
00209   if (event.type==vgui_DRAW || event.type==vgui_DRAW_OVERLAY)
00210   {
00211     bool retv = true;
00212 
00213     int ia = 0;
00214     for ( vcl_vector<vgui_parent_child_link>::iterator i = children.begin(); i != children.end(); ++i, ++ia)
00215     {
00216       PM.restore();
00217 
00218       if (visible[ia])
00219         if ( !(*i)->handle(event) )
00220           retv=false;
00221     }
00222     return retv;
00223   }
00224 
00225   // "normal" events -- pass them to the drag_mixin, but
00226   // remember this one in order that it can be passed on.
00227   this->saved_event_ = event;
00228   return vgui_tableau::handle(event);
00229 }
00230 
00231 bool vgui_listmanager2D_tableau::motion(int x, int y)
00232 {
00233   vgui_projection_inspector pi;
00234   float ix, iy;
00235   pi.window_to_image_coordinates(int(x),int(y), ix,iy);
00236 
00237   vcl_vector<vcl_vector<unsigned> > hits;
00238   get_hits(x,y,&hits);
00239 
00240   vgui_soview2D* closest_so;
00241   vgui_displaylist2D_tableau_sptr closest_display;
00242   find_closest(ix, iy, &hits, &closest_so, &closest_display);
00243 
00244 #ifdef DEBUG
00245   if (closest_so && closest_display)
00246     vcl_cerr << "vgui_listmanager2D_tableau::motion: hit " << closest_so->get_id()
00247              << " in vcl_list " << closest_display->get_id() << vcl_endl;
00248 #endif
00249 
00250   vgui_utils::begin_sw_overlay();
00251 
00252   if (highlight_so)
00253   {
00254     vgui_soview* so = highlight_so;
00255     vgui_style_sptr style = so->get_style();
00256     style->apply_point_size();
00257     style->apply_line_width();
00258 
00259     if (highlight_list->is_selected(so->get_id()))
00260       glColor3f(1.0f, 0.0f, 0.0f);
00261     else
00262     {
00263       style->apply_color();
00264     }
00265     so->draw();
00266   }
00267 
00268   if (closest_so)
00269   {
00270 #ifdef DEBUG
00271     vcl_cerr << "vgui_listmanager2D_tableau::motion highlighting : " << closest_id << '\n';
00272 #endif
00273     vgui_soview* so = closest_so;
00274     vgui_style_sptr style = so->get_style();
00275     style->apply_point_size();
00276     style->apply_line_width();
00277     glColor3f(0.0f,1.0f,1.0f);
00278     so->draw();
00279   }
00280 
00281   vgui_utils::end_sw_overlay();
00282 
00283   highlight_list = closest_display;
00284   highlight_so = closest_so;
00285 
00286   return true;
00287 }
00288 
00289 
00290 bool vgui_listmanager2D_tableau::mouse_down(int x, int y, vgui_button button, vgui_modifier modifier)
00291 {
00292   if (button == vgui_MIDDLE && (modifier & vgui_SHIFT))
00293   {
00294     int count=0;
00295     for (vcl_vector<vgui_parent_child_link>::iterator i=this->children.begin() ;
00296          i!=this->children.end() ; ++i, ++count)
00297     {
00298       vgui_displaylist2D_tableau_sptr display;
00299       display.vgui_tableau_sptr::operator=(i->child());
00300       if (this->active[count] && this->visible[count])
00301         display->handle(this->saved_event_);
00302     }
00303     return true;
00304   }
00305 
00306   // send the event only to the displaylist that contains the closest soview
00307   vgui_projection_inspector pi;
00308   float ix, iy;
00309   pi.window_to_image_coordinates(int(x),int(y), ix,iy);
00310 
00311   vcl_vector<vcl_vector<unsigned> > hits;
00312   get_hits(x,y,&hits);
00313 
00314   vgui_soview2D* closest_so;
00315   vgui_displaylist2D_tableau_sptr closest_display;
00316   find_closest(ix, iy, &hits, &closest_so, &closest_display);
00317 
00318   return closest_display && closest_display->handle(this->saved_event_);
00319 }
00320 
00321 bool vgui_listmanager2D_tableau::key_press(int /*x*/, int /*y*/, vgui_key key, vgui_modifier)
00322 {
00323 #ifdef DEBUG
00324   vcl_cerr << "vgui_listmanager2D_tableau_handler::key_press " << key << '\n';
00325 #endif
00326 
00327   if (key >= '1' && key <= '9')
00328   {
00329     char text[1];
00330     text[0] = key;
00331     int num = atoi(text);
00332 
00333     bool isactive = this->is_active(num-1);
00334     bool isvisible = this->is_visible(num-1);
00335 
00336     if (isactive)
00337     {
00338       this->set_active(num-1, false);
00339       this->set_visible(num-1, false);
00340       vgui_displaylist2D_tableau_sptr list;
00341       list.vgui_tableau_sptr::operator=(this->children[num-1].child());
00342       if (highlight_list == list)
00343       {
00344         highlight_list = vgui_displaylist2D_tableau_sptr();
00345         highlight_so = 0;
00346       }
00347     }
00348     else if (isvisible)
00349     {
00350       this->set_active(num-1, true);
00351       this->set_visible(num-1, true);
00352     }
00353     else
00354     {
00355       this->set_active(num-1, false);
00356       this->set_visible(num-1, true);
00357 
00358       vgui_displaylist2D_tableau_sptr list;
00359       list.vgui_tableau_sptr::operator=(this->children[num-1].child());
00360       if (highlight_list == list)
00361       {
00362         highlight_list = vgui_displaylist2D_tableau_sptr();
00363         highlight_so = 0;
00364       }
00365     }
00366 
00367     this->post_redraw();
00368     return true;
00369   }
00370   return false;
00371 }