mirror of https://github.com/KLayout/klayout.git
commit
e51b3545e0
|
|
@ -563,6 +563,7 @@ for k in dir(pya.PCellParameterDeclaration):
|
|||
|
||||
# Inject the PCellDeclarationHelper into pya module for consistency:
|
||||
setattr(pya, "PCellDeclarationHelper", _PCellDeclarationHelper)
|
||||
pya.__all__.append("PCellDeclarationHelper")
|
||||
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ Cell::box_type Cell::ms_empty_box = Cell::box_type ();
|
|||
|
||||
Cell::Cell (cell_index_type ci, db::Layout &l)
|
||||
: db::Object (l.manager ()),
|
||||
m_cell_index (ci), mp_layout (&l), m_instances (this), m_prop_id (0), m_hier_levels (0), m_bbox_needs_update (false), m_ghost_cell (false),
|
||||
m_cell_index (ci), mp_layout (&l), m_instances (this), m_prop_id (0), m_hier_levels (0),
|
||||
m_bbox_needs_update (false), m_ghost_cell (false),
|
||||
mp_last (0), mp_next (0)
|
||||
{
|
||||
// .. nothing yet
|
||||
|
|
@ -700,7 +701,7 @@ Cell::clear_parent_insts (size_t sz)
|
|||
void
|
||||
Cell::sort_child_insts ()
|
||||
{
|
||||
m_instances.sort_child_insts ();
|
||||
m_instances.sort_child_insts (false);
|
||||
}
|
||||
|
||||
std::pair<bool, db::pcell_id_type>
|
||||
|
|
@ -744,9 +745,9 @@ Cell::change_pcell_parameters (const instance_type &ref, const std::vector<tl::V
|
|||
}
|
||||
|
||||
void
|
||||
Cell::sort_inst_tree ()
|
||||
Cell::sort_inst_tree (bool force)
|
||||
{
|
||||
m_instances.sort_inst_tree (mp_layout);
|
||||
m_instances.sort_inst_tree (mp_layout, force);
|
||||
|
||||
// update the number of hierarchy levels
|
||||
m_hier_levels = count_hier_levels ();
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ private:
|
|||
db::properties_id_type m_prop_id;
|
||||
|
||||
// packed fields
|
||||
unsigned int m_hier_levels : 29;
|
||||
unsigned int m_hier_levels : 30;
|
||||
bool m_bbox_needs_update : 1;
|
||||
bool m_ghost_cell : 1;
|
||||
|
||||
|
|
@ -1147,9 +1147,9 @@ private:
|
|||
* This will sort the cell instance list. As a prerequesite
|
||||
* the cell's bounding boxes must have been computed.
|
||||
*
|
||||
* @param layers The maximum number of layers in the child cells
|
||||
* @param force Force sorting, even if not strictly needed
|
||||
*/
|
||||
void sort_inst_tree ();
|
||||
void sort_inst_tree (bool force);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -940,6 +940,9 @@ Instances::operator= (const Instances &d)
|
|||
|
||||
m_parent_insts = d.m_parent_insts;
|
||||
|
||||
set_instance_by_cell_index_needs_made (true);
|
||||
set_instance_tree_needs_sort (true);
|
||||
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -947,13 +950,24 @@ Instances::operator= (const Instances &d)
|
|||
bool
|
||||
Instances::is_editable () const
|
||||
{
|
||||
return mp_cell && mp_cell->layout () ? mp_cell->layout ()->is_editable () : true;
|
||||
return cell () && cell ()->layout () ? cell ()->layout ()->is_editable () : true;
|
||||
}
|
||||
|
||||
db::Layout *
|
||||
Instances::layout () const
|
||||
{
|
||||
return mp_cell ? mp_cell->layout () : 0;
|
||||
return cell () ? cell ()->layout () : 0;
|
||||
}
|
||||
|
||||
void
|
||||
Instances::invalidate_insts ()
|
||||
{
|
||||
if (cell ()) {
|
||||
cell ()->invalidate_insts ();
|
||||
}
|
||||
|
||||
set_instance_by_cell_index_needs_made (true);
|
||||
set_instance_tree_needs_sort (true);
|
||||
}
|
||||
|
||||
template <class Tag, class ET, class I>
|
||||
|
|
@ -962,14 +976,15 @@ Instances::erase_positions (Tag tag, ET editable_tag, I first, I last)
|
|||
{
|
||||
typedef instances_editable_traits<ET> editable_traits;
|
||||
|
||||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts (); // HINT: must come before the change is done!
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
invalidate_insts (); // HINT: must come before the change is done!
|
||||
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
if (! is_editable ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("No undo/redo support for non-editable instance lists in 'erase_positions'")));
|
||||
}
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, first, last, true /*dummy*/));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, first, last, true /*dummy*/));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -983,18 +998,19 @@ Instances::insert (const InstArray &inst)
|
|||
{
|
||||
bool editable = is_editable ();
|
||||
|
||||
if (mp_cell) {
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
if (editable) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesEditableTag> (true /*insert*/, inst));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<InstArray, InstancesEditableTag> (true /*insert*/, inst));
|
||||
} else {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesNonEditableTag> (true /*insert*/, inst));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<InstArray, InstancesNonEditableTag> (true /*insert*/, inst));
|
||||
}
|
||||
}
|
||||
mp_cell->invalidate_insts ();
|
||||
}
|
||||
|
||||
invalidate_insts ();
|
||||
|
||||
// TODO: simplify this, i.e. through instance_from_pointer
|
||||
if (editable) {
|
||||
return instance_type (this, inst_tree (typename InstArray::tag (), InstancesEditableTag ()).insert (inst));
|
||||
|
|
@ -1010,14 +1026,14 @@ Instances::insert (I from, I to)
|
|||
typedef std::iterator_traits<I> it_traits;
|
||||
typedef typename it_traits::value_type value_type;
|
||||
|
||||
if (mp_cell) {
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename it_traits::value_type, ET> (true /*insert*/, from, to));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<typename it_traits::value_type, ET> (true /*insert*/, from, to));
|
||||
}
|
||||
mp_cell->invalidate_insts ();
|
||||
}
|
||||
|
||||
invalidate_insts ();
|
||||
inst_tree (typename value_type::tag (), ET ()).insert (from, to);
|
||||
}
|
||||
|
||||
|
|
@ -1061,20 +1077,21 @@ template <class InstArray>
|
|||
void
|
||||
Instances::replace (const InstArray *replace, const InstArray &with)
|
||||
{
|
||||
if (mp_cell) {
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
if (is_editable ()) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesEditableTag> (false /*not insert*/, *replace));
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesEditableTag> (true /*insert*/, with));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<InstArray, InstancesEditableTag> (false /*not insert*/, *replace));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<InstArray, InstancesEditableTag> (true /*insert*/, with));
|
||||
} else {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesNonEditableTag> (false /*not insert*/, *replace));
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesNonEditableTag> (true /*insert*/, with));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<InstArray, InstancesNonEditableTag> (false /*not insert*/, *replace));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<InstArray, InstancesNonEditableTag> (true /*insert*/, with));
|
||||
}
|
||||
}
|
||||
mp_cell->invalidate_insts ();
|
||||
}
|
||||
|
||||
invalidate_insts ();
|
||||
|
||||
// HINT: this only works because we know our box trees well:
|
||||
*((InstArray *)replace) = with;
|
||||
}
|
||||
|
|
@ -1150,11 +1167,12 @@ Instances::erase_inst_by_iter (Tag tag, ET editable_tag, I iter)
|
|||
throw tl::Exception (tl::to_string (tr ("Trying to erase an object from a list that it does not belong to")));
|
||||
}
|
||||
|
||||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
invalidate_insts ();
|
||||
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, *iter));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, *iter));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1165,11 +1183,12 @@ template <class Tag, class ET>
|
|||
void
|
||||
Instances::erase_inst_by_tag (Tag tag, ET editable_tag, const typename Tag::object_type &obj)
|
||||
{
|
||||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
invalidate_insts ();
|
||||
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, obj));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1197,16 +1216,17 @@ template <class ET>
|
|||
void
|
||||
Instances::clear_insts (ET editable_tag)
|
||||
{
|
||||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
invalidate_insts ();
|
||||
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
const Instances *const_this = this;
|
||||
if (! const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).empty ()) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<cell_inst_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
}
|
||||
if (! const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).empty ()) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_wp_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ()));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<cell_inst_wp_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1227,9 +1247,7 @@ Instances::clear_insts ()
|
|||
void
|
||||
Instances::clear (Instances::cell_inst_array_type::tag)
|
||||
{
|
||||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
}
|
||||
invalidate_insts ();
|
||||
|
||||
if (m_generic.any) {
|
||||
if (is_editable ()) {
|
||||
|
|
@ -1244,9 +1262,7 @@ Instances::clear (Instances::cell_inst_array_type::tag)
|
|||
void
|
||||
Instances::clear (Instances::cell_inst_wp_array_type::tag)
|
||||
{
|
||||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
}
|
||||
invalidate_insts ();
|
||||
|
||||
if (m_generic_wp.any) {
|
||||
if (is_editable ()) {
|
||||
|
|
@ -1371,8 +1387,13 @@ struct cell_inst_compare_f
|
|||
};
|
||||
|
||||
void
|
||||
Instances::sort_child_insts ()
|
||||
Instances::sort_child_insts (bool force)
|
||||
{
|
||||
if (! force && ! instance_by_cell_index_needs_made ()) {
|
||||
return;
|
||||
}
|
||||
set_instance_by_cell_index_needs_made (false);
|
||||
|
||||
m_insts_by_cell_index = sorted_inst_vector ();
|
||||
m_insts_by_cell_index.reserve (cell_instances ());
|
||||
|
||||
|
|
@ -1406,15 +1427,20 @@ Instances::sort_child_insts ()
|
|||
}
|
||||
|
||||
void
|
||||
Instances::sort_inst_tree (const Layout *g)
|
||||
Instances::sort_inst_tree (const Layout *g, bool force)
|
||||
{
|
||||
if (! force && ! instance_tree_needs_sort ()) {
|
||||
return;
|
||||
}
|
||||
set_instance_tree_needs_sort (false);
|
||||
|
||||
if (m_generic.any) {
|
||||
if (is_editable ()) {
|
||||
m_generic.stable_tree->sort (cell_inst_array_box_converter (*g));
|
||||
} else {
|
||||
m_generic.unstable_tree->sort (cell_inst_array_box_converter (*g));
|
||||
// since we use unstable instance trees in non-editable mode, we need to resort the child instances in this case
|
||||
sort_child_insts ();
|
||||
sort_child_insts (true);
|
||||
}
|
||||
}
|
||||
if (m_generic_wp.any) {
|
||||
|
|
@ -1423,7 +1449,7 @@ Instances::sort_inst_tree (const Layout *g)
|
|||
} else {
|
||||
m_generic_wp.unstable_tree->sort (cell_inst_wp_array_box_converter (*g));
|
||||
// since we use unstable instance trees in non-editable mode, we need to resort the child instances in this case
|
||||
sort_child_insts ();
|
||||
sort_child_insts (true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1603,16 +1629,17 @@ void Instances::apply_op (const Op &op, ET editable_tag)
|
|||
bool has_insts = ! const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).empty ();
|
||||
bool has_wp_insts = ! const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).empty ();
|
||||
|
||||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
invalidate_insts ();
|
||||
|
||||
if (cell ()) {
|
||||
if (cell ()->manager () && cell ()->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
transacting = true;
|
||||
if (has_insts) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<cell_inst_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
}
|
||||
if (has_wp_insts) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_wp_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ()));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<cell_inst_wp_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1637,10 +1664,10 @@ void Instances::apply_op (const Op &op, ET editable_tag)
|
|||
|
||||
if (transacting) {
|
||||
if (has_insts) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_array_type, ET> (true /*insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<cell_inst_array_type, ET> (true /*insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
}
|
||||
if (has_wp_insts) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_wp_array_type, ET> (true /*insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ()));
|
||||
cell ()->manager ()->queue (cell (), new db::InstOp<cell_inst_wp_array_type, ET> (true /*insert*/, const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_wp_array_type::tag (), editable_tag).end ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1547,16 +1547,18 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Establish the instance index list giving the instances by cell index
|
||||
* If force is true, the instance tree is always sorted.
|
||||
*/
|
||||
void sort_child_insts ();
|
||||
void sort_child_insts (bool force);
|
||||
|
||||
/**
|
||||
* @brief Sort the cell instance list
|
||||
*
|
||||
* This will sort the cell instance list. As a prerequesite
|
||||
* This will sort the cell instance list (quad tree sort). As a prerequesite
|
||||
* the cell's bounding boxes must have been computed.
|
||||
* If force is true, the instance tree is always sorted.
|
||||
*/
|
||||
void sort_inst_tree (const layout_type *g);
|
||||
void sort_inst_tree (const layout_type *g, bool force);
|
||||
|
||||
/**
|
||||
* @brief Update the child-parent relationships
|
||||
|
|
@ -1701,14 +1703,6 @@ public:
|
|||
return m_parent_insts.end () == m_parent_insts.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the cell pointer the instance container is in
|
||||
*/
|
||||
db::Cell *cell () const
|
||||
{
|
||||
return mp_cell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the layout the instances collection lives in
|
||||
*/
|
||||
|
|
@ -1724,6 +1718,14 @@ public:
|
|||
*/
|
||||
bool is_editable () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cell pointer
|
||||
*/
|
||||
cell_type *cell () const
|
||||
{
|
||||
return reinterpret_cast<cell_type *> (size_t (mp_cell) & ~size_t (3));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delegate for the undo method
|
||||
*/
|
||||
|
|
@ -1735,6 +1737,7 @@ public:
|
|||
void redo (db::Op *op);
|
||||
|
||||
private:
|
||||
friend class Instance;
|
||||
friend struct NormalInstanceIteratorTraits;
|
||||
friend struct TouchingInstanceIteratorTraits;
|
||||
friend struct OverlappingInstanceIteratorTraits;
|
||||
|
|
@ -1761,6 +1764,43 @@ private:
|
|||
static stable_cell_inst_wp_tree_type ms_empty_stable_wp_tree;
|
||||
static stable_cell_inst_tree_type ms_empty_stable_tree;
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating that the instance tree needs sorting
|
||||
*/
|
||||
void set_instance_tree_needs_sort (bool f)
|
||||
{
|
||||
mp_cell = reinterpret_cast<cell_type *> ((size_t (mp_cell) & ~size_t (1)) | size_t (f ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating that the instance tree needs sorting
|
||||
*/
|
||||
bool instance_tree_needs_sort () const
|
||||
{
|
||||
return (size_t (mp_cell) & 1) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating that the instance by cell index cache needs made
|
||||
*/
|
||||
void set_instance_by_cell_index_needs_made (bool f)
|
||||
{
|
||||
mp_cell = reinterpret_cast<cell_type *> ((size_t (mp_cell) & ~size_t (2)) | size_t (f ? 2 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating that the instance tree needs sorting
|
||||
*/
|
||||
bool instance_by_cell_index_needs_made () const
|
||||
{
|
||||
return (size_t (mp_cell) & 2) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invalidates the instance information - called whenever something changes
|
||||
*/
|
||||
void invalidate_insts ();
|
||||
|
||||
/**
|
||||
* @brief Get the non-editable instance tree by instance type
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1097,15 +1097,17 @@ Layout::do_prune_cell_or_subcell (cell_index_type id, int levels, bool subcells)
|
|||
// collect the called cells
|
||||
std::set <cell_index_type> called;
|
||||
cref.collect_called_cells (called, levels);
|
||||
called.insert (id);
|
||||
if (! subcells) {
|
||||
called.insert (id);
|
||||
}
|
||||
|
||||
// From these cells erase all cells that have parents outside the subtree of our cell.
|
||||
// Make sure this is done recursively by doing this top-down.
|
||||
for (top_down_iterator c = begin_top_down (); c != end_top_down (); ++c) {
|
||||
if (called.find (*c) != called.end () && *c != id) {
|
||||
if (*c != id && called.find (*c) != called.end ()) {
|
||||
db::Cell &ccref = cell (*c);
|
||||
for (db::Cell::parent_cell_iterator pc = ccref.begin_parent_cells (); pc != ccref.end_parent_cells (); ++pc) {
|
||||
if (called.find (*pc) == called.end ()) {
|
||||
if (*pc != id && called.find (*pc) == called.end ()) {
|
||||
// we have a parent outside the subset considered currently (either the cell was never in or
|
||||
// it was removed itself already): remove this cell from the set of valid subcells.
|
||||
called.erase (*c);
|
||||
|
|
@ -1115,17 +1117,8 @@ Layout::do_prune_cell_or_subcell (cell_index_type id, int levels, bool subcells)
|
|||
}
|
||||
}
|
||||
|
||||
// order the called cells bottom-up
|
||||
std::vector <cell_index_type> cells_to_delete;
|
||||
cells_to_delete.reserve (called.size ());
|
||||
for (bottom_up_iterator c = begin_bottom_up (); c != end_bottom_up (); ++c) {
|
||||
if (called.find (*c) != called.end () && (!subcells || *c != id)) {
|
||||
cells_to_delete.push_back (*c);
|
||||
}
|
||||
}
|
||||
|
||||
// and delete these cells
|
||||
delete_cells (cells_to_delete.begin (), cells_to_delete.end ());
|
||||
// and delete the cells
|
||||
delete_cells (called);
|
||||
|
||||
// erase all instances in the subcells case (because, by definition we don't have any more instances)
|
||||
if (subcells) {
|
||||
|
|
@ -1799,8 +1792,9 @@ Layout::do_update ()
|
|||
for (bottom_up_iterator c = begin_bottom_up (); c != end_bottom_up (); ++c) {
|
||||
++*pr;
|
||||
cell_type &cp (cell (*c));
|
||||
if (hier_dirty () || dirty_parents.find (*c) != dirty_parents.end ()) {
|
||||
cp.sort_inst_tree ();
|
||||
bool force_sort_inst_tree = dirty_parents.find (*c) != dirty_parents.end ();
|
||||
if (hier_dirty () || force_sort_inst_tree) {
|
||||
cp.sort_inst_tree (force_sort_inst_tree);
|
||||
}
|
||||
if (cp.layers () > layers) {
|
||||
layers = cp.layers ();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "layQtTools.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "layDispatcher.h"
|
||||
#include "layBusy.h"
|
||||
#include "tlScriptError.h"
|
||||
|
||||
#include <QFrame>
|
||||
|
|
@ -604,6 +605,10 @@ PCellParametersPage::parameter_changed ()
|
|||
if (! mp_view->cellview (m_cv_index).is_valid ()) {
|
||||
return;
|
||||
}
|
||||
if (lay::BusySection::is_busy ()) {
|
||||
// ignore events for example during debugger execution
|
||||
return;
|
||||
}
|
||||
|
||||
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
|
||||
const db::PCellParameterDeclaration *pd = 0;
|
||||
|
|
@ -623,6 +628,7 @@ PCellParametersPage::parameter_changed ()
|
|||
// This is just about providing the inputs for the callback.
|
||||
get_parameters_internal (states, edit_error);
|
||||
|
||||
// Note: checking for is_busy prevents callbacks during debugger execution
|
||||
if (! edit_error) {
|
||||
mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), pd ? pd->get_name () : std::string (), states);
|
||||
m_states = states;
|
||||
|
|
|
|||
|
|
@ -148,18 +148,18 @@ MacroEditorHighlighters::MacroEditorHighlighters (QObject *parent)
|
|||
|
||||
for (std::vector<std::pair<std::string, GenericSyntaxHighlighterAttributes> >::iterator a = m_attributes.begin (); a != m_attributes.end (); ++a) {
|
||||
// Note: this loads and initializes the attributes
|
||||
delete highlighter_for_scheme (parent, a->first, &a->second);
|
||||
delete highlighter_for_scheme (parent, a->first, &a->second, true);
|
||||
}
|
||||
}
|
||||
|
||||
QSyntaxHighlighter *
|
||||
MacroEditorHighlighters::highlighter_for (QObject *parent, lym::Macro::Interpreter lang, const std::string &dsl_name)
|
||||
MacroEditorHighlighters::highlighter_for (QObject *parent, lym::Macro::Interpreter lang, const std::string &dsl_name, bool initialize)
|
||||
{
|
||||
std::string scheme = scheme_for (lang, dsl_name);
|
||||
|
||||
for (std::vector<std::pair<std::string, GenericSyntaxHighlighterAttributes> >::iterator a = m_attributes.begin (); a != m_attributes.end (); ++a) {
|
||||
if (a->first == scheme) {
|
||||
return highlighter_for_scheme (parent, a->first, &a->second);
|
||||
return highlighter_for_scheme (parent, a->first, &a->second, initialize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ MacroEditorHighlighters::highlighter_for (QObject *parent, lym::Macro::Interpret
|
|||
}
|
||||
|
||||
lay::GenericSyntaxHighlighter *
|
||||
MacroEditorHighlighters::highlighter_for_scheme (QObject *parent, const std::string &scheme, GenericSyntaxHighlighterAttributes *attributes)
|
||||
MacroEditorHighlighters::highlighter_for_scheme (QObject *parent, const std::string &scheme, GenericSyntaxHighlighterAttributes *attributes, bool initialize)
|
||||
{
|
||||
if (! scheme.empty ()) {
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ MacroEditorHighlighters::highlighter_for_scheme (QObject *parent, const std::str
|
|||
|
||||
QBuffer input (&data);
|
||||
input.open (QIODevice::ReadOnly);
|
||||
lay::GenericSyntaxHighlighter *hl = new GenericSyntaxHighlighter (parent, input, attributes);
|
||||
lay::GenericSyntaxHighlighter *hl = new GenericSyntaxHighlighter (parent, input, attributes, initialize);
|
||||
input.close ();
|
||||
|
||||
return hl;
|
||||
|
|
@ -1096,7 +1096,7 @@ void MacroEditorPage::connect_macro (lym::Macro *macro)
|
|||
mp_text->setPlainText (tl::to_qstring (mp_macro->text ()));
|
||||
mp_text->setReadOnly (macro->is_readonly ());
|
||||
mp_readonly_label->setVisible (macro->is_readonly ());
|
||||
mp_highlighter = mp_highlighters->highlighter_for (mp_text, mp_macro->interpreter (), mp_macro->dsl_interpreter ());
|
||||
mp_highlighter = mp_highlighters->highlighter_for (mp_text, mp_macro->interpreter (), mp_macro->dsl_interpreter (), false);
|
||||
if (mp_highlighter) {
|
||||
mp_highlighter->setDocument (mp_text->document ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class MacroEditorHighlighters
|
|||
public:
|
||||
MacroEditorHighlighters (QObject *parent);
|
||||
|
||||
QSyntaxHighlighter *highlighter_for (QObject *parent, lym::Macro::Interpreter lang, const std::string &dsl_name);
|
||||
QSyntaxHighlighter *highlighter_for (QObject *parent, lym::Macro::Interpreter lang, const std::string &dsl_name, bool initialize);
|
||||
|
||||
GenericSyntaxHighlighterAttributes *attributes_for (lym::Macro::Interpreter lang, const std::string &dsl_name);
|
||||
GenericSyntaxHighlighterAttributes *basic_attributes ();
|
||||
|
|
@ -98,7 +98,7 @@ private:
|
|||
std::vector<std::pair<std::string, GenericSyntaxHighlighterAttributes> > m_attributes;
|
||||
GenericSyntaxHighlighterAttributes m_basic_attributes;
|
||||
|
||||
lay::GenericSyntaxHighlighter *highlighter_for_scheme (QObject *parent, const std::string &scheme, GenericSyntaxHighlighterAttributes *attributes);
|
||||
lay::GenericSyntaxHighlighter *highlighter_for_scheme (QObject *parent, const std::string &scheme, GenericSyntaxHighlighterAttributes *attributes, bool initialize);
|
||||
std::string scheme_for (lym::Macro::Interpreter lang, const std::string &dsl_name);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ module MyLib
|
|||
super
|
||||
|
||||
# declare the parameters
|
||||
param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
|
||||
param(:l, TypeLayer, "Layer")
|
||||
param(:s, TypeShape, "", :default => DPoint::new(0, 0))
|
||||
param(:r, TypeDouble, "Radius", :default => 0.1)
|
||||
param(:n, TypeInt, "Number of points", :default => 64)
|
||||
|
|
@ -100,18 +100,14 @@ module MyLib
|
|||
|
||||
# This is the main part of the implementation: create the layout
|
||||
|
||||
# fetch the parameters
|
||||
ru_dbu = ru / layout.dbu
|
||||
|
||||
# compute the circle
|
||||
pts = []
|
||||
da = Math::PI * 2 / n
|
||||
n.times do |i|
|
||||
pts.push(Point.from_dpoint(DPoint.new(ru_dbu * Math::cos(i * da), ru_dbu * Math::sin(i * da))))
|
||||
pts = n.times.collect do |i|
|
||||
DPoint.new(ru * Math::cos(i * da), ru * Math::sin(i * da))
|
||||
end
|
||||
|
||||
# create the shape
|
||||
cell.shapes(l_layer).insert(Polygon.new(pts))
|
||||
cell.shapes(l_layer).insert(DPolygon.new(pts))
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class Circle(pya.PCellDeclarationHelper):
|
|||
super(Circle, self).__init__()
|
||||
|
||||
# declare the parameters
|
||||
self.param("l", self.TypeLayer, "Layer", default = pya.LayerInfo(1, 0))
|
||||
self.param("l", self.TypeLayer, "Layer")
|
||||
self.param("s", self.TypeShape, "", default = pya.DPoint(0, 0))
|
||||
self.param("r", self.TypeDouble, "Radius", default = 0.1)
|
||||
self.param("n", self.TypeInt, "Number of points", default = 64)
|
||||
|
|
@ -88,17 +88,12 @@ class Circle(pya.PCellDeclarationHelper):
|
|||
|
||||
# This is the main part of the implementation: create the layout
|
||||
|
||||
# fetch the parameters
|
||||
ru_dbu = self.ru / self.layout.dbu
|
||||
|
||||
# compute the circle
|
||||
pts = []
|
||||
da = math.pi * 2 / self.n
|
||||
for i in range(0, self.n):
|
||||
pts.append(pya.Point.from_dpoint(pya.DPoint(ru_dbu * math.cos(i * da), ru_dbu * math.sin(i * da))))
|
||||
pts = [ pya.DPoint(self.ru * math.cos(i * da), self.ru * math.sin(i * da)) for i in range(0, self.n) ]
|
||||
|
||||
# create the shape
|
||||
self.cell.shapes(self.l_layer).insert(pya.Polygon(pts))
|
||||
self.cell.shapes(self.l_layer).insert(pya.DPolygon(pts))
|
||||
|
||||
|
||||
class MyLib(pya.Library):
|
||||
|
|
|
|||
|
|
@ -2777,8 +2777,7 @@ LayoutViewBase::get_screenshot ()
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Save screenshot")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
return mp_canvas->screenshot ().to_image_copy ();
|
||||
}
|
||||
|
|
@ -2789,8 +2788,7 @@ LayoutViewBase::get_screenshot_pb ()
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Save screenshot")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
return mp_canvas->screenshot ();
|
||||
}
|
||||
|
|
@ -2828,9 +2826,8 @@ LayoutViewBase::save_screenshot (const std::string &fn)
|
|||
writer.setText (tl::to_qstring (i->first), tl::to_qstring (i->second));
|
||||
}
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
refresh ();
|
||||
|
||||
if (! writer.write (mp_canvas->screenshot ().to_image ())) {
|
||||
throw tl::Exception (tl::to_string (tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
|
||||
}
|
||||
|
|
@ -2843,8 +2840,7 @@ LayoutViewBase::save_screenshot (const std::string &fn)
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Save screenshot")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
tl::OutputStream stream (fn);
|
||||
tl::PixelBuffer img = mp_canvas->screenshot ();
|
||||
|
|
@ -2867,9 +2863,8 @@ LayoutViewBase::get_image (unsigned int width, unsigned int height)
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Get image")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
refresh ();
|
||||
|
||||
return mp_canvas->image (width, height).to_image_copy ();
|
||||
}
|
||||
#endif
|
||||
|
|
@ -2879,8 +2874,7 @@ LayoutViewBase::get_pixels (unsigned int width, unsigned int height)
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Get image")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
return mp_canvas->image (width, height);
|
||||
}
|
||||
|
|
@ -2892,9 +2886,8 @@ LayoutViewBase::get_image_with_options (unsigned int width, unsigned int height,
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Get image")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
refresh ();
|
||||
|
||||
if (monochrome) {
|
||||
return mp_canvas->image_with_options_mono (width, height, linewidth, background, foreground, active, target_box).to_image_copy ();
|
||||
} else {
|
||||
|
|
@ -2909,8 +2902,7 @@ LayoutViewBase::get_pixels_with_options (unsigned int width, unsigned int height
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Get image")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
return mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box);
|
||||
}
|
||||
|
|
@ -2921,8 +2913,7 @@ LayoutViewBase::get_pixels_with_options_mono (unsigned int width, unsigned int h
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Get image")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
return mp_canvas->image_with_options_mono (width, height, linewidth, background, foreground, active, target_box);
|
||||
}
|
||||
|
|
@ -2941,9 +2932,8 @@ LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned
|
|||
writer.setText (tl::to_qstring (i->first), tl::to_qstring (i->second));
|
||||
}
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
refresh ();
|
||||
|
||||
if (! writer.write (mp_canvas->image (width, height).to_image ())) {
|
||||
throw tl::Exception (tl::to_string (tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
|
||||
}
|
||||
|
|
@ -2958,8 +2948,7 @@ LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned
|
|||
|
||||
lay::Viewport vp (width, height, mp_canvas->viewport ().target_box ());
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
tl::OutputStream stream (fn);
|
||||
tl::PixelBuffer img = mp_canvas->image (width, height);
|
||||
|
|
@ -2993,8 +2982,7 @@ LayoutViewBase::save_image_with_options (const std::string &fn,
|
|||
writer.setText (tl::to_qstring (i->first), tl::to_qstring (i->second));
|
||||
}
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
if (monochrome) {
|
||||
if (! writer.write (mp_canvas->image_with_options_mono (width, height, linewidth, background, foreground, active, target_box).to_image ())) {
|
||||
|
|
@ -3019,8 +3007,7 @@ LayoutViewBase::save_image_with_options (const std::string &fn,
|
|||
lay::Viewport vp (width, height, mp_canvas->viewport ().target_box ());
|
||||
std::vector<std::pair<std::string, std::string> > texts = png_texts (this, vp.box ());
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
refresh ();
|
||||
|
||||
tl::OutputStream stream (fn);
|
||||
if (monochrome) {
|
||||
|
|
@ -3698,6 +3685,16 @@ LayoutViewBase::timer ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::refresh ()
|
||||
{
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
// Issue a "tick" to execute all other pending tasks
|
||||
timer ();
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::force_update_content ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2917,6 +2917,8 @@ private:
|
|||
void init_layer_properties (LayerProperties &props, const LayerPropertiesList &lp_list) const;
|
||||
void merge_dither_pattern (lay::LayerPropertiesList &props);
|
||||
|
||||
void refresh ();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Constructor for calling from a LayoutView
|
||||
|
|
|
|||
|
|
@ -1095,7 +1095,7 @@ UserPropertiesForm::UserPropertiesForm (QWidget *parent)
|
|||
input.open (QIODevice::ReadOnly);
|
||||
mp_hl_basic_attributes.reset (new GenericSyntaxHighlighterAttributes ());
|
||||
mp_hl_attributes.reset (new GenericSyntaxHighlighterAttributes (mp_hl_basic_attributes.get ()));
|
||||
lay::GenericSyntaxHighlighter *hl = new GenericSyntaxHighlighter (mp_ui->text_edit, input, mp_hl_attributes.get ());
|
||||
lay::GenericSyntaxHighlighter *hl = new GenericSyntaxHighlighter (mp_ui->text_edit, input, mp_hl_attributes.get (), true);
|
||||
input.close ();
|
||||
|
||||
hl->setDocument (mp_ui->text_edit->document ());
|
||||
|
|
|
|||
|
|
@ -975,6 +975,12 @@ GenericSyntaxHighlighterAttributes::assign (const GenericSyntaxHighlighterAttrib
|
|||
m_ids = other.m_ids;
|
||||
}
|
||||
|
||||
bool
|
||||
GenericSyntaxHighlighterAttributes::has_attribute (const QString &name) const
|
||||
{
|
||||
return m_ids.find (name) != m_ids.end ();
|
||||
}
|
||||
|
||||
int
|
||||
GenericSyntaxHighlighterAttributes::id (const QString &name)
|
||||
{
|
||||
|
|
@ -1467,9 +1473,15 @@ parse_context (QDomElement e, const std::map<QString, QDomElement> &contexts_by_
|
|||
}
|
||||
|
||||
static void
|
||||
parse_item_data (QDomElement e, GenericSyntaxHighlighterAttributes &attributes)
|
||||
parse_item_data (QDomElement e, GenericSyntaxHighlighterAttributes &attributes, bool initialize)
|
||||
{
|
||||
QString name = e.attributeNode (QString::fromUtf8 ("name")).value ();
|
||||
|
||||
// skip attribute if already present so we don't overwrite specific settings
|
||||
if (! initialize && attributes.has_attribute (name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int attribute_id = attributes.id (name);
|
||||
|
||||
def_style ds = dsNormal;
|
||||
|
|
@ -1532,7 +1544,7 @@ parse_item_data (QDomElement e, GenericSyntaxHighlighterAttributes &attributes)
|
|||
attributes.set_styles (attribute_id, ds, format);
|
||||
}
|
||||
|
||||
GenericSyntaxHighlighter::GenericSyntaxHighlighter (QObject *parent, QIODevice &input, GenericSyntaxHighlighterAttributes *attributes)
|
||||
GenericSyntaxHighlighter::GenericSyntaxHighlighter (QObject *parent, QIODevice &input, GenericSyntaxHighlighterAttributes *attributes, bool initialize_attributes)
|
||||
: QSyntaxHighlighter (parent), mp_attributes (attributes), m_generation_id (0)
|
||||
{
|
||||
QDomDocument d;
|
||||
|
|
@ -1593,7 +1605,7 @@ GenericSyntaxHighlighter::GenericSyntaxHighlighter (QObject *parent, QIODevice &
|
|||
if (nn.isElement()) {
|
||||
QDomElement ee = nn.toElement ();
|
||||
if (ee.tagName () == QString::fromUtf8 ("itemData")) {
|
||||
parse_item_data (ee, *mp_attributes);
|
||||
parse_item_data (ee, *mp_attributes, initialize_attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -607,6 +607,11 @@ public:
|
|||
return m_ids.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the given name is present already
|
||||
*/
|
||||
bool has_attribute (const QString &name) const;
|
||||
|
||||
/**
|
||||
* @brief Get the attribute ID for a given name
|
||||
*
|
||||
|
|
@ -716,7 +721,14 @@ class LAYUI_PUBLIC GenericSyntaxHighlighter
|
|||
: public QSyntaxHighlighter
|
||||
{
|
||||
public:
|
||||
GenericSyntaxHighlighter (QObject *parent, QIODevice &input, GenericSyntaxHighlighterAttributes *attributes);
|
||||
/**
|
||||
* @brief Creates a GenericSyntaxHighlighter
|
||||
* @param parent The owner of the highlighter
|
||||
* @param input The stream from which to pull
|
||||
* @param attributes The attributes
|
||||
* @param initialize_attributes If true, the attributes are initialized from the itemData lines
|
||||
*/
|
||||
GenericSyntaxHighlighter (QObject *parent, QIODevice &input, GenericSyntaxHighlighterAttributes *attributes, bool initialize_attributes);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the highlighter
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ CIFReader::get_char ()
|
|||
error ("Unexpected end of file");
|
||||
return 0;
|
||||
} else {
|
||||
m_progress.set (m_stream.line_number ());
|
||||
return m_stream.get_char ();
|
||||
}
|
||||
}
|
||||
|
|
@ -823,6 +824,8 @@ void
|
|||
CIFReader::do_read (db::Layout &layout)
|
||||
{
|
||||
try {
|
||||
|
||||
db::LayoutLocker locker (&layout);
|
||||
|
||||
double sf = 0.01 / m_dbu;
|
||||
layout.dbu (m_dbu);
|
||||
|
|
|
|||
|
|
@ -1150,6 +1150,22 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale)
|
|||
}
|
||||
}
|
||||
|
||||
// issue #1470
|
||||
static std::string fix_pin_name (const std::string &pin_name)
|
||||
{
|
||||
auto pos = pin_name.find (".extra");
|
||||
if (pos == std::string::npos) {
|
||||
return pin_name;
|
||||
} else {
|
||||
// TODO: do we need to be more specific?
|
||||
// Formally, the allowed specs are:
|
||||
// pinname.extraN
|
||||
// pinname.extraN[n]
|
||||
// pinname.extraN[n][m]...
|
||||
return std::string (pin_name.begin (), pin_name.begin () + pos);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
|
||||
{
|
||||
|
|
@ -1282,7 +1298,7 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale)
|
|||
if (flush || ! peek ("+")) {
|
||||
|
||||
// TODO: put a label on every single object?
|
||||
std::string label = pin_name;
|
||||
std::string label = fix_pin_name (pin_name);
|
||||
/* don't add the direction currently, a name is sufficient
|
||||
if (! dir.empty ()) {
|
||||
label += ":";
|
||||
|
|
|
|||
|
|
@ -968,7 +968,7 @@ LEFImporter::read_macro (Layout &layout)
|
|||
foreign_name = cn;
|
||||
|
||||
if (foreign_name != mn) {
|
||||
warn (tl::to_string (tr ("FOREIGN name differs from MACRO name in macro: ")) + mn);
|
||||
warn (tl::to_string (tl::sprintf (tl::to_string (tr ("FOREIGN name %s differs from MACRO %s")), foreign_name, mn)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ TEST(def2)
|
|||
{
|
||||
db::LEFDEFReaderOptions options = default_options ();
|
||||
options.set_cell_outline_layer ("OUTLINE (10/0)");
|
||||
run_test (_this, "def2", "lef:0.lef+lef:1.lef+def:in.def.gz", "au_2.oas.gz", options);
|
||||
run_test (_this, "def2", "lef:0.lef+lef:1.lef+def:in.def.gz", "au_3.oas.gz", options);
|
||||
}
|
||||
|
||||
TEST(def3)
|
||||
|
|
@ -429,7 +429,7 @@ TEST(def16)
|
|||
// (complete example)
|
||||
db::LEFDEFReaderOptions opt = default_options ();
|
||||
opt.set_macro_resolution_mode (1);
|
||||
run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au_2.oas.gz", opt);
|
||||
run_test (_this, "def16", "lef:a.lef+lef:tech.lef+def:a.def", "au_3.oas.gz", opt);
|
||||
}
|
||||
|
||||
TEST(100)
|
||||
|
|
|
|||
|
|
@ -163,6 +163,12 @@ def nh(h):
|
|||
|
||||
class DBPCellTests(unittest.TestCase):
|
||||
|
||||
def test_0(self):
|
||||
|
||||
# PCellDeclarationHelper is inside "pya.__all__"
|
||||
if hasattr(pya, "__all__"):
|
||||
self.assertEqual("PCellDeclarationHelper" in pya.__all__, True)
|
||||
|
||||
def test_1(self):
|
||||
|
||||
# instantiate and register the library
|
||||
|
|
|
|||
Loading…
Reference in New Issue