mirror of https://github.com/KLayout/klayout.git
commit
8ab398dc58
|
|
@ -2887,15 +2887,18 @@ Layout::get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &i
|
|||
if (pcell_variant) {
|
||||
|
||||
const db::PCellDeclaration *pcell_decl = ly->pcell_declaration (pcell_variant->pcell_id ());
|
||||
|
||||
const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
|
||||
std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin ();
|
||||
for (std::vector<tl::Variant>::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) {
|
||||
info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p));
|
||||
if (pcell_decl) {
|
||||
const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
|
||||
std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin ();
|
||||
for (std::vector<tl::Variant>::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) {
|
||||
info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p));
|
||||
}
|
||||
}
|
||||
|
||||
const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ());
|
||||
info.pcell_name = header->get_name ();
|
||||
if (header) {
|
||||
info.pcell_name = header->get_name ();
|
||||
}
|
||||
|
||||
} else if (ly != this) {
|
||||
info.cell_name = ly->cell_name (cptr->cell_index ());
|
||||
|
|
|
|||
|
|
@ -683,5 +683,106 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// break_polygons implementation
|
||||
|
||||
static bool split_polygon (bool first, db::Polygon &poly, size_t max_vertex_count, double max_area_ratio, std::vector<db::Polygon> &parts)
|
||||
{
|
||||
if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) ||
|
||||
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
|
||||
|
||||
std::vector<db::Polygon> sp;
|
||||
db::split_polygon (poly, sp);
|
||||
for (auto p = sp.begin (); p != sp.end (); ++p) {
|
||||
split_polygon (false, *p, max_vertex_count, max_area_ratio, parts);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
if (! first) {
|
||||
parts.push_back (db::Polygon ());
|
||||
parts.back ().swap (poly);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
break_polygons (db::Shapes &shapes, size_t max_vertex_count, double max_area_ratio)
|
||||
{
|
||||
if (shapes.is_editable ()) {
|
||||
|
||||
std::vector<db::Polygon> new_polygons;
|
||||
std::vector<db::Shape> to_delete;
|
||||
|
||||
for (auto s = shapes.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) {
|
||||
db::Polygon poly;
|
||||
s->instantiate (poly);
|
||||
if (split_polygon (true, poly, max_vertex_count, max_area_ratio, new_polygons)) {
|
||||
to_delete.push_back (*s);
|
||||
}
|
||||
}
|
||||
|
||||
shapes.erase_shapes (to_delete);
|
||||
|
||||
for (auto p = new_polygons.begin (); p != new_polygons.end (); ++p) {
|
||||
shapes.insert (*p);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// In non-editable mode we cannot do "erase", so we use a temporary, editable Shapes container
|
||||
db::Shapes tmp (true);
|
||||
tmp.insert (shapes);
|
||||
|
||||
shapes.clear ();
|
||||
break_polygons (tmp, max_vertex_count, max_area_ratio);
|
||||
shapes.insert (tmp);
|
||||
|
||||
tl_assert (!shapes.is_editable ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
break_polygons (db::Layout &layout, db::cell_index_type cell_index, unsigned int layer, size_t max_vertex_count, double max_area_ratio)
|
||||
{
|
||||
if (layout.is_valid_cell_index (cell_index) && layout.is_valid_layer (layer)) {
|
||||
db::Cell &cell = layout.cell (cell_index);
|
||||
break_polygons (cell.shapes (layer), max_vertex_count, max_area_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
break_polygons (db::Layout &layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio)
|
||||
{
|
||||
for (db::cell_index_type ci = 0; ci < layout.cells (); ++ci) {
|
||||
if (layout.is_valid_cell_index (ci)) {
|
||||
db::Cell &cell = layout.cell (ci);
|
||||
break_polygons (cell.shapes (layer), max_vertex_count, max_area_ratio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
break_polygons (db::Layout &layout, size_t max_vertex_count, double max_area_ratio)
|
||||
{
|
||||
for (db::cell_index_type ci = 0; ci < layout.cells (); ++ci) {
|
||||
if (layout.is_valid_cell_index (ci)) {
|
||||
db::Cell &cell = layout.cell (ci);
|
||||
for (unsigned int li = 0; li < layout.layers (); ++li) {
|
||||
if (layout.is_valid_layer (li)) {
|
||||
break_polygons (cell.shapes (li), max_vertex_count, max_area_ratio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -249,6 +249,33 @@ private:
|
|||
*/
|
||||
DB_PUBLIC void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d);
|
||||
|
||||
/**
|
||||
* @brief Breaks polygons according to max_vertex_count and max_area_ratio
|
||||
*
|
||||
* This method will investigate all polygons on the given layer and cell and split them in case they
|
||||
* have more than the specified vertices and an bounding-box area to polygon area ratio larget
|
||||
* than the specified max_area_ratio. This serves optimization for algorithms needing a good
|
||||
* bounding box approximation.
|
||||
*
|
||||
* Setting max_vertex_count or max_area_ratio to 0 disables the respective check.
|
||||
*/
|
||||
DB_PUBLIC void break_polygons (db::Layout &layout, db::cell_index_type cell_index, unsigned int layer, size_t max_vertex_count, double max_area_ratio);
|
||||
|
||||
/**
|
||||
* @brief Like "break_polygons" before, but applies it to all cells.
|
||||
*/
|
||||
DB_PUBLIC void break_polygons (db::Layout &layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio);
|
||||
|
||||
/**
|
||||
* @brief Like "break_polygons" before, but applies it to all cells and all layers.
|
||||
*/
|
||||
DB_PUBLIC void break_polygons (db::Layout &layout, size_t max_vertex_count, double max_area_ratio);
|
||||
|
||||
/**
|
||||
* @brief Like "break_polygons" before, but applies it to the given Shapes container.
|
||||
*/
|
||||
DB_PUBLIC void break_polygons (db::Shapes &shapes, size_t max_vertex_count, double max_area_ratio);
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -366,6 +366,47 @@ size_t Netlist::top_circuit_count () const
|
|||
return m_top_circuits;
|
||||
}
|
||||
|
||||
Circuit *Netlist::top_circuit ()
|
||||
{
|
||||
size_t ntop = top_circuit_count ();
|
||||
if (ntop == 0) {
|
||||
return 0;
|
||||
} else if (ntop > 1) {
|
||||
throw tl::Exception (tl::to_string (tr ("Netlist contains more than a single top circuit")));
|
||||
} else {
|
||||
return begin_top_down ().operator-> ();
|
||||
}
|
||||
}
|
||||
|
||||
const Circuit *Netlist::top_circuit () const
|
||||
{
|
||||
return const_cast<Netlist *> (this)->top_circuit ();
|
||||
}
|
||||
|
||||
std::vector<Circuit *> Netlist::top_circuits ()
|
||||
{
|
||||
size_t ntop = top_circuit_count ();
|
||||
std::vector<Circuit *> result;
|
||||
result.reserve (ntop);
|
||||
for (auto c = begin_top_down (); ntop > 0 && c != end_top_down (); ++c) {
|
||||
result.push_back (c.operator-> ());
|
||||
--ntop;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const Circuit *> Netlist::top_circuits () const
|
||||
{
|
||||
size_t ntop = top_circuit_count ();
|
||||
std::vector<const Circuit *> result;
|
||||
result.reserve (ntop);
|
||||
for (auto c = begin_top_down (); ntop > 0 && c != end_top_down (); ++c) {
|
||||
result.push_back (c.operator-> ());
|
||||
--ntop;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Netlist::bottom_up_circuit_iterator Netlist::begin_bottom_up ()
|
||||
{
|
||||
if (! m_valid_topology) {
|
||||
|
|
|
|||
|
|
@ -271,6 +271,32 @@ public:
|
|||
return m_circuit_by_cell_index.object_by (cell_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the top circuit if there is one
|
||||
* This method will assert if there is more than a single top circuit.
|
||||
* It will return 0 if there is no top circuit.
|
||||
*/
|
||||
Circuit *top_circuit ();
|
||||
|
||||
/**
|
||||
* @brief Gets the top circuit if there is one (const version)
|
||||
* This method will assert if there is more than a single top circuit.
|
||||
* It will return 0 if there is no top circuit.
|
||||
*/
|
||||
const Circuit *top_circuit () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the top circuits
|
||||
* This convenience method will return a list of top circuits.
|
||||
*/
|
||||
std::vector<Circuit *> top_circuits ();
|
||||
|
||||
/**
|
||||
* @brief Gets the top circuits (const version)
|
||||
* This convenience method will return a list of top circuits.
|
||||
*/
|
||||
std::vector<const Circuit *> top_circuits () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the top-down circuits iterator (begin)
|
||||
* This iterator will deliver the circuits in a top-down way - i.e. child circuits
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace db
|
|||
// Recursive shape iterator implementation
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const RecursiveShapeIterator &d)
|
||||
: gsi::ObjectBase (d)
|
||||
{
|
||||
operator= (d);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1104,14 +1104,14 @@ static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Va
|
|||
c->prop_id (layout->properties_repository ().properties_id (props));
|
||||
}
|
||||
|
||||
static tl::Variant get_cell_property (db::Cell *c, const tl::Variant &key)
|
||||
static tl::Variant get_cell_property (const db::Cell *c, const tl::Variant &key)
|
||||
{
|
||||
db::properties_id_type id = c->prop_id ();
|
||||
if (id == 0) {
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
||||
db::Layout *layout = c->layout ();
|
||||
const db::Layout *layout = c->layout ();
|
||||
if (! layout) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot retrieve properties")));
|
||||
}
|
||||
|
|
@ -1130,6 +1130,26 @@ static tl::Variant get_cell_property (db::Cell *c, const tl::Variant &key)
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_cell_properties (const db::Cell *c)
|
||||
{
|
||||
db::properties_id_type id = c->prop_id ();
|
||||
if (id == 0) {
|
||||
return tl::Variant::empty_array ();
|
||||
}
|
||||
|
||||
const db::Layout *layout = c->layout ();
|
||||
if (! layout) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot retrieve properties")));
|
||||
}
|
||||
|
||||
tl::Variant res = tl::Variant::empty_array ();
|
||||
const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id);
|
||||
for (auto i = props.begin (); i != props.end (); ++i) {
|
||||
res.insert (layout->properties_repository ().prop_name (i->first), i->second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool is_pcell_variant (const db::Cell *cell)
|
||||
{
|
||||
tl_assert (cell->layout () != 0);
|
||||
|
|
@ -1841,10 +1861,16 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"@brief Gets the user property with the given key\n"
|
||||
"This method is a convenience method that gets the property with the given key. "
|
||||
"If no property with that key exists, it will return nil. Using that method is more "
|
||||
"convenient than using the layout object and the properties ID to retrieve the property value. "
|
||||
"convenient than using the layout object and the properties ID to retrieve the property value.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method_ext ("properties", &get_cell_properties,
|
||||
"@brief Gets the user properties as a hash\n"
|
||||
"This method is a convenience method that gets all user properties as a single hash.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::method_ext ("add_meta_info", &cell_add_meta_info, gsi::arg ("info"),
|
||||
"@brief Adds meta information to the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
|
|
@ -3539,6 +3565,26 @@ static tl::Variant get_property (const db::Instance *i, const tl::Variant &key)
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_properties (const db::Instance *i)
|
||||
{
|
||||
db::properties_id_type id = i->prop_id ();
|
||||
if (id == 0) {
|
||||
return tl::Variant::empty_array ();
|
||||
}
|
||||
|
||||
const db::Layout *layout = layout_ptr_const (i);
|
||||
if (! layout) {
|
||||
throw tl::Exception (tl::to_string (tr ("Instance does not reside inside a layout - cannot retrieve properties")));
|
||||
}
|
||||
|
||||
tl::Variant res = tl::Variant::empty_array ();
|
||||
const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id);
|
||||
for (auto i = props.begin (); i != props.end (); ++i) {
|
||||
res.insert (layout->properties_repository ().prop_name (i->first), i->second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool inst_is_valid (const db::Instance *inst)
|
||||
{
|
||||
return inst->instances () && inst->instances ()->is_valid (*inst);
|
||||
|
|
@ -4011,6 +4057,12 @@ Class<db::Instance> decl_Instance ("db", "Instance",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.22."
|
||||
) +
|
||||
gsi::method_ext ("properties", &get_properties,
|
||||
"@brief Gets the user properties as a hash\n"
|
||||
"This method is a convenience method that gets all user properties as a single hash.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
method_ext ("[]", &inst_index, gsi::arg ("key"),
|
||||
"@brief Gets the user property with the given key or, if available, the PCell parameter with the name given by the key\n"
|
||||
"Getting the PCell parameter has priority over the user property."
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "dbLayerMapping.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbTechnology.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
|
|
@ -343,7 +344,7 @@ static void set_layout_property (db::Layout *l, const tl::Variant &key, const tl
|
|||
l->prop_id (l->properties_repository ().properties_id (props));
|
||||
}
|
||||
|
||||
static tl::Variant get_layout_property (db::Layout *l, const tl::Variant &key)
|
||||
static tl::Variant get_layout_property (const db::Layout *l, const tl::Variant &key)
|
||||
{
|
||||
// TODO: check if is editable
|
||||
|
||||
|
|
@ -366,6 +367,21 @@ static tl::Variant get_layout_property (db::Layout *l, const tl::Variant &key)
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_layout_properties (const db::Layout *layout)
|
||||
{
|
||||
db::properties_id_type id = layout->prop_id ();
|
||||
if (id == 0) {
|
||||
return tl::Variant::empty_array ();
|
||||
}
|
||||
|
||||
tl::Variant res = tl::Variant::empty_array ();
|
||||
const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id);
|
||||
for (auto i = props.begin (); i != props.end (); ++i) {
|
||||
res.insert (layout->properties_repository ().prop_name (i->first), i->second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static db::cell_index_type cell_by_name (db::Layout *l, const char *name)
|
||||
{
|
||||
std::pair<bool, db::cell_index_type> c = l->cell_by_name (name);
|
||||
|
|
@ -1050,6 +1066,16 @@ static void set_properties (db::Layout *layout, unsigned int index, const db::La
|
|||
}
|
||||
}
|
||||
|
||||
void break_polygons2 (db::Layout *layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio)
|
||||
{
|
||||
db::break_polygons (*layout, layer, max_vertex_count, max_area_ratio);
|
||||
}
|
||||
|
||||
void break_polygons1 (db::Layout *layout, size_t max_vertex_count, double max_area_ratio)
|
||||
{
|
||||
db::break_polygons (*layout, max_vertex_count, max_area_ratio);
|
||||
}
|
||||
|
||||
Class<db::Layout> decl_Layout ("db", "Layout",
|
||||
gsi::constructor ("new", &layout_ctor_with_manager, gsi::arg ("manager"),
|
||||
"@brief Creates a layout object attached to a manager\n"
|
||||
|
|
@ -1254,6 +1280,12 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.24."
|
||||
) +
|
||||
gsi::method_ext ("properties", &get_layout_properties,
|
||||
"@brief Gets the user properties as a hash\n"
|
||||
"This method is a convenience method that gets all user properties as a single hash.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::method_ext ("properties_id", &properties_id, gsi::arg ("properties"),
|
||||
"@brief Gets the properties ID for a given properties set\n"
|
||||
"\n"
|
||||
|
|
@ -1956,6 +1988,33 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.26.1.\n"
|
||||
) +
|
||||
gsi::method_ext ("break_polygons", &break_polygons1, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"),
|
||||
"@brief Breaks the polygons of the layout into smaller ones\n"
|
||||
"\n"
|
||||
"There are two criteria for splitting a polygon: a polygon is split into parts with less then "
|
||||
"'max_vertex_count' points and an bounding box-to-polygon area ratio less than 'max_area_ratio'. "
|
||||
"The area ratio is supposed to render polygons whose bounding box is a better approximation. "
|
||||
"This applies for example to 'L' shape polygons.\n"
|
||||
"\n"
|
||||
"Using a value of 0 for either limit means that the respective limit isn't checked. "
|
||||
"Breaking happens by cutting the polygons into parts at 'good' locations. The "
|
||||
"algorithm does not have a specific goal to minimize the number of parts for example. "
|
||||
"The only goal is to achieve parts within the given limits.\n"
|
||||
"\n"
|
||||
"Breaking also applies to paths if their polygon representation satisfies the breaking criterion. "
|
||||
"In that case, paths are converted to polygons and broken into smaller parts.\n"
|
||||
"\n"
|
||||
"This variant applies breaking to all cells and layers.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::method_ext ("break_polygons", &break_polygons2, gsi::arg ("layer"), gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"),
|
||||
"@brief Breaks the polygons of the layer into smaller ones\n"
|
||||
"\n"
|
||||
"This variant applies breaking to all cells and the given layer.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::method ("transform", (void (db::Layout::*) (const db::Trans &t)) &db::Layout::transform, gsi::arg ("trans"),
|
||||
"@brief Transforms the layout with the given transformation\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -2044,6 +2044,32 @@ Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.28.4.\n"
|
||||
) +
|
||||
gsi::method ("top_circuit", static_cast<db::Circuit *(db::Netlist::*) ()> (&db::Netlist::top_circuit),
|
||||
"@brief Gets the top circuit.\n"
|
||||
"This method will return nil, if there is no top circuit. It will raise an error, if there is more than "
|
||||
"a single top circuit.\n"
|
||||
"\n"
|
||||
"This convenience method has been added in version 0.29.5."
|
||||
) +
|
||||
gsi::method ("top_circuit", static_cast<const db::Circuit *(db::Netlist::*) () const> (&db::Netlist::top_circuit),
|
||||
"@brief Gets the top circuit (const version).\n"
|
||||
"This method will return nil, if there is no top circuit. It will raise an error, if there is more than "
|
||||
"a single top circuit.\n"
|
||||
"\n"
|
||||
"This convenience method has been added in version 0.29.5."
|
||||
) +
|
||||
gsi::method ("top_circuits", static_cast<std::vector<db::Circuit *> (db::Netlist::*) ()> (&db::Netlist::top_circuits),
|
||||
"@brief Gets the top circuits.\n"
|
||||
"Returns a list of top circuits.\n"
|
||||
"\n"
|
||||
"This convenience method has been added in version 0.29.5."
|
||||
) +
|
||||
gsi::method ("top_circuits", static_cast<std::vector<const db::Circuit *> (db::Netlist::*) () const> (&db::Netlist::top_circuits),
|
||||
"@brief Gets the top circuits.\n"
|
||||
"Returns a list of top circuits.\n"
|
||||
"\n"
|
||||
"This convenience method has been added in version 0.29.5."
|
||||
) +
|
||||
gsi::method_ext ("nets_by_name", &nets_by_name_const_from_netlist, gsi::arg ("name_pattern"),
|
||||
"@brief Gets the net objects for a given name filter (const version).\n"
|
||||
"The name filter is a glob pattern. This method will return all \\Net objects matching the glob pattern.\n"
|
||||
|
|
|
|||
|
|
@ -1132,6 +1132,24 @@ rasterize1 (const db::Region *region, const db::Point &origin, const db::Vector
|
|||
return rasterize2 (region, origin, pixel_size, pixel_size, nx, ny);
|
||||
}
|
||||
|
||||
static tl::Variant begin_shapes_rec (const db::Region *region)
|
||||
{
|
||||
auto res = region->begin_iter ();
|
||||
tl::Variant r = tl::Variant (std::vector<tl::Variant> ());
|
||||
r.push (tl::Variant (res.first));
|
||||
r.push (tl::Variant (res.second));
|
||||
return r;
|
||||
}
|
||||
|
||||
static tl::Variant begin_merged_shapes_rec (const db::Region *region)
|
||||
{
|
||||
auto res = region->begin_merged_iter ();
|
||||
tl::Variant r = tl::Variant (std::vector<tl::Variant> ());
|
||||
r.push (tl::Variant (res.first));
|
||||
r.push (tl::Variant (res.second));
|
||||
return r;
|
||||
}
|
||||
|
||||
static db::Point default_origin;
|
||||
|
||||
// provided by gsiDeclDbPolygon.cc:
|
||||
|
|
@ -2895,7 +2913,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"This method returns all polygons in self which are not rectilinear."
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("break", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0),
|
||||
method_ext ("break_polygons|#break", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0),
|
||||
"@brief Breaks the polygons of the region into smaller ones\n"
|
||||
"\n"
|
||||
"There are two criteria for splitting a polygon: a polygon is split into parts with less then "
|
||||
|
|
@ -2908,7 +2926,8 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"algorithm does not have a specific goal to minimize the number of parts for example. "
|
||||
"The only goal is to achieve parts within the given limits.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26."
|
||||
"This method has been introduced in version 0.26. The 'break_polygons' alias has been introduced "
|
||||
"in version 0.29.5 to avoid issues with reserved keywords."
|
||||
) +
|
||||
method_ext ("delaunay", &delaunay,
|
||||
"@brief Computes a constrained Delaunay triangulation from the given region\n"
|
||||
|
|
@ -2932,6 +2951,8 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"and is usually a good choice. The algorithm is stable up to roughly 1.2 which corresponds to "
|
||||
"a minimum angle of abouth 37 degree.\n"
|
||||
"\n"
|
||||
"The minimum angle of the resulting triangles relates to the 'b' parameter as: @t min_angle = arcsin(B/2) @/t.\n"
|
||||
"\n"
|
||||
"The area value is given in terms of DBU units. Picking a value of 0.0 for area and min b will "
|
||||
"make the implementation skip the refinement step. In that case, the results are identical to "
|
||||
"the standard constrained Delaunay triangulation.\n"
|
||||
|
|
@ -3756,7 +3777,32 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"metal1_all_nets = metal1.nets\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.28.4"
|
||||
"This method was introduced in version 0.28.4."
|
||||
) +
|
||||
gsi::method_ext ("begin_shapes_rec", &begin_shapes_rec,
|
||||
"@brief Returns a recursive shape iterator plus a transformation for the shapes constituting this region.\n"
|
||||
"This method returns a pair consisting of a \\RecursiveShapeIterator plus a \\ICplxTrans transformation. "
|
||||
"Both objects allow accessing the shapes (polygons) of the region in a detailed fashion. To iterate the "
|
||||
"the polygons use a code like this:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"iter, trans = region.begin_shapes_rec\n"
|
||||
"iter.each do |i|\n"
|
||||
" polygon = trans * iter.trans * i.shape.polygon\n"
|
||||
" ...\n"
|
||||
"end\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This method is the most powerful way of accessing the shapes inside the region. I allows for example to obtain the "
|
||||
"properties attached to the polygons of the region. It is primarily intended for special applications like iterating net-annotated shapes.\n"
|
||||
"\n"
|
||||
"This speciality method was introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::method_ext ("begin_merged_shapes_rec", &begin_merged_shapes_rec,
|
||||
"@brief Returns a recursive shape iterator plus a transformation for the shapes constituting the merged region.\n"
|
||||
"It can be used like \\begin_shapes_rec, but delivers shapes from the merged polygons pool.\n"
|
||||
"\n"
|
||||
"This speciality method was introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::make_property_methods<db::Region> ()
|
||||
,
|
||||
|
|
|
|||
|
|
@ -1004,6 +1004,26 @@ static tl::Variant get_property (const db::Shape *s, const tl::Variant &key)
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_properties (const db::Shape *s)
|
||||
{
|
||||
db::properties_id_type id = s->prop_id ();
|
||||
if (id == 0) {
|
||||
return tl::Variant::empty_array ();
|
||||
}
|
||||
|
||||
const db::Layout *layout = layout_ptr_const (s);
|
||||
if (! layout) {
|
||||
throw tl::Exception (tl::to_string (tr ("Shape does not reside inside a layout - cannot retrieve properties")));
|
||||
}
|
||||
|
||||
tl::Variant res = tl::Variant::empty_array ();
|
||||
const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id);
|
||||
for (auto i = props.begin (); i != props.end (); ++i) {
|
||||
res.insert (layout->properties_repository ().prop_name (i->first), i->second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
|
@ -1354,6 +1374,12 @@ Class<db::Shape> decl_Shape ("db", "Shape",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.22."
|
||||
) +
|
||||
gsi::method_ext ("properties", &get_properties,
|
||||
"@brief Gets the user properties\n"
|
||||
"This method is a convenience method that gets the properties of the shape as a single hash.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::iterator ("each_point", &db::Shape::begin_point, &db::Shape::end_point,
|
||||
"@brief Iterates over all points of the object\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "dbRegion.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
|
@ -441,6 +442,11 @@ static db::Layout *layout (db::Shapes *sh)
|
|||
}
|
||||
}
|
||||
|
||||
static void break_polygons (db::Shapes *sh, size_t max_vertex_count, double max_area_ratio)
|
||||
{
|
||||
db::break_polygons (*sh, max_vertex_count, max_area_ratio);
|
||||
}
|
||||
|
||||
static unsigned int s_all () { return db::ShapeIterator::All; }
|
||||
static unsigned int s_all_with_properties () { return db::ShapeIterator::AllWithProperties; }
|
||||
static unsigned int s_properties () { return db::ShapeIterator::Properties; }
|
||||
|
|
@ -791,6 +797,24 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.25.\n"
|
||||
) +
|
||||
gsi::method_ext ("break_polygons", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0),
|
||||
"@brief Breaks the polygons of the shape container into smaller ones\n"
|
||||
"\n"
|
||||
"There are two criteria for splitting a polygon: a polygon is split into parts with less then "
|
||||
"'max_vertex_count' points and an bounding box-to-polygon area ratio less than 'max_area_ratio'. "
|
||||
"The area ratio is supposed to render polygons whose bounding box is a better approximation. "
|
||||
"This applies for example to 'L' shape polygons.\n"
|
||||
"\n"
|
||||
"Using a value of 0 for either limit means that the respective limit isn't checked. "
|
||||
"Breaking happens by cutting the polygons into parts at 'good' locations. The "
|
||||
"algorithm does not have a specific goal to minimize the number of parts for example. "
|
||||
"The only goal is to achieve parts within the given limits.\n"
|
||||
"\n"
|
||||
"Breaking also applies to paths if their polygon representation satisfies the breaking criterion. "
|
||||
"In that case, paths are converted to polygons and broken into smaller parts.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::method_ext ("replace", &replace<db::Box>, gsi::arg ("shape"), gsi::arg ("box"),
|
||||
"@brief Replaces the given shape with a box\n"
|
||||
"@return A reference to the new shape (a \\Shape object)\n"
|
||||
|
|
|
|||
|
|
@ -779,3 +779,42 @@ TEST(20_scale_and_snap)
|
|||
db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns4.oas", db::NormalizationMode (db::WriteOAS + db::WithArrays));
|
||||
}
|
||||
|
||||
|
||||
TEST(21_break1)
|
||||
{
|
||||
db::Layout l1;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/break_polygons_test.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (l1);
|
||||
}
|
||||
|
||||
db::break_polygons (l1, 10, 3.0);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_bp1.gds");
|
||||
}
|
||||
|
||||
TEST(22_break2)
|
||||
{
|
||||
db::Layout l1;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/break_polygons_test.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (l1);
|
||||
}
|
||||
|
||||
unsigned int li1 = find_layer (l1, 1, 0);
|
||||
unsigned int li2 = find_layer (l1, 2, 0);
|
||||
|
||||
db::break_polygons (l1, li1, 10, 0.0);
|
||||
db::break_polygons (l1, li2, 0, 3.0);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_bp2.gds");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -208,6 +208,18 @@ static std::string parents2string (const db::Circuit *c)
|
|||
return res;
|
||||
}
|
||||
|
||||
static std::string td2string_nc (db::Netlist *nl)
|
||||
{
|
||||
std::string res;
|
||||
for (db::Netlist::top_down_circuit_iterator r = nl->begin_top_down (); r != nl->end_top_down (); ++r) {
|
||||
if (!res.empty ()) {
|
||||
res += ",";
|
||||
}
|
||||
res += r->name ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string td2string (const db::Netlist *nl)
|
||||
{
|
||||
std::string res;
|
||||
|
|
@ -220,6 +232,64 @@ static std::string td2string (const db::Netlist *nl)
|
|||
return res;
|
||||
}
|
||||
|
||||
static std::string tcs2string_nc (db::Netlist *nl)
|
||||
{
|
||||
std::string res;
|
||||
std::vector<db::Circuit *> tops = nl->top_circuits ();
|
||||
for (auto i = tops.begin (); i != tops.end (); ++i) {
|
||||
if (!res.empty ()) {
|
||||
res += ",";
|
||||
}
|
||||
res += (*i)->name ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string tcs2string (const db::Netlist *nl)
|
||||
{
|
||||
std::string res;
|
||||
std::vector<const db::Circuit *> tops = nl->top_circuits ();
|
||||
for (auto i = tops.begin (); i != tops.end (); ++i) {
|
||||
if (!res.empty ()) {
|
||||
res += ",";
|
||||
}
|
||||
res += (*i)->name ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string tc2string_nc (db::Netlist *nl)
|
||||
{
|
||||
const db::Circuit *tc = nl->top_circuit ();
|
||||
if (!tc) {
|
||||
return "(nil)";
|
||||
} else {
|
||||
return tc->name ();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string tc2string (const db::Netlist *nl)
|
||||
{
|
||||
const db::Circuit *tc = nl->top_circuit ();
|
||||
if (!tc) {
|
||||
return "(nil)";
|
||||
} else {
|
||||
return tc->name ();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string bu2string_nc (db::Netlist *nl)
|
||||
{
|
||||
std::string res;
|
||||
for (db::Netlist::bottom_up_circuit_iterator r = nl->begin_bottom_up (); r != nl->end_bottom_up (); ++r) {
|
||||
if (!res.empty ()) {
|
||||
res += ",";
|
||||
}
|
||||
res += r->name ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string bu2string (const db::Netlist *nl)
|
||||
{
|
||||
std::string res;
|
||||
|
|
@ -1038,20 +1108,44 @@ TEST(12_NetlistTopology)
|
|||
{
|
||||
std::unique_ptr<db::Netlist> nl (new db::Netlist ());
|
||||
EXPECT_EQ (nl->top_circuit_count (), size_t (0));
|
||||
EXPECT_EQ (tcs2string (nl.get ()), "");
|
||||
EXPECT_EQ (tcs2string_nc (nl.get ()), "");
|
||||
EXPECT_EQ (tc2string (nl.get ()), "(nil)");
|
||||
EXPECT_EQ (tc2string_nc (nl.get ()), "(nil)");
|
||||
|
||||
db::Circuit *c1 = new db::Circuit ();
|
||||
c1->set_name ("c1");
|
||||
nl->add_circuit (c1);
|
||||
EXPECT_EQ (nl->top_circuit_count (), size_t (1));
|
||||
EXPECT_EQ (td2string (nl.get ()), "c1");
|
||||
EXPECT_EQ (td2string_nc (nl.get ()), "c1");
|
||||
EXPECT_EQ (tcs2string (nl.get ()), "c1");
|
||||
EXPECT_EQ (tcs2string_nc (nl.get ()), "c1");
|
||||
EXPECT_EQ (tc2string (nl.get ()), "c1");
|
||||
EXPECT_EQ (tc2string_nc (nl.get ()), "c1");
|
||||
EXPECT_EQ (bu2string (nl.get ()), "c1");
|
||||
EXPECT_EQ (bu2string_nc (nl.get ()), "c1");
|
||||
|
||||
db::Circuit *c2 = new db::Circuit ();
|
||||
c2->set_name ("c2");
|
||||
nl->add_circuit (c2);
|
||||
EXPECT_EQ (nl->top_circuit_count (), size_t (2));
|
||||
EXPECT_EQ (td2string (nl.get ()), "c2,c1");
|
||||
EXPECT_EQ (td2string_nc (nl.get ()), "c2,c1");
|
||||
EXPECT_EQ (tcs2string (nl.get ()), "c2,c1");
|
||||
EXPECT_EQ (tcs2string_nc (nl.get ()), "c2,c1");
|
||||
try {
|
||||
tc2string (nl.get ());
|
||||
EXPECT_EQ (true, false);
|
||||
} catch (...) {
|
||||
}
|
||||
try {
|
||||
tc2string_nc (nl.get ());
|
||||
EXPECT_EQ (true, false);
|
||||
} catch (...) {
|
||||
}
|
||||
EXPECT_EQ (bu2string (nl.get ()), "c1,c2");
|
||||
EXPECT_EQ (bu2string_nc (nl.get ()), "c1,c2");
|
||||
|
||||
std::unique_ptr<db::NetlistLocker> locker (new db::NetlistLocker (nl.get ()));
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ namespace edt
|
|||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static std::string cell_name_from_sel (const edt::Service::obj_iterator &pos, edt::Service *service)
|
||||
static std::string cell_name_from_sel (EditableSelectionIterator::pointer pos, edt::Service *service)
|
||||
{
|
||||
if (! pos->is_cell_inst ()) {
|
||||
return std::string ();
|
||||
|
|
@ -81,7 +81,7 @@ struct SelectionPtrSort
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool operator() (const edt::Service::obj_iterator &a, const edt::Service::obj_iterator &b)
|
||||
bool operator() (EditableSelectionIterator::pointer a, EditableSelectionIterator::pointer b)
|
||||
{
|
||||
return cell_name_from_sel (a, mp_service) < cell_name_from_sel (b, mp_service);
|
||||
}
|
||||
|
|
@ -104,10 +104,9 @@ static bool is_orthogonal (const db::DVector &rv, const db::DVector &cv)
|
|||
InstPropertiesPage::InstPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
|
||||
: lay::PropertiesPage (parent, manager, service), mp_service (service), m_enable_cb_callback (true), mp_pcell_parameters (0)
|
||||
{
|
||||
const edt::Service::objects &selection = service->selection ();
|
||||
m_selection_ptrs.reserve (selection.size ());
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
m_selection_ptrs.push_back (s);
|
||||
m_selection_ptrs.reserve (service->selection_size ());
|
||||
for (EditableSelectionIterator s = service->begin_selection (); ! s.at_end (); ++s) {
|
||||
m_selection_ptrs.push_back (s.operator-> ());
|
||||
}
|
||||
|
||||
std::sort (m_selection_ptrs.begin (), m_selection_ptrs.end (), SelectionPtrSort (service));
|
||||
|
|
@ -221,7 +220,7 @@ BEGIN_PROTECTED
|
|||
lib = lib_cbx->current_library ();
|
||||
layout = &lib->layout ();
|
||||
} else {
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
layout = &cv->layout ();
|
||||
}
|
||||
|
|
@ -300,7 +299,7 @@ InstPropertiesPage::select_entries (const std::vector<size_t> &entries)
|
|||
std::string
|
||||
InstPropertiesPage::description (size_t entry) const
|
||||
{
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [entry];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [entry];
|
||||
std::string d = cell_name_from_sel (pos, mp_service);
|
||||
|
||||
if (! pos->is_cell_inst ()) {
|
||||
|
|
@ -343,12 +342,12 @@ InstPropertiesPage::update ()
|
|||
return;
|
||||
}
|
||||
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
tl_assert (pos->is_cell_inst ());
|
||||
|
||||
std::set<const lay::ObjectInstPath *> highlights;
|
||||
for (auto i = m_indexes.begin (); i != m_indexes.end (); ++i) {
|
||||
highlights.insert (m_selection_ptrs [*i].operator-> ());
|
||||
highlights.insert (m_selection_ptrs [*i]);
|
||||
}
|
||||
mp_service->highlight (highlights);
|
||||
|
||||
|
|
@ -472,7 +471,7 @@ InstPropertiesPage::show_cell ()
|
|||
return;
|
||||
}
|
||||
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
|
||||
lay::CellView::unspecific_cell_path_type path (mp_service->view ()->cellview (pos->cv_index ()).combined_unspecific_path ());
|
||||
for (lay::ObjectInstPath::iterator p = pos->begin (); p != pos->end (); ++p) {
|
||||
|
|
@ -509,7 +508,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
|
|||
|
||||
std::unique_ptr<CombinedChangeApplicator> appl (new CombinedChangeApplicator ());
|
||||
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
|
||||
bool du = dbu_cb->isChecked ();
|
||||
|
|
@ -786,16 +785,15 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
|
|||
void
|
||||
InstPropertiesPage::recompute_selection_ptrs (const std::vector<lay::ObjectInstPath> &new_sel)
|
||||
{
|
||||
std::map<lay::ObjectInstPath, edt::Service::obj_iterator> ptrs;
|
||||
std::map<lay::ObjectInstPath, EditableSelectionIterator::pointer> ptrs;
|
||||
|
||||
const edt::Service::objects &selection = mp_service->selection ();
|
||||
for (edt::Service::obj_iterator pos = selection.begin (); pos != selection.end (); ++pos) {
|
||||
ptrs.insert (std::make_pair (*pos, pos));
|
||||
for (EditableSelectionIterator pos = mp_service->begin_selection (); ! pos.at_end (); ++pos) {
|
||||
ptrs.insert (std::make_pair (*pos, pos.operator -> ()));
|
||||
}
|
||||
|
||||
m_selection_ptrs.clear ();
|
||||
for (std::vector<lay::ObjectInstPath>::const_iterator s = new_sel.begin (); s != new_sel.end (); ++s) {
|
||||
std::map<lay::ObjectInstPath, edt::Service::obj_iterator>::const_iterator pm = ptrs.find (*s);
|
||||
std::map<lay::ObjectInstPath, EditableSelectionIterator::pointer>::const_iterator pm = ptrs.find (*s);
|
||||
tl_assert (pm != ptrs.end ());
|
||||
m_selection_ptrs.push_back (pm->second);
|
||||
}
|
||||
|
|
@ -814,7 +812,7 @@ InstPropertiesPage::do_apply (bool current_only, bool relative)
|
|||
std::unique_ptr<ChangeApplicator> applicator;
|
||||
|
||||
{
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
tl_assert (pos->is_cell_inst ());
|
||||
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
|
|
@ -846,7 +844,7 @@ InstPropertiesPage::do_apply (bool current_only, bool relative)
|
|||
|
||||
std::vector<lay::ObjectInstPath> new_sel;
|
||||
new_sel.reserve (m_selection_ptrs.size ());
|
||||
for (std::vector<edt::Service::obj_iterator>::const_iterator p = m_selection_ptrs.begin (); p != m_selection_ptrs.end (); ++p) {
|
||||
for (std::vector<EditableSelectionIterator::pointer>::const_iterator p = m_selection_ptrs.begin (); p != m_selection_ptrs.end (); ++p) {
|
||||
new_sel.push_back (**p);
|
||||
}
|
||||
|
||||
|
|
@ -859,7 +857,7 @@ InstPropertiesPage::do_apply (bool current_only, bool relative)
|
|||
for (auto ii = m_indexes.begin (); ii != m_indexes.end (); ++ii) {
|
||||
|
||||
size_t index = *ii;
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [*ii];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [*ii];
|
||||
|
||||
// only update objects from the same layout - this is not practical limitation but saves a lot of effort for
|
||||
// managing different property id's etc.
|
||||
|
|
@ -958,7 +956,7 @@ InstPropertiesPage::update_pcell_parameters ()
|
|||
|
||||
} else {
|
||||
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
layout = &cv->layout ();
|
||||
|
||||
|
|
@ -982,7 +980,7 @@ InstPropertiesPage::update_pcell_parameters ()
|
|||
|
||||
std::vector<tl::Variant> parameters;
|
||||
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
db::Cell &cell = cv->layout ().cell (pos->cell_index ());
|
||||
std::pair<bool, db::pcell_id_type> pci = cell.is_pcell_instance (pos->back ().inst_ptr);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ private:
|
|||
void recompute_selection_ptrs (const std::vector<lay::ObjectInstPath> &new_sel);
|
||||
|
||||
protected:
|
||||
std::vector<edt::Service::obj_iterator> m_selection_ptrs;
|
||||
std::vector<EditableSelectionIterator::pointer> m_selection_ptrs;
|
||||
std::vector<size_t> m_indexes;
|
||||
edt::Service *mp_service;
|
||||
bool m_enable_cb_callback;
|
||||
|
|
|
|||
|
|
@ -310,8 +310,7 @@ MainService::cm_descend ()
|
|||
|
||||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end () && common_inst.valid (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::objects::const_iterator sel = selection.begin (); sel != selection.end () && common_inst.valid (); ++sel) {
|
||||
for (EditableSelectionIterator sel = (*es)->begin_selection (); ! sel.at_end () && common_inst.valid (); ++sel) {
|
||||
common_inst.add (*sel, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -335,12 +334,10 @@ MainService::cm_descend ()
|
|||
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
|
||||
new_selections.push_back (std::vector<lay::ObjectInstPath> ());
|
||||
new_selections.back ().reserve (selection.size ());
|
||||
new_selections.back ().reserve ((*es)->selection_size ());
|
||||
|
||||
for (edt::Service::objects::const_iterator sel = selection.begin (); sel != selection.end (); ++sel) {
|
||||
for (EditableSelectionIterator sel = (*es)->begin_selection (); ! sel.at_end (); ++sel) {
|
||||
|
||||
new_selections.back ().push_back (*sel);
|
||||
lay::ObjectInstPath &new_sel = new_selections.back ().back ();
|
||||
|
|
@ -378,7 +375,14 @@ MainService::cm_ascend ()
|
|||
new_selections.reserve (edt_services.size ());
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
new_selections.push_back (std::vector<lay::ObjectInstPath> ());
|
||||
new_selections.back ().insert (new_selections.back ().end (), (*es)->selection ().begin (), (*es)->selection ().end ());
|
||||
size_t n = 0;
|
||||
for (EditableSelectionIterator i = (*es)->begin_selection (); ! i.at_end (); ++i) {
|
||||
++n;
|
||||
}
|
||||
new_selections.back ().reserve (n);
|
||||
for (EditableSelectionIterator i = (*es)->begin_selection (); ! i.at_end (); ++i) {
|
||||
new_selections.back ().push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
// this will clear the selection:
|
||||
|
|
@ -439,8 +443,7 @@ MainService::cm_flatten_insts ()
|
|||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &sel = (*es)->selection ();
|
||||
for (edt::Service::objects::const_iterator r = sel.begin (); r != sel.end (); ++r) {
|
||||
for (EditableSelectionIterator r = (*es)->begin_selection (); ! r.at_end (); ++r) {
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (r->cv_index ());
|
||||
if (cv.is_valid ()) {
|
||||
|
|
@ -494,12 +497,10 @@ MainService::cm_move_hier_up ()
|
|||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
|
||||
std::vector<lay::ObjectInstPath> new_selection;
|
||||
new_selection.reserve (selection.size ());
|
||||
new_selection.reserve ((*es)->selection_size ());
|
||||
|
||||
for (edt::Service::objects::const_iterator r = selection.begin (); r != selection.end (); ++r) {
|
||||
for (EditableSelectionIterator r = (*es)->begin_selection (); ! r.at_end (); ++r) {
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (r->cv_index ());
|
||||
if (cv.is_valid ()) {
|
||||
|
|
@ -731,8 +732,7 @@ MainService::cm_make_cell_variants ()
|
|||
// TODO: this limitation is not really necessary, but makes the code somewhat simpler
|
||||
int cv_index = -1;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::objects::const_iterator r = selection.begin (); r != selection.end (); ++r) {
|
||||
for (EditableSelectionIterator r = (*es)->begin_selection (); ! r.at_end (); ++r) {
|
||||
if (cv_index < 0) {
|
||||
cv_index = r->cv_index ();
|
||||
} else if (cv_index != int (r->cv_index ())) {
|
||||
|
|
@ -755,8 +755,15 @@ MainService::cm_make_cell_variants ()
|
|||
}
|
||||
|
||||
std::vector<lay::ObjectInstPath> new_selection;
|
||||
size_t n = 0;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
new_selection.insert (new_selection.end (), (*es)->selection ().begin (), (*es)->selection ().end ());
|
||||
n += (*es)->selection_size ();
|
||||
}
|
||||
new_selection.reserve (n);
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
new_selection.push_back (*s);
|
||||
}
|
||||
}
|
||||
|
||||
size_t num_sel = new_selection.size ();
|
||||
|
|
@ -916,7 +923,7 @@ MainService::cm_make_cell_variants ()
|
|||
// Install the new selection
|
||||
size_t i0 = 0;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
size_t n = (*es)->selection ().size ();
|
||||
size_t n = (*es)->selection_size ();
|
||||
if (n + i0 <= new_selection.size ()) {
|
||||
(*es)->set_selection (new_selection.begin () + i0, new_selection.begin () + i0 + n);
|
||||
}
|
||||
|
|
@ -944,8 +951,7 @@ MainService::cm_resolve_arefs ()
|
|||
|
||||
int cv_index = -1;
|
||||
|
||||
const edt::Service::objects &selection = inst_service->selection ();
|
||||
for (edt::Service::objects::const_iterator r = selection.begin (); r != selection.end (); ++r) {
|
||||
for (EditableSelectionIterator r = inst_service->begin_selection (); ! r.at_end (); ++r) {
|
||||
if (r->is_cell_inst () && r->back ().inst_ptr.size () > 1) {
|
||||
if (cv_index < 0) {
|
||||
cv_index = r->cv_index ();
|
||||
|
|
@ -1026,8 +1032,7 @@ MainService::cm_make_cell ()
|
|||
int cv_index = -1;
|
||||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection () ;
|
||||
for (edt::Service::objects::const_iterator r = selection.begin (); r != selection.end (); ++r) {
|
||||
for (EditableSelectionIterator r = (*es)->begin_selection (); ! r.at_end (); ++r) {
|
||||
if (cv_index < 0) {
|
||||
cv_index = r->cv_index ();
|
||||
} else if (cv_index != int (r->cv_index ())) {
|
||||
|
|
@ -1051,8 +1056,7 @@ MainService::cm_make_cell ()
|
|||
db::Box selection_bbox;
|
||||
db::box_convert<db::CellInst> bc (cv->layout ());
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection () ;
|
||||
for (edt::Service::objects::const_iterator r = selection.begin (); r != selection.end (); ++r) {
|
||||
for (EditableSelectionIterator r = (*es)->begin_selection (); ! r.at_end (); ++r) {
|
||||
if (r->is_cell_inst ()) {
|
||||
selection_bbox += db::ICplxTrans (r->trans ()) * r->back ().bbox (bc);
|
||||
} else {
|
||||
|
|
@ -1086,8 +1090,7 @@ MainService::cm_make_cell ()
|
|||
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection () ;
|
||||
for (edt::Service::objects::const_iterator r = selection.begin (); r != selection.end (); ++r) {
|
||||
for (EditableSelectionIterator r = (*es)->begin_selection (); ! r.at_end (); ++r) {
|
||||
|
||||
if (r->is_cell_inst ()) {
|
||||
|
||||
|
|
@ -1148,8 +1151,7 @@ MainService::cm_convert_to_cell ()
|
|||
// Do the conversion
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection () ;
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (s->cv_index ());
|
||||
db::cell_index_type ci = s->cell_index_tot ();
|
||||
|
|
@ -1219,9 +1221,8 @@ MainService::cm_convert_to_pcell ()
|
|||
// check whether the selection contains instances and reject it in that case
|
||||
size_t num_selected = 0;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
num_selected += selection.size ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
num_selected += (*es)->selection_size ();
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
if (s->is_cell_inst ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Selection contains instances - they cannot be converted to PCells.")));
|
||||
}
|
||||
|
|
@ -1243,8 +1244,7 @@ MainService::cm_convert_to_pcell ()
|
|||
const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second);
|
||||
size_t n = 1000; // 1000 tries max.
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); n > 0 && pc_decl && s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); n > 0 && pc_decl && ! s.at_end (); ++s) {
|
||||
const lay::CellView &cv = view ()->cellview (s->cv_index ());
|
||||
if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) {
|
||||
--n;
|
||||
|
|
@ -1309,7 +1309,7 @@ MainService::cm_convert_to_pcell ()
|
|||
manager ()->transaction (tl::to_string (tr ("Convert to PCell")));
|
||||
}
|
||||
|
||||
std::vector<edt::Service::obj_iterator> to_delete;
|
||||
std::vector<EditableSelectionIterator::pointer> to_delete;
|
||||
std::vector<lay::ObjectInstPath> new_selection;
|
||||
|
||||
bool any_non_converted = false;
|
||||
|
|
@ -1321,8 +1321,7 @@ MainService::cm_convert_to_pcell ()
|
|||
// convert the shapes which can be converted
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (s->cv_index ());
|
||||
|
||||
|
|
@ -1346,7 +1345,7 @@ MainService::cm_convert_to_pcell ()
|
|||
new_selection.back ().add_path (db::InstElement (cell_inst));
|
||||
|
||||
// mark the shape for delete (later)
|
||||
to_delete.push_back (s);
|
||||
to_delete.push_back (s.operator-> ());
|
||||
|
||||
any_converted = true;
|
||||
|
||||
|
|
@ -1369,7 +1368,7 @@ MainService::cm_convert_to_pcell ()
|
|||
}
|
||||
|
||||
// Delete the shapes which have been converted
|
||||
for (std::vector<edt::Service::obj_iterator>::const_iterator td = to_delete.begin (); td != to_delete.end (); ++td) {
|
||||
for (std::vector<EditableSelectionIterator::pointer>::const_iterator td = to_delete.begin (); td != to_delete.end (); ++td) {
|
||||
db::Cell &cell = view ()->cellview ((*td)->cv_index ())->layout ().cell ((*td)->cell_index ());
|
||||
if (cell.shapes ((*td)->layer ()).is_valid ((*td)->shape ())) {
|
||||
cell.shapes ((*td)->layer ()).erase_shape ((*td)->shape ());
|
||||
|
|
@ -1421,8 +1420,7 @@ void MainService::cm_area_perimeter ()
|
|||
// get (common) cellview index of the primary selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
if (s->is_cell_inst ()) {
|
||||
continue;
|
||||
|
|
@ -1528,8 +1526,7 @@ MainService::cm_round_corners ()
|
|||
// get (common) cellview index of the primary selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
if (! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
|
||||
|
||||
|
|
@ -1603,8 +1600,7 @@ MainService::cm_round_corners ()
|
|||
|
||||
// Delete the current selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
if (! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
|
||||
db::Cell &cell = view ()->cellview (s->cv_index ())->layout ().cell (s->cell_index ());
|
||||
if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
|
||||
|
|
@ -1664,8 +1660,7 @@ MainService::cm_size ()
|
|||
|
||||
// get (common) cellview index of the primary selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
if (! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
|
||||
|
||||
|
|
@ -1735,8 +1730,7 @@ MainService::cm_size ()
|
|||
|
||||
// Delete the current selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
if (! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
|
||||
db::Cell &cell = view ()->cellview (s->cv_index ())->layout ().cell (s->cell_index ());
|
||||
if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
|
||||
|
|
@ -1792,8 +1786,7 @@ MainService::boolean_op (int mode)
|
|||
|
||||
// get (common) cellview index of the primary selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
if (s->seq () == 0 && ! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
|
||||
|
||||
|
|
@ -1827,8 +1820,7 @@ MainService::boolean_op (int mode)
|
|||
|
||||
// get the secondary selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
if (s->seq () > 0 && ! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
|
||||
|
||||
|
|
@ -1865,8 +1857,7 @@ MainService::boolean_op (int mode)
|
|||
// Let's see whether this heuristics is more accepted.
|
||||
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
if (! s->is_cell_inst () && int (s->layer ()) == layer_index && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) {
|
||||
db::Cell &cell = view ()->cellview (s->cv_index ())->layout ().cell (s->cell_index ());
|
||||
if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
|
||||
|
|
@ -2001,8 +1992,7 @@ MainService::cm_align ()
|
|||
|
||||
// get (common) bbox index of the primary selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
if (s->seq () == 0) {
|
||||
|
||||
|
|
@ -2032,13 +2022,11 @@ MainService::cm_align ()
|
|||
// do the alignment
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
|
||||
// create a transformation vector that describes each shape's transformation
|
||||
std::vector <db::DCplxTrans> tv;
|
||||
tv.reserve (selection.size ());
|
||||
tv.reserve ((*es)->selection_size ());
|
||||
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
db::DVector v;
|
||||
|
||||
|
|
@ -2105,8 +2093,7 @@ MainService::cm_distribute ()
|
|||
// count the items
|
||||
size_t n = 0;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
|
@ -2128,8 +2115,7 @@ MainService::cm_distribute ()
|
|||
|
||||
objects_for_service.push_back (std::make_pair (i, i));
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
const db::Layout &layout = view ()->cellview (s->cv_index ())->layout ();
|
||||
db::CplxTrans tr = db::CplxTrans (layout.dbu ()) * s->trans ();
|
||||
|
|
@ -2211,8 +2197,7 @@ MainService::cm_make_array ()
|
|||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
|
@ -2246,8 +2231,7 @@ MainService::cm_make_array ()
|
|||
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (s->cv_index ());
|
||||
if (! cv.is_valid ()) {
|
||||
|
|
@ -2544,8 +2528,7 @@ MainService::check_no_guiding_shapes ()
|
|||
{
|
||||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
const edt::Service::objects &selection = (*es)->selection ();
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
for (EditableSelectionIterator s = (*es)->begin_selection (); ! s.at_end (); ++s) {
|
||||
if (! s->is_cell_inst ()) {
|
||||
if (s->layer () == view ()->cellview (s->cv_index ())->layout ().guiding_shape_layer ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("This function cannot be applied to PCell guiding shapes")));
|
||||
|
|
|
|||
|
|
@ -1182,6 +1182,19 @@ PartialService::timeout ()
|
|||
mp_view->clear_transient_selection ();
|
||||
clear_mouse_cursors ();
|
||||
|
||||
double le = catch_distance () * 3.0; // see Editables::selection_catch_bbox()
|
||||
db::DBox sel_catch_box = selection_bbox ().enlarged (db::DVector (le, le));
|
||||
if (has_selection () && sel_catch_box.contains (m_hover_point)) {
|
||||
|
||||
// no transient selection if inside current selection - if we click there, we catch the
|
||||
// currently selected objects
|
||||
resize_markers (0, true);
|
||||
resize_inst_markers (0, true);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// compute search box
|
||||
double l = catch_distance ();
|
||||
db::DBox search_box = db::DBox (m_hover_point, m_hover_point).enlarged (db::DVector (l, l));
|
||||
|
|
@ -2035,45 +2048,13 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
|
|||
// select is allowed to throw an exception
|
||||
try {
|
||||
|
||||
// compute search box
|
||||
double l = catch_distance ();
|
||||
db::DBox search_box = db::DBox (p, p).enlarged (db::DVector (l, l));
|
||||
|
||||
// check, if there is a selected shape under the mouse - in this case, we do not do a new selection
|
||||
PartialShapeFinder finder (true /*point mode*/, m_top_level_sel, db::ShapeIterator::All);
|
||||
finder.find (view (), search_box);
|
||||
|
||||
// check, if there is a selected shape under the mouse - in this case, we do not do a new selection
|
||||
lay::InstFinder inst_finder (true /*point mode*/, m_top_level_sel, true /*full arrays*/, true /*enclose*/, 0 /*no excludes*/, true /*visible layers*/);
|
||||
inst_finder.find (view (), search_box);
|
||||
|
||||
// collect the founds from the finder
|
||||
// consider a new selection if new objects are selected or the current selection is shape-only
|
||||
// (this may happen if points have been inserted)
|
||||
bool new_selection = ((finder.begin () == finder.end () && inst_finder.begin () == inst_finder.end ())
|
||||
|| mode != lay::Editable::Replace);
|
||||
|
||||
for (PartialShapeFinder::iterator f = finder.begin (); f != finder.end () && ! new_selection; ++f) {
|
||||
partial_objects::const_iterator sel = m_selection.find (f->first);
|
||||
new_selection = true;
|
||||
if (sel != m_selection.end ()) {
|
||||
for (std::vector<edt::EdgeWithIndex>::const_iterator e = f->second.begin (); e != f->second.end () && new_selection; ++e) {
|
||||
if (sel->second.find (*e) != sel->second.end ()) {
|
||||
new_selection = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (finder.begin () == finder.end ()) {
|
||||
|
||||
for (lay::InstFinder::iterator f = inst_finder.begin (); f != inst_finder.end () && ! new_selection; ++f) {
|
||||
partial_objects::const_iterator sel = m_selection.find (*f);
|
||||
if (sel == m_selection.end ()) {
|
||||
new_selection = true;
|
||||
}
|
||||
}
|
||||
bool new_selection = true;
|
||||
|
||||
double le = catch_distance () * 3.0; // see Editables::selection_catch_bbox()
|
||||
db::DBox sel_catch_box = selection_bbox ().enlarged (db::DVector (le, le));
|
||||
if (mode == lay::Editable::Replace && has_selection () && sel_catch_box.contains (p)) {
|
||||
// drag current selection
|
||||
new_selection = false;
|
||||
}
|
||||
|
||||
if (new_selection) {
|
||||
|
|
@ -2082,6 +2063,18 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
|
|||
m_selection.clear ();
|
||||
}
|
||||
|
||||
// compute search box
|
||||
double l = catch_distance ();
|
||||
db::DBox search_box = db::DBox (p, p).enlarged (db::DVector (l, l));
|
||||
|
||||
// identify the edges under the mouse
|
||||
PartialShapeFinder finder (true /*point mode*/, m_top_level_sel, db::ShapeIterator::All);
|
||||
finder.find (view (), search_box);
|
||||
|
||||
// identify the instances under the mouse
|
||||
lay::InstFinder inst_finder (true /*point mode*/, m_top_level_sel, true /*full arrays*/, true /*enclose*/, 0 /*no excludes*/, true /*visible layers*/);
|
||||
inst_finder.find (view (), search_box);
|
||||
|
||||
// clear the selection if we now select a guiding shape or if it was consisting of a guiding shape before
|
||||
// (that way we ensure there is only a guiding shape selected)
|
||||
PartialShapeFinder::iterator f0 = finder.begin ();
|
||||
|
|
|
|||
|
|
@ -47,10 +47,9 @@ ShapePropertiesPage::ShapePropertiesPage (const std::string &description, edt::S
|
|||
: lay::PropertiesPage (parent, manager, service),
|
||||
m_description (description), mp_service (service), m_enable_cb_callback (true)
|
||||
{
|
||||
const edt::Service::objects &selection = service->selection ();
|
||||
m_selection_ptrs.reserve (selection.size ());
|
||||
for (edt::Service::obj_iterator s = selection.begin (); s != selection.end (); ++s) {
|
||||
m_selection_ptrs.push_back (s);
|
||||
m_selection_ptrs.reserve (service->selection_size ());
|
||||
for (edt::EditableSelectionIterator s = service->begin_selection (); ! s.at_end (); ++s) {
|
||||
m_selection_ptrs.push_back (s.operator-> ());
|
||||
}
|
||||
m_prop_id = 0;
|
||||
mp_service->clear_highlights ();
|
||||
|
|
@ -191,7 +190,7 @@ ShapePropertiesPage::update ()
|
|||
{
|
||||
std::set<const lay::ObjectInstPath *> highlights;
|
||||
for (auto i = m_indexes.begin (); i != m_indexes.end (); ++i) {
|
||||
highlights.insert (m_selection_ptrs [*i].operator-> ());
|
||||
highlights.insert (m_selection_ptrs [*i]);
|
||||
}
|
||||
mp_service->highlight (highlights);
|
||||
|
||||
|
|
@ -201,16 +200,15 @@ ShapePropertiesPage::update ()
|
|||
void
|
||||
ShapePropertiesPage::recompute_selection_ptrs (const std::vector<lay::ObjectInstPath> &new_sel)
|
||||
{
|
||||
std::map<lay::ObjectInstPath, edt::Service::obj_iterator> ptrs;
|
||||
std::map<lay::ObjectInstPath, EditableSelectionIterator::pointer> ptrs;
|
||||
|
||||
const edt::Service::objects &selection = mp_service->selection ();
|
||||
for (edt::Service::obj_iterator pos = selection.begin (); pos != selection.end (); ++pos) {
|
||||
ptrs.insert (std::make_pair (*pos, pos));
|
||||
for (EditableSelectionIterator pos = mp_service->begin_selection (); ! pos.at_end (); ++pos) {
|
||||
ptrs.insert (std::make_pair (*pos, pos.operator-> ()));
|
||||
}
|
||||
|
||||
m_selection_ptrs.clear ();
|
||||
for (std::vector<lay::ObjectInstPath>::const_iterator s = new_sel.begin (); s != new_sel.end (); ++s) {
|
||||
std::map<lay::ObjectInstPath, edt::Service::obj_iterator>::const_iterator pm = ptrs.find (*s);
|
||||
std::map<lay::ObjectInstPath, EditableSelectionIterator::pointer>::const_iterator pm = ptrs.find (*s);
|
||||
tl_assert (pm != ptrs.end ());
|
||||
m_selection_ptrs.push_back (pm->second);
|
||||
}
|
||||
|
|
@ -228,7 +226,7 @@ ShapePropertiesPage::do_apply (bool current_only, bool relative)
|
|||
unsigned int cv_index = m_selection_ptrs [m_indexes.front ()]->cv_index ();
|
||||
|
||||
{
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
tl_assert (! pos->is_cell_inst ());
|
||||
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
|
|
@ -261,7 +259,7 @@ ShapePropertiesPage::do_apply (bool current_only, bool relative)
|
|||
|
||||
std::vector<lay::ObjectInstPath> new_sel;
|
||||
new_sel.reserve (m_selection_ptrs.size ());
|
||||
for (std::vector<edt::Service::obj_iterator>::const_iterator p = m_selection_ptrs.begin (); p != m_selection_ptrs.end (); ++p) {
|
||||
for (std::vector<EditableSelectionIterator::pointer>::const_iterator p = m_selection_ptrs.begin (); p != m_selection_ptrs.end (); ++p) {
|
||||
new_sel.push_back (**p);
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +272,7 @@ ShapePropertiesPage::do_apply (bool current_only, bool relative)
|
|||
for (auto i = m_indexes.begin (); i != m_indexes.end (); ++i) {
|
||||
|
||||
size_t index = *i;
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [*i];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [*i];
|
||||
|
||||
// only update objects from the same layout - this is not practical limitation but saves a lot of effort for
|
||||
// managing different property id's etc.
|
||||
|
|
@ -376,7 +374,7 @@ ShapePropertiesPage::update_shape ()
|
|||
return;
|
||||
}
|
||||
|
||||
edt::Service::obj_iterator pos = m_selection_ptrs [m_indexes.front ()];
|
||||
EditableSelectionIterator::pointer pos = m_selection_ptrs [m_indexes.front ()];
|
||||
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
double dbu = cv->layout ().dbu ();
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ private:
|
|||
|
||||
protected:
|
||||
std::string m_description;
|
||||
std::vector<edt::Service::obj_iterator> m_selection_ptrs;
|
||||
std::vector<EditableSelectionIterator::pointer> m_selection_ptrs;
|
||||
std::vector<size_t> m_indexes;
|
||||
edt::Service *mp_service;
|
||||
bool m_enable_cb_callback;
|
||||
|
|
|
|||
|
|
@ -459,11 +459,10 @@ Service::copy_selected ()
|
|||
unsigned int inst_mode = 0;
|
||||
|
||||
if (m_hier_copy_mode < 0) {
|
||||
const objects &sel = selection ();
|
||||
for (objects::const_iterator r = sel.begin (); r != sel.end () && ! need_to_ask_for_copy_mode; ++r) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end () && ! need_to_ask_for_copy_mode; ++r) {
|
||||
if (r->is_cell_inst ()) {
|
||||
const db::Cell &cell = view ()->cellview (r->cv_index ())->layout ().cell (r->back ().inst_ptr.cell_index ());
|
||||
if (! cell.is_proxy ()) {
|
||||
if (! cell.is_proxy () && ! cell.is_leaf ()) {
|
||||
need_to_ask_for_copy_mode = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -500,12 +499,10 @@ Service::copy_selected ()
|
|||
void
|
||||
Service::copy_selected (unsigned int inst_mode)
|
||||
{
|
||||
const objects &sel = selection ();
|
||||
|
||||
// create one ClipboardData object per cv_index because, this one assumes that there is
|
||||
// only one source layout object.
|
||||
std::set <unsigned int> cv_indices;
|
||||
for (objects::const_iterator r = sel.begin (); r != sel.end (); ++r) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r) {
|
||||
cv_indices.insert (r->cv_index ());
|
||||
}
|
||||
|
||||
|
|
@ -515,7 +512,7 @@ Service::copy_selected (unsigned int inst_mode)
|
|||
|
||||
// add the selected objects to the clipboard data objects.
|
||||
const lay::CellView &cv = view ()->cellview (*cvi);
|
||||
for (objects::const_iterator r = sel.begin (); r != sel.end (); ++r) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r) {
|
||||
if (r->cv_index () == *cvi) {
|
||||
if (! r->is_cell_inst ()) {
|
||||
cd->get ().add (cv->layout (), r->layer (), r->shape (), cv.context_trans () * r->trans ());
|
||||
|
|
@ -618,8 +615,7 @@ Service::selection_bbox ()
|
|||
|
||||
db::DBox box;
|
||||
|
||||
const objects &sel = selection ();
|
||||
for (objects::const_iterator r = sel.begin (); r != sel.end (); ++r) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r) {
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (r->cv_index ());
|
||||
const db::Layout &layout = cv->layout ();
|
||||
|
|
@ -699,13 +695,10 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
|
||||
size_t n;
|
||||
|
||||
const objects &sel = selection ();
|
||||
|
||||
// build a list of object references corresponding to the p_trv vector
|
||||
std::vector <objects::iterator> obj_ptrs;
|
||||
obj_ptrs.reserve (sel.size ());
|
||||
for (objects::iterator r = sel.begin (); r != sel.end (); ++r) {
|
||||
obj_ptrs.push_back (r);
|
||||
std::vector <EditableSelectionIterator::pointer> obj_ptrs;
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r) {
|
||||
obj_ptrs.push_back (r.operator-> ());
|
||||
}
|
||||
|
||||
// build the transformation variants cache
|
||||
|
|
@ -717,7 +710,7 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
// The key is a triple: cell_index, cv_index, layer
|
||||
std::map <std::pair <db::cell_index_type, std::pair <unsigned int, unsigned int> >, std::vector <size_t> > shapes_by_cell;
|
||||
n = 0;
|
||||
for (objects::iterator r = sel.begin (); r != sel.end (); ++r, ++n) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r, ++n) {
|
||||
if (! r->is_cell_inst ()) {
|
||||
shapes_by_cell.insert (std::make_pair (std::make_pair (r->cell_index (), std::make_pair (r->cv_index (), r->layer ())), std::vector <size_t> ())).first->second.push_back (n);
|
||||
}
|
||||
|
|
@ -740,7 +733,7 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
|
||||
for (std::vector <size_t>::iterator si = sbc->second.begin (); si != sbc->second.end (); ++si) {
|
||||
|
||||
objects::iterator s = obj_ptrs [*si];
|
||||
EditableSelectionIterator::pointer s = obj_ptrs [*si];
|
||||
|
||||
// mt = transformation in DBU units
|
||||
db::ICplxTrans mt;
|
||||
|
|
@ -764,14 +757,14 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
|
||||
for (std::vector <size_t>::iterator si = sbc->second.begin (); si != sbc->second.end (); ++si) {
|
||||
|
||||
objects::iterator &s = obj_ptrs [*si];
|
||||
EditableSelectionIterator::pointer &s = obj_ptrs [*si];
|
||||
|
||||
lay::ObjectInstPath new_path (*s);
|
||||
new_path.set_shape (new_shapes.find (s->shape ())->second);
|
||||
|
||||
// modify the selection
|
||||
m_selection.erase (s);
|
||||
s = m_selection.insert (new_path).first;
|
||||
m_selection.erase (*s);
|
||||
s = m_selection.insert (new_path).first.operator-> ();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -787,7 +780,7 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
// The key is a pair: cell_index, cv_index
|
||||
std::map <std::pair <db::cell_index_type, unsigned int>, std::vector <size_t> > insts_by_cell;
|
||||
n = 0;
|
||||
for (objects::iterator r = sel.begin (); r != sel.end (); ++r, ++n) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r, ++n) {
|
||||
if (r->is_cell_inst ()) {
|
||||
insts_by_cell.insert (std::make_pair (std::make_pair (r->cell_index (), r->cv_index ()), std::vector <size_t> ())).first->second.push_back (n);
|
||||
}
|
||||
|
|
@ -810,7 +803,7 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
|
||||
for (std::vector <size_t>::iterator ii = ibc->second.begin (); ii != ibc->second.end (); ++ii) {
|
||||
|
||||
objects::iterator i = obj_ptrs [*ii];
|
||||
EditableSelectionIterator::pointer i = obj_ptrs [*ii];
|
||||
|
||||
// mt = transformation in DBU units
|
||||
db::ICplxTrans mt;
|
||||
|
|
@ -836,14 +829,14 @@ Service::transform (const db::DCplxTrans &trans, const std::vector<db::DCplxTran
|
|||
|
||||
for (std::vector <size_t>::iterator ii = ibc->second.begin (); ii != ibc->second.end (); ++ii) {
|
||||
|
||||
objects::iterator &i = obj_ptrs [*ii];
|
||||
EditableSelectionIterator::pointer &i = obj_ptrs [*ii];
|
||||
|
||||
lay::ObjectInstPath new_path (*i);
|
||||
new_path.back ().inst_ptr = new_insts.find (i->back ().inst_ptr)->second;
|
||||
|
||||
// modify the selection
|
||||
m_selection.erase (i);
|
||||
i = m_selection.insert (new_path).first;
|
||||
m_selection.erase (*i);
|
||||
i = m_selection.insert (new_path).first.operator-> ();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1039,8 +1032,7 @@ Service::del_selected ()
|
|||
std::set<db::Layout *> needs_cleanup;
|
||||
|
||||
// delete all shapes and instances.
|
||||
const objects &sel = selection ();
|
||||
for (objects::const_iterator r = sel.begin (); r != sel.end (); ++r) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r) {
|
||||
const lay::CellView &cv = view ()->cellview (r->cv_index ());
|
||||
if (cv.is_valid ()) {
|
||||
db::Cell &cell = cv->layout ().cell (r->cell_index ());
|
||||
|
|
@ -1326,11 +1318,12 @@ static std::string path_to_string (const db::Layout &layout, const lay::ObjectIn
|
|||
void
|
||||
Service::display_status (bool transient)
|
||||
{
|
||||
const objects *sel = transient ? &transient_selection () : &selection ();
|
||||
EditableSelectionIterator r = transient ? begin_transient_selection () : begin_selection ();
|
||||
EditableSelectionIterator rr = r;
|
||||
++rr;
|
||||
|
||||
if (sel->size () == 1) {
|
||||
if (rr.at_end ()) {
|
||||
|
||||
objects::const_iterator r = sel->begin ();
|
||||
const db::Layout &layout = view ()->cellview (r->cv_index ())->layout ();
|
||||
|
||||
if (m_cell_inst_service) {
|
||||
|
|
@ -1606,6 +1599,18 @@ Service::transient_selection () const
|
|||
return m_transient_selection;
|
||||
}
|
||||
|
||||
EditableSelectionIterator
|
||||
Service::begin_selection () const
|
||||
{
|
||||
return EditableSelectionIterator (this, false);
|
||||
}
|
||||
|
||||
EditableSelectionIterator
|
||||
Service::begin_transient_selection () const
|
||||
{
|
||||
return EditableSelectionIterator (this, true);
|
||||
}
|
||||
|
||||
bool
|
||||
Service::select (const lay::ObjectInstPath &obj, lay::Editable::SelectionMode mode)
|
||||
{
|
||||
|
|
@ -1730,17 +1735,15 @@ Service::selection_to_view ()
|
|||
void
|
||||
Service::do_selection_to_view ()
|
||||
{
|
||||
const objects &sel = selection ();
|
||||
|
||||
// Hint: this is a lower bound:
|
||||
m_markers.reserve (sel.size ());
|
||||
m_markers.reserve (selection_size ());
|
||||
|
||||
// build the transformation variants cache
|
||||
TransformationVariants tv (view ());
|
||||
|
||||
// Build markers
|
||||
|
||||
for (objects::const_iterator r = sel.begin (); r != sel.end (); ++r) {
|
||||
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r) {
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (r->cv_index ());
|
||||
|
||||
|
|
@ -1939,12 +1942,14 @@ Service::handle_guiding_shape_changes (const lay::ObjectInstPath &obj) const
|
|||
bool
|
||||
Service::handle_guiding_shape_changes ()
|
||||
{
|
||||
EditableSelectionIterator s = begin_selection ();
|
||||
|
||||
// just allow one guiding shape to be selected
|
||||
if (selection ().empty ()) {
|
||||
if (s.at_end ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<bool, lay::ObjectInstPath> gs = handle_guiding_shape_changes (*selection ().begin ());
|
||||
std::pair<bool, lay::ObjectInstPath> gs = handle_guiding_shape_changes (*s);
|
||||
if (gs.first) {
|
||||
|
||||
// remove superfluous proxies
|
||||
|
|
@ -1966,7 +1971,20 @@ 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)
|
||||
: m_services (services.begin (), services.end ()), m_service (0), m_transient_selection (transient)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
EditableSelectionIterator::EditableSelectionIterator (const edt::Service *service, bool transient)
|
||||
: m_services (), m_service (0), m_transient_selection (transient)
|
||||
{
|
||||
m_services.push_back (service);
|
||||
init ();
|
||||
}
|
||||
|
||||
void
|
||||
EditableSelectionIterator::init ()
|
||||
{
|
||||
if (! m_services.empty ()) {
|
||||
if (m_transient_selection) {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,41 @@ std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::stri
|
|||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief A utility class to implement a selection iterator across all editor services
|
||||
*/
|
||||
class EDT_PUBLIC EditableSelectionIterator
|
||||
{
|
||||
public:
|
||||
typedef std::set<lay::ObjectInstPath> objects;
|
||||
typedef objects::value_type value_type;
|
||||
typedef objects::const_iterator iterator_type;
|
||||
typedef const value_type *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);
|
||||
EditableSelectionIterator (const edt::Service *service, bool transient);
|
||||
|
||||
bool at_end () const;
|
||||
|
||||
EditableSelectionIterator &operator++ ();
|
||||
reference operator* () const;
|
||||
pointer operator-> () const;
|
||||
|
||||
private:
|
||||
std::vector<const edt::Service *> m_services;
|
||||
unsigned int m_service;
|
||||
bool m_transient_selection;
|
||||
iterator_type m_iter, m_end;
|
||||
|
||||
void next ();
|
||||
void init ();
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
class EDT_PUBLIC Service
|
||||
: public lay::EditorServiceBase,
|
||||
public db::Object
|
||||
|
|
@ -226,16 +261,6 @@ public:
|
|||
return m_color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the selection container
|
||||
*/
|
||||
const objects &selection () const;
|
||||
|
||||
/**
|
||||
* @brief Get the transient selection container
|
||||
*/
|
||||
const objects &transient_selection () const;
|
||||
|
||||
/**
|
||||
* @brief Access to the view object
|
||||
*/
|
||||
|
|
@ -257,11 +282,21 @@ public:
|
|||
*/
|
||||
void clear_previous_selection ();
|
||||
|
||||
/**
|
||||
* @brief Gets the selection iterator
|
||||
*/
|
||||
EditableSelectionIterator begin_selection () const;
|
||||
|
||||
/**
|
||||
* @brief Establish a transient selection
|
||||
*/
|
||||
bool transient_select (const db::DPoint &pos);
|
||||
|
||||
/**
|
||||
* @brief Gets the transient selection iterator
|
||||
*/
|
||||
EditableSelectionIterator begin_transient_selection () const;
|
||||
|
||||
/**
|
||||
* @brief Turns the transient selection to the selection
|
||||
*/
|
||||
|
|
@ -585,6 +620,8 @@ protected:
|
|||
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p) const;
|
||||
|
||||
private:
|
||||
friend class EditableSelectionIterator;
|
||||
|
||||
// The layout view that the editor service is attached to
|
||||
lay::LayoutViewBase *mp_view;
|
||||
|
||||
|
|
@ -685,6 +722,16 @@ private:
|
|||
*/
|
||||
void apply_highlights ();
|
||||
|
||||
/**
|
||||
* @brief Get the selection container
|
||||
*/
|
||||
const objects &selection () const;
|
||||
|
||||
/**
|
||||
* @brief Get the transient selection container
|
||||
*/
|
||||
const objects &transient_selection () const;
|
||||
|
||||
private:
|
||||
void copy_selected (unsigned int inst_mode);
|
||||
void update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const;
|
||||
|
|
@ -692,36 +739,6 @@ 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 const value_type *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++ ();
|
||||
reference operator* () const;
|
||||
pointer 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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -94,16 +94,23 @@ namespace lay
|
|||
// --------------------------------------------------------------------------------
|
||||
// Exception handlers
|
||||
|
||||
static void close_transaction ()
|
||||
{
|
||||
// if any transaction is pending (this may happen when an operation threw an exception)
|
||||
// close transactions.
|
||||
// NOTE: don't do this in breakpoint mode as we do not want to interfere with things happening outside
|
||||
if (lay::MainWindow::instance () && lay::MainWindow::instance ()->manager ().transacting () &&
|
||||
!(lay::MacroEditorDialog::instance () && lay::MacroEditorDialog::instance ()->in_breakpoint ())) {
|
||||
lay::MainWindow::instance ()->manager ().commit ();
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_exception_handler_tl (const tl::Exception &ex, QWidget *parent)
|
||||
{
|
||||
// Prevents severe side effects if there are pending deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
// if any transaction is pending (this may happen when an operation threw an exception)
|
||||
// close transactions.
|
||||
if (lay::MainWindow::instance () && lay::MainWindow::instance ()->manager ().transacting ()) {
|
||||
lay::MainWindow::instance ()->manager ().commit ();
|
||||
}
|
||||
close_transaction ();
|
||||
|
||||
const tl::ExitException *gsi_exit = dynamic_cast <const tl::ExitException *> (&ex);
|
||||
const tl::BreakException *gsi_break = dynamic_cast <const tl::BreakException *> (&ex);
|
||||
|
|
@ -155,13 +162,9 @@ static void ui_exception_handler_std (const std::exception &ex, QWidget *parent)
|
|||
// Prevents severe side effects if there are pending deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
// if any transaction is pending (this may happen when an operation threw an exception)
|
||||
// close transactions.
|
||||
if (lay::MainWindow::instance () && lay::MainWindow::instance ()->manager ().transacting ()) {
|
||||
lay::MainWindow::instance ()->manager ().commit ();
|
||||
}
|
||||
close_transaction ();
|
||||
|
||||
tl::error << ex.what ();
|
||||
tl::error << ex.what ();
|
||||
if (! parent) {
|
||||
parent = QApplication::activeWindow () ? QApplication::activeWindow () : lay::MainWindow::instance ();
|
||||
}
|
||||
|
|
@ -173,11 +176,7 @@ static void ui_exception_handler_def (QWidget *parent)
|
|||
// Prevents severe side effects if there are pending deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
// if any transaction is pending (this may happen when an operation threw an exception)
|
||||
// close transactions.
|
||||
if (lay::MainWindow::instance () && lay::MainWindow::instance ()->manager ().transacting ()) {
|
||||
lay::MainWindow::instance ()->manager ().commit ();
|
||||
}
|
||||
close_transaction ();
|
||||
|
||||
if (! parent) {
|
||||
parent = QApplication::activeWindow () ? QApplication::activeWindow () : lay::MainWindow::instance ();
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ FillDialog::get_fill_parameters ()
|
|||
// selection
|
||||
std::vector<edt::Service *> edt_services = mp_view->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
|
||||
for (edt::Service::objects::const_iterator sel = (*s)->selection ().begin (); sel != (*s)->selection ().end (); ++sel) {
|
||||
for (edt::EditableSelectionIterator sel = (*s)->begin_selection (); ! sel.at_end (); ++sel) {
|
||||
if (! sel->is_cell_inst () && (sel->shape ().is_polygon () || sel->shape ().is_path () || sel->shape ().is_box ())) {
|
||||
db::Polygon poly;
|
||||
sel->shape ().polygon (poly);
|
||||
|
|
|
|||
|
|
@ -1511,26 +1511,25 @@ MacroEditorDialog::eventFilter (QObject *obj, QEvent *event)
|
|||
|
||||
if (lay::BusySection::is_busy ()) {
|
||||
|
||||
#if 0
|
||||
if (dynamic_cast <QInputEvent *> (event) != 0 || dynamic_cast <QPaintEvent *> (event) != 0) {
|
||||
if (m_in_breakpoint && (dynamic_cast <QInputEvent *> (event) != 0 || dynamic_cast <QPaintEvent *> (event) != 0)) {
|
||||
|
||||
// In breakpoint or execution mode and while processing the events inside the debugger,
|
||||
// In breakpoint mode and while processing the events inside the debugger,
|
||||
// ignore all input or paint events targeted to widgets which are not children of this or the assistant dialog.
|
||||
// Ignoring the paint event is required because otherwise a repaint action would be triggered on a layout which
|
||||
// is potentially unstable or inconsistent.
|
||||
// We nevertheless allow events send to a HelpDialog or ProgressWidget since those are vital for the application's
|
||||
// functionality and are known not to cause any interference.
|
||||
QObject *rec = obj;
|
||||
while (rec && (rec != this && !dynamic_cast<lay::HelpDialog *> (rec) && !dynamic_cast<lay::ProgressWidget *> (rec))) {
|
||||
while (rec && rec != this) {
|
||||
rec = rec->parent ();
|
||||
}
|
||||
if (! rec) {
|
||||
// TODO: reschedule the paint events (?)
|
||||
event->accept ();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -2267,19 +2266,35 @@ END_PROTECTED
|
|||
}
|
||||
|
||||
void
|
||||
MacroEditorDialog::help_requested(const QString &s)
|
||||
MacroEditorDialog::help_requested (const QString &s)
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
// Do not allow modal popups in breakpoint mode - this would interfere with
|
||||
// event filtering during breakpoint execution
|
||||
if (m_in_breakpoint) {
|
||||
throw tl::Exception (tl::to_string (tr ("The help function is not available in breakpoint mode.")));
|
||||
}
|
||||
|
||||
lay::MainWindow::instance ()->show_assistant_topic (tl::to_string (s));
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MacroEditorDialog::help_button_clicked()
|
||||
MacroEditorDialog::help_button_clicked ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
// Do not allow modal popups in breakpoint mode - this would interfere with
|
||||
// event filtering during breakpoint execution
|
||||
if (m_in_breakpoint) {
|
||||
throw tl::Exception (tl::to_string (tr ("The help function is not available in breakpoint mode.")));
|
||||
}
|
||||
|
||||
lay::MainWindow::instance ()->show_assistant_url ("int:/code/index.xml");
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MacroEditorDialog::add_button_clicked()
|
||||
MacroEditorDialog::add_button_clicked ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
new_macro ();
|
||||
|
|
@ -2287,7 +2302,7 @@ END_PROTECTED
|
|||
}
|
||||
|
||||
lym::Macro *
|
||||
MacroEditorDialog::new_macro()
|
||||
MacroEditorDialog::new_macro ()
|
||||
{
|
||||
ensure_writeable_collection_selected ();
|
||||
|
||||
|
|
@ -3451,6 +3466,12 @@ MacroEditorDialog::leave_breakpoint_mode ()
|
|||
mp_current_interpreter = 0;
|
||||
do_update_ui_to_run_mode ();
|
||||
set_exec_point (0, -1, -1);
|
||||
|
||||
// refresh UI that might have been spoiled because we filter events
|
||||
auto tl_widgets = QApplication::topLevelWidgets ();
|
||||
for (auto w = tl_widgets.begin (); w != tl_widgets.end (); ++w) {
|
||||
(*w)->update ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -166,6 +166,14 @@ public:
|
|||
return m_in_exec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true while the macro IDE is in breakpoint mode
|
||||
*/
|
||||
bool in_breakpoint () const
|
||||
{
|
||||
return m_in_breakpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects the current category in the tree view
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ public:
|
|||
options.push_back (std::pair<std::string, std::string> (cfg_line_style_palette, lay::LineStylePalette ().to_string ()));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_no_stipple, "false"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_markers_visible, "true"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_copy_cell_mode, "-1"));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ static const std::string cfg_default_font_size ("default-font-size");
|
|||
static const std::string cfg_hide_empty_layers ("hide-empty-layers");
|
||||
static const std::string cfg_test_shapes_in_view ("test-shapes-in-view");
|
||||
|
||||
static const std::string cfg_copy_cell_mode ("copy-cell-mode");
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -1,46 +1,41 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CopyCellModeDialog</class>
|
||||
<widget class="QDialog" name="CopyCellModeDialog" >
|
||||
<property name="geometry" >
|
||||
<widget class="QDialog" name="CopyCellModeDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>178</height>
|
||||
<width>546</width>
|
||||
<height>198</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Copy Cell Options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox" >
|
||||
<property name="title" >
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Copy Cell Mode</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="shallow_rb" >
|
||||
<property name="text" >
|
||||
<widget class="QRadioButton" name="shallow_rb">
|
||||
<property name="text">
|
||||
<string>Shallow copy (don't copy subcells)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="deep_rb" >
|
||||
<property name="text" >
|
||||
<widget class="QRadioButton" name="deep_rb">
|
||||
<property name="text">
|
||||
<string>Deep copy (include subcells)</string>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -48,12 +43,19 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dont_ask_cbx">
|
||||
<property name="text">
|
||||
<string>Don't ask again (you can always reset this in Setup: Application/Cells page)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>31</height>
|
||||
|
|
@ -62,12 +64,12 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -86,11 +88,11 @@
|
|||
<receiver>CopyCellModeDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
|
|
@ -102,11 +104,11 @@
|
|||
<receiver>CopyCellModeDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LayoutViewConfigPage8</class>
|
||||
<widget class="QWidget" name="LayoutViewConfigPage8">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>414</width>
|
||||
<height>46</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Cell copy mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="hier_copy_mode_cbx">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Shallow mode (cell only)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Deep mode (cell and subcells)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Ask</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -579,7 +579,7 @@ CopyCellModeDialog::~CopyCellModeDialog ()
|
|||
}
|
||||
|
||||
bool
|
||||
CopyCellModeDialog::exec_dialog (int ©_mode)
|
||||
CopyCellModeDialog::exec_dialog (int ©_mode, bool &dont_ask)
|
||||
{
|
||||
QRadioButton *buttons [] = { mp_ui->shallow_rb, mp_ui->deep_rb };
|
||||
|
||||
|
|
@ -592,6 +592,7 @@ CopyCellModeDialog::exec_dialog (int ©_mode)
|
|||
if (buttons [i]->isChecked ()) {
|
||||
copy_mode = i;
|
||||
}
|
||||
dont_ask = mp_ui->dont_ask_cbx->isChecked ();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ public:
|
|||
*
|
||||
* The mode is either 0 (for shallow), 1 (for deep)
|
||||
*/
|
||||
bool exec_dialog (int ©_mode);
|
||||
bool exec_dialog (int ©_mode, bool &dont_ask_again);
|
||||
|
||||
private:
|
||||
Ui::CopyCellModeDialog *mp_ui;
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutViewBase *view, QWidget
|
|||
m_flat (false),
|
||||
m_split_mode (false),
|
||||
m_sorting (CellTreeModel::ByName),
|
||||
m_cell_copy_mode (-1),
|
||||
m_do_update_content_dm (this, &HierarchyControlPanel::do_update_content),
|
||||
m_do_full_update_content_dm (this, &HierarchyControlPanel::do_full_update_content)
|
||||
{
|
||||
|
|
@ -398,6 +399,12 @@ HierarchyControlPanel::clear_all ()
|
|||
mp_cell_lists.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyControlPanel::set_cell_copy_mode (int m)
|
||||
{
|
||||
m_cell_copy_mode = m;
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyControlPanel::set_flat (bool f)
|
||||
{
|
||||
|
|
@ -1002,6 +1009,47 @@ HierarchyControlPanel::has_focus () const
|
|||
return m_active_index >= 0 && m_active_index < int (mp_cell_lists.size ()) && mp_cell_lists [m_active_index]->hasFocus ();
|
||||
}
|
||||
|
||||
bool
|
||||
HierarchyControlPanel::ask_for_cell_copy_mode (const db::Layout &layout, const std::vector<cell_path_type> &paths, int &cell_copy_mode)
|
||||
{
|
||||
bool needs_to_ask = false;
|
||||
cell_copy_mode = 0;
|
||||
|
||||
if (m_cell_copy_mode < 0) { // ask
|
||||
|
||||
// check if there is a cell that we have to ask for
|
||||
for (std::vector<cell_path_type>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
|
||||
if (! p->empty ()) {
|
||||
const db::Cell &cell = layout.cell (p->back ());
|
||||
if (! cell.is_proxy () && ! cell.is_leaf ()) {
|
||||
needs_to_ask = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
cell_copy_mode = m_cell_copy_mode;
|
||||
}
|
||||
|
||||
if (needs_to_ask) {
|
||||
|
||||
bool dont_ask_again = false;
|
||||
|
||||
lay::CopyCellModeDialog mode_dialog (this);
|
||||
if (! mode_dialog.exec_dialog (cell_copy_mode, dont_ask_again)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dont_ask_again) {
|
||||
view ()->dispatcher ()->config_set (cfg_copy_cell_mode, tl::to_string (cell_copy_mode));
|
||||
view ()->dispatcher ()->config_end ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyControlPanel::cut ()
|
||||
{
|
||||
|
|
@ -1017,34 +1065,25 @@ HierarchyControlPanel::cut ()
|
|||
}
|
||||
|
||||
// first copy
|
||||
bool needs_to_ask = false;
|
||||
|
||||
db::Layout &layout = m_cellviews [m_active_index]->layout ();
|
||||
if (! layout.is_editable ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// collect the called cells of the cells to copy, so we don't copy a cell twice
|
||||
|
||||
db::Clipboard::instance ().clear ();
|
||||
|
||||
// don't copy the cells which would be copied anyway
|
||||
int cut_mode = 1; // 0: shallow, 1: deep
|
||||
if (! ask_for_cell_copy_mode (layout, paths, cut_mode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// collect the called cells of the cells to copy, so we don't copy a cell twice
|
||||
std::set<db::cell_index_type> called_cells;
|
||||
for (std::vector<cell_path_type>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
|
||||
if (! p->empty ()) {
|
||||
const db::Cell &cell = layout.cell (p->back ());
|
||||
cell.collect_called_cells (called_cells);
|
||||
if (cell.cell_instances () > 0) {
|
||||
needs_to_ask = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cut_mode = 1; // 0: shallow, 1: deep
|
||||
if (needs_to_ask) {
|
||||
lay::CopyCellModeDialog mode_dialog (this);
|
||||
if (! mode_dialog.exec_dialog (cut_mode)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1115,34 +1154,25 @@ HierarchyControlPanel::copy ()
|
|||
return;
|
||||
}
|
||||
|
||||
bool needs_to_ask = false;
|
||||
|
||||
db::Layout &layout = m_cellviews [m_active_index]->layout ();
|
||||
|
||||
// collect the called cells of the cells to copy, so we don't copy a cell twice
|
||||
|
||||
db::Clipboard::instance ().clear ();
|
||||
|
||||
// don't copy the cells which would be copied anyway
|
||||
int copy_mode = 1; // 0: shallow, 1: deep
|
||||
if (! ask_for_cell_copy_mode (layout, paths, copy_mode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// collect the called cells of the cells to copy, so we don't copy a cell twice
|
||||
std::set<db::cell_index_type> called_cells;
|
||||
for (std::vector<cell_path_type>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
|
||||
if (! p->empty ()) {
|
||||
const db::Cell &cell = layout.cell (p->back ());
|
||||
cell.collect_called_cells (called_cells);
|
||||
if (cell.cell_instances () > 0) {
|
||||
needs_to_ask = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int copy_mode = 1; // 0: shallow, 1: deep
|
||||
if (needs_to_ask) {
|
||||
lay::CopyCellModeDialog mode_dialog (this);
|
||||
if (! mode_dialog.exec_dialog (copy_mode)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// actually copy
|
||||
for (std::vector<cell_path_type>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
|
||||
if (! p->empty () && called_cells.find (p->back ()) == called_cells.end ()) {
|
||||
db::ClipboardValue<lay::CellClipboardData> *cd = new db::ClipboardValue<lay::CellClipboardData> ();
|
||||
|
|
|
|||
|
|
@ -219,6 +219,12 @@ public:
|
|||
*/
|
||||
void paste ();
|
||||
|
||||
/**
|
||||
* @brief Selects cell copy mode
|
||||
* 0: shallow, 1: deep, -1: ask
|
||||
*/
|
||||
void set_cell_copy_mode (int m);
|
||||
|
||||
/**
|
||||
* @brief Return true, if the panel has a selection
|
||||
*/
|
||||
|
|
@ -308,6 +314,7 @@ private:
|
|||
QSplitter *mp_splitter;
|
||||
tl::Color m_background_color;
|
||||
tl::Color m_text_color;
|
||||
int m_cell_copy_mode;
|
||||
tl::DeferredMethod<HierarchyControlPanel> m_do_update_content_dm;
|
||||
tl::DeferredMethod<HierarchyControlPanel> m_do_full_update_content_dm;
|
||||
std::unique_ptr<QStyle> mp_tree_style;
|
||||
|
|
@ -336,6 +343,9 @@ private:
|
|||
|
||||
// clears all widgets of the cell lists
|
||||
void clear_all ();
|
||||
|
||||
// ask for cell copy mode
|
||||
bool ask_for_cell_copy_mode (const db::Layout &layout, const std::vector<cell_path_type> &paths, int &cell_copy_mode);
|
||||
};
|
||||
|
||||
} // namespace lay
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "ui_LayoutViewConfigPage6.h"
|
||||
#include "ui_LayoutViewConfigPage6a.h"
|
||||
#include "ui_LayoutViewConfigPage7.h"
|
||||
#include "ui_LayoutViewConfigPage8.h"
|
||||
|
||||
#include "laySelectStippleForm.h"
|
||||
#include "laySelectLineStyleForm.h"
|
||||
|
|
@ -1529,6 +1530,37 @@ LayoutViewConfigPage7::commit (lay::Dispatcher *root)
|
|||
root->config_set (cfg_initial_hier_depth, mp_ui->def_depth->value ());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// LayoutConfigPage8 implementation
|
||||
|
||||
LayoutViewConfigPage8::LayoutViewConfigPage8 (QWidget *parent)
|
||||
: lay::ConfigPage (parent)
|
||||
{
|
||||
mp_ui = new Ui::LayoutViewConfigPage8 ();
|
||||
mp_ui->setupUi (this);
|
||||
}
|
||||
|
||||
LayoutViewConfigPage8::~LayoutViewConfigPage8 ()
|
||||
{
|
||||
delete mp_ui;
|
||||
mp_ui = 0;
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewConfigPage8::setup (lay::Dispatcher *root)
|
||||
{
|
||||
int cpm = -1;
|
||||
root->config_get (cfg_copy_cell_mode, cpm);
|
||||
mp_ui->hier_copy_mode_cbx->setCurrentIndex ((cpm < 0 || cpm > 1) ? 2 : cpm);
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewConfigPage8::commit (lay::Dispatcher *root)
|
||||
{
|
||||
int cpm = mp_ui->hier_copy_mode_cbx->currentIndex ();
|
||||
root->config_set (cfg_copy_cell_mode, (cpm < 0 || cpm > 1) ? -1 : cpm);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// The dummy plugin declaration to register the configuration options
|
||||
|
||||
|
|
@ -1554,6 +1586,7 @@ public:
|
|||
pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Application|Tracking")), new LayoutViewConfigPage2d (parent)));
|
||||
pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Application|Layer Properties")), new LayoutViewConfigPage5 (parent)));
|
||||
pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Application|Units")), new LayoutViewConfigPage3c (parent)));
|
||||
pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Application|Cells")), new LayoutViewConfigPage8 (parent)));
|
||||
|
||||
pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Navigation|New Cell")), new LayoutViewConfigPage3a (parent)));
|
||||
pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Navigation|Zoom And Pan")), new LayoutViewConfigPage3b (parent)));
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ namespace Ui {
|
|||
class LayoutViewConfigPage6;
|
||||
class LayoutViewConfigPage6a;
|
||||
class LayoutViewConfigPage7;
|
||||
class LayoutViewConfigPage8;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
|
|
@ -355,6 +356,22 @@ private:
|
|||
Ui::LayoutViewConfigPage7 *mp_ui;
|
||||
};
|
||||
|
||||
class LayoutViewConfigPage8
|
||||
: public lay::ConfigPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LayoutViewConfigPage8 (QWidget *parent);
|
||||
~LayoutViewConfigPage8 ();
|
||||
|
||||
virtual void setup (lay::Dispatcher *root);
|
||||
virtual void commit (lay::Dispatcher *root);
|
||||
|
||||
private:
|
||||
Ui::LayoutViewConfigPage8 *mp_ui;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ FORMS = \
|
|||
LayoutViewConfigPage6.ui \
|
||||
LayoutViewConfigPage7.ui \
|
||||
LayoutViewConfigPage.ui \
|
||||
LayoutViewConfigPage8.ui \
|
||||
LibraryCellSelectionForm.ui \
|
||||
LoadLayoutOptionsDialog.ui \
|
||||
MarkerBrowserConfigPage2.ui \
|
||||
|
|
|
|||
|
|
@ -938,6 +938,15 @@ LayoutView::configure (const std::string &name, const std::string &value)
|
|||
}
|
||||
return true;
|
||||
|
||||
} else if (name == cfg_copy_cell_mode) {
|
||||
|
||||
if (mp_hierarchy_panel) {
|
||||
int m = 0;
|
||||
tl::from_string (value, m);
|
||||
mp_hierarchy_panel->set_cell_copy_mode (m);
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (name == cfg_cell_list_sorting) {
|
||||
|
||||
if (mp_hierarchy_panel) {
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ NetTracerTechComponentEditor::NetTracerTechComponentEditor (QWidget *parent)
|
|||
connect (action, SIGNAL (triggered ()), this, SLOT (add_clicked ()));
|
||||
stack_tree->addAction (action);
|
||||
action = new QAction (QObject::tr ("Delete Selected Stacks"), this);
|
||||
connect (action, SIGNAL (triggered ()), this, SLOT (delete_clicked ()));
|
||||
connect (action, SIGNAL (triggered ()), this, SLOT (del_clicked ()));
|
||||
stack_tree->addAction (action);
|
||||
action = new QAction (QObject::tr ("Duplicate Stack"), this);
|
||||
connect (action, SIGNAL (triggered ()), this, SLOT (clone_clicked ()));
|
||||
|
|
|
|||
|
|
@ -684,7 +684,11 @@ PythonInterpreter::trace_func (PyFrameObject *frame, int event, PyObject *arg)
|
|||
exc_value = PythonPtr (PyTuple_GetItem (arg, 1));
|
||||
}
|
||||
|
||||
if (exc_type && exc_type.get () != PyExc_StopIteration) {
|
||||
#if PY_VERSION_HEX >= 0x03050000
|
||||
if (exc_type && exc_type.get () != PyExc_StopIteration && exc_type.get () != PyExc_GeneratorExit && exc_type.get () != PyExc_StopAsyncIteration) {
|
||||
#else
|
||||
if (exc_type && exc_type.get () != PyExc_StopIteration && exc_type.get () != PyExc_GeneratorExit) {
|
||||
#endif
|
||||
|
||||
// If the next exception shall be ignored, do so
|
||||
if (m_ignore_next_exception) {
|
||||
|
|
|
|||
|
|
@ -533,8 +533,13 @@ PyObject *c2python_func<const tl::Variant &>::operator() (const tl::Variant &c)
|
|||
|
||||
const gsi::ClassBase *cls = c.gsi_cls ();
|
||||
if (cls) {
|
||||
void *obj = const_cast<void *> (c.to_user ());
|
||||
return object_to_python (obj, 0, c.user_cls ()->gsi_cls (), false, false, true, false);
|
||||
if (! c.user_is_ref () && cls->is_managed ()) {
|
||||
void *obj = c.user_unshare ();
|
||||
return object_to_python (obj, 0, c.user_cls ()->gsi_cls (), true, c.user_is_const (), false, false);
|
||||
} else {
|
||||
void *obj = const_cast<void *> (c.to_user ());
|
||||
return object_to_python (obj, 0, c.user_cls ()->gsi_cls (), false, false, true, false);
|
||||
}
|
||||
} else {
|
||||
// not a known type -> return nil
|
||||
Py_RETURN_NONE;
|
||||
|
|
|
|||
|
|
@ -287,8 +287,13 @@ VALUE c2ruby<tl::Variant> (const tl::Variant &c)
|
|||
} else if (c.is_user ()) {
|
||||
const gsi::ClassBase *cls = c.gsi_cls ();
|
||||
if (cls) {
|
||||
void *obj = const_cast<void *> (c.to_user ());
|
||||
return object_to_ruby (obj, 0, c.user_cls ()->gsi_cls (), false, false, true, false);
|
||||
if (! c.user_is_ref () && cls->is_managed ()) {
|
||||
void *obj = c.user_unshare ();
|
||||
return object_to_ruby (obj, 0, c.user_cls ()->gsi_cls (), true, c.user_is_const (), false, false);
|
||||
} else {
|
||||
void *obj = const_cast<void *> (c.to_user ());
|
||||
return object_to_ruby (obj, 0, c.user_cls ()->gsi_cls (), false, false, true, false);
|
||||
}
|
||||
} else {
|
||||
// not a known type -> return nil
|
||||
return Qnil;
|
||||
|
|
|
|||
|
|
@ -227,6 +227,11 @@ const Object *WeakOrSharedPtr::get () const
|
|||
return mp_t;
|
||||
}
|
||||
|
||||
void WeakOrSharedPtr::unshare ()
|
||||
{
|
||||
m_is_shared = false;
|
||||
}
|
||||
|
||||
void WeakOrSharedPtr::reset_object ()
|
||||
{
|
||||
tl::MutexLocker locker (&lock ());
|
||||
|
|
|
|||
|
|
@ -197,6 +197,12 @@ public:
|
|||
*/
|
||||
void detach_from_all_events ();
|
||||
|
||||
/**
|
||||
* @brief Unshares the object
|
||||
* This will turn a shared reference into a weak one.
|
||||
*/
|
||||
void unshare ();
|
||||
|
||||
/**
|
||||
* @brief Indicates that this object is an event
|
||||
* This property is intended for internal use only.
|
||||
|
|
@ -401,6 +407,9 @@ public:
|
|||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
private:
|
||||
using weak_or_shared_ptr<T, false>::unshare;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -429,6 +438,9 @@ public:
|
|||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
private:
|
||||
using weak_or_shared_ptr<T, true>::unshare;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2723,6 +2723,21 @@ void *Variant::user_take ()
|
|||
return obj;
|
||||
}
|
||||
|
||||
void *Variant::user_unshare () const
|
||||
{
|
||||
tl_assert (is_user () && ! user_is_ref ());
|
||||
|
||||
if (m_type == t_user) {
|
||||
Variant *nc_this = const_cast<Variant *> (this);
|
||||
nc_this->m_var.mp_user.shared = false;
|
||||
} else if (m_type == t_user_ref) {
|
||||
tl::WeakOrSharedPtr *wptr = const_cast<tl::WeakOrSharedPtr *> (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr));
|
||||
wptr->unshare ();
|
||||
}
|
||||
|
||||
return const_cast<void *> (to_user ());
|
||||
}
|
||||
|
||||
void Variant::user_assign (const tl::Variant &other)
|
||||
{
|
||||
tl_assert (is_user ());
|
||||
|
|
|
|||
|
|
@ -994,6 +994,13 @@ public:
|
|||
*/
|
||||
void *user_take ();
|
||||
|
||||
/**
|
||||
* @brief Takes the user object and releases ownership by the variant
|
||||
* This method is const as it does not change the value, but the ownership of
|
||||
* the contained object. The object must not be "user_is_ref".
|
||||
*/
|
||||
void *user_unshare () const;
|
||||
|
||||
/**
|
||||
* @brief Assigns the object stored in other to self
|
||||
*
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -81,6 +81,31 @@ class DBRegionTest(unittest.TestCase):
|
|||
dss = None
|
||||
self.assertEqual(pya.DeepShapeStore.instance_count(), 0)
|
||||
|
||||
# begin_shapes_rec and begin_shapes_merged_rec
|
||||
def test_extended_iter(self):
|
||||
|
||||
r = pya.Region()
|
||||
|
||||
# NOTE: this also tests the copy semantics of the RecursiveShape to Variant binding in RBA:
|
||||
it, trans = r.begin_shapes_rec()
|
||||
s = ",".join([ str(trans*i.trans()*i.shape().polygon) for i in it.each() ])
|
||||
self.assertEqual(s, "")
|
||||
|
||||
it, trans = r.begin_merged_shapes_rec()
|
||||
s = ",".join([ str(trans*i.trans()*i.shape().polygon) for i in it.each() ])
|
||||
self.assertEqual(s, "")
|
||||
|
||||
r.insert(pya.Box(0, 0, 100, 100))
|
||||
r.insert(pya.Box(50, 50, 200, 200))
|
||||
|
||||
it, trans = r.begin_shapes_rec()
|
||||
s = ",".join([ str(trans*i.trans()*i.shape().polygon) for i in it.each() ])
|
||||
self.assertEqual(s, "(0,0;0,100;100,100;100,0),(50,50;50,200;200,200;200,50)")
|
||||
|
||||
it, trans = r.begin_merged_shapes_rec()
|
||||
s = ",".join([ str(trans*i.trans()*i.shape().polygon) for i in it.each() ])
|
||||
self.assertEqual(s, "(0,0;0,100;50,100;50,200;200,200;200,50;100,50;100,0)")
|
||||
|
||||
# run unit tests
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(DBRegionTest)
|
||||
|
|
|
|||
|
|
@ -1334,6 +1334,7 @@ class DBLayoutTests1_TestClass < TestBase
|
|||
i0 = nil
|
||||
c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i }
|
||||
assert_equal(i0.property("p"), 18)
|
||||
assert_equal(i0.properties, {"p" => 18})
|
||||
assert_equal(l.cell("c1$1").begin_shapes_rec(0).shape.property("p"), 17)
|
||||
|
||||
assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)")
|
||||
|
|
@ -1379,6 +1380,7 @@ class DBLayoutTests1_TestClass < TestBase
|
|||
|
||||
tt = RBA::Trans.new
|
||||
i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt))
|
||||
assert_equal(i0.properties, {})
|
||||
i0.set_property("p", 18)
|
||||
c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100))))
|
||||
c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1)))
|
||||
|
|
@ -2100,6 +2102,48 @@ class DBLayoutTests1_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# break_polygons
|
||||
def test_25
|
||||
|
||||
def shapes2str(shapes)
|
||||
str = []
|
||||
shapes.each do |s|
|
||||
str << s.to_s
|
||||
end
|
||||
str.join(";")
|
||||
end
|
||||
|
||||
ly = RBA::Layout::new
|
||||
top = ly.create_cell("TOP")
|
||||
l1 = ly.layer(1, 0)
|
||||
l2 = ly.layer(2, 0)
|
||||
|
||||
top.shapes(l1).insert(RBA::Polygon::new([ [0, 0], [0, 10000], [10000, 10000], [10000, 9000], [1000, 9000], [1000, 0] ]))
|
||||
top.shapes(l2).insert(RBA::Polygon::new([ [0, 0], [0, 10000], [10000, 10000], [10000, 9000], [1000, 9000], [1000, 0] ]))
|
||||
|
||||
assert_equal(shapes2str(top.shapes(l1)), "polygon (0,0;0,10000;10000,10000;10000,9000;1000,9000;1000,0)")
|
||||
assert_equal(shapes2str(top.shapes(l2)), "polygon (0,0;0,10000;10000,10000;10000,9000;1000,9000;1000,0)")
|
||||
|
||||
s1 = top.shapes(l1).dup
|
||||
assert_equal(shapes2str(s1), "polygon (0,0;0,10000;10000,10000;10000,9000;1000,9000;1000,0)")
|
||||
s1.break_polygons(10, 3.0)
|
||||
assert_equal(shapes2str(s1), "polygon (0,0;0,9000;1000,9000;1000,0);polygon (0,9000;0,10000;10000,10000;10000,9000)")
|
||||
|
||||
ly2 = ly.dup
|
||||
top2 = ly2.top_cell
|
||||
|
||||
ly.break_polygons(10, 3.0)
|
||||
|
||||
assert_equal(shapes2str(top.shapes(l1)), "polygon (0,0;0,9000;1000,9000;1000,0);polygon (0,9000;0,10000;10000,10000;10000,9000)")
|
||||
assert_equal(shapes2str(top.shapes(l2)), "polygon (0,0;0,9000;1000,9000;1000,0);polygon (0,9000;0,10000;10000,10000;10000,9000)")
|
||||
|
||||
ly2.break_polygons(ly2.layer(1, 0), 10, 3.0)
|
||||
|
||||
assert_equal(shapes2str(top2.shapes(ly2.layer(1, 0))), "polygon (0,0;0,9000;1000,9000;1000,0);polygon (0,9000;0,10000;10000,10000;10000,9000)")
|
||||
assert_equal(shapes2str(top2.shapes(ly2.layer(2, 0))), "polygon (0,0;0,10000;10000,10000;10000,9000;1000,9000;1000,0)")
|
||||
|
||||
end
|
||||
|
||||
# Iterating while flatten
|
||||
def test_issue200
|
||||
|
||||
|
|
|
|||
|
|
@ -674,6 +674,7 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
lindex = ly.insert_layer( linfo )
|
||||
|
||||
c1 = ly.cell( ci1 )
|
||||
assert_equal( c1.properties, {} )
|
||||
c2 = ly.cell( ci2 )
|
||||
tr = RBA::Trans::new
|
||||
inst = c2.insert( RBA::CellInstArray::new( c1.cell_index, tr ) )
|
||||
|
|
@ -701,6 +702,7 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
c1.prop_id = pid
|
||||
assert_equal( c1.prop_id, pid )
|
||||
assert_equal( c1.property( 17 ).inspect, "\"a\"" )
|
||||
assert_equal( c1.properties, { 17 => "a", "b" => [1, 5, 7] } )
|
||||
c1.set_property( 5, 23 )
|
||||
c1.delete_property( 17 )
|
||||
assert_equal( c1.property( 17 ).inspect, "nil" )
|
||||
|
|
@ -1027,6 +1029,7 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
def test_11
|
||||
|
||||
ly = RBA::Layout::new
|
||||
assert_equal(ly.properties, {})
|
||||
|
||||
assert_equal(ly.prop_id, 0)
|
||||
ly.prop_id = 1
|
||||
|
|
@ -1037,6 +1040,7 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
ly.set_property("x", 1)
|
||||
assert_equal(ly.prop_id, 1)
|
||||
assert_equal(ly.property("x"), 1)
|
||||
assert_equal(ly.properties, {"x" => 1})
|
||||
ly.set_property("x", 17)
|
||||
assert_equal(ly.prop_id, 2)
|
||||
assert_equal(ly.property("x"), 17)
|
||||
|
|
|
|||
|
|
@ -832,18 +832,25 @@ END
|
|||
|
||||
nl = RBA::Netlist::new
|
||||
assert_equal(nl.top_circuit_count, 0)
|
||||
assert_equal(nl.top_circuit == nil, true)
|
||||
|
||||
c1 = RBA::Circuit::new
|
||||
c1.name = "C1"
|
||||
c1.cell_index = 17
|
||||
nl.add(c1)
|
||||
assert_equal(nl.top_circuit_count, 1)
|
||||
assert_equal(nl.top_circuit.name, "C1")
|
||||
|
||||
c2 = RBA::Circuit::new
|
||||
c2.name = "C2"
|
||||
c1.cell_index = 42
|
||||
nl.add(c2)
|
||||
assert_equal(nl.top_circuit_count, 2)
|
||||
begin
|
||||
nl.top_circuit
|
||||
assert_equal(true, false)
|
||||
rescue
|
||||
end
|
||||
|
||||
c3 = RBA::Circuit::new
|
||||
c3.name = "C3"
|
||||
|
|
@ -854,6 +861,10 @@ END
|
|||
nl.each_circuit_top_down { |c| names << c.name }
|
||||
assert_equal(names.join(","), "C3,C2,C1")
|
||||
|
||||
names = []
|
||||
nl.top_circuits.each { |c| names << c.name }
|
||||
assert_equal(names.join(","), "C3,C2,C1")
|
||||
|
||||
names = []
|
||||
nl.each_circuit_bottom_up { |c| names << c.name }
|
||||
assert_equal(names.join(","), "C1,C2,C3")
|
||||
|
|
|
|||
|
|
@ -1471,6 +1471,33 @@ class DBRegion_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# begin_shapes_rec and begin_shapes_merged_rec
|
||||
def test_extended_iter
|
||||
|
||||
r = RBA::Region::new()
|
||||
|
||||
# NOTE: this also tests the copy semantics of the RecursiveShape to Variant binding in RBA:
|
||||
iter, trans = r.begin_shapes_rec
|
||||
str = iter.each.collect { |i| (trans*i.trans*i.shape.polygon).to_s }.join(",")
|
||||
assert_equal(str, "")
|
||||
|
||||
iter, trans = r.begin_merged_shapes_rec
|
||||
str = iter.each.collect { |i| (trans*i.trans*i.shape.polygon).to_s }.join(",")
|
||||
assert_equal(str, "")
|
||||
|
||||
r.insert(RBA::Box::new(0, 0, 100, 100))
|
||||
r.insert(RBA::Box::new(50, 50, 200, 200))
|
||||
|
||||
iter, trans = r.begin_shapes_rec
|
||||
str = iter.each.collect { |i| (trans*i.trans*i.shape.polygon).to_s }.join(",")
|
||||
assert_equal(str, "(0,0;0,100;100,100;100,0),(50,50;50,200;200,200;200,50)")
|
||||
|
||||
iter, trans = r.begin_merged_shapes_rec
|
||||
str = iter.each.collect { |i| (trans*i.trans*i.shape.polygon).to_s }.join(",")
|
||||
assert_equal(str, "(0,0;0,100;50,100;50,200;200,200;200,50;100,50;100,0)")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -1656,6 +1656,28 @@ class DBShapes_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# Shape objects and properties
|
||||
def test_13
|
||||
|
||||
ly = RBA::Layout::new
|
||||
l1 = ly.layer(1, 0)
|
||||
tc = ly.create_cell("TOP")
|
||||
sh = tc.shapes(l1).insert(RBA::Box::new(0, 0, 100, 200))
|
||||
|
||||
assert_equal(sh.property("k").inspect, "nil")
|
||||
assert_equal(sh.properties.inspect, "{}")
|
||||
|
||||
sh.set_property("k", 17)
|
||||
|
||||
assert_equal(sh.property("k").inspect, "17")
|
||||
assert_equal(sh.property("u").inspect, "nil")
|
||||
assert_equal(sh.properties.inspect, "{\"k\"=>17}")
|
||||
|
||||
sh.set_property("u", "42")
|
||||
assert_equal(sh.properties.inspect, "{\"k\"=>17, \"u\"=>\"42\"}")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue