mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' of github.com:KLayout/klayout into wip
This commit is contained in:
commit
545ff11899
|
|
@ -1582,8 +1582,7 @@ private:
|
|||
* @param interacting_clusters_out Receives the cluster interaction descriptors
|
||||
*
|
||||
* "interacting_clusters_out" will be cluster interactions in the parent instance space of i1 and i2 respectively.
|
||||
* Cluster ID will be valid in the parent cells containing i1 and i2 and the cluster instances property ID will be set to p1 and p2
|
||||
* respectively.
|
||||
* Cluster ID will be valid in the parent cells containing i1 and i2.
|
||||
*/
|
||||
void consider_instance_pair (const box_type &common,
|
||||
const db::Instance &i1, const db::ICplxTrans &t1, const db::CellInstArray::iterator &i1element,
|
||||
|
|
@ -1629,6 +1628,7 @@ private:
|
|||
db::ICplxTrans tt2 = t2 * i2t;
|
||||
|
||||
db::ICplxTrans cache_norm = tt1.inverted ();
|
||||
|
||||
ii_key = InstanceToInstanceInteraction ((! i1element.at_end () || i1.size () == 1) ? 0 : i1.cell_inst ().delegate (),
|
||||
(! i2element.at_end () || i2.size () == 1) ? 0 : i2.cell_inst ().delegate (),
|
||||
cache_norm, cache_norm * tt2);
|
||||
|
|
@ -1695,9 +1695,14 @@ private:
|
|||
|
||||
db::ICplxTrans i2t = i2.complex_trans (*ii2);
|
||||
db::ICplxTrans tt2 = t2 * i2t;
|
||||
|
||||
if (i1.cell_index () == i2.cell_index () && tt1 == tt2) {
|
||||
// skip interactions between identical instances (duplicate instance removal)
|
||||
continue;
|
||||
if (! i2element.at_end ()) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
box_type ib2 = bb2.transformed (tt2);
|
||||
|
|
@ -1903,6 +1908,7 @@ private:
|
|||
for (std::list<std::pair<ClusterInstance, ClusterInstance> >::iterator ii = ii_interactions.begin (); ii != ii_interactions.end (); ++ii) {
|
||||
propagate_cluster_inst (ii->second, i.cell_index (), tt2, i.prop_id ());
|
||||
}
|
||||
|
||||
interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ());
|
||||
|
||||
}
|
||||
|
|
@ -1974,6 +1980,7 @@ private:
|
|||
for (typename std::list<ClusterInstanceInteraction>::iterator ii = ci_interactions.begin (); ii != ci_interactions.end (); ++ii) {
|
||||
propagate_cluster_inst (ii->other_ci, i2.cell_index (), i2t, i2.prop_id ());
|
||||
}
|
||||
|
||||
interactions_out.splice (interactions_out.end (), ci_interactions, ci_interactions.begin (), ci_interactions.end ());
|
||||
|
||||
}
|
||||
|
|
@ -2088,6 +2095,10 @@ private:
|
|||
*
|
||||
* After calling this method, the cluster instance in ci is guaranteed to have connections from all
|
||||
* parent cells. One of these connections represents the instance ci.
|
||||
*
|
||||
* Returns false if the connection was already there in the same place (indicating duplicate instances).
|
||||
* In this case, the cluster instance should be skipped. In the other case, the cluster instance is
|
||||
* updated to reflect the connected cluster.
|
||||
*/
|
||||
void propagate_cluster_inst (ClusterInstance &ci, db::cell_index_type pci, const db::ICplxTrans &trans, db::properties_id_type prop_id) const
|
||||
{
|
||||
|
|
@ -2178,7 +2189,7 @@ hier_clusters<T>::propagate_cluster_inst (const db::Layout &layout, const db::Ce
|
|||
|
||||
if (parent_cluster > 0) {
|
||||
|
||||
// taken parent
|
||||
// take parent
|
||||
id_new = parent_cluster;
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1353,3 +1353,48 @@ TEST(200_issue609)
|
|||
EXPECT_EQ (root_nets (hc.clusters_per_cell (*td)), size_t (0));
|
||||
}
|
||||
}
|
||||
|
||||
// issue #1126
|
||||
TEST(201_issue1126)
|
||||
{
|
||||
{
|
||||
db::Layout ly;
|
||||
unsigned int l1 = 0;
|
||||
|
||||
{
|
||||
db::LayerProperties p;
|
||||
db::LayerMap lmap;
|
||||
|
||||
p.layer = 1;
|
||||
p.datatype = 0;
|
||||
lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ());
|
||||
ly.set_properties (l1, p);
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/issue-1126.gds.gz";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly, options);
|
||||
}
|
||||
|
||||
std::vector<std::string> strings;
|
||||
normalize_layer (ly, strings, l1);
|
||||
|
||||
// connect 1 to 1
|
||||
db::Connectivity conn;
|
||||
conn.connect (l1, l1);
|
||||
|
||||
db::hier_clusters<db::PolygonRef> hc;
|
||||
hc.build (ly, ly.cell (*ly.begin_top_down ()), conn);
|
||||
|
||||
// should not assert until here
|
||||
}
|
||||
|
||||
// detailed test:
|
||||
run_hc_test (_this, "issue-1126.gds.gz", "issue-1126_au.gds");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2846,6 +2846,7 @@ TEST(11_DuplicateInstances)
|
|||
// compare netlist as string
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
// suppressing duplicate cells:
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I12,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I25,OUT=$I1,$4=VSS,$5=VDD);\n"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@
|
|||
#include "tlStream.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "tlExpression.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlUri.h"
|
||||
#include "dbMemStatistics.h"
|
||||
#include "dbManager.h"
|
||||
#include "dbStream.h"
|
||||
|
|
@ -2902,29 +2904,28 @@ MainWindow::add_mru (const std::string &fn_rel)
|
|||
add_mru (fn_rel, m_initial_technology);
|
||||
}
|
||||
|
||||
const size_t max_mru = 16;
|
||||
const size_t max_mru = 16; // TODO: make configurable?
|
||||
|
||||
void
|
||||
MainWindow::add_mru (const std::string &fn_rel, const std::string &tech)
|
||||
{
|
||||
std::vector <std::pair<std::string, std::string> > new_mru (m_mru);
|
||||
std::vector <std::pair<std::string, std::string> > new_mru;
|
||||
std::string fn (tl::InputStream::absolute_path (fn_rel));
|
||||
|
||||
for (std::vector<std::pair<std::string, std::string> >::iterator mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
if (mru->first == fn) {
|
||||
new_mru.erase (mru);
|
||||
break;
|
||||
for (auto mru = m_mru.begin (); mru != m_mru.end (); ++mru) {
|
||||
if (mru->first != fn /* delete non-existing files: && tl::is_readable (mru->first) */) {
|
||||
new_mru.push_back (*mru);
|
||||
}
|
||||
}
|
||||
|
||||
new_mru.push_back (std::make_pair (fn, tech));
|
||||
|
||||
if (new_mru.size () > max_mru) {
|
||||
new_mru.erase (new_mru.begin ());
|
||||
new_mru.erase (new_mru.begin (), new_mru.end () - max_mru);
|
||||
}
|
||||
|
||||
std::string config_str;
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
for (auto mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
if (! config_str.empty ()) {
|
||||
config_str += " ";
|
||||
}
|
||||
|
|
@ -2952,20 +2953,19 @@ MainWindow::add_to_other_mru (const std::string &fn_rel, const std::string &cfg)
|
|||
tl_assert (false);
|
||||
}
|
||||
|
||||
std::vector <std::string> new_mru = *mru_ptr;
|
||||
std::vector <std::string> new_mru;
|
||||
std::string fn (tl::InputStream::absolute_path (fn_rel));
|
||||
|
||||
for (std::vector<std::string>::iterator mru = new_mru.begin (); mru != new_mru.end (); ++mru) {
|
||||
if (*mru == fn) {
|
||||
new_mru.erase (mru);
|
||||
break;
|
||||
for (auto mru = mru_ptr->begin (); mru != mru_ptr->end (); ++mru) {
|
||||
if (*mru != fn /* delete non-existing files: && tl::is_readable (*mru) */) {
|
||||
new_mru.push_back (*mru);
|
||||
}
|
||||
}
|
||||
|
||||
new_mru.push_back (fn);
|
||||
|
||||
if (new_mru.size () > max_mru) {
|
||||
new_mru.erase (new_mru.begin ());
|
||||
new_mru.erase (new_mru.begin (), new_mru.end () - max_mru);
|
||||
}
|
||||
|
||||
std::string config_str;
|
||||
|
|
@ -2986,72 +2986,45 @@ class OpenRecentAction
|
|||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
OpenRecentAction (lay::MainWindow *mw, size_t n, void (lay::MainWindow::*open_meth) (size_t), bool (lay::MainWindow::*avail_meth) (size_t))
|
||||
: lay::Action (), mp_mw (mw), m_n (n), m_open_meth (open_meth), m_avail_meth (avail_meth)
|
||||
{ }
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent (m_n);
|
||||
(mp_mw->*m_open_meth) (m_n);
|
||||
}
|
||||
|
||||
bool wants_enabled () const
|
||||
{
|
||||
return (mp_mw->*m_avail_meth) (m_n);
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
void (lay::MainWindow::*m_open_meth) (size_t);
|
||||
bool (lay::MainWindow::*m_avail_meth) (size_t);
|
||||
};
|
||||
|
||||
class OpenRecentSessionAction
|
||||
class ClearRecentAction
|
||||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentSessionAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
{ }
|
||||
ClearRecentAction (lay::MainWindow *mw, const std::string &cfg)
|
||||
: lay::Action (), mp_mw (mw), m_cfg (cfg)
|
||||
{
|
||||
set_title (tl::to_string (tr ("Clear List")));
|
||||
}
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent_session (m_n);
|
||||
mp_mw->configure (m_cfg, std::string ());
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
};
|
||||
|
||||
class OpenRecentLayerPropertiesAction
|
||||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentLayerPropertiesAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
{ }
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent_layer_properties (m_n);
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
};
|
||||
|
||||
class OpenRecentBookmarksAction
|
||||
: public lay::Action
|
||||
{
|
||||
public:
|
||||
OpenRecentBookmarksAction (lay::MainWindow *mw, size_t n)
|
||||
: lay::Action (), mp_mw (mw), m_n (n)
|
||||
{ }
|
||||
|
||||
void triggered ()
|
||||
{
|
||||
mp_mw->open_recent_bookmarks (m_n);
|
||||
}
|
||||
|
||||
private:
|
||||
lay::MainWindow *mp_mw;
|
||||
size_t m_n;
|
||||
std::string m_cfg;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -3074,11 +3047,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::pair<std::string, std::string> >::iterator mru = m_mru.end (); mru != m_mru.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru.begin (), mru);
|
||||
Action *action = new OpenRecentAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent, &lay::MainWindow::is_available_recent);
|
||||
action->set_title (mru->first);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3100,11 +3076,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::string>::iterator mru = m_mru_sessions.end (); mru != m_mru_sessions.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru_sessions.begin (), mru);
|
||||
Action *action = new OpenRecentSessionAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent_session, &lay::MainWindow::is_available_recent_session);
|
||||
action->set_title (*mru);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru_sessions));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3126,11 +3105,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::string>::iterator mru = m_mru_layer_properties.end (); mru != m_mru_layer_properties.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru_layer_properties.begin (), mru);
|
||||
Action *action = new OpenRecentLayerPropertiesAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent_layer_properties, &lay::MainWindow::is_available_recent_layer_properties);
|
||||
action->set_title (*mru);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru_layer_properties));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3152,11 +3134,14 @@ MainWindow::do_update_mru_menus ()
|
|||
for (std::vector<std::string>::iterator mru = m_mru_bookmarks.end (); mru != m_mru_bookmarks.begin (); ) {
|
||||
--mru;
|
||||
size_t i = std::distance (m_mru_bookmarks.begin (), mru);
|
||||
Action *action = new OpenRecentBookmarksAction (this, i);
|
||||
Action *action = new OpenRecentAction (this, i, &lay::MainWindow::open_recent_bookmarks, &lay::MainWindow::is_available_recent_bookmarks);
|
||||
action->set_title (*mru);
|
||||
menu ()->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
|
||||
}
|
||||
|
||||
menu ()->insert_separator (mru_menu + ".end", "clear_sep");
|
||||
menu ()->insert_item (mru_menu + ".end", "clear_recent", new ClearRecentAction (this, cfg_mru_bookmarks));
|
||||
|
||||
} else {
|
||||
open_recent_action->set_enabled (false);
|
||||
}
|
||||
|
|
@ -3218,6 +3203,25 @@ MainWindow::open_recent (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
static bool
|
||||
is_file_available (const std::string &fn)
|
||||
{
|
||||
tl::URI uri (fn);
|
||||
if (uri.scheme ().empty ()) {
|
||||
return tl::is_readable (fn);
|
||||
} else if (uri.scheme () == "file") {
|
||||
return tl::is_readable (uri.path ());
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent (size_t n)
|
||||
{
|
||||
return (n < m_mru.size () && is_file_available (m_mru [n].first));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open_recent_session (size_t n)
|
||||
{
|
||||
|
|
@ -3232,6 +3236,12 @@ MainWindow::open_recent_session (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent_session (size_t n)
|
||||
{
|
||||
return (n < m_mru_sessions.size () && is_file_available (m_mru_sessions [n]));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open_recent_layer_properties (size_t n)
|
||||
{
|
||||
|
|
@ -3246,6 +3256,12 @@ MainWindow::open_recent_layer_properties (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent_layer_properties (size_t n)
|
||||
{
|
||||
return (n < m_mru_layer_properties.size () && is_file_available (m_mru_layer_properties [n]));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open_recent_bookmarks (size_t n)
|
||||
{
|
||||
|
|
@ -3264,6 +3280,12 @@ MainWindow::open_recent_bookmarks (size_t n)
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::is_available_recent_bookmarks (size_t n)
|
||||
{
|
||||
return (n < m_mru_bookmarks.size () && is_file_available (m_mru_bookmarks [n]));
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::open (int mode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -637,6 +637,10 @@ public slots:
|
|||
void open_recent_session (size_t n);
|
||||
void open_recent_layer_properties (size_t n);
|
||||
void open_recent_bookmarks (size_t n);
|
||||
bool is_available_recent(size_t n);
|
||||
bool is_available_recent_session (size_t n);
|
||||
bool is_available_recent_layer_properties (size_t n);
|
||||
bool is_available_recent_bookmarks (size_t n);
|
||||
void view_selected (int index);
|
||||
void view_title_changed (lay::LayoutView *view);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,27 @@ public:
|
|||
on_triggered_event ();
|
||||
}
|
||||
|
||||
virtual bool wants_visible () const
|
||||
{
|
||||
if (wants_visible_cb.can_issue ()) {
|
||||
return wants_visible_cb.issue<lay::Action, bool> (&lay::Action::wants_visible);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool wants_enabled () const
|
||||
{
|
||||
if (wants_enabled_cb.can_issue ()) {
|
||||
return wants_enabled_cb.issue<lay::Action, bool> (&lay::Action::wants_enabled);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback triggered_cb;
|
||||
gsi::Callback wants_visible_cb;
|
||||
gsi::Callback wants_enabled_cb;
|
||||
tl::Event on_triggered_event;
|
||||
};
|
||||
|
||||
|
|
@ -291,10 +311,16 @@ Class<lay::Action> decl_ActionBase ("lay", "ActionBase",
|
|||
) +
|
||||
method ("is_effective_visible?", &lay::Action::is_effective_visible,
|
||||
"@brief Gets a value indicating whether the item is really visible\n"
|
||||
"This is the combined visibility from \\is_visible? and \\is_hidden?."
|
||||
"This is the combined visibility from \\is_visible? and \\is_hidden? and dynamic visibility (\\wants_visible)."
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.25.\n"
|
||||
) +
|
||||
method ("is_effective_enabled?", &lay::Action::is_effective_enabled,
|
||||
"@brief Gets a value indicating whether the item is really enabled\n"
|
||||
"This is the combined value from \\is_enabled? and dynamic value (\\wants_enabled)."
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.28.\n"
|
||||
) +
|
||||
method ("separator=", &lay::Action::set_separator, gsi::arg ("separator"),
|
||||
"@brief Makes an item a separator or not\n"
|
||||
"\n"
|
||||
|
|
@ -368,6 +394,24 @@ Class<ActionStub> decl_Action (decl_ActionBase, "lay", "Action",
|
|||
gsi::callback ("triggered", &ActionStub::triggered, &ActionStub::triggered_cb,
|
||||
"@brief This method is called if the menu item is selected"
|
||||
) +
|
||||
gsi::callback ("wants_visible", &ActionStub::wants_visible, &ActionStub::wants_visible_cb,
|
||||
"@brief Returns a value whether the action wants to become visible\n"
|
||||
"This is a dynamic query for visibility which the system uses to dynamically show or hide "
|
||||
"menu items, for example in the MRU lists. This visibility information is evaluated in addition "
|
||||
"to \\is_visible? and \\is_hidden? and contributes to the effective visibility status from "
|
||||
"\\is_effective_visible?.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::callback ("wants_enabled", &ActionStub::wants_enabled, &ActionStub::wants_enabled_cb,
|
||||
"@brief Returns a value whether the action wants to become enabled\n"
|
||||
"This is a dynamic query for enabled state which the system uses to dynamically show or hide "
|
||||
"menu items. This information is evaluated in addition "
|
||||
"to \\is_enabled? and contributes to the effective enabled status from "
|
||||
"\\is_effective_enabled?.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::event ("on_triggered", &ActionStub::on_triggered_event,
|
||||
"@brief This event is called if the menu item is selected\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ Action::Action () :
|
|||
#if defined(HAVE_QT)
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
if (mp_action) {
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -413,7 +413,7 @@ Action::Action (QAction *action, bool owned)
|
|||
sp_actionHandles->insert (this);
|
||||
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +436,8 @@ Action::Action (QMenu *menu, bool owned)
|
|||
sp_actionHandles->insert (this);
|
||||
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
connect (mp_menu, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_menu, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_menu, SIGNAL (aboutToShow ()), this, SLOT (menu_about_to_show ()));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -466,7 +467,7 @@ Action::Action (const std::string &title) :
|
|||
#if defined(HAVE_QT)
|
||||
// catch the destroyed signal to tell if the QAction object is deleted.
|
||||
if (mp_action) {
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -536,6 +537,30 @@ Action::configure_from_title (const std::string &s)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Action::menu_about_to_show ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
if (! mp_dispatcher || ! mp_dispatcher->menu ()) {
|
||||
return;
|
||||
}
|
||||
AbstractMenuItem *item = mp_dispatcher->menu ()->find_item_for_action (this);
|
||||
if (! item ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i = item->children.begin (); i != item->children.end (); ++i) {
|
||||
if (i->action ()) {
|
||||
i->action ()->sync_qaction ();
|
||||
}
|
||||
}
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Action::qaction_triggered ()
|
||||
|
|
@ -578,7 +603,7 @@ Action::menu () const
|
|||
}
|
||||
|
||||
void
|
||||
Action::destroyed (QObject *obj)
|
||||
Action::was_destroyed (QObject *obj)
|
||||
{
|
||||
if (obj == mp_action) {
|
||||
mp_action = 0;
|
||||
|
|
@ -591,17 +616,24 @@ Action::destroyed (QObject *obj)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Action::sync_qaction ()
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_action) {
|
||||
mp_action->setVisible (is_effective_visible ());
|
||||
mp_action->setShortcut (get_key_sequence ());
|
||||
mp_action->setEnabled (is_effective_enabled ());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
Action::set_visible (bool v)
|
||||
{
|
||||
if (m_visible != v) {
|
||||
m_visible = v;
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_action) {
|
||||
mp_action->setVisible (is_effective_visible ());
|
||||
mp_action->setShortcut (get_key_sequence ());
|
||||
}
|
||||
#endif
|
||||
sync_qaction ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -610,12 +642,7 @@ Action::set_hidden (bool h)
|
|||
{
|
||||
if (m_hidden != h) {
|
||||
m_hidden = h;
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_action) {
|
||||
mp_action->setVisible (is_effective_visible ());
|
||||
mp_action->setShortcut (get_key_sequence ());
|
||||
}
|
||||
#endif
|
||||
sync_qaction ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -634,7 +661,7 @@ Action::is_hidden () const
|
|||
bool
|
||||
Action::is_effective_visible () const
|
||||
{
|
||||
return m_visible && !m_hidden;
|
||||
return m_visible && !m_hidden && wants_visible ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -792,11 +819,7 @@ Action::is_checked () const
|
|||
bool
|
||||
Action::is_enabled () const
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
return qaction () ? qaction ()->isEnabled () : m_enabled;
|
||||
#else
|
||||
return m_enabled;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -808,12 +831,16 @@ Action::is_separator () const
|
|||
void
|
||||
Action::set_enabled (bool b)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
if (qaction ()) {
|
||||
qaction ()->setEnabled (b);
|
||||
if (m_enabled != b) {
|
||||
m_enabled = b;
|
||||
sync_qaction ();
|
||||
}
|
||||
#endif
|
||||
m_enabled = b;
|
||||
}
|
||||
|
||||
bool
|
||||
Action::is_effective_enabled () const
|
||||
{
|
||||
return m_enabled && wants_enabled ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1508,6 +1535,33 @@ AbstractMenu::delete_items (Action *action)
|
|||
}
|
||||
}
|
||||
|
||||
const AbstractMenuItem *
|
||||
AbstractMenu::find_item_for_action (const Action *action, const AbstractMenuItem *from) const
|
||||
{
|
||||
return (const_cast<AbstractMenu *> (this))->find_item_for_action (action, const_cast<AbstractMenuItem *> (from));
|
||||
}
|
||||
|
||||
AbstractMenuItem *
|
||||
AbstractMenu::find_item_for_action (const Action *action, AbstractMenuItem *from)
|
||||
{
|
||||
if (! from) {
|
||||
from = const_cast<AbstractMenuItem *> (&root ());
|
||||
}
|
||||
|
||||
if (from->action () == action) {
|
||||
return from;
|
||||
}
|
||||
|
||||
for (auto i = from->children.begin (); i != from->children.end (); ++i) {
|
||||
AbstractMenuItem *item = find_item_for_action (action, i.operator-> ());
|
||||
if (item) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const AbstractMenuItem *
|
||||
AbstractMenu::find_item_exact (const std::string &path) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -318,6 +318,34 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating the action is visible (dynamic calls)
|
||||
* In addition to static visibility (visible/hidden), an Action object can request to
|
||||
* become invisible dynamically based on conditions. This will work for menu-items
|
||||
* for which the system will query the status before the menu is shown.
|
||||
*/
|
||||
virtual bool wants_visible () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating the action is enabled (dynamic calls)
|
||||
* In addition to static visibility (visible/hidden), an Action object can request to
|
||||
* become invisible dynamically based on conditions. This will work for menu-items
|
||||
* for which the system will query the status before the menu is shown.
|
||||
*/
|
||||
virtual bool wants_enabled () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the effective enabled state
|
||||
* This is the combined value from is_enabled and wants_enabled.
|
||||
*/
|
||||
bool is_effective_enabled () const;
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Get the underlying QAction object
|
||||
|
|
@ -342,8 +370,9 @@ public:
|
|||
|
||||
#if defined(HAVE_QT)
|
||||
protected slots:
|
||||
void destroyed (QObject *obj);
|
||||
void was_destroyed (QObject *obj);
|
||||
void qaction_triggered ();
|
||||
void menu_about_to_show ();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
@ -381,6 +410,7 @@ private:
|
|||
#endif
|
||||
|
||||
void configure_from_title (const std::string &s);
|
||||
void sync_qaction ();
|
||||
|
||||
// no copying
|
||||
Action (const Action &);
|
||||
|
|
@ -801,7 +831,7 @@ public:
|
|||
* @param group The group name
|
||||
* @param A vector of all members (as actions) of the group
|
||||
*/
|
||||
std::vector<Action *> group_actions(const std::string &name);
|
||||
std::vector<Action *> group_actions (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Get the configure actions for a given configuration name
|
||||
|
|
@ -844,6 +874,8 @@ private:
|
|||
std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator> > find_item (tl::Extractor &extr);
|
||||
const AbstractMenuItem *find_item_exact (const std::string &path) const;
|
||||
AbstractMenuItem *find_item_exact (const std::string &path);
|
||||
const AbstractMenuItem *find_item_for_action (const Action *action, const AbstractMenuItem *from = 0) const;
|
||||
AbstractMenuItem *find_item_for_action (const Action *action, AbstractMenuItem *from = 0);
|
||||
#if defined(HAVE_QT)
|
||||
void build (QMenu *menu, std::list<AbstractMenuItem> &items);
|
||||
void build (QToolBar *tbar, std::list<AbstractMenuItem> &items);
|
||||
|
|
|
|||
|
|
@ -135,6 +135,26 @@ static db::Shape insert_shape (db::Cell &cell, unsigned int layer_id, const Shap
|
|||
}
|
||||
}
|
||||
|
||||
static db::Box box_for_label (const db::Polygon &p)
|
||||
{
|
||||
if (p.is_box ()) {
|
||||
return p.box ();
|
||||
} else if (p.begin_hull () != p.end_hull ()) {
|
||||
return db::Box (*p.begin_hull (), *p.begin_hull ());
|
||||
} else {
|
||||
return db::Box ();
|
||||
}
|
||||
}
|
||||
|
||||
static db::Box box_for_label (const db::Path &p)
|
||||
{
|
||||
if (p.begin () != p.end ()) {
|
||||
return db::Box (*p.begin (), *p.begin ());
|
||||
} else {
|
||||
return db::Box ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, LayerPurpose purpose, std::map<std::string, db::Box> *collect_boxes_for_labels, db::properties_id_type prop_id)
|
||||
{
|
||||
|
|
@ -201,7 +221,7 @@ LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, Laye
|
|||
db::Path pt = p.transformed (*t);
|
||||
lg->add_path (layer_name, purpose, pt, mask, prop_id);
|
||||
if (collect_boxes_for_labels) {
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = pt.box ();
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = box_for_label (pt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +229,7 @@ LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, Laye
|
|||
|
||||
lg->add_path (layer_name, purpose, p, mask, prop_id);
|
||||
if (collect_boxes_for_labels) {
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = p.box ();
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = box_for_label (p);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -249,7 +269,7 @@ LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, Laye
|
|||
db::Polygon pt = p.transformed (*t);
|
||||
lg->add_polygon (layer_name, purpose, pt, mask, prop_id);
|
||||
if (collect_boxes_for_labels) {
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = pt.box ();
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = box_for_label (pt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +277,7 @@ LEFImporter::read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, Laye
|
|||
|
||||
lg->add_polygon (layer_name, purpose, p, mask, prop_id);
|
||||
if (collect_boxes_for_labels) {
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = p.box ();
|
||||
collect_boxes_for_labels->insert (std::make_pair (layer_name, db::Box ())).first->second = box_for_label (p);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -883,7 +903,9 @@ LEFImporter::read_macro (Layout &layout)
|
|||
read_geometries (mg, layout.dbu (), LEFPins, &boxes_for_labels, prop_id);
|
||||
|
||||
for (std::map <std::string, db::Box>::const_iterator b = boxes_for_labels.begin (); b != boxes_for_labels.end (); ++b) {
|
||||
mg->add_text (b->first, LEFLabel, db::Text (label.c_str (), db::Trans (b->second.center () - db::Point ())), 0, 0);
|
||||
if (! b->second.empty ()) {
|
||||
mg->add_text (b->first, LEFLabel, db::Text (label.c_str (), db::Trans (b->second.center () - db::Point ())), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -930,3 +930,15 @@ TEST(203_regionsAndMapfileConcat)
|
|||
run_test (_this, "map_regions", "map:'test.map,test.add.map'+lef:test.lef+def:test.def", "au.oas.gz", lefdef_opt, false);
|
||||
}
|
||||
|
||||
// issue 1132
|
||||
TEST(204_concave_pins)
|
||||
{
|
||||
db::LEFDEFReaderOptions lefdef_opt = default_options ();
|
||||
lefdef_opt.set_lef_pins_datatype (12);
|
||||
lefdef_opt.set_lef_pins_suffix (".LEFPIN");
|
||||
lefdef_opt.set_lef_labels_datatype (11);
|
||||
lefdef_opt.set_lef_labels_suffix (".LEFLABEL");
|
||||
|
||||
run_test (_this, "issue-1132", "read:test.lef", "au.oas.gz", lefdef_opt, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,20 @@
|
|||
VERSION 5.7 ;
|
||||
DIVIDERCHAR "/" ;
|
||||
BUSBITCHARS "[]" ;
|
||||
|
||||
MACRO POLYGON_PIN
|
||||
FOREIGN POLYGON_PIN ;
|
||||
ORIGIN 0.000 0.000 ;
|
||||
SIZE 150.000 BY 200.000 ;
|
||||
PIN VDD
|
||||
DIRECTION INOUT ;
|
||||
USE POWER ;
|
||||
PORT
|
||||
LAYER met4 ;
|
||||
POLYGON 0.000 10.000 30.000 10.000 30.000 0.000 35.000 0.000 35.000 15.000 0.000 15.0000 ;
|
||||
END
|
||||
END VDD
|
||||
END POLYGON_PIN
|
||||
|
||||
END LIBRARY
|
||||
|
||||
|
|
@ -227,20 +227,20 @@ RESULT
|
|||
$a1.visible = false
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_visible?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_checked?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, true )
|
||||
|
||||
$a1.checked = true
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_visible?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_checked?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_checkable?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_enabled?, false )
|
||||
assert_equal( menu.action( "file_menu.#3" ).is_enabled?, true )
|
||||
|
||||
$a1.checked = false
|
||||
$a1.checkable = true;
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_visible?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_checked?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_checkable?, true )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, false )
|
||||
assert_equal( menu.action( "my_menu.new_item" ).is_enabled?, true )
|
||||
$a1.checked = true
|
||||
assert_equal( menu.action( "file_menu.#0" ).is_checked?, true )
|
||||
|
||||
|
|
@ -440,6 +440,50 @@ RESULT
|
|||
|
||||
end
|
||||
|
||||
class MyAction < RBA::Action
|
||||
attr_accessor :dyn_visible, :dyn_enabled
|
||||
def initialize
|
||||
self.dyn_visible = true
|
||||
self.dyn_enabled = true
|
||||
end
|
||||
def wants_visible
|
||||
self.dyn_visible
|
||||
end
|
||||
def wants_enabled
|
||||
self.dyn_enabled
|
||||
end
|
||||
end
|
||||
|
||||
def test_7
|
||||
|
||||
a = MyAction::new
|
||||
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
a.hidden = true
|
||||
assert_equal(a.is_effective_visible?, false)
|
||||
a.hidden = false
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
a.visible = false
|
||||
assert_equal(a.is_effective_visible?, false)
|
||||
a.visible = true
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
a.dyn_visible = false
|
||||
assert_equal(a.is_effective_visible?, false)
|
||||
a.dyn_visible = true
|
||||
assert_equal(a.is_effective_visible?, true)
|
||||
|
||||
assert_equal(a.is_effective_enabled?, true)
|
||||
a.enabled = false
|
||||
assert_equal(a.is_effective_enabled?, false)
|
||||
a.enabled = true
|
||||
assert_equal(a.is_effective_enabled?, true)
|
||||
a.dyn_enabled = false
|
||||
assert_equal(a.is_effective_enabled?, false)
|
||||
a.dyn_enabled = true
|
||||
assert_equal(a.is_effective_enabled?, true)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue