/* This file is part of the KDE project Copyright (c) 1999 Carsten Pfeiffer (pfeiffer@kde.org) Copyright (c) 2002 Igor Jansen (rm@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library 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 #include #include #include #include #include #include #include #include KoPixmapWidget::KoPixmapWidget(const QPixmap &aPixmap, QWidget *parent, const char *name): QFrame(parent, name, WType_Popup) { kdDebug() << "Popup created: " << name << "\n"; setFrameStyle(QFrame::WinPanel | QFrame::Raised); mPixmap = aPixmap; int w = mPixmap.width() + 2 * lineWidth(); int h = mPixmap.height() + 2 * lineWidth(); resize(w, h); } KoPixmapWidget::~KoPixmapWidget() { } // paint the centered pixmap; don't overpaint the frame void KoPixmapWidget::paintEvent(QPaintEvent *e) { QFrame::paintEvent(e); QPainter p(this); p.setClipRect(e->rect()); p.drawPixmap(lineWidth(), lineWidth(), mPixmap); } void KoPixmapWidget::mouseReleaseEvent(QMouseEvent *) { hide(); } KoIconChooser::KoIconChooser(QSize aIconSize, QWidget *parent, const char *name, bool sort): QGridView(parent, name) { QGridView::setBackgroundColor(Qt::white); mMargin = 2; setCellWidth(aIconSize.width() + 2 * mMargin); setCellHeight(aIconSize.height() + 2 * mMargin); mIconList.clear(); mPixmapWidget = 0L; mNCols = 0; mCurRow = 0; mCurCol = 0; mItemCount = 0; mItemWidth = aIconSize.width(); mItemHeight = aIconSize.height(); mMouseButtonDown = false; mDragEnabled = false; mSort = sort; } KoIconChooser::~KoIconChooser() { mIconList.clear(); if(mPixmapWidget) delete mPixmapWidget; } void KoIconChooser::addItem(KoIconItem *item) { Q_INT32 n = mItemCount; KoIconItem *current = currentItem(); Q_ASSERT(item); int i; if (mSort) { i = sortInsertionIndex(item); } else { i = mItemCount; } mIconList.insert(i, item); mItemCount++; calculateCells(); if (mSort) { setCurrentItem(current); updateContents(); } else { updateCell(n / numCols(), n - (n / numCols()) * numCols()); } } bool KoIconChooser::removeItem(KoIconItem *item) { int index = mIconList.find(item); bool ok = mIconList.remove(item); if( ok ) { mItemCount--; // select same cell as deleted cell, or new last cell if we deleted // last cell. setCurrentItem(itemAt(kMin(index, mItemCount - 1))); calculateCells(); } return ok; } void KoIconChooser::clear() { mItemCount = 0; mIconList.clear(); calculateCells(); } // return 0L if there is no current item KoIconItem *KoIconChooser::currentItem() { return itemAt(mCurRow, mCurCol); } // sets the current item to item // does NOT emit selected() (should it?) void KoIconChooser::setCurrentItem(KoIconItem *item) { int index = mIconList.find(item); // item is available if(index != -1 && mNCols > 0) { int oldRow = mCurRow; int oldCol = mCurCol; mCurRow = index / mNCols; mCurCol = index % mNCols; // repaint the old and the new item repaintCell(oldRow, oldCol); repaintCell(mCurRow, mCurCol); ensureCellVisible(mCurRow, mCurCol); } } // eventually select the item, clicked on void KoIconChooser::mousePressEvent(QMouseEvent *e) { QGridView::mousePressEvent(e); } void KoIconChooser::mouseMoveEvent(QMouseEvent *e) { if(mMouseButtonDown && mDragEnabled ) { #if 0 if(mPixmapWidget) { delete mPixmapWidget; mPixmapWidget = 0L; } #endif if( ( mDragStartPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() ) startDrag(); } } void KoIconChooser::startDrag() { mMouseButtonDown = false; } void KoIconChooser::mouseReleaseEvent(QMouseEvent * e) { mMouseButtonDown = true; if(e->button() == LeftButton) { QPoint p = e->pos(); mDragStartPos = p; int x = contentsX() + p.x(); int y = contentsY() + p.y(); QSize gridExtent = gridSize(); if (x < gridExtent.width() && y < gridExtent.height()) { int row = rowAt(y); int col = columnAt(x); KoIconItem *item = itemAt(row, col); if(item) { const QPixmap &pix = item->pixmap(); if(pix.width() > mItemWidth || pix.height() > mItemHeight) showFullPixmap(pix, p); setCurrentItem(item); emit selected( item ); } } } } // FIXME: implement keyboard navigation void KoIconChooser::keyPressEvent(QKeyEvent *e) { QGridView::keyPressEvent(e); } // recalculate the number of items that fit into one row // set the current item again after calculating the new grid void KoIconChooser::resizeEvent(QResizeEvent *e) { QGridView::resizeEvent(e); KoIconItem *item = currentItem(); int oldNCols = mNCols; if (cellWidth() != 0) { mNCols = e -> size().width() / cellWidth(); } if(mNCols != oldNCols) { setNumCols(mNCols); calculateCells(); setCurrentItem(item); updateContents(); } } // paint one cell // mark the current item and center items smaller than the cellSize // TODO: scale down big pixmaps and paint the size as text into the pixmap void KoIconChooser::paintCell(QPainter *p, int row, int col) { KoIconItem *item = itemAt(row, col); if(item) { const QPixmap &pix = item->pixmap(); int x = mMargin; int y = mMargin; int pw = pix.width(); int ph = pix.height(); int cw = cellWidth(); int ch = cellHeight(); // center small pixmaps if(pw < mItemWidth) x = (cw - pw) / 2; if(ph < mItemHeight) y = (cw - ph) / 2; if((!item->hasValidThumb()) || (pw <= mItemWidth && ph <= mItemHeight)) p->drawPixmap(x, y, pix, 0, 0, mItemWidth, mItemHeight); else { const QPixmap &thumbpix = item->thumbPixmap(); x = mMargin; y = mMargin; pw = thumbpix.width(); ph = thumbpix.height(); cw = cellWidth(); ch = cellHeight(); // center small pixmaps if(pw < mItemWidth) x = (cw - pw) / 2; if(ph < mItemHeight) y = (cw - ph) / 2; p->drawPixmap(x, y, thumbpix, 0, 0, mItemWidth, mItemHeight); } // highlight current item if(row == mCurRow && col == mCurCol) { p->setPen(blue); p->drawRect(0, 0, cw, ch); } else { p->setPen(gray); //p->drawRect(0, 0, cw, ch); p->drawLine(cw-1, 0, cw-1, ch-1); p->drawLine(0, ch-1, cw-1, ch-1); } } else { // empty cell p->fillRect(0, 0, cellWidth(), cellHeight(), QBrush(Qt::white)); } } // return the pointer of the item at (row,col) - beware, resizing disturbs // rows and cols! // return 0L if item is not found KoIconItem *KoIconChooser::itemAt(int row, int col) { return itemAt(cellIndex(row, col)); } // return the pointer of the item at position index // return 0L if item is not found KoIconItem *KoIconChooser::itemAt(int index) { if(index < 0) return 0L; return mIconList.count() > uint(index) ? mIconList.at(index) : 0; } // return the index of a cell, given row and column position // maps directly to the position in the itemlist // return -1 on failure int KoIconChooser::cellIndex(int row, int col) { if(row < 0 || col < 0) return -1; else return((row * mNCols) + col); } // calculate the grid and set the number of rows and columns // reorder all items approrpriately void KoIconChooser::calculateCells() { if(mNCols == 0) return; bool update = isUpdatesEnabled(); int rows = mItemCount / mNCols; setUpdatesEnabled(false); if((rows * mNCols) < mItemCount) rows++; setNumRows(rows); setUpdatesEnabled(update); updateContents(); } // show the full pixmap of a large item in an extra widget void KoIconChooser::showFullPixmap(const QPixmap &pix, const QPoint &/*p*/) { //delete mPixmapWidget; mPixmapWidget = new KoPixmapWidget(pix, this); // center widget under mouse cursor QPoint p = QCursor::pos(); int w = mPixmapWidget->width(); int h = mPixmapWidget->height(); mPixmapWidget->move(p.x() - w / 2, p.y() - h / 2); mPixmapWidget->show(); } int KoIconChooser::sortInsertionIndex(const KoIconItem *item) { int index = 0; if (!mIconList.isEmpty()) { // Binary insertion int first = 0; int last = mIconList.count() - 1; while (first != last) { int middle = (first + last) / 2; if (item -> compare(mIconList.at(middle)) < 0) { last = middle - 1; if (last < first) { last = first; } } else { first = middle + 1; if (first > last) { first = last; } } } if (item -> compare(mIconList.at(first)) < 0) { index = first; } else { index = first + 1; } } return index; } KoPatternChooser::KoPatternChooser( const QPtrList &list, QWidget *parent, const char *name ) : QWidget( parent, name ) { // only serves as beautifier for the iconchooser //frame = new QHBox( this ); //frame->setFrameStyle( QFrame::Panel | QFrame::Sunken ); chooser = new KoIconChooser( QSize(30,30), this, "pattern chooser" ); QObject::connect( chooser, SIGNAL(selected( KoIconItem * ) ), this, SIGNAL( selected( KoIconItem * ))); QPtrListIterator itr( list ); for( itr.toFirst(); itr.current(); ++itr ) chooser->addItem( itr.current() ); QVBoxLayout *mainLayout = new QVBoxLayout( this, 1, -1, "main layout" ); mainLayout->addWidget( chooser, 10 ); } KoPatternChooser::~KoPatternChooser() { delete chooser; //delete frame; } // set the active pattern in the chooser - does NOT emit selected() (should it?) void KoPatternChooser::setCurrentPattern( KoIconItem *pattern ) { chooser->setCurrentItem( pattern ); } void KoPatternChooser::addPattern( KoIconItem *pattern ) { chooser->addItem( pattern ); } // return the active pattern KoIconItem *KoPatternChooser::currentPattern() { return chooser->currentItem(); } void KoPatternChooser::removePattern( KoIconItem *pattern ) { chooser->removeItem( pattern ); } #include "koIconChooser.moc"