diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2011-09-06 11:59:18 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2011-09-06 11:59:18 +0400 |
commit | c94fe5e2995873536cbdb180652b1aa027e4ef8d (patch) | |
tree | 977908d8ac5cfa4fe6949eec62bba78fee17bad9 /source/blender/editors/gpencil/gpencil_paint.c | |
parent | a41f45946f8bf7b58e2b6bc048bfa30015e4ba2f (diff) |
Grease pencil: non-blocking sketch sessions
- Implement own undo stack for grease pencil, so now there'll be no keymaps conflicts.
- Supported redo's during sketch session.
- Get rid of flag stored in Globals -- use undo stack to check if grease pencil session is active.
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_paint.c')
-rw-r--r-- | source/blender/editors/gpencil/gpencil_paint.c | 136 |
1 files changed, 76 insertions, 60 deletions
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 04565eab155..df5fa65c980 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -152,7 +152,7 @@ static int gpencil_draw_poll (bContext *C) /* check if current context can support GPencil data */ if (gpencil_data_get_pointers(C, NULL) != NULL) { /* check if Grease Pencil isn't already running */ - if ((G.f & G_GREASEPENCIL) == 0) + if (ED_gpencil_session_active() == 0) return 1; else CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active"); @@ -893,8 +893,10 @@ static void gp_session_validatebuffer (tGPsdata *p) /* clear memory of buffer (or allocate it if starting a new session) */ if (gpd->sbuffer) memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX); - else + else { + //printf("\t\tGP - allocate sbuffer\n"); gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); + } /* reset indices */ gpd->sbuffer_size = 0; @@ -1051,8 +1053,11 @@ static tGPsdata *gp_session_initpaint (bContext *C) p->gpd= *gpd_ptr; } - /* set edit flags - so that buffer will get drawn */ - G.f |= G_GREASEPENCIL; + if(ED_gpencil_session_active()==0) { + /* initialize undo stack, + also, existing undo stack would make buffer drawn */ + gpencil_undo_init(p->gpd); + } /* clear out buffer (stored in gp-data), in case something contaminated it */ gp_session_validatebuffer(p); @@ -1078,6 +1083,7 @@ static void gp_session_cleanup (tGPsdata *p) /* free stroke buffer */ if (gpd->sbuffer) { + //printf("\t\tGP - free sbuffer\n"); MEM_freeN(gpd->sbuffer); gpd->sbuffer= NULL; } @@ -1247,7 +1253,8 @@ static void gp_paint_strokeend (tGPsdata *p) static void gp_paint_cleanup (tGPsdata *p) { /* finish off a stroke */ - gp_paint_strokeend(p); + if(p->gpd) + gp_paint_strokeend(p); /* "unlock" frame */ if (p->gpf) @@ -1260,8 +1267,8 @@ static void gpencil_draw_exit (bContext *C, wmOperator *op) { tGPsdata *p= op->customdata; - /* clear edit flags */ - G.f &= ~G_GREASEPENCIL; + /* clear undo stack */ + gpencil_undo_finish(); /* restore cursor to indicate end of drawing */ WM_cursor_restore(CTX_wm_window(C)); @@ -1592,6 +1599,7 @@ static int gpencil_draw_invoke (bContext *C, wmOperator *op, wmEvent *event) //printf("\tGP - hotkey invoked... waiting for click-drag\n"); } + WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL, NULL); /* add a modal handler for this operator, so that we can then draw continuous strokes */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; @@ -1609,16 +1617,60 @@ static int gpencil_area_exists(bContext *C, ScrArea *satest) return 0; } +static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) +{ + tGPsdata *p= op->customdata; + + /* 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"); + p->status= GP_STATUS_ERROR; + } + + /* free pointer used by previous stroke */ + if(p) + MEM_freeN(p); + + //printf("\t\tGP - start stroke \n"); + + /* 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 + + gpencil_draw_init(C, op); + + p= op->customdata; + + if(p->status != GP_STATUS_ERROR) + p->status= GP_STATUS_PAINTING; + + return op->customdata; +} + +static void gpencil_stroke_end(wmOperator *op) +{ + tGPsdata *p= op->customdata; + + gp_paint_cleanup(p); + + gpencil_undo_push(p->gpd); + + gp_session_cleanup(p); + + p->status= GP_STATUS_IDLING; + + p->gpd= NULL; + p->gpl= NULL; + p->gpf= NULL; +} + /* events handling during interactive drawing part of operator */ 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 */ - /* currently, grease pencil conflicts with such operators as undo and set object mode - which makes behavior of operator totally unpredictable and crash for some cases. - the only way to solve this proper is to ger rid of pointers to data which can - chage stored in operator custom data (sergey) */ - int estate = OPERATOR_RUNNING_MODAL; + int estate = OPERATOR_PASS_THROUGH; /* default exit state - not handled, so let others have a share of the pie */ // if (event->type == NDOF_MOTION) // return OPERATOR_PASS_THROUGH; @@ -1652,11 +1704,13 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event) 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_cleanup(p); - p->status= GP_STATUS_IDLING; + gpencil_stroke_end(op); /* we've just entered idling state, so this event was processed (but no others yet) */ estate = OPERATOR_RUNNING_MODAL; + + /* stroke could be smoothed, send notifier to refresh screen */ + ED_region_tag_redraw(p->ar); } else { //printf("\t\tGP - end of stroke + op\n"); @@ -1664,35 +1718,19 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event) estate = OPERATOR_FINISHED; } } - else { + else if (event->val == KM_PRESS) { /* 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"); - p->status= GP_STATUS_ERROR; + p= gpencil_stroke_begin(C, op); + + if (p->status == GP_STATUS_ERROR) { estate = OPERATOR_CANCELLED; } - else { - //printf("\t\tGP - start stroke \n"); - p->status= GP_STATUS_PAINTING; - - /* 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) { - estate = OPERATOR_CANCELLED; - } - } + } else { + p->status = GP_STATUS_IDLING; } } - - /* handle mode-specific events */ if (p->status == GP_STATUS_PAINTING) { /* handle painting mouse-movements? */ @@ -1704,7 +1742,7 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event) /* finish painting operation if anything went wrong just now */ if (p->status == GP_STATUS_ERROR) { - //printf("\t\t\t\tGP - add error done! \n"); + printf("\t\t\t\tGP - add error done! \n"); estate = OPERATOR_CANCELLED; } else { @@ -1721,28 +1759,6 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event) estate = OPERATOR_RUNNING_MODAL; } } - else if (p->status == GP_STATUS_IDLING) { - /* standard undo/redo shouldn't be allowed to execute or else it causes crashes, so catch it here */ - // FIXME: this is a hardcoded hotkey that can't be changed - // TODO: catch redo as well, but how? - if (event->type == ZKEY && event->val == KM_RELEASE) { - /* oskey = cmd key on macs as they seem to use cmd-z for undo as well? */ - if ((event->ctrl) || (event->oskey)) { - /* just delete last stroke, which will look like undo to the end user */ - //printf("caught attempted undo event... deleting last stroke \n"); - gpencil_frame_delete_laststroke(p->gpl, p->gpf); - /* undoing the last line can free p->gpf - * note, could do this in a bit more of an elegant way then a search but it at least prevents a crash */ - if(BLI_findindex(&p->gpl->frames, p->gpf) == -1) { - p->gpf= NULL; - } - - /* event handled, so force refresh */ - ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */ - estate = OPERATOR_RUNNING_MODAL; - } - } - } /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ if(0==gpencil_area_exists(C, p->sa)) |