00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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
00288
00289
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