Пример #1
0
 def create_item(self,
                 component,
                 coords=(),
                 item=None,
                 canvas=None,
                 silently=False,
                 **kwargs):
     canvas = canvas or self.canvas
     if item is None:
         opts = dict(**component.defaults)
         opts.update(kwargs)
         item = component(canvas, *coords, **opts)
         # generate a unique id
         item.name = self.generator.generate(component, self._ids)
     canvas._cv_items.append(item)
     item._prev_index = canvas._cv_items.index(item)
     node = canvas._cv_tree.add_as_node(item=item)
     item.bind("<ButtonRelease-1>", lambda e: self._handle_select(item, e),
               True)
     item.bind("<ButtonRelease-1>", lambda e: self._handle_end(item, e),
               True)
     item.bind("<Motion>", lambda e: self._handle_move(item, e), True)
     MenuUtils.bind_context(item, self._show_item_menu(item))
     MenuUtils.bind_all_context(node, self._show_item_menu(item))
     if not silently:
         self.studio.new_action(
             Action(lambda _: self.remove_items([item], silently=True),
                    lambda _: self.restore_items([item])))
     return item
Пример #2
0
 def on_layout_change(self):
     prev_data = {item: item._coord_restore for item in self.selected_items}
     data = {item: item.coords() for item in self.selected_items}
     for item in self.selected_items:
         item._coord_restore = item.coords()
     self.studio.new_action(
         Action(lambda _: self.restore_layouts(prev_data),
                lambda _: self.restore_layouts(data)))
Пример #3
0
 def paste_items(self, _clipboard=None):
     _clipboard = self._clipboard if _clipboard is None else _clipboard
     if _clipboard:
         items = []
         for item_data in _clipboard:
             item = CanvasItem.from_data(self.canvas, item_data,
                                         self._latch_pos)
             self.create_item(item.__class__, item=item, silently=True)
             items.append(item)
         # slightly displace latch position for next paste
         self._latch_pos = tuple(map(lambda x: x + 5, self._latch_pos))
         self.studio.new_action(
             Action(lambda _: self.remove_items(items, silently=True),
                    lambda _: self.restore_items(items)))
Пример #4
0
 def remove_items(self, items, silently=False):
     if not items:
         return
     # ideally all items will have the same canvas
     canvas = items[0].canvas
     items = sorted(items, key=canvas._cv_items.index)
     self.deselect_items(items)
     for item in items:
         item.hide()
         canvas._cv_items.remove(item)
         item.node.remove()
     if not silently:
         self.studio.new_action(
             Action(lambda _: self.restore_items(items),
                    lambda _: self.remove_items(items, silently=True)))
Пример #5
0
    def create_restore(self, widget):
        prev_restore_point = widget.recent_layout_info
        cur_restore_point = widget.layout.get_restore(widget)
        if prev_restore_point == cur_restore_point:
            return
        prev_container = prev_restore_point["container"]
        container = widget.layout

        def undo(_):
            container.remove_widget(widget)
            prev_container.restore_widget(widget, prev_restore_point)

        def redo(_):
            prev_container.remove_widget(widget)
            container.restore_widget(widget, cur_restore_point)

        self.studio.new_action(Action(undo, redo))
Пример #6
0
    def add(self, obj_class: PseudoWidget.__class__, x, y, **kwargs):
        if obj_class.group != Groups.container and self.root_obj is None:
            # We only need a container as the root widget
            self._show_root_widget_warning()
            return
        silent = kwargs.get("silently", False)
        name = self._get_unique(obj_class)
        obj = obj_class(self, name)
        if hasattr(obj, 'initial_dimensions'):
            width, height = obj.initial_dimensions
        else:
            width = kwargs.get(
                "width",
                self._base_font.measure(name) + self.WIDGET_INIT_PADDING)
            height = kwargs.get("height", self.WIDGET_INIT_HEIGHT)
        obj.layout = kwargs.get("intended_layout", None)
        self._attach(obj)  # apply extra bindings required
        layout = kwargs.get("layout")
        # If the object has a layout which actually the layout at the point of creation prepare and pass it
        # to the layout
        if isinstance(layout, Container):
            bounds = (x, y, x + width, y + height)
            bounds = geometry.resolve_bounds(bounds, self)
            layout.add_widget(obj, bounds)
            self.studio.add(obj, layout)
            restore_point = layout.get_restore(obj)
            # Create an undo redo point if add is not silent
            if not silent:
                self.studio.new_action(
                    Action(
                        # Delete silently to prevent adding the event to the undo/redo stack
                        lambda _: self.delete(obj, True),
                        lambda _: self.restore(obj, restore_point, obj.layout))
                )
        elif obj.layout is None:
            # This only happens when adding the main layout. We dont need to add this action to the undo/redo stack
            # This main layout is attached directly to the designer
            obj.layout = self
            self.layout_strategy.add_widget(obj,
                                            x=x,
                                            y=y,
                                            width=width,
                                            height=height)
            self.studio.add(obj, None)

        return obj
