[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    (no subject)
From:       Boudewijn Rempt <boud () valdyas ! org>
Date:       2003-12-22 22:30:29
[Download RAW message or body]

On Saturday 13 December 2003 21:51, Patrick Julien wrote:
>
> Well, yes, that is expected behavior.  I believe what you want to it keep
> your painter on the member list of your class... you begin() the painter on
> mousePress (or key, whatever) and end() on release.

I don't see how this can work... 

There is no way a single KisTileCommand can be reused from more than one call 
to bitBlt. If there is no transaction defined, then end() return 
endTransaction(), which, if there's no transaction, returns 0; if there is a 
transaction defined, every call to bitBlt creates a new KisTileCommand which 
is added to the transaction.

A transaction is a KMacroCommand or nothing; but a KMacroCommand isn't useful, 
because it is so slow in replaying/rewinding.

But a KisTileCommand is valid only for a specific rectangle, and notifies the 
image on that initially set rectangle only, but doesn't check whether all its 
tiles are inside that rectangle. If the rectangle could grow while adding 
tiles, it could hold changes all over the place, without adding memory 
constraints.

If you want to code a freehand paint function, it is impossible to move 
everything to KisPainter -- the tool will have to repeat issue fresh calls 
for every mouse movement/pen move, and those calls will have to be 
consolidated into a transaction.

So I think that it's necessary to have a transaction type in KisPainter that 
is purely tile based; that is, between beginTransaction() and 
endTransaction(), tiles are added to KisTileCommand, instead of 
KisTileCommands to a KMacroCommand. And then the KisTileCommand must update 
its rect based upon the normalized rectangle of all the tiles it contains. 

I've hacked KisPainter to support the kind of tile-consolidating transaction
I mean, instead of macro-like transactions, and undo/redo is now instant, of
course, and everything else still seems to work. I did have a problem, though: 
I couldn't figure out how to keep KisTileCommand local to the namespace of 
kis_painter.cc, and still declare m_transaction in kis_painter.h to be of 
type KisTileCommand, so I had to place the declaration of KisTileCommand in t 
kis_painter.h. No doubt someone with more knowledge of C++ knows how to do 
this correctly, but the only other option I could find was to dynamic cast
KCommand to KisTileCommand whenever I needed the addTile method.

Anyway, because of this, and because I have a precognition that I might have
missed something important, I've just attached the diff instead of blithely 
committing. (I've also removed the QPainter based methods I did in September 
or so, when I was learning Krita -- those were obsolete).

-- 
Boudewijn Rempt | http://www.valdyas.org/index2.html

["krita_undo_redo.diff" (text/x-diff)]

? Doxyfile
? krita.kdevelop
? krita.kdevelop.pcs
? krita.kdevses
Index: core/kis_paint_device.cc
===================================================================
RCS file: /home/kde/koffice/krita/core/kis_paint_device.cc,v
retrieving revision 1.50
diff -u -3 -u -p -w -r1.50 kis_paint_device.cc
Index: core/kis_paint_device.h
===================================================================
RCS file: /home/kde/koffice/krita/core/kis_paint_device.h,v
retrieving revision 1.41
diff -u -3 -u -p -w -r1.41 kis_paint_device.h
--- core/kis_paint_device.h	3 Nov 2003 15:04:41 -0000	1.41
+++ core/kis_paint_device.h	22 Dec 2003 22:18:25 -0000
@@ -70,8 +70,8 @@ public:
 	virtual const bool visible() const;
 	virtual void visible(bool v);
         /**
-         * Don't know what this does, to judge from the source nothing,
-         * but without it, painting won't be done.
+         * Reimplemented by KisSelection; here it does nothing useful, but it
+         * cannot be abstract, because otherwise this class would be abstract.
          */
 	virtual void anchor();
 
Index: core/kis_painter.cc
===================================================================
RCS file: /home/kde/koffice/krita/core/kis_painter.cc,v
retrieving revision 1.53
diff -u -3 -u -p -w -r1.53 kis_painter.cc
--- core/kis_painter.cc	31 Oct 2003 11:43:34 -0000	1.53
+++ core/kis_painter.cc	22 Dec 2003 22:18:25 -0000
@@ -52,35 +52,8 @@
 #include "kis_brush.h"
 #include "kis_gradient.h"
 #include "kis_pattern.h"
-
-namespace {
 #	include <qmap.h>
 
-	class KisTileCommand : public KCommand {
-		typedef QMap<Q_INT32, KisTileSP> TileMap;
-
-	public:
-		KisTileCommand(const QString& name, KisPaintDeviceSP device, Q_INT32 x, Q_INT32 y, \
                Q_INT32 width, Q_INT32 height);
-		KisTileCommand(const QString& name, KisPaintDeviceSP device, const QRect& rc);
-		KisTileCommand(const QString& name, KisPaintDeviceSP device);
-		virtual ~KisTileCommand();
-
-	public:
-		virtual void execute();
-		virtual void unexecute();
-		virtual QString name() const;
-
-	public:
-		void addTile(Q_INT32 tileNo, KisTileSP tile);
-
-	private:
-		TileMap m_tiles;
-		TileMap m_originals;
-		QString m_name;
-		KisPaintDeviceSP m_device;
-		QRect m_rc;
-	};
-
 	KisTileCommand::KisTileCommand(const QString& name, KisPaintDeviceSP device,
                                        Q_INT32 x, Q_INT32 y, Q_INT32 width, Q_INT32 \
height)  {
@@ -163,7 +136,6 @@ namespace {
 			m_tiles[tileNo] = tile;
 		}
 	}
-}
 
 KisPainter::KisPainter()
 {
@@ -194,20 +166,11 @@ KCommand *KisPainter::end()
 	return endTransaction();
 }
 
-void KisPainter::beginTransaction(KMacroCommand *command)
-{
-	if (m_transaction)
-		delete m_transaction;
-
-	m_transaction = command;
-}
-
 void KisPainter::beginTransaction(const QString& customName)
 {
 	if (m_transaction)
 		delete m_transaction;
-
-	m_transaction = new KMacroCommand(customName);
+        m_transaction = new KisTileCommand(customName, m_device);
 }
 
 KCommand *KisPainter::endTransaction()
@@ -294,7 +257,6 @@ void KisPainter::bitBlt(Q_INT32 dx, Q_IN
 	Q_INT32 yxtra;
 	Q_INT32 nrows = 0;
 	Q_INT32 ncols = 0;
-	KisTileCommand *tc;
 	Q_INT32 tileno;
 
 	if (dx < 0 || dy < 0 || sx < 0 || sy < 0)
@@ -313,11 +275,6 @@ void KisPainter::bitBlt(Q_INT32 dx, Q_IN
 	symod = sy % TILE_HEIGHT;
 	sxmod = sx % TILE_WIDTH;
 
-	if (m_transaction) {
-		tc = new KisTileCommand(m_transaction -> name(), m_device, dx, dy, sw, sh);
-		m_transaction -> addCommand(tc);
-	}
-
 	for (y = dy; y <= dy2; y += TILE_HEIGHT) {
 		sx = sx2;
 
@@ -325,7 +282,7 @@ void KisPainter::bitBlt(Q_INT32 dx, Q_IN
 			tileno = dsttm -> tileNum(x, y);
 
 			if (m_transaction && (dsttile = dsttm -> tile(tileno, TILEMODE_NONE)))
-				tc -> addTile(tileno, dsttile);
+                                m_transaction -> addTile(tileno, dsttile);
 
 			dsttile = dsttm -> tile(tileno, TILEMODE_RW);
 			srctile = srctm -> tile(sx, sy, TILEMODE_READ);
@@ -387,7 +344,7 @@ void KisPainter::bitBlt(Q_INT32 dx, Q_IN
 				tileno = dsttm -> tileNum(x, y + TILE_HEIGHT - (y % TILE_HEIGHT) + 1);
 
 				if (m_transaction && (tile = dsttm -> tile(tileno, TILEMODE_NONE)))
-					tc -> addTile(tileno, tile);
+                                        m_transaction -> addTile(tileno, tile);
 
 				tile = dsttm -> tile(tileno, TILEMODE_RW);
 
@@ -430,7 +387,7 @@ void KisPainter::bitBlt(Q_INT32 dx, Q_IN
 				tileno = dsttm -> tileNum(x + TILE_WIDTH - (x % TILE_WIDTH) + 1, y);
 
 				if (m_transaction && (tile = dsttm -> tile(tileno, TILEMODE_NONE)))
-					tc -> addTile(tileno, tile);
+                                        m_transaction -> addTile(tileno, tile);
 
 				tile = dsttm -> tile(tileno, TILEMODE_RW);
 
@@ -457,7 +414,7 @@ void KisPainter::bitBlt(Q_INT32 dx, Q_IN
                                                           y + TILE_HEIGHT - (y % \
TILE_HEIGHT) + 1);  
 				if (m_transaction && (tile = dsttm -> tile(tileno, TILEMODE_NONE)))
-					tc -> addTile(tileno, tile);
+                                        m_transaction -> addTile(tileno, tile);
 
 				tile = dsttm -> tile(tileno, TILEMODE_RW);
 
@@ -563,7 +520,6 @@ void KisPainter::fillRect(Q_INT32 x1, Q_
 	Q_INT32 ymod;
 	Q_INT32 xdiff;
 	Q_INT32 ydiff;
-	KisTileCommand *tc;
 	KisColorSpaceFactoryInterface *factory = \
KisColorSpaceFactoryInterface::singleton();  KisStrategyColorSpaceSP strategy;
 
@@ -573,11 +529,6 @@ void KisPainter::fillRect(Q_INT32 x1, Q_
 	stride = m_device -> image() -> depth();
         ydiff = y1 - TILE_HEIGHT * (y1 / TILE_HEIGHT);
 
-	if (m_transaction) {
-		tc = new KisTileCommand(m_transaction -> name(), m_device, x1, y1, w, h);
-		m_transaction -> addCommand(tc);
-	}
-
 	for (y = y1; y <= y2; y += TILE_HEIGHT - ydiff) {
 		xdiff = x1 - TILE_WIDTH * (x1 / TILE_WIDTH);
 
@@ -586,7 +537,7 @@ void KisPainter::fillRect(Q_INT32 x1, Q_
 			xmod = (x % TILE_WIDTH);
 
 			if (m_transaction && (tile = tm -> tile(x, y, TILEMODE_NONE)))
-				tc -> addTile(tm -> tileNum(x, y), tile);
+                                m_transaction -> addTile(tm -> tileNum(x, y), tile);
 
 			if (!(tile = tm -> tile(x, y, TILEMODE_WRITE)))
 				continue;
@@ -632,85 +583,3 @@ void KisPainter::fillRect(Q_INT32 x1, Q_
 	}
 
 }
-
-void KisPainter::drawPoint(Q_INT32 /*x*/, Q_INT32 /*y*/, const KoColor& /*c*/, const \
                KisBrush& /*brush*/) 
-{
-}
-
-
-
-void KisPainter::drawPolyline ( const QPointArray & polyline,
-                                const QColor & c)
-{
-    QRect r = polyline.boundingRect();
-
-    if ( r.left() < 0 ) r.setLeft( 1 );
-    if ( r.bottom() < 0 ) r.setBottom( 1 );
-    if ( r.right() < 0 ) r.setRight( 1 );
-    if ( r.top() < 0 ) r.setTop( 1 );
-
-    if ( r.left() >= m_device->width() ) r.setLeft( m_device->width() - 1);
-    if ( r.bottom() >= m_device->height() ) r.setBottom(  m_device->height() - 1);
-    if ( r.right() >= m_device->width() ) r.setRight( m_device->width() - 1);
-    if ( r.top() >= m_device->height() ) r.setTop( m_device->height() - 1);
-
-#if 0
-     kdDebug() << " left: " << r.left()
-               << " right: " << r.right()
-               << " bottom: " << r.bottom()
-               << " top: " << r.top() << endl;
-#endif
-
-    // XXX: should paint a single dot
-    if ( r.left() == r.right() && r.top() == r.bottom() ) return;
-
-    // XXX: This does not use the tile commands, and is thus not undoable
-    // XXX: This sometimes crashes when the pen leaves the paint area
-    // XXX: This sometimes shouts something weird about a null pixmap
-    // XXX: This probably won't work with thick pens
-
-    KisTileMgrSP tileMgr =  m_device->data();
-
-    KisPixelDataSP pd = new KisPixelData;
-    QImage img;
-
-    pd -> mgr = 0;
-    pd -> tile = 0;
-    pd -> mode = TILEMODE_READ;
-    pd -> x1 = r.left();
-    pd -> x2 = r.right();
-    pd -> y1 = r.top();
-    pd -> y2 = r.bottom();
-    pd -> width = r.width(); //pd -> x2 - pd -> x1 + 1;
-    pd -> height = r.height(); //pd -> y2 - pd -> y1 + 1;
-    pd -> depth = tileMgr -> depth();
-    pd -> stride = pd -> depth * pd -> width;
-    pd -> owner = true;
-
-    // XXX: this assumes RGBA.
-    pd -> data = new QUANTUM[pd->width * pd->height * 4];
-    tileMgr -> readPixelData(pd);
-
-    img = QImage(pd -> data,
-                 pd -> width, pd -> height,
-                 pd -> depth * CHAR_BIT,
-                 0, 0,
-                 QImage::LittleEndian);
-
-    QPixmap buffer = QPixmap( img );
-
-    QPainter p;
-    p.begin(&buffer);
-    p.translate( -r.x(),  -r.y() );
-    // Get currently selected brush or pattern, color and use
-    // that as the pen
-    p.setPen( c );
-    p.drawPolyline( polyline );
-    p.end();
-
-    QImage img2 = buffer.convertToImage();
-    memcpy(pd->data,  img2.bits(), pd->width * pd->height * 4 * sizeof( QUANTUM ));
-
-    tileMgr->writePixelData( pd );
-
-}
Index: core/kis_painter.h
===================================================================
RCS file: /home/kde/koffice/krita/core/kis_painter.h,v
retrieving revision 1.28
diff -u -3 -u -p -w -r1.28 kis_painter.h
--- core/kis_painter.h	11 Dec 2003 21:39:50 -0000	1.28
+++ core/kis_painter.h	22 Dec 2003 22:18:25 -0000
@@ -35,6 +35,7 @@
 #include <qpainter.h>
 
 #include <koColor.h>
+#include <kcommand.h>
 
 #include "kis_global.h"
 #include "kis_types.h"
@@ -45,7 +46,36 @@
 
 class QRect;
 class KCommand;
-class KMacroCommand;
+
+/*
+        KisTileCommand extends KCommand with an addTile method; I
+        haven't found a way to keep this private in the namespace of
+        kis_painter.cc and still declare m_transaction to be of type
+        KisTileCommand in kis_painter.h -- dynamically downcasting a
+        KCommand m_transaction just to keep everything private seems
+        excessive.
+*/
+class KisTileCommand : public KCommand {
+        typedef QMap<Q_INT32, KisTileSP> TileMap;
+
+public:
+        KisTileCommand(const QString& name, KisPaintDeviceSP device, Q_INT32 x, \
Q_INT32 y, Q_INT32 width, Q_INT32 height); +        KisTileCommand(const QString& \
name, KisPaintDeviceSP device, const QRect& rc); +        KisTileCommand(const \
QString& name, KisPaintDeviceSP device); +        virtual ~KisTileCommand();
+public:
+        virtual void execute();
+        virtual void unexecute();
+        virtual QString name() const;
+public:
+        void addTile(Q_INT32 tileNo, KisTileSP tile);
+private:
+        TileMap m_tiles;
+        TileMap m_originals;
+        QString m_name;
+        KisPaintDeviceSP m_device;
+        QRect m_rc;
+};
 
 /*
   KisPainter contains the graphics primitives necessary to draw on a
@@ -78,15 +108,11 @@ public:
 	KCommand *end();
 
         // ???
-	void beginTransaction(KMacroCommand *command);
-
-        // ???
 	void beginTransaction(const QString& customName = QString::null);
 
         // ???
 	KCommand *endTransaction();
 
-
         // The current paint device.
 	KisPaintDeviceSP device() const;
 
@@ -113,26 +139,6 @@ public:
 	void fillRect(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const KoColor& c, QUANTUM \
opacity);  void fillRect(const QRect& rc, const KoColor& c, QUANTUM opacity);
 
-	// Draw a point with the specified brush in the specified color at x, y
-	// XXX: brush, color, gradient, pattern etc. should be set
-	// as in QPainter.
-	void drawPoint(Q_INT32 x, Q_INT32 y, const KoColor &c, const KisBrush &brush);
-	void drawPoint(const QPoint &p,  const KoColor &c, const KisBrush &brush);
-
-
-        // ----------------------------------------------------------------------------------------
                
-        // QPainter-using methods.
-
-        // XXX: we actually use QPainter for everything.
-        // XXX: we even use QPixmaps, for added sluggishness.
-        // XXX: we don't even think about compositing.
-        // XXX: let alone colour strategies.
-
-        void drawPolyline ( const QPointArray & polyline, 
-                            const QColor & c );
-
-        // ----------------------------------------------------------------------------------------
                
-
 private:
 	void tileBlt(QUANTUM *dst, KisTileSP dsttile, QUANTUM *src,
                      KisTileSP srctile, Q_INT32 rows, Q_INT32 cols, 
@@ -140,14 +146,13 @@ private:
 	void tileBlt(QUANTUM *dst, KisTileSP dsttile, QUANTUM *src,
                      KisTileSP srctile, QUANTUM opacity, Q_INT32 rows, Q_INT32 cols, \
  CompositeOp op);
+
 	KisPainter(const KisPainter&);
 	KisPainter& operator=(const KisPainter&);
 
 private:
 	KisPaintDeviceSP m_device;	
-	KMacroCommand *m_transaction;
-
-
+        KisTileCommand  *m_transaction;
 };
 
 inline
@@ -180,12 +185,6 @@ void KisPainter::fillRect(const QRect& r
 	fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity);
 }
 
-inline
-void KisPainter::drawPoint(const QPoint &p,  const KoColor &c, const KisBrush \
                &brush) 
-{
-	drawPoint(p.x(), p.y(), c, brush);
-}
-
 
 inline
 KisPaintDeviceSP KisPainter::device() const
Index: tools/Makefile.am
===================================================================
RCS file: /home/kde/koffice/krita/tools/Makefile.am,v
retrieving revision 1.46
diff -u -3 -u -p -w -r1.46 Makefile.am
--- tools/Makefile.am	19 Nov 2003 22:36:25 -0000	1.46
+++ tools/Makefile.am	22 Dec 2003 22:18:25 -0000
@@ -12,11 +12,10 @@ libkistools_la_SOURCES = kis_tool_paint.
 	kis_tool_brush.cc
 
 #	kis_tool_paste.cc
-#	kis_tool_brush.cc
 #
 #  kis_tool_select_freehand.cc kis_tool_select_rectangular.cc \
kis_tool_select_polygonal.cc   #  kis_tool_select_elliptical.cc \
                kis_tool_select_contiguous.cc 
-#  kis_tool_brush.cc kis_tool_pen.cc kis_tool_airbrush.cc kis_tool_eraser.cc 
+#  kis_tool_pen.cc kis_tool_airbrush.cc kis_tool_eraser.cc 
 #  kis_tool_fill.cc kis_tool_stamp.cc 
 #  kis_tool_line.cc kis_tool_rectangle.cc 
 #  kis_tool_ellipse.cc kis_tool_polyline.cc kis_tool_polygon.cc 
Index: tools/kis_tool_brush.cc
===================================================================
RCS file: /home/kde/koffice/krita/tools/kis_tool_brush.cc,v
retrieving revision 1.66
diff -u -3 -u -p -w -r1.66 kis_tool_brush.cc
--- tools/kis_tool_brush.cc	11 Dec 2003 21:39:50 -0000	1.66
+++ tools/kis_tool_brush.cc	22 Dec 2003 22:18:25 -0000
@@ -36,53 +36,48 @@ KisToolBrush::KisToolBrush() 
 	: super(),
 	  m_mode( HOVER )
 {
-	m_macro = 0;
+        m_painter = 0;
 }
 
 KisToolBrush::~KisToolBrush()
 {
 }
 
-void KisToolBrush::mouseRelease(QMouseEvent* e)
+void KisToolBrush::mousePress(QMouseEvent *e)
 {
+        if (!m_subject) return;
+
+        if (!m_subject->currentBrush()) return;
+
  	if (e->button() == QMouseEvent::LeftButton) {
-		m_mode = HOVER;
+                m_mode = PAINT;
 		KisImageSP currentImage = m_subject -> currentImg();
 		KisPaintDeviceSP device;
 		if (currentImage && (device = currentImage -> activeDevice())) {
-			KisUndoAdapter *adapter = currentImage -> undoAdapter();
-			if (adapter) {
-				// If painting in mouse release, make sure painter is destructed or end()ed
-				adapter -> addCommand(m_macro);
-			} else {
-				delete m_macro;
-			}
-			m_macro = 0;
+                        if (m_painter)
+                                delete m_painter;
+                        m_painter = new KisPainter( device );
+                        m_painter->beginTransaction("brush");
 		}
+                paint(e->pos(), 128, 0, 0);
 	}
 }
 
-void KisToolBrush::mousePress(QMouseEvent *e)
-{
-	if (!m_subject) return;
-
- 	if (!m_subject->currentBrush()) return;
 
+void KisToolBrush::mouseRelease(QMouseEvent* e)
+{
  	if (e->button() == QMouseEvent::LeftButton) {
- 		m_mode = PAINT;
+                m_mode = HOVER;
 		KisImageSP currentImage = m_subject -> currentImg();
 		KisPaintDeviceSP device;
 		if (currentImage && (device = currentImage -> activeDevice())) {
-// 			KisPainter p( device );
-			if (m_macro) {
-				delete m_macro;
-				m_macro = 0;
+                        KisUndoAdapter *adapter = currentImage -> undoAdapter();
+                        if (adapter && m_painter) {
+                                // If painting in mouse release, make sure painter \
is destructed or end()ed +                                adapter -> \
addCommand(m_painter->endTransaction());  }
-			
-			m_macro = new KMacroCommand("brush");
-// 			p.beginTransaction(m_macro);
+                        m_painter = 0;
 		}
-		paint(e->pos(), 128, 0, 0);
  	}
 }
 
@@ -171,13 +166,9 @@ void KisToolBrush::paint(const QPoint & 
 		}
 	}
 	// Blit the temporary KisPaintDevice onto the current layer
-
         KisPaintDeviceSP device = currentImage -> activeDevice();
         if (device) {
-		KisPainter gc( device );
-		gc.beginTransaction(m_macro);
-		gc.bitBlt( pos.x(),  pos.y(),  COMPOSITE_NORMAL, tmpLayer.data() );
-		device->anchor();
+                m_painter->bitBlt( pos.x(),  pos.y(),  COMPOSITE_NORMAL, \
tmpLayer.data() );  }
         currentImage->invalidate( pos.x(),  pos.y(),  
 				  tmpLayer->width(),  
Index: tools/kis_tool_brush.h
===================================================================
RCS file: /home/kde/koffice/krita/tools/kis_tool_brush.h,v
retrieving revision 1.26
diff -u -3 -u -p -w -r1.26 kis_tool_brush.h
--- tools/kis_tool_brush.h	11 Dec 2003 21:39:50 -0000	1.26
+++ tools/kis_tool_brush.h	22 Dec 2003 22:18:25 -0000
@@ -23,6 +23,7 @@
 
 #include <kcommand.h>
 
+#include "kis_painter.h"
 #include "kis_tool.h"
 #include "kis_tool_paint.h"
 
@@ -53,6 +54,7 @@ private:
 
 	enumBrushMode m_mode;
 	KMacroCommand *m_macro;
+	KisPainter *m_painter;
 };
 #endif // KIS_TOOL_BRUSH_H_
 



_______________________________________________
kimageshop mailing list
kimageshop@kde.org
https://mail.kde.org/mailman/listinfo/kimageshop


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic