mirror of https://github.com/KLayout/klayout.git
commit
be1be467d4
|
|
@ -252,8 +252,8 @@ static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
|
||||||
|
|
||||||
// Plain move
|
// Plain move
|
||||||
|
|
||||||
// build cell variants for different orientations
|
// build cell variants for different orientations and magnifications
|
||||||
db::OrientationReducer same_orientation;
|
db::MagnificationAndOrientationReducer same_orientation;
|
||||||
|
|
||||||
db::VariantsCollectorBase vars (&same_orientation);
|
db::VariantsCollectorBase vars (&same_orientation);
|
||||||
vars.collect (deep_layer.layout (), deep_layer.initial_cell ());
|
vars.collect (deep_layer.layout (), deep_layer.initial_cell ());
|
||||||
|
|
|
||||||
|
|
@ -464,7 +464,7 @@ struct edge_defs
|
||||||
"@return The scaled edge\n"
|
"@return The scaled edge\n"
|
||||||
) +
|
) +
|
||||||
method ("contains?", &C::contains, gsi::arg ("p"),
|
method ("contains?", &C::contains, gsi::arg ("p"),
|
||||||
"@brief Test whether a point is on an edge.\n"
|
"@brief Tests whether a point is on an edge.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"A point is on a edge if it is on (or at least closer \n"
|
"A point is on a edge if it is on (or at least closer \n"
|
||||||
"than a grid point to) the edge.\n"
|
"than a grid point to) the edge.\n"
|
||||||
|
|
@ -474,7 +474,7 @@ struct edge_defs
|
||||||
"@return True if the point is on the edge.\n"
|
"@return True if the point is on the edge.\n"
|
||||||
) +
|
) +
|
||||||
method ("contains_excl?", &C::contains_excl, gsi::arg ("p"),
|
method ("contains_excl?", &C::contains_excl, gsi::arg ("p"),
|
||||||
"@brief Test whether a point is on an edge excluding the endpoints.\n"
|
"@brief Tests whether a point is on an edge excluding the endpoints.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"A point is on a edge if it is on (or at least closer \n"
|
"A point is on a edge if it is on (or at least closer \n"
|
||||||
"than a grid point to) the edge.\n"
|
"than a grid point to) the edge.\n"
|
||||||
|
|
@ -494,15 +494,18 @@ struct edge_defs
|
||||||
"\n"
|
"\n"
|
||||||
"@return True if the edges are coincident.\n"
|
"@return True if the edges are coincident.\n"
|
||||||
) +
|
) +
|
||||||
method ("intersect?", &C::intersect, gsi::arg ("e"),
|
method ("intersects?|#intersect?", &C::intersect, gsi::arg ("e"),
|
||||||
"@brief Intersection test. \n"
|
"@brief Intersection test. \n"
|
||||||
"\n"
|
"\n"
|
||||||
"Returns true if the edges intersect. Two edges intersect if they share at least one point. \n"
|
"Returns true if the edges intersect. Two edges intersect if they share at least one point. \n"
|
||||||
"If the edges coincide, they also intersect.\n"
|
"If the edges coincide, they also intersect.\n"
|
||||||
"For degenerated edges, the intersection is mapped to\n"
|
"If one of the edges is degenerate (both points are identical), that point is "
|
||||||
"point containment tests.\n"
|
"required to sit exaclty on the other edge. If both edges are degenerate, their "
|
||||||
|
"points are required to be identical.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@param e The edge to test.\n"
|
"@param e The edge to test.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'intersects' (with an 's') synonym has been introduced in version 0.28.12.\n"
|
||||||
) +
|
) +
|
||||||
method_ext ("intersection_point", &intersect_point, gsi::arg ("e"),
|
method_ext ("intersection_point", &intersect_point, gsi::arg ("e"),
|
||||||
"@brief Returns the intersection point of two edges. \n"
|
"@brief Returns the intersection point of two edges. \n"
|
||||||
|
|
@ -600,19 +603,21 @@ struct edge_defs
|
||||||
"This method has been introduced in version 0.23.\n"
|
"This method has been introduced in version 0.23.\n"
|
||||||
) +
|
) +
|
||||||
method ("crossed_by?", &C::crossed_by, gsi::arg ("e"),
|
method ("crossed_by?", &C::crossed_by, gsi::arg ("e"),
|
||||||
"@brief Check, if an edge is cut by a line (given by an edge)\n"
|
"@brief Checks, if the line given by self is crossed by the edge e\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method returns true if p1 is in one semispace \n"
|
"self if considered an infinite line. This predicate renders true "
|
||||||
"while p2 is in the other or one of them is on the line\n"
|
"if the edge e is cut by this line. In other words: "
|
||||||
"through the edge \"e\"\n"
|
"this method returns true if e.p1 is in one semispace of self \n"
|
||||||
|
"while e.p2 is in the other or one of them is exactly on self.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@param e The edge representing the line that the edge must be crossing.\n"
|
"@param e The edge representing the line that the edge must be crossing.\n"
|
||||||
) +
|
) +
|
||||||
method_ext ("crossing_point", &crossing_point, gsi::arg ("e"),
|
method_ext ("crossing_point", &crossing_point, gsi::arg ("e"),
|
||||||
"@brief Returns the crossing point on two edges. \n"
|
"@brief Returns the crossing point on two edges. \n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method delivers the point where the given edge (self) crosses the line given "
|
"This method delivers the point where the given line (self) crosses the edge given "
|
||||||
"by the edge in argument \"e\". If self does not cross this line, the result is undefined. "
|
"by the argument \"e\". self is considered infinitely long and is required to cut "
|
||||||
|
"through the edge \"e\". If self does not cut this line, the result is undefined. "
|
||||||
"See \\crossed_by? for a description of the crossing predicate.\n"
|
"See \\crossed_by? for a description of the crossing predicate.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@param e The edge representing the line that self must be crossing.\n"
|
"@param e The edge representing the line that self must be crossing.\n"
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,7 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.26."
|
"This method has been added in version 0.26."
|
||||||
) +
|
) +
|
||||||
method ("+", &db::EdgePairs::operator+, gsi::arg ("other"),
|
method ("+|join", &db::EdgePairs::operator+, gsi::arg ("other"),
|
||||||
"@brief Returns the combined edge pair collection of self and the other one\n"
|
"@brief Returns the combined edge pair collection of self and the other one\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The resulting edge pair collection\n"
|
"@return The resulting edge pair collection\n"
|
||||||
|
|
@ -433,8 +433,9 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
||||||
"This operator adds the edge pairs of the other collection to self and returns a new combined set.\n"
|
"This operator adds the edge pairs of the other collection to self and returns a new combined set.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.24.\n"
|
"This method has been introduced in version 0.24.\n"
|
||||||
) +
|
"The 'join' alias has been introduced in version 0.28.12."
|
||||||
method ("+=", &db::EdgePairs::operator+=, gsi::arg ("other"),
|
) +
|
||||||
|
method ("+=|join_with", &db::EdgePairs::operator+=, gsi::arg ("other"),
|
||||||
"@brief Adds the edge pairs of the other edge pair collection to self\n"
|
"@brief Adds the edge pairs of the other edge pair collection to self\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge pair collection after modification (self)\n"
|
"@return The edge pair collection after modification (self)\n"
|
||||||
|
|
@ -442,7 +443,12 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
||||||
"This operator adds the edge pairs of the other collection to self.\n"
|
"This operator adds the edge pairs of the other collection to self.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.24.\n"
|
"This method has been introduced in version 0.24.\n"
|
||||||
) +
|
"\n"
|
||||||
|
"Note that in Ruby, the '+=' operator actually does not exist, but is emulated by '+' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'join_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'join_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
method_ext ("move", &move_p, gsi::arg ("p"),
|
method_ext ("move", &move_p, gsi::arg ("p"),
|
||||||
"@brief Moves the edge pair collection\n"
|
"@brief Moves the edge pair collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
||||||
|
|
@ -769,7 +769,7 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"Crossing edges are not merged.\n"
|
"Crossing edges are not merged.\n"
|
||||||
"In contrast to \\merge, this method does not modify the edge collection but returns a merged copy.\n"
|
"In contrast to \\merge, this method does not modify the edge collection but returns a merged copy.\n"
|
||||||
) +
|
) +
|
||||||
method ("&", (db::Edges (db::Edges::*)(const db::Edges &) const) &db::Edges::operator&, gsi::arg ("other"),
|
method ("&|and", (db::Edges (db::Edges::*)(const db::Edges &) const) &db::Edges::operator&, gsi::arg ("other"),
|
||||||
"@brief Returns the boolean AND between self and the other edge collection\n"
|
"@brief Returns the boolean AND between self and the other edge collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The result of the boolean AND operation\n"
|
"@return The result of the boolean AND operation\n"
|
||||||
|
|
@ -777,17 +777,24 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"The boolean AND operation will return all parts of the edges in this collection which "
|
"The boolean AND operation will return all parts of the edges in this collection which "
|
||||||
"are coincident with parts of the edges in the other collection."
|
"are coincident with parts of the edges in the other collection."
|
||||||
"The result will be a merged edge collection.\n"
|
"The result will be a merged edge collection.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("&=", (db::Edges &(db::Edges::*)(const db::Edges &)) &db::Edges::operator&=, gsi::arg ("other"),
|
"The 'and' alias has been introduced in version 0.28.12."
|
||||||
"@brief Performs the boolean AND between self and the other edge collection\n"
|
) +
|
||||||
|
method ("&=|and_with", (db::Edges &(db::Edges::*)(const db::Edges &)) &db::Edges::operator&=, gsi::arg ("other"),
|
||||||
|
"@brief Performs the boolean AND between self and the other edge collection in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge collection after modification (self)\n"
|
"@return The edge collection after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The boolean AND operation will return all parts of the edges in this collection which "
|
"The boolean AND operation will return all parts of the edges in this collection which "
|
||||||
"are coincident with parts of the edges in the other collection."
|
"are coincident with parts of the edges in the other collection."
|
||||||
"The result will be a merged edge collection.\n"
|
"The result will be a merged edge collection.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("&", (db::Edges (db::Edges::*)(const db::Region &) const) &db::Edges::operator&, gsi::arg ("other"),
|
"Note that in Ruby, the '&=' operator actually does not exist, but is emulated by '&' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'and_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'and_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
|
method ("&|and", (db::Edges (db::Edges::*)(const db::Region &) const) &db::Edges::operator&, gsi::arg ("other"),
|
||||||
"@brief Returns the parts of the edges inside the given region\n"
|
"@brief Returns the parts of the edges inside the given region\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edges inside the given region\n"
|
"@return The edges inside the given region\n"
|
||||||
|
|
@ -798,9 +805,10 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"edges intersect.\n"
|
"edges intersect.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.24."
|
"This method has been introduced in version 0.24."
|
||||||
) +
|
"The 'and' alias has been introduced in version 0.28.12."
|
||||||
method ("&=", (db::Edges &(db::Edges::*)(const db::Region &)) &db::Edges::operator&=, gsi::arg ("other"),
|
) +
|
||||||
"@brief Selects the parts of the edges inside the given region\n"
|
method ("&=|and_with", (db::Edges &(db::Edges::*)(const db::Region &)) &db::Edges::operator&=, gsi::arg ("other"),
|
||||||
|
"@brief Selects the parts of the edges inside the given region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge collection after modification (self)\n"
|
"@return The edge collection after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -810,8 +818,13 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"edges intersect.\n"
|
"edges intersect.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.24."
|
"This method has been introduced in version 0.24."
|
||||||
) +
|
"\n"
|
||||||
method ("-", (db::Edges (db::Edges::*)(const db::Edges &) const) &db::Edges::operator-, gsi::arg ("other"),
|
"Note that in Ruby, the '&=' operator actually does not exist, but is emulated by '&' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'and_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'and_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
|
method ("-|not", (db::Edges (db::Edges::*)(const db::Edges &) const) &db::Edges::operator-, gsi::arg ("other"),
|
||||||
"@brief Returns the boolean NOT between self and the other edge collection\n"
|
"@brief Returns the boolean NOT between self and the other edge collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The result of the boolean NOT operation\n"
|
"@return The result of the boolean NOT operation\n"
|
||||||
|
|
@ -819,17 +832,24 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"The boolean NOT operation will return all parts of the edges in this collection which "
|
"The boolean NOT operation will return all parts of the edges in this collection which "
|
||||||
"are not coincident with parts of the edges in the other collection."
|
"are not coincident with parts of the edges in the other collection."
|
||||||
"The result will be a merged edge collection.\n"
|
"The result will be a merged edge collection.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("-=", (db::Edges &(db::Edges::*)(const db::Edges &)) &db::Edges::operator-=, gsi::arg ("other"),
|
"The 'not' alias has been introduced in version 0.28.12."
|
||||||
"@brief Performs the boolean NOT between self and the other edge collection\n"
|
) +
|
||||||
|
method ("-=|not_with", (db::Edges &(db::Edges::*)(const db::Edges &)) &db::Edges::operator-=, gsi::arg ("other"),
|
||||||
|
"@brief Performs the boolean NOT between self and the other edge collection in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge collection after modification (self)\n"
|
"@return The edge collection after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The boolean NOT operation will return all parts of the edges in this collection which "
|
"The boolean NOT operation will return all parts of the edges in this collection which "
|
||||||
"are not coincident with parts of the edges in the other collection."
|
"are not coincident with parts of the edges in the other collection."
|
||||||
"The result will be a merged edge collection.\n"
|
"The result will be a merged edge collection.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("-", (db::Edges (db::Edges::*)(const db::Region &) const) &db::Edges::operator-, gsi::arg ("other"),
|
"Note that in Ruby, the '-=' operator actually does not exist, but is emulated by '-' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'not_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'not_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
|
method ("-|not", (db::Edges (db::Edges::*)(const db::Region &) const) &db::Edges::operator-, gsi::arg ("other"),
|
||||||
"@brief Returns the parts of the edges outside the given region\n"
|
"@brief Returns the parts of the edges outside the given region\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edges outside the given region\n"
|
"@return The edges outside the given region\n"
|
||||||
|
|
@ -840,9 +860,10 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"edges intersect.\n"
|
"edges intersect.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.24."
|
"This method has been introduced in version 0.24."
|
||||||
) +
|
"The 'not' alias has been introduced in version 0.28.12."
|
||||||
method ("-=", (db::Edges &(db::Edges::*)(const db::Region &)) &db::Edges::operator-=, gsi::arg ("other"),
|
) +
|
||||||
"@brief Selects the parts of the edges outside the given region\n"
|
method ("-=|not_with", (db::Edges &(db::Edges::*)(const db::Region &)) &db::Edges::operator-=, gsi::arg ("other"),
|
||||||
|
"@brief Selects the parts of the edges outside the given region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge collection after modification (self)\n"
|
"@return The edge collection after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -851,8 +872,12 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"As a side effect, the edges are made non-intersecting by introducing cut points where\n"
|
"As a side effect, the edges are made non-intersecting by introducing cut points where\n"
|
||||||
"edges intersect.\n"
|
"edges intersect.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"Note that in Ruby, the '-=' operator actually does not exist, but is emulated by '-' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'not_with' instead.\n"
|
||||||
|
"\n"
|
||||||
"This method has been introduced in version 0.24."
|
"This method has been introduced in version 0.24."
|
||||||
) +
|
"The 'not_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
method_ext ("andnot", &andnot_with_edges, gsi::arg ("other"),
|
method_ext ("andnot", &andnot_with_edges, gsi::arg ("other"),
|
||||||
"@brief Returns the boolean AND and NOT between self and the other edge set\n"
|
"@brief Returns the boolean AND and NOT between self and the other edge set\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -873,7 +898,7 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.28.\n"
|
"This method has been added in version 0.28.\n"
|
||||||
) +
|
) +
|
||||||
method ("^", &db::Edges::operator^, gsi::arg ("other"),
|
method ("^|xor", &db::Edges::operator^, gsi::arg ("other"),
|
||||||
"@brief Returns the boolean XOR between self and the other edge collection\n"
|
"@brief Returns the boolean XOR between self and the other edge collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The result of the boolean XOR operation\n"
|
"@return The result of the boolean XOR operation\n"
|
||||||
|
|
@ -881,48 +906,69 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"The boolean XOR operation will return all parts of the edges in this and the other collection except "
|
"The boolean XOR operation will return all parts of the edges in this and the other collection except "
|
||||||
"the parts where both are coincident.\n"
|
"the parts where both are coincident.\n"
|
||||||
"The result will be a merged edge collection.\n"
|
"The result will be a merged edge collection.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("^=", &db::Edges::operator^=, gsi::arg ("other"),
|
"The 'xor' alias has been introduced in version 0.28.12."
|
||||||
"@brief Performs the boolean XOR between self and the other edge collection\n"
|
) +
|
||||||
|
method ("^=|xor_with", &db::Edges::operator^=, gsi::arg ("other"),
|
||||||
|
"@brief Performs the boolean XOR between self and the other edge collection in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge collection after modification (self)\n"
|
"@return The edge collection after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The boolean XOR operation will return all parts of the edges in this and the other collection except "
|
"The boolean XOR operation will return all parts of the edges in this and the other collection except "
|
||||||
"the parts where both are coincident.\n"
|
"the parts where both are coincident.\n"
|
||||||
"The result will be a merged edge collection.\n"
|
"The result will be a merged edge collection.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("\\|", &db::Edges::operator|, gsi::arg ("other"),
|
"Note that in Ruby, the '^=' operator actually does not exist, but is emulated by '^' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'xor_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'xor_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
|
method ("\\||or", &db::Edges::operator|, gsi::arg ("other"),
|
||||||
"@brief Returns the boolean OR between self and the other edge set\n"
|
"@brief Returns the boolean OR between self and the other edge set\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The resulting edge collection\n"
|
"@return The resulting edge collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The boolean OR is implemented by merging the edges of both edge sets. To simply join the edge collections "
|
"The boolean OR is implemented by merging the edges of both edge sets. To simply join the edge collections "
|
||||||
"without merging, the + operator is more efficient."
|
"without merging, the + operator is more efficient."
|
||||||
) +
|
"\n"
|
||||||
method ("\\|=", &db::Edges::operator|=, gsi::arg ("other"),
|
"The 'or' alias has been introduced in version 0.28.12."
|
||||||
"@brief Performs the boolean OR between self and the other edge set\n"
|
) +
|
||||||
|
method ("\\|=|or_with", &db::Edges::operator|=, gsi::arg ("other"),
|
||||||
|
"@brief Performs the boolean OR between self and the other edge set in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge collection after modification (self)\n"
|
"@return The edge collection after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The boolean OR is implemented by merging the edges of both edge sets. To simply join the edge collections "
|
"The boolean OR is implemented by merging the edges of both edge sets. To simply join the edge collections "
|
||||||
"without merging, the + operator is more efficient."
|
"without merging, the + operator is more efficient."
|
||||||
) +
|
"\n"
|
||||||
method ("+", &db::Edges::operator+, gsi::arg ("other"),
|
"Note that in Ruby, the '|=' operator actually does not exist, but is emulated by '|' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'or_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'or_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
|
method ("+|join", &db::Edges::operator+, gsi::arg ("other"),
|
||||||
"@brief Returns the combined edge set of self and the other one\n"
|
"@brief Returns the combined edge set of self and the other one\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The resulting edge set\n"
|
"@return The resulting edge set\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This operator adds the edges of the other edge set to self and returns a new combined edge set. "
|
"This operator adds the edges of the other edge set to self and returns a new combined edge set. "
|
||||||
"This usually creates unmerged edge sets and edges may overlap. Use \\merge if you want to ensure the result edge set is merged.\n"
|
"This usually creates unmerged edge sets and edges may overlap. Use \\merge if you want to ensure the result edge set is merged.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("+=", &db::Edges::operator+=, gsi::arg ("other"),
|
"The 'join' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
|
method ("+=|join_with", &db::Edges::operator+=, gsi::arg ("other"),
|
||||||
"@brief Adds the edges of the other edge collection to self\n"
|
"@brief Adds the edges of the other edge collection to self\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The edge set after modification (self)\n"
|
"@return The edge set after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This operator adds the edges of the other edge set to self. "
|
"This operator adds the edges of the other edge set to self. "
|
||||||
"This usually creates unmerged edge sets and edges may overlap. Use \\merge if you want to ensure the result edge set is merged.\n"
|
"This usually creates unmerged edge sets and edges may overlap. Use \\merge if you want to ensure the result edge set is merged.\n"
|
||||||
) +
|
"\n"
|
||||||
|
"Note that in Ruby, the '+=' operator actually does not exist, but is emulated by '+' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'join_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'join_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
|
method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
|
||||||
"@brief Returns the edges of this edge collection which overlap or touch edges from the other edge collection\n"
|
"@brief Returns the edges of this edge collection which overlap or touch edges from the other edge collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
||||||
|
|
@ -1037,6 +1037,22 @@ static void dtransform_cplx (db::Layout *layout, const db::DCplxTrans &trans)
|
||||||
layout->transform (dbu_trans.inverted () * trans * dbu_trans);
|
layout->transform (dbu_trans.inverted () * trans * dbu_trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static db::LayerProperties get_properties (const db::Layout *layout, unsigned int index)
|
||||||
|
{
|
||||||
|
if (layout->is_valid_layer (index)) {
|
||||||
|
return layout->get_properties (index);
|
||||||
|
} else {
|
||||||
|
return db::LayerProperties ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_properties (db::Layout *layout, unsigned int index, const db::LayerProperties &props)
|
||||||
|
{
|
||||||
|
if (layout->is_valid_layer (index)) {
|
||||||
|
layout->set_properties (index, props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Class<db::Layout> decl_Layout ("db", "Layout",
|
Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
gsi::constructor ("new", &layout_ctor_with_manager, gsi::arg ("manager"),
|
gsi::constructor ("new", &layout_ctor_with_manager, gsi::arg ("manager"),
|
||||||
"@brief Creates a layout object attached to a manager\n"
|
"@brief Creates a layout object attached to a manager\n"
|
||||||
|
|
@ -1667,11 +1683,12 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
||||||
"\n"
|
"\n"
|
||||||
"See \\insert_special_layer for a description of special layers."
|
"See \\insert_special_layer for a description of special layers."
|
||||||
) +
|
) +
|
||||||
gsi::method ("set_info", &db::Layout::set_properties, gsi::arg ("index"), gsi::arg ("props"),
|
gsi::method_ext ("set_info", &set_properties, gsi::arg ("index"), gsi::arg ("props"),
|
||||||
"@brief Sets the info structure for a specified layer\n"
|
"@brief Sets the info structure for a specified layer\n"
|
||||||
) +
|
) +
|
||||||
gsi::method ("get_info", &db::Layout::get_properties, gsi::arg ("index"),
|
gsi::method_ext ("get_info", &get_properties, gsi::arg ("index"),
|
||||||
"@brief Gets the info structure for a specified layer\n"
|
"@brief Gets the info structure for a specified layer\n"
|
||||||
|
"If the layer index is not a valid layer index, an empty LayerProperties object will be returned."
|
||||||
) +
|
) +
|
||||||
gsi::method ("cells", &db::Layout::cells,
|
gsi::method ("cells", &db::Layout::cells,
|
||||||
"@brief Returns the number of cells\n"
|
"@brief Returns the number of cells\n"
|
||||||
|
|
|
||||||
|
|
@ -1647,15 +1647,18 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
||||||
"This variant has been introduced in version 0.28.4."
|
"This variant has been introduced in version 0.28.4."
|
||||||
) +
|
) +
|
||||||
method ("&=", &db::Region::operator&=, gsi::arg ("other"),
|
method ("&=", &db::Region::operator&=, gsi::arg ("other"),
|
||||||
"@brief Performs the boolean AND between self and the other region\n"
|
"@brief Performs the boolean AND between self and the other region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The region after modification (self)\n"
|
"@return The region after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method will compute the boolean AND (intersection) between two regions. "
|
"This method will compute the boolean AND (intersection) between two regions. "
|
||||||
"The result is often but not necessarily always merged.\n"
|
"The result is often but not necessarily always merged.\n"
|
||||||
|
"\n"
|
||||||
|
"Note that in Ruby, the '&=' operator actually does not exist, but is emulated by '&' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'and_with' instead."
|
||||||
) +
|
) +
|
||||||
method ("and_with", &db::Region::bool_and_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
|
method ("and_with", &db::Region::bool_and_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
|
||||||
"@brief Performs the boolean AND between self and the other region\n"
|
"@brief Performs the boolean AND between self and the other region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The region after modification (self)\n"
|
"@return The region after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -1687,15 +1690,18 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
||||||
"This variant has been introduced in version 0.28.4."
|
"This variant has been introduced in version 0.28.4."
|
||||||
) +
|
) +
|
||||||
method ("-=", &db::Region::operator-=, gsi::arg ("other"),
|
method ("-=", &db::Region::operator-=, gsi::arg ("other"),
|
||||||
"@brief Performs the boolean NOT between self and the other region\n"
|
"@brief Performs the boolean NOT between self and the other region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The region after modification (self)\n"
|
"@return The region after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method will compute the boolean NOT (intersection) between two regions. "
|
"This method will compute the boolean NOT (intersection) between two regions. "
|
||||||
"The result is often but not necessarily always merged.\n"
|
"The result is often but not necessarily always merged.\n"
|
||||||
|
"\n"
|
||||||
|
"Note that in Ruby, the '-=' operator actually does not exist, but is emulated by '-' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'not_with' instead."
|
||||||
) +
|
) +
|
||||||
method ("not_with", &db::Region::bool_not_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
|
method ("not_with", &db::Region::bool_not_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"),
|
||||||
"@brief Performs the boolean NOT between self and the other region\n"
|
"@brief Performs the boolean NOT between self and the other region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The region after modification (self)\n"
|
"@return The region after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -1706,53 +1712,74 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
||||||
"\n"
|
"\n"
|
||||||
"This variant has been introduced in version 0.28.4."
|
"This variant has been introduced in version 0.28.4."
|
||||||
) +
|
) +
|
||||||
method ("^", &db::Region::operator^, gsi::arg ("other"),
|
method ("^|xor", &db::Region::operator^, gsi::arg ("other"),
|
||||||
"@brief Returns the boolean XOR between self and the other region\n"
|
"@brief Returns the boolean XOR between self and the other region\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The result of the boolean XOR operation\n"
|
"@return The result of the boolean XOR operation\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method will compute the boolean XOR (intersection) between two regions. "
|
"This method will compute the boolean XOR (intersection) between two regions. "
|
||||||
"The result is often but not necessarily always merged.\n"
|
"The result is often but not necessarily always merged.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'xor' alias has been introduced in version 0.28.12."
|
||||||
) +
|
) +
|
||||||
method ("^=", &db::Region::operator^=, gsi::arg ("other"),
|
method ("^=|xor_with", &db::Region::operator^=, gsi::arg ("other"),
|
||||||
"@brief Performs the boolean XOR between self and the other region\n"
|
"@brief Performs the boolean XOR between self and the other region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The region after modification (self)\n"
|
"@return The region after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method will compute the boolean XOR (intersection) between two regions. "
|
"This method will compute the boolean XOR (intersection) between two regions. "
|
||||||
"The result is often but not necessarily always merged.\n"
|
"The result is often but not necessarily always merged.\n"
|
||||||
|
"\n"
|
||||||
|
"Note that in Ruby, the '^=' operator actually does not exist, but is emulated by '^' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'xor_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'xor_with' alias has been introduced in version 0.28.12."
|
||||||
) +
|
) +
|
||||||
method ("\\|", &db::Region::operator|, gsi::arg ("other"),
|
method ("\\||or", &db::Region::operator|, gsi::arg ("other"),
|
||||||
"@brief Returns the boolean OR between self and the other region\n"
|
"@brief Returns the boolean OR between self and the other region\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The resulting region\n"
|
"@return The resulting region\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The boolean OR is implemented by merging the polygons of both regions. To simply join the regions "
|
"The boolean OR is implemented by merging the polygons of both regions. To simply join the regions "
|
||||||
"without merging, the + operator is more efficient."
|
"without merging, the + operator is more efficient."
|
||||||
|
"\n"
|
||||||
|
"The 'or' alias has been introduced in version 0.28.12."
|
||||||
) +
|
) +
|
||||||
method ("\\|=", &db::Region::operator|=, gsi::arg ("other"),
|
method ("\\|=|or_with", &db::Region::operator|=, gsi::arg ("other"),
|
||||||
"@brief Performs the boolean OR between self and the other region\n"
|
"@brief Performs the boolean OR between self and the other region in-place (modifying self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The region after modification (self)\n"
|
"@return The region after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The boolean OR is implemented by merging the polygons of both regions. To simply join the regions "
|
"The boolean OR is implemented by merging the polygons of both regions. To simply join the regions "
|
||||||
"without merging, the + operator is more efficient."
|
"without merging, the + operator is more efficient."
|
||||||
|
"\n"
|
||||||
|
"Note that in Ruby, the '|=' operator actually does not exist, but is emulated by '|' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'or_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'or_with' alias has been introduced in version 0.28.12."
|
||||||
) +
|
) +
|
||||||
method ("+", &db::Region::operator+, gsi::arg ("other"),
|
method ("+|join", &db::Region::operator+, gsi::arg ("other"),
|
||||||
"@brief Returns the combined region of self and the other region\n"
|
"@brief Returns the combined region of self and the other region\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The resulting region\n"
|
"@return The resulting region\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This operator adds the polygons of the other region to self and returns a new combined region. "
|
"This operator adds the polygons of the other region to self and returns a new combined region. "
|
||||||
"This usually creates unmerged regions and polygons may overlap. Use \\merge if you want to ensure the result region is merged.\n"
|
"This usually creates unmerged regions and polygons may overlap. Use \\merge if you want to ensure the result region is merged.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'join' alias has been introduced in version 0.28.12."
|
||||||
) +
|
) +
|
||||||
method ("+=", &db::Region::operator+=, gsi::arg ("other"),
|
method ("+=|join_with", &db::Region::operator+=, gsi::arg ("other"),
|
||||||
"@brief Adds the polygons of the other region to self\n"
|
"@brief Adds the polygons of the other region to self\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The region after modification (self)\n"
|
"@return The region after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This operator adds the polygons of the other region to self. "
|
"This operator adds the polygons of the other region to self. "
|
||||||
"This usually creates unmerged regions and polygons may overlap. Use \\merge if you want to ensure the result region is merged.\n"
|
"This usually creates unmerged regions and polygons may overlap. Use \\merge if you want to ensure the result region is merged.\n"
|
||||||
|
"\n"
|
||||||
|
"Note that in Ruby, the '+=' operator actually does not exist, but is emulated by '+' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'join_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'join_with' alias has been introduced in version 0.28.12."
|
||||||
) +
|
) +
|
||||||
method ("covering", &db::Region::selected_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
method ("covering", &db::Region::selected_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||||
"@brief Returns the polygons of this region which are completely covering polygons from the other region\n"
|
"@brief Returns the polygons of this region which are completely covering polygons from the other region\n"
|
||||||
|
|
|
||||||
|
|
@ -276,20 +276,27 @@ Class<db::Texts> decl_Texts (decl_dbShapeCollection, "db", "Texts",
|
||||||
method_ext ("data_id", &id,
|
method_ext ("data_id", &id,
|
||||||
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
||||||
) +
|
) +
|
||||||
method ("+", &db::Texts::operator+, gsi::arg ("other"),
|
method ("+|join", &db::Texts::operator+, gsi::arg ("other"),
|
||||||
"@brief Returns the combined text collection of self and the other one\n"
|
"@brief Returns the combined text collection of self and the other one\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The resulting text collection\n"
|
"@return The resulting text collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This operator adds the texts of the other collection to self and returns a new combined set.\n"
|
"This operator adds the texts of the other collection to self and returns a new combined set.\n"
|
||||||
) +
|
"\n"
|
||||||
method ("+=", &db::Texts::operator+=, gsi::arg ("other"),
|
"The 'join' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
|
method ("+=|join_with", &db::Texts::operator+=, gsi::arg ("other"),
|
||||||
"@brief Adds the texts of the other text collection to self\n"
|
"@brief Adds the texts of the other text collection to self\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@return The text collection after modification (self)\n"
|
"@return The text collection after modification (self)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This operator adds the texts of the other collection to self.\n"
|
"This operator adds the texts of the other collection to self.\n"
|
||||||
) +
|
"\n"
|
||||||
|
"Note that in Ruby, the '+=' operator actually does not exist, but is emulated by '+' followed by an assignment. "
|
||||||
|
"This is less efficient than the in-place operation, so it is recommended to use 'join_with' instead.\n"
|
||||||
|
"\n"
|
||||||
|
"The 'join_with' alias has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
method_ext ("move", &move_p, gsi::arg ("p"),
|
method_ext ("move", &move_p, gsi::arg ("p"),
|
||||||
"@brief Moves the text collection\n"
|
"@brief Moves the text collection\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
||||||
|
|
@ -2779,6 +2779,37 @@ TEST(issue_400_with_region)
|
||||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/deep_region_au400c.gds");
|
db::compare_layouts (_this, ly, tl::testdata () + "/algo/deep_region_au400c.gds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(deep_region_transform_with_scaled)
|
||||||
|
{
|
||||||
|
db::Layout ly;
|
||||||
|
{
|
||||||
|
std::string fn (tl::testdata ());
|
||||||
|
fn += "/algo/deep_region_transform_with_scaled.gds";
|
||||||
|
tl::InputStream stream (fn);
|
||||||
|
db::Reader reader (stream);
|
||||||
|
reader.read (ly);
|
||||||
|
}
|
||||||
|
|
||||||
|
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||||
|
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||||
|
|
||||||
|
db::DeepShapeStore dss;
|
||||||
|
|
||||||
|
for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) {
|
||||||
|
|
||||||
|
unsigned int li = (*l).first;
|
||||||
|
db::Region r (db::RecursiveShapeIterator (ly, top_cell, li), dss);
|
||||||
|
r.transform (db::Trans (db::Vector (10000, 0)));
|
||||||
|
|
||||||
|
ly.clear_layer (li);
|
||||||
|
r.insert_into (&ly, top_cell_index, li);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECKPOINT();
|
||||||
|
db::compare_layouts (_this, ly, tl::testdata () + "/algo/deep_region_transform_with_scaled_au.gds");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(issue_663_separation_from_inside)
|
TEST(issue_663_separation_from_inside)
|
||||||
{
|
{
|
||||||
db::Layout ly;
|
db::Layout ly;
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,10 @@ module DRC
|
||||||
end
|
end
|
||||||
|
|
||||||
def finish
|
def finish
|
||||||
@tmp_layers.each do |li|
|
@tmp_layers.each do |layout,li|
|
||||||
@layout.delete_layer(li)
|
layout.delete_layer(li)
|
||||||
end
|
end
|
||||||
|
@tmp_layers = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_box(method, *args)
|
def set_box(method, *args)
|
||||||
|
|
@ -347,7 +348,7 @@ CODE
|
||||||
|
|
||||||
if cell_filter
|
if cell_filter
|
||||||
tmp = @layout_var.insert_layer(RBA::LayerInfo::new)
|
tmp = @layout_var.insert_layer(RBA::LayerInfo::new)
|
||||||
@tmp_layers << tmp
|
@tmp_layers << [ @layout_var, tmp ]
|
||||||
@layout_var.cells(cell_filter).each do |cell|
|
@layout_var.cells(cell_filter).each do |cell|
|
||||||
cell.shapes(tmp).insert(cell.bbox)
|
cell.shapes(tmp).insert(cell.bbox)
|
||||||
end
|
end
|
||||||
|
|
@ -606,7 +607,7 @@ CODE
|
||||||
|
|
||||||
li = @layout.insert_layer(RBA::LayerInfo::new)
|
li = @layout.insert_layer(RBA::LayerInfo::new)
|
||||||
li && layers.push(li)
|
li && layers.push(li)
|
||||||
li && @tmp_layers.push(li)
|
li && @tmp_layers.push([ @layout, li ])
|
||||||
|
|
||||||
elsif (args.size == 1 && args[0].is_a?(RBA::LayerInfo))
|
elsif (args.size == 1 && args[0].is_a?(RBA::LayerInfo))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ module DRC
|
||||||
|
|
||||||
class DRCExecutable < RBA::Executable
|
class DRCExecutable < RBA::Executable
|
||||||
|
|
||||||
def initialize(macro, generator, rdb_index = nil)
|
def initialize(macro, interpreter, generator, rdb_index = nil)
|
||||||
|
|
||||||
@drc = DRCEngine::new
|
@drc = DRCEngine::new
|
||||||
@drc._rdb_index = rdb_index
|
@drc._rdb_index = rdb_index
|
||||||
|
|
@ -27,6 +27,8 @@ module DRC
|
||||||
|
|
||||||
@macro = macro
|
@macro = macro
|
||||||
|
|
||||||
|
@interpreter = interpreter
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
|
@ -38,9 +40,11 @@ module DRC
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
encoded_file, expanded_text = @interpreter.include_expansion(@macro)
|
||||||
|
|
||||||
# No verbosity set in drc engine - we cannot use the engine's logger
|
# No verbosity set in drc engine - we cannot use the engine's logger
|
||||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
||||||
@drc.instance_eval(@macro.text, @macro.path)
|
@drc.instance_eval(expanded_text, encoded_file)
|
||||||
|
|
||||||
rescue => ex
|
rescue => ex
|
||||||
|
|
||||||
|
|
@ -66,13 +70,40 @@ module DRC
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A recipe implementation allowing the DRC run to be redone
|
||||||
|
class DRCRecipe < RBA::Recipe
|
||||||
|
|
||||||
|
def initialize(interpreter)
|
||||||
|
|
||||||
|
super("drc", "DRC recipe")
|
||||||
|
|
||||||
|
@interpreter = interpreter
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def executable(params)
|
||||||
|
|
||||||
|
script = params["script"]
|
||||||
|
if ! script
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
macro = RBA::Macro::macro_by_path(script)
|
||||||
|
macro || raise("Can't find DRC script #{script} - unable to re-run")
|
||||||
|
|
||||||
|
DRCExecutable::new(macro, @interpreter, self.generator("script" => script), params["rdb_index"])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# A DSL implementation for a DRC language (XML format)
|
# A DSL implementation for a DRC language (XML format)
|
||||||
class DRCInterpreter < RBA::MacroInterpreter
|
class DRCInterpreter < RBA::MacroInterpreter
|
||||||
|
|
||||||
# Constructor
|
# Constructor
|
||||||
def initialize(recipe)
|
def initialize
|
||||||
|
|
||||||
@recipe = recipe
|
@recipe = DRCRecipe::new(self)
|
||||||
|
|
||||||
# Make the DSL use ruby syntax highlighting
|
# Make the DSL use ruby syntax highlighting
|
||||||
self.syntax_scheme = "ruby"
|
self.syntax_scheme = "ruby"
|
||||||
|
|
@ -97,7 +128,7 @@ module DRC
|
||||||
|
|
||||||
# Implements the execute method
|
# Implements the execute method
|
||||||
def executable(macro)
|
def executable(macro)
|
||||||
DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
|
DRCExecutable::new(macro, self, @recipe.generator("script" => macro.path))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -106,9 +137,9 @@ module DRC
|
||||||
class DRCPlainTextInterpreter < RBA::MacroInterpreter
|
class DRCPlainTextInterpreter < RBA::MacroInterpreter
|
||||||
|
|
||||||
# Constructor
|
# Constructor
|
||||||
def initialize(recipe)
|
def initialize
|
||||||
|
|
||||||
@recipe = recipe
|
@recipe = DRCRecipe::new(self)
|
||||||
|
|
||||||
# Make the DSL use ruby syntax highlighting
|
# Make the DSL use ruby syntax highlighting
|
||||||
self.syntax_scheme = "ruby"
|
self.syntax_scheme = "ruby"
|
||||||
|
|
@ -124,40 +155,14 @@ module DRC
|
||||||
|
|
||||||
# Implements the execute method
|
# Implements the execute method
|
||||||
def executable(macro)
|
def executable(macro)
|
||||||
DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
|
DRCExecutable::new(macro, self, @recipe.generator("script" => macro.path))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# A recipe implementation allowing the DRC run to be redone
|
|
||||||
class DRCRecipe < RBA::Recipe
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super("drc", "DRC recipe")
|
|
||||||
end
|
|
||||||
|
|
||||||
def executable(params)
|
|
||||||
|
|
||||||
script = params["script"]
|
|
||||||
if ! script
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
macro = RBA::Macro::macro_by_path(script)
|
|
||||||
macro || raise("Can't find DRC script #{script} - unable to re-run")
|
|
||||||
|
|
||||||
DRCExecutable::new(macro, self.generator("script" => script), params["rdb_index"])
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# Register the recipe
|
|
||||||
drc_recipe = DRCRecipe::new
|
|
||||||
|
|
||||||
# Register the new interpreters
|
# Register the new interpreters
|
||||||
DRCInterpreter::new(drc_recipe)
|
DRCInterpreter::new
|
||||||
DRCPlainTextInterpreter::new(drc_recipe)
|
DRCPlainTextInterpreter::new
|
||||||
|
|
||||||
# Creates a new macro category
|
# Creates a new macro category
|
||||||
if RBA.constants.member?(:Application) && RBA::Application::instance
|
if RBA.constants.member?(:Application) && RBA::Application::instance
|
||||||
|
|
|
||||||
|
|
@ -1146,8 +1146,6 @@ PartialService::move_ac () const
|
||||||
void
|
void
|
||||||
PartialService::deactivated ()
|
PartialService::deactivated ()
|
||||||
{
|
{
|
||||||
// clear selection when this mode is left
|
|
||||||
partial_select (db::DBox (), lay::Editable::Reset);
|
|
||||||
clear_partial_transient_selection ();
|
clear_partial_transient_selection ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2169,6 +2167,110 @@ PartialService::mouse_release_event (const db::DPoint &p, unsigned int buttons,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PartialService::begin_move (MoveMode mode, const db::DPoint &p, lay::angle_constraint_type ac)
|
||||||
|
{
|
||||||
|
if (has_selection () && mode == lay::Editable::Selected) {
|
||||||
|
|
||||||
|
m_alt_ac = ac;
|
||||||
|
|
||||||
|
m_dragging = true;
|
||||||
|
m_keep_selection = true;
|
||||||
|
|
||||||
|
if (is_single_point_selection ()) {
|
||||||
|
// for a single selected point we use the original point as the start location which
|
||||||
|
// allows bringing it to grid
|
||||||
|
m_current = m_start = single_selected_point ();
|
||||||
|
} else if (is_single_edge_selection ()) {
|
||||||
|
// for an edge selection use the point projected to edge as the start location which
|
||||||
|
// allows bringing it to grid
|
||||||
|
m_current = m_start = projected_to_edge (single_selected_edge (), p);
|
||||||
|
} else {
|
||||||
|
m_current = m_start = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_alt_ac = lay::AC_Global;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
|
||||||
|
{
|
||||||
|
m_alt_ac = ac;
|
||||||
|
|
||||||
|
set_cursor (lay::Cursor::size_all);
|
||||||
|
|
||||||
|
// drag the vertex or edge/segment
|
||||||
|
if (is_single_point_selection () || is_single_edge_selection ()) {
|
||||||
|
|
||||||
|
lay::PointSnapToObjectResult snap_details;
|
||||||
|
|
||||||
|
// for a single selected point or edge, m_start is the original position and we snap the target -
|
||||||
|
// thus, we can bring the point on grid or to an object's edge or vertex
|
||||||
|
snap_details = snap2 (p);
|
||||||
|
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
|
||||||
|
m_current = m_start + snap (p - m_start);
|
||||||
|
} else {
|
||||||
|
m_current = snap_details.snapped_point;
|
||||||
|
mouse_cursor_from_snap_details (snap_details);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// snap movement to angle and grid without object
|
||||||
|
m_current = m_start + snap (p - m_start);
|
||||||
|
clear_mouse_cursors ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
selection_to_view ();
|
||||||
|
|
||||||
|
m_alt_ac = lay::AC_Global;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac)
|
||||||
|
{
|
||||||
|
m_alt_ac = ac;
|
||||||
|
|
||||||
|
if (m_current != m_start) {
|
||||||
|
|
||||||
|
// stop dragging
|
||||||
|
ui ()->ungrab_mouse (this);
|
||||||
|
|
||||||
|
if (manager ()) {
|
||||||
|
manager ()->transaction (tl::to_string (tr ("Partial move")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// heuristically, if there is just one edge selected: do not confine to the movement
|
||||||
|
// angle constraint - the edge usually is confined enough
|
||||||
|
db::DTrans move_trans = db::DTrans (m_current - m_start);
|
||||||
|
|
||||||
|
transform_selection (move_trans);
|
||||||
|
|
||||||
|
if (manager ()) {
|
||||||
|
manager ()->commit ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! m_keep_selection) {
|
||||||
|
m_selection.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dragging = false;
|
||||||
|
selection_to_view ();
|
||||||
|
|
||||||
|
clear_mouse_cursors ();
|
||||||
|
|
||||||
|
m_alt_ac = lay::AC_Global;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PartialService::has_selection ()
|
PartialService::has_selection ()
|
||||||
{
|
{
|
||||||
|
|
@ -2181,6 +2283,58 @@ PartialService::selection_size ()
|
||||||
return m_selection.size ();
|
return m_selection.size ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db::DBox
|
||||||
|
PartialService::selection_bbox ()
|
||||||
|
{
|
||||||
|
// build the transformation variants cache
|
||||||
|
// TODO: this is done multiple times - once for each service!
|
||||||
|
TransformationVariants tv (view ());
|
||||||
|
const db::DCplxTrans &vp = view ()->viewport ().trans ();
|
||||||
|
|
||||||
|
lay::TextInfo text_info (view ());
|
||||||
|
|
||||||
|
db::DBox box;
|
||||||
|
for (partial_objects::const_iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
|
||||||
|
|
||||||
|
const lay::CellView &cv = view ()->cellview (r->first.cv_index ());
|
||||||
|
const db::Layout &layout = cv->layout ();
|
||||||
|
|
||||||
|
db::CplxTrans ctx_trans = db::CplxTrans (layout.dbu ()) * cv.context_trans () * r->first.trans ();
|
||||||
|
|
||||||
|
db::box_convert<db::CellInst> bc (layout);
|
||||||
|
if (! r->first.is_cell_inst ()) {
|
||||||
|
|
||||||
|
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv_and_layer (r->first.cv_index (), r->first.layer ());
|
||||||
|
if (tv_list != 0) {
|
||||||
|
for (std::vector<db::DCplxTrans>::const_iterator t = tv_list->begin (); t != tv_list->end (); ++t) {
|
||||||
|
if (r->first.shape ().is_text ()) {
|
||||||
|
db::Text text;
|
||||||
|
r->first.shape ().text (text);
|
||||||
|
box += *t * text_info.bbox (ctx_trans * text, vp * *t);
|
||||||
|
} else {
|
||||||
|
for (auto e = r->second.begin (); e != r->second.end (); ++e) {
|
||||||
|
box += *t * (ctx_trans * e->bbox ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv (r->first.cv_index ());
|
||||||
|
if (tv_list != 0) {
|
||||||
|
for (std::vector<db::DCplxTrans>::const_iterator t = tv_list->begin (); t != tv_list->end (); ++t) {
|
||||||
|
box += *t * (ctx_trans * r->first.back ().bbox (bc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PartialService::has_transient_selection ()
|
PartialService::has_transient_selection ()
|
||||||
{
|
{
|
||||||
|
|
@ -2191,6 +2345,8 @@ PartialService::has_transient_selection ()
|
||||||
void
|
void
|
||||||
PartialService::del ()
|
PartialService::del ()
|
||||||
{
|
{
|
||||||
|
std::set<db::Layout *> needs_cleanup;
|
||||||
|
|
||||||
// stop dragging
|
// stop dragging
|
||||||
ui ()->ungrab_mouse (this);
|
ui ()->ungrab_mouse (this);
|
||||||
|
|
||||||
|
|
@ -2272,6 +2428,9 @@ PartialService::del ()
|
||||||
if (r->first.is_cell_inst ()) {
|
if (r->first.is_cell_inst ()) {
|
||||||
const lay::CellView &cv = view ()->cellview (r->first.cv_index ());
|
const lay::CellView &cv = view ()->cellview (r->first.cv_index ());
|
||||||
if (cv.is_valid ()) {
|
if (cv.is_valid ()) {
|
||||||
|
if (cv->layout ().cell (r->first.back ().inst_ptr.cell_index ()).is_proxy ()) {
|
||||||
|
needs_cleanup.insert (& cv->layout ());
|
||||||
|
}
|
||||||
cv->layout ().cell (r->first.cell_index ()).erase (r->first.back ().inst_ptr);
|
cv->layout ().cell (r->first.cell_index ()).erase (r->first.back ().inst_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2285,6 +2444,11 @@ PartialService::del ()
|
||||||
m_selection.clear ();
|
m_selection.clear ();
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
selection_to_view ();
|
selection_to_view ();
|
||||||
|
|
||||||
|
// clean up the layouts that need to do so.
|
||||||
|
for (std::set<db::Layout *>::const_iterator l = needs_cleanup.begin (); l != needs_cleanup.end (); ++l) {
|
||||||
|
(*l)->cleanup ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lay::InstanceMarker *
|
lay::InstanceMarker *
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,26 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool has_transient_selection ();
|
virtual bool has_transient_selection ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the selection bounding box
|
||||||
|
*/
|
||||||
|
virtual db::DBox selection_bbox ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start a "move" operation
|
||||||
|
*/
|
||||||
|
virtual bool begin_move (MoveMode sel, const db::DPoint &p, lay::angle_constraint_type ac);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Continue a "move" operation
|
||||||
|
*/
|
||||||
|
virtual void move (const db::DPoint &p, lay::angle_constraint_type ac);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Terminate a "move" operation
|
||||||
|
*/
|
||||||
|
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implement the "select" method at least to clear the selection
|
* @brief Implement the "select" method at least to clear the selection
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -471,6 +471,7 @@ Service::selection_bbox ()
|
||||||
// build the transformation variants cache
|
// build the transformation variants cache
|
||||||
// TODO: this is done multiple times - once for each service!
|
// TODO: this is done multiple times - once for each service!
|
||||||
TransformationVariants tv (view ());
|
TransformationVariants tv (view ());
|
||||||
|
const db::DCplxTrans &vp = view ()->viewport ().trans ();
|
||||||
|
|
||||||
lay::TextInfo text_info (view ());
|
lay::TextInfo text_info (view ());
|
||||||
|
|
||||||
|
|
@ -491,7 +492,7 @@ Service::selection_bbox ()
|
||||||
if (r->shape ().is_text ()) {
|
if (r->shape ().is_text ()) {
|
||||||
db::Text text;
|
db::Text text;
|
||||||
r->shape ().text (text);
|
r->shape ().text (text);
|
||||||
box += *t * text_info.bbox (ctx_trans * text, *t);
|
box += *t * text_info.bbox (ctx_trans * text, vp * *t);
|
||||||
} else {
|
} else {
|
||||||
box += *t * (ctx_trans * r->shape ().bbox ());
|
box += *t * (ctx_trans * r->shape ().bbox ());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -463,6 +463,10 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../icons/icons.qrc">
|
||||||
|
<normaloff>:/breakpoint_16px.png</normaloff>:/breakpoint_16px.png</iconset>
|
||||||
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>F9</string>
|
<string>F9</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
@ -614,13 +618,20 @@
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>40</width>
|
<width>40</width>
|
||||||
<height>20</height>
|
<height>16</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="lay::DecoratedLineEdit" name="searchEditBox"/>
|
<widget class="lay::DecoratedLineEdit" name="searchEditBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Ignored">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="findNextButton">
|
<widget class="QToolButton" name="findNextButton">
|
||||||
|
|
@ -721,7 +732,14 @@
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="lay::DecoratedLineEdit" name="replaceText"/>
|
<widget class="lay::DecoratedLineEdit" name="replaceText">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Ignored">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="replaceNextButton">
|
<widget class="QToolButton" name="replaceNextButton">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<ui version="4.0" >
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
<class>TechMacrosPage</class>
|
<class>TechMacrosPage</class>
|
||||||
<widget class="QWidget" name="TechMacrosPage" >
|
<widget class="QWidget" name="TechMacrosPage">
|
||||||
<property name="geometry" >
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
|
|
@ -9,94 +10,86 @@
|
||||||
<height>492</height>
|
<height>492</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" >
|
<layout class="QVBoxLayout">
|
||||||
<property name="margin" >
|
<property name="spacing">
|
||||||
<number>9</number>
|
|
||||||
</property>
|
|
||||||
<property name="spacing" >
|
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="title_label" >
|
<widget class="QLabel" name="title_label">
|
||||||
<property name="sizePolicy" >
|
<property name="sizePolicy">
|
||||||
<sizepolicy>
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
<hsizetype>5</hsizetype>
|
|
||||||
<vsizetype>0</vsizetype>
|
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string>%CAT_DESC%</string>
|
<string>%CAT_DESC%</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QFrame" name="macro_frame" >
|
<widget class="QFrame" name="macro_frame">
|
||||||
<property name="sizePolicy" >
|
<property name="sizePolicy">
|
||||||
<sizepolicy>
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<hsizetype>5</hsizetype>
|
|
||||||
<vsizetype>5</vsizetype>
|
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>1</verstretch>
|
<verstretch>1</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape" >
|
<property name="frameShape">
|
||||||
<enum>QFrame::NoFrame</enum>
|
<enum>QFrame::NoFrame</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShadow" >
|
<property name="frameShadow">
|
||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" >
|
<layout class="QVBoxLayout">
|
||||||
<property name="margin" >
|
<property name="spacing">
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="spacing" >
|
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSplitter" name="splitter" >
|
<widget class="QSplitter" name="splitter">
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QTreeView" name="folder_tree" >
|
<widget class="QTreeView" name="folder_tree">
|
||||||
<property name="sizePolicy" >
|
<property name="sizePolicy">
|
||||||
<sizepolicy>
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
<hsizetype>5</hsizetype>
|
|
||||||
<vsizetype>7</vsizetype>
|
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QFrame" name="frame" >
|
<widget class="QFrame" name="frame">
|
||||||
<property name="sizePolicy" >
|
<property name="sizePolicy">
|
||||||
<sizepolicy>
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<hsizetype>5</hsizetype>
|
|
||||||
<vsizetype>5</vsizetype>
|
|
||||||
<horstretch>3</horstretch>
|
<horstretch>3</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape" >
|
<property name="frameShape">
|
||||||
<enum>QFrame::NoFrame</enum>
|
<enum>QFrame::NoFrame</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShadow" >
|
<property name="frameShadow">
|
||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" >
|
<layout class="QVBoxLayout">
|
||||||
<property name="margin" >
|
<property name="spacing">
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="spacing" >
|
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTextBrowser" name="macro_text" >
|
<widget class="QTextBrowser" name="macro_text">
|
||||||
<property name="lineWrapMode" >
|
<property name="lineWrapMode">
|
||||||
<enum>QTextEdit::NoWrap</enum>
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
@ -109,70 +102,68 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="note_label" >
|
<widget class="QLabel" name="note_label">
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string><html><body><span style=" font-weight:600;">Note</span>: to edit, add or delete scripts, use the macro development facility in "Tools/Macro Development" or "Tools/Verification/DRC/Edit DRC Scripts". You will find a branch for this technology there.</p></body></html></string>
|
<string><html><body><span style=" font-weight:600;">Note</span>: to edit, add or delete scripts, use the macro development facility in "Tools/Macro Development". You will find a branch for this technology there.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap" >
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="empty_label1" >
|
<widget class="QLabel" name="empty_label1">
|
||||||
<property name="sizePolicy" >
|
<property name="sizePolicy">
|
||||||
<sizepolicy>
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<hsizetype>5</hsizetype>
|
|
||||||
<vsizetype>5</vsizetype>
|
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string><html><body><span style=" font-weight:600;">Note</span>: this page is empty because no valid base path is set.<br/>Select a base path on the "General" page to establish one.</p></body></html></string>
|
<string><html><body><span style=" font-weight:600;">Note</span>: this page is empty because no valid base path is set.<br/>Select a base path on the "General" page to establish one.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment" >
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap" >
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QFrame" name="empty_label2_frame" >
|
<widget class="QFrame" name="empty_label2_frame">
|
||||||
<property name="minimumSize" >
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>16</width>
|
<width>16</width>
|
||||||
<height>200</height>
|
<height>200</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape" >
|
<property name="frameShape">
|
||||||
<enum>QFrame::NoFrame</enum>
|
<enum>QFrame::NoFrame</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShadow" >
|
<property name="frameShadow">
|
||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" >
|
<layout class="QGridLayout">
|
||||||
<property name="margin" >
|
<property name="margin" stdset="0">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="spacing" >
|
<property name="spacing">
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="2" column="1" >
|
<item row="2" column="1">
|
||||||
<widget class="QPushButton" name="create_folder_button" >
|
<widget class="QPushButton" name="create_folder_button">
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string>Create Folder Now</string>
|
<string>Create Folder Now</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="2" >
|
<item row="2" column="2">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" >
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>211</width>
|
<width>211</width>
|
||||||
<height>20</height>
|
<height>20</height>
|
||||||
|
|
@ -180,12 +171,12 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" >
|
<item row="2" column="0">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" >
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>231</width>
|
<width>231</width>
|
||||||
<height>20</height>
|
<height>20</height>
|
||||||
|
|
@ -193,12 +184,12 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="3" >
|
<item row="3" column="0" colspan="3">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" >
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>651</width>
|
<width>651</width>
|
||||||
<height>40</height>
|
<height>40</height>
|
||||||
|
|
@ -206,12 +197,12 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="3" >
|
<item row="0" column="0" colspan="3">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" >
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>671</width>
|
<width>671</width>
|
||||||
<height>40</height>
|
<height>40</height>
|
||||||
|
|
@ -219,23 +210,21 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0" colspan="3" >
|
<item row="1" column="0" colspan="3">
|
||||||
<widget class="QLabel" name="empty_label2" >
|
<widget class="QLabel" name="empty_label2">
|
||||||
<property name="sizePolicy" >
|
<property name="sizePolicy">
|
||||||
<sizepolicy>
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<hsizetype>5</hsizetype>
|
|
||||||
<vsizetype>5</vsizetype>
|
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string><html><body><span style=" font-weight:600;">Note</span>: this page is empty, because the corresponding macro folder</p><p style=" margin-top:5px; margin-bottom:5px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><i>%BASE_PATH%/%CAT%</i></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cannot be found or is not accessible.</p></body></html></string>
|
<string><html><body><span style=" font-weight:600;">Note</span>: this page is empty, because the corresponding macro folder</p><p style=" margin-top:5px; margin-bottom:5px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><i>%BASE_PATH%/%CAT%</i></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">cannot be found or is not accessible.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment" >
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap" >
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
@ -244,15 +233,15 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="empty_label3" >
|
<widget class="QLabel" name="empty_label3">
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string><html><body>
|
<string><html><body>
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span>: this page is empty, because the macro location is shared by a different macro site (specifically "<i>%ALT_DESC%</i>"). Such a site cannot be made technology specific. Choose a base path that points to a different location.</p></body></html></string>
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span>: this page is empty, because the macro location is shared by a different macro site (specifically "<i>%ALT_DESC%</i>"). Such a site cannot be made technology specific. Choose a base path that points to a different location.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment" >
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap" >
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
||||||
|
|
@ -385,9 +385,9 @@ MacroController::sync_implicit_macros (bool ask_before_autorun)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// determine the paths currently in use
|
// determine the paths currently in use
|
||||||
std::map<std::string, const ExternalPathDescriptor *> prev_folders_by_path;
|
std::map<std::string, ExternalPathDescriptor> prev_folders_by_path;
|
||||||
for (std::vector<ExternalPathDescriptor>::const_iterator p = m_external_paths.begin (); p != m_external_paths.end (); ++p) {
|
for (std::vector<ExternalPathDescriptor>::const_iterator p = m_external_paths.begin (); p != m_external_paths.end (); ++p) {
|
||||||
prev_folders_by_path.insert (std::make_pair (p->path, p.operator-> ()));
|
prev_folders_by_path.insert (std::make_pair (p->path, *p));
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets the external paths (tech, packages) into m_external_paths
|
// gets the external paths (tech, packages) into m_external_paths
|
||||||
|
|
@ -433,23 +433,39 @@ MacroController::sync_implicit_macros (bool ask_before_autorun)
|
||||||
|
|
||||||
for (std::vector<ExternalPathDescriptor>::const_iterator p = m_external_paths.begin (); p != m_external_paths.end (); ++p) {
|
for (std::vector<ExternalPathDescriptor>::const_iterator p = m_external_paths.begin (); p != m_external_paths.end (); ++p) {
|
||||||
|
|
||||||
if (prev_folders_by_path.find (p->path) != prev_folders_by_path.end ()) {
|
auto pf = prev_folders_by_path.find (p->path);
|
||||||
continue;
|
if (pf != prev_folders_by_path.end ()) {
|
||||||
}
|
|
||||||
|
|
||||||
if (tl::verbosity () >= 20) {
|
if (pf->second.version != p->version) {
|
||||||
tl::info << "Adding macro folder " << p->path << ", category '" << p->cat << "' for '" << p->description << "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the folder. Note: it may happen that a macro folder for the tech specific macros already exists in
|
if (tl::verbosity () >= 20) {
|
||||||
// a non-tech context.
|
tl::info << "New version (" << p->version << " vs. " << pf->second.version << ") of macro folder " << p->path << ", category '" << p->cat << "' for '" << p->description << "'";
|
||||||
// In that case, the add_folder method will return 0.
|
}
|
||||||
|
|
||||||
|
lym::MacroCollection *mc = lym::MacroCollection::root ().folder_by_name (p->path);
|
||||||
|
if (mc) {
|
||||||
|
new_folders.push_back (mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (tl::verbosity () >= 20) {
|
||||||
|
tl::info << "Adding macro folder " << p->path << ", category '" << p->cat << "' for '" << p->description << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the folder. Note: it may happen that a macro folder for the tech specific macros already exists in
|
||||||
|
// a non-tech context.
|
||||||
|
// In that case, the add_folder method will return 0.
|
||||||
|
|
||||||
|
// TODO: is it wise to make this writeable?
|
||||||
|
lym::MacroCollection *mc = lym::MacroCollection::root ().add_folder (p->description, p->path, p->cat, p->readonly);
|
||||||
|
if (mc) {
|
||||||
|
mc->set_virtual_mode (p->type);
|
||||||
|
new_folders.push_back (mc);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: is it wise to make this writeable?
|
|
||||||
lym::MacroCollection *mc = lym::MacroCollection::root ().add_folder (p->description, p->path, p->cat, p->readonly);
|
|
||||||
if (mc) {
|
|
||||||
mc->set_virtual_mode (p->type);
|
|
||||||
new_folders.push_back (mc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -565,7 +581,7 @@ MacroController::sync_macro_sources ()
|
||||||
if (*f != macro_categories () [c].name) {
|
if (*f != macro_categories () [c].name) {
|
||||||
description += " - " + tl::to_string (tr ("%1 branch").arg (tl::to_qstring (*f)));
|
description += " - " + tl::to_string (tr ("%1 branch").arg (tl::to_qstring (*f)));
|
||||||
}
|
}
|
||||||
external_paths.push_back (ExternalPathDescriptor (tl::to_string (macro_dir.path ()), description, macro_categories () [c].name, lym::MacroCollection::SaltFolder, g->is_readonly ()));
|
external_paths.push_back (ExternalPathDescriptor (tl::to_string (macro_dir.path ()), description, macro_categories () [c].name, lym::MacroCollection::SaltFolder, g->is_readonly (), g->version ()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -204,8 +204,8 @@ private:
|
||||||
*/
|
*/
|
||||||
struct ExternalPathDescriptor
|
struct ExternalPathDescriptor
|
||||||
{
|
{
|
||||||
ExternalPathDescriptor (const std::string &_path, const std::string &_description, const std::string &_cat, lym::MacroCollection::FolderType _type, bool _readonly)
|
ExternalPathDescriptor (const std::string &_path, const std::string &_description, const std::string &_cat, lym::MacroCollection::FolderType _type, bool _readonly, const std::string &_version = std::string ())
|
||||||
: path (_path), description (_description), cat (_cat), type (_type), readonly (_readonly)
|
: path (_path), description (_description), cat (_cat), type (_type), version (_version), readonly (_readonly)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -214,6 +214,7 @@ private:
|
||||||
std::string description;
|
std::string description;
|
||||||
std::string cat;
|
std::string cat;
|
||||||
lym::MacroCollection::FolderType type;
|
lym::MacroCollection::FolderType type;
|
||||||
|
std::string version;
|
||||||
bool readonly;
|
bool readonly;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,6 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
|
||||||
m_first_show (true), m_debugging_on (true),
|
m_first_show (true), m_debugging_on (true),
|
||||||
mp_run_macro (0),
|
mp_run_macro (0),
|
||||||
md_update_console_text (this, &MacroEditorDialog::update_console_text),
|
md_update_console_text (this, &MacroEditorDialog::update_console_text),
|
||||||
md_search_edited (this, &MacroEditorDialog::do_search_edited),
|
|
||||||
m_in_event_handler (false),
|
m_in_event_handler (false),
|
||||||
m_os (OS_none),
|
m_os (OS_none),
|
||||||
m_new_line (true),
|
m_new_line (true),
|
||||||
|
|
@ -429,6 +428,17 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
|
||||||
connect (action, SIGNAL (triggered ()), this, SLOT (close_all_right ()));
|
connect (action, SIGNAL (triggered ()), this, SLOT (close_all_right ()));
|
||||||
tabWidget->addAction (action);
|
tabWidget->addAction (action);
|
||||||
|
|
||||||
|
action = new QAction (this);
|
||||||
|
action->setSeparator (true);
|
||||||
|
tabWidget->addAction (action);
|
||||||
|
|
||||||
|
mp_tabs_menu = new QMenu ();
|
||||||
|
|
||||||
|
action = new QAction (tr ("Tabs"), this);
|
||||||
|
action->setMenu (mp_tabs_menu);
|
||||||
|
connect (mp_tabs_menu, SIGNAL (aboutToShow ()), this, SLOT (tabs_menu_about_to_show ()));
|
||||||
|
tabWidget->addAction (action);
|
||||||
|
|
||||||
dbgOn->setEnabled (true);
|
dbgOn->setEnabled (true);
|
||||||
runButton->setEnabled (true);
|
runButton->setEnabled (true);
|
||||||
runThisButton->setEnabled (true);
|
runThisButton->setEnabled (true);
|
||||||
|
|
@ -672,6 +682,34 @@ MacroEditorDialog::instance ()
|
||||||
return s_macro_editor_instance;
|
return s_macro_editor_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorDialog::tab_menu_selected ()
|
||||||
|
{
|
||||||
|
QAction *action = dynamic_cast<QAction *> (sender ());
|
||||||
|
if (action) {
|
||||||
|
tabWidget->setCurrentIndex (action->data ().toInt ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorDialog::tabs_menu_about_to_show ()
|
||||||
|
{
|
||||||
|
mp_tabs_menu->clear ();
|
||||||
|
|
||||||
|
for (int i = 0; i < tabWidget->count (); ++i) {
|
||||||
|
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->widget (i));
|
||||||
|
if (page) {
|
||||||
|
QAction *action = new QAction (tl::to_qstring (page->path ()), mp_tabs_menu);
|
||||||
|
action->setData (i);
|
||||||
|
connect (action, SIGNAL (triggered ()), this, SLOT (tab_menu_selected ()));
|
||||||
|
if (page->macro () == mp_run_macro) {
|
||||||
|
action->setIcon (QIcon (":/run_16px.png"));
|
||||||
|
}
|
||||||
|
mp_tabs_menu->addAction (action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroEditorDialog::select_category (const std::string &cat)
|
MacroEditorDialog::select_category (const std::string &cat)
|
||||||
{
|
{
|
||||||
|
|
@ -1770,8 +1808,6 @@ MacroEditorDialog::current_tab_changed (int index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the search
|
|
||||||
searchEditBox->clear ();
|
|
||||||
replaceFrame->setEnabled (page && page->macro () && !page->macro ()->is_readonly ());
|
replaceFrame->setEnabled (page && page->macro () && !page->macro ()->is_readonly ());
|
||||||
|
|
||||||
apply_search ();
|
apply_search ();
|
||||||
|
|
@ -2062,14 +2098,6 @@ MacroEditorDialog::search_editing ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
MacroEditorDialog::search_edited ()
|
|
||||||
{
|
|
||||||
// since we want to move the focus to the text field, we have to do this in the deferred method
|
|
||||||
// (this method is called from an event handler and setFocus does not have an effect then)
|
|
||||||
md_search_edited ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroEditorDialog::search_finished ()
|
MacroEditorDialog::search_finished ()
|
||||||
{
|
{
|
||||||
|
|
@ -2083,7 +2111,7 @@ MacroEditorDialog::search_finished ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroEditorDialog::do_search_edited ()
|
MacroEditorDialog::search_edited ()
|
||||||
{
|
{
|
||||||
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
|
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
|
||||||
if (! page) {
|
if (! page) {
|
||||||
|
|
@ -2095,7 +2123,6 @@ MacroEditorDialog::do_search_edited ()
|
||||||
if (! page->has_multi_block_selection ()) {
|
if (! page->has_multi_block_selection ()) {
|
||||||
page->find_next ();
|
page->find_next ();
|
||||||
}
|
}
|
||||||
set_editor_focus ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2375,6 +2402,15 @@ BEGIN_PROTECTED
|
||||||
END_PROTECTED
|
END_PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorDialog::close_requested ()
|
||||||
|
{
|
||||||
|
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (sender ());
|
||||||
|
if (! m_in_exec && page) {
|
||||||
|
tab_close_requested (tabWidget->indexOf (page));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroEditorDialog::tab_close_requested (int index)
|
MacroEditorDialog::tab_close_requested (int index)
|
||||||
{
|
{
|
||||||
|
|
@ -2607,66 +2643,65 @@ BEGIN_PROTECTED
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> modified_files;
|
std::map<std::string, MacroEditorPage *> path_to_page;
|
||||||
for (std::map <lym::Macro *, MacroEditorPage *>::const_iterator m = m_tab_widgets.begin (); m != m_tab_widgets.end (); ++m) {
|
for (int i = 0; i < tabWidget->count (); ++i) {
|
||||||
if (m->first->is_modified ()) {
|
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->widget (i));
|
||||||
modified_files.insert (m->first->path ());
|
if (page) {
|
||||||
|
path_to_page.insert (std::make_pair (page->path (), page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QString> conflicts;
|
|
||||||
for (std::vector<QString>::const_iterator f = m_changed_files.begin (); f != m_changed_files.end (); ++f) {
|
for (std::vector<QString>::const_iterator f = m_changed_files.begin (); f != m_changed_files.end (); ++f) {
|
||||||
if (modified_files.find (tl::to_string (*f)) != modified_files.end ()) {
|
|
||||||
conflicts.push_back (*f);
|
std::string fn = tl::to_string (*f);
|
||||||
|
auto w = path_to_page.find (fn);
|
||||||
|
if (w == path_to_page.end ()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w->second->macro () && w->second->macro ()->is_modified ()) {
|
||||||
|
|
||||||
|
lay::MacroEditorNotification n ("reload", tl::to_string (tr ("Macro has changed on disk, but was modified")), tl::Variant (fn));
|
||||||
|
n.add_action ("reload", tl::to_string (tr ("Reload and discard changes")));
|
||||||
|
w->second->add_notification (n);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
lay::MacroEditorNotification n ("reload", tl::to_string (tr ("Macro has changed on disk")), tl::Variant (fn));
|
||||||
|
n.add_action ("reload", tl::to_string (tr ("Reload")));
|
||||||
|
w->second->add_notification (n);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<QString>::const_iterator f = m_removed_files.begin (); f != m_removed_files.end (); ++f) {
|
for (std::vector<QString>::const_iterator f = m_removed_files.begin (); f != m_removed_files.end (); ++f) {
|
||||||
if (modified_files.find (tl::to_string (*f)) != modified_files.end ()) {
|
|
||||||
conflicts.push_back (*f);
|
std::string fn = tl::to_string (*f);
|
||||||
|
auto w = path_to_page.find (fn);
|
||||||
|
if (w == path_to_page.end ()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w->second->macro () && w->second->macro ()->is_modified ()) {
|
||||||
|
|
||||||
|
lay::MacroEditorNotification n ("close", tl::to_string (tr ("Macro has been removed on disk, but was modified")), tl::Variant (fn));
|
||||||
|
n.add_action ("close", tl::to_string (tr ("Close tab and discard changes")));
|
||||||
|
w->second->add_notification (n);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
lay::MacroEditorNotification n ("close", tl::to_string (tr ("Macro has been removed on disk")), tl::Variant (fn));
|
||||||
|
n.add_action ("close", tl::to_string (tr ("Close tab")));
|
||||||
|
w->second->add_notification (n);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString msg;
|
refresh_file_watcher ();
|
||||||
|
|
||||||
if (m_changed_files.size () + m_removed_files.size () == 1) {
|
|
||||||
msg = QObject::tr ("The following file has been changed on disk:\n\n");
|
|
||||||
for (std::vector<QString>::const_iterator f = m_changed_files.begin (); f != m_changed_files.end (); ++f) {
|
|
||||||
msg += QString::fromUtf8 (" %1 (modified)\n").arg (*f);
|
|
||||||
}
|
|
||||||
for (std::vector<QString>::const_iterator f = m_removed_files.begin (); f != m_removed_files.end (); ++f) {
|
|
||||||
msg += QString::fromUtf8 (" %1 (removed)\n").arg (*f);
|
|
||||||
}
|
|
||||||
if (!conflicts.empty ()) {
|
|
||||||
msg += tr ("\nThis file has been modified in the editor as well.\nRefresh this file and discard changes?");
|
|
||||||
} else {
|
|
||||||
msg += tr ("\nRefresh this file?");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
msg = QObject::tr ("The following files have been changed on disk:\n\n");
|
|
||||||
for (std::vector<QString>::const_iterator f = m_changed_files.begin (); f != m_changed_files.end (); ++f) {
|
|
||||||
msg += QString::fromUtf8 (" %1 (modified)\n").arg (*f);
|
|
||||||
}
|
|
||||||
for (std::vector<QString>::const_iterator f = m_removed_files.begin (); f != m_removed_files.end (); ++f) {
|
|
||||||
msg += QString::fromUtf8 (" %1 (removed)\n").arg (*f);
|
|
||||||
}
|
|
||||||
if (!conflicts.empty ()) {
|
|
||||||
msg += tr("\nSome of these files are modified on disk and in the editor:\n\n");
|
|
||||||
for (std::vector<QString>::const_iterator f = conflicts.begin (); f != conflicts.end (); ++f) {
|
|
||||||
msg += QString::fromUtf8 (" %1 (conflict)\n").arg (*f);
|
|
||||||
}
|
|
||||||
msg += tr ("\nRefresh these and the other files and discard all changes?");
|
|
||||||
} else {
|
|
||||||
msg += tr ("\nRefresh those files?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_changed_files.clear ();
|
m_changed_files.clear ();
|
||||||
m_removed_files.clear ();
|
m_removed_files.clear ();
|
||||||
|
|
||||||
if (QMessageBox::question (this, tr ("Refresh Files"), msg, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
|
||||||
reload_macros ();
|
|
||||||
}
|
|
||||||
|
|
||||||
END_PROTECTED
|
END_PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2790,7 +2825,7 @@ BEGIN_PROTECTED
|
||||||
std::string new_path = tl::to_string (QFileInfo (new_dir).absoluteFilePath ());
|
std::string new_path = tl::to_string (QFileInfo (new_dir).absoluteFilePath ());
|
||||||
paths.push_back (std::make_pair (new_path, cat));
|
paths.push_back (std::make_pair (new_path, cat));
|
||||||
|
|
||||||
lym::MacroCollection *c = mp_root->add_folder (tl::to_string (QObject::tr ("Project")) + " - " + new_path, new_path, cat, false);
|
lym::MacroCollection *c = mp_root->add_folder (tl::to_string (QObject::tr ("Project")) + " - " + new_path, new_path, cat, false /* writeable */, false /* do not auto-create folders */);
|
||||||
if (!c) {
|
if (!c) {
|
||||||
throw tl::Exception (tl::to_string (QObject::tr ("The selected directory is already installed as custom location")));
|
throw tl::Exception (tl::to_string (QObject::tr ("The selected directory is already installed as custom location")));
|
||||||
}
|
}
|
||||||
|
|
@ -3525,6 +3560,7 @@ MacroEditorDialog::create_page (lym::Macro *macro)
|
||||||
editor->set_font (m_font_family, m_font_size);
|
editor->set_font (m_font_family, m_font_size);
|
||||||
editor->exec_model ()->set_run_mode (m_in_exec);
|
editor->exec_model ()->set_run_mode (m_in_exec);
|
||||||
editor->connect_macro (macro);
|
editor->connect_macro (macro);
|
||||||
|
connect (editor.get (), SIGNAL (close_requested ()), this, SLOT (close_requested ()));
|
||||||
connect (editor.get (), SIGNAL (help_requested (const QString &)), this, SLOT (help_requested (const QString &)));
|
connect (editor.get (), SIGNAL (help_requested (const QString &)), this, SLOT (help_requested (const QString &)));
|
||||||
connect (editor.get (), SIGNAL (search_requested (const QString &, bool)), this, SLOT (search_requested (const QString &, bool)));
|
connect (editor.get (), SIGNAL (search_requested (const QString &, bool)), this, SLOT (search_requested (const QString &, bool)));
|
||||||
connect (editor.get (), SIGNAL (edit_trace (bool)), this, SLOT (add_edit_trace (bool)));
|
connect (editor.get (), SIGNAL (edit_trace (bool)), this, SLOT (add_edit_trace (bool)));
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,7 @@ private slots:
|
||||||
void search_editing ();
|
void search_editing ();
|
||||||
void search_finished ();
|
void search_finished ();
|
||||||
void tab_close_requested (int);
|
void tab_close_requested (int);
|
||||||
|
void close_requested ();
|
||||||
void close_all ();
|
void close_all ();
|
||||||
void close_all_but_this ();
|
void close_all_but_this ();
|
||||||
void close_all_left ();
|
void close_all_left ();
|
||||||
|
|
@ -232,6 +233,8 @@ private slots:
|
||||||
void del_watches ();
|
void del_watches ();
|
||||||
void clear_watches ();
|
void clear_watches ();
|
||||||
void set_debugging_on (bool on);
|
void set_debugging_on (bool on);
|
||||||
|
void tabs_menu_about_to_show ();
|
||||||
|
void tab_menu_selected ();
|
||||||
|
|
||||||
// edit trace navigation
|
// edit trace navigation
|
||||||
void forward ();
|
void forward ();
|
||||||
|
|
@ -311,7 +314,6 @@ private:
|
||||||
lym::Macro *mp_run_macro;
|
lym::Macro *mp_run_macro;
|
||||||
std::vector<lym::Macro *> m_macro_templates;
|
std::vector<lym::Macro *> m_macro_templates;
|
||||||
tl::DeferredMethod<MacroEditorDialog> md_update_console_text;
|
tl::DeferredMethod<MacroEditorDialog> md_update_console_text;
|
||||||
tl::DeferredMethod<MacroEditorDialog> md_search_edited;
|
|
||||||
TextEditWidget *mp_console_text;
|
TextEditWidget *mp_console_text;
|
||||||
std::map <lym::Macro *, MacroEditorPage *> m_tab_widgets;
|
std::map <lym::Macro *, MacroEditorPage *> m_tab_widgets;
|
||||||
int m_history_index;
|
int m_history_index;
|
||||||
|
|
@ -358,6 +360,7 @@ private:
|
||||||
std::vector<QString> m_changed_files, m_removed_files;
|
std::vector<QString> m_changed_files, m_removed_files;
|
||||||
tl::DeferredMethod<MacroEditorDialog> dm_refresh_file_watcher;
|
tl::DeferredMethod<MacroEditorDialog> dm_refresh_file_watcher;
|
||||||
tl::DeferredMethod<MacroEditorDialog> dm_update_ui_to_run_mode;
|
tl::DeferredMethod<MacroEditorDialog> dm_update_ui_to_run_mode;
|
||||||
|
QMenu *mp_tabs_menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
|
|
@ -81,6 +83,59 @@ void MacroEditorTextWidget::paintEvent (QPaintEvent *event)
|
||||||
return TextEditWidget::paintEvent (event);
|
return TextEditWidget::paintEvent (event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------------
|
||||||
|
// MacroEditorNotificationWidget implementation
|
||||||
|
|
||||||
|
MacroEditorNotificationWidget::MacroEditorNotificationWidget (MacroEditorPage *parent, const MacroEditorNotification *notification)
|
||||||
|
: QFrame (parent), mp_parent (parent), mp_notification (notification)
|
||||||
|
{
|
||||||
|
setBackgroundRole (QPalette::ToolTipBase);
|
||||||
|
setAutoFillBackground (true);
|
||||||
|
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout (this);
|
||||||
|
layout->setContentsMargins (4, 4, 4, 4);
|
||||||
|
|
||||||
|
QLabel *title_label = new QLabel (this);
|
||||||
|
layout->addWidget (title_label, 1);
|
||||||
|
title_label->setText (tl::to_qstring (notification->title ()));
|
||||||
|
title_label->setForegroundRole (QPalette::ToolTipText);
|
||||||
|
title_label->setWordWrap (true);
|
||||||
|
activate_help_links (title_label);
|
||||||
|
|
||||||
|
for (auto a = notification->actions ().begin (); a != notification->actions ().end (); ++a) {
|
||||||
|
|
||||||
|
QPushButton *pb = new QPushButton (this);
|
||||||
|
layout->addWidget (pb);
|
||||||
|
|
||||||
|
pb->setText (tl::to_qstring (a->second));
|
||||||
|
m_action_buttons.insert (std::make_pair (pb, a->first));
|
||||||
|
connect (pb, SIGNAL (clicked ()), this, SLOT (action_triggered ()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolButton *close_button = new QToolButton ();
|
||||||
|
close_button->setIcon (QIcon (":clear_edit_16px.png"));
|
||||||
|
close_button->setAutoRaise (true);
|
||||||
|
layout->addWidget (close_button);
|
||||||
|
|
||||||
|
connect (close_button, SIGNAL (clicked ()), this, SLOT (close_triggered ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorNotificationWidget::action_triggered ()
|
||||||
|
{
|
||||||
|
auto a = m_action_buttons.find (sender ());
|
||||||
|
if (a != m_action_buttons.end ()) {
|
||||||
|
mp_parent->notification_action (*mp_notification, a->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorNotificationWidget::close_triggered ()
|
||||||
|
{
|
||||||
|
mp_parent->remove_notification (*mp_notification);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------
|
||||||
// MacroEditorHighlighters implementation
|
// MacroEditorHighlighters implementation
|
||||||
|
|
||||||
|
|
@ -491,15 +546,20 @@ void MacroEditorSidePanel::paintEvent (QPaintEvent *)
|
||||||
MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters *highlighters)
|
MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters *highlighters)
|
||||||
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2), m_ignore_cursor_changed_event (false)
|
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2), m_ignore_cursor_changed_event (false)
|
||||||
{
|
{
|
||||||
QVBoxLayout *layout = new QVBoxLayout (this);
|
mp_layout = new QVBoxLayout (this);
|
||||||
|
mp_layout->setContentsMargins (0, 0, 0, 0);
|
||||||
|
|
||||||
|
QVBoxLayout *vlayout = new QVBoxLayout (this);
|
||||||
|
vlayout->setContentsMargins (4, 4, 4, 4);
|
||||||
|
mp_layout->addLayout (vlayout);
|
||||||
|
|
||||||
mp_readonly_label = new QLabel (this);
|
mp_readonly_label = new QLabel (this);
|
||||||
mp_readonly_label->setText (QObject::tr ("Macro is read-only and cannot be edited"));
|
mp_readonly_label->setText (QObject::tr ("Macro is read-only and cannot be edited"));
|
||||||
mp_readonly_label->hide ();
|
mp_readonly_label->hide ();
|
||||||
layout->addWidget (mp_readonly_label);
|
vlayout->addWidget (mp_readonly_label);
|
||||||
|
|
||||||
QHBoxLayout *hlayout = new QHBoxLayout ();
|
QHBoxLayout *hlayout = new QHBoxLayout ();
|
||||||
layout->addLayout (hlayout);
|
mp_layout->addLayout (hlayout);
|
||||||
|
|
||||||
mp_exec_model = new MacroEditorExecutionModel (this);
|
mp_exec_model = new MacroEditorExecutionModel (this);
|
||||||
mp_text = new MacroEditorTextWidget (this);
|
mp_text = new MacroEditorTextWidget (this);
|
||||||
|
|
@ -1021,6 +1081,8 @@ void MacroEditorPage::connect_macro (lym::Macro *macro)
|
||||||
|
|
||||||
if (mp_macro) {
|
if (mp_macro) {
|
||||||
|
|
||||||
|
m_path = mp_macro->path ();
|
||||||
|
|
||||||
connect (mp_macro, SIGNAL (changed ()), this, SLOT (update ()));
|
connect (mp_macro, SIGNAL (changed ()), this, SLOT (update ()));
|
||||||
|
|
||||||
lym::Macro::Interpreter lang = macro->interpreter ();
|
lym::Macro::Interpreter lang = macro->interpreter ();
|
||||||
|
|
@ -1924,5 +1986,54 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorPage::add_notification (const MacroEditorNotification ¬ification)
|
||||||
|
{
|
||||||
|
if (m_notification_widgets.find (¬ification) == m_notification_widgets.end ()) {
|
||||||
|
m_notifications.push_back (notification);
|
||||||
|
QWidget *w = new MacroEditorNotificationWidget (this, &m_notifications.back ());
|
||||||
|
m_notification_widgets.insert (std::make_pair (&m_notifications.back (), w));
|
||||||
|
mp_layout->insertWidget (0, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorPage::remove_notification (const MacroEditorNotification ¬ification)
|
||||||
|
{
|
||||||
|
auto nw = m_notification_widgets.find (¬ification);
|
||||||
|
if (nw != m_notification_widgets.end ()) {
|
||||||
|
|
||||||
|
nw->second->deleteLater ();
|
||||||
|
m_notification_widgets.erase (nw);
|
||||||
|
|
||||||
|
for (auto n = m_notifications.begin (); n != m_notifications.end (); ++n) {
|
||||||
|
if (*n == notification) {
|
||||||
|
m_notifications.erase (n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroEditorPage::notification_action (const MacroEditorNotification ¬ification, const std::string &action)
|
||||||
|
{
|
||||||
|
if (action == "close") {
|
||||||
|
|
||||||
|
remove_notification (notification);
|
||||||
|
|
||||||
|
emit close_requested ();
|
||||||
|
|
||||||
|
} else if (action == "reload") {
|
||||||
|
|
||||||
|
remove_notification (notification);
|
||||||
|
|
||||||
|
mp_macro->load ();
|
||||||
|
mp_macro->reset_modified ();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "lymMacro.h"
|
#include "lymMacro.h"
|
||||||
#include "layGenericSyntaxHighlighter.h"
|
#include "layGenericSyntaxHighlighter.h"
|
||||||
|
#include "tlVariant.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
|
@ -47,10 +48,13 @@ class QSyntaxHighlighter;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
class QWindow;
|
class QWindow;
|
||||||
class QListWidget;
|
class QListWidget;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class MacroEditorPage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A collection of highlighters
|
* @brief A collection of highlighters
|
||||||
*/
|
*/
|
||||||
|
|
@ -209,7 +213,92 @@ private:
|
||||||
bool m_debugging_on;
|
bool m_debugging_on;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroEditorPage
|
/**
|
||||||
|
* @brief Descriptor for a notification inside the macro editor
|
||||||
|
*
|
||||||
|
* Notifications are popups added at the top of the view to indicate need for reloading for example.
|
||||||
|
* Notifications have a name, a title, optional actions (id, title) and a parameter (e.g. file path to reload).
|
||||||
|
* Actions are mapped to QPushButtons.
|
||||||
|
*/
|
||||||
|
class MacroEditorNotification
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MacroEditorNotification (const std::string &name, const std::string &title, const tl::Variant ¶meter = tl::Variant ())
|
||||||
|
: m_name (name), m_title (title), m_parameter (parameter)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_action (const std::string &name, const std::string &title)
|
||||||
|
{
|
||||||
|
m_actions.push_back (std::make_pair (name, title));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::pair<std::string, std::string> > &actions () const
|
||||||
|
{
|
||||||
|
return m_actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &name () const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &title () const
|
||||||
|
{
|
||||||
|
return m_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tl::Variant ¶meter () const
|
||||||
|
{
|
||||||
|
return m_parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const MacroEditorNotification &other) const
|
||||||
|
{
|
||||||
|
if (m_name != other.name ()) {
|
||||||
|
return m_name < other.name ();
|
||||||
|
}
|
||||||
|
return m_parameter < other.parameter ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const MacroEditorNotification &other) const
|
||||||
|
{
|
||||||
|
if (m_name != other.name ()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return m_parameter == other.parameter ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
std::string m_title;
|
||||||
|
tl::Variant m_parameter;
|
||||||
|
std::vector<std::pair<std::string, std::string> > m_actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A widget representing a notification
|
||||||
|
*/
|
||||||
|
class MacroEditorNotificationWidget
|
||||||
|
: public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroEditorNotificationWidget (MacroEditorPage *parent, const MacroEditorNotification *notification);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void action_triggered ();
|
||||||
|
void close_triggered ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MacroEditorPage *mp_parent;
|
||||||
|
const MacroEditorNotification *mp_notification;
|
||||||
|
std::map<QObject *, std::string> m_action_buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroEditorPage
|
||||||
: public QWidget
|
: public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -224,6 +313,11 @@ public:
|
||||||
return mp_macro;
|
return mp_macro;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string path () const
|
||||||
|
{
|
||||||
|
return m_path;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_modified () const
|
bool is_modified () const
|
||||||
{
|
{
|
||||||
return m_is_modified;
|
return m_is_modified;
|
||||||
|
|
@ -269,10 +363,14 @@ public:
|
||||||
|
|
||||||
void set_editor_focus ();
|
void set_editor_focus ();
|
||||||
|
|
||||||
|
void add_notification (const MacroEditorNotification ¬ificaton);
|
||||||
|
void remove_notification (const MacroEditorNotification ¬ificaton);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void help_requested (const QString &s);
|
void help_requested (const QString &s);
|
||||||
void search_requested (const QString &s, bool backward);
|
void search_requested (const QString &s, bool backward);
|
||||||
void edit_trace (bool);
|
void edit_trace (bool);
|
||||||
|
void close_requested ();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void commit ();
|
void commit ();
|
||||||
|
|
@ -288,10 +386,22 @@ protected slots:
|
||||||
void hide_completer ();
|
void hide_completer ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class MacroEditorNotificationWidget;
|
||||||
|
|
||||||
|
struct CompareNotificationPointers
|
||||||
|
{
|
||||||
|
bool operator() (const MacroEditorNotification *a, const MacroEditorNotification *b) const
|
||||||
|
{
|
||||||
|
return *a < *b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
lym::Macro *mp_macro;
|
lym::Macro *mp_macro;
|
||||||
|
std::string m_path;
|
||||||
MacroEditorExecutionModel *mp_exec_model;
|
MacroEditorExecutionModel *mp_exec_model;
|
||||||
MacroEditorTextWidget *mp_text;
|
MacroEditorTextWidget *mp_text;
|
||||||
MacroEditorSidePanel *mp_side_panel;
|
MacroEditorSidePanel *mp_side_panel;
|
||||||
|
QVBoxLayout *mp_layout;
|
||||||
QLabel *mp_readonly_label;
|
QLabel *mp_readonly_label;
|
||||||
bool m_is_modified;
|
bool m_is_modified;
|
||||||
MacroEditorHighlighters *mp_highlighters;
|
MacroEditorHighlighters *mp_highlighters;
|
||||||
|
|
@ -305,6 +415,8 @@ private:
|
||||||
QTimer *mp_completer_timer;
|
QTimer *mp_completer_timer;
|
||||||
QWidget *mp_completer_popup;
|
QWidget *mp_completer_popup;
|
||||||
QListWidget *mp_completer_list;
|
QListWidget *mp_completer_list;
|
||||||
|
std::list<MacroEditorNotification> m_notifications;
|
||||||
|
std::map<const MacroEditorNotification *, QWidget *, CompareNotificationPointers> m_notification_widgets;
|
||||||
|
|
||||||
void update_extra_selections ();
|
void update_extra_selections ();
|
||||||
bool return_pressed ();
|
bool return_pressed ();
|
||||||
|
|
@ -316,6 +428,7 @@ private:
|
||||||
QTextCursor get_completer_cursor (int &pos0, int &pos);
|
QTextCursor get_completer_cursor (int &pos0, int &pos);
|
||||||
bool select_match_here ();
|
bool select_match_here ();
|
||||||
void replace_in_selection (const QString &replace, bool first);
|
void replace_in_selection (const QString &replace, bool first);
|
||||||
|
void notification_action (const MacroEditorNotification ¬ification, const std::string &action);
|
||||||
|
|
||||||
bool eventFilter (QObject *watched, QEvent *event);
|
bool eventFilter (QObject *watched, QEvent *event);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "layConfig.h"
|
#include "layConfig.h"
|
||||||
#include "layMainWindow.h"
|
#include "layMainWindow.h"
|
||||||
#include "layQtTools.h"
|
#include "layQtTools.h"
|
||||||
|
#include "layBusy.h"
|
||||||
#include "tlLog.h"
|
#include "tlLog.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
@ -138,11 +139,12 @@ SaltController::show_editor ()
|
||||||
lay::restore_dialog_state (mp_salt_dialog, s);
|
lay::restore_dialog_state (mp_salt_dialog, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// while running the dialog, don't watch file events - that would interfere with
|
{
|
||||||
// the changes applied by the dialog itself.
|
// while running the dialog, don't watch file events - that would interfere with
|
||||||
m_file_watcher->enable (false);
|
// the changes applied by the dialog itself.
|
||||||
mp_salt_dialog->exec ();
|
lay::BusySection busy_section; // disable file watcher
|
||||||
m_file_watcher->enable (true);
|
mp_salt_dialog->exec ();
|
||||||
|
}
|
||||||
|
|
||||||
mp_plugin_root->config_set (cfg_salt_manager_window_state, lay::save_dialog_state (mp_salt_dialog));
|
mp_plugin_root->config_set (cfg_salt_manager_window_state, lay::save_dialog_state (mp_salt_dialog));
|
||||||
|
|
||||||
|
|
@ -154,13 +156,13 @@ SaltController::show_editor ()
|
||||||
void
|
void
|
||||||
SaltController::sync_file_watcher ()
|
SaltController::sync_file_watcher ()
|
||||||
{
|
{
|
||||||
|
lay::BusySection busy_section; // disable file watcher
|
||||||
|
|
||||||
if (m_file_watcher) {
|
if (m_file_watcher) {
|
||||||
m_file_watcher->clear ();
|
m_file_watcher->clear ();
|
||||||
m_file_watcher->enable (false);
|
|
||||||
for (lay::Salt::flat_iterator g = m_salt.begin_flat (); g != m_salt.end_flat (); ++g) {
|
for (lay::Salt::flat_iterator g = m_salt.begin_flat (); g != m_salt.end_flat (); ++g) {
|
||||||
m_file_watcher->add_file ((*g)->path ());
|
m_file_watcher->add_file ((*g)->path ());
|
||||||
}
|
}
|
||||||
m_file_watcher->enable (true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,7 +218,18 @@ SaltController::install_packages (const std::vector<std::string> &packages, bool
|
||||||
manager.compute_packages (m_salt, salt_mine);
|
manager.compute_packages (m_salt, salt_mine);
|
||||||
}
|
}
|
||||||
|
|
||||||
return manager.execute (0, m_salt);
|
bool result = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
// while running the dialog, don't watch file events - that would interfere with
|
||||||
|
// the changes applied by the dialog itself.
|
||||||
|
lay::BusySection busy_section; // disable file watcher
|
||||||
|
result = manager.execute (0, m_salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_file_watcher ();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@
|
||||||
#include "tlException.h"
|
#include "tlException.h"
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
#include "tlLog.h"
|
#include "tlLog.h"
|
||||||
|
#include "tlFileUtils.h"
|
||||||
|
#include "tlStream.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
|
@ -297,16 +299,6 @@ void signal_handler (int signo, siginfo_t *si, void *)
|
||||||
lay::Version::name () + " " +
|
lay::Version::name () + " " +
|
||||||
lay::Version::version () + " (" + lay::Version::subversion () + ")\n";
|
lay::Version::version () + " (" + lay::Version::subversion () + ")\n";
|
||||||
|
|
||||||
std::unique_ptr<CrashMessage> msg;
|
|
||||||
|
|
||||||
bool has_gui = s_sh_has_gui && lay::ApplicationBase::instance () && lay::ApplicationBase::instance ()->has_gui ();
|
|
||||||
|
|
||||||
if (has_gui) {
|
|
||||||
msg.reset (new CrashMessage (0, false, tl::to_qstring (text) + QObject::tr ("\nCollecting backtrace ..")));
|
|
||||||
msg->show ();
|
|
||||||
lay::ApplicationBase::instance ()->qapp_gui ()->setOverrideCursor (Qt::WaitCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
text += std::string ("\nBacktrace:\n");
|
text += std::string ("\nBacktrace:\n");
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
@ -332,14 +324,6 @@ void signal_handler (int signo, siginfo_t *si, void *)
|
||||||
bool has_addr2line = true;
|
bool has_addr2line = true;
|
||||||
for (size_t i = 0; i < nptrs; ++i) {
|
for (size_t i = 0; i < nptrs; ++i) {
|
||||||
|
|
||||||
if (has_gui) {
|
|
||||||
lay::ApplicationBase::instance ()->qapp_gui ()->processEvents ();
|
|
||||||
if (msg->is_cancel_pressed ()) {
|
|
||||||
text += "...\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
dladdr (array [i], &info);
|
dladdr (array [i], &info);
|
||||||
|
|
||||||
|
|
@ -407,9 +391,25 @@ void signal_handler (int signo, siginfo_t *si, void *)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (has_gui) {
|
try {
|
||||||
|
|
||||||
lay::ApplicationBase::instance ()->qapp_gui ()->setOverrideCursor (QCursor ());
|
// write crash log
|
||||||
|
|
||||||
|
std::string crash_log = tl::combine_path (lay::ApplicationBase::instance () ? lay::ApplicationBase::instance ()->appdata_path () : ".", "klayout_crash.log");
|
||||||
|
|
||||||
|
tl::OutputStream os (crash_log, tl::OutputStream::OM_Plain, true);
|
||||||
|
os << text;
|
||||||
|
|
||||||
|
text += "\nCrash log written to " + crash_log;
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
// .. ignore errors
|
||||||
|
}
|
||||||
|
|
||||||
|
tl::error << text << tl::noendl;
|
||||||
|
|
||||||
|
bool has_gui = s_sh_has_gui && lay::ApplicationBase::instance () && lay::ApplicationBase::instance ()->has_gui ();
|
||||||
|
if (has_gui) {
|
||||||
|
|
||||||
// YES! I! KNOW!
|
// YES! I! KNOW!
|
||||||
// In a signal handler you shall not do fancy stuff (in particular not
|
// In a signal handler you shall not do fancy stuff (in particular not
|
||||||
|
|
@ -418,8 +418,10 @@ void signal_handler (int signo, siginfo_t *si, void *)
|
||||||
// from our stack frames) and everything is better than just core dumping.
|
// from our stack frames) and everything is better than just core dumping.
|
||||||
// Isn't it?
|
// Isn't it?
|
||||||
|
|
||||||
msg->set_text (tl::to_qstring (text));
|
lay::ApplicationBase::instance ()->qapp_gui ()->setOverrideCursor (QCursor ());
|
||||||
msg->set_can_resume (can_resume);
|
|
||||||
|
std::unique_ptr<CrashMessage> msg;
|
||||||
|
msg.reset (new CrashMessage (0, can_resume, tl::to_qstring (text)));
|
||||||
|
|
||||||
if (! msg->exec ()) {
|
if (! msg->exec ()) {
|
||||||
|
|
||||||
|
|
@ -438,7 +440,6 @@ void signal_handler (int signo, siginfo_t *si, void *)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
tl::error << text << tl::noendl;
|
|
||||||
_exit (signo);
|
_exit (signo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -748,10 +748,11 @@ InstFinder::find_internal (LayoutViewBase *view, unsigned int cv_index, const db
|
||||||
m_visible_layer_indexes.push_back (l->layer_index ());
|
m_visible_layer_indexes.push_back (l->layer_index ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// add guiding shape and error layers so we can select cells by error markers or guiding shapes
|
||||||
|
if (view->guiding_shapes_visible ()) {
|
||||||
if (!m_visible_layers || view->guiding_shapes_visible ()) {
|
m_visible_layer_indexes.push_back (cv->layout ().guiding_shape_layer ());
|
||||||
m_visible_layer_indexes.push_back (cv->layout ().guiding_shape_layer ());
|
}
|
||||||
|
m_visible_layer_indexes.push_back (cv->layout ().error_layer ());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cv_index = cv_index;
|
m_cv_index = cv_index;
|
||||||
|
|
|
||||||
|
|
@ -5308,7 +5308,7 @@ LayoutViewBase::paste ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayoutViewBase::paste_interactive ()
|
LayoutViewBase::paste_interactive (bool transient_mode)
|
||||||
{
|
{
|
||||||
clear_selection ();
|
clear_selection ();
|
||||||
|
|
||||||
|
|
@ -5320,7 +5320,7 @@ LayoutViewBase::paste_interactive ()
|
||||||
// operations.
|
// operations.
|
||||||
trans->close ();
|
trans->close ();
|
||||||
|
|
||||||
if (mp_move_service->begin_move (trans.release (), false)) {
|
if (mp_move_service->begin_move (trans.release (), transient_mode)) {
|
||||||
switch_mode (-1); // move mode
|
switch_mode (-1); // move mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Pastes from clipboard and initiates a move
|
* @brief Pastes from clipboard and initiates a move
|
||||||
*/
|
*/
|
||||||
void paste_interactive ();
|
void paste_interactive (bool transient_mode = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copies to clipboard
|
* @brief Copies to clipboard
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MoveService::begin_move (db::Transaction *transaction, bool selected_after_move)
|
MoveService::begin_move (db::Transaction *transaction, bool transient_selection)
|
||||||
{
|
{
|
||||||
if (m_dragging) {
|
if (m_dragging) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -248,16 +248,28 @@ MoveService::begin_move (db::Transaction *transaction, bool selected_after_move)
|
||||||
|
|
||||||
std::unique_ptr<db::Transaction> trans_holder (transaction);
|
std::unique_ptr<db::Transaction> trans_holder (transaction);
|
||||||
|
|
||||||
bool drag_transient = ! selected_after_move;
|
bool drag_transient = false;
|
||||||
if (! mp_editables->has_selection ()) {
|
|
||||||
// try to use the transient selection for the real one
|
if (! transaction) {
|
||||||
mp_editables->transient_to_selection ();
|
|
||||||
drag_transient = true;
|
// unless in "continue with move" use case try to establish a selection
|
||||||
}
|
|
||||||
|
if (! mp_editables->has_selection ()) {
|
||||||
|
// try to use the transient selection for the real one
|
||||||
|
mp_editables->transient_to_selection ();
|
||||||
|
drag_transient = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! mp_editables->has_selection ()) {
|
||||||
|
// still nothing selected
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// inherit transient selection mode from previous operation
|
||||||
|
drag_transient = transient_selection;
|
||||||
|
|
||||||
if (! mp_editables->has_selection ()) {
|
|
||||||
// still nothing selected
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db::DBox bbox = mp_editables->selection_bbox ();
|
db::DBox bbox = mp_editables->selection_bbox ();
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ public:
|
||||||
~MoveService ();
|
~MoveService ();
|
||||||
|
|
||||||
virtual bool configure (const std::string &name, const std::string &value);
|
virtual bool configure (const std::string &name, const std::string &value);
|
||||||
bool begin_move (db::Transaction *transaction = 0, bool selected_after_move = true);
|
bool begin_move (db::Transaction *transaction = 0, bool transient_selection = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,38 @@
|
||||||
<ui version="4.0" >
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
<class>RenameCellDialog</class>
|
<class>RenameCellDialog</class>
|
||||||
<widget class="QDialog" name="RenameCellDialog" >
|
<widget class="QDialog" name="RenameCellDialog">
|
||||||
<property name="geometry" >
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>286</width>
|
<width>540</width>
|
||||||
<height>124</height>
|
<height>133</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle">
|
||||||
<string>Rename Cell</string>
|
<string>Rename Cell</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" >
|
<layout class="QGridLayout">
|
||||||
<property name="margin" >
|
<property name="margin" stdset="0">
|
||||||
<number>9</number>
|
<number>9</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="spacing" >
|
<property name="spacing">
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="1" column="0" >
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label" >
|
<widget class="QLabel" name="label">
|
||||||
<property name="text" >
|
<property name="text">
|
||||||
<string>New cell name </string>
|
<string>New cell name </string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="2" >
|
<item row="0" column="0" colspan="2">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" >
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>268</width>
|
<width>268</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
|
|
@ -39,15 +40,15 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1" >
|
<item row="1" column="1">
|
||||||
<widget class="QLineEdit" name="name_le" />
|
<widget class="QLineEdit" name="name_le"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2" >
|
<item row="2" column="0" colspan="2">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" >
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>268</width>
|
<width>268</width>
|
||||||
<height>31</height>
|
<height>31</height>
|
||||||
|
|
@ -55,13 +56,13 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="2" >
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation" >
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons" >
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
@ -79,11 +80,11 @@
|
||||||
<receiver>RenameCellDialog</receiver>
|
<receiver>RenameCellDialog</receiver>
|
||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel" >
|
<hint type="sourcelabel">
|
||||||
<x>248</x>
|
<x>248</x>
|
||||||
<y>254</y>
|
<y>254</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel" >
|
<hint type="destinationlabel">
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
<y>274</y>
|
<y>274</y>
|
||||||
</hint>
|
</hint>
|
||||||
|
|
@ -95,11 +96,11 @@
|
||||||
<receiver>RenameCellDialog</receiver>
|
<receiver>RenameCellDialog</receiver>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel" >
|
<hint type="sourcelabel">
|
||||||
<x>316</x>
|
<x>316</x>
|
||||||
<y>260</y>
|
<y>260</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel" >
|
<hint type="destinationlabel">
|
||||||
<x>286</x>
|
<x>286</x>
|
||||||
<y>274</y>
|
<y>274</y>
|
||||||
</hint>
|
</hint>
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "layBusy.h"
|
#include "layBusy.h"
|
||||||
#include "tlThreads.h"
|
#include "tlThreads.h"
|
||||||
|
#include "tlFileSystemWatcher.h"
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
|
|
@ -61,6 +62,9 @@ BusySection::BusySection ()
|
||||||
m_previous_mode = mp_busy_mode->is_busy ();
|
m_previous_mode = mp_busy_mode->is_busy ();
|
||||||
mp_busy_mode->enter_busy_mode (true);
|
mp_busy_mode->enter_busy_mode (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disable file system watchers during busy periods
|
||||||
|
tl::FileSystemWatcher::global_enable (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BusySection::~BusySection ()
|
BusySection::~BusySection ()
|
||||||
|
|
@ -70,6 +74,8 @@ BusySection::~BusySection ()
|
||||||
mp_busy_mode->enter_busy_mode (m_previous_mode);
|
mp_busy_mode->enter_busy_mode (m_previous_mode);
|
||||||
}
|
}
|
||||||
mp_busy_mode = 0;
|
mp_busy_mode = 0;
|
||||||
|
|
||||||
|
tl::FileSystemWatcher::global_enable (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -1177,11 +1177,12 @@ LayoutViewFunctions::do_cm_duplicate (bool interactive)
|
||||||
db::Clipboard::instance ().swap (saved_clipboard);
|
db::Clipboard::instance ().swap (saved_clipboard);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
bool transient_mode = ! view ()->has_selection ();
|
||||||
view ()->copy_view_objects ();
|
view ()->copy_view_objects ();
|
||||||
view ()->clear_selection ();
|
view ()->clear_selection ();
|
||||||
view ()->cancel ();
|
view ()->cancel ();
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
view ()->paste_interactive ();
|
view ()->paste_interactive (transient_mode);
|
||||||
} else {
|
} else {
|
||||||
view ()->paste ();
|
view ()->paste ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,7 @@ PropertiesDialog::disconnect ()
|
||||||
delete *p;
|
delete *p;
|
||||||
}
|
}
|
||||||
mp_properties_pages.clear ();
|
mp_properties_pages.clear ();
|
||||||
|
m_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -604,7 +605,7 @@ PropertiesDialog::ok_pressed ()
|
||||||
{
|
{
|
||||||
BEGIN_PROTECTED
|
BEGIN_PROTECTED
|
||||||
|
|
||||||
if (! mp_properties_pages [m_index]->readonly ()) {
|
if (m_index >= 0 && m_index < int (mp_properties_pages.size ()) && ! mp_properties_pages [m_index]->readonly ()) {
|
||||||
|
|
||||||
db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id);
|
db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ module LVS
|
||||||
|
|
||||||
class LVSExecutable < RBA::Executable
|
class LVSExecutable < RBA::Executable
|
||||||
|
|
||||||
def initialize(macro, generator, l2ndb_index = nil)
|
def initialize(macro, interpreter, generator, l2ndb_index = nil)
|
||||||
|
|
||||||
@lvs = LVSEngine::new
|
@lvs = LVSEngine::new
|
||||||
@lvs._l2ndb_index = l2ndb_index
|
@lvs._l2ndb_index = l2ndb_index
|
||||||
|
|
@ -27,6 +27,8 @@ module LVS
|
||||||
|
|
||||||
@macro = macro
|
@macro = macro
|
||||||
|
|
||||||
|
@interpreter = interpreter
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
|
@ -38,9 +40,11 @@ module LVS
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
encoded_file, expanded_text = @interpreter.include_expansion(@macro)
|
||||||
|
|
||||||
# No verbosity set in lvs engine - we cannot use the engine's logger
|
# No verbosity set in lvs engine - we cannot use the engine's logger
|
||||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
||||||
@lvs.instance_eval(@macro.text, @macro.path)
|
@lvs.instance_eval(expanded_text, encoded_file)
|
||||||
|
|
||||||
rescue => ex
|
rescue => ex
|
||||||
|
|
||||||
|
|
@ -66,13 +70,40 @@ module LVS
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A recipe implementation allowing the LVS run to be redone
|
||||||
|
class LVSRecipe < RBA::Recipe
|
||||||
|
|
||||||
|
def initialize(interpreter)
|
||||||
|
|
||||||
|
super("lvs", "LVS recipe")
|
||||||
|
|
||||||
|
@interpreter = interpreter
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def executable(params)
|
||||||
|
|
||||||
|
script = params["script"]
|
||||||
|
if ! script
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
macro = RBA::Macro::macro_by_path(script)
|
||||||
|
macro || raise("Can't find LVS script #{script} - unable to re-run")
|
||||||
|
|
||||||
|
LVSExecutable::new(macro, @interpreter, self.generator("script" => script), params["l2ndb_index"])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# A DSL implementation for a LVS language (XML format)
|
# A DSL implementation for a LVS language (XML format)
|
||||||
class LVSInterpreter < RBA::MacroInterpreter
|
class LVSInterpreter < RBA::MacroInterpreter
|
||||||
|
|
||||||
# Constructor
|
# Constructor
|
||||||
def initialize(recipe)
|
def initialize
|
||||||
|
|
||||||
@recipe = recipe
|
@recipe = LVSRecipe::new(self)
|
||||||
|
|
||||||
# Make the DSL use ruby syntax highlighting
|
# Make the DSL use ruby syntax highlighting
|
||||||
self.syntax_scheme = "ruby"
|
self.syntax_scheme = "ruby"
|
||||||
|
|
@ -97,7 +128,7 @@ module LVS
|
||||||
|
|
||||||
# Implements the execute method
|
# Implements the execute method
|
||||||
def executable(macro)
|
def executable(macro)
|
||||||
LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
|
LVSExecutable::new(macro, self, @recipe.generator("script" => macro.path))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -106,9 +137,9 @@ module LVS
|
||||||
class LVSPlainTextInterpreter < RBA::MacroInterpreter
|
class LVSPlainTextInterpreter < RBA::MacroInterpreter
|
||||||
|
|
||||||
# Constructor
|
# Constructor
|
||||||
def initialize(recipe)
|
def initialize
|
||||||
|
|
||||||
@recipe = recipe
|
@recipe = LVSRecipe::new(self)
|
||||||
|
|
||||||
# Make the DSL use ruby syntax highlighting
|
# Make the DSL use ruby syntax highlighting
|
||||||
self.syntax_scheme = "ruby"
|
self.syntax_scheme = "ruby"
|
||||||
|
|
@ -124,40 +155,14 @@ module LVS
|
||||||
|
|
||||||
# Implements the execute method
|
# Implements the execute method
|
||||||
def executable(macro)
|
def executable(macro)
|
||||||
LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
|
LVSExecutable::new(macro, self, @recipe.generator("script" => macro.path))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# A recipe implementation allowing the LVS run to be redone
|
|
||||||
class LVSRecipe < RBA::Recipe
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super("lvs", "LVS recipe")
|
|
||||||
end
|
|
||||||
|
|
||||||
def executable(params)
|
|
||||||
|
|
||||||
script = params["script"]
|
|
||||||
if ! script
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
macro = RBA::Macro::macro_by_path(script)
|
|
||||||
macro || raise("Can't find LVS script #{script} - unable to re-run")
|
|
||||||
|
|
||||||
LVSExecutable::new(macro, self.generator("script" => script), params["l2ndb_index"])
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# Register the recipe
|
|
||||||
lvs_recipe = LVSRecipe::new
|
|
||||||
|
|
||||||
# Register the new interpreters
|
# Register the new interpreters
|
||||||
LVSInterpreter::new(lvs_recipe)
|
LVSInterpreter::new
|
||||||
LVSPlainTextInterpreter::new(lvs_recipe)
|
LVSPlainTextInterpreter::new
|
||||||
|
|
||||||
# Creates a new macro category
|
# Creates a new macro category
|
||||||
if RBA.constants.member?(:Application) && RBA::Application::instance
|
if RBA.constants.member?(:Application) && RBA::Application::instance
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,18 @@ private:
|
||||||
bool m_supports_include_expansion;
|
bool m_supports_include_expansion;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::vector<std::string>
|
||||||
|
include_expansion (MacroInterpreterImpl *interp, lym::Macro *macro)
|
||||||
|
{
|
||||||
|
std::vector<std::string> res;
|
||||||
|
|
||||||
|
auto sp = interp->include_expansion (macro);
|
||||||
|
res.push_back (sp.first);
|
||||||
|
res.push_back (sp.second);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
gsi::EnumIn<lym::Macro, lym::Macro::Format> decl_FormatEnum ("lay", "Format",
|
gsi::EnumIn<lym::Macro, lym::Macro::Format> decl_FormatEnum ("lay", "Format",
|
||||||
gsi::enum_const ("PlainTextFormat", lym::Macro::PlainTextFormat,
|
gsi::enum_const ("PlainTextFormat", lym::Macro::PlainTextFormat,
|
||||||
"@brief The macro has plain text format"
|
"@brief The macro has plain text format"
|
||||||
|
|
@ -298,6 +310,13 @@ Class<MacroInterpreterImpl> decl_MacroInterpreter ("lay", "MacroInterpreter",
|
||||||
gsi::method ("NoDebugger", &const_NoDebugger,
|
gsi::method ("NoDebugger", &const_NoDebugger,
|
||||||
"@brief Indicates no debugging for \\debugger_scheme\n"
|
"@brief Indicates no debugging for \\debugger_scheme\n"
|
||||||
) +
|
) +
|
||||||
|
gsi::method_ext ("include_expansion", &include_expansion, gsi::arg ("macro"),
|
||||||
|
"@brief Provides include expansion as defined by the interpreter\n"
|
||||||
|
"The return value will be a two-element array with the encoded file path "
|
||||||
|
"and the include-expanded text.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.28.12."
|
||||||
|
) +
|
||||||
gsi::method ("register", &MacroInterpreterImpl::register_gsi, gsi::arg ("name"),
|
gsi::method ("register", &MacroInterpreterImpl::register_gsi, gsi::arg ("name"),
|
||||||
"@brief Registers the macro interpreter\n"
|
"@brief Registers the macro interpreter\n"
|
||||||
"@param name The interpreter name. This is an arbitrary string which should be unique.\n"
|
"@param name The interpreter name. This is an arbitrary string which should be unique.\n"
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#include "tlProgress.h"
|
#include "tlProgress.h"
|
||||||
#include "tlFileUtils.h"
|
#include "tlFileUtils.h"
|
||||||
#include "tlResources.h"
|
#include "tlResources.h"
|
||||||
|
#include "tlEnv.h"
|
||||||
|
|
||||||
#include "rba.h"
|
#include "rba.h"
|
||||||
#include "pya.h"
|
#include "pya.h"
|
||||||
|
|
@ -262,7 +263,7 @@ MacroCollection::make_readonly (bool f)
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroCollection *
|
MacroCollection *
|
||||||
MacroCollection::add_folder (const std::string &description, const std::string &p, const std::string &cat, bool readonly, bool force_create)
|
MacroCollection::add_folder (const std::string &description, const std::string &p, const std::string &cat, bool readonly, bool auto_create)
|
||||||
{
|
{
|
||||||
if (! p.empty () && p[0] == ':') {
|
if (! p.empty () && p[0] == ':') {
|
||||||
|
|
||||||
|
|
@ -278,7 +279,7 @@ MacroCollection::add_folder (const std::string &description, const std::string &
|
||||||
if (! tl::file_exists (fp)) {
|
if (! tl::file_exists (fp)) {
|
||||||
|
|
||||||
// Try to create the folder since it does not exist yet or skip that one
|
// Try to create the folder since it does not exist yet or skip that one
|
||||||
if (! force_create) {
|
if (readonly || ! auto_create) {
|
||||||
|
|
||||||
if (tl::verbosity () >= 20) {
|
if (tl::verbosity () >= 20) {
|
||||||
tl::log << tl::to_string (tr ("Folder does not exist - skipping: ")) << fp;
|
tl::log << tl::to_string (tr ("Folder does not exist - skipping: ")) << fp;
|
||||||
|
|
@ -363,6 +364,22 @@ namespace {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Some directories are ignored in addition to dotfiles
|
||||||
|
static bool dir_is_ignored (const std::string &dn)
|
||||||
|
{
|
||||||
|
static std::set <std::string> ignored;
|
||||||
|
static bool initialized = false;
|
||||||
|
|
||||||
|
if (! initialized) {
|
||||||
|
// a colon-separated list of directory names
|
||||||
|
std::string ign = tl::get_env ("KLAYOUT_IGNORE_MACRO_DIRS", "__pycache__");
|
||||||
|
auto ignv = tl::split (ign, ":");
|
||||||
|
ignored.insert (ignv.begin (), ignv.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignored.find (dn) != ignored.end ();
|
||||||
|
}
|
||||||
|
|
||||||
void MacroCollection::scan ()
|
void MacroCollection::scan ()
|
||||||
{
|
{
|
||||||
std::string p = path ();
|
std::string p = path ();
|
||||||
|
|
@ -431,6 +448,10 @@ void MacroCollection::scan ()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dir_is_ignored (*f)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
MacroCollection *&mc = m_folders.insert (std::make_pair (*f, (MacroCollection *) 0)).first->second;
|
MacroCollection *&mc = m_folders.insert (std::make_pair (*f, (MacroCollection *) 0)).first->second;
|
||||||
|
|
@ -831,7 +852,7 @@ void MacroCollection::reload (bool safe)
|
||||||
|
|
||||||
lym::MacroCollection new_collection;
|
lym::MacroCollection new_collection;
|
||||||
for (lym::MacroCollection::child_iterator c = begin_children (); c != end_children (); ++c) {
|
for (lym::MacroCollection::child_iterator c = begin_children (); c != end_children (); ++c) {
|
||||||
new_collection.add_folder (c->second->description (), c->second->path (), c->second->category (), c->second->is_readonly (), false /* don't force to create */);
|
new_collection.add_folder (c->second->description (), c->second->path (), c->second->category (), c->second->is_readonly (), false /* don't auto-create folder */);
|
||||||
}
|
}
|
||||||
|
|
||||||
// and synchronize current with the actual one
|
// and synchronize current with the actual one
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ public:
|
||||||
* If force_create is true (the default), the folder will be created if it does not
|
* If force_create is true (the default), the folder will be created if it does not
|
||||||
* exist yet. On error, 0 is returned.
|
* exist yet. On error, 0 is returned.
|
||||||
*/
|
*/
|
||||||
MacroCollection *add_folder (const std::string &description, const std::string &path, const std::string &category, bool readonly, bool force_create = true);
|
MacroCollection *add_folder (const std::string &description, const std::string &path, const std::string &category, bool readonly, bool auto_create = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the category tag of the collection
|
* @brief Gets the category tag of the collection
|
||||||
|
|
|
||||||
|
|
@ -130,31 +130,15 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
|
||||||
|
|
||||||
if (cls.current_name () == macro->dsl_interpreter ()) {
|
if (cls.current_name () == macro->dsl_interpreter ()) {
|
||||||
|
|
||||||
std::pair<std::string, std::string> et = cls->include_expansion (macro);
|
std::unique_ptr<tl::Executable> eo (cls->executable (macro));
|
||||||
if (et.first.empty () || et.first == macro->path ()) {
|
if (eo.get ()) {
|
||||||
|
eo->do_execute ();
|
||||||
std::unique_ptr<tl::Executable> eo (cls->executable (macro));
|
|
||||||
if (eo.get ()) {
|
|
||||||
eo->do_execute ();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// provide a copy which takes the include-expanded version
|
|
||||||
lym::Macro tmp_macro;
|
|
||||||
tmp_macro.assign (*macro);
|
|
||||||
tmp_macro.set_text (et.second);
|
|
||||||
tmp_macro.set_file_path (et.first);
|
|
||||||
std::unique_ptr<tl::Executable> eo (cls->executable (&tmp_macro));
|
|
||||||
if (eo.get ()) {
|
|
||||||
eo->do_execute ();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw tl::Exception (tl::to_string (tr ("No interpreter registered for DSL type '")) + macro->dsl_interpreter () + "'");
|
throw tl::Exception (tl::to_string (tr ("No interpreter registered for DSL type '")) + macro->dsl_interpreter () + "'");
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,15 @@ module D25
|
||||||
|
|
||||||
class D25Executable < RBA::Executable
|
class D25Executable < RBA::Executable
|
||||||
|
|
||||||
def initialize(macro, generator)
|
def initialize(macro, interpreter, generator)
|
||||||
|
|
||||||
@d25 = D25Engine::new
|
@d25 = D25Engine::new
|
||||||
@d25._generator = generator
|
@d25._generator = generator
|
||||||
|
|
||||||
@macro = macro
|
@macro = macro
|
||||||
|
|
||||||
|
@interpreter = interpreter
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
|
@ -37,9 +39,11 @@ module D25
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
||||||
|
encoded_file, expanded_text = @interpreter.include_expansion(@macro)
|
||||||
|
|
||||||
# No verbosity set in d25 engine - we cannot use the engine's logger
|
# No verbosity set in d25 engine - we cannot use the engine's logger
|
||||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
||||||
@d25.instance_eval(@macro.text, @macro.path)
|
@d25.instance_eval(expanded_text, encoded_file)
|
||||||
|
|
||||||
rescue => ex
|
rescue => ex
|
||||||
|
|
||||||
|
|
@ -67,13 +71,40 @@ module D25
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A recipe implementation allowing the D25 run to be redone
|
||||||
|
class D25Recipe < RBA::Recipe
|
||||||
|
|
||||||
|
def initialize(interpreter)
|
||||||
|
|
||||||
|
super("d25", "D25 recipe")
|
||||||
|
|
||||||
|
@interpreter = interpreter
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def executable(params)
|
||||||
|
|
||||||
|
script = params["script"]
|
||||||
|
if ! script
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
macro = RBA::Macro::macro_by_path(script)
|
||||||
|
macro || raise("Can't find D25 script #{script} - unable to re-run")
|
||||||
|
|
||||||
|
D25Executable::new(macro, @interpreter, self.generator("script" => script))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# A DSL implementation for a D25 language (XML format)
|
# A DSL implementation for a D25 language (XML format)
|
||||||
class D25Interpreter < RBA::MacroInterpreter
|
class D25Interpreter < RBA::MacroInterpreter
|
||||||
|
|
||||||
# Constructor
|
# Constructor
|
||||||
def initialize(recipe)
|
def initialize
|
||||||
|
|
||||||
@recipe = recipe
|
@recipe = D25Recipe::new(self)
|
||||||
|
|
||||||
# Make the DSL use ruby syntax highlighting
|
# Make the DSL use ruby syntax highlighting
|
||||||
self.syntax_scheme = "ruby"
|
self.syntax_scheme = "ruby"
|
||||||
|
|
@ -98,7 +129,7 @@ module D25
|
||||||
|
|
||||||
# Implements the execute method
|
# Implements the execute method
|
||||||
def executable(macro)
|
def executable(macro)
|
||||||
D25Executable::new(macro, @recipe.generator("script" => macro.path))
|
D25Executable::new(macro, self, @recipe.generator("script" => macro.path))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -107,9 +138,9 @@ module D25
|
||||||
class D25PlainTextInterpreter < RBA::MacroInterpreter
|
class D25PlainTextInterpreter < RBA::MacroInterpreter
|
||||||
|
|
||||||
# Constructor
|
# Constructor
|
||||||
def initialize(recipe)
|
def initialize
|
||||||
|
|
||||||
@recipe = recipe
|
@recipe = D25Recipe::new(self)
|
||||||
|
|
||||||
# Make the DSL use ruby syntax highlighting
|
# Make the DSL use ruby syntax highlighting
|
||||||
self.syntax_scheme = "ruby"
|
self.syntax_scheme = "ruby"
|
||||||
|
|
@ -125,40 +156,14 @@ module D25
|
||||||
|
|
||||||
# Implements the execute method
|
# Implements the execute method
|
||||||
def executable(macro)
|
def executable(macro)
|
||||||
D25Executable::new(macro, @recipe.generator("script" => macro.path))
|
D25Executable::new(macro, self, @recipe.generator("script" => macro.path))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# A recipe implementation allowing the D25 run to be redone
|
|
||||||
class D25Recipe < RBA::Recipe
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super("d25", "D25 recipe")
|
|
||||||
end
|
|
||||||
|
|
||||||
def executable(params)
|
|
||||||
|
|
||||||
script = params["script"]
|
|
||||||
if ! script
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
macro = RBA::Macro::macro_by_path(script)
|
|
||||||
macro || raise("Can't find D25 script #{script} - unable to re-run")
|
|
||||||
|
|
||||||
D25Executable::new(macro, self.generator("script" => script))
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# Register the recipe
|
|
||||||
d25_recipe = D25Recipe::new
|
|
||||||
|
|
||||||
# Register the new interpreters
|
# Register the new interpreters
|
||||||
D25Interpreter::new(d25_recipe)
|
D25Interpreter::new
|
||||||
D25PlainTextInterpreter::new(d25_recipe)
|
D25PlainTextInterpreter::new
|
||||||
|
|
||||||
# Creates a new macro category
|
# Creates a new macro category
|
||||||
if RBA::Application::instance
|
if RBA::Application::instance
|
||||||
|
|
|
||||||
|
|
@ -109,13 +109,13 @@ public:
|
||||||
{
|
{
|
||||||
while (frame != NULL) {
|
while (frame != NULL) {
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x030B0000
|
#if PY_VERSION_HEX >= 0x030A0000
|
||||||
int line = PyFrame_GetLineNumber(frame);
|
int line = PyFrame_GetLineNumber(frame);
|
||||||
#else
|
#else
|
||||||
int line = frame->f_lineno;
|
int line = frame->f_lineno;
|
||||||
#endif
|
#endif
|
||||||
std::string fn;
|
std::string fn;
|
||||||
#if PY_VERSION_HEX >= 0x030B0000
|
#if PY_VERSION_HEX >= 0x030A0000
|
||||||
if (test_type<std::string> (PyFrame_GetCode(frame)->co_filename, true)) {
|
if (test_type<std::string> (PyFrame_GetCode(frame)->co_filename, true)) {
|
||||||
fn = normalize_path (python2c<std::string> (PyFrame_GetCode(frame)->co_filename));
|
fn = normalize_path (python2c<std::string> (PyFrame_GetCode(frame)->co_filename));
|
||||||
#else
|
#else
|
||||||
|
|
@ -125,7 +125,7 @@ public:
|
||||||
}
|
}
|
||||||
m_stack_trace.push_back (tl::BacktraceElement (fn, line));
|
m_stack_trace.push_back (tl::BacktraceElement (fn, line));
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x030B0000
|
#if PY_VERSION_HEX >= 0x030A0000
|
||||||
frame = PyFrame_GetBack(frame);
|
frame = PyFrame_GetBack(frame);
|
||||||
#else
|
#else
|
||||||
frame = frame->f_back;
|
frame = frame->f_back;
|
||||||
|
|
|
||||||
|
|
@ -115,13 +115,15 @@ rba_get_backtrace_from_array (VALUE backtrace, std::vector<tl::BacktraceElement>
|
||||||
void
|
void
|
||||||
block_exceptions (bool f)
|
block_exceptions (bool f)
|
||||||
{
|
{
|
||||||
RubyInterpreter::instance ()->block_exceptions (f);
|
if (RubyInterpreter::instance ()) {
|
||||||
|
RubyInterpreter::instance ()->block_exceptions (f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
exceptions_blocked ()
|
exceptions_blocked ()
|
||||||
{
|
{
|
||||||
return RubyInterpreter::instance ()->exceptions_blocked ();
|
return RubyInterpreter::instance () ? RubyInterpreter::instance ()->exceptions_blocked () : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -161,8 +163,10 @@ rba_check_error ()
|
||||||
std::vector <tl::BacktraceElement> bt;
|
std::vector <tl::BacktraceElement> bt;
|
||||||
rba_get_backtrace_from_array (rb_funcall (lasterr, rb_intern ("backtrace"), 0), bt, 0);
|
rba_get_backtrace_from_array (rb_funcall (lasterr, rb_intern ("backtrace"), 0), bt, 0);
|
||||||
|
|
||||||
const std::string &ds = RubyInterpreter::instance ()->debugger_scope ();
|
if (RubyInterpreter::instance ()) {
|
||||||
bt.erase (bt.begin (), bt.begin () + RubyStackTraceProvider::scope_index (bt, ds));
|
const std::string &ds = RubyInterpreter::instance ()->debugger_scope ();
|
||||||
|
bt.erase (bt.begin (), bt.begin () + RubyStackTraceProvider::scope_index (bt, ds));
|
||||||
|
}
|
||||||
|
|
||||||
// parse the backtrace to get the line number
|
// parse the backtrace to get the line number
|
||||||
tl::BacktraceElement info;
|
tl::BacktraceElement info;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@
|
||||||
namespace tl
|
namespace tl
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// The global enable counter (<0: disable)
|
||||||
|
static int s_global_enable = 0;
|
||||||
|
|
||||||
// The maximum allowed processing time in seconds
|
// The maximum allowed processing time in seconds
|
||||||
const double processing_time = 0.02;
|
const double processing_time = 0.02;
|
||||||
|
|
||||||
|
|
@ -47,6 +50,16 @@ FileSystemWatcher::FileSystemWatcher (QObject *parent)
|
||||||
m_batch_size = 1000;
|
m_batch_size = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FileSystemWatcher::global_enable (bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
++s_global_enable;
|
||||||
|
} else {
|
||||||
|
--s_global_enable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FileSystemWatcher::enable (bool en)
|
FileSystemWatcher::enable (bool en)
|
||||||
{
|
{
|
||||||
|
|
@ -120,6 +133,10 @@ FileSystemWatcher::remove_file (const std::string &path)
|
||||||
void
|
void
|
||||||
FileSystemWatcher::timeout ()
|
FileSystemWatcher::timeout ()
|
||||||
{
|
{
|
||||||
|
if (s_global_enable < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tl::Clock start = tl::Clock::current ();
|
tl::Clock start = tl::Clock::current ();
|
||||||
|
|
||||||
if (m_iter == m_files.end ()) {
|
if (m_iter == m_files.end ()) {
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,11 @@ public:
|
||||||
*/
|
*/
|
||||||
FileSystemWatcher (QObject *parent = 0);
|
FileSystemWatcher (QObject *parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Global enable/disable
|
||||||
|
*/
|
||||||
|
static void global_enable (bool en);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables or disables the file watcher
|
* @brief Enables or disables the file watcher
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -113,8 +113,13 @@ class DBEdgePairs_TestClass < TestBase
|
||||||
r2.insert(RBA::Edge::new(1, 1, 1, 101), RBA::Edge::new(-11, 1, -21, 51))
|
r2.insert(RBA::Edge::new(1, 1, 1, 101), RBA::Edge::new(-11, 1, -21, 51))
|
||||||
|
|
||||||
assert_equal(csort((r1 + r2).to_s), csort("(0,0;0,100)/(-10,0;-20,50);(0,1;0,101)/(-10,1;-20,51);(1,0;1,100)/(-11,0;-21,50);(1,1;1,101)/(-11,1;-21,51)"))
|
assert_equal(csort((r1 + r2).to_s), csort("(0,0;0,100)/(-10,0;-20,50);(0,1;0,101)/(-10,1;-20,51);(1,0;1,100)/(-11,0;-21,50);(1,1;1,101)/(-11,1;-21,51)"))
|
||||||
r1 += r2
|
assert_equal(csort((r1.join(r2)).to_s), csort("(0,0;0,100)/(-10,0;-20,50);(0,1;0,101)/(-10,1;-20,51);(1,0;1,100)/(-11,0;-21,50);(1,1;1,101)/(-11,1;-21,51)"))
|
||||||
assert_equal(csort(r1.to_s), csort("(0,0;0,100)/(-10,0;-20,50);(0,1;0,101)/(-10,1;-20,51);(1,0;1,100)/(-11,0;-21,50);(1,1;1,101)/(-11,1;-21,51)"))
|
rr1 = r1.dup
|
||||||
|
rr1 += r2
|
||||||
|
assert_equal(csort(rr1.to_s), csort("(0,0;0,100)/(-10,0;-20,50);(0,1;0,101)/(-10,1;-20,51);(1,0;1,100)/(-11,0;-21,50);(1,1;1,101)/(-11,1;-21,51)"))
|
||||||
|
rr1 = r1.dup
|
||||||
|
rr1.join_with(r2)
|
||||||
|
assert_equal(csort(rr1.to_s), csort("(0,0;0,100)/(-10,0;-20,50);(0,1;0,101)/(-10,1;-20,51);(1,0;1,100)/(-11,0;-21,50);(1,1;1,101)/(-11,1;-21,51)"))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,8 @@ class DBEdges_TestClass < TestBase
|
||||||
|
|
||||||
r = r1 + r2
|
r = r1 + r2
|
||||||
assert_equal(csort(r.to_s), csort("(0,0;100,0);(50,0;200,0)"))
|
assert_equal(csort(r.to_s), csort("(0,0;100,0);(50,0;200,0)"))
|
||||||
|
r = r1.join(r2)
|
||||||
|
assert_equal(csort(r.to_s), csort("(0,0;100,0);(50,0;200,0)"))
|
||||||
assert_equal(r.merged.to_s, "(0,0;200,0)")
|
assert_equal(r.merged.to_s, "(0,0;200,0)")
|
||||||
r.merge
|
r.merge
|
||||||
assert_equal(r.is_merged?, true)
|
assert_equal(r.is_merged?, true)
|
||||||
|
|
@ -322,9 +324,14 @@ class DBEdges_TestClass < TestBase
|
||||||
r = r1.dup
|
r = r1.dup
|
||||||
r += r2
|
r += r2
|
||||||
assert_equal(csort(r.to_s), csort("(0,0;100,0);(50,0;200,0)"))
|
assert_equal(csort(r.to_s), csort("(0,0;100,0);(50,0;200,0)"))
|
||||||
|
r = r1.dup
|
||||||
|
r.join_with(r2)
|
||||||
|
assert_equal(csort(r.to_s), csort("(0,0;100,0);(50,0;200,0)"))
|
||||||
|
|
||||||
r = r1 | r2
|
r = r1 | r2
|
||||||
assert_equal(r.to_s, "(0,0;200,0)")
|
assert_equal(r.to_s, "(0,0;200,0)")
|
||||||
|
r = r1.or(r2)
|
||||||
|
assert_equal(r.to_s, "(0,0;200,0)")
|
||||||
assert_equal(r.merged.to_s, "(0,0;200,0)")
|
assert_equal(r.merged.to_s, "(0,0;200,0)")
|
||||||
r.merge
|
r.merge
|
||||||
assert_equal(r.is_merged?, true)
|
assert_equal(r.is_merged?, true)
|
||||||
|
|
@ -332,9 +339,14 @@ class DBEdges_TestClass < TestBase
|
||||||
r = r1.dup
|
r = r1.dup
|
||||||
r |= r2
|
r |= r2
|
||||||
assert_equal(r.to_s, "(0,0;200,0)")
|
assert_equal(r.to_s, "(0,0;200,0)")
|
||||||
|
r = r1.dup
|
||||||
|
r.or_with(r2)
|
||||||
|
assert_equal(r.to_s, "(0,0;200,0)")
|
||||||
|
|
||||||
r = r1 & r2
|
r = r1 & r2
|
||||||
assert_equal(r.to_s, "(50,0;100,0)")
|
assert_equal(r.to_s, "(50,0;100,0)")
|
||||||
|
r = r1.and(r2)
|
||||||
|
assert_equal(r.to_s, "(50,0;100,0)")
|
||||||
assert_equal(r.is_merged?, true)
|
assert_equal(r.is_merged?, true)
|
||||||
r = r1.andnot(r2)[0]
|
r = r1.andnot(r2)[0]
|
||||||
assert_equal(r.to_s, "(50,0;100,0)")
|
assert_equal(r.to_s, "(50,0;100,0)")
|
||||||
|
|
@ -342,9 +354,14 @@ class DBEdges_TestClass < TestBase
|
||||||
r = r1.dup
|
r = r1.dup
|
||||||
r &= r2
|
r &= r2
|
||||||
assert_equal(r.to_s, "(50,0;100,0)")
|
assert_equal(r.to_s, "(50,0;100,0)")
|
||||||
|
r = r1.dup
|
||||||
|
r.and_with(r2)
|
||||||
|
assert_equal(r.to_s, "(50,0;100,0)")
|
||||||
|
|
||||||
r = r1 - r2
|
r = r1 - r2
|
||||||
assert_equal(r.to_s, "(0,0;50,0)")
|
assert_equal(r.to_s, "(0,0;50,0)")
|
||||||
|
r = r1.not(r2)
|
||||||
|
assert_equal(r.to_s, "(0,0;50,0)")
|
||||||
assert_equal(r.is_merged?, true)
|
assert_equal(r.is_merged?, true)
|
||||||
r = r1.andnot(r2)[1]
|
r = r1.andnot(r2)[1]
|
||||||
assert_equal(r.to_s, "(0,0;50,0)")
|
assert_equal(r.to_s, "(0,0;50,0)")
|
||||||
|
|
@ -352,13 +369,21 @@ class DBEdges_TestClass < TestBase
|
||||||
r = r1.dup
|
r = r1.dup
|
||||||
r -= r2
|
r -= r2
|
||||||
assert_equal(r.to_s, "(0,0;50,0)")
|
assert_equal(r.to_s, "(0,0;50,0)")
|
||||||
|
r = r1.dup
|
||||||
|
r.not_with(r2)
|
||||||
|
assert_equal(r.to_s, "(0,0;50,0)")
|
||||||
|
|
||||||
r = r1 ^ r2
|
r = r1 ^ r2
|
||||||
assert_equal(csort(r.to_s), csort("(0,0;50,0);(100,0;200,0)"))
|
assert_equal(csort(r.to_s), csort("(0,0;50,0);(100,0;200,0)"))
|
||||||
|
r = r1.xor(r2)
|
||||||
|
assert_equal(csort(r.to_s), csort("(0,0;50,0);(100,0;200,0)"))
|
||||||
assert_equal(r.is_merged?, true)
|
assert_equal(r.is_merged?, true)
|
||||||
r = r1.dup
|
r = r1.dup
|
||||||
r ^= r2
|
r ^= r2
|
||||||
assert_equal(csort(r.to_s), csort("(0,0;50,0);(100,0;200,0)"))
|
assert_equal(csort(r.to_s), csort("(0,0;50,0);(100,0;200,0)"))
|
||||||
|
r = r1.dup
|
||||||
|
r.xor_with(r2)
|
||||||
|
assert_equal(csort(r.to_s), csort("(0,0;50,0);(100,0;200,0)"))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,34 +274,54 @@ class DBRegion_TestClass < TestBase
|
||||||
r2 = RBA::Region::new(RBA::Box::new(-10, -20, 80, 160))
|
r2 = RBA::Region::new(RBA::Box::new(-10, -20, 80, 160))
|
||||||
|
|
||||||
assert_equal((r1 & r2).to_s, "(10,20;10,160;80,160;80,20)")
|
assert_equal((r1 & r2).to_s, "(10,20;10,160;80,160;80,20)")
|
||||||
|
assert_equal((r1.and(r2)).to_s, "(10,20;10,160;80,160;80,20)")
|
||||||
assert_equal(r1.andnot(r2).count, 2)
|
assert_equal(r1.andnot(r2).count, 2)
|
||||||
assert_equal(r1.andnot(r2)[0].to_s, "(10,20;10,160;80,160;80,20)")
|
assert_equal(r1.andnot(r2)[0].to_s, "(10,20;10,160;80,160;80,20)")
|
||||||
rr = r1.dup
|
rr = r1.dup
|
||||||
rr &= r2
|
rr &= r2
|
||||||
assert_equal(rr.to_s, "(10,20;10,160;80,160;80,20)")
|
assert_equal(rr.to_s, "(10,20;10,160;80,160;80,20)")
|
||||||
|
rr = r1.dup
|
||||||
|
rr.and_with(r2)
|
||||||
|
assert_equal(rr.to_s, "(10,20;10,160;80,160;80,20)")
|
||||||
|
|
||||||
assert_equal((r1 - r2).to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
assert_equal((r1 - r2).to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
||||||
|
assert_equal((r1.not(r2)).to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
||||||
assert_equal(r1.andnot(r2)[1].to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
assert_equal(r1.andnot(r2)[1].to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
||||||
rr = r1.dup
|
rr = r1.dup
|
||||||
rr -= r2
|
rr -= r2
|
||||||
assert_equal(rr.to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
assert_equal(rr.to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
||||||
|
rr = r1.dup
|
||||||
|
rr.not_with(r2)
|
||||||
|
assert_equal(rr.to_s, "(80,20;80,160;10,160;10,200;100,200;100,20)")
|
||||||
|
|
||||||
assert_equal((r1 ^ r2).to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20/10,20;80,20;80,160;10,160)")
|
assert_equal((r1 ^ r2).to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20/10,20;80,20;80,160;10,160)")
|
||||||
|
assert_equal((r1.xor(r2)).to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20/10,20;80,20;80,160;10,160)")
|
||||||
r1.min_coherence = true
|
r1.min_coherence = true
|
||||||
assert_equal(csort((r1 ^ r2).to_s), csort("(-10,-20;-10,160;10,160;10,20;80,20;80,-20);(80,20;80,160;10,160;10,200;100,200;100,20)"))
|
assert_equal(csort((r1 ^ r2).to_s), csort("(-10,-20;-10,160;10,160;10,20;80,20;80,-20);(80,20;80,160;10,160;10,200;100,200;100,20)"))
|
||||||
rr = r1.dup
|
rr = r1.dup
|
||||||
rr ^= r2
|
rr ^= r2
|
||||||
assert_equal(csort(rr.to_s), csort("(-10,-20;-10,160;10,160;10,20;80,20;80,-20);(80,20;80,160;10,160;10,200;100,200;100,20)"))
|
assert_equal(csort(rr.to_s), csort("(-10,-20;-10,160;10,160;10,20;80,20;80,-20);(80,20;80,160;10,160;10,200;100,200;100,20)"))
|
||||||
|
rr = r1.dup
|
||||||
|
rr.xor_with(r2)
|
||||||
|
assert_equal(csort(rr.to_s), csort("(-10,-20;-10,160;10,160;10,20;80,20;80,-20);(80,20;80,160;10,160;10,200;100,200;100,20)"))
|
||||||
|
|
||||||
assert_equal(csort((r1 + r2).to_s), csort("(10,20;10,200;100,200;100,20);(-10,-20;-10,160;80,160;80,-20)"))
|
assert_equal(csort((r1 + r2).to_s), csort("(10,20;10,200;100,200;100,20);(-10,-20;-10,160;80,160;80,-20)"))
|
||||||
|
assert_equal(csort((r1.join(r2)).to_s), csort("(10,20;10,200;100,200;100,20);(-10,-20;-10,160;80,160;80,-20)"))
|
||||||
rr = r1.dup
|
rr = r1.dup
|
||||||
rr += r2
|
rr += r2
|
||||||
assert_equal(csort(rr.to_s), csort("(10,20;10,200;100,200;100,20);(-10,-20;-10,160;80,160;80,-20)"))
|
assert_equal(csort(rr.to_s), csort("(10,20;10,200;100,200;100,20);(-10,-20;-10,160;80,160;80,-20)"))
|
||||||
|
rr = r1.dup
|
||||||
|
rr.join_with(r2)
|
||||||
|
assert_equal(csort(rr.to_s), csort("(10,20;10,200;100,200;100,20);(-10,-20;-10,160;80,160;80,-20)"))
|
||||||
|
|
||||||
assert_equal((r1 | r2).to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20)")
|
assert_equal((r1 | r2).to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20)")
|
||||||
|
assert_equal((r1.or(r2)).to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20)")
|
||||||
rr = r1.dup
|
rr = r1.dup
|
||||||
rr |= r2
|
rr |= r2
|
||||||
assert_equal(rr.to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20)")
|
assert_equal(rr.to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20)")
|
||||||
|
rr = r1.dup
|
||||||
|
rr.or_with(r2)
|
||||||
|
assert_equal(rr.to_s, "(-10,-20;-10,160;10,160;10,200;100,200;100,20;80,20;80,-20)")
|
||||||
|
|
||||||
assert_equal((r1 + r2).sized(10).to_s, "(-20,-30;-20,170;0,170;0,210;110,210;110,10;90,10;90,-30)")
|
assert_equal((r1 + r2).sized(10).to_s, "(-20,-30;-20,170;0,170;0,210;110,210;110,10;90,10;90,-30)")
|
||||||
rr = (r1 | r2).dup
|
rr = (r1 | r2).dup
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,12 @@ class DBTexts_TestClass < TestBase
|
||||||
r1.insert(RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(111, 211))))
|
r1.insert(RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(111, 211))))
|
||||||
|
|
||||||
assert_equal(csort((r1 + r2).to_s), csort("('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)"))
|
assert_equal(csort((r1 + r2).to_s), csort("('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)"))
|
||||||
r1 += r2
|
assert_equal(csort((r1.join(r2)).to_s), csort("('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)"))
|
||||||
|
rr1 = r1.dup
|
||||||
|
rr1 += r2
|
||||||
|
assert_equal(csort(r1.to_s), csort("('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)"))
|
||||||
|
rr1 = r1.dup
|
||||||
|
rr1.join_with(r2)
|
||||||
assert_equal(csort(r1.to_s), csort("('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)"))
|
assert_equal(csort(r1.to_s), csort("('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)"))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue