Merge branch 'issue-691'

This commit is contained in:
Matthias Koefferlein 2020-12-20 19:25:31 +01:00
commit 866ac7ec76
39 changed files with 1611 additions and 378 deletions

View File

@ -19,6 +19,7 @@ SOURCES = \
dbClipboard.cc \ dbClipboard.cc \
dbClipboardData.cc \ dbClipboardData.cc \
dbClip.cc \ dbClip.cc \
dbColdProxy.cc \
dbCommonReader.cc \ dbCommonReader.cc \
dbEdge.cc \ dbEdge.cc \
dbEdgePair.cc \ dbEdgePair.cc \
@ -214,6 +215,7 @@ HEADERS = \
dbClipboardData.h \ dbClipboardData.h \
dbClipboard.h \ dbClipboard.h \
dbClip.h \ dbClip.h \
dbColdProxy.h \
dbCommonReader.h \ dbCommonReader.h \
dbEdge.h \ dbEdge.h \
dbEdgePair.h \ dbEdgePair.h \

128
src/db/db/dbColdProxy.cc Normal file
View File

@ -0,0 +1,128 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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 "dbColdProxy.h"
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbLayout.h"
#include "dbLayoutUtils.h"
#include "tlThreads.h"
namespace db
{
static tl::Mutex s_map_mutex;
static std::map<std::string, tl::weak_collection<ColdProxy> > s_proxies_per_library_name;
const tl::weak_collection<ColdProxy> &
ColdProxy::cold_proxies_per_lib_name (const std::string &libname)
{
tl::MutexLocker locker (&s_map_mutex);
std::map<std::string, tl::weak_collection<ColdProxy> >::const_iterator i = s_proxies_per_library_name.find (libname);
if (i != s_proxies_per_library_name.end ()) {
return i->second;
} else {
static tl::weak_collection<ColdProxy> s_empty;
return s_empty;
}
}
ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info)
: Cell (ci, layout), mp_context_info (new ProxyContextInfo (info))
{
if (! info.lib_name.empty ()) {
tl::MutexLocker locker (&s_map_mutex);
s_proxies_per_library_name [info.lib_name].push_back (this);
}
}
ColdProxy::~ColdProxy ()
{
delete mp_context_info;
mp_context_info = 0;
}
Cell *
ColdProxy::clone (Layout &layout) const
{
Cell *cell = new ColdProxy (db::Cell::cell_index (), layout, *mp_context_info);
// copy the cell content
*cell = *this;
return cell;
}
std::string
ColdProxy::get_basic_name () const
{
if (! mp_context_info->pcell_name.empty ()) {
return "<defunct>" + mp_context_info->pcell_name;
} else if (! mp_context_info->cell_name.empty ()) {
return "<defunct>" + mp_context_info->cell_name;
} else {
return Cell::get_basic_name ();
}
}
std::string
ColdProxy::get_display_name () const
{
if (! mp_context_info->lib_name.empty ()) {
std::string stem = "<defunct>" + mp_context_info->lib_name + ".";
if (! mp_context_info->pcell_name.empty ()) {
return stem + mp_context_info->pcell_name;
} else if (! mp_context_info->cell_name.empty ()) {
return stem + mp_context_info->cell_name;
} else {
return stem + "<unknown>";
}
} else {
return Cell::get_display_name ();
}
}
std::string
ColdProxy::get_qualified_name () const
{
if (! mp_context_info->lib_name.empty ()) {
std::string stem = "<defunct>" + mp_context_info->lib_name + ".";
if (! mp_context_info->pcell_name.empty ()) {
if (mp_context_info->pcell_parameters.empty ()) {
return stem + mp_context_info->pcell_name;
} else {
// TODO: list parameters? Might be long.
return stem + mp_context_info->pcell_name + "(...)";
}
} else if (! mp_context_info->cell_name.empty ()) {
return stem + mp_context_info->cell_name;
} else {
return stem + "<unknown>";
}
} else {
return Cell::get_qualified_name ();
}
}
}

111
src/db/db/dbColdProxy.h Normal file
View File

@ -0,0 +1,111 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_dbColdProxy
#define HDR_dbColdProxy
#include "dbCommon.h"
#include "dbTypes.h"
#include "dbCell.h"
#include "tlObject.h"
namespace db
{
struct ProxyContextInfo;
/**
* @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope
*
* If a PCell or library cell gets disconnected - for example, because the technology has changed or during
* development of PCell code - this proxy replaces the original one. It stores the connection information, so
* it can be regenerated when it becomes valid again.
*/
class DB_PUBLIC ColdProxy
: public Cell, public tl::Object
{
public:
/**
* @brief The constructor
*
* Creates a cold proxy represented by the ProxyContextInfo data.
*/
ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info);
/**
* @brief The destructor
*/
~ColdProxy ();
/**
* @brief Cloning
*/
virtual Cell *clone (Layout &layout) const;
/**
* @brief Get the library id
*/
const ProxyContextInfo &context_info () const
{
return *mp_context_info;
}
/**
* @brief Indicates that this cell is a proxy cell
*/
virtual bool is_proxy () const
{
return true;
}
/**
* @brief Gets a list of cold proxies for a given library name
*/
static const tl::weak_collection<ColdProxy> &cold_proxies_per_lib_name (const std::string &libname);
/**
* @brief Gets the basic name
*/
virtual std::string get_basic_name () const;
/**
* @brief Gets the display name
*/
virtual std::string get_display_name () const;
/**
* @brief Gets the qualified name
*/
virtual std::string get_qualified_name () const;
private:
ProxyContextInfo *mp_context_info;
};
}
#endif

View File

