Merge branch 'master' of github.com:KLayout/klayout

This commit is contained in:
Matthias Koefferlein 2025-10-23 19:21:26 +02:00
commit 564111af77
21 changed files with 615 additions and 192 deletions

View File

@ -46,8 +46,8 @@ ViaType::init ()
// ---------------------------------------------------------------------------------------
std::vector<SelectedViaDefinition>
find_via_definitions_for (const std::string &technology, const db::LayerProperties &layer, int dir)
static std::vector<SelectedViaDefinition>
find_via_definitions_impl (const std::string &technology, const db::LayerProperties &layer, int dir, bool all)
{
std::vector<SelectedViaDefinition> via_defs;
@ -65,7 +65,8 @@ find_via_definitions_for (const std::string &technology, const db::LayerProperti
auto via_types = pcell->via_types ();
for (auto vt = via_types.begin (); vt != via_types.end (); ++vt) {
if ((dir >= 0 && vt->bottom.log_equal (layer) && vt->bottom_wired) ||
if (all ||
(dir >= 0 && vt->bottom.log_equal (layer) && vt->bottom_wired) ||
(dir <= 0 && vt->top.log_equal (layer) && vt->top_wired)) {
via_defs.push_back (SelectedViaDefinition (lib, pc->second, *vt));
}
@ -78,4 +79,16 @@ find_via_definitions_for (const std::string &technology, const db::LayerProperti
return via_defs;
}
std::vector<SelectedViaDefinition>
get_via_definitions (const std::string &technology)
{
return find_via_definitions_impl (technology, db::LayerProperties (), 0, true);
}
std::vector<SelectedViaDefinition>
find_via_definitions_for (const std::string &technology, const db::LayerProperties &layer, int dir)
{
return find_via_definitions_impl (technology, layer, dir, false);
}
}

View File

@ -210,6 +210,9 @@ struct SelectedViaDefinition
DB_PUBLIC std::vector<SelectedViaDefinition>
find_via_definitions_for (const std::string &technology, const db::LayerProperties &layer, int dir);
DB_PUBLIC std::vector<SelectedViaDefinition>
get_via_definitions (const std::string &technology);
}
#endif

View File

@ -29,8 +29,9 @@
#include "layEditorUtils.h"
#include "layObjectInstPath.h"
#include "layCellView.h"
#include "layLayoutViewBase.h"
#include "layMarker.h"
#include "layFinder.h"
#include "layLayerTreeModel.h"
#include "tlException.h"
#include "tlExceptions.h"
@ -725,6 +726,93 @@ AreaAndPerimeterDialog::exec_dialog (double area, double perimeter)
return exec () != 0;
}
// --------------------------------------------------------------------------------
// popup_tap_layer_menu implementation
lay::LayerPropertiesConstIterator
popup_tap_layer_menu (lay::LayoutViewBase *view, const std::set<db::LayerProperties, db::LPLogicalLessFunc> *filter, int cv_index)
{
QWidget *view_widget = lay::widget_from_view (view);
if (! view_widget) {
return lay::LayerPropertiesConstIterator ();
}
if (! view->canvas ()->mouse_in_window ()) {
return lay::LayerPropertiesConstIterator ();
}
lay::ShapeFinder finder (true, // point mode
false, // all hierarchy levels
db::ShapeIterator::flags_type (db::ShapeIterator::All - db::ShapeIterator::Texts), // do not consider texts - their bounding box may be too large
0, // no excludes
true // capture all shapes
);
// capture all objects in point mode (default: capture one only)
finder.set_catch_all (true);
// go through all visible layers of all cellviews
db::DPoint pt = view->canvas ()->mouse_position_um ();
finder.find (view, db::DBox (pt, pt));
std::set<std::pair<unsigned int, unsigned int> > layers_in_selection;
for (lay::ShapeFinder::iterator f = finder.begin (); f != finder.end (); ++f) {
if (cv_index < 0 || f->cv_index () == cv_index) {
const db::Layout &ly = view->cellview (f->cv_index ())->layout ();
// ignore guiding shapes and only provide layers from the filter
if (f->layer () != ly.guiding_shape_layer ()
&& (! filter || filter->find (ly.get_properties (f->layer ())) != filter->end ())) {
layers_in_selection.insert (std::make_pair (f->cv_index (), f->layer ()));
}
}
}
std::vector<lay::LayerPropertiesConstIterator> tapped_layers;
for (lay::LayerPropertiesConstIterator lp = view->begin_layers (view->current_layer_list ()); ! lp.at_end (); ++lp) {
const lay::LayerPropertiesNode *ln = lp.operator-> ();
if (layers_in_selection.find (std::make_pair ((unsigned int) ln->cellview_index (), (unsigned int) ln->layer_index ())) != layers_in_selection.end ()) {
tapped_layers.push_back (lp);
}
}
if (tapped_layers.empty ()) {
return lay::LayerPropertiesConstIterator ();
} else if (tapped_layers.size () == 1) {
return tapped_layers.front ();
}
// List the layers under the cursor as pop up a menu
#if QT_VERSION >= 0x050000
double dpr = view_widget->devicePixelRatio ();
#else
double dpr = 1.0;
#endif
std::unique_ptr<QMenu> menu (new QMenu (view_widget));
menu->show ();
int icon_size = menu->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
db::DPoint mp_local = view->canvas ()->mouse_position ();
QPoint mp = view->canvas ()->widget ()->mapToGlobal (QPoint (mp_local.x (), mp_local.y ()));
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, dpr, 0, true), tl::to_qstring ((*l)->display_string (view, true, true /*with source*/)));
a->setData (int (l - tapped_layers.begin ()));
}
QAction *action = menu->exec (mp);
if (action) {
int index = action->data ().toInt ();
return tapped_layers [index];
} else {
return lay::LayerPropertiesConstIterator ();
}
}
}
#endif

View File

