/* KLayout Layout Viewer Copyright (C) 2006-2017 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 */ #include "rdbMarkerBrowserDialog.h" #include "rdb.h" #include "rdbReader.h" #include "tlProgress.h" #include "layLayoutView.h" #include "tlExceptions.h" #include "layFileDialog.h" #include "layConverters.h" #include "layQtTools.h" #include "layConfigurationDialog.h" #include "dbLayoutUtils.h" #include "dbRecursiveShapeIterator.h" #include #include #include namespace rdb { extern std::string cfg_rdb_context_mode; extern std::string cfg_rdb_show_all; extern std::string cfg_rdb_window_state; extern std::string cfg_rdb_window_mode; extern std::string cfg_rdb_window_dim; extern std::string cfg_rdb_max_marker_count; extern std::string cfg_rdb_marker_color; extern std::string cfg_rdb_marker_line_width; extern std::string cfg_rdb_marker_vertex_size; extern std::string cfg_rdb_marker_halo; extern std::string cfg_rdb_marker_dither_pattern; MarkerBrowserDialog::MarkerBrowserDialog (lay::PluginRoot *root, lay::LayoutView *vw) : lay::Browser (root, vw), Ui::MarkerBrowserDialog (), m_context (rdb::AnyCell), m_window (rdb::FitMarker), m_window_dim (0.0), m_max_marker_count (0), m_marker_line_width (-1), m_marker_vertex_size (-1), m_marker_halo (-1), m_marker_dither_pattern (-1), m_cv_index (-1), m_rdb_index (-1) { Ui::MarkerBrowserDialog::setupUi (this); browser_frame->set_plugin_root (root); if (view ()) { view ()->cellviews_changed_event.add (this, &MarkerBrowserDialog::cellviews_changed); view ()->cellview_changed_event.add (this, &MarkerBrowserDialog::cellview_changed); view ()->rdb_list_changed_event.add (this, &MarkerBrowserDialog::rdbs_changed); } m_open_action = new QAction (QObject::tr ("Open"), file_menu); m_saveas_action = new QAction (QObject::tr ("Save As"), file_menu); m_export_action = new QAction (QObject::tr ("Export To Layout"), file_menu); m_reload_action = new QAction (QObject::tr ("Reload"), file_menu); m_unload_action = new QAction (QObject::tr ("Unload"), file_menu); m_unload_all_action = new QAction (QObject::tr ("Unload All"), file_menu); connect (m_open_action, SIGNAL (triggered ()), this, SLOT (open_clicked ())); connect (m_saveas_action, SIGNAL (triggered ()), this, SLOT (saveas_clicked ())); connect (m_export_action, SIGNAL (triggered ()), this, SLOT (export_clicked ())); connect (m_reload_action, SIGNAL (triggered ()), this, SLOT (reload_clicked ())); connect (m_unload_action, SIGNAL (triggered ()), this, SLOT (unload_clicked ())); connect (m_unload_all_action, SIGNAL (triggered ()), this, SLOT (unload_all_clicked ())); file_menu->addAction (m_open_action); file_menu->addAction (m_saveas_action); QAction *sep0 = new QAction (file_menu); sep0->setSeparator (true); file_menu->addAction (m_export_action); QAction *sep1 = new QAction (file_menu); sep1->setSeparator (true); file_menu->addAction (sep1); file_menu->addAction (m_reload_action); QAction *sep2 = new QAction (file_menu); sep2->setSeparator (true); file_menu->addAction (sep2); file_menu->addAction (m_unload_action); file_menu->addAction (m_unload_all_action); connect (layout_cb, SIGNAL (activated (int)), this, SLOT (cv_index_changed (int))); connect (rdb_cb, SIGNAL (activated (int)), this, SLOT (rdb_index_changed (int))); connect (configure_pb, SIGNAL (clicked ()), this, SLOT (configure_clicked ())); cellviews_changed (); } MarkerBrowserDialog::~MarkerBrowserDialog () { tl::Object::detach_from_all_events (); } void MarkerBrowserDialog::configure_clicked () { lay::ConfigurationDialog config_dialog (this, lay::PluginRoot::instance (), "MarkerBrowserPlugin"); config_dialog.exec (); } void MarkerBrowserDialog::unload_all_clicked () { BEGIN_PROTECTED bool modified = false; for (int i = 0; i < int (view ()->num_rdbs ()); ++i) { rdb::Database *rdb = view ()->get_rdb (i); if (rdb && rdb->is_modified ()) { modified = true; break; } } if (modified) { QMessageBox msgbox (QMessageBox::Question, QObject::tr ("Unload Without Saving"), QObject::tr ("At least one database was not saved.\nPress 'Continue' to continue anyway or 'Cancel' for not unloading the database.")); QPushButton *ok = msgbox.addButton (QObject::tr ("Continue"), QMessageBox::AcceptRole); msgbox.setDefaultButton (msgbox.addButton (QMessageBox::Cancel)); msgbox.exec (); if (msgbox.clickedButton () != ok) { return; } } while (view ()->num_rdbs () > 0) { view ()->remove_rdb (0); } rdb_index_changed (-1); END_PROTECTED } void MarkerBrowserDialog::unload_clicked () { BEGIN_PROTECTED if (m_rdb_index < int (view ()->num_rdbs ()) && m_rdb_index >= 0) { rdb::Database *rdb = view ()->get_rdb (m_rdb_index); if (rdb && rdb->is_modified ()) { QMessageBox msgbox (QMessageBox::Question, QObject::tr ("Unload Without Saving"), QObject::tr ("The database was not saved.\nPress 'Continue' to continue anyway or 'Cancel' for not unloading the database.")); QPushButton *ok = msgbox.addButton (QObject::tr ("Continue"), QMessageBox::AcceptRole); msgbox.setDefaultButton (msgbox.addButton (QMessageBox::Cancel)); msgbox.exec (); if (msgbox.clickedButton () != ok) { return; } } int new_rdb_index = m_rdb_index; view ()->remove_rdb (m_rdb_index); // try to use another rbd ... if (new_rdb_index >= int (view ()->num_rdbs ())) { --new_rdb_index; } if (new_rdb_index < int (view ()->num_rdbs ()) && new_rdb_index >= 0) { rdb_index_changed (new_rdb_index); } } END_PROTECTED } static void collect_categories (const Category *cat, std::vector &categories) { if (cat->sub_categories ().begin () == cat->sub_categories ().end ()) { if (cat->num_items () > 0) { categories.push_back (cat); } } else { for (Categories::const_iterator subcat = cat->sub_categories ().begin (); subcat != cat->sub_categories ().end (); ++subcat) { collect_categories (&*subcat, categories); } } } void MarkerBrowserDialog::export_clicked () { BEGIN_PROTECTED if (m_rdb_index >= int (view ()->num_rdbs ()) || m_rdb_index < 0) { return; } const rdb::Database *rdb = view ()->get_rdb (m_rdb_index); if (! rdb) { return; } const lay::CellView &cv = view ()->cellview (m_cv_index); if (! cv.is_valid ()) { return; } bool ok; QString text = QInputDialog::getText(this, QObject::tr ("Layer Offset"), QObject::tr ("Enter the first GDS layer that is produced.\nLeave empty for not producing GDS layer numbers at all:"), QLineEdit::Normal, QString (), &ok); if (! ok) { return; } text = text.simplified (); int lnum = -1; ok = false; if (! text.isEmpty ()) { lnum = text.toInt (&ok); if (! ok) { throw tl::Exception (tl::to_string (QObject::tr ("Invalid layer number: ")) + tl::to_string (text)); } } try { view ()->manager ()->transaction (tl::to_string (QObject::tr ("Export Markers"))); std::vector categories; for (rdb::Categories::const_iterator cat = rdb->categories ().begin (); cat != rdb->categories ().end (); ++cat) { collect_categories (&*cat, categories); } for (std::vector ::const_iterator cat = categories.begin (); cat != categories.end (); ++cat) { db::LayerProperties lp; if (lnum >= 0) { lp.layer = lnum++; lp.datatype = 0; } lp.name = (*cat)->name (); unsigned int layer = cv->layout ().insert_layer (lp); lay::LayerProperties props; props.set_source (lay::ParsedLayerSource (lp, m_cv_index)); view ()->init_layer_properties (props); view ()->insert_layer (view ()->end_layers (), props); for (Cells::const_iterator cell = rdb->cells ().begin (); cell != rdb->cells ().end (); ++cell) { std::pair be = rdb->items_by_cell_and_category (cell->id (), (*cat)->id ()); if (be.first == be.second) { continue; } db::cell_index_type target_cell = cv.cell_index (); db::DCplxTrans trans; // TODO: be more verbose if that fails: std::pair cc = cv->layout ().cell_by_name (cell->name ().c_str ()); if (cc.first) { target_cell = cc.second; } else { const rdb::Cell *top_cell = rdb->cell_by_qname (rdb->top_cell_name ()); if (top_cell) { std::pair context = cell->path_to (top_cell->id (), rdb); if (context.first) { trans = context.second; } } } for (Database::const_item_ref_iterator item = be.first; item != be.second; ++item) { // Produce the shapes ... for (rdb::Values::const_iterator v = (*item)->values ().begin (); v != (*item)->values ().end (); ++v) { const rdb::Value *polygon_value = dynamic_cast *> (v->get ()); const rdb::Value *box_value = dynamic_cast *> (v->get ()); const rdb::Value *edge_value = dynamic_cast *> (v->get ()); const rdb::Value *edge_pair_value = dynamic_cast *> (v->get ()); if (polygon_value) { db::Polygon polygon = db::Polygon (db::DCplxTrans (1.0 / cv->layout ().dbu ()) * trans * polygon_value->value ()); cv->layout ().cell (target_cell).shapes (layer).insert (polygon); } else if (edge_value) { db::Edge edge = db::Edge (db::DCplxTrans (1.0 / cv->layout ().dbu ()) * trans * edge_value->value ()); cv->layout ().cell (target_cell).shapes (layer).insert (edge); } else if (edge_pair_value) { // Note: there is no edge pair inside the database currently. Hence we convert it to a polygon db::EdgePair edge_pair = db::EdgePair (db::DCplxTrans (1.0 / cv->layout ().dbu ()) * trans * edge_pair_value->value ()); cv->layout ().cell (target_cell).shapes (layer).insert (edge_pair.to_polygon (1)); } else if (box_value) { db::Polygon polygon = db::Polygon (db::DCplxTrans (1.0 / cv->layout ().dbu ()) * trans * db::DPolygon (box_value->value ())); cv->layout ().cell (target_cell).shapes (layer).insert (polygon); } } } } } view ()->manager ()->commit (); view ()->update_content (); } catch (...) { view ()->manager ()->commit (); view ()->update_content (); throw; } END_PROTECTED } void MarkerBrowserDialog::saveas_clicked () { BEGIN_PROTECTED if (m_rdb_index < int (view ()->num_rdbs ()) && m_rdb_index >= 0) { rdb::Database *rdb = view ()->get_rdb (m_rdb_index); if (rdb) { // prepare and open the file dialog lay::FileDialog save_dialog (this, tl::to_string (QObject::tr ("Marker Database File")), "KLayout RDB files (*.lyrdb)"); std::string fn (rdb->filename ()); if (save_dialog.get_save (fn)) { rdb->save (fn); rdb->reset_modified (); } } } END_PROTECTED } void MarkerBrowserDialog::reload_clicked () { BEGIN_PROTECTED if (m_rdb_index < int (view ()->num_rdbs ()) && m_rdb_index >= 0) { rdb::Database *rdb = view ()->get_rdb (m_rdb_index); if (rdb && ! rdb->filename ().empty ()) { browser_frame->set_rdb (0); rdb->load (rdb->filename ()); browser_frame->set_rdb (rdb); } } END_PROTECTED } void MarkerBrowserDialog::open_clicked () { BEGIN_PROTECTED // collect the formats available ... std::string fmts = tl::to_string (QObject::tr ("All files (*)")); for (tl::Registrar::iterator rdr = tl::Registrar::begin (); rdr != tl::Registrar::end (); ++rdr) { fmts += ";;" + rdr->file_format (); } // prepare and open the file dialog lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Marker Database File")), fmts); if (open_dialog.get_open (m_open_filename)) { std::auto_ptr db (new rdb::Database ()); db->load (m_open_filename); int rdb_index = view ()->add_rdb (db.release ()); rdb_cb->setCurrentIndex (rdb_index); // it looks like the setCurrentIndex does not issue this signal: rdb_index_changed (rdb_index); } END_PROTECTED } bool MarkerBrowserDialog::configure (const std::string &name, const std::string &value) { bool need_update = false; bool taken = true; bool show_all = browser_frame->show_all (); if (name == cfg_rdb_context_mode) { context_mode_type context = m_context; MarkerBrowserContextModeConverter ().from_string (value, context); need_update = lay::test_and_set (m_context, context); } else if (name == cfg_rdb_show_all) { tl::from_string (value, show_all); } else if (name == cfg_rdb_window_mode) { window_type window = m_window; MarkerBrowserWindowModeConverter ().from_string (value, window); need_update = lay::test_and_set (m_window, window); } else if (name == cfg_rdb_window_dim) { double wdim = m_window_dim; tl::from_string (value, wdim); if (fabs (wdim - m_window_dim) > 1e-6) { m_window_dim = wdim; need_update = true; } } else if (name == cfg_rdb_max_marker_count) { unsigned int mc = 0; tl::from_string (value, mc); need_update = lay::test_and_set (m_max_marker_count, mc); } else if (name == cfg_rdb_marker_color) { QColor color; if (! value.empty ()) { lay::ColorConverter ().from_string (value, color); } if (color != m_marker_color) { m_marker_color = color; need_update = true; } } else if (name == cfg_rdb_marker_line_width) { int lw = 0; tl::from_string (value, lw); if (lw != m_marker_line_width) { m_marker_line_width = lw; need_update = true; } } else if (name == cfg_rdb_marker_vertex_size) { int vs = 0; tl::from_string (value, vs); if (vs != m_marker_vertex_size) { m_marker_vertex_size = vs; need_update = true; } } else if (name == cfg_rdb_marker_halo) { int halo = 0; tl::from_string (value, halo); if (halo != m_marker_halo) { m_marker_halo = halo; need_update = true; } } else if (name == cfg_rdb_marker_dither_pattern) { int dp = 0; tl::from_string (value, dp); if (dp != m_marker_dither_pattern) { m_marker_dither_pattern = dp; need_update = true; } } else { taken = false; } if (active () && need_update) { browser_frame->set_max_marker_count (m_max_marker_count); browser_frame->set_window (m_window, m_window_dim, m_context); browser_frame->set_marker_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern); } browser_frame->show_all (show_all); return taken; } void MarkerBrowserDialog::load (int rdb_index, int cv_index) { if (! view ()->get_rdb (rdb_index)) { return; } if (! view ()->cellview (cv_index).is_valid ()) { m_layout_name = std::string (); } else { m_layout_name = view ()->cellview (cv_index)->name (); } // set the new references (by name) m_rdb_name = view ()->get_rdb (rdb_index)->name (); // force an update rdbs_changed (); cellviews_changed (); activate (); } void MarkerBrowserDialog::rdbs_changed () { int rdb_index = -1; rdb_cb->clear (); for (unsigned int i = 0; i < view ()->num_rdbs (); ++i) { const rdb::Database *rdb = view ()->get_rdb (i); rdb_cb->addItem (tl::to_qstring (rdb->name ())); if (rdb->name () == m_rdb_name) { rdb_index = i; } } // force an update m_rdb_index = rdb_index; rdb_cb->setCurrentIndex (rdb_index); if (active ()) { update_content (); } } void MarkerBrowserDialog::cellview_changed (int) { browser_frame->update_markers (); } void MarkerBrowserDialog::cellviews_changed () { int cv_index = -1; layout_cb->clear (); for (unsigned int i = 0; i < view ()->cellviews (); ++i) { const lay::CellView &cv = view ()->cellview (i); layout_cb->addItem (tl::to_qstring (cv->name ())); if (cv.is_valid () && cv->name () == m_layout_name) { cv_index = i; } } layout_cb->setCurrentIndex (cv_index); cv_index_changed (cv_index); } void MarkerBrowserDialog::rdb_index_changed (int index) { if (m_rdb_index != index) { m_rdb_index = index; if (active ()) { update_content (); } } } void MarkerBrowserDialog::cv_index_changed (int index) { if (m_cv_index != index) { m_cv_index = index; if (active ()) { update_content (); } } } void MarkerBrowserDialog::activated () { std::string state; if (lay::PluginRoot::instance ()) { lay::PluginRoot::instance ()->config_get (cfg_rdb_window_state, state); } lay::restore_dialog_state (this, state); // Switch to the active cellview index when no valid one is set. lay::CellView cv = view ()->cellview (m_cv_index); if (! cv.is_valid ()) { m_cv_index = view ()->active_cellview_index (); } if (m_rdb_index < 0 && view ()->get_rdb (0) != 0) { m_rdb_name = view ()->get_rdb (0)->name (); rdbs_changed (); } else { update_content (); } } void MarkerBrowserDialog::update_content () { rdb::Database *rdb = view ()->get_rdb (m_rdb_index); if (!rdb ) { central_stack->setCurrentIndex (1); } m_saveas_action->setEnabled (rdb != 0); m_export_action->setEnabled (rdb != 0); m_unload_action->setEnabled (rdb != 0); m_unload_all_action->setEnabled (rdb != 0); m_reload_action->setEnabled (rdb != 0); browser_frame->enable_updates (false); // Avoid building the internal lists several times ... browser_frame->set_rdb (rdb); browser_frame->set_max_marker_count (m_max_marker_count); browser_frame->set_marker_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern); browser_frame->set_window (m_window, m_window_dim, m_context); browser_frame->set_view (view (), m_cv_index); browser_frame->enable_updates (true); if (rdb) { // Note: it appears to be required to show the browser page after it has been configured. // Otherwise the header gets messed up and the configuration is reset. central_stack->setCurrentIndex (0); } lay::CellView cv = view ()->cellview (m_cv_index); m_layout_name = std::string (); if (cv.is_valid ()) { m_layout_name = cv->name (); } if (layout_cb->currentIndex () != m_cv_index) { layout_cb->setCurrentIndex (m_cv_index); } if (rdb_cb->currentIndex () != m_rdb_index) { rdb_cb->setCurrentIndex (m_rdb_index); } } void MarkerBrowserDialog::deactivated () { if (lay::PluginRoot::instance ()) { lay::PluginRoot::instance ()->config_set (cfg_rdb_window_state, lay::save_dialog_state (this).c_str ()); } browser_frame->set_rdb (0); browser_frame->set_view (0, 0); } void MarkerBrowserDialog::scan_layer () { std::vector layers = view ()->selected_layers (); if (layers.empty ()) { throw tl::Exception (tl::to_string (QObject::tr ("No layer selected to get shapes from"))); } int cv_index = -1; for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { if (!(*l)->has_children ()) { if (cv_index < 0) { cv_index = (*l)->cellview_index (); } else if ((*l)->cellview_index () >= 0) { if (cv_index != (*l)->cellview_index ()) { throw tl::Exception (tl::to_string (QObject::tr ("All layers must originate from the same layout"))); } } } } if (cv_index < 0) { throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected"))); } tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Shapes To Markers")), 10000); progress.set_format (tl::to_string (QObject::tr ("%.0f0000 markers"))); progress.set_unit (10000); const lay::CellView &cv = view ()->cellview (cv_index); const db::Layout &layout = cv->layout (); std::auto_ptr rdb (new rdb::Database ()); rdb->set_name ("Shapes"); rdb->set_top_cell_name (layout.cell_name (cv.cell_index ())); rdb::Cell *rdb_top_cell = rdb->create_cell (rdb->top_cell_name ()); std::string desc; for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { if (! desc.empty ()) { desc += ", "; } desc += layout.get_properties ((*l)->layer_index ()).to_string (); } } rdb->set_description ("Shapes of layer(s) " + desc); for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ()); for (db::Layout::const_iterator cid = layout.begin (); cid != layout.end (); ++cid) { const db::Cell &cell = *cid; if (cell.shapes ((*l)->layer_index ()).size () > 0) { std::string cn = layout.cell_name (cell.cell_index ()); const rdb::Cell *rdb_cell = rdb->cell_by_qname (cn); if (! rdb_cell) { rdb::Cell *rdb_cell_nc = rdb->create_cell (cn); rdb_cell = rdb_cell_nc; std::pair ctx = db::find_layout_context (layout, cell.cell_index (), cv.cell_index ()); if (ctx.first) { db::DCplxTrans t = db::DCplxTrans (layout.dbu ()) * db::DCplxTrans (ctx.second) * db::DCplxTrans (1.0 / layout.dbu ()); rdb_cell_nc->references ().insert (Reference (t, rdb_top_cell->id ())); } } for (db::ShapeIterator shape = cell.shapes ((*l)->layer_index ()).begin (db::ShapeIterator::All); ! shape.at_end (); ++shape) { std::auto_ptr value; if (shape->is_polygon () || shape->is_box ()) { db::Polygon poly; shape->polygon (poly); value.reset (new rdb::Value (poly.transformed (db::CplxTrans (layout.dbu ())))); } else if (shape->is_path ()) { db::Path path; shape->path (path); value.reset (new rdb::Value (path.transformed (db::CplxTrans (layout.dbu ())))); } else if (shape->is_text ()) { db::Text text; shape->text (text); value.reset (new rdb::Value (text.transformed (db::CplxTrans (layout.dbu ())))); } else if (shape->is_edge ()) { db::Edge edge; shape->edge (edge); value.reset (new rdb::Value (edge.transformed (db::CplxTrans (layout.dbu ())))); } rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ()); item->values ().add (value.release ()); ++progress; } } } } } unsigned int rdb_index = view ()->add_rdb (rdb.release ()); view ()->open_rdb_browser (rdb_index, cv_index); } void MarkerBrowserDialog::scan_layer_flat () { std::vector layers = view ()->selected_layers (); if (layers.empty ()) { throw tl::Exception (tl::to_string (QObject::tr ("No layer selected to get shapes from"))); } int cv_index = -1; for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { if (!(*l)->has_children ()) { if (cv_index < 0) { cv_index = (*l)->cellview_index (); } else if ((*l)->cellview_index () >= 0) { if (cv_index != (*l)->cellview_index ()) { throw tl::Exception (tl::to_string (QObject::tr ("All layers must originate from the same layout"))); } } } } if (cv_index < 0) { throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected"))); } tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Shapes To Markers")), 10000); progress.set_format (tl::to_string (QObject::tr ("%.0f0000 markers"))); progress.set_unit (10000); const lay::CellView &cv = view ()->cellview (cv_index); const db::Layout &layout = cv->layout (); std::auto_ptr rdb (new rdb::Database ()); rdb->set_name ("Shapes"); rdb->set_top_cell_name (layout.cell_name (cv.cell_index ())); rdb::Cell *rdb_top_cell = rdb->create_cell (rdb->top_cell_name ()); std::string desc; for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { if (! desc.empty ()) { desc += ", "; } desc += layout.get_properties ((*l)->layer_index ()).to_string (); } } rdb->set_description ("Shapes of layer(s) " + desc); for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ()); db::RecursiveShapeIterator shape (layout, *cv.cell (), (*l)->layer_index ()); while (! shape.at_end ()) { std::auto_ptr value; if (shape->is_polygon () || shape->is_box ()) { db::Polygon poly; shape->polygon (poly); value.reset (new rdb::Value (poly.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); } else if (shape->is_path ()) { db::Path path; shape->path (path); value.reset (new rdb::Value (path.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); } else if (shape->is_text ()) { db::Text text; shape->text (text); value.reset (new rdb::Value (text.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); } else if (shape->is_edge ()) { db::Edge edge; shape->edge (edge); value.reset (new rdb::Value (edge.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); } rdb::Item *item = rdb->create_item (rdb_top_cell->id (), cat->id ()); item->values ().add (value.release ()); ++progress; ++shape; } } } unsigned int rdb_index = view ()->add_rdb (rdb.release ()); view ()->open_rdb_browser (rdb_index, cv_index); } void MarkerBrowserDialog::menu_activated (const std::string &symbol) { if (symbol == "marker_browser::show") { view ()->deactivate_all_browsers (); activate (); } else if (symbol == "marker_browser::scan_layers") { scan_layer (); } else if (symbol == "marker_browser::scan_layers_flat") { scan_layer_flat (); } else { lay::Browser::menu_activated (symbol); } } }