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 \
dbClipboardData.cc \
dbClip.cc \
dbColdProxy.cc \
dbCommonReader.cc \
dbEdge.cc \
dbEdgePair.cc \
@ -214,6 +215,7 @@ HEADERS = \
dbClipboardData.h \
dbClipboard.h \
dbClip.h \
dbColdProxy.h \
dbCommonReader.h \
dbEdge.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 "dbMemStatistics.h"
#include "dbTrans.h"
#include "dbTechnology.h"
#include "dbShapeRepository.h"
#include "dbPCellHeader.h"
#include "dbPCellVariant.h"
#include "dbPCellDeclaration.h"
#include "dbLibraryProxy.h"
#include "dbColdProxy.h"
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbRegion.h"
@ -84,6 +86,27 @@ private:
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
: 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));
}
// -----------------------------------------------------------------
// 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
@ -442,6 +524,187 @@ Layout::operator= (const Layout &d)
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
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
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);
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
tl_assert (header->get_variant (*this, parameters) == 0);
tl_assert (! (manager () && manager ()->transacting ()));
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);
m_cells.push_back_ptr (variant);
m_cell_ptrs [target_cell_index] = variant;
replace_cell (target_cell_index, variant, retain_layout);
// produce the layout
variant->update (layer_mapping);
if (! retain_layout) {
// produce the layout unless we retained it
variant->update (layer_mapping);
}
}
cell_index_type
@ -2168,10 +2456,29 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector<tl
}
bool
Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const
bool
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::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::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
ly = &lib->layout ();
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 ();
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) {
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 ());
context_info.push_back ("PCELL=" + header->get_name ());
info.pcell_name = header->get_name ();
} 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;
}
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
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;
}
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 ();
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name);
if (! lib) {
return false;
db::Cell *lib_cell = 0;
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name);
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) {
get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping);
return true;
@ -2237,38 +2565,28 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
} 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::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 ());
std::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
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;
}
} 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);
}
}
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;
}
@ -2279,55 +2597,54 @@ Layout::recover_proxy (std::vector <std::string>::const_iterator from, std::vect
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 (lib_name);
if (! lib) {
return 0;
Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name);
db::Cell *lib_cell = 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) {
cell_index_type cell_index = get_lib_proxy (lib, lib_cell->cell_index ());
return &cell (cell_index);
return m_cell_ptrs [get_lib_proxy (lib, lib_cell->cell_index ())];
}
} else {
std::map<std::string, tl::Variant> parameters;
while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) {
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;
db::Cell *proxy = recover_proxy_no_lib (info);
if (proxy) {
return proxy;
}
if (ex.test ("PCELL=")) {
}
std::pair<bool, pcell_id_type> pc = pcell_by_name (ex.skip ());
if (pc.first) {
cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (parameters));
return &cell (cell_index);
}
return m_cell_ptrs [create_cold_proxy (info)];
}
} 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 ());
if (cc.first) {
return &cell (cc.second);
}
std::pair<bool, pcell_id_type> pc = pcell_by_name (info.pcell_name.c_str ());
if (pc.first) {
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
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);
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);
m_cells.push_back_ptr (proxy);
m_cell_ptrs [target_cell_index] = proxy;
replace_cell (target_cell_index, proxy, retain_layout);
// produce the layout
proxy->update (layer_mapping);
if (! retain_layout) {
// produce the layout unless we retained it
proxy->update (layer_mapping);
}
}
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));
}
// produce the layout
// produce the layout
proxy->update ();
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
Layout::redo (db::Op *op)
{

View File

@ -67,6 +67,7 @@ class Region;
class Edges;
class EdgePairs;
class Texts;
class Technology;
class CellMapping;
class LayerMapping;
@ -456,6 +457,20 @@ public:
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
*
@ -555,10 +570,36 @@ public:
}
/**
* @brief Clear the layout
* @brief Clears the layout
*/
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
*/
@ -843,8 +884,9 @@ public:
* @param parameters The PCell parameters
* @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 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
@ -990,9 +1032,21 @@ public:
/**
* @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)
@ -1004,6 +1058,11 @@ public:
*/
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.
*
@ -1015,6 +1074,11 @@ public:
*/
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.
*
@ -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);
/**
* @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
*
@ -1738,6 +1823,11 @@ public:
*/
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:
/**
* @brief Establish the graph's internals according to the dirty flags
@ -1779,6 +1869,7 @@ private:
bool m_do_cleanup;
bool m_editable;
meta_info m_meta_info;
std::string m_tech_name;
tl::Mutex m_lock;
/**
@ -1832,6 +1923,11 @@ private:
* @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);
/**
* @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;
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) {
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) {
// substitute by static layout cell
std::string name = r->first->cell_name (ci);
db::Cell *old_cell = r->first->take_cell (ci);
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
delete old_cell;
// substitute by a cold proxy
db::ProxyContextInfo info;
r->first->get_context_info (ci, info);
r->first->create_cold_proxy_as (info, ci);
} else {
@ -203,11 +202,10 @@ Library::remap_to (db::Library *other)
const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second);
if (! old_pcell_decl || ! new_pcell_decl) {
// substitute by static layout cell
std::string name = r->first->cell_name (ci);
db::Cell *old_cell = r->first->take_cell (ci);
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
delete old_cell;
// substitute by a cold proxy
db::ProxyContextInfo info;
r->first->get_context_info (ci, info);
r->first->create_cold_proxy_as (info, ci);
} else {
@ -232,11 +230,10 @@ Library::remap_to (db::Library *other)
if (! cn.first) {
// unlink this proxy: substitute by static layout cell
std::string name = r->first->cell_name (ci);
db::Cell *old_cell = r->first->take_cell (ci);
r->first->insert_cell (ci, name, new db::Cell (*old_cell));
delete old_cell;
// substitute by a cold proxy
db::ProxyContextInfo info;
r->first->get_context_info (ci, info);
r->first->create_cold_proxy_as (info, ci);
} else {

View File

@ -24,6 +24,7 @@
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbCommon.h"
#include "dbColdProxy.h"
#include "tlAssert.h"
#include "tlStaticObjects.h"
@ -66,14 +67,39 @@ LibraryManager::~LibraryManager ()
}
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);
if (l == m_lib_by_name.end ()) {
return std::make_pair (false, lib_id_type (0));
} else {
return std::make_pair (true, l->second);
iterator l;
if (! for_technologies.empty ()) {
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
@ -116,15 +142,44 @@ LibraryManager::register_lib (Library *library)
library->set_id (id);
// 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 ());
if (ln != m_lib_by_name.end () && m_libs [ln->second]) {
m_libs [ln->second]->remap_to (library);
delete m_libs [ln->second];
m_libs [ln->second] = 0;
// (replacement is done only when all technologies are substituted)
lib_name_map::iterator l = m_lib_by_name.find (library->get_name ());
bool found = false;
while (l != m_lib_by_name.end () && l->first == library->get_name ()) {
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 ();
return id;

View File

@ -33,6 +33,7 @@
#include <map>
#include <vector>
#include <string>
#include <set>
namespace db
{
@ -50,7 +51,7 @@ class Library;
class DB_PUBLIC LibraryManager
{
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;
/**
@ -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.
*/
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
@ -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
*

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_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);
if (lib) {
lib->register_proxy (this, layout ());

View File

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

View File

@ -39,6 +39,7 @@
#include "dbLayoutUtils.h"
#include "dbLayerMapping.h"
#include "dbCellMapping.h"
#include "dbTechnology.h"
#include "tlStream.h"
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)
{
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) {
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)
{
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) {
return 0;
}
@ -988,6 +989,21 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"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,
"@brief Returns a value indicating whether 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 ();
}
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 ()
@ -57,6 +62,15 @@ static std::vector<std::string> library_names ()
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)
{
lib->set_name (name);
@ -110,22 +124,45 @@ LibraryClass decl_Library ("db", "Library",
gsi::constructor ("new", &new_lib,
"@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"
"Returns the library object for the given name. If the name is not a valid\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,
"@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"),
"@brief Registers the library with the given name\n"
"\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"
"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"
"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,
"@brief Deletes the library\n"

View File

@ -20,9 +20,12 @@
*/
#include "dbLayout.h"
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbColdProxy.h"
#include "dbLibraryProxy.h"
#include "dbTextWriter.h"
#include "tlString.h"
#include "tlUnitTest.h"
@ -464,3 +467,170 @@ TEST(4)
prop_id = g.properties_repository ().properties_id (ps);
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::EditorOptionsGeneric (lay::Dispatcher *dispatcher)
: EditorOptionsPage (dispatcher)
EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: EditorOptionsPage (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsGeneric ();
mp_ui->setupUi (this);
@ -206,8 +206,8 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------
// EditorOptionsText implementation
EditorOptionsText::EditorOptionsText (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher)
EditorOptionsText::EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsText ();
mp_ui->setupUi (this);
@ -284,8 +284,8 @@ EditorOptionsText::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------
// EditorOptionsPath implementation
EditorOptionsPath::EditorOptionsPath (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher)
EditorOptionsPath::EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsPath ();
mp_ui->setupUi (this);
@ -385,8 +385,8 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------
// EditorOptionsInst implementation
EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher)
EditorOptionsInst::EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher)
{
mp_ui = new Ui::EditorOptionsInst ();
mp_ui->setupUi (this);
@ -440,14 +440,13 @@ EditorOptionsInst::update_cell_edits ()
}
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
// the library selected
if (mp_ui->lib_cbx->current_library ()) {
layout = &mp_ui->lib_cbx->current_library ()->layout ();
} else if (view && view->cellview (m_cv_index).is_valid ()) {
layout = &view->cellview (m_cv_index)->layout ();
} else if (view ()->cellview (m_cv_index).is_valid ()) {
layout = &view ()->cellview (m_cv_index)->layout ();
}
if (! layout) {
@ -485,7 +484,7 @@ EditorOptionsInst::browse_cell ()
{
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
// the library selected
@ -495,7 +494,7 @@ BEGIN_PROTECTED
lib = mp_ui->lib_cbx->current_library ();
layout = &lib->layout ();
} 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);
@ -579,24 +578,36 @@ EditorOptionsInst::apply (lay::Dispatcher *root)
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)
{
m_cv_index = -1;
if (lay::LayoutView::current ()) {
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
}
m_cv_index = view ()->active_cellview_index ();
try {
mp_ui->lib_cbx->blockSignals (true);
std::string techname;
mp_ui->lib_cbx->update_list ();
if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true);
} else {
mp_ui->lib_cbx->set_technology_filter (std::string (), false);
if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
techname = view ()->cellview (m_cv_index)->tech_name ();
}
mp_ui->lib_cbx->set_technology_filter (techname, ! techname.empty ());
// cell name
std::string s;
@ -606,7 +617,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
// library
std::string 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);
update_cell_edits ();
@ -667,8 +678,8 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
// ------------------------------------------------------------------
// EditorOptionsInstPCellParam implementation
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
{
mp_ui = new Ui::EditorOptionsInstPCellParam ();
mp_ui->setupUi (this);
@ -693,11 +704,11 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
std::string param;
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) {
layout = &lib->layout ();
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
} else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
layout = &view ()->cellview (m_cv_index)->layout ();
}
bool ok = true;
@ -717,13 +728,16 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
}
}
void
EditorOptionsInstPCellParam::technology_changed (const std::string &)
{
setup (dispatcher ());
}
void
EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
{
m_cv_index = -1;
if (lay::LayoutView::current ()) {
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
}
m_cv_index = view ()->active_cellview_index ();
bool needs_update = (mp_pcell_parameters == 0);
@ -743,7 +757,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
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
std::string param;
@ -752,8 +766,8 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
db::Layout *layout = 0;
if (lib) {
layout = &lib->layout ();
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
} else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) {
layout = &view ()->cellview (m_cv_index)->layout ();
}
std::vector<tl::Variant> pv;
@ -820,15 +834,14 @@ void
EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> &parameters)
{
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
// 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) {
layout = &lib->layout ();
} else if (view) {
const lay::CellView &cv = view->cellview (m_cv_index);
} else {
const lay::CellView &cv = view ()->cellview (m_cv_index);
if (cv.is_valid ()) {
layout = &cv->layout ();
}
@ -856,10 +869,10 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Var
mp_pcell_parameters = 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->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);
mp_pcell_parameters->set_state (pcp_state);

