You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gwenview/src/gvcore/filethumbnailviewitem.cpp

406 lines
10 KiB

/* 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 <weis@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 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 <tqapplication.h>
#include <tqcolor.h>
#include <tqpainter.h>
#include <tqpen.h>
#include <tqpixmap.h>
// KDE includes
#include <kdebug.h>
#include <kwordwrap.h>
#include <kurldrag.h>
// 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<const FileThumbnailView*>(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<Line*>::ConstIterator it=mLines.begin();
TQValueVector<Line*>::ConstIterator itEnd=mLines.end();
for (;it!=itEnd; ++it) {
delete *it;
}
}
void FileThumbnailViewItem::updateLines() {
TQValueVector<Line*>::ConstIterator it=mLines.begin();
TQValueVector<Line*>::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<FileThumbnailView*>(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<FileThumbnailView*>(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<Line*>::ConstIterator it=mLines.begin();
TQValueVector<Line*>::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<FileThumbnailView*>(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<Line*>::ConstIterator it=mLines.begin();
TQValueVector<Line*>::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<TQIconDragItem>&) {
FileThumbnailView *view=static_cast<FileThumbnailView*>(iconView());
emit view->dropped(event,mFileItem);
}
void FileThumbnailViewItem::setImageSize(const TQSize& size) {
mImageSize=size;
updateLines();
}
} // namespace