mirror of https://github.com/KLayout/klayout.git
Merge pull request #923 from KLayout/usablity-enhancements
Usablity enhancements
This commit is contained in:
commit
7e6b4662ec
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -2115,7 +2115,7 @@ MainService::cm_tap ()
|
|||
QPoint mp = view ()->view_object_widget ()->mapToGlobal (view ()->view_object_widget ()->mouse_position ());
|
||||
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::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 ()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@
|
|||
<topic href="/manual/view_state.xml"/>
|
||||
<topic href="/manual/bookmarks.xml"/>
|
||||
<topic href="/manual/descend.xml"/>
|
||||
<topic href="/manual/layer_views.xml"/>
|
||||
<topic href="/manual/layer_color.xml"/>
|
||||
<topic href="/manual/layer_content.xml"/>
|
||||
<topic href="/manual/layer_content.xml"/>
|
||||
<topic href="/manual/line_style.xml"/>
|
||||
<topic href="/manual/layer_animation.xml"/>
|
||||
<topic href="/manual/layer_style.xml"/>
|
||||
|
|
|
|||
|
|
@ -100,5 +100,9 @@
|
|||
a selector as well, only those shapes will be shown that meet both criteria.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A general description for the source notation is found here: <link href="/about/layer_sources.xml"/>.
|
||||
</p>
|
||||
|
||||
</doc>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
||||
|
||||
<doc>
|
||||
|
||||
<title>The Layer List (Layer Views)</title>
|
||||
<keyword name="Layer list"/>
|
||||
<keyword name="Layer views"/>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See <link href="/manual/layer_source_expert.xml"/> for some source specification string applications
|
||||
and more details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Plus of course, the layer views have many options to specify the drawing style,
|
||||
animations and decorations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The concept of separating views from the database layers opens some interesting options:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>Multiple tabs can be present to provide multiple views on the same layouts. This is just an alternative set of
|
||||
layer views.</li>
|
||||
<li>Layer grouping, sorting etc. are just operations on the views, no database change is involved.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The concept on the other hand is slightly counter-intuitive at first.
|
||||
Here are some hints:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>Deleting a layer from the layer list does <b>not delete</b> the layer from the database. Use Edit/Layer/Delete Layer instead.</li>
|
||||
<li>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.</li>
|
||||
</ul>
|
||||
|
||||
</doc>
|
||||
|
||||
|
|
@ -158,6 +158,7 @@
|
|||
<file alias="landmarks.xml">doc/manual/landmarks.xml</file>
|
||||
<file alias="layer_animation.xml">doc/manual/layer_animation.xml</file>
|
||||
<file alias="layer_boolean.xml">doc/manual/layer_boolean.xml</file>
|
||||
<file alias="layer_views.xml">doc/manual/layer_views.xml</file>
|
||||
<file alias="layer_color.xml">doc/manual/layer_color.xml</file>
|
||||
<file alias="layer_content.xml">doc/manual/layer_content.xml</file>
|
||||
<file alias="layer_fill.xml">doc/manual/layer_fill.xml</file>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "tlLog.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlTimer.h"
|
||||
#include "rdbUtils.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QHeaderView>
|
||||
|
|
@ -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<tl::Variant>::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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -690,6 +690,11 @@ Class<lay::LayoutView> 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"
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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 ...")));
|
||||
|
|
|
|||
|
|
@ -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<db::Box> ()) {
|
||||
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Box> ());
|
||||
} else if (dbu > 0 && v.is_user<db::Point> ()) {
|
||||
db::DPoint p = db::CplxTrans (dbu) * v.to_user<db::Point> ();
|
||||
item->add_value (db::DEdge (p, p));
|
||||
} else if (dbu > 0 && v.is_user<db::Polygon> ()) {
|
||||
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Polygon> ());
|
||||
} else if (dbu > 0 && v.is_user<db::SimplePolygon> ()) {
|
||||
db::DPolygon p;
|
||||
db::DSimplePolygon sp = db::CplxTrans (dbu) * v.to_user<db::SimplePolygon> ();
|
||||
p.assign_hull (sp.begin_hull (), sp.end_hull ());
|
||||
item->add_value (p);
|
||||
} else if (dbu > 0 && v.is_user<db::Edge> ()) {
|
||||
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Edge> ());
|
||||
} else if (dbu > 0 && v.is_user<db::EdgePair> ()) {
|
||||
item->add_value (db::CplxTrans (dbu) * v.to_user<db::EdgePair> ());
|
||||
} else if (dbu > 0 && v.is_user<db::Path> ()) {
|
||||
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Path> ());
|
||||
} else if (dbu > 0 && v.is_user<db::Text> ()) {
|
||||
item->add_value (db::CplxTrans (dbu) * v.to_user<db::Text> ());
|
||||
} else if (v.is_user<db::DBox> ()) {
|
||||
item->add_value (v.to_user<db::DBox> ());
|
||||
} else if (v.is_user<db::DPoint> ()) {
|
||||
db::DPoint p = v.to_user<db::DPoint> ();
|
||||
item->add_value (db::DEdge (p, p));
|
||||
} else if (v.is_user<db::DPolygon> ()) {
|
||||
item->add_value (v.to_user<db::DPolygon> ());
|
||||
} else if (v.is_user<db::DSimplePolygon> ()) {
|
||||
db::DPolygon p;
|
||||
db::DSimplePolygon sp = v.to_user<db::DSimplePolygon> ();
|
||||
p.assign_hull (sp.begin_hull (), sp.end_hull ());
|
||||
item->add_value (p);
|
||||
} else if (v.is_user<db::DEdge> ()) {
|
||||
item->add_value (v.to_user<db::DEdge> ());
|
||||
} else if (v.is_user<db::DEdgePair> ()) {
|
||||
item->add_value (v.to_user<db::DEdgePair> ());
|
||||
} else if (v.is_user<db::DPath> ()) {
|
||||
item->add_value (v.to_user<db::DPath> ());
|
||||
} else if (v.is_user<db::DText> ()) {
|
||||
item->add_value (v.to_user<db::DText> ());
|
||||
} else {
|
||||
item->add_value (std::string (v.to_string ()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue