Merge pull request #78 from Kazzz-S/macos-build

Macos build
This commit is contained in:
Matthias Köfferlein 2018-02-24 17:53:11 +01:00 committed by GitHub
commit 78dcace2ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 2265 additions and 1415 deletions

View File

@ -343,7 +343,6 @@ Object::class_name () const
void void
Object::from_string (const char *s) Object::from_string (const char *s)
{ {
printf("@@@ %s\n", s); fflush(stdout);
tl::Extractor ex (s); tl::Extractor ex (s);
while (! ex.at_end ()) { while (! ex.at_end ()) {

View File

@ -1035,7 +1035,7 @@ public:
value_type operator* () const value_type operator* () const
{ {
return value_type (*(dynamic_cast<const ant::Object *> (m_iter->first->ptr ())), m_services[m_service]->view ()); return value_type (*(static_cast<const ant::Object *> (m_iter->first->ptr ())), m_services[m_service]->view ());
} }
private: private:

View File

@ -183,6 +183,13 @@ to create the \\LayerInfo object, i.e. like this:
The default implementation does nothing. All parameters not set in this method will receive their default value. The default implementation does nothing. All parameters not set in this method will receive their default value.
If you use a parameter called "layer" for example, the parameter getter will hide the
"layer" argument. Use "_layer" for the argument in this case (same for "layout", "shape" or "cell):
@code
set_layer layout.get_info(_layer)
@/code
@method transformation_from_shape_impl @method transformation_from_shape_impl
@brief Gets the initial PCell instance transformation when creating from a shape @brief Gets the initial PCell instance transformation when creating from a shape
@ -231,6 +238,13 @@ module RBA
# provide accessors for the current layout and cell (for prod) # provide accessors for the current layout and cell (for prod)
attr_reader :layout, :cell, :shape, :layer attr_reader :layout, :cell, :shape, :layer
# provide fallback accessors in case of a name clash with a
# parameter
def _layer; @layer; end
def _layout; @layout; end
def _cell; @cell; end
def _shape; @shape; end
# define a parameter # define a parameter
# name -&gt; the short name of the parameter # name -&gt; the short name of the parameter
# type -&gt; the type of the parameter # type -&gt; the type of the parameter
@ -246,6 +260,12 @@ module RBA
# set_{name} -&gt; write accessor ({name}= does not work because the # set_{name} -&gt; write accessor ({name}= does not work because the
# Ruby confuses that method with variables) # Ruby confuses that method with variables)
# {name}_layer -&gt; read accessor for the layer index for TypeLayer parameters # {name}_layer -&gt; read accessor for the layer index for TypeLayer parameters
# in addition, fallback accessors are defined which can be used if
# the parameter's name clashes with another name:
# param_{name}
# set_param_{name}
# param_{name}_layer
def param(name, type, description, args = {}) def param(name, type, description, args = {})
# create accessor methods for the parameters # create accessor methods for the parameters

View File

@ -26,7 +26,7 @@ class MyPCell(pya.PCellDeclarationHelper):
def __init__(self): def __init__(self):
# Important: initialize the super class # Important: initialize the super class
super(Circle, self).__init__() super(MyPCell, self).__init__()
# your initialization: add parameters with name, type, description and # your initialization: add parameters with name, type, description and
# optional other values # optional other values
@ -226,16 +226,27 @@ class _PCellDeclarationHelperLayerDescriptor(object):
class _PCellDeclarationHelperParameterDescriptor(object): class _PCellDeclarationHelperParameterDescriptor(object):
""" """
A descriptor object which translates the PCell parameters into class attributes A descriptor object which translates the PCell parameters into class attributes
In some cases (i.e. can_convert_from_shape), these placeholders are not
connected to real parameters (obj._param_values is None). In this case,
the descriptor acts as a value holder (self.value)
""" """
def __init__(self, param_index): def __init__(self, param_index):
self.param_index = param_index self.param_index = param_index
self.value = None
def __get__(self, obj, type = None): def __get__(self, obj, type = None):
return obj._param_values[self.param_index] if obj._param_values:
return obj._param_values[self.param_index]
else:
return self.value
def __set__(self, obj, value): def __set__(self, obj, value):
obj._param_values[self.param_index] = value if obj._param_values:
obj._param_values[self.param_index] = value
else:
self.value = value
class _PCellDeclarationHelper(pya.PCellDeclaration): class _PCellDeclarationHelper(pya.PCellDeclaration):
""" """
@ -322,6 +333,37 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
""" """
return self._param_decls return self._param_decls
def get_values(self):
"""
gets the temporary parameter values
"""
v = self._param_values
self._param_values = None
return v
def init_values(self, values = None, layers = None):
"""
initializes the temporary parameter values
"values" are the original values. If "None" is given, the
default values will be used.
"layers" are the layer indexes corresponding to the layer
parameters.
"""
if not values:
self._param_values = []
for pd in self._param_decls:
self._param_values.append(pd.default)
else:
self._param_values = values
self._layers = layers
def finish(self):
"""
Needs to be called at the end of produce() after init_values was used
"""
self._param_values = None
self._layers = None
def get_layers(self, parameters): def get_layers(self, parameters):
""" """
get the layer definitions get the layer definitions
@ -335,25 +377,23 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
""" """
coerce parameters (make consistent) coerce parameters (make consistent)
""" """
self._param_values = parameters self.init_values(parameters)
self.layout = layout self.layout = layout
self.coerce_parameters_impl() self.coerce_parameters_impl()
self.layout = None self.layout = None
return self._param_values return self.get_values()
def produce(self, layout, layers, parameters, cell): def produce(self, layout, layers, parameters, cell):
""" """
coerce parameters (make consistent) coerce parameters (make consistent)
""" """
self._layers = layers self.init_values(parameters, layers)
self.cell = cell self.cell = cell
self._param_values = parameters
self.layout = layout self.layout = layout
self.produce_impl() self.produce_impl()
self._layers = None
self.cell = None self.cell = None
self._param_values = None
self.layout = None self.layout = None
self.finish()
def can_create_from_shape(self, layout, shape, layer): def can_create_from_shape(self, layout, shape, layer):
""" """
@ -386,17 +426,16 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
produce a helper for parameters_from_shape produce a helper for parameters_from_shape
with this helper, the implementation can use the parameter setters with this helper, the implementation can use the parameter setters
""" """
self._param_values = [] self.init_values()
for pd in self._param_decls:
self._param_values.append(pd.default)
self.layout = layout self.layout = layout
self.shape = shape self.shape = shape
self.layer = layer self.layer = layer
self.parameters_from_shape_impl() self.parameters_from_shape_impl()
param = self.get_values()
self.layout = None self.layout = None
self.shape = None self.shape = None
self.layer = None self.layer = None
return self._param_values return param
def display_text_impl(self): def display_text_impl(self):
""" """
@ -432,7 +471,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
""" """
default implementation default implementation
""" """
return pya.Trans.new return pya.Trans()
# import the Type... constants from PCellParameterDeclaration # import the Type... constants from PCellParameterDeclaration
for k in dir(pya.PCellParameterDeclaration): for k in dir(pya.PCellParameterDeclaration):

View File

@ -1014,6 +1014,19 @@ EdgeProcessor::clear ()
mp_cpvector->clear (); mp_cpvector->clear ();
} }
static void
add_hparallel_cutpoints (WorkEdge &e1, WorkEdge &e2, std::vector <CutPoints> &cutpoints)
{
db::Coord e1_xmin = std::min (e1.x1 (), e1.x2 ());
db::Coord e1_xmax = std::max (e1.x1 (), e1.x2 ());
if (e2.x1 () > e1_xmin && e2.x1 () < e1_xmax) {
e1.make_cutpoints (cutpoints)->add (e2.p1 (), &cutpoints, false);
}
if (e2.x2 () > e1_xmin && e2.x2 () < e1_xmax) {
e1.make_cutpoints (cutpoints)->add (e2.p2 (), &cutpoints, false);
}
}
static void static void
get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <WorkEdge>::iterator current, std::vector <WorkEdge>::iterator future, db::Coord y, db::Coord yy, bool with_h) get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <WorkEdge>::iterator current, std::vector <WorkEdge>::iterator future, db::Coord y, db::Coord yy, bool with_h)
{ {
@ -1066,22 +1079,34 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
if (c2->dy () == 0) { if (c2->dy () == 0) {
if ((with_h || c1->dy () != 0) && c1 < c2 && c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () && if ((with_h || c1->dy () != 0) && c1 < c2) {
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
std::pair <bool, db::Point> cp = c1->intersect_point (*c2); if (c1->dy () == 0) {
if (cp.first) {
// add a cut point to c1 and c2 (c2 only if necessary) // parallel horizontal edges: produce the end points of each other edge as cutpoints
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true); if (c1->p1 ().y () == c2->p1 ().y ()) {
if (with_h) { add_hparallel_cutpoints (*c1, *c2, cutpoints);
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true); add_hparallel_cutpoints (*c2, *c1, cutpoints);
} }
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
std::pair <bool, db::Point> cp = c1->intersect_point (*c2);
if (cp.first) {
// add a cut point to c1 and c2 (c2 only if necessary)
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
if (with_h) {
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
}
#ifdef DEBUG_EDGE_PROCESSOR #ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s between %s and %s (1).\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ()); printf ("intersection point %s between %s and %s (1).\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
#endif #endif
}
} }
} }
@ -1287,51 +1312,67 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
if (c2->dy () == 0) { if (c2->dy () == 0) {
if ((with_h || c1->dy () != 0) && c1 < c2 && c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () && if ((with_h || c1->dy () != 0) && c1 < c2) {
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2); if (c1->dy () == 0) {
if (cp.first) {
bool on_edge1 = is_point_on_exact (*c1, cp.second); // parallel horizontal edges: produce the end points of each other edge as cutpoints
if (c1->p1 ().y () == c2->p1 ().y ()) {
// add a cut point to c1 and c2 (points not on the edge give strong attractors) add_hparallel_cutpoints (*c1, *c2, cutpoints);
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge1); add_hparallel_cutpoints (*c2, *c1, cutpoints);
if (with_h) {
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, false);
} }
#ifdef DEBUG_EDGE_PROCESSOR } else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
if (on_edge1) { c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
printf ("weak intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
} else {
printf ("intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
}
#endif
// The new cutpoint must be inserted into other edges as well. std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
// If the cutpoint is exactly on the edge and there is just one other edge if (cp.first) {
// the cutpoint will be a weak attractor - that is an optional cutpoint.
// In that case we can skip the cutpoint because no related edge will move. bool on_edge1 = is_point_on_exact (*c1, cp.second);
ip_weak.clear ();
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) { // add a cut point to c1 and c2 (points not on the edge give strong attractors)
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) { c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge1);
ip_weak.push_back (&*cc); if (with_h) {
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, false);
} }
}
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
if (ip_weak.size () > 1 || !on_edge1) {
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
#ifdef DEBUG_EDGE_PROCESSOR #ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ()); if (on_edge1) {
#endif printf ("weak intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
} else { } else {
CutPoints *cpp = (*icc)->make_cutpoints (cutpoints); printf ("intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
cpp->add_attractor (cp.second, (*icc)->data - 1);
#ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives weak attractor in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
#endif
} }
#endif
// The new cutpoint must be inserted into other edges as well.
// If the cutpoint is exactly on the edge and there is just one other edge
// the cutpoint will be a weak attractor - that is an optional cutpoint.
// In that case we can skip the cutpoint because no related edge will move.
ip_weak.clear ();
size_t n_off_edge = on_edge1 ? 0 : 1;
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
ip_weak.push_back (&*cc);
if (!is_point_on_exact (*cc, cp.second)) {
++n_off_edge;
}
}
}
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
if (n_off_edge > 1) {
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
#ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
#endif
} else {
CutPoints *cpp = (*icc)->make_cutpoints (cutpoints);
cpp->add_attractor (cp.second, (*icc)->data - 1);
#ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives weak attractor in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
#endif
}
}
} }
} }
@ -1398,13 +1439,23 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
// the cutpoint will be a weak attractor - that is an optional cutpoint. // the cutpoint will be a weak attractor - that is an optional cutpoint.
// In that case we can skip the cutpoint because no related edge will move. // In that case we can skip the cutpoint because no related edge will move.
ip_weak.clear (); ip_weak.clear ();
size_t n_off_edge = 0;
if (!on_edge1) {
n_off_edge += 1;
}
if (!on_edge2) {
n_off_edge += 1;
}
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) { for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) { if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
ip_weak.push_back (&*cc); ip_weak.push_back (&*cc);
if (!is_point_on_exact (*cc, cp.second)) {
++n_off_edge;
}
} }
} }
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) { for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
if (ip_weak.size () > 1 || !on_edge1 || !on_edge2) { if (n_off_edge > 1) {
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true); (*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
#ifdef DEBUG_EDGE_PROCESSOR #ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ()); printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());

View File

@ -255,6 +255,7 @@ public:
* *
* If this flag is set, the interaction will include "touching" interactions in mode 0, i.e. * If this flag is set, the interaction will include "touching" interactions in mode 0, i.e.
* touching shapes will be counted as interacting. * touching shapes will be counted as interacting.
* In the other modes, this flag should be true (the default).
*/ */
void set_include_touching (bool f) void set_include_touching (bool f)
{ {
@ -299,7 +300,7 @@ public:
virtual int edge (bool north, bool enter, property_type p); virtual int edge (bool north, bool enter, property_type p);
virtual int compare_ns () const; virtual int compare_ns () const;
virtual bool is_reset () const { return m_inside.empty (); } virtual bool is_reset () const { return m_inside.empty (); }
virtual bool prefer_touch () const { return m_mode == 0 && m_include_touching; } virtual bool prefer_touch () const { return m_include_touching; }
private: private:
int m_mode; int m_mode;

View File

@ -1884,6 +1884,26 @@ Layout::is_pcell_instance (cell_index_type cell_index) const
} }
} }
const Layout::pcell_declaration_type *
Layout::pcell_declaration_for_pcell_variant (cell_index_type variant_cell_index) const
{
const Cell *variant_cell = &cell (variant_cell_index);
const LibraryProxy *lib_proxy = dynamic_cast<const LibraryProxy *> (variant_cell);
if (lib_proxy) {
Library *lib = LibraryManager::instance ().lib (lib_proxy->lib_id ());
tl_assert (lib != 0);
return lib->layout ().pcell_declaration_for_pcell_variant (lib_proxy->library_cell_index ());
}
const PCellVariant *pcell_variant = dynamic_cast<const PCellVariant *> (variant_cell);
if (pcell_variant) {
return pcell_declaration (pcell_variant->pcell_id ());
} else {
return 0;
}
}
std::pair<db::Library *, db::cell_index_type> std::pair<db::Library *, db::cell_index_type>
Layout::defining_library (cell_index_type cell_index) const Layout::defining_library (cell_index_type cell_index) const
{ {

View File

@ -881,11 +881,22 @@ public:
*/ */
std::pair<db::Library *, db::cell_index_type> defining_library (cell_index_type cell_index) const; std::pair<db::Library *, db::cell_index_type> defining_library (cell_index_type cell_index) const;
/**
* @brief Gets the PCell declaration object for a PCell instance
*
* This method determines the PCell declaration object for a given PCell variant cell.
* Note, that the declaration may originate from a different layout than this, if the PCell
* is imported from a library.
*
* The cell given cell is not a PCell variant cell, 0 is returned.
*/
const Layout::pcell_declaration_type *pcell_declaration_for_pcell_variant (cell_index_type cell_index) const;
/** /**
* @brief Get the PCell parameters of a PCell instance * @brief Get the PCell parameters of a PCell instance
* *
* For the order of the parameters, ask the PCell declaration (available trough Layout::pcell_declaration * For the order of the parameters, ask the PCell declaration (available trough Layout::pcell_declaration
* from the PCell id). * from the PCell id or from Layout::pcell_declaration_for_pcell_variant from the cell_index).
* *
* @return A list of parameters in the order they are declared. * @return A list of parameters in the order they are declared.
*/ */

View File

@ -396,6 +396,12 @@ Repetition::set_base (RepetitionBase *base)
mp_base = base; mp_base = base;
} }
size_t
Repetition::size () const
{
return mp_base ? mp_base->size () : 1;
}
bool bool
Repetition::is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const Repetition::is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const
{ {

View File

@ -171,6 +171,11 @@ public:
return !operator== (d); return !operator== (d);
} }
/**
* @brief Gets the number of elements in this repetition
*/
size_t size () const;
/** /**
* @brief Check, if the repetition is an repetition at all * @brief Check, if the repetition is an repetition at all
* *
@ -183,7 +188,7 @@ public:
} }
/** /**
* @brief Check, if the repetition is a regular one * @brief Checks, if the repetition is a regular one
* *
* This method returns true, if the repetition is regular. It * This method returns true, if the repetition is regular. It
* returns true, if the repetition can be represented as a * returns true, if the repetition can be represented as a
@ -251,6 +256,7 @@ public:
virtual bool equals (const RepetitionBase *) const = 0; virtual bool equals (const RepetitionBase *) const = 0;
virtual bool less (const RepetitionBase *) const = 0; virtual bool less (const RepetitionBase *) const = 0;
virtual bool is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const = 0; virtual bool is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const = 0;
virtual size_t size () const = 0;
virtual const std::vector<db::Vector> *is_iterated () const = 0; virtual const std::vector<db::Vector> *is_iterated () const = 0;
virtual unsigned int type () = 0; virtual unsigned int type () = 0;
}; };
@ -294,6 +300,7 @@ public:
virtual bool is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const; virtual bool is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const;
virtual const std::vector<db::Vector> *is_iterated () const; virtual const std::vector<db::Vector> *is_iterated () const;
virtual unsigned int type () { return 1; } virtual unsigned int type () { return 1; }
virtual size_t size () const { return m_n * m_m; }
private: private:
friend class RegularRepetitionIterator; friend class RegularRepetitionIterator;
@ -336,6 +343,7 @@ public:
virtual bool is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const; virtual bool is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const;
virtual const std::vector<db::Vector> *is_iterated () const; virtual const std::vector<db::Vector> *is_iterated () const;
virtual unsigned int type () { return 2; } virtual unsigned int type () { return 2; }
virtual size_t size () const { return m_points.size () + 1; }
void reserve (size_t n) void reserve (size_t n)
{ {

View File

@ -110,6 +110,18 @@ OASISReader::OASISReader (tl::InputStream &s)
{ {
m_progress.set_format (tl::to_string (QObject::tr ("%.0f MB"))); m_progress.set_format (tl::to_string (QObject::tr ("%.0f MB")));
m_progress.set_unit (1024 * 1024); m_progress.set_unit (1024 * 1024);
m_first_cellname = 0;
m_first_propname = 0;
m_first_propstring = 0;
m_first_textstring = 0;
m_first_layername = 0;
m_in_table = NotInTable;
m_table_cellname = 0;
m_table_propname = 0;
m_table_propstring = 0;
m_table_textstring = 0;
m_table_layername = 0;
m_table_start = 0;
} }
OASISReader::~OASISReader () OASISReader::~OASISReader ()
@ -197,6 +209,16 @@ OASISReader::get_long ()
} }
} }
inline unsigned long
OASISReader::get_ulong_for_divider ()
{
unsigned long l = get_ulong ();
if (l == 0) {
error (tl::to_string (QObject::tr ("Divider must not be zero")));
}
return l;
}
inline unsigned long inline unsigned long
OASISReader::get_ulong () OASISReader::get_ulong ()
{ {
@ -295,21 +317,21 @@ OASISReader::get_real ()
} else if (t == 2) { } else if (t == 2) {
return 1.0 / double (get_ulong ()); return 1.0 / double (get_ulong_for_divider ());
} else if (t == 3) { } else if (t == 3) {
return -1.0 / double (get_ulong ()); return -1.0 / double (get_ulong_for_divider ());
} else if (t == 4) { } else if (t == 4) {
double d = double (get_ulong ()); double d = double (get_ulong ());
return d / double (get_ulong ()); return d / double (get_ulong_for_divider ());
} else if (t == 5) { } else if (t == 5) {
double d = double (get_ulong ()); double d = double (get_ulong ());
return -d / double (get_ulong ()); return -d / double (get_ulong_for_divider ());
} else if (t == 6) { } else if (t == 6) {
@ -1702,7 +1724,7 @@ OASISReader::read_pointlist (modal_variable <std::vector <db::Point> > &pointlis
pointlist.set_initialized (); pointlist.set_initialized ();
} }
void bool
OASISReader::read_repetition () OASISReader::read_repetition ()
{ {
unsigned char type = get_uint (); unsigned char type = get_uint ();
@ -1834,6 +1856,7 @@ OASISReader::read_repetition ()
error (tl::sprintf (tl::to_string (QObject::tr ("Invalid repetition type %d")), type)); error (tl::sprintf (tl::to_string (QObject::tr ("Invalid repetition type %d")), type));
} }
return mm_repetition.get ().size () > 1;
} }
void void
@ -1980,9 +2003,7 @@ OASISReader::do_read_placement (unsigned char r,
db::Vector pos (mm_placement_x.get (), mm_placement_y.get ()); db::Vector pos (mm_placement_x.get (), mm_placement_y.get ());
if (m & 0x8) { if ((m & 0x8) && read_repetition ()) {
read_repetition ();
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -2135,9 +2156,7 @@ OASISReader::do_read_text (bool xy_absolute,
ll = open_dl (layout, LDPair (mm_textlayer.get (), mm_texttype.get ()), m_create_layers); ll = open_dl (layout, LDPair (mm_textlayer.get (), mm_texttype.get ()), m_create_layers);
} }
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition ();
// TODO: should not read properties if layer is not enabled! // TODO: should not read properties if layer is not enabled!
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -2278,9 +2297,7 @@ OASISReader::do_read_rectangle (bool xy_absolute,
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition ();
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -2394,9 +2411,7 @@ OASISReader::do_read_polygon (bool xy_absolute, db::cell_index_type cell_index,
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition ();
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -2563,9 +2578,7 @@ OASISReader::do_read_path (bool xy_absolute, db::cell_index_type cell_index, db:
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers); std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()), m_create_layers);
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition ();
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -2740,9 +2753,7 @@ OASISReader::do_read_trapezoid (unsigned char r, bool xy_absolute,db::cell_index
pts [3] = db::Point (-std::min (delta_a, db::Coord (0)), db::Coord (0)); pts [3] = db::Point (-std::min (delta_a, db::Coord (0)), db::Coord (0));
} }
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition ();
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -3102,9 +3113,7 @@ OASISReader::do_read_ctrapezoid (bool xy_absolute,db::cell_index_type cell_index
--npts; --npts;
} }
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition ();
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -3239,9 +3248,7 @@ OASISReader::do_read_circle (bool xy_absolute, db::cell_index_type cell_index, d
ll.first = false; ll.first = false;
} }
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition ();
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false); std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
@ -3506,8 +3513,8 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout)
} }
} }
if (m & 0x4) { if ((m & 0x4) && read_repetition ()) {
read_repetition (); // later: handle XGEOMETRY with repetition
} }
read_element_properties (layout.properties_repository (), true); read_element_properties (layout.properties_repository (), true);

View File

@ -297,7 +297,7 @@ private:
void mark_start_table (); void mark_start_table ();
void read_offset_table (); void read_offset_table ();
void read_repetition (); bool read_repetition ();
void read_pointlist (modal_variable <std::vector <db::Point> > &pointlist, bool for_polygon); void read_pointlist (modal_variable <std::vector <db::Point> > &pointlist, bool for_polygon);
void read_properties (db::PropertiesRepository &rep); void read_properties (db::PropertiesRepository &rep);
void store_last_properties (db::PropertiesRepository &rep, db::PropertiesRepository::properties_set &properties, bool ignore_special); void store_last_properties (db::PropertiesRepository &rep, db::PropertiesRepository::properties_set &properties, bool ignore_special);
@ -318,6 +318,7 @@ private:
unsigned long long get_ulong_long (); unsigned long long get_ulong_long ();
long get_long (); long get_long ();
unsigned long get_ulong (); unsigned long get_ulong ();
unsigned long get_ulong_for_divider ();
int get_int (); int get_int ();
unsigned int get_uint (); unsigned int get_uint ();

View File

@ -186,15 +186,28 @@ PCellVariant::update (ImportLayerMapping *layer_mapping)
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (m_parameters[i].to_user<db::DBox> () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props))); shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (m_parameters[i].to_user<db::DBox> () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Box> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(m_parameters[i].to_user<db::Box> (), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DEdge> ()) { } else if (m_parameters[i].is_user<db::DEdge> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::EdgeWithProperties(db::Edge (m_parameters[i].to_user<db::DEdge> () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props))); shapes (layout ()->guiding_shape_layer ()).insert (db::EdgeWithProperties(db::Edge (m_parameters[i].to_user<db::DEdge> () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Edge> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::EdgeWithProperties(m_parameters[i].to_user<db::Edge> (), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DPoint> ()) { } else if (m_parameters[i].is_user<db::DPoint> ()) {
db::DPoint p = m_parameters[i].to_user<db::DPoint> (); db::DPoint p = m_parameters[i].to_user<db::DPoint> ();
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (db::DBox (p, p) * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props))); shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (db::DBox (p, p) * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Point> ()) {
db::Point p = m_parameters[i].to_user<db::Point> ();
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (p, p), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DPolygon> ()) { } else if (m_parameters[i].is_user<db::DPolygon> ()) {
db::complex_trans<db::DCoord, db::Coord> dbu_trans (1.0 / layout ()->dbu ()); db::complex_trans<db::DCoord, db::Coord> dbu_trans (1.0 / layout ()->dbu ());
@ -202,11 +215,21 @@ PCellVariant::update (ImportLayerMapping *layer_mapping)
// Hint: we don't compress the polygon since we don't want to loose information // Hint: we don't compress the polygon since we don't want to loose information
shapes (layout ()->guiding_shape_layer ()).insert (db::PolygonWithProperties(poly, layout ()->properties_repository ().properties_id (props))); shapes (layout ()->guiding_shape_layer ()).insert (db::PolygonWithProperties(poly, layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Polygon> ()) {
db::Polygon poly = m_parameters[i].to_user<db::Polygon> ();
// Hint: we don't compress the polygon since we don't want to loose information
shapes (layout ()->guiding_shape_layer ()).insert (db::PolygonWithProperties(poly, layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DPath> ()) { } else if (m_parameters[i].is_user<db::DPath> ()) {
db::complex_trans<db::DCoord, db::Coord> dbu_trans (1.0 / layout ()->dbu ()); db::complex_trans<db::DCoord, db::Coord> dbu_trans (1.0 / layout ()->dbu ());
shapes (layout ()->guiding_shape_layer ()).insert (db::PathWithProperties(dbu_trans * m_parameters[i].to_user<db::DPath> (), layout ()->properties_repository ().properties_id (props))); shapes (layout ()->guiding_shape_layer ()).insert (db::PathWithProperties(dbu_trans * m_parameters[i].to_user<db::DPath> (), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Path> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::PathWithProperties(m_parameters[i].to_user<db::Path> (), layout ()->properties_repository ().properties_id (props)));
} }
} }

View File

@ -62,7 +62,7 @@ Reader::Reader (tl::InputStream &stream)
} }
if (! mp_actual_reader) { if (! mp_actual_reader) {
throw db::ReaderException (tl::to_string (QObject::tr ("Stream has unknown format"))); throw db::ReaderException (tl::to_string (QObject::tr ("Stream has unknown format: ")) + stream.source ());
} }
} }

View File

@ -276,6 +276,8 @@ RecursiveShapeIterator::init ()
m_shape_inv_prop_sel = false; m_shape_inv_prop_sel = false;
m_inst_quad_id = 0; m_inst_quad_id = 0;
m_shape_quad_id = 0; m_shape_quad_id = 0;
mp_cell = 0;
m_current_layer = 0;
} }
void void

View File

@ -1273,7 +1273,7 @@ public:
*/ */
Region selected_inside (const Region &other) const Region selected_inside (const Region &other) const
{ {
return selected_interacting_generic (other, -1, false, false); return selected_interacting_generic (other, -1, true, false);
} }
/** /**
@ -1285,7 +1285,7 @@ public:
*/ */
Region selected_not_inside (const Region &other) const Region selected_not_inside (const Region &other) const
{ {
return selected_interacting_generic (other, -1, false, true); return selected_interacting_generic (other, -1, true, true);
} }
/** /**

View File

@ -883,8 +883,6 @@ static bool cell_has_prop_id (const db::Cell *c)
static void delete_cell_property (db::Cell *c, const tl::Variant &key) static void delete_cell_property (db::Cell *c, const tl::Variant &key)
{ {
check_is_editable (c);
db::properties_id_type id = c->prop_id (); db::properties_id_type id = c->prop_id ();
if (id == 0) { if (id == 0) {
return; return;
@ -911,8 +909,6 @@ static void delete_cell_property (db::Cell *c, const tl::Variant &key)
static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Variant &value) static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Variant &value)
{ {
check_is_editable (c);
db::properties_id_type id = c->prop_id (); db::properties_id_type id = c->prop_id ();
db::Layout *layout = c->layout (); db::Layout *layout = c->layout ();
@ -1110,13 +1106,11 @@ static void move_or_copy_from_other_cell (db::Cell *cell, db::Cell *src_cell, un
static void move_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer) static void move_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer)
{ {
check_is_editable (cell);
move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, true); move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, true);
} }
static void copy_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer) static void copy_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer)
{ {
check_is_editable (cell);
move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, false); move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, false);
} }
@ -1158,7 +1152,6 @@ write_options (const db::Cell *cell, const std::string &filename, const db::Save
static void static void
clear_all (db::Cell *cell) clear_all (db::Cell *cell)
{ {
check_is_editable (cell);
cell->clear_shapes (); cell->clear_shapes ();
cell->clear_insts (); cell->clear_insts ();
} }
@ -1166,7 +1159,6 @@ clear_all (db::Cell *cell)
static void static void
delete_cell (db::Cell *cell) delete_cell (db::Cell *cell)
{ {
check_is_editable (cell);
db::Layout *layout = cell->layout (); db::Layout *layout = cell->layout ();
if (layout) { if (layout) {
layout->delete_cell (cell->cell_index ()); layout->delete_cell (cell->cell_index ());
@ -1176,7 +1168,6 @@ delete_cell (db::Cell *cell)
static void static void
prune_subcells (db::Cell *cell, int levels) prune_subcells (db::Cell *cell, int levels)
{ {
check_is_editable (cell);
db::Layout *layout = cell->layout (); db::Layout *layout = cell->layout ();
if (layout) { if (layout) {
layout->prune_subcells (cell->cell_index (), levels); layout->prune_subcells (cell->cell_index (), levels);
@ -1192,7 +1183,6 @@ prune_subcells0 (db::Cell *cell)
static void static void
prune_cell (db::Cell *cell, int levels) prune_cell (db::Cell *cell, int levels)
{ {
check_is_editable (cell);
db::Layout *layout = cell->layout (); db::Layout *layout = cell->layout ();
if (layout) { if (layout) {
layout->prune_cell (cell->cell_index (), levels); layout->prune_cell (cell->cell_index (), levels);
@ -1208,7 +1198,6 @@ prune_cell0 (db::Cell *cell)
static void static void
flatten (db::Cell *cell, int levels, bool prune) flatten (db::Cell *cell, int levels, bool prune)
{ {
check_is_editable (cell);
db::Layout *layout = cell->layout (); db::Layout *layout = cell->layout ();
if (layout) { if (layout) {
layout->flatten (*cell, levels, prune); layout->flatten (*cell, levels, prune);
@ -1288,8 +1277,6 @@ begin_shapes_rec_overlapping_um (const db::Cell *cell, unsigned int layer, db::D
static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::LayerMapping &layer_mapping) static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::LayerMapping &layer_mapping)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
} }
@ -1318,8 +1305,6 @@ static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db:
static void copy_shapes1 (db::Cell *cell, const db::Cell &source_cell) static void copy_shapes1 (db::Cell *cell, const db::Cell &source_cell)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
} }
@ -1344,8 +1329,6 @@ static void copy_shapes1 (db::Cell *cell, const db::Cell &source_cell)
static void copy_instances (db::Cell *cell, const db::Cell &source_cell) static void copy_instances (db::Cell *cell, const db::Cell &source_cell)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy instances within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy instances within the same cell")));
} }
@ -1360,8 +1343,6 @@ static void copy_instances (db::Cell *cell, const db::Cell &source_cell)
static std::vector<db::cell_index_type> copy_tree (db::Cell *cell, const db::Cell &source_cell) static std::vector<db::cell_index_type> copy_tree (db::Cell *cell, const db::Cell &source_cell)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
} }
@ -1393,8 +1374,6 @@ static std::vector<db::cell_index_type> copy_tree (db::Cell *cell, const db::Cel
static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm) static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
} }
@ -1421,8 +1400,6 @@ static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, cons
static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm) static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
} }
@ -1446,8 +1423,6 @@ static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, cons
static void move_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::LayerMapping &layer_mapping) static void move_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::LayerMapping &layer_mapping)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
} }
@ -1478,8 +1453,6 @@ static void move_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::Layer
static void move_shapes1 (db::Cell *cell, db::Cell &source_cell) static void move_shapes1 (db::Cell *cell, db::Cell &source_cell)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
} }
@ -1505,8 +1478,6 @@ static void move_shapes1 (db::Cell *cell, db::Cell &source_cell)
static void move_instances (db::Cell *cell, db::Cell &source_cell) static void move_instances (db::Cell *cell, db::Cell &source_cell)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move instances within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot move instances within the same cell")));
} }
@ -1523,8 +1494,6 @@ static void move_instances (db::Cell *cell, db::Cell &source_cell)
static std::vector<db::cell_index_type> move_tree (db::Cell *cell, db::Cell &source_cell) static std::vector<db::cell_index_type> move_tree (db::Cell *cell, db::Cell &source_cell)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
} }
@ -1558,8 +1527,6 @@ static std::vector<db::cell_index_type> move_tree (db::Cell *cell, db::Cell &sou
static void move_tree_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm) static void move_tree_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
} }
@ -1586,8 +1553,6 @@ static void move_tree_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::
static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm) static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm)
{ {
check_is_editable (cell);
if (cell == &source_cell) { if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell"))); throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
} }
@ -1612,8 +1577,6 @@ static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::
static void static void
fill_region1 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin) fill_region1 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin)
{ {
check_is_editable (cell);
if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) { if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)"))); throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)")));
} }
@ -1624,8 +1587,6 @@ static void
fill_region2 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin, fill_region2 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin,
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons)
{ {
check_is_editable (cell);
if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) { if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)"))); throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)")));
} }

View File

@ -2244,3 +2244,54 @@ TEST(100)
db::compare_layouts (_this, lr, au_fn); db::compare_layouts (_this, lr, au_fn);
} }
// #74 (GitHub)
TEST(101)
{
db::EdgeProcessor ep;
{
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 10),
db::Point (10, 10),
db::Point (10, 0)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 0);
}
{
db::Point pts[] = {
db::Point (-1, -1),
db::Point (-1, 8),
db::Point (2, 11),
db::Point (2, -1)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 1);
}
{
db::Point pts[] = {
db::Point (2, -1),
db::Point (2, 11),
db::Point (11, 11),
db::Point (11, -1)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 1);
}
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, true);
db::BooleanOp op (db::BooleanOp::And);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(0,0;0,9;1,10;10,10;10,0)");
}

View File

@ -820,3 +820,58 @@ TEST(22)
EXPECT_EQ ((e & ee).to_string (), "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)"); EXPECT_EQ ((e & ee).to_string (), "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)");
} }
// GitHub issue #72 (Edges/Region NOT issue)
TEST(23)
{
db::Edges e;
e.insert (db::Edge (0, 0, 0, 1000));
e.insert (db::Edge (0, 1000, 3000, 1000));
e.insert (db::Edge (3000, 1000, 3000, 0));
e.insert (db::Edge (3000, 0, 0, 0));
db::Region r;
r.insert (db::Box (1000, -1000, 2000, 0));
r.insert (db::Box (1000, 1000, 2000, 2000));
EXPECT_EQ ((e - r).to_string (), "(0,0;0,1000);(1000,0;0,0);(3000,0;2000,0);(3000,1000;3000,0);(0,1000;1000,1000);(2000,1000;3000,1000)");
r.clear ();
r.insert (db::Box (1000, -1000, 2000, 2000));
EXPECT_EQ ((e - r).to_string (), "(0,0;0,1000);(1000,0;0,0);(3000,0;2000,0);(3000,1000;3000,0);(0,1000;1000,1000);(2000,1000;3000,1000)");
e.clear ();
e.insert (db::Edge (0, 0, 100, 1000));
e.insert (db::Edge (100, 1000, 3100, 1000));
e.insert (db::Edge (3100, 1000, 3000, 0));
e.insert (db::Edge (3000, 0, 0, 0));
r.clear ();
r.insert (db::Box (1000, -1000, 2000, 0));
r.insert (db::Box (1000, 1000, 2000, 2000));
EXPECT_EQ ((e - r).to_string (), "(0,0;100,1000);(1000,0;0,0);(3000,0;2000,0);(3100,1000;3000,0);(100,1000;1000,1000);(2000,1000;3100,1000)");
r.clear ();
r.insert (db::Box (1000, -1000, 2000, 2000));
EXPECT_EQ ((e - r).to_string (), "(0,0;100,1000);(1000,0;0,0);(3000,0;2000,0);(3100,1000;3000,0);(100,1000;1000,1000);(2000,1000;3100,1000)");
e.clear ();
e.insert (db::Edge (0, 0, 1000, 0));
e.insert (db::Edge (1000, 0, 1000, 3000));
e.insert (db::Edge (1000, 3000, 0, 3000));
e.insert (db::Edge (0, 3000, 0, 0));
r.clear ();
r.insert (db::Box (-1000, 1000, 0, 2000));
r.insert (db::Box (1000, 1000, 2000, 2000));
EXPECT_EQ ((e - r).to_string (), "(0,1000;0,0);(0,0;1000,0);(1000,0;1000,1000);(0,3000;0,2000);(1000,2000;1000,3000);(1000,3000;0,3000)");
r.clear ();
r.insert (db::Box (-1000, 1000, 2000, 2000));
EXPECT_EQ ((e - r).to_string (), "(0,1000;0,0);(0,0;1000,0);(1000,0;1000,1000);(0,3000;0,2000);(1000,2000;1000,3000);(1000,3000;0,3000)");
}

View File

@ -58,6 +58,7 @@ struct A : public db::Object
void redo (db::Op *op) throw () void redo (db::Op *op) throw ()
{ {
AO *aop = dynamic_cast<AO *> (op); AO *aop = dynamic_cast<AO *> (op);
tl_assert (aop != 0);
x += aop->d; x += aop->d;
} }
@ -162,6 +163,7 @@ struct B : public db::Object
void redo (db::Op *op) throw () void redo (db::Op *op) throw ()
{ {
BO *bop = dynamic_cast<BO *> (op); BO *bop = dynamic_cast<BO *> (op);
tl_assert (bop != 0);
x += bop->d; x += bop->d;
} }

View File

@ -748,6 +748,107 @@ TEST(18b)
} }
} }
TEST(18c)
{
// GitHub issue #69
db::Region r;
r.insert (db::Box (db::Point (-120, 0), db::Point (-100, 20)));
r.insert (db::Box (db::Point (-20, 0), db::Point (0, 20)));
r.insert (db::Box (db::Point (0, 0), db::Point (20, 20)));
r.insert (db::Box (db::Point (100, 0), db::Point (120, 20)));
db::Region rr;
rr.insert (db::Box (db::Point (-100, -10), db::Point (0, 30)));
rr.insert (db::Box (db::Point (0, -10), db::Point (100, 30)));
EXPECT_EQ (r.selected_outside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_inside (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_overlapping (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(-20,0;-20,20;20,20;20,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_outside (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_not_inside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_overlapping (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
r.clear ();
r.insert (db::Box (db::Point (-120, 0), db::Point (-100, 20)));
r.insert (db::Box (db::Point (-20, 0), db::Point (20, 20)));
r.insert (db::Box (db::Point (100, 0), db::Point (120, 20)));
rr.clear ();
rr.insert (db::Box (db::Point (-100, -10), db::Point (0, 30)));
rr.insert (db::Box (db::Point (0, -10), db::Point (100, 30)));
EXPECT_EQ (r.selected_outside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_inside (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_overlapping (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(-20,0;-20,20;20,20;20,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_outside (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_not_inside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_overlapping (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
r.clear ();
r.insert (db::Box (db::Point (-120, 0), db::Point (-100, 20)));
r.insert (db::Box (db::Point (-20, 0), db::Point (20, 20)));
r.insert (db::Box (db::Point (100, 0), db::Point (120, 20)));
rr.clear ();
rr.insert (db::Box (db::Point (-100, -10), db::Point (100, 30)));
EXPECT_EQ (r.selected_outside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_inside (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_overlapping (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(-20,0;-20,20;20,20;20,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_outside (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_not_inside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_overlapping (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
r.clear ();
r.insert (db::Box (db::Point (-120, 0), db::Point (-100, 20)));
r.insert (db::Box (db::Point (-20, 0), db::Point (20, 20)));
r.insert (db::Box (db::Point (100, 0), db::Point (120, 20)));
rr.clear ();
rr.insert (db::Box (db::Point (-100, -10), db::Point (0, 30)));
rr.insert (db::Box (db::Point (1, -10), db::Point (100, 30)));
EXPECT_EQ (r.selected_outside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_inside (rr).to_string (), "");
EXPECT_EQ (r.selected_overlapping (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(-20,0;-20,20;20,20;20,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_outside (rr).to_string (), "(-20,0;-20,20;20,20;20,0)");
EXPECT_EQ (r.selected_not_inside (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(-20,0;-20,20;20,20;20,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_overlapping (rr).to_string (), "(-120,0;-120,20;-100,20;-100,0);(100,0;100,20;120,20;120,0)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
r.clear ();
r.insert (db::Box (db::Point (-100, 0), db::Point (-80, 20)));
r.insert (db::Box (db::Point (-20, 0), db::Point (0, 20)));
r.insert (db::Box (db::Point (0, 0), db::Point (20, 20)));
r.insert (db::Box (db::Point (80, 0), db::Point (100, 20)));
rr.clear ();
rr.insert (db::Box (db::Point (-100, -10), db::Point (0, 30)));
rr.insert (db::Box (db::Point (0, -10), db::Point (100, 30)));
EXPECT_EQ (r.selected_outside (rr).to_string (), "");
EXPECT_EQ (r.selected_inside (rr).to_string (), "(-100,0;-100,20;-80,20;-80,0);(-20,0;-20,20;20,20;20,0);(80,0;80,20;100,20;100,0)");
EXPECT_EQ (r.selected_overlapping (rr).to_string (), "(-100,0;-100,20;-80,20;-80,0);(-20,0;-20,20;20,20;20,0);(80,0;80,20;100,20;100,0)");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,0;-100,20;-80,20;-80,0);(-20,0;-20,20;20,20;20,0);(80,0;80,20;100,20;100,0)");
EXPECT_EQ (r.selected_not_outside (rr).to_string (), "(-100,0;-100,20;-80,20;-80,0);(-20,0;-20,20;20,20;20,0);(80,0;80,20;100,20;100,0)");
EXPECT_EQ (r.selected_not_inside (rr).to_string (), "");
EXPECT_EQ (r.selected_not_overlapping (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
}
TEST(19) TEST(19)
{ {
db::Region r1; db::Region r1;

View File

@ -3922,9 +3922,9 @@ CODE
n = $1.to_i - 1 n = $1.to_i - 1
view = RBA::LayoutView::current view = RBA::LayoutView::current
view || raise("No view open") view || raise("No view open")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n}") (n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n + 1}")
cv = view.cellview(n) cv = view.cellview(n)
cv.is_valid? || raise("Invalid layout @#{n}") cv.is_valid? || raise("Invalid layout @#{n + 1}")
@def_source = make_source(cv.layout, cv.cell) @def_source = make_source(cv.layout, cv.cell)
else else
layout = RBA::Layout::new layout = RBA::Layout::new
@ -4016,9 +4016,9 @@ CODE
n = $1.to_i - 1 n = $1.to_i - 1
view = RBA::LayoutView::current view = RBA::LayoutView::current
view || raise("No view open") view || raise("No view open")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n}") (n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n + 1}")
cv = view.cellview(n) cv = view.cellview(n)
cv.is_valid? || raise("Invalid layout @#{n}") cv.is_valid? || raise("Invalid layout @#{n + 1}")
return make_source(cv.layout, cv.cell) return make_source(cv.layout, cv.cell)
else else
layout = RBA::Layout::new layout = RBA::Layout::new
@ -4173,9 +4173,9 @@ CODE
n = $1.to_i - 1 n = $1.to_i - 1
view = RBA::LayoutView::current view = RBA::LayoutView::current
view || raise("No view open") view || raise("No view open")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n}") (n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n + 1}")
cv = view.cellview(n) cv = view.cellview(n)
cv.is_valid? || raise("Invalid layout @#{n}") cv.is_valid? || raise("Invalid layout @#{n + 1}")
@output_layout = cv.layout @output_layout = cv.layout
@output_cell = cellname ? (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s)) : cv.cell @output_cell = cellname ? (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s)) : cv.cell
@output_layout_file = nil @output_layout_file = nil
@ -4694,11 +4694,20 @@ CODE
else else
output = @output_layout || @def_layout if @output_layout
output || raise("No output layout specified") output = @output_layout
if @output_cell
output_cell = @output_cell || @def_cell output_cell = @output_cell
output_cell || raise("No output cell specified") elsif @def_cell
output_cell = @output_layout.cell(@def_cell.name) || @output_layout.create_cell(@def_cell.name)
end
output_cell || raise("No output cell specified (see 'target' instruction)")
else
output = @def_layout
output || raise("No output layout specified")
output_cell = @output_cell || @def_cell
output_cell || raise("No output cell specified")
end
info = nil info = nil
if args.size == 1 if args.size == 1

View File

@ -1084,23 +1084,29 @@ MainService::cm_convert_to_pcell ()
db::Library *lib = db::LibraryManager::instance ().lib (l->second); db::Library *lib = db::LibraryManager::instance ().lib (l->second);
for (db::Layout::pcell_iterator pc = lib->layout ().begin_pcells (); pc != lib->layout ().end_pcells (); ++pc) { for (db::Layout::pcell_iterator pc = lib->layout ().begin_pcells (); pc != lib->layout ().end_pcells (); ++pc) {
const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second); try {
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 db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second);
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) { size_t n = 1000; // 1000 tries max.
const lay::CellView &cv = view ()->cellview (s->cv_index ()); for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) {
if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) { for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) {
--n; const lay::CellView &cv = view ()->cellview (s->cv_index ());
} else { if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) {
pc_decl = 0; // stop --n;
} else {
pc_decl = 0; // stop
}
} }
} }
}
// We have positive hit // We have positive hit
if (pc_decl) { if (pc_decl) {
pcells.push_back (std::make_pair (lib, pc->second)); pcells.push_back (std::make_pair (lib, pc->second));
items.push_back (tl::to_qstring (lib->get_name () + "." + pc_decl->name ())); items.push_back (tl::to_qstring (lib->get_name () + "." + pc_decl->name ()));
}
} catch (...) {
// ignore errors in can_create_from_shape
} }
} }
@ -1906,12 +1912,10 @@ MainService::cm_change_layer ()
// get (common) cellview index of the selected shapes // get (common) cellview index of the selected shapes
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
if (! s->is_cell_inst ()) { if (cv_index >= 0 && cv_index != int (s->cv_index ())) {
if (cv_index >= 0 && cv_index != int (s->cv_index ())) { throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case.")));
throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case.")));
}
cv_index = int (s->cv_index ());
} }
cv_index = int (s->cv_index ());
} }
} }
@ -1975,17 +1979,58 @@ MainService::cm_change_layer ()
// Insert and delete the shape. This exploits the fact, that a shape can be erased multiple times - // Insert and delete the shape. This exploits the fact, that a shape can be erased multiple times -
// this is important since the selection potentially contains the same shape multiple times. // this is important since the selection potentially contains the same shape multiple times.
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
if (!s->is_cell_inst () && int (s->layer ()) != layer) { if (!s->is_cell_inst () && int (s->layer ()) != layer) {
db::Cell &cell = layout.cell (s->cell_index ()); db::Cell &cell = layout.cell (s->cell_index ());
if (cell.shapes (s->layer ()).is_valid (s->shape ())) { if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
cell.shapes (layer).insert (s->shape ()); cell.shapes (layer).insert (s->shape ());
cell.shapes (s->layer ()).erase_shape (s->shape ()); cell.shapes (s->layer ()).erase_shape (s->shape ());
} }
} else if (s->is_cell_inst ()) {
// If the selected object is a PCell instance, and there is exactly one visible, writable layer type parameter, change this one
db::Instance inst = s->back ().inst_ptr;
db::Cell &cell = layout.cell (s->cell_index ());
if (cell.is_valid (inst)) {
const db::PCellDeclaration *pcell_decl = layout.pcell_declaration_for_pcell_variant (inst.cell_index ());
if (pcell_decl) {
size_t layer_par_index = 0;
int n_layer_par = 0;
for (std::vector<db::PCellParameterDeclaration>::const_iterator d = pcell_decl->parameter_declarations ().begin (); d != pcell_decl->parameter_declarations ().end () && n_layer_par < 2; ++d) {
if (d->get_type () == db::PCellParameterDeclaration::t_layer && !d->is_hidden () && !d->is_readonly ()) {
++n_layer_par;
layer_par_index = size_t (d - pcell_decl->parameter_declarations ().begin ());
}
}
if (n_layer_par == 1) {
std::vector<tl::Variant> parameters = cell.get_pcell_parameters (inst);
tl_assert (layer_par_index < parameters.size ());
parameters [layer_par_index] = layout.get_properties (layer);
cell.change_pcell_parameters (inst, parameters);
}
}
}
} }
} }
} }
// remove superfluous proxies
layout.cleanup ();
// The selection is no longer valid // The selection is no longer valid
view ()->clear_selection (); view ()->clear_selection ();

View File

@ -1092,7 +1092,7 @@ Net::Net ()
} }
Net::Net (const NetTracer &tracer, const db::ICplxTrans &trans, const db::Layout &layout, db::cell_index_type cell_index, const std::string &layout_filename, const std::string &layout_name, const NetTracerData &data) Net::Net (const NetTracer &tracer, const db::ICplxTrans &trans, const db::Layout &layout, db::cell_index_type cell_index, const std::string &layout_filename, const std::string &layout_name, const NetTracerData &data)
: m_name (tracer.name ()), m_incomplete (tracer.incomplete ()) : m_name (tracer.name ()), m_incomplete (tracer.incomplete ()), m_trace_path (false)
{ {
m_dbu = layout.dbu (); m_dbu = layout.dbu ();
m_top_cell_name = layout.cell_name (cell_index); m_top_cell_name = layout.cell_name (cell_index);

View File

@ -607,11 +607,30 @@ RS274XMacroAperture::do_produce_flash ()
} }
} }
void
RS274XMacroAperture::read_exposure (tl::Extractor &ex, bool &clear, bool &clear_set)
{
int pol = int (floor (read_expr (ex) + 0.5));
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear_set || !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
clear_set = true;
}
void void
RS274XMacroAperture::do_produce_flash_internal () RS274XMacroAperture::do_produce_flash_internal ()
{ {
tl::Extractor ex (m_def.c_str ()); tl::Extractor ex (m_def.c_str ());
bool clear = false; bool clear = false;
bool clear_set = false;
while (! ex.at_end ()) { while (! ex.at_end ()) {
@ -640,18 +659,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
if (code == 1) { if (code == 1) {
ex.expect (","); ex.expect (",");
int pol = (read_expr (ex) > 0.5); read_exposure (ex, clear, clear_set);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
ex.expect (","); ex.expect (",");
double d = read_expr (ex, true); double d = read_expr (ex, true);
ex.expect (","); ex.expect (",");
@ -670,18 +678,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 2 || code == 20) { } else if (code == 2 || code == 20) {
ex.expect (","); ex.expect (",");
int pol = (read_expr (ex) > 0.5); read_exposure (ex, clear, clear_set);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
ex.expect (","); ex.expect (",");
double w = read_expr (ex, true); double w = read_expr (ex, true);
ex.expect (","); ex.expect (",");
@ -723,18 +720,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 21 || code == 22) { } else if (code == 21 || code == 22) {
ex.expect (","); ex.expect (",");
int pol = (read_expr (ex) > 0.5); read_exposure (ex, clear, clear_set);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
ex.expect (","); ex.expect (",");
double w = read_expr (ex, true); double w = read_expr (ex, true);
ex.expect (","); ex.expect (",");
@ -766,18 +752,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 4) { } else if (code == 4) {
ex.expect (","); ex.expect (",");
int pol = (read_expr (ex) > 0.5); read_exposure (ex, clear, clear_set);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
ex.expect (","); ex.expect (",");
int n = int (read_expr (ex) + 0.5); int n = int (read_expr (ex) + 0.5);
if (n < 1) { if (n < 1) {
@ -854,18 +829,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 5) { } else if (code == 5) {
ex.expect (","); ex.expect (",");
int pol = (read_expr (ex) > 0.5); read_exposure (ex, clear, clear_set);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
ex.expect (","); ex.expect (",");
int n = int (read_expr (ex) + 0.5); int n = int (read_expr (ex) + 0.5);
if (n < 3) { if (n < 3) {

View File

@ -168,6 +168,7 @@ private:
double read_atom (tl::Extractor &ex); double read_atom (tl::Extractor &ex);
double read_dot_expr (tl::Extractor &ex); double read_dot_expr (tl::Extractor &ex);
double read_expr (tl::Extractor &ex, bool length = false); double read_expr (tl::Extractor &ex, bool length = false);
void read_exposure (tl::Extractor &ex, bool &clear, bool &clear_set);
void do_produce_flash_internal (); void do_produce_flash_internal ();
}; };

View File

@ -524,7 +524,6 @@ private:
ArgType m_ret_type; ArgType m_ret_type;
bool m_const : 1; bool m_const : 1;
bool m_static : 1; bool m_static : 1;
bool m_is_predicate : 1;
bool m_protected : 1; bool m_protected : 1;
unsigned int m_argsize; unsigned int m_argsize;
std::vector<MethodSynonym> m_method_synonyms; std::vector<MethodSynonym> m_method_synonyms;

View File

@ -697,12 +697,14 @@ static size_t make_id ()
Object::Object () Object::Object ()
: m_trans (1.0), mp_data (0), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0) : m_trans (1.0), mp_data (0), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
{ {
m_updates_enabled = false;
mp_pixel_data = 0; mp_pixel_data = 0;
} }
Object::Object (size_t w, size_t h, const db::DCplxTrans &trans, bool color) Object::Object (size_t w, size_t h, const db::DCplxTrans &trans, bool color)
: m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0) : m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
{ {
m_updates_enabled = false;
mp_pixel_data = 0; mp_pixel_data = 0;
mp_data = new DataHeader (w, h, color, false); mp_data = new DataHeader (w, h, color, false);

View File

@ -1380,6 +1380,17 @@ GuiApplication::notify (QObject *receiver, QEvent *e)
return ret; return ret;
} }
void
GuiApplication::force_update_app_menu ()
{
#if defined(__APPLE__)
// This is a workaround for a bug in the MacOS native menu integration:
// this signal forces the menu to become updated. Without this, any
// new menu items stay disabled.
emit focusWindowChanged (focusWindow ());
#endif
}
int int
GuiApplication::exec () GuiApplication::exec ()
{ {

View File

@ -432,6 +432,12 @@ public:
return mp_mw; return mp_mw;
} }
/**
* @brief Forces update of the application menu
* This function is used for work around a MacOS issue.
*/
void force_update_app_menu ();
protected: protected:
virtual void setup (); virtual void setup ();
virtual void shutdown (); virtual void shutdown ();

View File

@ -1195,10 +1195,6 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
pydoc = pya::PythonInterpreter::instance ()->python_doc (i->second.first); pydoc = pya::PythonInterpreter::instance ()->python_doc (i->second.first);
} }
os << "<a name=\"method" << n << "\"/>"
<< "<a name=\"m_" << escape_xml (i->first) << "\"/>"
<< "<keyword title=\"" << tl::to_string (QObject::tr ("API reference - Class")) << " " << escape_xml (cls) << ", " << tl::to_string (QObject::tr ("Method")) << " " << escape_xml (i->first) << "\" name=\"" << escape_xml (cls) << "#" << escape_xml (i->first) << "\"/>" << std::endl;
os << "<tr>"; os << "<tr>";
if (i->first != prev_title) { if (i->first != prev_title) {
int rows = 0; int rows = 0;
@ -1212,6 +1208,10 @@ GSIHelpProvider::produce_class_doc (const std::string &cls) const
} }
os << "<td style=\"padding-bottom: 16px\">"; os << "<td style=\"padding-bottom: 16px\">";
os << "<a name=\"method" << n << "\"/>"
<< "<a name=\"m_" << escape_xml (i->first) << "\"/>"
<< "<keyword title=\"" << tl::to_string (QObject::tr ("API reference - Class")) << " " << escape_xml (cls) << ", " << tl::to_string (QObject::tr ("Method")) << " " << escape_xml (i->first) << "\" name=\"" << escape_xml (cls) << "#" << escape_xml (i->first) << "\"/>" << std::endl;
os << "<p><b>" << tl::to_string (QObject::tr ("Signature")) << "</b>: "; os << "<p><b>" << tl::to_string (QObject::tr ("Signature")) << "</b>: ";
std::string attr = method_attributes (i->second.first, method_doc); std::string attr = method_attributes (i->second.first, method_doc);
if (! attr.empty ()) { if (! attr.empty ()) {

View File

@ -450,6 +450,7 @@ MainWindow::MainWindow (QApplication *app, const char *name)
m_disable_tab_selected (false), m_disable_tab_selected (false),
m_exited (false), m_exited (false),
dm_do_update_menu (this, &MainWindow::do_update_menu), dm_do_update_menu (this, &MainWindow::do_update_menu),
dm_do_update_file_menu (this, &MainWindow::do_update_file_menu),
dm_exit (this, &MainWindow::exit), dm_exit (this, &MainWindow::exit),
m_grid_micron (0.001), m_grid_micron (0.001),
m_default_grids_updated (true), m_default_grids_updated (true),
@ -608,15 +609,6 @@ MainWindow::MainWindow (QApplication *app, const char *name)
cp_frame_ly->addWidget (mp_cpy_label); cp_frame_ly->addWidget (mp_cpy_label);
cp_frame_ly->insertSpacing (-1, 6); cp_frame_ly->insertSpacing (-1, 6);
// connect to the menus to provide the dynamic parts
QMenu *bookmark_menu = mp_menu->menu ("bookmark_menu");
tl_assert (bookmark_menu != 0);
connect (bookmark_menu, SIGNAL (aboutToShow ()), this, SLOT (bookmark_menu_show ()));
QMenu *file_menu = mp_menu->menu ("file_menu");
tl_assert (file_menu != 0);
connect (file_menu, SIGNAL (aboutToShow ()), this, SLOT (file_menu_show ()));
// select the default mode // select the default mode
select_mode (lay::LayoutView::default_mode ()); select_mode (lay::LayoutView::default_mode ());
@ -1595,6 +1587,8 @@ MainWindow::configure (const std::string &name, const std::string &value)
} }
} }
dm_do_update_file_menu ();
return true; return true;
} else if (name == cfg_micron_digits) { } else if (name == cfg_micron_digits) {
@ -1799,6 +1793,12 @@ MainWindow::edits_enabled_changed ()
} }
} }
void
MainWindow::menu_needs_update ()
{
lay::LayoutView::update_menu (current_view (), *mp_menu);
}
void void
MainWindow::libraries_changed () MainWindow::libraries_changed ()
{ {
@ -2427,57 +2427,6 @@ MainWindow::cm_redo ()
END_PROTECTED END_PROTECTED
} }
void
MainWindow::bookmark_menu_show ()
{
if (mp_menu->is_valid ("bookmark_menu.goto_bookmark_menu")) {
Action goto_bookmark_action = mp_menu->action ("bookmark_menu.goto_bookmark_menu");
bool has_bookmarks = current_view () && current_view ()->bookmarks ().size () > 0;
if (has_bookmarks && edits_enabled ()) {
goto_bookmark_action.set_enabled (true);
QMenu *goto_bookmark_menu = goto_bookmark_action.qaction ()->menu ();
if (goto_bookmark_menu) {
goto_bookmark_menu->clear ();
if (current_view ()) {
const lay::BookmarkList &bookmarks = current_view ()->bookmarks ();
for (size_t i = 0; i < bookmarks.size (); ++i) {
QAction *action = goto_bookmark_menu->addAction (tl::to_qstring (bookmarks.name (i)));
action->setObjectName (tl::to_qstring (tl::sprintf ("bookmark_%d", i + 1)));
gtf::action_connect (action, SIGNAL (triggered ()), this, SLOT (goto_bookmark ()));
action->setData (QVariant (int (i)));
}
}
}
} else {
goto_bookmark_action.set_enabled (false);
}
}
}
void
MainWindow::goto_bookmark ()
{
BEGIN_PROTECTED
QAction *action = dynamic_cast <QAction *> (sender ());
tl_assert (action);
size_t id = size_t (action->data ().toInt ());
if (current_view () && current_view ()->bookmarks ().size () > id) {
current_view ()->goto_view (current_view ()->bookmarks ().state (id));
}
END_PROTECTED
}
void void
MainWindow::cm_goto_position () MainWindow::cm_goto_position ()
{ {
@ -2581,19 +2530,7 @@ MainWindow::cm_bookmark_view ()
BEGIN_PROTECTED BEGIN_PROTECTED
if (current_view ()) { if (current_view ()) {
while (true) { current_view ()->bookmark_current_view ();
bool ok = false;
QString text = QInputDialog::getText (this, QObject::tr ("Enter Bookmark Name"), QObject::tr ("Bookmark name"),
QLineEdit::Normal, QString::null, &ok);
if (! ok) {
break;
} else if (text.isEmpty ()) {
QMessageBox::critical (this, QObject::tr ("Error"), QObject::tr ("Enter a name for the bookmark"));
} else {
current_view ()->bookmark_view (tl::to_string (text));
break;
}
}
} }
END_PROTECTED END_PROTECTED
@ -3360,6 +3297,7 @@ MainWindow::select_view (int index)
clear_current_pos (); clear_current_pos ();
edits_enabled_changed (); edits_enabled_changed ();
clear_message (); clear_message ();
menu_needs_update ();
m_disable_tab_selected = dis; m_disable_tab_selected = dis;
@ -3739,6 +3677,7 @@ MainWindow::clone_current_view ()
connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ()));
connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ()));
connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ()));
connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ()));
connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int)));
connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
@ -4042,6 +3981,7 @@ MainWindow::close_view (int index)
clear_current_pos (); clear_current_pos ();
edits_enabled_changed (); edits_enabled_changed ();
menu_needs_update ();
clear_message (); clear_message ();
update_dock_widget_state (); update_dock_widget_state ();
@ -4173,30 +4113,28 @@ MainWindow::add_mru (const std::string &fn_rel, const std::string &tech)
} }
void void
MainWindow::file_menu_show () MainWindow::do_update_file_menu ()
{ {
if (mp_menu->is_valid ("file_menu.open_recent_menu")) { std::string mru_menu = "file_menu.open_recent_menu";
Action open_recent_action = mp_menu->action ("file_menu.open_recent_menu"); if (mp_menu->is_valid (mru_menu)) {
Action open_recent_action = mp_menu->action (mru_menu);
open_recent_action.set_enabled (true);
if (m_mru.size () > 0 && edits_enabled ()) { if (m_mru.size () > 0 && edits_enabled ()) {
open_recent_action.set_enabled (true); // rebuild MRU menu
mp_menu->clear_menu (mru_menu);
QMenu *open_recent_menu = open_recent_action.qaction ()->menu ();
if (open_recent_menu) {
open_recent_menu->clear ();
for (std::vector<std::pair<std::string, std::string> >::iterator mru = m_mru.end (); mru != m_mru.begin (); ) {
--mru;
unsigned int i = std::distance (m_mru.begin (), mru);
QAction *action = open_recent_menu->addAction (tl::to_qstring (mru->first));
action->setObjectName (tl::to_qstring (tl::sprintf ("open_recent_%d", i + 1)));
gtf::action_connect (action, SIGNAL (triggered ()), this, SLOT (open_recent ()));
action->setData (QVariant (int (i)));
}
for (std::vector<std::pair<std::string, std::string> >::iterator mru = m_mru.end (); mru != m_mru.begin (); ) {
--mru;
unsigned int i = std::distance (m_mru.begin (), mru);
Action action;
gtf::action_connect (action.qaction (), SIGNAL (triggered ()), this, SLOT (open_recent ()));
action.set_title (mru->first);
action.qaction ()->setData (QVariant (int (i)));
mp_menu->insert_item (mru_menu + ".end", tl::sprintf ("open_recent_%d", i + 1), action);
} }
} else { } else {
@ -4349,6 +4287,7 @@ MainWindow::do_create_view ()
connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ()));
connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ()));
connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ()));
connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ()));
connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int)));
connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
@ -5016,6 +4955,10 @@ void
MainWindow::do_update_menu () MainWindow::do_update_menu ()
{ {
mp_menu->build (menuBar (), mp_tool_bar); mp_menu->build (menuBar (), mp_tool_bar);
lay::GuiApplication *app = dynamic_cast<lay::GuiApplication *> (qApp);
if (app) {
app->force_update_app_menu ();
}
} }
void void

View File

@ -689,7 +689,6 @@ public slots:
void tab_close_requested (int); void tab_close_requested (int);
void enable_all (); void enable_all ();
void disable_all (); void disable_all ();
void goto_bookmark ();
void open_recent (); void open_recent ();
void view_selected (int index); void view_selected (int index);
void view_title_changed (); void view_title_changed ();
@ -858,9 +857,9 @@ public slots:
protected slots: protected slots:
void menu_changed (); void menu_changed ();
void message_timer (); void message_timer ();
void bookmark_menu_show ();
void file_menu_show ();
void edits_enabled_changed (); void edits_enabled_changed ();
void menu_needs_update ();
void file_changed_timer (); void file_changed_timer ();
void file_changed (const QString &path); void file_changed (const QString &path);
void file_removed (const QString &path); void file_removed (const QString &path);
@ -868,13 +867,13 @@ protected slots:
protected: protected:
void update_content (); void update_content ();
void do_update_menu (); void do_update_menu ();
void do_update_file_menu ();
private: private:
TextProgressDelegate m_text_progress; TextProgressDelegate m_text_progress;
// Main menu // Main menu
AbstractMenu *mp_menu; AbstractMenu *mp_menu;
QMenu *mp_goto_bookmark_menu;
QTabBar *mp_tab_bar; QTabBar *mp_tab_bar;
QToolBar *mp_tool_bar; QToolBar *mp_tool_bar;
QDockWidget *mp_navigator_dock_widget; QDockWidget *mp_navigator_dock_widget;
@ -911,6 +910,7 @@ private:
bool m_disable_tab_selected; bool m_disable_tab_selected;
bool m_exited; bool m_exited;
tl::DeferredMethod<MainWindow> dm_do_update_menu; tl::DeferredMethod<MainWindow> dm_do_update_menu;
tl::DeferredMethod<MainWindow> dm_do_update_file_menu;
tl::DeferredMethod<MainWindow> dm_exit; tl::DeferredMethod<MainWindow> dm_exit;
QTimer m_message_timer; QTimer m_message_timer;
QTimer m_file_changed_timer; QTimer m_file_changed_timer;

