diff options
Diffstat (limited to 'kiconedit/kicongrid.cpp')
-rw-r--r-- | kiconedit/kicongrid.cpp | 2263 |
1 files changed, 2263 insertions, 0 deletions
diff --git a/kiconedit/kicongrid.cpp b/kiconedit/kicongrid.cpp new file mode 100644 index 00000000..abfb848e --- /dev/null +++ b/kiconedit/kicongrid.cpp @@ -0,0 +1,2263 @@ +/* + KDE Icon Editor - a small graphics drawing program for the KDE. + Copyright (C) 1998 Thomas Tanghus ([email protected]) + + Includes portions of code from Qt, + Copyright (C) 1992-2000 Trolltech AS. + + 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 Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <stdlib.h> + +#include <qpainter.h> +#include <qwhatsthis.h> +#include <qscrollview.h> +#include <qbitmap.h> +#include <qclipboard.h> +#include <qdatetime.h> + +#include <kiconloader.h> +#include <kruler.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kdebug.h> + +#include "kresize.h" +#include "properties.h" +#include "kicongrid.h" +#include "kiconedit.h" +#ifndef PICS_INCLUDED +#include "pics/logo.xpm" +#define PICS_INCLUDED +#endif + +#include <X11/Xos.h> + +void DrawCommand::execute() +{ + oldcolor = *((uint*)image->scanLine(y) + x); + *((uint*)image->scanLine(y) + x) = newcolor; + int cell = y * grid->numCols() + x; + grid->setUndoColor( cell, newcolor, false ); +} + +void DrawCommand::unexecute() +{ + *((uint*)image->scanLine(y) + x) = oldcolor; + int cell = y * grid->numCols() + x; + grid->setUndoColor( cell, oldcolor, false ); +} + +void RepaintCommand::execute() +{ + grid->update( area); +} + +KGridView::KGridView(QImage *image, KCommandHistory* history, QWidget *parent, const char *name) +: QFrame(parent, name) +{ + _corner = 0L; + _hruler = _vruler = 0L; + _grid = 0L; + + acceptdrop = false; + + KIconEditProperties *props = KIconEditProperties::self(); + + viewport = new QScrollView(this); + Q_CHECK_PTR(viewport); + + _grid = new KIconEditGrid(image, history, viewport->viewport()); + Q_CHECK_PTR(_grid); + viewport->addChild(_grid); + _grid->setGrid(props->showGrid()); + _grid->setCellSize(props->gridScale()); + + QString str = i18n( "Icon draw grid\n\nThe icon grid is the area where" + " you draw the icons.\nYou can zoom in and out using the magnifying" + " glasses on the toolbar.\n(Tip: Hold the magnify button down for a" + " few seconds to zoom to a predefined scale)" ); + QWhatsThis::add( _grid, str ); + + if(props->bgMode() == FixedPixmap) + { + QPixmap pix(props->bgPixmap()); + if(pix.isNull()) + { + QPixmap pmlogo((const char **)logo); + pix = pmlogo; + } + viewport->viewport()->setBackgroundPixmap(pix); + _grid->setBackgroundPixmap(pix); + } + else + { + viewport->viewport()->setBackgroundColor(props->bgColor()); + } + + _corner = new QFrame(this); + _corner->setFrameStyle(QFrame::WinPanel | QFrame::Raised); + + _hruler = new KRuler(Qt::Horizontal, this); + _hruler->setEndLabel(i18n("width")); + _hruler->setOffset( -2 ); + _hruler->setRange(0, 1000); + + _vruler = new KRuler(Qt::Vertical, this); + _vruler->setEndLabel(i18n("height")); + _vruler->setOffset( -2 ); + _vruler->setRange(0, 1000); + + str = i18n( "Rulers\n\nThis is a visual representation of the current" + " cursor position" ); + QWhatsThis::add( _hruler, str ); + QWhatsThis::add( _vruler, str ); + + connect(_grid, SIGNAL(scalingchanged(int)), SLOT(scalingChange(int))); + connect(_grid, SIGNAL(sizechanged(int, int)), SLOT(sizeChange(int, int))); + connect(_grid, SIGNAL(needPainting()), SLOT(paintGrid())); + connect( _grid, SIGNAL(xposchanged(int)), _hruler, SLOT(slotNewValue(int)) ); + connect( _grid, SIGNAL(yposchanged(int)), _vruler, SLOT(slotNewValue(int)) ); + connect(viewport, SIGNAL(contentsMoving(int, int)), SLOT(moving(int, int))); + + setSizes(); + QResizeEvent e(size(), size()); + resizeEvent(&e); +} + +void KGridView::paintGrid() +{ + _grid->update(viewRect()); +} + +void KGridView::setSizes() +{ + if(KIconEditProperties::self()->showRulers()) + { + _hruler->setLittleMarkDistance(_grid->scaling()); + _vruler->setLittleMarkDistance(_grid->scaling()); + + _hruler->setMediumMarkDistance(5); + _vruler->setMediumMarkDistance(5); + + _hruler->setBigMarkDistance(10); + _vruler->setBigMarkDistance(10); + + _hruler->setShowTinyMarks(true); + _hruler->setShowLittleMarks(false); + _hruler->setShowMediumMarks(true); + _hruler->setShowBigMarks(true); + _hruler->setShowEndMarks(true); + + _vruler->setShowTinyMarks(true); + _vruler->setShowLittleMarks(false); + _vruler->setShowMediumMarks(true); + _vruler->setShowBigMarks(true); + _vruler->setShowEndMarks(true); + + _hruler->setPixelPerMark(_grid->scaling()); + _vruler->setPixelPerMark(_grid->scaling()); + + _hruler->setMaxValue(_grid->width()+20); + _vruler->setMaxValue(_grid->height()+20); + + _hruler->show(); + _vruler->show(); + + _corner->show(); + //resize(_grid->width()+_vruler->width(), _grid->height()+_hruler->height()); + } + else + { + _hruler->hide(); + _vruler->hide(); + _corner->hide(); + //resize(_grid->size()); + } +} + +void KGridView::sizeChange(int, int) +{ + setSizes(); +} + +void KGridView::moving(int x, int y) +{ + _hruler->setOffset(abs(x)); + _vruler->setOffset(abs(y)); +} + +void KGridView::scalingChange(int) +{ + setSizes(); +} + +void KGridView::setShowRulers(bool mode) +{ + KIconEditProperties::self()->setShowRulers( mode ); + setSizes(); + QResizeEvent e(size(), size()); + resizeEvent(&e); +} + +void KGridView::setAcceptDrop(bool a) +{ + if(a == acceptdrop) return; + acceptdrop = a; + paintDropSite(); +} + +void KGridView::checkClipboard() +{ + _grid->checkClipboard(); +} + +const QRect KGridView::viewRect() +{ + int x, y, cx, cy; + if(viewport->horizontalScrollBar()->isVisible()) + { + x = viewport->contentsX(); + cx = viewport->viewport()->width(); + } + else + { + x = 0; + cx = viewport->contentsWidth(); + } + + if(viewport->verticalScrollBar()->isVisible()) + { + y = viewport->contentsY(); + cy = viewport->viewport()->height(); + } + else + { + y = 0; + cy = viewport->contentsHeight(); + } + + return QRect(x, y, cx, cy); +} + +void KGridView::paintDropSite() +{ + QPainter p; + p.begin( _grid ); + p.setRasterOp (NotROP); + p.drawRect(viewRect()); + p.end(); +} + +void KGridView::paintEvent(QPaintEvent *) +{ + if(acceptdrop) + paintDropSite(); +} + + +void KGridView::resizeEvent(QResizeEvent*) +{ + kdDebug(4640) << "KGridView::resizeEvent" << endl; + + setSizes(); + + if(KIconEditProperties::self()->showRulers()) + { + _hruler->setGeometry(_vruler->width(), 0, width(), _hruler->height()); + _vruler->setGeometry(0, _hruler->height(), _vruler->width(), height()); + + _corner->setGeometry(0, 0, _vruler->width(), _hruler->height()); + viewport->setGeometry(_corner->width(), _corner->height(), + width()-_corner->width(), height()-_corner->height()); + } + else + viewport->setGeometry(0, 0, width(), height()); +} + + +KIconEditGrid::KIconEditGrid(QImage *image, KCommandHistory* h, QWidget *parent, const char *name) + : KColorGrid(parent, name, 1) +{ + img = image; + history = h; + selected = 0; + m_command = 0; + + // the 42 normal kde colors - there can be an additional + // 18 custom colors in the custom colors palette + for(uint i = 0; i < 42; i++) + iconcolors.append(iconpalette[i]); + + setupImageHandlers(); + btndown = isselecting = ispasting = modified = false; + + img->create(32, 32, 32); + img->setAlphaBuffer(true); + clearImage(img); + + currentcolor = qRgb(0,0,0)|OPAQUE_MASK; + emit colorSelected(currentcolor); + + setMouseTracking(true); + + setNumRows(32); + setNumCols(32); + fill(TRANSPARENT); + + connect( kapp->clipboard(), SIGNAL(dataChanged()), SLOT(checkClipboard())); + connect( h, SIGNAL(commandExecuted()), this, SLOT(updatePreviewPixmap() )); + createCursors(); + + KIconEditProperties *props = KIconEditProperties::self(); + + setTransparencyDisplayType(props->transparencyDisplayType()); + setTransparencySolidColor(props->transparencySolidColor()); + setCheckerboardColor1(props->checkerboardColor1()); + setCheckerboardColor2(props->checkerboardColor2()); + setCheckerboardSize(props->checkerboardSize()); +} + +KIconEditGrid::~KIconEditGrid() +{ + kdDebug(4640) << "KIconEditGrid - destructor: done" << endl; +} + +void KIconEditGrid::paintEvent(QPaintEvent *e) +{ + const QRect cellsRect(0, 0, numCols() * cellSize(), numRows() * cellSize()); + const QRect paintCellsRect = cellsRect.intersect(e->rect()); + + if(!paintCellsRect.isEmpty()) + { + //QTime time; + + //time.start(); + + QRgb *imageBuffer = new QRgb[paintCellsRect.width() * paintCellsRect.height()]; + const int cellsize = cellSize(); + const int firstCellPixelsRemaining = cellsize - paintCellsRect.left() % cellsize; + + if(transparencyDisplayType() == TRD_SOLIDCOLOR) + { + const QRgb backgroundColor = transparencySolidColor().rgb(); + const int backgroundRed = transparencySolidColor().red(); + const int backgroundGreen = transparencySolidColor().green(); + const int backgroundBlue = transparencySolidColor().blue(); + const int firstCellX = paintCellsRect.left() / cellsize; + + for(int y = paintCellsRect.top(); y <= paintCellsRect.bottom(); y++) + { + QRgb *dest = imageBuffer + (y - paintCellsRect.top()) * paintCellsRect.width(); + + if(y % cellsize == 0 || dest == imageBuffer) + { + // Paint the first scanline in each block of cellSize() identical lines. + // The remaineder can just be copied from this one. + const int cellY = y / cellsize; + QRgb *src = gridcolors.data() + cellY * numCols() + firstCellX; + + QRgb sourcePixel = *src++; + int sourceAlpha = qAlpha(sourcePixel); + + QRgb c; + + if(sourceAlpha == 255) + { + c = sourcePixel; + } + else + if(sourceAlpha == 0) + { + c = backgroundColor; + } + else + { + const int sourceRed = qRed(sourcePixel); + const int sourceGreen = qGreen(sourcePixel); + const int sourceBlue = qBlue(sourcePixel); + + int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80; + r = backgroundRed + ((r + (r >> 8)) >> 8); + + int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80; + g = backgroundGreen + ((g + (g >> 8)) >> 8); + + int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80; + b = backgroundBlue + ((b + (b >> 8)) >> 8); + + c = qRgb(r, g, b); + } + + int cellPixelsRemaining = firstCellPixelsRemaining; + + for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++) + { + if(cellPixelsRemaining == 0) + { + cellPixelsRemaining = cellsize; + + // Fetch the next source pixel + sourcePixel = *src++; + sourceAlpha = qAlpha(sourcePixel); + + if(sourceAlpha == 255) + { + c = sourcePixel; + } + else + if(sourceAlpha == 0) + { + c = backgroundColor; + } + else + { + const int sourceRed = qRed(sourcePixel); + const int sourceGreen = qGreen(sourcePixel); + const int sourceBlue = qBlue(sourcePixel); + + //int r = backgroundRed + (sourceAlpha * (sourceRed - backgroundRed)) / 255; + //int g = backgroundGreen + (sourceAlpha * (sourceGreen - backgroundGreen)) / 255; + //int b = backgroundBlue + (sourceAlpha * (sourceBlue - backgroundBlue)) / 255; + + int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80; + r = backgroundRed + ((r + (r >> 8)) >> 8); + + int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80; + g = backgroundGreen + ((g + (g >> 8)) >> 8); + + int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80; + b = backgroundBlue + ((b + (b >> 8)) >> 8); + + c = qRgb(r, g, b); + } + } + + cellPixelsRemaining--; + + *dest++ = c; + } + } + else + { + // Copy the scanline above. + memcpy(dest, dest - paintCellsRect.width(), paintCellsRect.width() * sizeof(QRgb)); + } + } + } + else + { + int squareSize; + const int fixedPointMultiplier = 4; + + if(checkerboardSize() == CHK_SMALL) + { + squareSize = (cellSize() * fixedPointMultiplier) / 4; + } + else + if(checkerboardSize() == CHK_MEDIUM) + { + squareSize = (cellSize() * fixedPointMultiplier) / 2; + } + else + { + squareSize = (2 * cellSize() * fixedPointMultiplier) / 2; + } + + QRgb *color1ScanLine = new QRgb[paintCellsRect.width()]; + QRgb *color2ScanLine = new QRgb[paintCellsRect.width()]; + QRgb *color1Buffer = color1ScanLine; + QRgb *color2Buffer = color2ScanLine; + + for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++) + { + if((((x * fixedPointMultiplier) / squareSize) & 1) == 0) + { + *color1Buffer++ = checkerboardColor1().rgb(); + *color2Buffer++ = checkerboardColor2().rgb(); + } + else + { + *color1Buffer++ = checkerboardColor2().rgb(); + *color2Buffer++ = checkerboardColor1().rgb(); + } + } + + const int firstCellX = paintCellsRect.left() / cellsize; + const int firstCellPixelsRemaining = cellsize - paintCellsRect.left() % cellsize; + int lastCellY = -1; + int lastLineFirstSquareColour = 0; + + for(int y = paintCellsRect.top(); y <= paintCellsRect.bottom(); y++) + { + QRgb *dest = imageBuffer + (y - paintCellsRect.top()) * paintCellsRect.width(); + const int cellY = y / cellsize; + + int firstSquareColour; + const QRgb *checkerboardSrc; + + if((((y * fixedPointMultiplier) / squareSize) & 1) == 0) + { + firstSquareColour = 1; + checkerboardSrc = color1ScanLine; + } + else + { + firstSquareColour = 2; + checkerboardSrc = color2ScanLine; + } + + if(cellY == lastCellY && firstSquareColour == lastLineFirstSquareColour) + { + // Copy the scanline above. + memcpy(dest, dest - paintCellsRect.width(), paintCellsRect.width() * sizeof(QRgb)); + } + else + { + QRgb *src = gridcolors.data() + cellY * numCols() + firstCellX; + + QRgb sourcePixel = *src++; + int sourceRed = qRed(sourcePixel); + int sourceGreen = qGreen(sourcePixel); + int sourceBlue = qBlue(sourcePixel); + int sourceAlpha = qAlpha(sourcePixel); + + int cellPixelsRemaining = firstCellPixelsRemaining; + + for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++) + { + if(cellPixelsRemaining == 0) + { + cellPixelsRemaining = cellsize; + + // Fetch the next source pixel + sourcePixel = *src++; + sourceRed = qRed(sourcePixel); + sourceGreen = qGreen(sourcePixel); + sourceBlue = qBlue(sourcePixel); + sourceAlpha = qAlpha(sourcePixel); + } + + cellPixelsRemaining--; + + QRgb c; + + if(sourceAlpha == 255) + { + c = sourcePixel; + } + else + if(sourceAlpha == 0) + { + c = *checkerboardSrc; + } + else + { + const int backgroundColor = *checkerboardSrc; + const int backgroundRed = qRed(backgroundColor); + const int backgroundGreen = qGreen(backgroundColor); + const int backgroundBlue = qBlue(backgroundColor); + + //int r = backgroundRed + (sourceAlpha * (sourceRed - backgroundRed)) / 255; + //int g = backgroundGreen + (sourceAlpha * (sourceGreen - backgroundGreen)) / 255; + //int b = backgroundBlue + (sourceAlpha * (sourceBlue - backgroundBlue)) / 255; + + int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80; + r = backgroundRed + ((r + (r >> 8)) >> 8); + + int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80; + g = backgroundGreen + ((g + (g >> 8)) >> 8); + + int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80; + b = backgroundBlue + ((b + (b >> 8)) >> 8); + + c = qRgb(r, g, b); + } + + *dest++ = c; + checkerboardSrc++; + } + } + + lastCellY = cellY; + lastLineFirstSquareColour = firstSquareColour; + } + + delete [] color1ScanLine; + delete [] color2ScanLine; + } + + QImage image((uchar *)(imageBuffer), paintCellsRect.width(), paintCellsRect.height(), 32, 0, 0, +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + QImage::LittleEndian); +#else + QImage::BigEndian); +#endif + Q_ASSERT(!image.isNull()); + + QPixmap _pixmap; + _pixmap.convertFromImage(image); + + QPainter p; + p.begin(&_pixmap); + paintForeground(&p, e); + p.end(); + + bitBlt(this, paintCellsRect.left(), paintCellsRect.top(), &_pixmap); + + //kdDebug(4640) << "Image render elapsed: " << time.elapsed() << endl; + + delete [] imageBuffer; + } +} + +void KIconEditGrid::paintForeground(QPainter* p, QPaintEvent* e) +{ + QWMatrix matrix; + + matrix.translate(-e->rect().x(), -e->rect().y()); + p->setWorldMatrix( matrix ); + + QRect cellsRect(0, 0, numCols() * cellSize(), numRows() * cellSize()); + QRect paintCellsRect = cellsRect.intersect(e->rect()); + + if(!paintCellsRect.isEmpty()) + { + int firstColumn = paintCellsRect.left() / cellSize(); + int lastColumn = paintCellsRect.right() / cellSize(); + + int firstRow = paintCellsRect.top() / cellSize(); + int lastRow = paintCellsRect.bottom() / cellSize(); + + p->setPen(QColor(0, 0, 0)); + p->setBrush(QColor(0, 0, 0)); + + for(int column = firstColumn; column <= lastColumn; column++) + { + for(int row = firstRow; row <= lastRow; row++) + { + int x = column * cellSize(); + int y = row * cellSize(); + + if((ispasting || isselecting) && isMarked(column, row)) + { + p->drawWinFocusRect(x + 1, y + 1, cellSize() - 2, cellSize() - 2); + } + else + { + switch( tool ) + { + case FilledRect: + case Rect: + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + case Line: + if(btndown && isMarked(column, row)) + { + if(cellSize() > 1) + { + p->drawWinFocusRect( x + 1, y + 1, cellSize() - 2, cellSize() - 2); + } + else + { + p->drawPoint(x, y); + } + } + break; + + default: + break; + } + } + } + } + } + + if(hasGrid()&& !(cellSize()==1)) + { + p->setPen(QColor(0, 0, 0)); + int x = e->rect().x() - ((e->rect().x() % cellSize()) + cellSize()); + if(x < 0) x = 0; + int y = e->rect().y() - ((e->rect().y() % cellSize()) + cellSize()); + if(y < 0) y = 0; + int cx = e->rect().right() + cellSize(); + int cy = e->rect().bottom() + cellSize(); + + // draw grid lines + for(int i = x; i < cx; i += cellSize()) + p->drawLine(i, y, i, cy); + + for(int i = y; i < cy; i += cellSize()) + p->drawLine(x, i, cx, i); + } +} + +void KIconEditGrid::mousePressEvent( QMouseEvent *e ) +{ + if(!e || (e->button() != LeftButton)) + return; + + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + //int cell = row * numCols() + col; + + if(!img->valid(col, row)) + return; + + btndown = true; + start.setX(col); + start.setY(row); + + if(ispasting) + { + ispasting = false; + editPaste(true); + } + + if(isselecting) + { + QPointArray a(pntarray.copy()); + pntarray.resize(0); + drawPointArray(a, Mark); + emit selecteddata(false); + } + + switch( tool ) + { + case SelectRect: + case SelectCircle: + isselecting = true; + break; + default: + break; + } +} + +void KIconEditGrid::mouseMoveEvent( QMouseEvent *e ) +{ + if(!e) return; + + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + int cell = row * numCols() + col; + + if(img->valid(col, row)) + { + //kdDebug(4640) << col << " X " << row << endl; + emit poschanged(col, row); + // for the rulers + emit xposchanged((col*scaling())+scaling()/2); + emit yposchanged((row*scaling())+scaling()/2); + } + + QPoint tmpp(col, row); + if(tmpp == end) return; + + // need to use intersection of rectangles to allow pasting + // only that part of clip image which intersects -jwc- + if(ispasting && !btndown && img->valid(col, row)) + { + if( (col + cbsize.width()) > (numCols()-1) ) + insrect.setX(numCols()-insrect.width()); + else + insrect.setX(col); + if( (row + cbsize.height()) > (numRows()-1) ) + insrect.setY(numRows()-insrect.height()); + else + insrect.setY(row); + + insrect.setSize(cbsize); + start = insrect.topLeft(); + end = insrect.bottomRight(); + drawRect(false); + return; + } + + if(!img->valid(col, row) || !btndown) + return; + + end.setX(col); + end.setY(row); + + if(isselecting) + { + if(tool == SelectRect) + drawRect(false); + else + drawEllipse(false); + return; + } + + bool erase=false; + switch( tool ) + { + case Eraser: + erase=true; + + case Freehand: + { + if( !m_command ) + m_command = new KMacroCommand( i18n("Free Hand") ); + + if(erase) + setColor( cell, TRANSPARENT ); + else + setColor( cell, currentcolor ); + + if ( selected != cell ) + { + setModified( true ); + int prevSel = selected; + selected = cell; + QRect area = QRect( col*cellsize,row*cellsize, cellsize, cellsize ).unite( + QRect ( (prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize ) ); + + m_command->addCommand( new RepaintCommand( area, this ) ); + DrawCommand* dc = new DrawCommand( col, row, colorAt(cell), img, this ); + RepaintCommand* rp = new RepaintCommand( area, this ); + dc->execute(); + rp->execute(); + m_command->addCommand( dc ); + m_command->addCommand( rp ); + } + break; + } + case Find: + { + iconcolors.closestMatch(colorAt(cell)); + if ( selected != cell ) + { + int prevSel = selected; + selected = cell; + update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize); + update(col*cellsize,row*cellsize, cellsize, cellsize); + emit colorSelected(colorAt(selected)); + } + break; + } + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + { + drawEllipse(false); + break; + } + case FilledRect: + case Rect: + { + drawRect(false); + break; + } + case Line: + { + drawLine(false, false); + break; + } + case Spray: + { + drawSpray(QPoint(col, row)); + setModified(true); + break; + } + default: + break; + } + + p = *img; + emit changed(QPixmap(p)); +} + +void KIconEditGrid::mouseReleaseEvent( QMouseEvent *e ) +{ + if(!e || (e->button() != LeftButton)) + return; + + int row = findRow( e->pos().y() ); + int col = findCol( e->pos().x() ); + btndown = false; + end.setX(col); + end.setY(row); + int cell = row * numCols() + col; + bool erase=false; + switch( tool ) + { + case Eraser: + erase=true; + //currentcolor = TRANSPARENT; + case Freehand: + { + if(!img->valid(col, row)) + return; + if(erase) + setColor( cell, TRANSPARENT ); + else + setColor( cell, currentcolor ); + //if ( selected != cell ) + //{ + setModified( true ); + int prevSel = selected; + selected = cell; + update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize); + update(col*cellsize,row*cellsize, cellsize, cellsize); + //updateCell( prevSel/numCols(), prevSel%numCols(), FALSE ); + //updateCell( row, col, FALSE ); + *((uint*)img->scanLine(row) + col) = colorAt(cell); + p = *img; + //} + + if( m_command ) { + history->addCommand( m_command, false ); + m_command = 0; + } + + break; + } + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + { + drawEllipse(true); + break; + } + case FilledRect: + case Rect: + { + drawRect(true); + break; + } + case Line: + { + drawLine(true, false); + break; + } + case Spray: + { + drawSpray(QPoint(col, row)); + break; + } + case FloodFill: + { + QApplication::setOverrideCursor(waitCursor); + drawFlood(col, row, colorAt(cell)); + QApplication::restoreOverrideCursor(); + updateColors(); + emit needPainting(); + p = *img; + break; + } + case Find: + { + currentcolor = colorAt(cell); + if ( selected != cell ) + { + int prevSel = selected; + selected = cell; + update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize); + update(col*cellsize,row*cellsize, cellsize, cellsize); + emit colorSelected(currentcolor); + //updateCell( prevSel/numCols(), prevSel%numCols(), FALSE ); + //updateCell( row, col, FALSE ); + } + + break; + } + default: + break; + } + + emit changed(QPixmap(p)); + //emit colorschanged(numColors(), data()); +} + +//void KIconEditGrid::setColorSelection( const QColor &color ) +void KIconEditGrid::setColorSelection( uint c ) +{ + currentcolor = c; + emit colorSelected(currentcolor); +} + +void KIconEditGrid::loadBlank( int w, int h ) +{ + img->create(w, h, 32); + img->setAlphaBuffer(true); + clearImage(img); + setNumRows(h); + setNumCols(w); + fill(TRANSPARENT); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + history->clear(); +} + + + +void KIconEditGrid::load( QImage *image) +{ + kdDebug(4640) << "KIconEditGrid::load" << endl; + + setUpdatesEnabled(false); + + if(image == 0L) + { + QString msg = i18n("There was an error loading a blank image.\n"); + KMessageBox::error(this, msg); + return; + } + + *img = image->convertDepth(32); + img->setAlphaBuffer(true); + setNumRows(img->height()); + setNumCols(img->width()); + + for(int y = 0; y < numRows(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < numCols(); x++, l++) + { + setColor((y*numCols())+x, *l, false); + } + //kdDebug(4640) << "Row: " << y << endl; + kapp->processEvents(200); + } + + updateColors(); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + emit changed(pixmap()); + setUpdatesEnabled(true); + emit needPainting(); + //repaint(viewRect(), false); + history->clear(); +} + +const QPixmap &KIconEditGrid::pixmap() +{ + if(!img->isNull()) + p = *img; + //p.convertFromImage(*img, 0); + return(p); +} + +void KIconEditGrid::getImage(QImage *image) +{ + kdDebug(4640) << "KIconEditGrid::getImage" << endl; + *image = *img; +} + +bool KIconEditGrid::zoomTo(int scale) +{ + QApplication::setOverrideCursor(waitCursor); + setUpdatesEnabled(false); + setCellSize( scale ); + setUpdatesEnabled(true); + emit needPainting(); + QApplication::restoreOverrideCursor(); + emit scalingchanged(cellSize()); + + if(scale == 1) + return false; + return true; +} + +bool KIconEditGrid::zoom(Direction d) +{ + int f = (d == DirIn) ? (cellSize()+1) : (cellSize()-1); + QApplication::setOverrideCursor(waitCursor); + setUpdatesEnabled(false); + setCellSize( f ); + setUpdatesEnabled(true); + //emit needPainting(); + QApplication::restoreOverrideCursor(); + + emit scalingchanged(cellSize()); + if(d == DirOut && cellSize() <= 1) + return false; + return true; +} + +void KIconEditGrid::checkClipboard() +{ + bool ok = false; + QImage tmp = clipboardImage(ok); + if(ok) + emit clipboarddata(true); + else + { + emit clipboarddata(false); + } +} + +QImage KIconEditGrid::clipboardImage(bool &ok) +{ + //###### Remove me later. + //Workaround Qt bug -- check whether format provided first. + //Code below is from QDragObject, to match the mimetype list.... + + QStrList fileFormats = QImageIO::inputFormats(); + fileFormats.first(); + bool oneIsSupported = false; + while ( fileFormats.current() ) + { + QCString format = fileFormats.current(); + QCString type = "image/" + format.lower(); + if (kapp->clipboard()->data()->provides(type ) ) + { + oneIsSupported = true; + } + fileFormats.next(); + } + if (!oneIsSupported) + { + ok = false; + return QImage(); + } + + QImage image = kapp->clipboard()->image(); + ok = !image.isNull(); + if ( ok ) + { + image = image.convertDepth(32); + image.setAlphaBuffer(true); + } + return image; +} + + +void KIconEditGrid::editSelectAll() +{ + start.setX(0); + start.setY(0); + end.setX(numCols()-1); + end.setY(numRows()-1); + isselecting = true; + drawRect(false); + emit newmessage(i18n("All selected")); +} + +void KIconEditGrid::editClear() +{ + clearImage(img); + fill(TRANSPARENT); + update(); + setModified(true); + p = *img; + emit changed(p); + emit newmessage(i18n("Cleared")); +} + +QImage KIconEditGrid::getSelection(bool cut) +{ + const QRect rect = pntarray.boundingRect(); + int nx = 0, ny = 0, nw = 0, nh = 0; + rect.rect(&nx, &ny, &nw, &nh); + + QImage tmp(nw, nh, 32); + tmp.setAlphaBuffer(true); + clearImage(&tmp); + + int s = pntarray.size(); + + for(int i = 0; i < s; i++) + { + int x = pntarray[i].x(); + int y = pntarray[i].y(); + if(img->valid(x, y) && rect.contains(QPoint(x, y))) + { + *((uint*)tmp.scanLine(y-ny) + (x-nx)) = *((uint*)img->scanLine(y) + x); + if(cut) + { + *((uint*)img->scanLine(y) + x) = TRANSPARENT; + setColor( (y*numCols()) + x, TRANSPARENT, false ); + } + } + } + + QPointArray a(pntarray.copy()); + pntarray.resize(0); + drawPointArray(a, Mark); + emit selecteddata(false); + if(cut) + { + updateColors(); + update(rect.x()*cellSize(), rect.y()*cellSize(), + rect.width()*cellSize(), rect.height()*cellSize()); + p = *img; + emit changed(p); + emit colorschanged(numColors(), data()); + emit newmessage(i18n("Selected area cut")); + setModified(true); + } + else + emit newmessage(i18n("Selected area copied")); + + return tmp; +} + +void KIconEditGrid::editCopy(bool cut) +{ + kapp->clipboard()->setImage(getSelection(cut)); + isselecting = false; +} + + +void KIconEditGrid::editPaste(bool paste) +{ + bool ok = false; + QImage tmp = clipboardImage(ok); + + KIconEditProperties *props = KIconEditProperties::self(); + + if(ok) + { + if( (tmp.size().width() > img->size().width()) + || (tmp.size().height() > img->size().height()) ) + { + if(KMessageBox::warningYesNo(this, + i18n("The clipboard image is larger than the current" + " image!\nPaste as new image?"),QString::null,i18n("Paste"), i18n("Do Not Paste")) == 0) + { + editPasteAsNew(); + } + return; + } + else if(!paste) + { + ispasting = true; + cbsize = tmp.size(); + return; + // emit newmessage(i18n("Pasting")); + } + else + { + //kdDebug(4640) << "KIconEditGrid: Pasting at: " << insrect.x() << " x " << insrect.y() << endl; + QApplication::setOverrideCursor(waitCursor); + + for(int y = insrect.y(), ny = 0; y < numRows() && ny < insrect.height(); y++, ny++) + { + uint *l = ((uint*)img->scanLine(y)+insrect.x()); + uint *cl = (uint*)tmp.scanLine(ny); + for(int x = insrect.x(), nx = 0; x < numCols() && nx < insrect.width(); x++, nx++, l++, cl++) + { + if(props->pasteTransparent()) + { + *l = *cl; + } + else + { + // Porter-Duff Over composition + double alphaS = qAlpha(*cl) / 255.0; + double alphaD = qAlpha(*l) / 255.0; + + double r = qRed(*cl) * alphaS + (1 - alphaS) * qRed(*l) * alphaD; + double g = qGreen(*cl) * alphaS + (1 - alphaS) * qGreen(*l) * alphaD; + double b = qBlue(*cl) * alphaS + (1 - alphaS) * qBlue(*l) * alphaD; + double a = alphaS + (1 - alphaS) * alphaD; + + // Remove multiplication by alpha + + if(a > 0) + { + r /= a; + g /= a; + b /= a; + } + else + { + r = 0; + g = 0; + b = 0; + } + + int ir = (int)(r + 0.5); + + if(ir < 0) + { + ir = 0; + } + else + if(ir > 255) + { + ir = 255; + } + + int ig = (int)(g + 0.5); + + if(ig < 0) + { + ig = 0; + } + else + if(ig > 255) + { + ig = 255; + } + + int ib = (int)(b + 0.5); + + if(ib < 0) + { + ib = 0; + } + else + if(ib > 255) + { + ib = 255; + } + + int ia = (int)((a * 255) + 0.5); + + if(ia < 0) + { + ia = 0; + } + else + if(ia > 255) + { + ia = 255; + } + + *l = qRgba(ir, ig, ib, ia); + } + + setColor((y*numCols())+x, (uint)*l, false); + } + } + updateColors(); + update(insrect.x()*cellSize(), insrect.y()*cellSize(), + insrect.width()*cellSize(), insrect.height()*cellSize()); + + QApplication::restoreOverrideCursor(); + + setModified(true); + p = *img; + emit changed(QPixmap(p)); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + emit newmessage(i18n("Done pasting")); + } + } + else + { + QString msg = i18n("Invalid pixmap data in clipboard!\n"); + KMessageBox::sorry(this, msg); + } +} + + +void KIconEditGrid::editPasteAsNew() +{ + bool ok = false; + QImage tmp = clipboardImage(ok); + + if(ok) + { + if(isModified()) + { + KIconEdit *w = new KIconEdit(tmp); + Q_CHECK_PTR(w); + } + else + { + *img = tmp; + load(img); + setModified(true); + //repaint(viewRect(), false); + + p = *img; + emit changed(QPixmap(p)); + emit sizechanged(numCols(), numRows()); + emit colorschanged(numColors(), data()); + emit newmessage(i18n("Done pasting")); + history->clear(); + } + } + else + { + QString msg = i18n("Invalid pixmap data in clipboard!\n"); + KMessageBox::error(this, msg); + } +} + + +void KIconEditGrid::editResize() +{ + kdDebug(4640) << "KIconGrid::editResize" << endl; + KResizeDialog *rs = new KResizeDialog(this, 0, QSize(numCols(), numRows())); + if(rs->exec()) + { + const QSize s = rs->getSize(); + *img = img->smoothScale(s.width(), s.height()); + load(img); + + setModified(true); + } + delete rs; +} + + +void KIconEditGrid::setSize(const QSize s) +{ + kdDebug(4640) << "::setSize: " << s.width() << " x " << s.height() << endl; + + img->create(s.width(), s.height(), 32); + img->setAlphaBuffer(true); + clearImage(img); + load(img); +} + + +void KIconEditGrid::createCursors() +{ + QBitmap mask(22, 22); + QPixmap pix; + + cursor_normal = QCursor(arrowCursor); + + pix = BarIcon("colorpicker-cursor"); + if(pix.isNull()) + { + cursor_colorpicker = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading colorpicker-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_colorpicker = QCursor(pix, 1, 21); + } + + pix = BarIcon("paintbrush-cursor"); + if(pix.isNull()) + { + cursor_paint = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading paintbrush.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_paint = QCursor(pix, 0, 19); + } + + pix = BarIcon("fill-cursor"); + if(pix.isNull()) + { + cursor_flood = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading fill-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_flood = QCursor(pix, 3, 20); + } + + pix = BarIcon("aim-cursor"); + if(pix.isNull()) + { + cursor_aim = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading aim-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(); + pix.setMask(mask); + cursor_aim = QCursor(pix, 10, 10); + } + + pix = BarIcon("airbrush-cursor"); + if(pix.isNull()) + { + cursor_spray = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading airbrush-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(true); + pix.setMask(mask); + cursor_spray = QCursor(pix, 0, 20); + } + + pix = BarIcon("eraser-cursor"); + if(pix.isNull()) + { + cursor_erase = cursor_normal; + kdDebug(4640) << "KIconEditGrid: Error loading eraser-cursor.xpm" << endl; + } + else + { + mask = pix.createHeuristicMask(true); + pix.setMask(mask); + cursor_erase = QCursor(pix, 1, 16); + } +} + + + +void KIconEditGrid::setTool(DrawTool t) +{ + btndown = false; + tool = t; + + if(tool != SelectRect && tool != SelectCircle) + isselecting = false; + + switch( tool ) + { + case SelectRect: + isselecting = true; + setCursor(cursor_aim); + break; + case SelectCircle: + isselecting = true; + setCursor(cursor_aim); + break; + case Line: + case Ellipse: + case Circle: + case FilledEllipse: + case FilledCircle: + case FilledRect: + case Rect: + setCursor(cursor_aim); + break; + case Freehand: + setCursor(cursor_paint); + break; + case Spray: + setCursor(cursor_spray); + break; + case Eraser: + setCursor(cursor_erase); + break; + case FloodFill: + setCursor(cursor_flood); + break; + case Find: + setCursor(cursor_colorpicker); + break; + default: + break; + } +} + + +void KIconEditGrid::drawFlood(int x, int y, uint oldcolor) +{ + if((!img->valid(x, y)) + || (colorAt((y * numCols())+x) != oldcolor) + || (colorAt((y * numCols())+x) == currentcolor)) + return; + + *((uint*)img->scanLine(y) + x) = currentcolor; + setColor((y*numCols())+x, currentcolor, false); + + setModified(true); + + drawFlood(x, y-1, oldcolor); + drawFlood(x, y+1, oldcolor); + drawFlood(x-1, y, oldcolor); + drawFlood(x+1, y, oldcolor); + //TODO: add undo +} + + +void KIconEditGrid::drawSpray(QPoint point) +{ + int x = (point.x()-5); + int y = (point.y()-5); + + //kdDebug(4640) << "drawSpray() - " << x << " X " << y << endl; + + pntarray.resize(0); + int points = 0; + for(int i = 1; i < 4; i++, points++) + { + int dx = (rand() % 10); + int dy = (rand() % 10); + pntarray.putPoints(points, 1, x+dx, y+dy); + } + + drawPointArray(pntarray, Draw); +} + + +//This routine is from Qt sources -- it's the branch of QPointArray::makeEllipse( int x, int y, int w, int h ) that's not normally compiled +//It seems like KIconEdit relied on the Qt1 semantics for makeEllipse, which broke +//the tool with reasonably recent Qt versions. +//Thankfully, Qt includes the old code #ifdef'd, which is hence included here +static void QPA_makeEllipse(QPointArray& ar, int x, int y, int w, int h ) +{ // midpoint, 1/4 ellipse + if ( w <= 0 || h <= 0 ) { + if ( w == 0 || h == 0 ) { + ar.resize( 0 ); + return; + } + if ( w < 0 ) { // negative width + w = -w; + x -= w; + } + if ( h < 0 ) { // negative height + h = -h; + y -= h; + } + } + int s = (w+h+2)/2; // max size of xx,yy array + int *px = new int[s]; // 1/4th of ellipse + int *py = new int[s]; + int xx, yy, i=0; + double d1, d2; + double a2=(w/2)*(w/2), b2=(h/2)*(h/2); + xx = 0; + yy = int(h/2); + d1 = b2 - a2*(h/2) + 0.25*a2; + px[i] = xx; + py[i] = yy; + i++; + while ( a2*(yy-0.5) > b2*(xx+0.5) ) { // region 1 + if ( d1 < 0 ) { + d1 = d1 + b2*(3.0+2*xx); + xx++; + } else { + d1 = d1 + b2*(3.0+2*xx) + 2.0*a2*(1-yy); + xx++; + yy--; + } + px[i] = xx; + py[i] = yy; + i++; + } + d2 = b2*(xx+0.5)*(xx+0.5) + a2*(yy-1)*(yy-1) - a2*b2; + while ( yy > 0 ) { // region 2 + if ( d2 < 0 ) { + d2 = d2 + 2.0*b2*(xx+1) + a2*(3-2*yy); + xx++; + yy--; + } else { + d2 = d2 + a2*(3-2*yy); + yy--; + } + px[i] = xx; + py[i] = yy; + i++; + } + s = i; + ar.resize( 4*s ); // make full point array + x += w/2; + y += h/2; + for ( i=0; i<s; i++ ) { // mirror + xx = px[i]; + yy = py[i]; + ar.setPoint( s-i-1, x+xx, y-yy ); + ar.setPoint( s+i, x-xx, y-yy ); + ar.setPoint( 3*s-i-1, x-xx, y+yy ); + ar.setPoint( 3*s+i, x+xx, y+yy ); + } + delete[] px; + delete[] py; +} + + + +void KIconEditGrid::drawEllipse(bool drawit) +{ + if(drawit) + { + drawPointArray(pntarray, Draw); + p = *img; + emit changed(p); + return; + } + + QPointArray a(pntarray.copy()); + int x = start.x(), y = start.y(), cx, cy; + + if(x > end.x()) + { + cx = x - end.x(); + x = x - cx; + } + else + cx = end.x() - x; + if(y > end.y()) + { + cy = y - end.y(); + y = y - cy; + } + else + cy = end.y() - y; + + int d = (cx > cy) ? cx : cy; + + //kdDebug(4640) << x << ", " << y << " - " << d << " " << d << endl; + pntarray.resize(0); + drawPointArray(a, Mark); + + if(tool == Circle || tool == FilledCircle || tool == SelectCircle) + QPA_makeEllipse(pntarray, x, y, d, d); + else if(tool == Ellipse || tool == FilledEllipse) + QPA_makeEllipse(pntarray, x, y, cx, cy); + + if((tool == FilledEllipse) || (tool == FilledCircle) + || (tool == SelectCircle)) + { + int s = pntarray.size(); + int points = s; + for(int i = 0; i < s; i++) + { + int x = pntarray[i].x(); + int y = pntarray[i].y(); + for(int j = 0; j < s; j++) + { + if((pntarray[j].y() == y) && (pntarray[j].x() > x)) + { + for(int k = x; k < pntarray[j].x(); k++, points++) + pntarray.putPoints(points, 1, k, y); + break; + } + } + } + } + + drawPointArray(pntarray, Mark); + + if(tool == SelectCircle && pntarray.size() > 0 && !ispasting) + emit selecteddata(true); +} + + +void KIconEditGrid::drawRect(bool drawit) +{ + if(drawit) + { + drawPointArray(pntarray, Draw); + p = *img; + emit changed(p); + return; + } + + QPointArray a(pntarray.copy()); + int x = start.x(), y = start.y(), cx, cy; + + if(x > end.x()) + { + cx = x - end.x(); + x = x - cx; + } + else + cx = end.x() - x; + if(y > end.y()) + { + cy = y - end.y(); + y = y - cy; + } + else + cy = end.y() - y; + + //kdDebug(4640) << x << ", " << y << " - " << cx << " " << cy << endl; + pntarray.resize(0); + drawPointArray(a, Mark); // remove previous marking + + int points = 0; + bool pasting = ispasting; + + if(tool == FilledRect || (tool == SelectRect)) + { + for(int i = x; i <= x + (pasting ? cx + 1 : cx); i++) + { + for(int j = y; j <= y+cy; j++, points++) + pntarray.putPoints(points, 1, i, j); + } + } + else + { + for(int i = x; i <= x+cx; i++, points++) + pntarray.putPoints(points, 1, i, y); + for(int i = y; i <= y+cy; i++, points++) + pntarray.putPoints(points, 1, x, i); + for(int i = x; i <= x+cx; i++, points++) + pntarray.putPoints(points, 1, i, y+cy); + for(int i = y; i <= y+cy; i++, points++) + pntarray.putPoints(points, 1, x+cx, i); + } + + drawPointArray(pntarray, Mark); + + if(tool == SelectRect && pntarray.size() > 0 && !ispasting) + emit selecteddata(true); +} + + +void KIconEditGrid::drawLine(bool drawit, bool drawStraight) +{ + if(drawit) + { + drawPointArray(pntarray, Draw); + p = *img; + emit changed(p); + return; + } + + QPointArray a(pntarray.copy()); + pntarray.resize(0); + + // remove previous marking + drawPointArray(a, Mark); + + int x, y, dx, dy, delta; + + dx = end.x() - start.x(); + dy = end.y() - start.y(); + x = start.x(); + y = start.y(); + + delta = QMAX(abs(dx), abs(dy)); + int deltaX = abs(dx); + int deltaY = abs(dy); + + if ((drawStraight) && (delta > 0)) + { + dx /= delta; + dy /= delta; + + for(int i = 0; i <= delta; i++) + { + pntarray.putPoints(i, 1, x, y); + x += dx; + y += dy; + } + } + + else if ((delta > 0) && (deltaX >= deltaY)) + { + for(int i = 0; i <= deltaX; i++) + { + pntarray.putPoints(i, 1, x, y); + + if(dx > 0) + x++; + else + x--; + + if(dy >= 0) + y = start.y() + (abs(start.x() - x) * deltaY) / deltaX; + else + y = start.y() - (abs(start.x() - x) * deltaY) / deltaX; + } + } + + else if ((delta > 0) && (deltaY > deltaX)) + { + for(int i = 0; i <= deltaY; i++) + { + pntarray.putPoints(i, 1, x, y); + + if(dy > 0) + y++; + else + y--; + + if(dx >= 0) + x = start.x() + (abs(start.y() - y) * deltaX) / deltaY; + else + x = start.x() - (abs(start.y() - y) * deltaX) / deltaY; + } + } + + drawPointArray(pntarray, Mark); +} + + +void KIconEditGrid::drawPointArray(QPointArray a, DrawAction action) +{ + QRect area( a.boundingRect().x()*cellSize()-1, a.boundingRect().y()*cellSize()-1, + a.boundingRect().width()*cellSize()+1, a.boundingRect().height()*cellSize()+1 ); + + KMacroCommand* macro = 0; + bool doupdate = false; + + if( a.size() > 0 && action == Draw ) { + // might cause a memmory leak, if + // macro is never used and never + // added to the history! TODO: Fix this + macro = new KMacroCommand( i18n("Drawn Array") ); + RepaintCommand* rc = new RepaintCommand( area, this ); + macro->addCommand( rc ); + } + + int s = a.size(); //((rect.size().width()) * (rect.size().height())); + for(int i = 0; i < s; i++) + { + int x = a[i].x(); + int y = a[i].y(); + + if(img->valid(x, y) && a.boundingRect().contains(a[ i ])) + { + //kdDebug(4640) << "x: " << x << " - y: " << y << endl; + switch( action ) + { + case Draw: + { + DrawCommand* dc = new DrawCommand( x, y, currentcolor, img, this ); + dc->execute(); + //*((uint*)img->scanLine(y) + x) = currentcolor; //colors[cell]|OPAQUE; + //int cell = y * numCols() + x; + //setColor( cell, currentcolor, false ); + doupdate = true; + //updateCell( y, x, FALSE ); + macro->addCommand( dc ); + break; + } + + case Mark: + case UnMark: + update(x*cellsize,y*cellsize, cellsize, cellsize); + //updateCell( y, x, true ); + break; + + default: + break; + } + } + } + + + if(doupdate) + { + setModified( true ); + updateColors(); + RepaintCommand* rc = new RepaintCommand( area, this ); + rc->execute(); + macro->addCommand( rc ); + pntarray.resize(0); + // add to undo/redo history + history->addCommand( macro, false ); } +} + +void KIconEditGrid::updatePreviewPixmap() +{ + p = *img; + emit changed(QPixmap(p)); +} + + +bool KIconEditGrid::isMarked(QPoint point) +{ + return isMarked(point.x(), point.y()); +} + + +bool KIconEditGrid::isMarked(int x, int y) +{ + if(((y * numCols()) + x) == selected) + return true; + + int s = pntarray.size(); + for(int i = 0; i < s; i++) + { + if(y == pntarray[i].y() && x == pntarray[i].x()) + return true; + } + + return false; +} + + +// Fast diffuse dither to 3x3x3 color cube +// Based on Qt's image conversion functions +static bool kdither_32_to_8( const QImage *src, QImage *dst ) +{ + register QRgb *p; + uchar *b; + int y; + + //printf("kconvert_32_to_8\n"); + + if ( !dst->create(src->width(), src->height(), 8, 256) ) { + kdWarning() << "OImage: destination image not valid" << endl; + return FALSE; + } + + int ncols = 256; + + static uint bm[16][16]; + static int init=0; + if (!init) + { + // Build a Bayer Matrix for dithering + init = 1; + int n, i, j; + + bm[0][0]=0; + + for (n=1; n<16; n*=2) + { + for (i=0; i<n; i++) + { + for (j=0; j<n; j++) + { + bm[i][j]*=4; + bm[i+n][j]=bm[i][j]+2; + bm[i][j+n]=bm[i][j]+3; + bm[i+n][j+n]=bm[i][j]+1; + } + } + } + + for (i=0; i<16; i++) + for (j=0; j<16; j++) + bm[i][j]<<=8; + } + + dst->setNumColors( ncols ); + +#define MAX_R 2 +#define MAX_G 2 +#define MAX_B 2 +#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b)) + + int rc, gc, bc; + + for ( rc=0; rc<=MAX_R; rc++ ) // build 2x2x2 color cube + for ( gc=0; gc<=MAX_G; gc++ ) + for ( bc=0; bc<=MAX_B; bc++ ) + { + dst->setColor( INDEXOF(rc,gc,bc), + qRgb( rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B ) ); + } + + int sw = src->width(); + int* line1[3]; + int* line2[3]; + int* pv[3]; + + line1[0] = new int[src->width()]; + line2[0] = new int[src->width()]; + line1[1] = new int[src->width()]; + line2[1] = new int[src->width()]; + line1[2] = new int[src->width()]; + line2[2] = new int[src->width()]; + pv[0] = new int[sw]; + pv[1] = new int[sw]; + pv[2] = new int[sw]; + + for ( y=0; y < src->height(); y++ ) + { + p = (QRgb *)src->scanLine(y); + b = dst->scanLine(y); + int endian = (QImage::systemByteOrder() == QImage::BigEndian); + int x; + uchar* q = src->scanLine(y); + uchar* q2 = src->scanLine(y+1 < src->height() ? y + 1 : 0); + for (int chan = 0; chan < 3; chan++) + { + b = dst->scanLine(y); + int *l1 = (y&1) ? line2[chan] : line1[chan]; + int *l2 = (y&1) ? line1[chan] : line2[chan]; + if ( y == 0 ) + { + for (int i=0; i<sw; i++) + l1[i] = q[i*4+chan+endian]; + } + if ( y+1 < src->height() ) + { + for (int i=0; i<sw; i++) + l2[i] = q2[i*4+chan+endian]; + } + // Bi-directional error diffusion + if ( y&1 ) + { + for (x=0; x<sw; x++) + { + int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0); + int err = l1[x] - pix * 255 / 2; + pv[chan][x] = pix; + + // Spread the error around... + if ( x+1<sw ) + { + l1[x+1] += (err*7)>>4; + l2[x+1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x>1) + l2[x-1]+=(err*3)>>4; + } + } + else + { + for (x=sw; x-->0; ) + { + int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0); + int err = l1[x] - pix * 255 / 2; + pv[chan][x] = pix; + + // Spread the error around... + if ( x > 0 ) + { + l1[x-1] += (err*7)>>4; + l2[x-1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x+1 < sw) + l2[x+1]+=(err*3)>>4; + } + } + } + if (endian) + { + for (x=0; x<sw; x++) + { + *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]); + } + } + else + { + for (x=0; x<sw; x++) + { + *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]); + } + } + } + + delete [] line1[0]; + delete [] line2[0]; + delete [] line1[1]; + delete [] line2[1]; + delete [] line1[2]; + delete [] line2[2]; + delete [] pv[0]; + delete [] pv[1]; + delete [] pv[2]; + +#undef MAX_R +#undef MAX_G +#undef MAX_B +#undef INDEXOF + + return TRUE; +} + +// this doesn't work the way it should but the way KPixmap does. +void KIconEditGrid::mapToKDEPalette() +{ + QImage dest; + + kdither_32_to_8(img, &dest); + *img = dest.convertDepth(32); + + for(int y = 0; y < img->height(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < img->width(); x++, l++) + { + if(*l < 0xff000000) + { + *l = *l | 0xff000000; + } + } + } + + load(img); + return; + +/* +#if QT_VERSION > 140 + *img = img->convertDepthWithPalette(32, iconpalette, 42); + load(img); + return; +#endif +*/ + + QApplication::setOverrideCursor(waitCursor); + for(int y = 0; y < numRows(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < numCols(); x++, l++) + { + if(*l != TRANSPARENT) + { + if(!iconcolors.contains(*l)) + *l = iconcolors.closestMatch(*l); + } + } + } + + load(img); + setModified(true); + QApplication::restoreOverrideCursor(); +} + + +void KIconEditGrid::grayScale() +{ + for(int y = 0; y < numRows(); y++) + { + uint *l = (uint*)img->scanLine(y); + for(int x = 0; x < numCols(); x++, l++) + { + if(*l != TRANSPARENT) + { + uint c = qGray(*l); + *l = qRgba(c, c, c, qAlpha(*l)); + } + } + } + + load(img); + setModified(true); +} + + +void KIconEditGrid::clearImage(QImage *image) +{ + if(image->depth() != 32) + { + image->fill(TRANSPARENT); + } + else + { + // QImage::fill() does not set the alpha channel so do it + // manually. + for(int y = 0; y < image->height(); y++) + { + uint *l = (uint*)image->scanLine(y); + for(int x = 0; x < image->width(); x++, l++) + { + *l = TRANSPARENT; + } + } + } +} + + +void KIconEditGrid::setModified(bool m) +{ + if(m != modified) + { + modified = m; + emit modifiedchanged(m); + } +} + + +#include "kicongrid.moc" +// vim: set ts=4: |