diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 021b9058e..8f09cf238 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1884,6 +1884,26 @@ Layout::is_pcell_instance (cell_index_type cell_index) const } } +const Layout::pcell_declaration_type * +Layout::pcell_declaration_for_pcell_variant (cell_index_type variant_cell_index) const +{ + const Cell *variant_cell = &cell (variant_cell_index); + + const LibraryProxy *lib_proxy = dynamic_cast (variant_cell); + if (lib_proxy) { + Library *lib = LibraryManager::instance ().lib (lib_proxy->lib_id ()); + tl_assert (lib != 0); + return lib->layout ().pcell_declaration_for_pcell_variant (lib_proxy->library_cell_index ()); + } + + const PCellVariant *pcell_variant = dynamic_cast (variant_cell); + if (pcell_variant) { + return pcell_declaration (pcell_variant->pcell_id ()); + } else { + return 0; + } +} + std::pair Layout::defining_library (cell_index_type cell_index) const { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 4a8a4222e..2506b0558 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -881,11 +881,22 @@ public: */ std::pair defining_library (cell_index_type cell_index) const; + /** + * @brief Gets the PCell declaration object for a PCell instance + * + * This method determines the PCell declaration object for a given PCell variant cell. + * Note, that the declaration may originate from a different layout than this, if the PCell + * is imported from a library. + * + * The cell given cell is not a PCell variant cell, 0 is returned. + */ + const Layout::pcell_declaration_type *pcell_declaration_for_pcell_variant (cell_index_type cell_index) const; + /** * @brief Get the PCell parameters of a PCell instance * * For the order of the parameters, ask the PCell declaration (available trough Layout::pcell_declaration - * from the PCell id). + * from the PCell id or from Layout::pcell_declaration_for_pcell_variant from the cell_index). * * @return A list of parameters in the order they are declared. */ diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index deb4f88cb..59bf0a572 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -1906,12 +1906,10 @@ MainService::cm_change_layer () // get (common) cellview index of the selected shapes for (std::vector::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { - if (! s->is_cell_inst ()) { - if (cv_index >= 0 && cv_index != int (s->cv_index ())) { - throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case."))); - } - cv_index = int (s->cv_index ()); + if (cv_index >= 0 && cv_index != int (s->cv_index ())) { + throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case."))); } + cv_index = int (s->cv_index ()); } } @@ -1975,17 +1973,58 @@ MainService::cm_change_layer () // Insert and delete the shape. This exploits the fact, that a shape can be erased multiple times - // this is important since the selection potentially contains the same shape multiple times. for (std::vector::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { + for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { + if (!s->is_cell_inst () && int (s->layer ()) != layer) { + db::Cell &cell = layout.cell (s->cell_index ()); if (cell.shapes (s->layer ()).is_valid (s->shape ())) { cell.shapes (layer).insert (s->shape ()); cell.shapes (s->layer ()).erase_shape (s->shape ()); } + + } else if (s->is_cell_inst ()) { + + // If the selected object is a PCell instance, and there is exactly one visible, writable layer type parameter, change this one + + db::Instance inst = s->back ().inst_ptr; + db::Cell &cell = layout.cell (s->cell_index ()); + + if (cell.is_valid (inst)) { + + const db::PCellDeclaration *pcell_decl = layout.pcell_declaration_for_pcell_variant (inst.cell_index ()); + if (pcell_decl) { + + size_t layer_par_index = 0; + int n_layer_par = 0; + for (std::vector::const_iterator d = pcell_decl->parameter_declarations ().begin (); d != pcell_decl->parameter_declarations ().end () && n_layer_par < 2; ++d) { + if (d->get_type () == db::PCellParameterDeclaration::t_layer && !d->is_hidden () && !d->is_readonly ()) { + ++n_layer_par; + layer_par_index = size_t (d - pcell_decl->parameter_declarations ().begin ()); + } + } + + if (n_layer_par == 1) { + std::vector parameters = cell.get_pcell_parameters (inst); + tl_assert (layer_par_index < parameters.size ()); + parameters [layer_par_index] = layout.get_properties (layer); + cell.change_pcell_parameters (inst, parameters); + } + + } + + } + } + } + } + // remove superfluous proxies + layout.cleanup (); + // The selection is no longer valid view ()->clear_selection ();