def _get_target_area_geometry(screen, mon_num): """Get a rect for putting windows in: normally based on monitor. :param Gdk.Screen screen: Target screen. :param int mon_num: Monitor number, e.g. that of the pointer. :returns: A hopefully usable target area. :rtype: lib.helpers.Rect This function operates like gdk_screen_get_monitor_geometry(), but falls back to the screen geometry for cases when that returns NULL. It also returns a type which has (around GTK 3.18.x) fewer weird typelib issues with construction or use. Ref: https://github.com/mypaint/mypaint/issues/424 Ref: https://github.com/mypaint/mypaint/issues/437 """ geom = None if mon_num >= 0: geom = screen.get_monitor_geometry(mon_num) if geom is not None: geom = Rect.new_from_gdk_rectangle(geom) else: logger.warning("gdk_screen_get_monitor_geometry() returned NULL: " "using screen size instead as a fallback.") geom = Rect(0, 0, screen.get_width(), screen.get_height()) return geom
def tdw_allocation(self): if not self._alloc: self._alloc = Rect.new_from_gdk_rectangle( self.tdw.get_allocation()) return self._alloc
def _recalculate_coordinates(self, redraw, *args): """Calculates geometric data that does not need updating every time""" # Skip calculations when the frame is not enabled (this is important # because otherwise all of this would be recalculated on moving, # scaling and rotating the canvas. if not (self.doc.model.frame_enabled or redraw): return tdw = self.doc.tdw # Canvas rectangle - regular and offset self._canvas_rect = Rect.new_from_gdk_rectangle(tdw.get_allocation()) self._canvas_rect_offset = self._canvas_rect.expanded( self.OUTLINE_WIDTH * 4) # Frame corners in model coordinates x, y, w, h = tuple(self.doc.model.get_frame()) corners = [(x, y), (x + w, y), (x + w, y + h), (x, y + h)] # Pixel-aligned frame corners in display space d_corners = [tdw.model_to_display(mx, my) for mx, my in corners] pxoffs = 0.5 if (self.OUTLINE_WIDTH % 2) else 0.0 self._prev_display_corners = self._display_corners self._display_corners = tuple( (int(x) + pxoffs, int(y) + pxoffs) for x, y in d_corners) # Position of the button for disabling/deleting the frame # Placed near the center of the frame, clamped to the viewport, # with an offset so it does not cover visually small frames # (when the frame _is_ small, or when zoomed out). xs, ys = zip(*d_corners) r = gui.style.FLOATING_BUTTON_RADIUS tx, ty = self._canvas_rect.expanded(-2 * r).clamped_point( sum(xs) / 4.0, sum(ys) / 4.0) self._trash_btn_pos = tx, ty r += 6 # margin for drop shadows self._prev_disable_button_rectangle = self._disable_button_rectangle self._disable_button_rectangle = (tx - r, ty - r, r * 2, r * 2) # Corners self._zone_corners = [] radius = gui.style.DRAGGABLE_POINT_HANDLE_SIZE canvas_limit = self._canvas_rect.expanded(radius) for i, (cx, cy) in enumerate(d_corners): if canvas_limit.contains_pixel(cx, cy): self._zone_corners.append((cx, cy, self._ZONE_EDGES[i])) # Intersecting frame lines & calculation of rectangles l_type = LineType.SEGMENT cx, cy, cw, ch = self._canvas_rect canvas_corners = ((cx, cy), (cx + cw, cy), (cx + cw, cy + ch), (cx, cy + ch)) intersections = [ intersection_of_vector_and_poly(canvas_corners, p1, p2, l_type) for p1, p2 in pairwise(d_corners) ] self._prev_rectangles = self._new_rectangles self._new_rectangles = [(), (), (), ()] if intersections != [None, None, None, None]: self._new_rectangles = [] m = radius + 6 # margin for handle drop shadows for intersection in intersections: if not intersection: self._new_rectangles.append(()) continue (x0, y0), (x1, y1) = intersection w = abs(x1 - x0) + 2 * m h = abs(y1 - y0) + 2 * m x = min(x0, x1) - m y = min(y0, y1) - m self._new_rectangles.append(Rect(x, y, w, h)) if redraw: self.redraw()