def _check_recording_started(self): """Ensure command is in the recording phase""" assert not self._recording_finished if self._recording_started: return # Cache the layer being painted to. This is accessed frequently # during the painting phase. model = self.doc layer = model.layer_stack.deepget(self._layer_path) assert layer is not None, \ "Layer with path %r not available" % (self._layer_path,) if not layer.get_paintable(): logger.warning( "Brushwork: skipped non-paintable layer %r", layer, ) return self._stroke_target_layer = layer assert self._sshot_before is None assert self._time_before is None assert self._stroke_seq is None self._sshot_before = layer.save_snapshot() self._time_before = model.unsaved_painting_time self._stroke_seq = lib.stroke.Stroke() self._stroke_seq.start_recording(model.brush) assert self._sshot_after is None self._recording_started = True
def update_cursor(self): # Callback for updating the cursor if not self.get_mapped(): return window = self.get_window() app = self.app if window is None: logger.error("update_cursor: no window") return override_cursor = self._override_cursor layer = self.doc._layers.current if override_cursor is not None: c = override_cursor elif self.get_state() == gtk.STATE_INSENSITIVE: c = None elif self.doc is None: logger.error("update_cursor: no document") return elif layer.locked or not layer.visible or not layer.get_paintable(): # Cursor to represent that one cannot draw. # Often a red circle with a diagonal bar through it. c = gdk.Cursor(gdk.CIRCLE) elif app is None: logger.error("update_cursor: no app") return # Last two cases only pertain to FreehandMode cursors. # XXX refactor: bad for separation of responsibilities, put the # special cases in the mode class. elif app.preferences.get("cursor.freehand.style", None) == 'crosshair': c = app.cursors.get_freehand_cursor() else: radius, style = self._get_cursor_info() c = cursor.get_brush_cursor(radius, style, self.app.preferences) window.set_cursor(c)
def stroke_to(self, dtime, x, y, pressure, xtilt, ytilt): """Painting: forward a stroke position update to the model :param float dtime: Seconds since the last call to this method :param float x: Document X position update :param float y: Document Y position update :param float pressure: Pressure, ranging from 0.0 to 1.0 :param float xtilt: X-axis tilt, ranging from -1.0 to 1.0 :param float ytilt: Y-axis tilt, ranging from -1.0 to 1.0 Stroke data is recorded at this level, but strokes are not autosplit here because that would involve the creation of a new Brushwork command on the CommandStack. Instead, callers should check `split_due` and split appropriately. An example of a GUI mode which does just this can be found in the complete MyPaint distribution in gui/. """ # Model and layer being painted on. Called frequently during the # painting phase, so use a cache to avoid excessive layers tree # climbing. model = self.doc if self._layer_ref is None: layer = model.layer_stack.deepget(self._layer_path) if not layer.get_paintable(): logger.debug("Skipped non-paintable layer %r", layer) return self._layer_ref = weakref.ref(layer) else: layer = self._layer_ref() if layer is None: logger.error("Layer was deleted while painting was in " "progress: undo stack is probably broken now") self.split_due = True return if not self._stroke_seq: self._stroke_seq = lib.stroke.Stroke() self._time_before = model.unsaved_painting_time self._sshot_before = layer.save_snapshot() self._stroke_seq.start_recording(model.brush) brush = model.brush self._stroke_seq.record_event(dtime, x, y, pressure, xtilt, ytilt) self.split_due = layer.stroke_to(brush, x, y, pressure, xtilt, ytilt, dtime) self._last_pos = (x, y, xtilt, ytilt)