mirror of https://github.com/KLayout/klayout.git
First draft of solution. Needs polishing.
This commit is contained in:
parent
d28822af3f
commit
5ee1daf945
|
|
@ -23,4 +23,78 @@
|
|||
|
||||
#include "dbInstElement.h"
|
||||
|
||||
// nothing yet ..
|
||||
namespace db
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// "to_string" implementation
|
||||
|
||||
std::string
|
||||
InstElement::to_string (bool resolve_cell_name) const
|
||||
{
|
||||
if (inst_ptr.is_null ()) {
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
db::cell_index_type ci = inst_ptr.cell_index ();
|
||||
|
||||
std::string r;
|
||||
if (resolve_cell_name && inst_ptr.instances () && inst_ptr.instances ()->cell () && inst_ptr.instances ()->cell ()->layout ()) {
|
||||
r = inst_ptr.instances ()->cell ()->layout ()->cell_name (ci);
|
||||
} else {
|
||||
r = "cell_index=" + tl::to_string (ci);
|
||||
}
|
||||
|
||||
r += " " + complex_trans ().to_string ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Implementation of "find_path"
|
||||
|
||||
static bool
|
||||
find_path (const db::Layout &layout, db::cell_index_type from, db::cell_index_type to, std::set <db::cell_index_type> &visited, std::vector<db::InstElement> &path)
|
||||
{
|
||||
const db::Cell &cell = layout.cell (from);
|
||||
for (db::Cell::parent_inst_iterator p = cell.begin_parent_insts (); ! p.at_end (); ++p) {
|
||||
|
||||
if (p->parent_cell_index () == to) {
|
||||
|
||||
path.push_back (db::InstElement (p->child_inst ()));
|
||||
return true;
|
||||
|
||||
} else if (visited.find (p->parent_cell_index ()) == visited.end ()) {
|
||||
|
||||
visited.insert (p->parent_cell_index ());
|
||||
path.push_back (db::InstElement (p->child_inst ()));
|
||||
if (find_path (layout, p->parent_cell_index (), to, visited, path)) {
|
||||
return true;
|
||||
}
|
||||
path.pop_back ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
find_path (const db::Layout &layout, db::cell_index_type from, db::cell_index_type to, std::vector<db::InstElement> &path)
|
||||
{
|
||||
path.clear ();
|
||||
if (from == to) {
|
||||
return true;
|
||||
} else {
|
||||
std::set <db::cell_index_type> v;
|
||||
if (find_path (layout, from, to, v, path)) {
|
||||
std::reverse (path.begin (), path.end ());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,8 +150,23 @@ struct DB_PUBLIC InstElement
|
|||
{
|
||||
return inst_ptr.cell_inst ().complex_trans (*array_inst);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a string representation of the element
|
||||
*/
|
||||
std::string to_string (bool resolve_cell_name = false) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Finds a path from the "from" to the "to" cell
|
||||
*
|
||||
* This function will determine one representative instantiation path leading
|
||||
* from the "from" cell to the "to" cell. If such a path exists, it is stored
|
||||
* in "path" and true is returned. If no such path exists, false is returned.
|
||||
*/
|
||||
DB_PUBLIC bool
|
||||
find_path (const db::Layout &layout, db::cell_index_type from, db::cell_index_type to, std::vector<db::InstElement> &path);
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "dbLayoutQuery.h"
|
||||
#include "dbCellGraphUtils.h"
|
||||
#include "dbStreamLayers.h"
|
||||
#include "dbInstElement.h"
|
||||
#include "tlAssert.h"
|
||||
#include "tlString.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
|
@ -476,6 +477,7 @@ struct ChildCellFilterPropertyIDs
|
|||
{
|
||||
path = q->register_property ("path", LQ_variant);
|
||||
path_names = q->register_property ("path_names", LQ_variant);
|
||||
inst_elements = q->register_property ("inst_elements", LQ_variant);
|
||||
initial_cell = q->register_property ("initial_cell", LQ_cell);
|
||||
initial_cell_index = q->register_property ("initial_cell_index", LQ_variant);
|
||||
initial_cell_name = q->register_property ("initial_cell_name", LQ_variant);
|
||||
|
|
@ -573,6 +575,7 @@ struct ChildCellFilterPropertyIDs
|
|||
unsigned int inst_bbox; // inst_bbox -> The instance bounding box in the top cell
|
||||
unsigned int inst_dbbox; // inst_dbbox -> The instance bounding box in the top cell in micrometer units
|
||||
unsigned int inst; // inst -> The instance object
|
||||
unsigned int inst_elements; // inst_elements -> Variant array with the db::InstElement objects for the path
|
||||
unsigned int array_a; // array_a -> The a vector for an array instance
|
||||
unsigned int array_da; // array_da -> The a vector for an array instance in micrometer units
|
||||
unsigned int array_na; // array_na -> The a axis array dimension
|
||||
|
|
@ -990,6 +993,31 @@ public:
|
|||
v.push (tl::Variant (cell_index ()));
|
||||
return true;
|
||||
|
||||
} else if (id == m_pids.inst_elements) {
|
||||
|
||||
if (! v.is_list ()) {
|
||||
std::vector<tl::Variant> vd;
|
||||
v = tl::Variant (vd.begin (), vd.end ());
|
||||
}
|
||||
|
||||
if (mp_parent) {
|
||||
FilterStateBase::get_property (id, v);
|
||||
}
|
||||
|
||||
db::Instance inst;
|
||||
if (m_reading) {
|
||||
inst = mp_parent->sorted_inst_ptr (std::distance (mp_parent->begin_sorted_insts (), m_inst));
|
||||
} else {
|
||||
inst = m_i;
|
||||
}
|
||||
|
||||
if (m_instance_mode == ArrayInstances) {
|
||||
v.push (tl::Variant (db::InstElement (inst)));
|
||||
} else {
|
||||
v.push (tl::Variant (db::InstElement (inst, m_array_iter)));
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (id == m_pids.path_names) {
|
||||
|
||||
if (! v.is_list ()) {
|
||||
|
|
|
|||
|
|
@ -1913,9 +1913,185 @@ Service::handle_guiding_shape_changes ()
|
|||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Implementation of EditableSelectionIterator
|
||||
|
||||
EditableSelectionIterator::EditableSelectionIterator (const std::vector<edt::Service *> &services, bool transient)
|
||||
: m_services (services), m_service (0), m_transient_selection (transient)
|
||||
{
|
||||
if (! m_services.empty ()) {
|
||||
if (m_transient_selection) {
|
||||
m_iter = m_services [m_service]->transient_selection ().begin ();
|
||||
m_end = m_services [m_service]->transient_selection ().end ();
|
||||
} else {
|
||||
m_iter = m_services [m_service]->selection ().begin ();
|
||||
m_end = m_services [m_service]->selection ().end ();
|
||||
}
|
||||
next ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
EditableSelectionIterator::at_end () const
|
||||
{
|
||||
return (m_service >= m_services.size ());
|
||||
}
|
||||
|
||||
EditableSelectionIterator &
|
||||
EditableSelectionIterator::operator++ ()
|
||||
{
|
||||
++m_iter;
|
||||
next ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const EditableSelectionIterator::value_type &
|
||||
EditableSelectionIterator::operator* () const
|
||||
{
|
||||
return *m_iter;
|
||||
}
|
||||
|
||||
void
|
||||
EditableSelectionIterator::next ()
|
||||
{
|
||||
while (m_iter == m_end) {
|
||||
++m_service;
|
||||
if (m_service < m_services.size ()) {
|
||||
if (m_transient_selection) {
|
||||
m_iter = m_services [m_service]->transient_selection ().begin ();
|
||||
m_end = m_services [m_service]->transient_selection ().end ();
|
||||
} else {
|
||||
m_iter = m_services [m_service]->selection ().begin ();
|
||||
m_end = m_services [m_service]->selection ().end ();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Selection utilities implementation
|
||||
|
||||
/**
|
||||
* @brief Gets the combined selections over all editor services in the layout view
|
||||
*/
|
||||
std::vector<edt::Service::objects::value_type> object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service::objects::value_type> result;
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
std::vector<edt::Service::objects::value_type> sel;
|
||||
(*s)->get_selection (sel);
|
||||
result.insert (result.end (), sel.begin (), sel.end ());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Distributes the combined selection over all editor services in the layout view
|
||||
*/
|
||||
void set_object_selection (const lay::LayoutViewBase *view, const std::vector<edt::Service::objects::value_type> &all_selected)
|
||||
{
|
||||
std::vector<edt::Service::objects::value_type> sel;
|
||||
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
|
||||
sel.clear ();
|
||||
|
||||
for (std::vector<edt::Service::objects::value_type>::const_iterator o = all_selected.begin (); o != all_selected.end (); ++o) {
|
||||
if ((*s)->selection_applies (*o)) {
|
||||
sel.push_back (*o);
|
||||
}
|
||||
}
|
||||
|
||||
(*s)->set_selection (sel.begin (), sel.end ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether any editor service in the view has a selection
|
||||
*/
|
||||
bool has_object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->has_selection ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the selection of all editor services in the view
|
||||
*/
|
||||
void clear_object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
(*s)->clear_selection ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects a specific object in the appropriate editor service of the view
|
||||
*/
|
||||
void select_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->selection_applies (object)) {
|
||||
(*s)->add_selection (object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unselects a specific object in the appropriate editor service of the view
|
||||
*/
|
||||
void unselect_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->selection_applies (object)) {
|
||||
(*s)->remove_selection (object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether any editor service in the view has a transient selection
|
||||
*/
|
||||
bool has_transient_object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->has_transient_selection ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over all selected object of all editor services
|
||||
*/
|
||||
EditableSelectionIterator begin_objects_selected (const lay::LayoutViewBase *view)
|
||||
{
|
||||
return EditableSelectionIterator (view->get_plugins <edt::Service> (), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over all transiently selected object of all editor services
|
||||
*/
|
||||
EditableSelectionIterator begin_objects_selected_transient (const lay::LayoutViewBase *view)
|
||||
{
|
||||
return EditableSelectionIterator (view->get_plugins <edt::Service> (), true);
|
||||
}
|
||||
|
||||
} // namespace edt
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -688,6 +688,80 @@ private:
|
|||
void update_vector_snapped_marker (const lay::InstanceMarker *sm, const db::DTrans &trans, db::DVector &vr, bool &result_set, size_t &count) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A utility class to implement a selection iterator across all editor services
|
||||
*/
|
||||
class EditableSelectionIterator
|
||||
{
|
||||
public:
|
||||
typedef edt::Service::objects::value_type value_type;
|
||||
typedef edt::Service::objects::const_iterator iterator_type;
|
||||
typedef void pointer;
|
||||
typedef const value_type &reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef void difference_type;
|
||||
|
||||
EditableSelectionIterator (const std::vector<edt::Service *> &services, bool transient);
|
||||
|
||||
bool at_end () const;
|
||||
|
||||
EditableSelectionIterator &operator++ ();
|
||||
const value_type &operator* () const;
|
||||
|
||||
private:
|
||||
std::vector<edt::Service *> m_services;
|
||||
unsigned int m_service;
|
||||
bool m_transient_selection;
|
||||
iterator_type m_iter, m_end;
|
||||
|
||||
void next ();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gets the combined selections over all editor services in the layout view
|
||||
*/
|
||||
EDT_PUBLIC std::vector<edt::Service::objects::value_type> object_selection (const lay::LayoutViewBase *view);
|
||||
|
||||
/**
|
||||
* @brief Distributes the combined selection over all editor services in the layout view
|
||||
*/
|
||||
EDT_PUBLIC void set_object_selection (const lay::LayoutViewBase *view, const std::vector<edt::Service::objects::value_type> &all_selected);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether any editor service in the view has a selection
|
||||
*/
|
||||
EDT_PUBLIC bool has_object_selection (const lay::LayoutViewBase *view);
|
||||
|
||||
/**
|
||||
* @brief Clears the selection of all editor services in the view
|
||||
*/
|
||||
EDT_PUBLIC void clear_object_selection (const lay::LayoutViewBase *view);
|
||||
|
||||
/**
|
||||
* @brief Selects a specific object in the appropriate editor service of the view
|
||||
*/
|
||||
EDT_PUBLIC void select_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object);
|
||||
|
||||
/**
|
||||
* @brief Unselects a specific object in the appropriate editor service of the view
|
||||
*/
|
||||
EDT_PUBLIC void unselect_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether any editor service in the view has a transient selection
|
||||
*/
|
||||
EDT_PUBLIC bool has_transient_object_selection (const lay::LayoutViewBase *view);
|
||||
|
||||
/**
|
||||
* @brief Iterates over all selected object of all editor services
|
||||
*/
|
||||
EDT_PUBLIC EditableSelectionIterator begin_objects_selected (const lay::LayoutViewBase *view);
|
||||
|
||||
/**
|
||||
* @brief Iterates over all transiently selected object of all editor services
|
||||
*/
|
||||
EDT_PUBLIC EditableSelectionIterator begin_objects_selected_transient (const lay::LayoutViewBase *view);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ gsi::Class<lay::ObjectInstPath> decl_ObjectInstPath ("lay", "ObjectInstPath",
|
|||
"\n"
|
||||
"The top cell is identical to the current cell provided by the cell view.\n"
|
||||
"It is the cell from which is instantiation path originates and the container cell "
|
||||
"if not instantiation path is set.\n"
|
||||
"if no instantiation path is set.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.24."
|
||||
) +
|
||||
|
|
@ -425,175 +425,12 @@ gsi::Class<lay::ObjectInstPath> decl_ObjectInstPath ("lay", "ObjectInstPath",
|
|||
"in the way shown above will help avoiding this issue.\n"
|
||||
);
|
||||
|
||||
class EditableSelectionIterator
|
||||
{
|
||||
public:
|
||||
typedef edt::Service::objects::value_type value_type;
|
||||
typedef edt::Service::objects::const_iterator iterator_type;
|
||||
typedef void pointer;
|
||||
typedef const value_type &reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef void difference_type;
|
||||
|
||||
EditableSelectionIterator (const std::vector<edt::Service *> &services, bool transient)
|
||||
: m_services (services), m_service (0), m_transient_selection (transient)
|
||||
{
|
||||
if (! m_services.empty ()) {
|
||||
if (m_transient_selection) {
|
||||
m_iter = m_services [m_service]->transient_selection ().begin ();
|
||||
m_end = m_services [m_service]->transient_selection ().end ();
|
||||
} else {
|
||||
m_iter = m_services [m_service]->selection ().begin ();
|
||||
m_end = m_services [m_service]->selection ().end ();
|
||||
}
|
||||
next ();
|
||||
}
|
||||
}
|
||||
|
||||
bool at_end () const
|
||||
{
|
||||
return (m_service >= m_services.size ());
|
||||
}
|
||||
|
||||
EditableSelectionIterator &operator++ ()
|
||||
{
|
||||
++m_iter;
|
||||
next ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const value_type &operator* () const
|
||||
{
|
||||
return *m_iter;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<edt::Service *> m_services;
|
||||
unsigned int m_service;
|
||||
bool m_transient_selection;
|
||||
iterator_type m_iter, m_end;
|
||||
|
||||
void next ()
|
||||
{
|
||||
while (m_iter == m_end) {
|
||||
++m_service;
|
||||
if (m_service < m_services.size ()) {
|
||||
if (m_transient_selection) {
|
||||
m_iter = m_services [m_service]->transient_selection ().begin ();
|
||||
m_end = m_services [m_service]->transient_selection ().end ();
|
||||
} else {
|
||||
m_iter = m_services [m_service]->selection ().begin ();
|
||||
m_end = m_services [m_service]->selection ().end ();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// extend the layout view by "edtService" specific methods
|
||||
|
||||
static std::vector<edt::Service::objects::value_type> object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service::objects::value_type> result;
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
std::vector<edt::Service::objects::value_type> sel;
|
||||
(*s)->get_selection (sel);
|
||||
result.insert (result.end (), sel.begin (), sel.end ());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void set_object_selection (const lay::LayoutViewBase *view, const std::vector<edt::Service::objects::value_type> &all_selected)
|
||||
{
|
||||
std::vector<edt::Service::objects::value_type> sel;
|
||||
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
|
||||
sel.clear ();
|
||||
|
||||
for (std::vector<edt::Service::objects::value_type>::const_iterator o = all_selected.begin (); o != all_selected.end (); ++o) {
|
||||
if ((*s)->selection_applies (*o)) {
|
||||
sel.push_back (*o);
|
||||
}
|
||||
}
|
||||
|
||||
(*s)->set_selection (sel.begin (), sel.end ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static bool has_object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->has_selection ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void clear_object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
(*s)->clear_selection ();
|
||||
}
|
||||
}
|
||||
|
||||
static void select_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->selection_applies (object)) {
|
||||
(*s)->add_selection (object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void unselect_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->selection_applies (object)) {
|
||||
(*s)->remove_selection (object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool has_transient_object_selection (const lay::LayoutViewBase *view)
|
||||
{
|
||||
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
if ((*s)->has_transient_selection ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static EditableSelectionIterator begin_objects_selected (const lay::LayoutViewBase *view)
|
||||
{
|
||||
return EditableSelectionIterator (view->get_plugins <edt::Service> (), false);
|
||||
}
|
||||
|
||||
static EditableSelectionIterator begin_objects_selected_transient (const lay::LayoutViewBase *view)
|
||||
{
|
||||
return EditableSelectionIterator (view->get_plugins <edt::Service> (), true);
|
||||
}
|
||||
|
||||
static
|
||||
gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
|
||||
gsi::method_ext ("has_object_selection?", &has_object_selection,
|
||||
gsi::method_ext ("has_object_selection?", &edt::has_object_selection,
|
||||
"@brief Returns true, if geometrical objects (shapes or cell instances) are selected in this view"
|
||||
) +
|
||||
gsi::method_ext ("object_selection", &object_selection,
|
||||
gsi::method_ext ("object_selection", &edt::object_selection,
|
||||
"@brief Returns a list of selected objects\n"
|
||||
"This method will deliver an array of \\ObjectInstPath objects listing the selected geometrical "
|
||||
"objects. Other selected objects such as annotations and images will not be contained in that "
|
||||
|
|
@ -607,7 +444,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
|
|||
"\n"
|
||||
"This method has been introduced in version 0.24.\n"
|
||||
) +
|
||||
gsi::method_ext ("object_selection=", &set_object_selection, gsi::arg ("sel"),
|
||||
gsi::method_ext ("object_selection=", &edt::set_object_selection, gsi::arg ("sel"),
|
||||
"@brief Sets the list of selected objects\n"
|
||||
"\n"
|
||||
"This method will set the selection of geometrical objects such as shapes and instances. "
|
||||
|
|
@ -617,13 +454,13 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
|
|||
"\n"
|
||||
"This method has been introduced in version 0.24.\n"
|
||||
) +
|
||||
gsi::method_ext ("clear_object_selection", &clear_object_selection,
|
||||
gsi::method_ext ("clear_object_selection", &edt::clear_object_selection,
|
||||
"@brief Clears the selection of geometrical objects (shapes or cell instances)\n"
|
||||
"The selection of other objects (such as annotations and images) will not be affected.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.24\n"
|
||||
) +
|
||||
gsi::method_ext ("select_object", &select_object, gsi::arg ("obj"),
|
||||
gsi::method_ext ("select_object", &edt::select_object, gsi::arg ("obj"),
|
||||
"@brief Adds the given selection to the list of selected objects\n"
|
||||
"\n"
|
||||
"The selection provided by the \\ObjectInstPath descriptor is added to the list of selected objects.\n"
|
||||
|
|
@ -635,7 +472,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
|
|||
"\n"
|
||||
"This method has been introduced in version 0.24\n"
|
||||
) +
|
||||
gsi::method_ext ("unselect_object", &unselect_object, gsi::arg ("obj"),
|
||||
gsi::method_ext ("unselect_object", &edt::unselect_object, gsi::arg ("obj"),
|
||||
"@brief Removes the given selection from the list of selected objects\n"
|
||||
"\n"
|
||||
"The selection provided by the \\ObjectInstPath descriptor is removed from the list of selected objects.\n"
|
||||
|
|
@ -644,7 +481,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
|
|||
"\n"
|
||||
"This method has been introduced in version 0.24\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_object_selected", &begin_objects_selected,
|
||||
gsi::iterator_ext ("each_object_selected", &edt::begin_objects_selected,
|
||||
"@brief Iterates over each selected geometrical object, yielding a \\ObjectInstPath object for each of them\n"
|
||||
"\n"
|
||||
"This iterator will deliver const objects - they cannot be modified. In order to modify the selection, "
|
||||
|
|
@ -653,7 +490,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
|
|||
"\n"
|
||||
"Another way of obtaining the selection is \\object_selection, which returns an array of \\ObjectInstPath objects.\n"
|
||||
) +
|
||||
gsi::method_ext ("has_transient_object_selection?", &has_transient_object_selection,
|
||||
gsi::method_ext ("has_transient_object_selection?", &edt::has_transient_object_selection,
|
||||
"@brief Returns true, if geometrical objects (shapes or cell instances) are selected in this view in the transient selection\n"
|
||||
"\n"
|
||||
"The transient selection represents the objects selected when the mouse hovers over the "
|
||||
|
|
@ -662,7 +499,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
|
|||
"\n"
|
||||
"This method was introduced in version 0.18."
|
||||
) +
|
||||
gsi::iterator_ext ("each_object_selected_transient", &begin_objects_selected_transient,
|
||||
gsi::iterator_ext ("each_object_selected_transient", &edt::begin_objects_selected_transient,
|
||||
"@brief Iterates over each geometrical objects in the transient selection, yielding a \\ObjectInstPath object for each of them\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.18."
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "tlProgress.h"
|
||||
#include "tlTimer.h"
|
||||
#include "rdbUtils.h"
|
||||
#include "edtService.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QHeaderView>
|
||||
|
|
@ -457,6 +458,73 @@ escape_csv (const std::string &s)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceResults::select_items (lay::LayoutViewBase *view, int cv_index)
|
||||
{
|
||||
const lay::CellView &cv = view->cellview (cv_index);
|
||||
const db::Layout &layout = cv->layout ();
|
||||
|
||||
std::vector<edt::Service::objects::value_type> sel;
|
||||
|
||||
int n_rows = int (size ());
|
||||
for (int r = 0; r < n_rows; ++r) {
|
||||
|
||||
if (r < int (shapes ().size ())) {
|
||||
|
||||
const SearchReplaceResults::QueryShapeResult &sr = shapes () [r];
|
||||
if (! sr.shape.is_null () && layout.is_valid_cell_index (sr.initial_cell_index) && layout.is_valid_cell_index (sr.cell_index)) {
|
||||
|
||||
sel.push_back (edt::Service::objects::value_type ());
|
||||
sel.back ().set_cv_index (cv_index);
|
||||
sel.back ().set_layer (sr.layer_index);
|
||||
sel.back ().set_shape (sr.shape);
|
||||
sel.back ().set_topcell (sr.initial_cell_index);
|
||||
|
||||
if (sr.inst_elements.has_value ()) {
|
||||
sel.back ().assign_path (sr.inst_elements->begin (), sr.inst_elements->end ());
|
||||
} else {
|
||||
std::vector<db::InstElement> path;
|
||||
if (db::find_path (layout, sr.cell_index, sr.initial_cell_index, path)) {
|
||||
sel.back ().assign_path (path.begin (), path.end ());
|
||||
} else {
|
||||
sel.pop_back ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (r < int (instances ().size ())) {
|
||||
|
||||
const SearchReplaceResults::QueryInstResult &ir = instances () [r];
|
||||
if (! ir.inst.is_null () && layout.is_valid_cell_index (ir.initial_cell_index) && layout.is_valid_cell_index (ir.cell_index)) {
|
||||
|
||||
sel.push_back (edt::Service::objects::value_type ());
|
||||
sel.back ().set_cv_index (cv_index);
|
||||
sel.back ().set_topcell (ir.initial_cell_index);
|
||||
|
||||
if (ir.inst_elements.has_value ()) {
|
||||
sel.back ().assign_path (ir.inst_elements->begin (), ir.inst_elements->end ());
|
||||
sel.back ().add_path (db::InstElement (ir.inst));
|
||||
} else {
|
||||
std::vector<db::InstElement> path;
|
||||
if (db::find_path (layout, ir.cell_index, ir.initial_cell_index, path)) {
|
||||
sel.back ().assign_path (path.begin (), path.end ());
|
||||
// TODO: specific array instance?
|
||||
sel.back ().add_path (db::InstElement (ir.inst));
|
||||
} else {
|
||||
sel.pop_back ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
edt::set_object_selection (view, sel);
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceResults::export_csv (const std::string &file)
|
||||
{
|
||||
|
|
@ -751,6 +819,7 @@ SearchReplaceDialog::SearchReplaceDialog (lay::Dispatcher *root, LayoutViewBase
|
|||
menu->addAction (QObject::tr ("To CSV file"), this, SLOT (export_csv ()));
|
||||
menu->addAction (QObject::tr ("To report database"), this, SLOT (export_rdb ()));
|
||||
menu->addAction (QObject::tr ("To layout"), this, SLOT (export_layout ()));
|
||||
menu->addAction (QObject::tr ("Select items"), this, SLOT (select_items ()));
|
||||
export_b->setMenu (menu);
|
||||
|
||||
bool editable = view->is_editable ();
|
||||
|
|
@ -933,6 +1002,38 @@ SearchReplaceDialog::save_state ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::select_items ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
int cv_index = m_last_query_cv_index;
|
||||
const lay::CellView &cv = mp_view->cellview (cv_index);
|
||||
if (! cv.is_valid ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
db::LayoutQuery lq (m_last_query);
|
||||
|
||||
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Running query")));
|
||||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << tl::to_string (QObject::tr ("Running query: ")) << m_last_query;
|
||||
}
|
||||
|
||||
SearchReplaceResults model;
|
||||
model.begin_changes (& cv->layout ());
|
||||
query_to_model (model, lq, iq, std::numeric_limits<size_t>::max (), true, true /*with paths*/);
|
||||
model.end_changes ();
|
||||
model.select_items (view (), cv_index);
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::export_csv ()
|
||||
{
|
||||
|
|
@ -1434,7 +1535,7 @@ SearchReplaceDialog::update_results (const std::string &q)
|
|||
}
|
||||
|
||||
try {
|
||||
fill_model (lq, iq, &cv->layout (), true);
|
||||
fill_model (lq, iq, &cv->layout (), true, false);
|
||||
attach_layout (&cv->layout ());
|
||||
} catch (...) {
|
||||
attach_layout (&cv->layout ());
|
||||
|
|
@ -1445,7 +1546,7 @@ SearchReplaceDialog::update_results (const std::string &q)
|
|||
}
|
||||
|
||||
bool
|
||||
SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all)
|
||||
SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all, bool with_path)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (QObject::tr ("Query run")));
|
||||
|
||||
|
|
@ -1456,6 +1557,7 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
|
|||
int shape_prop_id = lq.has_property ("shape") ? int (lq.property_by_name ("shape")) : -1;
|
||||
int layer_index_prop_id = lq.has_property ("layer_index") ? int (lq.property_by_name ("layer_index")) : -1;
|
||||
int instance_prop_id = lq.has_property ("inst") ? int (lq.property_by_name ("inst")) : -1;
|
||||
int inst_elements_prop_id = with_path && lq.has_property ("inst_elements") ? int (lq.property_by_name ("inst_elements")) : -1;
|
||||
int path_trans_prop_id = lq.has_property ("path_trans") ? int (lq.property_by_name ("path_trans")) : -1;
|
||||
int trans_prop_id = lq.has_property ("trans") ? int (lq.property_by_name ("trans")) : -1;
|
||||
int cell_index_prop_id = lq.has_property ("cell_index") ? int (lq.property_by_name ("cell_index")) : -1;
|
||||
|
|
@ -1503,6 +1605,18 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
|
|||
|
||||
model.push_back (SearchReplaceResults::QueryShapeResult (shape, layer_index, trans, cell_index, initial_cell_index));
|
||||
|
||||
if (inst_elements_prop_id >= 0 && iq.get (inst_elements_prop_id, v) && v.is_list ()) {
|
||||
try {
|
||||
std::vector<db::InstElement> inst_elements;
|
||||
for (auto i = v.begin (); i != v.end (); ++i) {
|
||||
inst_elements.push_back (i->to_user<db::InstElement> ());
|
||||
}
|
||||
model.shapes ().back ().inst_elements = std::move (inst_elements);
|
||||
} catch (...) {
|
||||
// ignore conversion errors
|
||||
}
|
||||
}
|
||||
|
||||
} else if (instance_prop_id >= 0) {
|
||||
|
||||
db::Instance instance;
|
||||
|
|
@ -1529,6 +1643,18 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
|
|||
|
||||
model.push_back (SearchReplaceResults::QueryInstResult (instance, trans, cell_index, initial_cell_index));
|
||||
|
||||
if (inst_elements_prop_id >= 0 && iq.get (inst_elements_prop_id, v) && v.is_list ()) {
|
||||
try {
|
||||
std::vector<db::InstElement> inst_elements;
|
||||
for (auto i = v.begin (); i != v.end (); ++i) {
|
||||
inst_elements.push_back (i->to_user<db::InstElement> ());
|
||||
}
|
||||
model.instances ().back ().inst_elements = std::move (inst_elements);
|
||||
} catch (...) {
|
||||
// ignore conversion errors
|
||||
}
|
||||
}
|
||||
|
||||
} else if (cell_index_prop_id >= 0) {
|
||||
|
||||
db::cell_index_type cell_index = std::numeric_limits<db::cell_index_type>::max ();
|
||||
|
|
@ -1559,7 +1685,7 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
|
|||
}
|
||||
|
||||
bool
|
||||
SearchReplaceDialog::fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all)
|
||||
SearchReplaceDialog::fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all, bool with_paths)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
|
|
@ -1568,7 +1694,7 @@ SearchReplaceDialog::fill_model (const db::LayoutQuery &lq, db::LayoutQueryItera
|
|||
m_model.begin_changes (layout);
|
||||
m_model.clear ();
|
||||
|
||||
res = query_to_model (m_model, lq, iq, m_max_item_count, all);
|
||||
res = query_to_model (m_model, lq, iq, m_max_item_count, all, with_paths);
|
||||
|
||||
m_model.end_changes ();
|
||||
results_stack->setCurrentIndex (0);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#include "dbLayout.h"
|
||||
#include "dbShape.h"
|
||||
#include "dbInstances.h"
|
||||
#include "dbInstElement.h"
|
||||
#include "tlOptional.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
|
|
@ -67,6 +69,7 @@ public:
|
|||
db::ICplxTrans trans;
|
||||
db::cell_index_type cell_index;
|
||||
db::cell_index_type initial_cell_index;
|
||||
tl::optional<std::vector<db::InstElement> > inst_elements;
|
||||
};
|
||||
|
||||
struct QueryInstResult
|
||||
|
|
@ -79,6 +82,7 @@ public:
|
|||
db::ICplxTrans trans;
|
||||
db::cell_index_type cell_index;
|
||||
db::cell_index_type initial_cell_index;
|
||||
tl::optional<std::vector<db::InstElement> > inst_elements;
|
||||
};
|
||||
|
||||
struct QueryCellResult
|
||||
|
|
@ -106,21 +110,41 @@ public:
|
|||
return m_data_result;
|
||||
}
|
||||
|
||||
std::vector<tl::Variant> &data ()
|
||||
{
|
||||
return m_data_result;
|
||||
}
|
||||
|
||||
const std::vector<QueryShapeResult> &shapes () const
|
||||
{
|
||||
return m_shape_result;
|
||||
}
|
||||
|
||||
std::vector<QueryShapeResult> &shapes ()
|
||||
{
|
||||
return m_shape_result;
|
||||
}
|
||||
|
||||
const std::vector<QueryInstResult> &instances () const
|
||||
{
|
||||
return m_inst_result;
|
||||
}
|
||||
|
||||
std::vector<QueryInstResult> &instances ()
|
||||
{
|
||||
return m_inst_result;
|
||||
}
|
||||
|
||||
const std::vector<QueryCellResult> &cells () const
|
||||
{
|
||||
return m_cell_result;
|
||||
}
|
||||
|
||||
std::vector<QueryCellResult> &cells ()
|
||||
{
|
||||
return m_cell_result;
|
||||
}
|
||||
|
||||
int columnCount (const QModelIndex &parent) const;
|
||||
QVariant data (const QModelIndex &index, int role) const;
|
||||
Qt::ItemFlags flags (const QModelIndex &index) const;
|
||||
|
|
@ -135,6 +159,7 @@ public:
|
|||
void export_csv (const std::string &file);
|
||||
void export_layout (db::Layout &layout);
|
||||
void export_rdb (rdb::Database &rdb, double dbu);
|
||||
void select_items (LayoutViewBase *view, int cv_index);
|
||||
|
||||
private:
|
||||
std::vector<tl::Variant> m_data_result;
|
||||
|
|
@ -212,6 +237,7 @@ private slots:
|
|||
void header_columns_changed (int from, int to);
|
||||
void cancel ();
|
||||
void cancel_exec ();
|
||||
void select_items ();
|
||||
void export_csv ();
|
||||
void export_rdb ();
|
||||
void export_layout ();
|
||||
|
|
@ -227,8 +253,8 @@ private:
|
|||
void issue_query (const std::string &q, const std::set<size_t> *selected_items, bool with_results);
|
||||
void update_results (const std::string &q);
|
||||
void remove_markers ();
|
||||
bool fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all);
|
||||
bool query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all);
|
||||
bool fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all, bool with_paths);
|
||||
bool query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all, bool with_path = false);
|
||||
void attach_layout (db::Layout *layout);
|
||||
void layout_changed ();
|
||||
|
||||
|
|
|
|||
|
|
@ -53,11 +53,30 @@ public:
|
|||
m_is_valid (false)
|
||||
{}
|
||||
|
||||
optional (const T &value) :
|
||||
explicit optional (const T &value) :
|
||||
m_value (value),
|
||||
m_is_valid (true)
|
||||
{}
|
||||
|
||||
explicit optional (T &&value) :
|
||||
m_value (value),
|
||||
m_is_valid (true)
|
||||
{}
|
||||
|
||||
optional &operator= (const T &value)
|
||||
{
|
||||
m_value = value;
|
||||
m_is_valid = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional &operator= (T &&value)
|
||||
{
|
||||
m_value = value;
|
||||
m_is_valid = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset ()
|
||||
{
|
||||
m_is_valid = false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue