def Transform(self, trafo, transform_properties = 1): undostyle = undo = NullUndo try: rect = self.bounding_rect undo = RectangularObject.Transform(self, trafo) if transform_properties: rects = (rect, self.bounding_rect) undostyle = Primitive.Transform(self, trafo, rects = rects) return CreateMultiUndo(undostyle, undo) except: Undo(undo) Undo(undostyle) raise
def RemoveObjects(self, infolist): if not infolist: return NullUndo sliced = selinfo.list_to_tree_sliced(infolist) sliced.reverse() undo = [self.begin_change_children()] try: for start, end in sliced: if type(end) == IntType: # > 1 adjacent children of self. XXX implement this raise SketchInternalError('Deletion of multiple objects' ' of BlendGroups not yet' ' implemented') elif type(end) == ListType: # remove grandchildren (children of child of self) if start % 2 == 0: # control object changes. This should result in # a recompute() automatically. undo.append(self.objects[start].RemoveObjects(end)) else: pass else: # a single child. If it's one of our control # objects, remove self undo.append(self.do_remove_child(start)) undo.append(self.end_change_children()) return CreateListUndo(undo) except: Undo(CreateListUndo(undo)) raise
def DuplicateObjects(self, infolist, offset): infolist = list_to_tree2(infolist) objects = self.objects undo = [self.begin_change_children()] selection = [] added = 0 try: for idx, obj in infolist: idx = idx + added if type(obj) == ListType: # duplicate in subobj sel, undoinfo = objects[idx].DuplicateObjects(obj, offset) undo.append(undoinfo) selection = selection + prepend_idx(idx, sel) else: obj = obj.Duplicate() obj.Translate(offset) sel, undoinfo = self.Insert(obj, idx + 1) undo.append(undoinfo) selection.append(sel) added = added + 1 undo.append(self.end_change_children()) return (selection, CreateListUndo(undo)) except: Undo(CreateListUndo(undo)) raise
def do_remove_child(self, idx): undo = [] try: if idx % 2 == 0: # a control object if self.document is not None: undo.append(self.document.AddClearRect(self.bounding_rect)) if len(self.objects) > 3: if idx == 0: undo.append(self.remove(1)) undo.append(self.remove(0)) elif idx == len(self.objects) - 1: undo.append(self.remove(idx)) undo.append(self.remove(idx - 1)) else: steps = self.objects[idx + 1].Steps() \ + self.objects[idx - 1].Steps() u = (UndoAfter, CreateMultiUndo(self.remove(idx + 1), self.remove(idx)), self.objects[idx - 1].SetParameters(steps)) undo.append(u) else: # remove one of only two control objects -> Remove self undo.append(self.parent.Remove(self)) return CreateListUndo(undo) else: # XXX implement this case raise ValueError, 'BlendGroup: cannot remove non control child' except: Undo(CreateListUndo(undo)) raise
def SetParameters(self, kw): undo = PluginCompound.SetParameters(self, kw) try: self.recompute() except: Undo(undo) raise return undo
def insert(self, obj, at): undo_info = None try: if type(at) != IntType or at > len(self.objects): at = len(self.objects) self.objects.insert(at, obj) obj.SetDocument(self.document) obj.SetParent(self) obj.Connect() undo_info = (self.remove, at) self._changed() return undo_info except: if undo_info is not None: Undo(undo_info) raise
def MoveObjectsUp(self, infolist): sliced = list_to_tree_sliced(infolist) sliced.reverse() undo = [self.begin_change_children()] selection = [] permutation = range(len(self.objects)) objects = self.objects max = len(objects) try: for start, end in sliced: if type(end) == IntType: if end < max: temp = permutation[start:end] del permutation[start:end] permutation[start + 1:start + 1] = temp selection = selection + select_range( start + 1, objects[start:end]) else: selection = selection + select_range( start, objects[start:end]) elif type(end) == ListType: sel, undo_info = objects[start].MoveObjectsUp(end) if undo_info is not NullUndo: undo.append(undo_info) selection = selection + prepend_idx(start, sel) else: if start < max - 1: del permutation[start] permutation.insert(start + 1, start) selection.append(build_info(start + 1, objects[start])) else: selection.append(build_info(start, objects[start])) undo_info = self.permute_objects(permutation) if undo_info is not NullUndo: undo.append(undo_info) undo.append(self.end_change_children()) if len(undo) <= 2: undo = NullUndo selection = infolist else: undo = CreateListUndo(undo) return (selection, undo) except: Undo(CreateListUndo(undo)) raise
def RemoveObjects(self, infolist): if not infolist: return NullUndo sliced = list_to_tree_sliced(infolist) sliced.reverse() # important! undo = [self.begin_change_children()] try: for start, end in sliced: if type(end) == IntType: undo.append(self.RemoveSlice(start, end)) elif type(end) == ListType: undo.append(self.objects[start].RemoveObjects(end)) else: undo.append(self.Remove(end, start)) undo.append(self.end_change_children()) return CreateListUndo(undo) except: Undo(CreateListUndo(undo)) raise
def undo_changes(self): Undo(CreateListUndo(self.undo))
def move_objects_to_top(self, infolist, to_bottom=0): # Implement the public methods MoveToTop (if to_bottom is false) # and MoveToBottom (if to_bottom is true). sliced = list_to_tree_sliced(infolist) sliced.reverse() undo = [self.begin_change_children()] selection = [] idxs = [] permutation = range(len(self.objects)) try: for start, end in sliced: if type(end) == IntType: # a contiguous range of self's children (start:end) idxs[:0] = permutation[start:end] del permutation[start:end] elif type(end) == ListType: # children of self.objects[start] child = self.objects[start] sel, undo_info = child.move_objects_to_top(end, to_bottom) if undo_info is not NullUndo: undo.append(undo_info) selection = selection + prepend_idx(start, sel) else: # a single object (self.object[start]) idxs.insert(0, start) del permutation[start] if idxs: # direct children of self are involved: apply the # permutation if to_bottom: permutation = idxs + permutation else: permutation = permutation + idxs undo_info = self.permute_objects(permutation) if undo_info is not NullUndo: undo.append(undo_info) # finished: undo.append(self.end_change_children()) if len(undo) <= 2: # We haven't really done anything (undo has length 2), # so we just pass the selection info back unchanged selection = infolist undo = NullUndo else: # We have done something, so figure out the new # selection info undo = CreateListUndo(undo) if to_bottom: selection = selection \ + select_range(0, self.objects[:len(idxs)]) else: min = len(self.objects) - len(idxs) selection = selection \ + select_range(min, self.objects[min:]) return (selection, undo) except: # Ooops, something's gone wrong. Undo everything we've done # so far... (hmm, this currently fails to undo everything if # undo.append(undo_info) fails... (the undo_info involved # would be lost)) Undo(CreateListUndo(undo)) raise
def Insert(self, obj, at): # Insert OBJ into the object hierarchy at the position described # by AT. AT should be either an integer or a tuple of integers. # OBJ can be a graphics object of a list of such objects. # # If AT is a tuple of 2 or more ints, self's child at AT[0] has # to be a compound object and its Insert method is called with # OBJ and AT[1:] as arguments. # # If AT is an int or a singleton of one int, insert OBJ at that # position in self's children. If OBJ is a graphics object, this # works just like a list objects insert method (insert(AT, # OBJ)). If its a list of graphics objects this method # effectively assigns that list to the slice AT:AT. # # As a side effect, this method calls the following methods of # the inserted objects: # # obj.SetDocument(self.document) # obj.SetParent(self) # obj.Connect() # # Return a tuple (SELINFO, UNDO), where SELINFO is selection # info for the inserted objects at their new positions, and UNDO # is the appropriate undo info. # # If self is modified directly, issue a CHANGED message. undo_info = None try: if type(at) == TupleType and at: if len(at) == 1: at = at[0] else: child = at[0] at = at[1:] sel_info, undo_info = self.objects[child].Insert(obj, at) sel_info = prepend_idx(child, sel_info) return (sel_info, undo_info) if type(at) != IntType or at > len(self.objects): at = len(self.objects) if type(obj) == InstanceType: self.objects.insert(at, obj) obj.SetDocument(self.document) obj.SetParent(self) obj.Connect() sel_info = build_info(at, obj) undo_info = (self.Remove, obj, at) else: self.objects[at:at] = obj for o in obj: # XXX: should we have undo info for these: o.SetDocument(self.document) o.SetParent(self) o.Connect() sel_info = select_range(at, obj) undo_info = (self.RemoveSlice, at, at + len(obj)) self._changed() return (sel_info, undo_info) except: if undo_info is not None: Undo(undo_info) raise
def _after_handler(undo, list): list[0] = Undo(undo)