diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index 115f3fdee..30023a97a 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -157,6 +157,53 @@ It is supposed to adjust parameters to render a consistent parameter set and to parameter range errors. This method is called for example inside the PCell user interface to compute the actual parameters when "Apply" is pressed. +@method callback_impl(name) + +@brief Provides a callback on a parameter change + +This method applies to user interface changes only. Whenever a parameter is changed +on the parameter page, this method is called with the name of the parameter. + +On some occasions, this method called to establish a configuration unspecifically. +In this case, the name is an empty string - indicating "all parameters may have changed". + +This method can change the state of this or any other parameter. For this, the +state objects are supplied instead of the parameter values. For example to enable +parameter "b" when a boolean parameter "a" is true, use the following code: + +@code +def callback_impl(name) + if name == "a" || name == "" + b.enabled = a.value + end +end +@/code + +The "enabled" attribute of the \\PCellParameterState object indicates whether the +parameter is enabled in the user interface. "a.value" delivers the value of the +(boolean type assumed) parameter "a". + +Note that the above code also checks for empty name to consider the case of a +global refresh. + +Further useful attributes of the parameters are: + +@ul + @li + @b enabled @/b: the parameter entry is grayed out if false + @/li + @li + @b readonly @/b: the parameter cannot be edited (less strict than enabled) + @/li + @li + @b visible @/b: the parameter entry is not visible if false + @/li + @li + @b icon @/b: Sets an icon in front of the parameter indicating an error or a + warning (use \\PCellParameterState#WarningIcon or \\PCellParameterState#ErrorIcon). + @/li +@/ul + @method can_create_from_shape_impl @brief Returns true if the PCell can be created from the given shape @@ -227,12 +274,13 @@ module RBA def initialize @param_decls = [] @param_values = nil + @param_states = nil @layout = nil @shape = nil @layer = nil @cell = nil @layer_param_index = [] - @layers = [] + @layers = nil end # provide accessors for the current layout and cell (for prod) @@ -244,6 +292,40 @@ module RBA def _layout; @layout; end def _cell; @cell; end def _shape; @shape; end + + # A helper method to access the nth parameter + + def _get_param(nth, name) + if @param_states + if ! @param_states.has_parameter?(name) + return RBA::PCellParameterState::new + else + return @param_states.parameter(name) + end + else + @param_values || raise("No parameters available.") + while @param_values.size <= nth + @param_values << nil + end + return @param_values[nth] + end + end + + # A helper method to set the nth parameter + + def _set_param(nth, value) + @param_values || raise("Cannot set parameter - inside 'callback_impl' use 'param_name.value = ...' to set the parameter's value.") + if @param_values.size > nth + @param_values[nth] = value + end + end + + # A helper method to access the nth layer + + def _get_layer(nth) + @layers || raise("No layer index available - layers can be used only inside 'produce_impl'.") + @layers[nth] + end # define a parameter # name -> the short name of the parameter @@ -267,14 +349,18 @@ module RBA # param_{name}_layer def param(name, type, description, args = {}) + + if name !~ /^[_A-Za-z]\w*$/ + raise "Invalid parameter name #{name} (needs to be a word)" + end # create accessor methods for the parameters param_index = @param_decls.length - self.instance_eval("def #{name.to_s}; @param_values[#{param_index}]; end") - self.instance_eval("def set_#{name.to_s}(v); @param_values[#{param_index}] = v; end") - self.instance_eval("def #{name.to_s}=(v); @param_values[#{param_index}] = v; end") + self.instance_eval("def #{name.to_s}; self._get_param(#{param_index}, '#{name}'); end") + self.instance_eval("def set_#{name.to_s}(v); self._set_param(#{param_index}, v); end") + self.instance_eval("def #{name.to_s}=(v); self._set_param(#{param_index}, v); end") if type == TypeLayer - self.instance_eval("def #{name.to_s}_layer; @layers[#{@layer_param_index.length}]; end") + self.instance_eval("def #{name.to_s}_layer; self._get_layer(#{@layer_param_index.length}); end") @layer_param_index.push(param_index) end @@ -307,8 +393,11 @@ module RBA # implementation of display_text def display_text(parameters) @param_values = parameters - text = display_text_impl - @param_values = nil + begin + text = display_text_impl + ensure + @param_values = nil + end text end @@ -326,9 +415,28 @@ module RBA def coerce_parameters(layout, parameters) @param_values = parameters @layout = layout - coerce_parameters_impl - @layout = nil - @param_values + ret = parameters + begin + coerce_parameters_impl + ensure + @layout = nil + ret = @param_values + @param_values = nil + end + ret + end + + # parameter change callback + def callback(layout, name, states) + @param_values = nil + @param_states = states + @layout = layout + begin + callback_impl(name) + ensure + @param_states = nil + @layout = nil + end end # produce the layout @@ -337,22 +445,29 @@ module RBA @cell = cell @param_values = parameters @layout = layout - produce_impl - @layers = nil - @cell = nil - @param_values = nil - @layout = nil + begin + produce_impl + ensure + @layers = nil + @cell = nil + @param_values = nil + @layout = nil + end end # produce a helper for can_create_from_shape def can_create_from_shape(layout, shape, layer) + ret = false @layout = layout @shape = shape @layer = layer - ret = can_create_from_shape_impl - @layout = nil - @shape = nil - @layer = nil + begin + ret = can_create_from_shape_impl + ensure + @layout = nil + @shape = nil + @layer = nil + end ret end @@ -361,10 +476,13 @@ module RBA @layout = layout @shape = shape @layer = layer - t = transformation_from_shape_impl - @layout = nil - @shape = nil - @layer = nil + begin + t = transformation_from_shape_impl + ensure + @layout = nil + @shape = nil + @layer = nil + end t end @@ -375,10 +493,13 @@ module RBA @layout = layout @shape = shape @layer = layer - parameters_from_shape_impl - @layout = nil - @shape = nil - @layer = nil + begin + parameters_from_shape_impl + ensure + @layout = nil + @shape = nil + @layer = nil + end @param_values end @@ -391,6 +512,10 @@ module RBA def coerce_parameters_impl end + # default implementation + def callback_impl(name) + end + # default implementation def produce_impl end diff --git a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym index 3632806fd..1df6dcb53 100644 --- a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym @@ -162,6 +162,51 @@ It is supposed to adjust parameters to render a consistent parameter set and to parameter range errors. This method is called for example inside the PCell user interface to compute the actual parameters when "Apply" is pressed. +@method callback_impl(name) + +@brief Provides a callback on a parameter change + +This method applies to user interface changes only. Whenever a parameter is changed +on the parameter page, this method is called with the name of the parameter. + +On some occasions, this method called to establish a configuration unspecifically. +In this case, the name is an empty string - indicating "all parameters may have changed". + +This method can change the state of this or any other parameter. For this, the +state objects are supplied instead of the parameter values. For example to enable +parameter "b" when a boolean parameter "a" is true, use the following code: + +@code +def callback_impl(self, name): + if name == "a" or name == "": + b.enabled = a.value +@/code + +The "enabled" attribute of the \\PCellParameterState object indicates whether the +parameter is enabled in the user interface. "a.value" delivers the value of the +(boolean type assumed) parameter "a". + +Note that the above code also checks for empty name to consider the case of a +global refresh. + +Further useful attributes of the parameters are: + +@ul + @li + @b enabled @/b: the parameter entry is grayed out if false + @/li + @li + @b readonly @/b: the parameter cannot be edited (less strict than enabled) + @/li + @li + @b visible @/b: the parameter entry is not visible if false + @/li + @li + @b icon @/b: Sets an icon in front of the parameter indicating an error or a + warning (use \\PCellParameterState#WarningIcon or \\PCellParameterState#ErrorIcon). + @/li +@/ul + @method can_create_from_shape_impl @brief Returns true if the PCell can be created from the given shape @@ -232,13 +277,16 @@ class _PCellDeclarationHelperParameterDescriptor(object): the descriptor acts as a value holder (self.value) """ - def __init__(self, param_index): + def __init__(self, param_index, param_name): self.param_index = param_index + self.param_name = param_name self.value = None def __get__(self, obj, type = None): if obj._param_values: return obj._param_values[self.param_index] + elif obj._param_states: + return obj._param_states.parameter(self.param_name) else: return self.value @@ -261,6 +309,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): # "private" attributes self._param_decls = [] self._param_values = None + self._param_states = None self._layer_param_index = [] self._layers = [] # public attributes @@ -290,7 +339,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): # create accessor methods for the parameters param_index = len(self._param_decls) - setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index)) + setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index, name)) if value_type == type(self).TypeLayer: setattr(type(self), name + "_layer", _PCellDeclarationHelperLayerDescriptor(len(self._layer_param_index))) @@ -323,8 +372,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): implementation of display_text """ self._param_values = parameters - text = self.display_text_impl() - self._param_values = None + try: + text = self.display_text_impl() + finally: + self._param_values = None return text def get_parameters(self): @@ -341,7 +392,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self._param_values = None return v - def init_values(self, values = None, layers = None): + def init_values(self, values = None, layers = None, states = None): """ initializes the temporary parameter values "values" are the original values. If "None" is given, the @@ -349,7 +400,11 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): "layers" are the layer indexes corresponding to the layer parameters. """ - if not values: + self._param_values = None + self._param_states = None + if states: + self._param_states = states + elif not values: self._param_values = [] for pd in self._param_decls: self._param_values.append(pd.default) @@ -359,29 +414,48 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): def finish(self): """ - Needs to be called at the end of produce() after init_values was used + Needs to be called at the end of an implementation """ self._param_values = None + self._param_states = None self._layers = None + self._cell = None + self._layout = None + self._layer = None + self._shape = None def get_layers(self, parameters): """ - get the layer definitions + gets the layer definitions """ layers = [] for i in self._layer_param_index: layers.append(parameters[i]) return layers + def callback(self, layout, name, states): + """ + callback (change state on parameter change) + """ + self.init_values(states = states) + self.layout = layout + try: + self.callback_impl(name) + finally: + self.finish() + def coerce_parameters(self, layout, parameters): """ coerce parameters (make consistent) """ self.init_values(parameters) self.layout = layout - self.coerce_parameters_impl() - self.layout = None - return self.get_values() + try: + self.coerce_parameters_impl() + parameters = self.get_values() + finally: + self.finish() + return parameters def produce(self, layout, layers, parameters, cell): """ @@ -390,10 +464,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.init_values(parameters, layers) self.cell = cell self.layout = layout - self.produce_impl() - self.cell = None - self.layout = None - self.finish() + try: + self.produce_impl() + finally: + self.finish() def can_create_from_shape(self, layout, shape, layer): """ @@ -402,10 +476,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - ret = self.can_create_from_shape_impl() - self.layout = None - self.shape = None - self.layer = None + try: + ret = self.can_create_from_shape_impl() + finally: + self.finish() return ret def transformation_from_shape(self, layout, shape, layer): @@ -415,10 +489,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - t = self.transformation_from_shape_impl() - self.layout = None - self.shape = None - self.layer = None + try: + t = self.transformation_from_shape_impl() + finally: + self.finish() return t def parameters_from_shape(self, layout, shape, layer): @@ -430,11 +504,11 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): 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 + try: + self.parameters_from_shape_impl() + param = self.get_values() + finally: + self.finish() return param def display_text_impl(self): @@ -449,6 +523,12 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): """ pass + def callback_impl(self, name): + """ + default implementation + """ + pass + def produce_impl(self): """ default implementation diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 067ffc03b..51f249d58 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -795,6 +795,8 @@ Layout::delete_cells (const std::set &cells_to_delete) } } + db::LayoutLocker locker (this); + // Clear all instances for (std::set::const_iterator c = cells_to_delete.begin (); c != cells_to_delete.end (); ++c) { diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 2f47d395f..8a7255ae8 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1414,7 +1414,7 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c db::PolygonRef::polygon_edge_iterator e = pr.begin_edge (); if (! e.at_end ()) { // pick one reference point for the label - if (! any_ref && (*e).p1 () < ref) { + if (! any_ref || (*e).p1 () < ref) { ref = (*e).p1 (); any_ref = true; } diff --git a/src/db/db/dbPCellDeclaration.cc b/src/db/db/dbPCellDeclaration.cc index 05ad1f4c1..acc1cafde 100644 --- a/src/db/db/dbPCellDeclaration.cc +++ b/src/db/db/dbPCellDeclaration.cc @@ -27,6 +27,80 @@ namespace db { +// ----------------------------------------------------------------------------------------- +// ParameterStates implementation + +ParameterStates::ParameterStates () + : m_states () +{ + // .. nothing yet .. +} + +ParameterStates::ParameterStates (const ParameterStates &other) + : m_states (other.m_states) +{ + // .. nothing yet .. +} + +ParameterStates::ParameterStates (ParameterStates &&other) + : m_states (std::move (other.m_states)) +{ + // .. nothing yet .. +} + +ParameterStates & +ParameterStates::operator= (const ParameterStates &other) +{ + if (this != &other) { + m_states = other.m_states; + } + return *this; +} + +void +ParameterStates::set_parameter (const std::string &name, const ParameterState &ps) +{ + m_states [name] = ps; +} + +ParameterState & +ParameterStates::parameter (const std::string &name) +{ + return m_states [name]; +} + +const ParameterState & +ParameterStates::parameter (const std::string &name) const +{ + auto i = m_states.find (name); + if (i == m_states.end ()) { + static ParameterState empty; + return empty; + } else { + return i->second; + } +} + +bool +ParameterStates::has_parameter (const std::string &name) const +{ + return m_states.find (name) != m_states.end (); +} + +bool +ParameterStates::values_are_equal (const db::ParameterStates &other) const +{ + auto i = m_states.begin (), j = other.m_states.begin (); + while (i != m_states.end () && j != other.m_states.end () && i->first == j->first && i->second.value () == j->second.value ()) { + ++i; ++j; + } + return i == m_states.end () && j == other.m_states.end (); +} + + +// ----------------------------------------------------------------------------------------- +// PCellDeclaration implementation + PCellDeclaration::PCellDeclaration () : m_ref_count (0), m_id (0), mp_layout (0), m_has_parameter_declarations (false) { diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index 808a75fe2..5afa58c35 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -61,6 +61,7 @@ public: t_layer, // a layer (value is a db::LayerProperties object) t_shape, // a shape (a db::Point, db::Box, db::Polygon, db::Edge or db::Path) rendering a guiding shape t_list, // a list of strings + t_callback, // callback only (button) t_none // no specific type }; @@ -323,6 +324,193 @@ public: std::string symbolic; }; +/** + * @brief Represents the dynamic state of a single parameter + */ +class DB_PUBLIC ParameterState +{ +public: + /** + * @brief A enum describing the icon type + */ + enum Icon { + NoIcon = 0, + InfoIcon = 1, + ErrorIcon = 2, + WarningIcon = 3 + }; + + /** + * @brief Parameterized constructor + */ + ParameterState () + : m_value (), m_visible (true), m_enabled (true), m_readonly (false), m_icon (NoIcon) + { + // .. nothing yet .. + } + + /** + * @brief Gets the value + */ + const tl::Variant &value () const + { + return m_value; + } + + /** + * @brief Sets the value + */ + void set_value (const tl::Variant &v) + { + m_value = v; + } + + /** + * @brief Gets the visibility state + */ + bool is_visible () const + { + return m_visible; + } + + /** + * @brief Sets the visibility + */ + void set_visible (bool v) + { + m_visible = v; + } + + /** + * @brief Gets the enabled state + */ + bool is_enabled () const + { + return m_enabled; + } + + /** + * @brief Sets the enabled state + */ + void set_enabled (bool v) + { + m_enabled = v; + } + + /** + * @brief Gets a value indicating whether the parameter is read-only + */ + bool is_readonly () const + { + return m_readonly; + } + + /** + * @brief Sets a value indicating whether the parameter is read-only + */ + void set_readonly (bool f) + { + m_readonly = f; + } + + /** + * @brief Gets the tooltip for the parameter + */ + const std::string &tooltip () const + { + return m_tooltip; + } + + /** + * @brief Sets the tooltip + */ + void set_tooltip (const std::string &s) + { + m_tooltip = s; + } + + /** + * @brief Gets the icon + */ + Icon icon () const + { + return m_icon; + } + + /** + * @brief Sets the icon + */ + void set_icon (Icon i) + { + m_icon = i; + } + +private: + tl::Variant m_value; + bool m_visible, m_enabled, m_readonly; + std::string m_tooltip; + Icon m_icon; +}; + +/** + * @brief Represents the state of call parameters for the callback implementation + */ +class DB_PUBLIC ParameterStates +{ +public: + /** + * @brief Default constructor + */ + ParameterStates (); + + /** + * @brief Copy constructor + */ + ParameterStates (const ParameterStates &other); + + /** + * @brief Move constructor + */ + ParameterStates (ParameterStates &&other); + + /** + * @brief Assignment + */ + ParameterStates &operator= (const ParameterStates &other); + + /** + * @brief Sets a parameter from a given state + */ + void set_parameter (const std::string &name, const ParameterState &ps); + + /** + * @brief Gets the parameter state for the parameter with the given name + * + * If the name is not a valid parameter name, the behavior is undefined. + */ + ParameterState ¶meter (const std::string &name); + + /** + * @brief Gets the parameter state for the parameter with the given name + * + * If the name is not a valid parameter name, the behavior is undefined. + */ + const ParameterState ¶meter (const std::string &name) const; + + /** + * @brief Gets a value indicating whether a parameter with that name is present + */ + bool has_parameter (const std::string &name) const; + + /** + * @brief Returns true, if the values of the parameter states are equal + */ + bool values_are_equal (const db::ParameterStates &other) const; + +public: + std::map m_states; +}; + /** * @brief A declaration for a PCell */ @@ -374,7 +562,25 @@ public: } /** - * @brief Produce a layout for the given parameter set and using the given layers. + * @brief Callback on parameter change + * + * This method allows implementing dynamic behavior on the change of a parameter value. + * A ParameterStatus object is supplied that allows changing parameter enabled status, visibility and value. + * The callback also acts as receiver for t_callback type parameters which only present a button. + * + * The callback function receives the name of the parameter that was changed. + * On some occasions, the callback is called unspecifically, for example for the initialization. + * In that case, the parameter name is empty. + * + * Exceptions from this implementation are ignored. + */ + virtual void callback (const db::Layout & /*layout*/, const std::string & /*name*/, ParameterStates & /*states*/) const + { + // the default implementation does nothing + } + + /** + * @brief Produces a layout for the given parameter set and using the given layers. * * A reimplementation of that method should produce the desired layout for the given parameter set. * The layout shall be put into the given cell. This code may create cell instances to other cells diff --git a/src/db/db/dbPolygonGenerators.h b/src/db/db/dbPolygonGenerators.h index e76c3cd87..a4127d59a 100644 --- a/src/db/db/dbPolygonGenerators.h +++ b/src/db/db/dbPolygonGenerators.h @@ -124,6 +124,11 @@ public: */ virtual void put (const db::Edge &e); + /** + * @brief Implementation of the EdgeSink interface + */ + virtual void put (const db::Edge & /*e*/, int /*tag*/) { } + /** * @brief Sets the way how holes are resolved dynamically * @@ -261,6 +266,11 @@ public: */ virtual void put (const db::Edge &e); + /** + * @brief Implementation of the EdgeSink interface + */ + virtual void put (const db::Edge & /*e*/, int /*tag*/) { } + private: db::Coord m_y; PolygonSink *mp_psink; diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 7d49fa7e4..a28cb05e1 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -911,6 +911,7 @@ class ErrorCatchingEdgeSink // TODO: we should not use exceptions to indicate a condition, but right now, there is no good alternative // and this is considered an error anyway. virtual void put (const db::Edge &) { throw OddPolygonException (); } + virtual void put (const db::Edge &, int) { } virtual void crossing_edge (const db::Edge &) { throw OddPolygonException (); } }; diff --git a/src/db/db/gsiDeclDbLayoutDiff.cc b/src/db/db/gsiDeclDbLayoutDiff.cc index d6e85f00a..cd9431a75 100644 --- a/src/db/db/gsiDeclDbLayoutDiff.cc +++ b/src/db/db/gsiDeclDbLayoutDiff.cc @@ -248,6 +248,26 @@ public: end_edge_differences_event (); } + virtual void begin_edge_pair_differences () + { + begin_edge_pair_differences_event (); + } + + virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > &a, const std::vector > &b) + { + for (std::vector >::const_iterator i = a.begin (); i != a.end (); ++i) { + edge_pair_in_a_only_event (i->first, i->second); + } + for (std::vector >::const_iterator i = b.begin (); i != b.end (); ++i) { + edge_pair_in_b_only_event (i->first, i->second); + } + } + + virtual void end_edge_pair_differences () + { + end_edge_pair_differences_event (); + } + virtual void begin_text_differences () { begin_text_differences_event (); @@ -353,6 +373,10 @@ public: tl::event edge_in_a_only_event; tl::event edge_in_b_only_event; tl::Event end_edge_differences_event; + tl::Event begin_edge_pair_differences_event; + tl::event edge_pair_in_a_only_event; + tl::event edge_pair_in_b_only_event; + tl::Event end_edge_pair_differences_event; tl::Event begin_text_differences_event; tl::event text_in_a_only_event; tl::event text_in_b_only_event; @@ -671,6 +695,29 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", gsi::event ("on_end_edge_differences", &LayoutDiff::end_edge_differences_event, "@brief This signal indicates the end of sequence of edge differences\n" ) + + gsi::event ("on_begin_edge_pair_differences", &LayoutDiff::begin_edge_pair_differences_event, + "@brief This signal indicates differences in the edge pairs on the current layer\n" + "The current layer is indicated by the \\begin_layer_event signal or can be obtained from the diff object " + "through \\LayoutDiff#layer_info_a, \\LayoutDiff#layer_index_a, \\LayoutDiff#layer_info_b and \\LayoutDiff#layer_index_b. " + "In verbose mode (see \\Verbose flag) more signals will be emitted for edge pairs that are different between the two layouts." + "\n" + "This event has been introduced in version 0.28." + ) + + gsi::event ("on_edge_pair_in_a_only", &LayoutDiff::edge_pair_in_a_only_event, gsi::arg ("anotb"), gsi::arg ("prop_id"), + "@brief This signal indicates an edge pair that is present in the first layout only" + "\n" + "This event has been introduced in version 0.28." + ) + + gsi::event ("on_edge_pair_in_b_only", &LayoutDiff::edge_pair_in_b_only_event, gsi::arg ("bnota"), gsi::arg ("prop_id"), + "@brief This signal indicates an edge pair that is present in the second layout only" + "\n" + "This event has been introduced in version 0.28." + ) + + gsi::event ("on_end_edge_pair_differences", &LayoutDiff::end_edge_pair_differences_event, + "@brief This signal indicates the end of sequence of edge pair differences\n" + "\n" + "This event has been introduced in version 0.28." + ) + gsi::event ("on_begin_text_differences", &LayoutDiff::begin_text_differences_event, "@brief This signal indicates differences in the texts on the current layer\n" "The current layer is indicated by the \\begin_layer_event signal or can be obtained from the diff object " diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index d6537599f..e2f89007b 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -23,6 +23,7 @@ #include "gsiDecl.h" +#include "gsiEnums.h" #include "dbLayout.h" #include "dbLibrary.h" #include "dbPCellDeclaration.h" @@ -276,15 +277,16 @@ static db::pcell_parameters_type coerce_parameters_native (const db::PCellDeclar // Provide a binding for db::PCellDeclaration for native PCell implementations Class decl_PCellDeclaration_Native ("db", "PCellDeclaration_Native", - gsi::method_ext ("get_layers", &get_layer_declarations_native) + + gsi::method_ext ("get_layers", &get_layer_declarations_native, gsi::arg ("parameters")) + gsi::method ("get_parameters", &db::PCellDeclaration::get_parameter_declarations) + - gsi::method ("produce", &db::PCellDeclaration::produce) + - gsi::method_ext ("coerce_parameters", &coerce_parameters_native) + - gsi::method ("can_create_from_shape", &db::PCellDeclaration::can_create_from_shape) + - gsi::method ("parameters_from_shape", &db::PCellDeclaration::parameters_from_shape) + - gsi::method ("transformation_from_shape", &db::PCellDeclaration::transformation_from_shape) + + gsi::method ("produce", &db::PCellDeclaration::produce, gsi::arg ("layout"), gsi::arg ("layers"), gsi::arg ("parameters"), gsi::arg ("cell")) + + gsi::method ("callback", &db::PCellDeclaration::callback, gsi::arg ("layout"), gsi::arg ("name"), gsi::arg ("states")) + + gsi::method_ext ("coerce_parameters", &coerce_parameters_native, gsi::arg ("layout"), gsi::arg ("parameters")) + + gsi::method ("can_create_from_shape", &db::PCellDeclaration::can_create_from_shape, gsi::arg ("layout"), gsi::arg ("shape"), gsi::arg ("layer")) + + gsi::method ("parameters_from_shape", &db::PCellDeclaration::parameters_from_shape, gsi::arg ("layout"), gsi::arg ("shape"), gsi::arg ("layer")) + + gsi::method ("transformation_from_shape", &db::PCellDeclaration::transformation_from_shape, gsi::arg ("layout"), gsi::arg ("shape"), gsi::arg ("layer")) + gsi::method ("wants_lazy_evaluation", &db::PCellDeclaration::wants_lazy_evaluation) + - gsi::method ("display_text", &db::PCellDeclaration::get_display_name) + + gsi::method ("display_text", &db::PCellDeclaration::get_display_name, gsi::arg ("parameters")) + gsi::method ("layout", &db::PCellDeclaration::layout, "@brief Gets the Layout object the PCell is registered in or nil if it is not registered yet.\n" "This attribute has been added in version 0.27.5." @@ -299,6 +301,97 @@ Class decl_PCellDeclaration_Native ("db", "PCellDeclaratio "@hide\n@alias PCellDeclaration\n" ); +// Provide a binding for db::ParameterState for native PCell implementations +Class decl_PCellParameterState ("db", "PCellParameterState", + gsi::method("value=", &db::ParameterState::set_value, gsi::arg ("v"), + "@brief Sets the value of the parameter\n" + ) + + gsi::method("value", &db::ParameterState::value, + "@brief Gets the value of the parameter\n" + ) + + gsi::method("visible=", &db::ParameterState::set_visible, gsi::arg ("f"), + "@brief Sets a value indicating whether the parameter is visible in the parameter form\n" + ) + + gsi::method("is_visible?", &db::ParameterState::is_visible, + "@brief Gets a value indicating whether the parameter is visible in the parameter form\n" + ) + + gsi::method("enabled=", &db::ParameterState::set_enabled, gsi::arg ("f"), + "@brief Sets a value indicating whether the parameter is enabled in the parameter form\n" + ) + + gsi::method("is_enabled?", &db::ParameterState::is_enabled, + "@brief Gets a value indicating whether the parameter is enabled in the parameter form\n" + ) + + gsi::method("readonly=", &db::ParameterState::set_readonly, gsi::arg ("f"), + "@brief Sets a value indicating whether the parameter is made read-only (not editable) in the parameter form\n" + ) + + gsi::method("is_readonly?", &db::ParameterState::is_readonly, + "@brief Gets a value indicating whether the parameter is read-only (not editable) in the parameter form\n" + ) + + gsi::method("tooltip=", &db::ParameterState::set_tooltip, gsi::arg ("s"), + "@brief Sets the tool tip text\n" + "\n" + "The tool tip is shown when hovering over the parameter label or edit field." + ) + + gsi::method("tooltip", &db::ParameterState::tooltip, + "@brief Gets the tool tip text\n" + ) + + gsi::method("icon=", &db::ParameterState::set_icon, gsi::arg ("i"), + "@brief Sets the icon for the parameter\n" + ) + + gsi::method("tooltip", &db::ParameterState::tooltip, + "@brief Gets the icon for the parameter\n" + ), + "@brief Provides access to the attributes of a single parameter within \\PCellParameterStates.\n" + "\n" + "See \\PCellParameterStates for details about this feature.\n" + "\n" + "This class has been introduced in version 0.28." +); + +gsi::EnumIn decl_PCellParameterState_Icon ("db", "ParameterStateIcon", + gsi::enum_const ("NoIcon", db::ParameterState::NoIcon, + "@brief No icon is shown for the parameter\n" + ) + + gsi::enum_const ("InfoIcon", db::ParameterState::InfoIcon, + "@brief A general 'information' icon is shown\n" + ) + + gsi::enum_const ("ErrorIcon", db::ParameterState::ErrorIcon, + "@brief An icon indicating an error is shown\n" + ) + + gsi::enum_const ("WarningIcon", db::ParameterState::WarningIcon, + "@brief An icon indicating a warning is shown\n" + ), + "@brief This enum specifies the icon shown next to the parameter in PCell parameter list.\n" + "\n" + "This enum was introduced in version 0.28.\n" +); + +// Inject the NetlistCrossReference::Status declarations into NetlistCrossReference: +gsi::ClassExt inject_PCellParameterState_Icon_in_parent (decl_PCellParameterState_Icon.defs ()); + +// Provide a binding for db::ParameterStates for native PCell implementations +Class decl_PCellParameterStates ("db", "PCellParameterStates", + gsi::method ("has_parameter?", &db::ParameterStates::has_parameter, gsi::arg ("name"), + "@brief Gets a value indicating whether a parameter with that name exists\n" + ) + + gsi::method ("parameter", static_cast (&db::ParameterStates::parameter), gsi::arg ("name"), + "@brief Gets the parameter by name\n" + "\n" + "This will return a \\PCellParameterState object that can be used to manipulate the " + "parameter state." + ), + "@brief Provides access to the parameter states inside a 'callback' implementation of a PCell\n" + "\n" + "Example: enables or disables a parameter 'n' based on the value:\n" + "\n" + "@code\n" + "n_param = states.parameter(\"n\")\n" + "n_param.enabled = n_param.value > 1.0\n" + "@/code\n" + "\n" + "This class has been introduced in version 0.28." +); + class PCellDeclarationImpl : public db::PCellDeclaration { @@ -359,6 +452,20 @@ public: } } + virtual void callback_fb (const db::Layout &layout, const std::string &name, db::ParameterStates &states) const + { + db::PCellDeclaration::callback (layout, name, states); + } + + virtual void callback (const db::Layout &layout, const std::string &name, db::ParameterStates &states) const + { + if (cb_callback.can_issue ()) { + cb_callback.issue (&db::PCellDeclaration::callback, layout, name, states); + } else { + db::PCellDeclaration::callback (layout, name, states); + } + } + void produce_fb (const db::Layout &layout, const std::vector &layer_ids, const db::pcell_parameters_type ¶meters, db::Cell &cell) const { return db::PCellDeclaration::produce (layout, layer_ids, parameters, cell); @@ -451,6 +558,7 @@ public: gsi::Callback cb_transformation_from_shape; gsi::Callback cb_wants_lazy_evaluation; gsi::Callback cb_coerce_parameters; + gsi::Callback cb_callback; gsi::Callback cb_get_display_name; }; @@ -458,6 +566,7 @@ Class decl_PCellDeclaration (decl_PCellDeclaration_Native, // fallback implementations to reroute Ruby calls to the base class: gsi::method ("get_parameters", &PCellDeclarationImpl::get_parameter_declarations_fb, "@hide") + gsi::method ("produce", &PCellDeclarationImpl::produce_fb, "@hide") + + gsi::method ("callback", &PCellDeclarationImpl::callback_fb, "@hide") + gsi::method ("can_create_from_shape", &PCellDeclarationImpl::can_create_from_shape_fb, "@hide") + gsi::method ("parameters_from_shape", &PCellDeclarationImpl::parameters_from_shape_fb, "@hide") + gsi::method ("transformation_from_shape", &PCellDeclarationImpl::transformation_from_shape_fb, "@hide") + @@ -493,6 +602,25 @@ Class decl_PCellDeclaration (decl_PCellDeclaration_Native, "\n" "It can raise an exception to indicate that something is not correct.\n" ) + + gsi::callback ("callback", &PCellDeclarationImpl::callback, &PCellDeclarationImpl::cb_callback, gsi::arg ("layout"), gsi::arg ("name"), gsi::arg ("states"), + "@brief Indicates a parameter change and allows implementing actions based on the parameter value\n" + "@param layout The layout object in which the PCell will be produced\n" + "@param name The name of the parameter which has changed or an empty string if all parameters need to be considered\n" + "@param states A \\PCellParameterStates object which can be used to manipulate the parameter states\n" + "This method may be reimplemented to implement parameter-specific actions upon value change or button callbacks. " + "Whenever the value of a parameter is changed in the PCell parameter form, this method is called with the name of the parameter " + "in 'name'. The implementation can manipulate values or states (enabled, visible) or parameters using the " + "\\PCellParameterStates object passed in 'states'.\n" + "\n" + "Initially, this method will be called with an empty parameter name to indicate a global change. The implementation " + "may then consolidate all states. The initial state is build from the 'readonly' (disabled) or 'hidden' (invisible) parameter " + "declarations.\n" + "\n" + "This method is also called when a button-type parameter is present and the button is pressed. In this case the parameter " + "name is the name of the button.\n" + "\n" + "This feature has been introduced in version 0.28." + ) + gsi::callback ("produce", &PCellDeclarationImpl::produce, &PCellDeclarationImpl::cb_produce, gsi::arg ("layout"), gsi::arg ("layer_ids"), gsi::arg ("parameters"), gsi::arg ("cell"), "@brief The production callback\n" "@param layout The layout object where the cell resides\n" @@ -634,6 +762,11 @@ static unsigned int pd_type_list () return (unsigned int) db::PCellParameterDeclaration::t_list; } +static unsigned int pd_type_callback () +{ + return (unsigned int) db::PCellParameterDeclaration::t_callback; +} + static unsigned int pd_type_none () { return (unsigned int) db::PCellParameterDeclaration::t_none; @@ -763,7 +896,8 @@ Class decl_PCellParameterDeclaration ("db", "PCel gsi::method ("TypeList", &pd_type_list, "@brief Type code: a list of variants") + gsi::method ("TypeLayer", &pd_type_layer, "@brief Type code: a layer (a \\LayerInfo object)") + gsi::method ("TypeShape", &pd_type_shape, "@brief Type code: a guiding shape (Box, Edge, Point, Polygon or Path)") + - gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type") + gsi::method ("TypeCallback", &pd_type_callback, "@brief Type code: a button triggering a callback\n\nThis code has been introduced in version 0.28.") + + gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type") , "@brief A PCell parameter declaration\n" "\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 0cc777b8b..926fa368a 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -2452,7 +2452,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2491,7 +2490,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2535,7 +2533,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2574,7 +2571,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2617,7 +2613,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2667,7 +2662,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2716,7 +2710,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " @@ -2765,7 +2758,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "\"metrics\" can be one of the constants \\Euclidian, \\Square or \\Projection. See there for " "a description of these constants.\n" - "Use nil for this value to select the default (Euclidian metrics).\n" "\n" "\"ignore_angle\" specifies the angle limit of two edges. If two edges form an angle equal or " "above the given value, they will not contribute in the check. " diff --git a/src/doc/doc/about/basic_lib.xml b/src/doc/doc/about/basic_lib.xml index a2592561e..3fa5c1715 100644 --- a/src/doc/doc/about/basic_lib.xml +++ b/src/doc/doc/about/basic_lib.xml @@ -83,7 +83,7 @@

Custom fonts are installed by copying the font file to a folder named "fonts" in one of the places in KLayout's path. The standard font can be found in - "src/std_font.gds" in the source package. + "src/db/db/std_font.gds" in the source package.

CIRCLE and ELLIPSE

diff --git a/src/doc/doc/about/drc_ref_layer.xml b/src/doc/doc/about/drc_ref_layer.xml index 6d105b8ea..4cc344d45 100644 --- a/src/doc/doc/about/drc_ref_layer.xml +++ b/src/doc/doc/about/drc_ref_layer.xml @@ -1125,6 +1125,25 @@ A more compact way of writing this is: p = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0))