View File

@ -51,6 +51,7 @@ namespace lay
{
class PluginDeclaration;
class Dispatcher;
class LayoutView;
class Plugin;
}
@ -68,7 +69,7 @@ class EditorOptionsGeneric
Q_OBJECT
public:
EditorOptionsGeneric (lay::Dispatcher *dispatcher);
EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher);
~EditorOptionsGeneric ();
virtual std::string title () const;
@ -91,7 +92,7 @@ class EditorOptionsText
: public lay::EditorOptionsPage
{
public:
EditorOptionsText (lay::Dispatcher *dispatcher);
EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher);
~EditorOptionsText ();
virtual std::string title () const;
@ -112,7 +113,7 @@ class EditorOptionsPath
Q_OBJECT
public:
EditorOptionsPath (lay::Dispatcher *dispatcher);
EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher);
~EditorOptionsPath ();
virtual std::string title () const;
@ -136,7 +137,7 @@ class EditorOptionsInst
Q_OBJECT
public:
EditorOptionsInst (lay::Dispatcher *root);
EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *root);
~EditorOptionsInst ();
virtual std::string title () const;
@ -154,6 +155,9 @@ private:
Ui::EditorOptionsInst *mp_ui;
edt::PCellParametersPage *mp_pcell_parameters;
int m_cv_index;
virtual void technology_changed (const std::string &);
virtual void active_cellview_changed ();
};
/**
@ -165,7 +169,7 @@ class EditorOptionsInstPCellParam
Q_OBJECT
public:
EditorOptionsInstPCellParam (lay::Dispatcher *root);
EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *root);
~EditorOptionsInstPCellParam ();
virtual std::string title () const;
@ -184,6 +188,7 @@ private:
std::string m_lib_name, m_cell_name;
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
PCellParametersPage::init ()
{
mp_pcell_decl = 0;
mp_pcell_decl.reset (0);
mp_layout = 0;
mp_view = 0;
m_cv_index = 0;
@ -185,7 +185,7 @@ PCellParametersPage::init ()
void
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_view = view;
m_cv_index = cv_index;
@ -457,131 +457,136 @@ std::vector<tl::Variant>
PCellParametersPage::get_parameters (bool *ok)
{
std::vector<tl::Variant> parameters;
bool edit_error = true;
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) {
try {
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 ()) {
parameters.push_back (m_parameters [r]);
} else {
parameters.push_back (p->get_default ());
}
bool edit_error = true;
} 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 ()) {
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;
if (r < (int) m_parameters.size ()) {
parameters.push_back (m_parameters [r]);
} else {
parameters.push_back (p->get_default ());
}
} 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 ()];
parameters.push_back (tl::Variant ());
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) {
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
PCellParametersPage::set_parameters (const std::vector<tl::Variant> &parameters)
{
if (! mp_pcell_decl) {
return;
}
// write the changed value back
size_t r = 0;
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();

View File

@ -104,7 +104,7 @@ public:
*/
const db::PCellDeclaration *pcell_decl () const
{
return mp_pcell_decl;
return mp_pcell_decl.get ();
}
/**
@ -122,7 +122,7 @@ private:
QScrollArea *mp_parameters_area;
QLabel *mp_error_label;
QLabel *mp_error_icon;
const db::PCellDeclaration *mp_pcell_decl;
tl::weak_ptr<db::PCellDeclaration> mp_pcell_decl;
std::vector<QWidget *> m_widgets;
const db::Layout *mp_layout;
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",
&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
@ -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",
&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
@ -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",
&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 EditorOptionsInst (dispatcher));
ret.push_back (new EditorOptionsInstPCellParam (view, dispatcher));
ret.push_back (new EditorOptionsInst (view, dispatcher));
}
template <class Svc>
@ -327,10 +327,10 @@ public:
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
EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (dispatcher);
EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (view, dispatcher);
pages.push_back (generic_opt);
}

View File

@ -56,7 +56,7 @@ RecentConfigurationPage::init ()
ly->addWidget (mp_tree_widget);
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 ()));
@ -179,15 +179,15 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
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;
try {
l = lp_iter_from_string (mp_view, values [column]);
l = lp_iter_from_string (view (), values [column]);
} catch (tl::Exception &ex) {
tl::error << tl::to_string (tr ("Configuration error (Layer): ")) << ex.msg ();
}
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]));
} else {
item->setIcon (column, QIcon ());
@ -241,7 +241,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
const db::Library *lib = 0;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) {
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;
}
}
@ -304,6 +308,12 @@ RecentConfigurationPage::layers_changed (int)
update_list (get_stored_values ());
}
void
RecentConfigurationPage::technology_changed (const std::string &)
{
update_list (get_stored_values ());
}
void
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);
}
mp_view->set_or_request_current_layer (cv_index, lp);
view ()->set_or_request_current_layer (cv_index, lp);
} else {
dispatcher ()->config_set (c->cfg_name, v);
@ -375,11 +385,11 @@ RecentConfigurationPage::commit_recent (lay::Dispatcher *root)
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 ();
const lay::CellView &cv = mp_view->cellview (cv_index);
int li = mp_view->current_layer ()->layer_index ();
int cv_index = view ()->current_layer ()->cellview_index ();
const lay::CellView &cv = view ()->cellview (cv_index);
int li = view ()->current_layer ()->layer_index ();
if (cv.is_valid () && cv->layout ().is_valid_layer (li)) {
s = cv->layout ().get_properties (li).to_string ();
if (cv_index > 0) {

View File

@ -46,8 +46,7 @@ class EditorOptionsPages;
* @brief The base class for a object properties page
*/
class RecentConfigurationPage
: public lay::EditorOptionsPage,
public tl::Object
: public lay::EditorOptionsPage
{
Q_OBJECT
@ -79,7 +78,7 @@ public:
template <class Iter>
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 ();
}
@ -96,7 +95,6 @@ private slots:
void item_clicked (QTreeWidgetItem *item);
private:
lay::LayoutView *mp_view;
std::string m_recent_cfg_name;
std::list<ConfigurationDescriptor> m_cfg;
QTreeWidget *mp_tree_widget;
@ -107,6 +105,7 @@ private:
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 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 ();
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
// 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);
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
// the library selected

