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:
authorJoshua Leung <aligorith@gmail.com>2011-01-04 06:14:01 +0300
committerJoshua Leung <aligorith@gmail.com>2011-01-04 06:14:01 +0300
commitcdc7d0b85f088967684c6b6efb7600d06398abc9 (patch)
tree309c828da7f6cafb48b056bc8cf06aa74315137b /source/blender/editors/gpencil
parent522615536952c02fababd72ab9106c0a68a8071d (diff)
Grease Pencil Todos: "Sketching Sessions"
Due to popular request and usability considerations, this commit reintroduces functionality similar to 2.4's "Draw Mode" for Grease Pencil. In the toolbar under the Draw/Line/Eraser buttons, you can find the "Use Sketching Sessions" toggle, which enables this feature. This is a per-scene setting, and defaults to off, so that the current 2.5 behaviour is still the default (i.e. the Grease Pencil operator will only do a single stroke at a time). With this option enabled, drawing with Grease Pencil will enter a semi-modal state where you can draw multiple strokes without needing to keep holding the DKEY throughout (though you'll still need to do so to start the strokes, unless you use some toolbar buttons), while still being able to manipulate the viewport. Header help-text prints show the appropriate keybindings (i.e. press ESCKEY or ENTER to end the sketching session). Notes: - To aid maintainability of the 3D-View toolbar code, I've taken the liberty to factor out the groups of widgets which commonly occur in most of the toolbars into separate functions (namely "Repeat" and "Grease Pencil"). Perhaps it might make it slightly harder to newbies to the toolbar code to grasp, though the physics panels are far worse ;) - I've reshuffled some code in the Grease Pencil code to separate out the various states of operation again more clearly, though some more work is still needed there (TODO) - There can now be only one Grease Pencil operator running at a time - Redoing Grease Pencil operations where sketching sessions was enabled still needs work. Namely, a way of delimiting the set of points recorded into strokes is still needed (TODO) - Ultimately, it should be possible to switch tools midway through a session. Currently sessions are limited to only being able to be used with a single drawing mode (TODO) - After ending a drawing session, the titlebar contols may not work on Windows without manually making the main window lose focus and then regain (i.e. click on some other window in toolbar, then come back). This may be related to (bug #25480)
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", "");
}