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.
tellico/src/gui/imagewidget.cpp

258 lines
7.8 KiB

/***************************************************************************
copyright : (C) 2003-2006 by Robby Stephenson
email : robby@periapsis.org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of version 2 of the GNU General Public License as *
* published by the Free Software Foundation; *
* *
***************************************************************************/
#include "imagewidget.h"
#include "../imagefactory.h"
#include "../image.h"
#include "../filehandler.h"
#include "../tellico_debug.h"
#include "../tellico_utils.h"
#include <tdefiledialog.h>
#include <tdelocale.h>
#include <kbuttonbox.h>
#include <kurldrag.h>
#include <tdemessagebox.h>
#include <tqwmatrix.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqcheckbox.h>
#include <tqdragobject.h>
#include <tqapplication.h> // needed for drag distance
namespace {
static const uint IMAGE_WIDGET_BUTTON_MARGIN = 8;
static const uint IMAGE_WIDGET_IMAGE_MARGIN = 4;
static const uint MAX_UNSCALED_WIDTH = 640;
static const uint MAX_UNSCALED_HEIGHT = 640;
}
using Tellico::GUI::ImageWidget;
ImageWidget::ImageWidget(TQWidget* parent_, const char* name_) : TQWidget(parent_, name_) {
TQHBoxLayout* l = new TQHBoxLayout(this);
l->setMargin(IMAGE_WIDGET_BUTTON_MARGIN);
m_label = new TQLabel(this);
m_label->setSizePolicy(TQSizePolicy(TQSizePolicy::Ignored, TQSizePolicy::Ignored));
m_label->setFrameStyle(TQFrame::Panel | TQFrame::Sunken);
m_label->setAlignment(TQt::AlignHCenter | TQt::AlignVCenter);
l->addWidget(m_label, 1);
l->addSpacing(IMAGE_WIDGET_BUTTON_MARGIN);
TQVBoxLayout* boxLayout = new TQVBoxLayout(l);
boxLayout->addStretch(1);
KButtonBox* box = new KButtonBox(this,TQt::Vertical);
box->addButton(i18n("Select Image..."), this, TQ_SLOT(slotGetImage()));
box->addButton(i18n("Clear"), this, TQ_SLOT(slotClear()));
box->layout();
boxLayout->addWidget(box);
boxLayout->addSpacing(8);
m_cbLinkOnly = new TQCheckBox(i18n("Save link only"), this);
connect(m_cbLinkOnly, TQ_SIGNAL(clicked()), TQ_SLOT(slotLinkOnlyClicked()));
boxLayout->addWidget(m_cbLinkOnly);
boxLayout->addStretch(1);
slotClear();
// accept image drops
setAcceptDrops(true);
}
void ImageWidget::setImage(const TQString& id_) {
if(id_.isEmpty()) {
slotClear();
return;
}
m_imageID = id_;
m_pixmap = ImageFactory::pixmap(id_, MAX_UNSCALED_WIDTH, MAX_UNSCALED_HEIGHT);
const bool link = ImageFactory::imageInfo(id_).linkOnly;
m_cbLinkOnly->setChecked(link);
m_cbLinkOnly->setEnabled(link);
// if we're using a link, then the original URL _is_ the id
m_originalURL = link ? id_ : KURL();
m_scaled = TQPixmap();
scale();
update();
}
void ImageWidget::setLinkOnlyChecked(bool link_) {
m_cbLinkOnly->setChecked(link_);
}
void ImageWidget::slotClear() {
// m_image = Data::Image();
m_imageID = TQString();
m_pixmap = TQPixmap();
m_scaled = m_pixmap;
m_originalURL = KURL();
m_label->setPixmap(m_scaled);
m_cbLinkOnly->setChecked(false);
m_cbLinkOnly->setEnabled(true);
update();
emit signalModified();
}
void ImageWidget::scale() {
int ww = m_label->width() - 2*IMAGE_WIDGET_IMAGE_MARGIN;
int wh = m_label->height() - 2*IMAGE_WIDGET_IMAGE_MARGIN;
int pw = m_pixmap.width();
int ph = m_pixmap.height();
if(ww < pw || wh < ph) {
int newWidth, newHeight;
if(pw*wh < ph*ww) {
newWidth = static_cast<int>(static_cast<double>(pw)*wh/static_cast<double>(ph));
newHeight = wh;
} else {
newWidth = ww;
newHeight = static_cast<int>(static_cast<double>(ph)*ww/static_cast<double>(pw));
}
TQWMatrix wm;
wm.scale(static_cast<double>(newWidth)/pw, static_cast<double>(newHeight)/ph);
m_scaled = m_pixmap.xForm(wm);
} else {
m_scaled = m_pixmap;
}
m_label->setPixmap(m_scaled);
}
void ImageWidget::resizeEvent(TQResizeEvent *) {
if(m_pixmap.isNull()) {
return;
}
scale();
update();
}
void ImageWidget::slotGetImage() {
KURL url = KFileDialog::getImageOpenURL(TQString(), this);
if(url.isEmpty() || !url.isValid()) {
return;
}
loadImage(url);
}
void ImageWidget::slotLinkOnlyClicked() {
if(m_imageID.isEmpty()) {
// nothing to do, it has an empty image;
return;
}
bool link = m_cbLinkOnly->isChecked();
// if the user is trying to link and can't before there's no information about the url
// the let him know that
if(link && m_originalURL.isEmpty()) {
KMessageBox::sorry(this, i18n("Saving a link is only possible for newly added images."));
m_cbLinkOnly->setChecked(false);
return;
}
// need to reset image id to be the original url
// if we're linking only, then we want the image id to be the same as the url
// so it needs to be added to the cache all over again
// probably could do this without downloading the image all over again,
// but I'm not going to do that right now
const TQString& id = ImageFactory::addImage(m_originalURL, false, KURL(), link);
// same image, so no need to call setImage
m_imageID = id;
emit signalModified();
}
void ImageWidget::mousePressEvent(TQMouseEvent* event_) {
// Only interested in LMB
if(event_->button() == TQt::LeftButton) {
// Store the position of the mouse press.
// check if position is inside the label
if(m_label->geometry().contains(event_->pos())) {
m_dragStart = event_->pos();
} else {
m_dragStart = TQPoint();
}
}
}
void ImageWidget::mouseMoveEvent(TQMouseEvent* event_) {
int delay = TQApplication::startDragDistance();
// Only interested in LMB
if(event_->state() & TQt::LeftButton) {
// only allow drag is the image is non-null, and the drag start point isn't null and the user dragged far enough
if(!m_imageID.isEmpty() && !m_dragStart.isNull() && (m_dragStart - event_->pos()).manhattanLength() > delay) {
const Data::Image& img = ImageFactory::imageById(m_imageID);
if(!img.isNull()) {
TQImageDrag* drag = new TQImageDrag(img, this);
drag->dragCopy();
}
}
}
}
void ImageWidget::dragEnterEvent(TQDragEnterEvent* event_) {
event_->accept(KURLDrag::canDecode(event_) || TQImageDrag::canDecode(event_) || TQTextDrag::canDecode(event_));
}
void ImageWidget::dropEvent(TQDropEvent* event_) {
TQImage image;
KURL::List urls;
TQString text;
GUI::CursorSaver cs(TQt::busyCursor);
if(TQImageDrag::decode(event_, image)) {
// TQt reads PNG data by default
const TQString& id = ImageFactory::addImage(image, TQString::fromLatin1("PNG"));
if(!id.isEmpty() && id != m_imageID) {
setImage(id);
emit signalModified();
}
} else if(KURLDrag::decode(event_, urls)) {
if(urls.isEmpty()) {
return;
}
// only care about the first one
const KURL& url = urls[0];
if(url.isEmpty() || !url.isValid()) {
return;
}
// kdDebug() << "ImageWidget::dropEvent() - " << url.prettyURL() << endl;
loadImage(url);
} else if(TQTextDrag::decode(event_, text)) {
KURL url(text);
if(url.isEmpty() || !url.isValid()) {
return;
}
loadImage(url);
}
}
void ImageWidget::loadImage(const KURL& url_) {
const bool link = m_cbLinkOnly->isChecked();
GUI::CursorSaver cs;
// if we're linking only, then we want the image id to be the same as the url
const TQString& id = ImageFactory::addImage(url_, false, KURL(), link);
if(id != m_imageID) {
setImage(id);
emit signalModified();
}
// at the end, cause setImage() resets it
m_originalURL = url_;
m_cbLinkOnly->setEnabled(true);
}
#include "imagewidget.moc"