View File

@ -122,7 +122,7 @@ LibraryController::sync_files ()
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
std::vector<std::pair<std::string, std::string> > paths;
@ -174,11 +174,11 @@ LibraryController::sync_files ()
QFileInfo fi (tl::to_qstring (lib_path));
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 ()) {
needs_load = true;
} else {
if (fi.lastModified () > ll->second.second) {
if (fi.lastModified () > ll->second.time) {
needs_load = true;
} else {
new_lib_files.insert (*ll);
@ -189,7 +189,9 @@ LibraryController::sync_files ()
std::auto_ptr<db::Library> lib (new db::Library ());
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 ()));
tl::log << "Reading library '" << lib_path << "'";
@ -205,8 +207,19 @@ LibraryController::sync_files ()
}
}
tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";
new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ())));
if (! p->second.empty ()) {
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 ());
@ -230,14 +243,14 @@ LibraryController::sync_files ()
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) {
new_names.insert (lf->second.first);
for (std::map<std::string, LibInfo>::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) {
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) {
if (new_names.find (lf->second.first) == new_names.end ()) {
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.name) == new_names.end ()) {
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) {
db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second));
}

View File

@ -119,9 +119,17 @@ private slots:
void sync_with_external_sources ();
private:
struct LibInfo
{
LibInfo () : name (), time (), tech () { }
std::string name;
QDateTime time;
std::set<std::string> tech;
};
tl::FileSystemWatcher *m_file_watcher;
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 ();
};

View File

@ -2506,7 +2506,7 @@ void
MainWindow::cm_new_layout ()
{
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;
double dbu = 0.0;

View File

@ -285,15 +285,33 @@ bool
TechnologyController::menu_activated (const std::string &symbol) const
{
if (symbol == "technology_selector:apply_technology") {
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) {
// Cancels the current modes - changing the technology may make libraries unavailable
// for example.
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;
} else {
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_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
layout->do_cleanup (true);
@ -108,6 +110,12 @@ LayoutHandle::~LayoutHandle ()
file_watcher ().remove_file (filename ());
}
void
LayoutHandle::on_technology_changed ()
{
technology_changed_event ();
}
void
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 *
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)
{
set_tech_name (tn);
@ -223,16 +238,8 @@ LayoutHandle::apply_technology (const std::string &tn)
void
LayoutHandle::set_tech_name (const std::string &tn)
{
if (tn != m_tech_name) {
if (db::Technologies::instance ()->has_technology (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 ();
if (mp_layout && tn != tech_name ()) {
mp_layout->set_technology_name (tn);
}
}
@ -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 (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 ()) {
set_tech_name (tech_from_reader);
}
@ -373,7 +380,7 @@ LayoutHandle::load ()
db::LayerMap new_lmap = reader.read (layout (), m_load_options);
// 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 ()) {
set_tech_name (tech_from_reader);
}

View File

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

View File

@ -24,6 +24,7 @@
#include "tlInternational.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h"
#include "layLayoutView.h"
namespace lay
{
@ -31,10 +32,10 @@ namespace lay
// ------------------------------------------------------------------
// EditorOptionsPage implementation
EditorOptionsPage::EditorOptionsPage (lay::Dispatcher *dispatcher)
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_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), mp_view (view)
{
// nothing yet ..
attach_events ();
}
EditorOptionsPage::~EditorOptionsPage ()
@ -42,6 +43,30 @@ EditorOptionsPage::~EditorOptionsPage ()
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
EditorOptionsPage::set_owner (EditorOptionsPages *owner)
{

View File

@ -25,6 +25,8 @@
#include "laybasicCommon.h"
#include "tlObject.h"
#include <QWidget>
namespace lay
@ -32,19 +34,21 @@ namespace lay
class PluginDeclaration;
class Dispatcher;
class LayoutView;
class Plugin;
class CellView;
class EditorOptionsPages;
/**
* @brief The base class for a object properties page
*/
class LAYBASIC_PUBLIC EditorOptionsPage
: public QWidget
: public QWidget, public tl::Object
{
Q_OBJECT
public:
EditorOptionsPage (lay::Dispatcher *dispatcher);
EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher);
virtual ~EditorOptionsPage ();
virtual std::string title () const = 0;
@ -72,11 +76,24 @@ protected:
return mp_dispatcher;
}
lay::LayoutView *view () const
{
return mp_view;
}
virtual void active_cellview_changed () { }
virtual void technology_changed (const std::string & /*tech*/) { }
private:
EditorOptionsPages *mp_owner;
bool m_active;
const lay::PluginDeclaration *mp_plugin_declaration;
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 imax = (lib_index < 0 ? std::numeric_limits <size_t>::max () : (size_t) lib_index);
std::string tech_name;
// rebuild 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);
std::vector<db::Library *> libraries;
for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) {
libraries.push_back (db::LibraryManager::instance ().lib (lib->second));
libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required);
libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required);
db::Library *lib_ptr = db::LibraryManager::instance ().lib (lib->second);
if (! lib_ptr->for_technologies () || lib_ptr->is_for_technology (tech_name)) {
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) {

View File

@ -298,6 +298,7 @@ struct LayerSelectionComboBoxPrivateData
const db::Layout *layout;
lay::LayoutView *view;
int cv_index;
db::LayerProperties last_props;
};
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->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 ();
}
@ -442,7 +451,7 @@ void
LayerSelectionComboBox::update_layer_list ()
{
int i = currentIndex ();
db::LayerProperties props;
db::LayerProperties props = mp_private->last_props;
if (i >= 0 && i < int (mp_private->layers.size ())) {
props = mp_private->layers [i].first;
}
@ -522,6 +531,8 @@ LayerSelectionComboBox::update_layer_list ()
void
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) {
if (ll->first.log_equal (props)) {
setCurrentIndex (std::distance (mp_private->layers.begin (), ll));
@ -562,7 +573,7 @@ LayerSelectionComboBox::current_layer_props () const
{
int i = currentIndex ();
if (i < 0 || i > int (mp_private->layers.size ())) {
return db::LayerProperties ();
return mp_private->last_props;
} else {
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) {
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 ();
if (! lib->get_description ().empty ()) {

View File

@ -26,6 +26,8 @@
#include "laybasicCommon.h"
#include "tlObject.h"
#include <QPushButton>
#include <QComboBox>
#include <QLabel>
@ -170,7 +172,7 @@ private:
* This combo box allows selecting a (physical) layer from a layout
*/
class LAYBASIC_PUBLIC LayerSelectionComboBox
: public QComboBox
: public QComboBox, public tl::Object
{
Q_OBJECT
@ -249,6 +251,7 @@ protected slots:
private:
LayerSelectionComboBoxPrivateData *mp_private;
void on_layer_list_changed (int);
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 *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);
if (ctx != m_context_info.end ()) {
GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers);
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:
cell = 0;
ignore_cell = true;
}
}
db::Cell *cell = 0;
if (! ignore_cell) {
cell = &layout.cell (cell_index);
}
long attr = 0;
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
// from there.
std::string tn = layout.meta_info_value ("technology");
const db::Technology *tech = 0;
if (! tn.empty ()) {
tech = db::Technologies::instance ()->technology_by_name (tn);
}
const db::Technology *tech = layout.technology ();
if (tech && ! tech->base_path ().empty ()) {
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 ();
mp_klayout_tech = 0;
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);
}
mp_klayout_tech = layout.technology ();
const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> ();
m_lambda = specific_options.lambda;

View File

@ -145,7 +145,7 @@ private:
std::map<std::string, std::string> m_use_lib_paths;
db::VCplxTrans m_dbu_trans_inv;
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_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;
if (tech.empty ()) {
tech = layout.meta_info_value ("technology");
tech = layout.technology_name ();
}
if (! tech.empty ()) {
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;
if (tech.empty ()) {
tech = layout.meta_info_value ("technology");
tech = layout.technology_name ();
}
if (! tech.empty ()) {
os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";