Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/gpencil')
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c205
1 files changed, 147 insertions, 58 deletions
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index d42e63bf354..6f5a7910dbc 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -141,17 +141,21 @@ static void gp_session_validatebuffer(tGPsdata *p);
/* check if context is suitable for drawing */
static int gpencil_draw_poll (bContext *C)
{
- if(ED_operator_regionactive(C)) {
+ if (ED_operator_regionactive(C)) {
/* check if current context can support GPencil data */
- if(gpencil_data_get_pointers(C, NULL) != NULL) {
- return 1;
+ if (gpencil_data_get_pointers(C, NULL) != NULL) {
+ /* check if Grease Pencil isn't already running */
+ if ((G.f & G_GREASEPENCIL) == 0)
+ return 1;
+ else
+ CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active");
}
else {
- CTX_wm_operator_poll_msg_set(C, "failed to find grease pencil data to draw into");
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
}
}
else {
- CTX_wm_operator_poll_msg_set(C, "active region not set");
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
}
return 0;
@@ -161,7 +165,7 @@ static int gpencil_draw_poll (bContext *C)
static int gpencil_project_check (tGPsdata *p)
{
bGPdata *gpd= p->gpd;
- return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (p->gpd->flag & (GP_DATA_DEPTH_VIEW | GP_DATA_DEPTH_STROKE))) ? 1:0;
+ return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (p->gpd->flag & (GP_DATA_DEPTH_VIEW | GP_DATA_DEPTH_STROKE)));
}
/* ******************************************* */
@@ -1015,9 +1019,6 @@ static tGPsdata *gp_session_initpaint (bContext *C)
/* set edit flags - so that buffer will get drawn */
G.f |= G_GREASEPENCIL;
- /* set initial run flag */
- p->flags |= GP_PAINTFLAG_FIRSTRUN;
-
/* clear out buffer (stored in gp-data), in case something contaminated it */
gp_session_validatebuffer(p);
@@ -1080,6 +1081,9 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode)
p->paintmode= paintmode;
if (p->paintmode == GP_PAINTMODE_ERASER)
p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
+
+ /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
+ p->flags |= GP_PAINTFLAG_FIRSTRUN;
/* check if points will need to be made in view-aligned space */
if (p->gpd->flag & GP_DATA_VIEWALIGN) {
@@ -1236,7 +1240,7 @@ static void gpencil_draw_exit (bContext *C, wmOperator *op)
}
/* cleanup */
- if(gpencil_project_check(p)) {
+ if (gpencil_project_check(p)) {
View3D *v3d= p->sa->spacedata.first;
/* need to restore the original projection settings before packing up */
@@ -1261,6 +1265,46 @@ static int gpencil_draw_cancel (bContext *C, wmOperator *op)
/* ------------------------------- */
+/* update UI indicators of status, including cursor and header prints */
+static void gpencil_draw_status_indicators (tGPsdata *p)
+{
+ /* header prints */
+ switch (p->status) {
+ case GP_STATUS_PAINTING:
+ /* only print this for paint-sessions, otherwise it gets annoying */
+ if (GPENCIL_SKETCH_SESSIONS_ON(p->scene))
+ ED_area_headerprint(p->sa, "Grease Pencil: Drawing/erasing stroke... Release to end stroke");
+ break;
+
+ case GP_STATUS_IDLING:
+ /* print status info */
+ switch (p->paintmode) {
+ case GP_PAINTMODE_ERASER:
+ ED_area_headerprint(p->sa, "Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | ESC/Enter to end");
+ break;
+ case GP_PAINTMODE_DRAW_STRAIGHT:
+ ED_area_headerprint(p->sa, "Grease Pencil Line Session: Hold and drag LMB to draw | ESC/Enter to end");
+ break;
+ case GP_PAINTMODE_DRAW:
+ ED_area_headerprint(p->sa, "Grease Pencil Freehand Session: Hold and drag LMB to draw | ESC/Enter to end");
+ break;
+
+ default: /* unhandled future cases */
+ ED_area_headerprint(p->sa, "Grease Pencil Session: ESC/Enter to end");
+ break;
+ }
+ break;
+
+ case GP_STATUS_ERROR:
+ case GP_STATUS_DONE:
+ /* clear status string */
+ ED_area_headerprint(p->sa, NULL);
+ break;
+ }
+}
+
+/* ------------------------------- */
+
/* create a new stroke point at the point indicated by the painting context */
static void gpencil_draw_apply (wmOperator *op, tGPsdata *p)
{
@@ -1325,6 +1369,7 @@ static void gpencil_draw_apply_event (wmOperator *op, wmEvent *event)
tablet= (wmtab->Active != EVT_TABLET_NONE);
p->pressure= wmtab->Pressure;
+
//if (wmtab->Active == EVT_TABLET_ERASER)
// TODO... this should get caught by the keymaps which call drawing in the first place
}
@@ -1347,6 +1392,7 @@ static void gpencil_draw_apply_event (wmOperator *op, wmEvent *event)
}
/* fill in stroke data (not actually used directly by gpencil_draw_apply) */
+ // FIXME: need a way to denote new strokes (for drawing session redo)
RNA_collection_add(op->ptr, "stroke", &itemptr);
mousef[0]= p->mval[0];
@@ -1384,6 +1430,7 @@ static int gpencil_draw_exec (bContext *C, wmOperator *op)
/* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
* setting the relevant values in context at each step, then applying
*/
+ // FIXME: this doesn't work for redoing stroke sessions
RNA_BEGIN(op->ptr, itemptr, "stroke")
{
float mousef[2];
@@ -1447,6 +1494,8 @@ static int gpencil_draw_invoke (bContext *C, wmOperator *op, wmEvent *event)
// TODO: set any additional settings that we can take from the events?
// TODO? if tablet is erasing, force eraser to be on?
+ // TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway...
+
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
// TODO: this involves mucking around with radial control, so we leave this for now..
@@ -1484,67 +1533,110 @@ static int gpencil_draw_invoke (bContext *C, wmOperator *op, wmEvent *event)
static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
{
tGPsdata *p= op->customdata;
+ int estate = OPERATOR_PASS_THROUGH; /* default exit state - not handled, so let others have a share of the pie */
//printf("\tGP - handle modal event...\n");
- switch (event->type) {
- /* end of stroke -> ONLY when a mouse-button release occurs
- * otherwise, carry on to mouse-move...
- */
- case LEFTMOUSE:
- case RIGHTMOUSE:
- /* if painting, end stroke */
- if (p->status == GP_STATUS_PAINTING) {
- /* basically, this should be mouse-button up */
- //printf("\t\tGP - end of stroke \n");
- gpencil_draw_exit(C, op);
-
- /* one last flush before we're done */
- WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work
+ /* exit painting mode (and/or end current stroke) */
+ if (ELEM3(event->type, RETKEY, PADENTER, ESCKEY)) {
+ /* exit() ends the current stroke before cleaning up */
+ //printf("\t\tGP - end of paint op + end of stroke\n");
+ gpencil_draw_exit(C, op);
+ p->status= GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+
+ /* toggle painting mode upon mouse-button movement */
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE)) {
+ /* if painting, end stroke */
+ if (p->status == GP_STATUS_PAINTING) {
+ /* basically, this should be mouse-button up = end stroke
+ * BUT what happens next depends on whether we 'painting sessions' is enabled
+ */
+ if (GPENCIL_SKETCH_SESSIONS_ON(p->scene)) {
+ /* end stroke only, and then wait to resume painting soon */
+ //printf("\t\tGP - end stroke only\n");
+ gp_paint_strokeend(p);
+ p->status= GP_STATUS_IDLING;
- return OPERATOR_FINISHED;
+ /* we've just entered idling state, so this event was processed (but no others yet) */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ //printf("\t\tGP - end of stroke + op\n");
+ gpencil_draw_exit(C, op);
+ p->status= GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else {
+ /* not painting, so start stroke (this should be mouse-button down) */
+
+ /* we must check that we're still within the area that we're set up to work from
+ * otherwise we could crash (see bug #20586)
+ */
+ if (CTX_wm_area(C) != p->sa) {
+ //printf("\t\t\tGP - wrong area execution abort! \n");
+ gpencil_draw_exit(C, op);
+ p->status= GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
}
else {
- /* not painting, so start stroke (this should be mouse-button down) */
-
- /* we must check that we're still within the area that we're set up to work from
- * otherwise we could crash (see bug #20586)
- */
- if (CTX_wm_area(C) != p->sa) {
- //printf("\t\t\tGP - wrong area execution abort! \n");
- gpencil_draw_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-
//printf("\t\tGP - start stroke \n");
p->status= GP_STATUS_PAINTING;
- /* no break now, since we should immediately start painting */
- }
-
- /* moving mouse - assumed that mouse button is down if in painting status */
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- /* check if we're currently painting */
- if (p->status == GP_STATUS_PAINTING) {
- /* handle drawing event */
- //printf("\t\tGP - add point\n");
- gpencil_draw_apply_event(op, event);
- /* finish painting operation if anything went wrong just now */
+ /* we may need to set up paint env again if we're resuming */
+ // XXX: watch it with the paintmode! in future, it'd be nice to allow changing paint-mode when in sketching-sessions
+ // XXX: with tablet events, we may event want to check for eraser here, for nicer tablet support
+ gp_paint_initstroke(p, p->paintmode);
+
if (p->status == GP_STATUS_ERROR) {
- //printf("\t\t\tGP - error done! \n");
gpencil_draw_exit(C, op);
- return OPERATOR_CANCELLED;
+ estate = OPERATOR_CANCELLED;
}
}
- break;
+ }
+ }
+
+ /* handle painting mouse-movements? */
+ if ((p->status == GP_STATUS_PAINTING) &&
+ (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) )
+ {
+ /* handle drawing event */
+ //printf("\t\tGP - add point\n");
+ gpencil_draw_apply_event(op, event);
- default:
- //printf("\t\tGP unknown event - %d \n", event->type);
+ /* finish painting operation if anything went wrong just now */
+ if (p->status == GP_STATUS_ERROR) {
+ //printf("\t\t\t\tGP - add error done! \n");
+ gpencil_draw_exit(C, op);
+ estate = OPERATOR_CANCELLED;
+ }
+ else {
+ /* event handled, so just tag as running modal */
+ //printf("\t\t\t\tGP - add point handled!\n");
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ /* update status indicators - cursor, header, etc. */
+ gpencil_draw_status_indicators(p);
+
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ /* one last flush before we're done */
+ WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work
+ break;
+
+ case OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH:
+ /* event doesn't need to be handled */
+ //printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n", event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE);
break;
}
- return OPERATOR_RUNNING_MODAL;
+ /* return status code */
+ return estate;
}
/* ------------------------------- */
@@ -1558,8 +1650,6 @@ static EnumPropertyItem prop_gpencil_drawmodes[] = {
void GPENCIL_OT_draw (wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name= "Grease Pencil Draw";
ot->idname= "GPENCIL_OT_draw";
@@ -1576,8 +1666,7 @@ void GPENCIL_OT_draw (wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
/* settings for drawing */
- prop= RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to intepret mouse movements.");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to intepret mouse movements.");
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}