/* KLayout Layout Viewer Copyright (C) 2006-2016 Matthias Koefferlein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef HDR_layAnnotationShapes #define HDR_layAnnotationShapes #include "laybasicCommon.h" #include "dbUserObject.h" #include "dbObject.h" #include "dbLayer.h" #include "dbLayoutStateModel.h" #include namespace lay { class AnnotationShapes; /** * @brief A undo/redo queue object for the layer * * This class is used internally to queue an insert or erase operation * into the db::Object manager's undo/redo queue. */ class LAYBASIC_PUBLIC AnnotationLayerOp : public db::Op { public: typedef db::DUserObject shape_type; AnnotationLayerOp (bool insert, const shape_type &sh) : m_insert (insert) { m_shapes.push_back (sh); } template AnnotationLayerOp (bool insert, Iter from, Iter to) : m_insert (insert) { m_shapes.insert (m_shapes.end (), from, to); } template AnnotationLayerOp (bool insert, Iter from, Iter to, bool /*dummy*/) : m_insert (insert) { m_shapes.reserve (std::distance (from, to)); for (Iter i = from; i != to; ++i) { m_shapes.push_back (**i); } } virtual void undo (AnnotationShapes *shapes) { if (m_insert) { erase (shapes); } else { insert (shapes); } } virtual void redo (AnnotationShapes *shapes) { if (m_insert) { insert (shapes); } else { erase (shapes); } } private: bool m_insert; std::vector m_shapes; void insert (AnnotationShapes *shapes); void erase (AnnotationShapes *shapes); }; /** * @brief A collection of DUserObject objects that serves as a container for annotation shapes */ class LAYBASIC_PUBLIC AnnotationShapes : public db::LayoutStateModel, public db::Object { public: typedef db::DCoord coord_type; typedef db::box box_type; typedef db::DUserObject shape_type; typedef db::layer layer_type; typedef layer_type::overlapping_iterator overlapping_iterator; typedef layer_type::touching_iterator touching_iterator; typedef layer_type::iterator iterator; /** * @brief Standard ctor: create an empty collection referencing a graph * * The graph reference is used to invalid the bbox flag of the graph * whenever something changes on the shapes list. */ AnnotationShapes (db::Manager *manager = 0); /** * @brief Dtor: clear all .. */ ~AnnotationShapes (); /** * @brief Copy ctor */ AnnotationShapes (const AnnotationShapes &d); /** * @brief Assignment operator */ AnnotationShapes &operator= (const AnnotationShapes &d); /** * @brief Insert a shape_type */ const shape_type &insert (const shape_type &sh); /** * @brief Insert a sequence of DUserObject shapes * * Inserts a sequence of shapes [from,to) */ template void insert (Iter from, Iter to) { if (manager () && manager ()->transacting ()) { manager ()->queue (this, new AnnotationLayerOp (true /*insert*/, from, to)); } invalidate_state (); m_layer.insert (from, to); } /** * @brief Reserve the number of elements for a shape type * * @param n The number of elements to reserve */ void reserve (size_t n); /** * @brief Erase an element * * Erases a shape at the given position * * @param tag The shape type's tag (i.e. db::Polygon::tag) * @param pos The position of the shape to erase */ void erase (layer_type::iterator pos); /** * @brief Erasing of multiple elements * * Erase a set of positions given by an iterator I: *(from,to). * *I must render an "iterator" object. * The iterators in the sequence from, to must be sorted in * "later" order. * * @param first The start of the sequence of iterators * @param last The end of the sequence of iterators */ template void erase_positions (I first, I last) { if (manager () && manager ()->transacting ()) { manager ()->queue (this, new AnnotationLayerOp (false /*not insert*/, first, last, true /*dummy*/)); } invalidate_state (); // HINT: must come before the change is done! m_layer.erase_positions (first, last); } /** * @brief Replace an element at the given position with another shape * * Replaces the element at the position pos with the * new element. * * @param pos The position at which to replace the shape * @param sh The shape to replace * * @return A reference to the object created */ const shape_type &replace (iterator pos, const shape_type &sh); /** * @brief updates the bbox * * Updating the bbox is required after insert operations * and is performed only as far as necessary. */ void update_bbox () { m_layer.update_bbox (); } /** * @brief check if the bounding box needs update * * Returns true if the bounding box of the shapes has changed and * requires an update. */ bool is_bbox_dirty () const { return m_layer.is_bbox_dirty (); } /** * @brief Retrieve the bbox * * Retrieving the bbox might required an update_bbox * before the bbox is valid. It will assert if the bbox * was not valid. * Doing a update_bbox before does not imply a performance penalty * since the state is cached. */ box_type bbox () const { return m_layer.bbox (); } /** * @brief Clears the collection */ void clear (); /** * @brief Do a region search in "touching" mode * * @return The region iterator */ layer_type::touching_iterator begin_touching (const box_type &b) const { const_cast (m_layer).sort (); // ensure the box tree is made return m_layer.begin_touching (b); } /** * @brief The region iterator end token */ size_t end_touching () const { return 0; // KLUDGE: some shortcut but basically an implementation detail .. } /** * @brief Do a region search in "overlapping" mode * * @return The region iterator */ layer_type::overlapping_iterator begin_overlapping (const box_type &b) const { const_cast (m_layer).sort (); // ensure the box tree is made return m_layer.begin_overlapping (b); } /** * @brief The region iterator end token */ size_t end_overlapping () const { return 0; // KLUDGE: some shortcut but basically an implementation detail .. } /** * @brief begin iterator of all elements * * @return The first position of the shapes */ layer_type::iterator begin () const { return m_layer.begin (); } /** * @brief end iterator of all elements * * @return The post-end position of the shapes */ layer_type::iterator end () const { return m_layer.end (); } /** * @brief find a given shape (exactly) * * @param s The shape to find * * @return end(Sh::tag) if the shape was not found, the position otherwise */ layer_type::iterator find (const shape_type &s) const { return m_layer.find (s); } /** * @brief get the iterator from a pointer * * @param p The pointer to the element to retrieve * @return The iterator pointing to that element */ layer_type::iterator iterator_from_pointer (const shape_type *p) const { return m_layer.iterator_from_pointer (p); } /** * @brief Implementation of the redo method */ void redo (db::Op *op); /** * @brief Implementation of the undo method */ void undo (db::Op *op); /** * @brief Collect memory usage */ void collect_mem_stat (db::MemStatistics &m) const; private: void invalidate_state () { invalidate_bboxes (); } virtual void do_update (); layer_type m_layer; }; } #endif