This commit is contained in:
Matthias Koefferlein 2021-03-15 10:24:09 +01:00
commit 15e5af8171
192 changed files with 11085 additions and 2871 deletions

1
.gitignore vendored
View File

@ -36,6 +36,7 @@
build-*
bin-*
mkqtdecl.tmp
mkqtdecl5.tmp
testtmp
*build.macos*
*bin.macos*

View File

@ -26,6 +26,14 @@ IS_WINDOWS="no"
IS_LINUX="no"
HAVE_QTBINDINGS=1
HAVE_QT_UITOOLS=1
HAVE_QT_NETWORK=1
HAVE_QT_SQL=1
HAVE_QT_SVG=1
HAVE_QT_PRINTSUPPORT=1
HAVE_QT_MULTIMEDIA=1
HAVE_QT_DESIGNER=1
HAVE_QT_XML=1
HAVE_64BIT_COORD=0
HAVE_QT=1
HAVE_QT5="" # not set
@ -83,15 +91,39 @@ while [ "$*" != "" ]; do
shift
case $a in
-with-qtbinding)
HAVE_QTBINDINGS=1
;;
-without-qt)
HAVE_QT=0
;;
-with-qtbinding)
HAVE_QTBINDINGS=1
;;
-without-qtbinding)
HAVE_QTBINDINGS=0
;;
-without-qt-uitools)
HAVE_QT_UITOOLS=0
;;
-without-qt-network)
HAVE_QT_NETWORK=0
;;
-without-qt-sql)
HAVE_QT_SQL=0
;;
-without-qt-svg)
HAVE_QT_SVG=0
;;
-without-qt-printsupport)
HAVE_QT_PRINTSUPPORT=0
;;
-without-qt-multimedia)
HAVE_QT_MULTIMEDIA=0
;;
-without-qt-designer)
HAVE_QT_DESIGNER=0
;;
-without-qt-xml)
HAVE_QT_XML=0
;;
-with-64bit-coord)
HAVE_64BIT_COORD=1
;;
@ -207,6 +239,7 @@ while [ "$*" != "" ]; do
echo ""
echo " -with-qtbinding Create Qt bindings for ruby scripts [default]"
echo " -without-qtbinding Don't create Qt bindings for ruby scripts"
echo " -without-qt-uitools Don't include uitools in Qt binding"
echo " -with-64bit-coord Use long (64bit) coordinates - EXPERIMENTAL FEATURE"
echo " (only available for gcc>=4.4 for 64bit build)"
echo " -without-64bit-coord Don't use long (64bit) coordinates [default]"
@ -604,6 +637,14 @@ qmake_options=(
PYTHONEXTSUFFIX="$PYTHONEXTSUFFIX"
HAVE_PYTHON="$HAVE_PYTHON"
HAVE_QTBINDINGS="$HAVE_QTBINDINGS"
HAVE_QT_UITOOLS="$HAVE_QT_UITOOLS"
HAVE_QT_NETWORK="$HAVE_QT_NETWORK"
HAVE_QT_SQL="$HAVE_QT_SQL"
HAVE_QT_SVG="$HAVE_QT_SVG"
HAVE_QT_PRINTSUPPORT="$HAVE_QT_PRINTSUPPORT"
HAVE_QT_MULTIMEDIA="$HAVE_QT_MULTIMEDIA"
HAVE_QT_DESIGNER="$HAVE_QT_DESIGNER"
HAVE_QT_XML="$HAVE_QT_XML"
HAVE_64BIT_COORD="$HAVE_64BIT_COORD"
HAVE_QT="$HAVE_QT"
HAVE_QT5="$HAVE_QT5"

View File

@ -49,8 +49,8 @@ inst_dir5=`pwd`/scripts/mkqtdecl5
src_dir=`pwd`/src
src_name4=gsiqt/qt4
src_name5=gsiqt/qt5
qt_mods4="QtCore QtGui QtDesigner QtNetwork QtSql QtXml"
qt_mods5="QtCore QtGui QtWidgets QtDesigner QtNetwork QtPrintSupport QtSql QtSvg QtXml QtXmlPatterns QtMultimedia"
qt_mods4="QtCore QtGui QtDesigner QtNetwork QtSql QtXml QtUiTools"
qt_mods5="QtCore QtGui QtWidgets QtDesigner QtNetwork QtPrintSupport QtSql QtSvg QtXml QtXmlPatterns QtMultimedia QtUiTools"
src_name=$src_name4
inst_dir=$inst_dir4

View File

@ -0,0 +1 @@
#include "QtUiTools/QUiLoader"

View File

@ -302,6 +302,13 @@ rename "QProcess", /QProcess::finished\(int[\s\w]*\)/, "finished_int" # disambig
drop_method "QCoreApplication", /QCoreApplication::QCoreApplication/
add_native_qapp_ctor_impl("QCoreApplication")
# Reasoning: "notify" is hardly needed (use postEvent or sendEvent instead). Reimplementing remains as a use case.
# Reimplementing this method however is questionable: providing an reimplementation hook has severe consequences as even
# Qt object constructors will route over this slot and invoke interpreter calls. This will for example lead to preliminary
# binding of Qt objects to Python objects, hence spoil their object identity.
drop_method "QCoreApplication", /QCoreApplication::notify/
drop_method "QApplication", /QApplication::notify/
# alternative implementation for QObject::findChild
add_native_impl_QObject_findChild
@ -886,6 +893,11 @@ no_copy_ctor "QFormLayout"
no_copy_ctor "QXmlParseException"
no_copy_ctor "QNetworkAccessManager"
# --------------------------------------------------------------
# QtUiTools
include "QUiLoader", [ "<QUiLoader>", "<QDir>", "<QAction>", "<QActionGroup>", "<QLayout>", "<QWidget>", "<QChildEvent>", "<QEvent>", "<QTimerEvent>" ]
# --------------------------------------------------------------
# events and properties
# NOTE: to generate these files use scripts/mkqtdecl/mkqtdecl_extract_props.rb

View File

@ -0,0 +1 @@
#include "QtUiTools/QUiLoader"

View File

@ -375,6 +375,14 @@ rename "QProcess", /QProcess::finished\(int[\s\w]*\)/, "finished_int" # disambig
drop_method "QCoreApplication", /QCoreApplication::QCoreApplication/
add_native_qapp_ctor_impl("QCoreApplication")
# Reasoning: "notify" is hardly needed (use postEvent or sendEvent instead). Reimplementing remains as a use case.
# Reimplementing this method however is questionable: providing an reimplementation hook has severe consequences as even
# Qt object constructors will route over this slot and invoke interpreter calls. This will for example lead to preliminary
# binding of Qt objects to Python objects, hence spoil their object identity.
drop_method "QCoreApplication", /QCoreApplication::notify/
drop_method "QApplication", /QApplication::notify/
drop_method "QGuiApplication", /QGuiApplication::notify/
# alternative implementation for QObject::findChild
add_native_impl_QObject_findChild
@ -1210,6 +1218,11 @@ rename "QNetworkSession", /QNetworkSession::error\(QNetworkSession::/, "error_si
rename "QSqlDriver", /QSqlDriver::notification\(const\s+QString\s*\&\s*\w*\s*\)/, "notification" # disambiguator
rename "QSqlDriver", /QSqlDriver::notification\(const\s+QString\s*\&\s*\w*\s*,/, "notification_withData" # disambiguator
# --------------------------------------------------------------
# QtUiTools
include "QUiLoader", [ "<QUiLoader>", "<QDir>", "<QAction>", "<QActionGroup>", "<QLayout>", "<QWidget>", "<QChildEvent>", "<QEvent>", "<QTimerEvent>" ]
# --------------------------------------------------------------
# events and properties
# NOTE: to generate these files use scripts/mkqtdecl/mkqtdecl_extract_props.rb

View File

@ -134,7 +134,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (x1->text ()), dx1);
lay::indicate_error (x1, 0);
lay::indicate_error (x1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x1, &ex);
has_error = true;
@ -142,7 +142,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (x2->text ()), dx2);
lay::indicate_error (x2, 0);
lay::indicate_error (x2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x2, &ex);
has_error = true;
@ -150,7 +150,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (y1->text ()), dy1);
lay::indicate_error (y1, 0);
lay::indicate_error (y1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y1, &ex);
has_error = true;
@ -158,7 +158,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (y2->text ()), dy2);
lay::indicate_error (y2, 0);
lay::indicate_error (y2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y2, &ex);
has_error = true;

View File

@ -71,13 +71,10 @@ public:
ProgressAdaptor (int verbosity);
virtual ~ProgressAdaptor ();
virtual void register_object (tl::Progress *progress);
virtual void unregister_object (tl::Progress *progress);
virtual void trigger (tl::Progress *progress);
virtual void yield (tl::Progress *progress);
private:
std::list<tl::Progress *> mp_objects;
int m_verbosity;
std::string m_progress_text, m_progress_value;
};
@ -93,36 +90,19 @@ ProgressAdaptor::~ProgressAdaptor ()
// .. nothing yet ..
}
void
ProgressAdaptor::register_object (tl::Progress *progress)
{
mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible.
}
void
ProgressAdaptor::unregister_object (tl::Progress *progress)
{
for (std::list<tl::Progress *>::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) {
if (*k == progress) {
mp_objects.erase (k);
return;
}
}
}
void
ProgressAdaptor::trigger (tl::Progress *progress)
{
if (! mp_objects.empty () && mp_objects.front () == progress && tl::verbosity () >= m_verbosity) {
if (progress && first () == progress && tl::verbosity () >= m_verbosity) {
std::string text = mp_objects.front ()->desc ();
std::string text = progress->desc ();
if (m_progress_text != text) {
tl::info << text << " ..";
m_progress_text = text;
}
std::string value = mp_objects.front ()->formatted_value ();
std::string value = progress->formatted_value ();
if (m_progress_value != value) {
tl::info << ".. " << value;
m_progress_value = value;

View File

@ -97,6 +97,9 @@ GenericReaderOptions::GenericReaderOptions ()
m_lefdef_produce_lef_pins = load_options.get_option_by_name ("lefdef_config.produce_lef_pins").to_bool ();
m_lefdef_lef_pins_suffix = load_options.get_option_by_name ("lefdef_config.lef_pins_suffix_str").to_string ();
m_lefdef_lef_pins_datatype = load_options.get_option_by_name ("lefdef_config.lef_pins_datatype_str").to_string ();
m_lefdef_produce_fills = load_options.get_option_by_name ("lefdef_config.produce_fills").to_bool ();
m_lefdef_fills_suffix = load_options.get_option_by_name ("lefdef_config.fills_suffix_str").to_string ();
m_lefdef_fills_datatype = load_options.get_option_by_name ("lefdef_config.fills_datatype_str").to_string ();
m_lefdef_produce_obstructions = load_options.get_option_by_name ("lefdef_config.produce_obstructions").to_bool ();
m_lefdef_obstruction_suffix = load_options.get_option_by_name ("lefdef_config.obstructions_suffix").to_string ();
m_lefdef_obstruction_datatype = load_options.get_option_by_name ("lefdef_config.obstructions_datatype").to_int ();
@ -500,6 +503,20 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd)
"The LEF pin geometry generation and layer mapping is designed in the same way than via geometry mapping. "
"See '--" + m_long_prefix + "lefdef-produce-via-geometry' for a description of the mapping scheme.\n"
)
<< tl::arg (group +
"#!--" + m_long_prefix + "lefdef-dont-produce-fills", &m_lefdef_produce_fills, "Skips fills when producing geometry",
"If this option is given, no fill geometry will be produced."
)
<< tl::arg (group +
"#--" + m_long_prefix + "lefdef-fills-suffix", &m_lefdef_fills_suffix, "Specifies the fill geometry layer suffix in pattern-based mode",
"The fill geometry generation and layer mapfillg is designed in the same way than via geometry mapfillg. "
"See '--" + m_long_prefix + "lefdef-via-geometry-suffix' for a description of the mapfillg scheme.\n"
)
<< tl::arg (group +
"#--" + m_long_prefix + "lefdef-fills-datatype", &m_lefdef_fills_datatype, "Specifies the fill geometry layer datatype in pattern-based mode",
"The fill geometry generation and layer mapfillg is designed in the same way than via geometry mapfillg. "
"See '--" + m_long_prefix + "lefdef-produce-via-geometry' for a description of the mapfillg scheme.\n"
)
<< tl::arg (group +
"#!--" + m_long_prefix + "lefdef-dont-produce-routing", &m_lefdef_produce_routing, "Skips routing when producing geometry",
"If this option is given, no routing geometry will be produced."
@ -724,6 +741,9 @@ GenericReaderOptions::configure (db::LoadLayoutOptions &load_options) const
load_options.set_option_by_name ("lefdef_config.produce_lef_pins", m_lefdef_produce_lef_pins);
load_options.set_option_by_name ("lefdef_config.lef_pins_suffix_str", m_lefdef_lef_pins_suffix);
load_options.set_option_by_name ("lefdef_config.lef_pins_datatype_str", m_lefdef_lef_pins_datatype);
load_options.set_option_by_name ("lefdef_config.produce_fills", m_lefdef_produce_fills);
load_options.set_option_by_name ("lefdef_config.fills_suffix_str", m_lefdef_fills_suffix);
load_options.set_option_by_name ("lefdef_config.fills_datatype_str", m_lefdef_fills_datatype);
load_options.set_option_by_name ("lefdef_config.produce_obstructions", m_lefdef_produce_obstructions);
load_options.set_option_by_name ("lefdef_config.obstructions_suffix", m_lefdef_obstruction_suffix);
load_options.set_option_by_name ("lefdef_config.obstructions_datatype", m_lefdef_obstruction_datatype);

View File

@ -161,6 +161,9 @@ private:
bool m_lefdef_produce_lef_pins;
std::string m_lefdef_lef_pins_suffix;
std::string m_lefdef_lef_pins_datatype;
bool m_lefdef_produce_fills;
std::string m_lefdef_fills_suffix;
std::string m_lefdef_fills_datatype;
bool m_lefdef_produce_obstructions;
std::string m_lefdef_obstruction_suffix;
int m_lefdef_obstruction_datatype;

View File

@ -27,6 +27,7 @@
// Testing the converter main implementation (CIF)
TEST(1)
{
#if defined(HAVE_PYTHON)
std::string fp (tl::testsrc ());
fp += "/testdata/bd/strmrun.py";
@ -51,5 +52,6 @@ TEST(1)
tl::info << data;
EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n");
#endif
}

View File

@ -61,6 +61,7 @@ SOURCES = \
dbPolygonGenerators.cc \
dbPropertiesRepository.cc \
dbReader.cc \
dbRecursiveInstanceIterator.cc \
dbRecursiveShapeIterator.cc \
dbRegion.cc \
dbRegionLocalOperations.cc \
@ -114,6 +115,7 @@ SOURCES = \
gsiDeclDbPoint.cc \
gsiDeclDbPolygon.cc \
gsiDeclDbReader.cc \
gsiDeclDbRecursiveInstanceIterator.cc \
gsiDeclDbRecursiveShapeIterator.cc \
gsiDeclDbRegion.cc \
gsiDeclDbShape.cc \
@ -269,6 +271,7 @@ HEADERS = \
dbPolygonGenerators.h \
dbPropertiesRepository.h \
dbReader.h \
dbRecursiveInstanceIterator.h \
dbRecursiveShapeIterator.h \
dbRegion.h \
dbRegionLocalOperations.h \

View File

@ -403,6 +403,8 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse,
db::local_processor<db::Polygon, db::Edge, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Edge> > others;
others.push_back (counting ? other.begin_merged () : other.begin ());
@ -479,6 +481,8 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse,
db::local_processor<db::Polygon, db::Text, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Text> > others;
others.push_back (other.begin ());
@ -564,6 +568,8 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
db::local_processor<db::Polygon, db::Polygon, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Polygon> > others;
others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ());
@ -702,6 +708,8 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
db::local_processor<db::Polygon, db::Edge, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Edge> > others;
others.push_back (other.begin_merged ());
@ -752,6 +760,8 @@ AsIfFlatRegion::pull_generic (const Texts &other) const
db::local_processor<db::Polygon, db::Text, db::Text> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Text> > others;
others.push_back (other.begin ());
@ -807,6 +817,8 @@ AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) cons
db::local_processor<db::Polygon, db::Polygon, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Polygon> > others;
others.push_back (other.begin_merged ());
@ -1170,6 +1182,8 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
db::local_processor<db::Polygon, db::Polygon, db::EdgePair> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Polygon> > others;
std::vector<bool> foreign;

View File

@ -601,6 +601,8 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
@ -620,6 +622,8 @@ DeepRegion::and_and_not_with (const DeepRegion *other) const
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
@ -1359,6 +1363,8 @@ Output *region_cop_impl (DeepRegion *region, db::CompoundRegionOperationNode &no
const_cast<db::Cell *> (&region->deep_layer ().initial_cell ()),
region->deep_layer ().breakout_cells ());
proc.set_description (region->progress_desc ());
proc.set_report_progress (region->report_progress ());
proc.set_base_verbosity (region->base_verbosity ());
proc.set_threads (region->deep_layer ().store ()->threads ());
@ -1464,6 +1470,8 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
deep_layer ().breakout_cells (),
other_deep ? other_deep->deep_layer ().breakout_cells () : 0);
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (polygons.store ()->threads ());
@ -1536,6 +1544,8 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count, true);
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (polygons.store ()->threads ());
if (split_after) {
@ -1575,6 +1585,8 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size
db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count, true);
db::local_processor<db::PolygonRef, db::Edge, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (polygons.store ()->threads ());
if (split_after) {
@ -1614,6 +1626,8 @@ DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
db::PullLocalOperation op (mode, touching);
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (polygons.store ()->threads ());
if (split_after) {
@ -1650,6 +1664,8 @@ DeepRegion::pull_generic (const Edges &other) const
db::PullWithEdgeLocalOperation op;
db::local_processor<db::PolygonRef, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_edges.layout (), &other_edges.initial_cell (), polygons.breakout_cells (), other_edges.breakout_cells ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (polygons.store ()->threads ());
proc.run (&op, polygons.layer (), other_edges.layer (), dl_out.layer ());
@ -1679,6 +1695,8 @@ DeepRegion::pull_generic (const Texts &other) const
db::PullWithTextLocalOperation op;
db::local_processor<db::PolygonRef, db::TextRef, db::TextRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (polygons.store ()->threads ());
proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ());
@ -1709,6 +1727,8 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size
db::InteractingWithTextLocalOperation op (inverse, min_count, max_count);
db::local_processor<db::PolygonRef, db::TextRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (polygons.store ()->threads ());
if (split_after) {

View File

@ -395,7 +395,7 @@ void NetlistSpiceReader::push_stream (const std::string &path)
istream = new tl::InputStream (tl::combine_path (tl::dirname (mp_stream->source ()), path));
}
} else {
istream = new tl::InputStream (current_uri.resolved (new_uri).to_string ());
istream = new tl::InputStream (current_uri.resolved (new_uri).to_abstract_path ());
}
m_streams.push_back (std::make_pair (istream, mp_stream.release ()));

View File

@ -725,7 +725,7 @@ template DB_PUBLIC void split_polygon<> (const db::DSimplePolygon &polygon, std:
// Smoothing tools
void
smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &points, db::Coord d)
smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &points, db::Coord d, bool keep_hv)
{
points.clear ();
points.reserve (std::distance (from, to));
@ -781,7 +781,9 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
bool can_drop = false;
if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
if (keep_hv && (p1.x () == p0.x () || p1.y () == p0.y () || p2.x () == p1.x () || p2.y () == p1.y ())) {
// keep points which participate in either a vertical or horizontal edge
} else if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
// jog configurations with small edges are candidates
can_drop = true;
} else if (db::vprod_sign (p2 - p1, p1 - p0) < 0) {
@ -839,19 +841,19 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
}
db::Polygon
smooth (const db::Polygon &polygon, db::Coord d)
smooth (const db::Polygon &polygon, db::Coord d, bool keep_hv)
{
db::Polygon new_poly;
std::vector <db::Point> new_pts;
smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d);
smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d, keep_hv);
if (new_pts.size () >= 3) {
new_poly.assign_hull (new_pts.begin (), new_pts.end (), false /*don't compress*/);
for (unsigned int h = 0; h < polygon.holes (); ++h) {
new_pts.clear ();
smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d);
smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d, keep_hv);
if (new_pts.size () >= 3) {
new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/);
}

View File

@ -449,6 +449,8 @@ db::Polygon DB_PUBLIC compute_rounded (const db::Polygon &poly, double rinner, d
*/
db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner, double router, unsigned int n);
#define KLAYOUT_SMOOTH_HAS_KEEP_HV 1
/**
* @brief Smooth a contour
*
@ -458,13 +460,14 @@ db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner,
* @param to The end of the contour
* @param new_pts The points that make up the new contour
* @param d The distance that determines the smoothing "roughness"
* @param keep_hv If true, vertical and horizontal edges are maintained
*/
void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, db::Coord d);
void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, db::Coord d, bool keep_hv);
/**
* @brief Smooth a polygon (apply smoothing to the whole polygon)
*/
db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d);
db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d, bool keep_hv);
/**
* @brief Returns a value indicating whether the polygon is an "strange polygon"

View File

@ -0,0 +1,755 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbRecursiveInstanceIterator.h"
#include "dbRegion.h"
#include "dbEdgeProcessor.h"
#include "tlProgress.h"
namespace db
{
// ------------------------------------------------------------------------------------
// Recursive shape iterator implementation
RecursiveInstanceIterator::RecursiveInstanceIterator (const RecursiveInstanceIterator &d)
{
operator= (d);
}
RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const RecursiveInstanceIterator &d)
{
if (&d != this) {
m_all_targets = d.m_all_targets;
m_targets = d.m_targets;
m_max_depth = d.m_max_depth;
m_min_depth = d.m_min_depth;
m_overlapping = d.m_overlapping;
m_start = d.m_start;
m_stop = d.m_stop;
mp_layout = d.mp_layout;
mp_top_cell = d.mp_top_cell;
m_region = d.m_region;
if (d.mp_complex_region.get () != 0) {
mp_complex_region.reset (new region_type (*d.mp_complex_region.get ()));
} else {
mp_complex_region.reset (0);
}
m_box_convert = d.m_box_convert;
m_inst = d.m_inst;
m_inst_array = d.m_inst_array;
m_empty_cells_cache = d.m_empty_cells_cache;
mp_cell = d.mp_cell;
m_trans = d.m_trans;
m_trans_stack = d.m_trans_stack;
m_inst_iterators = d.m_inst_iterators;
m_inst_array_iterators = d.m_inst_array_iterators;
m_cells = d.m_cells;
m_local_complex_region_stack = d.m_local_complex_region_stack;
m_local_region_stack = d.m_local_region_stack;
m_needs_reinit = d.m_needs_reinit;
m_inst_quad_id = d.m_inst_quad_id;
m_inst_quad_id_stack = d.m_inst_quad_id_stack;
}
return *this;
}
RecursiveInstanceIterator::RecursiveInstanceIterator ()
{
// anything. Not necessary reasonable.
mp_layout = 0;
mp_top_cell = 0;
mp_cell = 0;
m_overlapping = false;
m_max_depth = std::numeric_limits<int>::max (); // all
m_min_depth = 0;
m_needs_reinit = false;
m_inst_quad_id = 0;
m_all_targets = true;
}
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type &region, bool overlapping)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_top_cell = &cell;
m_overlapping = overlapping;
init ();
init_region (region);
}
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type &region, bool overlapping)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_top_cell = &cell;
m_overlapping = overlapping;
init ();
init_region (region);
}
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_top_cell = &cell;
m_overlapping = false;
init ();
init_region (box_type::world ());
}
RecursiveInstanceIterator::~RecursiveInstanceIterator ()
{
// .. nothing yet ..
}
void
RecursiveInstanceIterator::init ()
{
m_needs_reinit = true;
m_max_depth = std::numeric_limits<int>::max (); // all
m_min_depth = 0; // from the beginning
m_inst_quad_id = 0;
mp_cell = 0;
m_all_targets = true;
}
void
RecursiveInstanceIterator::init_region (const RecursiveInstanceIterator::box_type &region)
{
m_region = region;
mp_complex_region.reset (0);
}
void
RecursiveInstanceIterator::init_region (const RecursiveInstanceIterator::region_type &region)
{
if (region.empty ()) {
m_region = box_type ();
mp_complex_region.reset (0);
} else if (region.is_box ()) {
m_region = region.bbox ();
mp_complex_region.reset (0);
} else {
mp_complex_region.reset (new region_type (region));
m_region = region.bbox ();
// A small optimization. We can do this since we merge and translate to trapezoids anyway.
mp_complex_region->set_strict_handling (false);
}
}
void
RecursiveInstanceIterator::set_region (const box_type &region)
{
if (m_region != region || mp_complex_region.get () != 0) {
init_region (region);
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::set_region (const region_type &region)
{
init_region (region);
m_needs_reinit = true;
}
void
RecursiveInstanceIterator::confine_region (const box_type &region)
{
if (m_region.empty ()) {
// no more confinement
} else if (mp_complex_region.get ()) {
init_region (*mp_complex_region & region_type (region));
} else {
init_region (m_region & region);
}
m_needs_reinit = true;
}
void
RecursiveInstanceIterator::confine_region (const region_type &region)
{
if (m_region.empty ()) {
// no more confinement
} else if (mp_complex_region.get ()) {
init_region (*mp_complex_region & region);
} else {
init_region (region & region_type (m_region));
}
m_needs_reinit = true;
}
void
RecursiveInstanceIterator::enable_all_targets ()
{
if (! m_all_targets) {
m_all_targets = true;
m_targets.clear ();
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::set_targets (const std::set<db::cell_index_type> &tgt)
{
if (m_all_targets || m_targets != tgt) {
m_targets = tgt;
m_all_targets = false;
m_needs_reinit = true;
}
}
namespace {
struct BoxTreePusher
: public db::SimplePolygonSink
{
BoxTreePusher (RecursiveInstanceIterator::box_tree_type *bt)
: mp_bt (bt)
{
// .. nothing yet ..
}
void put (const db::SimplePolygon &sp)
{
mp_bt->insert (sp.box ());
}
private:
RecursiveInstanceIterator::box_tree_type *mp_bt;
};
}
void
RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const
{
if (! m_needs_reinit) {
return;
}
m_needs_reinit = false;
// re-initialize
mp_cell = mp_top_cell;
m_trans_stack.clear ();
m_inst_iterators.clear ();
m_inst_quad_id_stack.clear ();
m_inst_array_iterators.clear ();
m_cells.clear ();
m_trans = cplx_trans_type ();
m_local_region_stack.clear ();
m_local_region_stack.push_back (m_region);
m_local_complex_region_stack.clear ();
if (mp_complex_region.get ()) {
// prepare a local complex region
m_local_complex_region_stack.push_back (box_tree_type ());
// Use a merge and the trapezoid generator to produce a decomposition that goes into the complex region
db::EdgeProcessor ep;
size_t n = 0;
for (region_type::const_iterator p = mp_complex_region->begin (); !p.at_end (); ++p, ++n) {
ep.insert (*p, n);
}
BoxTreePusher btp (&m_local_complex_region_stack.back ());
db::TrapezoidGenerator tg (btp);
db::MergeOp op (0);
ep.process (tg, op);
m_local_complex_region_stack.back ().sort (db::box_convert <db::Box> ());
}
if (mp_top_cell) {
if (! m_all_targets) {
m_target_tree.clear ();
mp_top_cell->collect_called_cells (m_target_tree);
}
new_cell (receiver);
next_instance (receiver);
}
}
void
RecursiveInstanceIterator::reset_selection ()
{
if (mp_layout) {
m_start.clear ();
m_stop.clear ();
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::unselect_cells (const std::set<db::cell_index_type> &cells)
{
if (mp_layout) {
for (std::set<db::cell_index_type>::const_iterator c = cells.begin (); c != cells.end (); ++c) {
m_stop.insert (*c);
m_start.erase (*c);
}
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::unselect_all_cells ()
{
if (mp_layout) {
m_start.clear ();
for (db::Layout::const_iterator c = mp_layout->begin (); c != mp_layout->end (); ++c) {
m_stop.insert (c->cell_index ());
}
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::select_cells (const std::set<db::cell_index_type> &cells)
{
if (mp_layout) {
for (std::set<db::cell_index_type>::const_iterator c = cells.begin (); c != cells.end (); ++c) {
m_start.insert (*c);
m_stop.erase (*c);
}
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::select_all_cells ()
{
if (mp_layout) {
m_stop.clear ();
for (db::Layout::const_iterator c = mp_layout->begin (); c != mp_layout->end (); ++c) {
m_start.insert (c->cell_index ());
}
m_needs_reinit = true;
}
}
const RecursiveInstanceIterator::instance_element_type *
RecursiveInstanceIterator::operator-> () const
{
validate (0);
m_combined_instance = db::InstElement (*m_inst, m_inst_array);
return &m_combined_instance;
}
bool
RecursiveInstanceIterator::at_end () const
{
validate (0);
return m_inst.at_end ();
}
std::vector<db::InstElement>
RecursiveInstanceIterator::path () const
{
std::vector<db::InstElement> elements;
for (size_t i = 0; i < m_inst_array_iterators.size () && i < m_inst_iterators.size (); ++i) {
elements.push_back (db::InstElement (*m_inst_iterators [i], m_inst_array_iterators [i]));
}
return elements;
}
void
RecursiveInstanceIterator::skip_inst_iter_for_complex_region () const
{
while (! m_inst.at_end ()) {
// skip inst quad if possible
while (! m_inst.at_end ()) {
if (is_outside_complex_region (m_inst.quad_box ())) {
m_inst.skip_quad ();
} else {
m_inst_quad_id = m_inst.quad_id ();
break;
}
}
// skip insts outside the complex region
if (! m_inst.at_end ()) {
if (! is_outside_complex_region (m_inst->bbox ())) {
break;
} else {
++m_inst;
}
}
}
}
void
RecursiveInstanceIterator::next (RecursiveInstanceReceiver *receiver)
{
if (! at_end ()) {
++m_inst_array;
if (! m_inst_array.at_end ()) {
new_inst_member (receiver);
} else {
++m_inst;
new_inst (receiver);
next_instance (receiver);
}
}
}
bool
RecursiveInstanceIterator::needs_visit () const
{
return int (m_inst_iterators.size ()) >= m_min_depth && ! is_inactive () && (m_all_targets || m_targets.find (m_inst->cell_index ()) != m_targets.end ());
}
void
RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) const
{
while (true) {
if (! m_inst.at_end ()) {
if (int (m_inst_iterators.size ()) < m_max_depth && (m_all_targets || m_target_tree.find (m_inst->cell_index ()) != m_target_tree.end ())) {
down (receiver);
}
} else {
if (! m_inst_iterators.empty ()) {
// no more instances: up and next instance
up (receiver);
} else {
break;
}
}
if (! m_inst.at_end ()) {
if (! needs_visit ()) {
++m_inst_array;
if (! m_inst_array.at_end ()) {
new_inst_member (receiver);
} else {
++m_inst;
new_inst (receiver);
}
} else {
break;
}
}
}
}
void
RecursiveInstanceIterator::down (RecursiveInstanceReceiver *receiver) const
{
m_trans_stack.push_back (m_trans);
m_cells.push_back (mp_cell);
m_inst_iterators.push_back (m_inst);
m_inst_array_iterators.push_back (m_inst_array);
m_inst_quad_id_stack.push_back (m_inst_quad_id);
bool ia = is_inactive ();
bool aoi = is_all_of_instance ();
mp_cell = &mp_layout->cell (m_inst->cell_index ());
set_inactive (ia);
set_all_of_instance (aoi);
m_trans = m_trans * m_inst->complex_trans (*m_inst_array);
// don't transform the world region, since transformation of that region might not work properly
box_type new_region = box_type::world ();
// compute the region inside the new cell
if (new_region != m_local_region_stack.front ()) {
new_region = m_trans.inverted () * m_local_region_stack.front ();
new_region &= cell ()->bbox ();
}
m_local_region_stack.push_back (new_region);
if (! m_local_complex_region_stack.empty ()) {
m_local_complex_region_stack.push_back (box_tree_type ());
const box_tree_type &pcl = m_local_complex_region_stack.end ()[-2];
if (! new_region.empty ()) {
// compute a new, reduced complex region for use inside the new cell
db::CellInstArray::complex_trans_type tinst = m_inst->complex_trans (*m_inst_array);
db::CellInstArray::complex_trans_type tinst_inv = tinst.inverted ();
db::Box bb;
for (box_tree_type::touching_iterator b = pcl.begin_touching (correct_box_overlapping (new_region.transformed (tinst)), db::box_convert<db::Box> ()); ! b.at_end (); ++b) {
db::Box lb = (b->transformed (tinst_inv) & new_region);
if (! lb.empty ()) {
m_local_complex_region_stack.back ().insert (lb);
bb += lb;
}
}
m_local_complex_region_stack.back ().sort (db::box_convert<db::Box> ());
// re-adjust the new local region, so we take into account additional clipping by the complex region.
// in the extreme case, this box is empty:
m_local_region_stack.back () = bb;
}
}
if (receiver) {
receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
}
new_cell (receiver);
}
void
RecursiveInstanceIterator::up (RecursiveInstanceReceiver *receiver) const
{
if (receiver) {
receiver->leave_cell (this, cell ());
}
m_inst = m_inst_iterators.back ();
m_inst_array = m_inst_array_iterators.back ();
m_inst_quad_id = m_inst_quad_id_stack.back ();
m_inst_iterators.pop_back ();
m_inst_array_iterators.pop_back ();
m_inst_quad_id_stack.pop_back ();
m_trans = m_trans_stack.back ();
m_trans_stack.pop_back ();
mp_cell = m_cells.back ();
m_cells.pop_back ();
m_local_region_stack.pop_back ();
if (! m_local_complex_region_stack.empty ()) {
m_local_complex_region_stack.pop_back ();
}
}
void
RecursiveInstanceIterator::new_cell (RecursiveInstanceReceiver *receiver) const
{
bool new_cell_inactive = is_child_inactive (cell_index ());
if (is_inactive () != new_cell_inactive) {
set_inactive (new_cell_inactive);
}
m_inst = cell ()->begin_touching (correct_box_overlapping (m_local_region_stack.back ()));
m_inst_quad_id = 0;
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
skip_inst_iter_for_complex_region ();
}
new_inst (receiver);
}
void
RecursiveInstanceIterator::new_inst (RecursiveInstanceReceiver *receiver) const
{
// look for the next instance with a non-empty array iterator. The array iterator can be empty because we
// use a lookup region.
while (! m_inst.at_end ()) {
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
skip_inst_iter_for_complex_region ();
if (m_inst.at_end ()) {
break;
}
}
bool all_of_instance = false;
bool with_region = false;
if (m_local_region_stack.back () != box_type::world () && ! m_inst->cell_inst ().bbox (m_box_convert).inside (m_local_region_stack.back ())) {
with_region = true;
} else {
// TODO: optimization potential: only report all_of_instance == false, if not entirely within the complex region
all_of_instance = m_local_complex_region_stack.empty ();
}
RecursiveInstanceReceiver::new_inst_mode ni = RecursiveInstanceReceiver::NI_all;
if (receiver) {
ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
}
if (ni == RecursiveInstanceReceiver::NI_skip) {
m_inst_array = inst_array_iterator ();
} else if (ni == RecursiveInstanceReceiver::NI_single) {
// a singular iterator
m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false);
} else if (with_region) {
m_inst_array = m_inst->cell_inst ().begin_touching (correct_box_overlapping (m_local_region_stack.back ()), m_box_convert);
} else {
m_inst_array = m_inst->cell_inst ().begin ();
}
set_all_of_instance (all_of_instance);
new_inst_member (receiver);
if (! m_inst_array.at_end ()) {
break;
} else {
++m_inst;
}
}
}
void
RecursiveInstanceIterator::new_inst_member (RecursiveInstanceReceiver *receiver) const
{
if (! m_local_complex_region_stack.empty ()) {
// skip instance array members not part of the complex region
while (! m_inst_array.at_end ()) {
db::Box ia_box = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ());
if (! is_outside_complex_region (ia_box)) {
break;
} else {
++m_inst_array;
}
}
}
while (! m_inst_array.at_end () && receiver) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
break;
} else {
++m_inst_array;
}
}
}
RecursiveInstanceIterator::box_type
RecursiveInstanceIterator::correct_box_overlapping (const box_type &box) const
{
if (! m_overlapping) {
return box;
} else if (box.empty () || box == box_type::world ()) {
return box;
} else if (box.width () < 2 || box.height () < 2) {
return box;
} else {
return box.enlarged (box_type::vector_type (-1, -1));
}
}
bool
RecursiveInstanceIterator::is_outside_complex_region (const box_type &box) const
{
if (m_overlapping) {
return m_local_complex_region_stack.back ().begin_overlapping (box, db::box_convert<box_type> ()).at_end ();
} else {
return m_local_complex_region_stack.back ().begin_touching (box, db::box_convert<box_type> ()).at_end ();
}
}
bool
RecursiveInstanceIterator::is_child_inactive (db::cell_index_type new_child) const
{
bool inactive = is_inactive ();
if (! m_start.empty () && m_start.find (new_child) != m_start.end ()) {
inactive = false;
} else if (! m_stop.empty () && m_stop.find (new_child) != m_stop.end ()) {
inactive = true;
}
return inactive;
}
void
RecursiveInstanceIterator::push (RecursiveInstanceReceiver *receiver)
{
// force reset so we can validate with a receiver
reset ();
receiver->begin (this);
try {
validate (receiver);
while (! at_end ()) {
next (receiver);
}
receiver->end (this);
} catch (...) {
receiver->end (this);
throw;
}
}
}

View File

@ -0,0 +1,713 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_dbRecursiveInstanceIterator
#define HDR_dbRecursiveInstanceIterator
#include "dbCommon.h"
#include "dbLayout.h"
#include "dbInstElement.h"
#include "tlAssert.h"
#include <map>
#include <set>
#include <vector>
namespace db
{
class Region;
class RecursiveInstanceReceiver;
/**
* @brief An iterator delivering shapes that touch or overlap the given region recursively
*
* The iterator can be constructed from a layout, a cell and a region.
* It simplifies retrieval of instances from a geometrical region while considering
* subcells as well.
* Some options can be specified, i.e. the level to which to look into or which cells
* to select.
*
* The general iteration scheme is iterating is depth-first and child instances before parent instances.
*/
class DB_PUBLIC RecursiveInstanceIterator
{
public:
typedef db::Layout layout_type;
typedef db::Box box_type;
typedef db::Region region_type;
typedef db::Cell cell_type;
typedef db::Cell::touching_iterator inst_iterator;
typedef db::CellInstArray::iterator inst_array_iterator;
typedef db::Instances::overlapping_iterator overlapping_instance_iterator;
typedef db::Instances::touching_iterator touching_instance_iterator;
typedef db::Instance instance_type;
typedef db::InstElement instance_element_type;
typedef db::ICplxTrans cplx_trans_type;
typedef instance_element_type value_type;
typedef db::box_tree<db::Box, db::Box, db::box_convert<db::Box>, 20, 20> box_tree_type;
/**
* @brief Default constructor
*/
RecursiveInstanceIterator ();
/**
* @brief Copy constructor
*/
RecursiveInstanceIterator (const RecursiveInstanceIterator &d);
/**
* @brief Assignment
*/
RecursiveInstanceIterator &operator= (const RecursiveInstanceIterator &d);
/**
* @brief Standard constructor
*
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
* @param region The region from which to select the instances
* @param overlapping Specify overlapping mode
*
* By default the iterator operates in touching mode - i.e. instances that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers instances that
* overlap the given region by at least one database unit.
* The cell instances are selected according to their overall bounding box.
*/
RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type &region, bool overlapping = false);
/**
* @brief Standard constructor
*
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
* @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode
*
* By default the iterator operates in touching mode - i.e. instances that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers instances that
* overlap the given region by at least one database unit.
* The cell instances are selected according to their overall bounding box.
* This version offers a complex search region instead of a simple box.
*/
RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type &region, bool overlapping = false);
/**
* @brief Standard constructor for "overall" iteration
*
* This iterator delivers all instances recursively.
*
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
*/
RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell);
/**
* @brief Destructor
*/
~RecursiveInstanceIterator ();
/**
* @brief Specify the maximum hierarchy depth to look into
*
* A depth of 0 instructs the iterator to deliver only instances from the initial cell.
* A higher depth instructs the iterator to look deeper.
* The depth must be specified before the instances are being retrieved.
*/
void max_depth (int depth)
{
if (m_max_depth != depth) {
m_max_depth = depth;
m_needs_reinit = true;
}
}
/**
* @brief Gets the maximum hierarchy depth to search for
*/
int max_depth () const
{
return m_max_depth;
}
/**
* @brief Specify the minimum hierarchy depth to look into
*
* A depth of 0 instructs the iterator to deliver instance from the top level and below.
* 1 instructs to deliver instance from the first child level.
* The minimum depth must be specified before the instances are being retrieved.
*/
void min_depth (int depth)
{
if (m_min_depth != depth) {
m_min_depth = depth;
m_needs_reinit = true;
}
}
/**
* @brief Gets the minimum hierarchy depth to search for
*/
int min_depth () const
{
return m_min_depth;
}
/**
* @brief Gets the layout
*/
const layout_type *layout () const
{
return mp_layout;
}
/**
* @brief Gets the top cell
*
* The top cell is the cell with which the iterator was started
*/
const cell_type *top_cell () const
{
return mp_top_cell;
}
/**
* @brief Gets the basic region the iterator is using (will be world if none is set)
* In addition to the basic region, a complex region may be defined that is further confining the
* search to a subregion of the basic region.
*/
const box_type &region () const
{
return m_region;
}
/**
* @brief Returns true if a complex region is given
*/
bool has_complex_region () const
{
return mp_complex_region.get () != 0;
}
/**
* @brief Gets the complex region the iterator is using
*/
const region_type &complex_region () const
{
tl_assert (mp_complex_region.get ());
return *mp_complex_region;
}
/**
* @brief Sets the region to a basic rectangle
* This will reset the iterator.
*/
void set_region (const box_type &region);
/**
* @brief Sets a complex search region
* This will reset the iterator to the beginning.
*/
void set_region (const region_type &region);
/**
* @brief Confines the search further to the given rectangle.
* This will reset the iterator and confine the search to the given rectangle
* in addition to any region or complex region already defined.
*/
void confine_region (const box_type &region);
/**
* @brief Confines the search further to the given complex region.
* This will reset the iterator and confine the search to the given region
* in addition to any simple region or complex region already defined.
*/
void confine_region (const region_type &region);
/**
* @brief Gets a flag indicating whether overlapping instances are selected when a region is used
*/
bool overlapping () const
{
return m_overlapping;
}
/**
* @brief Sets a flag indicating whether overlapping instances are selected when a region is used
*/
void set_overlapping (bool f)
{
if (m_overlapping != f) {
m_overlapping = f;
m_needs_reinit = true;
}
}
/**
* @brief Reset the iterator
*/
void reset ()
{
m_needs_reinit = true;
}
/**
* @brief Gets the selected target cells
*
* Only instances of cells in the targets set are reported.
* By default the iterator is configured to deliver all instances.
* By using "set_targets" with a set of cell indexes, the reporting
* can be confined to certain cells only. To enable all-cell reporting
* use "enable_all_targets".
*
* "all_targets_enabled" can be used to check which mode is used.
*/
const std::set<db::cell_index_type> &targets () const
{
return m_targets;
}
/**
* @brief Gets a flags indicating whether all targets are selected
* See \targets for more details.
*/
bool all_targets_enabled () const
{
return m_all_targets;
}
/**
* @brief Selects all target cells
* See \targets for more details.
*/
void enable_all_targets ();
/**
* @brief Selects the given targets
*
* This will reset the "all_targets" flag to false.
* See \targets for more details.
*/
void set_targets (const std::set<db::cell_index_type> &set_targets);
/**
* @brief Select cells
*
* Cell selection allows confining the hierarchy traversal to subtrees of the
* hierarchy tree. This happens by "selecting" and "unselecting" cells in the traversal path.
* "selected" cells will make iterator traverse the tree below this cell while
* "unselected" cells make the iterator ignore this cell.
* Cells which are neither selected nor unselected will be traversed depending
* on their parent's state. They are traversed if their parents are and are not traversed
* if their parents are not.
*
* If no specific cells have been selected before, this method will confine the selection
* to the given cells (plus their sub-hierarchy).
* If cells have been selected before, this will add the given cells to the selection.
*/
void select_cells (const std::set<db::cell_index_type> &cells);
/**
* @brief Select all cells
*
* Makes all cells selected. After doing so, all unselect_cells calls
* will unselect only that specific cell without children.
*
* See \select_cells for more details.
*/
void select_all_cells ();
/**
* @brief Unselect cells
*
* This method will remove the given cells (plus their sub-hierarchy) from the selection.
*
* See \select_cells for more details.
*/
void unselect_cells (const std::set<db::cell_index_type> &cells);
/**
* @brief Unselect all cells
*
* Makes all cells unselected. After doing so, select_cells calls
* will select only that specific cell without children.
*
* See \select_cells for more details.
*/
void unselect_all_cells ();
/**
* @brief Resets the selection
*
* This will reset all selections and unselections.
* After calling this methods, all select_cells will again select the cells
* including their children.
*
* See \select_cells for more details.
*/
void reset_selection ();
/**
* @brief Returns the cells in the "enable" selection
*
* Cells in this set make the iterator become active, while cells in the
* disable selection make the iterator inactive. Only when active, the
* iterator will deliver shapes.
*/
const std::set<db::cell_index_type> &enables () const
{
return m_start;
}
/**
* @brief Returns the cells in the "disable" selection
*/
const std::set<db::cell_index_type> &disables () const
{
return m_stop;
}
/**
* @brief Get the current transformation by which the instances must be transformed into the initial cell
*
* The instances delivered are not transformed. Instead, this transformation must be applied to
* get the instance in the coordinate system of the top cell.
*/
const cplx_trans_type &trans () const
{
validate (0);
return m_trans;
}
/**
* @brief Gets the current depth
*
* Returns the number of hierarchy levels we are below top level currently.
*/
unsigned int depth () const
{
validate (0);
return (unsigned int) m_trans_stack.size ();
}
/**
* @brief Gets the current instance
*
* Returns the instance currently referred to by the recursive iterator.
* This instance is not transformed yet and is located in the current cell.
*/
instance_element_type instance () const
{
return *operator-> ();
}
/**
* @brief Access operator
*
* The access operator is identical to the instance method.
*/
instance_element_type operator* () const
{
return *operator-> ();
}
/**
* @brief Access (arrow) operator
*
* The access operator is identical to the instance method.
*/
const instance_element_type *operator-> () const;
/**
* @brief End of iterator predicate
*
* Returns true, if the iterator is at the end of the sequence
*/
bool at_end () const;
/**
* @brief Gets the current cell's index
*/
db::cell_index_type cell_index () const
{
return cell ()->cell_index ();
}
/**
* @brief Gets the current cell's reference
*/
const cell_type *cell () const
{
validate (0);
size_t c = reinterpret_cast<size_t> (mp_cell);
return reinterpret_cast<const cell_type *> (c - (c & size_t (3)));
}
/**
* @brief Increments the iterator (operator version)
*/
RecursiveInstanceIterator &operator++()
{
next (0);
return *this;
}
/**
* @brief Increments the iterator
*/
void next ()
{
next (0);
}
/**
* @brief Comparison of iterators - equality
*/
bool operator==(const RecursiveInstanceIterator &d) const
{
if (at_end () != d.at_end ()) {
return false;
} else if (at_end ()) {
return true;
} else {
return (*m_inst == *d.m_inst);
}
}
/**
* @brief Comparison of iterators - inequality
*/
bool operator!=(const RecursiveInstanceIterator &d) const
{
return !operator==(d);
}
/**
* @brief The instance path
*/
std::vector<instance_element_type> path () const;
/**
* @brief Push-mode delivery
*
* This method will deliver all instances to the given receiver.
* In contrast to pull mode, this method allows tailoring the
* traversal of the hierarchy tree during iteration.
* For this purpose, the receiver has methods that receive
* events and to some extend may modify the traversal (e.g.
* return value of enter_cell).
*
* See RecursiveInstanceReceiver class for more details.
*/
void push (RecursiveInstanceReceiver *receiver);
/**
* @brief Returns a value indicating whether the current cell is inactive (disabled)
*/
bool is_inactive () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
}
/**
* @brief Returns a value indicating whether a new child cell of the current cell will be inactive
*/
bool is_child_inactive (db::cell_index_type new_child) const;
private:
int m_max_depth;
int m_min_depth;
bool m_overlapping;
std::set<db::cell_index_type> m_start, m_stop;
std::set<db::cell_index_type> m_targets;
bool m_all_targets;
const layout_type *mp_layout;
const cell_type *mp_top_cell;
box_type m_region;
std::unique_ptr<region_type> mp_complex_region;
db::box_convert<db::CellInst> m_box_convert;
mutable inst_iterator m_inst;
mutable inst_array_iterator m_inst_array;
mutable instance_element_type m_combined_instance;
mutable std::map<db::cell_index_type, bool> m_empty_cells_cache;
mutable const cell_type *mp_cell;
mutable cplx_trans_type m_trans;
mutable std::vector<cplx_trans_type> m_trans_stack;
mutable std::vector<inst_iterator> m_inst_iterators;
mutable std::vector<inst_array_iterator> m_inst_array_iterators;
mutable std::vector<const cell_type *> m_cells;
mutable std::vector<box_tree_type> m_local_complex_region_stack;
mutable std::vector<box_type> m_local_region_stack;
mutable bool m_needs_reinit;
mutable size_t m_inst_quad_id;
mutable std::vector<size_t> m_inst_quad_id_stack;
mutable std::set<db::cell_index_type> m_target_tree;
void init ();
void init_region (const region_type &region);
void init_region (const box_type &region);
void skip_inst_iter_for_complex_region () const;
void validate (RecursiveInstanceReceiver *receiver) const;
void next (RecursiveInstanceReceiver *receiver);
bool needs_visit () const;
void next_instance (RecursiveInstanceReceiver *receiver) const;
void new_inst (RecursiveInstanceReceiver *receiver) const;
void new_inst_member (RecursiveInstanceReceiver *receiver) const;
void new_cell (RecursiveInstanceReceiver *receiver) const;
void up (RecursiveInstanceReceiver *receiver) const;
void down (RecursiveInstanceReceiver *receiver) const;
bool is_outside_complex_region (const box_type &box) const;
box_type correct_box_overlapping (const box_type &box) const;
void set_inactive (bool a) const
{
size_t c = reinterpret_cast<size_t> (mp_cell);
c -= (c & size_t (1));
mp_cell = reinterpret_cast<const db::Cell *> (c + (a ? 1 : 0));
}
bool is_all_of_instance () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (2)) != 0;
}
void set_all_of_instance (bool a) const
{
size_t c = reinterpret_cast<size_t> (mp_cell);
c -= (c & size_t (2));
mp_cell = reinterpret_cast<const db::Cell *> (c + (a ? 2 : 0));
}
};
/**
* @brief A receiver interface for "push" mode
*
* In push mode, the iterator will deliver the instances and hierarchy transitions
* to this interface. See "RecursiveInstanceIterator::push" for details about this
* mode.
*
* The receiver receives events for the start of the delivery, on each cell
* entry and on each instance (followed by a cell entry).
*/
class DB_PUBLIC RecursiveInstanceReceiver
{
public:
typedef RecursiveInstanceIterator::box_tree_type box_tree_type;
/**
* @brief See new_inst for details.
*/
enum new_inst_mode { NI_all = 0, NI_single = 1, NI_skip = 2 };
/**
* @brief Constructor
*/
RecursiveInstanceReceiver () { }
/**
* @brief Destructor
*/
virtual ~RecursiveInstanceReceiver () { }
/**
* @brief Called once when the iterator begins pushing
*/
virtual void begin (const RecursiveInstanceIterator * /*iter*/) { }
/**
* @brief Called once after the iterator pushed everything
*/
virtual void end (const RecursiveInstanceIterator * /*iter*/) { }
/**
* @brief Enters a cell
*
* This method is called when the recursive shape iterator
* enters a new cell. It is not called for the top cell. When it is called, "iter->trans()"
* will already be updated.
*
* @param iter The iterator
* @param cell The cell which is entered
* @param region The clip box as seen from "cell" or db::Box::world if there is no clip box
* @param complex_region A complex clip region if one is supplied together with "region"
*/
virtual void enter_cell (const RecursiveInstanceIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
/**
* @brief Leaves the current cell
*
* This method is the counterpart for "enter_cell". It is called when traversal of "cell" ended.
*/
virtual void leave_cell (const RecursiveInstanceIterator * /*iter*/, const db::Cell * /*cell*/) { }
/**
* @brief Enters a new instance
*
* This method is called before "enter_cell" and "new_inst_member" is called and will indicate the instance to follow.
* The sequence of events is
*
* new_inst(A)
* new_inst_member(A[0,0])
* enter_cell(A)
* ...
* leave_cell(A)
* new_inst_member(A[1,0])
* enter_cell(A)
* ...
* leave_cell(A)
* ...
* new_inst(B)
* ...
*
* The "all" parameter is true, if all instances of the array will be addressed.
*
* This method can return the following values:
* - NI_all: iterate all members through "new_inst_member"
* - NI_single: iterate a single member (the first one)
* - NI_skip: skips the whole array (not a single instance is iterated)
*/
virtual new_inst_mode new_inst (const RecursiveInstanceIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
/**
* @brief Enters a new array member of the instance
*
* See "new_inst" for a description. This method adds the "trans" parameter
* which holds the complex transformation for this particular instance of
* the array.
*
* "all" is true, if an instance array is iterated in "all" mode (see new_inst).
*
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered.
*/
virtual bool new_inst_member (const RecursiveInstanceIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
};
} // namespace db
#endif

View File

@ -263,15 +263,15 @@ Region::rounded_corners (double rinner, double router, unsigned int n) const
}
void
Region::smooth (coord_type d)
Region::smooth (coord_type d, bool keep_hv)
{
process (SmoothingProcessor (d));
process (SmoothingProcessor (d, keep_hv));
}
Region
Region::smoothed (coord_type d) const
Region::smoothed (coord_type d, bool keep_hv) const
{
return processed (SmoothingProcessor (d));
return processed (SmoothingProcessor (d, keep_hv));
}
void

View File

@ -1518,14 +1518,14 @@ public:
/**
* @brief Smoothes the region (in-place)
*/
void smooth (coord_type d);
void smooth (coord_type d, bool keep_hv);
/**
* @brief Returns the smoothed region
*
* @param d The smoothing accuracy
*/
Region smoothed (coord_type d) const;
Region smoothed (coord_type d, bool keep_hv) const;
/**
* @brief Returns the nth polygon

View File

@ -614,6 +614,34 @@ RectilinearFilter::vars () const
return 0;
}
// -------------------------------------------------------------------------------------
// HoleCountFilter implementation
HoleCountFilter::HoleCountFilter (size_t min_count, size_t max_count, bool inverse)
: m_min_count (min_count), m_max_count (max_count), m_inverse (inverse)
{
// .. nothing yet ..
}
bool
HoleCountFilter::selected (const db::Polygon &poly) const
{
bool ok = poly.holes () < m_max_count && poly.holes () >= m_min_count;
return ok != m_inverse;
}
bool
HoleCountFilter::selected (const db::PolygonRef &poly) const
{
bool ok = poly.obj ().holes () < m_max_count && poly.obj ().holes () >= m_min_count;
return ok != m_inverse;
}
const TransformationReducer *HoleCountFilter::vars () const
{
return 0;
}
// -------------------------------------------------------------------------------------
// RectilinearFilter implementation
@ -840,14 +868,14 @@ StrangePolygonCheckProcessor::process (const db::Polygon &poly, std::vector<db::
// -------------------------------------------------------------------------------------------------------------
// Smoothing processor
SmoothingProcessor::SmoothingProcessor (db::Coord d) : m_d (d) { }
SmoothingProcessor::SmoothingProcessor (db::Coord d, bool keep_hv) : m_d (d), m_keep_hv (keep_hv) { }
SmoothingProcessor::~SmoothingProcessor () { }
void
SmoothingProcessor::process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
{
res.push_back (db::smooth (poly, m_d));
res.push_back (db::smooth (poly, m_d, m_keep_hv));
}
// -------------------------------------------------------------------------------------------------------------

View File

@ -286,6 +286,51 @@ private:
bool m_inverse;
};
/**
* @brief Filters by number of holes
*
* This filter will select all polygons with a hole count between min_holes and max_holes (exclusively)
*/
struct DB_PUBLIC HoleCountFilter
: public AllMustMatchFilter
{
/**
* @brief Constructor
* @param inverse If set to true, only polygons not matching this criterion will be filtered
*/
HoleCountFilter (size_t min_count, size_t max_count, bool inverse);
/**
* @brief Returns true if the polygon is a rectangle
*/
virtual bool selected (const db::Polygon &poly) const;
/**
* @brief Returns true if the polygon is a rectangle
*/
virtual bool selected (const db::PolygonRef &poly) const;
/**
* @brief This filter does not need variants
*/
virtual const TransformationReducer *vars () const;
/**
* @brief This filter prefers producing variants
*/
virtual bool wants_variants () const { return true; }
/**
* @brief This filter wants merged input
*/
virtual bool requires_raw_input () const { return false; }
private:
size_t m_min_count, m_max_count;
bool m_inverse;
};
/**
* @brief A bounding box filter for use with Region::filter or Region::filtered
*
@ -459,7 +504,7 @@ class DB_PUBLIC SmoothingProcessor
: public PolygonProcessorBase
{
public:
SmoothingProcessor (db::Coord d);
SmoothingProcessor (db::Coord d, bool keep_hv);
~SmoothingProcessor ();
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const;
@ -472,6 +517,7 @@ public:
private:
db::Coord m_d;
bool m_keep_hv;
db::MagnificationReducer m_vars;
};

View File

@ -38,6 +38,8 @@
#include "dbCellMapping.h"
#include "dbPCellDeclaration.h"
#include "dbSaveLayoutOptions.h"
#include "dbRecursiveShapeIterator.h"
#include "dbRecursiveInstanceIterator.h"
#include "dbWriter.h"
#include "dbHash.h"
#include "tlStream.h"
@ -1204,6 +1206,56 @@ begin_shapes_rec_overlapping_um (const db::Cell *cell, unsigned int layer, db::D
return db::RecursiveShapeIterator (*layout, *cell, layer, db::CplxTrans (layout->dbu ()).inverted () * region, true);
}
static db::RecursiveInstanceIterator
begin_instances_rec (const db::Cell *cell)
{
const db::Layout *layout = cell->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell is not inside layout")));
}
return db::RecursiveInstanceIterator (*layout, *cell);
}
static db::RecursiveInstanceIterator
begin_instances_rec_touching (const db::Cell *cell, db::Box region)
{
const db::Layout *layout = cell->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell is not inside layout")));
}
return db::RecursiveInstanceIterator (*layout, *cell, region, false);
}
static db::RecursiveInstanceIterator
begin_instances_rec_touching_um (const db::Cell *cell, db::DBox region)
{
const db::Layout *layout = cell->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell is not inside layout")));
}
return db::RecursiveInstanceIterator (*layout, *cell, db::CplxTrans (layout->dbu ()).inverted () * region, false);
}
static db::RecursiveInstanceIterator
begin_instances_rec_overlapping (const db::Cell *cell, db::Box region)
{
const db::Layout *layout = cell->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell is not inside layout")));
}
return db::RecursiveInstanceIterator (*layout, *cell, region, true);
}
static db::RecursiveInstanceIterator
begin_instances_rec_overlapping_um (const db::Cell *cell, db::DBox region)
{
const db::Layout *layout = cell->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell is not inside layout")));
}
return db::RecursiveInstanceIterator (*layout, *cell, db::CplxTrans (layout->dbu ()).inverted () * region, true);
}
static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::LayerMapping &layer_mapping)
{
cell->copy_shapes (source_cell, layer_mapping);
@ -1833,6 +1885,54 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"\n"
"This variant has been added in version 0.25.\n"
) +
gsi::method_ext ("begin_instances_rec", &begin_instances_rec,
"@brief Delivers a recursive instance iterator for the instances below the cell\n"
"@return A suitable iterator\n"
"\n"
"For details see the description of the \\RecursiveInstanceIterator class.\n"
"\n"
"This method has been added in version 0.27.\n"
) +
gsi::method_ext ("begin_instances_rec_touching", &begin_instances_rec_touching, gsi::arg ("region"),
"@brief Delivers a recursive instance iterator for the instances below the cell\n"
"@param region The search region\n"
"@return A suitable iterator\n"
"\n"
"For details see the description of the \\RecursiveInstanceIterator class.\n"
"This version gives an iterator delivering instances whose bounding box touches the given region.\n"
"\n"
"This method has been added in version 0.27.\n"
) +
gsi::method_ext ("begin_instances_rec_touching", &begin_instances_rec_touching_um, gsi::arg ("region"),
"@brief Delivers a recursive instance iterator for the instances below the cell using a region search, with the region given in micrometer units\n"
"@param region The search region as \\DBox object in micrometer units\n"
"@return A suitable iterator\n"
"\n"
"For details see the description of the \\RecursiveInstanceIterator class.\n"
"This version gives an iterator delivering instances whose bounding box touches the given region.\n"
"\n"
"This variant has been added in version 0.27.\n"
) +
gsi::method_ext ("begin_instances_rec_overlapping", &begin_instances_rec_overlapping, gsi::arg ("region"),
"@brief Delivers a recursive instance iterator for the instances below the cell using a region search\n"
"@param region The search region\n"
"@return A suitable iterator\n"
"\n"
"For details see the description of the \\RecursiveInstanceIterator class.\n"
"This version gives an iterator delivering instances whose bounding box overlaps the given region.\n"
"\n"
"This method has been added in version 0.27.\n"
) +
gsi::method_ext ("begin_instances_rec_overlapping", &begin_instances_rec_overlapping_um, gsi::arg ("region"),
"@brief Delivers a recursive instance iterator for the instances below the cell using a region search, with the region given in micrometer units\n"
"@param region The search region as \\DBox object in micrometer units\n"
"@return A suitable iterator\n"
"\n"
"For details see the description of the \\RecursiveInstanceIterator class.\n"
"This version gives an iterator delivering instances whose bounding box overlaps the given region.\n"
"\n"
"This variant has been added in version 0.27.\n"
) +
gsi::method_ext ("copy_shapes", &copy_shapes1, gsi::arg ("source_cell"),
"@brief Copies the shapes from the given cell into this cell\n"
"@param source_cell The cell from where to copy shapes\n"

View File

@ -185,10 +185,10 @@ static db::CompoundRegionOperationNode *new_strange_polygons_filter (db::Compoun
return new db::CompoundRegionProcessingOperationNode (new db::StrangePolygonCheckProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d)
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d, bool keep_hv)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/, d);
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d, keep_hv), input, true /*processor is owned*/, d);
}
static db::CompoundRegionOperationNode *new_rounded_corners (db::CompoundRegionOperationNode *input, double rinner, double router, unsigned int n)
@ -466,6 +466,12 @@ static db::CompoundRegionOperationNode *new_perimeter_sum_filter (db::CompoundRe
return new db::CompoundRegionFilterOperationNode (new db::RegionPerimeterFilter (pmin, pmax, inverse), input, true, true /*sum of set*/);
}
static db::CompoundRegionOperationNode *new_hole_count_filter (db::CompoundRegionOperationNode *input, bool inverse, size_t hmin, size_t hmax)
{
check_non_null (input, "input");
return new db::CompoundRegionFilterOperationNode (new db::HoleCountFilter (hmin, hmax, inverse), input, true);
}
static db::CompoundRegionOperationNode *new_area_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits<db::Coord>::area_type amin, db::coord_traits<db::Coord>::area_type amax)
{
check_non_null (input, "input");
@ -566,9 +572,10 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
"@brief Creates a node extracting strange polygons.\n"
"'strange polygons' are ones which cannot be oriented - e.g. '8' shape polygons."
) +
gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"),
gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Creates a node smoothing the polygons.\n"
"@param d The tolerance to be applied for the smoothing."
"@param d The tolerance to be applied for the smoothing.\n"
"@param keep_hv If true, horizontal and vertical edges are maintained.\n"
) +
gsi::constructor ("new_rounded_corners", &new_rounded_corners, gsi::arg ("input"), gsi::arg ("rinner"), gsi::arg ("router"), gsi::arg ("n"),
"@brief Creates a node generating rounded corners.\n"
@ -672,6 +679,11 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
"@brief Creates a node filtering the input by area sum.\n"
"Like \\new_area_filter, but applies to the sum of all shapes in the current set.\n"
) +
gsi::constructor ("new_hole_count_filter", &new_hole_count_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("hmin", 0), gsi::arg ("hmax", std::numeric_limits<size_t>::max (), "max"),
"@brief Creates a node filtering the input by number of holes per polygon.\n"
"This node renders the input if the hole count is between hmin and hmax (exclusively). If 'inverse' is set to true, the "
"input shape is returned if the hole count is less than hmin (exclusively) or larger than hmax (inclusively)."
) +
gsi::constructor ("new_bbox_filter", &new_bbox_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits<db::coord_traits<db::Coord>::area_type>::max (), "max"),
"@brief Creates a node filtering the input by bounding box parameters.\n"
"This node renders the input if the specified bounding box parameter of the input shape is between pmin and pmax (exclusively). If 'inverse' is set to true, the "

View File

@ -1716,9 +1716,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"For details see the description of the \\RecursiveShapeIterator class.\n"
"This version is convenience overload which takes a cell object instead of a cell index.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec instead.\n"
"\n"
"This method has been added in version 0.24.\n"
) +
gsi::method_ext ("begin_shapes", &begin_shapes, gsi::arg ("cell_index"), gsi::arg ("layer"),
gsi::method_ext ("#begin_shapes", &begin_shapes, gsi::arg ("cell_index"), gsi::arg ("layer"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer\n"
"@param cell_index The index of the initial (top) cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1726,9 +1728,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"For details see the description of the \\RecursiveShapeIterator class.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec instead.\n"
"\n"
"This method has been added in version 0.18.\n"
) +
gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n"
"@param cell_index The index of the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1738,9 +1742,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"For details see the description of the \\RecursiveShapeIterator class.\n"
"This version gives an iterator delivering shapes whose bounding box touches the given region.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n"
"\n"
"This method has been added in version 0.18.\n"
) +
gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching2, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching2, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n"
"@param cell The cell object for the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1751,9 +1757,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"This version gives an iterator delivering shapes whose bounding box touches the given region.\n"
"It is convenience overload which takes a cell object instead of a cell index.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n"
"\n"
"This method has been added in version 0.24.\n"
) +
gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n"
"@param cell_index The index of the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1763,9 +1771,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"For details see the description of the \\RecursiveShapeIterator class.\n"
"This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n"
"\n"
"This method has been added in version 0.18.\n"
) +
gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping2, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping2, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search\n"
"@param cell The cell object for the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1776,9 +1786,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n"
"It is convenience overload which takes a cell object instead of a cell index.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n"
"\n"
"This method has been added in version 0.24.\n"
) +
gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n"
"@param cell_index The index of the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1788,9 +1800,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"For details see the description of the \\RecursiveShapeIterator class.\n"
"This version gives an iterator delivering shapes whose bounding box touches the given region.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n"
"\n"
"This variant has been added in version 0.25.\n"
) +
gsi::method_ext ("begin_shapes_touching", &begin_shapes_touching2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_touching", &begin_shapes_touching2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n"
"@param cell The cell object for the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1801,9 +1815,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"This version gives an iterator delivering shapes whose bounding box touches the given region.\n"
"It is convenience overload which takes a cell object instead of a cell index.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_touching instead.\n"
"\n"
"This variant has been added in version 0.25.\n"
) +
gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping_um, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n"
"@param cell_index The index of the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1813,9 +1829,11 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"For details see the description of the \\RecursiveShapeIterator class.\n"
"This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n"
"\n"
"This variant has been added in version 0.25.\n"
) +
gsi::method_ext ("begin_shapes_overlapping", &begin_shapes_overlapping2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"),
gsi::method_ext ("#begin_shapes_overlapping", &begin_shapes_overlapping2_um, gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Delivers a recursive shape iterator for the shapes below the given cell on the given layer using a region search, the region given in micrometer units\n"
"@param cell The cell object for the starting cell\n"
"@param layer The layer from which to get the shapes\n"
@ -1826,6 +1844,8 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"This version gives an iterator delivering shapes whose bounding box overlaps the given region.\n"
"It is convenience overload which takes a cell object instead of a cell index.\n"
"\n"
"This method is deprecated. Use \\Cell#begin_shapes_rec_overlapping instead.\n"
"\n"
"This variant has been added in version 0.25.\n"
) +
gsi::method_ext ("#write", &write_options2, gsi::arg ("filename"), gsi::arg ("gzip"), gsi::arg ("options"),

View File

@ -1602,9 +1602,9 @@ static db::Polygon transformed_icplx_dp (const db::Polygon *p, const db::ICplxTr
return p->transformed (t, false /*don't compress*/);
}
static db::Polygon smooth (const db::Polygon *p, db::Coord d)
static db::Polygon smooth (const db::Polygon *p, db::Coord d, bool keep_hv)
{
return db::smooth (*p, d);
return db::smooth (*p, d, keep_hv);
}
static db::Polygon minkowsky_sum_pe (const db::Polygon *p, const db::Edge &e, bool rh)
@ -1787,17 +1787,18 @@ Class<db::Polygon> decl_Polygon ("db", "Polygon",
"\n"
"This method was introduced in version 0.22.\n"
) +
method_ext ("smooth", &smooth, gsi::arg ("d"),
method_ext ("smooth", &smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Smoothes a polygon\n"
"\n"
"Remove vertices that deviate by more than the distance d from the average contour.\n"
"The value d is basically the roughness which is removed.\n"
"\n"
"@param d The smoothing \"roughness\".\n"
"@param keep_hv If true, horizontal and vertical edges will be preserved always.\n"
"\n"
"@return The smoothed polygon.\n"
"\n"
"This method was introduced in version 0.23.\n"
"This method was introduced in version 0.23. The 'keep_hv' optional parameter was added in version 0.27.\n"
) +
method_ext ("minkowsky_sum", &minkowsky_sum_pe, gsi::arg ("e"), gsi::arg ("resolve_holes"),
"@brief Computes the Minkowsky sum of the polygon and an edge\n"

View File

@ -0,0 +1,558 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "gsiDecl.h"
#include "dbRecursiveInstanceIterator.h"
#include "dbRegion.h"
#include "tlGlobPattern.h"
namespace gsi
{
// ---------------------------------------------------------------
// db::RecursiveInstanceIterator binding
static db::RecursiveInstanceIterator *new_si1 (const db::Layout &layout, const db::Cell &cell)
{
return new db::RecursiveInstanceIterator (layout, cell);
}
static db::RecursiveInstanceIterator *new_si2 (const db::Layout &layout, const db::Cell &cell, const db::Box &box, bool overlapping)
{
return new db::RecursiveInstanceIterator (layout, cell, box, overlapping);
}
static db::RecursiveInstanceIterator *new_si2a (const db::Layout &layout, const db::Cell &cell, const db::Region &region, bool overlapping)
{
return new db::RecursiveInstanceIterator (layout, cell, region, overlapping);
}
static db::DCplxTrans si_dtrans (const db::RecursiveInstanceIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * r->trans () * db::VCplxTrans (1.0 / ly->dbu ());
}
static void set_targets1 (db::RecursiveInstanceIterator *r, const std::vector<db::cell_index_type> &cells)
{
std::set<db::cell_index_type> cc;
cc.insert (cells.begin (), cells.end ());
r->set_targets (cc);
}
static db::DCplxTrans inst_dtrans (const db::RecursiveInstanceIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * (*r)->complex_trans () * db::VCplxTrans (1.0 / ly->dbu ());
}
static db::ICplxTrans inst_trans (const db::RecursiveInstanceIterator *r)
{
return (*r)->complex_trans ();
}
static db::Cell *inst_cell (const db::RecursiveInstanceIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return const_cast<db::Cell *> (&ly->cell ((*r)->inst_ptr.cell_index ()));
}
static void set_targets2 (db::RecursiveInstanceIterator *r, const std::string &pattern)
{
tl::GlobPattern p (pattern);
std::set<db::cell_index_type> cc;
for (db::Layout::const_iterator ci = r->layout ()->begin (); ci != r->layout ()->end (); ++ci) {
if (p.match (r->layout ()->cell_name (ci->cell_index ()))) {
cc.insert (ci->cell_index ());
}
}
r->set_targets (cc);
}
static void select_cells1 (db::RecursiveInstanceIterator *r, const std::vector<db::cell_index_type> &cells)
{
std::set<db::cell_index_type> cc;
cc.insert (cells.begin (), cells.end ());
r->select_cells (cc);
}
static void select_cells2 (db::RecursiveInstanceIterator *r, const std::string &pattern)
{
tl::GlobPattern p (pattern);
std::set<db::cell_index_type> cc;
for (db::Layout::const_iterator ci = r->layout ()->begin (); ci != r->layout ()->end (); ++ci) {
if (p.match (r->layout ()->cell_name (ci->cell_index ()))) {
cc.insert (ci->cell_index ());
}
}
r->select_cells (cc);
}
static void unselect_cells1 (db::RecursiveInstanceIterator *r, const std::vector<db::cell_index_type> &cells)
{
std::set<db::cell_index_type> cc;
cc.insert (cells.begin (), cells.end ());
r->unselect_cells (cc);
}
static void unselect_cells2 (db::RecursiveInstanceIterator *r, const std::string &pattern)
{
tl::GlobPattern p (pattern);
std::set<db::cell_index_type> cc;
for (db::Layout::const_iterator ci = r->layout ()->begin (); ci != r->layout ()->end (); ++ci) {
if (p.match (r->layout ()->cell_name (ci->cell_index ()))) {
cc.insert (ci->cell_index ());
}
}
r->unselect_cells (cc);
}
static db::Region complex_region (const db::RecursiveInstanceIterator *iter)
{
if (iter->has_complex_region ()) {
return iter->complex_region ();
} else {
return db::Region (iter->region ());
}
}
Class<db::RecursiveInstanceIterator> decl_RecursiveInstanceIterator ("db", "RecursiveInstanceIterator",
gsi::constructor ("new", &new_si1, gsi::arg ("layout"), gsi::arg ("cell"),
"@brief Creates a recursive instance iterator.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param layer The layer (index) from which the shapes are taken\n"
"\n"
"This constructor creates a new recursive instance iterator which delivers the instances of "
"the given cell plus its children.\n"
) +
gsi::constructor ("new", &new_si2, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("box"), gsi::arg ("overlapping", false),
"@brief Creates a recursive instance iterator with a search region.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param box The search region\n"
"@param overlapping If set to true, instances overlapping the search region are reported, otherwise touching is sufficient\n"
"\n"
"This constructor creates a new recursive instance iterator which delivers the instances of "
"the given cell plus its children.\n"
"\n"
"The search is confined to the region given by the \"box\" parameter. If \"overlapping\" is true, instances whose "
"bounding box is overlapping the search region are reported. If \"overlapping\" is false, instances whose "
"bounding box touches the search region are reported. The bounding box of instances is measured taking all layers "
"of the target cell into account.\n"
) +
gsi::constructor ("new", &new_si2a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("region"), gsi::arg ("overlapping"),
"@brief Creates a recursive instance iterator with a search region.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param region The search region\n"
"@param overlapping If set to true, instances overlapping the search region are reported, otherwise touching is sufficient\n"
"\n"
"This constructor creates a new recursive instance iterator which delivers the instances of "
"the given cell plus its children.\n"
"\n"
"The search is confined to the region given by the \"region\" parameter. The region needs to be a rectilinear region.\n"
"If \"overlapping\" is true, instances whose "
"bounding box is overlapping the search region are reported. If \"overlapping\" is false, instances whose "
"bounding box touches the search region are reported. The bounding box of instances is measured taking all layers "
"of the target cell into account.\n"
) +
gsi::method ("max_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::max_depth, gsi::arg ("depth"),
"@brief Specifies the maximum hierarchy depth to look into\n"
"\n"
"A depth of 0 instructs the iterator to deliver only instances from the initial cell.\n"
"A higher depth instructs the iterator to look deeper.\n"
"The depth must be specified before the instances are being retrieved.\n"
) +
gsi::method ("max_depth", (int (db::RecursiveInstanceIterator::*) () const) &db::RecursiveInstanceIterator::max_depth,
"@brief Gets the maximum hierarchy depth\n"
"\n"
"See \\max_depth= for a description of that attribute.\n"
) +
gsi::method ("min_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::min_depth, gsi::arg ("depth"),
"@brief Specifies the minimum hierarchy depth to look into\n"
"\n"
"A depth of 0 instructs the iterator to deliver instances from the top level.\n"
"1 instructs to deliver instances from the first child level.\n"
"The minimum depth must be specified before the instances are being retrieved.\n"
) +
gsi::method ("min_depth", (int (db::RecursiveInstanceIterator::*) () const) &db::RecursiveInstanceIterator::min_depth,
"@brief Gets the minimum hierarchy depth\n"
"\n"
"See \\min_depth= for a description of that attribute.\n"
) +
gsi::method ("reset", &db::RecursiveInstanceIterator::reset,
"@brief Resets the iterator to the initial state\n"
) +
gsi::method ("reset_selection", &db::RecursiveInstanceIterator::reset_selection,
"@brief Resets the selection to the default state\n"
"\n"
"In the initial state, the top cell and its children are selected. Child cells can be switched on and off "
"together with their sub-hierarchy using \\select_cells and \\unselect_cells.\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method ("layout", &db::RecursiveInstanceIterator::layout,
"@brief Gets the layout this iterator is connected to\n"
) +
gsi::method ("top_cell", &db::RecursiveInstanceIterator::top_cell,
"@brief Gets the top cell this iterator is connected to\n"
) +
gsi::method ("region", &db::RecursiveInstanceIterator::region,
"@brief Gets the basic region that is iterator is using\n"
"The basic region is the overall box the region iterator iterates over. "
"There may be an additional complex region that confines the region iterator. "
"See \\complex_region for this attribute.\n"
) +
gsi::method_ext ("complex_region", &complex_region,
"@brief Gets the complex region that is iterator is using\n"
"The complex region is the effective region (a \\Region object) that the "
"iterator is selecting from the layout. This region can be a single box "
"or a complex region.\n"
) +
gsi::method ("region=", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::box_type &)) &db::RecursiveInstanceIterator::set_region, gsi::arg ("box_region"),
"@brief Sets the rectangular region that is iterator is iterating over\n"
"See \\region for a description of this attribute.\n"
"Setting a simple region will reset the complex region to a rectangle and reset the iterator to "
"the beginning of the sequence."
) +
gsi::method ("region=", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::region_type &)) &db::RecursiveInstanceIterator::set_region, gsi::arg ("complex_region"),
"@brief Sets the complex region that is iterator is using\n"
"See \\complex_region for a description of this attribute. Setting the complex region will "
"reset the basic region (see \\region) to the bounding box of the complex region and "
"reset the iterator to the beginning of the sequence.\n"
) +
gsi::method ("confine_region", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::box_type &)) &db::RecursiveInstanceIterator::confine_region, gsi::arg ("box_region"),
"@brief Confines the region that is iterator is iterating over\n"
"This method is similar to setting the region (see \\region=), but will confine any region (complex or simple) already set. "
"Essentially it does a logical AND operation between the existing and given region. "
"Hence this method can only reduce a region, not extend it.\n"
) +
gsi::method ("confine_region", (void (db::RecursiveInstanceIterator::*)(const db::RecursiveInstanceIterator::region_type &)) &db::RecursiveInstanceIterator::confine_region, gsi::arg ("complex_region"),
"@brief Confines the region that is iterator is iterating over\n"
"This method is similar to setting the region (see \\region=), but will confine any region (complex or simple) already set. "
"Essentially it does a logical AND operation between the existing and given region. "
"Hence this method can only reduce a region, not extend it.\n"
) +
gsi::method ("overlapping?", &db::RecursiveInstanceIterator::overlapping,
"@brief Gets a flag indicating whether overlapping instances are selected when a region is used\n"
) +
gsi::method ("overlapping=", &db::RecursiveInstanceIterator::set_overlapping, gsi::arg ("region"),
"@brief Sets a flag indicating whether overlapping instances are selected when a region is used\n"
"\n"
"If this flag is false, instances touching the search region are returned.\n"
) +
gsi::method ("unselect_all_cells", &db::RecursiveInstanceIterator::unselect_all_cells,
"@brief Unselects all cells.\n"
"\n"
"This method will set the \"unselected\" mark on all cells. The effect is "
"that subsequent calls of \\select_cells will select only the specified cells, not "
"their children, because they are still unselected.\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method ("select_all_cells", &db::RecursiveInstanceIterator::select_all_cells,
"@brief Selects all cells.\n"
"\n"
"This method will set the \"selected\" mark on all cells. The effect is "
"that subsequent calls of \\unselect_cells will unselect only the specified cells, not "
"their children, because they are still unselected.\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method_ext ("unselect_cells", &unselect_cells1, gsi::arg ("cells"),
"@brief Unselects the given cells.\n"
"\n"
"This method will sets the \"unselected\" mark on the given cells. "
"That means that these cells or their child cells will not be visited, unless "
"they are marked as \"selected\" again with the \\select_cells method.\n"
"\n"
"The cells are given as a list of cell indexes.\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method_ext ("unselect_cells", &unselect_cells2, gsi::arg ("cells"),
"@brief Unselects the given cells.\n"
"\n"
"This method will sets the \"unselected\" mark on the given cells. "
"That means that these cells or their child cells will not be visited, unless "
"they are marked as \"selected\" again with the \\select_cells method.\n"
"\n"
"The cells are given as a glob pattern.\n"
"A glob pattern follows the syntax of "
"file names on the shell (i.e. \"A*\" are all cells starting with a letter \"A\").\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method_ext ("select_cells", &select_cells1, gsi::arg ("cells"),
"@brief Unselects the given cells.\n"
"\n"
"This method will sets the \"selected\" mark on the given cells. "
"That means that these cells or their child cells are visited, unless "
"they are marked as \"unselected\" again with the \\unselect_cells method.\n"
"\n"
"The cells are given as a list of cell indexes.\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method_ext ("select_cells", &select_cells2, gsi::arg ("cells"),
"@brief Unselects the given cells.\n"
"\n"
"This method will sets the \"selected\" mark on the given cells. "
"That means that these cells or their child cells are visited, unless "
"they are marked as \"unselected\" again with the \\unselect_cells method.\n"
"\n"
"The cells are given as a glob pattern.\n"
"A glob pattern follows the syntax of "
"file names on the shell (i.e. \"A*\" are all cells starting with a letter \"A\").\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method_ext ("targets=", &set_targets1, gsi::arg ("cells"),
"@brief Specifies the target cells.\n"
"\n"
"If target cells are specified, only instances of these cells are delivered. "
"This version takes a list of cell indexes for the targets. "
"By default, no target cell list is present and the instances of all cells "
"are delivered by the iterator. See \\all_targets_enabled? and \\enable_all_targets for "
"a description of this mode. Once a target list is specified, the iteration is "
"confined to the cells from this list."
"\n"
"The cells are given as a list of cell indexes.\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method_ext ("targets=", &set_targets2, gsi::arg ("cells"),
"@brief Specifies the target cells.\n"
"\n"
"If target cells are specified, only instances of these cells are delivered. "
"This version takes a cell list as a glob pattern. "
"A glob pattern follows the syntax of "
"file names on the shell (i.e. \"A*\" are all cells starting with a letter \"A\").\n"
"Use the curly-bracket notation to list different cells, e.g \"{A,B,C}\" for cells A, B and C.\n"
"\n"
"By default, no target cell list is present and the instances of all cells "
"are delivered by the iterator. See \\all_targets_enabled? and \\enable_all_targets for "
"a description of this mode. Once a target list is specified, the iteration is "
"confined to the cells from this list."
"\n"
"The cells are given as a list of cell indexes.\n"
"\n"
"This method will also reset the iterator.\n"
) +
gsi::method ("targets", &db::RecursiveInstanceIterator::targets,
"@brief Gets the list of target cells\n"
"See \\targets= for a description of the target cell concept. "
"This method returns a list of cell indexes of the selected target cells."
) +
gsi::method ("all_targets_enabled?", &db::RecursiveInstanceIterator::all_targets_enabled,
"@brief Gets a value indicating whether instances of all cells are reported\n"
"See \\targets= for a description of the target cell concept. "
) +
gsi::method ("enable_all_targets", &db::RecursiveInstanceIterator::enable_all_targets,
"@brief Enables 'all targets' mode in which instances of all cells are reported\n"
"See \\targets= for a description of the target cell concept. "
) +
gsi::method ("trans", &db::RecursiveInstanceIterator::trans,
"@brief Gets the accumulated transformation of the current instance parent cell to the top cell\n"
"\n"
"This transformation represents how the current instance is seen in the top cell.\n"
) +
gsi::method_ext ("dtrans", &gsi::si_dtrans,
"@brief Gets the accumulated transformation of the current instance parent cell to the top cell\n"
"\n"
"This transformation represents how the current instance is seen in the top cell.\n"
"This version returns the micon-unit transformation.\n"
) +
gsi::method ("at_end?", &db::RecursiveInstanceIterator::at_end,
"@brief End of iterator predicate\n"
"\n"
"Returns true, if the iterator is at the end of the sequence\n"
) +
gsi::method ("cell", &db::RecursiveInstanceIterator::cell,
"@brief Gets the cell the current instance sits in\n"
) +
gsi::method ("cell_index", &db::RecursiveInstanceIterator::cell_index,
"@brief Gets the index of the cell the current instance sits in\n"
"This is equivalent to 'cell.cell_index'."
) +
gsi::method_ext ("inst_trans", &inst_trans,
"@brief Gets the integer-unit transformation of the current instance\n"
"This is the transformation of the current instance inside its parent.\n"
"'trans * inst_trans' gives the full transformation how the current cell is seen in the top cell.\n"
"See also \\inst_dtrans and \\inst_cell.\n"
) +
gsi::method_ext ("inst_dtrans", &inst_dtrans,
"@brief Gets the micron-unit transformation of the current instance\n"
"This is the transformation of the current instance inside its parent.\n"
"'dtrans * inst_dtrans' gives the full micron-unit transformation how the current cell is seen in the top cell.\n"
"See also \\inst_trans and \\inst_cell.\n"
) +
gsi::method_ext ("inst_cell", &inst_cell,
"@brief Gets the target cell of the current instance\n"
"This is the cell the current instance refers to. It is one of the \\targets if a target list is given.\n"
) +
gsi::method ("current_inst_element", &db::RecursiveInstanceIterator::instance,
"@brief Gets the current instance\n"
"\n"
"This is the instance/array element the iterator currently refers to.\n"
"This is a \\InstElement object representing the current instance and the array element the iterator currently points at.\n"
"\n"
"See \\inst_trans, \\inst_dtrans and \\inst_cell for convenience methods to access the details of the current element.\n"
) +
gsi::method ("next", (void (db::RecursiveInstanceIterator::*) ()) &db::RecursiveInstanceIterator::next,
"@brief Increments the iterator\n"
"This moves the iterator to the next instance inside the search scope."
) +
gsi::method ("path", &db::RecursiveInstanceIterator::path,
"@brief Gets the instantatiation path of the instance addressed currently\n"
"\n"
"This attribute is a sequence of \\InstElement objects describing the cell instance path from the initial "
"cell to the current instance. The path is empty if the current instance is in the top cell.\n"
) +
gsi::method ("==", &db::RecursiveInstanceIterator::operator==, gsi::arg ("other"),
"@brief Comparison of iterators - equality\n"
"\n"
"Two iterators are equal if they point to the same instance.\n"
) +
gsi::method ("!=", &db::RecursiveInstanceIterator::operator!=, gsi::arg ("other"),
"@brief Comparison of iterators - inequality\n"
"\n"
"Two iterators are not equal if they do not point to the same instance.\n"
),
"@brief An iterator delivering instances recursively\n"
"\n"
"The iterator can be obtained from a cell and optionally a region.\n"
"It simplifies retrieval of instances while considering\n"
"subcells as well.\n"
"Some options can be specified in addition, i.e. the hierarchy level to which to look into.\n"
"The search can be confined to instances of certain cells (see \\targets=) or to certain regions. "
"Subtrees can be selected for traversal or excluded from it (see \\select_cells).\n"
"\n"
"This is some sample code:\n"
"\n"
"@code\n"
"# prints the effective instances of cell \"A\" as seen from the initial cell \"cell\"\n"
"iter = cell.begin_instances_rec\n"
"iter.targets = \"A\"\n"
"while !iter.at_end?\n"
" puts \"Instance of #{iter.inst_cell.name} in #{cell.name}: \" + (iter.dtrans * iter.inst_dtrans).to_s\n"
" iter.next\n"
"end\n"
"@/code\n"
"\n"
"Here, a target cell is specified which confines the search to instances of this particular cell.\n"
"'iter.dtrans' gives us the accumulated transformation of all parents up to the top cell. "
"'iter.inst_dtrans' gives us the transformation from the current instance. "
"'iter.inst_cell' finally gives us the target cell of the current instance (which is always 'A' in our case).\n"
"\n"
"\\Cell offers three methods to get these iterators: begin_instances_rec, begin_instances_rec_touching and begin_instances_rec_overlapping.\n"
"\\Cell#begin_instances_rec will deliver a standard recursive instance iterator which starts from the given cell and iterates "
"over all child cells. \\Cell#begin_instances_rec_touching creates a RecursiveInstanceIterator which delivers the instances "
"whose bounding boxed touch the given search box. \\Layout#begin_instances_rec_overlapping gives an iterator which delivers all instances whose bounding box "
"overlaps the search box.\n"
"\n"
"A RecursiveInstanceIterator object can also be created directly, like this:\n"
"\n"
"@code\n"
"iter = RBA::RecursiveInstanceIterator::new(layout, cell [, options ])\n"
"@/code\n"
"\n"
"\"layout\" is the layout object, \"cell\" the \\Cell object of the initial cell.\n"
"\n"
"The recursive instance iterator can be confined to a maximum hierarchy depth. By using \\max_depth=, the "
"iterator will restrict the search depth to the given depth in the cell tree.\n"
"In the same way, the iterator can be configured to start from a certain hierarchy depth using \\min_depth=. "
"The hierarchy depth always applies to the parent of the instances iterated.\n"
"\n"
"In addition, the recursive instance iterator supports selection and exclusion of subtrees. For that purpose "
"it keeps flags per cell telling it for which cells to turn instance delivery on and off. The \\select_cells method "
"sets the \"start delivery\" flag while \\unselect_cells sets the \"stop delivery\" flag. In effect, using "
"\\unselect_cells will exclude that cell plus the subtree from delivery. Parts of that subtree can be "
"turned on again using \\select_cells. For the cells selected that way, the instances of these cells and their "
"child cells are delivered, even if their parent was unselected.\n"
"\n"
"To get instances from a specific cell, i.e. \"MACRO\" plus its child cells, unselect the top cell first "
"and the select the desired cell again:\n"
"\n"
"@code\n"
"# deliver all instances inside \"MACRO\" and the sub-hierarchy:\n"
"iter = RBA::RecursiveInstanceIterator::new(layout, cell)\n"
"iter.unselect_cells(cell.cell_index)\n"
"iter.select_cells(\"MACRO\")\n"
"...\n"
"@/code\n"
"\n"
"The \\unselect_all_cells and \\select_all_cells methods turn on the \"stop\" and \"start\" flag "
"for all cells respectively. If you use \\unselect_all_cells and use \\select_cells for a specific cell, "
"the iterator will deliver only the instances of the selected cell, not its children. Those are still "
"unselected by \\unselect_all_cells:\n"
"\n"
"@code\n"
"# deliver all instance inside \"MACRO\" but not of child cells:\n"
"iter = RBA::RecursiveInstanceIterator::new(layout, cell)\n"
"iter.unselect_all_cells\n"
"iter.select_cells(\"MACRO\")\n"
"...\n"
"@/code\n"
"\n"
"Cell selection is done using cell indexes or glob pattern. Glob pattern are equivalent to the usual "
"file name wildcards used on various command line shells. For example \"A*\" matches all cells starting with "
"an \"A\". The curly brace notation and character classes are supported as well. For example \"C{125,512}\" matches "
"\"C125\" and \"C512\" and \"[ABC]*\" matches all cells starting with an \"A\", a \"B\" or \"C\". \"[^ABC]*\" matches "
"all cells not starting with one of that letters.\n"
"\n"
"To confine instance iteration to instances of certain cells, use the \\targets feature:\n"
"\n"
"@code\n"
"# deliver all instance of \"INV1\":\n"
"iter = RBA::RecursiveInstanceIterator::new(layout, cell)\n"
"iter.targets = \"INV1\"\n"
"...\n"
"@/code\n"
"\n"
"Targets can be specified either as lists of cell indexes or through a glob pattern.\n"
"\n"
"Instances are always delivered depth-first with child instances before their parents. A default recursive instance "
"iterator will first deliver leaf cells, followed by the parent of these cells.\n"
"\n"
"When a search region is used, instances whose bounding box touch or overlap (depending on 'overlapping' flag) will "
"be reported. The instance bounding box taken as reference is computed using all layers of the layout.\n"
"\n"
"The iterator will deliver the individual elements of instance arrays, confined to the search region if one is given. "
"Consequently the return value (\\current_inst_element) is an \\InstElement "
"object which is basically a combination of an \\Instance object and information about the current array element.\n"
"\\inst_cell, \\inst_trans and \\inst_dtrans are methods provided for convenience to access the current array member's transformation "
"and the target cell of the current instance.\n"
"\n"
"The RecursiveInstanceIterator class has been introduced in version 0.27.\n"
);
}

View File

@ -123,89 +123,89 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
gsi::constructor ("new", &new_si1, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"),
"@brief Creates a recursive, single-layer shape iterator.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param layer The layer (index) from which the shapes are taken\n"
"\n"
"This constructor creates a new recursive shape iterator which delivers the shapes of "
"the given cell plus it's children from the layer given by the layer index in the \"layer\" parameter.\n"
"the given cell plus its children from the layer given by the layer index in the \"layer\" parameter.\n"
"\n"
"This constructor has been introduced in version 0.23.\n"
) +
gsi::constructor ("new", &new_si2, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"),
"@brief Creates a recursive, multi-layer shape iterator.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param layers The layer indexes from which the shapes are taken\n"
"\n"
"This constructor creates a new recursive shape iterator which delivers the shapes of "
"the given cell plus it's children from the layers given by the layer indexes in the \"layers\" parameter.\n"
"the given cell plus its children from the layers given by the layer indexes in the \"layers\" parameter.\n"
"While iterating use the \\layer method to retrieve the layer of the current shape.\n"
"\n"
"This constructor has been introduced in version 0.23.\n"
) +
gsi::constructor ("new", &new_si3, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("box"), gsi::arg ("overlapping"),
gsi::constructor ("new", &new_si3, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("box"), gsi::arg ("overlapping", false),
"@brief Creates a recursive, single-layer shape iterator with a region.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param layer The layer (index) from which the shapes are taken\n"
"@param box The search region\n"
"@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n"
"\n"
"This constructor creates a new recursive shape iterator which delivers the shapes of "
"the given cell plus it's children from the layer given by the layer index in the \"layer\" parameter.\n"
"the given cell plus its children from the layer given by the layer index in the \"layer\" parameter.\n"
"\n"
"The search is confined to the region given by the \"box\" parameter. If \"overlapping\" is true, shapes whose "
"bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose "
"bounding box touches the search region are reported.\n"
"\n"
"This constructor has been introduced in version 0.23.\n"
"This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n"
) +
gsi::constructor ("new", &new_si3a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), gsi::arg ("overlapping"),
gsi::constructor ("new", &new_si3a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layer"), gsi::arg ("region"), gsi::arg ("overlapping", false),
"@brief Creates a recursive, single-layer shape iterator with a region.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param layer The layer (index) from which the shapes are taken\n"
"@param region The search region\n"
"@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n"
"\n"
"This constructor creates a new recursive shape iterator which delivers the shapes of "
"the given cell plus it's children from the layer given by the layer index in the \"layer\" parameter.\n"
"the given cell plus its children from the layer given by the layer index in the \"layer\" parameter.\n"
"\n"
"The search is confined to the region given by the \"region\" parameter. The region needs to be a rectilinear region.\n"
"If \"overlapping\" is true, shapes whose "
"bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose "
"bounding box touches the search region are reported.\n"
"\n"
"This constructor has been introduced in version 0.25.\n"
"This constructor has been introduced in version 0.25. The 'overlapping' parameter has been made optional in version 0.27.\n"
) +
gsi::constructor ("new", &new_si4, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("box"), gsi::arg ("overlapping"),
gsi::constructor ("new", &new_si4, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("box"), gsi::arg ("overlapping", false),
"@brief Creates a recursive, multi-layer shape iterator with a region.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param layers The layer indexes from which the shapes are taken\n"
"@param box The search region\n"
"@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n"
"\n"
"This constructor creates a new recursive shape iterator which delivers the shapes of "
"the given cell plus it's children from the layers given by the layer indexes in the \"layers\" parameter.\n"
"the given cell plus its children from the layers given by the layer indexes in the \"layers\" parameter.\n"
"While iterating use the \\layer method to retrieve the layer of the current shape.\n"
"\n"
"The search is confined to the region given by the \"box\" parameter. If \"overlapping\" is true, shapes whose "
"bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose "
"bounding box touches the search region are reported.\n"
"\n"
"This constructor has been introduced in version 0.23.\n"
"This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n"
) +
gsi::constructor ("new", &new_si4a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("region"), gsi::arg ("overlapping"),
gsi::constructor ("new", &new_si4a, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("layers"), gsi::arg ("region"), gsi::arg ("overlapping", false),
"@brief Creates a recursive, multi-layer shape iterator with a region.\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param cell The initial cell which shall be iterated (including its children)\n"
"@param layers The layer indexes from which the shapes are taken\n"
"@param region The search region\n"
"@param overlapping If set to true, shapes overlapping the search region are reported, otherwise touching is sufficient\n"
"\n"
"This constructor creates a new recursive shape iterator which delivers the shapes of "
"the given cell plus it's children from the layers given by the layer indexes in the \"layers\" parameter.\n"
"the given cell plus its children from the layers given by the layer indexes in the \"layers\" parameter.\n"
"While iterating use the \\layer method to retrieve the layer of the current shape.\n"
"\n"
"The search is confined to the region given by the \"region\" parameter. The region needs to be a rectilinear region.\n"
@ -213,10 +213,10 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"bounding box is overlapping the search region are reported. If \"overlapping\" is false, shapes whose "
"bounding box touches the search region are reported.\n"
"\n"
"This constructor has been introduced in version 0.23.\n"
"This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n"
) +
gsi::method ("max_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::max_depth, gsi::arg ("depth"),
"@brief Specify the maximum hierarchy depth to look into\n"
"@brief Specifies the maximum hierarchy depth to look into\n"
"\n"
"A depth of 0 instructs the iterator to deliver only shapes from the initial cell.\n"
"The depth must be specified before the shapes are being retrieved.\n"
@ -229,7 +229,23 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method ("reset", &db::RecursiveShapeIterator::reset,
gsi::method ("min_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::min_depth, gsi::arg ("depth"),
"@brief Specifies the minimum hierarchy depth to look into\n"
"\n"
"A depth of 0 instructs the iterator to deliver shapes from the top level.\n"
"1 instructs to deliver shapes from the first child level.\n"
"The minimum depth must be specified before the shapes are being retrieved.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("min_depth", (int (db::RecursiveShapeIterator::*) () const) &db::RecursiveShapeIterator::min_depth,
"@brief Gets the minimum hierarchy depth\n"
"\n"
"See \\min_depth= for a description of that attribute.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("reset", &db::RecursiveShapeIterator::reset,
"@brief Resets the iterator to the initial state\n"
"\n"
"This method has been introduced in version 0.23.\n"
@ -237,7 +253,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
gsi::method ("reset_selection", &db::RecursiveShapeIterator::reset_selection,
"@brief Resets the selection to the default state\n"
"\n"
"In the initial state, the top cell and it's children are selected. Child cells can be switched on and off "
"In the initial state, the top cell and its children are selected. Child cells can be switched on and off "
"together with their sub-hierarchy using \\select_cells and \\unselect_cells.\n"
"\n"
"This method will also reset the iterator.\n"
@ -436,7 +452,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"@brief Gets the current cell's index \n"
) +
gsi::method ("next", (void (db::RecursiveShapeIterator::*) ()) &db::RecursiveShapeIterator::next,
"@brief Increment the iterator\n"
"@brief Increments the iterator\n"
"This moves the iterator to the next shape inside the search scope."
) +
gsi::method ("layer", &db::RecursiveShapeIterator::layer,
@ -462,12 +478,12 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n"
"Two iterators are not equal if they do not point to the same shape.\n"
),
"@brief An iterator delivering shapes that touch or overlap the given region recursively\n"
"@brief An iterator delivering shapes recursively\n"
"\n"
"The iterator can be obtained from a layout, specifying a starting cell, a layer and optionally a region.\n"
"The iterator can be obtained from a cell, a layer and optionally a region.\n"
"It simplifies retrieval of shapes from a geometrical region while considering\n"
"subcells as well.\n"
"Some options can be specified, i.e. the level to which to look into or\n"
"Some options can be specified in addition, i.e. the level to which to look into or\n"
"shape classes and shape properties. The shapes are retrieved by using the \\shape method,\n"
"\\next moves to the next shape and \\at_end tells, if the iterator has move shapes to deliver.\n"
"\n"
@ -475,7 +491,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n"
"@code\n"
"# print the polygon-like objects as seen from the initial cell \"cell\"\n"
"iter = layout.begin_shapes(cell_index, layer)\n"
"iter = cell.begin_shapes_rec(layer)\n"
"while !iter.at_end?\n"
" if iter.shape.renders_polygon?\n"
" polygon = iter.shape.polygon.transformed(iter.itrans)\n"
@ -485,10 +501,10 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"end\n"
"@/code\n"
"\n"
"\\Layout offers three methods to get these iterators: begin_shapes, begin_shapes_touching and begin_shapes_overlapping.\n"
"\\Layout#begin_shapes will deliver a standard recursive shape iterator which starts from the given cell and iterates "
"over all child cells. \\Layout#begin_shapes_touching delivers a RecursiveShapeIterator which delivers the shapes "
"whose bounding boxed touch the given search box. \\Layout#begin_shapes_overlapping delivers all shapes whose bounding box "
"\\Cell offers three methods to get these iterators: begin_shapes_rec, begin_shapes_rec_touching and begin_shapes_rec_overlapping.\n"
"\\Cell#begin_shapes_rec will deliver a standard recursive shape iterator which starts from the given cell and iterates "
"over all child cells. \\Cell#begin_shapes_rec_touching delivers a RecursiveShapeIterator which delivers the shapes "
"whose bounding boxed touch the given search box. \\Cell#begin_shapes_rec_overlapping delivers all shapes whose bounding box "
"overlaps the search box.\n"
"\n"
"A RecursiveShapeIterator object can also be created explicitly. This allows some more options, i.e. using "
@ -510,7 +526,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"sets the \"start delivery\" flag while \\unselect_cells sets the \"stop delivery\" flag. In effect, using "
"\\unselect_cells will exclude that cell plus the subtree from delivery. Parts of that subtree can be "
"turned on again using \\select_cells. For the cells selected that way, the shapes of these cells and their "
"child cells are delivered, even if their parents was unselected.\n"
"child cells are delivered, even if their parent was unselected.\n"
"\n"
"To get shapes from a specific cell, i.e. \"MACRO\" plus its child cells, unselect the top cell first "
"and the select the desired cell again:\n"

View File

@ -308,6 +308,18 @@ static db::Region with_area2 (const db::Region *r, const tl::Variant &min, const
return r->filtered (f);
}
static db::Region with_holes1 (const db::Region *r, size_t n, bool inverse)
{
db::HoleCountFilter f (n, n + 1, inverse);
return r->filtered (f);
}
static db::Region with_holes2 (const db::Region *r, const tl::Variant &min, const tl::Variant &max, bool inverse)
{
db::HoleCountFilter f (min.is_nil () ? size_t (0) : min.to<size_t> (), max.is_nil () ? std::numeric_limits <size_t>::max () : max.to<size_t> (), inverse);
return r->filtered (f);
}
static db::Region with_bbox_width1 (const db::Region *r, db::Region::distance_type bbox_width, bool inverse)
{
db::RegionBBoxFilter f (bbox_width, bbox_width + 1, inverse, db::RegionBBoxFilter::BoxWidth);
@ -925,6 +937,30 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method_ext ("with_holes", with_holes1, gsi::arg ("nholes"), gsi::arg ("inverse"),
"@brief Filters the polygons by their number of holes\n"
"Filters the polygons of the region by number of holes. If \"inverse\" is false, only "
"polygons which have the given number of holes are returned. If \"inverse\" is true, "
"polygons not having the given of holes are returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("with_holes", with_holes2, gsi::arg ("min_bholes"), gsi::arg ("max_nholes"), gsi::arg ("inverse"),
"@brief Filter the polygons by their number of holes\n"
"Filters the polygons of the region by number of holes. If \"inverse\" is false, only "
"polygons which have a hole count larger or equal to \"min_nholes\" and less than \"max_nholes\" are "
"returned. If \"inverse\" is true, "
"polygons having a hole count less than \"min_nholes\" or larger or equal than \"max_nholes\" are "
"returned.\n"
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("with_bbox_width", with_bbox_width1, gsi::arg ("width"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width\n"
"Filters the polygons of the region by the width of their bounding box. If \"inverse\" is false, only "
@ -1376,9 +1412,10 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"See \\round_corners for a description of this method. This version returns a new region instead of "
"modifying self (out-of-place)."
) +
method ("smooth", &db::Region::smooth, gsi::arg ("d"),
method ("smooth", &db::Region::smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Smoothing\n"
"@param d The smoothing tolerance (in database units)\n"
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
"\n"
"This method will simplify the merged polygons of the region by removing vertexes if the "
"resulting polygon stays equivalent with the original polygon. Equivalence is measured "
@ -1387,9 +1424,10 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method modifies the region. \\smoothed is a method that does the same but returns a new "
"region without modifying self. Merged semantics applies for this method.\n"
) +
method ("smoothed", &db::Region::smoothed, gsi::arg ("d"),
method ("smoothed", &db::Region::smoothed, gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Smoothing\n"
"@param d The smoothing tolerance (in database units)\n"
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
"\n"
"See \\smooth for a description of this method. This version returns a new region instead of "
"modifying self (out-of-place). It has been introduced in version 0.25."

View File

@ -733,7 +733,8 @@ TEST(11_RoundAndSmoothed)
r1_sized -= r1;
db::Region rounded = r1_sized.rounded_corners (3000, 5000, 100);
db::Region smoothed = rounded.smoothed (100);
db::Region smoothed = rounded.smoothed (100, false);
db::Region smoothed_keep_hv = rounded.smoothed (100, true);
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@ -741,6 +742,7 @@ TEST(11_RoundAndSmoothed)
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1_sized);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), rounded);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), smoothed);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), smoothed_keep_hv);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au11.gds");

View File

@ -1188,8 +1188,8 @@ TEST(100)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 5).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)");
EXPECT_EQ (smooth (p, 20).to_string (), "(0,-100;0,0;150,0;150,-100)");
EXPECT_EQ (smooth (p, 5, true).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)");
EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,-100;0,0;150,0;150,-100)");
}
// smoothing
@ -1207,8 +1207,8 @@ TEST(101)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)");
EXPECT_EQ (smooth (p, 20).to_string (), "(0,0;0,100;150,100;150,0)");
EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)");
EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,0;0,100;150,100;150,0)");
}
// smoothing
@ -1224,8 +1224,8 @@ TEST(102)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 20).to_string (), "()");
EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;150,0;0,0;50,10)");
EXPECT_EQ (smooth (p, 20, true).to_string (), "()");
EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;150,0;0,0;50,10)");
}
// smoothing
@ -1251,9 +1251,9 @@ TEST(103)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 0).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)");
EXPECT_EQ (smooth (p, 50).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)");
EXPECT_EQ (smooth (p, 5000).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)");
EXPECT_EQ (smooth (p, 0, true).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)");
EXPECT_EQ (smooth (p, 50, true).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)");
EXPECT_EQ (smooth (p, 5000, true).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)");
}
// smoothing
@ -1272,7 +1272,8 @@ TEST(104)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 12).to_string (), "(-244,-942;-942,-246;248,943;943,246)");
EXPECT_EQ (smooth (p, 12, false).to_string (), "(-244,-942;-942,-246;248,943;943,246)");
EXPECT_EQ (smooth (p, 12, true).to_string (), "(-245,-942;-942,-247;-942,-246;247,943;248,943;943,246;-244,-942)");
}
// smoothing
@ -1292,11 +1293,46 @@ TEST(105)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 0).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 50).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 80).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 90).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 100).to_string (), "(0,0;0,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 50, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 80, false).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 90, false).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;0,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
}
// smoothing
TEST(106)
{
db::Point pattern [] = {
db::Point (0, 0),
db::Point (0, 73235),
db::Point (100, 74568),
db::Point (700, 82468),
db::Point (1200, 90468),
db::Point (2000, 106468),
db::Point (2300, 114468),
db::Point (2700, 130468),
db::Point (2800, 138468),
db::Point (2800, 154468),
db::Point (2700, 162468),
db::Point (2300, 178468),
db::Point (2000, 186468),
db::Point (1200, 202468),
db::Point (700, 210468),
db::Point (100, 218368),
db::Point (0, 219701),
db::Point (0, 272971),
db::Point (126450, 272971),
db::Point (126450, 0),
};
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,73235;100,74568;700,82468;1200,90468;2000,106468;2300,114468;2700,130468;2800,138468;2800,154468;2700,162468;2300,178468;2000,186468;1200,202468;700,210468;100,218368;0,219701;0,272971;126450,272971;126450,0)");
EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;100,74568;1200,90468;2300,114468;2800,138468;2700,162468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)");
EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,73235;1200,90468;2300,114468;2800,138468;2800,154468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)");
}
// rounding
@ -1501,7 +1537,7 @@ TEST(203)
in.push_back (pp);
ep.simple_merge (in, out, false /*no cut line*/);
pp = out.front ();
pp = smooth (pp, 1);
pp = smooth (pp, 1, true);
EXPECT_EQ (pp.hull ().size (), size_t (300));
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);
@ -1547,7 +1583,7 @@ TEST(204)
in.push_back (pp);
ep.simple_merge (in, out, false /*no cut line*/);
pp = out.front ();
pp = smooth (pp, 1);
pp = smooth (pp, 1, true);
EXPECT_EQ (pp.hull ().size (), size_t (200));
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);

View File

