diff --git a/src/db/db/dbCell.cc b/src/db/db/dbCell.cc index 802614a2b..7200b30da 100644 --- a/src/db/db/dbCell.cc +++ b/src/db/db/dbCell.cc @@ -945,7 +945,7 @@ std::string Cell::get_display_name () const { tl_assert (layout () != 0); - if (is_ghost_cell () && empty ()) { + if (is_real_ghost_cell ()) { return std::string ("(") + layout ()->cell_name (cell_index ()) + std::string (")"); } else { return layout ()->cell_name (cell_index ()); @@ -959,6 +959,20 @@ Cell::set_name (const std::string &name) layout ()->rename_cell (cell_index (), name.c_str ()); } +void +Cell::set_ghost_cell (bool g) +{ + // NOTE: this change is not undo managed + if (m_ghost_cell != g) { + + m_ghost_cell = g; + tl_assert (layout () != 0); + // To trigger a redraw and cell tree rebuild + layout ()->cell_name_changed (); + + } +} + void Cell::check_locked () const { diff --git a/src/db/db/dbCell.h b/src/db/db/dbCell.h index 5bfe8b61c..c616a105d 100644 --- a/src/db/db/dbCell.h +++ b/src/db/db/dbCell.h @@ -925,15 +925,26 @@ public: return m_ghost_cell; } + /** + * @brief Gets a value indicating whether the cell is a "real" ghost cell + * + * A ghost cell is a real ghost cell only if the ghost cell flag is set + * and the cell is empty. Only in that case for example the cell is written + * to GDS files as a ghost cell. + * + * Otherwise, the ghost cell flag is mostly ignored. + */ + bool is_real_ghost_cell () const + { + return m_ghost_cell && empty (); + } + /** * @brief Sets the "ghost cell" flag * * See "is_ghost_cell" for a description of this property. */ - void set_ghost_cell (bool g) - { - m_ghost_cell = g; - } + void set_ghost_cell (bool g); /** * @brief Gets a value indicating whether the cell is locked diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index dacfcbd4f..40557f375 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1417,7 +1417,7 @@ Layout::add_cell (const char *name) if (cm != m_cell_map.end ()) { const db::Cell &c= cell (cm->second); - if (c.is_ghost_cell () && c.empty ()) { + if (c.is_real_ghost_cell ()) { // ghost cells are available as new cells - the idea is to // treat them as non-existing. return cm->second; diff --git a/src/db/db/dbLayoutStateModel.h b/src/db/db/dbLayoutStateModel.h index d6f209241..3524f75c2 100644 --- a/src/db/db/dbLayoutStateModel.h +++ b/src/db/db/dbLayoutStateModel.h @@ -183,6 +183,14 @@ public: return m_busy; } + /** + * @brief Issue a "cell name changed event" + */ + void cell_name_changed () + { + cell_name_changed_event (); + } + protected: friend class PropertiesRepository; @@ -191,14 +199,6 @@ protected: */ virtual void do_update () { } - /** - * @brief Issue a "prop id's changed event" - */ - void cell_name_changed () - { - cell_name_changed_event (); - } - /** * @brief Issue a "layer properties changed event" */ diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index b9218f533..4a53b12df 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -3450,6 +3450,9 @@ Class decl_Cell ("db", "Cell", "To satisfy the references inside the layout, a dummy cell is created in this case\n" "which has the \"ghost cell\" flag set to true.\n" "\n" + "A ghost cell is a real ghost cell only if the cell is empty. In that case, it is written " + "as a ghost cell to GDS files for example. If a cell is not empty, this flag is ignored.\n" + "\n" "This method has been introduced in version 0.20.\n" ) + gsi::method ("ghost_cell=", &db::Cell::set_ghost_cell, gsi::arg ("flag"), diff --git a/src/laybasic/laybasic/layFinder.cc b/src/laybasic/laybasic/layFinder.cc index 81c969f41..ef7c7c97b 100644 --- a/src/laybasic/laybasic/layFinder.cc +++ b/src/laybasic/laybasic/layFinder.cc @@ -220,7 +220,7 @@ Finder::do_find (const db::Cell &cell, int level, const db::DCplxTrans &vp, cons && (t * m_cell_box_convert (cell)).touches (m_scan_region) && (mp_view->select_inside_pcells_mode () || !cell.is_proxy ()) && !mp_view->is_cell_hidden (cell.cell_index (), m_cv_index) - && !cell.is_ghost_cell ()) { + && !cell.is_real_ghost_cell ()) { db::ICplxTrans it = t.inverted (); db::Box scan_box (it * m_scan_region); @@ -846,7 +846,7 @@ InstFinder::reset_counter () bool InstFinder::consider_cell (const db::Cell &cell) const { - return cell.is_ghost_cell () ? m_consider_ghost_cells : m_consider_normal_cells; + return cell.is_real_ghost_cell () ? m_consider_ghost_cells : m_consider_normal_cells; } void @@ -877,7 +877,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d // just consider the instances exactly at the last level of // hierarchy (this is where the boxes are drawn) or of cells that // are hidden. - if (level == max_level () - 1 || inst_cell.is_proxy () || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { + if (level == max_level () - 1 || inst_cell.is_proxy () || inst_cell.is_real_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { db::box_convert bc (layout ()); for (db::CellInstArray::iterator p = cell_inst.begin_touching (search_box, bc); ! p.at_end (); ++p) { @@ -885,7 +885,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d checkpoint (); db::Box ibox; - if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { + if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || inst_cell.is_real_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { ibox = inst_cell.bbox_with_empty (); } else if (inst_cell.bbox ().empty ()) { // empty cells cannot be found by visible layers, so we always select them here @@ -954,7 +954,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d // just consider the instances exactly at the last level of // hierarchy (this is where the boxes are drawn) or if of cells that // are hidden. - if (level == max_level () - 1 || inst_cell.is_proxy () || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { + if (level == max_level () - 1 || inst_cell.is_proxy () || inst_cell.is_real_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { db::box_convert bc (layout ()); for (db::CellInstArray::iterator p = cell_inst.begin_touching (search_box, bc); ! p.at_end (); ++p) { @@ -965,7 +965,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d double d = std::numeric_limits::max (); db::Box ibox; - if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { + if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || inst_cell.is_real_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) { ibox = inst_cell.bbox_with_empty (); } else if (inst_cell.bbox ().empty ()) { // empty cells cannot be found by visible layers, so we always select them here diff --git a/src/laybasic/laybasic/layRedrawThreadWorker.cc b/src/laybasic/laybasic/layRedrawThreadWorker.cc index d05a4de63..f193fa1cd 100644 --- a/src/laybasic/laybasic/layRedrawThreadWorker.cc +++ b/src/laybasic/laybasic/layRedrawThreadWorker.cc @@ -714,7 +714,7 @@ RedrawThreadWorker::setup (LayoutViewBase *view, RedrawThreadCanvas *canvas, con std::set &gc = m_ghost_cells [i]; const db::Layout &ly = view->cellview (i)->layout (); for (auto c = ly.begin (); c != ly.end (); ++c) { - if (c->is_ghost_cell ()) { + if (c->is_real_ghost_cell ()) { gc.insert (c->cell_index ()); } } @@ -950,12 +950,12 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c bbox_for_label = bbox; } - if (for_ghosts && cell.is_ghost_cell ()) { + if (for_ghosts && cell.is_real_ghost_cell ()) { // paint the box on this level draw_cell (drawing_context, level, trans, bbox, bbox_for_label, empty_cell, mp_layout->display_name (ci), opt_bitmap); - } else if (! for_ghosts && ! cell.is_ghost_cell () && (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()))) { + } else if (! for_ghosts && ! cell.is_real_ghost_cell () && (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()))) { // paint the box on this level draw_cell (drawing_context, level, trans, bbox, bbox_for_label, empty_cell, mp_layout->display_name (ci), opt_bitmap); @@ -1186,12 +1186,12 @@ RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_ind // small cell dropped - } else if (for_ghosts && cell.is_ghost_cell ()) { + } else if (for_ghosts && cell.is_real_ghost_cell ()) { // paint the box on this level draw_cell_properties (drawing_context, level, trans, bbox, prop_id); - } else if (! for_ghosts && ! cell.is_ghost_cell () && (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()))) { + } else if (! for_ghosts && ! cell.is_real_ghost_cell () && (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()))) { // paint the box on this level draw_cell_properties (drawing_context, level, trans, bbox, prop_id); @@ -1317,7 +1317,7 @@ RedrawThreadWorker::any_shapes (db::cell_index_type cell_index, unsigned int lev // Ghost cells are not drawn either const db::Cell &cell = mp_layout->cell (cell_index); - if (cell.is_ghost_cell ()) { + if (cell.is_real_ghost_cell ()) { return false; } @@ -1359,7 +1359,7 @@ RedrawThreadWorker::any_cell_box (db::cell_index_type cell_index, unsigned int l // ghost cells are also drawn const db::Cell &cell = mp_layout->cell (cell_index); - if (cell.is_ghost_cell ()) { + if (cell.is_real_ghost_cell ()) { return true; } @@ -1400,7 +1400,7 @@ RedrawThreadWorker::any_text_shapes (db::cell_index_type cell_index, unsigned in // Ghost cells are not drawn either const db::Cell &cell = mp_layout->cell (cell_index); - if (cell.is_ghost_cell ()) { + if (cell.is_real_ghost_cell ()) { return false; } @@ -1503,7 +1503,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c } else if (! bbox.empty ()) { - bool hidden = cell.is_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())); + bool hidden = cell.is_real_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())); bool need_to_dive = (level + 1 < m_to_level) && ! hidden; db::Box cell_bbox = cell.bbox (); @@ -1637,7 +1637,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c ++inst; db::cell_index_type new_ci = cell_inst.object ().cell_index (); - bool hidden = mp_layout->cell (new_ci).is_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ())); + bool hidden = mp_layout->cell (new_ci).is_real_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ())); db::Box cell_box = mp_layout->cell (new_ci).bbox (m_layer); if (! cell_box.empty () && ! hidden) { @@ -1939,7 +1939,7 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_ ++inst; db::cell_index_type new_ci = cell_inst.object ().cell_index (); - bool hidden = mp_layout->cell (new_ci).is_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ())); + bool hidden = mp_layout->cell (new_ci).is_real_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ())); db::Box new_cell_box = mp_layout->cell (new_ci).bbox (m_layer); if (! new_cell_box.empty () && ! hidden) { @@ -2096,7 +2096,7 @@ RedrawThreadWorker::draw_layer (int from_level, int to_level, db::cell_index_typ db::Box cell_bbox = cell.bbox (); // Nothing to draw - if (bbox.empty () || cell.is_ghost_cell ()) { + if (bbox.empty () || cell.is_real_ghost_cell ()) { return; } diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc index 3f37a0606..c6b7a3ea2 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc @@ -577,7 +577,7 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S // don't write ghost cells unless they are not empty (any more) // also don't write proxy cells which are not employed - if ((! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ())) { + if (! cref.is_real_ghost_cell () && (! cref.is_proxy () || ! cref.is_top ())) { try { write_cell (layout, cref, layers, cell_set, sf, time_data); diff --git a/src/plugins/streamers/lstream/db_plugin/lstrWriter.cc b/src/plugins/streamers/lstream/db_plugin/lstrWriter.cc index 4de9a2fc4..ccd31f815 100644 --- a/src/plugins/streamers/lstream/db_plugin/lstrWriter.cc +++ b/src/plugins/streamers/lstream/db_plugin/lstrWriter.cc @@ -913,7 +913,7 @@ Writer::make_meta_data (const db::Cell *cell, stream::metaData::MetaData::Builde void Writer::write_cell (db::cell_index_type ci, kj::BufferedOutputStream &os) { - bool needs_layout_view = ! mp_layout->cell (ci).is_ghost_cell (); + bool needs_layout_view = ! mp_layout->cell (ci).is_real_ghost_cell (); bool needs_meta_data_view = mp_layout->begin_meta (ci) != mp_layout->end_meta (ci); capnp::MallocMessageBuilder message; diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc index e7ce59048..49f7b7077 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc @@ -1443,12 +1443,6 @@ static bool must_write_cell (const db::Cell &cref) return ! cref.is_proxy () || ! cref.is_top (); } -static bool skip_cell_body (const db::Cell &cref) -{ - // Skip cell bodies for ghost cells unless empty (they are not longer ghost cells in this case) - return cref.is_ghost_cell () && cref.empty (); -} - void OASISWriter::create_cell_nstrings (const db::Layout &layout, const std::set &cell_set) { @@ -1670,7 +1664,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save mp_cell = &cref; // skip cell body if the cell is not to be written - if (skip_cell_body (cref)) { + if (cref.is_real_ghost_cell ()) { continue; }