Пример #7
0
 def paste(self, node, silently=False):
     if not self.current_obj:
         return
     layout = self.current_obj if isinstance(self.current_obj, Container) else self.current_obj.layout
     width = int(BaseConverter.get_attr(node, "width", "layout") or 0)
     height = int(BaseConverter.get_attr(node, "height", "layout") or 0)
     x, y = self._last_click_pos or (self.winfo_rootx() + 50, self.winfo_rooty() + 50)
     self._last_click_pos = x + 5, y + 5  # slightly displace click position so multiple pastes are still visible
     bounds = geometry.resolve_bounds((x, y, x + width, y + height), self)
     obj = self.xml.load_section(node, layout, bounds)
     restore_point = layout.get_restore(obj)
     # Create an undo redo point if add is not silent
     if not silently:
         self.studio.new_action(Action(
             # Delete silently to prevent adding the event to the undo/redo stack
             lambda: self.delete(obj, True),
             lambda: self.restore(obj, restore_point, obj.layout)
         ))
     return obj
Пример #8
0
 def delete(self, widget, silently=False):
     if not widget:
         return
     if not silently:
         restore_point = widget.layout.get_restore(widget)
         self.studio.new_action(Action(
             lambda: self.restore(widget, restore_point, widget.layout),
             lambda: self.studio.delete(widget)
         ))
     else:
         self.studio.delete(widget, self)
     widget.layout.remove_widget(widget)
     if widget == self.root_obj:
         # try finding another toplevel widget that can be a root obj otherwise leave it as none
         self.root_obj = None
         for w in self.layout_strategy.children:
             if isinstance(w, Container):
                 self.root_obj = w
                 break
     self._uproot_widget(widget)
Пример #9
0
 def _update_stacking(self, canvas, data=None, silently=False):
     if data:
         canvas._cv_tree.reorder(data)
     else:
         data = {}
     canvas._cv_items.sort(
         key=lambda x: canvas._cv_tree.nodes.index(x.node))
     prev_data = {}
     for index, item in enumerate(canvas._cv_items):
         if item._prev_index != index:
             # old data
             prev_data[item] = item._prev_index
             # new data
             data[item] = index
         item._prev_index = index
         if index > 0:
             item.lift(canvas._cv_items[index - 1]._id)
     if not silently and prev_data != data:
         self.studio.new_action(
             Action(
                 lambda _: self._update_stacking(canvas, prev_data, True),
                 lambda _: self._update_stacking(canvas, data, True)))
Пример #10
0
 def apply(self, prop, value, widget=None, silent=False):
     is_external = widget is not None
     widget = self.widget if widget is None else widget
     if widget is None:
         return
     try:
         prev_val = self._get_prop(prop, widget)
         data = self._get_action_data(widget, prop)
         self._set_prop(prop, value, widget)
         new_data = self._get_action_data(widget, prop)
         self.style_pane.widget_modified(widget)
         if is_external:
             if widget == self.widget:
                 self.items[prop].set_silently(value)
         if silent:
             return
         key = self._get_key(widget, prop)
         action = self.style_pane.last_action()
         if action is None or action.key != key:
             self.style_pane.new_action(
                 Action(
                     lambda _: self._apply_action(prop, prev_val, widget,
                                                  data),
                     lambda _: self._apply_action(prop, value, widget,
                                                  new_data),
                     key=key,
                 ))
         else:
             action.update_redo(lambda _: self._apply_action(
                 prop, value, widget, new_data))
     except Exception as e:
         # Empty string values are too common to be useful in logger debug
         if value != '':
             logging.error(e)
             logging.error(
                 f"Could not set {self.__class__.__name__} {prop} as {value}",
             )
Пример #11
0
 def create_restore(self, widget):
     restore_point = widget.layout.get_restore()
     self.studio.new_action(Action(
         lambda: self.restore(widget, restore_point, widget.layout),
         lambda: self.studio.delete(widget)
     ))