Merge pull request #315 from KLayout/lib-browser

Lib browser
This commit is contained in:
Matthias Köfferlein 2019-08-18 17:31:02 +02:00 committed by GitHub
commit bf41da69da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 2272 additions and 236 deletions

View File

@ -1186,7 +1186,7 @@ Layout::allocate_new_cell ()
}
void
Layout::cleanup ()
Layout::cleanup (const std::set<db::cell_index_type> &keep)
{
// deleting cells may create new top cells which need to be deleted as well, hence we iterate
// until there are no more cells to delete
@ -1200,6 +1200,10 @@ Layout::cleanup ()
}
}
for (std::set<db::cell_index_type>::const_iterator k = keep.begin (); k != keep.end (); ++k) {
cells_to_delete.erase (*k);
}
if (cells_to_delete.empty ()) {
break;
}

View File

@ -45,6 +45,7 @@
#include <cstring>
#include <map>
#include <set>
#include <string>
#include <list>
#include <vector>
@ -1446,9 +1447,10 @@ public:
/**
* @brief Cleans up the layout
*
* This method removes proxy objects which are no longer used
* This method removes proxy objects which are no longer used.
* It can be given a list of cells which need to be kept.
*/
void cleanup ();
void cleanup (const std::set<db::cell_index_type> &keep = std::set<db::cell_index_type> ());
/**
* @brief Implementation of the undo operations

View File

@ -208,7 +208,7 @@ size_t LayoutToNetlist::link_net_to_parent_circuit (const Net *subcircuit_net, C
connected_clusters<db::PolygonRef> &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ());
size_t id = parent_net_clusters.insert_dummy (); // @@@
size_t id = parent_net_clusters.insert_dummy ();
parent_net_clusters.add_connection (id, db::ClusterInstance (subcircuit_net->cluster_id (), subcircuit_net->circuit ()->cell_index (), trans, 0));
return id;

View File

@ -51,6 +51,7 @@ Library::register_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly)
{
m_referrers.insert (std::make_pair (ly, 0)).first->second += 1;
m_refcount.insert (std::make_pair (lib_proxy->library_cell_index (), 0)).first->second += 1;
retired_state_changed_event ();
}
void
@ -73,10 +74,38 @@ Library::unregister_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly)
layout ().delete_cell (ci);
}
}
retired_state_changed_event ();
}
}
void
void
Library::retire_proxy (db::LibraryProxy *lib_proxy)
{
m_retired_count.insert (std::make_pair (lib_proxy->library_cell_index (), 0)).first->second += 1;
retired_state_changed_event ();
}
void
Library::unretire_proxy (db::LibraryProxy *lib_proxy)
{
std::map<db::cell_index_type, int>::iterator c = m_retired_count.find (lib_proxy->library_cell_index ());
if (c != m_retired_count.end ()) {
if (! --c->second) {
m_retired_count.erase (c);
}
retired_state_changed_event ();
}
}
bool
Library::is_retired (const db::cell_index_type library_cell_index) const
{
std::map<db::cell_index_type, int>::const_iterator i = m_refcount.find (library_cell_index);
std::map<db::cell_index_type, int>::const_iterator j = m_retired_count.find (library_cell_index);
return (i != m_refcount.end () && j != m_retired_count.end () && i->second == j->second);
}
void
Library::remap_to (db::Library *other)
{
// Hint: in the loop over the referrers we might unregister (delete from m_referrers) a referrer because no more cells refer to us.

View File

@ -28,6 +28,7 @@
#include "gsiObject.h"
#include "dbLayout.h"
#include "tlTypeTraits.h"
#include "tlObject.h"
#include <string>
@ -45,7 +46,7 @@ class Layout;
* is provided. To do so, this class must be reimplemented.
*/
class DB_PUBLIC Library
: public gsi::ObjectBase
: public gsi::ObjectBase, public tl::Object
{
public:
/**
@ -162,6 +163,26 @@ public:
*/
void unregister_proxy (db::LibraryProxy *lib_proxy, db::Layout *layout);
/**
* @brief Retires a LibraryProxy in the given layout
*
* A proxy becomes entirely retired if the refcount is equal to the
* retired count. This feature is used to decide whether a proxy
* is actually used or only present as a shadow object for the transaction
* management.
*/
void retire_proxy (db::LibraryProxy *lib_proxy);
/**
* @brief Unretires the Library proxy
*/
void unretire_proxy (db::LibraryProxy *lib_proxy);
/**
* @brief Gets a value indicating whether a proxy is entirely retired
*/
bool is_retired (const cell_index_type library_cell_index) const;
/**
* @brief Remap the library proxies to a different library
*
@ -169,6 +190,11 @@ public:
*/
void remap_to (db::Library *other);
/**
* @brief This event is fired if proxies get retired on unretired
*/
tl::Event retired_state_changed_event;
private:
std::string m_name;
std::string m_description;
@ -176,7 +202,7 @@ private:
lib_id_type m_id;
db::Layout m_layout;
std::map<db::Layout *, int> m_referrers;
std::map<db::cell_index_type, int> m_refcount;
std::map<db::cell_index_type, int> m_refcount, m_retired_count;
// no copying.
Library &operator=(const Library &);

View File

@ -59,6 +59,12 @@ LibraryProxy::unregister ()
if (layout ()) {
layout ()->unregister_lib_proxy (this);
}
if (db::LibraryManager::initialized ()) {
db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id);
if (lib) {
lib->retire_proxy (this);
}
}
}
void
@ -67,6 +73,12 @@ LibraryProxy::reregister ()
if (layout ()) {
layout ()->register_lib_proxy (this);
}
if (db::LibraryManager::initialized ()) {
db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id);
if (lib) {
lib->unretire_proxy (this);
}
}
}
void

View File

@ -262,10 +262,18 @@ class DB_PUBLIC Transaction
{
public:
Transaction (db::Manager *manager, const std::string &desc)
: mp_manager (manager)
: mp_manager (manager), m_transaction_id (0)
{
if (mp_manager) {
mp_manager->transaction (desc);
m_transaction_id = mp_manager->transaction (desc);
}
}
Transaction (db::Manager *manager, const std::string &desc, db::Manager::transaction_id_t join_with)
: mp_manager (manager), m_transaction_id (0)
{
if (mp_manager) {
m_transaction_id = mp_manager->transaction (desc, join_with);
}
}
@ -277,8 +285,14 @@ public:
}
}
db::Manager::transaction_id_t id () const
{
return m_transaction_id;
}
private:
db::Manager *mp_manager;
db::Manager::transaction_id_t m_transaction_id;
// no copying.
Transaction (const Transaction &);

View File

@ -3005,9 +3005,6 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph
++j;
}
if (i - ii == size_t(2)) {
printf("@@@1\n"); fflush(stdout);
}
align (ii, i, jj, j, DeviceConnectionDistance ());
for ( ; ii != i && jj != j; ++ii, ++jj) {

View File

@ -111,5 +111,22 @@ PCellDeclaration::map_parameters (const std::map<std::string, tl::Variant> &para
return new_param;
}
std::map<std::string, tl::Variant>
PCellDeclaration::named_parameters (const pcell_parameters_type &pv) const
{
std::map<std::string, tl::Variant> np;
const std::vector<db::PCellParameterDeclaration> &pcp = parameter_declarations ();
for (std::vector<PCellParameterDeclaration>::const_iterator pd = pcp.begin (); pd != pcp.end (); ++pd) {
size_t index = pd - pcp.begin ();
if (index >= pv.size ()) {
break;
}
np.insert (std::make_pair (pd->get_name (), pv [index]));
}
return np;
}
}

View File

@ -496,6 +496,11 @@ public:
*/
pcell_parameters_type map_parameters (const std::map<std::string, tl::Variant> &named_parameters) const;
/**
* @brief Converts a parameter vector to named parameters
*/
std::map<std::string, tl::Variant> named_parameters (const pcell_parameters_type &pv) const;
protected:
/**
* @brief Gets a value indicating whether the PCell wants caching of the parameter declarations

View File

@ -51,6 +51,7 @@ class DB_PUBLIC PCellHeader
{
public:
typedef std::map<const pcell_parameters_type *, db::PCellVariant *, PCellParametersCompareFunc> variant_map_t;
typedef variant_map_t::const_iterator variant_iterator;
/**
* @brief The default constructor
@ -112,6 +113,22 @@ public:
*/
void register_variant (PCellVariant *variant);
/**
* @brief Iterates the variants (begin)
*/
variant_iterator begin () const
{
return m_variant_map.begin ();
}
/**
* @brief Iterates the variants (end)
*/
variant_iterator end () const
{
return m_variant_map.end ();
}
/**
* @brief Get the PCell Id for this variant
*/

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PCellParametersDialog</class>
<widget class="QDialog" name="PCellParametersDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>429</height>
</rect>
</property>
<property name="windowTitle">
<string>Instantiation Path</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="edt::PCellParametersPage" name="parameters" native="true"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttons">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>edt::PCellParametersPage</class>
<extends>QWidget</extends>
<header>edtPCellParametersPage.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttons</sender>
<signal>rejected()</signal>
<receiver>PCellParametersDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>321</x>
<y>405</y>
</hint>
<hint type="destinationlabel">
<x>337</x>
<y>423</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttons</sender>
<signal>accepted()</signal>
<receiver>PCellParametersDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>427</x>
<y>405</y>
</hint>
<hint type="destinationlabel">
<x>443</x>
<y>425</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -20,7 +20,8 @@ HEADERS = \
edtService.h \
edtServiceImpl.h \
edtUtils.h \
edtCommon.h
edtCommon.h \
edtPCellParametersDialog.h
FORMS = \
AlignOptionsDialog.ui \
@ -41,6 +42,7 @@ FORMS = \
PolygonPropertiesPage.ui \
RoundCornerOptionsDialog.ui \
TextPropertiesPage.ui \
PCellParametersDialog.ui
SOURCES = \
edtConfig.cc \
@ -57,6 +59,7 @@ SOURCES = \
edtServiceImpl.cc \
edtUtils.cc \
gsiDeclEdt.cc \
edtPCellParametersDialog.cc
INCLUDEPATH += $$TL_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC

View File

@ -28,6 +28,7 @@
#include "edtEditorOptionsPages.h"
#include "edtPCellParametersPage.h"
#include "edtConfig.h"
#include "edtService.h"
#include "tlExceptions.h"
#include "layPlugin.h"
#include "layLayoutView.h"
@ -643,13 +644,7 @@ EditorOptionsInst::apply (lay::Plugin *root)
if (pc.first) {
const db::PCellDeclaration *pc_decl = layout->pcell_declaration (pc.second);
if (pc_decl) {
std::vector<tl::Variant> pv = mp_pcell_parameters->get_parameters ();
const std::vector<db::PCellParameterDeclaration> &pcp = pc_decl->parameter_declarations ();
for (size_t i = 0; i < std::min (pv.size (), pcp.size ()); ++i) {
param += tl::to_word_or_quoted_string (pcp [i].get_name ()) + ":";
param += pv [i].to_parsable_string ();
param += ";";
}
param = pcell_parameters_to_string (pc_decl->named_parameters (mp_pcell_parameters->get_parameters ()));
}
}
}
@ -742,6 +737,7 @@ EditorOptionsInst::setup (lay::Plugin *root)
std::map<std::string, tl::Variant> parameters;
try {
tl::Extractor ex (param.c_str ());
ex.test ("!"); // used to flag PCells
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n);

View File

@ -0,0 +1,65 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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 "edtPCellParametersDialog.h"
#include <QPushButton>
namespace edt
{
PCellParametersDialog::PCellParametersDialog (QWidget *parent)
: QDialog (parent)
{
setupUi (this);
connect (buttons->button (QDialogButtonBox::Apply), SIGNAL (clicked ()), this, SLOT (apply_pressed ()));
}
void
PCellParametersDialog::apply_pressed ()
{
emit parameters_changed ();
parameters_changed_event ();
}
std::vector<tl::Variant>
PCellParametersDialog::get_parameters ()
{
return parameters->get_parameters ();
}
void
PCellParametersDialog::set_parameters (const std::vector<tl::Variant> &p)
{
parameters->set_parameters (p);
}
int
PCellParametersDialog::exec (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &p)
{
parameters->setup (layout, view, cv_index, pcell_decl, p);
return QDialog::exec ();
}
}

View File

@ -0,0 +1,86 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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_edtPCellParametersDialog
#define HDR_edtPCellParametersDialog
#include "dbPCellDeclaration.h"
#include "ui_PCellParametersDialog.h"
#include <QDialog>
namespace lay
{
class LayoutView;
}
namespace edt
{
/**
* @brief A QScrollArea that displays and allows editing PCell parameters
*/
class PCellParametersDialog
: public QDialog, private Ui::PCellParametersDialog
{
Q_OBJECT
public:
/**
* @brief Constructor: create a dialog showing the given parameters
* @param parent The parent widget
*/
PCellParametersDialog (QWidget *parent);
/**
* @brief Executes the parameter dialog
* @param layout The layout in which the PCell instance resides
* @param view The layout view from which to take layers for example
* @param cv_index The index of the cellview in "view"
* @param pcell_decl The PCell declaration
* @param parameters The parameter values to show (if empty, the default values are used)
*/
int exec (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &p);
/**
* @brief Get the current parameters
*/
std::vector<tl::Variant> get_parameters ();
/**
* @brief Sets the given parameters as values
*/
void set_parameters (const std::vector<tl::Variant> &values);
tl::Event parameters_changed_event;
signals:
void parameters_changed ();
private slots:
void apply_pressed ();
};
}
#endif

View File

@ -129,15 +129,30 @@ static void set_value (const db::PCellParameterDeclaration &p, const db::Layout
}
PCellParametersPage::PCellParametersPage (QWidget *parent, const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters)
: QFrame (parent), mp_pcell_decl (pcell_decl), mp_layout (layout), mp_view (view), m_cv_index (cv_index)
: QFrame (parent)
{
init ();
setup (layout, view, cv_index, pcell_decl, parameters);
}
PCellParametersPage::PCellParametersPage (QWidget *parent)
: QFrame (parent)
{
init ();
}
void
PCellParametersPage::init ()
{
mp_pcell_decl = 0;
mp_layout = 0;
mp_view = 0;
m_cv_index = 0;
mp_parameters_area = 0;
QGridLayout *frame_layout = new QGridLayout (this);
setLayout (frame_layout);
mp_parameters_area = new QScrollArea (this);
frame_layout->addWidget (mp_parameters_area, 0, 0, 1, 2);
frame_layout->setRowStretch (0, 1);
mp_error_icon = new QLabel (this);
mp_error_icon->setPixmap (QPixmap (":/warn.png"));
mp_error_icon->hide ();
@ -153,9 +168,28 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, const db::Layout *lay
mp_error_label->hide ();
frame_layout->addWidget (mp_error_label, 1, 1, 1, 1);
frame_layout->setColumnStretch (1, 1);
}
void
PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters)
{
mp_pcell_decl = pcell_decl;
mp_layout = layout;
mp_view = view;
m_cv_index = cv_index;
m_parameters = parameters;
if (mp_parameters_area) {
delete mp_parameters_area;
}
m_widgets.clear ();
mp_parameters_area = new QScrollArea (this);
QGridLayout *frame_layout = dynamic_cast<QGridLayout *> (QFrame::layout ());
frame_layout->addWidget (mp_parameters_area, 0, 0, 1, 2);
frame_layout->setRowStretch (0, 1);
QFrame *fi = new QFrame (mp_parameters_area);
QWidget *inner_frame = fi;
fi->setFrameShape (QFrame::NoFrame);

View File

@ -57,7 +57,7 @@ public:
};
/**
* @brief Constructor: create a page showing the given parameters
* @brief Constructor: creates a page showing the given parameters
*
* @param parent The parent widget
* @param layout The layout in which the PCell instance resides
@ -68,6 +68,20 @@ public:
*/
PCellParametersPage (QWidget *parent, const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters);
/**
* @brief Default constructor
*
* Use "setup" to configure the page.
*/
PCellParametersPage (QWidget *parent);
/**
* @brief Delayed initialization
*
* Use this method to setup when the arguments are not available in the constructor
*/
void setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters);
/**
* @brief Gets the pages current state
*/
@ -110,6 +124,8 @@ private:
lay::LayoutView *mp_view;
int m_cv_index;
db::pcell_parameters_type m_parameters;
void init ();
};
}

View File

@ -60,6 +60,45 @@ ac_from_buttons (unsigned int buttons)
// -------------------------------------------------------------
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> &parameters)
{
std::string param;
param = "!"; // flags PCells
for (std::map<std::string, tl::Variant>::const_iterator p = parameters.begin (); p != parameters.end (); ++p) {
param += tl::to_word_or_quoted_string (p->first);
param += ":";
param += p->second.to_parsable_string ();
param += ";";
}
return param;
}
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s)
{
tl::Extractor ex (s.c_str ());
std::map<std::string, tl::Variant> pm;
ex.test ("!");
try {
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n);
ex.test (":");
ex.read (pm.insert (std::make_pair (n, tl::Variant ())).first->second);
ex.test (";");
}
} catch (...) {
// ignore errors
}
return pm;
}
// -------------------------------------------------------------
Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator::flags_type flags)
: lay::ViewService (view->view_object_widget ()),
lay::Editable (view),

View File

@ -57,6 +57,18 @@ extern lay::angle_constraint_type ac_from_buttons (unsigned int buttons);
// -------------------------------------------------------------
/**
* @brief Utility function: serialize PCell parameters into a string
*/
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> &parameters);
/**
* @brief Utility: deserialize PCell parameters from a string
*/
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s);
// -------------------------------------------------------------
class EDT_PUBLIC Service
: public lay::ViewService,
public lay::Editable,

View File