+The "shape" method takes several forms: +

+

    +
  • shape(layer, object, object ...) (1)
  • +
  • shape(layer, datatype, object, object ...) (2)
  • +
  • shape(name, object, object ...) (3)
  • +
  • shape(layer_info, object, object ...) (4)
  • +
+

+The first form takes a GDS2 layer number. The datatype is assumed to be 0. +The second form takes a GDS layer and datatype number. +The third form takes a layer name for layout systems with named layers +(like Magic, CIF or DXF). +The forth form takes a LayerInfo object to specify the layer. +All forms take one to many geometry objects which are written to the respective layer. +Geometry objects can either be created using the generator functions +(box, polygon, path). The core classes DBox, DPolygon, DPath or +DText are also accepted as geometry objects. +

The fill pattern can be given a reference point which is used for placing the pattern. The reference point is the one which is aligned with the pattern origin. The following code will assign (-0.5, -0.5) as the reference point for the 1x1 micron rectangle. Hence the reference point is a little below and left of the rectangle which diff --git a/src/doc/doc/manual/net_tracing.xml b/src/doc/doc/manual/net_tracing.xml index b903ae388..b775c453e 100644 --- a/src/doc/doc/manual/net_tracing.xml +++ b/src/doc/doc/manual/net_tracing.xml @@ -34,20 +34,35 @@

