def react(self, event) -> int: # Checks, based on the cursor position whether we can insert before, into or after the node # Returns 0, 1 or 2 respectively # It is mostly with respect to the nodes head element known as the strip except for --- case * --- below self.clear_indicators() # The cursor is at the top edge of the node so we can attempt to insert before it if event.y_root < self.strip.winfo_rooty() + 5: self.tree.edge_indicator.top( upscale_bounds(bounds(self.strip), self)) return self.InsertType.INSERT_BEFORE # The cursor is at the center of the node so we can attempt a direct insert into the node if self.strip.winfo_rooty( ) + 5 < event.y_root < self.strip.winfo_rooty( ) + self.strip.height - 5: if not self._is_terminal: # If node is terminal then id does not support children and consequently insertion self.highlight() return self.InsertType.INSERT_INTO # The cursor is at the bottom edge of the node so we attempt to insert immediately after the node elif self._expanded: # --- Case * --- # If the node is expanded we would want to edge indicate at the very bottom after its last child if event.y_root > self.winfo_rooty() + self.height - 5: self.tree.edge_indicator.bottom(bounds(self)) return self.InsertType.INSERT_AFTER else: self.tree.edge_indicator.bottom( upscale_bounds(bounds(self.strip), self)) return self.InsertType.INSERT_AFTER
def _location_analysis(self, bounds): self.clear_indicators() self._edge_indicator.update_idletasks() bounds = geometry.relative_bounds(bounds, self.container) x, y = bounds[0], bounds[1] col, row = self.container.grid_location(x, y) x, y = geometry.upscale_bounds(bounds, self.container)[:2] slaves = self.container.grid_slaves(max(0, row), max(0, col)) if len(slaves) == 0: self.container.update_idletasks() bbox = self.container.grid_bbox(col, row) bounds = *bbox[:2], bbox[0] + bbox[2], bbox[1] + bbox[3] # Make bounds relative to designer bounds = geometry.upscale_bounds(bounds, self.container) else: bounds = geometry.bounds(slaves[0]) y_offset, x_offset = 10, 10 # 0.15*(bounds[3] - bounds[1]), 0.15*(bounds[2] - bounds[0]) # If the position is empty no need to alter the row or column resize = 1 if len(slaves) else 0 if y - bounds[1] < y_offset: self._edge_indicator.top(bounds) return row, col, resize, 0 elif bounds[3] - y < y_offset: self._edge_indicator.bottom(bounds) return row + resize, col, resize, 0 elif x - bounds[0] < x_offset: self._edge_indicator.left(bounds) return row, col, 0, resize elif bounds[2] - x < x_offset: self._edge_indicator.right(bounds) return row, col + resize, 0, resize else: self._highlighter.highlight_bounds(bounds) return row, col, 0, 0
def layout_at(self, bounds): for container in sorted(filter(lambda x: isinstance(x, Container) and x != self.current_obj, self.objects), key=lambda x: len(self.objects) - x.level): if isinstance(self.current_obj, Container) and self.current_obj.level < container.level: continue if self.compute_overlap(geometry.bounds(container), bounds): return container return None
def initialize(self, former_strategy=None): # create a list of children and their bounds which won't change during iteration bounding_map = [(child, geometry.bounds(child)) for child in self.children] if former_strategy: former_strategy.clear_all() for child, bounds in bounding_map: self.add_widget(child, bounds)
def _stop_displace(self, _): if self._displace_active: # this ensures event is added to undo redo stack self._on_release(geometry.bounds(self.current_obj)) # mark the latest action as designer displace latest = self.studio.last_action() if latest is not None: latest.key = "designer_displace" self._displace_active = False
def displace(self, side): if not self.current_obj: return bounds = geometry.bounds(self.current_obj) x1, y1, x2, y2 = bounds if side == 'right': bounds = x1 + 1, y1, x2 + 1, y2 elif side == 'left': bounds = x1 - 1, y1, x2 - 1, y2 elif side == 'up': bounds = x1, y1 - 1, x2, y2 - 1 elif side == 'down': bounds = x1, y1 + 1, x2, y2 + 1 self._on_move(bounds) self._on_release(bounds)
def displace(self, side): if not self.current_obj: return if time.time() - self._last_displace < .5: self.studio.pop_last_action("designer_displace") self._on_start() self._displace_active = True self._last_displace = time.time() bounds = geometry.bounds(self.current_obj) x1, y1, x2, y2 = bounds if side == 'right': bounds = x1 + 1, y1, x2 + 1, y2 elif side == 'left': bounds = x1 - 1, y1, x2 - 1, y2 elif side == 'up': bounds = x1, y1 - 1, x2, y2 - 1 elif side == 'down': bounds = x1, y1 + 1, x2, y2 + 1 self._on_move(bounds)
def bbox(self, child): # return the canvas bbox if possible else use the normal bound # canvas bbox is more accurate if self._child_map.get(child) is not None: return self._frame.bbox(self._child_map[child]) return geometry.relative_bounds(geometry.bounds(child), self._frame)
def bounds(self): return geometry.bounds(self.container)