@ -25,6 +25,8 @@
#include "edtServiceImpl.h"
#include "edtPropertiesPages.h"
#include "edtInstPropertiesPage.h"
#include "edtPCellParametersDialog.h"
#include "edtService.h"
#include "dbEdge.h"
#include "dbLibrary.h"
#include "dbLibraryManager.h"
@ -1107,12 +1109,12 @@ PathService::config_finalize ()
InstService::InstService (db::Manager *manager, lay::LayoutView *view)
: edt::Service (manager, view),
m_angle (0.0), m_scale (1.0),
m_mirror (false), m_cell_name (""), m_lib_name (""), m_pcell_parameters (""),
m_mirror (false), m_is_pcell (false),
m_array (false), m_rows (1), m_columns (1),
m_row_x (0.0), m_row_y (0.0), m_column_x (0.0), m_column_y (0.0),
m_place_origin (false), m_reference_transaction_id (0),
m_needs_update (true), m_has_valid_cell (false), m_in_drag_drop (false),
m_current_cell (0), m_drag_drop_cell (0), m_cv_index (-1)
m_current_cell (0), mp_current_layout (0), mp_pcell_decl (0), m_cv_index (-1)
{
// .. nothing yet ..
}
@ -1138,26 +1140,75 @@ InstService::do_activated ()
return true; // start editing immediately
}
tl::Variant
InstService::get_default_layer_for_pcell ()
{
lay::LayerPropertiesConstIterator cl = view ()->current_layer ();
if (! cl.is_null () && ! cl->has_children () && (cl->source (true).cv_index() < 0 || cl->source (true).cv_index () == view ()->active_cellview_index ())) {
db::LayerProperties lp = cl->source (true).layer_props ();
if (! lp.is_null ()) {
return tl::Variant (lp);
}
}
return tl::Variant ();
}
bool
InstService::drag_enter_event (const db::DPoint &p, const lay::DragDropDataBase *data)
{
const lay::CellDragDropData *cd = dynamic_cast <const lay::CellDragDropData *> (data);
if (view ()->is_editable () && cd && cd->layout () == & view ()->active_cellview ()->layout ()) {
if (view ()->is_editable () && cd && (cd->layout () == & view ()->active_cellview ()->layout () || cd->library ())) {
view ()->cancel ();
// NOTE: the cancel above might delete the cell we are dragging (if that is
// a non-placed PCell). Hence we need to check whether the cell still is valid
if (cd->layout ()->is_valid_cell_index (cd->cell_index ())) {
set_edit_marker (0);
set_edit_marker (0);
m_cv_index = view ()->active_cellview_index ();
m_in_drag_drop = true;
m_cv_index = view ()->active_cellview_index ();
m_in_drag_drop = true;
m_drag_drop_cell = cd->cell_index ();
if (cd->library ()) {
if (m_lib_name != cd->library ()->get_name ()) {
m_lib_name = cd->library ()->get_name ();
m_pcell_parameters.clear ();
}
} else {
m_lib_name.clear ();
}
m_is_pcell = false;
if (cd->is_pcell ()) {
const db::PCellDeclaration *pcell_decl = cd->layout ()->pcell_declaration (cd->cell_index ());
if (pcell_decl) {
if (m_cell_or_pcell_name != pcell_decl->name ()) {
m_cell_or_pcell_name = pcell_decl->name ();
m_pcell_parameters.clear ();
}
m_is_pcell = true;
// NOTE: we reuse previous parameters for convenience unless PCell or library has changed
const std::vector<db::PCellParameterDeclaration> &pd = pcell_decl->parameter_declarations();
for (std::vector<db::PCellParameterDeclaration>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
if (i->get_type () == db::PCellParameterDeclaration::t_layer && !i->is_hidden () && !i->is_readonly () && i->get_default ().is_nil ()) {
m_pcell_parameters.insert (std::make_pair (i->get_name (), get_default_layer_for_pcell ()));
} else {
m_pcell_parameters.insert (std::make_pair (i->get_name (), i->get_default ()));
}
}
do_begin_edit (p);
return true;
}
} else if (cd->layout ()->is_valid_cell_index (cd->cell_index ())) {
m_cell_or_pcell_name = cd->layout ()->cell_name (cd->cell_index ());
do_begin_edit (p);
return true;
}
@ -1197,14 +1248,69 @@ bool
InstService::drop_event (const db::DPoint & /*p*/, const lay::DragDropDataBase * /*data*/)
{
if (m_in_drag_drop) {
const lay::CellView &cv = view ()->cellview (m_cv_index);
if (! cv.is_valid ()) {
return false;
}
make_cell (cv);
bool accepted = true;
if (m_has_valid_cell && mp_pcell_decl) {
std::vector<tl::Variant> pv = mp_pcell_decl->map_parameters (m_pcell_parameters);
// Turn off the drag cursor for the modal dialog
QApplication::restoreOverrideCursor ();
// for PCells dragged show the parameter dialog for a chance to edit the initial parameters
if (! mp_pcell_parameters_dialog.get ()) {
mp_pcell_parameters_dialog.reset (new edt::PCellParametersDialog (view ()));
mp_pcell_parameters_dialog->parameters_changed_event.add (this, &InstService::apply_edits);
}
if (! mp_pcell_parameters_dialog->exec (mp_current_layout, view (), m_cv_index, mp_pcell_decl, pv)) {
accepted = false;
} else {
m_has_valid_cell = false;
m_pcell_parameters = mp_pcell_decl->named_parameters (mp_pcell_parameters_dialog->get_parameters ());
}
}
set_edit_marker (0);
do_finish_edit ();
if (accepted) {
do_finish_edit ();
} else {
do_cancel_edit ();
}
sync_to_config ();
return true;
} else {
return false;
}
}
void
InstService::sync_to_config ()
{
// push the current setup to configuration so the instance dialog will take these as default
// and "apply" of these instance properties doesn't fail because of insistency.
plugin_root ()->config_set (cfg_edit_inst_lib_name, m_lib_name);
plugin_root ()->config_set (cfg_edit_inst_cell_name, m_cell_or_pcell_name);
if (m_is_pcell) {
plugin_root ()->config_set (cfg_edit_inst_pcell_parameters, pcell_parameters_to_string (m_pcell_parameters));
} else {
plugin_root ()->config_set (cfg_edit_inst_pcell_parameters, std::string ());
}
plugin_root ()->config_end ();
}
void
InstService::do_begin_edit (const db::DPoint &p)
{
@ -1260,89 +1366,79 @@ InstService::do_begin_edit (const db::DPoint &p)
std::pair<bool, db::cell_index_type>
InstService::make_cell (const lay::CellView &cv)
{
if (m_in_drag_drop) {
return std::make_pair (true, m_drag_drop_cell);
}
if (m_has_valid_cell) {
return std::make_pair (true, m_current_cell);
}
// NOTE: do this at the beginning: creating a transaction might delete transactions behind the
// head transaction, hence releasing (thus: deleting) cells. To prevert interference, create
// the transaction at the beginning.
db::Transaction tr (manager (), tl::to_string (QObject::tr ("Create reference cell")), m_reference_transaction_id);
m_reference_transaction_id = tr.id ();
lay::LayerState layer_state = view ()->layer_snapshot ();
db::Layout *layout;
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
// find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected
if (lib) {
layout = &lib->layout ();
mp_current_layout = &lib->layout ();
} else {
layout = &cv->layout ();
mp_current_layout = &cv->layout ();
}
std::pair<bool, db::cell_index_type> ci (false, db::cell_index_type (0));
std::pair<bool, db::pcell_id_type> pci (false, db::pcell_id_type (0));
if (! m_is_pcell) {
ci = mp_current_layout->cell_by_name (m_cell_or_pcell_name.c_str ());
} else {
pci = mp_current_layout->pcell_by_name (m_cell_or_pcell_name.c_str ());
}
std::pair<bool, db::cell_index_type> ci = layout->cell_by_name (m_cell_name.c_str ());
std::pair<bool, db::pcell_id_type> pci = layout->pcell_by_name (m_cell_name.c_str ());
if (! ci.first && ! pci.first) {
// throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
return std::pair<bool, db::cell_index_type> (false, 0);
}
m_reference_transaction_id = manager ()->transaction (tl::to_string (QObject::tr ("Create reference cell")), m_reference_transaction_id);
db::cell_index_type inst_cell_index = ci.second;
try {
mp_pcell_decl = 0;
// instantiate the PCell
if (pci.first) {
// instantiate the PCell
if (pci.first) {
std::vector<tl::Variant> pv;
std::vector<tl::Variant> pv;
const db::PCellDeclaration *pc_decl = layout->pcell_declaration (pci.second);
if (pc_decl) {
mp_pcell_decl = mp_current_layout->pcell_declaration (pci.second);
if (mp_pcell_decl) {
std::map<std::string, tl::Variant> parameters;
tl::Extractor ex (m_pcell_parameters.c_str ());
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n);
ex.test (":");
ex.read (parameters.insert (std::make_pair (n, tl::Variant ())).first->second);
ex.test (";");
}
pv = mp_pcell_decl->map_parameters (m_pcell_parameters);
const std::vector<db::PCellParameterDeclaration> &pcp = pc_decl->parameter_declarations ();
for (std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin (); pd != pcp.end (); ++pd) {
std::map<std::string, tl::Variant>::const_iterator p = parameters.find (pd->get_name ());
if (p != parameters.end ()) {
pv.push_back (p->second);
} else {
pv.push_back (pd->get_default ());
}
}
}
inst_cell_index = layout->get_pcell_variant (pci.second, pv);
// make the parameters fit (i.e. PCells may not define consistent default parameters)
mp_pcell_decl->coerce_parameters (*mp_current_layout, pv);
}
// reference the library
if (lib) {
layout = & cv->layout ();
layout->cleanup ();
inst_cell_index = layout->get_lib_proxy (lib, inst_cell_index);
}
inst_cell_index = mp_current_layout->get_pcell_variant (pci.second, pv);
view ()->add_new_layers (layer_state);
manager ()->commit ();
} catch (...) {
manager ()->commit ();
throw;
}
// reference the library
if (lib) {
mp_current_layout = & cv->layout ();
inst_cell_index = mp_current_layout->get_lib_proxy (lib, inst_cell_index);
// remove unused references
std::set<db::cell_index_type> keep;
keep.insert (inst_cell_index);
mp_current_layout->cleanup (keep);
}
view ()->add_new_layers (layer_state);
m_has_valid_cell = true;
m_current_cell = inst_cell_index;
@ -1479,7 +1575,7 @@ bool
InstService::configure (const std::string &name, const std::string &value)
{
if (name == cfg_edit_inst_cell_name) {
m_cell_name = value;
m_cell_or_pcell_name = value;
m_needs_update = true;
return true; // taken
}
@ -1491,9 +1587,13 @@ InstService::configure (const std::string &name, const std::string &value)
}
if (name == cfg_edit_inst_pcell_parameters) {
m_pcell_parameters = value;
m_pcell_parameters = pcell_parameters_from_string (value);
m_is_pcell = ! value.empty ();
m_needs_update = true;
return true; // taken
}
if (name == cfg_edit_inst_place_origin) {
@ -1577,6 +1677,16 @@ InstService::config_finalize ()
edt::Service::config_finalize ();
}
void
InstService::apply_edits()
{
if (mp_pcell_decl && mp_pcell_parameters_dialog.get ()) {
m_pcell_parameters = mp_pcell_decl->named_parameters (mp_pcell_parameters_dialog->get_parameters ());
}
sync_to_config ();
}
void
InstService::update_marker ()
{

View File

@ -27,6 +27,8 @@
#include "edtService.h"
#include "edtConfig.h"
#include <memory>
namespace lay
{
class CellView;
@ -35,6 +37,8 @@ namespace lay
namespace edt
{
class PCellParametersDialog;
/**
* @brief Implementation of the edt::Service for generic shape editing
*/
@ -223,7 +227,9 @@ private:
double m_scale;
bool m_mirror;
db::DPoint m_disp;
std::string m_cell_name, m_lib_name, m_pcell_parameters;
std::string m_cell_or_pcell_name, m_lib_name;
std::map<std::string, tl::Variant> m_pcell_parameters;
bool m_is_pcell;
bool m_array;
unsigned int m_rows, m_columns;
double m_row_x, m_row_y, m_column_x, m_column_y;
@ -232,13 +238,19 @@ private:
bool m_needs_update;
bool m_has_valid_cell;
bool m_in_drag_drop;
db::cell_index_type m_current_cell, m_drag_drop_cell;
db::cell_index_type m_current_cell;
db::Layout *mp_current_layout;
const db::PCellDeclaration *mp_pcell_decl;
int m_cv_index;
db::ICplxTrans m_trans;
std::auto_ptr<edt::PCellParametersDialog> mp_pcell_parameters_dialog;
void update_marker ();
void apply_edits ();
bool get_inst (db::CellInstArray &inst);
std::pair<bool, db::cell_index_type> make_cell (const lay::CellView &cv);
tl::Variant get_default_layer_for_pcell ();
void sync_to_config ();
};
}

View File

@ -101,6 +101,3 @@ plugins.depends += lib rdb db
unit_tests.depends += plugins $$MAIN_DEPENDS
RESOURCES += \
laybasic/laybasic/layResources.qrc

View File

@ -17,6 +17,7 @@
<topic href="/manual/cell.xml"/>
<topic href="/manual/hier.xml"/>
<topic href="/manual/cell_list.xml"/>
<topic href="/manual/library_view.xml"/>
<topic href="/manual/hiding.xml"/>
<topic href="/manual/zoom.xml"/>
<topic href="/manual/global_trans.xml"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<doc>
<title>The Library View</title>
<keyword name="Library View"/>
<keyword name="View"/>
<p>
Beside the cell list, a library view is provided as a support view
for the layout panel. This sub-panel displays the libraries available
and allows browsing the cells and PCells inside a library.
</p>
<p>
By default, the library view is shown below the cell tree. You can
rearrange the views by dragging them at their title bar and docking
them in other places of the main window.
To reset the window arrangement to the default configuration, use "Restore Window" from the
"View" menu.
</p>
<p>
The library view shows the cells and PCells of one library. To select a library,
choose it from the selection box at the top of the library view.
</p>
<p>
PCells are shown with a small "gear" icon in the library view. If PCells are
instantiated, the variants in use are shown as entries below the PCell entry.
</p>
<p>
In edit mode, cells can conveniently be placed by dragging them from the
library view to the layout canvas. If a PCell variant is dragged, another
instance of this PCell variant is created. If a PCell master is dragged,
KLayout will pop up the PCell parameter definition dialog on drop.
</p>
</doc>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 KiB

After

Width:  |  Height:  |  Size: 776 KiB

View File

@ -18,7 +18,7 @@
<img src="/manual/main_window.png"/>
</p>
<h2>Left Part - The Hierarchy Browser and Navigator</h2>
<h2>Left Part - The Hierarchy Browser, Library View and Navigator</h2>
<p>
The left panel is the
@ -45,6 +45,20 @@
<img src="/manual/hierarchy_panel.png"/>
</p>
<p>
The sub-panel below the hierarchy browser is the library view. This view
shows the libraries registered in the system and their content:
</p>
<p>
<img src="/manual/library_view.png"/>
</p>
<p>
The library view is used to browse and place library cells, which can
be normal cells or PCells. Read more about the library view here: <link href="/manual/library_view.xml"/>.
</p>
<p>
The navigator is invisible by default but can be activated by checking the
"Navigator" menu item in the "View" menu. The navigator shows an overview

View File

@ -49,6 +49,7 @@ static const std::string cfg_navigator_all_hier_levels ("navigator-show-all-hier
static const std::string cfg_navigator_show_images ("navigator-show-images");
static const std::string cfg_show_layer_toolbox ("show-layer-toolbox");
static const std::string cfg_show_hierarchy_panel ("show-hierarchy-panel");
static const std::string cfg_show_libraries_view ("show-libraries-view");
static const std::string cfg_show_layer_panel ("show-layer-panel");
static const std::string cfg_window_state ("window-state");
static const std::string cfg_layout_file_watcher_enabled ("layout-file-watcher-enabled");

View File

@ -147,6 +147,8 @@
<file alias="browse_instances.xml">doc/manual/browse_instances.xml</file>
<file alias="browse_shapes.xml">doc/manual/browse_shapes.xml</file>
<file alias="cell_list.xml">doc/manual/cell_list.xml</file>
<file alias="library_view.xml">doc/manual/library_view.xml</file>
<file alias="library_view.png">doc/manual/library_view.png</file>
<file alias="cell.xml">doc/manual/cell.xml</file>
<file alias="clip.xml">doc/manual/clip.xml</file>
<file alias="copypaste_cell.xml">doc/manual/copypaste_cell.xml</file>

View File

@ -68,6 +68,7 @@ public:
options.push_back (std::pair<std::string, std::string> (cfg_show_toolbar, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_show_layer_toolbox, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_show_hierarchy_panel, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_show_libraries_view, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_show_layer_panel, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_layout_file_watcher_enabled, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_window_state, ""));

View File

@ -506,6 +506,13 @@ MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const cha
connect (mp_hp_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_hp_visible = true;
mp_libs_dock_widget = new QDockWidget (QObject::tr ("Libraries"), this);
mp_libs_dock_widget->setObjectName (QString::fromUtf8 ("libs_dock_widget"));
mp_libs_stack = new ControlWidgetStack (mp_libs_dock_widget, "libs_stack");
mp_libs_dock_widget->setWidget (mp_libs_stack);
connect (mp_libs_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
m_libs_visible = true;
mp_view_stack = new ViewWidgetStack (mp_main_frame);
mp_view_stack->setObjectName (QString::fromUtf8 ("view_stack"));
vbl->addWidget (mp_view_stack);
@ -537,6 +544,7 @@ MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const cha
#endif
addDockWidget(Qt::LeftDockWidgetArea, mp_navigator_dock_widget);
addDockWidget(Qt::LeftDockWidgetArea, mp_hp_dock_widget);
addDockWidget(Qt::LeftDockWidgetArea, mp_libs_dock_widget);
addDockWidget(Qt::RightDockWidgetArea, mp_lp_dock_widget);
addDockWidget(Qt::RightDockWidgetArea, mp_layer_toolbox_dock_widget);
@ -849,6 +857,7 @@ MainWindow::init_menu ()
MenuLayoutEntry ("show_layer_panel", tl::to_string (QObject::tr ("Layers")), std::make_pair (cfg_show_layer_panel, "?")),
MenuLayoutEntry ("show_layer_toolbox", tl::to_string (QObject::tr ("Layer Toolbox")), std::make_pair (cfg_show_layer_toolbox, "?")),
MenuLayoutEntry ("show_hierarchy_panel", tl::to_string (QObject::tr ("Cells")), std::make_pair (cfg_show_hierarchy_panel, "?")),
MenuLayoutEntry ("show_libraries_view", tl::to_string (QObject::tr ("Libraries")), std::make_pair (cfg_show_libraries_view, "?")),
MenuLayoutEntry ("reset_window_state", tl::to_string (QObject::tr ("Restore Window")), SLOT (cm_reset_window_state ())),
MenuLayoutEntry::separator ("selection_group"),
MenuLayoutEntry ("transient_selection", tl::to_string (QObject::tr ("Highlight Object Under Mouse")), std::make_pair (cfg_sel_transient_mode, "?")),
@ -1073,6 +1082,8 @@ MainWindow::dock_widget_visibility_changed (bool /*visible*/)
plugin_root ()->config_set (cfg_show_layer_panel, tl::to_string (!mp_lp_dock_widget->isHidden ()));
} else if (sender () == mp_hp_dock_widget) {
plugin_root ()->config_set (cfg_show_hierarchy_panel, tl::to_string (!mp_hp_dock_widget->isHidden ()));
} else if (sender () == mp_libs_dock_widget) {
plugin_root ()->config_set (cfg_show_libraries_view, tl::to_string (!mp_libs_dock_widget->isHidden ()));
} else if (sender () == mp_navigator_dock_widget) {
plugin_root ()->config_set (cfg_show_navigator, tl::to_string (!mp_navigator_dock_widget->isHidden ()));
} else if (sender () == mp_layer_toolbox_dock_widget) {
@ -1237,6 +1248,7 @@ MainWindow::close_all ()
mp_views.pop_back ();
mp_lp_stack->removeWidget (mp_views.size ());
mp_hp_stack->removeWidget (mp_views.size ());
mp_libs_stack->removeWidget (mp_views.size ());
mp_view_stack->removeWidget (mp_views.size ());
delete view;
@ -1685,6 +1697,17 @@ MainWindow::configure (const std::string &name, const std::string &value)
return true;
} else if (name == cfg_show_libraries_view) {
tl::from_string (value, m_libs_visible);
if (m_libs_visible) {
mp_libs_dock_widget->show ();
} else {
mp_libs_dock_widget->hide ();
}
return true;
} else if (name == cfg_show_layer_panel) {
tl::from_string (value, m_lp_visible);
@ -1797,6 +1820,7 @@ MainWindow::read_dock_widget_state ()
{
plugin_root ()->config_set (cfg_show_layer_panel, tl::to_string (!mp_lp_dock_widget->isHidden ()));
plugin_root ()->config_set (cfg_show_hierarchy_panel, tl::to_string (!mp_hp_dock_widget->isHidden ()));
plugin_root ()->config_set (cfg_show_libraries_view, tl::to_string (!mp_libs_dock_widget->isHidden ()));
plugin_root ()->config_set (cfg_show_navigator, tl::to_string (!mp_navigator_dock_widget->isHidden ()));
plugin_root ()->config_set (cfg_show_layer_toolbox, tl::to_string (!mp_layer_toolbox_dock_widget->isHidden ()));
}
@ -1810,6 +1834,12 @@ MainWindow::update_dock_widget_state ()
mp_hp_dock_widget->hide ();
}
if (m_libs_visible) {
mp_libs_dock_widget->show ();
} else {
mp_libs_dock_widget->hide ();
}
if (m_lp_visible) {
mp_lp_dock_widget->show ();
} else {
@ -3270,6 +3300,7 @@ MainWindow::select_view (int index)
mp_view_stack->raiseWidget (index);
mp_hp_stack->raiseWidget (index);
mp_lp_stack->raiseWidget (index);
mp_libs_stack->raiseWidget (index);
mp_setup_form->setup ();
}
@ -3694,6 +3725,7 @@ MainWindow::clone_current_view ()
mp_view_stack->addWidget (view);
mp_lp_stack->addWidget (view->layer_control_frame ());
mp_hp_stack->addWidget (view->hierarchy_control_frame ());
mp_libs_stack->addWidget (view->libraries_frame ());
bool f = m_disable_tab_selected;
m_disable_tab_selected = true;
@ -3940,6 +3972,7 @@ MainWindow::close_view (int index)
mp_view_stack->removeWidget (index);
mp_lp_stack->removeWidget (index);
mp_hp_stack->removeWidget (index);
mp_libs_stack->removeWidget (index);
view_closed_event (int (index));
@ -4312,6 +4345,7 @@ MainWindow::create_view ()
mp_view_stack->addWidget (mp_views.back ());
mp_lp_stack->addWidget (mp_views.back ()->layer_control_frame ());
mp_hp_stack->addWidget (mp_views.back ()->hierarchy_control_frame ());
mp_libs_stack->addWidget (mp_views.back ()->libraries_frame ());
bool f = m_disable_tab_selected;
m_disable_tab_selected = true;
@ -4373,6 +4407,7 @@ MainWindow::create_or_load_layout (const std::string *filename, const db::LoadLa
mp_view_stack->addWidget (mp_views.back ());
mp_lp_stack->addWidget (mp_views.back ()->layer_control_frame ());
mp_hp_stack->addWidget (mp_views.back ()->hierarchy_control_frame ());
mp_libs_stack->addWidget (mp_views.back ()->libraries_frame ());
bool f = m_disable_tab_selected;
m_disable_tab_selected = true;

View File

@ -872,9 +872,9 @@ private:
QToolBar *mp_tool_bar;
QDockWidget *mp_navigator_dock_widget;
lay::Navigator *mp_navigator;
QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget;
ControlWidgetStack *mp_hp_stack, *mp_lp_stack;
bool m_hp_visible, m_lp_visible, m_navigator_visible, m_layer_toolbox_visible;
QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget, *mp_libs_dock_widget;
ControlWidgetStack *mp_hp_stack, *mp_lp_stack, *mp_libs_stack;
bool m_hp_visible, m_lp_visible, m_libs_visible, m_navigator_visible, m_layer_toolbox_visible;
QDockWidget *mp_layer_toolbox_dock_widget;
lay::LayerToolbox *mp_layer_toolbox;
ViewWidgetStack *mp_view_stack;

View File

@ -384,7 +384,7 @@ CellSelectionForm::select_entry (lay::CellView::cell_index_type ci)
QModelIndex mi;
for (int c = 0; c < model->toplevel_items (); ++c) {
lay::CellTreeItem *item = model->toplevel_item (c);
if (item->cell_index () == ci) {
if (item->cell_or_pcell_index () == ci) {
mi = model->model_index (item);
break;
}
@ -736,7 +736,7 @@ LibraryCellSelectionForm::select_pcell_entry (db::pcell_id_type pci)
QModelIndex mi;
for (int c = 0; c < model->toplevel_items (); ++c) {
lay::CellTreeItem *item = model->toplevel_item (c);
if (item->is_pcell () && item->cell_index () == pci) {
if (item->is_pcell () && item->cell_or_pcell_index () == pci) {
mi = model->model_index (item);
break;
}
@ -775,7 +775,7 @@ LibraryCellSelectionForm::select_entry (lay::CellView::cell_index_type ci)
QModelIndex mi;
for (int c = 0; c < model->toplevel_items (); ++c) {
lay::CellTreeItem *item = model->toplevel_item (c);
if (item->cell_index () == ci) {
if (item->cell_or_pcell_index () == ci) {
mi = model->model_index (item);
break;
}

View File

@ -25,6 +25,9 @@
#include "layLayoutView.h"
#include "tlGlobPattern.h"
#include "dbPCellHeader.h"
#include "dbPCellVariant.h"
#include "dbLibraryProxy.h"
#include "dbLibrary.h"
#include <QTreeView>
#include <QPalette>
@ -82,11 +85,11 @@ struct cmp_cell_tree_item_vs_name_f
// --------------------------------------------------------------------
// CellTreeItem implementation
CellTreeItem::CellTreeItem (const db::Layout *layout, CellTreeItem *parent, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting s)
: mp_layout (layout), mp_parent (parent), m_sorting (s), m_is_pcell (is_pcell), m_index (0), m_children (), m_cell_or_pcell_index (cell_or_pcell_index)
CellTreeItem::CellTreeItem (const db::Layout *layout, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting s)
: mp_layout (layout), mp_parent (0), m_sorting (s), m_is_pcell (is_pcell), m_index (0), m_children (), m_cell_or_pcell_index (cell_or_pcell_index)
{
if (! flat && ! is_pcell) {
m_child_count = int (mp_layout->cell (cell_index ()).child_cells ());
m_child_count = int (mp_layout->cell (cell_or_pcell_index).child_cells ());
} else {
m_child_count = 0;
}
@ -100,13 +103,19 @@ CellTreeItem::~CellTreeItem ()
m_children.clear ();
}
bool
CellTreeItem::is_valid () const
{
return m_is_pcell || mp_layout->is_valid_cell_index (cell_or_pcell_index ());
}
std::string
CellTreeItem::display_text () const
{
if (m_is_pcell) {
return name ();
} else if (mp_layout->is_valid_cell_index (cell_index ())) {
return mp_layout->cell (cell_index ()).get_display_name ();
} else if (mp_layout->is_valid_cell_index (cell_or_pcell_index ())) {
return mp_layout->cell (cell_or_pcell_index ()).get_display_name ();
} else {
return std::string ();
}
@ -125,28 +134,45 @@ CellTreeItem::child (int index)
// create a list of child sub-item
const db::Cell *cell = & mp_layout->cell (cell_index ());
const db::Cell *cell = & mp_layout->cell (cell_or_pcell_index ());
m_children.reserve (m_child_count);
for (db::Cell::child_cell_iterator child = cell->begin_child_cells (); ! child.at_end (); ++child) {
CellTreeItem *child_item = new CellTreeItem (mp_layout, this, false, *child, false, m_sorting);
m_children.push_back (child_item);
add_child (new CellTreeItem (mp_layout, false, *child, false, m_sorting));
}
std::sort (m_children.begin (), m_children.end (), cmp_cell_tree_items_f (m_sorting));
for (size_t i = 0; i < m_children.size (); ++i) {
m_children [i]->set_index (i);
}
finish_children ();
}
return m_children [index];
}
void
CellTreeItem::add_child (CellTreeItem *item)
{
// explicitly added
if (size_t (m_child_count) == m_children.size ()) {
++m_child_count;
}
item->mp_parent = this;
m_children.push_back (item);
}
void
CellTreeItem::finish_children ()
{
std::sort (m_children.begin (), m_children.end (), cmp_cell_tree_items_f (m_sorting));
for (size_t i = 0; i < m_children.size (); ++i) {
m_children [i]->set_index (i);
}
}
db::cell_index_type
CellTreeItem::cell_index () const
CellTreeItem::cell_or_pcell_index () const
{
return db::cell_index_type (m_cell_or_pcell_index);
}
@ -161,7 +187,7 @@ const char *
CellTreeItem::name () const
{
if (! m_is_pcell) {
return mp_layout->cell_name (cell_index ());
return mp_layout->cell_name (cell_or_pcell_index ());
} else {
return mp_layout->pcell_header (m_cell_or_pcell_index)->get_name ().c_str ();
}
@ -214,7 +240,7 @@ CellTreeItem::by_area_less_than (const CellTreeItem *b) const
return m_is_pcell > b->is_pcell ();
}
// Hint: since mp_layout == b.mp_layout, not conversion to um^2 is required because of different DBU
return mp_layout->cell (cell_index ()).bbox ().area () < b->mp_layout->cell (b->cell_index ()).bbox ().area ();
return mp_layout->cell (cell_or_pcell_index ()).bbox ().area () < b->mp_layout->cell (b->cell_or_pcell_index ()).bbox ().area ();
}
bool
@ -224,7 +250,7 @@ CellTreeItem::by_area_equal_than (const CellTreeItem *b) const
return false;
}
// Hint: since mp_layout == b.mp_layout, not conversion to um^2 is required because of different DBU
return mp_layout->cell (cell_index ()).bbox ().area () == b->mp_layout->cell (b->cell_index ()).bbox ().area ();
return mp_layout->cell (cell_or_pcell_index ()).bbox ().area () == b->mp_layout->cell (b->cell_or_pcell_index ()).bbox ().area ();
}
// --------------------------------------------------------------------
@ -249,6 +275,7 @@ CellTreeModel::CellTreeModel (QWidget *parent, lay::LayoutView *view, int cv_ind
m_pad = ((flags & NoPadding) == 0);
mp_layout = & view->cellview (cv_index)->layout ();
mp_library = 0;
tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
build_top_level ();
@ -269,6 +296,28 @@ CellTreeModel::CellTreeModel (QWidget *parent, db::Layout *layout, unsigned int
m_pad = ((flags & NoPadding) == 0);
mp_layout = layout;
mp_library = 0;
tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
build_top_level ();
m_current_index = m_selected_indexes.begin ();
}
CellTreeModel::CellTreeModel (QWidget *parent, db::Library *library, unsigned int flags, const db::Cell *base, Sorting sorting)
: QAbstractItemModel (parent),
m_flags (flags),
m_sorting (sorting),
mp_parent (parent),
mp_view (0),
m_cv_index (-1),
mp_base (base)
{
m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
m_pad = ((flags & NoPadding) == 0);
mp_layout = &library->layout ();
mp_library = library;
tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
build_top_level ();
@ -284,8 +333,26 @@ CellTreeModel::~CellTreeModel ()
void
CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting)
{
bool flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
db::Layout *layout = & view->cellview (cv_index)->layout ();
do_configure (layout, 0, view, cv_index, flags, base, sorting);
}
void
CellTreeModel::configure (db::Layout *layout, unsigned int flags, const db::Cell *base, Sorting sorting)
{
do_configure (layout, 0, 0, -1, flags, base, sorting);
}
void
CellTreeModel::configure (db::Library *library, unsigned int flags, const db::Cell *base, Sorting sorting)
{
do_configure (& library->layout (), library, 0, -1, flags, base, sorting);
}
void
CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting)
{
bool flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
bool need_reset = false;
if (flat != m_flat || layout != mp_layout || view != mp_view) {
@ -300,13 +367,17 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
if (view != mp_view) {
mp_view->cell_visibility_changed_event.remove (this, &CellTreeModel::signal_data_changed);
mp_view->cellview_changed_event.remove (this, &CellTreeModel::signal_data_changed_with_int);
if (mp_view) {
mp_view->cell_visibility_changed_event.remove (this, &CellTreeModel::signal_data_changed);
mp_view->cellview_changed_event.remove (this, &CellTreeModel::signal_data_changed_with_int);
}
mp_view = view;
mp_view->cell_visibility_changed_event.add (this, &CellTreeModel::signal_data_changed);
mp_view->cellview_changed_event.add (this, &CellTreeModel::signal_data_changed_with_int);
if (mp_view) {
mp_view->cell_visibility_changed_event.add (this, &CellTreeModel::signal_data_changed);
mp_view->cellview_changed_event.add (this, &CellTreeModel::signal_data_changed_with_int);
}
}
@ -321,6 +392,7 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
m_pad = ((flags & NoPadding) == 0);
mp_layout = layout;
mp_library = library;
tl_assert (! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ()));
build_top_level ();
@ -339,10 +411,10 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
for (QModelIndexList::const_iterator index = indexes.begin (); index != indexes.end (); ++index) {
std::vector<db::cell_index_type> path;
std::vector<std::pair<bool, db::cell_index_type> > path;
CellTreeItem *item = (CellTreeItem *) index->internalPointer ();
while (item) {
path.push_back (item->cell_index ());
path.push_back (std::make_pair (item->is_pcell (), item->cell_or_pcell_index ()));
item = item->parent ();
}
@ -354,22 +426,22 @@ CellTreeModel::configure (lay::LayoutView *view, int cv_index, unsigned int flag
// because we push_back'd on our way up:
std::reverse (path.begin (), path.end ());
for (std::vector<db::cell_index_type>::const_iterator ci = path.begin (); ci != path.end (); ++ci) {
for (std::vector<std::pair<bool, db::cell_index_type> >::const_iterator ci = path.begin (); ci != path.end (); ++ci) {
CellTreeItem *new_parent = 0;
if (! layout->is_valid_cell_index (*ci)) {
if ((! ci->first && ! layout->is_valid_cell_index (ci->second)) || (ci->first && ! layout->pcell_declaration (ci->second))) {
// can't translate this index
} else if (parent == 0) {
for (int i = 0; i < int (m_toplevel.size ()) && !new_parent; ++i) {
if (m_toplevel [i]->cell_index () == *ci) {
if (m_toplevel [i]->cell_or_pcell_index () == ci->second && m_toplevel [i]->is_pcell () == ci->first) {
new_parent = m_toplevel [i];
row = i;
}
}
} else {
for (int i = 0; i < parent->children () && !new_parent; ++i) {
if (parent->child (i)->cell_index () == *ci) {
if (parent->child (i)->cell_or_pcell_index () == ci->second && parent->child (i)->is_pcell () == ci->first) {
new_parent = parent->child (i);
row = i;
}
@ -406,7 +478,7 @@ void
CellTreeModel::set_sorting (Sorting s)
{
if (s != m_sorting) {
configure (mp_view, m_cv_index, m_flags, mp_base, s);
do_configure (mp_layout, mp_library, mp_view, m_cv_index, m_flags, mp_base, s);
}
}
@ -435,7 +507,7 @@ CellTreeModel::build_top_level ()
if (mp_base) {
m_toplevel.reserve (mp_base->child_cells ());
for (db::Cell::child_cell_iterator child = mp_base->begin_child_cells (); ! child.at_end (); ++child) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *child, true, m_sorting);
CellTreeItem *item = new CellTreeItem (mp_layout, false, *child, true, m_sorting);
m_toplevel.push_back (item);
}
}
@ -447,7 +519,7 @@ CellTreeModel::build_top_level ()
if (mp_base) {
m_toplevel.reserve (mp_base->parent_cells ());
for (db::Cell::parent_cell_iterator parent = mp_base->begin_parent_cells (); parent != mp_base->end_parent_cells (); ++parent) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *parent, true, m_sorting);
CellTreeItem *item = new CellTreeItem (mp_layout, false, *parent, true, m_sorting);
m_toplevel.push_back (item);
}
}
@ -462,11 +534,11 @@ CellTreeModel::build_top_level ()
while (top != mp_layout->end_top_down ()) {
if (m_flat) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *top, true, m_sorting);
CellTreeItem *item = new CellTreeItem (mp_layout, false, *top, true, m_sorting);
m_toplevel.push_back (item);
} else if (mp_layout->cell (*top).is_top ()) {
if ((m_flags & BasicCells) == 0 || ! mp_layout->cell (*top).is_proxy ()) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *top, (m_flags & TopCells) != 0, m_sorting);
CellTreeItem *item = new CellTreeItem (mp_layout, false, *top, (m_flags & TopCells) != 0, m_sorting);
m_toplevel.push_back (item);
}
} else {
@ -478,10 +550,30 @@ CellTreeModel::build_top_level ()
}
if ((m_flags & BasicCells) != 0) {
for (db::Layout::pcell_iterator pc = mp_layout->begin_pcells (); pc != mp_layout->end_pcells (); ++pc) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, true, pc->second, true, m_sorting);
CellTreeItem *item = new CellTreeItem (mp_layout, true, pc->second, true, m_sorting);
m_toplevel.push_back (item);
if ((m_flags & WithVariants) != 0) {
const db::PCellHeader *pcell_header = mp_layout->pcell_header (pc->second);
for (db::PCellHeader::variant_iterator v = pcell_header->begin (); v != pcell_header->end (); ++v) {
if (mp_library && mp_library->is_retired (v->second->cell_index ())) {
// skip retired cells - this means we won't show variants which are just kept
// as shadow variants for the transactions.
} else {
item->add_child (new CellTreeItem (mp_layout, false, v->second->cell_index (), true, m_sorting));
}
}
item->finish_children ();
}
}
}
}
@ -510,19 +602,23 @@ CellTreeModel::mimeTypes () const
QMimeData *
CellTreeModel::mimeData(const QModelIndexList &indexes) const
{
const db::Cell *c = 0;
for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end () && !c; ++i) {
for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end (); ++i) {
if (i->isValid()) {
c = cell (*i);
if (is_pcell (*i)) {
lay::CellDragDropData data (mp_layout, mp_library, pcell_id (*i), true);
return data.to_mime_data ();
} else if (cell (*i)) {
lay::CellDragDropData data (mp_layout, mp_library, cell_index (*i), false);
return data.to_mime_data ();
}
}
}
if (c) {
lay::CellDragDropData data (mp_layout, c->cell_index ());
return data.to_mime_data ();
} else {
return 0;
}
return 0;
}
int
@ -561,7 +657,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
const lay::CellView::specific_cell_path_type &ctx_path = mp_view->cellview (m_cv_index).specific_path ();
if (! path.empty ()) {
if (item->cell_index () == path.back ()) {
if (item->cell_or_pcell_index () == path.back ()) {
if (m_flat) {
f.setBold (true);
} else {
@ -569,7 +665,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
lay::CellView::unspecific_cell_path_type::const_iterator p = path.end ();
while (it && p != path.begin ()) {
--p;
if (it->cell_index () != *p) {
if (it->cell_or_pcell_index () != *p) {
break;
}
it = it->parent ();
@ -578,7 +674,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
f.setBold (true);
}
}
} else if (! ctx_path.empty () && item->cell_index () == ctx_path.back ().inst_ptr.cell_index ()) {
} else if (! ctx_path.empty () && item->cell_or_pcell_index () == ctx_path.back ().inst_ptr.cell_index ()) {
if (m_flat) {
f.setUnderline (true);
} else {
@ -586,7 +682,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
lay::CellView::specific_cell_path_type::const_iterator cp = ctx_path.end ();
while (it && cp != ctx_path.begin ()) {
--cp;
if (it->cell_index () != cp->inst_ptr.cell_index ()) {
if (it->cell_or_pcell_index () != cp->inst_ptr.cell_index ()) {
break;
}
it = it->parent ();
@ -595,7 +691,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
lay::CellView::unspecific_cell_path_type::const_iterator p = path.end ();
while (it && p != path.begin ()) {
--p;
if (it->cell_index () != *p) {
if (it->cell_or_pcell_index () != *p) {
break;
}
it = it->parent ();
@ -608,7 +704,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
}
}
if (mp_view->is_cell_hidden (item->cell_index (), m_cv_index)) {
if (mp_view->is_cell_hidden (item->cell_or_pcell_index (), m_cv_index)) {
f.setStrikeOut (true);
}
@ -647,6 +743,17 @@ CellTreeModel::data (const QModelIndex &index, int role) const
return QVariant ();
#endif
} else if (role == Qt::DecorationRole && (m_flags & WithIcons) != 0) {
// TODO: icons for normal cells too?
if (item->is_pcell ()) {
QIcon icon (":/setup.png");
return QVariant (icon);
} else {
QIcon icon (":/instance.png");
return QVariant (icon);
}
} else {
return QVariant ();
@ -660,19 +767,6 @@ CellTreeModel::headerData (int /*section*/, Qt::Orientation /*orientation*/, int
return QVariant ();
}
bool searchItemPtr(CellTreeItem *parent, CellTreeItem *search)
{
if (parent == search) {
return true;
}
for (int i = 0; i < parent->children(); ++i) {
if (searchItemPtr(parent->child(i), search)) {
return true;
}
}
return false;
}
int
CellTreeModel::rowCount (const QModelIndex &parent) const
{
@ -682,7 +776,7 @@ CellTreeModel::rowCount (const QModelIndex &parent) const
CellTreeItem *item = (CellTreeItem *) parent.internalPointer ();
if (! item) {
return 0;
} else if (! mp_layout->is_valid_cell_index (item->cell_index ())) {
} else if (! item->is_valid ()) {
// for safety we return 0 children for invalid cells
return 0;
} else {
@ -702,7 +796,7 @@ CellTreeModel::index (int row, int column, const QModelIndex &parent) const
CellTreeItem *item = (CellTreeItem *) parent.internalPointer ();
if (! item) {
return QModelIndex ();
} else if (! mp_layout->is_valid_cell_index (item->cell_index ())) {
} else if (! item->is_valid ()) {
// for safety we don't return valid child indexes for invalid cells
return QModelIndex ();
} else {
@ -784,7 +878,7 @@ CellTreeModel::pcell_id (const QModelIndex &index) const
return 0;
} else {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
return item->cell_index ();
return item->cell_or_pcell_index ();
}
}
@ -795,7 +889,7 @@ CellTreeModel::cell_index (const QModelIndex &index) const
return 0;
} else {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
return item->cell_index ();
return item->cell_or_pcell_index ();
}
}
@ -804,7 +898,7 @@ CellTreeModel::cell (const QModelIndex &index) const
{
if (index.isValid () && ! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ())) {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
return & mp_layout->cell (item->cell_index ());
return & mp_layout->cell (item->cell_or_pcell_index ());
} else {
return 0;
}
@ -816,9 +910,9 @@ CellTreeModel::cell_name (const QModelIndex &index) const
if (index.isValid () && ! mp_layout->under_construction () && ! (mp_layout->manager () && mp_layout->manager ()->transacting ())) {
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
if (item->is_pcell ()) {
return mp_layout->pcell_header (item->cell_index ())->get_name ().c_str ();
return mp_layout->pcell_header (item->cell_or_pcell_index ())->get_name ().c_str ();
} else {
return mp_layout->cell_name (item->cell_index ());
return mp_layout->cell_name (item->cell_or_pcell_index ());
}
} else {
return 0;

View File

@ -37,6 +37,11 @@ namespace tl
class GlobPattern;
}
namespace db
{
class Library;
}
namespace lay
{
@ -56,18 +61,20 @@ class CellTreeModel
{
public:
enum Flags {
Flat = 1, // flat list (rather than hierarchy)
Children = 2, // direct children of cell "base"
Parents = 4, // direct parents of cell "base"
TopCells = 8, // show top cells only
BasicCells = 16, // show basic cells (PCells included, no proxies)
NoPadding = 32 // enable padding of display string with a blank at the beginning and end
Flat = 1, // flat list (rather than hierarchy)
Children = 2, // direct children of cell "base"
Parents = 4, // direct parents of cell "base"
TopCells = 8, // show top cells only
BasicCells = 16, // show basic cells (PCells included, no proxies)
WithVariants = 32, // show PCell variants below PCells
WithIcons = 64, // show icons for the top level cell type
NoPadding = 128 // disable padding of display string with a blank at the beginning and end
};
enum Sorting {
ByName, // sort by name
ByArea, // sort by cell area (small to large)
ByAreaReverse // sort by cell area (large to small)
ByName, // sort by name
ByArea, // sort by cell area (small to large)
ByAreaReverse // sort by cell area (large to small)
};
/**
@ -87,6 +94,13 @@ public:
*/
CellTreeModel (QWidget *parent, db::Layout *layout, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
/**
* @brief Constructor
*
* This constructor does not take a view but rather a layout from a library. It does not display hidden status or similar.
*/
CellTreeModel (QWidget *parent, db::Library *library, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
/**
* @brief Dtor
*/
@ -104,10 +118,20 @@ public:
virtual QMimeData *mimeData (const QModelIndexList &indexes) const;
/**
* @brief Reconfigures the model
* @brief Reconfigures the model with a LayoutView
*/
void configure (lay::LayoutView *view, int cv_index, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
/**
* @brief Reconfigures the model with a pure Layout
*/
void configure (db::Layout *layout, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
/**
* @brief Reconfigures the model with a pure Layout from a library
*/
void configure (db::Library *library, unsigned int flags = 0, const db::Cell *base = 0, Sorting sorting = ByName);
/**
* @brief Gets the layout this model is connected to
*/
@ -219,7 +243,8 @@ private:
Sorting m_sorting;
QWidget *mp_parent;
lay::LayoutView *mp_view;
const db::Layout *mp_layout;
db::Layout *mp_layout;
db::Library *mp_library;
int m_cv_index;
const db::Cell *mp_base;
std::vector <CellTreeItem *> m_toplevel;
@ -230,6 +255,7 @@ private:
void build_top_level ();
void clear_top_level ();
void search_children (const tl::GlobPattern &pattern, CellTreeItem *item);
void do_configure (db::Layout *layout, db::Library *library, lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting);
};
/**
@ -241,12 +267,12 @@ private:
class CellTreeItem
{
public:
CellTreeItem (const db::Layout *layout, CellTreeItem *parent, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting sorting);
CellTreeItem (const db::Layout *layout, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting sorting);
~CellTreeItem ();
int children () const;
CellTreeItem *child (int index);
db::cell_index_type cell_index () const;
db::cell_index_type cell_or_pcell_index () const;
CellTreeItem *parent () const;
bool by_name_less_than (const CellTreeItem *b) const;
bool by_area_less_than (const CellTreeItem *b) const;
@ -255,6 +281,9 @@ public:
bool name_equals (const char *name) const;
bool name_matches (const tl::GlobPattern &p) const;
std::string display_text () const;
void add_child (CellTreeItem *item);
void finish_children ();
bool is_valid () const;
bool is_pcell () const
{

View File

@ -526,6 +526,10 @@ HierarchyControlPanel::search_prev ()
void
HierarchyControlPanel::search_editing_finished ()
{
if (! mp_search_frame->isVisible ()) {
return;
}
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
CellTreeModel *m = dynamic_cast<CellTreeModel *> ((*v)->model ());
if (m) {
@ -572,13 +576,13 @@ HierarchyControlPanel::path_from_index (const QModelIndex &index, int cv_index,
// construct a path in the flat case
lay::CellView cv (m_cellviews [cv_index]);
cv.set_cell (item->cell_index ());
cv.set_cell (item->cell_or_pcell_index ());
path = cv.unspecific_path ();
} else {
while (item) {
path.push_back (item->cell_index ());
path.push_back (item->cell_or_pcell_index ());
item = item->parent ();
}
@ -630,10 +634,10 @@ HierarchyControlPanel::double_clicked (const QModelIndex &index)
set_active_celltree_from_sender ();
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Show or hide cell")));
CellTreeItem *item = (CellTreeItem *) index.internalPointer ();
if (mp_view->is_cell_hidden (item->cell_index (), m_active_index)) {
mp_view->show_cell (item->cell_index (), m_active_index);
if (mp_view->is_cell_hidden (item->cell_or_pcell_index (), m_active_index)) {
mp_view->show_cell (item->cell_or_pcell_index (), m_active_index);
} else {
mp_view->hide_cell (item->cell_index (), m_active_index);
mp_view->hide_cell (item->cell_or_pcell_index (), m_active_index);
}
mp_view->manager ()->commit ();
}
@ -733,6 +737,8 @@ HierarchyControlPanel::selection_changed (int index)
{
if (index != m_active_index) {
search_editing_finished ();
m_active_index = index;
bool split_mode = m_split_mode;
@ -744,6 +750,9 @@ HierarchyControlPanel::selection_changed (int index)
int i = 0;
for (std::vector <QFrame *>::const_iterator f = mp_cell_list_frames.begin (); f != mp_cell_list_frames.end (); ++f, ++i) {
(*f)->setVisible (i == index || split_mode);
if (i == index) {
mp_cell_lists [i]->setFocus ();
}
}
i = 0;
@ -771,7 +780,7 @@ HierarchyControlPanel::index_from_path (const cell_path_type &path, int cv_index
// TODO: linear search might not be effective enough ..
for (int c = 0; c < model->toplevel_items (); ++c) {
CellTreeItem *item = model->toplevel_item (c);
if (item->cell_index () == path.back ()) {
if (item->cell_or_pcell_index () == path.back ()) {
return model->model_index (item);
}
}
@ -780,7 +789,7 @@ HierarchyControlPanel::index_from_path (const cell_path_type &path, int cv_index
for (int c = 0; c < model->toplevel_items (); ++c) {
CellTreeItem *item = model->toplevel_item (c);
if (item->cell_index () == path.front ()) {
if (item->cell_or_pcell_index () == path.front ()) {
item = find_child_item (path.begin () + 1, path.end (), item);
if (item) {
return model->model_index (item);
@ -804,7 +813,7 @@ HierarchyControlPanel::find_child_item (cell_path_type::const_iterator start, ce
for (int n = 0; n < p->children (); ++n) {
CellTreeItem *item = p->child (n);
if (item && item->cell_index () == *start) {
if (item && item->cell_or_pcell_index () == *start) {
return find_child_item (start + 1, end, item);
}
}

View File

@ -61,6 +61,7 @@
#include "layLayoutCanvas.h"
#include "layLayerControlPanel.h"
#include "layHierarchyControlPanel.h"
#include "layLibrariesView.h"
#include "layBrowser.h"
#include "layRedrawThread.h"
#include "layRedrawThreadWorker.h"
@ -72,6 +73,7 @@
#include "dbRecursiveShapeIterator.h"
#include "dbManager.h"
#include "dbEdgeProcessor.h"
#include "dbLibrary.h"
#include "rdb.h"
#include "rdbMarkerBrowserDialog.h"
#include "dbLayoutToNetlist.h"
@ -356,6 +358,8 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/)
mp_control_frame = 0;
mp_hierarchy_panel = 0;
mp_hierarchy_frame = 0;
mp_libraries_view = 0;
mp_libraries_frame = 0;
mp_min_hier_spbx = 0;
mp_max_hier_spbx = 0;
m_from_level = 0;
@ -445,6 +449,17 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/)
vbl->setMargin (0);
vbl->setSpacing (0);
mp_canvas = new lay::LayoutCanvas (this, this);
vbl->addWidget (mp_canvas);
connect (mp_canvas, SIGNAL (left_arrow_key_pressed ()), this, SLOT (pan_left ()));
connect (mp_canvas, SIGNAL (up_arrow_key_pressed ()), this, SLOT (pan_up ()));
connect (mp_canvas, SIGNAL (right_arrow_key_pressed ()), this, SLOT (pan_right ()));
connect (mp_canvas, SIGNAL (down_arrow_key_pressed ()), this, SLOT (pan_down ()));
connect (mp_canvas, SIGNAL (left_arrow_key_pressed_with_shift ()), this, SLOT (pan_left_fast ()));
connect (mp_canvas, SIGNAL (up_arrow_key_pressed_with_shift ()), this, SLOT (pan_up_fast ()));
connect (mp_canvas, SIGNAL (right_arrow_key_pressed_with_shift ()), this, SLOT (pan_right_fast ()));
connect (mp_canvas, SIGNAL (down_arrow_key_pressed_with_shift ()), this, SLOT (pan_down_fast ()));
if ((m_options & LV_NoHierarchyPanel) == 0 && (m_options & LV_Naked) == 0) {
QFrame *hierarchy_frame = new QFrame (0);
@ -491,16 +506,21 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/)
}
mp_canvas = new lay::LayoutCanvas (this, this);
vbl->addWidget (mp_canvas);
connect (mp_canvas, SIGNAL (left_arrow_key_pressed ()), this, SLOT (pan_left ()));
connect (mp_canvas, SIGNAL (up_arrow_key_pressed ()), this, SLOT (pan_up ()));
connect (mp_canvas, SIGNAL (right_arrow_key_pressed ()), this, SLOT (pan_right ()));
connect (mp_canvas, SIGNAL (down_arrow_key_pressed ()), this, SLOT (pan_down ()));
connect (mp_canvas, SIGNAL (left_arrow_key_pressed_with_shift ()), this, SLOT (pan_left_fast ()));
connect (mp_canvas, SIGNAL (up_arrow_key_pressed_with_shift ()), this, SLOT (pan_up_fast ()));
connect (mp_canvas, SIGNAL (right_arrow_key_pressed_with_shift ()), this, SLOT (pan_right_fast ()));
connect (mp_canvas, SIGNAL (down_arrow_key_pressed_with_shift ()), this, SLOT (pan_down_fast ()));
if ((m_options & LV_NoLibrariesView) == 0 && (m_options & LV_Naked) == 0) {
QFrame *libraries_frame = new QFrame (0);
libraries_frame->setObjectName (QString::fromUtf8 ("libs_frame"));
mp_libraries_frame = libraries_frame;
QVBoxLayout *left_frame_ly = new QVBoxLayout (libraries_frame);
left_frame_ly->setMargin (0);
left_frame_ly->setSpacing (0);
mp_libraries_view = new lay::LibrariesView (this, libraries_frame, "libs");
left_frame_ly->addWidget (mp_libraries_view, 1 /*stretch*/);
connect (mp_libraries_view, SIGNAL (active_library_changed (int)), this, SLOT (active_library_changed (int)));
}
// occupy services and editables:
// these services get deleted by the canvas destructor automatically:
@ -628,6 +648,12 @@ LayoutView::~LayoutView ()
}
mp_hierarchy_frame = 0;
mp_hierarchy_panel = 0;
if (mp_libraries_frame) {
delete mp_libraries_frame;
}
mp_libraries_frame = 0;
mp_libraries_view = 0;
}
void LayoutView::hideEvent (QHideEvent *)
@ -790,6 +816,7 @@ LayoutView::init_menu (lay::AbstractMenu &menu)
{
lay::LayerControlPanel::init_menu (menu);
lay::HierarchyControlPanel::init_menu (menu);
lay::LibrariesView::init_menu (menu);
}
void
@ -951,6 +978,22 @@ LayoutView::configure (const std::string &name, const std::string &value)
}
return true;
} else if (name == cfg_split_lib_views) {
bool f;
tl::from_string (value, f);
if (mp_libraries_view) {
mp_libraries_view->set_split_mode (f);
}
return true;
} else if (name == cfg_current_lib_view) {
if (mp_libraries_view) {
mp_libraries_view->select_active_lib_by_name (value);
}
return true;
} else if (name == cfg_cell_list_sorting) {
if (mp_hierarchy_panel) {
@ -4472,6 +4515,11 @@ LayoutView::background_color (QColor c)
mp_hierarchy_panel->set_text_color (contrast);
}
if (mp_libraries_view) {
mp_libraries_view->set_background_color (c);
mp_libraries_view->set_text_color (contrast);
}
if (mp_selection_service) {
mp_selection_service->set_colors (c, contrast);
}
@ -4550,6 +4598,19 @@ LayoutView::active_cellview_changed (int index)
}
}
void
LayoutView::active_library_changed (int /*index*/)
{
std::string lib_name;
if (mp_libraries_view->active_lib ()) {
lib_name = mp_libraries_view->active_lib ()->get_name ();
}
// commit the new active library to the other views and persist this state
// TODO: could be passed through the LibraryController (like through some LibraryController::active_library)
plugin_root ()->config_set (cfg_current_lib_view, lib_name);
}
void
LayoutView::cellview_changed (unsigned int index)
{
@ -7243,7 +7304,7 @@ LayoutView::sizeHint () const
{
if ((m_options & LV_Naked) != 0) {
return QSize (200, 200);
} else if ((m_options & LV_NoLayers) != 0 || (m_options & LV_NoHierarchyPanel) != 0) {
} else if ((m_options & LV_NoLayers) != 0 || (m_options & LV_NoHierarchyPanel) != 0 || (m_options & LV_NoLibrariesView) != 0) {
return QSize (400, 200);
} else {
return QSize (600, 200);

View File

@ -70,6 +70,7 @@ namespace lay {
class AbstractMenu;
class LayerControlPanel;
class HierarchyControlPanel;
class LibrariesView;
class MouseTracker;
class ZoomService;
class SelectionService;
@ -168,13 +169,14 @@ public:
LV_Normal = 0,
LV_NoLayers = 1,
LV_NoHierarchyPanel = 2,
LV_Naked = 4,
LV_NoZoom = 8,
LV_NoGrid = 16,
LV_NoMove = 32,
LV_NoTracker = 64,
LV_NoSelection = 128,
LV_NoPlugins = 256,
LV_NoLibrariesView = 4,
LV_Naked = 8,
LV_NoZoom = 16,
LV_NoGrid = 32,
LV_NoMove = 64,
LV_NoTracker = 128,
LV_NoSelection = 256,
LV_NoPlugins = 512,
LV_NoServices = LV_NoMove + LV_NoTracker + LV_NoSelection + LV_NoPlugins
};
@ -221,7 +223,7 @@ public:
bool has_selection ();
/**
* @brief Get the container with the layer control panel
* @brief Gets the container with the layer control panel
*/
QWidget *layer_control_frame ()
{
@ -229,7 +231,7 @@ public:
}
/**
* @brief Get the container with the hierarchy control panel
* @brief Gets the container with the hierarchy control panel
*/
QWidget *hierarchy_control_frame ()
{
@ -237,7 +239,15 @@ public:
}
/**
* @brief Paste from clipboard
* @brief Gets the container with the libraries view
*/
QWidget *libraries_frame ()
{
return mp_libraries_frame;
}
/**
* @brief Pastes from clipboard
*
* This reimplementation of the lay::Editables interface additionally
* looks for paste receivers in the tree views for example.
@ -245,7 +255,7 @@ public:
void paste ();
/**
* @brief Copy to clipboard
* @brief Copies to clipboard
*
* This reimplementation of the lay::Editables interface additionally
* looks for copy providers in the tree views for example.
@ -253,7 +263,7 @@ public:
void copy ();
/**
* @brief Cut to clipboard
* @brief Cuts to clipboard
*
* This reimplementation of the lay::Editables interface additionally
* looks for cut & copy providers in the tree views for example.
@ -261,7 +271,7 @@ public:
void cut ();
/**
* @brief Get the explicit title string of the view
* @brief Gets the explicit title string of the view
*
* This is the one explicitly set, not the one displayed. The displayed text is composed of internal information
* if no title string is set.
@ -272,17 +282,17 @@ public:
}
/**
* @brief Get the window title of the view
* @brief Gets the window title of the view
*/
std::string title () const;
/**
* @brief Set the window title to an explicit string
* @brief Sets the window title to an explicit string
*/
void set_title (const std::string &t);
/**
* @brief Reset the explicit title and enable the automatic naming
* @brief Resets the explicit title and enable the automatic naming
*/
void reset_title ();
@ -2627,6 +2637,7 @@ public slots:
private slots:
void active_cellview_changed (int index);
void active_library_changed (int index);
void goto_bookmark ();
signals:
@ -2695,7 +2706,8 @@ private:
QFrame *mp_left_frame;
lay::LayerControlPanel *mp_control_panel;
lay::HierarchyControlPanel *mp_hierarchy_panel;
QWidget *mp_control_frame, *mp_hierarchy_frame;
lay::LibrariesView *mp_libraries_view;
QWidget *mp_control_frame, *mp_hierarchy_frame, *mp_libraries_frame;
QSpinBox *mp_min_hier_spbx;
QSpinBox *mp_max_hier_spbx;
std::list <CellView> m_cellviews;

View File

@ -1486,6 +1486,8 @@ public:
options.push_back (std::pair<std::string, std::string> (cfg_flat_cell_list, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_split_cell_list, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_cell_list_sorting, "by-name"));
options.push_back (std::pair<std::string, std::string> (cfg_split_lib_views, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_current_lib_view, ""));
options.push_back (std::pair<std::string, std::string> (cfg_hide_empty_layers, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_min_inst_label_size, "16"));
options.push_back (std::pair<std::string, std::string> (cfg_cell_box_text_font, "0"));

View File

@ -0,0 +1,820 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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 <string>
#include <QTreeView>
#include <QHeaderView>
#include <QComboBox>
#include <QResizeEvent>
#include <QMenu>
#include <QApplication>
#include <QDrag>
#include <QSplitter>
#include <QFrame>
#include <QLabel>
#include <QToolButton>
#include <QCheckBox>
#include <QProxyStyle>
#include <QPainter>
#include <QPen>
#include <QVBoxLayout>
#include "dbClipboard.h"
#include "dbClipboardData.h"
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "layLibrariesView.h"
#include "layCellTreeModel.h"
#include "layLayoutView.h"
#include "layAbstractMenu.h"
#include "layAbstractMenuProvider.h"
#include "layDialogs.h"
#include "tlExceptions.h"
#include "laybasicConfig.h"
#include "tlInternational.h"
#include "tlString.h"
#include "gtf.h"
namespace lay
{
// --------------------------------------------------------------------
// A helper class the identifies clipboard data
class CellClipboardData
: public db::ClipboardData
{
public:
CellClipboardData () { }
};
// --------------------------------------------------------------------
// LibraryTreeWidget implementation
LibraryTreeWidget::LibraryTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver)
: QTreeView (parent), mp_key_event_receiver (key_event_receiver)
{
// Allow dragging from here to
setDragDropMode (QAbstractItemView::DragOnly);
setObjectName (QString::fromUtf8 (name));
}
bool
LibraryTreeWidget::event (QEvent *event)
{
#if 0
// Handling this event makes the widget receive all keystrokes.
// Without this code, shortcuts override the search function.
if (event->type () == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent *> (event);
QString t = ke->text ();
if (!t.isEmpty () && t[0].isPrint ()) {
ke->accept ();
}
}
#endif
return QTreeView::event (event);
}
bool
LibraryTreeWidget::focusNextPrevChild (bool /*next*/)
{
return false;
}
void
LibraryTreeWidget::keyPressEvent (QKeyEvent *event)
{
QString t = event->text ();
if (! t.isEmpty () && t[0].isPrint ()) {
// "/" is a search initiator
if (t == QString::fromUtf8 ("/")) {
t.clear ();
}
emit search_triggered (t);
} else if (mp_key_event_receiver) {
// send other key events to the alternative receiver - this way we can make the
// view receive arrow keys for panning.
QCoreApplication::sendEvent (mp_key_event_receiver, event);
} else {
return QTreeView::keyPressEvent (event);
}
}
void
LibraryTreeWidget::startDrag (Qt::DropActions supportedActions)
{
QModelIndex index = selectionModel ()->currentIndex ();
if (index.isValid ()) {
QModelIndexList indexes;
indexes << index;
QMimeData *data = model ()->mimeData (indexes);
if (!data) {
return;
}
QDrag *drag = new QDrag (this);
drag->setMimeData(data);
QPixmap px (1, 1);
px.fill (QColor (0, 0, 0));
px.createMaskFromColor (QColor (0, 0, 0), Qt::MaskOutColor);
drag->setPixmap (px);
Qt::DropAction defaultDropAction = Qt::IgnoreAction;
if (supportedActions & Qt::CopyAction) {
defaultDropAction = Qt::CopyAction;
}
drag->exec(supportedActions, defaultDropAction);
}
}
void
LibraryTreeWidget::mouseDoubleClickEvent (QMouseEvent *event)
{
QModelIndex index (indexAt (event->pos ()));
if (index.isValid ()) {
emit cell_double_clicked (index);
}
}
void
LibraryTreeWidget::mousePressEvent (QMouseEvent *event)
{
if (event->button () == Qt::MidButton) {
// eat this event.
} else {
QModelIndex index (indexAt (event->pos ()));
if (index.isValid ()) {
emit cell_clicked (index);
}
QTreeView::mousePressEvent (event);
}
}
void
LibraryTreeWidget::mouseReleaseEvent (QMouseEvent *event)
{
if (event->button () == Qt::MidButton) {
QModelIndex index (indexAt (event->pos ()));
if (index.isValid ()) {
emit cell_middle_clicked (index);
}
} else {
QTreeView::mouseReleaseEvent (event);
}
}
// --------------------------------------------------------------------
// LibrariesView implementation
const int max_cellviews_in_split_mode = 5;
void
LibrariesView::init_menu (lay::AbstractMenu &menu)
{
MenuLayoutEntry context_menu [] = {
#if 0
// doesn't make sense for many libs
MenuLayoutEntry ("split_mode", tl::to_string (QObject::tr ("Split Mode")), std::make_pair (cfg_split_lib_views, "?")),
#endif
MenuLayoutEntry::last ()
};
MenuLayoutEntry main_menu [] = {
MenuLayoutEntry ("@lib_context_menu", "", context_menu),
MenuLayoutEntry::last ()
};
menu.init (main_menu);
}
LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char *name)
: QFrame (parent),
m_enable_cb (true),
mp_view (view),
m_split_mode (false),
m_do_update_content_dm (this, &LibrariesView::do_update_content),
m_do_full_update_content_dm (this, &LibrariesView::do_full_update_content)
{
setObjectName (QString::fromUtf8 (name));
QVBoxLayout *ly = new QVBoxLayout (this);
ly->setSpacing (0);
ly->setContentsMargins (0, 0, 0, 0);
mp_selector = new QComboBox (this);
mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
ly->addWidget (mp_selector);
mp_search_frame = new QFrame (this);
ly->addWidget (mp_search_frame);
mp_search_frame->hide ();
mp_search_frame->setAutoFillBackground (true);
mp_search_frame->setObjectName (QString::fromUtf8 ("panel"));
mp_search_frame->setFrameStyle (QFrame::Panel | QFrame::Raised);
mp_search_frame->setLineWidth (1);
mp_search_frame->setBackgroundRole (QPalette::Highlight);
QHBoxLayout *sf_ly = new QHBoxLayout (mp_search_frame);
sf_ly->setMargin (0);
sf_ly->setContentsMargins (0, 0, 0, 0);
sf_ly->setSpacing (0);
mp_search_close_cb = new QCheckBox (mp_search_frame);
sf_ly->addWidget (mp_search_close_cb);
mp_search_close_cb->setFocusPolicy (Qt::NoFocus);
mp_search_close_cb->setBackgroundRole (QPalette::Highlight);
mp_search_close_cb->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred));
QPalette pl (mp_search_close_cb->palette ());
pl.setColor (QPalette::Foreground, pl.color (QPalette::Active, QPalette::HighlightedText));
mp_search_close_cb->setPalette (pl);
mp_search_close_cb->setMaximumSize (QSize (mp_search_close_cb->maximumSize ().width (), mp_search_close_cb->sizeHint ().height () - 4));
connect (mp_search_close_cb, SIGNAL (clicked ()), this, SLOT (search_editing_finished ()));
mp_search_model = 0;
mp_search_edit_box = new lay::DecoratedLineEdit (mp_search_frame);
mp_search_edit_box->setObjectName (QString::fromUtf8 ("cellview_search_edit_box"));
mp_search_edit_box->set_escape_signal_enabled (true);
mp_search_edit_box->set_tab_signal_enabled (true);
connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ()));
connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited ()));
connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ()));
connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ()));
connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ()));
sf_ly->addWidget (mp_search_edit_box);
mp_use_regular_expressions = new QAction (this);
mp_use_regular_expressions->setCheckable (true);
mp_use_regular_expressions->setChecked (true);
mp_use_regular_expressions->setText (tr ("Use expressions (use * and ? for any character)"));
mp_case_sensitive = new QAction (this);
mp_case_sensitive->setCheckable (true);
mp_case_sensitive->setChecked (true);
mp_case_sensitive->setText (tr ("Case sensitive search"));
QMenu *m = new QMenu (mp_search_edit_box);
m->addAction (mp_use_regular_expressions);
m->addAction (mp_case_sensitive);
connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ()));
mp_search_edit_box->set_clear_button_enabled (true);
mp_search_edit_box->set_options_button_enabled (true);
mp_search_edit_box->set_options_menu (m);
QToolButton *sf_next = new QToolButton (mp_search_frame);
sf_next->setAutoRaise (true);
sf_next->setToolTip (tr ("Find next"));
sf_next->setIcon (QIcon (QString::fromUtf8 (":/find.png")));
connect (sf_next, SIGNAL (clicked ()), this, SLOT (search_next ()));
sf_ly->addWidget (sf_next);
mp_splitter = new QSplitter (Qt::Vertical, this);
ly->addWidget (mp_splitter);
connect (mp_selector, SIGNAL (activated (int)), this, SLOT (selection_changed (int)));
QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Preferred);
sp.setHorizontalStretch (0);
sp.setVerticalStretch (0);
setSizePolicy (sp);
do_update_content ();
}
LibrariesView::~LibrariesView ()
{
// .. nothing yet ..
}
QSize
LibrariesView::sizeHint () const
{
int w = 120; // TODO: better(?): mp_cell_list->sizeHint ().width ();
return QSize (w, 0);
}
bool
LibrariesView::event (QEvent *e)
{
if (e->type () == QEvent::MaxUser) {
// GTF probe event
e->accept ();
return true;
} else {
return QFrame::event (e);
}
}
void
LibrariesView::context_menu (const QPoint &p)
{
tl_assert (lay::AbstractMenuProvider::instance () != 0);
QTreeView *cell_list = dynamic_cast<QTreeView *> (sender ());
if (cell_list) {
QMenu *ctx_menu = lay::AbstractMenuProvider::instance ()->menu ()->detached_menu ("lib_context_menu");
ctx_menu->exec (cell_list->mapToGlobal (p));
}
}
void
LibrariesView::set_split_mode (bool f)
{
if (f != m_split_mode) {
m_split_mode = f;
m_do_update_content_dm ();
}
}
void
LibrariesView::clear_all ()
{
m_libraries.clear ();
m_needs_update.clear ();
m_force_close.clear ();
for (size_t i = 0; i < mp_cell_list_frames.size (); ++i) {
delete mp_cell_list_frames [i];
}
mp_cell_list_frames.clear ();
mp_cell_list_headers.clear ();
mp_cell_lists.clear ();
}
void
LibrariesView::search_triggered (const QString &t)
{
mp_search_model = 0;
lay::LibraryTreeWidget *w = dynamic_cast<lay::LibraryTreeWidget *> (sender ());
if (w) {
for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
if (mp_cell_lists [i] == w) {
// Switch the active list for split mode -> CAUTION: this may trigger a search_editing_finished call
select_active (int (i));
mp_search_model = dynamic_cast<lay::CellTreeModel *> (w->model ());
break;
}
}
}
if (mp_search_model) {
mp_search_close_cb->setChecked (true);
mp_search_frame->show ();
mp_search_edit_box->setText (t);
mp_search_edit_box->setFocus ();
search_edited ();
}
}
void
LibrariesView::search_edited ()
{
QString t = mp_search_edit_box->text ();
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
if (t.isEmpty ()) {
mp_search_model->clear_locate ();
(*v)->setCurrentIndex (QModelIndex ());
} else {
QModelIndex found = mp_search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false);
(*v)->setCurrentIndex (found);
if (found.isValid ()) {
(*v)->scrollTo (found);
}
}
break;
}
}
}
void
LibrariesView::search_next ()
{
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
QModelIndex found = mp_search_model->locate_next ();
if (found.isValid ()) {
(*v)->setCurrentIndex (found);
(*v)->scrollTo (found);
}
break;
}
}
}
void
LibrariesView::search_prev ()
{
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
QModelIndex found = mp_search_model->locate_prev ();
if (found.isValid ()) {
(*v)->setCurrentIndex (found);
(*v)->scrollTo (found);
}
break;
}
}
}
void
LibrariesView::search_editing_finished ()
{
if (! mp_search_frame->isVisible ()) {
return;
}
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
CellTreeModel *m = dynamic_cast<CellTreeModel *> ((*v)->model ());
if (m) {
m->clear_locate ();
}
}
// give back the focus to the cell list
for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
if (mp_cell_lists [i]->model () == mp_search_model) {
mp_cell_lists [i]->setFocus ();
break;
}
}
mp_search_frame->hide ();
mp_search_model = 0;
}
void
LibrariesView::middle_clicked (const QModelIndex &index)
{
// ... nothing yet ..
}
void
LibrariesView::header_clicked ()
{
// ... nothing yet ..
}
void
LibrariesView::clicked (const QModelIndex & /*index*/)
{
// ... nothing yet ..
}
void
LibrariesView::double_clicked (const QModelIndex &index)
{
// ... nothing yet ..
}
void
LibrariesView::set_background_color (QColor c)
{
m_background_color = c;
for (std::vector <QTreeView *>::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) {
QPalette pl ((*f)->palette ());
pl.setColor (QPalette::Base, c);
(*f)->setPalette (pl);
}
}
void
LibrariesView::set_text_color (QColor c)
{
m_text_color = c;
for (std::vector <QTreeView *>::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) {
QPalette pl ((*f)->palette ());
pl.setColor (QPalette::Text, c);
(*f)->setPalette (pl);
}
}
void
LibrariesView::update_required ()
{
m_do_full_update_content_dm ();
}
void
LibrariesView::do_full_update_content ()
{
size_t i = 0;
for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib, ++i) {
if (m_needs_update.size () > i) {
m_needs_update [i] = true;
}
if (m_force_close.size () > i) {
m_force_close [i] = true;
}
}
do_update_content ();
}
void
LibrariesView::do_update_content (int lib_index)
{
// close the search box since we will modify the model
mp_search_frame->hide ();
mp_search_model = 0;
size_t imin = (lib_index < 0 ? 0 : (size_t) lib_index);
size_t imax = (lib_index < 0 ? std::numeric_limits <size_t>::max () : (size_t) lib_index);
// rebuild all events
detach_from_all_events ();
db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required);
std::vector<db::Library *> libraries;
for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) {
libraries.push_back (db::LibraryManager::instance ().lib (lib->second));
libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required);
libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required);
}
for (size_t i = imin; i < libraries.size () && i <= imax; ++i) {
if (i < m_libraries.size () && ! m_libraries[i].get ()) {
tl_assert (i < m_force_close.size ());
m_force_close [i] = true;
}
if (i >= m_force_close.size ()) {
m_force_close.push_back (true);
}
if (i >= m_needs_update.size ()) {
m_needs_update.push_back (true);
}
if (i >= libraries.size ()) {
m_force_close [i] = true;
m_needs_update [i] = true;
}
}
size_t n = std::min (m_libraries.size (), libraries.size ());
for (size_t i = imin; i < n && i <= imax; ++i) {
if (m_libraries [i].get () != libraries [i]) {
m_needs_update [i] = true;
m_force_close [i] = true;
}
if (m_needs_update [i]) {
mp_cell_lists [i]->doItemsLayout (); // triggers a redraw
}
m_libraries [i].reset (libraries [i]);
}
if (m_libraries.size () < libraries.size ()) {
for (size_t i = n; i < libraries.size (); ++i) {
m_libraries.push_back (tl::weak_ptr<db::Library> (libraries [i]));
}
} else if (m_libraries.size () > libraries.size ()) {
m_libraries.erase (m_libraries.begin () + libraries.size (), m_libraries.end ());
}
bool split_mode = m_split_mode;
// for more than max_cellviews_in_split_mode cellviews, switch to overlay mode
if (int (m_libraries.size ()) > max_cellviews_in_split_mode) {
split_mode = false;
}
while (mp_cell_lists.size () < m_libraries.size ()) {
size_t i = mp_cell_lists.size ();
QPalette pl;
QFrame *cl_frame = new QFrame (this);
cl_frame->setFrameShape (QFrame::NoFrame);
QVBoxLayout *cl_ly = new QVBoxLayout (cl_frame);
cl_ly->setSpacing (0);
cl_ly->setContentsMargins (0, 0, 0, 0);
QToolButton *header = new QToolButton (cl_frame);
connect (header, SIGNAL (clicked ()), this, SLOT (header_clicked ()));
header->setText (tl::to_qstring (display_string (int (i))));
header->setFocusPolicy (Qt::NoFocus);
header->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred);
header->setCheckable (true);
header->setAutoRaise (true);
header->setAutoFillBackground (true);
header->setVisible (split_mode);
cl_ly->addWidget (header);
LibraryTreeWidget *cell_list = new LibraryTreeWidget (cl_frame, "tree", mp_view->view_object_widget ());
cl_ly->addWidget (cell_list);
cell_list->setModel (new CellTreeModel (cell_list, m_libraries [i].get (), CellTreeModel::Flat | CellTreeModel::TopCells | CellTreeModel::BasicCells | CellTreeModel::WithVariants | CellTreeModel::WithIcons, 0));
cell_list->setUniformRowHeights (true);
pl = cell_list->palette ();
if (m_text_color.isValid ()) {
pl.setColor (QPalette::Text, m_text_color);
}
if (m_background_color.isValid ()) {
pl.setColor (QPalette::Base, m_background_color);
}
cell_list->setPalette (pl);
cell_list->header ()->hide ();
cell_list->setSelectionMode (QTreeView::ExtendedSelection);
cell_list->setRootIsDecorated (true);
cell_list->setContextMenuPolicy (Qt::CustomContextMenu);
connect (cell_list, SIGNAL (customContextMenuRequested (const QPoint &)), this, SLOT (context_menu (const QPoint &)));
connect (cell_list, SIGNAL (cell_clicked (const QModelIndex &)), this, SLOT (clicked (const QModelIndex &)));
connect (cell_list, SIGNAL (cell_double_clicked (const QModelIndex &)), this, SLOT (double_clicked (const QModelIndex &)));
connect (cell_list, SIGNAL (cell_middle_clicked (const QModelIndex &)), this, SLOT (middle_clicked (const QModelIndex &)));
connect (cell_list, SIGNAL (search_triggered (const QString &)), this, SLOT (search_triggered (const QString &)));
mp_cell_lists.push_back (cell_list);
mp_cell_list_frames.push_back (cl_frame);
mp_cell_list_headers.push_back (header);
mp_splitter->addWidget (cl_frame);
}
while (mp_cell_lists.size () > m_libraries.size ()) {
delete mp_cell_list_frames.back ();
mp_cell_list_frames.pop_back ();
mp_cell_list_headers.pop_back ();
mp_cell_lists.pop_back ();
}
for (unsigned int i = imin; i < m_libraries.size () && i < (unsigned int) mp_selector->count () && i <= imax; ++i) {
mp_selector->setItemText (i, tl::to_qstring (display_string (i)));
}
while (mp_selector->count () < int (m_libraries.size ())) {
mp_selector->addItem (tl::to_qstring (display_string (mp_selector->count ())));
}
while (mp_selector->count () > int (m_libraries.size ())) {
mp_selector->removeItem (mp_selector->count () - 1);
}
if (m_active_index >= int (m_libraries.size ())) {
m_active_index = int (m_libraries.size ()) - 1;
} else if (m_active_index < 0 && ! m_libraries.empty ()) {
m_active_index = 0;
}
mp_selector->setCurrentIndex (m_active_index);
mp_selector->setVisible (mp_cell_lists.size () > 1 && ! split_mode);
for (unsigned int i = imin; i < m_libraries.size () && i <= imax; ++i) {
if (m_needs_update [i]) {
mp_cell_list_headers [i]->setText (tl::to_qstring (display_string (i)));
// draw the cells in the level of the current cell,
// add an "above" entry if there is a level above.
// highlight the current entry. If the index is
// invalid, just clear the list.
if (m_force_close [i]) {
m_force_close [i] = false;
CellTreeModel *model = dynamic_cast <CellTreeModel *> (mp_cell_lists [i]->model ());
if (model) {
model->configure (m_libraries [i].get (), CellTreeModel::Flat | CellTreeModel::TopCells | CellTreeModel::BasicCells | CellTreeModel::WithVariants | CellTreeModel::WithIcons, 0);
}
}
m_needs_update [i] = false;
}
mp_cell_list_headers [i]->setVisible (split_mode && m_libraries.size () > 1);
mp_cell_list_headers [i]->setChecked (int (i) == m_active_index);
mp_cell_list_frames [i]->setVisible (int (i) == m_active_index || split_mode);
}
}
void
LibrariesView::select_active_lib_by_name (const std::string &name)
{
for (std::vector<tl::weak_ptr<db::Library> >::const_iterator i = m_libraries.begin (); i != m_libraries.end (); ++i) {
if (i->get () && (*i)->get_name () == name) {
select_active (int (i - m_libraries.begin ()));
break;
}
}
}
void
LibrariesView::select_active (int lib_index)
{
if (lib_index != m_active_index) {
mp_selector->setCurrentIndex (lib_index);
selection_changed (lib_index);
}
}
db::Library *
LibrariesView::active_lib ()
{
if (m_active_index >= 0 && m_active_index < int (m_libraries.size ())) {
return m_libraries [m_active_index].get ();
}
return 0;
}
void
LibrariesView::selection_changed (int index)
{
if (index != m_active_index) {
search_editing_finished ();
m_active_index = index;
bool split_mode = m_split_mode;
// for more than max_cellviews_in_split_mode cellviews, switch to overlay mode
if (int (m_libraries.size ()) > max_cellviews_in_split_mode) {
split_mode = false;
}
int i = 0;
for (std::vector <QFrame *>::const_iterator f = mp_cell_list_frames.begin (); f != mp_cell_list_frames.end (); ++f, ++i) {
(*f)->setVisible (i == index || split_mode);
if (i == index) {
mp_cell_lists [i]->setFocus ();
}
}
i = 0;
for (std::vector <QToolButton *>::const_iterator f = mp_cell_list_headers.begin (); f != mp_cell_list_headers.end (); ++f, ++i) {
(*f)->setChecked (i == index);
}
emit active_library_changed (index);
}
}
std::string
LibrariesView::display_string (int n) const
{
const db::Library *lib = m_libraries [n].get ();
std::string text = lib->get_name ();
if (! lib->get_description ().empty ()) {
text += " - " + lib->get_description ();
}
return text;
}
CellTreeItem *
LibrariesView::current_item () const
{
if (m_active_index < 0 || m_active_index >= int (mp_cell_lists.size ())) {
return 0;
}
if (mp_cell_lists [m_active_index]->currentIndex ().isValid ()) {
return (CellTreeItem *) mp_cell_lists [m_active_index]->currentIndex ().internalPointer ();
} else {
return 0;
}
}
bool
LibrariesView::has_focus () const
{
return m_active_index >= 0 && m_active_index < int (mp_cell_lists.size ()) && mp_cell_lists [m_active_index]->hasFocus ();
}
} // namespace lay

