diff --git a/src/buddies/src/bd/strmxor.cc b/src/buddies/src/bd/strmxor.cc
index 6741f773b..6072e1e73 100644
--- a/src/buddies/src/bd/strmxor.cc
+++ b/src/buddies/src/bd/strmxor.cc
@@ -180,7 +180,8 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
<< tl::arg ("input_b", &infile_b, "The second input file (any format, may be gzip compressed)")
<< tl::arg ("?output", &output, "The output file to which the XOR differences are written",
"This argument is optional. If not given, the exit status alone will indicate whether the layouts "
- "are identical or not."
+ "are identical or not. The output is a layout file. The format of the file is derived "
+ "from the file name's suffix (.oas[.gz] for (gzipped) OASIS, .gds[.gz] for (gzipped) GDS2 etc.)."
)
<< tl::arg ("-ta|--top-a=name", &top_a, "Specifies the top cell for the first layout",
"Use this option to take a specific cell as the top cell from the first layout. All "
@@ -248,6 +249,8 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
db::Layout layout_b;
{
+ tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading file (A): ")) + infile_a);
+
db::LoadLayoutOptions load_options;
generic_reader_options_a.configure (load_options);
@@ -257,6 +260,8 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
}
{
+ tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading file (B): ")) + infile_b);
+
db::LoadLayoutOptions load_options;
generic_reader_options_b.configure (load_options);
diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc
index f778d6fe2..133b6f18a 100644
--- a/src/edt/edt/edtMainService.cc
+++ b/src/edt/edt/edtMainService.cc
@@ -2115,7 +2115,7 @@ MainService::cm_tap ()
QPoint mp = view ()->view_object_widget ()->mapToGlobal (view ()->view_object_widget ()->mouse_position ());
for (std::vector::const_iterator l = tapped_layers.begin (); l != tapped_layers.end (); ++l) {
- QAction *a = menu->addAction (lay::LayerTreeModel::icon_for_layer (*l, view (), icon_size, icon_size, 0, true), tl::to_qstring ((*l)->source (true).to_string ()));
+ QAction *a = menu->addAction (lay::LayerTreeModel::icon_for_layer (*l, view (), icon_size, icon_size, 0, true), tl::to_qstring ((*l)->display_string (view (), true, true /*with source*/)));
a->setData (int (l - tapped_layers.begin ()));
}
diff --git a/src/lay/lay/doc/manual/basic.xml b/src/lay/lay/doc/manual/basic.xml
index 92969e177..ec136b253 100644
--- a/src/lay/lay/doc/manual/basic.xml
+++ b/src/lay/lay/doc/manual/basic.xml
@@ -24,9 +24,9 @@
+
-
diff --git a/src/lay/lay/doc/manual/layer_source_expert.xml b/src/lay/lay/doc/manual/layer_source_expert.xml
index 30619a4c1..97a50d9dc 100644
--- a/src/lay/lay/doc/manual/layer_source_expert.xml
+++ b/src/lay/lay/doc/manual/layer_source_expert.xml
@@ -100,5 +100,9 @@
a selector as well, only those shapes will be shown that meet both criteria.
+
+ A general description for the source notation is found here: .
+
+
diff --git a/src/lay/lay/doc/manual/layer_views.xml b/src/lay/lay/doc/manual/layer_views.xml
new file mode 100644
index 000000000..c9c294b0c
--- /dev/null
+++ b/src/lay/lay/doc/manual/layer_views.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+ The Layer List (Layer Views)
+
+
+
+
+ An important concept in KLayout are the layer views. KLayout displays the layers
+ of a layout by default in a list on the right side of the main window.
+ This list however, does not directly reflect the layers in the layout database.
+ Instead this list is a collection of "views". A view is a description of what is
+ to be displayed and how.
+
+
+
+ Essentially, the entries in the layer list are pointers to layers in the
+ database, together with a description how to paint the shapes on these layers (the
+ "layer properties").
+
+
+
+ The pointer is the "source" of a layer view. This is typically a GDS layer and datatype,
+ but can be a layer name (for DXF for example). There are also abstract sources (such as
+ cell boundaries) and the sources can include selectors or modifiers. Selectors are
+ used to only display shapes with certain user properties or from certain hierarchy
+ levels. Modifiers transform the shapes before they are drawn for example.
+ The source is defined by a "source specification" - this is a string describing the
+ database layer and selectors and modifiers. A simple source string is "1/0" which is
+ for GDS layer 1, datatype 0 without and selectors or modifiers.
+ To change the source, use "Change Source" from the layer list's context menu.
+
+
+
+ See for some source specification string applications
+ and more details.
+
+
+
+ Beside the source, a layer entry has a display name. This is an arbitrary text
+ providing a description for the user. By default - when no such name is present -
+ the source of the layer will be displayed.
+ To change the display name, use "Rename" from the layer list's context menu.
+
+
+
+ Plus of course, the layer views have many options to specify the drawing style,
+ animations and decorations.
+
+
+
+ The concept of separating views from the database layers opens some interesting options:
+
+
+
+
Layer views can refer to individual layouts from multi-layout views (through the "@1", "@2", ... notation in the source).
+ Hence, multiple layouts can be mixed in a single layer list.
+
Layers can be present in the list which do not need to be present in the database. Such a layer is shown as empty.
+ This is important as in GDS an empty layer is equivalent to non-existing. Still you may want to have it shown in the
+ layer list - the views offer this option.
+
Vice versa, database layer may not be listed in the layer list if no corresponding layer view is present. This
+ way, auxiliary or debug layers can be omitted from the layer list. A "wildcard specification" is available to make
+ sure, all layers are shown if you need to see all.
+
Multiple tabs can be present to provide multiple views on the same layouts. This is just an alternative set of
+ layer views.
+
Layer grouping, sorting etc. are just operations on the views, no database change is involved.
+
+
+
+ The concept on the other hand is slightly counter-intuitive at first.
+ Here are some hints:
+
+
+
+
Renaming a layer does not change the source - if you rename a layer to something like "1/0", you are likely to fool yourself thinking this is layer 1, datatype 0.
+
Changing a layer view's source does not change the database too - it will just change the pointer. To change a layer's information in the database, use Edit/Layer/Edit Layer Specification.
+
Deleting a layer from the layer list does not delete the layer from the database. Use Edit/Layer/Delete Layer instead.
+
Additing a new layer does not immediately create the layer in the database. Only once you draw something on that layer, it is generated in the database.
+
+
+
+
diff --git a/src/lay/lay/layHelpResources.qrc b/src/lay/lay/layHelpResources.qrc
index 0e0053df0..06524e1f5 100644
--- a/src/lay/lay/layHelpResources.qrc
+++ b/src/lay/lay/layHelpResources.qrc
@@ -158,6 +158,7 @@
doc/manual/landmarks.xmldoc/manual/layer_animation.xmldoc/manual/layer_boolean.xml
+ doc/manual/layer_views.xmldoc/manual/layer_color.xmldoc/manual/layer_content.xmldoc/manual/layer_fill.xml
diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc
index c97f0def7..b886acfc8 100644
--- a/src/lay/lay/layMainWindow.cc
+++ b/src/lay/lay/layMainWindow.cc
@@ -2025,44 +2025,47 @@ MainWindow::cm_load_layer_props ()
if (current_view ()) {
std::string fn;
if (mp_lprops_fdia->get_open (fn, tl::to_string (QObject::tr ("Load Layer Properties File")))) {
-
- int target_cv_index = -2;
-
- if (current_view ()->cellviews () > 1 && is_single_cv_layer_properties_file (fn)) {
-
- QStringList items;
- items << QString (QObject::tr ("Take it as it is"));
- items << QString (QObject::tr ("Apply to all layouts"));
- for (unsigned int i = 0; i < current_view ()->cellviews (); ++i) {
- items << QString (tl::to_qstring (tl::to_string (QObject::tr ("Apply to ")) + current_view ()->cellview (i)->name () + " (@" + tl::to_string (i + 1) + ")"));
- }
-
- bool ok;
- QString item = QInputDialog::getItem(this, QObject::tr ("Apply Layer Properties File"),
- QObject::tr ("There are multiple layouts in that panel but the layer properties file contains properties for a single one.\nWhat should be done?"),
- items, 1, false, &ok);
- if (!ok || item.isEmpty()) {
- return;
- }
-
- target_cv_index = items.indexOf (item) - 2;
-
- }
-
- if (target_cv_index > -2) {
- load_layer_properties (fn, target_cv_index, false /*current view only*/, false /*don't add default*/);
- } else {
- load_layer_properties (fn, false /*current view only*/, false /*don't add default*/);
- }
-
+ load_layer_props_from_file (fn);
add_to_other_mru (fn, cfg_mru_layer_properties);
-
}
} else {
throw tl::Exception (tl::to_string (QObject::tr ("No view open to load the layer properties for")));
}
}
+void
+MainWindow::load_layer_props_from_file (const std::string &fn)
+{
+ int target_cv_index = -2;
+
+ if (current_view ()->cellviews () > 1 && is_single_cv_layer_properties_file (fn)) {
+
+ QStringList items;
+ items << QString (QObject::tr ("Take it as it is"));
+ items << QString (QObject::tr ("Apply to all layouts"));
+ for (unsigned int i = 0; i < current_view ()->cellviews (); ++i) {
+ items << QString (tl::to_qstring (tl::to_string (QObject::tr ("Apply to ")) + current_view ()->cellview (i)->name () + " (@" + tl::to_string (i + 1) + ")"));
+ }
+
+ bool ok;
+ QString item = QInputDialog::getItem(this, QObject::tr ("Apply Layer Properties File"),
+ QObject::tr ("There are multiple layouts in that panel but the layer properties file contains properties for a single one.\nWhat should be done?"),
+ items, 1, false, &ok);
+ if (!ok || item.isEmpty()) {
+ return;
+ }
+
+ target_cv_index = items.indexOf (item) - 2;
+
+ }
+
+ if (target_cv_index > -2) {
+ load_layer_properties (fn, target_cv_index, false /*current view only*/, false /*don't add default*/);
+ } else {
+ load_layer_properties (fn, false /*current view only*/, false /*don't add default*/);
+ }
+}
+
void
MainWindow::save_session (const std::string &fn)
{
@@ -3238,7 +3241,7 @@ MainWindow::open_recent_layer_properties (size_t n)
if (n < m_mru_layer_properties.size ()) {
std::string fn = m_mru_layer_properties [n];
- load_layer_properties (fn, false /*current view only*/, false /*don't add default*/);
+ load_layer_props_from_file (fn);
add_to_other_mru (fn, cfg_mru_layer_properties); // make it the latest
}
diff --git a/src/lay/lay/layMainWindow.h b/src/lay/lay/layMainWindow.h
index f9fe51611..cb2f2246d 100644
--- a/src/lay/lay/layMainWindow.h
+++ b/src/lay/lay/layMainWindow.h
@@ -805,6 +805,7 @@ private:
int dirty_files (std::string &dirty_files);
+ void load_layer_props_from_file (const std::string &fn);
void interactive_close_view (int index, bool all_cellviews);
void call_on_current_view (void (lay::LayoutView::*func) (), const std::string &op_desc);
void current_view_changed ();
diff --git a/src/lay/lay/laySearchReplaceDialog.cc b/src/lay/lay/laySearchReplaceDialog.cc
index 4f8196e64..3c70640ba 100644
--- a/src/lay/lay/laySearchReplaceDialog.cc
+++ b/src/lay/lay/laySearchReplaceDialog.cc
@@ -38,6 +38,7 @@
#include "tlLog.h"
#include "tlProgress.h"
#include "tlTimer.h"
+#include "rdbUtils.h"
#include
#include
@@ -537,10 +538,10 @@ SearchReplaceResults::export_rdb (rdb::Database &rdb, double dbu)
rdb::Item *item = rdb.create_item (cell->id (), cat->id ());
if (! v->is_list ()) {
- item->add_value (std::string (v->to_string ()));
+ rdb::add_item_value (item, *v, dbu);
} else {
for (std::vector::const_iterator i = v->get_list ().begin (); i != v->get_list ().end (); ++i) {
- item->add_value (std::string (i->to_string ()));
+ rdb::add_item_value (item, *i, dbu);
}
}
diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc
index a01db5183..938ca9d36 100644
--- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc
+++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc
@@ -690,6 +690,11 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"\n"
"In 0.25, this method has been moved from MainWindow to LayoutView.\n"
) +
+ gsi::method ("is_editable?", &lay::LayoutView::is_editable,
+ "@brief Returns true if the view is in editable mode\n"
+ "\n"
+ "This read-only attribute has been added in version 0.27.5.\n"
+ ) +
gsi::method ("reload_layout", &lay::LayoutView::reload_layout, gsi::arg ("cv"),
"@brief Reloads the given cellview\n"
"\n"
diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc
index 0055a43cf..603136699 100644
--- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc
+++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc
@@ -203,7 +203,7 @@ D25View::activated ()
bool any = mp_ui->d25_view->attach_view (view ());
if (! any) {
mp_ui->d25_view->attach_view (0);
- throw tl::Exception (tl::to_string (tr ("No z data configured for the layers in the view.\nUse \"Tools/Manage Technologies\" to set up a z stack.")));
+ throw tl::Exception (tl::to_string (tr ("No z data configured for the layers in this view.\nUse \"Tools/Manage Technologies\" to set up a z stack or check if it applies to the layers here.")));
}
mp_ui->d25_view->reset ();
diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc
index f83b57214..3eb97dfee 100644
--- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc
+++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc
@@ -311,13 +311,13 @@ D25ViewWidget::keyPressEvent (QKeyEvent *event)
// Move "into" or "out"
- double d = (event->key () == Qt::Key_Up ? 0.1 : -0.1);
+ double d = (event->key () == Qt::Key_Up ? 0.05 : -0.05);
QMatrix4x4 t;
t.rotate (cam_azimuth (), 0.0, 1.0, 0.0);
QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ()));
- set_displacement (displacement () + d * cd);
+ set_displacement (displacement () + d * cd / m_scale_factor);
}
@@ -327,7 +327,7 @@ D25ViewWidget::keyPressEvent (QKeyEvent *event)
// Ctrl + left/right changes azimuths
- double d = (event->key () == Qt::Key_Right ? 2 : -2);
+ double d = (event->key () == Qt::Key_Right ? 1 : -1);
double a = cam_azimuth () + d;
if (a < -180.0) {
@@ -348,7 +348,7 @@ D25ViewWidget::keyPressEvent (QKeyEvent *event)
t.rotate (cam_azimuth (), 0.0, 1.0, 0.0);
QVector3D cd = t.inverted ().map (QVector3D (cam_dist (), 0, 0));
- set_displacement (displacement () + d * cd);
+ set_displacement (displacement () + d * cd / m_scale_factor);
}
@@ -634,11 +634,6 @@ D25ViewWidget::prepare_view ()
}
- m_bbox &= cell_bbox;
- if (m_bbox.empty ()) {
- return false;
- }
-
bool any = false;
tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ...")));
diff --git a/src/rdb/rdb/rdbUtils.cc b/src/rdb/rdb/rdbUtils.cc
index 336ed963e..c6940a56a 100644
--- a/src/rdb/rdb/rdbUtils.cc
+++ b/src/rdb/rdb/rdbUtils.cc
@@ -317,5 +317,52 @@ void create_items_from_edge_pairs (rdb::Database *db, rdb::id_type cell_id, rdb:
}
}
+void add_item_value (rdb::Item *item, const tl::Variant &v, double dbu)
+{
+ if (dbu > 0 && v.is_user ()) {
+ item->add_value (db::CplxTrans (dbu) * v.to_user ());
+ } else if (dbu > 0 && v.is_user ()) {
+ db::DPoint p = db::CplxTrans (dbu) * v.to_user ();
+ item->add_value (db::DEdge (p, p));
+ } else if (dbu > 0 && v.is_user ()) {
+ item->add_value (db::CplxTrans (dbu) * v.to_user ());
+ } else if (dbu > 0 && v.is_user ()) {
+ db::DPolygon p;
+ db::DSimplePolygon sp = db::CplxTrans (dbu) * v.to_user ();
+ p.assign_hull (sp.begin_hull (), sp.end_hull ());
+ item->add_value (p);
+ } else if (dbu > 0 && v.is_user ()) {
+ item->add_value (db::CplxTrans (dbu) * v.to_user ());
+ } else if (dbu > 0 && v.is_user ()) {
+ item->add_value (db::CplxTrans (dbu) * v.to_user ());
+ } else if (dbu > 0 && v.is_user ()) {
+ item->add_value (db::CplxTrans (dbu) * v.to_user ());
+ } else if (dbu > 0 && v.is_user ()) {
+ item->add_value (db::CplxTrans (dbu) * v.to_user ());
+ } else if (v.is_user ()) {
+ item->add_value (v.to_user ());
+ } else if (v.is_user ()) {
+ db::DPoint p = v.to_user ();
+ item->add_value (db::DEdge (p, p));
+ } else if (v.is_user ()) {
+ item->add_value (v.to_user ());
+ } else if (v.is_user ()) {
+ db::DPolygon p;
+ db::DSimplePolygon sp = v.to_user ();
+ p.assign_hull (sp.begin_hull (), sp.end_hull ());
+ item->add_value (p);
+ } else if (v.is_user ()) {
+ item->add_value (v.to_user ());
+ } else if (v.is_user ()) {
+ item->add_value (v.to_user ());
+ } else if (v.is_user ()) {
+ item->add_value (v.to_user ());
+ } else if (v.is_user ()) {
+ item->add_value (v.to_user ());
+ } else {
+ item->add_value (std::string (v.to_string ()));
+ }
+}
+
}
diff --git a/src/rdb/rdb/rdbUtils.h b/src/rdb/rdb/rdbUtils.h
index d89cd6c72..f6b579008 100644
--- a/src/rdb/rdb/rdbUtils.h
+++ b/src/rdb/rdb/rdbUtils.h
@@ -136,6 +136,18 @@ RDB_PUBLIC_TEMPLATE void create_items_from_sequence (rdb::Database *db, rdb::id_
}
}
+/**
+ * @brief Creates a value from a tl::Variant
+ *
+ * This produces values which reflect some values the variant can assume - specifically
+ * shapes are converted into corresponding RDB values. The database unit is used to
+ * translate integer-type values. Using a database unit of 0 will disable the conversion of
+ * such types.
+ *
+ * Unknown types are converted to strings.
+ */
+RDB_PUBLIC void add_item_value (rdb::Item *item, const tl::Variant &v, double dbu = 0.0);
+
}
#endif