View File

@ -211,10 +211,12 @@ ProgressReporter::set_visible (bool vis)
// actual operation // actual operation
tl::DeferredMethodScheduler::enable (!vis); tl::DeferredMethodScheduler::enable (!vis);
if (!vis) { if (mp_pb) {
mp_pb->progress_remove_widget (); if (!vis) {
} else if (mp_pb->progress_wants_widget () && mp_objects.front ()) { mp_pb->progress_remove_widget ();
mp_pb->progress_add_widget (mp_objects.front ()->progress_widget ()); } else if (mp_pb->progress_wants_widget () && mp_objects.front ()) {
mp_pb->progress_add_widget (mp_objects.front ()->progress_widget ());
}
} }
m_pw_visible = vis; m_pw_visible = vis;

View File

@ -279,12 +279,13 @@ Salt::remove_grain (const SaltGrain &grain)
{ {
emit collections_about_to_change (); emit collections_about_to_change ();
tl::info << QObject::tr ("Removing package '%1' ..").arg (tl::to_qstring (grain.name ())); QString name = tl::to_qstring (grain.name ());
tl::info << QObject::tr ("Removing package '%1' ..").arg (name);
bool res = remove_from_collection (m_root, grain.name ()); bool res = remove_from_collection (m_root, grain.name ());
if (res) { if (res) {
tl::info << QObject::tr ("Package '%1' removed.").arg (tl::to_qstring (grain.name ())); tl::info << QObject::tr ("Package '%1' removed.").arg (name);
} else { } else {
tl::warn << QObject::tr ("Failed to remove package '%1'.").arg (tl::to_qstring (grain.name ())); tl::warn << QObject::tr ("Failed to remove package '%1'.").arg (name);
} }
invalidate (); invalidate ();

View File

@ -160,7 +160,7 @@ SaltDownloadManager::compute_list (const lay::Salt &salt, const lay::Salt &salt_
size_t n = m_registry.size (); size_t n = m_registry.size ();
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
const Descriptor &p = m_registry [i]; Descriptor p = m_registry [i];
for (std::vector<SaltGrain::Dependency>::const_iterator d = p.grain.dependencies ().begin (); d != p.grain.dependencies ().end (); ++d) { for (std::vector<SaltGrain::Dependency>::const_iterator d = p.grain.dependencies ().begin (); d != p.grain.dependencies ().end (); ++d) {

View File

@ -259,7 +259,7 @@ SaltGrainPropertiesDialog::dependency_changed (QTreeWidgetItem *item, int column
m_update_enabled = false; m_update_enabled = false;
std::string name = tl::to_string (item->data (0, Qt::UserRole).toString ().simplified ()); std::string name = tl::to_string (item->data (0, Qt::UserRole).toString ().simplified ());
SaltGrain *g = mp_salt->grain_by_name (name); SaltGrain *g = mp_salt ? mp_salt->grain_by_name (name) : 0;
if (column == 0 && mp_salt) { if (column == 0 && mp_salt) {

View File

@ -858,12 +858,12 @@ SaltManagerDialog::selected_changed ()
details_text->set_grain (g); details_text->set_grain (g);
if (!g) { if (!g) {
details_frame->setEnabled (false); details_frame->setEnabled (false);
delete_button->setEnabled (false);
} else { } else {
details_frame->setEnabled (true); details_frame->setEnabled (true);
delete_button->setEnabled (true);
edit_button->setEnabled (! g->is_readonly ()); edit_button->setEnabled (! g->is_readonly ());
} }
delete_button->setEnabled (! current_grains ().empty ());
} }
lay::SaltGrain * lay::SaltGrain *

View File

@ -45,7 +45,7 @@ static lay::Technology *create_technology (const std::string &name)
{ {
lay::Technology *tech = new lay::Technology (); lay::Technology *tech = new lay::Technology ();
tech->set_name (name); tech->set_name (name);
lay::Technologies::instance ()->add (tech); lay::Technologies::instance ()->add_new (tech);
return tech; return tech;
} }

View File

@ -217,7 +217,17 @@ class ActionObject
: public QAction : public QAction
{ {
public: public:
ActionObject (QObject *parent) : QAction (parent) { } ActionObject (QObject *parent)
: QAction (parent)
{
static size_t s_id = 0;
m_id = ++s_id;
}
size_t id () const
{
return m_id;
}
bool event(QEvent *e) bool event(QEvent *e)
{ {
@ -251,8 +261,18 @@ public:
return QAction::event(e); return QAction::event(e);
} }
private:
size_t m_id;
}; };
static size_t
id_from_action (QAction *action)
{
ActionObject *ao = dynamic_cast<ActionObject *> (action);
return ao ? ao->id () : 0;
}
ActionHandle::ActionHandle (QWidget *parent) ActionHandle::ActionHandle (QWidget *parent)
: mp_menu (0), : mp_menu (0),
mp_action (new ActionObject (parent)), mp_action (new ActionObject (parent)),
@ -1013,9 +1033,11 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
m_helper_menu_items.clear (); m_helper_menu_items.clear ();
tbar->clear (); tbar->clear ();
std::set<QAction *> present_actions; std::set<std::pair<size_t, QAction *> > present_actions;
QList<QAction *> a = mbar->actions (); QList<QAction *> a = mbar->actions ();
present_actions.insert (a.begin (), a.end ()); for (QList<QAction *>::const_iterator i = a.begin (); i != a.end (); ++i) {
present_actions.insert (std::make_pair (id_from_action (*i), *i));
}
for (std::list<AbstractMenuItem>::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) { for (std::list<AbstractMenuItem>::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) {
@ -1053,10 +1075,10 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
c->set_action (Action (new ActionHandle (menu)), true); c->set_action (Action (new ActionHandle (menu)), true);
} else { } else {
// Move the action to the end if present in the menu already // Move the action to the end if present in the menu already
std::set<QAction *>::iterator a = present_actions.find (c->menu ()->menuAction ()); std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ()));
if (a != present_actions.end ()) { if (a != present_actions.end ()) {
if (s_can_move_menu) { if (s_can_move_menu) {
mbar->removeAction (*a); mbar->removeAction (a->second);
mbar->addMenu (c->menu ()); mbar->addMenu (c->menu ());
} }
present_actions.erase (*a); present_actions.erase (*a);
@ -1071,10 +1093,10 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
} else { } else {
// Move the action to the end if present in the menu already // Move the action to the end if present in the menu already
std::set<QAction *>::iterator a = present_actions.find (c->action ().qaction ()); std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ().qaction ()), c->action ().qaction ()));
if (a != present_actions.end ()) { if (a != present_actions.end ()) {
if (s_can_move_menu) { if (s_can_move_menu) {
mbar->removeAction (*a); mbar->removeAction (a->second);
mbar->addAction (c->action ().qaction ()); mbar->addAction (c->action ().qaction ());
} }
present_actions.erase (*a); present_actions.erase (*a);
@ -1086,17 +1108,19 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
} }
// Remove all actions that have vanished // Remove all actions that have vanished
for (std::set<QAction *>::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
mbar->removeAction (*a); mbar->removeAction (a->second);
} }
} }
void void
AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items) AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
{ {
std::set<QAction *> present_actions; std::set<std::pair<size_t, QAction *> > present_actions;
QList<QAction *> a = m->actions (); QList<QAction *> a = m->actions ();
present_actions.insert (a.begin (), a.end ()); for (QList<QAction *>::const_iterator i = a.begin (); i != a.end (); ++i) {
present_actions.insert (std::make_pair (id_from_action (*i), *i));
}
for (std::list<AbstractMenuItem>::iterator c = items.begin (); c != items.end (); ++c) { for (std::list<AbstractMenuItem>::iterator c = items.begin (); c != items.end (); ++c) {
@ -1111,10 +1135,10 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
c->set_action (Action (new ActionHandle (menu)), true); c->set_action (Action (new ActionHandle (menu)), true);
} else { } else {
// Move the action to the end if present in the menu already // Move the action to the end if present in the menu already
std::set<QAction *>::iterator a = present_actions.find (c->menu ()->menuAction ()); std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ()));
if (a != present_actions.end ()) { if (a != present_actions.end ()) {
if (s_can_move_menu) { if (s_can_move_menu) {
m->removeAction (*a); m->removeAction (a->second);
m->addMenu (c->menu ()); m->addMenu (c->menu ());
} }
present_actions.erase (*a); present_actions.erase (*a);
@ -1128,10 +1152,10 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
} else { } else {
// Move the action to the end if present in the menu already // Move the action to the end if present in the menu already
std::set<QAction *>::iterator a = present_actions.find (c->action ().qaction ()); std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ().qaction ()), c->action ().qaction ()));
if (a != present_actions.end ()) { if (a != present_actions.end ()) {
if (s_can_move_menu) { if (s_can_move_menu) {
m->removeAction (*a); m->removeAction (a->second);
m->addAction (c->action ().qaction ()); m->addAction (c->action ().qaction ());
} }
present_actions.erase (*a); present_actions.erase (*a);
@ -1143,8 +1167,8 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
} }
// Remove all actions that have vanished // Remove all actions that have vanished
for (std::set<QAction *>::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
m->removeAction (*a); m->removeAction (a->second);
} }
} }
@ -1330,6 +1354,17 @@ AbstractMenu::insert_menu (const std::string &path, const std::string &name, con
insert_menu (path, name, create_action (title)); insert_menu (path, name, create_action (title));
} }
void
AbstractMenu::clear_menu (const std::string &p)
{
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
path_type path = find_item (p);
if (! path.empty () && ! path.back ().second->children.empty ()) {
path.back ().second->children.clear ();
emit changed ();
}
}
void void
AbstractMenu::delete_item (const std::string &p) AbstractMenu::delete_item (const std::string &p)
{ {

View File

@ -784,6 +784,13 @@ public:
*/ */
void insert_menu (const std::string &path, const std::string &name, const std::string &title); void insert_menu (const std::string &path, const std::string &name, const std::string &title);
/**
* @brief Deletes the children of the item with the given path
*
* If the item does not exist or is not a menu, this method does nothing.
*/
void clear_menu (const std::string &path);
/** /**
* @brief Delete the item given by the path * @brief Delete the item given by the path
* *

View File

@ -42,6 +42,7 @@
#include "tlString.h" #include "tlString.h"
#include "tlLog.h" #include "tlLog.h"
#include "tlAssert.h" #include "tlAssert.h"
#include "tlExceptions.h"
#include "layLayoutView.h" #include "layLayoutView.h"
#include "layViewOp.h" #include "layViewOp.h"
#include "layViewObject.h" #include "layViewObject.h"
@ -74,6 +75,7 @@
#include "rdbMarkerBrowserDialog.h" #include "rdbMarkerBrowserDialog.h"
#include "tlXMLParser.h" #include "tlXMLParser.h"
#include "gsi.h" #include "gsi.h"
#include "gtf.h"
#include <limits> #include <limits>
@ -772,6 +774,37 @@ LayoutView::init_menu (lay::AbstractMenu &menu)
lay::HierarchyControlPanel::init_menu (menu); lay::HierarchyControlPanel::init_menu (menu);
} }
void
LayoutView::update_menu (lay::LayoutView *view, lay::AbstractMenu &menu)
{
std::string bm_menu = "bookmark_menu.goto_bookmark_menu";
if (menu.is_valid (bm_menu)) {
menu.clear_menu (bm_menu);
Action goto_bookmark_action = menu.action (bm_menu);
if (view && view->bookmarks ().size () > 0) {
goto_bookmark_action.set_enabled (true);
const lay::BookmarkList &bookmarks = view->bookmarks ();
for (size_t i = 0; i < bookmarks.size (); ++i) {
Action action;
gtf::action_connect (action.qaction (), SIGNAL (triggered ()), view, SLOT (goto_bookmark ()));
action.set_title (bookmarks.name (i));
action.qaction ()->setData (QVariant (int (i)));
menu.insert_item (bm_menu + ".end", tl::sprintf ("bookmark_%d", i + 1), action);
}
} else {
goto_bookmark_action.set_enabled (false);
}
}
}
void void
LayoutView::set_drawing_workers (int workers) LayoutView::set_drawing_workers (int workers)
{ {
@ -3650,6 +3683,24 @@ LayoutView::cancel ()
clear_selection (); clear_selection ();
} }
void
LayoutView::bookmark_current_view ()
{
while (true) {
bool ok = false;
QString text = QInputDialog::getText (this, QObject::tr ("Enter Bookmark Name"), QObject::tr ("Bookmark name"),
QLineEdit::Normal, QString::null, &ok);
if (! ok) {
break;
} else if (text.isEmpty ()) {
QMessageBox::critical (this, QObject::tr ("Error"), QObject::tr ("Enter a name for the bookmark"));
} else {
bookmark_view (tl::to_string (text));
break;
}
}
}
void void
LayoutView::manage_bookmarks () LayoutView::manage_bookmarks ()
{ {
@ -3663,6 +3714,7 @@ void
LayoutView::bookmarks (const BookmarkList &b) LayoutView::bookmarks (const BookmarkList &b)
{ {
m_bookmarks = b; m_bookmarks = b;
emit menu_needs_update ();
} }
void void
@ -3670,6 +3722,22 @@ LayoutView::bookmark_view (const std::string &name)
{ {
DisplayState state (box (), get_min_hier_levels (), get_max_hier_levels (), m_cellviews); DisplayState state (box (), get_min_hier_levels (), get_max_hier_levels (), m_cellviews);
m_bookmarks.add (name, state); m_bookmarks.add (name, state);
emit menu_needs_update ();
}
void
LayoutView::goto_bookmark ()
{
BEGIN_PROTECTED
QAction *action = dynamic_cast <QAction *> (sender ());
tl_assert (action);
size_t id = size_t (action->data ().toInt ());
if (bookmarks ().size () > id) {
goto_view (bookmarks ().state (id));
}
END_PROTECTED
} }
void void

View File

@ -1557,6 +1557,11 @@ public:
*/ */
void bookmark_view (const std::string &name); void bookmark_view (const std::string &name);
/**
* @brief Asks for a bookmark name and bookmark the current view under this name
*/
void bookmark_current_view ();
/** /**
* @brief Show the bookmark management form * @brief Show the bookmark management form
*/ */
@ -1603,6 +1608,12 @@ public:
*/ */
static void init_menu (lay::AbstractMenu &menu); static void init_menu (lay::AbstractMenu &menu);
/**
* @brief Updates the menu for the given view
* If the view is 0, the menu shall be updated to reflect "no view active"
*/
static void update_menu (lay::LayoutView *view, lay::AbstractMenu &menu);
/** /**
* @brief Query the default mode * @brief Query the default mode
*/ */
@ -2530,6 +2541,7 @@ public slots:
private slots: private slots:
void active_cellview_changed (int index); void active_cellview_changed (int index);
void goto_bookmark ();
signals: signals:
/** /**
@ -2562,6 +2574,11 @@ signals:
*/ */
void edits_enabled_changed (); void edits_enabled_changed ();
/**
* @brief This signal is sent when the view wants to update the menu
*/
void menu_needs_update ();
protected: protected:
/** /**
* @brief Establish the view operations * @brief Establish the view operations

View File

@ -88,11 +88,13 @@ save_dialog_state (QWidget *w)
} }
for (QList<QObject *>::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) { if (w) {
if (dynamic_cast <QWidget *> (*c)) { for (QList<QObject *>::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) {
std::string cs = save_dialog_state (dynamic_cast <QWidget *> (*c)); if (dynamic_cast <QWidget *> (*c)) {
if (! cs.empty ()) { std::string cs = save_dialog_state (dynamic_cast <QWidget *> (*c));
s += cs; if (! cs.empty ()) {
s += cs;
}
} }
} }
} }

View File

@ -45,6 +45,8 @@ Technologies::Technologies ()
Technologies::Technologies (const Technologies &other) Technologies::Technologies (const Technologies &other)
: tl::Object () : tl::Object ()
{ {
m_changed = false;
m_in_update = false;
operator= (other); operator= (other);
} }
@ -115,19 +117,30 @@ Technologies::load_from_xml (const std::string &s)
} }
void void
Technologies::add (Technology *technology) Technologies::add_tech (Technology *tech, bool replace_same)
{ {
for (tl::stable_vector<Technology>::iterator t = m_technologies.begin (); technology && t != m_technologies.end (); ++t) { if (! tech) {
if (t->name () == technology->name ()) { return;
*t = *technology; }
delete technology;
technology = 0; std::auto_ptr<Technology> tech_ptr (tech);
Technology *t = 0;
for (tl::stable_vector<Technology>::iterator i = m_technologies.begin (); !t && i != m_technologies.end (); ++i) {
if (i->name () == tech->name ()) {
t = i.operator-> ();
} }
} }
if (technology) { if (t) {
m_technologies.push_back (technology); if (replace_same) {
technology->technology_changed_with_sender_event.add (this, &Technologies::technology_changed); *t = *tech;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("A technology with this name already exists: %1").arg (tl::to_qstring (tech->name ()))));
}
} else {
m_technologies.push_back (tech_ptr.release ());
tech->technology_changed_with_sender_event.add (this, &Technologies::technology_changed);
} }
technologies_changed (); technologies_changed ();
@ -218,6 +231,7 @@ Technologies::technology_by_name (const std::string &name)
} }
} }
tl_assert (! m_technologies.empty ());
return &*m_technologies.begin (); return &*m_technologies.begin ();
} }

View File

@ -126,7 +126,22 @@ public:
* The container becomes owner of the technology object. * The container becomes owner of the technology object.
* Replaces a technology with the name of the given technology. * Replaces a technology with the name of the given technology.
*/ */
void add (Technology *technology); void add (Technology *technology)
{
add_tech (technology, true /*replace*/);
}
/**
* @brief Adds a technology with a new name
*
* Like \add, but throws an exception if a technology with this name
* already exists. Takes over ownership over the technology object.
* The technology object is discarded if an exception is thrown.
*/
void add_new (Technology *technology)
{
add_tech (technology, false /*throws exception on same name*/);
}
/** /**
* @brief Remove a technology with the given name from the setup * @brief Remove a technology with the given name from the setup
@ -233,6 +248,8 @@ private:
tl::stable_vector<Technology> m_technologies; tl::stable_vector<Technology> m_technologies;
bool m_changed; bool m_changed;
bool m_in_update; bool m_in_update;
void add_tech (Technology *technology, bool replace_same);
}; };
/** /**

View File

@ -124,5 +124,14 @@ TEST(1)
menu.delete_item ("n1.c2"); menu.delete_item ("n1.c2");
EXPECT_EQ (menu_to_string (menu), "(n2)"); EXPECT_EQ (menu_to_string (menu), "(n2)");
}
menu.clear_menu ("n1");
EXPECT_EQ (menu_to_string (menu), "(n2)");
menu.insert_menu ("end", "n1", lay::Action ("title:n1"));
menu.insert_item ("n1.begin", "c1", lay::Action ("title:c1"));
menu.insert_item ("n1.end", "c2", lay::Action ("title:c2"));
EXPECT_EQ (menu_to_string (menu), "(n2,n1(n1.c1,n1.c2))");
menu.clear_menu ("n1");
EXPECT_EQ (menu_to_string (menu), "(n2,n1)");
}

View File

@ -915,26 +915,28 @@ void Macro::install_doc () const
if (cls == 0) { if (cls == 0) {
tl::error << tl::to_string (QObject::tr ("Reading class doc from ")) << path () << ": " << tl::to_string (QObject::tr ("@method without preceeding @class")); tl::error << tl::to_string (QObject::tr ("Reading class doc from ")) << path () << ": " << tl::to_string (QObject::tr ("@method without preceeding @class"));
} } else {
std::string n; std::string n;
ex.read_word_or_quoted (n); ex.read_word_or_quoted (n);
std::string doc; std::string doc;
while (++i < lines.size ()) { while (++i < lines.size ()) {
std::string l = tl::trim (lines [i]); std::string l = tl::trim (lines [i]);
if (l.find ("@method") == 0 || l.find ("@static_method") == 0) { if (l.find ("@method") == 0 || l.find ("@static_method") == 0) {
break; break;
}
if (! doc.empty ()) {
doc += "\n";
}
doc += lines [i];
} }
if (! doc.empty ()) { --i;
doc += "\n";
}
doc += lines [i];
}
--i;
ExternalMethod *meth = new ExternalMethod (n, doc, false, st); ExternalMethod *meth = new ExternalMethod (n, doc, false, st);
cls->add_method (meth); cls->add_method (meth);
}
} }

View File

@ -1945,7 +1945,11 @@ property_setter_impl (int mid, PyObject *self, PyObject *value)
if (meth->is_signal ()) { if (meth->is_signal ()) {
if (PyObject_IsInstance (value, (PyObject *) PYASignal::cls)) { if (!p) {
// TODO: Static signals?
} else if (PyObject_IsInstance (value, (PyObject *) PYASignal::cls)) {
// assigning a signal to a signal works if it applies to the same handler - // assigning a signal to a signal works if it applies to the same handler -
// this simplifies the implementation of += and -=. // this simplifies the implementation of += and -=.

View File

@ -2270,6 +2270,7 @@ RubyInterpreter::begin_exec ()
{ {
d->exit_on_next = false; d->exit_on_next = false;
d->block_exceptions = false; d->block_exceptions = false;
d->file_id_map.clear ();
if (d->current_exec_level++ == 0 && d->current_exec_handler) { if (d->current_exec_level++ == 0 && d->current_exec_handler) {
d->current_exec_handler->start_exec (this); d->current_exec_handler->start_exec (this);
} }

View File

@ -495,7 +495,7 @@ public:
bool compare (const ValueBase *other) const bool compare (const ValueBase *other) const
{ {
return m_value < dynamic_cast<const Value<C> *> (other)->m_value; return m_value < static_cast<const Value<C> *> (other)->m_value;
} }
std::string to_string () const; std::string to_string () const;

View File

@ -1,67 +1,132 @@
<ui version="4.0" > <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PasswordDialog</class> <class>PasswordDialog</class>
<widget class="QDialog" name="PasswordDialog" > <widget class="QDialog" name="PasswordDialog">
<property name="geometry" > <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>338</width> <width>338</width>
<height>230</height> <height>229</height>
</rect> </rect>
</property> </property>
<property name="windowTitle" > <property name="windowTitle">
<string>Authentication Required</string> <string>Authentication Required</string>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout">
<property name="margin" > <property name="leftMargin">
<number>9</number> <number>9</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="5" column="1" > <item row="8" column="1" colspan="2">
<widget class="QLabel" name="label_3" > <spacer>
<property name="text" > <property name="orientation">
<string>Password </string> <enum>Qt::Vertical</enum>
</property> </property>
</widget> <property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item> </item>
<item row="5" column="2" > <item row="7" column="2">
<widget class="QLineEdit" name="password_le" > <widget class="QLineEdit" name="password_le">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="echoMode" > <property name="echoMode">
<enum>QLineEdit::Password</enum> <enum>QLineEdit::Password</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="2" > <item row="6" column="1">
<widget class="QLineEdit" name="user_le" > <widget class="QLabel" name="label">
<property name="sizePolicy" > <property name="text">
<sizepolicy> <string>User</string>
<hsizetype>5</hsizetype> </property>
<vsizetype>0</vsizetype> </widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Password </string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLineEdit" name="user_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0" > <item row="9" column="0" colspan="4">
<spacer> <widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation" > <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeType" > <property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="2" colspan="4">
<widget class="QLabel" name="realm_label">
<property name="text">
<string>-</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum> <enum>QSizePolicy::Expanding</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0">
<size> <size>
<width>10</width> <width>10</width>
<height>20</height> <height>20</height>
@ -69,35 +134,62 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="4" column="1" > <item row="4" column="1" colspan="3">
<widget class="QLabel" name="label" > <widget class="QLabel" name="attempt_label">
<property name="text" > <property name="palette">
<string>User</string> <palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string># of attempt</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1" colspan="2" > <item row="6" column="3">
<spacer> <spacer>
<property name="orientation" > <property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="3" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0">
<size> <size>
<width>40</width> <width>40</width>
<height>20</height> <height>20</height>
@ -105,51 +197,31 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="7" column="0" colspan="4" > <item row="2" column="0" colspan="4">
<widget class="QDialogButtonBox" name="buttonBox" > <widget class="QLabel" name="where_label">
<property name="orientation" > <property name="text">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4" >
<widget class="QLabel" name="where_label" >
<property name="text" >
<string>-</string> <string>-</string>
</property> </property>
<property name="alignment" > <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<property name="wordWrap" > <property name="wordWrap">
<bool>false</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item rowspan="2" row="0" column="0" colspan="4" > <item row="5" column="1" colspan="2">
<widget class="QLabel" name="realm_label" > <spacer name="verticalSpacer">
<property name="text" > <property name="orientation">
<string>-</string>
</property>
<property name="alignment" >
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="1" colspan="2" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>0</height> <height>10</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -169,11 +241,11 @@
<receiver>PasswordDialog</receiver> <receiver>PasswordDialog</receiver>
<slot>accept()</slot> <slot>accept()</slot>
<hints> <hints>
<hint type="sourcelabel" > <hint type="sourcelabel">
<x>248</x> <x>248</x>
<y>254</y> <y>254</y>
</hint> </hint>
<hint type="destinationlabel" > <hint type="destinationlabel">
<x>157</x> <x>157</x>
<y>274</y> <y>274</y>
</hint> </hint>
@ -185,11 +257,11 @@
<receiver>PasswordDialog</receiver> <receiver>PasswordDialog</receiver>
<slot>reject()</slot> <slot>reject()</slot>
<hints> <hints>
<hint type="sourcelabel" > <hint type="sourcelabel">
<x>316</x> <x>316</x>
<y>260</y> <y>260</y>
</hint> </hint>
<hint type="destinationlabel" > <hint type="destinationlabel">
<x>286</x> <x>286</x>
<y>274</y> <y>274</y>
</hint> </hint>

View File

@ -54,13 +54,20 @@ public:
setupUi (this); setupUi (this);
} }
bool exec_auth (bool proxy, const QString &where, QAuthenticator *auth) bool exec_auth (bool proxy, int attempt, const QString &where, QAuthenticator *auth)
{ {
realm_label->setText (QString::fromUtf8 ("<b>Realm:</b> ") + auth->realm ()); realm_label->setText (tr ("<b>Realm:</b> ") + auth->realm ());
if (proxy) { if (proxy) {
where_label->setText (QString::fromUtf8 ("<b>Proxy:</b> ") + where); where_label->setText (tr ("<b>Proxy:</b> ") + where);
} else { } else {
where_label->setText (QString::fromUtf8 ("<b>URL:</b> ") + where); where_label->setText (tr ("<b>URL:</b> ") + where);
}
if (attempt > 1) {
attempt_label->setText (tr ("Authentication failed - please try again"));
attempt_label->show ();
} else {
attempt_label->hide ();
} }
if (QDialog::exec ()) { if (QDialog::exec ()) {
@ -78,23 +85,30 @@ public:
// AuthenticationHandler implementation // AuthenticationHandler implementation
AuthenticationHandler::AuthenticationHandler () AuthenticationHandler::AuthenticationHandler ()
: QObject (0) : QObject (0), m_retry (0), m_proxy_retry (0)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
void
AuthenticationHandler::reset ()
{
m_retry = 0;
m_proxy_retry = 0;
}
void void
AuthenticationHandler::authenticationRequired (QNetworkReply *reply, QAuthenticator *auth) AuthenticationHandler::authenticationRequired (QNetworkReply *reply, QAuthenticator *auth)
{ {
PasswordDialog pw_dialog (0 /*no parent*/); PasswordDialog pw_dialog (0 /*no parent*/);
pw_dialog.exec_auth (false, reply->url ().toString (), auth); pw_dialog.exec_auth (false, ++m_retry, reply->url ().toString (), auth);
} }
void void
AuthenticationHandler::proxyAuthenticationRequired (const QNetworkProxy &proxy, QAuthenticator *auth) AuthenticationHandler::proxyAuthenticationRequired (const QNetworkProxy &proxy, QAuthenticator *auth)
{ {
PasswordDialog pw_dialog (0 /*no parent*/); PasswordDialog pw_dialog (0 /*no parent*/);
pw_dialog.exec_auth (true, proxy.hostName (), auth); pw_dialog.exec_auth (true, ++m_proxy_retry, proxy.hostName (), auth);
} }
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -176,6 +190,9 @@ InputHttpStream::issue_request (const QUrl &url)
delete mp_buffer; delete mp_buffer;
mp_buffer = 0; mp_buffer = 0;
// reset the retry counters -> this way we can detect authentication failures
s_auth_handler->reset ();
QNetworkRequest request (url); QNetworkRequest request (url);
if (tl::verbosity() >= 30) { if (tl::verbosity() >= 30) {
tl::info << "HTTP request URL: " << url.toString ().toUtf8 ().constData (); tl::info << "HTTP request URL: " << url.toString ().toUtf8 ().constData ();
@ -230,17 +247,42 @@ InputHttpStream::read (char *b, size_t n)
} }
if (mp_reply->error () != QNetworkReply::NoError) { if (mp_reply->error () != QNetworkReply::NoError) {
// throw an error // throw an error
std::string em = tl::to_string (mp_reply->attribute (QNetworkRequest::HttpReasonPhraseAttribute).toString ()); std::string em = tl::to_string (mp_reply->attribute (QNetworkRequest::HttpReasonPhraseAttribute).toString ());
if (tl::verbosity() >= 30) { if (tl::verbosity() >= 30) {
tl::info << "HTTP response error: " << em; tl::info << "HTTP response error: " << em;
} }
int ec = mp_reply->attribute (QNetworkRequest::HttpStatusCodeAttribute).toInt (); int ec = mp_reply->attribute (QNetworkRequest::HttpStatusCodeAttribute).toInt ();
if (ec == 0) { if (ec == 0) {
switch (mp_reply->error ()) {
case QNetworkReply::ConnectionRefusedError:
em = tl::to_string (QObject::tr ("Connection refused"));
break;
case QNetworkReply::RemoteHostClosedError:
em = tl::to_string (QObject::tr ("Remote host closed connection"));
break;
case QNetworkReply::HostNotFoundError:
em = tl::to_string (QObject::tr ("Host not found"));
break;
case QNetworkReply::TimeoutError:
em = tl::to_string (QObject::tr ("Timeout"));
break;
case QNetworkReply::ContentAccessDenied:
em = tl::to_string (QObject::tr ("Access denied"));
break;
case QNetworkReply::ContentNotFoundError:
em = tl::to_string (QObject::tr ("Content not found"));
break;
default:
em = tl::to_string (QObject::tr ("Network API error"));
}
ec = int (mp_reply->error ()); ec = int (mp_reply->error ());
em = tl::to_string (QObject::tr ("Network API error"));
} }
throw HttpErrorException (em, ec, m_url); throw HttpErrorException (em, ec, m_url);
} }
QByteArray data = mp_reply->read (n); QByteArray data = mp_reply->read (n);

View File

@ -60,6 +60,10 @@ public:
public slots: public slots:
void authenticationRequired (QNetworkReply *, QAuthenticator *); void authenticationRequired (QNetworkReply *, QAuthenticator *);
void proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *); void proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *);
void reset ();
private:
int m_retry, m_proxy_retry;
}; };
/** /**

View File

@ -213,7 +213,7 @@ public:
++lb0; ++lb0;
} }
--lb; --lb;
if (lb != m_index_map.end () && i2 < lb->first.second) { if (i2 < lb->first.second) {
// the last one is overlapping above i2: cut it // the last one is overlapping above i2: cut it
lb->first.first = i2; lb->first.first = i2;
} else { } else {

View File

@ -424,17 +424,20 @@ JobBase::schedule (Task *task)
{ {
m_lock.lock (); m_lock.lock ();
// Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition)
if (m_stopping) { if (m_stopping) {
m_lock.unlock ();
throw TaskTerminatedException ();
}
// Add the task to the task queue // Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition)
m_task_list.put (task); delete task;
} else {
// Add the task to the task queue
m_task_list.put (task);
if (m_running) {
m_task_available_condition.wakeAll ();
}
if (m_running) {
m_task_available_condition.wakeAll ();
} }
m_lock.unlock (); m_lock.unlock ();

View File

@ -1298,7 +1298,7 @@ Variant::can_convert_to_long () const
case t_double: case t_double:
return m_var.m_double <= std::numeric_limits<long>::max () && m_var.m_double >= std::numeric_limits<long>::min (); return m_var.m_double <= std::numeric_limits<long>::max () && m_var.m_double >= std::numeric_limits<long>::min ();
case t_float: case t_float:
return m_var.m_float <= std::numeric_limits<long>::max () && m_var.m_float >= std::numeric_limits<long>::min (); return m_var.m_float <= float (std::numeric_limits<long>::max ()) && m_var.m_float >= float (std::numeric_limits<long>::min ());
#if defined(HAVE_64BIT_COORD) #if defined(HAVE_64BIT_COORD)
case t_int128: case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<long>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<long>::min ()); return m_var.m_int128 <= __int128 (std::numeric_limits<long>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<long>::min ());

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -53,19 +53,24 @@ class BoxPCell(pya.PCellDeclaration):
# create the shape # create the shape
cell.shapes(layers[0]).insert(pya.Box(-w / 2, -h / 2, w / 2, h / 2)) cell.shapes(layers[0]).insert(pya.Box(-w / 2, -h / 2, w / 2, h / 2))
def can_create_from_shape(self, layout, shape, layer):
return shape.is_box()
def transformation_from_shape(self, layout, shape, layer):
return pya.Trans(shape.box.center() - pya.Point())
def parameters_from_shape(self, layout, shape, layer):
return [ layout.get_info(layer), shape.box.width() * layout.dbu, shape.box.height() * layout.dbu ]
class PCellTestLib(pya.Library): class PCellTestLib(pya.Library):
boxpcell = None
def __init__(self): def __init__(self):
# set the description # set the description
self.description = "PCell test lib" self.description = "PCell test lib"
# create the PCell declarations # create the PCell declarations
boxpcell = BoxPCell() self.layout().register_pcell("Box", BoxPCell())
self.layout().register_pcell("Box", boxpcell)
sb_index = self.layout().add_cell("StaticBox") sb_index = self.layout().add_cell("StaticBox")
l10 = self.layout().insert_layer(pya.LayerInfo(10, 0)) l10 = self.layout().insert_layer(pya.LayerInfo(10, 0))
@ -75,6 +80,60 @@ class PCellTestLib(pya.Library):
# register us with the name "MyLib" # register us with the name "MyLib"
self.register("PCellTestLib") self.register("PCellTestLib")
# A PCell based on the declaration helper
class BoxPCell2(pya.PCellDeclarationHelper):
def __init__(self):
super(BoxPCell2, self).__init__()
self.param("layer", self.TypeLayer, "Layer", default = pya.LayerInfo(0, 0))
self.param("width", self.TypeDouble, "Width", default = 1.0)
self.param("height", self.TypeDouble, "Height", default = 1.0)
def display_text_impl(self):
# provide a descriptive text for the cell
return "Box2(L=" + str(self.layer) + ",W=" + ('%.3f' % self.width) + ",H=" + ('%.3f' % self.height) + ")"
def produce_impl(self):
dbu = self.layout.dbu
# fetch the parameters
l = self.layer_layer
w = self.width / self.layout.dbu
h = self.height / self.layout.dbu
# create the shape
self.cell.shapes(l).insert(pya.Box(-w / 2, -h / 2, w / 2, h / 2))
def can_create_from_shape_impl(self):
return self.shape.is_box()
def transformation_from_shape_impl(self):
return pya.Trans(self.shape.box.center() - pya.Point())
def parameters_from_shape_impl(self):
self.layer = self.layout.get_info(self.layer)
self.width = self.shape.box.width() * self.layout.dbu
self.height = self.shape.box.height() * self.layout.dbu
class PCellTestLib2(pya.Library):
def __init__(self):
# set the description
self.description = "PCell test lib2"
# create the PCell declarations
self.layout().register_pcell("Box2", BoxPCell2())
# register us with the name "MyLib"
self.register("PCellTestLib2")
def inspect_LayerInfo(self): def inspect_LayerInfo(self):
return "<" + str(self) + ">" return "<" + str(self) + ">"
@ -233,6 +292,75 @@ class DBPCellTests(unittest.TestCase):
pcell_inst.cell_index = new_id pcell_inst.cell_index = new_id
self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-500,-100;500,100)") self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-500,-100;500,100)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(pya.Box(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(pya.Text("hello", pya.Trans()))
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False)
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True)
self.assertEqual(repr(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]")
self.assertEqual(str(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110")
def test_1a(self):
# instantiate and register the library
tl = PCellTestLib2()
ly = pya.Layout(True)
ly.dbu = 0.01
li1 = find_layer(ly, "1/0")
self.assertEqual(li1 == None, True)
ci1 = ly.add_cell("c1")
c1 = ly.cell(ci1)
lib = pya.Library.library_by_name("PCellTestLib2")
self.assertEqual(lib != None, True)
pcell_decl = lib.layout().pcell_declaration("Box2")
param = [ pya.LayerInfo(1, 0) ] # rest is filled with defaults
pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param)
pcell_var = ly.cell(pcell_var_id)
pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans()))
self.assertEqual(pcell_var.basic_name(), "Box2")
self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]")
self.assertEqual(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)")
self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(pcell_var.pcell_parameter("height").__repr__(), "1.0")
self.assertEqual(c1.pcell_parameters(pcell_inst).__repr__(), "[<1/0>, 1.0, 1.0]")
self.assertEqual(nh(c1.pcell_parameters_by_name(pcell_inst)), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(c1.pcell_parameter(pcell_inst, "height").__repr__(), "1.0")
self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(pcell_inst["height"].__repr__(), "1.0")
self.assertEqual(pcell_inst.pcell_parameter("height").__repr__(), "1.0")
self.assertEqual(pcell_var.pcell_declaration().__repr__(), pcell_decl.__repr__())
self.assertEqual(c1.pcell_declaration(pcell_inst).__repr__(), pcell_decl.__repr__())
self.assertEqual(pcell_inst.pcell_declaration().__repr__(), pcell_decl.__repr__())
li1 = find_layer(ly, "1/0")
self.assertEqual(li1 == None, False)
pcell_inst.change_pcell_parameter("height", 2.0)
self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 2.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-50,-100;50,100)")
param = { "layer": pya.LayerInfo(2, 0), "width": 2, "height": 1 }
li2 = ly.layer(2, 0)
c1.change_pcell_parameters(pcell_inst, param)
self.assertEqual(ly.begin_shapes(c1.cell_index(), li2).shape().__str__(), "box (-100,-50;100,50)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(pya.Box(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(pya.Text("hello", pya.Trans()))
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False)
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True)
self.assertEqual(repr(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]")
self.assertEqual(str(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110")
def test_2(self): def test_2(self):
# instantiate and register the library # instantiate and register the library

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,18 @@ class BoxPCell < RBA::PCellDeclaration
end end
def can_create_from_shape(layout, shape, layer)
return shape.is_box?
end
def transformation_from_shape(layout, shape, layer)
return RBA::Trans::new(shape.box.center - RBA::Point::new)
end
def parameters_from_shape(layout, shape, layer)
return [ layout.get_info(layer), shape.box.width * layout.dbu, shape.box.height * layout.dbu ]
end
end end
class PCellTestLib < RBA::Library class PCellTestLib < RBA::Library
@ -85,6 +97,72 @@ class PCellTestLib < RBA::Library
end end
# A PCell based on the declaration helper
class BoxPCell2 < RBA::PCellDeclarationHelper
def initialize
super()
param("layer", BoxPCell2::TypeLayer, "Layer", :default => RBA::LayerInfo::new(0, 0))
param("width", BoxPCell2::TypeDouble, "Width", :default => 1.0)
param("height", BoxPCell2::TypeDouble, "Height", :default => 1.0)
end
def display_text_impl
# provide a descriptive text for the cell
return "Box2(L=" + layer.to_s + ",W=" + ('%.3f' % width) + ",H=" + ('%.3f' % height) + ")"
end
def produce_impl
# fetch the parameters
l = layer_layer
w = width / layout.dbu
h = height / layout.dbu
# create the shape
cell.shapes(l).insert(RBA::Box::new(-w / 2, -h / 2, w / 2, h / 2))
end
def can_create_from_shape_impl
return self.shape.is_box?
end
def transformation_from_shape_impl
return RBA::Trans::new(shape.box.center - RBA::Point::new)
end
def parameters_from_shape_impl
# NOTE: because there is one parameter called "layer" already, we need to use
# the "_layer" fallback to access the argument to this method
set_layer(_layout.get_info(_layer))
set_width(shape.box.width * _layout.dbu)
set_height(shape.box.height * _layout.dbu)
end
end
class PCellTestLib2 < RBA::Library
def initialize
# set the description
description = "PCell test lib2"
# create the PCell declarations
layout.register_pcell("Box2", BoxPCell2::new)
# register us with the name "MyLib"
self.register("PCellTestLib2")
end
end
# A helper for testing: provide an inspect method # A helper for testing: provide an inspect method
class RBA::LayerInfo class RBA::LayerInfo
def inspect def inspect
@ -115,8 +193,7 @@ class DBPCell_TestClass < TestBase
ly = RBA::Layout::new(true) ly = RBA::Layout::new(true)
ly.dbu = 0.01 ly.dbu = 0.01
li1 = ly.layer_indices.find { |li| ly.get_info(li).to_s == "1/0" } li1 = ly.layer(1, 0)
assert_equal(li1 == nil, true)
ci1 = ly.add_cell("c1") ci1 = ly.add_cell("c1")
c1 = ly.cell(ci1) c1 = ly.cell(ci1)
@ -241,10 +318,84 @@ class DBPCell_TestClass < TestBase
pcell_inst.cell_index = new_id pcell_inst.cell_index = new_id
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-500,-100;500,100)") assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-500,-100;500,100)")
#ly.destroy l10 = ly.layer(10, 0)
c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new))
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0]")
assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110")
ly.destroy
ensure ensure
#tl.delete tl.delete
end
end
def test_1a
# instantiate and register the library
tl = PCellTestLib2::new
begin
ly = RBA::Layout::new(true)
ly.dbu = 0.01
ci1 = ly.add_cell("c1")
c1 = ly.cell(ci1)
lib = RBA::Library.library_by_name("PCellTestLib2")
assert_equal(lib != nil, true)
pcell_decl = lib.layout().pcell_declaration("Box2")
param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults
pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param)
pcell_var = ly.cell(pcell_var_id)
pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new))
assert_equal(pcell_var.basic_name, "Box2")
assert_equal(pcell_var.pcell_parameters().inspect, "[<1/0>, 1.0, 1.0]")
assert_equal(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)")
assert_equal(norm_hash(pcell_var.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(pcell_var.pcell_parameter("height").inspect(), "1.0")
assert_equal(c1.pcell_parameters(pcell_inst).inspect(), "[<1/0>, 1.0, 1.0]")
assert_equal(norm_hash(c1.pcell_parameters_by_name(pcell_inst)), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(c1.pcell_parameter(pcell_inst, "height").inspect(), "1.0")
assert_equal(norm_hash(pcell_inst.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(pcell_inst["height"].inspect(), "1.0")
assert_equal(pcell_inst.pcell_parameter("height").inspect(), "1.0")
assert_equal(pcell_var.pcell_declaration().inspect(), pcell_decl.inspect)
assert_equal(c1.pcell_declaration(pcell_inst).inspect(), pcell_decl.inspect)
assert_equal(pcell_inst.pcell_declaration().inspect(), pcell_decl.inspect)
li1 = ly.layer(1, 0)
assert_equal(li1 == nil, false)
pcell_inst.change_pcell_parameter("height", 2.0)
assert_equal(norm_hash(pcell_inst.pcell_parameters_by_name()), "{\"height\"=>2.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(ly.begin_shapes(c1.cell_index(), li1).shape().to_s, "box (-50,-100;50,100)")
param = { "layer" => RBA::LayerInfo::new(2, 0), "width" => 2, "height" => 1 }
li2 = ly.layer(2, 0)
c1.change_pcell_parameters(pcell_inst, param)
assert_equal(ly.begin_shapes(c1.cell_index(), li2).shape().to_s, "box (-100,-50;100,50)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new))
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0]")
assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110")
ly.destroy
ensure
tl.delete
end end
end end