@ -34,6 +34,9 @@
#include "dbLayout.h"
#include "dbPoint.h"
#include "dbLayerProperties.h"
#include "layLayoutView.h"
#include "ui_InstantiationForm.h"
#include "ui_ChangeLayerOptionsDialog.h"
@ -47,7 +50,6 @@
namespace lay
{
class LayoutViewBase;
class Marker;
class ObjectInstPath;
}
@ -222,6 +224,17 @@ public:
bool exec_dialog (double area, double perimeter);
};
/**
* @brief Obtains an layer iterator for one of the layers present under the mouse cursor
*
* This is not really a dialog, but a popup menu.
*
* @param view The LayoutView object
* @param filter An optional set of layers to show. Only layers from this set are shown.
* @return A layer iterator which is at_end if no specific layer was selected
*/
lay::LayerPropertiesConstIterator popup_tap_layer_menu (lay::LayoutViewBase *view, const std::set<db::LayerProperties, db::LPLogicalLessFunc> *filter = 0, int cv_index = -1);
} // namespace edt
#endif

View File

@ -47,7 +47,6 @@
#if defined(HAVE_QT)
# include "layDialogs.h"
# include "layLayerTreeModel.h"
# include "layCellSelectionForm.h"
# include "edtDialogs.h"
# include "edtEditorOptionsPages.h"
@ -2361,88 +2360,16 @@ void
MainService::cm_tap ()
{
#if ! defined(HAVE_QT)
tl_assert (false); // see TODO
#endif
#if defined(HAVE_QT)
QWidget *view_widget = lay::widget_from_view (view ());
if (! view_widget) {
return;
}
#endif
if (! view ()->canvas ()->mouse_in_window ()) {
return;
}
lay::ShapeFinder finder (true, // point mode
false, // all hierarchy levels
db::ShapeIterator::flags_type (db::ShapeIterator::All - db::ShapeIterator::Texts), // do not consider texts - their bounding box may be too large
0, // no excludes
true // capture all shapes
);
// capture all objects in point mode (default: capture one only)
finder.set_catch_all (true);
// go through all visible layers of all cellviews
db::DPoint pt = view ()->canvas ()->mouse_position_um ();
finder.find (view (), db::DBox (pt, pt));
std::set<std::pair<unsigned int, unsigned int> > layers_in_selection;
for (lay::ShapeFinder::iterator f = finder.begin (); f != finder.end (); ++f) {
// ignore guiding shapes
if (f->layer () != view ()->cellview (f->cv_index ())->layout ().guiding_shape_layer ()) {
layers_in_selection.insert (std::make_pair (f->cv_index (), f->layer ()));
}
}
std::vector<lay::LayerPropertiesConstIterator> tapped_layers;
for (lay::LayerPropertiesConstIterator lp = view ()->begin_layers (view ()->current_layer_list ()); ! lp.at_end (); ++lp) {
const lay::LayerPropertiesNode *ln = lp.operator-> ();
if (layers_in_selection.find (std::make_pair ((unsigned int) ln->cellview_index (), (unsigned int) ln->layer_index ())) != layers_in_selection.end ()) {
tapped_layers.push_back (lp);
}
}
if (tapped_layers.empty ()) {
return;
}
// List the layers under the cursor as pop up a menu
#if defined(HAVE_QT)
// TODO: what to do here in Qt-less case? Store results in configuration so they can be retrieved externally?
#if QT_VERSION >= 0x050000
double dpr = view_widget->devicePixelRatio ();
tl_assert (false); // TODO
#else
double dpr = 1.0;
#endif
lay::LayerPropertiesConstIterator iter = edt::popup_tap_layer_menu (view ());
if (! iter.at_end ()) {
std::unique_ptr<QMenu> menu (new QMenu (view_widget));
menu->show ();
int icon_size = menu->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
db::DPoint mp_local = view ()->canvas ()->mouse_position ();
QPoint mp = view ()->canvas ()->widget ()->mapToGlobal (QPoint (mp_local.x (), mp_local.y ()));
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, dpr, 0, true), tl::to_qstring ((*l)->display_string (view (), true, true /*with source*/)));
a->setData (int (l - tapped_layers.begin ()));
}
QAction *action = menu->exec (mp);
if (action) {
int index = action->data ().toInt ();
lay::LayerPropertiesConstIterator iter = tapped_layers [index];
view ()->set_current_layer (iter);
edt::Service *es = dynamic_cast<edt::Service *> (view ()->canvas ()->active_service ());
if (es) {
db::DPoint pt = view ()->canvas ()->mouse_position_um ();
es->tap (pt);
}
@ -2486,9 +2413,11 @@ MainService::via_impl (int dir)
return;
}
edt::Service *es = dynamic_cast<edt::Service *> (view ()->canvas ()->active_service ());
if (es) {
es->via (dir);
// via generation is delegated to the path service always
edt::PathService *ps = view ()->get_plugin<edt::PathService> ();
if (ps) {
view ()->switch_mode (ps->plugin_declaration ()->id ());
ps->via (dir);
}
}

View File

@ -22,15 +22,12 @@
#include "edtPathService.h"
#include "edtDialogs.h"
#include "edtPropertiesPages.h"
#include "layLayoutViewBase.h"
#include "layFinder.h"
#if defined(HAVE_QT)
# include "edtPropertiesPages.h"
# include "layLayoutView.h"
#endif
namespace edt
{
@ -268,6 +265,35 @@ PathService::via (int dir)
#endif
}
db::LayerProperties
PathService::get_layer_for_via (unsigned int cv_index)
{
#if defined(HAVE_QT)
const lay::CellView &cv = view ()->cellview (cv_index);
if (! cv.is_valid ()) {
return db::LayerProperties ();
}
std::vector<db::SelectedViaDefinition> via_defs = db::get_via_definitions (cv->layout ().technology_name ());
std::set<db::LayerProperties, db::LPLogicalLessFunc> lp_filter;
for (auto vd = via_defs.begin (); vd != via_defs.end (); ++vd) {
lp_filter.insert (vd->via_type.bottom);
lp_filter.insert (vd->via_type.top);
}
lay::LayerPropertiesConstIterator iter;
iter = edt::popup_tap_layer_menu (view (), &lp_filter, cv_index);
if (iter.at_end ()) {
return db::LayerProperties ();
}
return cv->layout ().get_properties (iter->layer_index ());
#else
return db::LayerProperties ();
#endif
}
bool
PathService::get_via_for (const db::LayerProperties &lp, unsigned int cv_index, int dir, db::SelectedViaDefinition &via_def)
{
@ -364,19 +390,20 @@ PathService::via_initial (int dir)
return;
}
const lay::CellView &cv = view ()->cellview (r->cv_index ());
if (! cv.is_valid ()) {
// the first found provides the cellview index
int cv_index = r->cv_index ();
db::LayerProperties lp = get_layer_for_via (cv_index);
if (lp.is_null ()) {
return;
}
db::LayerProperties lp = cv->layout ().get_properties (r->layer ());
db::SelectedViaDefinition via_def;
if (! get_via_for (lp, r->cv_index (), dir, via_def)) {
if (! get_via_for (lp, cv_index, dir, via_def)) {
return;
}
set_layer (lp, r->cv_index ());
set_layer (lp, cv_index);
bool is_bottom = via_def.via_type.bottom.log_equal (lp);
db::LayerProperties lp_new = is_bottom ? via_def.via_type.top : via_def.via_type.bottom;

View File

@ -89,6 +89,7 @@ private:
void via_initial (int dir);
void via_editing (int dir);
bool get_via_for (const db::LayerProperties &lp, unsigned int cv_index, int dir, db::SelectedViaDefinition &via_def);
db::LayerProperties get_layer_for_via (unsigned int cv_index);
void push_segment (const db::Shape &shape, const db::Instance &instance, const db::ViaType &via_type, db::Manager::transaction_id_t transaction_id);
void pop_segment ();
};

View File

@ -26,17 +26,13 @@
#include "dbLibrary.h"
#include "edtPlugin.h"
#include "edtService.h"
#if defined(HAVE_QT)
# include "edtEditorOptionsPages.h"
# include "edtDialogs.h"
#endif
#include "edtEditorOptionsPages.h"
#include "edtDialogs.h"
#include "layFinder.h"
#include "layLayoutView.h"
#include "laySnap.h"
#include "layConverters.h"
#if defined(HAVE_QT)
# include "layEditorOptionsPages.h"
#endif
#include "layEditorOptionsPages.h"
#include "tlProgress.h"
#include "tlTimer.h"
@ -1159,6 +1155,8 @@ Service::transient_select (const db::DPoint &pos)
if (m_cell_inst_service) {
lay::InstFinder finder (true, view ()->is_editable () && m_top_level_sel, view ()->is_editable () /*full arrays in editable mode*/, true /*enclose instances*/, &m_previous_selection, true /*visible layers only*/);
finder.consider_ghost_cells (view ()->ghost_cells_visible ());
finder.consider_normal_cells (view ()->cell_box_visible ());
// go through all transform variants
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants_with_empty ();
@ -1208,7 +1206,7 @@ Service::transient_select (const db::DPoint &pos)
// In viewer mode, individual instances of arrays can be selected. Since that is not supported by
// InstanceMarker, we just indicate the individual instance's bounding box.
lay::Marker *marker = new lay::Marker (view (), r->cv_index ());
db::box_convert<db::CellInst> bc (cv->layout ());
db::box_convert<db::CellInst, false> bc (cv->layout ());
marker->set (bc (r->back ().inst_ptr.cell_inst ().object ()), gt * r->back ().inst_ptr.cell_inst ().complex_trans (*r->back ().array_inst), tv);
marker->set_vertex_size (view ()->default_transient_marker_vertex_size ());
marker->set_line_width (view ()->default_transient_marker_line_width ());
@ -1493,6 +1491,8 @@ Service::select (const db::DBox &box, lay::Editable::SelectionMode mode)
} else if (m_cell_inst_service) {
lay::InstFinder finder (box.is_point (), view ()->is_editable () && m_top_level_sel, view ()->is_editable () /*full arrays in editable mode*/, true /*enclose_inst*/, exclude, true /*only visible layers*/);
finder.consider_ghost_cells (view ()->ghost_cells_visible ());
finder.consider_normal_cells (view ()->cell_box_visible ());
// go through all cell views
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants_with_empty ();
@ -1709,13 +1709,13 @@ Service::begin_edit (const db::DPoint &p)
}
void
Service::tap (const db::DPoint & /*initial*/)
Service::tap (const db::DPoint & /*pt*/)
{
// .. nothing here ..
}
void
Service::via (int)
Service::via (int /*dir*/)
{
// .. nothing here ..
}
@ -1806,7 +1806,7 @@ Service::do_selection_to_view ()
if (r->seq () > 0 && m_indicate_secondary_selection) {
marker->set_dither_pattern (3);
}
db::box_convert<db::CellInst> bc (cv->layout ());
db::box_convert<db::CellInst, false> bc (cv->layout ());
marker->set (bc (r->back ().inst_ptr.cell_inst ().object ()), gt * r->back ().inst_ptr.cell_inst ().complex_trans (*r->back ().array_inst), *tv_list);
m_markers.push_back (std::make_pair (r.operator-> (), marker));

View File

@ -22,16 +22,18 @@
#include "edtShapeService.h"
#include "edtMainService.h"
#include "edtPathService.h"
#include "edtPropertiesPages.h"
#include "layLayoutView.h"
#include "dbEdgeProcessor.h"
#include "dbPolygonTools.h"
#if defined(HAVE_QT)
# include "edtPropertiesPages.h"
# include "layTipDialog.h"
# include "layEditorOptionsPages.h"
# include "layTipDialog.h"
#endif
#include "layEditorOptionsPages.h"
namespace edt
{

View File

@ -30,6 +30,7 @@
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbReader.h"
#include "dbCellMapping.h"
#include "tlLog.h"
#include "tlStream.h"
#include "tlFileUtils.h"
@ -51,6 +52,12 @@ public:
set_description (tl::filename (path));
}
void merge_with_other_layout (const std::string &path)
{
m_other_paths.push_back (path);
merge_impl (path);
}
virtual std::string reload ()
{
std::string name = tl::basename (m_path);
@ -70,11 +77,42 @@ public:
}
}
for (auto p = m_other_paths.begin (); p != m_other_paths.end (); ++p) {
merge_impl (*p);
}
return name;
}
private:
std::string m_path;
std::list<std::string> m_other_paths;
void merge_impl (const std::string &path)
{
db::Layout ly;
tl::InputStream stream (path);
db::Reader reader (stream);
reader.read (ly);
std::vector<db::cell_index_type> target_cells, source_cells;
// collect the cells to pull in (all top cells of the library layout)
// NOTE: cells are not overwritten - the first layout wins, in terms
// of cell names and also in terms of database unit.
for (auto c = ly.begin_top_down (); c != ly.end_top_cells (); ++c) {
std::string cn = ly.cell_name (*c);
if (! layout ().has_cell (cn.c_str ())) {
source_cells.push_back (*c);
target_cells.push_back (layout ().add_cell (cn.c_str ()));
}
}
db::CellMapping cm;
cm.create_multi_mapping_full (layout (), target_cells, ly, source_cells);
layout ().copy_tree_shapes (ly, cm);
}
};
// -------------------------------------------------------------------------------------------
@ -201,60 +239,111 @@ LibraryController::sync_files ()
m_file_watcher->add_file (tl::to_string (lp.absolutePath ()));
}
tl::log << "Scanning library path '" << tl::to_string (lp.absolutePath ()) << "'";
QStringList name_filters;
name_filters << QString::fromUtf8 ("*");
// NOTE: this should return a list sorted by name
QStringList libs = lp.entryList (name_filters, QDir::Files);
for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) {
bool needs_load = false;
for (QStringList::const_iterator im = libs.begin (); im != libs.end () && ! needs_load; ++im) {
std::string lib_path = tl::to_string (lp.absoluteFilePath (*im));
QFileInfo fi (tl::to_qstring (lib_path));
try {
auto ll = m_lib_files.find (lib_path);
if (ll == m_lib_files.end ()) {
needs_load = true;
} else if (fi.lastModified () > ll->second.time) {
needs_load = true;
}
QFileInfo fi (tl::to_qstring (lib_path));
}
bool needs_load = false;
std::map<std::string, LibInfo>::iterator ll = m_lib_files.find (lib_path);
if (ll == m_lib_files.end ()) {
needs_load = true;
} else {
if (fi.lastModified () > ll->second.time) {
needs_load = true;
} else {
new_lib_files.insert (*ll);
}
if (! needs_load) {
// If not reloading, register the existing files as known ones - this allows detecting if
// a file got removed.
for (QStringList::const_iterator im = libs.begin (); im != libs.end () && ! needs_load; ++im) {
std::string lib_path = tl::to_string (lp.absoluteFilePath (*im));
auto ll = m_lib_files.find (lib_path);
if (ll != m_lib_files.end ()) {
new_lib_files.insert (*ll);
}
if (needs_load) {
}
std::unique_ptr<db::Library> lib (new FileBasedLibrary (lib_path));
} else {
std::map<std::string, FileBasedLibrary *> libs_by_name_here;
// Reload all files
for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) {
std::string lib_path = tl::to_string (lp.absoluteFilePath (*im));
QFileInfo fi (tl::to_qstring (lib_path));
try {
std::unique_ptr<FileBasedLibrary> lib (new FileBasedLibrary (lib_path));
if (! p->second.empty ()) {
lib->set_technology (p->second);
}
tl::log << "Reading library '" << lib_path << "'";
lib->set_name (lib->reload ());
std::string libname = lib->reload ();
// merge with existing lib if there is already one in this folder with the right name
auto il = libs_by_name_here.find (libname);
if (il != libs_by_name_here.end ()) {
tl::log << "Merging with other library file with the same name: " << libname;
il->second->merge_with_other_layout (lib_path);
// now, we can forget the new library as it is included in the first one
if (! p->second.empty ()) {
tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";
} else {
tl::log << "Registering as '" << lib->get_name () << "'";
// otherwise register the new library
if (! p->second.empty ()) {
tl::log << "Registering as '" << libname << "' for tech '" << p->second << "'";
} else {
tl::log << "Registering as '" << libname << "'";
}
LibInfo li;
li.name = libname;
li.time = fi.lastModified ();
if (! p->second.empty ()) {
li.tech.insert (p->second);
}
new_lib_files.insert (std::make_pair (lib_path, li));
lib->set_name (libname);
libs_by_name_here.insert (std::make_pair (libname, lib.release ()));
}
LibInfo li;
li.name = lib->get_name ();
li.time = fi.lastModified ();
if (! p->second.empty ()) {
li.tech.insert (p->second);
}
new_lib_files.insert (std::make_pair (lib_path, li));
db::LibraryManager::instance ().register_lib (lib.release ());
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
}
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
}
// Register the libs (NOTE: this needs to happen after the merge)
for (auto l = libs_by_name_here.begin (); l != libs_by_name_here.end (); ++l) {
try {
db::LibraryManager::instance ().register_lib (l->second);
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
} catch (...) {
}
}
}
@ -280,8 +369,15 @@ LibraryController::sync_files ()
try {
std::pair<bool, db::lib_id_type> li = db::LibraryManager::instance ().lib_by_name (lf->second.name, lf->second.tech);
if (li.first) {
if (! lf->second.tech.empty ()) {
tl::log << "Unregistering lib '" << lf->second.name << "' for technology '" << *lf->second.tech.begin () << "' as the file no longer exists: " << lf->first;
} else {
tl::log << "Unregistering lib '" << lf->second.name << "' as the file no longer exists: " << lf->first;
}
db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second));
}
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
} catch (...) {
}
}

View File

@ -4507,6 +4507,7 @@ public:
menu_entries.push_back (lay::config_menu_item ("show_markers", at, tl::to_string (QObject::tr ("Show Markers")), cfg_markers_visible, "?"));
menu_entries.push_back (lay::config_menu_item ("show_texts", at, tl::to_string (QObject::tr ("Show Texts")), cfg_text_visible, "?"));
menu_entries.push_back (lay::config_menu_item ("show_cell_boxes", at, tl::to_string (QObject::tr ("Show Cell Frames")), cfg_cell_box_visible, "?"));
menu_entries.push_back (lay::config_menu_item ("show_ghost_cells", at, tl::to_string (QObject::tr ("Show Unresolved References")), cfg_ghost_cells_visible, "?"));
menu_entries.push_back (lay::config_menu_item ("no_stipples", at, tl::to_string (QObject::tr ("Show Layers Without Fill")), cfg_no_stipple, "?"));
menu_entries.push_back (lay::config_menu_item ("synchronized_views", at, tl::to_string (QObject::tr ("Synchronized Views")), cfg_synchronized_views, "?"));
menu_entries.push_back (lay::config_menu_item ("edit_top_level_selection:edit_mode", at, tl::to_string (QObject::tr ("Select Top Level Objects")), edt::cfg_edit_top_level_selection, "?"));

View File

@ -721,6 +721,8 @@ InstFinder::InstFinder (bool point_mode, bool top_level_sel, bool full_arrays, b
m_full_arrays (full_arrays),
m_enclose_insts (enclose_inst),
m_visible_layers (visible_layers),
m_consider_ghost_cells (true),
m_consider_normal_cells (true),
mp_view (0),
mp_progress (0)
{
@ -805,6 +807,12 @@ InstFinder::checkpoint ()
}
}
bool
InstFinder::consider_cell (const db::Cell &cell) const
{
return cell.is_ghost_cell () ? m_consider_ghost_cells : m_consider_normal_cells;
}
void
InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const db::Box & /*scan_box*/, const db::DCplxTrans &vp, const db::ICplxTrans &t, int level)
{
@ -818,15 +826,18 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
++*mp_progress;
// look for instances to check here ..
db::Cell::touching_iterator inst = cell.begin_touching (search_box);
while (! inst.at_end ()) {
for (db::Cell::touching_iterator inst = cell.begin_touching (search_box); ! inst.at_end (); ++inst) {
const db::CellInstArray &cell_inst = inst->cell_inst ();
const db::Cell &inst_cell = layout ().cell (cell_inst.object ().cell_index ());
++*mp_progress;
// just consider the instances exactly at the last level of
if (! consider_cell (inst_cell)) {
continue;
}
// just consider the instances exactly at the last level of
// hierarchy (this is where the boxes are drawn) or of cells that
// are hidden.
if (level == max_level () - 1 || inst_cell.is_proxy () || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
@ -887,21 +898,22 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
}
++inst;
}
} else {
// look for instances to check here ..
db::Cell::touching_iterator inst = cell.begin_touching (search_box);
while (! inst.at_end ()) {
for (db::Cell::touching_iterator inst = cell.begin_touching (search_box); ! inst.at_end (); ++inst) {
checkpoint ();
const db::CellInstArray &cell_inst = inst->cell_inst ();
const db::Cell &inst_cell = layout ().cell (cell_inst.object ().cell_index ());
if (! consider_cell (inst_cell)) {
continue;
}
// just consider the instances exactly at the last level of
// hierarchy (this is where the boxes are drawn) or if of cells that
// are hidden.
@ -909,7 +921,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
db::box_convert <db::CellInst, false> bc (layout ());
for (db::CellInstArray::iterator p = cell_inst.begin_touching (search_box, bc); ! p.at_end (); ++p) {
checkpoint ();
bool match = false;
@ -1000,8 +1012,6 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
}
++inst;
}
}

View File

@ -343,7 +343,17 @@ public:
bool find (LayoutViewBase *view, unsigned int cv_index, const db::DCplxTrans &trans, const db::DBox &region_mu);
bool find (LayoutViewBase *view, const db::DBox &region_mu);
void consider_ghost_cells (bool f)
{
m_consider_ghost_cells = f;
}
void consider_normal_cells (bool f)
{
m_consider_normal_cells = f;
}
iterator begin () const
{
return m_founds.begin ();
@ -360,6 +370,7 @@ private:
virtual void visit_cell (const db::Cell &cell, const db::Box &hit_box, const db::Box &scan_box, const db::DCplxTrans &vp, const db::ICplxTrans &t, int level);
bool find_internal (LayoutViewBase *view, unsigned int cv_index, const db::DCplxTrans &trans_mu, const db::DBox &region_mu);
bool consider_cell (const db::Cell &cell) const;
unsigned int m_cv_index;
db::cell_index_type m_topcell;
@ -369,6 +380,8 @@ private:
bool m_full_arrays;
bool m_enclose_insts;
bool m_visible_layers;
bool m_consider_ghost_cells;
bool m_consider_normal_cells;
std::vector<int> m_visible_layer_indexes;
LayoutViewBase *mp_view;
tl::AbsoluteProgress *mp_progress;

View File

@ -343,6 +343,7 @@ LayoutViewBase::init (db::Manager *mgr)
m_box_font = 0;
m_min_size_for_label = 16;
m_cell_box_visible = true;
m_ghost_cells_visible = true;
m_text_visible = true;
m_default_font_size = lay::FixedFont::default_font_size ();
m_text_lazy_rendering = true;
@ -964,6 +965,13 @@ LayoutViewBase::configure (const std::string &name, const std::string &value)
cell_box_visible (flag);
return true;
} else if (name == cfg_ghost_cells_visible) {
bool flag;
tl::from_string (value, flag);
ghost_cells_visible (flag);
return true;
} else if (name == cfg_cell_box_color) {
tl::Color color;
@ -4333,6 +4341,62 @@ LayoutViewBase::set_view_ops ()
}
}
// ghost cells
if (m_ghost_cells_visible) {
lay::ViewOp vop, vopv;
// context level
if (m_ctx_color.is_valid ()) {
vop = lay::ViewOp (m_ctx_color.rgb (), lay::ViewOp::Copy, 0, 0, 0);
} else {
vop = lay::ViewOp (lay::LayerProperties::brighter (box_color.rgb (), brightness_for_context), lay::ViewOp::Copy, 0, 0, 0);
}
vopv = vop;
vopv.shape (lay::ViewOp::Cross);
vopv.width (mark_size);
// fill, frame, text, vertex
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vop);
view_ops.push_back (vop);
view_ops.push_back (vopv);
// child level
if (m_child_ctx_color.is_valid ()) {
vop = lay::ViewOp (m_child_ctx_color.rgb (), lay::ViewOp::Copy, 0, 0, 0);
} else {
vop = lay::ViewOp (lay::LayerProperties::brighter (box_color.rgb (), brightness_for_context), lay::ViewOp::Copy, 0, 0, 0);
}
vopv = vop;
vopv.shape (lay::ViewOp::Cross);
vopv.width (mark_size);
// fill, frame, text, vertex
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vop);
view_ops.push_back (vop);
view_ops.push_back (vopv);
// current level
vop = lay::ViewOp (box_color.rgb (), lay::ViewOp::Copy, 0, 0, 0);
vopv = vop;
vopv.shape (lay::ViewOp::Cross);
vopv.width (mark_size);
// fill, frame, text, vertex
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vop);
view_ops.push_back (vop);
view_ops.push_back (vopv);
} else {
// invisible
for (unsigned int i = 0; i < (unsigned int) planes_per_layer; ++i) { // frame, fill, vertex, text
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
}
}
// sanity check: number of planes defined in layRedrawThreadWorker must match to view_ops layout
tl_assert (view_ops.size () == (size_t)cell_box_planes);
@ -5385,7 +5449,16 @@ LayoutViewBase::cell_box_visible (bool vis)
}
}
void
void
LayoutViewBase::ghost_cells_visible (bool vis)
{
if (m_ghost_cells_visible != vis) {
m_ghost_cells_visible = vis;
update_content ();
}
}
void
LayoutViewBase::text_font (unsigned int f)
{
if (m_text_font != f) {

View File

@ -1123,6 +1123,19 @@ public:
return m_cell_box_visible;
}
/**
* @brief Visibility of ghost cells
*/
void ghost_cells_visible (bool vis);
/**
* @brief Visibility of ghost cells
*/
bool ghost_cells_visible () const
{
return m_ghost_cells_visible;
}
/**
* @brief Min instance label size setter
*/
@ -2929,6 +2942,7 @@ private:
unsigned int m_box_font;
int m_min_size_for_label;
bool m_cell_box_visible;
bool m_ghost_cells_visible;
tl::Color m_marker_color;
int m_marker_line_width;

View File

@ -59,6 +59,7 @@ public:
options.push_back (std::pair<std::string, std::string> (cfg_cell_box_text_transform, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_cell_box_color, "auto"));
options.push_back (std::pair<std::string, std::string> (cfg_cell_box_visible, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_ghost_cells_visible, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_text_color, "auto"));
options.push_back (std::pair<std::string, std::string> (cfg_text_visible, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_text_lazy_rendering, "true"));

View File

@ -316,6 +316,73 @@ RedrawThreadWorker::perform_task (tl::Task *task)
transfer ();
// Draw the ghost cells
// HINT: the order in which the planes are delivered (the index stored in the first member of the pair below)
// must correspond with the order by which the ViewOp's are created inside LayoutView::set_view_ops
m_buffers.clear ();
for (unsigned int i = 0; i < (unsigned int) planes_per_layer / 3; ++i) {
// context level planes
unsigned int i1 = plain_cell_box_planes + i;
mp_canvas->initialize_plane (m_planes[i], i1);
m_buffers.push_back (std::make_pair (i1, m_planes [i]));
// child level planes (if used)
unsigned int i2 = plain_cell_box_planes + i + planes_per_layer / 3;
mp_canvas->initialize_plane (m_planes [i + planes_per_layer / 3], i2);
m_buffers.push_back (std::make_pair (i2, m_planes [i + planes_per_layer / 3]));
// current level planes
unsigned int i3 = plain_cell_box_planes + i + 2 * (planes_per_layer / 3);
mp_canvas->initialize_plane (m_planes [i + 2 * (planes_per_layer / 3)], i3);
m_buffers.push_back (std::make_pair (i3, m_planes [i + 2 * (planes_per_layer / 3)]));
}
// detect whether the text planes are empty. If not, the whole text plane must be redrawn to account for clipped texts
text_planes_empty = true;
for (unsigned int i = 0; i < (unsigned int) planes_per_layer && text_planes_empty; i += (unsigned int) planes_per_layer / 3) {
lay::Bitmap *text = dynamic_cast<lay::Bitmap *> (m_planes[i + 2]);
if (text && ! text->empty ()) {
text_planes_empty = false;
}
}
text_redraw_regions = m_redraw_region;
if (! text_planes_empty) {
// if there are non-empty text planes, redraw the whole area for texts
text_redraw_regions.clear ();
text_redraw_regions.push_back(db::Box(0, 0, mp_canvas->canvas_width (), mp_canvas->canvas_height ()));
for (unsigned int i = 0; i < (unsigned int) planes_per_layer; i += (unsigned int) planes_per_layer / 3) {
lay::Bitmap *text = dynamic_cast<lay::Bitmap *> (m_planes[i + 2]);
if (text) {
text->clear ();
}
}
}
for (std::set< std::pair<db::DCplxTrans, int> >::const_iterator b = m_box_variants.begin (); b != m_box_variants.end (); ++b) {
const lay::CellView &cv = m_cellviews [b->second];
if (cv.is_valid () && ! cv->layout ().under_construction () && ! (cv->layout ().manager () && cv->layout ().manager ()->transacting ())) {
mp_layout = &cv->layout ();
m_cv_index = b->second;
db::CplxTrans trans = m_vp_trans * b->first * db::CplxTrans (mp_layout->dbu ());
iterate_variants (m_redraw_region, cv.cell_index (), trans, &RedrawThreadWorker::draw_boxes_for_ghosts);
iterate_variants (text_redraw_regions, cv.cell_index (), trans, &RedrawThreadWorker::draw_box_properties_for_ghosts);
}
}
transfer ();
// draw guiding and error shapes
// HINT: the order in which the planes are delivered (the index stored in the first member of the pair below)
// must correspond with the order by which the ViewOp's are created inside LayoutView::set_view_ops
m_buffers.clear ();
@ -689,31 +756,51 @@ cells_in (const db::Layout *layout, const db::Cell &cell,
}
bool
RedrawThreadWorker::need_draw_box (const db::Layout *layout, const db::Cell &cell, int level)
RedrawThreadWorker::need_draw_box (const db::Layout *layout, const db::Cell &cell, int level, bool for_ghosts)
{
if (level > m_to_level) {
return false;
}
if (m_ghost_cells.size () > (size_t) m_cv_index && ! m_ghost_cells [m_cv_index].empty ()) {
std::set <std::pair <int, db::cell_index_type> > cache;
if (cells_in (layout, cell, m_ghost_cells [m_cv_index], m_to_level - level, cache)) {
return true;
} else if (for_ghosts) {
if (m_ghost_cells.size () > (size_t) m_cv_index && ! m_ghost_cells [m_cv_index].empty ()) {
std::set <std::pair <int, db::cell_index_type> > cache;
if (cells_in (layout, cell, m_ghost_cells [m_cv_index], m_to_level - level, cache)) {
return true;
}
}
}
if (m_hidden_cells.size () > (size_t) m_cv_index && ! m_hidden_cells [m_cv_index].empty ()) {
std::set <std::pair <int, db::cell_index_type> > cache;
if (cells_in (layout, cell, m_hidden_cells [m_cv_index], m_to_level - level, cache)) {
return true;
return false;
} else {
if (m_hidden_cells.size () > (size_t) m_cv_index && ! m_hidden_cells [m_cv_index].empty ()) {
std::set <std::pair <int, db::cell_index_type> > cache;
if (cells_in (layout, cell, m_hidden_cells [m_cv_index], m_to_level - level, cache)) {
return true;
}
}
}
return int (cell.hierarchy_levels ()) + level >= m_to_level;
return int (cell.hierarchy_levels ()) + level >= m_to_level;
}
}
void
RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &redraw_regions, int level)
{
draw_boxes_impl (drawing_context, ci, trans, redraw_regions, level, false);
}
void
RedrawThreadWorker::draw_boxes_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &redraw_regions, int level)
{
draw_boxes_impl (drawing_context, ci, trans, redraw_regions, level, true);
}
void
RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &redraw_regions, int level, bool for_ghosts)
{
// do not draw, if there is nothing to draw
if (mp_layout->cells () <= ci || redraw_regions.empty ()) {
@ -723,7 +810,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
const db::Cell &cell = mp_layout->cell (ci);
// we will never come to a valid level ..
if (! need_draw_box (mp_layout, cell, level)) {
if (! need_draw_box (mp_layout, cell, level, for_ghosts)) {
return;
}
if (cell_var_cached (ci, trans)) {
@ -731,12 +818,12 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
}
for (std::vector<db::Box>::const_iterator b = redraw_regions.begin (); b != redraw_regions.end (); ++b) {
draw_boxes (drawing_context, ci, trans, *b, level);
draw_boxes_impl (drawing_context, ci, trans, *b, level, for_ghosts);
}
}
void
RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level)
RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, bool for_ghosts)
{
lay::Renderer &r = *mp_renderer;
const db::Cell &cell = mp_layout->cell (ci);
@ -749,7 +836,12 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
// small cell dropped
} else if (level == m_to_level || cell.is_ghost_cell () || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())) {
} else if (for_ghosts && cell.is_ghost_cell ()) {
// paint the box on this level
draw_cell (drawing_context, level, trans, bbox, empty_cell, mp_layout->display_name (ci));
} else if (! for_ghosts && ! cell.is_ghost_cell () && (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()))) {
// paint the box on this level
draw_cell (drawing_context, level, trans, bbox, empty_cell, mp_layout->display_name (ci));
@ -759,7 +851,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
db::DBox dbbox = trans * bbox;
if (!empty_cell && (dbbox.width () < 1.5 && dbbox.height () < 1.5)) {
if (need_draw_box (mp_layout, cell, level)) {
if (need_draw_box (mp_layout, cell, level, for_ghosts)) {
// the cell is a very small box and we know there must be
// some level at which to draw the boundary: just draw it
// here and stop looking further down ..
@ -836,7 +928,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
if (simplify) {
// The array can be simplified if there are levels below to draw
if (need_draw_box (mp_layout, mp_layout->cell (new_ci), level + 1)) {
if (need_draw_box (mp_layout, mp_layout->cell (new_ci), level + 1, for_ghosts)) {
unsigned int plane_group = 2;
if (drawing_context) {
@ -865,7 +957,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
test_snapshot (0);
db::ICplxTrans t (cell_inst.complex_trans (*p));
db::Box new_vp = safe_transformed_box (*v, t.inverted ());
draw_boxes (drawing_context, new_ci, trans * t, new_vp, level + 1);
draw_boxes_impl (drawing_context, new_ci, trans * t, new_vp, level + 1, for_ghosts);
if (p.quad_id () > 0 && p.quad_id () != qid) {
@ -902,18 +994,30 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
}
void
void
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level)
{
draw_box_properties_impl (drawing_context, ci, trans, vp, level, false);
}
void
RedrawThreadWorker::draw_box_properties_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level)
{
draw_box_properties_impl (drawing_context, ci, trans, vp, level, true);
}
void
RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level, bool for_ghosts)
{
if (! m_text_visible) {
return;
}
draw_box_properties (drawing_context, ci, trans, vp, level, 0);
draw_box_properties_impl (drawing_context, ci, trans, vp, level, 0, for_ghosts);
}
void
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level, db::properties_id_type prop_id)
RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level, db::properties_id_type prop_id, bool for_ghosts)
{
// do not draw, if there is nothing to draw
if (mp_layout->cells () <= ci || vp.empty ()) {
@ -923,7 +1027,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
const db::Cell &cell = mp_layout->cell (ci);
// we will never come to a valid level ..
if (! need_draw_box (mp_layout, cell, level)) {
if (! need_draw_box (mp_layout, cell, level, for_ghosts)) {
return;
}
if (cell_var_cached (ci, trans)) {
@ -931,12 +1035,12 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
}
for (std::vector<db::Box>::const_iterator b = vp.begin (); b != vp.end (); ++b) {
draw_box_properties (drawing_context, ci, trans, *b, level, prop_id);
draw_box_properties_impl (drawing_context, ci, trans, *b, level, prop_id, for_ghosts);
}
}
void
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, db::properties_id_type prop_id)
RedrawThreadWorker::draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, db::properties_id_type prop_id, bool for_ghosts)
{
const db::Cell &cell = mp_layout->cell (ci);
@ -948,7 +1052,12 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
// small cell dropped
} else if (level == m_to_level || cell.is_ghost_cell () || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())) {
} else if (for_ghosts && cell.is_ghost_cell ()) {
// paint the box on this level
draw_cell_properties (drawing_context, level, trans, bbox, prop_id);
} else if (! for_ghosts && ! cell.is_ghost_cell () && (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()))) {
// paint the box on this level
draw_cell_properties (drawing_context, level, trans, bbox, prop_id);
@ -1036,7 +1145,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
test_snapshot (0);
db::ICplxTrans t (cell_inst.complex_trans (*p));
db::Box new_vp = safe_transformed_box (*v, t.inverted ());
draw_box_properties (drawing_context, new_ci, trans * t, new_vp, level + 1, cell_inst_prop);
draw_box_properties_impl (drawing_context, new_ci, trans * t, new_vp, level + 1, cell_inst_prop, for_ghosts);
}

View File

@ -44,7 +44,8 @@ class CanvasPlane;
// some helpful constants
const int planes_per_layer = 12;
const int cell_box_planes = planes_per_layer; // for cell boxes
const int plain_cell_box_planes = planes_per_layer; // for cell boxes, not including ghost_cells
const int cell_box_planes = planes_per_layer * 2; // for cell boxes, including ghost cells
const int guiding_shape_planes = planes_per_layer; // for guiding shapes
const int special_planes_before = cell_box_planes + guiding_shape_planes;
const int special_planes_after = 1;
@ -181,11 +182,15 @@ private:
void draw_layer_wo_cache (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vv, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot);
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, Bitmap *opt_bitmap);
void draw_boxes_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level);
void draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, bool for_ghosts);
void draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, bool for_ghosts);
void draw_box_properties_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, db::properties_id_type prop_id);
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, db::properties_id_type prop_id);
void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, bool for_ghosts);
void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, db::properties_id_type prop_id, bool for_ghosts);
void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, db::properties_id_type prop_id, bool for_ghosts);
void draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, bool empty_cell, const std::string &txt);
void draw_cell_properties (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, db::properties_id_type prop_id);
void draw_cell_shapes (const db::CplxTrans &trans, const db::Cell &cell, const db::Box &vp, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text);
@ -199,7 +204,7 @@ private:
bool any_shapes (db::cell_index_type cell_index, unsigned int levels);
bool any_text_shapes (db::cell_index_type cell_index, unsigned int levels);
bool any_cell_box (db::cell_index_type cell_index, unsigned int levels);
bool need_draw_box (const db::Layout *layout, const db::Cell &cell, int level);
bool need_draw_box (const db::Layout *layout, const db::Cell &cell, int level, bool for_ghosts);
RedrawThread *mp_redraw_thread;
std::vector <db::Box> m_redraw_region;

View File

@ -95,6 +95,7 @@ static const std::string cfg_cell_box_text_font ("inst-label-font");
static const std::string cfg_cell_box_text_transform ("inst-label-transform");
static const std::string cfg_cell_box_color ("inst-color");
static const std::string cfg_cell_box_visible ("inst-visible");
static const std::string cfg_ghost_cells_visible ("ghost-cells-visible");
static const std::string cfg_text_color ("text-color");
static const std::string cfg_text_visible ("text-visible");
static const std::string cfg_text_lazy_rendering ("text-lazy-rendering");

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>631</width>
<height>320</height>
<width>656</width>
<height>397</height>
</rect>
</property>
<property name="windowTitle">
@ -21,13 +21,33 @@
<number>9</number>
</property>
<item>
<widget class="QGroupBox" name="cell_group">
<property name="title">
<widget class="QCheckBox" name="cell_boxes_visible">
<property name="text">
<string>Show cell boxes</string>
</property>
<property name="checkable">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ghost_cells_visible">
<property name="text">
<string>Show unresolved references (ghost cells) </string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="cell_group">
<property name="title">
<string>Cell box appearance</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout">
<property name="margin" stdset="0">
<number>9</number>

View File

@ -207,7 +207,10 @@ LayoutViewConfigPage2a::setup (lay::Dispatcher *root)
mp_ui->cell_xform_text_cbx->setChecked (flag);
root->config_get (cfg_cell_box_visible, flag);
mp_ui->cell_group->setChecked (flag);
mp_ui->cell_boxes_visible->setChecked (flag);
root->config_get (cfg_ghost_cells_visible, flag);
mp_ui->ghost_cells_visible->setChecked (flag);
int font = 0;
root->config_get (cfg_cell_box_text_font, font);
@ -247,7 +250,8 @@ LayoutViewConfigPage2a::commit (lay::Dispatcher *root)
root->config_set (cfg_cell_box_text_transform, mp_ui->cell_xform_text_cbx->isChecked ());
root->config_set (cfg_cell_box_text_font, mp_ui->cell_font_cb->currentIndex ());
root->config_set (cfg_cell_box_color, mp_ui->cell_box_color_pb->get_color (), ColorConverter ());
root->config_set (cfg_cell_box_visible, mp_ui->cell_group->isChecked ());
root->config_set (cfg_cell_box_visible, mp_ui->cell_boxes_visible->isChecked ());
root->config_set (cfg_ghost_cells_visible, mp_ui->ghost_cells_visible->isChecked ());
root->config_set (cfg_guiding_shape_visible, mp_ui->pcell_gs_group->isChecked ());
root->config_set (cfg_guiding_shape_line_width, mp_ui->pcell_gs_lw->value ());