mirror of https://github.com/KLayout/klayout.git
commit
bf41da69da
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 &);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 &);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -111,5 +111,22 @@ PCellDeclaration::map_parameters (const std::map<std::string, tl::Variant> ¶
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ¶meters)
|
||||
: 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 ¶meters)
|
||||
{
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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 ¶meters);
|
||||
|
||||
/**
|
||||
* @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 ¶meters);
|
||||
|
||||
/**
|
||||
* @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 ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,45 @@ ac_from_buttons (unsigned int buttons)
|
|||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters)
|
||||
{
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -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> ¶meters);
|
||||
|
||||
/**
|
||||
* @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,
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,3 @@ plugins.depends += lib rdb db
|
|||
|
||||
unit_tests.depends += plugins $$MAIN_DEPENDS
|
||||
|
||||
RESOURCES += \
|
||||
laybasic/laybasic/layResources.qrc
|
||||
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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, ""));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -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 ¶meters) 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>
|
||||
|
|
|
|||
|
|
@ -177,7 +177,8 @@ BasicText::get_display_name (const db::pcell_parameters_type ¶meters) 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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue