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:
authorSergey Sharybin <sergey.vfx@gmail.com>2011-09-06 11:59:18 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2011-09-06 11:59:18 +0400
commitc94fe5e2995873536cbdb180652b1aa027e4ef8d (patch)
tree977908d8ac5cfa4fe6949eec62bba78fee17bad9
parenta41f45946f8bf7b58e2b6bc048bfa30015e4ba2f (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.
-rw-r--r--source/blender/blenkernel/BKE_global.h2
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt1
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h6
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c136
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c168
-rw-r--r--source/blender/editors/include/ED_gpencil.h4
-rw-r--r--source/blender/editors/util/undo.c6
8 files changed, 263 insertions, 62 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 17876c6ec9d..0e48673f1b1 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -111,7 +111,7 @@ typedef struct Global {
#define G_SCRIPT_OVERRIDE_PREF (1 << 14) /* when this flag is set ignore the userprefs */
/* #define G_NOFROZEN (1 << 17) also removed */
-#define G_GREASEPENCIL (1 << 17)
+/* #define G_GREASEPENCIL (1 << 17) also removed */
/* #define G_AUTOMATKEYS (1 << 30) also removed */
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 7a2f196fd6d..b312f397939 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRC
gpencil_edit.c
gpencil_ops.c
gpencil_paint.c
+ gpencil_undo.c
gpencil_intern.h
)
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 440d5ee7c4d..cfa9585868e 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -644,7 +644,7 @@ static void gp_draw_data (bGPdata *gpd, int offsx, int offsy, int winx, int winy
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
*/
- if ((G.f & G_GREASEPENCIL) && (gpl->flag & GP_LAYER_ACTIVE) &&
+ if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
(gpf->flag & GP_FRAME_PAINT))
{
/* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index c31de8d30a7..db4315a8ca6 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -37,6 +37,7 @@
/* ***************************************************** */
/* Operator Defines */
+struct bGPdata;
struct wmOperatorType;
/* drawing ---------- */
@@ -61,6 +62,11 @@ void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
+/* undo stack ---------- */
+
+void gpencil_undo_init(struct bGPdata *gpd);
+void gpencil_undo_push(struct bGPdata *gpd);
+void gpencil_undo_finish(void);
/******************************************************* */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
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))
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
new file mode 100644
index 00000000000..1154975e3cc
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -0,0 +1,168 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_listBase.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+
+#include "BLI_listbase.h"
+
+#include "ED_gpencil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "gpencil_intern.h"
+
+#define MAXUNDONAME 64
+
+typedef struct bGPundonode {
+ struct bGPundonode *next, *prev;
+
+ char name[MAXUNDONAME];
+ struct bGPdata *gpd;
+} bGPundonode;
+
+static ListBase undo_nodes = {NULL, NULL};
+static bGPundonode *cur_node = NULL;
+
+int ED_gpencil_session_active(void)
+{
+ return undo_nodes.first != NULL;
+}
+
+int ED_undo_gpencil_step(bContext *C, int step, const char *name)
+{
+ bGPdata **gpd_ptr= NULL, *new_gpd= NULL;
+
+ gpd_ptr= gpencil_data_get_pointers(C, NULL);
+
+ if(step==1) { /* undo */
+ //printf("\t\tGP - undo step\n");
+ if(cur_node->prev) {
+ if(!name || strcmp(cur_node->name, name) == 0) {
+ cur_node= cur_node->prev;
+ new_gpd= cur_node->gpd;
+ }
+ }
+ }
+ else if (step==-1) {
+ //printf("\t\tGP - redo step\n");
+ if(cur_node->next) {
+ if(!name || strcmp(cur_node->name, name) == 0) {
+ cur_node= cur_node->next;
+ new_gpd= cur_node->gpd;
+ }
+ }
+ }
+
+ if(new_gpd) {
+ if(gpd_ptr) {
+ if(*gpd_ptr) {
+ bGPdata *gpd= *gpd_ptr;
+ bGPDlayer *gpl, *gpld;
+
+ free_gpencil_layers(&gpd->layers);
+
+ /* copy layers */
+ gpd->layers.first= gpd->layers.last= NULL;
+
+ for (gpl= new_gpd->layers.first; gpl; gpl= gpl->next) {
+ /* make a copy of source layer and its data */
+ gpld= gpencil_layer_duplicate(gpl);
+ BLI_addtail(&gpd->layers, gpld);
+ }
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void gpencil_undo_init(bGPdata *gpd)
+{
+ gpencil_undo_push(gpd);
+}
+
+void gpencil_undo_push(bGPdata *gpd)
+{
+ bGPundonode *undo_node;
+
+ //printf("\t\tGP - undo push\n");
+
+ if(cur_node) {
+ /* remove all un-done nodes from stack */
+ undo_node= cur_node->next;
+
+ while(undo_node) {
+ bGPundonode *next_node= undo_node->next;
+
+ free_gpencil_data(undo_node->gpd);
+ MEM_freeN(undo_node->gpd);
+
+ BLI_freelinkN(&undo_nodes, undo_node);
+
+ undo_node= next_node;
+ }
+ }
+
+ /* create new undo node */
+ undo_node= MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
+ undo_node->gpd= gpencil_data_duplicate(gpd);
+
+ cur_node= undo_node;
+
+ BLI_addtail(&undo_nodes, undo_node);
+}
+
+void gpencil_undo_finish(void)
+{
+ bGPundonode *undo_node= undo_nodes.first;
+
+ while(undo_node) {
+ free_gpencil_data(undo_node->gpd);
+ MEM_freeN(undo_node->gpd);
+
+ undo_node= undo_node->next;
+ }
+
+ BLI_freelistN(&undo_nodes);
+
+ cur_node= NULL;
+}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 07dcc959e32..bfd16487ae5 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -106,4 +106,8 @@ void paste_gpdata(void);
void snap_gplayer_frames(struct bGPDlayer *gpl, short mode);
void mirror_gplayer_frames(struct bGPDlayer *gpl, short mode);
+/* ------------ Grease-Pencil Undo System ------------------ */
+int ED_gpencil_session_active(void);
+int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
+
#endif /* ED_GPENCIL_H */
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index a2381a208ef..c1aca61f795 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -54,6 +54,7 @@
#include "ED_armature.h"
#include "ED_particle.h"
#include "ED_curve.h"
+#include "ED_gpencil.h"
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_object.h"
@@ -126,6 +127,11 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
Object *obact= CTX_data_active_object(C);
ScrArea *sa= CTX_wm_area(C);
+ /* grease pencil can be can be used in plenty of spaces, so check it first */
+ if(ED_gpencil_session_active()) {
+ return ED_undo_gpencil_step(C, step, undoname);
+ }
+
if(sa && sa->spacetype==SPACE_IMAGE) {
SpaceImage *sima= (SpaceImage *)sa->spacedata.first;