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