@ -24,11 +24,13 @@
#include "dbLayout.h" #include "dbLayout.h"
#include "dbMemStatistics.h" #include "dbMemStatistics.h"
#include "dbTrans.h" #include "dbTrans.h"
#include "dbTechnology.h"
#include "dbShapeRepository.h" #include "dbShapeRepository.h"
#include "dbPCellHeader.h" #include "dbPCellHeader.h"
#include "dbPCellVariant.h" #include "dbPCellVariant.h"
#include "dbPCellDeclaration.h" #include "dbPCellDeclaration.h"
#include "dbLibraryProxy.h" #include "dbLibraryProxy.h"
#include "dbColdProxy.h"
#include "dbLibraryManager.h" #include "dbLibraryManager.h"
#include "dbLibrary.h" #include "dbLibrary.h"
#include "dbRegion.h" #include "dbRegion.h"
@ -84,6 +86,27 @@ private:
db::properties_id_type m_from, m_to; db::properties_id_type m_from, m_to;
}; };
struct SetLayoutTechName
: public LayoutOp
{
SetLayoutTechName (const std::string &from, const std::string &to)
: m_from (from), m_to (to)
{ }
virtual void redo (db::Layout *layout) const
{
layout->set_technology_name_without_update (m_to);
}
virtual void undo (db::Layout *layout) const
{
layout->set_technology_name_without_update (m_from);
}
private:
std::string m_from, m_to;
};
struct SetLayoutDBU struct SetLayoutDBU
: public LayoutOp : public LayoutOp
{ {
@ -259,6 +282,65 @@ LayerIterator::operator*() const
return std::pair<unsigned int, const db::LayerProperties *> (m_layer_index, &m_layout.get_properties (m_layer_index)); return std::pair<unsigned int, const db::LayerProperties *> (m_layer_index, &m_layout.get_properties (m_layer_index));
} }
// -----------------------------------------------------------------
// Implementation of the ProxyContextInfo class
ProxyContextInfo
ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to)
{
ProxyContextInfo info;
for (std::vector<std::string>::const_iterator i = from; i != to; ++i) {
tl::Extractor ex (i->c_str ());
if (ex.test ("LIB=")) {
info.lib_name = ex.skip ();
} else if (ex.test ("P(")) {
std::pair<std::string, tl::Variant> vv;
ex.read_word_or_quoted (vv.first);
ex.test (")");
ex.test ("=");
ex.read (vv.second);
info.pcell_parameters.insert (vv);
} else if (ex.test ("PCELL=")) {
info.pcell_name = ex.skip ();
} else if (ex.test ("CELL=")) {
info.cell_name = ex.skip ();
}
}
return info;
}
void
ProxyContextInfo::serialize (std::vector<std::string> &strings)
{
if (! lib_name.empty ()) {
strings.push_back ("LIB=" + lib_name);
}
for (std::map<std::string, tl::Variant> ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) {
strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ());
}
if (! pcell_name.empty ()) {
strings.push_back ("PCELL=" + pcell_name);
}
if (! cell_name.empty ()) {
strings.push_back ("CELL=" + cell_name);
}
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// Implementation of the Layout class // Implementation of the Layout class
@ -442,6 +524,187 @@ Layout::operator= (const Layout &d)
return *this; return *this;
} }
const db::Technology *
Layout::technology () const
{
return db::Technologies::instance ()->technology_by_name (m_tech_name);
}
void
Layout::set_technology_name_without_update (const std::string &tech)
{
if (tech != m_tech_name) {
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new SetLayoutTechName (m_tech_name, tech));
}
m_tech_name = tech;
technology_changed_event ();
}
}
void
Layout::set_technology_name (const std::string &tech)
{
if (tech == m_tech_name) {
return;
}
// determine which library to map to what
std::map<db::lib_id_type, db::lib_id_type> mapping;
std::set<db::lib_id_type> seen;
std::set<db::lib_id_type> lost;
for (db::Layout::iterator c = begin (); c != end (); ++c) {
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
if (lib_proxy && seen.find (lib_proxy->lib_id ()) == seen.end ()) {
seen.insert (lib_proxy->lib_id ());
std::pair<bool, db::lib_id_type> new_id (false, 0);
const db::Library *l = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
if (l) {
new_id = db::LibraryManager::instance ().lib_by_name (l->get_name (), tech);
}
if (new_id.first && new_id.second != l->get_id ()) {
mapping.insert (std::make_pair (l->get_id (), new_id.second));
} else if (! new_id.first) {
lost.insert (lib_proxy->lib_id ());
}
}
}
if (! mapping.empty () || ! lost.empty ()) {
bool needs_cleanup = false;
std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> > pcells_to_map;
std::vector<db::LibraryProxy *> lib_cells_to_map;
std::vector<db::LibraryProxy *> lib_cells_lost;
for (db::Layout::iterator c = begin (); c != end (); ++c) {
std::map<db::lib_id_type, db::lib_id_type>::const_iterator m;
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
if (! lib_proxy) {
continue;
}
if ((m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) {
db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ());
db::PCellVariant *lib_pcell = dynamic_cast <db::PCellVariant *> (lib_cell);
if (lib_pcell) {
pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell));
} else {
lib_cells_to_map.push_back (lib_proxy);
}
needs_cleanup = true;
} else if (lost.find (lib_proxy->lib_id ()) != lost.end ()) {
lib_cells_lost.push_back (lib_proxy);
needs_cleanup = true;
}
}
// We do PCell resolution before the library proxy resolution. The reason is that
// PCells may generate library proxies in their instantiation. Hence we must instantiate
// the PCells before we can resolve them.
for (std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> >::const_iterator lp = pcells_to_map.begin (); lp != pcells_to_map.end (); ++lp) {
db::cell_index_type ci = lp->first->Cell::cell_index ();
db::PCellVariant *lib_pcell = lp->second;
std::pair<bool, pcell_id_type> pn = lib_pcell->layout ()->pcell_by_name (lp->first->get_basic_name ().c_str ());
if (! pn.first) {
// substitute by a cold proxy
db::ProxyContextInfo info;
get_context_info (ci, info);
create_cold_proxy_as (info, ci);
} else {
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]);
const db::PCellDeclaration *old_pcell_decl = lib_pcell->layout ()->pcell_declaration (lib_pcell->pcell_id ());
const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second);
if (! old_pcell_decl || ! new_pcell_decl) {
// substitute by a cold proxy
db::ProxyContextInfo info;
get_context_info (ci, info);
create_cold_proxy_as (info, ci);
} else {
// map pcell parameters by name
std::map<std::string, tl::Variant> param_by_name = lib_pcell->parameters_by_name ();
lp->first->remap (new_lib->get_id (), new_lib->layout ().get_pcell_variant (pn.second, new_pcell_decl->map_parameters (param_by_name)));
}
}
}
for (std::vector<db::LibraryProxy *>::const_iterator lp = lib_cells_to_map.begin (); lp != lib_cells_to_map.end (); ++lp) {
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [(*lp)->lib_id ()]);
db::cell_index_type ci = (*lp)->Cell::cell_index ();
std::pair<bool, cell_index_type> cn = new_lib->layout ().cell_by_name ((*lp)->get_basic_name ().c_str ());
if (! cn.first) {
// unlink this proxy: substitute by a cold proxy
db::ProxyContextInfo info;
get_context_info (ci, info);
create_cold_proxy_as (info, ci);
} else {
(*lp)->remap (new_lib->get_id (), cn.second);
}
}
for (std::vector<db::LibraryProxy *>::const_iterator lp = lib_cells_lost.begin (); lp != lib_cells_lost.end (); ++lp) {
db::cell_index_type ci = (*lp)->Cell::cell_index ();
// substitute by a cold proxy
db::ProxyContextInfo info;
get_context_info (ci, info);
create_cold_proxy_as (info, ci);
}
if (needs_cleanup) {
cleanup ();
}
}
set_technology_name_without_update (tech);
// we may have re-established a connection for pending ("cold") proxies so we can try to restore them
restore_proxies ();
}
void void
Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
{ {
@ -1800,8 +2063,37 @@ static const std::vector<tl::Variant> &gauge_parameters (const std::vector<tl::V
} }
} }
void
Layout::replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout)
{
invalidate_hier ();
db::Cell *old_cell = m_cell_ptrs [target_cell_index];
if (old_cell) {
old_cell->unregister ();
if (retain_layout) {
new_cell->Cell::operator= (*old_cell);
}
}
if (manager () && manager ()->transacting ()) {
// note the "take" method - this takes out the cell but does not delete it (we need it inside undo)
m_cells.take (iterator (old_cell));
manager ()->queue (this, new NewRemoveCellOp (target_cell_index, cell_name (target_cell_index), true /*remove*/, old_cell));
} else {
m_cells.erase (iterator (old_cell));
}
m_cells.push_back_ptr (new_cell);
m_cell_ptrs [target_cell_index] = new_cell;
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new NewRemoveCellOp (target_cell_index, m_cell_names [target_cell_index], false /*new*/, 0));
}
}
void void
Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout)
{ {
pcell_header_type *header = pcell_header (pcell_id); pcell_header_type *header = pcell_header (pcell_id);
tl_assert (header != 0); tl_assert (header != 0);
@ -1812,19 +2104,15 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Vari
// this variant must not exist yet for "get as" semantics // this variant must not exist yet for "get as" semantics
tl_assert (header->get_variant (*this, parameters) == 0); tl_assert (header->get_variant (*this, parameters) == 0);
tl_assert (! (manager () && manager ()->transacting ()));
tl_assert (m_cell_ptrs [target_cell_index] != 0); tl_assert (m_cell_ptrs [target_cell_index] != 0);
invalidate_hier ();
m_cells.erase (iterator (m_cell_ptrs [target_cell_index]));
pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters); pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters);
m_cells.push_back_ptr (variant); replace_cell (target_cell_index, variant, retain_layout);
m_cell_ptrs [target_cell_index] = variant;
// produce the layout if (! retain_layout) {
variant->update (layer_mapping); // produce the layout unless we retained it
variant->update (layer_mapping);
}
} }
cell_index_type cell_index_type
@ -2168,10 +2456,29 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector<tl
} }
bool bool
Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &strings) const
{
ProxyContextInfo info;
if (! get_context_info (cell_index, info)) {
return false;
} else {
info.serialize (strings);
return true;
}
}
bool
Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const
{ {
const db::Cell *cptr = &cell (cell_index); const db::Cell *cptr = &cell (cell_index);
const db::ColdProxy *cold_proxy = dynamic_cast <const db::ColdProxy *> (cptr);
if (cold_proxy) {
info = cold_proxy->context_info ();
return true;
}
const db::Layout *ly = this; const db::Layout *ly = this;
const db::LibraryProxy *lib_proxy; const db::LibraryProxy *lib_proxy;
@ -2185,7 +2492,7 @@ Layout::get_context_info (cell_index_type cell_index, std::vector <std::string>
// one level of library indirection // one level of library indirection
ly = &lib->layout (); ly = &lib->layout ();
cptr = &ly->cell (lib_proxy->library_cell_index ()); cptr = &ly->cell (lib_proxy->library_cell_index ());
context_info.push_back ("LIB=" + lib->get_name ()); info.lib_name = lib->get_name ();
} }
@ -2199,19 +2506,36 @@ Layout::get_context_info (cell_index_type cell_index, std::vector <std::string>
const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations (); const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin (); std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin ();
for (std::vector<tl::Variant>::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) { for (std::vector<tl::Variant>::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) {
context_info.push_back ("P(" + tl::to_word_or_quoted_string (pd->get_name ()) + ")=" + p->to_parsable_string ()); info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p));
} }
const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ()); const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ());
context_info.push_back ("PCELL=" + header->get_name ()); info.pcell_name = header->get_name ();
} else { } else {
context_info.push_back ("CELL=" + std::string (ly->cell_name (cptr->cell_index ()))); info.cell_name = ly->cell_name (cptr->cell_index ());
} }
return true; return true;
} }
void
Layout::restore_proxies (ImportLayerMapping *layer_mapping)
{
std::vector<db::ColdProxy *> cold_proxies;
for (iterator c = begin (); c != end (); ++c) {
db::ColdProxy *proxy = dynamic_cast<db::ColdProxy *> (c.operator-> ());
if (proxy) {
cold_proxies.push_back (proxy);
}
}
for (std::vector<db::ColdProxy *>::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) {
recover_proxy_as ((*p)->cell_index (), (*p)->context_info (), layer_mapping);
}
}
bool bool
Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to, ImportLayerMapping *layer_mapping) Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to, ImportLayerMapping *layer_mapping)
{ {
@ -2219,17 +2543,21 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
return false; return false;
} }
tl::Extractor ex (from->c_str ()); return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping);
}
if (ex.test ("LIB=")) { bool
Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping)
{
if (! info.lib_name.empty ()) {
std::string lib_name = ex.skip (); db::Cell *lib_cell = 0;
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name);
if (! lib) { Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name);
return false; if (lib) {
lib_cell = lib->layout ().recover_proxy_no_lib (info);
} }
db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to);
if (lib_cell) { if (lib_cell) {
get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping); get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping);
return true; return true;
@ -2237,38 +2565,28 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
} else { } else {
std::map<std::string, tl::Variant> parameters; if (! info.pcell_name.empty ()) {
while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { std::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
std::string name;
ex.read_word_or_quoted (name);
ex.test (")");
ex.test ("=");
ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second);
++from;
}
if (ex.test ("PCELL=")) {
std::pair<bool, pcell_id_type> pc = pcell_by_name (ex.skip ());
if (pc.first) { if (pc.first) {
get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (parameters), cell_index, layer_mapping); get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters), cell_index, layer_mapping);
return true; return true;
} }
} else if (ex.test ("CELL=")) { } else if (! info.cell_name.empty ()) {
// This should not happen. A cell (given by the cell index) cannot be proxy to another cell in the same layout. // This should not happen. A cell (given by the cell name) cannot be proxy to another cell in the same layout.
tl_assert (false); tl_assert (false);
} }
} }
if (! dynamic_cast<db::ColdProxy *> (m_cell_ptrs [cell_index])) {
// create a cold proxy representing the context information so we can restore it
create_cold_proxy_as (info, cell_index);
}
return false; return false;
} }
@ -2279,55 +2597,54 @@ Layout::recover_proxy (std::vector <std::string>::const_iterator from, std::vect
return 0; return 0;
} }
tl::Extractor ex (from->c_str ()); return recover_proxy (ProxyContextInfo::deserialize (from, to));
}
if (ex.test ("LIB=")) { db::Cell *
Layout::recover_proxy (const ProxyContextInfo &info)
{
if (! info.lib_name.empty ()) {
std::string lib_name = ex.skip (); Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name);
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name);
if (! lib) { db::Cell *lib_cell = 0;
return 0; if (lib) {
lib_cell = lib->layout ().recover_proxy_no_lib (info);
} }
db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to);
if (lib_cell) { if (lib_cell) {
cell_index_type cell_index = get_lib_proxy (lib, lib_cell->cell_index ()); return m_cell_ptrs [get_lib_proxy (lib, lib_cell->cell_index ())];
return &cell (cell_index);
} }
} else { } else {
std::map<std::string, tl::Variant> parameters; db::Cell *proxy = recover_proxy_no_lib (info);
if (proxy) {
while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { return proxy;
std::string name;
ex.read_word_or_quoted (name);
ex.test (")");
ex.test ("=");
ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second);
++from;
} }
if (ex.test ("PCELL=")) { }
std::pair<bool, pcell_id_type> pc = pcell_by_name (ex.skip ()); return m_cell_ptrs [create_cold_proxy (info)];
if (pc.first) { }
cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (parameters));
return &cell (cell_index);
}
} else if (ex.test ("CELL=")) { db::Cell *
Layout::recover_proxy_no_lib (const ProxyContextInfo &info)
{
if (! info.pcell_name.empty ()) {
std::pair<bool, cell_index_type> cc = cell_by_name (ex.skip ()); std::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
if (cc.first) { if (pc.first) {
return &cell (cc.second); cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters));
} return m_cell_ptrs [cell_index];
}
} } else if (! info.cell_name.empty ()) {
std::pair<bool, cell_index_type> cc = cell_by_name (info.cell_name.c_str ());
if (cc.first) {
return m_cell_ptrs [cc.second];
}
} }
@ -2359,21 +2676,17 @@ Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy)
} }
void void
Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout)
{ {
tl_assert (! (manager () && manager ()->transacting ()));
tl_assert (m_cell_ptrs [target_cell_index] != 0); tl_assert (m_cell_ptrs [target_cell_index] != 0);
invalidate_hier ();
m_cells.erase (iterator (m_cell_ptrs [target_cell_index]));
LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index); LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index);
m_cells.push_back_ptr (proxy); replace_cell (target_cell_index, proxy, retain_layout);
m_cell_ptrs [target_cell_index] = proxy;
// produce the layout if (! retain_layout) {
proxy->update (layer_mapping); // produce the layout unless we retained it
proxy->update (layer_mapping);
}
} }
cell_index_type cell_index_type
@ -2404,7 +2717,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
} }
// produce the layout // produce the layout
proxy->update (); proxy->update ();
return new_index; return new_index;
@ -2412,6 +2725,46 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
} }
} }
cell_index_type
Layout::create_cold_proxy (const db::ProxyContextInfo &info)
{
// create a new unique name
std::string b;
if (! info.cell_name.empty ()) {
b = info.cell_name;
} else if (! info.pcell_name.empty ()) {
b = info.pcell_name;
}
if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) {
b = uniquify_cell_name (b.c_str ());
}
// create a new cell (a LibraryProxy)
cell_index_type new_index = allocate_new_cell ();
ColdProxy *proxy = new ColdProxy (new_index, *this, info);
m_cells.push_back_ptr (proxy);
m_cell_ptrs [new_index] = proxy;
// enter it's index and cell_name
register_cell_name (b.c_str (), new_index);
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
}
return new_index;
}
void
Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index)
{
tl_assert (m_cell_ptrs [target_cell_index] != 0);
ColdProxy *proxy = new ColdProxy (target_cell_index, *this, info);
replace_cell (target_cell_index, proxy, true);
}
void void
Layout::redo (db::Op *op) Layout::redo (db::Op *op)
{ {

View File

@ -67,6 +67,7 @@ class Region;
class Edges; class Edges;
class EdgePairs; class EdgePairs;
class Texts; class Texts;
class Technology;
class CellMapping; class CellMapping;
class LayerMapping; class LayerMapping;
@ -456,6 +457,20 @@ public:
virtual std::pair <bool, unsigned int> map_layer (const LayerProperties &lprops) = 0; virtual std::pair <bool, unsigned int> map_layer (const LayerProperties &lprops) = 0;
}; };
/**
* @brief A binary object representing context information for regenerating library proxies and PCells
*/
struct DB_PUBLIC ProxyContextInfo
{
std::string lib_name;
std::string cell_name;
std::string pcell_name;
std::map<std::string, tl::Variant> pcell_parameters;
static ProxyContextInfo deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to);
void serialize (std::vector<std::string> &strings);
};
/** /**
* @brief The layout object * @brief The layout object
* *
@ -555,10 +570,36 @@ public:
} }
/** /**
* @brief Clear the layout * @brief Clears the layout
*/ */
void clear (); void clear ();
/**
* @brief Gets the technology name the layout is associated with
*/
const std::string &technology_name () const
{
return m_tech_name;
}
/**
* @brief Gets the technology object the layout is associated with or null if no valid technology is associated
*/
const db::Technology *technology () const;
/**
* @brief Changes the technology, the layout is associated with
* Changing the layout may re-assess all the library references as libraries can be technology specific
*/
void set_technology_name (const std::string &tech);
/**
* @brief Changes the technology name
* This method will only change the technology name, but does not re-assess the library links.
* It's provided mainly to support undo/redo and testing.
*/
void set_technology_name_without_update (const std::string &tech);
/** /**
* @brief Accessor to the array repository * @brief Accessor to the array repository
*/ */
@ -843,8 +884,9 @@ public:
* @param parameters The PCell parameters * @param parameters The PCell parameters
* @param cell_index The cell index which is to be replaced by the PCell variant proxy * @param cell_index The cell index which is to be replaced by the PCell variant proxy
* @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers * @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers
* @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach)
*/ */
void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &parameters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0); void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &parameters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false);
/** /**
* @brief Get the PCell variant cell of a existing cell with new parameters * @brief Get the PCell variant cell of a existing cell with new parameters
@ -990,9 +1032,21 @@ public:
/** /**
* @brief Get the proxy cell (index) for a given library an cell index (inside that library) * @brief Get the proxy cell (index) for a given library an cell index (inside that library)
* *
* This method replaces the cell with the given target cell index by a library. * @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach)
*
* This method replaces the cell with the given target cell index by a library.
*/ */
void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0); void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false);
/**
* @brief Creates a cold proxy representing the given context information
*/
cell_index_type create_cold_proxy (const db::ProxyContextInfo &info);
/**
* @brief Subsitutes the given cell by a cold proxy representing the given context information
*/
void create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type cell_index);
/** /**
* @brief Get the context information for a given cell (for writing into a file) * @brief Get the context information for a given cell (for writing into a file)
@ -1004,6 +1058,11 @@ public:
*/ */
bool get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const; bool get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const;
/**
* @brief Gets the context information as a binary object
*/
bool get_context_info (cell_index_type cell_index, ProxyContextInfo &context_info) const;
/** /**
* @brief Recover a proxy cell from the given context info. * @brief Recover a proxy cell from the given context info.
* *
@ -1015,6 +1074,11 @@ public:
*/ */
db::Cell *recover_proxy (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to); db::Cell *recover_proxy (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to);
/**
* @brief Recover a proxy cell from the given binary context info object.
*/
db::Cell *recover_proxy (const ProxyContextInfo &context_info);
/** /**
* @brief Recover a proxy cell from the given context info. * @brief Recover a proxy cell from the given context info.
* *
@ -1030,6 +1094,27 @@ public:
*/ */
bool recover_proxy_as (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to, ImportLayerMapping *layer_mapping = 0); bool recover_proxy_as (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to, ImportLayerMapping *layer_mapping = 0);
/**
* @brief Recover a proxy cell from the given binary context info object
*
* See the string-based version of "recover_proxy_as" for details.
*/
bool recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &context_info, ImportLayerMapping *layer_mapping = 0);
/**
* @brief Restores proxies as far as possible
*
* This feature can be used after a library update to make sure that proxies are updated.
* Library updates may enabled lost connections which are help in cold proxies. This method will recover
* these connections.
*/
void restore_proxies(ImportLayerMapping *layer_mapping = 0);
/**
* @brief Replaces the given cell index with the new cell
*/
void replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout);
/** /**
* @brief Delete a cell plus the subcells not used otherwise * @brief Delete a cell plus the subcells not used otherwise
* *
@ -1738,6 +1823,11 @@ public:
*/ */
const std::string &meta_info_value (const std::string &name) const; const std::string &meta_info_value (const std::string &name) const;
/**
* @brief This event is triggered when the technology changes
*/
tl::Event technology_changed_event;
protected: protected:
/** /**
* @brief Establish the graph's internals according to the dirty flags * @brief Establish the graph's internals according to the dirty flags
@ -1779,6 +1869,7 @@ private:
bool m_do_cleanup; bool m_do_cleanup;
bool m_editable; bool m_editable;
meta_info m_meta_info; meta_info m_meta_info;
std::string m_tech_name;
tl::Mutex m_lock; tl::Mutex m_lock;
/** /**
@ -1832,6 +1923,11 @@ private:
* @brief Implementation of prune_cells and some prune_subcells variants * @brief Implementation of prune_cells and some prune_subcells variants
*/ */
void do_prune_cells_or_subcells (const std::set<cell_index_type> &ids, int levels, bool subcells); void do_prune_cells_or_subcells (const std::set<cell_index_type> &ids, int levels, bool subcells);
/**
* @brief Recovers a proxy without considering the library from context_info
*/
db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info);
}; };
/** /**

View File

@ -80,7 +80,7 @@ tl::Variant LayoutContextHandler::eval_double_bracket (const std::string &s) con
std::string tail = cp + 1; std::string tail = cp + 1;
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, mp_layout->technology_name ());
if (! lib) { if (! lib) {
throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + libname); throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + libname);
} }

View File

@ -191,11 +191,10 @@ Library::remap_to (db::Library *other)
if (! pn.first) { if (! pn.first) {
// substitute by static layout cell // substitute by a cold proxy
std::string name = r->first->cell_name (ci); db::ProxyContextInfo info;
db::Cell *old_cell = r->first->take_cell (ci); r->first->get_context_info (ci, info);
r->first->insert_cell (ci, name, new db::Cell (*old_cell)); r->first->create_cold_proxy_as (info, ci);
delete old_cell;
} else { } else {
@ -203,11 +202,10 @@ Library::remap_to (db::Library *other)
const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second); const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second);
if (! old_pcell_decl || ! new_pcell_decl) { if (! old_pcell_decl || ! new_pcell_decl) {
// substitute by static layout cell // substitute by a cold proxy
std::string name = r->first->cell_name (ci); db::ProxyContextInfo info;
db::Cell *old_cell = r->first->take_cell (ci); r->first->get_context_info (ci, info);
r->first->insert_cell (ci, name, new db::Cell (*old_cell)); r->first->create_cold_proxy_as (info, ci);
delete old_cell;
} else { } else {
@ -232,11 +230,10 @@ Library::remap_to (db::Library *other)
if (! cn.first) { if (! cn.first) {
// unlink this proxy: substitute by static layout cell // substitute by a cold proxy
std::string name = r->first->cell_name (ci); db::ProxyContextInfo info;
db::Cell *old_cell = r->first->take_cell (ci); r->first->get_context_info (ci, info);
r->first->insert_cell (ci, name, new db::Cell (*old_cell)); r->first->create_cold_proxy_as (info, ci);
delete old_cell;
} else { } else {

View File

@ -24,6 +24,7 @@
#include "dbLibraryManager.h" #include "dbLibraryManager.h"
#include "dbLibrary.h" #include "dbLibrary.h"
#include "dbCommon.h" #include "dbCommon.h"
#include "dbColdProxy.h"
#include "tlAssert.h" #include "tlAssert.h"
#include "tlStaticObjects.h" #include "tlStaticObjects.h"
@ -66,14 +67,39 @@ LibraryManager::~LibraryManager ()
} }
std::pair<bool, lib_id_type> std::pair<bool, lib_id_type>
LibraryManager::lib_by_name (const std::string &name) const LibraryManager::lib_by_name (const std::string &name, const std::set<std::string> &for_technologies) const
{ {
iterator l = m_lib_by_name.find (name); iterator l;
if (l == m_lib_by_name.end ()) {
return std::make_pair (false, lib_id_type (0)); if (! for_technologies.empty ()) {
} else {
return std::make_pair (true, l->second); l = m_lib_by_name.find (name);
while (l != m_lib_by_name.end () && l->first == name) {
const db::Library *lptr = lib (l->second);
bool found = lptr->for_technologies ();
for (std::set<std::string>::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) {
if (! lptr->is_for_technology (*t)) {
found = false;
}
}
if (found) {
return std::make_pair (true, l->second);
}
++l;
}
} }
// fallback: technology-unspecific libs
l = m_lib_by_name.find (name);
while (l != m_lib_by_name.end () && l->first == name) {
if (! lib (l->second)->for_technologies ()) {
return std::make_pair (true, l->second);
}
++l;
}
return std::make_pair (false, lib_id_type (0));
} }
void void
@ -116,15 +142,44 @@ LibraryManager::register_lib (Library *library)
library->set_id (id); library->set_id (id);
// if the new library replaces the old one, remap existing library proxies before deleting the library // if the new library replaces the old one, remap existing library proxies before deleting the library
lib_name_map::iterator ln = m_lib_by_name.find (library->get_name ()); // (replacement is done only when all technologies are substituted)
if (ln != m_lib_by_name.end () && m_libs [ln->second]) { lib_name_map::iterator l = m_lib_by_name.find (library->get_name ());
m_libs [ln->second]->remap_to (library); bool found = false;
delete m_libs [ln->second]; while (l != m_lib_by_name.end () && l->first == library->get_name ()) {
m_libs [ln->second] = 0; if (m_libs [l->second] && m_libs [l->second]->get_technologies () == library->get_technologies ()) {
found = true;
break;
}
++l;
} }
m_lib_by_name.insert (std::make_pair (library->get_name (), id)).first->second = id; if (found) {
// substitute
m_libs [l->second]->remap_to (library);
delete m_libs [l->second];
m_libs [l->second] = 0;
m_lib_by_name.erase (l);
}
// insert new lib as first of this name
l = m_lib_by_name.find (library->get_name ());
m_lib_by_name.insert (l, std::make_pair (library->get_name (), id));
// take care of cold referrers - these may not get valid
// NOTE: this will try to substitute the cold proxies we may have generated during "remap_to" above, but
// "restore_proxies" takes care not to re-substitute cold proxies.
const tl::weak_collection<db::ColdProxy> &cold_proxies = db::ColdProxy::cold_proxies_per_lib_name (library->get_name ());
std::set<db::Layout *> to_refresh;
for (tl::weak_collection<db::ColdProxy>::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) {
to_refresh.insert (const_cast<db::Layout *> (p->layout ()));
}
for (std::set<db::Layout *>::const_iterator l = to_refresh.begin (); l != to_refresh.end (); ++l) {
(*l)->restore_proxies (0);
}
// issue the change notification
changed_event (); changed_event ();
return id; return id;

View File

@ -33,6 +33,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <string> #include <string>
#include <set>
namespace db namespace db
{ {
@ -50,7 +51,7 @@ class Library;
class DB_PUBLIC LibraryManager class DB_PUBLIC LibraryManager
{ {
public: public:
typedef std::map <std::string, lib_id_type> lib_name_map; typedef std::multimap <std::string, lib_id_type> lib_name_map;
typedef lib_name_map::const_iterator iterator; typedef lib_name_map::const_iterator iterator;
/** /**
@ -90,11 +91,41 @@ public:
} }
/** /**
* @brief Get the library by name * @brief Get the library by name which is valid for all given technologies
*
* This method looks up a library which is valid for all technologies listed in "for_technologies". It may be
* responsible for more than that too.
* *
* @return A pair, the boolean is true, if the name is valid. The second member is the library id. * @return A pair, the boolean is true, if the name is valid. The second member is the library id.
*/ */
std::pair<bool, lib_id_type> lib_by_name (const std::string &name) const; std::pair<bool, lib_id_type> lib_by_name (const std::string &name, const std::set<std::string> &for_technologies) const;
/**
* @brief Get the library by name which is valid for the given technology
*
* This method looks up a library which is valid for the given technology. It may be
* responsible for more than that too.
*
* @return A pair, the boolean is true, if the name is valid. The second member is the library id.
*/
std::pair<bool, lib_id_type> lib_by_name (const std::string &name, const std::string &for_technology) const
{
std::set<std::string> techs;
if (! for_technology.empty ()) {
techs.insert (for_technology);
}
return lib_by_name (name, techs);
}
/**
* @brief Get the library by name for any technology
*
* @return A pair, the boolean is true, if the name is valid. The second member is the library id.
*/
std::pair<bool, lib_id_type> lib_by_name (const std::string &name) const
{
return lib_by_name (name, std::set<std::string> ());
}
/** /**
* @brief Get the library by name * @brief Get the library by name
@ -111,6 +142,36 @@ public:
} }
} }
/**
* @brief Get the library by name and technology
*
* @return The pointer to the library or 0, if there is no library with that name.
*/
Library *lib_ptr_by_name (const std::string &name, const std::string &for_technology) const
{
std::pair<bool, lib_id_type> ll = lib_by_name (name, for_technology);
if (ll.first) {
return lib (ll.second);
} else {
return 0;
}
}
/**
* @brief Get the library by name and technology
*
* @return The pointer to the library or 0, if there is no library with that name.
*/
Library *lib_ptr_by_name (const std::string &name, const std::set<std::string> &for_technologies) const
{
std::pair<bool, lib_id_type> ll = lib_by_name (name, for_technologies);
if (ll.first) {
return lib (ll.second);
} else {
return 0;
}
}
/** /**
* @brief Register a library under the given name and associate a id * @brief Register a library under the given name and associate a id
* *

View File

@ -99,8 +99,6 @@ LibraryProxy::remap (lib_id_type lib_id, cell_index_type lib_cell_index)
m_lib_id = lib_id; m_lib_id = lib_id;
m_library_cell_index = lib_cell_index; m_library_cell_index = lib_cell_index;
// It's important to register at the new library, but the old library is about to the deleted, so we don't unregister.
// That does not disturb the old library iterating over the layouts.
db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id); db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id);
if (lib) { if (lib) {
lib->register_proxy (this, layout ()); lib->register_proxy (this, layout ());

View File

@ -29,6 +29,7 @@
#include "gsiObject.h" #include "gsiObject.h"
#include "dbLayout.h" #include "dbLayout.h"
#include "tlVariant.h" #include "tlVariant.h"
#include "tlObject.h"
namespace db namespace db
{ {
@ -327,7 +328,8 @@ public:
* @brief A declaration for a PCell * @brief A declaration for a PCell
*/ */
class DB_PUBLIC PCellDeclaration class DB_PUBLIC PCellDeclaration
: public gsi::ObjectBase : public gsi::ObjectBase,
public tl::Object
{ {
public: public:
/** /**

View File

@ -39,6 +39,7 @@
#include "dbLayoutUtils.h" #include "dbLayoutUtils.h"
#include "dbLayerMapping.h" #include "dbLayerMapping.h"
#include "dbCellMapping.h" #include "dbCellMapping.h"
#include "dbTechnology.h"
#include "tlStream.h" #include "tlStream.h"
namespace gsi namespace gsi
@ -750,7 +751,7 @@ static db::Cell *create_cell2 (db::Layout *layout, const std::string &name, cons
static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, const std::string &libname) static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, const std::string &libname)
{ {
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ());
if (! lib) { if (! lib) {
return 0; return 0;
} }
@ -765,7 +766,7 @@ static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, cons
static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, const std::string &libname, const std::map<std::string, tl::Variant> &params) static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, const std::string &libname, const std::map<std::string, tl::Variant> &params)
{ {
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ());
if (! lib) { if (! lib) {
return 0; return 0;
} }
@ -988,6 +989,21 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n" "\n"
"This method has been introduced in version 0.25." "This method has been introduced in version 0.25."
) + ) +
gsi::method ("technology_name", &db::Layout::technology_name,
"@brief Gets the name of the technology this layout is associated with\n"
"This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element."
) +
gsi::method ("technology", &db::Layout::technology,
"@brief Gets the \\Technology object of the technology this layout is associated with or nil if the layout is not associated with a technology\n"
"This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element."
) +
gsi::method ("technology_name=", &db::Layout::set_technology_name, gsi::arg ("name"),
"@brief Sets the name of the technology this layout is associated with\n"
"Changing the technology name will re-assess all library references because libraries can be technology specified. "
"Cell layouts may be substituted during this re-assessment.\n"
"\n"
"This method has been introduced in version 0.27."
) +
gsi::method ("is_editable?", &db::Layout::is_editable, gsi::method ("is_editable?", &db::Layout::is_editable,
"@brief Returns a value indicating whether the layout is editable.\n" "@brief Returns a value indicating whether the layout is editable.\n"
"@return True, if the layout is editable.\n" "@return True, if the layout is editable.\n"

View File

@ -43,9 +43,14 @@ static db::Library *new_lib ()
return new db::Library (); return new db::Library ();
} }
static db::Library *library_by_name (const std::string &name) static db::Library *library_by_name (const std::string &name, const std::string &for_technology)
{ {
return db::LibraryManager::instance ().lib_ptr_by_name (name); return db::LibraryManager::instance ().lib_ptr_by_name (name, for_technology);
}
static db::Library *library_by_id (db::lib_id_type id)
{
return db::LibraryManager::instance ().lib (id);
} }
static std::vector<std::string> library_names () static std::vector<std::string> library_names ()
@ -57,6 +62,15 @@ static std::vector<std::string> library_names ()
return r; return r;
} }
static std::vector<db::lib_id_type> library_ids ()
{
std::vector<db::lib_id_type> r;
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
r.push_back (l->second);
}
return r;
}
static void register_lib (db::Library *lib, const std::string &name) static void register_lib (db::Library *lib, const std::string &name)
{ {
lib->set_name (name); lib->set_name (name);
@ -110,22 +124,45 @@ LibraryClass decl_Library ("db", "Library",
gsi::constructor ("new", &new_lib, gsi::constructor ("new", &new_lib,
"@brief Creates a new, empty library" "@brief Creates a new, empty library"
) + ) +
gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"),
"@brief Gets a library by name\n" "@brief Gets a library by name\n"
"Returns the library object for the given name. If the name is not a valid\n" "Returns the library object for the given name. If the name is not a valid\n"
"library name, nil is returned.\n" "library name, nil is returned.\n"
"\n"
"Different libraries can be registered under the same names for different technologies. When a technology name is given in 'for_technologies', "
"the first library matching this technology is returned. If no technology is given, the first library is returned.\n"
"\n"
"The technology selector has been introduced in version 0.27."
) +
gsi::method ("library_by_id", &library_by_id, gsi::arg ("id"),
"@brief Gets the library object for the given ID\n"
"If the ID is not valid, nil is returned.\n"
"\n"
"This method has been introduced in version 0.27."
) + ) +
gsi::method ("library_names", &library_names, gsi::method ("library_names", &library_names,
"@brief Returns a list of the names of all libraries registered in the system.\n" "@brief Returns a list of the names of all libraries registered in the system.\n"
"\n"
"NOTE: starting with version 0.27, the name of a library does not need to be unique if libraries are associated with specific technologies. "
"This method will only return the names and it's not possible not unambiguously derive the library object. It is recommended to use "
"\\library_ids and \\library_by_id to obtain the library unambiguously."
) +
gsi::method ("library_ids", &library_ids,
"@brief Returns a list of valid library IDs.\n"
"See \\library_names for the reasoning behind this method."
"\n"
"This method has been introduced in version 0.27."
) + ) +
gsi::method_ext ("register", &register_lib, gsi::arg ("name"), gsi::method_ext ("register", &register_lib, gsi::arg ("name"),
"@brief Registers the library with the given name\n" "@brief Registers the library with the given name\n"
"\n" "\n"
"This method can be called in the constructor to register the library after \n" "This method can be called in the constructor to register the library after \n"
"the layout object has been filled with content. If a library with that name\n" "the layout object has been filled with content. If a library with that name\n"
"already exists, it will be replaced with this library. \n" "already exists for the same technologies, it will be replaced with this library. \n"
"\n" "\n"
"This method will set the libraries' name.\n" "This method will set the libraries' name.\n"
"\n"
"The technology specific bahvior has been introduced in version 0.27."
) + ) +
gsi::method_ext ("delete", &delete_lib, gsi::method_ext ("delete", &delete_lib,
"@brief Deletes the library\n" "@brief Deletes the library\n"

View File

@ -20,9 +20,12 @@
*/ */
#include "dbLayout.h" #include "dbLayout.h"
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbColdProxy.h"
#include "dbLibraryProxy.h"
#include "dbTextWriter.h"
#include "tlString.h" #include "tlString.h"
#include "tlUnitTest.h" #include "tlUnitTest.h"
@ -464,3 +467,170 @@ TEST(4)
prop_id = g.properties_repository ().properties_id (ps); prop_id = g.properties_repository ().properties_id (ps);
EXPECT_EQ (el.property_ids_dirty, true); EXPECT_EQ (el.property_ids_dirty, true);
} }
static std::string l2s (const db::Layout &layout)
{
tl::OutputStringStream os;
tl::OutputStream ostream (os);
db::TextWriter writer (ostream);
writer.write (layout);
return os.string ();
}
TEST(5)
{
// Technology management and library substitution
db::cell_index_type ci;
unsigned int li;
db::Cell *cell;
db::Library *lib_a = new db::Library ();
lib_a->set_name ("LIB");
ci = lib_a->layout ().add_cell ("LIBCELL");
li = lib_a->layout ().insert_layer (db::LayerProperties (1, 0));
lib_a->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 100, 200));
lib_a->add_technology ("A");
db::LibraryManager::instance ().register_lib (lib_a);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").second, lib_a->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "A") == lib_a, true);
db::Library *lib_b = new db::Library ();
lib_b->set_name ("LIB");
ci = lib_b->layout ().add_cell ("LIBCELL");
li = lib_b->layout ().insert_layer (db::LayerProperties (2, 0));
lib_b->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100));
lib_b->add_technology ("B");
db::LibraryManager::instance ().register_lib (lib_b);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").second, lib_b->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "B") == lib_b, true);
db::Library *lib_c = new db::Library ();
lib_c->set_name ("LIB");
ci = lib_c->layout ().add_cell ("LIBCELL2");
li = lib_c->layout ().insert_layer (db::LayerProperties (2, 0));
lib_c->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100));
lib_c->add_technology ("C");
db::LibraryManager::instance ().register_lib (lib_c);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").second, lib_c->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "C") == lib_c, true);
db::Manager m;
db::Layout l (&m);
EXPECT_EQ (l.technology_name (), "");
db::ProxyContextInfo info;
info.lib_name = "LIB";
info.cell_name = "LIBCELL";
cell = l.recover_proxy (info);
EXPECT_EQ (dynamic_cast<db::ColdProxy *> (cell) != 0, true);
EXPECT_EQ (cell->get_qualified_name (), "<defunct>LIB.LIBCELL");
EXPECT_EQ (cell->get_basic_name (), "<defunct>LIBCELL");
EXPECT_EQ (cell->get_display_name (), "<defunct>LIB.LIBCELL");
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nend_cell\nend_lib\n");
// now restore the proxies
l.set_technology_name ("A");
EXPECT_EQ (l.technology_name (), "A");
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n");
// now switch to cold proxies again as the technology does not have "LIBCELL" (but rather LIBCELL2)
l.set_technology_name ("C");
EXPECT_EQ (l.technology_name (), "C");
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
EXPECT_EQ (dynamic_cast<db::ColdProxy *> (cell) != 0, true);
EXPECT_EQ (cell->get_qualified_name (), "<defunct>LIB.LIBCELL");
EXPECT_EQ (cell->get_basic_name (), "<defunct>LIBCELL");
EXPECT_EQ (cell->get_display_name (), "<defunct>LIB.LIBCELL");
// NOTE: the box on 1/0 retained
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n");
// switch to another LIBCELL, this time using layer 2/0
m.transaction ("switch_to_b");
l.set_technology_name ("B");
m.commit ();
EXPECT_EQ (l.technology_name (), "B");
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
EXPECT_EQ (dynamic_cast<db::LibraryProxy *> (cell) != 0, true);
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n");
m.undo ();
EXPECT_EQ (l.technology_name (), "C");
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
EXPECT_EQ (dynamic_cast<db::ColdProxy *> (cell) != 0, true);
EXPECT_EQ (cell->get_qualified_name (), "<defunct>LIB.LIBCELL");
EXPECT_EQ (cell->get_basic_name (), "<defunct>LIBCELL");
EXPECT_EQ (cell->get_display_name (), "<defunct>LIB.LIBCELL");
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n");
m.redo ();
EXPECT_EQ (l.technology_name (), "B");
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
EXPECT_EQ (dynamic_cast<db::LibraryProxy *> (cell) != 0, true);
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n");
db::LibraryManager::instance ().delete_lib (lib_a);
db::LibraryManager::instance ().delete_lib (lib_b);
db::LibraryManager::instance ().delete_lib (lib_c);
}
TEST(6)
{
// Cold proxies and context serialization
db::Cell *cell;
db::Manager m;
db::Layout l (&m);
EXPECT_EQ (l.technology_name (), "");
db::ProxyContextInfo info;
info.lib_name = "Basic";
info.pcell_name = "CIRCLE";
info.pcell_parameters ["actual_radius"] = tl::Variant (10.0);
info.pcell_parameters ["npoints"] = tl::Variant (8);
info.pcell_parameters ["layer"] = tl::Variant (db::LayerProperties (1, 0));
m.transaction ("import");
cell = l.recover_proxy (info);
m.commit ();
EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE");
EXPECT_EQ (cell->get_basic_name (), "CIRCLE");
EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=10,n=8)");
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n");
db::ProxyContextInfo info2;
l.get_context_info (cell->cell_index (), info2);
info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0);
m.transaction ("modify");
db::cell_index_type ci = cell->cell_index ();
l.recover_proxy_as (ci, info2);
m.commit ();
cell = &l.cell (ci);
EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE");
EXPECT_EQ (cell->get_basic_name (), "CIRCLE");
EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=5,n=8)");
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n");
m.undo ();
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n");
m.redo ();
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n");
}

View File

@ -617,3 +617,61 @@ TEST(3)
} }
} }
TEST(4)
{
LIBT_A *lib_a1 = new LIBT_A ();
lib_a1->add_technology ("X");
db::LibraryManager::instance ().register_lib (lib_a1);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a1->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a1->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ());
LIBT_A *lib_a2 = new LIBT_A ();
lib_a2->add_technology ("Y");
db::LibraryManager::instance ().register_lib (lib_a2);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a2->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a2->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ());
LIBT_A *lib_a3 = new LIBT_A ();
lib_a3->add_technology ("X");
db::LibraryManager::instance ().register_lib (lib_a3);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ());
LIBT_A *lib_a4 = new LIBT_A ();
db::LibraryManager::instance ().register_lib (lib_a4);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ());
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true);
EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ());
}

View File

@ -69,8 +69,8 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// EditorOptionsGeneric implementation // EditorOptionsGeneric implementation
EditorOptionsGeneric::EditorOptionsGeneric (lay::Dispatcher *dispatcher) EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: EditorOptionsPage (dispatcher) : EditorOptionsPage (view, dispatcher)
{ {
mp_ui = new Ui::EditorOptionsGeneric (); mp_ui = new Ui::EditorOptionsGeneric ();
mp_ui->setupUi (this); mp_ui->setupUi (this);
@ -206,8 +206,8 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// EditorOptionsText implementation // EditorOptionsText implementation
EditorOptionsText::EditorOptionsText (lay::Dispatcher *dispatcher) EditorOptionsText::EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher) : lay::EditorOptionsPage (view, dispatcher)
{ {
mp_ui = new Ui::EditorOptionsText (); mp_ui = new Ui::EditorOptionsText ();
mp_ui->setupUi (this); mp_ui->setupUi (this);
@ -284,8 +284,8 @@ EditorOptionsText::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// EditorOptionsPath implementation // EditorOptionsPath implementation
EditorOptionsPath::EditorOptionsPath (lay::Dispatcher *dispatcher) EditorOptionsPath::EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher) : lay::EditorOptionsPage (view, dispatcher)
{ {
mp_ui = new Ui::EditorOptionsPath (); mp_ui = new Ui::EditorOptionsPath ();
mp_ui->setupUi (this); mp_ui->setupUi (this);
@ -385,8 +385,8 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// EditorOptionsInst implementation // EditorOptionsInst implementation
EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *dispatcher) EditorOptionsInst::EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher) : lay::EditorOptionsPage (view, dispatcher)
{ {
mp_ui = new Ui::EditorOptionsInst (); mp_ui = new Ui::EditorOptionsInst ();
mp_ui->setupUi (this); mp_ui->setupUi (this);
@ -440,14 +440,13 @@ EditorOptionsInst::update_cell_edits ()
} }
db::Layout *layout = 0; db::Layout *layout = 0;
lay::LayoutView *view = lay::LayoutView::current ();
// find the layout the cell has to be looked up: that is either the layout of the current instance or // find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected // the library selected
if (mp_ui->lib_cbx->current_library ()) { if (mp_ui->lib_cbx->current_library ()) {
layout = &mp_ui->lib_cbx->current_library ()->layout (); layout = &mp_ui->lib_cbx->current_library ()->layout ();
} else if (view && view->cellview (m_cv_index).is_valid ()) { } else if (view ()->cellview (m_cv_index).is_valid ()) {
layout = &view->cellview (m_cv_index)->layout (); layout = &view ()->cellview (m_cv_index)->layout ();
} }
if (! layout) { if (! layout) {
@ -485,7 +484,7 @@ EditorOptionsInst::browse_cell ()
{ {
BEGIN_PROTECTED BEGIN_PROTECTED
if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
// find the layout the cell has to be looked up: that is either the layout of the current instance or // find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected // the library selected
@ -495,7 +494,7 @@ BEGIN_PROTECTED
lib = mp_ui->lib_cbx->current_library (); lib = mp_ui->lib_cbx->current_library ();
layout = &lib->layout (); layout = &lib->layout ();
} else { } else {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); layout = &view ()->cellview (m_cv_index)->layout ();
} }
bool all_cells = (mp_ui->lib_cbx->current_library () != 0 ? false : true); bool all_cells = (mp_ui->lib_cbx->current_library () != 0 ? false : true);
@ -579,24 +578,36 @@ EditorOptionsInst::apply (lay::Dispatcher *root)
root->config_set (cfg_edit_inst_place_origin, tl::to_string (place_origin)); root->config_set (cfg_edit_inst_place_origin, tl::to_string (place_origin));
} }
void void
EditorOptionsInst::technology_changed (const std::string &)
{
// The layout's technology has changed
setup (dispatcher ());
}
void
EditorOptionsInst::active_cellview_changed ()
{
// The active cellview has changed
setup (dispatcher ());
}
void
EditorOptionsInst::setup (lay::Dispatcher *root) EditorOptionsInst::setup (lay::Dispatcher *root)
{ {
m_cv_index = -1; m_cv_index = view ()->active_cellview_index ();
if (lay::LayoutView::current ()) {
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
}
try { try {
mp_ui->lib_cbx->blockSignals (true); mp_ui->lib_cbx->blockSignals (true);
std::string techname;
mp_ui->lib_cbx->update_list (); mp_ui->lib_cbx->update_list ();
if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true); techname = view ()->cellview (m_cv_index)->tech_name ();
} else {
mp_ui->lib_cbx->set_technology_filter (std::string (), false);
} }
mp_ui->lib_cbx->set_technology_filter (techname, ! techname.empty ());
// cell name // cell name
std::string s; std::string s;
@ -606,7 +617,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
// library // library
std::string l; std::string l;
root->config_get (cfg_edit_inst_lib_name, l); root->config_get (cfg_edit_inst_lib_name, l);
mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l)); mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l, techname));
mp_ui->lib_cbx->blockSignals (false); mp_ui->lib_cbx->blockSignals (false);
update_cell_edits (); update_cell_edits ();
@ -667,8 +678,8 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// EditorOptionsInstPCellParam implementation // EditorOptionsInstPCellParam implementation
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::Dispatcher *dispatcher) EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0) : lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
{ {
mp_ui = new Ui::EditorOptionsInstPCellParam (); mp_ui = new Ui::EditorOptionsInstPCellParam ();
mp_ui->setupUi (this); mp_ui->setupUi (this);
@ -693,11 +704,11 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
std::string param; std::string param;
db::Layout *layout = 0; db::Layout *layout = 0;
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ());
if (lib) { if (lib) {
layout = &lib->layout (); layout = &lib->layout ();
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { } else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); layout = &view ()->cellview (m_cv_index)->layout ();
} }
bool ok = true; bool ok = true;
@ -717,13 +728,16 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
} }
} }
void
EditorOptionsInstPCellParam::technology_changed (const std::string &)
{
setup (dispatcher ());
}
void void
EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
{ {
m_cv_index = -1; m_cv_index = view ()->active_cellview_index ();
if (lay::LayoutView::current ()) {
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
}
bool needs_update = (mp_pcell_parameters == 0); bool needs_update = (mp_pcell_parameters == 0);
@ -743,7 +757,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
needs_update = true; needs_update = true;
} }
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ());
// pcell parameters // pcell parameters
std::string param; std::string param;
@ -752,8 +766,8 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
db::Layout *layout = 0; db::Layout *layout = 0;
if (lib) { if (lib) {
layout = &lib->layout (); layout = &lib->layout ();
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { } else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); layout = &view ()->cellview (m_cv_index)->layout ();
} }
std::vector<tl::Variant> pv; std::vector<tl::Variant> pv;
@ -820,15 +834,14 @@ void
EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> &parameters) EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> &parameters)
{ {
db::Layout *layout = 0; db::Layout *layout = 0;
lay::LayoutView *view = lay::LayoutView::current ();
// find the layout the cell has to be looked up: that is either the layout of the current instance or // find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected // the library selected
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ());
if (lib) { if (lib) {
layout = &lib->layout (); layout = &lib->layout ();
} else if (view) { } else {
const lay::CellView &cv = view->cellview (m_cv_index); const lay::CellView &cv = view ()->cellview (m_cv_index);
if (cv.is_valid ()) { if (cv.is_valid ()) {
layout = &cv->layout (); layout = &cv->layout ();
} }
@ -856,10 +869,10 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Var
mp_pcell_parameters = 0; mp_pcell_parameters = 0;
mp_placeholder_label = 0; mp_placeholder_label = 0;
if (pc.first && layout->pcell_declaration (pc.second) && view && view->cellview (m_cv_index).is_valid ()) { if (pc.first && layout->pcell_declaration (pc.second) && view ()->cellview (m_cv_index).is_valid ()) {
mp_pcell_parameters = new PCellParametersPage (this, true /*dense*/); mp_pcell_parameters = new PCellParametersPage (this, true /*dense*/);
mp_pcell_parameters->setup (&view->cellview (m_cv_index)->layout (), view, m_cv_index, layout->pcell_declaration (pc.second), parameters); mp_pcell_parameters->setup (&view ()->cellview (m_cv_index)->layout (), view (), m_cv_index, layout->pcell_declaration (pc.second), parameters);
this->layout ()->addWidget (mp_pcell_parameters); this->layout ()->addWidget (mp_pcell_parameters);
mp_pcell_parameters->set_state (pcp_state); mp_pcell_parameters->set_state (pcp_state);

View File

@ -51,6 +51,7 @@ namespace lay
{ {
class PluginDeclaration; class PluginDeclaration;
class Dispatcher; class Dispatcher;
class LayoutView;
class Plugin; class Plugin;
} }
@ -68,7 +69,7 @@ class EditorOptionsGeneric
Q_OBJECT Q_OBJECT
public: public:
EditorOptionsGeneric (lay::Dispatcher *dispatcher); EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher);
~EditorOptionsGeneric (); ~EditorOptionsGeneric ();
virtual std::string title () const; virtual std::string title () const;
@ -91,7 +92,7 @@ class EditorOptionsText
: public lay::EditorOptionsPage : public lay::EditorOptionsPage
{ {
public: public:
EditorOptionsText (lay::Dispatcher *dispatcher); EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher);
~EditorOptionsText (); ~EditorOptionsText ();
virtual std::string title () const; virtual std::string title () const;
@ -112,7 +113,7 @@ class EditorOptionsPath
Q_OBJECT Q_OBJECT
public: public:
EditorOptionsPath (lay::Dispatcher *dispatcher); EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher);
~EditorOptionsPath (); ~EditorOptionsPath ();
virtual std::string title () const; virtual std::string title () const;
@ -136,7 +137,7 @@ class EditorOptionsInst
Q_OBJECT Q_OBJECT
public: public:
EditorOptionsInst (lay::Dispatcher *root); EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *root);
~EditorOptionsInst (); ~EditorOptionsInst ();
virtual std::string title () const; virtual std::string title () const;
@ -154,6 +155,9 @@ private:
Ui::EditorOptionsInst *mp_ui; Ui::EditorOptionsInst *mp_ui;
edt::PCellParametersPage *mp_pcell_parameters; edt::PCellParametersPage *mp_pcell_parameters;
int m_cv_index; int m_cv_index;
virtual void technology_changed (const std::string &);
virtual void active_cellview_changed ();
}; };
/** /**
@ -165,7 +169,7 @@ class EditorOptionsInstPCellParam
Q_OBJECT Q_OBJECT
public: public:
EditorOptionsInstPCellParam (lay::Dispatcher *root); EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *root);
~EditorOptionsInstPCellParam (); ~EditorOptionsInstPCellParam ();
virtual std::string title () const; virtual std::string title () const;
@ -184,6 +188,7 @@ private:
std::string m_lib_name, m_cell_name; std::string m_lib_name, m_cell_name;
void update_pcell_parameters (const std::vector <tl::Variant> &parameters); void update_pcell_parameters (const std::vector <tl::Variant> &parameters);
virtual void technology_changed (const std::string &);
}; };
} }

View File

@ -153,7 +153,7 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense)
void void
PCellParametersPage::init () PCellParametersPage::init ()
{ {
mp_pcell_decl = 0; mp_pcell_decl.reset (0);
mp_layout = 0; mp_layout = 0;
mp_view = 0; mp_view = 0;
m_cv_index = 0; m_cv_index = 0;
@ -185,7 +185,7 @@ PCellParametersPage::init ()
void void
PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters) PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters)
{ {
mp_pcell_decl = pcell_decl; mp_pcell_decl.reset (const_cast<db::PCellDeclaration *> (pcell_decl)); // no const weak_ptr ...
mp_layout = layout; mp_layout = layout;
mp_view = view; mp_view = view;
m_cv_index = cv_index; m_cv_index = cv_index;
@ -457,131 +457,136 @@ std::vector<tl::Variant>
PCellParametersPage::get_parameters (bool *ok) PCellParametersPage::get_parameters (bool *ok)
{ {
std::vector<tl::Variant> parameters; std::vector<tl::Variant> parameters;
bool edit_error = true;
int r = 0; try {
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
for (std::vector<db::PCellParameterDeclaration>::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) {
if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { if (! mp_pcell_decl) {
throw tl::Exception (tl::to_string (tr ("PCell no longer valid.")));
}
if (r < (int) m_parameters.size ()) { bool edit_error = true;
parameters.push_back (m_parameters [r]);
} else {
parameters.push_back (p->get_default ());
}
} else { int r = 0;
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
for (std::vector<db::PCellParameterDeclaration>::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) {
parameters.push_back (tl::Variant ()); if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) {
if (p->get_choices ().empty ()) { if (r < (int) m_parameters.size ()) {
parameters.push_back (m_parameters [r]);
switch (p->get_type ()) { } else {
parameters.push_back (p->get_default ());
case db::PCellParameterDeclaration::t_int:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
try {
int v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
edit_error = false;
}
}
}
break;
case db::PCellParameterDeclaration::t_double:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
try {
double v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
edit_error = false;
}
}
}
break;
case db::PCellParameterDeclaration::t_string:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
parameters.back () = tl::Variant (tl::to_string (le->text ()));
}
}
break;
case db::PCellParameterDeclaration::t_list:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
std::vector<std::string> values = tl::split (tl::to_string (le->text ()), ",");
parameters.back () = tl::Variant (values.begin (), values.end ());
}
}
break;
case db::PCellParameterDeclaration::t_layer:
{
lay::LayerSelectionComboBox *ly = dynamic_cast<lay::LayerSelectionComboBox *> (m_widgets [r]);
if (ly) {
parameters.back () = tl::Variant (ly->current_layer_props ());
}
}
break;
case db::PCellParameterDeclaration::t_boolean:
{
QCheckBox *cbx = dynamic_cast<QCheckBox *> (m_widgets [r]);
if (cbx) {
parameters.back () = tl::Variant (cbx->isChecked ());
}
}
break;
default:
break;
} }
} else { } else {
QComboBox *cb = dynamic_cast<QComboBox*> (m_widgets [r]); parameters.push_back (tl::Variant ());
if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) {
parameters.back () = p->get_choices () [cb->currentIndex ()]; if (p->get_choices ().empty ()) {
switch (p->get_type ()) {
case db::PCellParameterDeclaration::t_int:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
try {
int v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
edit_error = false;
}
}
}
break;
case db::PCellParameterDeclaration::t_double:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
try {
double v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
edit_error = false;
}
}
}
break;
case db::PCellParameterDeclaration::t_string:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
parameters.back () = tl::Variant (tl::to_string (le->text ()));
}
}
break;
case db::PCellParameterDeclaration::t_list:
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
std::vector<std::string> values = tl::split (tl::to_string (le->text ()), ",");
parameters.back () = tl::Variant (values.begin (), values.end ());
}
}
break;
case db::PCellParameterDeclaration::t_layer:
{
lay::LayerSelectionComboBox *ly = dynamic_cast<lay::LayerSelectionComboBox *> (m_widgets [r]);
if (ly) {
parameters.back () = tl::Variant (ly->current_layer_props ());
}
}
break;
case db::PCellParameterDeclaration::t_boolean:
{
QCheckBox *cbx = dynamic_cast<QCheckBox *> (m_widgets [r]);
if (cbx) {
parameters.back () = tl::Variant (cbx->isChecked ());
}
}
break;
default:
break;
}
} else {
QComboBox *cb = dynamic_cast<QComboBox*> (m_widgets [r]);
if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) {
parameters.back () = p->get_choices () [cb->currentIndex ()];
}
} }
} }
} }
}
try {
if (! edit_error) { if (! edit_error) {
throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details."))); throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details.")));
} }
@ -628,6 +633,10 @@ PCellParametersPage::get_parameters (bool *ok)
void void
PCellParametersPage::set_parameters (const std::vector<tl::Variant> &parameters) PCellParametersPage::set_parameters (const std::vector<tl::Variant> &parameters)
{ {
if (! mp_pcell_decl) {
return;
}
// write the changed value back // write the changed value back
size_t r = 0; size_t r = 0;
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations (); const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();

View File

@ -104,7 +104,7 @@ public:
*/ */
const db::PCellDeclaration *pcell_decl () const const db::PCellDeclaration *pcell_decl () const
{ {
return mp_pcell_decl; return mp_pcell_decl.get ();
} }
/** /**
@ -122,7 +122,7 @@ private:
QScrollArea *mp_parameters_area; QScrollArea *mp_parameters_area;
QLabel *mp_error_label; QLabel *mp_error_label;
QLabel *mp_error_icon; QLabel *mp_error_icon;
const db::PCellDeclaration *mp_pcell_decl; tl::weak_ptr<db::PCellDeclaration> mp_pcell_decl;
std::vector<QWidget *> m_widgets; std::vector<QWidget *> m_widgets;
const db::Layout *mp_layout; const db::Layout *mp_layout;
lay::LayoutView *mp_view; lay::LayoutView *mp_view;

View File

@ -75,7 +75,7 @@ void get_text_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret,
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-text-param", ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-text-param",
&text_cfg_descriptors[0], &text_cfg_descriptors[sizeof (text_cfg_descriptors) / sizeof (text_cfg_descriptors[0])])); &text_cfg_descriptors[0], &text_cfg_descriptors[sizeof (text_cfg_descriptors) / sizeof (text_cfg_descriptors[0])]));
ret.push_back (new edt::EditorOptionsText (dispatcher)); ret.push_back (new edt::EditorOptionsText (view, dispatcher));
} }
static static
@ -101,7 +101,7 @@ void get_path_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret,
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-path-param", ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-path-param",
&path_cfg_descriptors[0], &path_cfg_descriptors[sizeof (path_cfg_descriptors) / sizeof (path_cfg_descriptors[0])])); &path_cfg_descriptors[0], &path_cfg_descriptors[sizeof (path_cfg_descriptors) / sizeof (path_cfg_descriptors[0])]));
ret.push_back (new EditorOptionsPath (dispatcher)); ret.push_back (new EditorOptionsPath (view, dispatcher));
} }
static static
@ -145,8 +145,8 @@ void get_inst_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret,
ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param", ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param",
&inst_cfg_descriptors[0], &inst_cfg_descriptors[sizeof (inst_cfg_descriptors) / sizeof (inst_cfg_descriptors[0])])); &inst_cfg_descriptors[0], &inst_cfg_descriptors[sizeof (inst_cfg_descriptors) / sizeof (inst_cfg_descriptors[0])]));
ret.push_back (new EditorOptionsInstPCellParam (dispatcher)); ret.push_back (new EditorOptionsInstPCellParam (view, dispatcher));
ret.push_back (new EditorOptionsInst (dispatcher)); ret.push_back (new EditorOptionsInst (view, dispatcher));
} }
template <class Svc> template <class Svc>
@ -327,10 +327,10 @@ public:
return false; return false;
} }
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutView * /*view*/, lay::Dispatcher *dispatcher) const virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutView *view, lay::Dispatcher *dispatcher) const
{ {
// NOTE: we do not set plugin_declaration which makes the page unspecific // NOTE: we do not set plugin_declaration which makes the page unspecific
EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (dispatcher); EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (view, dispatcher);
pages.push_back (generic_opt); pages.push_back (generic_opt);
} }

View File

@ -56,7 +56,7 @@ RecentConfigurationPage::init ()
ly->addWidget (mp_tree_widget); ly->addWidget (mp_tree_widget);
connect (mp_tree_widget, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (item_clicked (QTreeWidgetItem *))); connect (mp_tree_widget, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (item_clicked (QTreeWidgetItem *)));
mp_view->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed); view ()->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed);
mp_tree_widget->setColumnCount (int (m_cfg.size ())); mp_tree_widget->setColumnCount (int (m_cfg.size ()));
@ -179,15 +179,15 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
case RecentConfigurationPage::Layer: case RecentConfigurationPage::Layer:
{ {
int icon_size = mp_view->style ()->pixelMetric (QStyle::PM_ButtonIconSize); int icon_size = view ()->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
lay::LayerPropertiesConstIterator l; lay::LayerPropertiesConstIterator l;
try { try {
l = lp_iter_from_string (mp_view, values [column]); l = lp_iter_from_string (view (), values [column]);
} catch (tl::Exception &ex) { } catch (tl::Exception &ex) {
tl::error << tl::to_string (tr ("Configuration error (Layer): ")) << ex.msg (); tl::error << tl::to_string (tr ("Configuration error (Layer): ")) << ex.msg ();
} }
if (! l.is_null () && ! l.at_end ()) { if (! l.is_null () && ! l.at_end ()) {
item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, mp_view, icon_size, icon_size, 0, true)); item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, view (), icon_size, icon_size, 0, true));
item->setText (column, tl::to_qstring (values [column])); item->setText (column, tl::to_qstring (values [column]));
} else { } else {
item->setIcon (column, QIcon ()); item->setIcon (column, QIcon ());
@ -241,7 +241,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
const db::Library *lib = 0; const db::Library *lib = 0;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) { for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) {
if (c->rendering == RecentConfigurationPage::CellLibraryName) { if (c->rendering == RecentConfigurationPage::CellLibraryName) {
lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]); if (view ()->active_cellview ().is_valid ()) {
lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview ()->tech_name ());
} else {
lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]);
}
break; break;
} }
} }
@ -304,6 +308,12 @@ RecentConfigurationPage::layers_changed (int)
update_list (get_stored_values ()); update_list (get_stored_values ());
} }
void
RecentConfigurationPage::technology_changed (const std::string &)
{
update_list (get_stored_values ());
}
void void
RecentConfigurationPage::update_list (const std::list<std::vector<std::string> > &stored_values) RecentConfigurationPage::update_list (const std::list<std::vector<std::string> > &stored_values)
{ {
@ -353,7 +363,7 @@ RecentConfigurationPage::item_clicked (QTreeWidgetItem *item)
ex.read (cv_index); ex.read (cv_index);
} }
mp_view->set_or_request_current_layer (cv_index, lp); view ()->set_or_request_current_layer (cv_index, lp);
} else { } else {
dispatcher ()->config_set (c->cfg_name, v); dispatcher ()->config_set (c->cfg_name, v);
@ -375,11 +385,11 @@ RecentConfigurationPage::commit_recent (lay::Dispatcher *root)
std::string s; std::string s;
if (!(mp_view->current_layer ().is_null () || mp_view->current_layer ().at_end ()) && mp_view->current_layer ()->is_visual ()) { if (!(view ()->current_layer ().is_null () || view ()->current_layer ().at_end ()) && view ()->current_layer ()->is_visual ()) {
int cv_index = mp_view->current_layer ()->cellview_index (); int cv_index = view ()->current_layer ()->cellview_index ();
const lay::CellView &cv = mp_view->cellview (cv_index); const lay::CellView &cv = view ()->cellview (cv_index);
int li = mp_view->current_layer ()->layer_index (); int li = view ()->current_layer ()->layer_index ();
if (cv.is_valid () && cv->layout ().is_valid_layer (li)) { if (cv.is_valid () && cv->layout ().is_valid_layer (li)) {
s = cv->layout ().get_properties (li).to_string (); s = cv->layout ().get_properties (li).to_string ();
if (cv_index > 0) { if (cv_index > 0) {

View File

@ -46,8 +46,7 @@ class EditorOptionsPages;
* @brief The base class for a object properties page * @brief The base class for a object properties page
*/ */
class RecentConfigurationPage class RecentConfigurationPage
: public lay::EditorOptionsPage, : public lay::EditorOptionsPage
public tl::Object
{ {
Q_OBJECT Q_OBJECT
@ -79,7 +78,7 @@ public:
template <class Iter> template <class Iter>
RecentConfigurationPage (lay::LayoutView *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg) RecentConfigurationPage (lay::LayoutView *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg)
: EditorOptionsPage (dispatcher), mp_view (view), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg) : EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg)
{ {
init (); init ();
} }
@ -96,7 +95,6 @@ private slots:
void item_clicked (QTreeWidgetItem *item); void item_clicked (QTreeWidgetItem *item);
private: private:
lay::LayoutView *mp_view;
std::string m_recent_cfg_name; std::string m_recent_cfg_name;
std::list<ConfigurationDescriptor> m_cfg; std::list<ConfigurationDescriptor> m_cfg;
QTreeWidget *mp_tree_widget; QTreeWidget *mp_tree_widget;
@ -107,6 +105,7 @@ private:
void set_stored_values (const std::list<std::vector<std::string> > &values) const; void set_stored_values (const std::list<std::vector<std::string> > &values) const;
void render_to (QTreeWidgetItem *item, int column, const std::vector<std::string> &values, RecentConfigurationPage::ConfigurationRendering rendering); void render_to (QTreeWidgetItem *item, int column, const std::vector<std::string> &values, RecentConfigurationPage::ConfigurationRendering rendering);
void layers_changed (int); void layers_changed (int);
virtual void technology_changed (const std::string &);
}; };
} }

View File

@ -1414,7 +1414,7 @@ InstService::make_cell (const lay::CellView &cv)
lay::LayerState layer_state = view ()->layer_snapshot (); lay::LayerState layer_state = view ()->layer_snapshot ();
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ());
// find the layout the cell has to be looked up: that is either the layout of the current instance or // find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected // the library selected
@ -1853,8 +1853,13 @@ InstService::switch_cell_or_pcell (bool switch_parameters)
} }
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
const lay::CellView &cv = view ()->cellview (m_cv_index); const lay::CellView &cv = view ()->cellview (m_cv_index);
db::Library *lib = 0;
if (cv.is_valid ()) {
lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ());
} else {
lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
}
// find the layout the cell has to be looked up: that is either the layout of the current instance or // find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected // the library selected

View File

@ -122,7 +122,7 @@ LibraryController::sync_files ()
m_file_watcher->enable (false); m_file_watcher->enable (false);
} }
std::map<std::string, std::pair<std::string, QDateTime> > new_lib_files; std::map<std::string, LibInfo> new_lib_files;
// build a list of paths vs. technology // build a list of paths vs. technology
std::vector<std::pair<std::string, std::string> > paths; std::vector<std::pair<std::string, std::string> > paths;
@ -174,11 +174,11 @@ LibraryController::sync_files ()
QFileInfo fi (tl::to_qstring (lib_path)); QFileInfo fi (tl::to_qstring (lib_path));
bool needs_load = false; bool needs_load = false;
std::map<std::string, std::pair<std::string, QDateTime> >::iterator ll = m_lib_files.find (lib_path); std::map<std::string, LibInfo>::iterator ll = m_lib_files.find (lib_path);
if (ll == m_lib_files.end ()) { if (ll == m_lib_files.end ()) {
needs_load = true; needs_load = true;
} else { } else {
if (fi.lastModified () > ll->second.second) { if (fi.lastModified () > ll->second.time) {
needs_load = true; needs_load = true;
} else { } else {
new_lib_files.insert (*ll); new_lib_files.insert (*ll);
@ -189,7 +189,9 @@ LibraryController::sync_files ()
std::auto_ptr<db::Library> lib (new db::Library ()); std::auto_ptr<db::Library> lib (new db::Library ());
lib->set_description (filename); lib->set_description (filename);
lib->set_technology (p->second); if (! p->second.empty ()) {
lib->set_technology (p->second);
}
lib->set_name (tl::to_string (QFileInfo (*im).baseName ())); lib->set_name (tl::to_string (QFileInfo (*im).baseName ()));
tl::log << "Reading library '" << lib_path << "'"; tl::log << "Reading library '" << lib_path << "'";
@ -205,8 +207,19 @@ LibraryController::sync_files ()
} }
} }
tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'"; if (! p->second.empty ()) {
new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ()))); tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";
} else {
tl::log << "Registering as '" << lib->get_name () << "'";
}
LibInfo li;
li.name = lib->get_name ();
li.time = fi.lastModified ();
if (! p->second.empty ()) {
li.tech.insert (p->second);
}
new_lib_files.insert (std::make_pair (lib_path, li));
db::LibraryManager::instance ().register_lib (lib.release ()); db::LibraryManager::instance ().register_lib (lib.release ());
@ -230,14 +243,14 @@ LibraryController::sync_files ()
std::set<std::string> new_names; std::set<std::string> new_names;
for (std::map<std::string, std::pair<std::string, QDateTime> >::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) { for (std::map<std::string, LibInfo>::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) {
new_names.insert (lf->second.first); new_names.insert (lf->second.name);
} }
for (std::map<std::string, std::pair<std::string, QDateTime> >::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) { for (std::map<std::string, LibInfo>::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) {
if (new_names.find (lf->second.first) == new_names.end ()) { if (new_names.find (lf->second.name) == new_names.end ()) {
try { try {
std::pair<bool, db::lib_id_type> li = db::LibraryManager::instance ().lib_by_name (lf->second.first); std::pair<bool, db::lib_id_type> li = db::LibraryManager::instance ().lib_by_name (lf->second.name, lf->second.tech);
if (li.first) { if (li.first) {
db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second)); db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second));
} }

View File

@ -119,9 +119,17 @@ private slots:
void sync_with_external_sources (); void sync_with_external_sources ();
private: private:
struct LibInfo
{
LibInfo () : name (), time (), tech () { }
std::string name;
QDateTime time;
std::set<std::string> tech;
};
tl::FileSystemWatcher *m_file_watcher; tl::FileSystemWatcher *m_file_watcher;
tl::DeferredMethod<LibraryController> dm_sync_files; tl::DeferredMethod<LibraryController> dm_sync_files;
std::map<std::string, std::pair<std::string, QDateTime> > m_lib_files; std::map<std::string, LibInfo> m_lib_files;
void sync_files (); void sync_files ();
}; };