View File

@ -0,0 +1,280 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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_layLibrariesView
#define HDR_layLibrariesView
#include <vector>
#include <string>
#include <algorithm>
#include <QFrame>
#include <QTreeView>
#include "dbLayout.h"
#include "layCanvasPlane.h"
#include "layViewOp.h"
#include "layLayoutView.h"
#include "layCellTreeModel.h"
#include "layWidgets.h"
#include "tlDeferredExecution.h"
class QModelIndex;
class QComboBox;
class QMenu;
class QSplitter;
class QFrame;
class QToolButton;
class QLineEdit;
class QAction;
class QCheckBox;
namespace lay
{
/**
* @brief A special QTreeView customization
*
* A customized QTreeView that is used to receive middle-mouse-button
* events and processes double clicks by bypassing the standard implementation
* that closes and opens branches.
*/
class LibraryTreeWidget
: public QTreeView
{
Q_OBJECT
public:
LibraryTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver);
signals:
void cell_clicked (const QModelIndex &);
void cell_double_clicked (const QModelIndex &);
void cell_middle_clicked (const QModelIndex &);
void search_triggered (const QString &t);
protected:
virtual void mouseDoubleClickEvent (QMouseEvent *event);
virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event);
virtual void startDrag (Qt::DropActions supportedActions);
virtual bool focusNextPrevChild (bool next);
virtual void keyPressEvent (QKeyEvent *event);
virtual bool event (QEvent *event);
QWidget *mp_key_event_receiver;
};
/**
* @brief The hierarchy control panel
*
* The hierarchy control panel allows changing the cell shown, to
* browse the hierarchy and disable/enable cells
*
* The class communicates with a Layout interface for
* retrieval of the cell hierarchy
*/
class LibrariesView
: public QFrame,
public tl::Object
{
Q_OBJECT
public:
/**
* @brief Constructor
*
* @param parent The Qt parent widget
* @param name The layer control panel's widget name
*/
LibrariesView (lay::LayoutView *view, QWidget *parent = 0, const char *name = "libraries_view");
/**
* @brief Destructor
*/
~LibrariesView ();
/**
* @brief Perform the cell control panel's initialisations on the main menu
*/
static void init_menu (lay::AbstractMenu &menu);
/**
* @brief The sizeHint implementation for Qt layout management
*/
virtual QSize sizeHint () const;
/**
* @brief Changing of the background color
*/
void set_background_color (QColor c);
/**
* @brief Changing of the text color
*/
void set_text_color (QColor c);
/**
* @brief Sets the active library by name
*/
void select_active_lib_by_name (const std::string &name);
/**
* @brief Select the active cellview
*
* selects the active cellview by index. The index must be
* a valid index within the context of the layout view.
*/
void select_active (int lib_index);
/**
* @brief Get the active cellview
*
* get the active cellview index.
*/
int active ()
{
return m_active_index;
}
/**
* @brief Gets the active library or 0 if there is no active library
*/
db::Library *active_lib ();
/**
* @brief Update the contents if necessary
*
* Update the cell trees according to the hierarchy found in
* the layouts. This version includes a hint which cellview has changed.
*/
void do_update_content (int cv_index);
/**
* @brief Update the contents if necessary
*
* Update the cell trees according to the hierarchy found in
* the layouts.
*/
void do_update_content ()
{
do_update_content (-1);
}
/**
* @brief Event handler
*
* The object subclasses the event handler in order to intercept
* the GTF probe events (Qt::MaxUser).
*/
virtual bool event (QEvent *e);
/**
* @brief Return true, if the tree view has the focus
*/
bool has_focus () const;
/**
* @brief Select split mode
* In split mode all cell trees are shown stacked
*/
void set_split_mode (bool sbs);
/**
* @brief Returns true if side-by-side mode is set
*/
bool split_mode () const
{
return m_split_mode;
}
/**
* @brief Gets the layout view this panel is attached to
*/
lay::LayoutView *view ()
{
return mp_view;
}
signals:
void active_library_changed (int cellview_index);
public slots:
void clicked (const QModelIndex &index);
void header_clicked ();
void double_clicked (const QModelIndex &index);
void middle_clicked (const QModelIndex &index);
void selection_changed (int index);
void context_menu (const QPoint &pt);
void search_triggered (const QString &t);
void search_edited ();
void search_editing_finished ();
void search_next ();
void search_prev ();
private:
db::Layout *mp_layout;
bool m_enable_cb;
lay::LayoutView *mp_view;
std::vector <QTreeView *> mp_cell_lists;
std::vector <QToolButton *> mp_cell_list_headers;
std::vector <QFrame *> mp_cell_list_frames;
std::vector <bool> m_force_close;
std::vector <bool> m_needs_update;
int m_active_index;
bool m_split_mode;
QComboBox *mp_selector;
lay::DecoratedLineEdit *mp_search_edit_box;
QAction *mp_case_sensitive;
QAction *mp_use_regular_expressions;
CellTreeModel *mp_search_model;
QFrame *mp_search_frame;
QCheckBox *mp_search_close_cb;
QSplitter *mp_splitter;
QColor m_background_color;
QColor m_text_color;
tl::DeferredMethod<LibrariesView> m_do_update_content_dm;
tl::DeferredMethod<LibrariesView> m_do_full_update_content_dm;
std::auto_ptr<QStyle> mp_tree_style;
std::vector<tl::weak_ptr<db::Library> > m_libraries;
// event listener for changes in the cellview and layout
void update_required ();
// get the current item
CellTreeItem *current_item () const;
// clears all widgets of the cell lists
void clear_all ();
// display string of nth cellview
std::string display_string (int n) const;
// forces a complete update
void do_full_update_content ();
};
} // namespace lay
#endif

View File

@ -70,7 +70,9 @@ CellDragDropData::serialized () const
stream << QString::fromUtf8 ("CellDragDropData");
stream << (quintptr) mp_layout;
stream << (quintptr) mp_library;
stream << m_cell_index;
stream << m_is_pcell;
return data;
}
@ -88,7 +90,10 @@ CellDragDropData::deserialize (const QByteArray &ba)
quintptr p = 0;
stream >> p;
mp_layout = reinterpret_cast <const db::Layout *> (p);
stream >> p;
mp_library = reinterpret_cast <const db::Library *> (p);
stream >> m_cell_index;
stream >> m_is_pcell;
return true;
} else {

View File

@ -53,6 +53,12 @@ class QDragLeaveEvent;
class QDropEvent;
class QMimeData;
namespace db
{
class Library;
class Layout;
}
namespace lay {
class Viewport;
@ -113,7 +119,7 @@ public:
* @brief Default ctor
*/
CellDragDropData ()
: mp_layout (0), m_cell_index (0)
: mp_layout (0), mp_library (0), m_cell_index (0), m_is_pcell (false)
{
// .. nothing yet ..
}
@ -124,8 +130,8 @@ public:
* @param layout the layout where the cell lives in
* @param cell_index The index of the cell
*/
CellDragDropData (const db::Layout *layout, db::cell_index_type cell_index)
: mp_layout (layout), m_cell_index (cell_index)
CellDragDropData (const db::Layout *layout, const db::Library *library, db::cell_index_type cell_or_pcell_index, bool is_pcell)
: mp_layout (layout), mp_library (library), m_cell_index (cell_or_pcell_index), m_is_pcell (is_pcell)
{
// .. nothing yet ..
}
@ -138,6 +144,14 @@ public:
return mp_layout;
}
/**
* @brief Gets the layout object where the cell lives in
*/
const db::Library *library () const
{
return mp_library;
}
/**
* @brief Gets the index of the cell
*/
@ -146,6 +160,14 @@ public:
return m_cell_index;
}
/**
* @brief Gets a value indicating whether the cell is a pcell
*/
bool is_pcell () const
{
return m_is_pcell;
}
/**
* @brief Serializes itself to an QByteArray
*/
@ -160,7 +182,9 @@ public:
private:
const db::Layout *mp_layout;
const db::Library *mp_library;
db::cell_index_type m_cell_index;
bool m_is_pcell;
};
/**

View File

@ -175,7 +175,8 @@ SOURCES = \
layNetlistBrowserModel.cc \
layIndexedNetlistModel.cc \
layNetlistCrossReferenceModel.cc \
layNetlistBrowserTreeModel.cc
layNetlistBrowserTreeModel.cc \
layLibrariesView.cc
HEADERS = \
gtf.h \
@ -271,7 +272,8 @@ HEADERS = \
layNetlistBrowserModel.h \
layIndexedNetlistModel.h \
layNetlistCrossReferenceModel.h \
layNetlistBrowserTreeModel.h
layNetlistBrowserTreeModel.h \
layLibrariesView.h
INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC

View File

@ -124,6 +124,9 @@ static const std::string cfg_flat_cell_list ("flat-cell-list");
static const std::string cfg_split_cell_list ("split-cell-list");
static const std::string cfg_cell_list_sorting ("cell-list-sorting");
static const std::string cfg_split_lib_views ("split-lib-views");
static const std::string cfg_current_lib_view ("current-lib-view");
static const std::string cfg_pan_distance ("pan-distance");
static const std::string cfg_paste_display_mode ("paste-display-mode");

View File

@ -204,7 +204,13 @@ BasicArc::produce (const db::Layout &layout, const std::vector<unsigned int> &la
std::string
BasicArc::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string("ARC(r=") + tl::micron_to_string (parameters [p_actual_radius1].to_double ()) + ".." + tl::micron_to_string (parameters [p_actual_radius2].to_double ()) + ",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) + ".." + tl::to_string (parameters [p_end_angle].to_double (), 6) + ")";
return "ARC(l=" + std::string (parameters [p_layer].to_string ()) +
",r=" + tl::to_string (parameters [p_actual_radius1].to_double ()) +
".." + tl::to_string (parameters [p_actual_radius2].to_double ()) +
",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) +
".." + tl::to_string (parameters [p_end_angle].to_double (), 6) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -142,7 +142,10 @@ BasicCircle::produce (const db::Layout &layout, const std::vector<unsigned int>
std::string
BasicCircle::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string("CIRCLE(r=") + tl::micron_to_string (parameters [p_actual_radius].to_double ()) + ")";
return "CIRCLE(l=" + std::string (parameters [p_layer].to_string ()) +
",r=" + tl::to_string (parameters [p_actual_radius].to_double ()) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -169,7 +169,11 @@ BasicDonut::produce (const db::Layout &layout, const std::vector<unsigned int> &
std::string
BasicDonut::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string("DONUT(r=") + tl::micron_to_string (parameters [p_actual_radius1].to_double ()) + ".." + tl::micron_to_string (parameters [p_actual_radius2].to_double ()) + ")";
return "DONUT(l=" + std::string (parameters [p_layer].to_string ()) +
",r=" + tl::to_string (parameters [p_actual_radius1].to_double ()) +
".." + tl::to_string (parameters [p_actual_radius2].to_double ()) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -173,7 +173,11 @@ BasicEllipse::produce (const db::Layout &layout, const std::vector<unsigned int>
std::string
BasicEllipse::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string("ELLIPSE(rx=") + tl::micron_to_string (parameters [p_actual_radius_x].to_double ()) + ",ry=" + tl::micron_to_string (parameters [p_actual_radius_y].to_double ()) + ")";
return "ELLIPSE(l=" + std::string (parameters [p_layer].to_string ()) +
",rx=" + tl::to_string (parameters [p_actual_radius_x].to_double ()) +
",ry=" + tl::to_string (parameters [p_actual_radius_y].to_double ()) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -186,7 +186,12 @@ BasicPie::produce (const db::Layout &layout, const std::vector<unsigned int> &la
std::string
BasicPie::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string("PIE(r=") + tl::micron_to_string (parameters [p_actual_radius].to_double ()) + ",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) + ".." + tl::to_string (parameters [p_end_angle].to_double (), 6) + ")";
return "PIE(l=" + std::string (parameters [p_layer].to_string ()) +
",r=" + tl::to_string (parameters [p_actual_radius].to_double ()) +
",a=" + tl::to_string (parameters [p_start_angle].to_double (), 6) +
".." + tl::to_string (parameters [p_end_angle].to_double (), 6) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -108,7 +108,10 @@ BasicRoundPath::produce (const db::Layout &layout, const std::vector<unsigned in
std::string
BasicRoundPath::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string("ROUND_PATH(r=") + tl::micron_to_string (parameters [p_radius].to_double ()) + ")";
return "ROUND_PATH(l=" + std::string (parameters [p_layer].to_string ()) +
",r=" + tl::to_string (parameters [p_radius].to_double ()) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -112,7 +112,10 @@ BasicRoundPolygon::produce (const db::Layout &layout, const std::vector<unsigned
std::string
BasicRoundPolygon::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string("ROUND_POLYGON(r=") + tl::micron_to_string (parameters [p_radius].to_double ()) + ")";
return "ROUND_POLYGON(l=" + std::string (parameters [p_layer].to_string ()) +
",r=" + tl::to_string (parameters [p_radius].to_double ()) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -134,7 +134,12 @@ BasicStrokedPolygon::produce (const db::Layout &layout, const std::vector<unsign
std::string
BasicStrokedPolygon::get_display_name (const db::pcell_parameters_type &parameters) const
{
return std::string(m_box ? "STROKED_BOX" : "STROKED_POLYGON") + "(w=" + tl::micron_to_string (parameters [p_width].to_double ()) + ",r=" + tl::micron_to_string (parameters [p_radius].to_double ()) + ")";
return std::string(m_box ? "STROKED_BOX" : "STROKED_POLYGON") +
"(l=" + std::string (parameters [p_layer].to_string ()) +
",w=" + tl::to_string (parameters [p_width].to_double ()) +
",r=" + tl::to_string (parameters [p_radius].to_double ()) +
",n=" + tl::to_string (parameters [p_npoints].to_int ()) +
")";
}
std::vector<db::PCellParameterDeclaration>

View File

@ -177,7 +177,8 @@ BasicText::get_display_name (const db::pcell_parameters_type &parameters) const
if (! parameters.empty ()) {
t = parameters [p_text].to_string ();
}
return std::string("TEXT('") + t + "')";
return "TEXT(l=" + std::string (parameters [p_layer].to_string ()) +
",'" + t + "')";
}
std::vector<db::PCellParameterDeclaration>