Before nets can be extracted, a layer stack must be specified. Press "Layer Stack" on the user interface to open the - layer stack dialog. Layers must be specified in the "layer/datatype" notation. The + layer stack dialog or use "Edit Layer Stack" in the "Tools" menu. Layers must be specified in the "layer/datatype" notation. The via specification is optional. If no via layer is specified, both metal layer shapes are required to touch in order to form a connection. If a via layer is specified, a via shape must be present to form the connection.

- KLayout allows specification of symbolic layers and to use boolean expressions. That way it is possible to + The layer stack (also referred to as "Connectivity") is also a technology component. This means + if you select a technology for layout, the technology specific stack is selected. To edit the stack + for all technologies, use the Technology Manager ("Tools/Manage Technologies") and use the + "Connectivity" section from the technologies. +

+ +

+ A connectivity definition can specify multiple stacks, out of which one has to be selected. + This is useful, if your technology setup features multiple routing metal schemes for example. + You do not need to setup different technologies for each scheme. If you have declared multiple + stacks, you can choose one in the "Trace Net" dialog in the drop-down button right of the + "Layer Stack" and the "Configuration" button at the bottom left. +

+ +

+ Within the stack definition, KLayout allows specification of symbolic layers and to use boolean expressions. That way it is possible to assign meaningful names to layers (i.e. "POLY" or "VIA1") and to use derived layers (i.e. "ACTIVE-POLY" for the source and drain regions of a CMOS transistor). Read more about these features in and .

- If a layer stack has been defined, a net can be traced by pressing the "Trace Net" button and clicking on a point in the + Once a layer stack has been defined and selected, a net can be traced by pressing the "Trace Net" button and clicking on a point in the layout. Starting from shapes found under this point, the net is extracted and listed in the net list on the left side of the net tracing dialog. If "Lock" is checked, another net can be traced by clicking at another point without having to press the "Trace Net" button again. diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 88ab7e0b7..c8e2731a5 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -4712,6 +4712,25 @@ CODE # p = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0)) # @/code # + # The "shape" method takes several forms: + # + # @ul + # @li @tt shape(layer, object, object ...) @/tt (1) @/li + # @li @tt shape(layer, datatype, object, object ...) @/tt (2) @/li + # @li @tt shape(name, object, object ...) @/tt (3) @/li + # @li @tt shape(layer_info, object, object ...) @/tt (4) @/li + # @/ul + # + # The first form takes a GDS2 layer number. The datatype is assumed to be 0. + # The second form takes a GDS layer and datatype number. + # The third form takes a layer name for layout systems with named layers + # (like Magic, CIF or DXF). + # The forth form takes a RBA::LayerInfo object to specify the layer. + # All forms take one to many geometry objects which are written to the respective layer. + # Geometry objects can either be created using the generator functions + # (\global#box, \global#polygon, \global#path). The core classes RBA::DBox, RBA::DPolygon, RBA::DPath or + # RBA::DText are also accepted as geometry objects. + # # The fill pattern can be given a reference point which is used for placing the pattern. The reference point # is the one which is aligned with the pattern origin. The following code will assign (-0.5, -0.5) as the reference # point for the 1x1 micron rectangle. Hence the reference point is a little below and left of the rectangle which diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb index dedd797ef..86fd67e8d 100644 --- a/src/drc/drc/built-in-macros/_drc_tags.rb +++ b/src/drc/drc/built-in-macros/_drc_tags.rb @@ -256,6 +256,10 @@ module DRC else raise("Argument ##{ai+1} not understood for FillCell#shape") end + elsif a.is_a?(RBA::LayerInfo) + layer = a.layer + datatype = a.datatype + name = a.name elsif a.is_a?(String) if !name name = a diff --git a/src/edt/edt/AlignOptionsDialog.ui b/src/edt/edt/AlignOptionsDialog.ui index c6e21d7da..d94795de2 100644 --- a/src/edt/edt/AlignOptionsDialog.ui +++ b/src/edt/edt/AlignOptionsDialog.ui @@ -26,7 +26,7 @@ - + :/align_none_32px.png:/align_none_32px.png @@ -43,7 +43,7 @@ - + :/align_left_32px.png:/align_left_32px.png @@ -60,7 +60,7 @@ - + :/align_hcenter_32px.png:/align_hcenter_32px.png @@ -77,7 +77,7 @@ - + :/align_right_32px.png:/align_right_32px.png @@ -204,7 +204,7 @@ - + :/align_none_32px.png:/align_none_32px.png @@ -221,7 +221,7 @@ - + :/align_top_32px.png:/align_top_32px.png @@ -238,7 +238,7 @@ - + :/align_vcenter_32px.png:/align_vcenter_32px.png @@ -308,7 +308,7 @@ - + :/align_bottom_32px.png:/align_bottom_32px.png @@ -432,7 +432,7 @@ buttonBox - + diff --git a/src/edt/edt/AreaAndPerimeterDialog.ui b/src/edt/edt/AreaAndPerimeterDialog.ui new file mode 100644 index 000000000..9fd1a263a --- /dev/null +++ b/src/edt/edt/AreaAndPerimeterDialog.ui @@ -0,0 +1,130 @@ + + + AreaAndPerimeterDialog + + + + 0 + 0 + 367 + 205 + + + + Area And Perimeter + + + + + + Qt::Vertical + + + + 10 + 11 + + + + + + + + true + + + + + + + Area + + + + + + + µm + + + + + + + µm² + + + + + + + Perimeter + + + + + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + Note: area and perimeter are computed in "merged mode". This means, overlapping shapes are counted once for area calculation. +The perimeter calculation only takes true outside edges into account. Internal edges are ignored. + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + + buttonBox + accepted() + AreaAndPerimeterDialog + accept() + + + 303 + 185 + + + 311 + 201 + + + + + diff --git a/src/edt/edt/DistributeOptionsDialog.ui b/src/edt/edt/DistributeOptionsDialog.ui index 900a68f5f..f70b9c04a 100644 --- a/src/edt/edt/DistributeOptionsDialog.ui +++ b/src/edt/edt/DistributeOptionsDialog.ui @@ -278,7 +278,7 @@ - + :/align_none_32px.png:/align_none_32px.png @@ -311,7 +311,7 @@ - + :/align_left_32px.png:/align_left_32px.png @@ -344,7 +344,7 @@ - + :/align_hcenter_32px.png:/align_hcenter_32px.png @@ -377,7 +377,7 @@ - + :/align_right_32px.png:/align_right_32px.png @@ -456,7 +456,7 @@ - + :/align_none_32px.png:/align_none_32px.png @@ -489,7 +489,7 @@ - + :/align_top_32px.png:/align_top_32px.png @@ -522,7 +522,7 @@ - + :/align_vcenter_32px.png:/align_vcenter_32px.png @@ -555,7 +555,7 @@ - + :/align_bottom_32px.png:/align_bottom_32px.png @@ -676,7 +676,7 @@ buttonBox - + diff --git a/src/edt/edt/EditorOptionsInst.ui b/src/edt/edt/EditorOptionsInst.ui index bfbe93beb..86b3e2c56 100644 --- a/src/edt/edt/EditorOptionsInst.ui +++ b/src/edt/edt/EditorOptionsInst.ui @@ -158,7 +158,7 @@ ... - + :/find_16px.png:/find_16px.png @@ -549,7 +549,7 @@ - + diff --git a/src/edt/edt/InstPropertiesPage.ui b/src/edt/edt/InstPropertiesPage.ui index e022a1cd4..f389d23f1 100644 --- a/src/edt/edt/InstPropertiesPage.ui +++ b/src/edt/edt/InstPropertiesPage.ui @@ -59,7 +59,6 @@ Sans Serif 12 - 75 false true false @@ -731,7 +730,7 @@ - :/warn_16px@2x.png + :/warn_16px@2x.png Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -899,7 +898,7 @@ inst_pb - + diff --git a/src/edt/edt/MakeCellOptionsDialog.ui b/src/edt/edt/MakeCellOptionsDialog.ui index 9fae1b2bc..e40f36a75 100644 --- a/src/edt/edt/MakeCellOptionsDialog.ui +++ b/src/edt/edt/MakeCellOptionsDialog.ui @@ -144,7 +144,7 @@ ... - + :/ct_31px.png:/ct_31px.png @@ -164,7 +164,7 @@ ... - + :/lt_31px.png:/lt_31px.png @@ -184,7 +184,7 @@ ... - + :/rt_31px.png:/rt_31px.png @@ -204,7 +204,7 @@ ... - + :/lc_31px.png:/lc_31px.png @@ -224,7 +224,7 @@ ... - + :/cc_31px.png:/cc_31px.png @@ -244,7 +244,7 @@ ... - + :/rc_31px.png:/rc_31px.png @@ -264,7 +264,7 @@ ... - + :/lb_31px.png:/lb_31px.png @@ -284,7 +284,7 @@ ... - + :/cb_31px.png:/cb_31px.png @@ -304,7 +304,7 @@ ... - + :/rb_31px.png:/rb_31px.png @@ -366,7 +366,7 @@ - + diff --git a/src/edt/edt/edt.pro b/src/edt/edt/edt.pro index 24075ca3b..7680a9946 100644 --- a/src/edt/edt/edt.pro +++ b/src/edt/edt/edt.pro @@ -27,7 +27,8 @@ DEFINES += MAKE_EDT_LIBRARY RoundCornerOptionsDialog.ui \ TextPropertiesPage.ui \ DistributeOptionsDialog.ui \ - EditorOptionsInstPCellParam.ui + EditorOptionsInstPCellParam.ui \ + AreaAndPerimeterDialog.ui } diff --git a/src/edt/edt/edtDialogs.cc b/src/edt/edt/edtDialogs.cc index 1486b2abf..498eb8e47 100644 --- a/src/edt/edt/edtDialogs.cc +++ b/src/edt/edt/edtDialogs.cc @@ -683,6 +683,29 @@ BEGIN_PROTECTED; END_PROTECTED; } +// -------------------------------------------------------------------------------- +// AreaAndPerimeterDialog implementation + +AreaAndPerimeterDialog::AreaAndPerimeterDialog (QWidget *parent) + : QDialog (parent) +{ + setupUi (this); +} + +AreaAndPerimeterDialog::~AreaAndPerimeterDialog () +{ + // .. nothing yet .. +} + +bool +AreaAndPerimeterDialog::exec_dialog (double area, double perimeter) +{ + area_le->setText (tl::to_qstring (tl::sprintf ("%.12g", area))); + perimeter_le->setText (tl::to_qstring (tl::sprintf ("%.12g", perimeter))); + + return exec () != 0; +} + } #endif diff --git a/src/edt/edt/edtDialogs.h b/src/edt/edt/edtDialogs.h index 5864a8d54..a108585b5 100644 --- a/src/edt/edt/edtDialogs.h +++ b/src/edt/edt/edtDialogs.h @@ -43,6 +43,7 @@ #include "ui_MakeCellOptionsDialog.h" #include "ui_MakeArrayOptionsDialog.h" #include "ui_RoundCornerOptionsDialog.h" +#include "ui_AreaAndPerimeterDialog.h" namespace lay { @@ -205,6 +206,22 @@ private: bool m_has_extracted; }; +/** + * @brief Result dialog for "area and perimeter" + */ +class AreaAndPerimeterDialog + : public QDialog, + private Ui::AreaAndPerimeterDialog +{ +Q_OBJECT + +public: + AreaAndPerimeterDialog (QWidget *parent); + ~AreaAndPerimeterDialog (); + + bool exec_dialog (double area, double perimeter); +}; + } // namespace edt #endif diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index ce5c0d14e..8cfdac462 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -555,7 +555,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & tl_assert (mp_pcell_parameters); std::vector param = mp_pcell_parameters->get_parameters (0); - const std::vector &initial_param = mp_pcell_parameters->initial_parameters (); + std::vector initial_param = mp_pcell_parameters->initial_parameters (); const std::vector &pcp = mp_pcell_parameters->pcell_decl ()->parameter_declarations (); for (std::vector::const_iterator pd = pcp.begin (); pd != pcp.end (); ++pd) { diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index 0f97e0166..c7b51e1b9 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -25,6 +25,7 @@ #include "dbPolygonTools.h" #include "dbLibrary.h" #include "dbLibraryManager.h" +#include "dbRegion.h" #include "tlExceptions.h" #include "layLayoutView.h" #include "laySelector.h" @@ -82,6 +83,7 @@ MainService::MainService (db::Manager *manager, lay::LayoutViewBase *view, lay:: { #if defined(HAVE_QT) mp_round_corners_dialog = 0; + mp_area_and_perimeter_dialog = 0; mp_align_options_dialog = 0; mp_distribute_options_dialog = 0; mp_flatten_inst_options_dialog = 0; @@ -106,6 +108,15 @@ MainService::round_corners_dialog () return mp_round_corners_dialog; } +edt::AreaAndPerimeterDialog * +MainService::area_and_perimeter_dialog () +{ + if (! mp_area_and_perimeter_dialog) { + mp_area_and_perimeter_dialog = new edt::AreaAndPerimeterDialog (lay::widget_from_view (view ())); + } + return mp_area_and_perimeter_dialog; +} + edt::AlignOptionsDialog * MainService::align_options_dialog () { @@ -168,6 +179,8 @@ MainService::menu_activated (const std::string &symbol) cm_tap (); } else if (symbol == "edt::sel_round_corners") { cm_round_corners (); + } else if (symbol == "edt::sel_area_perimeter") { + cm_area_perimeter (); } else if (symbol == "edt::sel_convert_to_pcell") { cm_convert_to_pcell (); } else if (symbol == "edt::sel_convert_to_cell") { @@ -1346,6 +1359,67 @@ MainService::cm_convert_to_pcell () } } +void MainService::cm_area_perimeter () +{ +#if ! defined(HAVE_QT) + tl_assert (false); // see TODO +#endif + + double dbu = 0.0; + + std::vector edt_services = view ()->get_plugins (); + + db::Region region; + + // get (common) cellview index of the primary selection + for (std::vector::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 ()) { + continue; + } + + db::Polygon poly; + if (!s->shape ().polygon (poly)) { + continue; + } + + double shape_dbu = view ()->cellview (s->cv_index ())->layout ().dbu (); + + if (dbu == 0.0) { + // first CV is used for reference DBU + dbu = shape_dbu; + } + + if (fabs (shape_dbu - dbu) < db::epsilon) { + region.insert (s->trans () * poly); + } else { + region.insert ((db::ICplxTrans (shape_dbu / dbu) * s->trans ()) * poly); + } + + } + + } + +#if defined(HAVE_QT) + if (region.count () > 100000) { + if (QMessageBox::warning (lay::widget_from_view (view ()), tr ("Warning: Big Selection"), + tr ("The selection contains many shapes. Area and perimeter computation may take a long time.\nContinue anyway?"), + QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) { + return; + } + } +#endif + + double area = region.area () * dbu * dbu; + double perimeter = region.perimeter () * dbu; + +#if defined(HAVE_QT) + area_and_perimeter_dialog ()->exec_dialog (area, perimeter); +#endif +} + static bool extract_rad (std::vector &poly, double &rinner, double &router, unsigned int &n) { std::vector new_pts; @@ -1356,7 +1430,7 @@ static bool extract_rad (std::vector &poly, double &rinner, double db::Polygon new_poly; new_pts.clear (); - if (! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts) && + if (! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts) && ! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts, true)) { // ultimate fallback: assign original contour new_poly.assign_hull (p->begin_hull (), p->end_hull (), false /*don't compress*/); @@ -1368,7 +1442,7 @@ static bool extract_rad (std::vector &poly, double &rinner, double for (unsigned int h = 0; h < p->holes (); ++h) { new_pts.clear (); - if (! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts) && + if (! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts) && ! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts, true)) { // ultimate fallback: assign original contour new_poly.insert_hole (p->begin_hole (h), p->end_hole (h), false /*don't compress*/); diff --git a/src/edt/edt/edtMainService.h b/src/edt/edt/edtMainService.h index e6b26f98b..cc9fc2426 100644 --- a/src/edt/edt/edtMainService.h +++ b/src/edt/edt/edtMainService.h @@ -48,6 +48,7 @@ class Service; class EditorOptionsPages; class EditorOptionsPage; class RoundCornerOptionsDialog; +class AreaAndPerimeterDialog; class MakeCellOptionsDialog; class MakeArrayOptionsDialog; class AlignOptionsDialog; @@ -104,6 +105,11 @@ public: */ void cm_round_corners (); + /** + * @brief Show area and perimeter of selection + */ + void cm_area_perimeter (); + /** * @brief Convert selection to PCell */ @@ -223,6 +229,7 @@ private: bool m_undo_before_apply; #if defined(HAVE_QT) edt::RoundCornerOptionsDialog *mp_round_corners_dialog; + edt::AreaAndPerimeterDialog *mp_area_and_perimeter_dialog; edt::AlignOptionsDialog *mp_align_options_dialog; edt::DistributeOptionsDialog *mp_distribute_options_dialog; lay::FlattenInstOptionsDialog *mp_flatten_inst_options_dialog; @@ -234,6 +241,7 @@ private: void check_no_guiding_shapes (); #if defined(HAVE_QT) edt::RoundCornerOptionsDialog *round_corners_dialog (); + edt::AreaAndPerimeterDialog *area_and_perimeter_dialog (); edt::AlignOptionsDialog *align_options_dialog (); edt::DistributeOptionsDialog *distribute_options_dialog (); lay::FlattenInstOptionsDialog *flatten_inst_options_dialog (); diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index ed28773cf..e7e72f0c6 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -149,7 +149,7 @@ static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget, } PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense) - : QFrame (parent), m_dense (dense), dm_parameter_changed (this, &PCellParametersPage::do_parameter_changed) + : QFrame (parent), m_dense (dense), m_show_parameter_names (false), dm_parameter_changed (this, &PCellParametersPage::do_parameter_changed) { init (); } @@ -170,7 +170,7 @@ PCellParametersPage::init () frame_layout->setContentsMargins (0, 0, 0, 0); setLayout (frame_layout); - mp_update_frame = new QFrame (); + mp_update_frame = new QFrame (this); mp_update_frame->setFrameShape (QFrame::NoFrame); frame_layout->addWidget (mp_update_frame, 0, 0, 1, 1); @@ -197,7 +197,7 @@ PCellParametersPage::init () update_frame_layout->setColumnStretch (2, 1); - mp_error_frame = new QFrame (); + mp_error_frame = new QFrame (this); mp_error_frame->setFrameShape (QFrame::NoFrame); frame_layout->addWidget (mp_error_frame, 1, 0, 1, 1); @@ -224,6 +224,13 @@ PCellParametersPage::init () error_frame_layout->addWidget (mp_error_label, 1, 1, 1, 2); error_frame_layout->setColumnStretch (2, 1); + + mp_show_parameter_names_cb = new QCheckBox (this); + mp_show_parameter_names_cb->setText (tr ("Show parameter names")); + mp_show_parameter_names_cb->setChecked (m_show_parameter_names); + frame_layout->addWidget (mp_show_parameter_names_cb, 3, 0, 1, 1); + + connect (mp_show_parameter_names_cb, SIGNAL (clicked (bool)), this, SLOT (show_parameter_names (bool))); } bool @@ -232,19 +239,34 @@ PCellParametersPage::lazy_evaluation () return mp_pcell_decl.get () && mp_pcell_decl->wants_lazy_evaluation (); } +void +PCellParametersPage::show_parameter_names (bool f) +{ + if (m_show_parameter_names == f) { + return; + } + + m_show_parameter_names = f; + mp_show_parameter_names_cb->setChecked (f); + setup (mp_view, m_cv_index, mp_pcell_decl.get (), get_parameters ()); +} + void PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) { mp_pcell_decl.reset (const_cast (pcell_decl)); // no const weak_ptr ... mp_view = view; m_cv_index = cv_index; - m_parameters = parameters; + m_states = db::ParameterStates (); + m_initial_states = db::ParameterStates (); if (mp_parameters_area) { delete mp_parameters_area; } m_widgets.clear (); + m_icon_widgets.clear (); + m_all_widgets.clear (); mp_parameters_area = new QScrollArea (this); mp_parameters_area->setFrameShape (QFrame::NoFrame); @@ -268,6 +290,12 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P QWidget *main_frame = inner_frame; QGridLayout *main_grid = inner_grid; + if (! mp_pcell_decl) { + mp_parameters_area->setWidget (main_frame); + update_current_parameters (); + return; + } + int main_row = 0; int row = 0; std::string group_title; @@ -276,8 +304,23 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P const std::vector &pcp = pcell_decl->parameter_declarations (); for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { + tl::Variant value; + if (r < int (parameters.size ())) { + value = parameters [r]; + } else { + value = p->get_default (); + } + + db::ParameterState &ps = m_states.parameter (p->get_name ()); + ps.set_value (value); + ps.set_readonly (p->is_readonly ()); + ps.set_visible (! p->is_hidden ()); + + m_all_widgets.push_back (std::vector ()); + + if (p->get_type () == db::PCellParameterDeclaration::t_shape) { m_widgets.push_back (0); + m_icon_widgets.push_back (0); continue; } @@ -297,7 +340,7 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P // create a new group QGroupBox *gb = new QGroupBox (main_frame); gb->setTitle (tl::to_qstring (gt)); - main_grid->addWidget (gb, main_row, 0, 1, 2); + main_grid->addWidget (gb, main_row, 0, 1, 3); inner_grid = new QGridLayout (gb); if (m_dense) { @@ -324,13 +367,28 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P } - inner_grid->addWidget (new QLabel (tl::to_qstring (description), inner_frame), row, 0); + QLabel *icon_label = new QLabel (QString (), inner_frame); + inner_grid->addWidget (icon_label, row, 0); + m_icon_widgets.push_back (icon_label); + m_all_widgets.back ().push_back (icon_label); + + if (p->get_type () != db::PCellParameterDeclaration::t_callback) { + + std::string leader; + if (m_show_parameter_names) { + leader = tl::sprintf ("[%s] ", p->get_name ()); + } + + QLabel *l = new QLabel (tl::to_qstring (leader + description), inner_frame); + inner_grid->addWidget (l, row, 1); + m_all_widgets.back ().push_back (l); + + } else if (m_show_parameter_names) { + + QLabel *l = new QLabel (tl::to_qstring (tl::sprintf ("[%s]", p->get_name ())), inner_frame); + inner_grid->addWidget (l, row, 1); + m_all_widgets.back ().push_back (l); - tl::Variant value; - if (r < int (parameters.size ())) { - value = parameters [r]; - } else { - value = p->get_default (); } if (p->get_choices ().empty ()) { @@ -347,7 +405,6 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P f->setFrameShape (QFrame::NoFrame); QLineEdit *le = new QLineEdit (f); - le->setEnabled (! p->is_readonly ()); hb->addWidget (le); le->setMaximumWidth (150); le->setObjectName (tl::to_qstring (p->get_name ())); @@ -357,21 +414,37 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P hb->addWidget (ul, 1); ul->setText (tl::to_qstring (p->get_unit ())); - inner_grid->addWidget (f, row, 1); + inner_grid->addWidget (f, row, 2); + m_all_widgets.back ().push_back (f); connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ())); } break; + case db::PCellParameterDeclaration::t_callback: + { + QPushButton *pb = new QPushButton (inner_frame); + pb->setObjectName (tl::to_qstring (p->get_name ())); + pb->setText (tl::to_qstring (description)); + pb->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred); + m_widgets.push_back (pb); + + inner_grid->addWidget (pb, row, 2); + m_all_widgets.back ().push_back (pb); + + connect (pb, SIGNAL (clicked ()), this, SLOT (parameter_changed ())); + } + break; + case db::PCellParameterDeclaration::t_string: case db::PCellParameterDeclaration::t_shape: case db::PCellParameterDeclaration::t_list: { QLineEdit *le = new QLineEdit (inner_frame); - le->setEnabled (! p->is_readonly ()); le->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (le); - inner_grid->addWidget (le, row, 1); + inner_grid->addWidget (le, row, 2); + m_all_widgets.back ().push_back (le); connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ())); } @@ -380,12 +453,12 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P case db::PCellParameterDeclaration::t_layer: { lay::LayerSelectionComboBox *ly = new lay::LayerSelectionComboBox (inner_frame); - ly->setEnabled (! p->is_readonly ()); ly->set_no_layer_available (true); ly->set_view (mp_view, m_cv_index, true /*all layers*/); ly->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (ly); - inner_grid->addWidget (ly, row, 1); + inner_grid->addWidget (ly, row, 2); + m_all_widgets.back ().push_back (ly); connect (ly, SIGNAL (activated (int)), this, SLOT (parameter_changed ())); } @@ -396,10 +469,10 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P QCheckBox *cbx = new QCheckBox (inner_frame); // this makes the checkbox not stretch over the full width - better when navigating with tab cbx->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred)); - cbx->setEnabled (! p->is_readonly ()); cbx->setObjectName (tl::to_qstring (p->get_name ())); m_widgets.push_back (cbx); - inner_grid->addWidget (cbx, row, 1); + inner_grid->addWidget (cbx, row, 2); + m_all_widgets.back ().push_back (cbx); connect (cbx, SIGNAL (stateChanged (int)), this, SLOT (parameter_changed ())); } @@ -426,16 +499,14 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P connect (cb, SIGNAL (activated (int)), this, SLOT (parameter_changed ())); - cb->setEnabled (! p->is_readonly ()); cb->setMinimumContentsLength (30); cb->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon); m_widgets.push_back (cb); - inner_grid->addWidget (cb, row, 1); + inner_grid->addWidget (cb, row, 2); + m_all_widgets.back ().push_back (cb); } - set_value (*p, m_widgets.back (), value); - ++row; if (inner_frame == main_frame) { ++main_row; @@ -443,6 +514,22 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P } + // initial callback + + try { + mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), std::string (), m_states); + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + + m_initial_states = m_states; + update_widgets_from_states (m_states); + mp_parameters_area->setWidget (main_frame); main_frame->show (); @@ -458,6 +545,8 @@ PCellParametersPage::get_state () s.vScrollPosition = mp_parameters_area->verticalScrollBar ()->value (); s.hScrollPosition = mp_parameters_area->horizontalScrollBar ()->value (); + s.show_parameter_names = m_show_parameter_names; + if (focusWidget ()) { s.focusWidget = focusWidget ()->objectName (); } @@ -473,6 +562,10 @@ PCellParametersPage::set_state (const State &s) mp_parameters_area->verticalScrollBar ()->setValue (s.vScrollPosition); mp_parameters_area->horizontalScrollBar ()->setValue (s.hScrollPosition); + if (s.show_parameter_names != m_show_parameter_names) { + show_parameter_names (s.show_parameter_names); + } + if (! s.focusWidget.isEmpty ()) { QWidget *c = findChild (s.focusWidget); if (c) { @@ -483,18 +576,58 @@ PCellParametersPage::set_state (const State &s) } } -void +void PCellParametersPage::parameter_changed () { + if (! mp_pcell_decl) { + return; + } + if (! mp_view->cellview (m_cv_index).is_valid ()) { + return; + } + + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + const db::PCellParameterDeclaration *pd = 0; + for (auto w = m_widgets.begin (); w != m_widgets.end (); ++w) { + if (*w == sender ()) { + pd = &pcp [w - m_widgets.begin ()]; + break; + } + } + + try { + + db::ParameterStates states = m_states; + + bool edit_error = false; + // Silent and without coerce - this will be done later in do_parameter_changed(). + // This is just about providing the inputs for the callback. + get_parameters_internal (states, edit_error); + + if (! edit_error) { + mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), pd ? pd->get_name () : std::string (), states); + m_states = states; + } + + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + dm_parameter_changed (); } void PCellParametersPage::do_parameter_changed () { - // does a coerce and update - bool ok = false; - std::vector parameters = get_parameters (&ok); + bool ok = true; + db::ParameterStates states = m_states; + get_parameters (states, &ok); // includes coerce + update_widgets_from_states (states); if (ok && ! lazy_evaluation ()) { emit edited (); } @@ -511,159 +644,166 @@ PCellParametersPage::update_button_pressed () bool PCellParametersPage::update_current_parameters () { - bool ok = false; - std::vector parameters = get_parameters (&ok); + bool ok = true; + db::ParameterStates states = m_states; + get_parameters (states, &ok); // includes coerce if (ok) { - m_current_parameters = parameters; + m_current_states = states; mp_update_frame->hide (); } return ok; } -std::vector -PCellParametersPage::get_parameters (bool *ok) +void +PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool &edit_error) { - std::vector parameters; + edit_error = false; + int r = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + + db::ParameterState &ps = states.parameter (p->get_name ()); + + if (! ps.is_visible () || ! ps.is_enabled () || ps.is_readonly () || p->get_type () == db::PCellParameterDeclaration::t_shape) { + continue; + } + + if (p->get_choices ().empty ()) { + + switch (p->get_type ()) { + + case db::PCellParameterDeclaration::t_int: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + int v = 0; + tl::from_string_ext (tl::to_string (le->text ()), v); + + ps.set_value (tl::Variant (v)); + lay::indicate_error (le, (tl::Exception *) 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = true; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_double: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + double v = 0; + tl::from_string_ext (tl::to_string (le->text ()), v); + + ps.set_value (tl::Variant (v)); + lay::indicate_error (le, (tl::Exception *) 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = true; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_string: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + ps.set_value (tl::Variant (tl::to_string (le->text ()))); + } + } + break; + + case db::PCellParameterDeclaration::t_list: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + std::vector values = tl::split (tl::to_string (le->text ()), ","); + ps.set_value (tl::Variant (values.begin (), values.end ())); + } + } + break; + + case db::PCellParameterDeclaration::t_layer: + { + lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); + if (ly) { + ps.set_value (tl::Variant (ly->current_layer_props ())); + } + } + break; + case db::PCellParameterDeclaration::t_boolean: + { + QCheckBox *cbx = dynamic_cast (m_widgets [r]); + if (cbx) { + ps.set_value (tl::Variant (cbx->isChecked ())); + } + } + break; + + default: + break; + } + + } else { + + QComboBox *cb = dynamic_cast (m_widgets [r]); + if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { + ps.set_value (p->get_choices () [cb->currentIndex ()]); + } + + } + + } +} + +void +PCellParametersPage::get_parameters (db::ParameterStates &states, bool *ok) +{ try { if (! mp_pcell_decl) { throw tl::Exception (tl::to_string (tr ("PCell no longer valid."))); } - bool edit_error = true; + bool edit_error = false; - int r = 0; - const std::vector &pcp = mp_pcell_decl->parameter_declarations (); - for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + get_parameters_internal (states, edit_error); - if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { - - if (r < (int) m_parameters.size ()) { - parameters.push_back (m_parameters [r]); - } else { - parameters.push_back (p->get_default ()); - } - - } else { - - parameters.push_back (tl::Variant ()); - - if (p->get_choices ().empty ()) { - - switch (p->get_type ()) { - - case db::PCellParameterDeclaration::t_int: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - int v = 0; - tl::from_string_ext (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, (tl::Exception *) 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_double: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - double v = 0; - tl::from_string_ext (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, (tl::Exception *) 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_string: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - parameters.back () = tl::Variant (tl::to_string (le->text ())); - } - } - break; - - case db::PCellParameterDeclaration::t_list: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - std::vector values = tl::split (tl::to_string (le->text ()), ","); - parameters.back () = tl::Variant (values.begin (), values.end ()); - } - } - break; - - case db::PCellParameterDeclaration::t_layer: - { - lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); - if (ly) { - parameters.back () = tl::Variant (ly->current_layer_props ()); - } - } - break; - case db::PCellParameterDeclaration::t_boolean: - { - QCheckBox *cbx = dynamic_cast (m_widgets [r]); - if (cbx) { - parameters.back () = tl::Variant (cbx->isChecked ()); - } - } - break; - - default: - break; - } - - } else { - - QComboBox *cb = dynamic_cast (m_widgets [r]); - if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { - parameters.back () = p->get_choices () [cb->currentIndex ()]; - } - - } - - } - - } - - if (! edit_error) { + if (edit_error) { throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details."))); } - // coerce the parameters + // coerces the parameters and writes the changed values back if (mp_view->cellview (m_cv_index).is_valid ()) { + + auto parameters = parameter_from_states (states); + auto before_coerce = parameters; mp_pcell_decl->coerce_parameters (mp_view->cellview (m_cv_index)->layout (), parameters); + + if (parameters != before_coerce) { + states_from_parameters (states, parameters); + set_parameters_internal (states, lazy_evaluation ()); + } + } - set_parameters_internal (parameters, lazy_evaluation ()); if (ok) { *ok = true; @@ -691,19 +831,112 @@ PCellParametersPage::get_parameters (bool *ok) } } +} - return parameters; +std::vector +PCellParametersPage::get_parameters (bool *ok) +{ + db::ParameterStates states = m_states; + get_parameters (states, ok); + + return parameter_from_states (states); } void PCellParametersPage::set_parameters (const std::vector ¶meters) { - m_parameters = parameters; - set_parameters_internal (parameters, false); + if (! mp_pcell_decl) { + return; + } + + states_from_parameters (m_states, parameters); + + try { + if (mp_view->cellview (m_cv_index).is_valid ()) { + mp_pcell_decl->callback (mp_view->cellview (m_cv_index)->layout (), std::string (), m_states); + } + } catch (tl::Exception &ex) { + // potentially caused by script errors in callback implementation + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore other errors + } + + m_initial_states = m_states; + set_parameters_internal (m_states, false); } void -PCellParametersPage::set_parameters_internal (const std::vector ¶meters, bool tentatively) +PCellParametersPage::update_widgets_from_states (const db::ParameterStates &states) +{ + if (! mp_pcell_decl) { + return; + } + + size_t i = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end () && i < m_widgets.size (); ++p, ++i) { + + const std::string &name = p->get_name (); + const db::ParameterState &ps = states.parameter (name); + + if (m_widgets [i]) { + QLineEdit *le = dynamic_cast (m_widgets [i]); + if (le) { + le->setEnabled (ps.is_enabled ()); + le->setReadOnly (ps.is_readonly ()); + } else { + m_widgets [i]->setEnabled (ps.is_enabled () && ! ps.is_readonly ()); + } + } + + for (auto w = m_all_widgets [i].begin (); w != m_all_widgets [i].end (); ++w) { + if (*w != m_widgets [i]) { + (*w)->setEnabled (ps.is_enabled ()); + } + if (*w != m_icon_widgets [i]) { + (*w)->setVisible (ps.is_visible ()); + } + (*w)->setToolTip (tl::to_qstring (ps.tooltip ())); + } + + if (m_icon_widgets [i]) { + + static QPixmap error (":/error_16px@2x.png"); + static QPixmap info (":/info_16px@2x.png"); + static QPixmap warning (":/warn_16px@2x.png"); + + switch (ps.icon ()) { + case db::ParameterState::NoIcon: + default: + m_icon_widgets [i]->setPixmap (QPixmap ()); + m_icon_widgets [i]->hide (); + break; + case db::ParameterState::InfoIcon: + m_icon_widgets [i]->setPixmap (info); + m_icon_widgets [i]->show (); + break; + case db::ParameterState::WarningIcon: + m_icon_widgets [i]->setPixmap (warning); + m_icon_widgets [i]->show (); + break; + case db::ParameterState::ErrorIcon: + m_icon_widgets [i]->setPixmap (error); + m_icon_widgets [i]->show (); + break; + } + + } + + } + + set_parameters_internal (states, lazy_evaluation ()); +} + +void +PCellParametersPage::set_parameters_internal (const db::ParameterStates &states, bool tentatively) { if (! mp_pcell_decl) { return; @@ -713,8 +946,8 @@ PCellParametersPage::set_parameters_internal (const std::vector &pa size_t r = 0; const std::vector &pcp = mp_pcell_decl->parameter_declarations (); for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - if (r < parameters.size () && m_widgets [r]) { - set_value (*p, m_widgets [r], parameters [r]); + if (m_widgets [r]) { + set_value (*p, m_widgets [r], states.parameter (p->get_name ()).value ()); } } @@ -723,14 +956,53 @@ PCellParametersPage::set_parameters_internal (const std::vector &pa bool update_needed = false; if (! tentatively) { - m_current_parameters = parameters; + m_current_states = states; } else { - update_needed = (m_current_parameters != parameters); + update_needed = ! m_current_states.values_are_equal (states); } mp_update_frame->setVisible (update_needed); } +std::vector +PCellParametersPage::parameter_from_states (const db::ParameterStates &states) const +{ + std::vector parameters; + if (mp_pcell_decl) { + + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (auto p = pcp.begin (); p != pcp.end (); ++p) { + if (! states.has_parameter (p->get_name ())) { + parameters.push_back (p->get_default ()); + } else { + parameters.push_back (states.parameter (p->get_name ()).value ()); + } + } + + } + + return parameters; +} + +void +PCellParametersPage::states_from_parameters (db::ParameterStates &states, const std::vector ¶meters) +{ + if (! mp_pcell_decl) { + return; + } + + size_t r = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + db::ParameterState &ps = states.parameter (p->get_name ()); + if (r < parameters.size ()) { + ps.set_value (parameters [r]); + } else { + ps.set_value (p->get_default ()); + } + } +} + } #endif diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index 83eadfea1..05462eb02 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace lay { @@ -52,9 +53,10 @@ Q_OBJECT public: struct State { - State () : valid (false), hScrollPosition (0), vScrollPosition (0) { } + State () : valid (false), show_parameter_names (false), hScrollPosition (0), vScrollPosition (0) { } bool valid; + bool show_parameter_names; int hScrollPosition; int vScrollPosition; QString focusWidget; @@ -93,7 +95,7 @@ public: void set_state (const State &s); /** - * @brief Get the current parameters + * @brief Gets the current parameters * * *ok is set to true, if there is no error. In case of an error it's set to false. * The error is indicated in the error label in the editor page. @@ -102,13 +104,24 @@ public: std::vector get_parameters (bool *ok = 0); /** - * @brief Gets the initial parameters + * @brief Gets the current parameters into a ParameterStates object * - * The initial parameters are the ones present on "setup". + * *ok is set to true, if there is no error. In case of an error it's set to false. + * The error is indicated in the error label in the editor page. + * If ok is null, an exception is thrown. + * + * The value fields of the ParameterState members is set to the parameter value. + * The other attributes are not changed. Parameters not present inside the + * ParameterStates object are created with their corresponding name. */ - const std::vector &initial_parameters () const + void get_parameters (db::ParameterStates &states, bool *ok = 0); + + /** + * @brief Gets the initial parameters + */ + std::vector initial_parameters () const { - return m_parameters; + return parameter_from_states (m_initial_states); } /** @@ -127,6 +140,9 @@ public: signals: void edited (); +public slots: + void show_parameter_names (bool f); + private slots: void parameter_changed (); void update_button_pressed (); @@ -139,20 +155,27 @@ private: QLabel *mp_changed_icon; QToolButton *mp_update_button; QFrame *mp_error_frame, *mp_update_frame; + QCheckBox *mp_show_parameter_names_cb; tl::weak_ptr mp_pcell_decl; std::vector m_widgets; + std::vector m_icon_widgets; + std::vector > m_all_widgets; lay::LayoutViewBase *mp_view; int m_cv_index; - db::pcell_parameters_type m_parameters; - bool m_dense; + bool m_dense, m_show_parameter_names; tl::DeferredMethod dm_parameter_changed; - std::vector m_current_parameters; + db::ParameterStates m_current_states, m_initial_states; + db::ParameterStates m_states; void init (); void do_parameter_changed (); bool lazy_evaluation (); - void set_parameters_internal (const std::vector &values, bool tentatively); + void set_parameters_internal (const db::ParameterStates &states, bool tentatively); bool update_current_parameters (); + void update_widgets_from_states (const db::ParameterStates &states); + void get_parameters_internal (db::ParameterStates &states, bool &edit_error); + std::vector parameter_from_states (const db::ParameterStates &states) const; + void states_from_parameters (db::ParameterStates &states, const std::vector ¶meters); }; } diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc index 8df9edfa7..f4aed23d9 100644 --- a/src/edt/edt/edtPlugin.cc +++ b/src/edt/edt/edtPlugin.cc @@ -342,6 +342,8 @@ public: menu_entries.push_back (lay::menu_item ("edt::sel_make_cell_variants", "make_cell_variants:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Make Cell Variants")))); menu_entries.push_back (lay::menu_item ("edt::sel_convert_to_pcell", "convert_to_pcell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Convert To PCell")))); menu_entries.push_back (lay::menu_item ("edt::sel_convert_to_cell", "convert_to_cell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Convert To Static Cell")))); + menu_entries.push_back (lay::separator ("hier_group:edit_info", "edit_menu.selection_menu.end")); + menu_entries.push_back (lay::menu_item ("edt::sel_area_perimeter", "area_perimeter", "edit_menu.selection_menu.end", tl::to_string (tr ("Area and Perimeter")))); menu_entries.push_back (lay::menu_item ("edt::combine_mode", "combine_mode:edit_mode", "@toolbar.end_modes", tl::to_string (tr ("Combine{Select background combination mode}")))); } diff --git a/src/edt/edt/edtPropertiesPages.h b/src/edt/edt/edtPropertiesPages.h index 834da0fb2..0e933c804 100644 --- a/src/edt/edt/edtPropertiesPages.h +++ b/src/edt/edt/edtPropertiesPages.h @@ -52,8 +52,9 @@ public: virtual size_t count () const; virtual void select_entries (const std::vector &entries); virtual std::string description (size_t entry) const; - virtual QIcon icon (size_t entry, int w, int h) const; virtual std::string description () const; + virtual QIcon icon (size_t entry, int w, int h) const; + virtual QIcon icon (int w, int h) const { return lay::PropertiesPage::icon (w, h); } virtual void leave (); protected: @@ -105,6 +106,7 @@ public: PolygonPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -129,6 +131,7 @@ public: BoxPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -159,6 +162,7 @@ public: TextPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -177,6 +181,7 @@ public: PathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); @@ -198,6 +203,7 @@ public: EditablePathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent); virtual std::string description (size_t entry) const; + virtual std::string description () const { return ShapePropertiesPage::description (); } virtual void do_update (const db::Shape &shape, double dbu, const std::string &lname); virtual ChangeApplicator *create_applicator (db::Shapes &shapes, const db::Shape &shape, double dbu); diff --git a/src/gsi/gsi/gsiMethods.h b/src/gsi/gsi/gsiMethods.h index a2e131587..71cf4ba43 100644 --- a/src/gsi/gsi/gsiMethods.h +++ b/src/gsi/gsi/gsiMethods.h @@ -524,7 +524,7 @@ public: // .. nothing yet .. } -#if !defined(NDEBUG) +#if defined(TRACE_METHOD_CALLS) public: /** diff --git a/src/klayout.pri b/src/klayout.pri index 042cf972f..0cb25c0ab 100644 --- a/src/klayout.pri +++ b/src/klayout.pri @@ -130,6 +130,11 @@ equals(HAVE_CRONOLOGY, "1") { INCLUDEPATH += $$CRONOLOGY_INCLUDE } +!lessThan(QT_MAJOR_VERSION, 6) { + # internal resource readers to not support zstd so far + QMAKE_RESOURCE_FLAGS += --compress-algo zlib +} + msvc { QMAKE_CXXFLAGS += \ @@ -162,16 +167,25 @@ msvc { QMAKE_CXXFLAGS_WARN_ON += \ -pedantic \ -Woverloaded-virtual \ - -Wsign-promo \ -Wsynth \ -Wno-deprecated \ -Wno-long-long \ -Wno-strict-aliasing \ -Wno-deprecated-declarations \ - -Wno-reserved-user-defined-literal \ - # because we use unordered_map/unordered_set: - QMAKE_CXXFLAGS += -std=c++11 + # too noisy on Qt: + # QMAKE_CXXFLAGS_WARN_ON += \ + # -Wsign-promo \ + # -Wno-reserved-user-defined-literal \ + # + + lessThan(QT_MAJOR_VERSION, 6) { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++11 + } else { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++17 + } win32 { diff --git a/src/lay/lay/SaltManagerDialog.ui b/src/lay/lay/SaltManagerDialog.ui index de9b8baa4..18a5f2ea2 100644 --- a/src/lay/lay/SaltManagerDialog.ui +++ b/src/lay/lay/SaltManagerDialog.ui @@ -17,7 +17,7 @@ - 0 + 2 @@ -217,6 +217,12 @@ + + + 1 + 0 + + true @@ -227,6 +233,19 @@ + + + + + 0 + 0 + + + + More details + + + @@ -515,6 +534,12 @@ + + + 1 + 0 + + true @@ -525,6 +550,13 @@ + + + + More details + + + @@ -935,8 +967,21 @@ 0 + + + + true + + + + + + 1 + 0 + + true @@ -947,7 +992,7 @@ - + Edit Package Details @@ -964,10 +1009,10 @@ - - - - true + + + + More details @@ -1157,20 +1202,33 @@ lay::SaltGrainDetailsTextWidget QTextBrowser