@ -0,0 +1,621 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbRecursiveInstanceIterator.h"
#include "dbRegion.h"
#include "dbLayoutDiff.h"
#include "tlString.h"
#include "tlUnitTest.h"
#include <vector>
std::string collect(db::RecursiveInstanceIterator &s, const db::Layout &layout)
{
std::string res;
while (! s.at_end ()) {
if (! res.empty ()) {
res += "/";
}
if (s.cell ()) {
res += std::string ("[") + layout.cell_name (s.cell ()->cell_index ()) + "]";
} else {
res += "[]";
}
res += s->inst_ptr.to_string (true);
++s;
}
return res;
}
std::string collect_with_copy(db::RecursiveInstanceIterator s, const db::Layout &layout)
{
s.reset ();
return collect (s, layout);
}
TEST(1)
{
db::Manager m (true);
db::Layout g (&m);
g.insert_layer (0);
g.insert_layer (1);
g.insert_layer (2);
db::Cell &c0 (g.cell (g.add_cell ()));
db::RecursiveInstanceIterator idef;
EXPECT_EQ (idef.at_end (), true);
EXPECT_EQ (collect (idef, g), "");
EXPECT_EQ (collect_with_copy (idef, g), "");
db::RecursiveInstanceIterator i00 (g, c0, db::Box (0, 0, 100, 100));
EXPECT_EQ (collect (i00, g), "");
EXPECT_EQ (collect_with_copy (i00, g), "");
db::Cell &c1 (g.cell (g.add_cell ()));
db::Cell &c2 (g.cell (g.add_cell ()));
db::Cell &c3 (g.cell (g.add_cell ()));
db::RecursiveInstanceIterator i0 (g, c0, db::Box (0, 0, 100, 100));
EXPECT_EQ (collect (i0, g), "");
EXPECT_EQ (collect_with_copy (i0, g), "");
db::Box b (0, 100, 1000, 1200);
c0.shapes (0).insert (b);
c1.shapes (0).insert (b);
c2.shapes (0).insert (b);
c3.shapes (0).insert (b);
c0.shapes (2).insert (b);
c0.shapes (2).insert (b.moved (db::Vector (50, 50)));
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100))));
c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1)));
c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0))));
std::string x;
db::RecursiveInstanceIterator i1 (g, c0, db::Box (0, 0, 100, 100));
x = collect(i1, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
db::RecursiveInstanceIterator i1_1inf (g, c0, db::Box (0, 0, 100, 100));
i1_1inf.min_depth(0);
x = collect(i1_1inf, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
x = collect_with_copy(i1_1inf, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
db::RecursiveInstanceIterator i1_11 (g, c0, db::Box (0, 0, 2000, 100));
i1_11.min_depth(0);
i1_11.max_depth(0);
x = collect(i1_11, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
x = collect_with_copy(i1_11, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
db::RecursiveInstanceIterator i1_12 (g, c0, db::Box (0, 0, 2000, 100));
i1_12.min_depth(0);
i1_12.max_depth(1);
x = collect(i1_12, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100");
x = collect_with_copy(i1_12, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100");
db::RecursiveInstanceIterator i1_22 (g, c0, db::Box (0, 0, 2000, 100));
i1_22.min_depth(1);
i1_22.max_depth(1);
x = collect(i1_22, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
x = collect_with_copy(i1_22, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
db::RecursiveInstanceIterator i1o (g, c0, db::Box (0, 0, 100, 100), true);
x = collect(i1o, g);
EXPECT_EQ (x, "");
x = collect_with_copy(i1o, g);
EXPECT_EQ (x, "");
i1o = db::RecursiveInstanceIterator (g, c0, db::Box (0, 0, 100, 101), true);
x = collect(i1o, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0");
x = collect_with_copy(i1o, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0");
i1o = db::RecursiveInstanceIterator (g, c0, db::Box (0, 0, 101, 101), true);
x = collect(i1o, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
x = collect_with_copy(i1o, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
db::RecursiveInstanceIterator i2 (g, c0, db::Box (-100, 0, 100, 100));
db::RecursiveInstanceIterator i2c = i2;
x = collect(i2, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i2, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect(i2c, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i2c, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
db::RecursiveInstanceIterator i2o (g, c0, db::Box (-100, 0, 100, 100), true);
x = collect(i2o, g);
EXPECT_EQ (x, "");
x = collect_with_copy(i2o, g);
EXPECT_EQ (x, "");
i2o = db::RecursiveInstanceIterator (g, c0, db::Box (-101, 0, 101, 101), true);
x = collect(i2o, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i2o, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
db::Region r;
r.insert (db::Box (-600, -100, -500, 0));
r.insert (db::Box (1600, 0, 1700, 100));
db::RecursiveInstanceIterator i2r (g, c0, r);
db::RecursiveInstanceIterator i2rc = i2r;
x = collect(i2r, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i2r, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect(i2rc, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i2rc, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
db::RecursiveInstanceIterator i2ro (g, c0, r, true);
x = collect(i2ro, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100");
x = collect_with_copy(i2ro, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$3 r0 100,-100");
db::RecursiveInstanceIterator i4 (g, c0, db::Box (-100, 0, 2000, 100));
db::RecursiveInstanceIterator i4_copy (g, c0, db::Box (-100, 0, 2000, 100));
i4.max_depth (0);
x = collect(i4, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i4, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
EXPECT_EQ (i4 == i4, true);
EXPECT_EQ (i4 != i4, false);
EXPECT_EQ (i4 == i4_copy, false);
EXPECT_EQ (i4 != i4_copy, true);
i4 = i4_copy;
EXPECT_EQ (i4 == i4_copy, true);
EXPECT_EQ (i4 != i4_copy, false);
i4.max_depth (1);
x = collect(i4, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i4, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
i4 = i4_copy;
x = collect(i4, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i4, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
db::RecursiveInstanceIterator i5 (g, c0, db::Box::world ());
x = collect(i5, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(i5, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
std::set<db::cell_index_type> cc;
db::RecursiveInstanceIterator ii;
ii = db::RecursiveInstanceIterator (g, c0, db::Box::world ());
cc.clear ();
cc.insert (c2.cell_index ());
ii.unselect_all_cells ();
ii.select_cells (cc);
x = collect(ii, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
x = collect_with_copy(ii, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
ii.reset ();
x = collect(ii, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
x = collect_with_copy(ii, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
ii.reset_selection ();
x = collect(ii, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(ii, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$3]$4 r0 1100,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
ii.reset_selection ();
cc.clear ();
cc.insert (c0.cell_index ());
cc.insert (c2.cell_index ());
ii.unselect_cells (cc);
cc.clear ();
cc.insert (c2.cell_index ());
ii.select_cells (cc);
x = collect(ii, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
x = collect_with_copy(ii, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0");
ii = db::RecursiveInstanceIterator (g, c0, db::Box::world ());
ii.unselect_all_cells ();
cc.clear ();
cc.insert (c0.cell_index ());
ii.select_cells (cc);
x = collect(ii, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
x = collect_with_copy(ii, g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100/[$1]$4 r90 0,0");
db::RecursiveInstanceIterator i1z (g, c0);
EXPECT_EQ (i1z.all_targets_enabled (), true);
std::set<db::cell_index_type> ct;
ct.insert (c3.cell_index ());
i1z.set_targets (ct);
EXPECT_EQ (i1z.all_targets_enabled (), false);
EXPECT_EQ (i1z.targets () == ct, true);
i1z.enable_all_targets ();
EXPECT_EQ (i1z.all_targets_enabled (), true);
i1z.set_targets (ct);
EXPECT_EQ (i1z.all_targets_enabled (), false);
x = collect(i1z, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$4 r90 0,0");
x = collect_with_copy(i1z, g);
EXPECT_EQ (x, "[$3]$4 r0 1100,0/[$1]$4 r90 0,0");
}
static db::Layout boxes2layout (const std::set<db::Box> &boxes)
{
db::Layout l;
l.insert_layer(0, db::LayerProperties (1, 0));
db::Cell &top (l.cell (l.add_cell ()));
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
top.shapes (0).insert (*b);
}
return l;
}
namespace {
class FlatPusher
: public db::RecursiveInstanceReceiver
{
public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
void enter_cell (const db::RecursiveInstanceIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
mp_boxes->insert (iter->trans () * cell->bbox ());
}
private:
std::set<db::Box> *mp_boxes;
};
}
TEST(2)
{
// Big fun with cells
db::Manager m (true);
db::Layout g (&m);
g.insert_layer(0);
db::Cell &c0 (g.cell (g.add_cell ()));
db::Cell &c1 (g.cell (g.add_cell ()));
db::Box basic_box (0, 0, 10, 10);
c1.shapes (0).insert (basic_box);
std::set<db::Box> boxes;
for (int i = 0; i < 100000; ++i) {
int x = rand () % 10000;
int y = rand () % 10000;
boxes.insert (basic_box.moved (db::Vector (x, y)));
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (x, y))));
}
db::Box search_box (2500, 2500, 7500, 7500);
std::set<db::Box> selected_boxes;
std::set<db::Box> selected_boxes2;
for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, search_box, true); !iter.at_end (); ++iter) {
selected_boxes.insert (iter.trans () * iter->inst_ptr.bbox ());
}
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (*b)) {
selected_boxes2.insert (*b);
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveInstanceIterator (g, c0, search_box, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
selected_boxes2.clear ();
db::Region reg;
reg.insert (search_box);
reg.insert (search_box2);
for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg, true); !iter.at_end (); ++iter) {
selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert<db::CellInst> (g)));
}
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (*b) || search_box2.overlaps (*b)) {
selected_boxes2.insert (*b);
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveInstanceIterator (g, c0, reg, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
}
TEST(3)
{
// Big fun with cells - 2 hierarchy levels
db::Manager m (true);
db::Layout g (&m);
g.insert_layer(0);
db::Cell &c0 (g.cell (g.add_cell ()));
db::Cell &c1 (g.cell (g.add_cell ()));
db::Cell &c2 (g.cell (g.add_cell ()));
db::Box basic_box (0, 0, 10, 10);
c2.shapes (0).insert (basic_box);
c1.insert (db::CellInstArray (c2.cell_index (), db::Trans (db::Vector (1, -1))));
std::set<db::Box> boxes;
int nboxes = 100000;
for (int i = 0; i < nboxes; ++i) {
int x, y;
do {
x = rand () % 10000;
y = rand () % 10000;
} while (boxes.find (basic_box.moved (db::Vector (x + 1, y - 1))) != boxes.end ());
boxes.insert (basic_box.moved (db::Vector (x + 1, y - 1)));
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (x, y))));
}
db::Box search_box (2500, 2500, 7500, 7500);
std::set<db::Box> selected_boxes;
std::set<db::Box> selected_boxes2;
db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, search_box, true);
std::set<db::cell_index_type> tc;
tc.insert (c2.cell_index ());
iter.set_targets (tc);
int n = 0;
for ( ; !iter.at_end (); ++iter) {
++n;
selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert<db::CellInst> (g)));
}
int nn = 0;
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (*b)) {
++nn;
selected_boxes2.insert (*b);
}
}
EXPECT_EQ (n, nn);
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveInstanceIterator (g, c0, search_box, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
selected_boxes2.clear ();
db::Region reg;
reg.insert (search_box);
reg.insert (search_box2);
for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg, true); !iter.at_end (); ++iter) {
selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert<db::CellInst> (g)));
}
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (*b) || search_box2.overlaps (*b)) {
selected_boxes2.insert (*b);
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveInstanceIterator (g, c0, reg, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
}
TEST(4)
{
// Big fun with cells - 2 hierarchy levels + touching mode
db::Manager m (true);
db::Layout g (&m);
g.insert_layer(0);
db::Cell &c0 (g.cell (g.add_cell ()));
db::Cell &c1 (g.cell (g.add_cell ()));
db::Cell &c2 (g.cell (g.add_cell ()));
db::Box basic_box (0, 0, 10, 10);
c2.shapes (0).insert (basic_box);
c1.insert (db::CellInstArray (c2.cell_index (), db::Trans (db::Vector (1, -1))));
std::set<db::Box> boxes;
int nboxes = 100000;
for (int i = 0; i < nboxes; ++i) {
int x, y;
do {
x = rand () % 10000;
y = rand () % 10000;
} while (boxes.find (basic_box.moved (db::Vector (x + 1, y - 1))) != boxes.end ());
boxes.insert (basic_box.moved (db::Vector (x + 1, y - 1)));
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (x, y))));
}
db::Box search_box (2500, 2500, 7500, 7500);
std::set<db::Box> selected_boxes;
std::set<db::Box> selected_boxes2;
db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, search_box);
std::set<db::cell_index_type> tc;
tc.insert (c2.cell_index ());
iter.set_targets (tc);
int n = 0;
for ( ; !iter.at_end (); ++iter) {
++n;
selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert<db::CellInst> (g)));
}
int nn = 0;
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.touches (*b)) {
++nn;
selected_boxes2.insert (*b);
}
}
EXPECT_EQ (n, nn);
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveInstanceIterator (g, c0, search_box).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
selected_boxes2.clear ();
db::Region reg;
reg.insert (search_box);
reg.insert (search_box2);
for (db::RecursiveInstanceIterator iter = db::RecursiveInstanceIterator (g, c0, reg); !iter.at_end (); ++iter) {
selected_boxes.insert (iter.trans () * iter->bbox (db::box_convert<db::CellInst> (g)));
}
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.touches (*b) || search_box2.touches (*b)) {
selected_boxes2.insert (*b);
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveInstanceIterator (g, c0, reg).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
}

View File

@ -723,20 +723,24 @@ static db::Layout boxes2layout (const std::set<db::Box> &boxes)
return l;
}
class FlatPusher
: public db::RecursiveShapeReceiver
{
public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
namespace {
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
class FlatPusher
: public db::RecursiveShapeReceiver
{
mp_boxes->insert (trans * shape.bbox ());
}
public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
private:
std::set<db::Box> *mp_boxes;
};
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
mp_boxes->insert (trans * shape.bbox ());
}
private:
std::set<db::Box> *mp_boxes;
};
}
TEST(4)
{
@ -1023,6 +1027,8 @@ TEST(10)
db::Box b (1000, -500, 2000, 500);
c2.shapes (0).insert (b);
c0.shapes (0).insert (b.moved (db::Vector (-1000, 500)));
c0.shapes (0).insert (b.moved (db::Vector (-2000, 500)));
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2));
@ -1036,6 +1042,9 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
// It's a bit weird to have shape events after new_inst_member, but remember, new_inst_member is a query callback, not an event.
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
@ -1126,6 +1135,8 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"leave_cell($2)\n"
@ -1152,6 +1163,8 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
@ -1194,6 +1207,8 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n" // -> skipped
@ -1271,6 +1286,8 @@ TEST(10)
EXPECT_EQ (rr2.text (),
"begin\n"
"new_inst($2,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"end\n"
);
@ -1282,6 +1299,8 @@ TEST(10)
"begin\n"
"new_inst($2)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3)\n"
"new_inst_member($3,r0 *1 0,0)\n"

View File

@ -1973,6 +1973,27 @@ TEST(35c_interact_with_count_text)
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
TEST(40_with_holes)
{
db::Region r;
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
db::Region rr;
rr.insert (db::Box (db::Point (10, 10), db::Point (20, 20)));
rr.insert (db::Box (db::Point (30, 30), db::Point (40, 40)));
r.set_merged_semantics (true);
r.set_min_coherence (false);
r -= rr;
EXPECT_EQ (rr.filtered (db::HoleCountFilter (0, 1, false)).to_string (), "(10,10;10,20;20,20;20,10);(30,30;30,40;40,40;40,30)");
EXPECT_EQ (r.filtered (db::HoleCountFilter (2, 3, false)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)");
EXPECT_EQ (r.filtered (db::HoleCountFilter (1, 2, false)).to_string (), "");
EXPECT_EQ (r.filtered (db::HoleCountFilter (1, 3, false)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)");
EXPECT_EQ (r.filtered (db::HoleCountFilter (0, 2, false)).to_string (), "");
EXPECT_EQ (r.filtered (db::HoleCountFilter (2, 5, false)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)");
EXPECT_EQ (r.filtered (db::HoleCountFilter (3, 5, true)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)");
}
TEST(100_Processors)
{
db::Region r;

View File

@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
dbCompoundOperationTests.cc \
dbRecursiveInstanceIteratorTests.cc \
dbRegionUtilsTests.cc \
dbUtilsTests.cc \
dbWriterTools.cc \

View File

@ -71,6 +71,7 @@ module DRC
# @li \global#space @/li
# @li \global#squares @/li
# @li \global#width @/li
# @li \global#with_holes @/li
# @/ul
#
# The following documentation will list the methods available for DRC expression objects.
@ -434,7 +435,7 @@ CODE
# result. Without "if_any" three corners are returned for each triangle.
def count
DRCOpNodeCountFilter::new(@engine, self)
DRCOpNodeCountFilter::new(@engine, self, :new_count_filter, "count")
end
# %DRC%
@ -738,16 +739,18 @@ CODE
# %DRC%
# @name smoothed
# @brief Applies smoothing
# @synopsis expression.smoothed(d)
# @synopsis expression.smoothed(d [, keep_hv ])
#
# This operation acts on polygons and applies polygon smoothing with the tolerance d. See \Layer#smoothed for more details.
# This operation acts on polygons and applies polygon smoothing with the tolerance d. 'keep_hv' indicates
# whether horizontal and vertical edges are maintained. Default is 'no' which means such edges may be distorted.
# See \Layer#smoothed for more details.
#
# The "smoothed" method is available as a plain function or as a method on \DRC# expressions.
# The plain function is equivalent to "primary.smoothed".
def smoothed(d)
def smoothed(d, keep_hv = false)
@engine._context("smoothed") do
DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d))
DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d), keep_hv)
end
end
@ -1003,6 +1006,24 @@ CODE
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges")
end
# %DRC%
# @name with_holes
# @brief Selects all input polygons with the specified number of holes
# @synopsis expression.with_holes (in condition)
#
# This operation can be used as a plain function in which case it acts on primary
# shapes or can be used as method on another DRC expression.
# The following example selects all polygons with more than 2 holes:
#
# @code
# out = in.drc(with_holes > 2)
# out = in.drc(primary.with_holes > 2) # equivalent
# @/code
def with_holes
return DRCOpNodeCountFilter::new(@engine, self, :new_hole_count_filter, "with_holes")
end
# %DRC%
# @name merged
# @brief Returns the merged input polygons, optionally selecting multi-overlap
@ -1552,16 +1573,19 @@ class DRCOpNodeCountFilter < DRCOpNodeWithCompare
attr_accessor :input
attr_accessor :inverse
attr_accessor :method
attr_accessor :name
def initialize(engine, input)
def initialize(engine, input, method, name)
super(engine)
self.input = input
self.inverse = false
self.description = "count"
self.description = name
self.method = method
end
def _description_for_dump
self.inverse ? "count" : "not_count"
self.inverse ? name : "not_" + name
end
def do_create_node(cache)
@ -1570,7 +1594,7 @@ class DRCOpNodeCountFilter < DRCOpNodeWithCompare
if self.lt || self.le
args << (self.lt ? @engine._make_numeric_value(self.lt) : @engine._make_numeric_value(self.le) + 1)
end
RBA::CompoundRegionOperationNode::new_count_filter(*args)
RBA::CompoundRegionOperationNode::send(self.method, *args)
end
def inverted

View File

@ -953,6 +953,19 @@ CODE
CODE
end
# %DRC%
# @name with_holes
# @brief Selects all input polygons according to their number of holes in DRC expressions
# @synopsis with_holes (in condition)
#
# "with_holes" represents a polygon selector for
# \DRC# expressions selecting polygons of the primary by their number of holes
# (see \Layer#drc and \DRC#with_holes for more details).
def with_holes
primary.with_holes
end
# %DRC%
# @name enclosing
# @brief Performs an enclosing check

View File

@ -498,6 +498,20 @@ module DRC
end
end
# %DRC%
# @name warn
# @brief Prints a warning
# @synopsis warn(message)
# Similar to \log, but the message is printed formatted as a warning
def warn(arg)
if @log_file
@log_file.puts("WARNING: " + arg)
else
RBA::Logger::warn(arg)
end
end
# %DRC%
# @name log_file
# @brief Specify the log file where to send to log to
@ -1840,7 +1854,7 @@ CODE
def run_timed(desc, obj)
info(desc)
log(desc)
# enable progress
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)

View File

@ -488,7 +488,7 @@ CODE
#
# This method is available for polygon layers only.
%w(bbox_height bbox_max bbox_min bbox_width perimeter).each do |f|
%w(bbox_height bbox_max bbox_min bbox_width perimeter holes).each do |f|
[true, false].each do |inv|
mn = (inv ? "without" : "with") + "_" + f
eval <<"CODE"
@ -517,6 +517,61 @@ CODE
end
end
# %DRC%
# @name with_holes
# @brief Selects all polygons with the specified number of holes
# @synopsis layer.with_holes(count)
# @synopsis layer.with_holes(min_count, max_count)
# @synopsis layer.with_holes(min_count .. max_count)
#
# This method is available for polygon layers. It will select all polygons from the input layer
# which have the specified number of holes.
# %DRC%
# @name without_holes
# @brief Selects all polygons with the specified number of holes
# @synopsis layer.without_holes(count)
# @synopsis layer.without_holes(min_count, max_count)
# @synopsis layer.without_holes(min_count .. max_count)
#
# This method is available for polygon layers. It will select all polygons from the input layer
# which do not have the specified number of holes.
%w(holes).each do |f|
[true, false].each do |inv|
mn = (inv ? "without" : "with") + "_" + f
eval <<"CODE"
def #{mn}(*args)
@engine._context("#{mn}") do
requires_region
if args.size == 1
a = args[0]
if a.is_a?(Range)
min = @engine._make_numeric_value_with_nil(a.begin)
max = @engine._make_numeric_value_with_nil(a.end)
max && (max += 1)
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, min, max, #{inv.inspect}))
else
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, @engine._make_value(a), #{inv.inspect}))
end
elsif args.size == 2
min = @engine._make_numeric_value_with_nil(args[0])
max = @engine._make_numeric_value_with_nil(args[1])
max && (max += 1)
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, min, max, #{inv.inspect}))
else
raise("Invalid number of arguments (1 or 2 expected)")
end
end
end
CODE
end
end
# %DRC%
# @name with_bbox_aspect_ratio
# @brief Selects polygons by the aspect ratio of their bounding box

View File

@ -25,6 +25,8 @@ module DRC
drc._rdb_index = rdb_index
drc._generator = generator
drc_progress = RBA::AbstractProgress::new("DRC: " + macro.path)
begin
# Set a debugger scope so that our errors end up with the debugger set to the DRC's line
@ -46,6 +48,9 @@ module DRC
# cleans up and creates layout and report views
drc._finish
# unlocks the UI
drc_progress._destroy
end
timer.stop

View File

@ -238,3 +238,13 @@ TEST(17d)
{
run_test (_this, "17", true);
}
TEST(18)
{
run_test (_this, "18", false);
}
TEST(18d)
{
run_test (_this, "18", true);
}

View File

@ -1152,3 +1152,14 @@ TEST(28_inputFragmentation)
{
run_test (_this, "28", true);
}
TEST(29_holes)
{
run_test (_this, "29", false);
}
TEST(29d_holes)
{
run_test (_this, "29", true);
}

View File

@ -60,7 +60,7 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
Value value = Value (0);
tl::from_string (tl::to_string (le->text ()), value);
dispatcher->config_set (cfg_name, tl::to_string (value));
lay::indicate_error (le, 0);
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
}
@ -114,7 +114,7 @@ EditorOptionsGeneric::apply (lay::Dispatcher *root)
try {
db::DVector eg;
egc.from_string_picky (tl::to_string (mp_ui->edit_grid_le->text ()), eg);
lay::indicate_error (mp_ui->edit_grid_le, 0);
lay::indicate_error (mp_ui->edit_grid_le, (tl::Exception *) 0);
root->config_set (cfg_edit_grid, egc.to_string (eg));
} catch (tl::Exception &ex) {
lay::indicate_error (mp_ui->edit_grid_le, &ex);
@ -166,7 +166,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
mp_ui->edit_grid_le->setText (tl::to_qstring (egc.to_string (eg)));
}
grid_changed (mp_ui->grid_cb->currentIndex ());
lay::indicate_error (mp_ui->edit_grid_le, 0);
lay::indicate_error (mp_ui->edit_grid_le, (tl::Exception *) 0);
// edit & move angle
@ -196,7 +196,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
unsigned int max_shapes = 1000;
root->config_get (cfg_edit_max_shapes_of_instances, max_shapes);
mp_ui->max_shapes_le->setText (tl::to_qstring (tl::to_string (max_shapes)));
lay::indicate_error (mp_ui->max_shapes_le, 0);
lay::indicate_error (mp_ui->max_shapes_le, (tl::Exception *) 0);
bool show_shapes = true;
root->config_get (cfg_edit_show_shapes_of_instances, show_shapes);
@ -356,7 +356,7 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
double w = 0.0;
root->config_get (cfg_edit_path_width, w);
mp_ui->width_le->setText (tl::to_qstring (tl::to_string (w)));
lay::indicate_error (mp_ui->width_le, 0);
lay::indicate_error (mp_ui->width_le, (tl::Exception *) 0);
// path type and extensions
@ -377,9 +377,9 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
root->config_get (cfg_edit_path_ext_var_begin, bgnext);
root->config_get (cfg_edit_path_ext_var_end, endext);
mp_ui->start_ext_le->setText (tl::to_qstring (tl::to_string (bgnext)));
lay::indicate_error (mp_ui->start_ext_le, 0);
lay::indicate_error (mp_ui->start_ext_le, (tl::Exception *) 0);
mp_ui->end_ext_le->setText (tl::to_qstring (tl::to_string (endext)));
lay::indicate_error (mp_ui->end_ext_le, 0);
lay::indicate_error (mp_ui->end_ext_le, (tl::Exception *) 0);
}
// ------------------------------------------------------------------
@ -631,7 +631,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
double angle = 0.0;
root->config_get (cfg_edit_inst_angle, angle);
mp_ui->angle_le->setText (tl::to_qstring (tl::to_string (angle)));
lay::indicate_error (mp_ui->angle_le, 0);
lay::indicate_error (mp_ui->angle_le, (tl::Exception *) 0);
bool mirror = false;
root->config_get (cfg_edit_inst_mirror, mirror);
@ -640,7 +640,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
double scale = 1.0;
root->config_get (cfg_edit_inst_scale, scale);
mp_ui->scale_le->setText (tl::to_qstring (tl::to_string (scale)));
lay::indicate_error (mp_ui->scale_le, 0);
lay::indicate_error (mp_ui->scale_le, (tl::Exception *) 0);
// array
bool array = false;
@ -657,17 +657,17 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
root->config_get (cfg_edit_inst_column_y, column_y);
mp_ui->rows_le->setText (tl::to_qstring (tl::to_string (rows)));
lay::indicate_error (mp_ui->rows_le, 0);
lay::indicate_error (mp_ui->rows_le, (tl::Exception *) 0);
mp_ui->row_x_le->setText (tl::to_qstring (tl::to_string (row_x)));
lay::indicate_error (mp_ui->row_x_le, 0);
lay::indicate_error (mp_ui->row_x_le, (tl::Exception *) 0);
mp_ui->row_y_le->setText (tl::to_qstring (tl::to_string (row_y)));
lay::indicate_error (mp_ui->row_y_le, 0);
lay::indicate_error (mp_ui->row_y_le, (tl::Exception *) 0);
mp_ui->columns_le->setText (tl::to_qstring (tl::to_string (columns)));
lay::indicate_error (mp_ui->columns_le, 0);
lay::indicate_error (mp_ui->columns_le, (tl::Exception *) 0);
mp_ui->column_x_le->setText (tl::to_qstring (tl::to_string (column_x)));
lay::indicate_error (mp_ui->column_x_le, 0);
lay::indicate_error (mp_ui->column_x_le, (tl::Exception *) 0);
mp_ui->column_y_le->setText (tl::to_qstring (tl::to_string (column_y)));
lay::indicate_error (mp_ui->column_y_le, 0);
lay::indicate_error (mp_ui->column_y_le, (tl::Exception *) 0);
// place origin of cell flag
bool place_origin = false;

View File

@ -405,7 +405,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
}
lay::indicate_error (cell_name_le, 0);
lay::indicate_error (cell_name_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cell_name_le, &ex);
@ -447,7 +447,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (pos_x_le->text ()), x);
lay::indicate_error (pos_x_le, 0);
lay::indicate_error (pos_x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pos_x_le, &ex);
has_error = true;
@ -455,7 +455,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (pos_y_le->text ()), y);
lay::indicate_error (pos_y_le, 0);
lay::indicate_error (pos_y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pos_y_le, &ex);
has_error = true;
@ -472,7 +472,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
double angle = 0.0;
try {
tl::from_string (tl::to_string (angle_le->text ()), angle);
lay::indicate_error (angle_le, 0);
lay::indicate_error (angle_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (angle_le, &ex);
has_error = true;
@ -481,7 +481,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
double mag = 0.0;
try {
tl::from_string (tl::to_string (mag_le->text ()), mag);
lay::indicate_error (mag_le, 0);
lay::indicate_error (mag_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (mag_le, &ex);
has_error = true;
@ -510,7 +510,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (column_x_le->text ()), cx);
lay::indicate_error (column_x_le, 0);
lay::indicate_error (column_x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (column_x_le, &ex);
has_error = true;
@ -518,7 +518,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (column_y_le->text ()), cy);
lay::indicate_error (column_y_le, 0);
lay::indicate_error (column_y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (column_y_le, &ex);
has_error = true;
@ -526,7 +526,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (row_x_le->text ()), rx);
lay::indicate_error (row_x_le, 0);
lay::indicate_error (row_x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (row_x_le, &ex);
has_error = true;
@ -534,7 +534,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (row_y_le->text ()), ry);
lay::indicate_error (row_y_le, 0);
lay::indicate_error (row_y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (row_y_le, &ex);
has_error = true;
@ -542,7 +542,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (rows_le->text ()), rows);
lay::indicate_error (rows_le, 0);
lay::indicate_error (rows_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (rows_le, &ex);
has_error = true;
@ -550,7 +550,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (columns_le->text ()), cols);
lay::indicate_error (columns_le, 0);
lay::indicate_error (columns_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (columns_le, &ex);
has_error = true;
@ -766,7 +766,7 @@ InstPropertiesPage::update_pcell_parameters ()
tl::Exception ex (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
lay::indicate_error (cell_name_le, &ex);
} else {
lay::indicate_error (cell_name_le, 0);
lay::indicate_error (cell_name_le, (tl::Exception *) 0);
}
if (pc.first && layout->pcell_declaration (pc.second)) {

View File

@ -1387,7 +1387,7 @@ MainService::cm_round_corners ()
std::vector <db::Polygon> in;
ep.merge (primary, in, 0 /*min_wc*/, false /*resolve holes*/, true /*min coherence*/);
for (std::vector <db::Polygon>::iterator p = in.begin (); p != in.end (); ++p) {
*p = smooth (*p, 1);
*p = smooth (*p, 1, true);
}
std::vector <db::Polygon> out = in;

View File

@ -496,7 +496,7 @@ PCellParametersPage::get_parameters (bool *ok)
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
@ -520,7 +520,7 @@ PCellParametersPage::get_parameters (bool *ok)
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {

View File

@ -509,7 +509,7 @@ PolygonPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Sha
}
lay::indicate_error (pointListEdit, 0);
lay::indicate_error (pointListEdit, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pointListEdit, &ex);
@ -609,7 +609,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (x1_le_1->text ()), x1);
lay::indicate_error (x1_le_1, 0);
lay::indicate_error (x1_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x1_le_1, &ex);
has_error = true;
@ -617,7 +617,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (y1_le_1->text ()), y1);
lay::indicate_error (y1_le_1, 0);
lay::indicate_error (y1_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y1_le_1, &ex);
has_error = true;
@ -625,7 +625,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (x2_le_1->text ()), x2);
lay::indicate_error (x2_le_1, 0);
lay::indicate_error (x2_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x2_le_1, &ex);
has_error = true;
@ -633,7 +633,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (y2_le_1->text ()), y2);
lay::indicate_error (y2_le_1, 0);
lay::indicate_error (y2_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y2_le_1, &ex);
has_error = true;
@ -669,7 +669,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (cx_le_2->text ()), cx);
lay::indicate_error (cx_le_2, 0);
lay::indicate_error (cx_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cx_le_2, &ex);
has_error = true;
@ -677,7 +677,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (cy_le_2->text ()), cy);
lay::indicate_error (cy_le_2, 0);
lay::indicate_error (cy_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cy_le_2, &ex);
has_error = true;
@ -685,7 +685,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (w_le_2->text ()), w);
lay::indicate_error (w_le_2, 0);
lay::indicate_error (w_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (w_le_2, &ex);
has_error = true;
@ -693,7 +693,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (h_le_2->text ()), h);
lay::indicate_error (h_le_2, 0);
lay::indicate_error (h_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (h_le_2, &ex);
has_error = true;
@ -834,7 +834,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
try {
tl::from_string (tl::to_string (x_le->text ()), x);
lay::indicate_error (x_le, 0);
lay::indicate_error (x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x_le, &ex);
has_error = true;
@ -842,7 +842,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
try {
tl::from_string (tl::to_string (y_le->text ()), y);
lay::indicate_error (y_le, 0);
lay::indicate_error (y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y_le, &ex);
has_error = true;
@ -875,7 +875,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
if (! size_le->text ().isEmpty ()) {
try {
size = coord_from_string (tl::to_string (size_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (size_le, 0);
lay::indicate_error (size_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (size_le, &ex);
has_error = true;
@ -1084,7 +1084,7 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
throw tl::Exception (tl::to_string (QObject::tr ("The path must have at least one point")));
}
lay::indicate_error (ptlist_le, 0);
lay::indicate_error (ptlist_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (ptlist_le, &ex);
@ -1094,7 +1094,7 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
db::Coord w = 0;
try {
w = coord_from_string (tl::to_string (width_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (width_le, 0);
lay::indicate_error (width_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (width_le, &ex);
has_error = true;
@ -1111,14 +1111,14 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
case 2: // variable
try {
se = coord_from_string (tl::to_string (start_ext_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (start_ext_le, 0);
lay::indicate_error (start_ext_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (start_ext_le, &ex);
has_error = true;
}
try {
ee = coord_from_string (tl::to_string (end_ext_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (end_ext_le, 0);
lay::indicate_error (end_ext_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (end_ext_le, &ex);
has_error = true;

View File

@ -201,25 +201,6 @@ Class<tl::Timer> decl_Timer ("tl", "Timer",
// ----------------------------------------------------------------
// Progress reporter objects
namespace tl {
template <> struct type_traits<tl::Progress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template <> struct type_traits<tl::RelativeProgress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template <> struct type_traits<tl::AbsoluteProgress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
namespace gsi
{
@ -247,6 +228,27 @@ Class<tl::Progress> decl_Progress ("tl", "Progress",
"This class has been introduced in version 0.23.\n"
);
static tl::AbstractProgress *abstract_progress (const std::string &desc)
{
return new tl::AbstractProgress (desc);
}
Class<tl::AbstractProgress> decl_AbstractProgress (decl_Progress, "tl", "AbstractProgress",
gsi::constructor ("new", &abstract_progress, gsi::arg ("desc"),
"@brief Creates an abstract progress reporter with the given description\n"
),
"@brief The abstract progress reporter\n"
"\n"
"The abstract progress reporter acts as a 'bracket' for a sequence of operations which are connected "
"logically. For example, a DRC script consists of multiple operations. An abstract progress reportert "
"is instantiated during the run time of the DRC script. This way, the application leaves the UI open while "
"the DRC executes and log messages can be collected.\n"
"\n"
"The abstract progress does not have a value.\n"
"\n"
"This class has been introduced in version 0.27.\n"
);
static tl::RelativeProgress *rel_progress_2 (const std::string &desc, size_t max)
{
return new tl::RelativeProgress (desc, max);

View File

@ -77,28 +77,6 @@ static void _call_f_filterEvent_2477 (const qt_gsi::GenericMethod * /*decl*/, vo
}
// bool QCoreApplication::notify(QObject *, QEvent *)
static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = gsi::arg_reader<QObject * >() (args, heap);
QEvent *arg2 = gsi::arg_reader<QEvent * >() (args, heap);
ret.write<bool > ((bool)((QCoreApplication *)cls)->notify (arg1, arg2));
}
// static void QCoreApplication::addLibraryPath(const QString &)
@ -941,7 +919,6 @@ static gsi::Methods methods_QCoreApplication () {
gsi::Methods methods;
methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo);
methods += new qt_gsi::GenericMethod ("filterEvent", "@brief Method bool QCoreApplication::filterEvent(void *message, long int *result)\n", false, &_init_f_filterEvent_2477, &_call_f_filterEvent_2477);
methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QCoreApplication::notify(QObject *, QEvent *)\n", false, &_init_f_notify_2411, &_call_f_notify_2411);
methods += gsi::qt_signal ("aboutToQuit()", "aboutToQuit", "@brief Signal declaration for QCoreApplication::aboutToQuit()\nYou can bind a procedure to this signal.");
methods += gsi::qt_signal<QObject * > ("destroyed(QObject *)", "destroyed", gsi::arg("arg1"), "@brief Signal declaration for QCoreApplication::destroyed(QObject *)\nYou can bind a procedure to this signal.");
methods += gsi::qt_signal<int > ("unixSignal(int)", "unixSignal", gsi::arg("arg1"), "@brief Signal declaration for QCoreApplication::unixSignal(int)\nYou can bind a procedure to this signal.");
@ -1054,21 +1031,6 @@ public:
}
}
// [adaptor impl] bool QCoreApplication::notify(QObject *, QEvent *)
bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2)
{
return QCoreApplication::notify(arg1, arg2);
}
virtual bool notify(QObject *arg1, QEvent *arg2)
{
if (cb_notify_2411_0.can_issue()) {
return cb_notify_2411_0.issue<QCoreApplication_Adaptor, bool, QObject *, QEvent *>(&QCoreApplication_Adaptor::cbs_notify_2411_0, arg1, arg2);
} else {
return QCoreApplication::notify(arg1, arg2);
}
}
// [emitter impl] void QCoreApplication::aboutToQuit()
void emitter_QCoreApplication_aboutToQuit_0()
{
@ -1163,7 +1125,6 @@ public:
}
gsi::Callback cb_eventFilter_2411_0;
gsi::Callback cb_notify_2411_0;
gsi::Callback cb_childEvent_1701_0;
gsi::Callback cb_customEvent_1217_0;
gsi::Callback cb_disconnectNotify_1731_0;
@ -1326,32 +1287,6 @@ static void _set_callback_cbs_eventFilter_2411_0 (void *cls, const gsi::Callback
}
// bool QCoreApplication::notify(QObject *, QEvent *)
static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = args.read<QObject * > (heap);
QEvent *arg2 = args.read<QEvent * > (heap);
ret.write<bool > ((bool)((QCoreApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2));
}
static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb)
{
((QCoreApplication_Adaptor *)cls)->cb_notify_2411_0 = cb;
}
// exposed int QCoreApplication::receivers(const char *signal)
static void _init_fp_receivers_c1731 (qt_gsi::GenericMethod *decl)
@ -1445,8 +1380,6 @@ static gsi::Methods methods_QCoreApplication_Adaptor () {
methods += new qt_gsi::GenericMethod ("*event", "@hide", false, &_init_cbs_event_1217_0, &_call_cbs_event_1217_0, &_set_callback_cbs_event_1217_0);
methods += new qt_gsi::GenericMethod ("eventFilter", "@brief Virtual method bool QCoreApplication::eventFilter(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0);
methods += new qt_gsi::GenericMethod ("eventFilter", "@hide", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0, &_set_callback_cbs_eventFilter_2411_0);
methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QCoreApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("*receivers", "@brief Method int QCoreApplication::receivers(const char *signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_receivers_c1731, &_call_fp_receivers_c1731);
methods += new qt_gsi::GenericMethod ("*sender", "@brief Method QObject *QCoreApplication::sender()\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_sender_c0, &_call_fp_sender_c0);
methods += new qt_gsi::GenericMethod ("*timerEvent", "@brief Virtual method void QCoreApplication::timerEvent(QTimerEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0);

View File

@ -101,28 +101,6 @@ static void _call_f_isSessionRestored_c0 (const qt_gsi::GenericMethod * /*decl*/
}
// bool QApplication::notify(QObject *, QEvent *)
static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = gsi::arg_reader<QObject * >() (args, heap);
QEvent *arg2 = gsi::arg_reader<QEvent * >() (args, heap);
ret.write<bool > ((bool)((QApplication *)cls)->notify (arg1, arg2));
}
// QString QApplication::sessionId()
@ -1534,7 +1512,6 @@ static gsi::Methods methods_QApplication () {
methods += new qt_gsi::GenericMethod (":autoSipEnabled", "@brief Method bool QApplication::autoSipEnabled()\n", true, &_init_f_autoSipEnabled_c0, &_call_f_autoSipEnabled_c0);
methods += new qt_gsi::GenericMethod (":inputContext", "@brief Method QInputContext *QApplication::inputContext()\n", true, &_init_f_inputContext_c0, &_call_f_inputContext_c0);
methods += new qt_gsi::GenericMethod ("isSessionRestored?", "@brief Method bool QApplication::isSessionRestored()\n", true, &_init_f_isSessionRestored_c0, &_call_f_isSessionRestored_c0);
methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QApplication::notify(QObject *, QEvent *)\nThis is a reimplementation of QCoreApplication::notify", false, &_init_f_notify_2411, &_call_f_notify_2411);
methods += new qt_gsi::GenericMethod ("sessionId", "@brief Method QString QApplication::sessionId()\n", true, &_init_f_sessionId_c0, &_call_f_sessionId_c0);
methods += new qt_gsi::GenericMethod ("sessionKey", "@brief Method QString QApplication::sessionKey()\n", true, &_init_f_sessionKey_c0, &_call_f_sessionKey_c0);
methods += new qt_gsi::GenericMethod ("setAutoSipEnabled|autoSipEnabled=", "@brief Method void QApplication::setAutoSipEnabled(const bool enabled)\n", false, &_init_f_setAutoSipEnabled_1559, &_call_f_setAutoSipEnabled_1559);
@ -1686,21 +1663,6 @@ public:
}
}
// [adaptor impl] bool QApplication::notify(QObject *, QEvent *)
bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2)
{
return QApplication::notify(arg1, arg2);
}
virtual bool notify(QObject *arg1, QEvent *arg2)
{
if (cb_notify_2411_0.can_issue()) {
return cb_notify_2411_0.issue<QApplication_Adaptor, bool, QObject *, QEvent *>(&QApplication_Adaptor::cbs_notify_2411_0, arg1, arg2);
} else {
return QApplication::notify(arg1, arg2);
}
}
// [emitter impl] void QApplication::aboutToQuit()
void emitter_QApplication_aboutToQuit_0()
{
@ -1813,7 +1775,6 @@ public:
}
gsi::Callback cb_eventFilter_2411_0;
gsi::Callback cb_notify_2411_0;
gsi::Callback cb_childEvent_1701_0;
gsi::Callback cb_customEvent_1217_0;
gsi::Callback cb_disconnectNotify_1731_0;
@ -2025,32 +1986,6 @@ static void _call_emitter_lastWindowClosed_0 (const qt_gsi::GenericMethod * /*de
}
// bool QApplication::notify(QObject *, QEvent *)
static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = args.read<QObject * > (heap);
QEvent *arg2 = args.read<QEvent * > (heap);
ret.write<bool > ((bool)((QApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2));
}
static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb)
{
((QApplication_Adaptor *)cls)->cb_notify_2411_0 = cb;
}
// exposed int QApplication::receivers(const char *signal)
static void _init_fp_receivers_c1731 (qt_gsi::GenericMethod *decl)
@ -2147,8 +2082,6 @@ static gsi::Methods methods_QApplication_Adaptor () {
methods += new qt_gsi::GenericMethod ("emit_focusChanged", "@brief Emitter for signal void QApplication::focusChanged(QWidget *old, QWidget *now)\nCall this method to emit this signal.", false, &_init_emitter_focusChanged_2522, &_call_emitter_focusChanged_2522);
methods += new qt_gsi::GenericMethod ("emit_fontDatabaseChanged", "@brief Emitter for signal void QApplication::fontDatabaseChanged()\nCall this method to emit this signal.", false, &_init_emitter_fontDatabaseChanged_0, &_call_emitter_fontDatabaseChanged_0);
methods += new qt_gsi::GenericMethod ("emit_lastWindowClosed", "@brief Emitter for signal void QApplication::lastWindowClosed()\nCall this method to emit this signal.", false, &_init_emitter_lastWindowClosed_0, &_call_emitter_lastWindowClosed_0);
methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("*receivers", "@brief Method int QApplication::receivers(const char *signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_receivers_c1731, &_call_fp_receivers_c1731);
methods += new qt_gsi::GenericMethod ("*sender", "@brief Method QObject *QApplication::sender()\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_sender_c0, &_call_fp_sender_c0);
methods += new qt_gsi::GenericMethod ("*timerEvent", "@brief Virtual method void QApplication::timerEvent(QTimerEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_timerEvent_1730_0, &_call_cbs_timerEvent_1730_0);

View File

@ -0,0 +1,13 @@
#
# Partial QMAKE project file for Qt bindings
#
# DO NOT EDIT THIS FILE.
# This file has been created automatically
#
SOURCES += \
gsiQtUiToolsMain.cc \
$$PWD/gsiDeclQUiLoader.cc
HEADERS += gsiQtUiToolsCommon.h

View File

@ -0,0 +1,20 @@
DESTDIR = $$OUT_PWD/../../..
TARGET = klayout_QtUiTools
include($$PWD/../../../lib.pri)
DEFINES += MAKE_GSI_QTUITOOLS_LIBRARY
INCLUDEPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_qtbasic
SOURCES += \
HEADERS += \
include(QtUiTools.pri)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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
*/
/**
* @file generated/gsiDeclQtUiToolsTypeTraits.h
* @brief Type traits for the Qt binding classes
*
* DO NOT EDIT THIS FILE.
* This file has been created automatically
*/
#ifndef _HDR_gsiDeclQtUiToolsTypeTraits
#define _HDR_gsiDeclQtUiToolsTypeTraits
#include "gsiTypes.h"
struct QMetaObject;
namespace tl {
template <> struct type_traits<QMetaObject> : public type_traits<void> {
};
}
class QObject;
namespace tl {
template <> struct type_traits<QObject> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class QObject_Adaptor;
namespace tl {
template <> struct type_traits<QObject_Adaptor> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class QSysInfo;
namespace tl {
template <> struct type_traits<QSysInfo> : public type_traits<void> {
};
}
class QUiLoader;
namespace tl {
template <> struct type_traits<QUiLoader> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class QUiLoader_Adaptor;
namespace tl {
template <> struct type_traits<QUiLoader_Adaptor> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class Qt_Namespace;
namespace tl {
template <> struct type_traits<Qt_Namespace> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
#endif

View File

@ -0,0 +1,48 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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
*/
/*
External declarations for for Qt bindings
DO NOT EDIT THIS FILE.
This file has been created automatically
*/
#if !defined(HDR_gsiQtUiToolsExternals)
#define HDR_gsiQtUiToolsExternals
#include "gsiClass.h"
#include "gsiQtUiToolsCommon.h"
class QUiLoader;
namespace tl { template <> struct type_traits<QUiLoader> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
}; }
namespace gsi { GSI_QTUITOOLS_PUBLIC gsi::Class<QUiLoader> &qtdecl_QUiLoader (); }
#define QT_EXTERNAL_BASE(X) gsi::qtdecl_##X(),
#endif

View File

@ -0,0 +1,25 @@
/**
* Common header for Qt binding definition library
*
* DO NOT EDIT THIS FILE.
* This file has been created automatically
*/
#include "tlDefs.h"
#if !defined(HDR_gsiQtUiToolsCommon_h)
# define HDR_gsiQtUiToolsCommon_h
# ifdef MAKE_GSI_QTUITOOLS_LIBRARY
# define GSI_QTUITOOLS_PUBLIC DEF_INSIDE_PUBLIC
# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_INSIDE_PUBLIC_TEMPLATE
# define GSI_QTUITOOLS_LOCAL DEF_INSIDE_LOCAL
# else
# define GSI_QTUITOOLS_PUBLIC DEF_OUTSIDE_PUBLIC
# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_OUTSIDE_PUBLIC_TEMPLATE
# define GSI_QTUITOOLS_LOCAL DEF_OUTSIDE_LOCAL
# endif
#define FORCE_LINK_GSI_QTUITOOLS GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f (); int _force_link_gsiQtUiTools = _force_link_gsiQtUiTools_f ();
#endif

View File

@ -0,0 +1,11 @@
/**
* Main source file for Qt binding definition library
*
* DO NOT EDIT THIS FILE.
* This file has been created automatically
*/
#include "gsiQtUiToolsCommon.h"
GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f () { return 0; }

View File

@ -1,16 +1,36 @@
include($$PWD/../../klayout.pri)
TEMPLATE = subdirs
SUBDIRS = \
QtCore \
QtGui \
QtXml \
QtSql \
QtNetwork \
QtDesigner
QtGui
QtGui.depends += QtCore
QtNetwork.depends += QtCore
QtSql.depends += QtCore
QtDesigner.depends += QtCore
QtXml.depends += QtCore
equals(HAVE_QT_NETWORK, "1") {
SUBDIRS += QtNetwork
QtNetwork.depends += QtCore
}
equals(HAVE_QT_SQL, "1") {
SUBDIRS += QtSql
QtSql.depends += QtCore
}
equals(HAVE_QT_DESIGNER, "1") {
SUBDIRS += QtDesigner
QtDesigner.depends += QtCore
}
equals(HAVE_QT_XML, "1") {
SUBDIRS += QtXml
QtXml.depends += QtCore
}
equals(HAVE_QT_UITOOLS, "1") {
SUBDIRS += QtUiTools
QtUiTools.depends += QtCore
}

View File

@ -72,28 +72,6 @@ static void _call_f_installNativeEventFilter_3266 (const qt_gsi::GenericMethod *
}
// bool QCoreApplication::notify(QObject *, QEvent *)
static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = gsi::arg_reader<QObject * >() (args, heap);
QEvent *arg2 = gsi::arg_reader<QEvent * >() (args, heap);
ret.write<bool > ((bool)((QCoreApplication *)cls)->notify (arg1, arg2));
}
// void QCoreApplication::removeNativeEventFilter(QAbstractNativeEventFilter *filterObj)
@ -924,7 +902,6 @@ static gsi::Methods methods_QCoreApplication () {
gsi::Methods methods;
methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo);
methods += new qt_gsi::GenericMethod ("installNativeEventFilter", "@brief Method void QCoreApplication::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)\n", false, &_init_f_installNativeEventFilter_3266, &_call_f_installNativeEventFilter_3266);
methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QCoreApplication::notify(QObject *, QEvent *)\n", false, &_init_f_notify_2411, &_call_f_notify_2411);
methods += new qt_gsi::GenericMethod ("removeNativeEventFilter", "@brief Method void QCoreApplication::removeNativeEventFilter(QAbstractNativeEventFilter *filterObj)\n", false, &_init_f_removeNativeEventFilter_3266, &_call_f_removeNativeEventFilter_3266);
methods += gsi::qt_signal ("aboutToQuit()", "aboutToQuit", "@brief Signal declaration for QCoreApplication::aboutToQuit()\nYou can bind a procedure to this signal.");
methods += gsi::qt_signal ("applicationNameChanged()", "applicationNameChanged", "@brief Signal declaration for QCoreApplication::applicationNameChanged()\nYou can bind a procedure to this signal.");
@ -1076,21 +1053,6 @@ public:
}
}
// [adaptor impl] bool QCoreApplication::notify(QObject *, QEvent *)
bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2)
{
return QCoreApplication::notify(arg1, arg2);
}
virtual bool notify(QObject *arg1, QEvent *arg2)
{
if (cb_notify_2411_0.can_issue()) {
return cb_notify_2411_0.issue<QCoreApplication_Adaptor, bool, QObject *, QEvent *>(&QCoreApplication_Adaptor::cbs_notify_2411_0, arg1, arg2);
} else {
return QCoreApplication::notify(arg1, arg2);
}
}
// [emitter impl] void QCoreApplication::objectNameChanged(const QString &objectName)
void emitter_QCoreApplication_objectNameChanged_4567(const QString &objectName)
{
@ -1186,7 +1148,6 @@ public:
}
gsi::Callback cb_eventFilter_2411_0;
gsi::Callback cb_notify_2411_0;
gsi::Callback cb_childEvent_1701_0;
gsi::Callback cb_customEvent_1217_0;
gsi::Callback cb_disconnectNotify_2394_0;
@ -1395,32 +1356,6 @@ static void _call_fp_isSignalConnected_c2394 (const qt_gsi::GenericMethod * /*de
}
// bool QCoreApplication::notify(QObject *, QEvent *)
static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = args.read<QObject * > (heap);
QEvent *arg2 = args.read<QEvent * > (heap);
ret.write<bool > ((bool)((QCoreApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2));
}
static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb)
{
((QCoreApplication_Adaptor *)cls)->cb_notify_2411_0 = cb;
}
// emitter void QCoreApplication::objectNameChanged(const QString &objectName)
static void _init_emitter_objectNameChanged_4567 (qt_gsi::GenericMethod *decl)
@ -1559,8 +1494,6 @@ static gsi::Methods methods_QCoreApplication_Adaptor () {
methods += new qt_gsi::GenericMethod ("eventFilter", "@brief Virtual method bool QCoreApplication::eventFilter(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0);
methods += new qt_gsi::GenericMethod ("eventFilter", "@hide", false, &_init_cbs_eventFilter_2411_0, &_call_cbs_eventFilter_2411_0, &_set_callback_cbs_eventFilter_2411_0);
methods += new qt_gsi::GenericMethod ("*isSignalConnected", "@brief Method bool QCoreApplication::isSignalConnected(const QMetaMethod &signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_isSignalConnected_c2394, &_call_fp_isSignalConnected_c2394);
methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QCoreApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("emit_objectNameChanged", "@brief Emitter for signal void QCoreApplication::objectNameChanged(const QString &objectName)\nCall this method to emit this signal.", false, &_init_emitter_objectNameChanged_4567, &_call_emitter_objectNameChanged_4567);
methods += new qt_gsi::GenericMethod ("emit_organizationDomainChanged", "@brief Emitter for signal void QCoreApplication::organizationDomainChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationDomainChanged_0, &_call_emitter_organizationDomainChanged_0);
methods += new qt_gsi::GenericMethod ("emit_organizationNameChanged", "@brief Emitter for signal void QCoreApplication::organizationNameChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationNameChanged_0, &_call_emitter_organizationNameChanged_0);

View File

@ -99,28 +99,6 @@ static void _call_f_isSessionRestored_c0 (const qt_gsi::GenericMethod * /*decl*/
}
// bool QGuiApplication::notify(QObject *, QEvent *)
static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = gsi::arg_reader<QObject * >() (args, heap);
QEvent *arg2 = gsi::arg_reader<QEvent * >() (args, heap);
ret.write<bool > ((bool)((QGuiApplication *)cls)->notify (arg1, arg2));
}
// QString QGuiApplication::sessionId()
@ -831,7 +809,6 @@ static gsi::Methods methods_QGuiApplication () {
methods += new qt_gsi::GenericMethod ("devicePixelRatio", "@brief Method double QGuiApplication::devicePixelRatio()\n", true, &_init_f_devicePixelRatio_c0, &_call_f_devicePixelRatio_c0);
methods += new qt_gsi::GenericMethod ("isSavingSession?", "@brief Method bool QGuiApplication::isSavingSession()\n", true, &_init_f_isSavingSession_c0, &_call_f_isSavingSession_c0);
methods += new qt_gsi::GenericMethod ("isSessionRestored?", "@brief Method bool QGuiApplication::isSessionRestored()\n", true, &_init_f_isSessionRestored_c0, &_call_f_isSessionRestored_c0);
methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QGuiApplication::notify(QObject *, QEvent *)\nThis is a reimplementation of QCoreApplication::notify", false, &_init_f_notify_2411, &_call_f_notify_2411);
methods += new qt_gsi::GenericMethod ("sessionId", "@brief Method QString QGuiApplication::sessionId()\n", true, &_init_f_sessionId_c0, &_call_f_sessionId_c0);
methods += new qt_gsi::GenericMethod ("sessionKey", "@brief Method QString QGuiApplication::sessionKey()\n", true, &_init_f_sessionKey_c0, &_call_f_sessionKey_c0);
methods += gsi::qt_signal ("aboutToQuit()", "aboutToQuit", "@brief Signal declaration for QGuiApplication::aboutToQuit()\nYou can bind a procedure to this signal.");
@ -1034,21 +1011,6 @@ public:
emit QGuiApplication::layoutDirectionChanged(direction);
}
// [adaptor impl] bool QGuiApplication::notify(QObject *, QEvent *)
bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2)
{
return QGuiApplication::notify(arg1, arg2);
}
virtual bool notify(QObject *arg1, QEvent *arg2)
{
if (cb_notify_2411_0.can_issue()) {
return cb_notify_2411_0.issue<QGuiApplication_Adaptor, bool, QObject *, QEvent *>(&QGuiApplication_Adaptor::cbs_notify_2411_0, arg1, arg2);
} else {
return QGuiApplication::notify(arg1, arg2);
}
}
// [emitter impl] void QGuiApplication::objectNameChanged(const QString &objectName)
void emitter_QGuiApplication_objectNameChanged_4567(const QString &objectName)
{
@ -1168,7 +1130,6 @@ public:
}
gsi::Callback cb_eventFilter_2411_0;
gsi::Callback cb_notify_2411_0;
gsi::Callback cb_childEvent_1701_0;
gsi::Callback cb_customEvent_1217_0;
gsi::Callback cb_disconnectNotify_2394_0;
@ -1495,32 +1456,6 @@ static void _call_emitter_layoutDirectionChanged_2316 (const qt_gsi::GenericMeth
}
// bool QGuiApplication::notify(QObject *, QEvent *)
static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = args.read<QObject * > (heap);
QEvent *arg2 = args.read<QEvent * > (heap);
ret.write<bool > ((bool)((QGuiApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2));
}
static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb)
{
((QGuiApplication_Adaptor *)cls)->cb_notify_2411_0 = cb;
}
// emitter void QGuiApplication::objectNameChanged(const QString &objectName)
static void _init_emitter_objectNameChanged_4567 (qt_gsi::GenericMethod *decl)
@ -1738,8 +1673,6 @@ static gsi::Methods methods_QGuiApplication_Adaptor () {
methods += new qt_gsi::GenericMethod ("*isSignalConnected", "@brief Method bool QGuiApplication::isSignalConnected(const QMetaMethod &signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_isSignalConnected_c2394, &_call_fp_isSignalConnected_c2394);
methods += new qt_gsi::GenericMethod ("emit_lastWindowClosed", "@brief Emitter for signal void QGuiApplication::lastWindowClosed()\nCall this method to emit this signal.", false, &_init_emitter_lastWindowClosed_0, &_call_emitter_lastWindowClosed_0);
methods += new qt_gsi::GenericMethod ("emit_layoutDirectionChanged", "@brief Emitter for signal void QGuiApplication::layoutDirectionChanged(Qt::LayoutDirection direction)\nCall this method to emit this signal.", false, &_init_emitter_layoutDirectionChanged_2316, &_call_emitter_layoutDirectionChanged_2316);
methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QGuiApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("emit_objectNameChanged", "@brief Emitter for signal void QGuiApplication::objectNameChanged(const QString &objectName)\nCall this method to emit this signal.", false, &_init_emitter_objectNameChanged_4567, &_call_emitter_objectNameChanged_4567);
methods += new qt_gsi::GenericMethod ("emit_organizationDomainChanged", "@brief Emitter for signal void QGuiApplication::organizationDomainChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationDomainChanged_0, &_call_emitter_organizationDomainChanged_0);
methods += new qt_gsi::GenericMethod ("emit_organizationNameChanged", "@brief Emitter for signal void QGuiApplication::organizationNameChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationNameChanged_0, &_call_emitter_organizationNameChanged_0);

View File

@ -0,0 +1,13 @@
#
# Partial QMAKE project file for Qt bindings
#
# DO NOT EDIT THIS FILE.
# This file has been created automatically
#
SOURCES += \
gsiQtUiToolsMain.cc \
$$PWD/gsiDeclQUiLoader.cc
HEADERS += gsiQtUiToolsCommon.h

View File

@ -0,0 +1,20 @@
DESTDIR = $$OUT_PWD/../../..
TARGET = klayout_QtUiTools
include($$PWD/../../../lib.pri)
DEFINES += MAKE_GSI_QTUITOOLS_LIBRARY
INCLUDEPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$QTBASIC_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_qtbasic -lklayout_QtCore
SOURCES += \
HEADERS += \
include(QtUiTools.pri)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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
*/
/**
* @file generated/gsiDeclQtUiToolsTypeTraits.h
* @brief Type traits for the Qt binding classes
*
* DO NOT EDIT THIS FILE.
* This file has been created automatically
*/
#ifndef _HDR_gsiDeclQtUiToolsTypeTraits
#define _HDR_gsiDeclQtUiToolsTypeTraits
#include "gsiTypes.h"
struct QByteArrayDataPtr;
namespace tl {
template <> struct type_traits<QByteArrayDataPtr> : public type_traits<void> {
};
}
class QMessageLogContext;
namespace tl {
template <> struct type_traits<QMessageLogContext> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class QMessageLogger;
namespace tl {
template <> struct type_traits<QMessageLogger> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
struct QMetaObject;
namespace tl {
template <> struct type_traits<QMetaObject> : public type_traits<void> {
};
}
#include <QMetaObject>
namespace tl {
template <> struct type_traits<QMetaObject::Connection> : public type_traits<void> {
};
}
class QObject;
namespace tl {
template <> struct type_traits<QObject> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class QObject_Adaptor;
namespace tl {
template <> struct type_traits<QObject_Adaptor> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class QRegExp;
namespace tl {
template <> struct type_traits<QRegExp> : public type_traits<void> {
};
}
class QSignalBlocker;
namespace tl {
template <> struct type_traits<QSignalBlocker> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
struct QStringDataPtr;
namespace tl {
template <> struct type_traits<QStringDataPtr> : public type_traits<void> {
};
}
class QStringMatcher;
namespace tl {
template <> struct type_traits<QStringMatcher> : public type_traits<void> {
};
}
class QSysInfo;
namespace tl {
template <> struct type_traits<QSysInfo> : public type_traits<void> {
};
}
class QUiLoader;
namespace tl {
template <> struct type_traits<QUiLoader> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class QUiLoader_Adaptor;
namespace tl {
template <> struct type_traits<QUiLoader_Adaptor> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
class Qt_Namespace;
namespace tl {
template <> struct type_traits<Qt_Namespace> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
#endif

View File

@ -0,0 +1,48 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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
*/
/*
External declarations for for Qt bindings
DO NOT EDIT THIS FILE.
This file has been created automatically
*/
#if !defined(HDR_gsiQtUiToolsExternals)
#define HDR_gsiQtUiToolsExternals
#include "gsiClass.h"
#include "gsiQtUiToolsCommon.h"
class QUiLoader;
namespace tl { template <> struct type_traits<QUiLoader> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
}; }
namespace gsi { GSI_QTUITOOLS_PUBLIC gsi::Class<QUiLoader> &qtdecl_QUiLoader (); }
#define QT_EXTERNAL_BASE(X) gsi::qtdecl_##X(),
#endif

View File

@ -0,0 +1,25 @@
/**
* Common header for Qt binding definition library
*
* DO NOT EDIT THIS FILE.
* This file has been created automatically
*/
#include "tlDefs.h"
#if !defined(HDR_gsiQtUiToolsCommon_h)
# define HDR_gsiQtUiToolsCommon_h
# ifdef MAKE_GSI_QTUITOOLS_LIBRARY
# define GSI_QTUITOOLS_PUBLIC DEF_INSIDE_PUBLIC
# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_INSIDE_PUBLIC_TEMPLATE
# define GSI_QTUITOOLS_LOCAL DEF_INSIDE_LOCAL
# else
# define GSI_QTUITOOLS_PUBLIC DEF_OUTSIDE_PUBLIC
# define GSI_QTUITOOLS_PUBLIC_TEMPLATE DEF_OUTSIDE_PUBLIC_TEMPLATE
# define GSI_QTUITOOLS_LOCAL DEF_OUTSIDE_LOCAL
# endif
#define FORCE_LINK_GSI_QTUITOOLS GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f (); int _force_link_gsiQtUiTools = _force_link_gsiQtUiTools_f ();
#endif

View File

@ -0,0 +1,11 @@
/**
* Main source file for Qt binding definition library
*
* DO NOT EDIT THIS FILE.
* This file has been created automatically
*/
#include "gsiQtUiToolsCommon.h"
GSI_QTUITOOLS_PUBLIC int _force_link_gsiQtUiTools_f () { return 0; }

View File

@ -69,28 +69,6 @@ static void _call_f_autoSipEnabled_c0 (const qt_gsi::GenericMethod * /*decl*/, v
}
// bool QApplication::notify(QObject *, QEvent *)
static void _init_f_notify_2411 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_f_notify_2411 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = gsi::arg_reader<QObject * >() (args, heap);
QEvent *arg2 = gsi::arg_reader<QEvent * >() (args, heap);
ret.write<bool > ((bool)((QApplication *)cls)->notify (arg1, arg2));
}
// void QApplication::setAutoSipEnabled(const bool enabled)
@ -1074,7 +1052,6 @@ static gsi::Methods methods_QApplication () {
gsi::Methods methods;
methods += new qt_gsi::GenericStaticMethod ("staticMetaObject", "@brief Obtains the static MetaObject for this class.", &_init_smo, &_call_smo);
methods += new qt_gsi::GenericMethod (":autoSipEnabled", "@brief Method bool QApplication::autoSipEnabled()\n", true, &_init_f_autoSipEnabled_c0, &_call_f_autoSipEnabled_c0);
methods += new qt_gsi::GenericMethod ("notify", "@brief Method bool QApplication::notify(QObject *, QEvent *)\nThis is a reimplementation of QGuiApplication::notify", false, &_init_f_notify_2411, &_call_f_notify_2411);
methods += new qt_gsi::GenericMethod ("setAutoSipEnabled|autoSipEnabled=", "@brief Method void QApplication::setAutoSipEnabled(const bool enabled)\n", false, &_init_f_setAutoSipEnabled_1559, &_call_f_setAutoSipEnabled_1559);
methods += new qt_gsi::GenericMethod ("setStyleSheet|styleSheet=", "@brief Method void QApplication::setStyleSheet(const QString &sheet)\n", false, &_init_f_setStyleSheet_2025, &_call_f_setStyleSheet_2025);
methods += new qt_gsi::GenericMethod (":styleSheet", "@brief Method QString QApplication::styleSheet()\n", true, &_init_f_styleSheet_c0, &_call_f_styleSheet_c0);
@ -1296,21 +1273,6 @@ public:
emit QApplication::layoutDirectionChanged(direction);
}
// [adaptor impl] bool QApplication::notify(QObject *, QEvent *)
bool cbs_notify_2411_0(QObject *arg1, QEvent *arg2)
{
return QApplication::notify(arg1, arg2);
}
virtual bool notify(QObject *arg1, QEvent *arg2)
{
if (cb_notify_2411_0.can_issue()) {
return cb_notify_2411_0.issue<QApplication_Adaptor, bool, QObject *, QEvent *>(&QApplication_Adaptor::cbs_notify_2411_0, arg1, arg2);
} else {
return QApplication::notify(arg1, arg2);
}
}
// [emitter impl] void QApplication::objectNameChanged(const QString &objectName)
void emitter_QApplication_objectNameChanged_4567(const QString &objectName)
{
@ -1430,7 +1392,6 @@ public:
}
gsi::Callback cb_eventFilter_2411_0;
gsi::Callback cb_notify_2411_0;
gsi::Callback cb_childEvent_1701_0;
gsi::Callback cb_customEvent_1217_0;
gsi::Callback cb_disconnectNotify_2394_0;
@ -1778,32 +1739,6 @@ static void _call_emitter_layoutDirectionChanged_2316 (const qt_gsi::GenericMeth
}
// bool QApplication::notify(QObject *, QEvent *)
static void _init_cbs_notify_2411_0 (qt_gsi::GenericMethod *decl)
{
static gsi::ArgSpecBase argspec_0 ("arg1");
decl->add_arg<QObject * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("arg2");
decl->add_arg<QEvent * > (argspec_1);
decl->set_return<bool > ();
}
static void _call_cbs_notify_2411_0 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
{
__SUPPRESS_UNUSED_WARNING(args);
tl::Heap heap;
QObject *arg1 = args.read<QObject * > (heap);
QEvent *arg2 = args.read<QEvent * > (heap);
ret.write<bool > ((bool)((QApplication_Adaptor *)cls)->cbs_notify_2411_0 (arg1, arg2));
}
static void _set_callback_cbs_notify_2411_0 (void *cls, const gsi::Callback &cb)
{
((QApplication_Adaptor *)cls)->cb_notify_2411_0 = cb;
}
// emitter void QApplication::objectNameChanged(const QString &objectName)
static void _init_emitter_objectNameChanged_4567 (qt_gsi::GenericMethod *decl)
@ -2022,8 +1957,6 @@ static gsi::Methods methods_QApplication_Adaptor () {
methods += new qt_gsi::GenericMethod ("*isSignalConnected", "@brief Method bool QApplication::isSignalConnected(const QMetaMethod &signal)\nThis method is protected and can only be called from inside a derived class.", true, &_init_fp_isSignalConnected_c2394, &_call_fp_isSignalConnected_c2394);
methods += new qt_gsi::GenericMethod ("emit_lastWindowClosed", "@brief Emitter for signal void QApplication::lastWindowClosed()\nCall this method to emit this signal.", false, &_init_emitter_lastWindowClosed_0, &_call_emitter_lastWindowClosed_0);
methods += new qt_gsi::GenericMethod ("emit_layoutDirectionChanged", "@brief Emitter for signal void QApplication::layoutDirectionChanged(Qt::LayoutDirection direction)\nCall this method to emit this signal.", false, &_init_emitter_layoutDirectionChanged_2316, &_call_emitter_layoutDirectionChanged_2316);
methods += new qt_gsi::GenericMethod ("notify", "@brief Virtual method bool QApplication::notify(QObject *, QEvent *)\nThis method can be reimplemented in a derived class.", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("notify", "@hide", false, &_init_cbs_notify_2411_0, &_call_cbs_notify_2411_0, &_set_callback_cbs_notify_2411_0);
methods += new qt_gsi::GenericMethod ("emit_objectNameChanged", "@brief Emitter for signal void QApplication::objectNameChanged(const QString &objectName)\nCall this method to emit this signal.", false, &_init_emitter_objectNameChanged_4567, &_call_emitter_objectNameChanged_4567);
methods += new qt_gsi::GenericMethod ("emit_organizationDomainChanged", "@brief Emitter for signal void QApplication::organizationDomainChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationDomainChanged_0, &_call_emitter_organizationDomainChanged_0);
methods += new qt_gsi::GenericMethod ("emit_organizationNameChanged", "@brief Emitter for signal void QApplication::organizationNameChanged()\nCall this method to emit this signal.", false, &_init_emitter_organizationNameChanged_0, &_call_emitter_organizationNameChanged_0);

View File

@ -1,26 +1,53 @@
include($$PWD/../../klayout.pri)
TEMPLATE = subdirs
SUBDIRS = \
QtCore \
QtGui \
QtNetwork \
QtSql \
QtWidgets \
QtDesigner \
QtMultimedia \
QtPrintSupport \
QtSvg \
QtXmlPatterns \
QtXml
QtWidgets
QtGui.depends += QtCore
QtNetwork.depends += QtCore
QtSql.depends += QtCore
QtWidgets.depends += QtGui
QtDesigner.depends += QtCore
QtMultimedia.depends += QtCore QtWidgets QtNetwork
QtPrintSupport.depends += QtCore QtWidgets
QtSvg.depends += QtCore QtWidgets
QtXmlPatterns.depends += QtCore
QtXml.depends += QtCore
equals(HAVE_QT_NETWORK, "1") {
SUBDIRS += QtNetwork
QtNetwork.depends += QtCore
}
equals(HAVE_QT_SQL, "1") {
SUBDIRS += QtSql
QtSql.depends += QtCore
}
equals(HAVE_QT_SVG, "1") {
SUBDIRS += QtSvg
QtSvg.depends += QtCore QtWidgets
}
equals(HAVE_QT_PRINTSUPPORT, "1") {
SUBDIRS += QtPrintSupport
QtPrintSupport.depends += QtCore QtWidgets
}
equals(HAVE_QT_MULTIMEDIA, "1") {
SUBDIRS += QtMultimedia
QtMultimedia.depends += QtCore QtWidgets QtNetwork
}
equals(HAVE_QT_DESIGNER, "1") {
SUBDIRS += QtDesigner
QtDesigner.depends += QtCore
}
equals(HAVE_QT_XML, "1") {
SUBDIRS += QtXml QtXmlPatterns
QtXmlPatterns.depends += QtCore
QtXml.depends += QtCore
}
equals(HAVE_QT_UITOOLS, "1") {
SUBDIRS += QtUiTools
QtUiTools.depends += QtCore
}

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_DESIGNER)
# define FORCE_LINK_GSI_QTDESIGNER
#elif QT_VERSION >= 0x050000
# include "../qt5/QtDesigner/gsiQtExternals.h"
#else
# include "../qt4/QtDesigner/gsiQtExternals.h"

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_MULTIMEDIA)
# define FORCE_LINK_GSI_QTMULTIMEDIA
#elif QT_VERSION >= 0x050000
# include "../qt5/QtMultimedia/gsiQtExternals.h"
#else
// no present in Qt4

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_NETWORK)
# define FORCE_LINK_GSI_QTNETWORK
#elif QT_VERSION >= 0x050000
# include "../qt5/QtNetwork/gsiQtExternals.h"
#else
# include "../qt4/QtNetwork/gsiQtExternals.h"

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_PRINTSUPPORT)
# define FORCE_LINK_GSI_QTPRINTSUPPORT
#elif QT_VERSION >= 0x050000
# include "../qt5/QtPrintSupport/gsiQtExternals.h"
#else
// no present in Qt4

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_SQL)
# define FORCE_LINK_GSI_QTSQL
#elif QT_VERSION >= 0x050000
# include "../qt5/QtSql/gsiQtExternals.h"
#else
# include "../qt4/QtSql/gsiQtExternals.h"

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_SVG)
# define FORCE_LINK_GSI_QTSVG
#elif QT_VERSION >= 0x050000
# include "../qt5/QtSvg/gsiQtExternals.h"
#else
// no present in Qt4

View File

@ -0,0 +1,29 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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 !defined(HAVE_QT_UITOOLS)
# define FORCE_LINK_GSI_QTUITOOLS
#elif QT_VERSION >= 0x050000
# include "../qt5/QtUiTools/gsiQtExternals.h"
#else
# include "../qt4/QtUiTools/gsiQtExternals.h"
#endif

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_XML)
# define FORCE_LINK_GSI_QTXML
#elif QT_VERSION >= 0x050000
# include "../qt5/QtXml/gsiQtExternals.h"
#else
# include "../qt4/QtXml/gsiQtExternals.h"

View File

@ -20,7 +20,9 @@
*/
#if QT_VERSION >= 0x050000
#if !defined(HAVE_QT_XML)
# define FORCE_LINK_GSI_QTXMLPATTERNS
#elif QT_VERSION >= 0x050000
# include "../qt5/QtXmlPatterns/gsiQtExternals.h"
#else
// Not present in Qt4

View File

@ -17,5 +17,19 @@ SOURCES += \
gsiQtHelper.cc
HEADERS += \
gsiDeclQtAllTypeTraits.h \
gsiQt.h \
gsiQtBasicCommon.h \
gsiQtBasicCommon.h \ \
gsiQtCoreExternals.h \
gsiQtDesignerExternals.h \
gsiQtGuiExternals.h \
gsiQtHelper.h \
gsiQtMultimediaExternals.h \
gsiQtNetworkExternals.h \
gsiQtPrintSupportExternals.h \
gsiQtSqlExternals.h \
gsiQtSvgExternals.h \
gsiQtUiToolsExternals.h \
gsiQtWidgetsExternals.h \
gsiQtXmlExternals.h \
gsiQtXmlPatternsExternals.h

View File

@ -1343,7 +1343,7 @@ Object::from_string (const char *str, const char *base_dir)
tl::URI fp_uri (m_filename);
if (base_dir && ! tl::is_absolute (fp_uri.path ())) {
m_filename = tl::URI (base_dir).resolved (fp_uri).to_string ();
m_filename = tl::URI (base_dir).resolved (fp_uri).to_abstract_path ();
}
read_file ();

View File

@ -219,7 +219,7 @@ PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out)
try {
tl::from_string (tl::to_string (from_le->text ()), xmin);
lay::indicate_error (from_le, 0);
lay::indicate_error (from_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (from_le, &ex);
has_error = true;
@ -227,7 +227,7 @@ PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out)
try {
tl::from_string (tl::to_string (to_le->text ()), xmax);
lay::indicate_error (to_le, 0);
lay::indicate_error (to_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (to_le, &ex);
has_error = true;
@ -336,7 +336,7 @@ PropertiesPage::value_changed ()
double x = 0.0;
try {
tl::from_string (tl::to_string (value_le->text ()), x);
lay::indicate_error (value_le, 0);
lay::indicate_error (value_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (value_le, &ex);
has_error = true;
@ -805,7 +805,7 @@ PropertiesPage::apply ()
if (w <= 0.0 || h <= 0.0) {
throw tl::Exception (tl::to_string (QObject::tr ("Pixel width or height must be positive, non-null values")));
}
lay::indicate_error (width_le, 0);
lay::indicate_error (width_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (width_le, &ex);
has_error = true;
@ -813,7 +813,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (height_le->text ()), h);
lay::indicate_error (height_le, 0);
lay::indicate_error (height_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (height_le, &ex);
has_error = true;
@ -821,7 +821,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (x_offset_le->text ()), x);
lay::indicate_error (x_offset_le, 0);
lay::indicate_error (x_offset_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x_offset_le, &ex);
has_error = true;
@ -829,7 +829,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (y_offset_le->text ()), y);
lay::indicate_error (y_offset_le, 0);
lay::indicate_error (y_offset_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y_offset_le, &ex);
has_error = true;
@ -837,7 +837,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (angle_le->text ()), a);
lay::indicate_error (angle_le, 0);
lay::indicate_error (angle_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (angle_le, &ex);
has_error = true;
@ -848,7 +848,7 @@ PropertiesPage::apply ()
if (sa <= -45 || sa >= 45) {
throw tl::Exception (tl::to_string (QObject::tr ("The shear angle must be larger than -45 and less than 45 degree")));
}
lay::indicate_error (shear_le, 0);
lay::indicate_error (shear_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (shear_le, &ex);
has_error = true;
@ -859,7 +859,7 @@ PropertiesPage::apply ()
if (tx <= -90 || tx >= 90) {
throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree")));
}
lay::indicate_error (persp_tx_le, 0);
lay::indicate_error (persp_tx_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (persp_tx_le, &ex);
has_error = true;
@ -870,7 +870,7 @@ PropertiesPage::apply ()
if (ty <= -90 || ty >= 90) {
throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree")));
}
lay::indicate_error (persp_ty_le, 0);
lay::indicate_error (persp_ty_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (persp_ty_le, &ex);
has_error = true;

View File

@ -40,6 +40,15 @@ equals(HAVE_QTBINDINGS, "1") {
DEFINES += HAVE_QTBINDINGS
}
!equals(HAVE_QT_UITOOLS, "0") {
# auto-select uitools, not all distributions have it
contains(QT_MODULES, "uitools") {
HAVE_QT_UITOOLS = 1
} else {
HAVE_QT_UITOOLS = 0
}
}
equals(HAVE_64BIT_COORD, "1") {
DEFINES += HAVE_64BIT_COORD
}
@ -160,18 +169,77 @@ equals(HAVE_QT, "0") {
} else {
DEFINES += HAVE_QT
QT += core network xml sql
QT += core xml network
equals(HAVE_QT5, "1") {
QT += designer printsupport widgets
equals(HAVE_QTBINDINGS, "1") {
QT += multimedia multimediawidgets xmlpatterns svg gui
equals(HAVE_QTBINDINGS, "1") {
# sql isn't needed by the base application
!equals(HAVE_QT_SQL, "0") {
QT += sql
}
} else {
# questionable: use uitools instead?
CONFIG += designer
}
equals(HAVE_QT5, "1") {
QT += widgets gui printsupport xmlpatterns
equals(HAVE_QTBINDINGS, "1") {
!equals(HAVE_QT_DESIGNER, "0") {
# designer isn't needed by the base application
QT += designer
}
!equals(HAVE_QT_MULTIMEDIA, "0") {
# multimedia isn't needed by the base application
QT += multimedia multimediawidgets
}
!equals(HAVE_QT_SVG, "0") {
# svg isn't needed by the base application
QT += svg
}
!equals(HAVE_QT_UITOOLS, "0") {
# uitools isn't needed by the base application
QT += uitools
}
}
} else {
equals(HAVE_QTBINDINGS, "1") {
!equals(HAVE_QT_DESIGNER, "0") {
# designer isn't needed by the base application
CONFIG += designer
}
!equals(HAVE_QT_UITOOLS, "0") {
# uitools isn't needed by the base application
CONFIG += uitools
}
}
}
!equals(HAVE_QT_UITOOLS, "0") {
DEFINES += HAVE_QT_UITOOLS
}
!equals(HAVE_QT_NETWORK, "0") {
DEFINES += HAVE_QT_NETWORK
}
!equals(HAVE_QT_SQL, "0") {
DEFINES += HAVE_QT_SQL
}
!equals(HAVE_QT_SVG, "0") {
DEFINES += HAVE_QT_SVG
}
!equals(HAVE_QT_PRINTSUPPORT, "0") {
DEFINES += HAVE_QT_PRINTSUPPORT
}
!equals(HAVE_QT_MULTIMEDIA, "0") {
DEFINES += HAVE_QT_MULTIMEDIA
}
!equals(HAVE_QT_DESIGNER, "0") {
DEFINES += HAVE_QT_DESIGNER
}
!equals(HAVE_QT_XML, "0") {
DEFINES += HAVE_QT_XML
}
}
VERSION_STRING = $$KLAYOUT_VERSION

View File

@ -51,18 +51,30 @@
// pulls in the Qt GSI binding modules
# include "gsiQtGuiExternals.h"
# include "gsiQtWidgetsExternals.h"
# include "gsiQtCoreExternals.h"
# include "gsiQtMultimediaExternals.h"
# include "gsiQtPrintSupportExternals.h"
# include "gsiQtXmlExternals.h"
# include "gsiQtXmlPatternsExternals.h"
# include "gsiQtSqlExternals.h"
# include "gsiQtSvgExternals.h"
# include "gsiQtNetworkExternals.h"
# include "gsiQtDesignerExternals.h"
# include "gsiQtUiToolsExternals.h"
FORCE_LINK_GSI_QTCORE
FORCE_LINK_GSI_QTGUI
FORCE_LINK_GSI_QTWIDGETS
FORCE_LINK_GSI_QTMULTIMEDIA
FORCE_LINK_GSI_QTPRINTSUPPORT
FORCE_LINK_GSI_QTXML
FORCE_LINK_GSI_QTXMLPATTERNS
FORCE_LINK_GSI_QTDESIGNER
FORCE_LINK_GSI_QTNETWORK
FORCE_LINK_GSI_QTSQL
FORCE_LINK_GSI_QTSVG
FORCE_LINK_GSI_QTUITOOLS
#else
# define QT_EXTERNAL_BASE(x)

View File

@ -5,6 +5,7 @@ include($$PWD/../../klayout.pri)
TARGET = klayout
include($$PWD/../../klayout.pri)
include($$PWD/../../app.pri)
include($$PWD/../../with_all_libs.pri)
@ -25,8 +26,42 @@ INCLUDEPATH += $$QTBASIC_INC
DEPENDPATH += $$QTBASIC_INC
equals(HAVE_QTBINDINGS, "1") {
LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtNetwork -lklayout_QtSql -lklayout_QtDesigner
equals(HAVE_QT5, "1") {
LIBS += -lklayout_QtMultimedia -lklayout_QtPrintSupport -lklayout_QtSvg -lklayout_QtWidgets -lklayout_QtXmlPatterns
LIBS += -lklayout_qtbasic -lklayout_QtGui
!equals(HAVE_QT_XML, "0") {
LIBS += -lklayout_QtXml
}
!equals(HAVE_QT_NETWORK, "0") {
LIBS += -lklayout_QtNetwork
}
!equals(HAVE_QT_SQL, "0") {
LIBS += -lklayout_QtSql
}
!equals(HAVE_QT_DESIGNER, "0") {
LIBS += -lklayout_QtDesigner
}
!equals(HAVE_QT_UITOOLS, "0") {
LIBS += -lklayout_QtUiTools
}
equals(HAVE_QT5, "1") {
LIBS += -lklayout_QtWidgets
!equals(HAVE_QT_MULTIMEDIA, "0") {
LIBS += -lklayout_QtMultimedia
}
!equals(HAVE_QT_PRINTSUPPORT, "0") {
LIBS += -lklayout_QtPrintSupport
}
!equals(HAVE_QT_SVG, "0") {
LIBS += -lklayout_QtSvg
}
!equals(HAVE_QT_XML, "0") {
LIBS += -lklayout_QtXmlPatterns
}
}
}

View File

@ -1383,63 +1383,6 @@ p, li { white-space: pre-wrap; }
</widget>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_5">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Close</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
<action name="actionNewFolder">
<property name="icon">
@ -1596,22 +1539,5 @@ p, li { white-space: pre-wrap; }
<resources>
<include location="layResources.qrc"/>
</resources>
<connections>
<connection>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>MacroEditorDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>905</x>
<y>694</y>
</hint>
<hint type="destinationlabel">
<x>929</x>
<y>696</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

View File

@ -30,6 +30,7 @@
<li>QtSql: database support</li>
<li>QtNetwork: various network protocols and supporting classes</li>
<li>QtDesigner: dynamically load designer files (.ui)</li>
<li>QtUiTools: dynamically load designer files (.ui)</li>
<li>QtMultimedia (Qt5): multimedia support</li>
<li>QtPrintSupport (Qt5): print support</li>
<li>QtSvg (Qt5): SVG implementation</li>

View File

@ -97,7 +97,7 @@ Class<lay::HelpDialog> decl_HelpDialog (QT_EXTERNAL_BASE (QDialog) "lay", "HelpD
LAYBASIC_PUBLIC Class<lay::BrowserSource> &laybasicdecl_BrowserSource ();
Class<lay::HelpSource> decl_HelpSource (laybasicdecl_BrowserSource (), "lay", "HelpSource",
#if defined(HAVE_QTBINDINGS)
#if defined(HAVE_QTBINDINGS) && defined(HAVE_QT_XML)
gsi::method ("get_dom", &lay::HelpSource::get_dom, "@brief For internal use") +
#endif
gsi::method ("urls", &lay::HelpSource::urls, "@brief Reserved for internal use") +

View File

@ -203,7 +203,10 @@ INCLUDEPATH += $$QTBASIC_INC
DEPENDPATH += $$QTBASIC_INC
equals(HAVE_QTBINDINGS, "1") {
LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtXml -lklayout_QtCore
LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtCore
!equals(HAVE_QT_XML, "0") {
LIBS += -lklayout_QtXml
}
equals(HAVE_QT5, "1") {
LIBS += -lklayout_QtWidgets
}

View File

@ -200,11 +200,33 @@ LogFile::timeout ()
}
}
void
LogFile::set_max_entries (size_t n)
{
QMutexLocker locker (&m_lock);
m_max_entries = n;
while (m_messages.size () > m_max_entries) {
m_messages.pop_front ();
}
}
size_t
LogFile::max_entries () const
{
return m_max_entries;
}
void
LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued)
{
QMutexLocker locker (&m_lock);
if (m_max_entries == 0) {
return;
}
if (m_messages.size () >= m_max_entries) {
m_messages.pop_front ();
}

View File

@ -192,6 +192,18 @@ public slots:
return m_log_receiver;
}
/**
* @brief Sets the maximum number of entries to show
*
* Setting this value to 0 basically disables the log collection
*/
void set_max_entries (size_t n);
/**
* @brief Gets the maximum number of entries to show
*/
size_t max_entries () const;
private slots:
void timeout ();

View File

@ -244,6 +244,7 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
m_highlighters (this),
m_in_exec (false),
m_in_breakpoint (false),
m_ignore_exec_events (false),
mp_exec_controller (0),
mp_current_interpreter (0),
m_continue (false),
@ -355,8 +356,8 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
QMenu *m = new QMenu (searchEditBox);
m->addAction (actionUseRegularExpressions);
m->addAction (actionCaseSensitive);
connect (actionUseRegularExpressions, SIGNAL (triggered ()), this, SLOT (apply_search ()));
connect (actionCaseSensitive, SIGNAL (triggered ()), this, SLOT (apply_search ()));
connect (actionUseRegularExpressions, SIGNAL (triggered ()), this, SLOT (search_editing ()));
connect (actionCaseSensitive, SIGNAL (triggered ()), this, SLOT (search_editing ()));
addAction (actionSearchReplace);
connect (actionSearchReplace, SIGNAL (triggered ()), this, SLOT (search_replace ()));
@ -364,7 +365,11 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
searchEditBox->set_clear_button_enabled (true);
searchEditBox->set_options_button_enabled (true);
searchEditBox->set_options_menu (m);
searchEditBox->set_escape_signal_enabled (true);
searchEditBox->set_tab_signal_enabled (true);
replaceText->set_clear_button_enabled (true);
replaceText->set_escape_signal_enabled (true);
replaceText->set_tab_signal_enabled (true);
#if QT_VERSION >= 0x40700
searchEditBox->setPlaceholderText (tr ("Find text ..."));
replaceText->setPlaceholderText (tr ("Replace text ..."));
@ -382,8 +387,6 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
tabWidget->setMovable (true);
tabWidget->setTabsClosable (true);
connect (tabWidget, SIGNAL (tabCloseRequested (int)), this, SLOT (tab_close_requested (int)));
closeButton->hide ();
closeButtonSeparator->hide ();
#endif
dbgOn->setEnabled (true);
@ -411,7 +414,6 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
connect (helpButton, SIGNAL (clicked ()), this, SLOT (help_button_clicked ()));
connect (addButton, SIGNAL (clicked ()), this, SLOT (add_button_clicked ()));
connect (actionAddMacro, SIGNAL (triggered ()), this, SLOT (add_button_clicked ()));
connect (closeButton, SIGNAL (clicked ()), this, SLOT (close_button_clicked ()));
connect (deleteButton, SIGNAL (clicked ()), this, SLOT (delete_button_clicked ()));
connect (actionDelete, SIGNAL (triggered ()), this, SLOT (delete_button_clicked ()));
connect (renameButton, SIGNAL (clicked ()), this, SLOT (rename_button_clicked ()));
@ -438,9 +440,16 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
connect (callStack, SIGNAL (itemDoubleClicked (QListWidgetItem *)), this, SLOT (stack_element_double_clicked (QListWidgetItem *)));
connect (singleStepButton, SIGNAL (clicked ()), this, SLOT (single_step_button_clicked ()));
connect (nextStepButton, SIGNAL (clicked ()), this, SLOT (next_step_button_clicked ()));
connect (searchEditBox, SIGNAL (textEdited (const QString &)), this, SLOT (search_editing ()));
connect (searchEditBox, SIGNAL (returnPressed ()), this, SLOT (search_edited ()));
connect (searchEditBox, SIGNAL (editingFinished ()), this, SLOT (search_edited ()));
connect (searchEditBox, SIGNAL (textEdited (QString)), this, SLOT (apply_search ()));
connect (searchEditBox, SIGNAL (esc_pressed ()), this, SLOT (search_finished ()));
connect (searchEditBox, SIGNAL (tab_pressed ()), this, SLOT (find_next_button_clicked ()));
connect (searchEditBox, SIGNAL (backtab_pressed ()), this, SLOT (find_prev_button_clicked ()));
connect (replaceText, SIGNAL (esc_pressed ()), this, SLOT (search_finished ()));
connect (replaceText, SIGNAL (tab_pressed ()), this, SLOT (find_next_button_clicked ()));
connect (replaceText, SIGNAL (backtab_pressed ()), this, SLOT (find_prev_button_clicked ()));
connect (replaceText, SIGNAL (returnPressed ()), this, SLOT (replace_next_button_clicked ()));
connect (replaceModeButton, SIGNAL (clicked ()), this, SLOT (replace_mode_button_clicked ()));
connect (replaceNextButton, SIGNAL (clicked ()), this, SLOT (replace_next_button_clicked ()));
connect (findNextButton, SIGNAL (clicked ()), this, SLOT (find_next_button_clicked ()));
@ -946,15 +955,13 @@ MacroEditorDialog::showEvent (QShowEvent *)
void
MacroEditorDialog::reject ()
{
closeEvent (0);
QDialog::reject ();
// .. ignore Esc ..
}
void
MacroEditorDialog::accept ()
{
closeEvent (0);
QDialog::accept ();
// .. ignore Enter ..
}
void
@ -1105,12 +1112,6 @@ MacroEditorDialog::can_exit ()
return true;
}
void
MacroEditorDialog::search_replace ()
{
searchEditBox->setFocus (Qt::TabFocusReason);
}
void
MacroEditorDialog::add_edit_trace (bool compress)
{
@ -1882,6 +1883,18 @@ BEGIN_PROTECTED
END_PROTECTED
}
void
MacroEditorDialog::set_editor_focus ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
lay::SignalBlocker signal_blocker (searchEditBox);
page->set_editor_focus ();
}
void
MacroEditorDialog::replace_mode_button_clicked ()
{
@ -1905,10 +1918,27 @@ MacroEditorDialog::find_next_button_clicked ()
apply_search (true);
page->find_next ();
page->set_editor_focus ();
if (sender () != searchEditBox && sender () != replaceText) {
set_editor_focus ();
}
}
void
void
MacroEditorDialog::find_prev_button_clicked ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
apply_search (true);
page->find_prev ();
if (sender () != searchEditBox && sender () != replaceText) {
set_editor_focus ();
}
}
void
MacroEditorDialog::replace_next_button_clicked ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
@ -1918,10 +1948,12 @@ MacroEditorDialog::replace_next_button_clicked ()
apply_search (true);
page->replace_and_find_next (replaceText->text ());
page->set_editor_focus ();
if (sender () != replaceText) {
set_editor_focus ();
}
}
void
void
MacroEditorDialog::replace_all_button_clicked ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
@ -1931,7 +1963,34 @@ MacroEditorDialog::replace_all_button_clicked ()
apply_search (true);
page->replace_all (replaceText->text ());
page->set_editor_focus ();
set_editor_focus ();
}
void
MacroEditorDialog::search_requested (const QString &s)
{
searchEditBox->setText (s);
searchEditBox->setFocus ();
search_editing ();
}
void
MacroEditorDialog::search_replace ()
{
searchEditBox->setFocus (Qt::TabFocusReason);
}
void
MacroEditorDialog::search_editing ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
apply_search ();
page->find_reset (); // search from the initial position
page->find_next ();
}
void
@ -1942,6 +2001,18 @@ MacroEditorDialog::search_edited ()
md_search_edited ();
}
void
MacroEditorDialog::search_finished ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
page->find_reset (); // search from the initial position
set_editor_focus ();
}
void
MacroEditorDialog::do_search_edited ()
{
@ -1951,8 +2022,9 @@ MacroEditorDialog::do_search_edited ()
}
apply_search ();
page->find_reset (); // search from the initial position
page->find_next ();
page->set_editor_focus ();
set_editor_focus ();
}
void
@ -1963,7 +2035,7 @@ MacroEditorDialog::apply_search (bool if_needed)
return;
}
if (searchEditBox->text ().size () > 0) {
if (! searchEditBox->text ().isEmpty ()) {
QRegExp re (searchEditBox->text (),
actionCaseSensitive->isChecked () ? Qt::CaseSensitive : Qt::CaseInsensitive,
actionUseRegularExpressions->isChecked () ? QRegExp::RegExp : QRegExp::FixedString);
@ -2080,7 +2152,7 @@ BEGIN_PROTECTED
END_PROTECTED
}
void
void
MacroEditorDialog::help_requested(const QString &s)
{
lay::MainWindow::instance ()->show_assistant_topic (tl::to_string (s));
@ -2779,54 +2851,77 @@ MacroEditorDialog::start_exec (gsi::Interpreter *ec)
if (m_in_exec) {
tl_assert (ec != mp_exec_controller);
return;
} else if (m_ignore_exec_events) {
return;
}
m_file_to_widget.clear ();
m_include_expanders.clear ();
m_include_paths_to_ids.clear ();
m_include_file_id_cache.clear ();
// prevents recursion
m_ignore_exec_events = true;
m_last_process_events = tl::Clock::current ();
try {
m_in_exec = true;
mp_exec_controller = ec;
m_in_breakpoint = false;
m_continue = true;
m_trace_count = 0;
m_current_stack_depth = -1;
m_process_events_interval = 0.05;
m_file_to_widget.clear ();
m_include_expanders.clear ();
m_include_paths_to_ids.clear ();
m_include_file_id_cache.clear ();
for (std::map<lym::Macro *, MacroEditorPage *>::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) {
f->second->exec_model ()->set_current_line (-1);
f->second->exec_model ()->set_run_mode (true);
m_last_process_events = tl::Clock::current ();
m_in_exec = true;
mp_exec_controller = ec;
m_in_breakpoint = false;
m_continue = true;
m_trace_count = 0;
m_current_stack_depth = -1;
m_process_events_interval = 0.05;
for (std::map<lym::Macro *, MacroEditorPage *>::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) {
f->second->exec_model ()->set_current_line (-1);
f->second->exec_model ()->set_run_mode (true);
}
do_update_ui_to_run_mode ();
} catch (...) {
// .. ignore exceptions here ..
}
do_update_ui_to_run_mode ();
m_ignore_exec_events = false;
}
void
MacroEditorDialog::end_exec (gsi::Interpreter *ec)
{
// ignore calls from other interpreters
if (m_in_exec && ec != mp_exec_controller) {
if ((m_in_exec && ec != mp_exec_controller) || m_ignore_exec_events) {
return;
}
if (QApplication::activeModalWidget () == this) {
// close this window if it was shown in modal mode
QDialog::accept ();
// prevents recursion
m_ignore_exec_events = true;
try {
m_in_exec = false;
mp_exec_controller = 0;
m_continue = false;
m_current_stack_depth = -1;
if (QApplication::activeModalWidget () == this) {
// close this window if it was shown in modal mode
QDialog::accept ();
}
for (std::map<lym::Macro *, MacroEditorPage *>::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) {
f->second->exec_model ()->set_run_mode (false);
}
do_update_ui_to_run_mode ();
} catch (...) {
// .. ignore exceptions here ..
}
m_in_exec = false;
mp_exec_controller = 0;
m_continue = false;
m_current_stack_depth = -1;
for (std::map<lym::Macro *, MacroEditorPage *>::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) {
f->second->exec_model ()->set_run_mode (false);
}
do_update_ui_to_run_mode ();
m_ignore_exec_events = false;
}
const size_t pseudo_file_offset = std::numeric_limits<size_t>::max () / 2;
@ -3172,7 +3267,6 @@ MacroEditorDialog::do_update_ui_to_run_mode ()
addButton->setEnabled (! m_in_exec);
actionAddMacro->setEnabled (! m_in_exec);
closeButton->setEnabled (! m_in_exec);
deleteButton->setEnabled (! m_in_exec);
actionDelete->setEnabled (! m_in_exec);
renameButton->setEnabled (! m_in_exec);
@ -3270,6 +3364,7 @@ MacroEditorDialog::create_page (lym::Macro *macro)
editor->exec_model ()->set_run_mode (m_in_exec);
editor->connect_macro (macro);
connect (editor.get (), SIGNAL (help_requested (const QString &)), this, SLOT (help_requested (const QString &)));
connect (editor.get (), SIGNAL (search_requested (const QString &)), this, SLOT (search_requested (const QString &)));
connect (editor.get (), SIGNAL (edit_trace (bool)), this, SLOT (add_edit_trace (bool)));
return editor.release ();
}

View File

@ -209,12 +209,16 @@ private slots:
void commit ();
void stack_element_double_clicked (QListWidgetItem *item);
void search_edited ();
void search_editing ();
void search_finished ();
void tab_close_requested (int);
void replace_mode_button_clicked ();
void replace_next_button_clicked ();
void replace_all_button_clicked ();
void find_next_button_clicked ();
void find_prev_button_clicked ();
void help_requested (const QString &s);
void search_requested (const QString &s);
void macro_changed (lym::Macro *macro);
void macro_deleted (lym::Macro *macro);
void macro_collection_deleted (lym::MacroCollection *collection);
@ -288,6 +292,7 @@ private:
void update_watches ();
lym::Macro *new_macro ();
void do_search_edited ();
void set_editor_focus ();
void select_trace (size_t index);
bool configure (const std::string &name, const std::string &value);
void config_finalize ();
@ -318,7 +323,7 @@ private:
std::map<std::string, size_t> m_include_paths_to_ids;
std::map<std::pair<size_t, int>, std::pair<size_t, int> > m_include_file_id_cache;
std::vector<lay::MacroEditorTree *> m_macro_trees;
bool m_in_exec, m_in_breakpoint;
bool m_in_exec, m_in_breakpoint, m_ignore_exec_events;
gsi::Interpreter *mp_exec_controller, *mp_current_interpreter;
bool m_continue;
int m_trace_count;

View File

@ -25,6 +25,7 @@
#include "lymMacroInterpreter.h"
#include "tlExceptions.h"
#include "tlString.h"
#include "layQtTools.h"
#include <cstdio>
#include <iostream>
@ -42,6 +43,9 @@
#include <QChar>
#include <QResource>
#include <QBuffer>
#include <QTimer>
#include <QListWidget>
#include <QApplication>
namespace lay
{
@ -475,7 +479,7 @@ void MacroEditorSidePanel::paintEvent (QPaintEvent *)
// MacroEditorPage implementation
MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters *highlighters)
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2)
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2), m_ignore_cursor_changed_event (false)
{
QVBoxLayout *layout = new QVBoxLayout (this);
@ -499,11 +503,26 @@ MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters
connect (mp_text, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
connect (mp_text, SIGNAL (cursorPositionChanged ()), this, SLOT (cursor_position_changed ()));
connect (mp_text->horizontalScrollBar (), SIGNAL (valueChanged (int)), this, SLOT (hide_completer ()));
connect (mp_text->verticalScrollBar (), SIGNAL (valueChanged (int)), this, SLOT (hide_completer ()));
connect (mp_exec_model, SIGNAL (breakpoints_changed ()), this, SLOT (breakpoints_changed ()));
connect (mp_exec_model, SIGNAL (current_line_changed ()), this, SLOT (current_line_changed ()));
connect (mp_exec_model, SIGNAL (run_mode_changed ()), this, SLOT (run_mode_changed ()));
mp_text->installEventFilter (this);
mp_completer_popup = new QWidget (window (), Qt::ToolTip);
mp_completer_popup->setWindowModality (Qt::NonModal);
QHBoxLayout *ly = new QHBoxLayout (mp_completer_popup);
ly->setMargin (0);
mp_completer_list = new QListWidget (mp_completer_popup);
ly->addWidget (mp_completer_list);
mp_completer_popup->hide ();
mp_completer_timer = new QTimer (this);
mp_completer_timer->setInterval (1000);
mp_completer_timer->setSingleShot (true);
connect (mp_completer_timer, SIGNAL (timeout ()), this, SLOT (completer_timer ()));
}
void MacroEditorPage::update ()
@ -566,12 +585,23 @@ void MacroEditorPage::current_line_changed ()
void MacroEditorPage::run_mode_changed ()
{
if (mp_exec_model->run_mode ()) {
set_error_line (0);
// this prevents recursion when the following lines trigger anything that routes through the interpreter
bool bl = mp_exec_model->blockSignals (true);
try {
if (mp_exec_model->run_mode ()) {
set_error_line (0);
}
mp_text->setReadOnly (! mp_macro || mp_macro->is_readonly () || mp_exec_model->run_mode ());
update_extra_selections ();
} catch (...) {
// .. ignore exceptions here ..
}
mp_text->setReadOnly (! mp_macro || mp_macro->is_readonly () || mp_exec_model->run_mode ());
update_extra_selections ();
mp_exec_model->blockSignals (bl);
}
void MacroEditorPage::breakpoints_changed ()
@ -598,9 +628,110 @@ static bool valid_element (const SyntaxHighlighterElement &e)
return e.basic_attribute_id != lay::dsComment && e.basic_attribute_id != lay::dsString;
}
void MacroEditorPage::complete ()
{
QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () != c.selectionEnd ()) {
return;
}
c.select (QTextCursor::WordUnderCursor);
if (mp_completer_list->currentItem ()) {
QString s = mp_completer_list->currentItem ()->text ();
c.insertText (s);
}
}
void MacroEditorPage::fill_completer_list ()
{
QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () != c.selectionEnd ()) {
return;
}
int pos = c.anchor ();
c.select (QTextCursor::WordUnderCursor);
int pos0 = c.selectionStart ();
if (pos0 >= pos) {
return;
}
QString ssel = c.selectedText ();
QString s = ssel.mid (0, pos - pos0);
QString text = mp_text->toPlainText ();
std::set<QString> words;
int i = 0;
while (i >= 0) {
i = text.indexOf (s, i);
if (i >= 0) {
QString::iterator c = text.begin () + i;
QString w;
while (c->isLetterOrNumber () || c->toLatin1 () == '_') {
w += *c;
++c;
}
if (! w.isEmpty () && w != s && w != ssel) {
words.insert (w);
}
++i;
}
}
for (std::set<QString>::const_iterator w = words.begin (); w != words.end (); ++w) {
mp_completer_list->addItem (*w);
}
}
void MacroEditorPage::completer_timer ()
{
if (! mp_text->hasFocus ()) {
return;
}
mp_completer_list->clear ();
fill_completer_list ();
if (mp_completer_list->count () > 0) {
mp_completer_list->setCurrentRow (0);
QTextCursor c = mp_text->textCursor ();
c.clearSelection ();
QRect r = mp_text->cursorRect (c);
QPoint pos = mp_text->mapToGlobal (r.bottomLeft ());
QSize sz = mp_completer_list->sizeHint ();
QFontMetrics fm (mp_completer_list->font ());
mp_completer_popup->setGeometry (pos.x (), pos.y () + r.height () / 3, sz.width (), 4 + 4 * fm.height () /*sz.height ()*/);
mp_completer_popup->show ();
mp_text->setFocus ();
} else {
mp_completer_popup->hide ();
}
}
void MacroEditorPage::hide_completer ()
{
mp_completer_popup->hide ();
}
void MacroEditorPage::cursor_position_changed ()
{
if (m_ignore_cursor_changed_event) {
return;
}
mp_completer_popup->hide ();
mp_completer_timer->stop ();
mp_completer_timer->start ();
QTextCursor cursor = mp_text->textCursor ();
m_edit_cursor = cursor;
// prepare a format for the bracket highlights
QTextCharFormat fmt;
@ -861,11 +992,23 @@ void MacroEditorPage::connect_macro (lym::Macro *macro)
}
}
void
MacroEditorPage::find_reset ()
{
m_ignore_cursor_changed_event = true;
mp_text->setTextCursor (m_edit_cursor);
m_ignore_cursor_changed_event = false;
}
bool
MacroEditorPage::find_prev ()
{
update_extra_selections ();
if (m_current_search == QRegExp ()) {
return false;
}
QTextCursor c = mp_text->textCursor ();
bool first = true;
@ -891,7 +1034,9 @@ MacroEditorPage::find_prev ()
QTextCursor newc (b);
newc.setPosition (i + b.position () + l);
newc.setPosition (i + b.position (), QTextCursor::KeepAnchor);
m_ignore_cursor_changed_event = true;
mp_text->setTextCursor (newc);
m_ignore_cursor_changed_event = false;
return true;
}
@ -913,6 +1058,10 @@ MacroEditorPage::find_next ()
{
update_extra_selections ();
if (m_current_search == QRegExp ()) {
return false;
}
QTextCursor c = mp_text->textCursor ();
bool first = true;
@ -926,7 +1075,9 @@ MacroEditorPage::find_next ()
QTextCursor newc (b);
newc.setPosition (i + b.position () + m_current_search.matchedLength ());
newc.setPosition (i + b.position (), QTextCursor::KeepAnchor);
m_ignore_cursor_changed_event = true;
mp_text->setTextCursor (newc);
m_ignore_cursor_changed_event = false;
emit edit_trace (false);
return true;
}
@ -1152,263 +1303,391 @@ MacroEditorPage::current_pos () const
return mp_text->textCursor ().position () - mp_text->textCursor ().block ().position ();
}
bool
MacroEditorPage::tab_key_pressed ()
{
if (mp_text->isReadOnly ()) {
return false;
}
QTextBlock bs, be;
bool adjust_end = false;
bool indent = false;
if (mp_text->textCursor ().hasSelection ()) {
bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
if (be != bs) {
indent = true;
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
}
if (indent) {
// tab out
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
bool has_tabs = false;
int p = 0;
int i = 0;
for (; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
has_tabs = true;
} else {
break;
}
}
if (has_tabs) {
for ( ; i > 0; --i) {
c.deleteChar ();
}
c.insertText (QString (m_nindent + p, QChar::fromLatin1 (' ')));
} else {
c.insertText (QString (m_nindent, QChar::fromLatin1 (' ')));
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
} else {
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
int p = 0;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else {
++p;
}
}
c.insertText (QString (m_nindent - p % m_nindent, QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
}
return true;
}
bool
MacroEditorPage::back_tab_key_pressed ()
{
if (!mp_text->textCursor ().hasSelection () || mp_text->isReadOnly ()) {
return false;
}
// tab in
QTextBlock bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
QTextBlock be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
bool adjust_end = false;
if (be != bs) {
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
int n = m_nindent;
int p = 0;
for (int i = 0; i < text.length () && n > 0; ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
--n;
c.deleteChar ();
} else if (text [i] == QChar::fromLatin1 ('\t')) {
c.deleteChar ();
int pp = p;
p = (p - p % m_ntab) + m_ntab;
if (p - pp >= n) {
if (p - pp > n) {
c.insertText (QString (p - pp - n, QChar::fromLatin1 (' ')));
}
n = 0;
} else {
n -= p - pp;
}
} else {
break;
}
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
return true;
}
bool
MacroEditorPage::backspace_pressed ()
{
if (mp_text->textCursor ().hasSelection () || mp_text->isReadOnly()) {
return false;
}
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
if (col > 0) {
int p = 0;
bool only_space_before = true;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else {
only_space_before = false;
}
}
if (only_space_before) {
for (int i = 0; i < col; ++i) {
c.deletePreviousChar ();
}
c.insertText (QString (std::max (0, ((p - 1) / m_nindent) * m_nindent), QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
return true;
}
}
return false;
}
bool
MacroEditorPage::return_pressed ()
{
if (mp_text->isReadOnly ()) {
return false;
}
// Implement auto-indent on return
QTextCursor c = mp_text->textCursor ();
QTextBlock b = c.block ();
c.insertBlock ();
QString l;
if (b.isValid ()) {
QString text = b.text ();
for (int i = 0; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 ('\t') || text [i] == QChar::fromLatin1 (' ')) {
l += text [i];
} else {
break;
}
}
}
c.insertText (l);
mp_text->setTextCursor (c);
return true;
}
static bool is_tab_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0;
}
static bool is_backtab_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0);
}
static bool is_backspace_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Backspace;
}
static bool is_escape_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Escape;
}
static bool is_return_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Return;
}
static bool is_help_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_F1;
}
static bool is_find_next_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_F3;
}
static bool is_find_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0;
}
static bool is_up_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Up;
}
static bool is_down_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Down;
}
static bool is_any_known_key (QKeyEvent *ke)
{
return is_tab_key (ke) ||
is_backtab_key (ke) ||
is_backspace_key (ke) ||
is_escape_key (ke) ||
is_return_key (ke) ||
is_help_key (ke) ||
is_find_next_key (ke) ||
is_find_key (ke) ||
is_up_key (ke) ||
is_down_key (ke);
}
bool
MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
{
if (watched == mp_text) {
if (event->type () == QEvent::KeyPress) {
if (event->type () == QEvent::ShortcutOverride) {
// override shortcuts if the collide with keys we accept ourselves
QKeyEvent *ke = dynamic_cast<QKeyEvent *> (event);
if (! ke) {
return false; // should not happen
}
if (is_any_known_key (ke)) {
event->accept ();
return true;
}
} else if (event->type () == QEvent::FocusOut) {
hide_completer ();
return true;
} else if (event->type () == QEvent::KeyPress) {
m_error_line = -1;
mp_text->setExtraSelections (QList<QTextEdit::ExtraSelection> ());
QKeyEvent *ke = dynamic_cast<QKeyEvent *> (event);
if (ke && ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) {
if (! ke) {
return false; // should not happen
}
if (!mp_text->isReadOnly ()) {
QTextBlock bs, be;
bool adjust_end = false;
bool indent = false;
if (mp_text->textCursor ().hasSelection ()) {
bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
if (be != bs) {
indent = true;
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
}
if (indent) {
// tab out
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
bool has_tabs = false;
int p = 0;
int i = 0;
for (; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
has_tabs = true;
} else {
break;
}
}
if (has_tabs) {
for ( ; i > 0; --i) {
c.deleteChar ();
}
c.insertText (QString (m_nindent + p, QChar::fromLatin1 (' ')));
} else {
c.insertText (QString (m_nindent, QChar::fromLatin1 (' ')));
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
} else {
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
int p = 0;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else {
++p;
}
}
c.insertText (QString (m_nindent - p % m_nindent, QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
}
}
return true;
} else if (ke && (ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) {
if (mp_text->textCursor ().hasSelection () && !mp_text->isReadOnly ()) {
// tab in
QTextBlock bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
QTextBlock be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
bool adjust_end = false;
if (be != bs) {
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
int n = m_nindent;
int p = 0;
for (int i = 0; i < text.length () && n > 0; ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
--n;
c.deleteChar ();
} else if (text [i] == QChar::fromLatin1 ('\t')) {
c.deleteChar ();
int pp = p;
p = (p - p % m_ntab) + m_ntab;
if (p - pp >= n) {
if (p - pp > n) {
c.insertText (QString (p - pp - n, QChar::fromLatin1 (' ')));
}
n = 0;
} else {
n -= p - pp;
}
} else {
break;
}
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
}
return true;
} else if (ke && ke->key () == Qt::Key_Backspace) {
if (!mp_text->textCursor ().hasSelection () && !mp_text->isReadOnly()) {
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
if (col > 0) {
int p = 0;
bool only_space_before = true;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else {
only_space_before = false;
}
}
if (only_space_before) {
for (int i = 0; i < col; ++i) {
c.deletePreviousChar ();
}
c.insertText (QString (std::max (0, ((p - 1) / m_nindent) * m_nindent), QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
return true;
}
}
}
} else if (ke && ke->key () == Qt::Key_Escape) {
// Handle Esc to clear the selection
QTextCursor c = mp_text->textCursor ();
c.clearSelection ();
mp_text->setTextCursor (c);
return true;
} else if (ke && ke->key () == Qt::Key_Return) {
if (!mp_text->isReadOnly ()) {
// Implement auto-indent on return
QTextCursor c = mp_text->textCursor ();
QTextBlock b = c.block ();
c.insertBlock ();
QString l;
if (b.isValid ()) {
QString text = b.text ();
for (int i = 0; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 ('\t') || text [i] == QChar::fromLatin1 (' ')) {
l += text [i];
} else {
break;
}
}
}
c.insertText (l);
mp_text->setTextCursor (c);
if (is_tab_key (ke)) {
if (mp_completer_popup->isVisible ()) {
complete ();
return true;
} else {
return tab_key_pressed ();
}
} else if (ke && ke->key () == Qt::Key_F1) {
} else if (is_backtab_key (ke)) {
return back_tab_key_pressed ();
} else if (is_backspace_key (ke)) {
return backspace_pressed ();
} else if (is_escape_key (ke)) {
// Handle Esc to return to the before-find position and clear the selection or to hide popup
if (mp_completer_popup->isVisible ()) {
mp_completer_popup->hide ();
} else {
find_reset ();
QTextCursor c = mp_text->textCursor ();
c.clearSelection ();
mp_text->setTextCursor (c);
}
return true;
} else if (is_return_key (ke)) {
if (mp_completer_popup->isVisible ()) {
complete ();
return true;
} else {
return return_pressed ();
}
} else if (is_help_key (ke)) {
QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () == c.selectionEnd ()) {
@ -1418,7 +1697,19 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return true;
} else if (ke && ke->key () == Qt::Key_F3) {
} else if (mp_completer_popup->isVisible () && (is_up_key (ke) || is_down_key (ke))) {
QApplication::sendEvent (mp_completer_list, event);
return true;
} else if (is_find_key (ke)) {
QTextCursor c = mp_text->textCursor ();
emit search_requested (c.selectedText ());
return true;
} else if (is_find_next_key (ke)) {
// Jump to the next occurence of the search string

View File

@ -45,6 +45,9 @@ typedef QTextEdit TextEditWidget;
class QLabel;
class QSyntaxHighlighter;
class QTimer;
class QWindow;
class QListWidget;
namespace lay
{
@ -254,8 +257,8 @@ public:
return m_current_search;
}
void find_reset ();
bool find_next ();
bool find_prev ();
void replace_and_find_next (const QString &replace);
@ -268,6 +271,7 @@ public:
signals:
void help_requested (const QString &s);
void search_requested (const QString &s);
void edit_trace (bool);
public slots:
@ -280,6 +284,8 @@ protected slots:
void breakpoints_changed ();
void current_line_changed ();
void run_mode_changed ();
void completer_timer ();
void hide_completer ();
private:
lym::Macro *mp_macro;
@ -294,8 +300,20 @@ private:
int m_ntab, m_nindent;
std::set<QTextBlock> m_breakpoints;
QRegExp m_current_search;
QTextCursor m_edit_cursor;
bool m_ignore_cursor_changed_event;
QTimer *mp_completer_timer;
QWidget *mp_completer_popup;
QListWidget *mp_completer_list;
void update_extra_selections ();
bool return_pressed ();
bool backspace_pressed ();
bool back_tab_key_pressed ();
bool tab_key_pressed ();
void fill_completer_list ();
void complete ();
bool eventFilter (QObject *watched, QEvent *event);
};

View File

@ -50,6 +50,7 @@
#include "tlAssert.h"
#include "tlStream.h"
#include "tlExceptions.h"
#include "tlExpression.h"
#include "dbMemStatistics.h"
#include "dbManager.h"
#include "dbStream.h"
@ -1773,13 +1774,17 @@ MainWindow::cm_goto_position ()
double x = 0.0, y = 0.0, s = 0.0;
std::string tt (tl::to_string (text));
tl::Extractor ex (tt.c_str ());
ex >> x >> "," >> y;
x = tl::Eval ().parse (ex).execute ().to_double ();
ex.test (",");
y = tl::Eval ().parse (ex).execute ().to_double ();
db::DPoint pt (x, y);
if (! ex.at_end ()) {
ex >> "," >> s >> tl::Extractor::end ();
ex.test (",");
s = tl::Eval ().parse (ex).execute ().to_double ();
current_view ()->goto_window (pt, s);
} else {
current_view ()->goto_window (pt);
@ -2520,21 +2525,30 @@ MainWindow::cm_new_layout ()
std::string technology = m_initial_technology;
static std::string s_new_cell_cell_name ("TOP");
static double s_new_cell_window_size = 2.0;
static std::vector<db::LayerProperties> s_layers;
double dbu = 0.0;
lay::NewLayoutPropertiesDialog dialog (this);
if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, m_new_layout_current_panel)) {
if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, s_layers, m_new_layout_current_panel)) {
lay::CellViewRef cellview = create_or_load_layout (0, 0, technology, m_new_layout_current_panel ? 2 : 1 /*= new view*/);
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (& manager ()), std::string ()));
handle->rename ("new");
if (dbu > 1e-10) {
cellview->layout ().dbu (dbu);
handle->layout ().dbu (dbu);
}
db::cell_index_type new_ci = cellview->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ());
cellview.set_cell (new_ci);
db::cell_index_type new_ci = handle->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ());
current_view ()->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1));
for (std::vector<db::LayerProperties>::const_iterator l = s_layers.begin (); l != s_layers.end (); ++l) {
handle->layout ().insert_layer (*l);
}
lay::LayoutView *mp_view = (m_new_layout_current_panel && current_view ()) ? current_view () : view (create_view ());
unsigned int ci = mp_view->add_layout (handle.release (), true);
mp_view->cellview_ref (ci).set_cell (new_ci);
mp_view->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1));
}
}

View File

@ -86,14 +86,13 @@ ProgressReporter::set_progress_bar (lay::ProgressBar *pb)
void
ProgressReporter::register_object (tl::Progress *progress)
{
if (mp_objects.empty ()) {
if (begin () == end ()) {
// to avoid recursions of any kind, disallow any user interaction except
// cancelling the operation
QApplication::instance ()->installEventFilter (this);
}
mp_objects.push_back (*progress); // this keeps the outmost one visible. push_front would make the latest one visible.
// mp_objects.push_front (progress);
tl::ProgressAdaptor::register_object (progress);
if (m_start_time == tl::Clock () && ! m_pw_visible) {
m_start_time = tl::Clock::current ();
@ -104,33 +103,47 @@ ProgressReporter::register_object (tl::Progress *progress)
set_visible (true);
}
update_and_yield ();
if (progress->is_abstract ()) {
if (mp_pb) {
mp_pb->update_progress (progress);
}
process_events ();
} else {
update_and_yield ();
}
}
void
ProgressReporter::unregister_object (tl::Progress *progress)
{
progress->unlink ();
tl::ProgressAdaptor::unregister_object (progress);
// close or refresh window
if (mp_objects.empty ()) {
if (begin () == end ()) {
if (m_pw_visible) {
set_visible (false);
}
m_start_time = tl::Clock ();
}
update_and_yield ();
if (mp_pb) {
mp_pb->update_progress (0);
}
process_events ();
if (mp_objects.empty ()) {
QApplication::instance ()->removeEventFilter (this);
} else {
update_and_yield ();
}
}
void
ProgressReporter::trigger (tl::Progress * /*progress*/)
{
if (! mp_objects.empty ()) {
if (begin () != end ()) {
// make dialog visible after some time has passed
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
set_visible (true);
@ -152,27 +165,22 @@ ProgressReporter::yield (tl::Progress * /*progress*/)
}
}
void
ProgressReporter::signal_break ()
{
for (tl::list<tl::Progress>::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) {
k->signal_break ();
}
}
void
ProgressReporter::update_and_yield ()
{
if (m_pw_visible && ! mp_objects.empty ()) {
if (mp_pb) {
mp_pb->update_progress (mp_objects.first ());
QWidget *w = mp_pb->progress_get_widget ();
if (w) {
mp_objects.first ()->render_progress (w);
}
}
process_events (); // Qt4 seems to need this
if (! m_pw_visible) {
return;
}
if (mp_pb && first ()) {
mp_pb->update_progress (first ());
QWidget *w = mp_pb->progress_get_widget ();
if (w) {
first ()->render_progress (w);
}
}
process_events (); // Qt4 seems to need this
}
void
@ -202,8 +210,8 @@ ProgressReporter::set_visible (bool vis)
if (mp_pb) {
if (!vis) {
mp_pb->progress_remove_widget ();
} else if (mp_pb->progress_wants_widget () && mp_objects.first ()) {
mp_pb->progress_add_widget (mp_objects.first ()->progress_widget ());
} else if (mp_pb->progress_wants_widget () && first ()) {
mp_pb->progress_add_widget (first ()->progress_widget ());
}
}

View File

@ -68,16 +68,9 @@ public:
virtual void yield (tl::Progress *progress);
virtual bool eventFilter (QObject *dest, QEvent *event);
void signal_break ();
void set_progress_bar (lay::ProgressBar *pb);
bool is_busy () const
{
return !mp_objects.empty ();
}
private:
tl::list<tl::Progress> mp_objects;
tl::Clock m_start_time;
lay::ProgressBar *mp_pb;
bool m_pw_visible;

View File

@ -26,6 +26,7 @@
#include <QFrame>
#include <QGridLayout>
#include <QLabel>
#include <QListView>
#include <math.h>
@ -59,7 +60,7 @@ private:
ProgressBarWidget::ProgressBarWidget (QWidget *parent, const char *name)
: QWidget (parent),
m_value (0.0), m_width (64), m_length (0), m_fw (1), m_bw (0)
m_value (0.0), m_width (200), m_length (0), m_fw (1), m_bw (0)
{
setObjectName (QString::fromUtf8 (name));
setMinimumSize (64, 10);
@ -134,13 +135,46 @@ ProgressBarWidget::resizeEvent (QResizeEvent *)
// --------------------------------------------------------------------
ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full_width)
ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
: QFrame (parent),
mp_widget (0), mp_pr (pr)
mp_widget (0), mp_pr (pr), m_log_file (0, true), m_log_visible (false)
{
QVBoxLayout *top_layout = new QVBoxLayout (this);
top_layout->addStretch (1);
mp_log_frame = new QFrame (this);
mp_log_frame->setFrameShape (QFrame::NoFrame);
mp_log_frame->hide ();
top_layout->addWidget (mp_log_frame);
QVBoxLayout *log_layout = new QVBoxLayout (mp_log_frame);
QListView *log_view = new QListView (this);
log_view->setModel (&m_log_file);
log_view->setUniformItemSizes (true);
log_layout->addWidget (log_view);
QFrame *attn_frame = new QFrame (this);
attn_frame->setFrameShape (QFrame::NoFrame);
attn_frame->hide ();
log_layout->addWidget (attn_frame);
QHBoxLayout *attn_layout = new QHBoxLayout (attn_frame);
attn_layout->setContentsMargins (0, 0, 0, 0);
QLabel *attn_label1 = new QLabel (attn_frame);
attn_label1->setPixmap (QPixmap (QString::fromUtf8 (":/warn_16.png")));
attn_layout->addWidget (attn_label1);
QLabel *attn_label2 = new QLabel (attn_frame);
attn_label2->setText (tr ("There are errors or warnings"));
attn_layout->addWidget (attn_label2);
attn_layout->addStretch (1);
connect (&m_log_file, SIGNAL (layoutChanged ()), log_view, SLOT (scrollToBottom ()));
connect (&m_log_file, SIGNAL (attention_changed (bool)), attn_frame, SLOT (setVisible (bool)));
QFrame *bar_frame = new QFrame (this);
top_layout->addWidget (bar_frame);
@ -157,12 +191,11 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full
int col = 0;
if (! full_width) {
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1);
layout->setColumnStretch (col++, 1);
}
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1);
m_left_col = col++;
mp_label = new QLabel (bar_frame);
layout->setColumnStretch(col, 2);
layout->addWidget (mp_label, 0, col++, 1, 1);
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1);
@ -171,7 +204,6 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full
progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain);
progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget (progress_bar_frame, 0, col, 1, 1);
layout->setColumnStretch(col++, 2);
QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame);
progress_bar_frame->setLayout (pbf_layout);
@ -191,16 +223,41 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full
mp_cancel_button->setText (QObject::tr ("Cancel"));
layout->addWidget (mp_cancel_button, 0, col++, 1, 1);
if (! full_width) {
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1);
layout->setColumnStretch (col++, 1);
}
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1);
m_right_col = col++;
layout->addItem (new QSpacerItem (10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0, 1, col);
m_widget_col = col;
connect (mp_cancel_button, SIGNAL (clicked ()), this, SLOT (signal_break ()));
set_full_width (fw);
}
void
ProgressWidget::set_log_visible (bool f)
{
if (f != m_log_visible) {
m_log_visible = f;
mp_log_frame->setVisible (f);
set_full_width (m_full_width);
}
}
void
ProgressWidget::set_full_width (bool fw)
{
m_full_width = fw;
bool f = (fw || m_log_visible);
mp_layout->setColumnStretch (m_left_col, f ? 0 : 1);
mp_layout->setColumnStretch (m_right_col, f ? 0 : 1);
}
bool
ProgressWidget::full_width () const
{
return m_full_width;
}
QWidget *
@ -233,6 +290,13 @@ ProgressWidget::remove_widget ()
void
ProgressWidget::set_progress (tl::Progress *progress)
{
if (! progress || progress->is_abstract ()) {
m_log_file.clear ();
m_log_file.set_max_entries (progress ? 1000 : 0);
set_log_visible (progress != 0);
return;
}
bool can_cancel = false;
std::string text;

Some files were not shown because too many files have changed in this diff Show More