Flatten and Propagate
false
false
true
macros_menu.examples>end("Examples").end
ruby
# @title Editing: hierarchical propagation
#
# This application provides two new toolbar entries bound to keys F7 and F8. The first function brings up
# all selected shapes and instances to the current cell level and removes them from their original cell. This
# makes sense only if the selection contains objects from subcells (hence not in "top level only" selection
# mode).
# The second function brings up such objects one level in hierarchy.
# Both functions just bring up objects along the selection path, not into all instances of the selected
# cell. They are very similar to the "Move up in hierarchy" function in the "Edit/Selection" menu.
#
# The new functions can only be used in "Edit" mode and require version 0.16 or later.
#
# This code demonstrates in particular:
# <ul>
# <li>How to use the selection set of objects</li>
# <li>How to modify geometrical objects (transform, erase, copy)</li>
# <li>How to implement undo/redo support, which is pretty simple using the LayoutView's "transaction" and "commit" methods</li>
# </ul>
module Examples
# HINT: this simple implementation does not account
# for variant building - the shapes and instances are simply taken
# out from the original shapes and therefore might disappear somewhere else.
@f7_handler = RBA::Action.new
@f7_handler.title = "Flatten"
@f7_handler.shortcut = "F7"
@f7_handler.on_triggered do
app = RBA::Application.instance
mw = app.main_window
lv = mw.current_view
if lv == nil
raise "Flatten: No view selected"
end
# start transaction for "undo"
lv.transaction("Flatten")
begin
# because objects might be referenced multiple times (thru different hierarchy paths)
# we must first copy and then delete them
# copy & transform them
lv.each_object_selected do |sel|
cv = lv.cellview(sel.cv_index)
target = cv.cell
# only if not flat already ..
if target.cell_index != sel.cell_index
source = cv.layout.cell(sel.cell_index)
if sel.is_cell_inst?
# copy and transform
new_inst = target.insert(sel.inst)
target.transform(new_inst, sel.source_trans)
else
# copy and transform
target_shapes = target.shapes(sel.layer)
new_shape = target_shapes.insert(sel.shape)
target_shapes.transform(new_shape, sel.source_trans)
end
end
end
# delete the objects
# HINT: since it is possible that a certain object is used multiple times, we need to test
# each reference, if it is still valid (i.e. the object has not been deleted yet).
lv.each_object_selected do |sel|
cv = lv.cellview(sel.cv_index)
target = cv.cell
# only if not flat already ..
if target.cell_index != sel.cell_index
source = cv.layout.cell(sel.cell_index)
if sel.is_cell_inst?
if source.is_valid?(sel.inst)
source.erase(sel.inst)
end
else
if source.shapes(sel.layer).is_valid?(sel.shape)
source.shapes(sel.layer).erase(sel.shape)
end
end
end
end
ensure
# always execute that code:
# commit transaction
lv.commit
# clear selection and cancel all other edit operations, so
# nothing refers to shapes that might have been deleted.
lv.cancel
end
end
# HINT: this simple implementation does not account
# for variant building - the shapes and instances are simply taken
# out from the original shapes and therefore might disappear somewhere else.
@f8_handler = RBA::Action.new
@f8_handler.title = "Propagate"
@f8_handler.shortcut = "F8"
@f8_handler.on_triggered do
app = RBA::Application.instance
mw = app.main_window
lv = mw.current_view
if lv == nil
raise "Propagate: No view selected"
end
# start transaction for "undo"
lv.transaction("Propagate")
begin
# because objects might be referenced multiple times (thru different hierarchy paths)
# we must first copy and then delete them
# copy & transform them
lv.each_object_selected do |sel|
cv = lv.cellview(sel.cv_index)
# only if not flat already ..
if cv.cell_index != sel.cell_index
source = cv.layout.cell(sel.cell_index)
if sel.is_cell_inst?
# copy and transform
if sel.path_length <= 2
target = cv.cell
else
target = cv.layout.cell(sel.path_nth(sel.path_length - 3).cell_inst.cell_index)
end
new_inst = target.insert(sel.inst)
target.transform(new_inst, sel.path_nth(sel.path_length - 2).specific_cplx_trans)
else
# copy and transform
if sel.path_length <= 1
target = cv.cell
else
target = cv.layout.cell(sel.path_nth(sel.path_length - 2).cell_inst.cell_index)
end
target_shapes = target.shapes(sel.layer)
new_shape = target_shapes.insert(sel.shape)
target_shapes.transform(new_shape, sel.path_nth(sel.path_length - 1).specific_cplx_trans)
end
end
end
# delete the objects
# HINT: since it is possible that a certain object is used multiple times, we need to test
# each reference, if it is still valid (i.e. the object has not been deleted yet).
lv.each_object_selected do |sel|
cv = lv.cellview(sel.cv_index)
target = cv.cell
# only if not flat already ..
if target.cell_index != sel.cell_index
source = cv.layout.cell(sel.cell_index)
if sel.is_cell_inst?
if source.is_valid?(sel.inst)
source.erase(sel.inst)
end
else
if source.shapes(sel.layer).is_valid?(sel.shape)
source.shapes(sel.layer).erase(sel.shape)
end
end
end
end
ensure
# always execute that code:
# commit transaction
lv.commit
# clear selection and cancel all other edit operations, so
# nothing refers to shapes that might have been deleted.
lv.cancel
end
end
app = RBA::Application.instance
mw = app.main_window
menu = mw.menu
menu.insert_separator("@toolbar.end", "name")
menu.insert_item("@toolbar.end", "rba_flatten", @f7_handler)
menu.insert_item("@toolbar.end", "rba_propagate", @f8_handler)
end