laySaltGrainDetailsTextWidget.h
+ + show_detailed_view(bool) + mode_tab + mark_new_button + search_new_edit + salt_mine_view_new + detailed_view + toolButton + details_new_text + mark_update_button + search_update_edit + salt_mine_view_update + detailed_view2 + toolButton_2 + details_update_text search_installed_edit salt_view - details_text + detailed_view3 edit_button - search_new_edit - mark_new_button - salt_mine_view_new - details_new_text - toolButton + details_text + create_button apply_new_button + apply_update_button scrollArea @@ -1193,5 +1251,53 @@ + + detailed_view + clicked(bool) + details_new_text + show_detailed_view(bool) + + + 588 + 57 + + + 578 + 121 + + + + + detailed_view2 + clicked(bool) + details_update_text + show_detailed_view(bool) + + + 616 + 58 + + + 615 + 96 + + + + + detailed_view3 + clicked(bool) + details_text + show_detailed_view(bool) + + + 602 + 58 + + + 603 + 91 + + + diff --git a/src/lay/lay/layMacroController.cc b/src/lay/lay/layMacroController.cc index 51b1111ef..41167c001 100644 --- a/src/lay/lay/layMacroController.cc +++ b/src/lay/lay/layMacroController.cc @@ -328,6 +328,10 @@ MacroController::drop_url (const std::string &path_or_url) void MacroController::show_editor (const std::string &cat, bool force_add) { + if (macro_categories ().empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Application has not been compiled with scripting support - no macro IDE available"))); + } + if (mp_macro_editor) { mp_macro_editor->show (cat, force_add); } diff --git a/src/lay/lay/laySaltGrainDetailsTextWidget.cc b/src/lay/lay/laySaltGrainDetailsTextWidget.cc index 3bbda18a2..e09b80e82 100644 --- a/src/lay/lay/laySaltGrainDetailsTextWidget.cc +++ b/src/lay/lay/laySaltGrainDetailsTextWidget.cc @@ -36,14 +36,15 @@ namespace lay { SaltGrainDetailsTextWidget::SaltGrainDetailsTextWidget (QWidget *w) - : QTextBrowser (w), mp_grain () + : QTextBrowser (w), mp_grain (), m_detailed_view (false) { setOpenLinks (false); setOpenExternalLinks (false); connect (this, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (open_link (const QUrl &))); } -void SaltGrainDetailsTextWidget::set_grain (const SaltGrain *g) +void +SaltGrainDetailsTextWidget::set_grain (const SaltGrain *g) { if (g) { mp_grain.reset (new SaltGrain (*g)); @@ -53,6 +54,15 @@ void SaltGrainDetailsTextWidget::set_grain (const SaltGrain *g) setHtml (details_text ()); } +void +SaltGrainDetailsTextWidget::show_detailed_view (bool f) +{ + if (m_detailed_view != f) { + m_detailed_view = f; + setHtml (details_text ()); + } +} + void SaltGrainDetailsTextWidget::open_link (const QUrl &url) { @@ -276,32 +286,36 @@ SaltGrainDetailsTextWidget::details_text () stream << "

" << QObject::tr ("Screenshot") << "

"; } - stream << "
"; - stream << "

" << QObject::tr ("Installation") << "

"; + if (m_detailed_view) { - if (! g->url ().empty ()) { - stream << "

" << QObject::tr ("Download URL: ") << "" << tl::to_qstring (tl::escaped_to_html (g->url ())) << "

"; - } - if (! g->path ().empty () && ! g->installed_time ().isNull ()) { - stream << "

" << QObject::tr ("Installed: ") << "" << g->installed_time ().toString () << "

"; - } - if (! g->dependencies ().empty ()) { - stream << "

" << QObject::tr ("Depends on: ") << "
"; - for (std::vector::const_iterator d = g->dependencies ().begin (); d != g->dependencies ().end (); ++d) { - stream << "    " << tl::to_qstring (tl::escaped_to_html (d->name)) << " "; - stream << tl::to_qstring (tl::escaped_to_html (d->version)); - if (! d->url.empty ()) { - stream << " - "; - stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]
"; - } + stream << "
"; + stream << "

" << QObject::tr ("Installation") << "

"; + + if (! g->url ().empty ()) { + stream << "

" << QObject::tr ("Download URL: ") << "" << tl::to_qstring (tl::escaped_to_html (g->url ())) << "

"; + } + if (! g->path ().empty () && ! g->installed_time ().isNull ()) { + stream << "

" << QObject::tr ("Installed: ") << "" << g->installed_time ().toString () << "

"; + } + if (! g->dependencies ().empty ()) { + stream << "

" << QObject::tr ("Depends on: ") << "
"; + for (std::vector::const_iterator d = g->dependencies ().begin (); d != g->dependencies ().end (); ++d) { + stream << "    " << tl::to_qstring (tl::escaped_to_html (d->name)) << " "; + stream << tl::to_qstring (tl::escaped_to_html (d->version)); + if (! d->url.empty ()) { + stream << " - "; + stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]
"; + } + } + stream << "

"; + } + + if (! g->path ().empty ()) { + stream << "

" << QObject::tr ("Installed files: ") << "

"; + produce_listing (stream, QDir (tl::to_qstring (g->path ())), 0); + stream << "

"; } - stream << "

"; - } - if (! g->path ().empty ()) { - stream << "

" << QObject::tr ("Installed files: ") << "

"; - produce_listing (stream, QDir (tl::to_qstring (g->path ())), 0); - stream << "

"; } stream << ""; diff --git a/src/lay/lay/laySaltGrainDetailsTextWidget.h b/src/lay/lay/laySaltGrainDetailsTextWidget.h index 1e0221235..47dc485ed 100644 --- a/src/lay/lay/laySaltGrainDetailsTextWidget.h +++ b/src/lay/lay/laySaltGrainDetailsTextWidget.h @@ -55,6 +55,9 @@ public: protected: virtual QVariant loadResource (int type, const QUrl &url); +public slots: + void show_detailed_view (bool f); + private slots: void open_link (const QUrl &url); @@ -62,6 +65,7 @@ private: std::unique_ptr mp_grain; QString details_text (); + bool m_detailed_view; }; } diff --git a/src/laybasic/laybasic/layObjectInstPath.cc b/src/laybasic/laybasic/layObjectInstPath.cc index d22f654e8..2187e9c1d 100644 --- a/src/laybasic/laybasic/layObjectInstPath.cc +++ b/src/laybasic/laybasic/layObjectInstPath.cc @@ -65,7 +65,7 @@ ObjectInstPath::is_valid (lay::LayoutViewBase *view) const } if (! is_cell_inst ()) { - if (! ly.is_valid_layer (layer ())) { + if (! ly.is_valid_layer (layer ()) && layer () != ly.guiding_shape_layer ()) { return false; } if (! ly.cell (ci).shapes (layer ()).is_valid (shape ())) { diff --git a/src/lym/unit_tests/lymBasicTests.cc b/src/lym/unit_tests/lymBasicTests.cc index d0b2eaf14..90fac66bb 100644 --- a/src/lym/unit_tests/lymBasicTests.cc +++ b/src/lym/unit_tests/lymBasicTests.cc @@ -53,13 +53,13 @@ private: std::string m_text; }; +#if defined(HAVE_RUBY) + static std::string np (const std::string &s) { return tl::replaced (s, "\\", "/"); } -#if defined(HAVE_RUBY) - TEST(1_BasicRuby) { tl_assert (rba::RubyInterpreter::instance () != 0); diff --git a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui index dbb3e9401..f14df467b 100644 --- a/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui +++ b/src/plugins/streamers/lefdef/lay_plugin/LEFDEFImportOptionsDialog.ui @@ -190,7 +190,7 @@ ... - + :/clear_16px.png:/clear_16px.png @@ -204,7 +204,7 @@ ... - + :/add_16px.png:/add_16px.png @@ -218,7 +218,7 @@ ... - + :/up_16px.png:/up_16px.png @@ -232,7 +232,7 @@ ... - + :/down_16px.png:/down_16px.png @@ -298,7 +298,7 @@ buttonBox - + diff --git a/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui b/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui index 4dd76f3b7..107165a8e 100644 --- a/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui +++ b/src/plugins/streamers/magic/lay_plugin/MAGReaderOptionPage.ui @@ -147,7 +147,7 @@ ... - + :/clear_16px.png:/clear_16px.png @@ -161,7 +161,7 @@ ... - + :/down_16px.png:/down_16px.png @@ -175,7 +175,7 @@ ... - + :/add_16px.png:/add_16px.png @@ -197,7 +197,7 @@ You can use expressions inside the path components for variable paths ... - + :/up_16px.png:/up_16px.png @@ -315,7 +315,7 @@ You can use expressions inside the path components for variable paths read_all_cbx - + diff --git a/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui b/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui index 995fbd702..78110075f 100644 --- a/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui +++ b/src/plugins/streamers/oasis/lay_plugin/OASISWriterOptionPage.ui @@ -284,7 +284,7 @@ - :/warn_16px@2x.png + :/warn_16px@2x.png @@ -379,7 +379,7 @@ - :/warn_16px@2x.png + :/warn_16px@2x.png @@ -430,7 +430,7 @@ subst_char - + diff --git a/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro b/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro index 666291b59..4ca7fd7d4 100644 --- a/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro +++ b/src/plugins/streamers/oasis/lay_plugin/lay_plugin.pro @@ -22,3 +22,4 @@ SOURCES = \ FORMS = \ OASISWriterOptionPage.ui \ + diff --git a/src/plugins/tools/xor/lay_plugin/layXORProgress.cc b/src/plugins/tools/xor/lay_plugin/layXORProgress.cc index c5f87c6f0..c0cd49e56 100644 --- a/src/plugins/tools/xor/lay_plugin/layXORProgress.cc +++ b/src/plugins/tools/xor/lay_plugin/layXORProgress.cc @@ -202,13 +202,13 @@ public: } else { - int y2 = m_pixmap_size - 1 - (iy * m_pixmap_size + m_pixmap_size / 2) / ny; - int y1 = m_pixmap_size - 1 - ((iy + 1) * m_pixmap_size + m_pixmap_size / 2) / ny; - int x1 = (ix * m_pixmap_size + m_pixmap_size / 2) / nx; - int x2 = ((ix + 1) * m_pixmap_size + m_pixmap_size / 2) / nx; + int y2 = std::min (m_pixmap_size - 1, m_pixmap_size - 1 - (iy * m_pixmap_size + ny / 2) / ny); + int y1 = std::max (0, m_pixmap_size - 1 - ((iy + 1) * m_pixmap_size + ny / 2) / ny); + int x1 = std::max (0, (ix * m_pixmap_size + nx / 2) / nx); + int x2 = std::min (m_pixmap_size - 1, ((ix + 1) * m_pixmap_size + nx / 2) / nx); // "draw" the field - for (int y = y1; y <= y2 && y >= 0 && y < m_pixmap_size; ++y) { + for (int y = y1; y <= y2; ++y) { *((uint32_t *) img->scanLine (y)) &= (((1 << x1) - 1) | ~((1 << (x2 + 1)) - 1)); } @@ -319,8 +319,8 @@ public: grad.setColorAt (0.0, QColor (248, 248, 248)); grad.setColorAt (1.0, QColor (224, 224, 224)); painter.setBrush (QBrush (grad)); - painter.setPen (QPen (Qt::black)); - painter.drawRect (QRect (QPoint (x, y - 2), QSize (m_pixmap_size + 3, m_pixmap_size + 3))); + painter.setPen (QPen (Qt::black, 1.0, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); + painter.drawRect (QRectF (QPointF (x + 1, y - 1), QSizeF (m_pixmap_size + 2, m_pixmap_size + 2))); painter.setBackgroundMode (Qt::TransparentMode); painter.setPen (QColor (128, 255, 128)); diff --git a/src/pya/pya/pyaModule.cc b/src/pya/pya/pyaModule.cc index 191adb70d..8f0fb40a3 100644 --- a/src/pya/pya/pyaModule.cc +++ b/src/pya/pya/pyaModule.cc @@ -408,19 +408,19 @@ struct PythonClassClientData : public gsi::PerClassClientSpecificData { PythonClassClientData (const gsi::ClassBase *_cls, PyTypeObject *_py_type, PyTypeObject *_py_type_static) - : py_type_object (_py_type), py_type_object_static (_py_type_static), method_table (_cls) + : py_type_object ((PyObject *) _py_type), py_type_object_static ((PyObject *) _py_type_static), method_table (_cls) { // .. nothing yet .. } - PyTypeObject *py_type_object; - PyTypeObject *py_type_object_static; + PythonPtr py_type_object; + PythonPtr py_type_object_static; MethodTable method_table; static PyTypeObject *py_type (const gsi::ClassBase &cls_decl, bool as_static) { PythonClassClientData *cd = dynamic_cast(cls_decl.data (gsi::ClientIndex::Python)); - return cd ? (as_static ? cd->py_type_object_static : cd->py_type_object) : 0; + return (PyTypeObject *) (cd ? (as_static ? cd->py_type_object_static.get () : cd->py_type_object.get ()) : 0); } static void initialize (const gsi::ClassBase &cls_decl, PyTypeObject *py_type, bool as_static) @@ -428,9 +428,9 @@ struct PythonClassClientData PythonClassClientData *cd = dynamic_cast(cls_decl.data (gsi::ClientIndex::Python)); if (cd) { if (as_static) { - cd->py_type_object_static = py_type; + cd->py_type_object_static = (PyObject *) py_type; } else { - cd->py_type_object = py_type; + cd->py_type_object = (PyObject *) py_type; } } else { cls_decl.set_data (gsi::ClientIndex::Python, new PythonClassClientData (&cls_decl, as_static ? NULL : py_type, as_static ? py_type : NULL)); @@ -2475,7 +2475,11 @@ public: PyTypeObject *type = (PyTypeObject *) PyObject_Call ((PyObject *) &PyType_Type, args.get (), NULL); if (type == NULL) { - check_error (); + try { + check_error (); + } catch (tl::Exception &ex) { + tl::error << ex.msg (); + } tl_assert (false); } diff --git a/src/pymod/bridge_sample/bridge_sample.pro b/src/pymod/bridge_sample/bridge_sample.pro index 372729f5e..bfff5c5df 100644 --- a/src/pymod/bridge_sample/bridge_sample.pro +++ b/src/pymod/bridge_sample/bridge_sample.pro @@ -79,20 +79,28 @@ LIBS += -L$$LIBDIR -lklayout_db !msvc { - # Some standard compiler warnings on QMAKE_CXXFLAGS_WARN_ON += \ -pedantic \ -Woverloaded-virtual \ - -Wsign-promo \ -Wsynth \ -Wno-deprecated \ -Wno-long-long \ -Wno-strict-aliasing \ -Wno-deprecated-declarations \ - -Wno-reserved-user-defined-literal \ - # because we use unordered_map/unordered_set: - QMAKE_CXXFLAGS += -std=c++11 + # too noisy on Qt: + # QMAKE_CXXFLAGS_WARN_ON += \ + # -Wsign-promo \ + # -Wno-reserved-user-defined-literal \ + # + + lessThan(QT_MAJOR_VERSION, 6) { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++11 + } else { + # because we use unordered_map/unordered_set: + QMAKE_CXXFLAGS += -std=c++17 + } # Python is somewhat sloppy and relies on the compiler initializing fields # of strucs to 0: diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 2813a9114..7a9c78df3 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -212,9 +212,9 @@ InputStream::InputStream (const std::string &abstract_path) QByteArray data; #if QT_VERSION >= 0x60000 - if (res.compressionAlgorithm () == QResource::ZlibCompression) { + if (res.compressionAlgorithm () == QResource::ZlibCompression) { #else - if (res.isCompressed ()) { + if (res.isCompressed ()) { #endif data = qUncompress ((const unsigned char *)res.data (), (int)res.size ()); } else { diff --git a/testdata/drc/drcSimpleTests_46.drc b/testdata/drc/drcSimpleTests_46.drc index 1278a4681..493b4aee1 100644 --- a/testdata/drc/drcSimpleTests_46.drc +++ b/testdata/drc/drcSimpleTests_46.drc @@ -14,10 +14,10 @@ to_fill = extent - l1 fp1 = fill_pattern("FP1").shape(10, 0, box(0, 0, 800.nm, 800.nm)).origin(-100.nm, -100.nm) to_fill = to_fill.fill_with_left(fp1, hstep(1.um), vstep(200.nm, 1.um), multi_origin) -fp2 = fill_pattern("FP2").shape(10, 0, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm) +fp2 = fill_pattern("FP2").shape(10, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm) to_fill = to_fill.fill_with_left(fp2, hstep(0.5.um), vstep(100.nm, 0.5.um), multi_origin) -fp3 = fill_pattern("FP3").shape(10, 0, box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm) +fp3 = fill_pattern("FP3").shape(RBA::LayerInfo::new(10, 0), box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm) to_fill = to_fill.fill_with_left(fp3, hstep(0.25.um), vstep(50.nm, 0.25.um), multi_origin) to_fill.output(100, 0) diff --git a/testdata/drc/drcSimpleTests_au5.gds b/testdata/drc/drcSimpleTests_au5.gds index e5cca0f9e..3902b4aed 100644 Binary files a/testdata/drc/drcSimpleTests_au5.gds and b/testdata/drc/drcSimpleTests_au5.gds differ diff --git a/testdata/drc/drcSimpleTests_au6.gds b/testdata/drc/drcSimpleTests_au6.gds index 08fada80b..70ac9f50b 100644 Binary files a/testdata/drc/drcSimpleTests_au6.gds and b/testdata/drc/drcSimpleTests_au6.gds differ diff --git a/testdata/drc/drcSimpleTests_au7.gds b/testdata/drc/drcSimpleTests_au7.gds index cb37bf096..e2e886e00 100644 Binary files a/testdata/drc/drcSimpleTests_au7.gds and b/testdata/drc/drcSimpleTests_au7.gds differ