diff options
| author | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-11-22 18:41:30 +0900 | 
|---|---|---|
| committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-11-22 20:55:03 +0900 | 
| commit | 5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90 (patch) | |
| tree | f89cc49efc9ca1d0e1579ecb079ee7e7088ff8c8 /src/utilities/imageeditor/canvas/canvas.cpp | |
| parent | 0bfbf616d9c1fd7abb1bd02732389ab35e5f8771 (diff) | |
| download | digikam-5bed6e4a.tar.gz digikam-5bed6e4a.zip | |
Rename 'digikam' folder to 'src'
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
(cherry picked from commit ee0d99607c14cb63d3ebdb3a970b508949fa8219)
Diffstat (limited to 'src/utilities/imageeditor/canvas/canvas.cpp')
| -rw-r--r-- | src/utilities/imageeditor/canvas/canvas.cpp | 1421 | 
1 files changed, 1421 insertions, 0 deletions
| diff --git a/src/utilities/imageeditor/canvas/canvas.cpp b/src/utilities/imageeditor/canvas/canvas.cpp new file mode 100644 index 00000000..89758c3d --- /dev/null +++ b/src/utilities/imageeditor/canvas/canvas.cpp @@ -0,0 +1,1421 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date        : 2003-01-09 + * Description : image editor canvas management class + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * 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, 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdio> +#include <cmath> + +// TQt includes. + +#include <tqtooltip.h> +#include <tqfile.h> +#include <tqstring.h> +#include <tqevent.h> +#include <tqpoint.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqpixmap.h> +#include <tqstyle.h> +#include <tqapplication.h> +#include <tqcursor.h> +#include <tqimage.h> +#include <tqregion.h> +#include <tqtimer.h> +#include <tqcache.h> +#include <tqcolor.h> +#include <tqdragobject.h>  +#include <tqclipboard.h> +#include <tqtoolbutton.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <kdatetbl.h> +#include <tdeglobalsettings.h> + +// Local includes. + +#include "ddebug.h" +#include "imagehistogram.h" +#include "imagepaniconwidget.h" +#include "dimginterface.h" +#include "iccsettingscontainer.h" +#include "exposurecontainer.h" +#include "iofilesettingscontainer.h" +#include "loadingcacheinterface.h" +#include "canvas.h" +#include "canvas.moc" + +namespace Digikam +{ + +class CanvasPrivate +{ + +public: + +    CanvasPrivate() :  +        tileSize(128), minZoom(0.1), maxZoom(12.0), zoomMultiplier(1.2)  +    { +        rubber           = 0; +        pressedMoved     = false; +        pressedMoving    = false; +        ltActive         = false; +        rtActive         = false; +        lbActive         = false; +        rbActive         = false; +        midButtonPressed = false; +        midButtonX       = 0; +        midButtonY       = 0; +        panIconPopup     = 0; +        panIconWidget    = 0; +        cornerButton     = 0; +        parent           = 0; +        im               = 0; +        rubber           = 0; +        autoZoom         = false; +        fullScreen       = false; +        zoom             = 1.0; +        tileTmpPix       = new TQPixmap(tileSize, tileSize); + +        tileCache.setMaxCost((10*1024*1024)/(tileSize*tileSize*4)); +        tileCache.setAutoDelete(true); +    } + +    bool                 autoZoom; +    bool                 fullScreen; +    bool                 pressedMoved; +    bool                 pressedMoving; +    bool                 ltActive; +    bool                 rtActive; +    bool                 lbActive; +    bool                 rbActive; +    bool                 midButtonPressed; + +    const int            tileSize; +    int                  midButtonX; +    int                  midButtonY; + +    double               zoom; +    const double         minZoom; +    const double         maxZoom; +    const double         zoomMultiplier; + +    TQToolButton         *cornerButton; + +    TQRect               *rubber; +    TQRect                pixmapRect; + +    TQCache<TQPixmap>      tileCache; + +    TQPixmap*             tileTmpPix; +    TQPixmap              qcheck; + +    TQColor               bgColor; + +    TQWidget             *parent; + +    TDEPopupFrame         *panIconPopup; + +    DImgInterface       *im; + +    ImagePanIconWidget  *panIconWidget; +}; + +Canvas::Canvas(TQWidget *parent) +      : TQScrollView(parent) +{ +    d = new CanvasPrivate; +    d->im     = new DImgInterface(); +    d->parent = parent; +    d->bgColor.setRgb(0, 0, 0); + +    d->qcheck.resize(16, 16); +    TQPainter p(&d->qcheck); +    p.fillRect(0, 0, 8, 8, TQColor(144, 144, 144)); +    p.fillRect(8, 8, 8, 8, TQColor(144, 144, 144)); +    p.fillRect(0, 8, 8, 8, TQColor(100, 100, 100)); +    p.fillRect(8, 0, 8, 8, TQColor(100, 100, 100)); +    p.end(); + +    d->cornerButton = new TQToolButton(this); +    d->cornerButton->setIconSet(SmallIcon("move")); +    d->cornerButton->hide(); +    TQToolTip::add(d->cornerButton, i18n("Pan the image to a region")); +    setCornerWidget(d->cornerButton); + +    viewport()->setBackgroundMode(TQt::NoBackground); +    viewport()->setMouseTracking(false); +    setFrameStyle( TQFrame::NoFrame ); + +    // ------------------------------------------------------------ + +    connect(this, TQ_SIGNAL(signalZoomChanged(double)), +            this, TQ_SLOT(slotZoomChanged(double))); + +    connect(d->cornerButton, TQ_SIGNAL(pressed()), +            this, TQ_SLOT(slotCornerButtonPressed())); + +    connect(d->im, TQ_SIGNAL(signalModified()), +            this, TQ_SLOT(slotModified())); + +    connect(d->im, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool)), +            this, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool))); + +    connect(d->im, TQ_SIGNAL(signalLoadingStarted(const TQString&)), +            this, TQ_SIGNAL(signalLoadingStarted(const TQString&))); + +    connect(d->im, TQ_SIGNAL(signalImageLoaded(const TQString&, bool)), +            this, TQ_SLOT(slotImageLoaded(const TQString&, bool))); + +    connect(d->im, TQ_SIGNAL(signalImageSaved(const TQString&, bool)), +            this, TQ_SLOT(slotImageSaved(const TQString&, bool))); + +    connect(d->im, TQ_SIGNAL(signalLoadingProgress(const TQString&, float)), +            this, TQ_SIGNAL(signalLoadingProgress(const TQString&, float))); + +    connect(d->im, TQ_SIGNAL(signalSavingProgress(const TQString&, float)), +            this, TQ_SIGNAL(signalSavingProgress(const TQString&, float))); + +    connect(this, TQ_SIGNAL(signalSelected(bool)), +            this, TQ_SLOT(slotSelected())); +} + +Canvas::~Canvas() +{ +    delete d->tileTmpPix; +    delete d->im; + +    if (d->rubber) +        delete d->rubber; + +    delete d; +} + +void Canvas::resetImage() +{ +    reset(); +    viewport()->setUpdatesEnabled(false); +    d->im->resetImage(); +} + +void Canvas::reset() +{ +    if (d->rubber) +    { +        delete d->rubber; +        d->rubber = 0; +        if (d->im->imageValid()) +            emit signalSelected(false); +    } + +    d->tileCache.clear(); +} + +void Canvas::load(const TQString& filename, IOFileSettingsContainer *IOFileSettings) +{ +    reset(); + +    viewport()->setUpdatesEnabled(false); + +    d->im->load( filename, IOFileSettings, d->parent ); + +    emit signalPrepareToLoad(); +} + +void Canvas::slotImageLoaded(const TQString& filePath, bool success) +{ +    d->zoom = 1.0; +    d->im->zoom(d->zoom); + +    if (d->autoZoom) +        updateAutoZoom(); + +    updateContentsSize(true); + +    viewport()->setUpdatesEnabled(true); +    viewport()->update(); + +    emit signalZoomChanged(d->zoom); + +    emit signalLoadingFinished(filePath, success); +} + +void Canvas::preload(const TQString& /*filename*/) +{ +//    d->im->preload(filename); +} + +/* +These code part are unused and untested +void Canvas::save(const TQString& filename, IOFileSettingsContainer *IOFileSettings) +{ +    d->im->save(filename, IOFileSettings); +    emit signalSavingStarted(filename); +} + +void Canvas::saveAs(const TQString& filename,IOFileSettingsContainer *IOFileSettings, +                    const TQString& mimeType) +{ +    d->im->saveAs(filename, IOFileSettings, mimeType); +    emit signalSavingStarted(filename); +} +*/ + +void Canvas::saveAs(const TQString& filename, IOFileSettingsContainer *IOFileSettings, +                    bool setExifOrientationTag, const TQString& mimeType) +{ +    d->im->saveAs(filename, IOFileSettings, setExifOrientationTag, mimeType); +    emit signalSavingStarted(filename); +} + +void Canvas::slotImageSaved(const TQString& filePath, bool success) +{ +    emit signalSavingFinished(filePath, success); +} + +void Canvas::switchToLastSaved(const TQString& newFilename) +{ +    d->im->switchToLastSaved(newFilename); +} + +void Canvas::abortSaving() +{ +    d->im->abortSaving(); +} + +void Canvas::setModified() +{ +    d->im->setModified(); +} + +void Canvas::readMetadataFromFile(const TQString &file) +{ +    d->im->readMetadataFromFile(file); +} + +void Canvas::clearUndoHistory() +{ +    d->im->clearUndoManager(); +} + +void Canvas::setUndoHistoryOrigin() +{ +    d->im->setUndoManagerOrigin(); +} + +void Canvas::updateUndoState() +{ +    d->im->updateUndoState(); +} + +DImg Canvas::currentImage() +{ +    return DImg(*d->im->getImg()); +} + +TQString Canvas::currentImageFileFormat() +{ +    return d->im->getImageFormat(); +} + +TQString Canvas::currentImageFilePath() +{ +    return d->im->getImageFilePath(); +} + +int Canvas::imageWidth() +{ +    return d->im->origWidth();   +} + +int Canvas::imageHeight() +{ +    return d->im->origHeight(); +} + +bool Canvas::isReadOnly() +{ +    return d->im->isReadOnly(); +} + +TQRect Canvas::getSelectedArea() +{ +    int x, y, w, h; +    d->im->getSelectedArea(x, y, w, h); +    return ( TQRect(x, y, w, h) ); +} + +DImgInterface *Canvas::interface() const +{ +    return d->im; +} + +void Canvas::makeDefaultEditingCanvas() +{ +    DImgInterface::setDefaultInterface(d->im); +} + +double Canvas::calcAutoZoomFactor() +{ +    if (!d->im->imageValid()) return d->zoom; + +    double srcWidth  = d->im->origWidth(); +    double srcHeight = d->im->origHeight(); +    double dstWidth  = contentsRect().width(); +    double dstHeight = contentsRect().height(); +    return TQMIN(dstWidth/srcWidth, dstHeight/srcHeight); +} + +void Canvas::updateAutoZoom() +{ +    d->zoom = calcAutoZoomFactor(); +    d->im->zoom(d->zoom); +    emit signalZoomChanged(d->zoom); +} + +void Canvas::updateContentsSize(bool deleteRubber) +{ +    viewport()->setUpdatesEnabled(false); + +    if (deleteRubber && d->rubber) +    { +        delete d->rubber; +        d->rubber       = 0; +        d->ltActive     = false; +        d->rtActive     = false; +        d->lbActive     = false; +        d->rbActive     = false; +        d->pressedMoved = false; +        viewport()->unsetCursor(); +        viewport()->setMouseTracking(false); +        if (d->im->imageValid()) +            emit signalSelected(false); +    } +     +    int wZ = d->im->width(); +    int hZ = d->im->height(); +     +    if (visibleWidth() > wZ || visibleHeight() > hZ) +    { +        // Center the image +        int centerx = contentsRect().width()/2; +        int centery = contentsRect().height()/2; +        int xoffset = int(centerx - wZ/2); +        int yoffset = int(centery - hZ/2); +        xoffset     = TQMAX(xoffset, 0); +        yoffset     = TQMAX(yoffset, 0); + +        d->pixmapRect = TQRect(xoffset, yoffset, wZ, hZ); +    } +    else +    { +        d->pixmapRect = TQRect(0, 0, wZ, hZ); +    } + +    if (!deleteRubber && d->rubber) +    { +        int xSel, ySel, wSel, hSel; +        d->im->getSelectedArea(xSel, ySel, wSel, hSel); +        xSel = (int)((xSel * d->tileSize) / floor(d->tileSize / d->zoom)); +        ySel = (int)((ySel * d->tileSize) / floor(d->tileSize / d->zoom)); +        wSel = (int)((wSel * d->tileSize) / floor(d->tileSize / d->zoom)); +        hSel = (int)((hSel * d->tileSize) / floor(d->tileSize / d->zoom)); +        d->rubber->setX(xSel); +        d->rubber->setY(ySel); +        d->rubber->setWidth(wSel); +        d->rubber->setHeight(hSel); +        d->rubber->moveBy(d->pixmapRect.x(), d->pixmapRect.y()); +    } +     +    d->tileCache.clear();     +    resizeContents(wZ, hZ); +    viewport()->setUpdatesEnabled(true); +} + +void Canvas::resizeEvent(TQResizeEvent* e) +{ +    if (!e) +        return; + +    TQScrollView::resizeEvent(e); + +    if (d->autoZoom) +        updateAutoZoom(); + +    updateContentsSize(false); + +    // No need to repaint. its called    +    // automatically after resize + +    // To be sure than corner widget used to pan image will be hide/show  +    // accordinly with resize event. +    slotZoomChanged(d->zoom); +} + +void Canvas::viewportPaintEvent(TQPaintEvent *e) +{ +    TQRect er(e->rect()); +    er = TQRect(TQMAX(er.x() - 1, 0), +               TQMAX(er.y() - 1, 0), +               TQMIN(er.width()  + 2, contentsRect().width()), +               TQMIN(er.height() + 2, contentsRect().height())); +     +    paintViewport(er, (d->zoom <= 1.0) ? true : false); +} + +void Canvas::paintViewport(const TQRect& er, bool antialias) +{ +    TQRect o_cr(viewportToContents(er.topLeft()), viewportToContents(er.bottomRight())); +    TQRect cr = o_cr; + +    TQRegion clipRegion(er); +    cr = d->pixmapRect.intersect(cr); + +    if (!cr.isEmpty() && d->im->imageValid()) +    { +        clipRegion -= TQRect(contentsToViewport(cr.topLeft()), cr.size()); + +        TQRect pr = TQRect(cr.x() - d->pixmapRect.x(), cr.y() - d->pixmapRect.y(), +                         cr.width(), cr.height()); + +        int x1 = (int)floor((double)pr.x()      / (double)d->tileSize) * d->tileSize; +        int y1 = (int)floor((double)pr.y()      / (double)d->tileSize) * d->tileSize; +        int x2 = (int)ceilf((double)pr.right()  / (double)d->tileSize) * d->tileSize; +        int y2 = (int)ceilf((double)pr.bottom() / (double)d->tileSize) * d->tileSize; + +        TQPixmap pix(d->tileSize, d->tileSize); +        int sx, sy, sw, sh; +        int step = (int)floor(d->tileSize / d->zoom); + +        bool hasRubber = (d->rubber && d->pressedMoved && d->pressedMoving && d->rubber->intersects(pr)); +        if (hasRubber) +        { +            // remove rubber +            drawRubber(); +        } + +        for (int j = y1 ; j < y2 ; j += d->tileSize) +        { +            for (int i = x1 ; i < x2 ; i += d->tileSize) +            { +                TQString key  = TQString("%1,%2").arg(i).arg(j); +                TQPixmap *pix = d->tileCache.find(key); + +                if (!pix) +                { +                    if (antialias) +                    { +                        pix = new TQPixmap(d->tileSize, d->tileSize); +                        d->tileCache.insert(key, pix); +                    } +                    else +                    { +                        pix = d->tileTmpPix; +                    } + +                    if (d->im->hasAlpha()) +                    { +                        TQPainter p(pix); +                        p.drawTiledPixmap(0, 0, d->tileSize, d->tileSize, +                                          d->qcheck, 0, 0); +                        p.end(); +                    } +                    else +                    { +                        pix->fill(d->bgColor); +                    } + +                    // NOTE : with implementations <= 0.9.1, the canvas doesn't work properly using high zoom level (> 500). +                    // The sx, sy, sw, sh values haven't be computed properly and "tile" artefacts been appears  +                    // over the image. Look the example here: +                    // http://digikam3rdparty.free.fr/Screenshots/editorhighzoomartefact.png +                    // Note than these "tile" artifacts are not the real tiles of canvas. +                    // The new implementation below fix this problem to handle properly the areas to  +                    // use from the source image to generate the canvas pixmap tiles.   + +                    sx = (int)floor((double)i / d->tileSize) * step; +                    sy = (int)floor((double)j / d->tileSize) * step; +                    sw = step; +                    sh = step; + +                    if (d->rubber && d->pressedMoved && !d->pressedMoving) +                    { +                        TQRect rr(d->rubber->normalize()); +                        TQRect  r(i, j, d->tileSize, d->tileSize); + +                        d->im->paintOnDevice(pix, sx, sy, sw, sh, +                                             0, 0, d->tileSize, d->tileSize, +                                             rr.x() - i - d->pixmapRect.x(), +                                             rr.y() - j - d->pixmapRect.y(), +                                             rr.width(), rr.height(), +                                             antialias); + +                        rr.moveBy(-i -d->pixmapRect.x(), -j -d->pixmapRect.y()); +  +                        TQPainter p(pix); +                        p.setPen(TQPen(TQColor(250, 250, 255), 1)); +                        p.drawRect(rr); +                        if (rr.width() >= 10 && rr.height() >= 10) +                        { +                            p.drawRect(rr.x(),              rr.y(),               5, 5); +                            p.drawRect(rr.x(),              rr.y()+rr.height()-5, 5, 5); +                            p.drawRect(rr.x()+rr.width()-5, rr.y()+rr.height()-5, 5, 5); +                            p.drawRect(rr.x()+rr.width()-5, rr.y(),               5, 5); +                        } +                        p.end(); +                    } +                    else +                    { +                        d->im->paintOnDevice(pix, sx, sy, sw, sh, +                                             0, 0, d->tileSize, d->tileSize, +                                             antialias); +                    } +                } + +                TQRect  r(i, j, d->tileSize, d->tileSize); +                TQRect  ir = pr.intersect(r); +                TQPoint pt(contentsToViewport(TQPoint(ir.x() + d->pixmapRect.x(), +                                                    ir.y() + d->pixmapRect.y()))); + +                bitBlt(viewport(), pt.x(), pt.y(), +                       pix, +                       ir.x()-r.x(), ir.y()-r.y(), +                       ir.width(), ir.height()); +            } +        } + +        if (hasRubber) +        { +            // restore rubber +            drawRubber(); +        } +    } + +    TQPainter painter(viewport()); +    painter.setClipRegion(clipRegion); +    painter.fillRect(er, d->bgColor); +    painter.end(); +} + +void Canvas::drawRubber() +{ +    if (!d->rubber || !d->im->imageValid()) +        return; + +    TQPainter p(viewport()); +    p.setRasterOp(TQt::NotROP ); +    p.setPen(TQPen(TQt::color0, 1)); +    p.setBrush(NoBrush); + +    TQRect r(d->rubber->normalize()); +    r = TQRect(contentsToViewport(TQPoint(r.x(), r.y())), r.size()); + +    TQPoint pnt(r.x(), r.y()); + +    style().drawPrimitive(TQStyle::PE_FocusRect, &p, +                          TQRect(pnt.x(), pnt.y(), r.width(), r.height()), +                          colorGroup(), TQStyle::Style_Default, +                          TQStyleOption(colorGroup().base())); +    p.end(); +} + +void Canvas::contentsMousePressEvent(TQMouseEvent *e) +{ +    if (!e || e->button() == TQt::RightButton) +        return; + +    d->midButtonPressed = false; + +    if (e->button() == TQt::LeftButton) +    { +        if (d->ltActive || d->rtActive || +            d->lbActive || d->rbActive) +        { +            Q_ASSERT( d->rubber ); +            if (!d->rubber) +                return; + +            // Set diagonally opposite corner as anchor +         +            TQRect r(d->rubber->normalize()); + +            if (d->ltActive) +            { +                d->rubber->setTopLeft(r.bottomRight()); +                d->rubber->setBottomRight(r.topLeft()); +            } +            else if (d->rtActive) +            { +                d->rubber->setTopLeft(r.bottomLeft()); +                d->rubber->setBottomRight(r.topRight()); +            } +            else if (d->lbActive) +            { +                d->rubber->setTopLeft(r.topRight()); +                d->rubber->setBottomRight(r.bottomLeft()); +            } +            else if (d->rbActive) +            { +                d->rubber->setTopLeft(r.topLeft()); +                d->rubber->setBottomRight(r.bottomLeft()); +            } +         +            viewport()->setMouseTracking(false); +            d->pressedMoved  = false; +            d->pressedMoving = true; + +            d->tileCache.clear(); +            viewport()->repaint(false); + +            return; +        } +    } +    else if (e->button() == TQt::MidButton) +    { +        if (visibleWidth()  < d->im->width() || +            visibleHeight() < d->im->height()) +        { +            viewport()->setCursor(TQt::SizeAllCursor); +            d->midButtonPressed = true; +            d->midButtonX       = e->x(); +            d->midButtonY       = e->y(); +        } +        return; +    } +     +    if (d->rubber) +    { +        delete d->rubber; +        d->rubber = 0;         +    } + +    d->rubber = new TQRect(e->x(), e->y(), 0, 0); + +    if (d->pressedMoved) +    { +        d->tileCache.clear(); +        viewport()->update(); +    } +     +    d->pressedMoved  = false; +    d->pressedMoving = true; + +    viewport()->setMouseTracking(false); +} + +void Canvas::contentsMouseMoveEvent(TQMouseEvent *e) +{ +    if (!e) +        return; + +    if (e->state() & TQt::MidButton) +    { +        if (d->midButtonPressed) +        { +            scrollBy(d->midButtonX - e->x(), +                     d->midButtonY - e->y()); +        } +    } +    else if (!viewport()->hasMouseTracking()) +    { +        if (!d->rubber) +            return; +         +        if (e->state() != TQt::LeftButton && +            !(d->ltActive || d->rtActive || +              d->lbActive || d->rbActive)) +            return; + +        // Clear old rubber. +        if (d->pressedMoved) +            drawRubber(); + +        // Move content if necessary. +        blockSignals(true); +        setUpdatesEnabled(false); +        ensureVisible(e->x(), e->y(), 10, 10); +        setUpdatesEnabled(true); +        blockSignals(false); + +        // draw the new rubber position. +        int r, b; +        r = (e->x() > d->pixmapRect.left()) ? e->x() : d->pixmapRect.left(); +        r = (r < d->pixmapRect.right())     ? r      : d->pixmapRect.right(); +        b = (e->y() > d->pixmapRect.top())  ? e->y() : d->pixmapRect.top(); +        b = (b < d->pixmapRect.bottom())    ? b      : d->pixmapRect.bottom(); +        d->rubber->setRight(r); +        d->rubber->setBottom(b); +        drawRubber(); + +        d->pressedMoved  = true; +        d->pressedMoving = true; + +        // To refresh editor status bar with current selection. +        emit signalSelectionChanged(calcSeletedArea()); +    } +    else +    { +        if (!d->rubber) +            return; +         +        TQRect r(d->rubber->normalize()); +         +        TQRect lt(r.x()-5,           r.y()-5,            10, 10); +        TQRect rt(r.x()+r.width()-5, r.y()-5,            10, 10); +        TQRect lb(r.x()-5,           r.y()+r.height()-5, 10, 10); +        TQRect rb(r.x()+r.width()-5, r.y()+r.height()-5, 10, 10); + +        d->ltActive = false; +        d->rtActive = false; +        d->lbActive = false; +        d->rbActive = false; +         +        if (lt.contains(e->x(), e->y())) +        { +            viewport()->setCursor(TQt::SizeFDiagCursor); +            d->ltActive = true; +        } +        else if (rb.contains(e->x(), e->y())) +        { +            viewport()->setCursor(TQt::SizeFDiagCursor); +            d->rbActive = true; +        } +        else if (lb.contains(e->x(), e->y())) +        { +            viewport()->setCursor(TQt::SizeBDiagCursor); +            d->lbActive = true; +        } +        else if (rt.contains(e->x(), e->y())) +        { +            viewport()->setCursor(TQt::SizeBDiagCursor); +            d->rtActive = true; +        } +        else +            viewport()->unsetCursor(); +    } +} +     +void Canvas::contentsMouseReleaseEvent(TQMouseEvent *e) +{ +    if (!e) +        return; + +    d->midButtonPressed = false; +     +    if (d->pressedMoving) +    { +        d->pressedMoving = false; +        viewport()->update(); +    } + +    if (d->pressedMoved && d->rubber) +    { +        // Normalize rubber rectangle to always have the selection into the image  +        TQRect rec = d->rubber->normalize();         + +        if (rec.left()   < d->pixmapRect.left())   rec.setLeft(d->pixmapRect.left());  +        if (rec.right()  > d->pixmapRect.right())  rec.setRight(d->pixmapRect.right());  +        if (rec.top()    < d->pixmapRect.top())    rec.setTop(d->pixmapRect.top());  +        if (rec.bottom() > d->pixmapRect.bottom()) rec.setBottom(d->pixmapRect.bottom());  + +        d->rubber->setLeft(rec.left()); +        d->rubber->setRight(rec.right()); +        d->rubber->setTop(rec.top()); +        d->rubber->setBottom(rec.bottom()); + +        d->tileCache.clear(); +        viewport()->setMouseTracking(true); +        if (d->im->imageValid()) +            emit signalSelected(true); +    } +    else +    { +        d->ltActive = false; +        d->rtActive = false; +        d->lbActive = false; +        d->rbActive = false; +        viewport()->setMouseTracking(false); +        viewport()->unsetCursor(); +        if (d->im->imageValid()) +            emit signalSelected(false); +    } + +    if (e->button() != TQt::LeftButton) +    { +        viewport()->unsetCursor(); +    } + +    if (e->button() == TQt::RightButton) +    { +        emit signalRightButtonClicked(); +    } +} + +void Canvas::contentsWheelEvent(TQWheelEvent *e) +{ +    e->accept(); + +    if (e->state() & TQt::ShiftButton) +    { +        if (e->delta() < 0) +            emit signalShowNextImage(); +        else if (e->delta() > 0) +            emit signalShowPrevImage(); +        return; +    } +    else if (e->state() & TQt::ControlButton) +    { +        if (e->delta() < 0) +            slotDecreaseZoom(); +        else if (e->delta() > 0) +            slotIncreaseZoom(); +        return; +    } + +    TQScrollView::contentsWheelEvent(e); +} + +bool Canvas::maxZoom() +{ +    return ((d->zoom * d->zoomMultiplier) >= d->maxZoom); +} + +bool Canvas::minZoom() +{ +    return ((d->zoom / d->zoomMultiplier) <= d->minZoom); +} + +bool Canvas::exifRotated() +{ +    return d->im->exifRotated(); +} + +double Canvas::snapZoom(double zoom) +{ +    // If the zoom value gets changed from d->zoom to zoom +    // across 50%, 100% or fit-to-window, then return the +    // the corresponding special value. Otherwise zoom is returned unchanged. +    double fit = calcAutoZoomFactor(); +    TQValueList<double> snapValues; +    snapValues.append(0.5); +    snapValues.append(1.0); +    snapValues.append(fit); + +    qHeapSort(snapValues); +    TQValueList<double>::const_iterator it; + +    if (d->zoom < zoom)  +    { +        for(it = snapValues.constBegin(); it != snapValues.constEnd(); ++it) +        { +            double z = *it; +            if ((d->zoom < z) && (zoom > z)) +            { +                 zoom = z; +                 break; +            } +        } +    } +    else +    { +        // We need to go through the list in reverse order, +        // however, tqCopyBackward does not seem to work here, so  +        // a simple for loop over integers is used instead. +        for(int i=snapValues.size()-1; i>=0; i--)  +        { +            double z = snapValues[i]; +            if ((d->zoom > z) && (zoom < z)) +            { +                 zoom = z; +                 break; +            } +        } +    } + +    return zoom; +} + +void Canvas::slotIncreaseZoom() +{ +    if (maxZoom()) +        return; + +    double zoom = d->zoom * d->zoomMultiplier; +    zoom        = snapZoom(zoom); +    setZoomFactor(zoom); +} + +void Canvas::slotDecreaseZoom() +{ +    if (minZoom()) +        return; + +    double zoom = d->zoom / d->zoomMultiplier; +    zoom        = snapZoom(zoom); +    setZoomFactor(zoom); +} + +void Canvas::setZoomFactorSnapped(double zoom) +{ +    double fit = calcAutoZoomFactor(); + +    if (fabs(zoom-fit) < 0.05) +    { +        // If 1.0 or 0.5 are even closer to zoom than fit, then choose these. +        if  (fabs(zoom-fit) > fabs(zoom-1.0) ) +        { +            zoom = 1.0; +        } +        else if  (fabs(zoom-fit) > fabs(zoom-0.5) ) +        { +            zoom = 0.5; +        } +        else +        { +            zoom = fit; +        } +    } +    else +    { +        if (fabs(zoom-1.0) < 0.05) +        { +            zoom = 1.0; +        } +        if (fabs(zoom-0.5) < 0.05) +        { +            zoom = 0.5; +        } +    } +    setZoomFactor(zoom); +} + +double Canvas::zoomFactor() +{ +    return d->zoom; +} + +void Canvas::setZoomFactor(double zoom) +{ +    if (d->autoZoom) +    { +        d->autoZoom = false; +        emit signalToggleOffFitToWindow(); +    } + +    // Zoom using center of canvas and given zoom factor. + +    double cpx = contentsX() + visibleWidth()  / 2.0;  +    double cpy = contentsY() + visibleHeight() / 2.0; + +    cpx = (cpx / d->tileSize) * floor(d->tileSize / d->zoom); +    cpy = (cpy / d->tileSize) * floor(d->tileSize / d->zoom); + +    d->zoom = zoom; + +    d->im->zoom(d->zoom); +    updateContentsSize(false); + +    viewport()->setUpdatesEnabled(false); +    center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)),  +           (int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom))); +    viewport()->setUpdatesEnabled(true); +    viewport()->update(); + +    emit signalZoomChanged(d->zoom); +} + +void Canvas::fitToSelect() +{ +    int xSel, ySel, wSel, hSel; +    d->im->getSelectedArea(xSel, ySel, wSel, hSel); +     +    if (wSel && hSel )    +    {    +        // If selected area, use center of selection +        // and recompute zoom factor accordinly. +        double cpx = xSel + wSel / 2.0;  +        double cpy = ySel + hSel / 2.0; + +        double srcWidth  = wSel; +        double srcHeight = hSel; +        double dstWidth  = contentsRect().width(); +        double dstHeight = contentsRect().height(); +     +        d->zoom = TQMIN(dstWidth/srcWidth, dstHeight/srcHeight); + +        d->autoZoom = false; +        emit signalToggleOffFitToWindow(); +        d->im->zoom(d->zoom); +        updateContentsSize(true); +     +        viewport()->setUpdatesEnabled(false); +        center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)),  +               (int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom))); +        viewport()->setUpdatesEnabled(true); +        viewport()->update(); +     +        emit signalZoomChanged(d->zoom); +    } +} + +bool Canvas::fitToWindow() +{ +    return d->autoZoom; +} + +void Canvas::toggleFitToWindow() +{ +    d->autoZoom = !d->autoZoom; + +    if (d->autoZoom) +        updateAutoZoom(); +    else +    { +        d->zoom = 1.0; +        emit signalZoomChanged(d->zoom); +    } + +    d->im->zoom(d->zoom); +    updateContentsSize(false); +    slotZoomChanged(d->zoom); +    viewport()->update(); +} + +void Canvas::slotRotate90() +{ +    d->im->rotate90(); +} + +void Canvas::slotRotate180() +{ +    d->im->rotate180(); +} + +void Canvas::slotRotate270() +{ +    d->im->rotate270(); +} + +void Canvas::slotFlipHoriz() +{ +    d->im->flipHoriz(); +} + +void Canvas::slotFlipVert() +{ +    d->im->flipVert(); +} + +void Canvas::slotCrop() +{ +    int x, y, w, h; +    d->im->getSelectedArea(x, y, w, h); + +    if (!w && !h )  // No current selection. +        return; + +    d->im->crop(x, y, w, h); +} + +void Canvas::resizeImage(int w, int h) +{ +    d->im->resize(w, h); +} + +void Canvas::setBackgroundColor(const TQColor& color) +{ +    if (d->bgColor == color) +        return; +     +    d->bgColor = color; +    viewport()->update(); +} + +void Canvas::setICCSettings(ICCSettingsContainer *cmSettings) +{ +    d->im->setICCSettings(cmSettings); +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::setExposureSettings(ExposureSettingsContainer *expoSettings) +{ +    d->im->setExposureSettings(expoSettings); +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::setExifOrient(bool exifOrient) +{ +    d->im->setExifOrient(exifOrient); +    viewport()->update(); +} + +void Canvas::increaseGamma() +{ +    d->im->changeGamma(1);     +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::decreaseGamma() +{ +    d->im->changeGamma(-1);     +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::increaseBrightness() +{ +    d->im->changeBrightness(1);     +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::decreaseBrightness() +{ +    d->im->changeBrightness(-1);     +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::increaseContrast() +{ +    d->im->changeContrast(5);     +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::decreaseContrast() +{ +    d->im->changeContrast(-5);     +    d->tileCache.clear();     +    viewport()->update(); +} + +void Canvas::slotRestore() +{ +    d->im->restore(); +} + +void Canvas::slotUndo(int steps) +{ +    while(steps > 0) +    { +        d->im->undo(); +        --steps; +    } +} + +void Canvas::getUndoHistory(TQStringList &titles) +{ +    d->im->getUndoHistory(titles); +} + +void Canvas::getRedoHistory(TQStringList &titles) +{ +    d->im->getRedoHistory(titles); +} + +void Canvas::slotRedo(int steps) +{ +    while(steps > 0) +    { +        d->im->redo(); +        --steps; +    } +} + +void Canvas::slotCopy() +{ +    int x, y, w, h; +    d->im->getSelectedArea(x, y, w, h); + +    if (!w && !h )  // No current selection. +        return; + +    TQApplication::setOverrideCursor (TQt::waitCursor); +    uchar* data = d->im->getImageSelection(); +    DImg selDImg = DImg(w, h, d->im->sixteenBit(), d->im->hasAlpha(), data); +    delete [] data; + +    TQImage selImg = selDImg.copyTQImage(); +    TQApplication::clipboard()->setData(new TQImageDrag(selImg), TQClipboard::Clipboard); +    TQApplication::restoreOverrideCursor (); +} + +void Canvas::slotSelected() +{ +    int x=0, y=0, w=0, h=0; +     +    if (d->rubber && d->pressedMoved)  +    { +        TQRect sel = calcSeletedArea(); +        x = sel.x(); +        y = sel.y(); +        w = sel.width(); +        h = sel.height(); +    } + +    d->im->setSelectedArea(x, y, w, h); +} + +TQRect Canvas::calcSeletedArea() +{ +    int x=0, y=0, w=0, h=0; +    TQRect r(d->rubber->normalize()); +     +    if (r.isValid())  +    { +        r.moveBy(- d->pixmapRect.x(), - d->pixmapRect.y()); + +        x = (int)(((double)r.x()      / d->tileSize) * floor(d->tileSize / d->zoom)); +        y = (int)(((double)r.y()      / d->tileSize) * floor(d->tileSize / d->zoom)); +        w = (int)(((double)r.width()  / d->tileSize) * floor(d->tileSize / d->zoom));    +        h = (int)(((double)r.height() / d->tileSize) * floor(d->tileSize / d->zoom)); + +        x = TQMIN(imageWidth(),  TQMAX(x, 0));    +        y = TQMIN(imageHeight(), TQMAX(y, 0)); +        w = TQMIN(imageWidth(),  TQMAX(w, 0)); +        h = TQMIN(imageHeight(), TQMAX(h, 0)); + +        // Avoid empty selection by rubberband - at least mark one pixel +        // At high zoom factors, the rubberband may operate at subpixel level! +        if (w == 0) +            w = 1; +        if (h == 0) +            h = 1; +    } +     +    return TQRect(x, y, w, h);  +} + +void Canvas::slotModified() +{ +    if (d->autoZoom) +        updateAutoZoom(); +    d->im->zoom(d->zoom); + +    updateContentsSize(true); +    viewport()->update(); + +    // To be sure than corner widget used to pan image will be hide/show  +    // accordinly with new image size (if changed). +    slotZoomChanged(d->zoom); + +    emit signalChanged(); +} + +void Canvas::slotCornerButtonPressed() +{     +    if (d->panIconPopup) +    { +        d->panIconPopup->hide(); +        delete d->panIconPopup; +        d->panIconPopup = 0; +    } + +    d->panIconPopup         = new TDEPopupFrame(this); +    ImagePanIconWidget *pan = new ImagePanIconWidget(180, 120, d->panIconPopup); +    d->panIconPopup->setMainWidget(pan); + +    TQRect r((int)(contentsX()    / d->zoom), (int)(contentsY()     / d->zoom), +            (int)(visibleWidth() / d->zoom), (int)(visibleHeight() / d->zoom)); +    pan->setRegionSelection(r); +    pan->setMouseFocus(); + +    connect(pan, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)), +            this, TQ_SLOT(slotPanIconSelectionMoved(const TQRect&, bool))); +     +    connect(pan, TQ_SIGNAL(signalHiden()), +            this, TQ_SLOT(slotPanIconHiden())); +     +    TQPoint g = mapToGlobal(viewport()->pos()); +    g.setX(g.x()+ viewport()->size().width()); +    g.setY(g.y()+ viewport()->size().height()); +    d->panIconPopup->popup(TQPoint(g.x() - d->panIconPopup->width(),  +                                  g.y() - d->panIconPopup->height())); + +    pan->setCursorToLocalRegionSelectionCenter(); +} + +void Canvas::slotPanIconHiden() +{ +    d->cornerButton->blockSignals(true); +    d->cornerButton->animateClick(); +    d->cornerButton->blockSignals(false); +} + +void Canvas::slotPanIconSelectionMoved(const TQRect& r, bool b) +{ +    setContentsPos((int)(r.x()*d->zoom), (int)(r.y()*d->zoom)); + +    if (b) +    { +        d->panIconPopup->hide(); +        delete d->panIconPopup; +        d->panIconPopup = 0; +        slotPanIconHiden(); +    } +} + +void Canvas::slotZoomChanged(double /*zoom*/) +{ +    updateScrollBars(); + +    if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible()) +        d->cornerButton->show(); +    else +        d->cornerButton->hide();         +} + +void Canvas::slotSelectAll() +{ +    if (d->rubber) +    { +        delete d->rubber; +        d->rubber = 0;         +    } + +    d->rubber       = new TQRect(d->pixmapRect); +    d->pressedMoved = true; +    d->tileCache.clear(); +    viewport()->setMouseTracking(true); +    viewport()->update(); + +    if (d->im->imageValid()) +        emit signalSelected(true); +} + +void Canvas::slotSelectNone() +{ +    reset(); +    viewport()->update(); +} + +}  // namespace Digikam | 
