From 0016710573435fc4e549cd59d2b347dc9c4930a8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Oct 2025 23:06:23 +0200 Subject: [PATCH 1/4] Preparations: more planes, for ghost cells too --- src/laybasic/laybasic/layLayoutViewBase.cc | 56 ++++++ .../laybasic/layRedrawThreadWorker.cc | 165 +++++++++++++++--- src/laybasic/laybasic/layRedrawThreadWorker.h | 15 +- 3 files changed, 203 insertions(+), 33 deletions(-) diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index 50a160e5d..f2ed75b5e 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -4327,6 +4327,62 @@ LayoutViewBase::set_view_ops () } } + // ghost cells + if (m_cell_box_visible) { // @@@ + + lay::ViewOp vop, vopv; + + // context level + if (m_ctx_color.is_valid ()) { + vop = lay::ViewOp (m_ctx_color.rgb (), lay::ViewOp::Copy, 0, 0, 0); + } else { + vop = lay::ViewOp (lay::LayerProperties::brighter (box_color.rgb (), brightness_for_context), lay::ViewOp::Copy, 0, 0, 0); + } + vopv = vop; + vopv.shape (lay::ViewOp::Cross); + vopv.width (mark_size); + + // fill, frame, text, vertex + view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0)); + view_ops.push_back (vop); + view_ops.push_back (vop); + view_ops.push_back (vopv); + + // child level + if (m_child_ctx_color.is_valid ()) { + vop = lay::ViewOp (m_child_ctx_color.rgb (), lay::ViewOp::Copy, 0, 0, 0); + } else { + vop = lay::ViewOp (lay::LayerProperties::brighter (box_color.rgb (), brightness_for_context), lay::ViewOp::Copy, 0, 0, 0); + } + vopv = vop; + vopv.shape (lay::ViewOp::Cross); + vopv.width (mark_size); + + // fill, frame, text, vertex + view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0)); + view_ops.push_back (vop); + view_ops.push_back (vop); + view_ops.push_back (vopv); + + // current level + vop = lay::ViewOp (box_color.rgb (), lay::ViewOp::Copy, 0, 0, 0); + vopv = vop; + vopv.shape (lay::ViewOp::Cross); + vopv.width (mark_size); + + // fill, frame, text, vertex + view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0)); + view_ops.push_back (vop); + view_ops.push_back (vop); + view_ops.push_back (vopv); + + } else { + // invisible + for (unsigned int i = 0; i < (unsigned int) planes_per_layer; ++i) { // frame, fill, vertex, text + view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0)); + } + } + // sanity check: number of planes defined in layRedrawThreadWorker must match to view_ops layout tl_assert (view_ops.size () == (size_t)cell_box_planes); diff --git a/src/laybasic/laybasic/layRedrawThreadWorker.cc b/src/laybasic/laybasic/layRedrawThreadWorker.cc index d5151f6b6..fe1275a41 100644 --- a/src/laybasic/laybasic/layRedrawThreadWorker.cc +++ b/src/laybasic/laybasic/layRedrawThreadWorker.cc @@ -316,6 +316,73 @@ RedrawThreadWorker::perform_task (tl::Task *task) transfer (); + // Draw the ghost cells + + // HINT: the order in which the planes are delivered (the index stored in the first member of the pair below) + // must correspond with the order by which the ViewOp's are created inside LayoutView::set_view_ops + m_buffers.clear (); + for (unsigned int i = 0; i < (unsigned int) planes_per_layer / 3; ++i) { + + // context level planes + unsigned int i1 = plain_cell_box_planes + i; + mp_canvas->initialize_plane (m_planes[i], i1); + m_buffers.push_back (std::make_pair (i1, m_planes [i])); + + // child level planes (if used) + unsigned int i2 = plain_cell_box_planes + i + planes_per_layer / 3; + mp_canvas->initialize_plane (m_planes [i + planes_per_layer / 3], i2); + m_buffers.push_back (std::make_pair (i2, m_planes [i + planes_per_layer / 3])); + + // current level planes + unsigned int i3 = plain_cell_box_planes + i + 2 * (planes_per_layer / 3); + mp_canvas->initialize_plane (m_planes [i + 2 * (planes_per_layer / 3)], i3); + m_buffers.push_back (std::make_pair (i3, m_planes [i + 2 * (planes_per_layer / 3)])); + + } + + // detect whether the text planes are empty. If not, the whole text plane must be redrawn to account for clipped texts + text_planes_empty = true; + for (unsigned int i = 0; i < (unsigned int) planes_per_layer && text_planes_empty; i += (unsigned int) planes_per_layer / 3) { + lay::Bitmap *text = dynamic_cast (m_planes[i + 2]); + if (text && ! text->empty ()) { + text_planes_empty = false; + } + } + + text_redraw_regions = m_redraw_region; + if (! text_planes_empty) { + // if there are non-empty text planes, redraw the whole area for texts + text_redraw_regions.clear (); + text_redraw_regions.push_back(db::Box(0, 0, mp_canvas->canvas_width (), mp_canvas->canvas_height ())); + for (unsigned int i = 0; i < (unsigned int) planes_per_layer; i += (unsigned int) planes_per_layer / 3) { + lay::Bitmap *text = dynamic_cast (m_planes[i + 2]); + if (text) { + text->clear (); + } + } + } + + for (std::set< std::pair >::const_iterator b = m_box_variants.begin (); b != m_box_variants.end (); ++b) { + + const lay::CellView &cv = m_cellviews [b->second]; + if (cv.is_valid () && ! cv->layout ().under_construction () && ! (cv->layout ().manager () && cv->layout ().manager ()->transacting ())) { + + mp_layout = &cv->layout (); + m_cv_index = b->second; + + db::CplxTrans trans = m_vp_trans * b->first * db::CplxTrans (mp_layout->dbu ()); + + iterate_variants (m_redraw_region, cv.cell_index (), trans, &RedrawThreadWorker::draw_boxes_for_ghosts); + iterate_variants (text_redraw_regions, cv.cell_index (), trans, &RedrawThreadWorker::draw_box_properties_for_ghosts); + + } + + } + + transfer (); + + // draw guiding and error shapes + // HINT: the order in which the planes are delivered (the index stored in the first member of the pair below) // must correspond with the order by which the ViewOp's are created inside LayoutView::set_view_ops m_buffers.clear (); @@ -689,31 +756,51 @@ cells_in (const db::Layout *layout, const db::Cell &cell, } bool -RedrawThreadWorker::need_draw_box (const db::Layout *layout, const db::Cell &cell, int level) +RedrawThreadWorker::need_draw_box (const db::Layout *layout, const db::Cell &cell, int level, bool for_ghosts) { if (level > m_to_level) { + return false; - } - if (m_ghost_cells.size () > (size_t) m_cv_index && ! m_ghost_cells [m_cv_index].empty ()) { - std::set > cache; - if (cells_in (layout, cell, m_ghost_cells [m_cv_index], m_to_level - level, cache)) { - return true; + } else if (for_ghosts) { + + if (m_ghost_cells.size () > (size_t) m_cv_index && ! m_ghost_cells [m_cv_index].empty ()) { + std::set > cache; + if (cells_in (layout, cell, m_ghost_cells [m_cv_index], m_to_level - level, cache)) { + return true; + } } - } - if (m_hidden_cells.size () > (size_t) m_cv_index && ! m_hidden_cells [m_cv_index].empty ()) { - std::set > cache; - if (cells_in (layout, cell, m_hidden_cells [m_cv_index], m_to_level - level, cache)) { - return true; + return false; + + } else { + + if (m_hidden_cells.size () > (size_t) m_cv_index && ! m_hidden_cells [m_cv_index].empty ()) { + std::set > cache; + if (cells_in (layout, cell, m_hidden_cells [m_cv_index], m_to_level - level, cache)) { + return true; + } } - } - return int (cell.hierarchy_levels ()) + level >= m_to_level; + return int (cell.hierarchy_levels ()) + level >= m_to_level; + + } } void RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level) +{ + draw_boxes_impl (drawing_context, ci, trans, redraw_regions, level, false); +} + +void +RedrawThreadWorker::draw_boxes_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level) +{ + draw_boxes_impl (drawing_context, ci, trans, redraw_regions, level, true); +} + +void +RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level, bool for_ghosts) { // do not draw, if there is nothing to draw if (mp_layout->cells () <= ci || redraw_regions.empty ()) { @@ -723,7 +810,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co const db::Cell &cell = mp_layout->cell (ci); // we will never come to a valid level .. - if (! need_draw_box (mp_layout, cell, level)) { + if (! need_draw_box (mp_layout, cell, level, for_ghosts)) { return; } if (cell_var_cached (ci, trans)) { @@ -731,12 +818,12 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co } for (std::vector::const_iterator b = redraw_regions.begin (); b != redraw_regions.end (); ++b) { - draw_boxes (drawing_context, ci, trans, *b, level); + draw_boxes_impl (drawing_context, ci, trans, *b, level, for_ghosts); } } void -RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level) +RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, bool for_ghosts) { lay::Renderer &r = *mp_renderer; const db::Cell &cell = mp_layout->cell (ci); @@ -749,7 +836,12 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co // small cell dropped - } else if (level == m_to_level || 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 ())) { + } else if (for_ghosts && cell.is_ghost_cell ()) { + + // paint the box on this level + draw_cell (drawing_context, level, trans, bbox, empty_cell, mp_layout->display_name (ci)); + + } else if (! for_ghosts && (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, empty_cell, mp_layout->display_name (ci)); @@ -759,7 +851,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co db::DBox dbbox = trans * bbox; if (!empty_cell && (dbbox.width () < 1.5 && dbbox.height () < 1.5)) { - if (need_draw_box (mp_layout, cell, level)) { + if (need_draw_box (mp_layout, cell, level, for_ghosts)) { // the cell is a very small box and we know there must be // some level at which to draw the boundary: just draw it // here and stop looking further down .. @@ -836,7 +928,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co if (simplify) { // The array can be simplified if there are levels below to draw - if (need_draw_box (mp_layout, mp_layout->cell (new_ci), level + 1)) { + if (need_draw_box (mp_layout, mp_layout->cell (new_ci), level + 1, for_ghosts)) { unsigned int plane_group = 2; if (drawing_context) { @@ -865,7 +957,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co test_snapshot (0); db::ICplxTrans t (cell_inst.complex_trans (*p)); db::Box new_vp = safe_transformed_box (*v, t.inverted ()); - draw_boxes (drawing_context, new_ci, trans * t, new_vp, level + 1); + draw_boxes_impl (drawing_context, new_ci, trans * t, new_vp, level + 1, for_ghosts); if (p.quad_id () > 0 && p.quad_id () != qid) { @@ -902,18 +994,30 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co } -void +void RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &vp, int level) +{ + draw_box_properties_impl (drawing_context, ci, trans, vp, level, false); +} + +void +RedrawThreadWorker::draw_box_properties_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &vp, int level) +{ + draw_box_properties_impl (drawing_context, ci, trans, vp, level, false); +} + +void +RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &vp, int level, bool for_ghosts) { if (! m_text_visible) { return; } - draw_box_properties (drawing_context, ci, trans, vp, level, 0); + draw_box_properties_impl (drawing_context, ci, trans, vp, level, 0, for_ghosts); } void -RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &vp, int level, db::properties_id_type prop_id) +RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &vp, int level, db::properties_id_type prop_id, bool for_ghosts) { // do not draw, if there is nothing to draw if (mp_layout->cells () <= ci || vp.empty ()) { @@ -923,7 +1027,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty const db::Cell &cell = mp_layout->cell (ci); // we will never come to a valid level .. - if (! need_draw_box (mp_layout, cell, level)) { + if (! need_draw_box (mp_layout, cell, level, for_ghosts)) { return; } if (cell_var_cached (ci, trans)) { @@ -931,12 +1035,12 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty } for (std::vector::const_iterator b = vp.begin (); b != vp.end (); ++b) { - draw_box_properties (drawing_context, ci, trans, *b, level, prop_id); + draw_box_properties_impl (drawing_context, ci, trans, *b, level, prop_id, for_ghosts); } } void -RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, db::properties_id_type prop_id) +RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, db::properties_id_type prop_id, bool for_ghosts) { const db::Cell &cell = mp_layout->cell (ci); @@ -948,7 +1052,12 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty // small cell dropped - } else if (level == m_to_level || 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 ())) { + } else if (for_ghosts && cell.is_ghost_cell ()) { + + // paint the box on this level + draw_cell_properties (drawing_context, level, trans, bbox, prop_id); + + } else if (! for_ghosts && (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); @@ -1036,7 +1145,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty test_snapshot (0); db::ICplxTrans t (cell_inst.complex_trans (*p)); db::Box new_vp = safe_transformed_box (*v, t.inverted ()); - draw_box_properties (drawing_context, new_ci, trans * t, new_vp, level + 1, cell_inst_prop); + draw_box_properties_impl (drawing_context, new_ci, trans * t, new_vp, level + 1, cell_inst_prop, for_ghosts); } diff --git a/src/laybasic/laybasic/layRedrawThreadWorker.h b/src/laybasic/laybasic/layRedrawThreadWorker.h index a02b8637a..4f108c587 100644 --- a/src/laybasic/laybasic/layRedrawThreadWorker.h +++ b/src/laybasic/laybasic/layRedrawThreadWorker.h @@ -44,7 +44,8 @@ class CanvasPlane; // some helpful constants const int planes_per_layer = 12; -const int cell_box_planes = planes_per_layer; // for cell boxes +const int plain_cell_box_planes = planes_per_layer; // for cell boxes, not including ghost_cells +const int cell_box_planes = planes_per_layer * 2; // for cell boxes, including ghost cells const int guiding_shape_planes = planes_per_layer; // for guiding shapes const int special_planes_before = cell_box_planes + guiding_shape_planes; const int special_planes_after = 1; @@ -181,11 +182,15 @@ private: void draw_layer_wo_cache (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &vv, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot); void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level); void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, Bitmap *opt_bitmap); + void draw_boxes_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level); void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level); - void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level); + void draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level, bool for_ghosts); + void draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, bool for_ghosts); + void draw_box_properties_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level); void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level); - void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level, db::properties_id_type prop_id); - void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, db::properties_id_type prop_id); + void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level, bool for_ghosts); + void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &redraw_regions, int level, db::properties_id_type prop_id, bool for_ghosts); + void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, db::properties_id_type prop_id, bool for_ghosts); void draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, bool empty_cell, const std::string &txt); void draw_cell_properties (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, db::properties_id_type prop_id); void draw_cell_shapes (const db::CplxTrans &trans, const db::Cell &cell, const db::Box &vp, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text); @@ -199,7 +204,7 @@ private: bool any_shapes (db::cell_index_type cell_index, unsigned int levels); bool any_text_shapes (db::cell_index_type cell_index, unsigned int levels); bool any_cell_box (db::cell_index_type cell_index, unsigned int levels); - bool need_draw_box (const db::Layout *layout, const db::Cell &cell, int level); + bool need_draw_box (const db::Layout *layout, const db::Cell &cell, int level, bool for_ghosts); RedrawThread *mp_redraw_thread; std::vector m_redraw_region; From 19dc5e8edbb56c6e7a25e1405f46fd0902ca7ace Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Oct 2025 23:40:50 +0200 Subject: [PATCH 2/4] Implemented a solution for #2180 Implements a new option to show/hide unresolved references (ghost cells). The option is found in "Display/Cells" in the Setup dialog and also in the View menu. --- src/lay/lay/layMainWindow.cc | 1 + src/laybasic/laybasic/layLayoutViewBase.cc | 21 +++++++++++-- src/laybasic/laybasic/layLayoutViewBase.h | 14 +++++++++ src/laybasic/laybasic/layLayoutViewConfig.cc | 1 + .../laybasic/layRedrawThreadWorker.cc | 6 ++-- src/laybasic/laybasic/laybasicConfig.h | 1 + src/layui/layui/LayoutViewConfigPage2a.ui | 30 +++++++++++++++---- src/layui/layui/layLayoutViewConfigPages.cc | 8 +++-- 8 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 72430e410..8e4f976f0 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -4489,6 +4489,7 @@ public: menu_entries.push_back (lay::config_menu_item ("show_markers", at, tl::to_string (QObject::tr ("Show Markers")), cfg_markers_visible, "?")); menu_entries.push_back (lay::config_menu_item ("show_texts", at, tl::to_string (QObject::tr ("Show Texts")), cfg_text_visible, "?")); menu_entries.push_back (lay::config_menu_item ("show_cell_boxes", at, tl::to_string (QObject::tr ("Show Cell Frames")), cfg_cell_box_visible, "?")); + menu_entries.push_back (lay::config_menu_item ("show_ghost_cells", at, tl::to_string (QObject::tr ("Show Unresolved References")), cfg_ghost_cells_visible, "?")); menu_entries.push_back (lay::config_menu_item ("no_stipples", at, tl::to_string (QObject::tr ("Show Layers Without Fill")), cfg_no_stipple, "?")); menu_entries.push_back (lay::config_menu_item ("synchronized_views", at, tl::to_string (QObject::tr ("Synchronized Views")), cfg_synchronized_views, "?")); menu_entries.push_back (lay::config_menu_item ("edit_top_level_selection:edit_mode", at, tl::to_string (QObject::tr ("Select Top Level Objects")), edt::cfg_edit_top_level_selection, "?")); diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index f2ed75b5e..8877903bc 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -343,6 +343,7 @@ LayoutViewBase::init (db::Manager *mgr) m_box_font = 0; m_min_size_for_label = 16; m_cell_box_visible = true; + m_ghost_cells_visible = true; m_text_visible = true; m_default_font_size = lay::FixedFont::default_font_size (); m_text_lazy_rendering = true; @@ -958,6 +959,13 @@ LayoutViewBase::configure (const std::string &name, const std::string &value) cell_box_visible (flag); return true; + } else if (name == cfg_ghost_cells_visible) { + + bool flag; + tl::from_string (value, flag); + ghost_cells_visible (flag); + return true; + } else if (name == cfg_cell_box_color) { tl::Color color; @@ -4328,7 +4336,7 @@ LayoutViewBase::set_view_ops () } // ghost cells - if (m_cell_box_visible) { // @@@ + if (m_ghost_cells_visible) { lay::ViewOp vop, vopv; @@ -5422,7 +5430,16 @@ LayoutViewBase::cell_box_visible (bool vis) } } -void +void +LayoutViewBase::ghost_cells_visible (bool vis) +{ + if (m_ghost_cells_visible != vis) { + m_ghost_cells_visible = vis; + update_content (); + } +} + +void LayoutViewBase::text_font (unsigned int f) { if (m_text_font != f) { diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index eeda5619a..1799a5c20 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -1115,6 +1115,19 @@ public: return m_cell_box_visible; } + /** + * @brief Visibility of ghost cells + */ + void ghost_cells_visible (bool vis); + + /** + * @brief Visibility of ghost cells + */ + bool ghost_cells_visible () const + { + return m_ghost_cells_visible; + } + /** * @brief Min instance label size setter */ @@ -2910,6 +2923,7 @@ private: unsigned int m_box_font; int m_min_size_for_label; bool m_cell_box_visible; + bool m_ghost_cells_visible; tl::Color m_marker_color; int m_marker_line_width; diff --git a/src/laybasic/laybasic/layLayoutViewConfig.cc b/src/laybasic/laybasic/layLayoutViewConfig.cc index 30c161f77..7f7908bd8 100644 --- a/src/laybasic/laybasic/layLayoutViewConfig.cc +++ b/src/laybasic/laybasic/layLayoutViewConfig.cc @@ -59,6 +59,7 @@ public: options.push_back (std::pair (cfg_cell_box_text_transform, "true")); options.push_back (std::pair (cfg_cell_box_color, "auto")); options.push_back (std::pair (cfg_cell_box_visible, "true")); + options.push_back (std::pair (cfg_ghost_cells_visible, "true")); options.push_back (std::pair (cfg_text_color, "auto")); options.push_back (std::pair (cfg_text_visible, "true")); options.push_back (std::pair (cfg_text_lazy_rendering, "true")); diff --git a/src/laybasic/laybasic/layRedrawThreadWorker.cc b/src/laybasic/laybasic/layRedrawThreadWorker.cc index fe1275a41..d8a332b50 100644 --- a/src/laybasic/laybasic/layRedrawThreadWorker.cc +++ b/src/laybasic/laybasic/layRedrawThreadWorker.cc @@ -841,7 +841,7 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c // paint the box on this level draw_cell (drawing_context, level, trans, bbox, empty_cell, mp_layout->display_name (ci)); - } else if (! for_ghosts && (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_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, empty_cell, mp_layout->display_name (ci)); @@ -1003,7 +1003,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty void RedrawThreadWorker::draw_box_properties_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector &vp, int level) { - draw_box_properties_impl (drawing_context, ci, trans, vp, level, false); + draw_box_properties_impl (drawing_context, ci, trans, vp, level, true); } void @@ -1057,7 +1057,7 @@ RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_ind // paint the box on this level draw_cell_properties (drawing_context, level, trans, bbox, prop_id); - } else if (! for_ghosts && (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_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); diff --git a/src/laybasic/laybasic/laybasicConfig.h b/src/laybasic/laybasic/laybasicConfig.h index 47ec7a75f..681c3c8ac 100644 --- a/src/laybasic/laybasic/laybasicConfig.h +++ b/src/laybasic/laybasic/laybasicConfig.h @@ -95,6 +95,7 @@ static const std::string cfg_cell_box_text_font ("inst-label-font"); static const std::string cfg_cell_box_text_transform ("inst-label-transform"); static const std::string cfg_cell_box_color ("inst-color"); static const std::string cfg_cell_box_visible ("inst-visible"); +static const std::string cfg_ghost_cells_visible ("ghost-cells-visible"); static const std::string cfg_text_color ("text-color"); static const std::string cfg_text_visible ("text-visible"); static const std::string cfg_text_lazy_rendering ("text-lazy-rendering"); diff --git a/src/layui/layui/LayoutViewConfigPage2a.ui b/src/layui/layui/LayoutViewConfigPage2a.ui index 2f4e6911a..23bc34c44 100644 --- a/src/layui/layui/LayoutViewConfigPage2a.ui +++ b/src/layui/layui/LayoutViewConfigPage2a.ui @@ -6,8 +6,8 @@ 0 0 - 631 - 320 + 656 + 397 @@ -21,13 +21,33 @@ 9 - - + + Show cell boxes - + true + + + + + + Show unresolved references (ghost cells) + + + true + + + + + + + Cell box appearance + + + false + 9 diff --git a/src/layui/layui/layLayoutViewConfigPages.cc b/src/layui/layui/layLayoutViewConfigPages.cc index da43a394e..55a766913 100644 --- a/src/layui/layui/layLayoutViewConfigPages.cc +++ b/src/layui/layui/layLayoutViewConfigPages.cc @@ -207,7 +207,10 @@ LayoutViewConfigPage2a::setup (lay::Dispatcher *root) mp_ui->cell_xform_text_cbx->setChecked (flag); root->config_get (cfg_cell_box_visible, flag); - mp_ui->cell_group->setChecked (flag); + mp_ui->cell_boxes_visible->setChecked (flag); + + root->config_get (cfg_ghost_cells_visible, flag); + mp_ui->ghost_cells_visible->setChecked (flag); int font = 0; root->config_get (cfg_cell_box_text_font, font); @@ -247,7 +250,8 @@ LayoutViewConfigPage2a::commit (lay::Dispatcher *root) root->config_set (cfg_cell_box_text_transform, mp_ui->cell_xform_text_cbx->isChecked ()); root->config_set (cfg_cell_box_text_font, mp_ui->cell_font_cb->currentIndex ()); root->config_set (cfg_cell_box_color, mp_ui->cell_box_color_pb->get_color (), ColorConverter ()); - root->config_set (cfg_cell_box_visible, mp_ui->cell_group->isChecked ()); + root->config_set (cfg_cell_box_visible, mp_ui->cell_boxes_visible->isChecked ()); + root->config_set (cfg_ghost_cells_visible, mp_ui->ghost_cells_visible->isChecked ()); root->config_set (cfg_guiding_shape_visible, mp_ui->pcell_gs_group->isChecked ()); root->config_set (cfg_guiding_shape_line_width, mp_ui->pcell_gs_lw->value ()); From 6746dad08a0f1436eb95a1df1b82cbf5d7fc7531 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 19 Oct 2025 19:39:46 +0200 Subject: [PATCH 3/4] Fixed display of markers for ghost cells in viewer mode --- src/edt/edt/edtService.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index ceab2f786..8dbabaf7e 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -1208,7 +1208,7 @@ Service::transient_select (const db::DPoint &pos) // In viewer mode, individual instances of arrays can be selected. Since that is not supported by // InstanceMarker, we just indicate the individual instance's bounding box. lay::Marker *marker = new lay::Marker (view (), r->cv_index ()); - db::box_convert bc (cv->layout ()); + db::box_convert bc (cv->layout ()); marker->set (bc (r->back ().inst_ptr.cell_inst ().object ()), gt * r->back ().inst_ptr.cell_inst ().complex_trans (*r->back ().array_inst), tv); marker->set_vertex_size (view ()->default_transient_marker_vertex_size ()); marker->set_line_width (view ()->default_transient_marker_line_width ()); @@ -1806,7 +1806,7 @@ Service::do_selection_to_view () if (r->seq () > 0 && m_indicate_secondary_selection) { marker->set_dither_pattern (3); } - db::box_convert bc (cv->layout ()); + db::box_convert bc (cv->layout ()); marker->set (bc (r->back ().inst_ptr.cell_inst ().object ()), gt * r->back ().inst_ptr.cell_inst ().complex_trans (*r->back ().array_inst), *tv_list); m_markers.push_back (std::make_pair (r.operator-> (), marker)); From a1d6ff9a3cb9bb72a1c331db9d7e1faa5ee32880 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 20 Oct 2025 22:57:03 +0200 Subject: [PATCH 4/4] Selectability follows visibility --- src/edt/edt/edtService.cc | 4 ++++ src/laybasic/laybasic/layFinder.cc | 30 ++++++++++++++++++++---------- src/laybasic/laybasic/layFinder.h | 13 +++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 8dbabaf7e..e9fd9b520 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -1159,6 +1159,8 @@ Service::transient_select (const db::DPoint &pos) if (m_cell_inst_service) { lay::InstFinder finder (true, view ()->is_editable () && m_top_level_sel, view ()->is_editable () /*full arrays in editable mode*/, true /*enclose instances*/, &m_previous_selection, true /*visible layers only*/); + finder.consider_ghost_cells (view ()->ghost_cells_visible ()); + finder.consider_normal_cells (view ()->cell_box_visible ()); // go through all transform variants std::set< std::pair > variants = view ()->cv_transform_variants_with_empty (); @@ -1493,6 +1495,8 @@ Service::select (const db::DBox &box, lay::Editable::SelectionMode mode) } else if (m_cell_inst_service) { lay::InstFinder finder (box.is_point (), view ()->is_editable () && m_top_level_sel, view ()->is_editable () /*full arrays in editable mode*/, true /*enclose_inst*/, exclude, true /*only visible layers*/); + finder.consider_ghost_cells (view ()->ghost_cells_visible ()); + finder.consider_normal_cells (view ()->cell_box_visible ()); // go through all cell views std::set< std::pair > variants = view ()->cv_transform_variants_with_empty (); diff --git a/src/laybasic/laybasic/layFinder.cc b/src/laybasic/laybasic/layFinder.cc index 72884fa33..f3083e2d8 100644 --- a/src/laybasic/laybasic/layFinder.cc +++ b/src/laybasic/laybasic/layFinder.cc @@ -721,6 +721,8 @@ InstFinder::InstFinder (bool point_mode, bool top_level_sel, bool full_arrays, b m_full_arrays (full_arrays), m_enclose_insts (enclose_inst), m_visible_layers (visible_layers), + m_consider_ghost_cells (true), + m_consider_normal_cells (true), mp_view (0), mp_progress (0) { @@ -805,6 +807,12 @@ InstFinder::checkpoint () } } +bool +InstFinder::consider_cell (const db::Cell &cell) const +{ + return cell.is_ghost_cell () ? m_consider_ghost_cells : m_consider_normal_cells; +} + void InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const db::Box & /*scan_box*/, const db::DCplxTrans &vp, const db::ICplxTrans &t, int level) { @@ -818,15 +826,18 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d ++*mp_progress; // look for instances to check here .. - db::Cell::touching_iterator inst = cell.begin_touching (search_box); - while (! inst.at_end ()) { + for (db::Cell::touching_iterator inst = cell.begin_touching (search_box); ! inst.at_end (); ++inst) { const db::CellInstArray &cell_inst = inst->cell_inst (); const db::Cell &inst_cell = layout ().cell (cell_inst.object ().cell_index ()); ++*mp_progress; - // just consider the instances exactly at the last level of + if (! consider_cell (inst_cell)) { + continue; + } + + // 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)) { @@ -887,21 +898,22 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d } - ++inst; - } } else { // look for instances to check here .. - db::Cell::touching_iterator inst = cell.begin_touching (search_box); - while (! inst.at_end ()) { + for (db::Cell::touching_iterator inst = cell.begin_touching (search_box); ! inst.at_end (); ++inst) { checkpoint (); const db::CellInstArray &cell_inst = inst->cell_inst (); const db::Cell &inst_cell = layout ().cell (cell_inst.object ().cell_index ()); + if (! consider_cell (inst_cell)) { + continue; + } + // 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. @@ -909,7 +921,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d db::box_convert bc (layout ()); for (db::CellInstArray::iterator p = cell_inst.begin_touching (search_box, bc); ! p.at_end (); ++p) { - + checkpoint (); bool match = false; @@ -1000,8 +1012,6 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d } - ++inst; - } } diff --git a/src/laybasic/laybasic/layFinder.h b/src/laybasic/laybasic/layFinder.h index d93e0c9f1..f0ecdcc46 100644 --- a/src/laybasic/laybasic/layFinder.h +++ b/src/laybasic/laybasic/layFinder.h @@ -343,7 +343,17 @@ public: bool find (LayoutViewBase *view, unsigned int cv_index, const db::DCplxTrans &trans, const db::DBox ®ion_mu); bool find (LayoutViewBase *view, const db::DBox ®ion_mu); + + void consider_ghost_cells (bool f) + { + m_consider_ghost_cells = f; + } + void consider_normal_cells (bool f) + { + m_consider_normal_cells = f; + } + iterator begin () const { return m_founds.begin (); @@ -360,6 +370,7 @@ private: virtual void visit_cell (const db::Cell &cell, const db::Box &hit_box, const db::Box &scan_box, const db::DCplxTrans &vp, const db::ICplxTrans &t, int level); bool find_internal (LayoutViewBase *view, unsigned int cv_index, const db::DCplxTrans &trans_mu, const db::DBox ®ion_mu); + bool consider_cell (const db::Cell &cell) const; unsigned int m_cv_index; db::cell_index_type m_topcell; @@ -369,6 +380,8 @@ private: bool m_full_arrays; bool m_enclose_insts; bool m_visible_layers; + bool m_consider_ghost_cells; + bool m_consider_normal_cells; std::vector m_visible_layer_indexes; LayoutViewBase *mp_view; tl::AbsoluteProgress *mp_progress;