/* Gwenview - A simple image viewer for TDE Copyright 2000-2004 Aurélien Gâteau This class is based on the TDEIconViewItem class from KDE libs. Original copyright follows. */ /* This file is part of the KDE libraries Copyright (C) 1999 Torben Weis This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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. */ // TQt includes #include #include #include #include #include // KDE includes #include #include #include // Our includes #include "archive.h" #include "filethumbnailview.h" #include "filethumbnailviewitem.h" #include "fileviewconfig.h" #include "timeutils.h" namespace Gwenview { const int SHOWN_ITEM_INDICATOR_SIZE = 8; #if 0 static void printRect(const TQString& txt,const TQRect& rect) { kdWarning() << txt << " : " << rect.x() << "x" << rect.y() << " " << rect.width() << "x" << rect.height() << endl; } #endif /** * An helper class to handle a caption line and help drawing it */ class FileThumbnailViewItem::Line { protected: const TQIconViewItem* mItem; TQString mTxt; int mWidth; public: Line(const TQIconViewItem* item, const TQString& txt) : mItem(item) , mTxt(txt) , mWidth(-1) { } virtual ~Line() {} virtual void setWidth(int width) { mWidth=width; } virtual int height() const=0; void paint(TQPainter* p, int textX, int textY, int align) const { Q_ASSERT(mWidth!=-1); int length=fontMetrics().width(mTxt); if (length<=mWidth ) { p->drawText( textX, textY, mWidth, fontMetrics().height(), align, mTxt); } else { p->save(); complexPaint(p, textX, textY, align); p->restore(); } }; protected: const FileThumbnailView* view() const { return static_cast(mItem->iconView()); } TQFontMetrics fontMetrics() const { return view()->fontMetrics(); } /** * Called when the text won't fit the available space */ virtual void complexPaint(TQPainter* p, int textX, int textY, int align) const=0; }; /** * A line which will get cropped if necessary */ class FileThumbnailViewItem::CroppedLine : public FileThumbnailViewItem::Line { public: CroppedLine(const TQIconViewItem* item, const TQString& txt) : Line(item, txt) {} int height() const { return fontMetrics().height(); } void complexPaint(TQPainter* p, int textX, int textY, int /*align*/) const { KWordWrap::drawFadeoutText(p, textX, textY + fontMetrics().ascent(), mWidth, mTxt); } }; /** * A line which will get wrapped if necessary */ class FileThumbnailViewItem::WrappedLine : public FileThumbnailViewItem::Line { KWordWrap* mWordWrap; public: WrappedLine(const TQIconViewItem* item, const TQString& txt) : Line(item, txt) , mWordWrap(0) {} ~WrappedLine() { delete mWordWrap; } int height() const { Q_ASSERT(mWordWrap); if (!mWordWrap) return 0; return mWordWrap->boundingRect().height(); } /** * Regenerates mWordWrap if the width has changed */ void setWidth(int width) { if (width==mWidth) return; mWidth=width; delete mWordWrap; TQFontMetrics fm=fontMetrics(); mWordWrap=KWordWrap::formatText(fm, TQRect(0, 0, mWidth, fm.height()*3), 0 /*flags*/, mTxt); } void complexPaint(TQPainter* p, int textX, int textY, int align) const { Q_ASSERT(mWordWrap); if (!mWordWrap) return; int xpos=0; if (align & AlignHCenter) { xpos=( mWidth - mWordWrap->boundingRect().width() ) / 2; } mWordWrap->drawText(p, textX + xpos, textY, align); } }; FileThumbnailViewItem::FileThumbnailViewItem(TQIconView* view,const TQString& text,const TQPixmap& icon, KFileItem* fileItem) : TQIconViewItem(view,text,icon), mFileItem(fileItem) { updateLines(); calcRect(); } FileThumbnailViewItem::~FileThumbnailViewItem() { TQValueVector::ConstIterator it=mLines.begin(); TQValueVector::ConstIterator itEnd=mLines.end(); for (;it!=itEnd; ++it) { delete *it; } } void FileThumbnailViewItem::updateLines() { TQValueVector::ConstIterator it=mLines.begin(); TQValueVector::ConstIterator itEnd=mLines.end(); for (;it!=itEnd; ++it) { delete *it; } mLines.clear(); if (!mFileItem) return; bool showName, showDate, showImageSize, showFilesize; bool isDir=mFileItem->isDir(); if (iconView()->itemTextPos()==TQIconView::Right) { // Text is on the right, show everything showName = true; showDate = true; showImageSize = true; showFilesize = !isDir; } else { // Text is below the icon, only show details selected in // view->itemDetails() FileThumbnailView *view=static_cast(iconView()); int details=view->itemDetails(); bool isImage=!Archive::fileItemIsDirOrArchive(mFileItem); showName = !isImage || ( details & FileThumbnailView::FILENAME ); showDate = ( details & FileThumbnailView::FILEDATE ); showImageSize = ( details & FileThumbnailView::IMAGESIZE ); showFilesize = !isDir && ( details & FileThumbnailView::FILESIZE ); } if (showName) { mLines.append( new WrappedLine(this, mFileItem->name()) ); } if (showDate) { time_t time = TimeUtils::getTime(mFileItem); mLines.append( new CroppedLine(this, TimeUtils::formatTime(time)) ); } if (showImageSize) { TQSize sz; if (mImageSize.isValid()) { sz=mImageSize; } else if (FileViewConfig::loadMetadata()) { const KFileMetaInfo& info = mFileItem->metaInfo(/*autogen=*/false); if (info.isValid()) { sz = info.value("Dimensions").toSize(); } } if (sz.isValid()) { TQString txt = TQString::number(sz.width())+"x"+TQString::number(sz.height()); mLines.append( new CroppedLine(this, txt) ); } else if (iconView()->itemTextPos()==TQIconView::Right) { // add empty line for they would nicely alligned; // for text at the bottom it doesn't look that nice mLines.append( new CroppedLine(this, TQString())); } } if (showFilesize) { mLines.append( new CroppedLine(this, TDEIO::convertSize(mFileItem->size())) ); } calcRect(); } void FileThumbnailViewItem::calcRect(const TQString&) { FileThumbnailView *view=static_cast(iconView()); bool isRight=view->itemTextPos()==TQIconView::Right; int textW=view->gridX(); int thumbnailSize=FileViewConfig::thumbnailSize(); if (isRight) { textW-=PADDING * 3 + thumbnailSize; } else { textW-=PADDING * 2; } int textH=0; TQValueVector::ConstIterator it=mLines.begin(); TQValueVector::ConstIterator itEnd=mLines.end(); for (;it!=itEnd; ++it) { (*it)->setWidth(textW); textH+=(*it)->height(); } TQRect itemRect(x(), y(), view->gridX(), 0); TQRect itemPixmapRect(PADDING, PADDING, thumbnailSize, thumbnailSize); TQRect itemTextRect(0, 0, textW, textH); if (isRight) { itemRect.setHeight( TQMAX(thumbnailSize + PADDING*2, textH) ); itemTextRect.moveLeft(thumbnailSize + PADDING * 2 ); itemTextRect.moveTop((itemRect.height() - textH)/2); } else { itemPixmapRect.moveLeft( (itemRect.width() - itemPixmapRect.width()) / 2 ); itemRect.setHeight(thumbnailSize + PADDING*3 + textH); itemTextRect.moveLeft(PADDING); itemTextRect.moveTop(thumbnailSize + PADDING * 2); } // Update rects // NOTE: this results in 3 calls to TQIconViewContainer(), which is costly if // there are a lot (tens of thousands) of items, unfortunately there // is no way to workaround this in current (14.1.1, 2024) TQt API if ( itemPixmapRect != pixmapRect() ) { setPixmapRect( itemPixmapRect ); } if ( itemTextRect != textRect() ) { setTextRect( itemTextRect ); } if ( itemRect != rect() ) { setItemRect( itemRect ); } } void FileThumbnailViewItem::paintItem(TQPainter *p, const TQColorGroup &cg) { FileThumbnailView *view=static_cast(iconView()); Q_ASSERT(view); if (!view) return; bool isRight=view->itemTextPos()==TQIconView::Right; bool isShownItem=view->shownFileItem() && view->shownFileItem()->extraData(view)==this; bool isImage=!Archive::fileItemIsDirOrArchive(mFileItem); int textX, textY; int thumbnailSize=FileViewConfig::thumbnailSize(); textX=textRect(false).x(); textY=textRect(false).y(); // Draw pixmap TQRect pRect = pixmapRect(false); int pixX = pRect.left() + ( thumbnailSize - pixmap()->width() ) / 2; int pixY = pRect.top() + ( thumbnailSize - pixmap()->height() ) / 2; p->drawPixmap( pixX, pixY, *pixmap() ); TQColor bg; if ( isSelected() ) { bg=cg.highlight(); } else { bg=cg.mid(); } // Draw shown item indicator if (isShownItem) { TQPointArray pa(3); pa[0] = pixmapRect(false).bottomLeft(); pa[0].rx() += pixmapRect(false).width() / 2; pa[0].ry() += PADDING - 1; pa[0].ry() -= SHOWN_ITEM_INDICATOR_SIZE; pa[1] = pa[0]; pa[1].rx() -= SHOWN_ITEM_INDICATOR_SIZE; pa[1].ry() += SHOWN_ITEM_INDICATOR_SIZE; pa[2] = pa[1]; pa[2].rx() += SHOWN_ITEM_INDICATOR_SIZE * 2; p->setBrush(cg.highlight()); p->setPen(cg.base()); p->drawPolygon(pa); } if (isImage || isSelected()) { // Draw frame TQRect frmRect=pixmapRect(false); frmRect.addCoords(-PADDING, -PADDING, PADDING, PADDING); p->setBrush(TQBrush()); p->setPen(bg); p->drawRect(frmRect); if (isSelected()) { frmRect.addCoords(1, 1, -1, -1); p->drawRect(frmRect); } } // Draw text p->setPen(cg.text()); p->setBackgroundColor(cg.base()); int align = (isRight ? AlignAuto : AlignHCenter) | AlignTop; TQValueVector::ConstIterator it=mLines.begin(); TQValueVector::ConstIterator itEnd=mLines.end(); for (;it!=itEnd; ++it) { const Line* line=*it; line->paint(p, textX, textY, align); textY+=line->height(); } } bool FileThumbnailViewItem::acceptDrop(const TQMimeSource* source) const { return KURLDrag::canDecode(source); } void FileThumbnailViewItem::dropped(TQDropEvent* event, const TQValueList&) { FileThumbnailView *view=static_cast(iconView()); emit view->dropped(event,mFileItem); } void FileThumbnailViewItem::setImageSize(const TQSize& size) { mImageSize=size; updateLines(); } } // namespace