View File

@ -2506,7 +2506,7 @@ void
MainWindow::cm_new_layout () MainWindow::cm_new_layout ()
{ {
std::string technology = m_initial_technology; std::string technology = m_initial_technology;
static std::string s_new_cell_cell_name; static std::string s_new_cell_cell_name ("TOP");
static double s_new_cell_window_size = 2.0; static double s_new_cell_window_size = 2.0;
double dbu = 0.0; double dbu = 0.0;

View File

@ -285,15 +285,33 @@ bool
TechnologyController::menu_activated (const std::string &symbol) const TechnologyController::menu_activated (const std::string &symbol) const
{ {
if (symbol == "technology_selector:apply_technology") { if (symbol == "technology_selector:apply_technology") {
if (lay::LayoutView::current () && lay::LayoutView::current ()->active_cellview ().is_valid ()) { if (lay::LayoutView::current () && lay::LayoutView::current ()->active_cellview ().is_valid ()) {
// Cancels the current modes - changing the technology may make libraries unavailable
// for example.
if (mp_mw) { if (mp_mw) {
// Cancels the current modes - changing the technology may make libraries unavailable
// for example.
mp_mw->cancel (); mp_mw->cancel ();
// apply technology with undo
mp_mw->manager ().transaction (tl::sprintf (tl::to_string (tr ("Apply technology '%s'")), m_current_technology));
try {
lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology);
mp_mw->manager ().commit ();
} catch (...) {
mp_mw->manager ().cancel ();
throw;
}
} else {
lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology);
} }
lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology);
} }
return true; return true;
} else { } else {
return lay::PluginDeclaration::menu_activated (symbol); return lay::PluginDeclaration::menu_activated (symbol);
} }

View File

@ -59,6 +59,8 @@ LayoutHandle::LayoutHandle (db::Layout *layout, const std::string &filename)
m_dirty (false), m_dirty (false),
m_save_options_valid (false) m_save_options_valid (false)
{ {
layout->technology_changed_event.add (this, &LayoutHandle::on_technology_changed);
// layouts in the managed layouts space participate in spare proxy cleanup // layouts in the managed layouts space participate in spare proxy cleanup
layout->do_cleanup (true); layout->do_cleanup (true);
@ -108,6 +110,12 @@ LayoutHandle::~LayoutHandle ()
file_watcher ().remove_file (filename ()); file_watcher ().remove_file (filename ());
} }
void
LayoutHandle::on_technology_changed ()
{
technology_changed_event ();
}
void void
LayoutHandle::layout_changed () LayoutHandle::layout_changed ()
{ {
@ -206,13 +214,20 @@ LayoutHandle::remove_ref ()
} }
} }
const std::string &
LayoutHandle::tech_name () const
{
static std::string s_empty;
return mp_layout ? mp_layout->technology_name () : s_empty;
}
const db::Technology * const db::Technology *
LayoutHandle::technology () const LayoutHandle::technology () const
{ {
return db::Technologies::instance ()->technology_by_name (m_tech_name); return mp_layout ? mp_layout->technology () : 0;
} }
void void
LayoutHandle::apply_technology (const std::string &tn) LayoutHandle::apply_technology (const std::string &tn)
{ {
set_tech_name (tn); set_tech_name (tn);
@ -223,16 +238,8 @@ LayoutHandle::apply_technology (const std::string &tn)
void void
LayoutHandle::set_tech_name (const std::string &tn) LayoutHandle::set_tech_name (const std::string &tn)
{ {
if (tn != m_tech_name) { if (mp_layout && tn != tech_name ()) {
if (db::Technologies::instance ()->has_technology (tn)) { mp_layout->set_technology_name (tn);
m_tech_name = tn;
} else {
m_tech_name = std::string ();
}
if (mp_layout) {
mp_layout->add_meta_info (db::MetaInfo ("technology", tl::to_string (tr ("Technology name")), tn));
}
technology_changed_event ();
} }
} }
@ -347,7 +354,7 @@ LayoutHandle::load (const db::LoadLayoutOptions &options, const std::string &tec
// If there is no technology given and the reader reports one, use this one // If there is no technology given and the reader reports one, use this one
if (technology.empty ()) { if (technology.empty ()) {
std::string tech_from_reader = layout ().meta_info_value ("technology"); std::string tech_from_reader = layout ().technology_name ();
if (! tech_from_reader.empty ()) { if (! tech_from_reader.empty ()) {
set_tech_name (tech_from_reader); set_tech_name (tech_from_reader);
} }
@ -373,7 +380,7 @@ LayoutHandle::load ()
db::LayerMap new_lmap = reader.read (layout (), m_load_options); db::LayerMap new_lmap = reader.read (layout (), m_load_options);
// Attach the technology from the reader if it reports one // Attach the technology from the reader if it reports one
std::string tech_from_reader = layout ().meta_info_value ("technology"); std::string tech_from_reader = layout ().technology_name ();
if (! tech_from_reader.empty ()) { if (! tech_from_reader.empty ()) {
set_tech_name (tech_from_reader); set_tech_name (tech_from_reader);
} }

View File

@ -115,10 +115,7 @@ public:
* *
* An empty name indicates the default technology should be used. * An empty name indicates the default technology should be used.
*/ */
const std::string &tech_name () const const std::string &tech_name () const;
{
return m_tech_name;
}
/** /**
* @brief Applies the given technology * @brief Applies the given technology
@ -300,12 +297,13 @@ private:
int m_ref_count; int m_ref_count;
std::string m_name; std::string m_name;
std::string m_filename; std::string m_filename;
std::string m_tech_name;
bool m_dirty; bool m_dirty;
db::SaveLayoutOptions m_save_options; db::SaveLayoutOptions m_save_options;
bool m_save_options_valid; bool m_save_options_valid;
db::LoadLayoutOptions m_load_options; db::LoadLayoutOptions m_load_options;
void on_technology_changed ();
static std::map <std::string, LayoutHandle *> ms_dict; static std::map <std::string, LayoutHandle *> ms_dict;
static tl::FileSystemWatcher *mp_file_watcher; static tl::FileSystemWatcher *mp_file_watcher;
}; };

View File

@ -24,6 +24,7 @@
#include "tlInternational.h" #include "tlInternational.h"
#include "layEditorOptionsPage.h" #include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h" #include "layEditorOptionsPages.h"
#include "layLayoutView.h"
namespace lay namespace lay
{ {
@ -31,10 +32,10 @@ namespace lay
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// EditorOptionsPage implementation // EditorOptionsPage implementation
EditorOptionsPage::EditorOptionsPage (lay::Dispatcher *dispatcher) EditorOptionsPage::EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher) : QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
{ {
// nothing yet .. attach_events ();
} }
EditorOptionsPage::~EditorOptionsPage () EditorOptionsPage::~EditorOptionsPage ()
@ -42,6 +43,30 @@ EditorOptionsPage::~EditorOptionsPage ()
set_owner (0); set_owner (0);
} }
void
EditorOptionsPage::attach_events ()
{
detach_from_all_events ();
view ()->active_cellview_changed_event.add (this, &EditorOptionsPage::on_active_cellview_changed);
int cv_index = view ()->active_cellview_index ();
if (cv_index >= 0) {
view ()->cellview (cv_index)->technology_changed_event.add (this, &EditorOptionsPage::on_technology_changed);
}
}
void
EditorOptionsPage::on_active_cellview_changed ()
{
active_cellview_changed ();
attach_events ();
}
void
EditorOptionsPage::on_technology_changed ()
{
technology_changed (view ()->active_cellview_ref ()->tech_name ());
}
void void
EditorOptionsPage::set_owner (EditorOptionsPages *owner) EditorOptionsPage::set_owner (EditorOptionsPages *owner)
{ {

View File

@ -25,6 +25,8 @@
#include "laybasicCommon.h" #include "laybasicCommon.h"
#include "tlObject.h"
#include <QWidget> #include <QWidget>
namespace lay namespace lay
@ -32,19 +34,21 @@ namespace lay
class PluginDeclaration; class PluginDeclaration;
class Dispatcher; class Dispatcher;
class LayoutView;
class Plugin; class Plugin;
class CellView;
class EditorOptionsPages; class EditorOptionsPages;
/** /**
* @brief The base class for a object properties page * @brief The base class for a object properties page
*/ */
class LAYBASIC_PUBLIC EditorOptionsPage class LAYBASIC_PUBLIC EditorOptionsPage
: public QWidget : public QWidget, public tl::Object
{ {
Q_OBJECT Q_OBJECT
public: public:
EditorOptionsPage (lay::Dispatcher *dispatcher); EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher);
virtual ~EditorOptionsPage (); virtual ~EditorOptionsPage ();
virtual std::string title () const = 0; virtual std::string title () const = 0;
@ -72,11 +76,24 @@ protected:
return mp_dispatcher; return mp_dispatcher;
} }
lay::LayoutView *view () const
{
return mp_view;
}
virtual void active_cellview_changed () { }
virtual void technology_changed (const std::string & /*tech*/) { }
private: private:
EditorOptionsPages *mp_owner; EditorOptionsPages *mp_owner;
bool m_active; bool m_active;
const lay::PluginDeclaration *mp_plugin_declaration; const lay::PluginDeclaration *mp_plugin_declaration;
lay::Dispatcher *mp_dispatcher; lay::Dispatcher *mp_dispatcher;
lay::LayoutView *mp_view;
void on_active_cellview_changed ();
void on_technology_changed ();
void attach_events ();
}; };
} }

View File

@ -530,16 +530,28 @@ LibrariesView::do_update_content (int lib_index)
size_t imin = (lib_index < 0 ? 0 : (size_t) lib_index); size_t imin = (lib_index < 0 ? 0 : (size_t) lib_index);
size_t imax = (lib_index < 0 ? std::numeric_limits <size_t>::max () : (size_t) lib_index); size_t imax = (lib_index < 0 ? std::numeric_limits <size_t>::max () : (size_t) lib_index);
std::string tech_name;
// rebuild all events // rebuild all events
detach_from_all_events (); detach_from_all_events ();
mp_view->active_cellview_changed_event.add (this, &LibrariesView::update_required);
lay::CellViewRef cv = mp_view->active_cellview_ref ();
if (cv.is_valid ()) {
cv->technology_changed_event.add (this, &LibrariesView::update_required);
tech_name = cv->tech_name ();
}
db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required); db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required);
std::vector<db::Library *> libraries; std::vector<db::Library *> libraries;
for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) { for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) {
libraries.push_back (db::LibraryManager::instance ().lib (lib->second)); db::Library *lib_ptr = db::LibraryManager::instance ().lib (lib->second);
libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required); if (! lib_ptr->for_technologies () || lib_ptr->is_for_technology (tech_name)) {
libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required); libraries.push_back (lib_ptr);
libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required);
libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required);
}
} }
for (size_t i = imin; i < libraries.size () && i <= imax; ++i) { for (size_t i = imin; i < libraries.size () && i <= imax; ++i) {

View File

@ -298,6 +298,7 @@ struct LayerSelectionComboBoxPrivateData
const db::Layout *layout; const db::Layout *layout;
lay::LayoutView *view; lay::LayoutView *view;
int cv_index; int cv_index;
db::LayerProperties last_props;
}; };
LayerSelectionComboBox::LayerSelectionComboBox (QWidget *parent) LayerSelectionComboBox::LayerSelectionComboBox (QWidget *parent)
@ -424,6 +425,14 @@ LayerSelectionComboBox::set_view (lay::LayoutView *view, int cv_index, bool all_
mp_private->cv_index = cv_index; mp_private->cv_index = cv_index;
mp_private->all_layers = all_layers; mp_private->all_layers = all_layers;
view->layer_list_changed_event.add (this, &LayerSelectionComboBox::on_layer_list_changed);
update_layer_list ();
}
void
LayerSelectionComboBox::on_layer_list_changed (int)
{
update_layer_list (); update_layer_list ();
} }
@ -442,7 +451,7 @@ void
LayerSelectionComboBox::update_layer_list () LayerSelectionComboBox::update_layer_list ()
{ {
int i = currentIndex (); int i = currentIndex ();
db::LayerProperties props; db::LayerProperties props = mp_private->last_props;
if (i >= 0 && i < int (mp_private->layers.size ())) { if (i >= 0 && i < int (mp_private->layers.size ())) {
props = mp_private->layers [i].first; props = mp_private->layers [i].first;
} }
@ -522,6 +531,8 @@ LayerSelectionComboBox::update_layer_list ()
void void
LayerSelectionComboBox::set_current_layer (const db::LayerProperties &props) LayerSelectionComboBox::set_current_layer (const db::LayerProperties &props)
{ {
mp_private->last_props = props;
for (std::vector <std::pair <db::LayerProperties, int> >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) { for (std::vector <std::pair <db::LayerProperties, int> >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) {
if (ll->first.log_equal (props)) { if (ll->first.log_equal (props)) {
setCurrentIndex (std::distance (mp_private->layers.begin (), ll)); setCurrentIndex (std::distance (mp_private->layers.begin (), ll));
@ -562,7 +573,7 @@ LayerSelectionComboBox::current_layer_props () const
{ {
int i = currentIndex (); int i = currentIndex ();
if (i < 0 || i > int (mp_private->layers.size ())) { if (i < 0 || i > int (mp_private->layers.size ())) {
return db::LayerProperties (); return mp_private->last_props;
} else { } else {
return mp_private->layers [i].first; return mp_private->layers [i].first;
} }
@ -600,7 +611,7 @@ LibrarySelectionComboBox::update_list ()
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
db::Library *lib = db::LibraryManager::instance ().lib (l->second); db::Library *lib = db::LibraryManager::instance ().lib (l->second);
if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) { if (! m_tech_set || !lib->for_technologies () || lib->is_for_technology (m_tech)) {
std::string item_text = lib->get_name (); std::string item_text = lib->get_name ();
if (! lib->get_description ().empty ()) { if (! lib->get_description ().empty ()) {

View File

@ -26,6 +26,8 @@
#include "laybasicCommon.h" #include "laybasicCommon.h"
#include "tlObject.h"
#include <QPushButton> #include <QPushButton>
#include <QComboBox> #include <QComboBox>
#include <QLabel> #include <QLabel>
@ -170,7 +172,7 @@ private:
* This combo box allows selecting a (physical) layer from a layout * This combo box allows selecting a (physical) layer from a layout
*/ */
class LAYBASIC_PUBLIC LayerSelectionComboBox class LAYBASIC_PUBLIC LayerSelectionComboBox
: public QComboBox : public QComboBox, public tl::Object
{ {
Q_OBJECT Q_OBJECT
@ -249,6 +251,7 @@ protected slots:
private: private:
LayerSelectionComboBoxPrivateData *mp_private; LayerSelectionComboBoxPrivateData *mp_private;
void on_layer_list_changed (int);
void update_layer_list (); void update_layer_list ();
}; };

View File

@ -358,17 +358,21 @@ GDS2ReaderBase::do_read (db::Layout &layout)
db::cell_index_type cell_index = make_cell (layout, m_cellname); db::cell_index_type cell_index = make_cell (layout, m_cellname);
db::Cell *cell = &layout.cell (cell_index); bool ignore_cell = false;
std::map <tl::string, std::vector <std::string> >::const_iterator ctx = m_context_info.find (m_cellname); std::map <tl::string, std::vector <std::string> >::const_iterator ctx = m_context_info.find (m_cellname);
if (ctx != m_context_info.end ()) { if (ctx != m_context_info.end ()) {
GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers); GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers);
if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) { if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) {
// ignore everything in that cell since it is created by the import: // ignore everything in that cell since it is created by the import:
cell = 0; ignore_cell = true;
} }
} }
db::Cell *cell = 0;
if (! ignore_cell) {
cell = &layout.cell (cell_index);
}
long attr = 0; long attr = 0;
db::PropertiesRepository::properties_set cell_properties; db::PropertiesRepository::properties_set cell_properties;

View File

@ -43,11 +43,7 @@ std::string correct_path (const std::string &fn, const db::Layout &layout, const
// if a technology is given and the file can be found in the technology's base path, take it // if a technology is given and the file can be found in the technology's base path, take it
// from there. // from there.
std::string tn = layout.meta_info_value ("technology"); const db::Technology *tech = layout.technology ();
const db::Technology *tech = 0;
if (! tn.empty ()) {
tech = db::Technologies::instance ()->technology_by_name (tn);
}
if (tech && ! tech->base_path ().empty ()) { if (tech && ! tech->base_path ().empty ()) {
std::string new_fn = tl::combine_path (tech->base_path (), fn); std::string new_fn = tl::combine_path (tech->base_path (), fn);

View File

@ -74,11 +74,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
{ {
prepare_layers (); prepare_layers ();
mp_klayout_tech = 0; mp_klayout_tech = layout.technology ();
std::string klayout_tech_name = layout.meta_info_value ("technology");
if (! klayout_tech_name.empty () && db::Technologies::instance ()->has_technology (klayout_tech_name)) {
mp_klayout_tech = db::Technologies::instance ()->technology_by_name (klayout_tech_name);
}
const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> (); const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> ();
m_lambda = specific_options.lambda; m_lambda = specific_options.lambda;

View File

@ -145,7 +145,7 @@ private:
std::map<std::string, std::string> m_use_lib_paths; std::map<std::string, std::string> m_use_lib_paths;
db::VCplxTrans m_dbu_trans_inv; db::VCplxTrans m_dbu_trans_inv;
std::string m_tech; std::string m_tech;
db::Technology *mp_klayout_tech; const db::Technology *mp_klayout_tech;
void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream);
void do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream); void do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream);

View File

@ -122,7 +122,7 @@ MAGWriter::write_dummmy_top (const std::set<db::cell_index_type> &cell_set, cons
std::string tech = m_options.tech; std::string tech = m_options.tech;
if (tech.empty ()) { if (tech.empty ()) {
tech = layout.meta_info_value ("technology"); tech = layout.technology_name ();
} }
if (! tech.empty ()) { if (! tech.empty ()) {
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n"; os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
@ -177,7 +177,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector <std::pair <
std::string tech = m_options.tech; std::string tech = m_options.tech;
if (tech.empty ()) { if (tech.empty ()) {
tech = layout.meta_info_value ("technology"); tech = layout.technology_name ();
} }
if (! tech.empty ()) { if (! tech.empty ()) {
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n"; os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";