mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into feature/issue-2147
This commit is contained in:
commit
6d234d4ea5
|
|
@ -66,7 +66,7 @@ jobs:
|
||||||
mkdir -p $HOST_CCACHE_DIR
|
mkdir -p $HOST_CCACHE_DIR
|
||||||
- name: Build wheels (ARM)
|
- name: Build wheels (ARM)
|
||||||
if: matrix.os == 'ubuntu-24.04-arm'
|
if: matrix.os == 'ubuntu-24.04-arm'
|
||||||
uses: pypa/cibuildwheel@v3.1.4
|
uses: pypa/cibuildwheel@v3.2.0
|
||||||
env:
|
env:
|
||||||
# override the default CentOS “yum install … ccache” and drop ccache
|
# override the default CentOS “yum install … ccache” and drop ccache
|
||||||
CIBW_BEFORE_ALL_LINUX: |
|
CIBW_BEFORE_ALL_LINUX: |
|
||||||
|
|
@ -81,7 +81,7 @@ jobs:
|
||||||
|
|
||||||
- name: Build wheels (all other platforms)
|
- name: Build wheels (all other platforms)
|
||||||
if: matrix.os != 'ubuntu-24.04-arm'
|
if: matrix.os != 'ubuntu-24.04-arm'
|
||||||
uses: pypa/cibuildwheel@v3.1.4
|
uses: pypa/cibuildwheel@v3.2.0
|
||||||
env:
|
env:
|
||||||
CIBW_BUILD: ${{ matrix.cibuild }}
|
CIBW_BUILD: ${{ matrix.cibuild }}
|
||||||
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
|
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
|
||||||
|
|
|
||||||
|
|
@ -145,9 +145,20 @@ Library::is_retired (const db::cell_index_type library_cell_index) const
|
||||||
return (i != m_refcount.end () && j != m_retired_count.end () && i->second == j->second);
|
return (i != m_refcount.end () && j != m_retired_count.end () && i->second == j->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Library::rename (const std::string &name)
|
||||||
|
{
|
||||||
|
if (name != get_name () && db::LibraryManager::initialized ()) {
|
||||||
|
db::LibraryManager::instance ().rename (get_id (), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Library::refresh ()
|
Library::refresh ()
|
||||||
{
|
{
|
||||||
|
std::string name = reload ();
|
||||||
|
rename (name);
|
||||||
|
|
||||||
layout ().refresh ();
|
layout ().refresh ();
|
||||||
remap_to (this);
|
remap_to (this);
|
||||||
}
|
}
|
||||||
|
|
@ -271,6 +282,9 @@ Library::remap_to (db::Library *other)
|
||||||
// Do a cleanup later since the referrers now might have invalid proxy instances
|
// Do a cleanup later since the referrers now might have invalid proxy instances
|
||||||
for (std::set<db::Layout *>::const_iterator c = needs_cleanup.begin (); c != needs_cleanup.end (); ++c) {
|
for (std::set<db::Layout *>::const_iterator c = needs_cleanup.begin (); c != needs_cleanup.end (); ++c) {
|
||||||
(*c)->cleanup ();
|
(*c)->cleanup ();
|
||||||
|
// forces an update of the cell tree in the application - this will reflect the changed name
|
||||||
|
// of the library reference
|
||||||
|
(*c)->invalidate_hier ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,20 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual ~Library ();
|
virtual ~Library ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called to reload the library
|
||||||
|
*
|
||||||
|
* If the library is a file-based one, this method can be reimplemented to reload
|
||||||
|
* the file. This method must not change the name of the library, but return a new
|
||||||
|
* name in case it has changed.
|
||||||
|
*
|
||||||
|
* @return The new name of the library
|
||||||
|
*/
|
||||||
|
virtual std::string reload ()
|
||||||
|
{
|
||||||
|
return get_name ();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The layout object
|
* @brief The layout object
|
||||||
*
|
*
|
||||||
|
|
@ -211,6 +225,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void refresh ();
|
void refresh ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Renames the library
|
||||||
|
*
|
||||||
|
* Unlike "set_name", this method will take care of properly re-registering the library
|
||||||
|
* under the new name.
|
||||||
|
*/
|
||||||
|
void rename (const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Remap the library proxies to a different library
|
* @brief Remap the library proxies to a different library
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,39 @@ LibraryManager::~LibraryManager ()
|
||||||
clear ();
|
clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibraryManager::rename (lib_id_type lib_id, const std::string &name)
|
||||||
|
{
|
||||||
|
db::Library *lib = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::MutexLocker locker (&m_lock);
|
||||||
|
|
||||||
|
lib = lib_internal (lib_id);
|
||||||
|
if (! lib) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string org_name = lib->get_name ();
|
||||||
|
|
||||||
|
for (auto it = m_lib_by_name.find (org_name);it != m_lib_by_name.end () && it->first == org_name; ++it) {
|
||||||
|
if (it->second == lib_id) {
|
||||||
|
m_lib_by_name.erase (it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lib_by_name.insert (std::make_pair (name, lib_id));
|
||||||
|
lib->set_name (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// triggers a layout update
|
||||||
|
lib->remap_to (lib);
|
||||||
|
|
||||||
|
// issue the change notification
|
||||||
|
changed_event ();
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<bool, lib_id_type>
|
std::pair<bool, lib_id_type>
|
||||||
LibraryManager::lib_by_name (const std::string &name, const std::set<std::string> &for_technologies) const
|
LibraryManager::lib_by_name (const std::string &name, const std::set<std::string> &for_technologies) const
|
||||||
{
|
{
|
||||||
|
|
@ -112,6 +145,8 @@ LibraryManager::unregister_lib (Library *library)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
library->remap_to (0);
|
||||||
|
|
||||||
{
|
{
|
||||||
tl::MutexLocker locker (&m_lock);
|
tl::MutexLocker locker (&m_lock);
|
||||||
|
|
||||||
|
|
@ -124,8 +159,10 @@ LibraryManager::unregister_lib (Library *library)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
library->remap_to (0);
|
|
||||||
library->set_id (std::numeric_limits<lib_id_type>::max ());
|
library->set_id (std::numeric_limits<lib_id_type>::max ());
|
||||||
|
|
||||||
|
// issue the change notification
|
||||||
|
changed_event ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -244,6 +281,16 @@ LibraryManager::lib_internal (lib_id_type id) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibraryManager::refresh_all ()
|
||||||
|
{
|
||||||
|
for (std::vector<Library *>::iterator l = m_libs.begin (); l != m_libs.end (); ++l) {
|
||||||
|
if (*l) {
|
||||||
|
(*l)->refresh ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LibraryManager::clear ()
|
LibraryManager::clear ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,11 @@ public:
|
||||||
return m_lib_by_name.end ();
|
return m_lib_by_name.end ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Renames a library
|
||||||
|
*/
|
||||||
|
void rename (lib_id_type lib_id, const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the library by name which is valid for all given technologies
|
* @brief Get the library by name which is valid for all given technologies
|
||||||
*
|
*
|
||||||
|
|
@ -212,6 +217,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void clear ();
|
void clear ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Refreshes all libraries
|
||||||
|
*/
|
||||||
|
void refresh_all ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Library *> m_libs;
|
std::vector<Library *> m_libs;
|
||||||
lib_name_map m_lib_by_name;
|
lib_name_map m_lib_by_name;
|
||||||
|
|
|
||||||
|
|
@ -974,6 +974,45 @@ static db::Library *library (const db::Cell *cell)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void change_library_ref (db::Cell *cell, db::lib_id_type lib_id, db::cell_index_type cell_index)
|
||||||
|
{
|
||||||
|
db::LibraryProxy *l = dynamic_cast<db::LibraryProxy *> (cell);
|
||||||
|
if (! l) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("Cell is not a library reference - cannot change that reference")));
|
||||||
|
}
|
||||||
|
|
||||||
|
const db::Library *lib = db::LibraryManager::instance ().lib (lib_id);
|
||||||
|
if (! lib) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("'lib_id' is not a valid library ID")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! lib->layout ().is_valid_cell_index (cell_index)) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("'cell_index' is not a valid cell index in the context of the library")));
|
||||||
|
}
|
||||||
|
|
||||||
|
l->remap (lib_id, cell_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void change_library_ref2 (db::Cell *cell, const std::string &lib_name, const std::string &cell_name)
|
||||||
|
{
|
||||||
|
db::LibraryProxy *l = dynamic_cast<db::LibraryProxy *> (cell);
|
||||||
|
if (! l) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("Cell is not a library reference - cannot change that reference")));
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name);
|
||||||
|
if (! lib) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + lib_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cbn = lib->layout ().cell_by_name (cell_name.c_str ());
|
||||||
|
if (! cbn.first) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("Not a valid cell name: ")) + cell_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
l->remap (lib->get_id (), cbn.second);
|
||||||
|
}
|
||||||
|
|
||||||
static const db::Layout *layout_const (const db::Cell *cell)
|
static const db::Layout *layout_const (const db::Cell *cell)
|
||||||
{
|
{
|
||||||
return cell->layout ();
|
return cell->layout ();
|
||||||
|
|
@ -3194,7 +3233,23 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
"@brief Returns a reference to the library from which the cell is imported\n"
|
"@brief Returns a reference to the library from which the cell is imported\n"
|
||||||
"if the cell is not imported from a library, this reference is nil.\n"
|
"if the cell is not imported from a library, this reference is nil.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"this method has been introduced in version 0.22.\n"
|
"This method has been introduced in version 0.22.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("change_ref", &change_library_ref, gsi::arg ("lib_id"), gsi::arg ("lib_cell_index"),
|
||||||
|
"@brief Changes the reference to a different library cell\n"
|
||||||
|
"This method requires a cell that is a library reference (i.e. \\is_library_cell? is true). It will "
|
||||||
|
"change that reference to a new cell, potentially from a different library.\n"
|
||||||
|
"The library is given by library ID, the cell by cell inside inside that library.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.30.5.\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("change_ref", &change_library_ref2, gsi::arg ("lib_name"), gsi::arg ("cell_name"),
|
||||||
|
"@brief Changes the reference to a different library cell\n"
|
||||||
|
"This method requires a cell that is a library reference (i.e. \\is_library_cell? is true). It will "
|
||||||
|
"change that reference to a new cell, potentially from a different library.\n"
|
||||||
|
"This version takes a library name and cell name (from that library).\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.30.5.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method_ext ("layout", &layout,
|
gsi::method_ext ("layout", &layout,
|
||||||
"@brief Returns a reference to the layout where the cell resides\n"
|
"@brief Returns a reference to the layout where the cell resides\n"
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,20 @@ static void dump_mem_statistics (const db::Layout *layout, bool detailed)
|
||||||
ms.print ();
|
ms.print ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_cell_index (const db::Layout *layout, db::cell_index_type ci)
|
||||||
|
{
|
||||||
|
if (! layout->is_valid_cell_index (ci)) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("Not a valid cell index: ")) + tl::to_string (ci));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_layer (const db::Layout *layout, unsigned int layer)
|
||||||
|
{
|
||||||
|
if (! layout->is_valid_layer (layer) && ! layout->is_special_layer (layer)) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("Invalid layer index: ")) + tl::to_string (layer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool layout_has_prop_id (const db::Layout *l)
|
static bool layout_has_prop_id (const db::Layout *l)
|
||||||
{
|
{
|
||||||
return l->prop_id () != 0;
|
return l->prop_id () != 0;
|
||||||
|
|
@ -630,30 +644,45 @@ static tl::Variant get_property_from_id (db::properties_id_type id, const tl::Va
|
||||||
static void
|
static void
|
||||||
delete_cells (db::Layout *layout, const std::vector<db::cell_index_type> &cell_indices)
|
delete_cells (db::Layout *layout, const std::vector<db::cell_index_type> &cell_indices)
|
||||||
{
|
{
|
||||||
|
for (auto ci = cell_indices.begin (); ci != cell_indices.end (); ++ci) {
|
||||||
|
check_cell_index (layout, *ci);
|
||||||
|
}
|
||||||
layout->delete_cells (cell_indices.begin (), cell_indices.end ());
|
layout->delete_cells (cell_indices.begin (), cell_indices.end ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_cell_rec (db::Layout *layout, db::cell_index_type cell_index)
|
||||||
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
|
layout->delete_cell_rec (cell_index);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prune_cell (db::Layout *layout, db::cell_index_type cell_index, int levels)
|
prune_cell (db::Layout *layout, db::cell_index_type cell_index, int levels)
|
||||||
{
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
layout->prune_cell (cell_index, levels);
|
layout->prune_cell (cell_index, levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prune_subcells (db::Layout *layout, db::cell_index_type cell_index, int levels)
|
prune_subcells (db::Layout *layout, db::cell_index_type cell_index, int levels)
|
||||||
{
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
layout->prune_subcells (cell_index, levels);
|
layout->prune_subcells (cell_index, levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
flatten (db::Layout *layout, db::cell_index_type cell_index, int levels, bool prune)
|
flatten (db::Layout *layout, db::cell_index_type cell_index, int levels, bool prune)
|
||||||
{
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
layout->flatten (layout->cell (cell_index), levels, prune);
|
layout->flatten (layout->cell (cell_index), levels, prune);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
flatten_into (db::Layout *layout, db::cell_index_type cell_index, db::cell_index_type target_cell_index, const db::ICplxTrans &t, int levels)
|
flatten_into (db::Layout *layout, db::cell_index_type cell_index, db::cell_index_type target_cell_index, const db::ICplxTrans &t, int levels)
|
||||||
{
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
|
check_cell_index (layout, target_cell_index);
|
||||||
layout->flatten (layout->cell (cell_index), layout->cell (target_cell_index), t, levels);
|
layout->flatten (layout->cell (cell_index), layout->cell (target_cell_index), t, levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -698,20 +727,11 @@ write_bytes (db::Layout *layout, const db::SaveLayoutOptions &options)
|
||||||
return std::vector<char> (byte_stream.data (), byte_stream.data () + byte_stream.size ());
|
return std::vector<char> (byte_stream.data (), byte_stream.data () + byte_stream.size ());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_layer (const db::Layout *layout, unsigned int layer)
|
|
||||||
{
|
|
||||||
if (! layout->is_valid_layer (layer) && ! layout->is_special_layer (layer)) {
|
|
||||||
throw tl::Exception (tl::to_string (tr ("Invalid layer index")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static db::RecursiveShapeIterator
|
static db::RecursiveShapeIterator
|
||||||
begin_shapes (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer)
|
begin_shapes (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer)
|
||||||
{
|
{
|
||||||
if (! layout->is_valid_layer (layer)) {
|
|
||||||
throw tl::Exception (tl::to_string (tr ("Invalid layer index")));
|
|
||||||
}
|
|
||||||
check_layer (layout, layer);
|
check_layer (layout, layer);
|
||||||
|
check_cell_index (layout, starting_cell);
|
||||||
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer);
|
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -725,9 +745,7 @@ static db::RecursiveShapeIterator
|
||||||
begin_shapes_touching (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::Box region)
|
begin_shapes_touching (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::Box region)
|
||||||
{
|
{
|
||||||
check_layer (layout, layer);
|
check_layer (layout, layer);
|
||||||
if (! layout->is_valid_cell_index (starting_cell)) {
|
check_cell_index (layout, starting_cell);
|
||||||
throw tl::Exception (tl::to_string (tr ("Invalid cell index")));
|
|
||||||
}
|
|
||||||
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, region, false);
|
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, region, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -741,9 +759,7 @@ static db::RecursiveShapeIterator
|
||||||
begin_shapes_overlapping (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::Box region)
|
begin_shapes_overlapping (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::Box region)
|
||||||
{
|
{
|
||||||
check_layer (layout, layer);
|
check_layer (layout, layer);
|
||||||
if (! layout->is_valid_cell_index (starting_cell)) {
|
check_cell_index (layout, starting_cell);
|
||||||
throw tl::Exception (tl::to_string (tr ("Invalid cell index")));
|
|
||||||
}
|
|
||||||
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, region, true);
|
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, region, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -757,9 +773,7 @@ static db::RecursiveShapeIterator
|
||||||
begin_shapes_touching_um (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::DBox region)
|
begin_shapes_touching_um (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::DBox region)
|
||||||
{
|
{
|
||||||
check_layer (layout, layer);
|
check_layer (layout, layer);
|
||||||
if (! layout->is_valid_cell_index (starting_cell)) {
|
check_cell_index (layout, starting_cell);
|
||||||
throw tl::Exception (tl::to_string (tr ("Invalid cell index")));
|
|
||||||
}
|
|
||||||
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, db::CplxTrans (layout->dbu ()).inverted () * region, false);
|
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, db::CplxTrans (layout->dbu ()).inverted () * region, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -773,9 +787,7 @@ static db::RecursiveShapeIterator
|
||||||
begin_shapes_overlapping_um (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::DBox region)
|
begin_shapes_overlapping_um (const db::Layout *layout, db::cell_index_type starting_cell, unsigned int layer, db::DBox region)
|
||||||
{
|
{
|
||||||
check_layer (layout, layer);
|
check_layer (layout, layer);
|
||||||
if (! layout->is_valid_cell_index (starting_cell)) {
|
check_cell_index (layout, starting_cell);
|
||||||
throw tl::Exception (tl::to_string (tr ("Invalid cell index")));
|
|
||||||
}
|
|
||||||
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, db::CplxTrans (layout->dbu ()).inverted () * region, true);
|
return db::RecursiveShapeIterator (*layout, layout->cell (starting_cell), layer, db::CplxTrans (layout->dbu ()).inverted () * region, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -847,11 +859,21 @@ static std::vector<std::string> pcell_names (const db::Layout *layout)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void delete_cell (db::Layout *ly, db::cell_index_type ci)
|
||||||
|
{
|
||||||
|
check_cell_index (ly, ci);
|
||||||
|
ly->delete_cell (ci);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rename_cell (db::Layout *ly, db::cell_index_type ci, const std::string &name)
|
||||||
|
{
|
||||||
|
check_cell_index (ly, ci);
|
||||||
|
ly->rename_cell (ci, name.c_str ());
|
||||||
|
}
|
||||||
|
|
||||||
static db::Cell *cell_from_index (db::Layout *ly, db::cell_index_type ci)
|
static db::Cell *cell_from_index (db::Layout *ly, db::cell_index_type ci)
|
||||||
{
|
{
|
||||||
if (! ly->is_valid_cell_index (ci)) {
|
check_cell_index (ly, ci);
|
||||||
throw tl::Exception (tl::to_string (tr ("Not a valid cell index: ")) + tl::to_string (ci));
|
|
||||||
}
|
|
||||||
return &ly->cell (ci);
|
return &ly->cell (ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1094,17 +1116,17 @@ static void set_properties (db::Layout *layout, unsigned int index, const db::La
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void break_polygons2 (db::Layout *layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio)
|
static void break_polygons2 (db::Layout *layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio)
|
||||||
{
|
{
|
||||||
db::break_polygons (*layout, layer, max_vertex_count, max_area_ratio);
|
db::break_polygons (*layout, layer, max_vertex_count, max_area_ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void break_polygons1 (db::Layout *layout, size_t max_vertex_count, double max_area_ratio)
|
static void break_polygons1 (db::Layout *layout, size_t max_vertex_count, double max_area_ratio)
|
||||||
{
|
{
|
||||||
db::break_polygons (*layout, max_vertex_count, max_area_ratio);
|
db::break_polygons (*layout, max_vertex_count, max_area_ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_layer_from_info (db::Layout *layout, const db::LayerProperties &info)
|
static void delete_layer_from_info (db::Layout *layout, const db::LayerProperties &info)
|
||||||
{
|
{
|
||||||
int li = layout->get_layer_maybe (info);
|
int li = layout->get_layer_maybe (info);
|
||||||
if (li >= 0) {
|
if (li >= 0) {
|
||||||
|
|
@ -1112,7 +1134,7 @@ void delete_layer_from_info (db::Layout *layout, const db::LayerProperties &info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_layer_from_info (db::Layout *layout, const db::LayerProperties &info)
|
static void clear_layer_from_info (db::Layout *layout, const db::LayerProperties &info)
|
||||||
{
|
{
|
||||||
int li = layout->get_layer_maybe (info);
|
int li = layout->get_layer_maybe (info);
|
||||||
if (li >= 0) {
|
if (li >= 0) {
|
||||||
|
|
@ -1120,7 +1142,7 @@ void clear_layer_from_info (db::Layout *layout, const db::LayerProperties &info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_layer_from_info_with_flags (db::Layout *layout, const db::LayerProperties &info, unsigned int flags)
|
static void clear_layer_from_info_with_flags (db::Layout *layout, const db::LayerProperties &info, unsigned int flags)
|
||||||
{
|
{
|
||||||
int li = layout->get_layer_maybe (info);
|
int li = layout->get_layer_maybe (info);
|
||||||
if (li >= 0) {
|
if (li >= 0) {
|
||||||
|
|
@ -1128,6 +1150,34 @@ void clear_layer_from_info_with_flags (db::Layout *layout, const db::LayerProper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void insert_region (db::Layout *layout, db::cell_index_type cell_index, int layer_index, const db::Region &r)
|
||||||
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
|
check_layer (layout, layer_index);
|
||||||
|
layout->insert (cell_index, layer_index, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_edges (db::Layout *layout, db::cell_index_type cell_index, int layer_index, const db::Edges &e)
|
||||||
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
|
check_layer (layout, layer_index);
|
||||||
|
layout->insert (cell_index, layer_index, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_texts (db::Layout *layout, db::cell_index_type cell_index, int layer_index, const db::Texts &t)
|
||||||
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
|
check_layer (layout, layer_index);
|
||||||
|
layout->insert (cell_index, layer_index, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_edge_pairs (db::Layout *layout, db::cell_index_type cell_index, int layer_index, const db::EdgePairs &ep)
|
||||||
|
{
|
||||||
|
check_cell_index (layout, cell_index);
|
||||||
|
check_layer (layout, layer_index);
|
||||||
|
layout->insert (cell_index, layer_index, ep);
|
||||||
|
}
|
||||||
|
|
||||||
Class<db::Layout> decl_Layout ("db", "Layout",
|
Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
gsi::constructor ("new", &layout_ctor_with_manager, gsi::arg ("manager"),
|
gsi::constructor ("new", &layout_ctor_with_manager, gsi::arg ("manager"),
|
||||||
"@brief Creates a layout object attached to a manager\n"
|
"@brief Creates a layout object attached to a manager\n"
|
||||||
|
|
@ -1584,13 +1634,13 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"From version 0.23 on this method is deprecated because another method exists which is more convenient because "
|
"From version 0.23 on this method is deprecated because another method exists which is more convenient because "
|
||||||
"is returns a \\Cell object (\\create_cell).\n"
|
"is returns a \\Cell object (\\create_cell).\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("rename_cell", &db::Layout::rename_cell, gsi::arg ("index"), gsi::arg ("name"),
|
gsi::method_ext ("rename_cell", &rename_cell, gsi::arg ("index"), gsi::arg ("name"),
|
||||||
"@brief Renames the cell with given index\n"
|
"@brief Renames the cell with given index\n"
|
||||||
"The cell with the given index is renamed to the given name. NOTE: it is not ensured that the name is unique. "
|
"The cell with the given index is renamed to the given name. NOTE: it is not ensured that the name is unique. "
|
||||||
"This method allows assigning identical names to different cells which usually breaks things.\n"
|
"This method allows assigning identical names to different cells which usually breaks things.\n"
|
||||||
"Consider using \\unique_cell_name to generate truely unique names.\n"
|
"Consider using \\unique_cell_name to generate truely unique names.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("delete_cell", &db::Layout::delete_cell, gsi::arg ("cell_index"),
|
gsi::method_ext ("delete_cell", &delete_cell, gsi::arg ("cell_index"),
|
||||||
"@brief Deletes a cell \n"
|
"@brief Deletes a cell \n"
|
||||||
"\n"
|
"\n"
|
||||||
"This deletes a cell but not the sub cells of the cell.\n"
|
"This deletes a cell but not the sub cells of the cell.\n"
|
||||||
|
|
@ -1641,7 +1691,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.20.\n"
|
"This method has been introduced in version 0.20.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("delete_cell_rec", &db::Layout::delete_cell_rec, gsi::arg ("cell_index"),
|
gsi::method_ext ("delete_cell_rec", &delete_cell_rec, gsi::arg ("cell_index"),
|
||||||
"@brief Deletes a cell plus all subcells\n"
|
"@brief Deletes a cell plus all subcells\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This deletes a cell and also all sub cells of the cell.\n"
|
"This deletes a cell and also all sub cells of the cell.\n"
|
||||||
|
|
@ -1651,7 +1701,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.20.\n"
|
"This method has been introduced in version 0.20.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::Region &)) &db::Layout::insert,
|
gsi::method_ext ("insert", &insert_region,
|
||||||
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
|
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
|
||||||
"@brief Inserts a region into the given cell and layer\n"
|
"@brief Inserts a region into the given cell and layer\n"
|
||||||
"If the region is (conceptionally) a flat region, it will be inserted into the cell's shapes "
|
"If the region is (conceptionally) a flat region, it will be inserted into the cell's shapes "
|
||||||
|
|
@ -1663,7 +1713,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.26.\n"
|
"This method has been introduced in version 0.26.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::Edges &)) &db::Layout::insert,
|
gsi::method_ext ("insert", &insert_edges,
|
||||||
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("edges"),
|
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("edges"),
|
||||||
"@brief Inserts an edge collection into the given cell and layer\n"
|
"@brief Inserts an edge collection into the given cell and layer\n"
|
||||||
"If the edge collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
"If the edge collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
||||||
|
|
@ -1675,7 +1725,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.26.\n"
|
"This method has been introduced in version 0.26.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::EdgePairs &)) &db::Layout::insert,
|
gsi::method_ext ("insert", &insert_edge_pairs,
|
||||||
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("edge_pairs"),
|
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("edge_pairs"),
|
||||||
"@brief Inserts an edge pair collection into the given cell and layer\n"
|
"@brief Inserts an edge pair collection into the given cell and layer\n"
|
||||||
"If the edge pair collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
"If the edge pair collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
||||||
|
|
@ -1687,7 +1737,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.27.\n"
|
"This method has been introduced in version 0.27.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::Texts &)) &db::Layout::insert,
|
gsi::method_ext ("insert", &insert_texts,
|
||||||
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("texts"),
|
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("texts"),
|
||||||
"@brief Inserts an text collection into the given cell and layer\n"
|
"@brief Inserts an text collection into the given cell and layer\n"
|
||||||
"If the text collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
"If the text collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
||||||
|
|
|
||||||
|
|
@ -37,14 +37,6 @@ namespace gsi
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// db::Library binding
|
// db::Library binding
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A basic implementation of the library
|
|
||||||
*/
|
|
||||||
static db::Library *new_lib ()
|
|
||||||
{
|
|
||||||
return new db::Library ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static db::Library *library_by_name (const std::string &name, const std::string &for_technology)
|
static db::Library *library_by_name (const std::string &name, const std::string &for_technology)
|
||||||
{
|
{
|
||||||
return db::LibraryManager::instance ().lib_ptr_by_name (name, for_technology);
|
return db::LibraryManager::instance ().lib_ptr_by_name (name, for_technology);
|
||||||
|
|
@ -73,12 +65,22 @@ static std::vector<db::lib_id_type> library_ids ()
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void refresh_all ()
|
||||||
|
{
|
||||||
|
db::LibraryManager::instance ().refresh_all ();
|
||||||
|
}
|
||||||
|
|
||||||
static void register_lib (db::Library *lib, const std::string &name)
|
static void register_lib (db::Library *lib, const std::string &name)
|
||||||
{
|
{
|
||||||
lib->set_name (name);
|
lib->set_name (name);
|
||||||
db::LibraryManager::instance ().register_lib (lib);
|
db::LibraryManager::instance ().register_lib (lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unregister_lib (db::Library *lib)
|
||||||
|
{
|
||||||
|
db::LibraryManager::instance ().unregister_lib (lib);
|
||||||
|
}
|
||||||
|
|
||||||
static void delete_lib (db::Library *lib)
|
static void delete_lib (db::Library *lib)
|
||||||
{
|
{
|
||||||
db::LibraryManager::instance ().delete_lib (lib);
|
db::LibraryManager::instance ().delete_lib (lib);
|
||||||
|
|
@ -97,7 +99,7 @@ static std::string get_technology (db::Library *lib)
|
||||||
static void destroy_lib (db::Library *lib)
|
static void destroy_lib (db::Library *lib)
|
||||||
{
|
{
|
||||||
if (db::LibraryManager::instance ().lib_ptr_by_name (lib->get_name ()) == lib) {
|
if (db::LibraryManager::instance ().lib_ptr_by_name (lib->get_name ()) == lib) {
|
||||||
// Library is registered -> do not delete
|
delete_lib (lib);
|
||||||
} else {
|
} else {
|
||||||
delete lib;
|
delete lib;
|
||||||
}
|
}
|
||||||
|
|
@ -105,31 +107,63 @@ static void destroy_lib (db::Library *lib)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
template <class Base>
|
||||||
class LibraryClass
|
class LibraryClass
|
||||||
: public Class<db::Library>
|
: public gsi::Class<Base>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LibraryClass (const char *module, const char *name, const gsi::Methods &methods, const char *description)
|
LibraryClass (const char *module, const char *name, const gsi::Methods &methods, const char *description)
|
||||||
: Class<db::Library> (module, name, methods, description)
|
: gsi::Class<Base> (module, name, methods, description)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template <class B>
|
||||||
|
LibraryClass (const gsi::Class<B> &base, const char *module, const char *name, const gsi::Methods &methods, const char *description)
|
||||||
|
: gsi::Class<Base> (base, module, name, methods, description)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void destroy (void *p) const
|
virtual void destroy (void *p) const
|
||||||
{
|
{
|
||||||
db::Library *lib = reinterpret_cast<db::Library *> (p);
|
Base *lib = reinterpret_cast<Base *> (p);
|
||||||
destroy_lib (lib);
|
destroy_lib (lib);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LibraryImpl
|
||||||
|
: public db::Library
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LibraryImpl () : db::Library ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string reload ()
|
||||||
|
{
|
||||||
|
if (cb_reload.can_issue ()) {
|
||||||
|
return cb_reload.issue<db::Library, std::string> (&db::Library::reload);
|
||||||
|
} else {
|
||||||
|
return db::Library::reload ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gsi::Callback cb_reload;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryClass decl_Library ("db", "Library",
|
static LibraryImpl *new_lib ()
|
||||||
gsi::constructor ("new", &new_lib,
|
{
|
||||||
"@brief Creates a new, empty library"
|
return new LibraryImpl ();
|
||||||
) +
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A basic implementation of the library
|
||||||
|
*/
|
||||||
|
|
||||||
|
LibraryClass<db::Library> decl_Library ("db", "LibraryBase",
|
||||||
gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"),
|
gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"),
|
||||||
"@brief Gets a library by name\n"
|
"@brief Gets a library by name\n"
|
||||||
"Returns the library object for the given name. If the name is not a valid\n"
|
"Returns the library object for the given name. If the name is not a valid library name, nil is returned.\n"
|
||||||
"library name, nil is returned.\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"Different libraries can be registered under the same names for different technologies. When a technology name is given in 'for_technologies', "
|
"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"
|
"the first library matching this technology is returned. If no technology is given, the first library is returned.\n"
|
||||||
|
|
@ -155,6 +189,11 @@ LibraryClass decl_Library ("db", "Library",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.27."
|
"This method has been introduced in version 0.27."
|
||||||
) +
|
) +
|
||||||
|
gsi::method ("refresh_all", &refresh_all,
|
||||||
|
"@brief Calls \\refresh on all libraries.\n"
|
||||||
|
"\n"
|
||||||
|
"This convenience method has been introduced in version 0.30.4."
|
||||||
|
) +
|
||||||
gsi::method_ext ("register", ®ister_lib, gsi::arg ("name"),
|
gsi::method_ext ("register", ®ister_lib, gsi::arg ("name"),
|
||||||
"@brief Registers the library with the given name\n"
|
"@brief Registers the library with the given name\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -166,6 +205,22 @@ LibraryClass decl_Library ("db", "Library",
|
||||||
"\n"
|
"\n"
|
||||||
"The technology specific behaviour has been introduced in version 0.27."
|
"The technology specific behaviour has been introduced in version 0.27."
|
||||||
) +
|
) +
|
||||||
|
gsi::method_ext ("unregister", &unregister_lib,
|
||||||
|
"@brief Unregisters the library\n"
|
||||||
|
"\n"
|
||||||
|
"Unregisters the library from the system. This will break all references of cells "
|
||||||
|
"using this library and make them 'defunct'.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.30.5."
|
||||||
|
) +
|
||||||
|
gsi::method ("rename", &db::Library::rename, gsi::arg ("name"),
|
||||||
|
"@brief Renames the library\n"
|
||||||
|
"\n"
|
||||||
|
"Re-registers the library under a new name. Note that this method will also change the references "
|
||||||
|
"to the library.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.30.5."
|
||||||
|
) +
|
||||||
gsi::method_ext ("delete", &delete_lib,
|
gsi::method_ext ("delete", &delete_lib,
|
||||||
"@brief Deletes the library\n"
|
"@brief Deletes the library\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -176,7 +231,7 @@ LibraryClass decl_Library ("db", "Library",
|
||||||
) +
|
) +
|
||||||
gsi::method ("name", &db::Library::get_name,
|
gsi::method ("name", &db::Library::get_name,
|
||||||
"@brief Returns the libraries' name\n"
|
"@brief Returns the libraries' name\n"
|
||||||
"The name is set when the library is registered and cannot be changed\n"
|
"The name is set when the library is registered. To change it use \\rename.\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("id", &db::Library::get_id,
|
gsi::method ("id", &db::Library::get_id,
|
||||||
"@brief Returns the library's ID\n"
|
"@brief Returns the library's ID\n"
|
||||||
|
|
@ -240,9 +295,32 @@ LibraryClass decl_Library ("db", "Library",
|
||||||
"@brief Updates all layouts using this library.\n"
|
"@brief Updates all layouts using this library.\n"
|
||||||
"This method will retire cells or update layouts in the attached clients.\n"
|
"This method will retire cells or update layouts in the attached clients.\n"
|
||||||
"It will also recompute the PCells inside the library. "
|
"It will also recompute the PCells inside the library. "
|
||||||
|
"Starting with version 0.30.5, this method will also call 'reload' on all libraries to "
|
||||||
|
"refresh cells located in external files.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.27.8."
|
"This method has been introduced in version 0.27.8."
|
||||||
),
|
),
|
||||||
|
"@hide"
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The reimplementation stub
|
||||||
|
*/
|
||||||
|
|
||||||
|
LibraryClass<LibraryImpl> decl_LibraryImpl (decl_Library, "db", "Library",
|
||||||
|
gsi::constructor ("new", &new_lib,
|
||||||
|
"@brief Creates a new, empty library"
|
||||||
|
) +
|
||||||
|
gsi::callback ("reload", &LibraryImpl::reload, &LibraryImpl::cb_reload,
|
||||||
|
"@brief Reloads resources for the library.\n"
|
||||||
|
"Reimplement this method if you like to reload resources the library was created from - "
|
||||||
|
"for example layout files. Make sure you return the new name of the library from this function. "
|
||||||
|
"If you do not want to change the name of the library, return the current name (i.e. the value of \\name).\n"
|
||||||
|
"\n"
|
||||||
|
"@return The new name of the library or the original name if it did not change.\n"
|
||||||
|
"\n"
|
||||||
|
"This method is called on \\refresh. It was introduced in version 0.30.5.\n"
|
||||||
|
),
|
||||||
"@brief A Library \n"
|
"@brief A Library \n"
|
||||||
"\n"
|
"\n"
|
||||||
"A library is basically a wrapper around a layout object. The layout object\n"
|
"A library is basically a wrapper around a layout object. The layout object\n"
|
||||||
|
|
|
||||||
|
|
@ -1034,7 +1034,7 @@ Class<db::EqualDeviceParameters> decl_dbEqualDeviceParameters ("db", "EqualDevic
|
||||||
|
|
||||||
Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_dbEqualDeviceParameters, "db", "GenericDeviceParameterCompare",
|
Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_dbEqualDeviceParameters, "db", "GenericDeviceParameterCompare",
|
||||||
gsi::callback ("less", &GenericDeviceParameterCompare::less, &GenericDeviceParameterCompare::cb_less, gsi::arg ("device_a"), gsi::arg ("device_b"),
|
gsi::callback ("less", &GenericDeviceParameterCompare::less, &GenericDeviceParameterCompare::cb_less, gsi::arg ("device_a"), gsi::arg ("device_b"),
|
||||||
"@brief Compares the parameters of two devices for a begin less than b. "
|
"@brief Compares the parameters of two devices for a begin less than b.\n"
|
||||||
"Returns true, if the parameters of device a are considered less than those of device b."
|
"Returns true, if the parameters of device a are considered less than those of device b."
|
||||||
"The 'less' implementation needs to ensure strict weak ordering. Specifically, less(a,b) == false and less(b,a) implies that a is equal to b and "
|
"The 'less' implementation needs to ensure strict weak ordering. Specifically, less(a,b) == false and less(b,a) implies that a is equal to b and "
|
||||||
"less(a,b) == true implies that less(b,a) is false and vice versa. If not, an internal error "
|
"less(a,b) == true implies that less(b,a) is false and vice versa. If not, an internal error "
|
||||||
|
|
|
||||||
|
|
@ -150,8 +150,7 @@ ShapeEditService::get_edit_layer ()
|
||||||
mp_layout = &(cv->layout ());
|
mp_layout = &(cv->layout ());
|
||||||
mp_cell = cv.cell ();
|
mp_cell = cv.cell ();
|
||||||
|
|
||||||
// fetches the last configuration for the given layer
|
view ()->set_active_cellview_index_silent (cv_index);
|
||||||
view ()->set_active_cellview_index (cv_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -173,8 +172,9 @@ ShapeEditService::change_edit_layer (const db::LayerProperties &lp)
|
||||||
close_editor_hooks (false);
|
close_editor_hooks (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
view ()->set_active_cellview_index_silent (m_cv_index);
|
||||||
|
|
||||||
// fetches the last configuration for the given layer
|
// fetches the last configuration for the given layer
|
||||||
view ()->set_active_cellview_index (m_cv_index);
|
|
||||||
config_recent_for_layer (lp, m_cv_index);
|
config_recent_for_layer (lp, m_cv_index);
|
||||||
|
|
||||||
if (editing ()) {
|
if (editing ()) {
|
||||||
|
|
@ -237,7 +237,9 @@ ShapeEditService::update_edit_layer (const lay::LayerPropertiesConstIterator &cl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
view ()->set_active_cellview_index (cv_index);
|
// NOTE: we don't want side effects during this operation - i.e. some that
|
||||||
|
// change the selection. Hence no events here.
|
||||||
|
view ()->set_active_cellview_index_silent (cv_index);
|
||||||
|
|
||||||
const lay::ParsedLayerSource &source = cl->source (true /*real*/);
|
const lay::ParsedLayerSource &source = cl->source (true /*real*/);
|
||||||
int layer = cl->layer_index ();
|
int layer = cl->layer_index ();
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ static const char *cm_symbols[] = {
|
||||||
"cm_save",
|
"cm_save",
|
||||||
"cm_save_all",
|
"cm_save_all",
|
||||||
"cm_reload",
|
"cm_reload",
|
||||||
|
"cm_refresh",
|
||||||
"cm_close",
|
"cm_close",
|
||||||
"cm_close_all",
|
"cm_close_all",
|
||||||
"cm_clone",
|
"cm_clone",
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,86 @@
|
||||||
#include "dbCellMapping.h"
|
#include "dbCellMapping.h"
|
||||||
#include "tlLog.h"
|
#include "tlLog.h"
|
||||||
#include "tlStream.h"
|
#include "tlStream.h"
|
||||||
|
#include "tlFileUtils.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class FileBasedLibrary
|
||||||
|
: public db::Library
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileBasedLibrary (const std::string &path)
|
||||||
|
: db::Library (), m_path (path)
|
||||||
|
{
|
||||||
|
set_description (tl::filename (path));
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge_with_other_layout (const std::string &path)
|
||||||
|
{
|
||||||
|
m_other_paths.push_back (path);
|
||||||
|
merge_impl (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string reload ()
|
||||||
|
{
|
||||||
|
std::string name = tl::basename (m_path);
|
||||||
|
|
||||||
|
layout ().clear ();
|
||||||
|
|
||||||
|
tl::InputStream stream (m_path);
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (layout ());
|
||||||
|
|
||||||
|
// Use the libname if there is one
|
||||||
|
db::Layout::meta_info_name_id_type libname_name_id = layout ().meta_info_name_id ("libname");
|
||||||
|
for (db::Layout::meta_info_iterator m = layout ().begin_meta (); m != layout ().end_meta (); ++m) {
|
||||||
|
if (m->first == libname_name_id && ! m->second.value.is_nil ()) {
|
||||||
|
name = m->second.value.to_string ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto p = m_other_paths.begin (); p != m_other_paths.end (); ++p) {
|
||||||
|
merge_impl (*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_path;
|
||||||
|
std::list<std::string> m_other_paths;
|
||||||
|
|
||||||
|
void merge_impl (const std::string &path)
|
||||||
|
{
|
||||||
|
db::Layout ly;
|
||||||
|
|
||||||
|
tl::InputStream stream (path);
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (ly);
|
||||||
|
|
||||||
|
std::vector<db::cell_index_type> target_cells, source_cells;
|
||||||
|
|
||||||
|
// collect the cells to pull in (all top cells of the library layout)
|
||||||
|
for (auto c = ly.begin_top_down (); c != ly.end_top_cells (); ++c) {
|
||||||
|
std::string cn = ly.cell_name (*c);
|
||||||
|
source_cells.push_back (*c);
|
||||||
|
target_cells.push_back (layout ().add_cell (cn.c_str ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
db::CellMapping cm;
|
||||||
|
cm.create_multi_mapping_full (layout (), target_cells, ly, source_cells);
|
||||||
|
layout ().copy_tree_shapes (ly, cm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
LibraryController::LibraryController ()
|
LibraryController::LibraryController ()
|
||||||
: m_file_watcher (0),
|
: m_file_watcher (0),
|
||||||
dm_sync_files (this, &LibraryController::sync_files)
|
dm_sync_files (this, &LibraryController::sync_files)
|
||||||
|
|
@ -201,38 +275,23 @@ LibraryController::sync_files ()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
std::map<std::string, db::Library *> libs_by_name_here;
|
std::map<std::string, FileBasedLibrary *> libs_by_name_here;
|
||||||
|
|
||||||
// Reload all files
|
// Reload all files
|
||||||
for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) {
|
for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) {
|
||||||
|
|
||||||
std::string filename = tl::to_string (*im);
|
|
||||||
std::string lib_path = tl::to_string (lp.absoluteFilePath (*im));
|
std::string lib_path = tl::to_string (lp.absoluteFilePath (*im));
|
||||||
QFileInfo fi (tl::to_qstring (lib_path));
|
QFileInfo fi (tl::to_qstring (lib_path));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
std::unique_ptr<db::Library> lib (new db::Library ());
|
std::unique_ptr<FileBasedLibrary> lib (new FileBasedLibrary (lib_path));
|
||||||
lib->set_description (filename);
|
|
||||||
if (! p->second.empty ()) {
|
if (! p->second.empty ()) {
|
||||||
lib->set_technology (p->second);
|
lib->set_technology (p->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string libname = tl::to_string (QFileInfo (*im).baseName ());
|
|
||||||
|
|
||||||
tl::log << "Reading library '" << lib_path << "'";
|
tl::log << "Reading library '" << lib_path << "'";
|
||||||
tl::InputStream stream (lib_path);
|
std::string libname = lib->reload ();
|
||||||
db::Reader reader (stream);
|
|
||||||
reader.read (lib->layout ());
|
|
||||||
|
|
||||||
// Use the libname if there is one
|
|
||||||
db::Layout::meta_info_name_id_type libname_name_id = lib->layout ().meta_info_name_id ("libname");
|
|
||||||
for (db::Layout::meta_info_iterator m = lib->layout ().begin_meta (); m != lib->layout ().end_meta (); ++m) {
|
|
||||||
if (m->first == libname_name_id && ! m->second.value.is_nil ()) {
|
|
||||||
libname = m->second.value.to_string ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge with existing lib if there is already one in this folder with the right name
|
// merge with existing lib if there is already one in this folder with the right name
|
||||||
auto il = libs_by_name_here.find (libname);
|
auto il = libs_by_name_here.find (libname);
|
||||||
|
|
@ -240,21 +299,7 @@ LibraryController::sync_files ()
|
||||||
|
|
||||||
tl::log << "Merging with other library file with the same name: " << libname;
|
tl::log << "Merging with other library file with the same name: " << libname;
|
||||||
|
|
||||||
db::Library *org_lib = il->second;
|
il->second->merge_with_other_layout (lib_path);
|
||||||
db::Layout &org_layout = org_lib->layout ();
|
|
||||||
|
|
||||||
std::vector<db::cell_index_type> target_cells, source_cells;
|
|
||||||
|
|
||||||
// collect the cells to pull in (all top cells of the library layout)
|
|
||||||
for (auto c = lib->layout ().begin_top_down (); c != lib->layout ().end_top_cells (); ++c) {
|
|
||||||
std::string cn = lib->layout ().cell_name (*c);
|
|
||||||
source_cells.push_back (*c);
|
|
||||||
target_cells.push_back (org_layout.add_cell (cn.c_str ()));
|
|
||||||
}
|
|
||||||
|
|
||||||
db::CellMapping cm;
|
|
||||||
cm.create_multi_mapping_full (org_layout, target_cells, lib->layout (), source_cells);
|
|
||||||
org_layout.copy_tree_shapes (lib->layout (), cm);
|
|
||||||
|
|
||||||
// now, we can forget the new library as it is included in the first one
|
// now, we can forget the new library as it is included in the first one
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2564,6 +2564,12 @@ MainWindow::cm_writer_options ()
|
||||||
mp_layout_save_options->edit_global_options (dispatcher (), db::Technologies::instance ());
|
mp_layout_save_options->edit_global_options (dispatcher (), db::Technologies::instance ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MainWindow::cm_refresh ()
|
||||||
|
{
|
||||||
|
db::LibraryManager::instance ().refresh_all ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::cm_new_panel ()
|
MainWindow::cm_new_panel ()
|
||||||
{
|
{
|
||||||
|
|
@ -4045,6 +4051,8 @@ MainWindow::menu_activated (const std::string &symbol)
|
||||||
cm_reader_options ();
|
cm_reader_options ();
|
||||||
} else if (symbol == "cm_writer_options") {
|
} else if (symbol == "cm_writer_options") {
|
||||||
cm_writer_options ();
|
cm_writer_options ();
|
||||||
|
} else if (symbol == "cm_refresh") {
|
||||||
|
cm_refresh ();
|
||||||
} else if (symbol == "cm_new_panel") {
|
} else if (symbol == "cm_new_panel") {
|
||||||
cm_new_panel ();
|
cm_new_panel ();
|
||||||
} else if (symbol == "cm_new_layout") {
|
} else if (symbol == "cm_new_layout") {
|
||||||
|
|
@ -4458,6 +4466,7 @@ public:
|
||||||
menu_entries.push_back (lay::menu_item ("cm_close_all", "close_all:edit", at, tl::to_string (QObject::tr ("Close All(Shift+Ctrl+W)"))));
|
menu_entries.push_back (lay::menu_item ("cm_close_all", "close_all:edit", at, tl::to_string (QObject::tr ("Close All(Shift+Ctrl+W)"))));
|
||||||
menu_entries.push_back (lay::menu_item ("cm_clone", "clone", at, tl::to_string (QObject::tr ("Clone Panel"))));
|
menu_entries.push_back (lay::menu_item ("cm_clone", "clone", at, tl::to_string (QObject::tr ("Clone Panel"))));
|
||||||
menu_entries.push_back (lay::menu_item ("cm_reload", "reload:edit", at, tl::to_string (QObject::tr ("Reload(Ctrl+R)"))));
|
menu_entries.push_back (lay::menu_item ("cm_reload", "reload:edit", at, tl::to_string (QObject::tr ("Reload(Ctrl+R)"))));
|
||||||
|
menu_entries.push_back (lay::menu_item ("cm_refresh", "refresh:edit", at, tl::to_string (QObject::tr ("Refresh Libraries"))));
|
||||||
menu_entries.push_back (lay::menu_item ("cm_pull_in", "pull_in:edit", at, tl::to_string (QObject::tr ("Pull In Other Layout"))));
|
menu_entries.push_back (lay::menu_item ("cm_pull_in", "pull_in:edit", at, tl::to_string (QObject::tr ("Pull In Other Layout"))));
|
||||||
menu_entries.push_back (lay::menu_item ("cm_reader_options", "reader_options", at, tl::to_string (QObject::tr ("Reader Options"))));
|
menu_entries.push_back (lay::menu_item ("cm_reader_options", "reader_options", at, tl::to_string (QObject::tr ("Reader Options"))));
|
||||||
menu_entries.push_back (lay::separator ("open_recent_group", at));
|
menu_entries.push_back (lay::separator ("open_recent_group", at));
|
||||||
|
|
|
||||||
|
|
@ -837,6 +837,7 @@ private:
|
||||||
void cm_pull_in ();
|
void cm_pull_in ();
|
||||||
void cm_reader_options ();
|
void cm_reader_options ();
|
||||||
void cm_writer_options ();
|
void cm_writer_options ();
|
||||||
|
void cm_refresh ();
|
||||||
void cm_new_panel ();
|
void cm_new_panel ();
|
||||||
void cm_new_layout ();
|
void cm_new_layout ();
|
||||||
void cm_clone ();
|
void cm_clone ();
|
||||||
|
|
|
||||||
|
|
@ -879,6 +879,7 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase (decl_Dispatcher,
|
||||||
gsi::method ("active_cellview_index=|#active_setview_index=|#set_active_cellview_index", &lay::LayoutViewBase::set_active_cellview_index, gsi::arg ("index"),
|
gsi::method ("active_cellview_index=|#active_setview_index=|#set_active_cellview_index", &lay::LayoutViewBase::set_active_cellview_index, gsi::arg ("index"),
|
||||||
"@brief Makes the cellview with the given index the active one (shown in hierarchy browser)\n"
|
"@brief Makes the cellview with the given index the active one (shown in hierarchy browser)\n"
|
||||||
"See \\active_cellview_index.\n"
|
"See \\active_cellview_index.\n"
|
||||||
|
"Note, that this changing the active cell view index has side effects such as terminating an editing operation.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been renamed from set_active_cellview_index to active_cellview_index= in version 0.25. "
|
"This method has been renamed from set_active_cellview_index to active_cellview_index= in version 0.25. "
|
||||||
"The original name is still available, but is deprecated."
|
"The original name is still available, but is deprecated."
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ Editables::del (db::Transaction *transaction)
|
||||||
e->del ();
|
e->del ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signal_selection_changed ();
|
||||||
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
trans_holder->cancel ();
|
trans_holder->cancel ();
|
||||||
throw;
|
throw;
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,12 @@ LayoutViewBase::shutdown ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: this must happen before the services are deleted
|
||||||
|
mp_move_service = 0;
|
||||||
|
mp_selection_service = 0;
|
||||||
|
mp_tracker = 0;
|
||||||
|
mp_zoom_service = 0;
|
||||||
|
|
||||||
// delete all plugins
|
// delete all plugins
|
||||||
std::vector<lay::Plugin *> plugins;
|
std::vector<lay::Plugin *> plugins;
|
||||||
plugins.swap (mp_plugins);
|
plugins.swap (mp_plugins);
|
||||||
|
|
@ -4943,6 +4949,19 @@ LayoutViewBase::active_cellview_index () const
|
||||||
return m_active_cellview_index;
|
return m_active_cellview_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayoutViewBase::set_active_cellview_index_silent (int index)
|
||||||
|
{
|
||||||
|
enable_active_cellview_changed_event (false);
|
||||||
|
try {
|
||||||
|
set_active_cellview_index (index);
|
||||||
|
enable_active_cellview_changed_event (true, true /*silent*/);
|
||||||
|
} catch (...) {
|
||||||
|
enable_active_cellview_changed_event (true, true /*silent*/);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayoutViewBase::set_active_cellview_index (int index)
|
LayoutViewBase::set_active_cellview_index (int index)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2151,6 +2151,12 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void set_active_cellview_index (int index);
|
virtual void set_active_cellview_index (int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select a certain cellview for the active one
|
||||||
|
* This version does not emit any events while changing the cellview index
|
||||||
|
*/
|
||||||
|
void set_active_cellview_index_silent (int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief An event triggered if the active cellview changes
|
* @brief An event triggered if the active cellview changes
|
||||||
* This event is triggered after the active cellview changed.
|
* This event is triggered after the active cellview changed.
|
||||||
|
|
|
||||||
|
|
@ -707,11 +707,41 @@ HierarchyControlPanel::update_required ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
HierarchyControlPanel::select_active (int cellview_index)
|
HierarchyControlPanel::select_active (int cellview_index, bool silent)
|
||||||
{
|
{
|
||||||
if (cellview_index != m_active_index) {
|
if (cellview_index != m_active_index) {
|
||||||
mp_selector->setCurrentIndex (cellview_index);
|
mp_selector->setCurrentIndex (cellview_index);
|
||||||
selection_changed (cellview_index);
|
change_active_cellview (cellview_index);
|
||||||
|
if (! silent) {
|
||||||
|
emit active_cellview_changed (cellview_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HierarchyControlPanel::change_active_cellview (int index)
|
||||||
|
{
|
||||||
|
search_editing_finished ();
|
||||||
|
|
||||||
|
m_active_index = index;
|
||||||
|
|
||||||
|
bool split_mode = m_split_mode;
|
||||||
|
// for more than max_cellviews_in_split_mode cellviews, switch to overlay mode
|
||||||
|
if (int (m_cellviews.size ()) > max_cellviews_in_split_mode) {
|
||||||
|
split_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (std::vector <QFrame *>::const_iterator f = mp_cell_list_frames.begin (); f != mp_cell_list_frames.end (); ++f, ++i) {
|
||||||
|
(*f)->setVisible (i == index || split_mode);
|
||||||
|
if (i == index) {
|
||||||
|
mp_cell_lists [i]->setFocus ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (std::vector <QToolButton *>::const_iterator f = mp_cell_list_headers.begin (); f != mp_cell_list_headers.end (); ++f, ++i) {
|
||||||
|
(*f)->setChecked (i == index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -719,32 +749,8 @@ void
|
||||||
HierarchyControlPanel::selection_changed (int index)
|
HierarchyControlPanel::selection_changed (int index)
|
||||||
{
|
{
|
||||||
if (index != m_active_index) {
|
if (index != m_active_index) {
|
||||||
|
change_active_cellview (index);
|
||||||
search_editing_finished ();
|
|
||||||
|
|
||||||
m_active_index = index;
|
|
||||||
|
|
||||||
bool split_mode = m_split_mode;
|
|
||||||
// for more than max_cellviews_in_split_mode cellviews, switch to overlay mode
|
|
||||||
if (int (m_cellviews.size ()) > max_cellviews_in_split_mode) {
|
|
||||||
split_mode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (std::vector <QFrame *>::const_iterator f = mp_cell_list_frames.begin (); f != mp_cell_list_frames.end (); ++f, ++i) {
|
|
||||||
(*f)->setVisible (i == index || split_mode);
|
|
||||||
if (i == index) {
|
|
||||||
mp_cell_lists [i]->setFocus ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (std::vector <QToolButton *>::const_iterator f = mp_cell_list_headers.begin (); f != mp_cell_list_headers.end (); ++f, ++i) {
|
|
||||||
(*f)->setChecked (i == index);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit active_cellview_changed (index);
|
emit active_cellview_changed (index);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ public:
|
||||||
* selects the active cellview by index. The index must be
|
* selects the active cellview by index. The index must be
|
||||||
* a valid index within the context of the layout view.
|
* a valid index within the context of the layout view.
|
||||||
*/
|
*/
|
||||||
void select_active (int cellview_index);
|
void select_active (int cellview_index, bool silent = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the active cellview
|
* @brief Get the active cellview
|
||||||
|
|
@ -346,6 +346,9 @@ private:
|
||||||
|
|
||||||
// ask for cell copy mode
|
// ask for cell copy mode
|
||||||
bool ask_for_cell_copy_mode (const db::Layout &layout, const std::vector<cell_path_type> &paths, int &cell_copy_mode);
|
bool ask_for_cell_copy_mode (const db::Layout &layout, const std::vector<cell_path_type> &paths, int &cell_copy_mode);
|
||||||
|
|
||||||
|
// changes the active cellview
|
||||||
|
void change_active_cellview (int index);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lay
|
} // namespace lay
|
||||||
|
|
|
||||||
|
|
@ -341,6 +341,8 @@ BEGIN_PROTECTED
|
||||||
|
|
||||||
// confine the selection
|
// confine the selection
|
||||||
|
|
||||||
|
auto prev_selected = mp_editables->selection_size ();
|
||||||
|
|
||||||
mp_tree_model->begin_reset_model ();
|
mp_tree_model->begin_reset_model ();
|
||||||
|
|
||||||
auto selection = mp_ui->tree->selectionModel ()->selectedIndexes ();
|
auto selection = mp_ui->tree->selectionModel ()->selectedIndexes ();
|
||||||
|
|
@ -409,6 +411,10 @@ BEGIN_PROTECTED
|
||||||
|
|
||||||
update_controls ();
|
update_controls ();
|
||||||
|
|
||||||
|
if (m_objects != prev_selected) {
|
||||||
|
mp_editables->signal_selection_changed ();
|
||||||
|
}
|
||||||
|
|
||||||
END_PROTECTED
|
END_PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1392,7 +1392,8 @@ LayoutView::set_active_cellview_index (int index)
|
||||||
{
|
{
|
||||||
if (index >= 0 && index < int (cellviews ())) {
|
if (index >= 0 && index < int (cellviews ())) {
|
||||||
if (mp_hierarchy_panel) {
|
if (mp_hierarchy_panel) {
|
||||||
mp_hierarchy_panel->select_active (index);
|
// NOTE: we don't send events from here, that is done in "LayoutViewBase::set_active_cellview_index"
|
||||||
|
mp_hierarchy_panel->select_active (index, true /*no events*/);
|
||||||
}
|
}
|
||||||
LayoutViewBase::set_active_cellview_index (index);
|
LayoutViewBase::set_active_cellview_index (index);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,12 @@ class DBLayoutTests1_TestClass < TestBase
|
||||||
# delete_cell
|
# delete_cell
|
||||||
|
|
||||||
l = RBA::Layout.new
|
l = RBA::Layout.new
|
||||||
|
begin
|
||||||
|
l.delete_cell(0) # must throw an exception
|
||||||
|
assert_equal(true, false)
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
|
||||||
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
||||||
c0 = l.cell(l.add_cell("c0"))
|
c0 = l.cell(l.add_cell("c0"))
|
||||||
c1 = l.cell(l.add_cell("c1"))
|
c1 = l.cell(l.add_cell("c1"))
|
||||||
|
|
@ -371,6 +377,12 @@ class DBLayoutTests1_TestClass < TestBase
|
||||||
# delete_cells
|
# delete_cells
|
||||||
|
|
||||||
l = RBA::Layout.new
|
l = RBA::Layout.new
|
||||||
|
begin
|
||||||
|
l.delete_cells([0, 1]) # must throw an exception
|
||||||
|
assert_equal(true, false)
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
|
||||||
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
||||||
c0 = l.cell(l.add_cell("c0"))
|
c0 = l.cell(l.add_cell("c0"))
|
||||||
c1 = l.cell(l.add_cell("c1"))
|
c1 = l.cell(l.add_cell("c1"))
|
||||||
|
|
@ -412,6 +424,12 @@ class DBLayoutTests1_TestClass < TestBase
|
||||||
# prune_cell
|
# prune_cell
|
||||||
|
|
||||||
l = RBA::Layout.new
|
l = RBA::Layout.new
|
||||||
|
begin
|
||||||
|
l.prune_cell(0) # must throw an exception
|
||||||
|
assert_equal(true, false)
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
|
||||||
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
||||||
c0 = l.cell(l.add_cell("c0"))
|
c0 = l.cell(l.add_cell("c0"))
|
||||||
c1 = l.cell(l.add_cell("c1"))
|
c1 = l.cell(l.add_cell("c1"))
|
||||||
|
|
@ -488,6 +506,12 @@ class DBLayoutTests1_TestClass < TestBase
|
||||||
# delete_cell_rec
|
# delete_cell_rec
|
||||||
|
|
||||||
l = RBA::Layout.new
|
l = RBA::Layout.new
|
||||||
|
begin
|
||||||
|
l.delete_cell_rec(0) # must throw an exception
|
||||||
|
assert_equal(true, false)
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
|
||||||
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
||||||
c0 = l.cell(l.add_cell("c0"))
|
c0 = l.cell(l.add_cell("c0"))
|
||||||
c1 = l.cell(l.add_cell("c1"))
|
c1 = l.cell(l.add_cell("c1"))
|
||||||
|
|
@ -643,6 +667,12 @@ class DBLayoutTests1_TestClass < TestBase
|
||||||
# prune_subcells
|
# prune_subcells
|
||||||
|
|
||||||
l = RBA::Layout.new
|
l = RBA::Layout.new
|
||||||
|
begin
|
||||||
|
l.prune_subcells(0) # must throw an exception
|
||||||
|
assert_equal(true, false)
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
|
||||||
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
||||||
c0 = l.cell(l.add_cell("c0"))
|
c0 = l.cell(l.add_cell("c0"))
|
||||||
c1 = l.cell(l.add_cell("c1"))
|
c1 = l.cell(l.add_cell("c1"))
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,19 @@ end
|
||||||
|
|
||||||
load("test_prologue.rb")
|
load("test_prologue.rb")
|
||||||
|
|
||||||
|
class MyLibImpl < RBA::Library
|
||||||
|
def initialize
|
||||||
|
@reload_count = 0
|
||||||
|
end
|
||||||
|
def reload_count
|
||||||
|
@reload_count
|
||||||
|
end
|
||||||
|
def reload
|
||||||
|
@reload_count += 1
|
||||||
|
return "RBA-unit-test2"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class DBLibrary_TestClass < TestBase
|
class DBLibrary_TestClass < TestBase
|
||||||
|
|
||||||
def test_1_registration
|
def test_1_registration
|
||||||
|
|
@ -45,14 +58,17 @@ class DBLibrary_TestClass < TestBase
|
||||||
assert_equal(RBA::Library::library_names.member?("RBA-unit-test"), true)
|
assert_equal(RBA::Library::library_names.member?("RBA-unit-test"), true)
|
||||||
assert_equal(RBA::Library::library_by_name("RBA-unit-test").id, lib_id)
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test").id, lib_id)
|
||||||
|
|
||||||
# destroy should not do anything as libraries are not to be removed through the destructor
|
# The library reference is kept internally
|
||||||
lib._destroy
|
lib = nil
|
||||||
assert_equal(RBA::Library::library_by_name("RBA-unit-test").id, lib_id)
|
GC.start
|
||||||
assert_equal(lib.destroyed?, true)
|
GC.start
|
||||||
|
|
||||||
lib = RBA::Library::library_by_name("RBA-unit-test")
|
lib = RBA::Library::library_by_name("RBA-unit-test")
|
||||||
assert_equal(lib.destroyed?, false)
|
assert_equal(lib.name, "RBA-unit-test")
|
||||||
lib.delete
|
|
||||||
|
lib._destroy
|
||||||
|
assert_equal(lib.destroyed?, true)
|
||||||
|
|
||||||
assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -103,6 +119,128 @@ class DBLibrary_TestClass < TestBase
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_4_library_registration_and_rename
|
||||||
|
|
||||||
|
lib = RBA::Library::new
|
||||||
|
lib.description = "LIB1"
|
||||||
|
lib.delete
|
||||||
|
assert_equal(lib.destroyed?, true)
|
||||||
|
|
||||||
|
lib = RBA::Library::new
|
||||||
|
lib.layout.create_cell("A")
|
||||||
|
lib.description = "LIB1"
|
||||||
|
lib.register("RBA-unit-test")
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test").description, "LIB1")
|
||||||
|
|
||||||
|
lib.unregister
|
||||||
|
assert_equal(lib.destroyed?, false)
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
|
||||||
|
|
||||||
|
lib.register("RBA-unit-test")
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test").description, "LIB1")
|
||||||
|
|
||||||
|
ly = RBA::Layout::new
|
||||||
|
ci = ly.create_cell("A", "RBA-unit-test").cell_index
|
||||||
|
assert_equal(ly.cell(ci).qname, "RBA-unit-test.A")
|
||||||
|
|
||||||
|
lib.rename("RBA-unit-test2")
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test2").description, "LIB1")
|
||||||
|
|
||||||
|
assert_equal(ly.cell(ci).qname, "RBA-unit-test2.A")
|
||||||
|
|
||||||
|
lib.delete
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test2"), nil)
|
||||||
|
|
||||||
|
assert_equal(ly.cell(ci).qname, "<defunct>RBA-unit-test2.A")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5_reload
|
||||||
|
|
||||||
|
lib = MyLibImpl::new
|
||||||
|
lib.description = "LIB1"
|
||||||
|
lib.register("RBA-unit-test")
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test").description, "LIB1")
|
||||||
|
|
||||||
|
lib.refresh
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test2").description, "LIB1")
|
||||||
|
|
||||||
|
assert_equal(lib.reload_count, 1)
|
||||||
|
|
||||||
|
lib.delete
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
|
||||||
|
assert_equal(RBA::Library::library_by_name("RBA-unit-test2"), nil)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_6_cells_become_defunct_after_unregister
|
||||||
|
|
||||||
|
lib = RBA::Library::new
|
||||||
|
lib.description = "LIB1"
|
||||||
|
lib.register("RBA-unit-test")
|
||||||
|
|
||||||
|
cell_a = lib.layout.create_cell("A")
|
||||||
|
l1 = lib.layout.layer(1, 0)
|
||||||
|
cell_a.shapes(l1).insert(RBA::Box::new(0, 0, 1000, 2000))
|
||||||
|
|
||||||
|
ly = RBA::Layout::new
|
||||||
|
lc = ly.create_cell("A", "RBA-unit-test")
|
||||||
|
assert_equal(lc.qname, "RBA-unit-test.A")
|
||||||
|
ci = lc.cell_index
|
||||||
|
|
||||||
|
lib.unregister
|
||||||
|
|
||||||
|
# NOTE: cleanup has not been called, so we can find the cell using the cell_index
|
||||||
|
# (the actual cell object is no longer there because it has been replaced by
|
||||||
|
# a cold proxy)
|
||||||
|
lc = ly.cell(ci)
|
||||||
|
assert_equal(lc.qname, "<defunct>RBA-unit-test.A")
|
||||||
|
|
||||||
|
# this will restore the reference
|
||||||
|
lib.register("RBA-unit-test")
|
||||||
|
|
||||||
|
lc = ly.cell(ci)
|
||||||
|
assert_equal(lc.qname, "RBA-unit-test.A")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_7_change_ref
|
||||||
|
|
||||||
|
lib = RBA::Library::new
|
||||||
|
lib.description = "LIB1"
|
||||||
|
lib.register("RBA-unit-test")
|
||||||
|
l1 = lib.layout.layer(1, 0)
|
||||||
|
|
||||||
|
cell_a = lib.layout.create_cell("A")
|
||||||
|
cell_a.shapes(l1).insert(RBA::Box::new(0, 0, 1000, 2000))
|
||||||
|
|
||||||
|
lib2 = RBA::Library::new
|
||||||
|
lib2.description = "LIB2"
|
||||||
|
lib2.register("RBA-unit-test2")
|
||||||
|
l1 = lib2.layout.layer(1, 0)
|
||||||
|
|
||||||
|
cell_b = lib2.layout.create_cell("B")
|
||||||
|
cell_b.shapes(l1).insert(RBA::Box::new(0, 0, 2000, 1000))
|
||||||
|
|
||||||
|
ly = RBA::Layout::new
|
||||||
|
c1 = ly.create_cell("A", "RBA-unit-test")
|
||||||
|
assert_equal(c1.qname, "RBA-unit-test.A")
|
||||||
|
|
||||||
|
c1.change_ref(lib2.id, cell_b.cell_index)
|
||||||
|
assert_equal(c1.qname, "RBA-unit-test2.B")
|
||||||
|
|
||||||
|
ly = RBA::Layout::new
|
||||||
|
c1 = ly.create_cell("A", "RBA-unit-test")
|
||||||
|
assert_equal(c1.qname, "RBA-unit-test.A")
|
||||||
|
|
||||||
|
c1.change_ref("RBA-unit-test2", "B")
|
||||||
|
assert_equal(c1.qname, "RBA-unit-test2.B")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
load("test_epilogue.rb")
|
load("test_epilogue.rb")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue