mirror of https://github.com/KLayout/klayout.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
33139dd40c
|
|
@ -1,12 +1,12 @@
|
|||
klayout is packaged by Peter C.S. Scholtens <peter.scholtens@xs4all.nl>
|
||||
and Matthias Köfferlein <matthias@koefferlein.de>
|
||||
and was obtained from http://klayout.de/klayout-0.25.tar.gz
|
||||
and was obtained from https://www.klayout.org/downloads/source/klayout-0.25.1.tar.gz
|
||||
|
||||
Authors:
|
||||
Matthias Köfferlein
|
||||
|
||||
Copyright:
|
||||
Copyright (C) 2006-2017 by Matthias Köfferlein.
|
||||
Copyright (C) 2006-2018 by Matthias Köfferlein.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
|||
44
Changelog
44
Changelog
|
|
@ -1,3 +1,47 @@
|
|||
0.25.1 (2018-02-23):
|
||||
* Enhancements: build compatibility with MacOS, Qt 5.9.
|
||||
Qt 4.6+4.7 supported as well with restrictions:
|
||||
the package installation feature is not working.
|
||||
* Bugfix: Package manager
|
||||
- Remove button wasn't enabled if multiple packages were selected
|
||||
- A potential crash ob removing packages was fixed
|
||||
* Enhancement: 64 bit coordinate support enabled on Windows builds
|
||||
* Further bugfixes: See links
|
||||
- https://github.com/klayoutmatthias/klayout/issues/21 (Autorun(-early) doesn't seem to run when lym files are inside a package)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/24 (Text insert dialog possible)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/26 (Exceptions are reported every time they propagate up in the call chain in the ruby debugger)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/28 (CIF format detection failed)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/30 (Writer options dialog non-functional on a fresh configuration)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/32 (rounding issue with instance properties)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/33 (Plugin factory not working when using with Python)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/36 (hardening against destruction of object inside event handler)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/39 (Action cannot be reassigned)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/40 (Crash in Python binding)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/41 (Polygon#touches? issue)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/42 (headless mode support with Qt5/-zz)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/43 (crash when using Qt specific command line options)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/44 (Transformation constructor with x,y not working)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/45 (Partial selection does not capture instance)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/48 (Cancel does not reset current tool)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/51 (Segmentation fault on return to main window and other opportunities)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/53 (unreadable 'about' text)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/59 (async download of package index and details)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/62 (QXmlSimpleReader#parse cannot be called)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/63 (wrong output on DRC non_interacting with empty second input)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/64 (crash on exit)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/68 (OASIS reader issue with degenerated shapes)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/69 (DRC: 'inside' does not merge shapes of second input)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/71 (target cell argument is required)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/72 (Edges/Region NOT issue)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/73 (allow 'change layers' on PCells which support a single layer parameter)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/74 (small-corner boolean issue)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/75 (Python PCell issue when parameters are called 'layer')
|
||||
- https://github.com/klayoutmatthias/klayout/issues/79 (Replace function enabled also for read-only macros)
|
||||
* Further enhancements: see links
|
||||
- https://github.com/klayoutmatthias/klayout/issues/29 (permissive mode for OASIS writer on odd-width paths)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/66 (Authentication dialog indicates retry)
|
||||
- https://github.com/klayoutmatthias/klayout/issues/77 (copy_tree works in non-editable mode too)
|
||||
|
||||
0.25 (2017-11-04):
|
||||
* Enhancement: Menu customization
|
||||
Menu items can be disabled or enabled now. The former
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
klayout (0.25.1-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Thu, 22 Feb 2018 22:52:56 +0100
|
||||
|
||||
klayout (0.25-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
|
|
|
|||
|
|
@ -343,7 +343,6 @@ Object::class_name () const
|
|||
void
|
||||
Object::from_string (const char *s)
|
||||
{
|
||||
printf("@@@ %s\n", s); fflush(stdout);
|
||||
tl::Extractor ex (s);
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
|
|
|
|||
|
|
@ -1035,7 +1035,7 @@ public:
|
|||
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
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
|
||||
|
||||
@brief Gets the initial PCell instance transformation when creating from a shape
|
||||
|
|
@ -230,6 +237,13 @@ module RBA
|
|||
|
||||
# provide accessors for the current layout and cell (for prod)
|
||||
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
|
||||
# name -> the short name of the parameter
|
||||
|
|
@ -246,6 +260,12 @@ module RBA
|
|||
# set_{name} -> write accessor ({name}= does not work because the
|
||||
# Ruby confuses that method with variables)
|
||||
# {name}_layer -> 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 = {})
|
||||
|
||||
# create accessor methods for the parameters
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class MyPCell(pya.PCellDeclarationHelper):
|
|||
def __init__(self):
|
||||
|
||||
# Important: initialize the super class
|
||||
super(Circle, self).__init__()
|
||||
super(MyPCell, self).__init__()
|
||||
|
||||
# your initialization: add parameters with name, type, description and
|
||||
# optional other values
|
||||
|
|
@ -226,16 +226,27 @@ class _PCellDeclarationHelperLayerDescriptor(object):
|
|||
class _PCellDeclarationHelperParameterDescriptor(object):
|
||||
"""
|
||||
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):
|
||||
self.param_index = param_index
|
||||
self.value = 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):
|
||||
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):
|
||||
"""
|
||||
|
|
@ -321,7 +332,38 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
|
|||
gets the parameters
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
get the layer definitions
|
||||
|
|
@ -335,25 +377,23 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
|
|||
"""
|
||||
coerce parameters (make consistent)
|
||||
"""
|
||||
self._param_values = parameters
|
||||
self.init_values(parameters)
|
||||
self.layout = layout
|
||||
self.coerce_parameters_impl()
|
||||
self.layout = None
|
||||
return self._param_values
|
||||
return self.get_values()
|
||||
|
||||
def produce(self, layout, layers, parameters, cell):
|
||||
"""
|
||||
coerce parameters (make consistent)
|
||||
"""
|
||||
self._layers = layers
|
||||
self.init_values(parameters, layers)
|
||||
self.cell = cell
|
||||
self._param_values = parameters
|
||||
self.layout = layout
|
||||
self.produce_impl()
|
||||
self._layers = None
|
||||
self.cell = None
|
||||
self._param_values = None
|
||||
self.layout = None
|
||||
self.finish()
|
||||
|
||||
def can_create_from_shape(self, layout, shape, layer):
|
||||
"""
|
||||
|
|
@ -386,17 +426,16 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
|
|||
produce a helper for parameters_from_shape
|
||||
with this helper, the implementation can use the parameter setters
|
||||
"""
|
||||
self._param_values = []
|
||||
for pd in self._param_decls:
|
||||
self._param_values.append(pd.default)
|
||||
self.init_values()
|
||||
self.layout = layout
|
||||
self.shape = shape
|
||||
self.layer = layer
|
||||
self.parameters_from_shape_impl()
|
||||
param = self.get_values()
|
||||
self.layout = None
|
||||
self.shape = None
|
||||
self.layer = None
|
||||
return self._param_values
|
||||
return param
|
||||
|
||||
def display_text_impl(self):
|
||||
"""
|
||||
|
|
@ -432,7 +471,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
|
|||
"""
|
||||
default implementation
|
||||
"""
|
||||
return pya.Trans.new
|
||||
return pya.Trans()
|
||||
|
||||
# import the Type... constants from PCellParameterDeclaration
|
||||
for k in dir(pya.PCellParameterDeclaration):
|
||||
|
|
|
|||
|
|
@ -1349,13 +1349,17 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
// 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 (ip_weak.size () > 1 || !on_edge1) {
|
||||
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 ());
|
||||
|
|
@ -1435,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.
|
||||
// In that case we can skip the cutpoint because no related edge will move.
|
||||
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) {
|
||||
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 (ip_weak.size () > 1 || !on_edge1 || !on_edge2) {
|
||||
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 ());
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
Layout::defining_library (cell_index_type cell_index) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -881,11 +881,22 @@ public:
|
|||
*/
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -110,6 +110,18 @@ OASISReader::OASISReader (tl::InputStream &s)
|
|||
{
|
||||
m_progress.set_format (tl::to_string (QObject::tr ("%.0f MB")));
|
||||
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 ()
|
||||
|
|
@ -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
|
||||
OASISReader::get_ulong ()
|
||||
{
|
||||
|
|
@ -295,21 +317,21 @@ OASISReader::get_real ()
|
|||
|
||||
} else if (t == 2) {
|
||||
|
||||
return 1.0 / double (get_ulong ());
|
||||
return 1.0 / double (get_ulong_for_divider ());
|
||||
|
||||
} else if (t == 3) {
|
||||
|
||||
return -1.0 / double (get_ulong ());
|
||||
return -1.0 / double (get_ulong_for_divider ());
|
||||
|
||||
} else if (t == 4) {
|
||||
|
||||
double d = double (get_ulong ());
|
||||
return d / double (get_ulong ());
|
||||
return d / double (get_ulong_for_divider ());
|
||||
|
||||
} else if (t == 5) {
|
||||
|
||||
double d = double (get_ulong ());
|
||||
return -d / double (get_ulong ());
|
||||
return -d / double (get_ulong_for_divider ());
|
||||
|
||||
} else if (t == 6) {
|
||||
|
||||
|
|
|
|||
|
|
@ -318,6 +318,7 @@ private:
|
|||
unsigned long long get_ulong_long ();
|
||||
long get_long ();
|
||||
unsigned long get_ulong ();
|
||||
unsigned long get_ulong_for_divider ();
|
||||
int get_int ();
|
||||
unsigned int get_uint ();
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
||||
} 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> ()) {
|
||||
|
||||
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> ()) {
|
||||
|
||||
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)));
|
||||
|
||||
} 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> ()) {
|
||||
|
||||
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
|
||||
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> ()) {
|
||||
|
||||
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)));
|
||||
|
||||
} 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)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ Reader::Reader (tl::InputStream &stream)
|
|||
}
|
||||
|
||||
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 ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,6 +276,8 @@ RecursiveShapeIterator::init ()
|
|||
m_shape_inv_prop_sel = false;
|
||||
m_inst_quad_id = 0;
|
||||
m_shape_quad_id = 0;
|
||||
mp_cell = 0;
|
||||
m_current_layer = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
check_is_editable (c);
|
||||
|
||||
db::properties_id_type id = c->prop_id ();
|
||||
if (id == 0) {
|
||||
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)
|
||||
{
|
||||
check_is_editable (c);
|
||||
|
||||
db::properties_id_type id = c->prop_id ();
|
||||
|
||||
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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
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
|
||||
clear_all (db::Cell *cell)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
cell->clear_shapes ();
|
||||
cell->clear_insts ();
|
||||
}
|
||||
|
|
@ -1166,7 +1159,6 @@ clear_all (db::Cell *cell)
|
|||
static void
|
||||
delete_cell (db::Cell *cell)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
db::Layout *layout = cell->layout ();
|
||||
if (layout) {
|
||||
layout->delete_cell (cell->cell_index ());
|
||||
|
|
@ -1176,7 +1168,6 @@ delete_cell (db::Cell *cell)
|
|||
static void
|
||||
prune_subcells (db::Cell *cell, int levels)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
db::Layout *layout = cell->layout ();
|
||||
if (layout) {
|
||||
layout->prune_subcells (cell->cell_index (), levels);
|
||||
|
|
@ -1192,7 +1183,6 @@ prune_subcells0 (db::Cell *cell)
|
|||
static void
|
||||
prune_cell (db::Cell *cell, int levels)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
db::Layout *layout = cell->layout ();
|
||||
if (layout) {
|
||||
layout->prune_cell (cell->cell_index (), levels);
|
||||
|
|
@ -1208,7 +1198,6 @@ prune_cell0 (db::Cell *cell)
|
|||
static void
|
||||
flatten (db::Cell *cell, int levels, bool prune)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
db::Layout *layout = cell->layout ();
|
||||
if (layout) {
|
||||
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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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)
|
||||
{
|
||||
check_is_editable (cell);
|
||||
|
||||
if (cell == &source_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
|
||||
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) {
|
||||
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,
|
||||
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) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)")));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2244,3 +2244,54 @@ TEST(100)
|
|||
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)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ struct A : public db::Object
|
|||
void redo (db::Op *op) throw ()
|
||||
{
|
||||
AO *aop = dynamic_cast<AO *> (op);
|
||||
tl_assert (aop != 0);
|
||||
x += aop->d;
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +163,7 @@ struct B : public db::Object
|
|||
void redo (db::Op *op) throw ()
|
||||
{
|
||||
BO *bop = dynamic_cast<BO *> (op);
|
||||
tl_assert (bop != 0);
|
||||
x += bop->d;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3922,9 +3922,9 @@ CODE
|
|||
n = $1.to_i - 1
|
||||
view = RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n}")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
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)
|
||||
else
|
||||
layout = RBA::Layout::new
|
||||
|
|
@ -4016,9 +4016,9 @@ CODE
|
|||
n = $1.to_i - 1
|
||||
view = RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n}")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
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)
|
||||
else
|
||||
layout = RBA::Layout::new
|
||||
|
|
@ -4173,9 +4173,9 @@ CODE
|
|||
n = $1.to_i - 1
|
||||
view = RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n}")
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
cv = view.cellview(n)
|
||||
cv.is_valid? || raise("Invalid layout @#{n}")
|
||||
cv.is_valid? || raise("Invalid layout @#{n + 1}")
|
||||
@output_layout = cv.layout
|
||||
@output_cell = cellname ? (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s)) : cv.cell
|
||||
@output_layout_file = nil
|
||||
|
|
@ -4694,11 +4694,20 @@ CODE
|
|||
|
||||
else
|
||||
|
||||
output = @output_layout || @def_layout
|
||||
output || raise("No output layout specified")
|
||||
|
||||
output_cell = @output_cell || @def_cell
|
||||
output_cell || raise("No output cell specified")
|
||||
if @output_layout
|
||||
output = @output_layout
|
||||
if @output_cell
|
||||
output_cell = @output_cell
|
||||
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
|
||||
if args.size == 1
|
||||
|
|
|
|||
|
|
@ -1084,23 +1084,29 @@ MainService::cm_convert_to_pcell ()
|
|||
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) {
|
||||
|
||||
const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second);
|
||||
size_t n = 1000; // 1000 tries max.
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) {
|
||||
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) {
|
||||
const lay::CellView &cv = view ()->cellview (s->cv_index ());
|
||||
if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) {
|
||||
--n;
|
||||
} else {
|
||||
pc_decl = 0; // stop
|
||||
try {
|
||||
|
||||
const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second);
|
||||
size_t n = 1000; // 1000 tries max.
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) {
|
||||
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) {
|
||||
const lay::CellView &cv = view ()->cellview (s->cv_index ());
|
||||
if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) {
|
||||
--n;
|
||||
} else {
|
||||
pc_decl = 0; // stop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have positive hit
|
||||
if (pc_decl) {
|
||||
pcells.push_back (std::make_pair (lib, pc->second));
|
||||
items.push_back (tl::to_qstring (lib->get_name () + "." + pc_decl->name ()));
|
||||
// We have positive hit
|
||||
if (pc_decl) {
|
||||
pcells.push_back (std::make_pair (lib, pc->second));
|
||||
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
|
||||
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) {
|
||||
if (! s->is_cell_inst ()) {
|
||||
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.")));
|
||||
}
|
||||
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.")));
|
||||
}
|
||||
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 -
|
||||
// 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 (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
|
||||
|
||||
if (!s->is_cell_inst () && int (s->layer ()) != layer) {
|
||||
|
||||
db::Cell &cell = layout.cell (s->cell_index ());
|
||||
if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
|
||||
cell.shapes (layer).insert (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
|
||||
view ()->clear_selection ();
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
: 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_top_cell_name = layout.cell_name (cell_index);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
RS274XMacroAperture::do_produce_flash_internal ()
|
||||
{
|
||||
tl::Extractor ex (m_def.c_str ());
|
||||
bool clear = false;
|
||||
bool clear_set = false;
|
||||
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
|
|
@ -640,18 +659,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
|
|||
if (code == 1) {
|
||||
|
||||
ex.expect (",");
|
||||
int pol = (read_expr (ex) > 0.5);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
read_exposure (ex, clear, clear_set);
|
||||
ex.expect (",");
|
||||
double d = read_expr (ex, true);
|
||||
ex.expect (",");
|
||||
|
|
@ -670,18 +678,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
|
|||
} else if (code == 2 || code == 20) {
|
||||
|
||||
ex.expect (",");
|
||||
int pol = (read_expr (ex) > 0.5);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
read_exposure (ex, clear, clear_set);
|
||||
ex.expect (",");
|
||||
double w = read_expr (ex, true);
|
||||
ex.expect (",");
|
||||
|
|
@ -723,18 +720,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
|
|||
} else if (code == 21 || code == 22) {
|
||||
|
||||
ex.expect (",");
|
||||
int pol = (read_expr (ex) > 0.5);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
read_exposure (ex, clear, clear_set);
|
||||
ex.expect (",");
|
||||
double w = read_expr (ex, true);
|
||||
ex.expect (",");
|
||||
|
|
@ -766,18 +752,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
|
|||
} else if (code == 4) {
|
||||
|
||||
ex.expect (",");
|
||||
int pol = (read_expr (ex) > 0.5);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
read_exposure (ex, clear, clear_set);
|
||||
ex.expect (",");
|
||||
int n = int (read_expr (ex) + 0.5);
|
||||
if (n < 1) {
|
||||
|
|
@ -854,18 +829,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
|
|||
} else if (code == 5) {
|
||||
|
||||
ex.expect (",");
|
||||
int pol = (read_expr (ex) > 0.5);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
read_exposure (ex, clear, clear_set);
|
||||
ex.expect (",");
|
||||
int n = int (read_expr (ex) + 0.5);
|
||||
if (n < 3) {
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ private:
|
|||
double read_atom (tl::Extractor &ex);
|
||||
double read_dot_expr (tl::Extractor &ex);
|
||||
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 ();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -524,7 +524,6 @@ private:
|
|||
ArgType m_ret_type;
|
||||
bool m_const : 1;
|
||||
bool m_static : 1;
|
||||
bool m_is_predicate : 1;
|
||||
bool m_protected : 1;
|
||||
unsigned int m_argsize;
|
||||
std::vector<MethodSynonym> m_method_synonyms;
|
||||
|
|
|
|||
|
|
@ -697,12 +697,14 @@ static size_t make_id ()
|
|||
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_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
}
|
||||
|
||||
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_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = new DataHeader (w, h, color, false);
|
||||
|
|
|
|||
|
|
@ -1380,6 +1380,17 @@ GuiApplication::notify (QObject *receiver, QEvent *e)
|
|||
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
|
||||
GuiApplication::exec ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -432,6 +432,12 @@ public:
|
|||
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:
|
||||
virtual void setup ();
|
||||
virtual void shutdown ();
|
||||
|
|
|
|||
|
|
@ -1621,6 +1621,8 @@ MacroEditorDialog::current_tab_changed (int index)
|
|||
|
||||
// clear the search
|
||||
searchEditBox->clear ();
|
||||
replaceFrame->setEnabled (page && page->macro () && !page->macro ()->is_readonly ());
|
||||
|
||||
apply_search ();
|
||||
|
||||
do_update_ui_to_run_mode ();
|
||||
|
|
|
|||
|
|
@ -971,6 +971,10 @@ static QString interpolate_string (const QString &replace, const QRegExp &re)
|
|||
void
|
||||
MacroEditorPage::replace_and_find_next (const QString &replace)
|
||||
{
|
||||
if (! mp_macro || mp_macro->is_readonly ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTextCursor c = mp_text->textCursor ();
|
||||
if (c.hasSelection ()) {
|
||||
c.insertText (interpolate_string (replace, m_current_search));
|
||||
|
|
@ -982,6 +986,10 @@ MacroEditorPage::replace_and_find_next (const QString &replace)
|
|||
void
|
||||
MacroEditorPage::replace_all (const QString &replace)
|
||||
{
|
||||
if (! mp_macro || mp_macro->is_readonly ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QTextDocument *doc = mp_text->document ();
|
||||
|
||||
QTextCursor c = mp_text->textCursor ();
|
||||
|
|
|
|||
|
|
@ -450,6 +450,7 @@ MainWindow::MainWindow (QApplication *app, const char *name)
|
|||
m_disable_tab_selected (false),
|
||||
m_exited (false),
|
||||
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),
|
||||
m_grid_micron (0.001),
|
||||
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->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_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;
|
||||
|
||||
} 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
|
||||
MainWindow::libraries_changed ()
|
||||
{
|
||||
|
|
@ -2427,57 +2427,6 @@ MainWindow::cm_redo ()
|
|||
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
|
||||
MainWindow::cm_goto_position ()
|
||||
{
|
||||
|
|
@ -2581,19 +2530,7 @@ MainWindow::cm_bookmark_view ()
|
|||
BEGIN_PROTECTED
|
||||
|
||||
if (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 {
|
||||
current_view ()->bookmark_view (tl::to_string (text));
|
||||
break;
|
||||
}
|
||||
}
|
||||
current_view ()->bookmark_current_view ();
|
||||
}
|
||||
|
||||
END_PROTECTED
|
||||
|
|
@ -3360,6 +3297,7 @@ MainWindow::select_view (int index)
|
|||
clear_current_pos ();
|
||||
edits_enabled_changed ();
|
||||
clear_message ();
|
||||
menu_needs_update ();
|
||||
|
||||
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 (dirty_changed ()), this, SLOT (view_title_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 (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
|
||||
connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
|
||||
|
|
@ -4042,6 +3981,7 @@ MainWindow::close_view (int index)
|
|||
|
||||
clear_current_pos ();
|
||||
edits_enabled_changed ();
|
||||
menu_needs_update ();
|
||||
clear_message ();
|
||||
|
||||
update_dock_widget_state ();
|
||||
|
|
@ -4173,30 +4113,28 @@ MainWindow::add_mru (const std::string &fn_rel, const std::string &tech)
|
|||
}
|
||||
|
||||
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 ()) {
|
||||
|
||||
open_recent_action.set_enabled (true);
|
||||
|
||||
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)));
|
||||
}
|
||||
// rebuild MRU menu
|
||||
mp_menu->clear_menu (mru_menu);
|
||||
|
||||
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 {
|
||||
|
|
@ -4349,6 +4287,7 @@ MainWindow::do_create_view ()
|
|||
connect (view, SIGNAL (title_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 (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 (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
|
||||
connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
|
||||
|
|
@ -5016,6 +4955,10 @@ void
|
|||
MainWindow::do_update_menu ()
|
||||
{
|
||||
mp_menu->build (menuBar (), mp_tool_bar);
|
||||
lay::GuiApplication *app = dynamic_cast<lay::GuiApplication *> (qApp);
|
||||
if (app) {
|
||||
app->force_update_app_menu ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -689,7 +689,6 @@ public slots:
|
|||
void tab_close_requested (int);
|
||||
void enable_all ();
|
||||
void disable_all ();
|
||||
void goto_bookmark ();
|
||||
void open_recent ();
|
||||
void view_selected (int index);
|
||||
void view_title_changed ();
|
||||
|
|
@ -858,9 +857,9 @@ public slots:
|
|||
protected slots:
|
||||
void menu_changed ();
|
||||
void message_timer ();
|
||||
void bookmark_menu_show ();
|
||||
void file_menu_show ();
|
||||
void edits_enabled_changed ();
|
||||
void menu_needs_update ();
|
||||
|
||||
void file_changed_timer ();
|
||||
void file_changed (const QString &path);
|
||||
void file_removed (const QString &path);
|
||||
|
|
@ -868,13 +867,13 @@ protected slots:
|
|||
protected:
|
||||
void update_content ();
|
||||
void do_update_menu ();
|
||||
void do_update_file_menu ();
|
||||
|
||||
private:
|
||||
TextProgressDelegate m_text_progress;
|
||||
|
||||
// Main menu
|
||||
AbstractMenu *mp_menu;
|
||||
QMenu *mp_goto_bookmark_menu;
|
||||
QTabBar *mp_tab_bar;
|
||||
QToolBar *mp_tool_bar;
|
||||
QDockWidget *mp_navigator_dock_widget;
|
||||
|
|
@ -911,6 +910,7 @@ private:
|
|||
bool m_disable_tab_selected;
|
||||
bool m_exited;
|
||||
tl::DeferredMethod<MainWindow> dm_do_update_menu;
|
||||
tl::DeferredMethod<MainWindow> dm_do_update_file_menu;
|
||||
tl::DeferredMethod<MainWindow> dm_exit;
|
||||
QTimer m_message_timer;
|
||||
QTimer m_file_changed_timer;
|
||||
|
|
|
|||
|
|
@ -211,10 +211,12 @@ ProgressReporter::set_visible (bool vis)
|
|||
// actual operation
|
||||
tl::DeferredMethodScheduler::enable (!vis);
|
||||
|
||||
if (!vis) {
|
||||
mp_pb->progress_remove_widget ();
|
||||
} else if (mp_pb->progress_wants_widget () && mp_objects.front ()) {
|
||||
mp_pb->progress_add_widget (mp_objects.front ()->progress_widget ());
|
||||
if (mp_pb) {
|
||||
if (!vis) {
|
||||
mp_pb->progress_remove_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;
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ SaltGrainPropertiesDialog::dependency_changed (QTreeWidgetItem *item, int column
|
|||
m_update_enabled = false;
|
||||
|
||||
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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static lay::Technology *create_technology (const std::string &name)
|
|||
{
|
||||
lay::Technology *tech = new lay::Technology ();
|
||||
tech->set_name (name);
|
||||
lay::Technologies::instance ()->add (tech);
|
||||
lay::Technologies::instance ()->add_new (tech);
|
||||
return tech;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ static const bool s_can_move_menu = true;
|
|||
#endif
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Helper function to parse a title with potential shortcut and
|
||||
// Helper function to parse a title with potential shortcut and
|
||||
// icon specification
|
||||
|
||||
static void
|
||||
|
|
@ -122,19 +122,19 @@ parse_menu_title (const std::string &s, std::string &title, std::string &shortcu
|
|||
// ---------------------------------------------------------------
|
||||
// AbstractMenuItem implementation
|
||||
|
||||
AbstractMenuItem::AbstractMenuItem ()
|
||||
AbstractMenuItem::AbstractMenuItem ()
|
||||
: m_has_submenu (false), m_remove_on_empty (false)
|
||||
{
|
||||
// ... nothing yet ..
|
||||
}
|
||||
|
||||
AbstractMenuItem::AbstractMenuItem (const AbstractMenuItem &)
|
||||
AbstractMenuItem::AbstractMenuItem (const AbstractMenuItem &)
|
||||
: m_has_submenu (false), m_remove_on_empty (false)
|
||||
{
|
||||
{
|
||||
// ... nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenuItem::setup_item (const std::string &pn, const std::string &s, const Action &a)
|
||||
{
|
||||
m_basename.clear ();
|
||||
|
|
@ -162,7 +162,7 @@ AbstractMenuItem::setup_item (const std::string &pn, const std::string &s, const
|
|||
set_action (a, false);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenuItem::set_action (const Action &a, bool copy_properties)
|
||||
{
|
||||
Action acopy = a;
|
||||
|
|
@ -187,13 +187,13 @@ AbstractMenuItem::set_action (const Action &a, bool copy_properties)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenuItem::set_action_title (const std::string &s)
|
||||
{
|
||||
m_action.set_title (s);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenuItem::set_has_submenu ()
|
||||
{
|
||||
m_has_submenu = true;
|
||||
|
|
@ -214,10 +214,20 @@ static std::set<ActionHandle *> *sp_actionHandles = 0;
|
|||
* @brief A specialization that provides a way to catch ambiguous key shortcuts
|
||||
*/
|
||||
class ActionObject
|
||||
: public QAction
|
||||
: public QAction
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
@ -251,8 +261,18 @@ public:
|
|||
|
||||
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)
|
||||
: mp_menu (0),
|
||||
mp_action (new ActionObject (parent)),
|
||||
|
|
@ -260,7 +280,7 @@ ActionHandle::ActionHandle (QWidget *parent)
|
|||
m_owned (true),
|
||||
m_visible (true),
|
||||
m_hidden (false)
|
||||
{
|
||||
{
|
||||
if (! sp_actionHandles) {
|
||||
sp_actionHandles = new std::set<ActionHandle *> ();
|
||||
}
|
||||
|
|
@ -273,11 +293,11 @@ ActionHandle::ActionHandle (QWidget *parent)
|
|||
ActionHandle::ActionHandle (QAction *action, bool owned)
|
||||
: mp_menu (0),
|
||||
mp_action (action),
|
||||
m_ref_count (0),
|
||||
m_ref_count (0),
|
||||
m_owned (owned),
|
||||
m_visible (true),
|
||||
m_hidden (false)
|
||||
{
|
||||
{
|
||||
if (! sp_actionHandles) {
|
||||
sp_actionHandles = new std::set<ActionHandle *> ();
|
||||
}
|
||||
|
|
@ -330,13 +350,13 @@ ActionHandle::~ActionHandle ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ActionHandle::add_ref ()
|
||||
void
|
||||
ActionHandle::add_ref ()
|
||||
{
|
||||
++m_ref_count;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
ActionHandle::remove_ref ()
|
||||
{
|
||||
if (--m_ref_count == 0) {
|
||||
|
|
@ -356,7 +376,7 @@ ActionHandle::menu () const
|
|||
return mp_menu;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
ActionHandle::destroyed (QObject * /*obj*/)
|
||||
{
|
||||
mp_action = 0;
|
||||
|
|
@ -548,7 +568,7 @@ Action::triggered_slot ()
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Action::set_title (const std::string &t)
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -556,7 +576,7 @@ Action::set_title (const std::string &t)
|
|||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
std::string
|
||||
Action::get_title () const
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -566,7 +586,7 @@ Action::get_title () const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Action::set_shortcut (const QKeySequence &s)
|
||||
{
|
||||
if (mp_handle) {
|
||||
|
|
@ -732,7 +752,7 @@ Action::set_separator (bool s)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Action::set_icon (const std::string &filename)
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -744,7 +764,7 @@ Action::set_icon (const std::string &filename)
|
|||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
std::string
|
||||
Action::get_tool_tip () const
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -754,7 +774,7 @@ Action::get_tool_tip () const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Action::set_tool_tip (const std::string &text)
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -766,7 +786,7 @@ Action::set_tool_tip (const std::string &text)
|
|||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
std::string
|
||||
Action::get_icon_text () const
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -776,7 +796,7 @@ Action::get_icon_text () const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Action::set_icon_text (const std::string &icon_text)
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -788,7 +808,7 @@ Action::set_icon_text (const std::string &icon_text)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Action::set_object_name (const std::string &name)
|
||||
{
|
||||
if (qaction ()) {
|
||||
|
|
@ -814,7 +834,7 @@ ConfigureAction::ConfigureAction (lay::PluginRoot *pr, const std::string &cname,
|
|||
}
|
||||
|
||||
reg ();
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAction::ConfigureAction (lay::PluginRoot *pr, const std::string &title, const std::string &cname, const std::string &cvalue)
|
||||
: Action (title), m_pr (pr), m_cname (cname), m_cvalue (cvalue), m_type (ConfigureAction::setter_type)
|
||||
|
|
@ -831,19 +851,19 @@ ConfigureAction::ConfigureAction (lay::PluginRoot *pr, const std::string &title,
|
|||
}
|
||||
|
||||
reg ();
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureAction::~ConfigureAction ()
|
||||
{
|
||||
unreg ();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
ConfigureAction::triggered ()
|
||||
{
|
||||
if (m_type == boolean_type) {
|
||||
m_cvalue = tl::to_string (is_checked ());
|
||||
}
|
||||
}
|
||||
|
||||
m_pr->config_set (m_cname, m_cvalue);
|
||||
}
|
||||
|
|
@ -880,7 +900,7 @@ ConfigureAction::configure (const std::string &value)
|
|||
set_checkable (true);
|
||||
set_checked (m_cvalue == value);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
|
@ -897,7 +917,7 @@ AbstractMenu::create_action (const std::string &s)
|
|||
std::string tool_tip;
|
||||
|
||||
parse_menu_title (s, title, shortcut, res, tool_tip);
|
||||
|
||||
|
||||
ActionHandle *ah = new ActionHandle (lay::AbstractMenuProvider::instance ()->menu_parent_widget ());
|
||||
ah->ptr ()->setText (tl::to_qstring (title));
|
||||
|
||||
|
|
@ -927,7 +947,7 @@ AbstractMenu::~AbstractMenu ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::init (const MenuLayoutEntry *layout)
|
||||
{
|
||||
m_root.set_has_submenu ();
|
||||
|
|
@ -943,12 +963,12 @@ AbstractMenu::make_exclusive_group (const std::string &name)
|
|||
QActionGroup *ag = new QActionGroup (this);
|
||||
ag->setExclusive (true);
|
||||
a = m_action_groups.insert (std::make_pair (name, ag)).first;
|
||||
}
|
||||
}
|
||||
|
||||
return a->second;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::build_detached (const std::string &name, QFrame *mbar)
|
||||
{
|
||||
// Clean up the menu bar before rebuilding
|
||||
|
|
@ -1005,7 +1025,7 @@ AbstractMenu::build_detached (const std::string &name, QFrame *mbar)
|
|||
menu_layout->addStretch (1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
||||
{
|
||||
tl_assert (mp_provider != 0);
|
||||
|
|
@ -1013,9 +1033,11 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
m_helper_menu_items.clear ();
|
||||
tbar->clear ();
|
||||
|
||||
std::set<QAction *> present_actions;
|
||||
std::set<std::pair<size_t, QAction *> > present_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) {
|
||||
|
||||
|
|
@ -1027,7 +1049,7 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
|
||||
} else if (c->name ().find ("@@") == 0) {
|
||||
|
||||
// nothing: let build_detached build the menu
|
||||
// nothing: let build_detached build the menu
|
||||
|
||||
} else if (c->name ().find ("@") == 0) {
|
||||
|
||||
|
|
@ -1035,9 +1057,9 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
QMenu *menu = new QMenu (tl::to_qstring (c->action ().get_title ()));
|
||||
// HINT: it is necessary to add the menu action to a widget below the main window.
|
||||
// Otherwise, the keyboard shortcuts do not work for menu items inside such a
|
||||
// popup menu. It seems not to have a negative effect to add the menu to the
|
||||
// popup menu. It seems not to have a negative effect to add the menu to the
|
||||
// main widget.
|
||||
mp_provider->menu_parent_widget ()->addAction (menu->menuAction ());
|
||||
mp_provider->menu_parent_widget ()->addAction (menu->menuAction ());
|
||||
c->set_action (Action (new ActionHandle (menu)), true);
|
||||
}
|
||||
|
||||
|
|
@ -1053,10 +1075,10 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
c->set_action (Action (new ActionHandle (menu)), true);
|
||||
} else {
|
||||
// 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 (s_can_move_menu) {
|
||||
mbar->removeAction (*a);
|
||||
mbar->removeAction (a->second);
|
||||
mbar->addMenu (c->menu ());
|
||||
}
|
||||
present_actions.erase (*a);
|
||||
|
|
@ -1071,10 +1093,10 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
|
||||
} else {
|
||||
// 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 (s_can_move_menu) {
|
||||
mbar->removeAction (*a);
|
||||
mbar->removeAction (a->second);
|
||||
mbar->addAction (c->action ().qaction ());
|
||||
}
|
||||
present_actions.erase (*a);
|
||||
|
|
@ -1086,17 +1108,19 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
}
|
||||
|
||||
// Remove all actions that have vanished
|
||||
for (std::set<QAction *>::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
|
||||
mbar->removeAction (*a);
|
||||
for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
|
||||
mbar->removeAction (a->second);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
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 ();
|
||||
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) {
|
||||
|
||||
|
|
@ -1111,10 +1135,10 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
|
|||
c->set_action (Action (new ActionHandle (menu)), true);
|
||||
} else {
|
||||
// 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 (s_can_move_menu) {
|
||||
m->removeAction (*a);
|
||||
m->removeAction (a->second);
|
||||
m->addMenu (c->menu ());
|
||||
}
|
||||
present_actions.erase (*a);
|
||||
|
|
@ -1128,10 +1152,10 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
|
|||
} else {
|
||||
|
||||
// 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 (s_can_move_menu) {
|
||||
m->removeAction (*a);
|
||||
m->removeAction (a->second);
|
||||
m->addAction (c->action ().qaction ());
|
||||
}
|
||||
present_actions.erase (*a);
|
||||
|
|
@ -1143,26 +1167,26 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
|
|||
}
|
||||
|
||||
// Remove all actions that have vanished
|
||||
for (std::set<QAction *>::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
|
||||
m->removeAction (*a);
|
||||
for (std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) {
|
||||
m->removeAction (a->second);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::build (QToolBar *t, std::list<AbstractMenuItem> &items)
|
||||
{
|
||||
for (std::list<AbstractMenuItem>::iterator c = items.begin (); c != items.end (); ++c) {
|
||||
|
||||
if (! c->children.empty ()) {
|
||||
|
||||
// To support tool buttons with menu we have to attach a helper menu
|
||||
// item to the QAction object.
|
||||
// To support tool buttons with menu we have to attach a helper menu
|
||||
// item to the QAction object.
|
||||
// TODO: this hurts if we use this QAction otherwise. In this case, this
|
||||
// QAction would get a menu too. However, hopefully this usage is constrained
|
||||
// to special toolbar buttons only.
|
||||
// In order to be able to manage the QMenu ourselves, we must not give it a parent.
|
||||
QMenu *menu = new QMenu (0);
|
||||
m_helper_menu_items.push_back (menu); // will be owned by the stable vector
|
||||
m_helper_menu_items.push_back (menu); // will be owned by the stable vector
|
||||
c->action ().qaction ()->setMenu (menu);
|
||||
t->addAction (c->action ().qaction ());
|
||||
build (menu, c->children);
|
||||
|
|
@ -1183,7 +1207,7 @@ AbstractMenu::detached_menu (const std::string &name)
|
|||
}
|
||||
|
||||
QMenu *
|
||||
AbstractMenu::menu (const std::string &path)
|
||||
AbstractMenu::menu (const std::string &path)
|
||||
{
|
||||
AbstractMenuItem *item = find_item_exact (path);
|
||||
if (item) {
|
||||
|
|
@ -1214,7 +1238,7 @@ AbstractMenu::is_separator (const std::string &path) const
|
|||
return item != 0 && item->action ().is_separator ();
|
||||
}
|
||||
|
||||
Action
|
||||
Action
|
||||
AbstractMenu::action (const std::string &path) const
|
||||
{
|
||||
const AbstractMenuItem *item = find_item_exact (path);
|
||||
|
|
@ -1224,7 +1248,7 @@ AbstractMenu::action (const std::string &path) const
|
|||
return item->action ();
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
std::vector<std::string>
|
||||
AbstractMenu::items (const std::string &path) const
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
|
@ -1240,7 +1264,7 @@ AbstractMenu::items (const std::string &path) const
|
|||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::insert_item (const std::string &p, const std::string &name, const Action &action)
|
||||
{
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
|
|
@ -1271,7 +1295,7 @@ AbstractMenu::insert_item (const std::string &p, const std::string &name, const
|
|||
emit changed ();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::insert_separator (const std::string &p, const std::string &name)
|
||||
{
|
||||
tl_assert (mp_provider != 0); // required to get the parent for the new QAction (via ActionHandle)
|
||||
|
|
@ -1294,7 +1318,7 @@ AbstractMenu::insert_separator (const std::string &p, const std::string &name)
|
|||
emit changed ();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::insert_menu (const std::string &p, const std::string &name, const Action &action)
|
||||
{
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
|
|
@ -1324,13 +1348,24 @@ AbstractMenu::insert_menu (const std::string &p, const std::string &name, const
|
|||
emit changed ();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::insert_menu (const std::string &path, const std::string &name, const std::string &title)
|
||||
{
|
||||
insert_menu (path, name, create_action (title));
|
||||
}
|
||||
|
||||
void
|
||||
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
|
||||
AbstractMenu::delete_item (const std::string &p)
|
||||
{
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
|
|
@ -1387,7 +1422,7 @@ AbstractMenu::find_item_exact (const std::string &path) const
|
|||
}
|
||||
|
||||
AbstractMenuItem *
|
||||
AbstractMenu::find_item_exact (const std::string &path)
|
||||
AbstractMenu::find_item_exact (const std::string &path)
|
||||
{
|
||||
tl::Extractor extr (path.c_str ());
|
||||
AbstractMenuItem *item = &m_root;
|
||||
|
|
@ -1406,7 +1441,7 @@ AbstractMenu::find_item_exact (const std::string &path)
|
|||
}
|
||||
if (n > 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
item = &*c;
|
||||
|
||||
|
|
@ -1576,7 +1611,7 @@ AbstractMenu::find_item (const std::string &p)
|
|||
return path;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item)
|
||||
{
|
||||
tl_assert (mp_provider != 0);
|
||||
|
|
@ -1609,7 +1644,7 @@ AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item)
|
|||
std::string tool_tip;
|
||||
|
||||
parse_menu_title (layout->title, title, shortcut, res, tool_tip);
|
||||
|
||||
|
||||
a.set_separator (false);
|
||||
a.set_title (title);
|
||||
|
||||
|
|
@ -1641,7 +1676,7 @@ AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item)
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
std::vector<std::string>
|
||||
AbstractMenu::group (const std::string &name) const
|
||||
{
|
||||
std::vector<std::string> grp;
|
||||
|
|
@ -1649,7 +1684,7 @@ AbstractMenu::group (const std::string &name) const
|
|||
return grp;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
AbstractMenu::collect_group (std::vector<std::string> &grp, const std::string &name, const AbstractMenuItem &item) const
|
||||
{
|
||||
for (std::list<AbstractMenuItem>::const_iterator c = item.children.begin (); c != item.children.end (); ++c) {
|
||||
|
|
|
|||
|
|
@ -784,6 +784,13 @@ public:
|
|||
*/
|
||||
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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "tlString.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlAssert.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "layLayoutView.h"
|
||||
#include "layViewOp.h"
|
||||
#include "layViewObject.h"
|
||||
|
|
@ -74,6 +75,7 @@
|
|||
#include "rdbMarkerBrowserDialog.h"
|
||||
#include "tlXMLParser.h"
|
||||
#include "gsi.h"
|
||||
#include "gtf.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
|
@ -772,6 +774,37 @@ LayoutView::init_menu (lay::AbstractMenu &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
|
||||
LayoutView::set_drawing_workers (int workers)
|
||||
{
|
||||
|
|
@ -3650,6 +3683,24 @@ LayoutView::cancel ()
|
|||
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
|
||||
LayoutView::manage_bookmarks ()
|
||||
{
|
||||
|
|
@ -3663,6 +3714,7 @@ void
|
|||
LayoutView::bookmarks (const BookmarkList &b)
|
||||
{
|
||||
m_bookmarks = b;
|
||||
emit menu_needs_update ();
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1557,6 +1557,11 @@ public:
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
@ -1603,6 +1608,12 @@ public:
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
@ -2530,6 +2541,7 @@ public slots:
|
|||
|
||||
private slots:
|
||||
void active_cellview_changed (int index);
|
||||
void goto_bookmark ();
|
||||
|
||||
signals:
|
||||
/**
|
||||
|
|
@ -2562,6 +2574,11 @@ signals:
|
|||
*/
|
||||
void edits_enabled_changed ();
|
||||
|
||||
/**
|
||||
* @brief This signal is sent when the view wants to update the menu
|
||||
*/
|
||||
void menu_needs_update ();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Establish the view operations
|
||||
|
|
|
|||
|
|
@ -88,11 +88,13 @@ save_dialog_state (QWidget *w)
|
|||
|
||||
}
|
||||
|
||||
for (QList<QObject *>::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) {
|
||||
if (dynamic_cast <QWidget *> (*c)) {
|
||||
std::string cs = save_dialog_state (dynamic_cast <QWidget *> (*c));
|
||||
if (! cs.empty ()) {
|
||||
s += cs;
|
||||
if (w) {
|
||||
for (QList<QObject *>::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) {
|
||||
if (dynamic_cast <QWidget *> (*c)) {
|
||||
std::string cs = save_dialog_state (dynamic_cast <QWidget *> (*c));
|
||||
if (! cs.empty ()) {
|
||||
s += cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ Technologies::Technologies ()
|
|||
Technologies::Technologies (const Technologies &other)
|
||||
: tl::Object ()
|
||||
{
|
||||
m_changed = false;
|
||||
m_in_update = false;
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
|
|
@ -115,19 +117,30 @@ Technologies::load_from_xml (const std::string &s)
|
|||
}
|
||||
|
||||
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 (t->name () == technology->name ()) {
|
||||
*t = *technology;
|
||||
delete technology;
|
||||
technology = 0;
|
||||
if (! tech) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
m_technologies.push_back (technology);
|
||||
technology->technology_changed_with_sender_event.add (this, &Technologies::technology_changed);
|
||||
if (t) {
|
||||
if (replace_same) {
|
||||
*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 ();
|
||||
|
|
@ -218,6 +231,7 @@ Technologies::technology_by_name (const std::string &name)
|
|||
}
|
||||
}
|
||||
|
||||
tl_assert (! m_technologies.empty ());
|
||||
return &*m_technologies.begin ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,22 @@ public:
|
|||
* The container becomes owner of the technology object.
|
||||
* 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
|
||||
|
|
@ -233,6 +248,8 @@ private:
|
|||
tl::stable_vector<Technology> m_technologies;
|
||||
bool m_changed;
|
||||
bool m_in_update;
|
||||
|
||||
void add_tech (Technology *technology, bool replace_same);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -124,5 +124,14 @@ TEST(1)
|
|||
|
||||
menu.delete_item ("n1.c2");
|
||||
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)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -915,26 +915,28 @@ void Macro::install_doc () const
|
|||
|
||||
if (cls == 0) {
|
||||
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;
|
||||
ex.read_word_or_quoted (n);
|
||||
std::string n;
|
||||
ex.read_word_or_quoted (n);
|
||||
|
||||
std::string doc;
|
||||
while (++i < lines.size ()) {
|
||||
std::string l = tl::trim (lines [i]);
|
||||
if (l.find ("@method") == 0 || l.find ("@static_method") == 0) {
|
||||
break;
|
||||
std::string doc;
|
||||
while (++i < lines.size ()) {
|
||||
std::string l = tl::trim (lines [i]);
|
||||
if (l.find ("@method") == 0 || l.find ("@static_method") == 0) {
|
||||
break;
|
||||
}
|
||||
if (! doc.empty ()) {
|
||||
doc += "\n";
|
||||
}
|
||||
doc += lines [i];
|
||||
}
|
||||
if (! doc.empty ()) {
|
||||
doc += "\n";
|
||||
}
|
||||
doc += lines [i];
|
||||
}
|
||||
--i;
|
||||
--i;
|
||||
|
||||
ExternalMethod *meth = new ExternalMethod (n, doc, false, st);
|
||||
cls->add_method (meth);
|
||||
ExternalMethod *meth = new ExternalMethod (n, doc, false, st);
|
||||
cls->add_method (meth);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,27 @@ class PYAObjectBase;
|
|||
*/
|
||||
PythonInterpreter *sp_interpreter = 0;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Normalizes the file path
|
||||
* This function normalizes the file path so it only contains one
|
||||
* kind of slashes on Windows.
|
||||
*/
|
||||
static
|
||||
std::string normalize_path (const std::string &p)
|
||||
{
|
||||
#if defined(__WIN32)
|
||||
std::string np;
|
||||
np.reserve (p.size ());
|
||||
for (const char *c = p.c_str (); *c; ++c) {
|
||||
np += (*c == '\\' ? '/' : *c);
|
||||
}
|
||||
return np;
|
||||
#else
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// The lookup table for the method overload resolution
|
||||
|
|
@ -438,7 +459,7 @@ public:
|
|||
int line = frame->f_lineno;
|
||||
std::string fn;
|
||||
if (test_type<std::string> (frame->f_code->co_filename, true)) {
|
||||
fn = python2c<std::string> (frame->f_code->co_filename);
|
||||
fn = normalize_path (python2c<std::string> (frame->f_code->co_filename));
|
||||
}
|
||||
m_stack_trace.push_back (tl::BacktraceElement (fn, line));
|
||||
|
||||
|
|
@ -1945,7 +1966,11 @@ property_setter_impl (int mid, PyObject *self, PyObject *value)
|
|||
|
||||
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 -
|
||||
// this simplifies the implementation of += and -=.
|
||||
|
|
@ -3221,7 +3246,7 @@ PythonInterpreter::prepare_trace (PyObject *fn_object)
|
|||
{
|
||||
std::map<PyObject *, size_t>::const_iterator f = m_file_id_map.find (fn_object);
|
||||
if (f == m_file_id_map.end ()) {
|
||||
f = m_file_id_map.insert (std::make_pair (fn_object, mp_current_exec_handler->id_for_path (this, python2c<std::string> (fn_object)))).first;
|
||||
f = m_file_id_map.insert (std::make_pair (fn_object, mp_current_exec_handler->id_for_path (this, normalize_path (python2c<std::string> (fn_object))))).first;
|
||||
}
|
||||
|
||||
return f->second;
|
||||
|
|
@ -3511,4 +3536,3 @@ PythonInterpreter *PythonInterpreter::instance ()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -495,7 +495,7 @@ public:
|
|||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ public:
|
|||
++lb0;
|
||||
}
|
||||
--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
|
||||
lb->first.first = i2;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -424,17 +424,20 @@ JobBase::schedule (Task *task)
|
|||
{
|
||||
m_lock.lock ();
|
||||
|
||||
// Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition)
|
||||
if (m_stopping) {
|
||||
m_lock.unlock ();
|
||||
throw TaskTerminatedException ();
|
||||
}
|
||||
|
||||
// Add the task to the task queue
|
||||
m_task_list.put (task);
|
||||
// Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition)
|
||||
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 ();
|
||||
|
|
|
|||
|
|
@ -1298,7 +1298,7 @@ Variant::can_convert_to_long () const
|
|||
case t_double:
|
||||
return m_var.m_double <= std::numeric_limits<long>::max () && m_var.m_double >= std::numeric_limits<long>::min ();
|
||||
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)
|
||||
case t_int128:
|
||||
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.
|
|
@ -52,20 +52,25 @@ class BoxPCell(pya.PCellDeclaration):
|
|||
|
||||
# create the shape
|
||||
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):
|
||||
|
||||
boxpcell = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# set the description
|
||||
self.description = "PCell test lib"
|
||||
|
||||
# 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")
|
||||
l10 = self.layout().insert_layer(pya.LayerInfo(10, 0))
|
||||
|
|
@ -75,6 +80,60 @@ class PCellTestLib(pya.Library):
|
|||
# register us with the name "MyLib"
|
||||
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):
|
||||
return "<" + str(self) + ">"
|
||||
|
||||
|
|
@ -233,6 +292,75 @@ class DBPCellTests(unittest.TestCase):
|
|||
pcell_inst.cell_index = new_id
|
||||
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):
|
||||
|
||||
# instantiate and register the library
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -61,6 +61,18 @@ class BoxPCell < RBA::PCellDeclaration
|
|||
|
||||
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
|
||||
|
||||
class PCellTestLib < RBA::Library
|
||||
|
|
@ -85,6 +97,72 @@ class PCellTestLib < RBA::Library
|
|||
|
||||
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
|
||||
class RBA::LayerInfo
|
||||
def inspect
|
||||
|
|
@ -115,8 +193,7 @@ class DBPCell_TestClass < TestBase
|
|||
ly = RBA::Layout::new(true)
|
||||
ly.dbu = 0.01
|
||||
|
||||
li1 = ly.layer_indices.find { |li| ly.get_info(li).to_s == "1/0" }
|
||||
assert_equal(li1 == nil, true)
|
||||
li1 = ly.layer(1, 0)
|
||||
|
||||
ci1 = ly.add_cell("c1")
|
||||
c1 = ly.cell(ci1)
|
||||
|
|
@ -241,10 +318,84 @@ class DBPCell_TestClass < TestBase
|
|||
pcell_inst.cell_index = new_id
|
||||
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
|
||||
#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
|
||||
|
|
|
|||
Loading…
Reference in New Issue