diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc index c079103cb..75fdfa989 100644 --- a/src/edt/edt/edtPartialService.cc +++ b/src/edt/edt/edtPartialService.cc @@ -2412,127 +2412,131 @@ PartialService::selection_to_view () } - // build the transformation variants cache - TransformationVariants tv (view ()); - size_t n_marker = 0; size_t n_inst_marker = 0; - for (partial_objects::const_iterator r = m_selection.begin (); r != m_selection.end (); ++r) { + if (! m_selection.empty ()) { - const lay::CellView &cv = view ()->cellview (r->first.cv_index ()); + // build the transformation variants cache + TransformationVariants tv (view ()); - if (! r->first.is_cell_inst ()) { + for (partial_objects::const_iterator r = m_selection.begin (); r != m_selection.end (); ++r) { - const std::vector *tv_list = tv.per_cv_and_layer (r->first.cv_index (), r->first.layer ()); - if (tv_list && !tv_list->empty ()) { + const lay::CellView &cv = view ()->cellview (r->first.cv_index ()); - // use only the first one of the explicit transformations - // TODO: clarify how this can be implemented in a more generic form or leave it thus. - db::ICplxTrans gt (cv.context_trans () * r->first.trans ()); - db::CplxTrans tt = (*tv_list) [0] * db::CplxTrans (cv->layout ().dbu ()) * gt; - db::Vector move_vector (tt.inverted () * (move_trans * (tt * db::Point ()))); + if (! r->first.is_cell_inst ()) { - // create the shift sets describing how points and edges are being moved - - std::map new_edges; - std::map new_points; + const std::vector *tv_list = tv.per_cv_and_layer (r->first.cv_index (), r->first.layer ()); + if (tv_list && !tv_list->empty ()) { - if (m_dragging) { - create_shift_sets (r->first.shape (), r->second, new_points, new_edges, move_vector); - } + // use only the first one of the explicit transformations + // TODO: clarify how this can be implemented in a more generic form or leave it thus. + db::ICplxTrans gt (cv.context_trans () * r->first.trans ()); + db::CplxTrans tt = (*tv_list) [0] * db::CplxTrans (cv->layout ().dbu ()) * gt; + db::Vector move_vector (tt.inverted () * (move_trans * (tt * db::Point ()))); - // create the markers to represent vertices and edges + // create the shift sets describing how points and edges are being moved - enter_vertices (n_marker, r, new_points, new_edges, gt, *tv_list, false); + std::map new_edges; + std::map new_points; - if (r->first.shape ().is_polygon ()) { + if (m_dragging) { + create_shift_sets (r->first.shape (), r->second, new_points, new_edges, move_vector); + } - for (unsigned int c = 0; c < r->first.shape ().holes () + 1; ++c) { + // create the markers to represent vertices and edges + enter_vertices (n_marker, r, new_points, new_edges, gt, *tv_list, false); + + if (r->first.shape ().is_polygon ()) { + + for (unsigned int c = 0; c < r->first.shape ().holes () + 1; ++c) { + + unsigned int n = 0; + db::Shape::polygon_edge_iterator ee; + for (db::Shape::polygon_edge_iterator e = r->first.shape ().begin_edge (c); ! e.at_end (); e = ee, ++n) { + ee = e; + ++ee; + unsigned int nn = ee.at_end () ? 0 : n + 1; + enter_edge (EdgeWithIndex (*e, n, nn, c), n_marker, r, new_points, new_edges, gt, *tv_list, false); + } + + } + + db::Polygon poly; + r->first.shape ().polygon (poly); + + // warning: poly is modified: + enter_polygon (poly, n_marker, r, new_points, new_edges, gt, *tv_list, false); + + } else if (r->first.shape ().is_path ()) { + + if (r->first.shape ().begin_point () != r->first.shape ().end_point ()) { + + db::Shape::point_iterator pt = r->first.shape ().begin_point (); + db::Point p1 = *pt; + + unsigned int n = 0; + while (true) { + + ++pt; + if (pt == r->first.shape ().end_point ()) { + break; + } + + enter_edge (EdgeWithIndex (db::Edge (p1, *pt), n, n + 1, 0), n_marker, r, new_points, new_edges, gt, *tv_list, false); + + p1 = *pt; + ++n; + + } + + // TODO: ... put this somewhere else: + db::Path path; + r->first.shape ().path (path); + + // warning: path is modified: + enter_path (path, n_marker, r, new_points, new_edges, gt, *tv_list, false); + + } + + } else if (r->first.shape ().is_box ()) { + + // convert to polygon and test those edges + db::Polygon poly (r->first.shape ().box ()); unsigned int n = 0; db::Shape::polygon_edge_iterator ee; - for (db::Shape::polygon_edge_iterator e = r->first.shape ().begin_edge (c); ! e.at_end (); e = ee, ++n) { + for (db::Shape::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); e = ee, ++n) { ee = e; ++ee; unsigned int nn = ee.at_end () ? 0 : n + 1; - enter_edge (EdgeWithIndex (*e, n, nn, c), n_marker, r, new_points, new_edges, gt, *tv_list, false); + enter_edge (EdgeWithIndex (*e, n, nn, 0), n_marker, r, new_points, new_edges, gt, *tv_list, false); } - } + // warning: poly is modified: + enter_polygon (poly, n_marker, r, new_points, new_edges, gt, *tv_list, false); - db::Polygon poly; - r->first.shape ().polygon (poly); + } else if (r->first.shape ().is_text ()) { - // warning: poly is modified: - enter_polygon (poly, n_marker, r, new_points, new_edges, gt, *tv_list, false); - - } else if (r->first.shape ().is_path ()) { - - if (r->first.shape ().begin_point () != r->first.shape ().end_point ()) { - - db::Shape::point_iterator pt = r->first.shape ().begin_point (); - db::Point p1 = *pt; - - unsigned int n = 0; - while (true) { - - ++pt; - if (pt == r->first.shape ().end_point ()) { - break; - } - - enter_edge (EdgeWithIndex (db::Edge (p1, *pt), n, n + 1, 0), n_marker, r, new_points, new_edges, gt, *tv_list, false); - - p1 = *pt; - ++n; - - } - - // TODO: ... put this somewhere else: - db::Path path; - r->first.shape ().path (path); - - // warning: path is modified: - enter_path (path, n_marker, r, new_points, new_edges, gt, *tv_list, false); + db::Point tp (r->first.shape ().text_trans () * db::Point ()); + enter_edge (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0), n_marker, r, new_points, new_edges, gt, *tv_list, false); } - } else if (r->first.shape ().is_box ()) { - - // convert to polygon and test those edges - db::Polygon poly (r->first.shape ().box ()); - unsigned int n = 0; - db::Shape::polygon_edge_iterator ee; - for (db::Shape::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); e = ee, ++n) { - ee = e; - ++ee; - unsigned int nn = ee.at_end () ? 0 : n + 1; - enter_edge (EdgeWithIndex (*e, n, nn, 0), n_marker, r, new_points, new_edges, gt, *tv_list, false); - } - - // warning: poly is modified: - enter_polygon (poly, n_marker, r, new_points, new_edges, gt, *tv_list, false); - - } else if (r->first.shape ().is_text ()) { - - db::Point tp (r->first.shape ().text_trans () * db::Point ()); - enter_edge (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0), n_marker, r, new_points, new_edges, gt, *tv_list, false); - } - } + } else { - } else { + // compute the global transformation including movement, context and explicit transformation + db::ICplxTrans gt = db::VCplxTrans (1.0 / cv->layout ().dbu ()) * db::DCplxTrans (move_trans) * db::CplxTrans (cv->layout ().dbu ()); + gt *= (cv.context_trans () * r->first.trans ()); - // compute the global transformation including movement, context and explicit transformation - db::ICplxTrans gt = db::VCplxTrans (1.0 / cv->layout ().dbu ()) * db::DCplxTrans (move_trans) * db::CplxTrans (cv->layout ().dbu ()); - gt *= (cv.context_trans () * r->first.trans ()); + const std::vector *tv_list = tv.per_cv (r->first.cv_index ()); + if (tv_list && ! tv_list->empty ()) { + lay::InstanceMarker *marker = new_inst_marker (n_inst_marker, r->first.cv_index (), false); + marker->set (r->first.back ().inst_ptr, gt, *tv_list); + } - const std::vector *tv_list = tv.per_cv (r->first.cv_index ()); - if (tv_list && ! tv_list->empty ()) { - lay::InstanceMarker *marker = new_inst_marker (n_inst_marker, r->first.cv_index (), false); - marker->set (r->first.back ().inst_ptr, gt, *tv_list); } } diff --git a/src/laybasic/laybasic/layCellView.cc b/src/laybasic/laybasic/layCellView.cc index dafded284..af6c5e947 100644 --- a/src/laybasic/laybasic/layCellView.cc +++ b/src/laybasic/laybasic/layCellView.cc @@ -501,13 +501,13 @@ CellView::is_valid () const } // check, if the path references valid cell indices. - for (specific_cell_path_type::const_iterator pp = m_specific_path.begin (); pp != m_specific_path.end (); ++pp) { - if (! m_layout_href.get ()->layout ().is_valid_cell_index (pp->inst_ptr.cell_index ())) { + for (unspecific_cell_path_type::const_iterator pp = m_unspecific_path.begin (); pp != m_unspecific_path.end (); ++pp) { + if (! m_layout_href.get ()->layout ().is_valid_cell_index (*pp)) { return false; } } - for (unspecific_cell_path_type::const_iterator pp = m_unspecific_path.begin (); pp != m_unspecific_path.end (); ++pp) { - if (! m_layout_href.get ()->layout ().is_valid_cell_index (*pp)) { + for (specific_cell_path_type::const_iterator pp = m_specific_path.begin (); pp != m_specific_path.end (); ++pp) { + if (! pp->inst_ptr.instances () || ! pp->inst_ptr.instances ()->is_valid (pp->inst_ptr) || ! m_layout_href.get ()->layout ().is_valid_cell_index (pp->inst_ptr.cell_index ())) { return false; } } diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.cc b/src/laybasic/laybasic/layHierarchyControlPanel.cc index 5fe8ea03c..ea6befe14 100644 --- a/src/laybasic/laybasic/layHierarchyControlPanel.cc +++ b/src/laybasic/laybasic/layHierarchyControlPanel.cc @@ -836,6 +836,8 @@ HierarchyControlPanel::do_update_content (int cv_index) if (&m_cellviews [i]->layout () != &mp_view->cellview (i)->layout ()) { m_needs_update [i] = true; m_force_close [i] = true; + } else if (! m_cellviews [i].is_valid ()) { + m_needs_update [i] = true; } else if (m_cellviews [i].combined_unspecific_path () != mp_view->cellview (i).combined_unspecific_path ()) { m_needs_update [i] = true; } diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index aa4c9a3f2..3a2686bfa 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -4896,6 +4896,7 @@ LayoutView::select_cell_fit (const cell_path_type &path, int index) set_min_hier_levels (0); cancel (); + cellview_iter (index)->set_specific_path (lay::CellView::specific_cell_path_type ()); cellview_iter (index)->set_unspecific_path (path); set_active_cellview_index (index); redraw (); @@ -4985,6 +4986,7 @@ LayoutView::select_cell (const cell_path_type &path, int index) set_min_hier_levels (0); cancel (); + cellview_iter (index)->set_specific_path (lay::CellView::specific_cell_path_type ()); cellview_iter (index)->set_unspecific_path (path); set_active_cellview_index (index); redraw (); diff --git a/src/laybasic/laybasic/layLayoutViewFunctions.cc b/src/laybasic/laybasic/layLayoutViewFunctions.cc index a8b739a4b..060cd7b1e 100644 --- a/src/laybasic/laybasic/layLayoutViewFunctions.cc +++ b/src/laybasic/laybasic/layLayoutViewFunctions.cc @@ -42,6 +42,41 @@ namespace lay { +static void +collect_cells_to_delete (const db::Layout &layout, const db::Cell &cell, std::set &called) +{ + // don't delete proxies - they are deleted later when the layout is cleaned + for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); ! cc.at_end (); ++cc) { + if (called.find (*cc) == called.end () && !layout.cell (*cc).is_proxy ()) { + called.insert (*cc); + collect_cells_to_delete (layout, layout.cell (*cc), called); + } + } +} + +static bool +validate_cell_path (const db::Layout &layout, lay::LayoutView::cell_path_type &path) +{ + for (size_t i = 0; i < path.size (); ++i) { + + if (! layout.is_valid_cell_index (path [i])) { + + if (layout.is_valid_cell_index (path.back ())) { + // use a stub path + path.erase (path.begin (), --path.end ()); + } else { + // strip everything that is not valid + path.erase (path.begin () + i, path.end ()); + } + + return true; + + } + } + + return false; +} + LayoutViewFunctions::LayoutViewFunctions (db::Manager *manager, LayoutView *view) : lay::Plugin (view), mp_view (view), mp_manager (manager) { @@ -493,18 +528,7 @@ LayoutViewFunctions::cm_cell_replace () view ()->commit (); - // If one of the cells in the path was deleted, establish a valid path - - bool needs_update = false; - for (size_t i = cell_path.size (); i > 0; ) { - --i; - if (! layout.is_valid_cell_index (cell_path [i])) { - cell_path.erase (cell_path.begin () + i, cell_path.end ()); - needs_update = true; - } - } - - if (needs_update) { + if (validate_cell_path (layout, cell_path)) { view ()->select_cell (cell_path, cv_index); } @@ -613,36 +637,13 @@ LayoutViewFunctions::cm_cell_convert_to_static () view ()->commit (); - // If one of the cells in the path was deleted, establish a valid path - - bool needs_update = false; - for (size_t i = cell_path.size (); i > 0; ) { - --i; - if (! layout.is_valid_cell_index (cell_path [i])) { - cell_path.erase (cell_path.begin () + i, cell_path.end ()); - needs_update = true; - } - } - - if (needs_update) { + if (validate_cell_path (layout, cell_path)) { view ()->select_cell (cell_path, cv_index); } } } -static void -collect_cells_to_delete (const db::Layout &layout, const db::Cell &cell, std::set &called) -{ - // don't delete proxies - they are deleted later when the layout is cleaned - for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); ! cc.at_end (); ++cc) { - if (called.find (*cc) == called.end () && !layout.cell (*cc).is_proxy ()) { - called.insert (*cc); - collect_cells_to_delete (layout, layout.cell (*cc), called); - } - } -} - void LayoutViewFunctions::cm_cell_delete () { @@ -704,18 +705,7 @@ LayoutViewFunctions::cm_cell_delete () view ()->commit (); - // If one of the cells in the path was deleted, establish a valid path - - bool needs_update = false; - for (size_t i = cell_path.size (); i > 0; ) { - --i; - if (! layout.is_valid_cell_index (cell_path [i])) { - cell_path.erase (cell_path.begin () + i, cell_path.end ()); - needs_update = true; - } - } - - if (needs_update) { + if (validate_cell_path (layout, cell_path)) { view ()->select_cell (cell_path, cv_index); }