mirror of https://github.com/KLayout/klayout.git
Merge remote-tracking branch 'origin/master' into wip
This commit is contained in:
commit
5055d4fcf4
|
|
@ -707,14 +707,12 @@ Layout::set_technology_name (const std::string &tech)
|
||||||
|
|
||||||
for (db::Layout::iterator c = begin (); c != end (); ++c) {
|
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);
|
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
|
||||||
if (! lib_proxy) {
|
if (! lib_proxy) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) {
|
if (mapping.find (lib_proxy->lib_id ()) != mapping.end ()) {
|
||||||
|
|
||||||
db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
|
db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
|
||||||
db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ());
|
db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ());
|
||||||
|
|
@ -745,7 +743,10 @@ Layout::set_technology_name (const std::string &tech)
|
||||||
db::cell_index_type ci = lp->first->Cell::cell_index ();
|
db::cell_index_type ci = lp->first->Cell::cell_index ();
|
||||||
db::PCellVariant *lib_pcell = lp->second;
|
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 ());
|
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]);
|
||||||
|
tl_assert (new_lib != 0);
|
||||||
|
|
||||||
|
std::pair<bool, pcell_id_type> pn = new_lib->layout ().pcell_by_name (lp->first->get_basic_name ().c_str ());
|
||||||
|
|
||||||
if (! pn.first) {
|
if (! pn.first) {
|
||||||
|
|
||||||
|
|
@ -756,8 +757,6 @@ Layout::set_technology_name (const std::string &tech)
|
||||||
|
|
||||||
} else {
|
} 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 *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);
|
const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second);
|
||||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "layStream.h"
|
#include "layStream.h"
|
||||||
#include "layAbstractMenu.h"
|
#include "layAbstractMenu.h"
|
||||||
#include "layMainWindow.h"
|
#include "layMainWindow.h"
|
||||||
|
#include "tlLog.h"
|
||||||
#include "ui_MainConfigPage.h"
|
#include "ui_MainConfigPage.h"
|
||||||
#include "ui_MainConfigPage2.h"
|
#include "ui_MainConfigPage2.h"
|
||||||
#include "ui_MainConfigPage3.h"
|
#include "ui_MainConfigPage3.h"
|
||||||
|
|
@ -412,15 +413,31 @@ CustomizeMenuConfigPage::apply (const std::vector<std::pair<std::string, std::st
|
||||||
// gets the current bindings and merges with the given ones
|
// gets the current bindings and merges with the given ones
|
||||||
m_current_bindings = mp_dispatcher->menu ()->get_shortcuts (false);
|
m_current_bindings = mp_dispatcher->menu ()->get_shortcuts (false);
|
||||||
|
|
||||||
|
// retained bindings, even if not configured
|
||||||
|
std::vector<std::map<std::string, std::string>::iterator> retained;
|
||||||
|
std::set<std::string> shortcuts;
|
||||||
|
|
||||||
|
// initialize configured bindings, clear others (for now) and remember
|
||||||
std::map<std::string, std::string> b;
|
std::map<std::string, std::string> b;
|
||||||
b.insert (key_bindings.begin (), key_bindings.end ());
|
b.insert (key_bindings.begin (), key_bindings.end ());
|
||||||
for (std::map<std::string, std::string>::iterator kb = m_current_bindings.begin (); kb != m_current_bindings.end (); ++kb) {
|
for (auto kb = m_current_bindings.begin (); kb != m_current_bindings.end (); ++kb) {
|
||||||
std::map<std::string, std::string>::iterator bb = b.find (kb->first);
|
std::map<std::string, std::string>::iterator bb = b.find (kb->first);
|
||||||
if (bb != b.end ()) {
|
if (bb != b.end ()) {
|
||||||
lay::Action *a = mp_dispatcher->menu ()->action (kb->first);
|
lay::Action *a = mp_dispatcher->menu ()->action (kb->first);
|
||||||
kb->second = a->get_effective_shortcut_for (bb->second);
|
kb->second = a->get_effective_shortcut_for (bb->second);
|
||||||
} else {
|
if (! kb->second.empty ()) {
|
||||||
kb->second.clear ();
|
shortcuts.insert (kb->second);
|
||||||
|
}
|
||||||
|
} else if (! kb->second.empty ()) {
|
||||||
|
retained.push_back (kb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retain key bindings which don't conflict
|
||||||
|
for (auto i = retained.begin (); i != retained.end (); ++i) {
|
||||||
|
if (shortcuts.find ((*i)->second) != shortcuts.end ()) {
|
||||||
|
tl::warn << tl::sprintf (tl::to_string (tr ("Resetting key binding for '%s' (was '%s') because of conflicts")), (*i)->first, (*i)->second);
|
||||||
|
(*i)->second.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1970,6 +1970,18 @@ MainWindow::redraw ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MainWindow::cm_grid_decrease ()
|
||||||
|
{
|
||||||
|
change_grid (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MainWindow::cm_grid_increase ()
|
||||||
|
{
|
||||||
|
change_grid (1);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::cm_cancel ()
|
MainWindow::cm_cancel ()
|
||||||
{
|
{
|
||||||
|
|
@ -4041,6 +4053,10 @@ MainWindow::menu_activated (const std::string &symbol)
|
||||||
cm_bookmark_view ();
|
cm_bookmark_view ();
|
||||||
} else if (symbol == "cm_cancel") {
|
} else if (symbol == "cm_cancel") {
|
||||||
cm_cancel ();
|
cm_cancel ();
|
||||||
|
} else if (symbol == "cm_grid_decrease") {
|
||||||
|
cm_grid_decrease ();
|
||||||
|
} else if (symbol == "cm_grid_increase") {
|
||||||
|
cm_grid_increase ();
|
||||||
} else if (symbol == "cm_save_layer_props") {
|
} else if (symbol == "cm_save_layer_props") {
|
||||||
cm_save_layer_props ();
|
cm_save_layer_props ();
|
||||||
} else if (symbol == "cm_load_layer_props") {
|
} else if (symbol == "cm_load_layer_props") {
|
||||||
|
|
@ -4137,38 +4153,114 @@ MainWindow::menu_changed ()
|
||||||
dm_do_update_menu ();
|
dm_do_update_menu ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
std::vector<double>
|
||||||
MainWindow::do_update_grids ()
|
MainWindow::default_grids () const
|
||||||
{
|
{
|
||||||
const std::vector<double> *grids = &m_default_grids;
|
|
||||||
double default_grid = m_default_grid;
|
|
||||||
|
|
||||||
std::vector<double> tech_grids;
|
|
||||||
lay::TechnologyController *tc = lay::TechnologyController::instance ();
|
lay::TechnologyController *tc = lay::TechnologyController::instance ();
|
||||||
if (tc && tc->active_technology ()) {
|
if (tc && tc->active_technology ()) {
|
||||||
tech_grids = tc->active_technology ()->default_grid_list ();
|
std::vector<double> tech_grids = tc->active_technology ()->default_grid_list ();
|
||||||
if (! tech_grids.empty ()) {
|
if (! tech_grids.empty ()) {
|
||||||
grids = &tech_grids;
|
return tech_grids;
|
||||||
default_grid = tc->active_technology ()->default_grid ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (default_grid > db::epsilon) {
|
return m_default_grids;
|
||||||
for (auto g = grids->begin (); g != grids->end (); ++g) {
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
MainWindow::default_grid () const
|
||||||
|
{
|
||||||
|
lay::TechnologyController *tc = lay::TechnologyController::instance ();
|
||||||
|
if (tc && tc->active_technology ()) {
|
||||||
|
auto tech_grids = tc->active_technology ()->default_grid_list ();
|
||||||
|
if (! tech_grids.empty ()) {
|
||||||
|
return tc->active_technology ()->default_grid ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_default_grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MainWindow::change_grid (int dir)
|
||||||
|
{
|
||||||
|
std::vector<double> grids = default_grids ();
|
||||||
|
if (grids.empty ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort (grids.begin (), grids.end ());
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (std::vector<double>::const_iterator g = grids.begin (); g != grids.end (); ++g, ++i) {
|
||||||
|
if (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == grids.size ()) {
|
||||||
|
i = (dir > 0 ? grids.size () - 1 : 0);
|
||||||
|
} else {
|
||||||
|
if (dir > 0) {
|
||||||
|
if (i + 1 < grids.size ()) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
} else if (dir < 0) {
|
||||||
|
if (i > 0) {
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcher ()->config_set (cfg_grid, grids [i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MainWindow::do_update_grids ()
|
||||||
|
{
|
||||||
|
std::vector<double> grids = default_grids ();
|
||||||
|
double def_grid = default_grid ();
|
||||||
|
|
||||||
|
if (def_grid > db::epsilon) {
|
||||||
|
for (auto g = grids.begin (); g != grids.end (); ++g) {
|
||||||
if (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron)) {
|
if (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron)) {
|
||||||
default_grid = 0.0;
|
def_grid = 0.0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (default_grid > db::epsilon) {
|
if (def_grid > db::epsilon) {
|
||||||
dispatcher ()->config_set (cfg_grid, default_grid);
|
dispatcher ()->config_set (cfg_grid, def_grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
do_update_menu ();
|
do_update_menu ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class GenericMenuAction
|
||||||
|
: public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GenericMenuAction (lay::Dispatcher *dispatcher, const std::string &title, const std::string &symbol)
|
||||||
|
: Action (title), mp_dispatcher (dispatcher), m_symbol (symbol)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void triggered ()
|
||||||
|
{
|
||||||
|
if (mp_dispatcher) {
|
||||||
|
mp_dispatcher->menu_activated (m_symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Dispatcher *mp_dispatcher;
|
||||||
|
std::string m_symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::do_update_menu ()
|
MainWindow::do_update_menu ()
|
||||||
{
|
{
|
||||||
|
|
@ -4176,27 +4268,26 @@ MainWindow::do_update_menu ()
|
||||||
|
|
||||||
m_default_grids_updated = false;
|
m_default_grids_updated = false;
|
||||||
|
|
||||||
const std::vector<double> *grids = &m_default_grids;
|
std::vector<double> grids = default_grids ();
|
||||||
std::vector<double> tech_grids;
|
double def_grid = default_grid ();
|
||||||
lay::TechnologyController *tc = lay::TechnologyController::instance ();
|
|
||||||
if (tc && tc->active_technology ()) {
|
|
||||||
tech_grids = tc->active_technology ()->default_grid_list ();
|
|
||||||
if (! tech_grids.empty ()) {
|
|
||||||
grids = &tech_grids;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> group = menu ()->group ("default_grids_group");
|
std::vector<std::string> group = menu ()->group ("default_grids_group");
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator t = group.begin (); t != group.end (); ++t) {
|
for (std::vector<std::string>::const_iterator t = group.begin (); t != group.end (); ++t) {
|
||||||
|
|
||||||
std::vector<std::string> items = menu ()->items (*t);
|
std::vector<std::string> items = menu ()->items (*t);
|
||||||
for (std::vector<std::string>::const_iterator i = items.begin (); i != items.end (); ++i) {
|
for (std::vector<std::string>::const_iterator i = items.begin (); i != items.end (); ++i) {
|
||||||
menu ()->delete_item (*i);
|
menu ()->delete_item (*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu ()->insert_item (*t + ".end", "finer_grid", new GenericMenuAction (dispatcher (), tl::to_string (tr ("Finer Grid(G)")), "cm_grid_decrease"));
|
||||||
|
menu ()->insert_item (*t + ".end", "coarser_grid", new GenericMenuAction (dispatcher (), tl::to_string (tr ("Coarser Grid(Shift+G)")), "cm_grid_increase"));
|
||||||
|
menu ()->insert_separator (*t + ".end", "default_grids_group_separator");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
for (std::vector<double>::const_iterator g = grids->begin (); g != grids->end (); ++g, ++i) {
|
for (std::vector<double>::const_iterator g = grids.begin (); g != grids.end (); ++g, ++i) {
|
||||||
|
|
||||||
std::string name = "default_grid_" + tl::to_string (i);
|
std::string name = "default_grid_" + tl::to_string (i);
|
||||||
|
|
||||||
|
|
@ -4208,6 +4299,10 @@ MainWindow::do_update_menu ()
|
||||||
gs = tl::to_string (*g) + tl::to_string (QObject::tr (" um"));
|
gs = tl::to_string (*g) + tl::to_string (QObject::tr (" um"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (def_grid > 0 && db::coord_traits<db::DCoord>::equals (*g, def_grid)) {
|
||||||
|
gs += tl::to_string (tr (" \\(default)"));
|
||||||
|
}
|
||||||
|
|
||||||
lay::Action *ga = new lay::ConfigureAction (gs, cfg_grid, tl::to_string (*g));
|
lay::Action *ga = new lay::ConfigureAction (gs, cfg_grid, tl::to_string (*g));
|
||||||
ga->set_checkable (true);
|
ga->set_checkable (true);
|
||||||
ga->set_checked (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron));
|
ga->set_checked (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron));
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,28 @@ public:
|
||||||
*/
|
*/
|
||||||
double grid_micron () const;
|
double grid_micron () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a list of the default grids
|
||||||
|
*
|
||||||
|
* The default grids are globally defined, but may change depending on the technology
|
||||||
|
* selected in the current view.
|
||||||
|
*/
|
||||||
|
std::vector<double> default_grids () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the default grid
|
||||||
|
*
|
||||||
|
* The default (fallback) grid is the one marked with "!" in the grid list
|
||||||
|
* and it is used, when the current grid is not one of the provided grids
|
||||||
|
* in the default grid list.
|
||||||
|
*
|
||||||
|
* The default grid is globally defined, but my change depending on the technology
|
||||||
|
* selected in the current view.
|
||||||
|
*
|
||||||
|
* If no such grid exists, 0 is returned.
|
||||||
|
*/
|
||||||
|
double default_grid () const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Hierarchy level selection setter
|
* @brief Hierarchy level selection setter
|
||||||
*/
|
*/
|
||||||
|
|
@ -818,6 +840,8 @@ private:
|
||||||
void cm_manage_bookmarks ();
|
void cm_manage_bookmarks ();
|
||||||
void cm_bookmark_view ();
|
void cm_bookmark_view ();
|
||||||
void cm_cancel ();
|
void cm_cancel ();
|
||||||
|
void cm_grid_decrease ();
|
||||||
|
void cm_grid_increase ();
|
||||||
void cm_save_layer_props ();
|
void cm_save_layer_props ();
|
||||||
void cm_load_layer_props ();
|
void cm_load_layer_props ();
|
||||||
void cm_save_session ();
|
void cm_save_session ();
|
||||||
|
|
@ -863,6 +887,8 @@ private:
|
||||||
void update_tab_title (int i);
|
void update_tab_title (int i);
|
||||||
void add_view (LayoutViewWidget *view);
|
void add_view (LayoutViewWidget *view);
|
||||||
|
|
||||||
|
void change_grid (int dir);
|
||||||
|
|
||||||
bool can_close ();
|
bool can_close ();
|
||||||
lay::CellViewRef create_or_load_layout (const std::string *filename, const db::LoadLayoutOptions *options, const std::string &tech, const int mode);
|
lay::CellViewRef create_or_load_layout (const std::string *filename, const db::LoadLayoutOptions *options, const std::string &tech, const int mode);
|
||||||
int do_create_view ();
|
int do_create_view ();
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "layPixelBufferPainter.h"
|
#include "layPixelBufferPainter.h"
|
||||||
#include "laySnap.h"
|
#include "laySnap.h"
|
||||||
#include "tlColor.h"
|
#include "tlColor.h"
|
||||||
|
#include "tlInternational.h"
|
||||||
#include "dbTrans.h"
|
#include "dbTrans.h"
|
||||||
|
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
|
|
@ -118,7 +119,7 @@ GridNetPluginDeclaration::get_options (std::vector < std::pair<std::string, std:
|
||||||
lay::ConfigPage *
|
lay::ConfigPage *
|
||||||
GridNetPluginDeclaration::config_page (QWidget *parent, std::string &title) const
|
GridNetPluginDeclaration::config_page (QWidget *parent, std::string &title) const
|
||||||
{
|
{
|
||||||
title = tl::to_string (QObject::tr ("Display|Background"));
|
title = tl::to_string (tr ("Display|Background"));
|
||||||
return new GridNetConfigPage (parent);
|
return new GridNetConfigPage (parent);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -216,9 +217,21 @@ GridNet::configure (const std::string &name, const std::string &value)
|
||||||
double g = 0;
|
double g = 0;
|
||||||
tl::from_string (value, g);
|
tl::from_string (value, g);
|
||||||
if (fabs (g - m_grid) > 1e-6) {
|
if (fabs (g - m_grid) > 1e-6) {
|
||||||
|
|
||||||
m_grid = g;
|
m_grid = g;
|
||||||
need_update = true;
|
need_update = true;
|
||||||
|
|
||||||
|
std::string gs;
|
||||||
|
if (m_grid < 0.4) {
|
||||||
|
// pick nm units below 400nm
|
||||||
|
gs = tl::to_string (m_grid * 1000.0) + tl::to_string (tr (" nm"));
|
||||||
|
} else {
|
||||||
|
gs = tl::to_string (m_grid) + tl::to_string (tr (" um"));
|
||||||
|
}
|
||||||
|
mp_view->message (tl::sprintf (tl::to_string (tr ("Grid: %s")), gs));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
taken = false; // to let others use the grid too.
|
taken = false; // to let others use the grid too.
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@ namespace pya
|
||||||
void
|
void
|
||||||
pya_object_deallocate (PyObject *self)
|
pya_object_deallocate (PyObject *self)
|
||||||
{
|
{
|
||||||
|
// Clear weak refs - needed for signal binding and other purposes
|
||||||
|
#if PY_VERSION_HEX > 0x03020000
|
||||||
|
PyObject_ClearWeakRefs (self);
|
||||||
|
#endif
|
||||||
|
|
||||||
// This avoids an assertion in debug builds (Python, gcmodule.c - update_refs).
|
// This avoids an assertion in debug builds (Python, gcmodule.c - update_refs).
|
||||||
// In short, the GC expects not to see objects with refcount 0 and asserts.
|
// In short, the GC expects not to see objects with refcount 0 and asserts.
|
||||||
// However, due to triggering of signals or similar, the destructor call below
|
// However, due to triggering of signals or similar, the destructor call below
|
||||||
|
|
|
||||||
|
|
@ -337,6 +337,11 @@ public:
|
||||||
#if PY_VERSION_HEX >= 0x030D0000
|
#if PY_VERSION_HEX >= 0x030D0000
|
||||||
// crashes with this option set
|
// crashes with this option set
|
||||||
type->tp_flags &= ~Py_TPFLAGS_INLINE_VALUES;
|
type->tp_flags &= ~Py_TPFLAGS_INLINE_VALUES;
|
||||||
|
#endif
|
||||||
|
#if PY_VERSION_HEX < 0x03000000
|
||||||
|
type->tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS;
|
||||||
|
type->tp_weaklistoffset = type->tp_basicsize;
|
||||||
|
type->tp_basicsize += sizeof (PyObject *);
|
||||||
#endif
|
#endif
|
||||||
type->tp_basicsize += sizeof (PYAObjectBase);
|
type->tp_basicsize += sizeof (PYAObjectBase);
|
||||||
type->tp_init = &pya_object_init;
|
type->tp_init = &pya_object_init;
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ RUBYTEST (dbNetlistReaderTests, "dbNetlistReaderTests.rb")
|
||||||
RUBYTEST (dbNetlistCompare, "dbNetlistCompare.rb")
|
RUBYTEST (dbNetlistCompare, "dbNetlistCompare.rb")
|
||||||
RUBYTEST (dbPathTest, "dbPathTest.rb")
|
RUBYTEST (dbPathTest, "dbPathTest.rb")
|
||||||
RUBYTEST (dbPCells, "dbPCells.rb")
|
RUBYTEST (dbPCells, "dbPCells.rb")
|
||||||
|
RUBYTEST (dbPCellsRebind, "dbPCellsRebind.rb")
|
||||||
RUBYTEST (dbPointTest, "dbPointTest.rb")
|
RUBYTEST (dbPointTest, "dbPointTest.rb")
|
||||||
RUBYTEST (dbPolygonTest, "dbPolygonTest.rb")
|
RUBYTEST (dbPolygonTest, "dbPolygonTest.rb")
|
||||||
RUBYTEST (dbRegionTest, "dbRegionTest.rb")
|
RUBYTEST (dbRegionTest, "dbRegionTest.rb")
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import gc
|
import gc
|
||||||
import copy
|
import copy
|
||||||
|
import weakref
|
||||||
|
|
||||||
# Set this to True to disable some tests involving exceptions
|
# Set this to True to disable some tests involving exceptions
|
||||||
leak_check = "TEST_LEAK_CHECK" in os.environ
|
leak_check = "TEST_LEAK_CHECK" in os.environ
|
||||||
|
|
@ -3352,6 +3353,20 @@ class BasicTest(unittest.TestCase):
|
||||||
self.assertEqual(bc.str(), "xyz")
|
self.assertEqual(bc.str(), "xyz")
|
||||||
self.assertEqual(bnc.str(), "xyz")
|
self.assertEqual(bnc.str(), "xyz")
|
||||||
|
|
||||||
|
# weak refs
|
||||||
|
def test_94(self):
|
||||||
|
|
||||||
|
b = pya.B()
|
||||||
|
b.set_str("abc")
|
||||||
|
|
||||||
|
r = weakref.ref(b)
|
||||||
|
self.assertEqual(r() is None, False)
|
||||||
|
self.assertEqual(r().str(), "abc")
|
||||||
|
|
||||||
|
b = None
|
||||||
|
self.assertEqual(r() is None, True)
|
||||||
|
|
||||||
|
|
||||||
# run unit tests
|
# run unit tests
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
# encoding: UTF-8
|
||||||
|
|
||||||
|
# KLayout Layout Viewer
|
||||||
|
# Copyright (C) 2006-2026 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
|
||||||
|
|
||||||
|
if !$:.member?(File::dirname($0))
|
||||||
|
$:.push(File::dirname($0))
|
||||||
|
end
|
||||||
|
|
||||||
|
load("test_prologue.rb")
|
||||||
|
|
||||||
|
class PCellRebindVar < RBA::PCellDeclaration
|
||||||
|
|
||||||
|
def initialize(name, layer, w_name, w_default)
|
||||||
|
@name = name
|
||||||
|
@layer = layer
|
||||||
|
@w_name = w_name
|
||||||
|
@w_default = w_default
|
||||||
|
end
|
||||||
|
|
||||||
|
def display_text(parameters)
|
||||||
|
return "#{@name}(L=#{@layer},#{@w_name}=#{parameters[0].to_s},H=#{parameters[1].to_s})"
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_parameters
|
||||||
|
|
||||||
|
# prepare a set of parameter declarations
|
||||||
|
param = []
|
||||||
|
|
||||||
|
param.push(RBA::PCellParameterDeclaration.new(@w_name, RBA::PCellParameterDeclaration::TypeDouble, "Width", @w_default))
|
||||||
|
param.push(RBA::PCellParameterDeclaration.new("H", RBA::PCellParameterDeclaration::TypeDouble, "Height", 1.0))
|
||||||
|
|
||||||
|
return param
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_layers(parameters)
|
||||||
|
return [ RBA::LayerInfo::new(@layer, 0) ]
|
||||||
|
end
|
||||||
|
|
||||||
|
def produce(layout, layers, parameters, cell)
|
||||||
|
|
||||||
|
# fetch the parameters
|
||||||
|
w = parameters[0]
|
||||||
|
h = parameters[1]
|
||||||
|
|
||||||
|
# create the shape
|
||||||
|
cell.shapes(layout.layer(@layer, 0)).insert(RBA::DBox.new(-w / 2, -h / 2, w / 2, h / 2))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class RebindTestLib < RBA::Library
|
||||||
|
|
||||||
|
def initialize(var)
|
||||||
|
|
||||||
|
# set the description
|
||||||
|
self.description = "PCell rebind test lib"
|
||||||
|
|
||||||
|
# create the PCell declarations
|
||||||
|
if var == 0
|
||||||
|
layout.register_pcell("Box0", PCellRebindVar::new("Box0", 0, "W", 3.0))
|
||||||
|
layout.register_pcell("Box1", PCellRebindVar::new("Box1", 1, "W", 2.0))
|
||||||
|
layout.register_pcell("Box2A", PCellRebindVar::new("Box2A", 2, "W", 1.0))
|
||||||
|
else
|
||||||
|
layout.register_pcell("Box2B", PCellRebindVar::new("Box2B", 12, "W", 1.5))
|
||||||
|
layout.register_pcell("Box1", PCellRebindVar::new("Box1", 11, "WW", 2.5))
|
||||||
|
layout.register_pcell("Box0", PCellRebindVar::new("Box0", 10, "W", 3.5))
|
||||||
|
end
|
||||||
|
|
||||||
|
self.technology = (var == 0 ? "T0" : "T1")
|
||||||
|
|
||||||
|
register("RebindTestLib")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def c2s(cell)
|
||||||
|
ly = cell.layout
|
||||||
|
s = []
|
||||||
|
ly.layer_indexes.collect { |li| ly.get_info(li) }.sort { |a,b| [ a.layer, a.datatype ] <=> [ b.layer, b.datatype ] }.each do |lp|
|
||||||
|
bbox = cell.dbbox(ly.layer(lp))
|
||||||
|
bbox.empty? || (s << lp.to_s + ":" + bbox.to_s)
|
||||||
|
end
|
||||||
|
s.join(";")
|
||||||
|
end
|
||||||
|
|
||||||
|
class DBPCellRebind_TestClass < TestBase
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
|
||||||
|
tl0 = RebindTestLib::new(0)
|
||||||
|
tl1 = RebindTestLib::new(1)
|
||||||
|
|
||||||
|
assert_equal(tl0.is_for_technology("T0"), true)
|
||||||
|
assert_equal(tl0.is_for_technology("T1"), false)
|
||||||
|
assert_equal(tl1.is_for_technology("T0"), false)
|
||||||
|
assert_equal(tl1.is_for_technology("T1"), true)
|
||||||
|
|
||||||
|
ly = RBA::Layout::new
|
||||||
|
ly.technology_name = "T0"
|
||||||
|
|
||||||
|
top = ly.create_cell("TOP")
|
||||||
|
|
||||||
|
# in T0:
|
||||||
|
# Box0 -> on layer 0, w parameter is "W" with default 3.0
|
||||||
|
# Box1 -> on layer 1, w parameter is "W" with default 2.0
|
||||||
|
# Box2A -> on layer 2, w parameter is "W" with default 1.0
|
||||||
|
# Box2B does not exist
|
||||||
|
|
||||||
|
c0 = ly.create_cell("Box0", "RebindTestLib", { "W" => 0.3, "H" => 0.5 })
|
||||||
|
c1 = ly.create_cell("Box1", "RebindTestLib", { "W" => 0.4, "H" => 0.6 })
|
||||||
|
c2 = ly.create_cell("Box2A", "RebindTestLib", { "W" => 0.5, "H" => 0.7 })
|
||||||
|
|
||||||
|
top.insert(RBA::CellInstArray::new(c0.cell_index(), RBA::Trans::new))
|
||||||
|
top.insert(RBA::CellInstArray::new(c1.cell_index(), RBA::Trans::new))
|
||||||
|
top.insert(RBA::CellInstArray::new(c2.cell_index(), RBA::Trans::new))
|
||||||
|
|
||||||
|
assert_equal(c0.display_title, "RebindTestLib.Box0(L=0,W=0.3,H=0.5)")
|
||||||
|
assert_equal(c2s(c0), "0/0:(-0.15,-0.25;0.15,0.25)")
|
||||||
|
|
||||||
|
assert_equal(c1.display_title, "RebindTestLib.Box1(L=1,W=0.4,H=0.6)")
|
||||||
|
assert_equal(c2s(c1), "1/0:(-0.2,-0.3;0.2,0.3)")
|
||||||
|
|
||||||
|
assert_equal(c2.display_title, "RebindTestLib.Box2A(L=2,W=0.5,H=0.7)")
|
||||||
|
assert_equal(c2s(c2), "2/0:(-0.25,-0.35;0.25,0.35)")
|
||||||
|
|
||||||
|
# in T0:
|
||||||
|
# Box0 -> on layer 0, w parameter is "W" with default 3.5
|
||||||
|
# Box1 -> on layer 1, w parameter is "WW" with default 2.5
|
||||||
|
# Box2A does not exist
|
||||||
|
# Box2B -> on layer 2, w parameter is "W" with default 1.5
|
||||||
|
|
||||||
|
ly.technology_name = "T1"
|
||||||
|
|
||||||
|
assert_equal(c0.destroyed, false)
|
||||||
|
assert_equal(c1.destroyed, false)
|
||||||
|
assert_equal(c2.destroyed, true) # becomes a cold proxy
|
||||||
|
|
||||||
|
c0 = ly.cell("Box0")
|
||||||
|
c1 = ly.cell("Box1")
|
||||||
|
c2 = ly.cell("Box2A")
|
||||||
|
|
||||||
|
# layer changed, but parameters can be translated
|
||||||
|
assert_equal(c0.display_title, "RebindTestLib.Box0(L=10,W=0.3,H=0.5)")
|
||||||
|
assert_equal(c2s(c0), "10/0:(-0.15,-0.25;0.15,0.25)")
|
||||||
|
|
||||||
|
# Layer changed and "W" parameter can't be translated as the name changed to "WW"
|
||||||
|
assert_equal(c1.display_title, "RebindTestLib.Box1(L=11,WW=2.5,H=0.6)")
|
||||||
|
assert_equal(c2s(c1), "11/0:(-1.25,-0.3;1.25,0.3)")
|
||||||
|
|
||||||
|
# Box2A does no longer exist -> cold proxy
|
||||||
|
assert_equal(c2.display_title, "<defunct>RebindTestLib.Box2A")
|
||||||
|
assert_equal(c2s(c2), "2/0:(-0.25,-0.35;0.25,0.35)")
|
||||||
|
|
||||||
|
ly.technology_name = "T0"
|
||||||
|
|
||||||
|
assert_equal(c0.destroyed, false)
|
||||||
|
assert_equal(c1.destroyed, false)
|
||||||
|
assert_equal(c2.destroyed, true) # became an active PCell variant again
|
||||||
|
|
||||||
|
c0 = ly.cell("Box0")
|
||||||
|
c1 = ly.cell("Box1")
|
||||||
|
c2 = ly.cell("Box2A")
|
||||||
|
|
||||||
|
# layer changed, but parameters can be translated
|
||||||
|
assert_equal(c0.display_title, "RebindTestLib.Box0(L=0,W=0.3,H=0.5)")
|
||||||
|
assert_equal(c2s(c0), "0/0:(-0.15,-0.25;0.15,0.25)")
|
||||||
|
|
||||||
|
# Layer changed and "WW" parameter can't be translated as the name changed back to "W"
|
||||||
|
assert_equal(c1.display_title, "RebindTestLib.Box1(L=1,W=2.0,H=0.6)")
|
||||||
|
assert_equal(c2s(c1), "1/0:(-1,-0.3;1,0.3)")
|
||||||
|
|
||||||
|
# Box2A is back to normal as the cold proxy kept the information
|
||||||
|
assert_equal(c2.display_title, "RebindTestLib.Box2A(L=2,W=0.5,H=0.7)")
|
||||||
|
assert_equal(c2s(c2), "2/0:(-0.25,-0.35;0.25,0.35)")
|
||||||
|
|
||||||
|
tl0._destroy
|
||||||
|
tl1._destroy
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
load("test_epilogue.rb")
|
||||||
|
|
||||||
Loading…
Reference in New Issue