gxseparator.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2000-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Thu Nov  2 11:24:04 2000
00010 // commit: $Id: gxseparator.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/gfx/gxseparator.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_GFX_GXSEPARATOR_CC_UTC20050626084024_DEFINED
00035 #define GROOVX_GFX_GXSEPARATOR_CC_UTC20050626084024_DEFINED
00036 
00037 #include "gxseparator.h"
00038 
00039 #include "geom/box.h"
00040 #include "geom/rect.h"
00041 
00042 #include "gfx/bbox.h"
00043 #include "gfx/canvas.h"
00044 
00045 #include "io/readutils.h"
00046 #include "io/writeutils.h"
00047 
00048 #include "nub/ref.h"
00049 #include "nub/volatileobject.h"
00050 
00051 #include "rutz/error.h"
00052 #include "rutz/iter.h"
00053 #include "rutz/sfmt.h"
00054 
00055 #include <list>
00056 #include <vector>
00057 
00058 #include "rutz/trace.h"
00059 
00060 using rutz::shared_ptr;
00061 
00062 class GxSeparator::Impl : public nub::volatile_object
00063 {
00064   Impl(const Impl&);
00065   Impl& operator=(const Impl&);
00066 
00067 public:
00068   Impl(GxSeparator* p) :
00069     owner(p),
00070     children(),
00071     debugMode(false)
00072   {}
00073 
00074   virtual ~Impl() throw() {}
00075 
00076   static Impl* make(GxSeparator* owner) { return new Impl(owner); }
00077 
00078   bool contains(GxNode* other) const
00079     {
00080       if (owner == other) return true;
00081 
00082       for(VecType::const_iterator
00083             itr = children.begin(),
00084             end = children.end();
00085           itr != end;
00086           ++itr)
00087         {
00088           if ((*itr)->contains(other)) return true;
00089         }
00090 
00091       return false;
00092     }
00093 
00094   void ensureNoCycle(GxNode* other) const
00095     {
00096       if (other->contains(owner))
00097         {
00098           throw rutz::error("couldn't add node without generating a cycle", SRC_POS);
00099         }
00100     }
00101 
00102   GxSeparator* owner;
00103 
00104   typedef std::vector<nub::ref<GxNode> > VecType;
00105   VecType children;
00106 
00107   bool debugMode;
00108 };
00109 
00110 GxSeparator* GxSeparator::make()
00111 {
00112 GVX_TRACE("GxSeparator::make");
00113   return new GxSeparator;
00114 }
00115 
00116 GxSeparator::GxSeparator() :
00117   rep(Impl::make(this))
00118 {
00119 GVX_TRACE("GxSeparator::GxSeparator");
00120 }
00121 
00122 GxSeparator::~GxSeparator() throw()
00123 {
00124 GVX_TRACE("GxSeparator::~GxSeparator");
00125   rep->destroy();
00126 }
00127 
00128 void GxSeparator::read_from(io::reader& reader)
00129 {
00130 GVX_TRACE("GxSeparator::read_from");
00131 
00132   for(unsigned int i = 0; i < rep->children.size(); ++i)
00133     {
00134       rep->children[i]->sigNodeChanged
00135         .disconnect(this->sigNodeChanged.slot());
00136     }
00137 
00138   rep->children.clear();
00139   io::read_utils::read_object_seq<GxNode>(
00140           reader, "children", std::back_inserter(rep->children));
00141 
00142   for(unsigned int i = 0; i < rep->children.size(); ++i)
00143     {
00144       rep->children[i]->sigNodeChanged
00145         .connect(this->sigNodeChanged.slot());
00146     }
00147 
00148   this->sigNodeChanged.emit();
00149 }
00150 
00151 void GxSeparator::write_to(io::writer& writer) const
00152 {
00153 GVX_TRACE("GxSeparator::write_to");
00154   io::write_utils::write_object_seq(writer, "children",
00155                                     rep->children.begin(),
00156                                     rep->children.end());
00157 }
00158 
00159 GxSeparator::ChildId GxSeparator::addChild(nub::ref<GxNode> item)
00160 {
00161 GVX_TRACE("GxSeparator::addChild");
00162 
00163   rep->ensureNoCycle(item.get());
00164 
00165   rep->children.push_back(item);
00166 
00167   item->sigNodeChanged.connect(this->sigNodeChanged.slot());
00168 
00169   this->sigNodeChanged.emit();
00170 
00171   return (rep->children.size() - 1);
00172 }
00173 
00174 void GxSeparator::insertChild(nub::ref<GxNode> item, ChildId at_index)
00175 {
00176 GVX_TRACE("GxSeparator::insertChild");
00177 
00178   rep->ensureNoCycle(item.get());
00179 
00180   if (at_index > rep->children.size())
00181     at_index = rep->children.size();
00182 
00183   rep->children.insert(rep->children.begin()+at_index, item);
00184 
00185   item->sigNodeChanged.connect(this->sigNodeChanged.slot());
00186 
00187   this->sigNodeChanged.emit();
00188 }
00189 
00190 void GxSeparator::removeChildAt(ChildId index)
00191 {
00192 GVX_TRACE("GxSeparator::removeChildAt");
00193   if (index < rep->children.size())
00194     {
00195       rep->children[index]->sigNodeChanged
00196         .disconnect(this->sigNodeChanged.slot());
00197       rep->children.erase(rep->children.begin()+index);
00198 
00199       this->sigNodeChanged.emit();
00200     }
00201 }
00202 
00203 void GxSeparator::removeChild(nub::ref<GxNode> item)
00204 {
00205 GVX_TRACE("GxSeparator::removeChild");
00206 
00207   const nub::uid target = item.id();
00208 
00209   for(Impl::VecType::iterator
00210         itr = rep->children.begin(),
00211         end = rep->children.end();
00212       itr != end;
00213       ++itr)
00214     {
00215       if ( (*itr)->id() == target )
00216         {
00217           (*itr)->sigNodeChanged.disconnect(this->sigNodeChanged.slot());
00218           rep->children.erase(itr);
00219           this->sigNodeChanged.emit();
00220           break;
00221         }
00222     }
00223 }
00224 
00225 unsigned int GxSeparator::numChildren() const
00226 {
00227 GVX_TRACE("GxSeparator::numChildren");
00228   return rep->children.size();
00229 }
00230 
00231 nub::ref<GxNode> GxSeparator::getChild(ChildId index) const
00232 {
00233 GVX_TRACE("GxSeparator::getChild");
00234   if (index >= rep->children.size())
00235     {
00236       throw rutz::error(rutz::sfmt("GxSeparator has no child with "
00237                                    "index '%u'", index), SRC_POS);
00238     }
00239 
00240   return rep->children[index];
00241 }
00242 
00243 rutz::fwd_iter<nub::ref<GxNode> > GxSeparator::children() const
00244 {
00245 GVX_TRACE("GxSeparator::children");
00246 
00247   return rutz::fwd_iter<nub::ref<GxNode> >(rep->children.begin(),
00248                                            rep->children.end());
00249 }
00250 
00251 class GxSepIter : public rutz::fwd_iter_ifx<const nub::ref<GxNode> >
00252 {
00253 public:
00254   GxSepIter(GxSeparator* root) :
00255     itsNodes()
00256   {
00257     for (rutz::fwd_iter<nub::ref<GxNode> > itr(root->children());
00258          itr.is_valid();
00259          ++itr)
00260       {
00261         addDeepChildren(*itr);
00262       }
00263   }
00264 
00265   void addDeepChildren(nub::ref<GxNode> node)
00266   {
00267     for (rutz::fwd_iter<const nub::ref<GxNode> > itr(node->deepChildren());
00268          itr.is_valid();
00269          ++itr)
00270       {
00271         itsNodes.push_back(*itr);
00272       }
00273   }
00274 
00275   typedef const nub::ref<GxNode> ValType;
00276 
00277   virtual rutz::fwd_iter_ifx<ValType>* clone() const
00278   {
00279     return new GxSepIter(*this);
00280   }
00281 
00282   virtual bool     at_end() const { return itsNodes.empty(); }
00283   virtual ValType&   get()  const { return itsNodes.front(); }
00284   virtual void      next()        { if (!at_end()) itsNodes.pop_front(); }
00285 
00286 private:
00287   // Want to use a list instead of a vector-type container here since
00288   // we need both push_back() and pop_front(). Could potentially use a
00289   // deque instead.
00290   mutable std::list<nub::ref<GxNode> > itsNodes;
00291 };
00292 
00293 rutz::fwd_iter<const nub::ref<GxNode> > GxSeparator::deepChildren()
00294 {
00295 GVX_TRACE("GxSeparator::deepChildren");
00296 
00297   return rutz::fwd_iter<const nub::ref<GxNode> >
00298     (shared_ptr<GxSepIter>(new GxSepIter(this)));
00299 }
00300 
00301 bool GxSeparator::contains(GxNode* other) const
00302 {
00303 GVX_TRACE("GxSeparator::contains");
00304   return rep->contains(other);
00305 }
00306 
00307 void GxSeparator::getBoundingCube(Gfx::Bbox& bbox) const
00308 {
00309 GVX_TRACE("GxSeparator::getBoundingCube");
00310 
00311   if (!rep->children.empty())
00312     {
00313       bbox.push();
00314 
00315       for(Impl::VecType::iterator
00316             itr = rep->children.begin(),
00317             end = rep->children.end();
00318           itr != end;
00319           ++itr)
00320         {
00321           (*itr)->getBoundingCube(bbox);
00322         }
00323 
00324       bbox.pop();
00325     }
00326 }
00327 
00328 bool GxSeparator::getDebugMode() const
00329 {
00330 GVX_TRACE("GxSeparator::getDebugMode");
00331 
00332   return rep->debugMode;
00333 }
00334 
00335 void GxSeparator::setDebugMode(bool b)
00336 {
00337 GVX_TRACE("GxSeparator::setDebugMode");
00338 
00339   if (rep->debugMode != b)
00340     {
00341       rep->debugMode = b;
00342       this->sigNodeChanged.emit();
00343     }
00344 }
00345 
00346 void GxSeparator::draw(Gfx::Canvas& canvas) const
00347 {
00348 GVX_TRACE("GxSeparator::draw");
00349 
00350   if (rep->debugMode)
00351     {
00352       Gfx::Bbox bbox(canvas);
00353       getBoundingCube(bbox);
00354       canvas.drawBox(bbox.cube());
00355     }
00356 
00357   if (!rep->children.empty())
00358     {
00359       Gfx::MatrixSaver state(canvas);
00360       Gfx::AttribSaver attribs(canvas);
00361 
00362       for(Impl::VecType::iterator
00363             itr = rep->children.begin(),
00364             end = rep->children.end();
00365           itr != end;
00366           ++itr)
00367         {
00368           (*itr)->draw(canvas);
00369         }
00370     }
00371 }
00372 
00373 static const char __attribute__((used)) vcid_groovx_gfx_gxseparator_cc_utc20050626084024[] = "$Id: gxseparator.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00374 #endif // !GROOVX_GFX_GXSEPARATOR_CC_UTC20050626084024_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:38 2008 by Doxygen version 1.5.5.