summaryrefslogtreecommitdiffstats
path: root/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp')
-rw-r--r--src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp1422
1 files changed, 1422 insertions, 0 deletions
diff --git a/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp
new file mode 100644
index 00000000..17eaf415
--- /dev/null
+++ b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp
@@ -0,0 +1,1422 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-12-09
+ * Description : image selection widget used by ratio crop tool.
+ *
+ * Copyright (C) 2007 by Jaromir Malenko <malenko at email.cz>
+ * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com>
+ * Copyright (C) 2004-2009 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.
+ *
+ * ============================================================ */
+
+#define OPACITY 0.7
+#define RCOL 0xAA
+#define GCOL 0xAA
+#define BCOL 0xAA
+
+#define MINRANGE 0
+
+// Golden number (1+sqrt(5))/2
+#define PHI 1.61803398874989479
+// 1/PHI
+#define INVPHI 0.61803398874989479
+
+// C++ includes.
+
+#include <iostream>
+#include <cstdio>
+#include <cmath>
+#include <cstdlib>
+
+// TQt includes.
+
+#include <tqregion.h>
+#include <tqcolor.h>
+#include <tqpainter.h>
+#include <tqbrush.h>
+#include <tqpixmap.h>
+#include <tqimage.h>
+#include <tqpen.h>
+#include <tqpoint.h>
+#include <tqtimer.h>
+#include <tqsizepolicy.h>
+
+// KDE includes.
+
+#include <kstandarddirs.h>
+#include <kcursor.h>
+#include <tdeglobal.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "imageiface.h"
+#include "dimg.h"
+#include "imageselectionwidget.h"
+#include "imageselectionwidget.moc"
+
+namespace DigikamImagesPluginCore
+{
+
+class ImageSelectionWidgetPriv
+{
+public:
+
+ enum ResizingMode
+ {
+ ResizingNone = 0,
+ ResizingTopLeft,
+ ResizingTopRight,
+ ResizingBottomLeft,
+ ResizingBottomRight
+ };
+
+ ImageSelectionWidgetPriv()
+ {
+ currentResizing = ResizingNone;
+ iface = 0;
+ pixmap = 0;
+ guideSize = 1;
+ }
+
+ // Golden guide types.
+ bool drawGoldenSection;
+ bool drawGoldenSpiralSection;
+ bool drawGoldenSpiral;
+ bool drawGoldenTriangle;
+
+ // Golden guide translations.
+ bool flipHorGoldenGuide;
+ bool flipVerGoldenGuide;
+
+ bool moving;
+ bool autoOrientation;
+ bool preciseCrop;
+
+ int guideLinesType;
+ int guideSize;
+
+ int currentAspectRatioType;
+ int currentResizing;
+ int currentOrientation;
+
+ float currentWidthRatioValue;
+ float currentHeightRatioValue;
+
+ TQPoint lastPos;
+
+ TQRect rect;
+ TQRect image; // Real image dimension.
+ TQRect regionSelection; // Real size image selection.
+ TQRect localRegionSelection; // Local size selection.
+
+ // Draggable local region selection corners.
+ TQRect localTopLeftCorner;
+ TQRect localBottomLeftCorner;
+ TQRect localTopRightCorner;
+ TQRect localBottomRightCorner;
+
+ TQPixmap *pixmap;
+
+ TQColor guideColor;
+
+ Digikam::DImg preview;
+
+ Digikam::ImageIface *iface;
+};
+
+ImageSelectionWidget::ImageSelectionWidget(int w, int h, TQWidget *parent,
+ int widthRatioValue, int heightRatioValue,
+ int aspectRatioType, int orient, int guideLinesType)
+ : TQWidget(parent, 0, TQt::WDestructiveClose)
+{
+ d = new ImageSelectionWidgetPriv;
+ d->currentAspectRatioType = aspectRatioType;
+ d->currentWidthRatioValue = widthRatioValue;
+ d->currentHeightRatioValue = heightRatioValue;
+ d->currentOrientation = orient;
+ d->guideLinesType = guideLinesType;
+ d->autoOrientation = false;
+ d->preciseCrop = false;
+ d->moving = true;
+ reverseRatioValues();
+
+ setBackgroundMode(TQt::NoBackground);
+ setMinimumSize(w, h);
+ setMouseTracking(true);
+
+ d->iface = new Digikam::ImageIface(w, h);
+ uchar *data = d->iface->getPreviewImage();
+ int width = d->iface->previewWidth();
+ int height = d->iface->previewHeight();
+ bool sixteenBit = d->iface->previewSixteenBit();
+ bool hasAlpha = d->iface->previewHasAlpha();
+ d->preview = Digikam::DImg(width, height, sixteenBit, hasAlpha, data);
+ delete [] data;
+ d->preview.convertToEightBit();
+ d->pixmap = new TQPixmap(w, h);
+
+ d->image = TQRect(0, 0, d->iface->originalWidth(), d->iface->originalHeight());
+ d->rect = TQRect(w/2-d->preview.width()/2, h/2-d->preview.height()/2,
+ d->preview.width(), d->preview.height());
+ updatePixmap();
+ setGoldenGuideTypes(true, false, false, false, false, false);
+}
+
+ImageSelectionWidget::~ImageSelectionWidget()
+{
+ delete d->iface;
+ delete d->pixmap;
+ delete d;
+}
+
+Digikam::ImageIface* ImageSelectionWidget::imageIface()
+{
+ return d->iface;
+}
+
+void ImageSelectionWidget::resizeEvent(TQResizeEvent *e)
+{
+ delete d->pixmap;
+
+ int w = e->size().width();
+ int h = e->size().height();
+
+ uchar *data = d->iface->setPreviewImageSize(w, h);
+ int width = d->iface->previewWidth();
+ int height = d->iface->previewHeight();
+ bool sixteenBit = d->iface->previewSixteenBit();
+ bool hasAlpha = d->iface->previewHasAlpha();
+ d->preview = Digikam::DImg(width, height, sixteenBit, hasAlpha, data);
+ delete [] data;
+ d->preview.convertToEightBit();
+
+ d->pixmap = new TQPixmap(w, h);
+
+ d->rect = TQRect(w/2-d->preview.width()/2, h/2-d->preview.height()/2,
+ d->preview.width(), d->preview.height());
+ updatePixmap();
+}
+
+int ImageSelectionWidget::getOriginalImageWidth()
+{
+ return d->image.width();
+}
+
+int ImageSelectionWidget::getOriginalImageHeight()
+{
+ return d->image.height();
+}
+
+TQRect ImageSelectionWidget::getRegionSelection()
+{
+ return d->regionSelection;
+}
+
+int ImageSelectionWidget::getMinWidthRange()
+{
+ return MINRANGE;
+}
+
+int ImageSelectionWidget::getMinHeightRange()
+{
+ return MINRANGE;
+}
+
+int ImageSelectionWidget::getMaxWidthRange()
+{
+ int maxW = d->image.width() - d->regionSelection.left();
+
+ if (d->currentAspectRatioType != RATIONONE)
+ {
+ // Compute max width taking aspect ratio into account
+ int t = d->currentWidthRatioValue > d->currentHeightRatioValue ? 1 : 0;
+ int h = d->image.height() - d->regionSelection.top();
+ int w = rint( ( h + t ) * d->currentWidthRatioValue /
+ d->currentHeightRatioValue ) - t;
+ if ( w < maxW )
+ maxW = w;
+ }
+
+ // Return max width adjusted if a precise crop is wanted
+ return computePreciseSize(maxW, d->currentWidthRatioValue);
+}
+
+int ImageSelectionWidget::getMaxHeightRange()
+{
+ int maxH = d->image.height() - d->regionSelection.top();
+
+ if (d->currentAspectRatioType != RATIONONE)
+ {
+ // Compute max height taking aspect ratio into account
+ int t = d->currentHeightRatioValue > d->currentWidthRatioValue ? 1 : 0;
+ int w = d->image.width() - d->regionSelection.left();
+ int h = rint( ( w + t ) * d->currentHeightRatioValue /
+ d->currentWidthRatioValue ) - t;
+ if ( h < maxH )
+ maxH = h;
+ }
+
+ // Return max height adjusted if a precise crop is wanted
+ return computePreciseSize(maxH, d->currentHeightRatioValue);
+}
+
+int ImageSelectionWidget::getWidthStep()
+{
+ if ( d->preciseCrop && preciseCropAvailable() )
+ return d->currentWidthRatioValue;
+ else
+ return 1;
+}
+
+int ImageSelectionWidget::getHeightStep()
+{
+ if ( d->preciseCrop && preciseCropAvailable() )
+ return d->currentHeightRatioValue;
+ else
+ return 1;
+}
+
+// Draw a new centered selection with half width (if orientation = Landscape)
+// or with half height (if orientation = Portrait)
+void ImageSelectionWidget::resetSelection()
+{
+ d->regionSelection.setWidth(d->image.width()/2);
+ d->regionSelection.setHeight(d->image.height()/2);
+ applyAspectRatio(d->currentOrientation == Portrait, false);
+
+ setCenterSelection(CenterImage);
+}
+
+void ImageSelectionWidget::setCenterSelection(int centerType)
+{
+ // Adjust selection size if bigger than real image
+ if ( d->regionSelection.height() > d->image.height() )
+ {
+ d->regionSelection.setHeight(d->image.height());
+ applyAspectRatio(true, false);
+ }
+ if ( d->regionSelection.width() > d->image.width() )
+ {
+ d->regionSelection.setWidth(d->image.width());
+ applyAspectRatio(false, false);
+ }
+
+ // Set center point for selection
+ TQPoint center = d->image.center();
+ switch (centerType)
+ {
+ case CenterWidth:
+ center.setY(d->regionSelection.center().y());
+ break;
+
+ case CenterHeight:
+ center.setX(d->regionSelection.center().x());
+ break;
+ }
+ d->regionSelection.moveCenter(center);
+
+ // Repaint
+ updatePixmap();
+ repaint(false);
+ regionSelectionChanged();
+}
+
+// Draw a new centered selection with max size
+void ImageSelectionWidget::maxAspectSelection()
+{
+ d->regionSelection.setWidth(d->image.width());
+ d->regionSelection.setHeight(d->image.height());
+ if ( d->currentAspectRatioType != RATIONONE )
+ applyAspectRatio(d->currentOrientation == Portrait, false);
+
+ setCenterSelection(CenterImage);
+}
+
+void ImageSelectionWidget::setGoldenGuideTypes(bool drawGoldenSection, bool drawGoldenSpiralSection,
+ bool drawGoldenSpiral, bool drawGoldenTriangle,
+ bool flipHorGoldenGuide, bool flipVerGoldenGuide)
+{
+ d->drawGoldenSection = drawGoldenSection;
+ d->drawGoldenSpiralSection = drawGoldenSpiralSection;
+ d->drawGoldenSpiral = drawGoldenSpiral;
+ d->drawGoldenTriangle = drawGoldenTriangle;
+ d->flipHorGoldenGuide = flipHorGoldenGuide;
+ d->flipVerGoldenGuide = flipVerGoldenGuide;
+}
+
+void ImageSelectionWidget::slotGuideLines(int guideLinesType)
+{
+ d->guideLinesType = guideLinesType;
+ updatePixmap();
+ repaint(false);
+}
+
+void ImageSelectionWidget::slotChangeGuideColor(const TQColor &color)
+{
+ d->guideColor = color;
+ updatePixmap();
+ repaint(false);
+}
+
+void ImageSelectionWidget::slotChangeGuideSize(int size)
+{
+ d->guideSize = size;
+ updatePixmap();
+ repaint(false);
+}
+
+void ImageSelectionWidget::setSelectionOrientation(int orient)
+{
+ d->currentOrientation = orient;
+ reverseRatioValues();
+ applyAspectRatio(true);
+ emit signalSelectionOrientationChanged( d->currentOrientation );
+}
+
+void ImageSelectionWidget::setSelectionAspectRatioType(int aspectRatioType)
+{
+ d->currentAspectRatioType = aspectRatioType;
+
+ // Set ratio values
+ switch(aspectRatioType)
+ {
+ case RATIO01X01:
+ d->currentWidthRatioValue = 1.0;
+ d->currentHeightRatioValue = 1.0;
+ break;
+
+ case RATIO03X04:
+ d->currentWidthRatioValue = 4.0;
+ d->currentHeightRatioValue = 3.0;
+ break;
+
+ case RATIO02x03:
+ d->currentWidthRatioValue = 3.0;
+ d->currentHeightRatioValue = 2.0;
+ break;
+
+ case RATIO05x07:
+ d->currentWidthRatioValue = 7.0;
+ d->currentHeightRatioValue = 5.0;
+ break;
+
+ case RATIO07x10:
+ d->currentWidthRatioValue = 10.0;
+ d->currentHeightRatioValue = 7.0;
+ break;
+
+ case RATIO04X05:
+ d->currentWidthRatioValue = 5.0;
+ d->currentHeightRatioValue = 4.0;
+ break;
+
+ case RATIOGOLDEN:
+ d->currentWidthRatioValue = PHI;
+ d->currentHeightRatioValue = 1.0;
+ break;
+ }
+
+ reverseRatioValues();
+ applyAspectRatio(false);
+}
+
+void ImageSelectionWidget::setSelectionAspectRatioValue(int widthRatioValue,
+ int heightRatioValue)
+{
+ int gdc = widthRatioValue;
+
+ // Compute greatest common divisor using Euclidean algorithm
+ for (int tmp, mod = heightRatioValue; mod != 0; mod = tmp % mod)
+ {
+ tmp = gdc;
+ gdc = mod;
+ }
+
+ d->currentWidthRatioValue = widthRatioValue / gdc;
+ d->currentHeightRatioValue = heightRatioValue / gdc;
+ d->currentAspectRatioType = RATIOCUSTOM;
+
+ // Fix orientation
+ if ( d->autoOrientation )
+ {
+ if ( heightRatioValue > widthRatioValue &&
+ d->currentOrientation == Landscape )
+ {
+ d->currentOrientation = Portrait;
+ emit signalSelectionOrientationChanged( d->currentOrientation );
+ }
+ else if ( widthRatioValue > heightRatioValue &&
+ d->currentOrientation == Portrait )
+ {
+ d->currentOrientation = Landscape;
+ emit signalSelectionOrientationChanged( d->currentOrientation );
+ }
+ }
+ else
+ reverseRatioValues();
+
+ applyAspectRatio(false);
+}
+
+void ImageSelectionWidget::reverseRatioValues()
+{
+ // Reverse ratio values if needed
+ if ( ( d->currentWidthRatioValue > d->currentHeightRatioValue &&
+ d->currentOrientation == Portrait ) ||
+ ( d->currentHeightRatioValue > d->currentWidthRatioValue &&
+ d->currentOrientation == Landscape ) )
+ {
+ float tmp = d->currentWidthRatioValue;
+ d->currentWidthRatioValue = d->currentHeightRatioValue;
+ d->currentHeightRatioValue = tmp;
+ }
+}
+
+bool ImageSelectionWidget::preciseCropAvailable()
+{
+ // Define when precise crop feature can be used
+ // No needed when aspect ratio is 1:1
+ switch(d->currentAspectRatioType)
+ {
+ case RATIONONE:
+ case RATIO01X01:
+ case RATIOGOLDEN:
+ return false;
+
+ case RATIOCUSTOM:
+ return ( d->currentWidthRatioValue != d->currentHeightRatioValue );
+
+ default:
+ return true;
+ }
+}
+
+void ImageSelectionWidget::setPreciseCrop(bool precise)
+{
+ d->preciseCrop = precise;
+ applyAspectRatio(false, true);
+ regionSelectionChanged();
+}
+
+void ImageSelectionWidget::setAutoOrientation(bool orientation)
+{
+ d->autoOrientation = orientation;
+}
+
+void ImageSelectionWidget::setSelectionX(int x)
+{
+ d->regionSelection.moveLeft(x);
+ regionSelectionMoved();
+}
+
+void ImageSelectionWidget::setSelectionY(int y)
+{
+ d->regionSelection.moveTop(y);
+ regionSelectionMoved();
+}
+
+void ImageSelectionWidget::setSelectionWidth(int w)
+{
+ d->regionSelection.setWidth(w);
+ applyAspectRatio(false, true);
+
+ regionSelectionChanged();
+}
+
+void ImageSelectionWidget::setSelectionHeight(int h)
+{
+ d->regionSelection.setHeight(h);
+ applyAspectRatio(true, true);
+
+ regionSelectionChanged();
+}
+
+TQPoint ImageSelectionWidget::convertPoint(const TQPoint pm, bool localToReal)
+{
+ return convertPoint(pm.x(), pm.y(), localToReal);
+}
+
+TQPoint ImageSelectionWidget::convertPoint(int x, int y, bool localToReal)
+{
+ int pmX, pmY;
+
+ if (localToReal)
+ {
+ pmX = ( x - d->rect.left() ) * (float)d->image.width() /
+ (float)d->preview.width();
+
+ pmY = ( y - d->rect.top() ) * (float)d->image.height() /
+ (float)d->preview.height();
+ }
+ else
+ {
+ pmX = d->rect.left() + ( x * (float)d->preview.width() /
+ (float)d->image.width() );
+
+ pmY = d->rect.top() + ( y * (float)d->preview.height() /
+ (float)d->image.height() );
+ }
+
+ return TQPoint(pmX, pmY);
+}
+
+int ImageSelectionWidget::computePreciseSize(int size, int step)
+{
+ // Adjust size if precise crop is wanted
+ if ( d->preciseCrop && preciseCropAvailable() )
+ size = int(size / step) * step;
+
+ return size;
+}
+
+void ImageSelectionWidget::applyAspectRatio(bool useHeight, bool repaintWidget)
+{
+ // Save selection area for re-adjustment after changing width and height.
+ TQRect oldRegionSelection = d->regionSelection;
+
+ if ( !useHeight ) // Width changed.
+ {
+ int w = computePreciseSize(d->regionSelection.width(),
+ d->currentWidthRatioValue);
+
+ d->regionSelection.setWidth(w);
+ switch(d->currentAspectRatioType)
+ {
+ case RATIONONE:
+ break;
+
+ default:
+ d->regionSelection.setHeight(rint( w * d->currentHeightRatioValue /
+ d->currentWidthRatioValue ) );
+ break;
+ }
+ }
+ else // Height changed.
+ {
+ int h = computePreciseSize(d->regionSelection.height(),
+ d->currentHeightRatioValue);
+
+ d->regionSelection.setHeight(h);
+ switch(d->currentAspectRatioType)
+ {
+ case RATIONONE:
+ break;
+
+ default:
+ d->regionSelection.setWidth(rint( h * d->currentWidthRatioValue /
+ d->currentHeightRatioValue ) );
+ break;
+ }
+ }
+
+ // If we change selection size by a corner, re-adjust the oposite corner position.
+ switch(d->currentResizing)
+ {
+ case ImageSelectionWidgetPriv::ResizingTopLeft:
+ d->regionSelection.moveBottomRight( oldRegionSelection.bottomRight() );
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingTopRight:
+ d->regionSelection.moveBottomLeft( oldRegionSelection.bottomLeft() );
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomLeft:
+ d->regionSelection.moveTopRight( oldRegionSelection.topRight() );
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomRight:
+ d->regionSelection.moveTopLeft( oldRegionSelection.topLeft() );
+ break;
+ }
+
+ if (repaintWidget)
+ {
+ updatePixmap();
+ repaint(false);
+ }
+}
+
+void ImageSelectionWidget::normalizeRegion()
+{
+ // Perform normalization of selection area.
+
+ if (d->regionSelection.left() < d->image.left())
+ d->regionSelection.moveLeft(d->image.left());
+
+ if (d->regionSelection.top() < d->image.top())
+ d->regionSelection.moveTop(d->image.top());
+
+ if (d->regionSelection.right() > d->image.right())
+ d->regionSelection.moveRight(d->image.right());
+
+ if (d->regionSelection.bottom() > d->image.bottom())
+ d->regionSelection.moveBottom(d->image.bottom());
+}
+
+void ImageSelectionWidget::regionSelectionMoved()
+{
+ normalizeRegion();
+
+ updatePixmap();
+ repaint(false);
+
+ emit signalSelectionMoved( d->regionSelection );
+}
+
+void ImageSelectionWidget::regionSelectionChanged()
+{
+ // Compute the intersection of selection region and image region
+ TQRect cut = d->regionSelection & d->image;
+
+ // Adjust selection size if it was cropped
+ if ( d->regionSelection.width() > cut.width() )
+ {
+ d->regionSelection = cut;
+ applyAspectRatio(false);
+ }
+ if ( d->regionSelection.height() > cut.height() )
+ {
+ d->regionSelection = cut;
+ applyAspectRatio(true);
+ }
+
+ emit signalSelectionChanged( d->regionSelection );
+}
+
+void ImageSelectionWidget::updatePixmap()
+{
+ // Updated local selection region.
+ d->localRegionSelection.setTopLeft(
+ convertPoint(d->regionSelection.topLeft(), false));
+ d->localRegionSelection.setBottomRight(
+ convertPoint(d->regionSelection.bottomRight(), false));
+
+ // Updated dragging corners region.
+ d->localTopLeftCorner.setRect(d->localRegionSelection.left(),
+ d->localRegionSelection.top(), 8, 8);
+ d->localBottomLeftCorner.setRect(d->localRegionSelection.left(),
+ d->localRegionSelection.bottom() - 7, 8, 8);
+ d->localTopRightCorner.setRect(d->localRegionSelection.right() - 7,
+ d->localRegionSelection.top(), 8, 8);
+ d->localBottomRightCorner.setRect(d->localRegionSelection.right() - 7,
+ d->localRegionSelection.bottom() - 7, 8, 8);
+
+ // Drawing background and image.
+ d->pixmap->fill(colorGroup().background());
+
+ if (d->preview.isNull())
+ return;
+
+ // Drawing region outside selection grayed.
+
+ Digikam::DImg image = d->preview.copy();
+
+ uchar* ptr = image.bits();
+ uchar r, g, b;
+
+ for (int y=d->rect.top() ; y <= d->rect.bottom() ; y++)
+ {
+ for (int x=d->rect.left() ; x <= d->rect.right() ; x++)
+ {
+ if (! d->localRegionSelection.contains(x, y, true) )
+ {
+ b = ptr[0];
+ g = ptr[1];
+ r = ptr[2];
+
+ r += (uchar)((RCOL - r) * OPACITY);
+ g += (uchar)((GCOL - g) * OPACITY);
+ b += (uchar)((BCOL - b) * OPACITY);
+
+ ptr[0] = b;
+ ptr[1] = g;
+ ptr[2] = r;
+ }
+
+ ptr+=4;
+ }
+ }
+
+ TQPixmap pix = d->iface->convertToPixmap(image);
+ bitBlt(d->pixmap, d->rect.x(), d->rect.y(), &pix);
+
+ // Stop here if no selection to draw
+ if ( d->regionSelection.isEmpty() )
+ return;
+
+ TQPainter p(d->pixmap);
+
+ // Drawing selection borders.
+
+ p.setPen(TQPen(TQColor(250, 250, 255), 1, TQt::SolidLine));
+ p.drawRect(d->localRegionSelection);
+
+ // Drawing selection corners.
+
+ p.drawRect(d->localTopLeftCorner);
+ p.drawRect(d->localBottomLeftCorner);
+ p.drawRect(d->localTopRightCorner);
+ p.drawRect(d->localBottomRightCorner);
+
+ // Drawing guide lines.
+
+ // Constraint drawing only on local selection region.
+ // This is needed because arcs and incurved lines can draw
+ // outside a little of local selection region.
+ p.setClipping(true);
+ p.setClipRect(d->localRegionSelection);
+
+ switch (d->guideLinesType)
+ {
+ case RulesOfThirds:
+ {
+ int xThird = d->localRegionSelection.width() / 3;
+ int yThird = d->localRegionSelection.height() / 3;
+
+ p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine));
+ p.drawLine( d->localRegionSelection.left() + xThird, d->localRegionSelection.top(),
+ d->localRegionSelection.left() + xThird, d->localRegionSelection.bottom() );
+ p.drawLine( d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.top(),
+ d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.bottom() );
+
+ p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + yThird,
+ d->localRegionSelection.right(), d->localRegionSelection.top() + yThird );
+ p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + 2*yThird,
+ d->localRegionSelection.right(), d->localRegionSelection.top() + 2*yThird );
+
+ p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine));
+ p.drawLine( d->localRegionSelection.left() + xThird, d->localRegionSelection.top(),
+ d->localRegionSelection.left() + xThird, d->localRegionSelection.bottom() );
+ p.drawLine( d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.top(),
+ d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.bottom() );
+
+ p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + yThird,
+ d->localRegionSelection.right(), d->localRegionSelection.top() + yThird );
+ p.drawLine( d->localRegionSelection.left(), d->localRegionSelection.top() + 2*yThird,
+ d->localRegionSelection.right(), d->localRegionSelection.top() + 2*yThird );
+ break;
+ }
+
+ case DiagonalMethod:
+ {
+ // Move coordinates to top, left
+ p.translate(d->localRegionSelection.topLeft().x(), d->localRegionSelection.topLeft().y());
+
+ float w = (float)d->localRegionSelection.width();
+ float h = (float)d->localRegionSelection.height();
+
+ p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine));
+ if (w > h)
+ {
+ p.drawLine( 0, 0, h, h);
+ p.drawLine( 0, h, h, 0);
+ p.drawLine( w-h, 0, w, h);
+ p.drawLine( w-h, h, w, 0);
+
+ }
+ else
+ {
+ p.drawLine( 0, 0, w, w);
+ p.drawLine( 0, w, w, 0);
+ p.drawLine( 0, h-w, w, h);
+ p.drawLine( 0, h, w, h-w);
+ }
+
+ p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine));
+ if (w > h)
+ {
+ p.drawLine( 0, 0, h, h);
+ p.drawLine( 0, h, h, 0);
+ p.drawLine( w-h, 0, w, h);
+ p.drawLine( w-h, h, w, 0);
+
+ }
+ else
+ {
+ p.drawLine( 0, 0, w, w);
+ p.drawLine( 0, w, w, 0);
+ p.drawLine( 0, h-w, w, h);
+ p.drawLine( 0, h, w, h-w);
+ }
+ break;
+ }
+
+ case HarmoniousTriangles:
+ {
+ // Move coordinates to local center selection.
+ p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y());
+
+ // Flip horizontal.
+ if (d->flipHorGoldenGuide)
+ p.scale(-1, 1);
+
+ // Flip verical.
+ if (d->flipVerGoldenGuide)
+ p.scale(1, -1);
+
+ float w = (float)d->localRegionSelection.width();
+ float h = (float)d->localRegionSelection.height();
+ int dst = (int)((h*cos(atan(w/h)) / (cos(atan(h/w)))));
+
+ p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine));
+ p.drawLine( -d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2,
+ d->localRegionSelection.width()/2, d->localRegionSelection.height()/2);
+
+ p.drawLine( -d->localRegionSelection.width()/2 + dst, -d->localRegionSelection.height()/2,
+ -d->localRegionSelection.width()/2, d->localRegionSelection.height()/2);
+
+ p.drawLine( d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2,
+ d->localRegionSelection.width()/2 - dst, d->localRegionSelection.height()/2);
+
+ p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine));
+ p.drawLine( -d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2,
+ d->localRegionSelection.width()/2, d->localRegionSelection.height()/2);
+
+ p.drawLine( -d->localRegionSelection.width()/2 + dst, -d->localRegionSelection.height()/2,
+ -d->localRegionSelection.width()/2, d->localRegionSelection.height()/2);
+
+ p.drawLine( d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2,
+ d->localRegionSelection.width()/2 - dst, d->localRegionSelection.height()/2);
+ break;
+ }
+
+ case GoldenMean:
+ {
+ // Move coordinates to local center selection.
+ p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y());
+
+ // Flip horizontal.
+ if (d->flipHorGoldenGuide)
+ p.scale(-1, 1);
+
+ // Flip vertical.
+ if (d->flipVerGoldenGuide)
+ p.scale(1, -1);
+
+ int w = d->localRegionSelection.width();
+ int h = d->localRegionSelection.height();
+
+ // lengths for the golden mean and half the sizes of the region:
+ int w_g = (int)(w*INVPHI);
+ int h_g = (int)(h*INVPHI);
+ int w_2 = w/2;
+ int h_2 = h/2;
+
+ TQRect R1(-w_2, -h_2, w_g, h);
+ // w - 2*w_2 corrects for one-pixel difference
+ // so that R2.right() is really at the right end of the region
+ TQRect R2(w_g-w_2, h_2-h_g, w-w_g+1-(w - 2*w_2), h_g);
+
+ TQRect R3((int)(w_2 - R2.width()*INVPHI), -h_2,
+ (int)(R2.width()*INVPHI), h - R2.height());
+ TQRect R4(R2.x(), R1.y(), R3.x() - R2.x(),
+ (int)(R3.height()*INVPHI));
+ TQRect R5(R4.x(), R4.bottom(), (int)(R4.width()*INVPHI),
+ R3.height() - R4.height());
+ TQRect R6(R5.x() + R5.width(), R5.bottom() - (int)(R5.height()*INVPHI),
+ R3.x() - R5.right(), (int)(R5.height()*INVPHI));
+ TQRect R7(R6.right() - (int)(R6.width()*INVPHI), R4.bottom(),
+ (int)(R6.width()*INVPHI), R5.height() - R6.height());
+
+ p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine));
+
+ // Drawing Golden sections.
+ if (d->drawGoldenSection)
+ {
+ // horizontal lines:
+ p.drawLine( R1.left(), R2.top(),
+ R2.right(), R2.top());
+
+ p.drawLine( R1.left(), R1.top() + R2.height(),
+ R2.right(), R1.top() + R2.height());
+
+ // vertical lines:
+ p.drawLine( R1.right(), R1.top(),
+ R1.right(), R1.bottom() );
+
+ p.drawLine( R1.left()+R2.width(), R1.top(),
+ R1.left()+R2.width(), R1.bottom() );
+ }
+
+ // Drawing Golden triangle guides.
+ if (d->drawGoldenTriangle)
+ {
+ p.drawLine( R1.left(), R1.bottom(),
+ R2.right(), R1.top() );
+
+ p.drawLine( R1.left(), R1.top(),
+ R2.right() - R1.width(), R1.bottom());
+
+ p.drawLine( R1.left() + R1.width(), R1.top(),
+ R2.right(), R1.bottom() );
+ }
+
+ // Drawing Golden spiral sections.
+ if (d->drawGoldenSpiralSection)
+ {
+ p.drawLine( R1.topRight(), R1.bottomRight() );
+ p.drawLine( R2.topLeft(), R2.topRight() );
+ p.drawLine( R3.topLeft(), R3.bottomLeft() );
+ p.drawLine( R4.bottomLeft(), R4.bottomRight() );
+ p.drawLine( R5.topRight(), R5.bottomRight() );
+ p.drawLine( R6.topLeft(), R6.topRight() );
+ p.drawLine( R7.topLeft(), R7.bottomLeft() );
+ }
+
+ // Drawing Golden Spiral.
+ if (d->drawGoldenSpiral)
+ {
+ p.drawArc ( R1.left(),
+ R1.top() - R1.height(),
+ 2*R1.width(), 2*R1.height(),
+ 180*16, 90*16);
+
+ p.drawArc ( R2.right() - 2*R2.width(),
+ R1.bottom() - 2*R2.height(),
+ 2*R2.width(), 2*R2.height(),
+ 270*16, 90*16);
+
+ p.drawArc ( R2.right() - 2*R3.width(),
+ R3.top(),
+ 2*R3.width(), 2*R3.height(),
+ 0, 90*16);
+
+ p.drawArc ( R4.left(),
+ R4.top(),
+ 2*R4.width(), 2*R4.height(),
+ 90*16, 90*16);
+
+ p.drawArc ( R5.left(),
+ R5.top()-R5.height(),
+ 2*R5.width(), 2*R5.height(),
+ 180*16, 90*16);
+
+ p.drawArc ( R6.left()-R6.width(),
+ R6.top()-R6.height(),
+ 2*R6.width(), 2*R6.height(),
+ 270*16, 90*16);
+
+ p.drawArc ( R7.left()-R7.width(),
+ R7.top(),
+ 2*R7.width(), 2*R7.height(),
+ 0, 90*16);
+ }
+
+ p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine));
+
+ // Drawing Golden sections.
+ if (d->drawGoldenSection)
+ {
+ // horizontal lines:
+ p.drawLine( R1.left(), R2.top(),
+ R2.right(), R2.top());
+
+ p.drawLine( R1.left(), R1.top() + R2.height(),
+ R2.right(), R1.top() + R2.height());
+
+ // vertical lines:
+ p.drawLine( R1.right(), R1.top(),
+ R1.right(), R1.bottom() );
+
+ p.drawLine( R1.left()+R2.width(), R1.top(),
+ R1.left()+R2.width(), R1.bottom() );
+ }
+
+ // Drawing Golden triangle guides.
+ if (d->drawGoldenTriangle)
+ {
+ p.drawLine( R1.left(), R1.bottom(),
+ R2.right(), R1.top() );
+
+ p.drawLine( R1.left(), R1.top(),
+ R2.right() - R1.width(), R1.bottom());
+
+ p.drawLine( R1.left() + R1.width(), R1.top(),
+ R2.right(), R1.bottom() );
+ }
+
+ // Drawing Golden spiral sections.
+ if (d->drawGoldenSpiralSection)
+ {
+ p.drawLine( R1.topRight(), R1.bottomRight() );
+ p.drawLine( R2.topLeft(), R2.topRight() );
+ p.drawLine( R3.topLeft(), R3.bottomLeft() );
+ p.drawLine( R4.bottomLeft(), R4.bottomRight() );
+ p.drawLine( R5.topRight(), R5.bottomRight() );
+ p.drawLine( R6.topLeft(), R6.topRight() );
+ p.drawLine( R7.topLeft(), R7.bottomLeft() );
+ }
+
+ // Drawing Golden Spiral.
+ if (d->drawGoldenSpiral)
+ {
+ p.drawArc ( R1.left(),
+ R1.top() - R1.height(),
+ 2*R1.width(), 2*R1.height(),
+ 180*16, 90*16);
+
+ p.drawArc ( R2.right() - 2*R2.width(),
+ R1.bottom() - 2*R2.height(),
+ 2*R2.width(), 2*R2.height(),
+ 270*16, 90*16);
+
+ p.drawArc ( R2.right() - 2*R3.width(),
+ R3.top(),
+ 2*R3.width(), 2*R3.height(),
+ 0, 90*16);
+
+ p.drawArc ( R4.left(),
+ R4.top(),
+ 2*R4.width(), 2*R4.height(),
+ 90*16, 90*16);
+
+ p.drawArc ( R5.left(),
+ R5.top()-R5.height(),
+ 2*R5.width(), 2*R5.height(),
+ 180*16, 90*16);
+
+ p.drawArc ( R6.left()-R6.width(),
+ R6.top()-R6.height(),
+ 2*R6.width(), 2*R6.height(),
+ 270*16, 90*16);
+
+ p.drawArc ( R7.left()-R7.width(),
+ R7.top(),
+ 2*R7.width(), 2*R7.height(),
+ 0, 90*16);
+ }
+
+ break;
+ }
+ }
+
+ p.setClipping(false);
+
+ p.end();
+}
+
+void ImageSelectionWidget::paintEvent( TQPaintEvent * )
+{
+ bitBlt(this, 0, 0, d->pixmap);
+}
+
+TQPoint ImageSelectionWidget::opposite()
+{
+ TQPoint opp;
+
+ switch(d->currentResizing)
+ {
+ case ImageSelectionWidgetPriv::ResizingTopRight:
+ opp = d->regionSelection.bottomLeft();
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomLeft:
+ opp = d->regionSelection.topRight();
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomRight:
+ opp = d->regionSelection.topLeft();
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingTopLeft:
+ default:
+ opp = d->regionSelection.bottomRight();
+ break;
+ }
+
+ return opp;
+}
+
+float ImageSelectionWidget::distance(TQPoint a, TQPoint b)
+{
+ return sqrt(pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2));
+}
+
+void ImageSelectionWidget::setCursorResizing()
+{
+ switch(d->currentResizing)
+ {
+ case ImageSelectionWidgetPriv::ResizingTopLeft:
+ setCursor( KCursor::sizeFDiagCursor() );
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingTopRight:
+ setCursor( KCursor::sizeBDiagCursor() );
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomLeft:
+ setCursor( KCursor::sizeBDiagCursor() );
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomRight:
+ setCursor( KCursor::sizeFDiagCursor() );
+ break;
+ }
+}
+
+void ImageSelectionWidget::placeSelection(TQPoint pm, bool symmetric, TQPoint center)
+{
+ // Set orientation
+ if ( d->autoOrientation )
+ {
+ TQPoint rel = pm - opposite();
+
+ if ( abs(rel.x()) > abs(rel.y()) )
+ {
+ if ( d->currentOrientation == Portrait )
+ {
+ d->currentOrientation = Landscape;
+ reverseRatioValues();
+ emit signalSelectionOrientationChanged( d->currentOrientation );
+ }
+ }
+ else
+ {
+ if ( d->currentOrientation == Landscape )
+ {
+ d->currentOrientation = Portrait;
+ reverseRatioValues();
+ emit signalSelectionOrientationChanged( d->currentOrientation );
+ }
+ }
+ }
+
+ // Place the corner at the mouse
+ // If a symmetric selection is wanted, place opposite corner to
+ // the center, double selection size and move it to old center after
+ // computing aspect ratio.
+ switch(d->currentResizing)
+ {
+ case ImageSelectionWidgetPriv::ResizingTopLeft:
+ // Place corners to the proper position
+ d->regionSelection.setTopLeft(pm);
+ if ( symmetric )
+ d->regionSelection.setBottomRight(center);
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingTopRight:
+ d->regionSelection.setTopRight(pm);
+ if ( symmetric )
+ d->regionSelection.setBottomLeft(center);
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomLeft:
+ d->regionSelection.setBottomLeft(pm);
+ if ( symmetric )
+ d->regionSelection.setTopRight(center);
+ break;
+
+ case ImageSelectionWidgetPriv::ResizingBottomRight:
+ d->regionSelection.setBottomRight(pm);
+ if ( symmetric )
+ d->regionSelection.setTopLeft(center);
+ break;
+ }
+
+ if ( symmetric )
+ d->regionSelection.setSize(d->regionSelection.size()*2);
+ applyAspectRatio(d->currentOrientation == Portrait, false);
+ if ( symmetric )
+ d->regionSelection.moveCenter(center);
+
+ // Repaint
+ updatePixmap();
+ repaint(false);
+}
+
+void ImageSelectionWidget::mousePressEvent ( TQMouseEvent * e )
+{
+ if ( e->button() == TQt::LeftButton )
+ {
+ TQPoint pm = TQPoint(e->x(), e->y());
+ TQPoint pmVirtual = convertPoint(pm);
+ d->moving = false;
+
+ if ( (e->state() & TQt::ShiftButton) == TQt::ShiftButton )
+ {
+ bool symmetric = (e->state() & TQt::ControlButton ) == TQt::ControlButton;
+ TQPoint center = d->regionSelection.center();
+
+ // Find the closest corner
+
+ TQPoint points[] = { d->regionSelection.topLeft(),
+ d->regionSelection.topRight(),
+ d->regionSelection.bottomLeft(),
+ d->regionSelection.bottomRight() };
+ int resizings[] = { ImageSelectionWidgetPriv::ResizingTopLeft,
+ ImageSelectionWidgetPriv::ResizingTopRight,
+ ImageSelectionWidgetPriv::ResizingBottomLeft,
+ ImageSelectionWidgetPriv::ResizingBottomRight };
+ float dist = -1;
+ for (int i = 0 ; i < 4 ; i++)
+ {
+ TQPoint point = points[i];
+ float dist2 = distance(pmVirtual, point);
+ if (dist2 < dist || d->currentResizing == ImageSelectionWidgetPriv::ResizingNone)
+ {
+ dist = dist2;
+ d->currentResizing = resizings[i];
+ }
+ }
+
+ setCursorResizing();
+
+ placeSelection(pmVirtual, symmetric, center);
+ }
+ else
+ {
+ if ( d->localTopLeftCorner.contains( pm ) )
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingTopLeft;
+ else if ( d->localTopRightCorner.contains( pm ) )
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingTopRight;
+ else if ( d->localBottomLeftCorner.contains( pm ) )
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomLeft;
+ else if ( d->localBottomRightCorner.contains( pm ) )
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomRight;
+ else
+ {
+ d->lastPos = pmVirtual;
+ setCursor( KCursor::sizeAllCursor() );
+
+ if (d->regionSelection.contains( pmVirtual ) )
+ {
+ d->moving = true;
+ }
+ else
+ {
+ d->regionSelection.moveCenter( pmVirtual );
+ normalizeRegion();
+ updatePixmap();
+ repaint(false);
+ }
+ }
+ }
+ }
+}
+
+void ImageSelectionWidget::mouseReleaseEvent ( TQMouseEvent * )
+{
+ if ( d->currentResizing != ImageSelectionWidgetPriv::ResizingNone )
+ {
+ setCursor( KCursor::arrowCursor() );
+ regionSelectionChanged();
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingNone;
+ }
+ else if ( d->regionSelection.contains( d->lastPos ) )
+ {
+ setCursor( KCursor::handCursor() );
+ regionSelectionMoved();
+ }
+ else
+ {
+ setCursor( KCursor::arrowCursor() );
+ regionSelectionMoved();
+ }
+}
+
+void ImageSelectionWidget::mouseMoveEvent ( TQMouseEvent * e )
+{
+ if ( ( e->state() & TQt::LeftButton ) == TQt::LeftButton )
+ {
+ if ( d->moving )
+ {
+ setCursor( KCursor::sizeAllCursor() );
+ TQPoint newPos = convertPoint(e->x(), e->y());
+
+ d->regionSelection.moveBy( newPos.x() - d->lastPos.x(),
+ newPos.y() - d->lastPos.y() );
+
+ d->lastPos = newPos;
+
+ normalizeRegion();
+
+ updatePixmap();
+ repaint(false);
+ }
+ else
+ {
+ TQPoint pmVirtual = convertPoint(e->x(), e->y());
+
+ if ( d->currentResizing == ImageSelectionWidgetPriv::ResizingNone )
+ {
+ d->regionSelection.setTopLeft( pmVirtual );
+ d->regionSelection.setBottomRight( pmVirtual );
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingTopLeft; // set to anything
+ }
+
+ TQPoint center = d->regionSelection.center();
+ bool symmetric = (e->state() & TQt::ControlButton ) == TQt::ControlButton;
+
+ // Change resizing mode
+
+ TQPoint opp = symmetric ? center : opposite();
+ TQPoint dir = pmVirtual - opp;
+
+ if ( dir.x() > 0 && dir.y() > 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingBottomRight)
+ {
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomRight;
+ d->regionSelection.setTopLeft( opp );
+ setCursor( KCursor::sizeFDiagCursor() );
+ }
+ else if ( dir.x() > 0 && dir.y() < 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingTopRight)
+ {
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingTopRight;
+ d->regionSelection.setBottomLeft( opp );
+ setCursor( KCursor::sizeBDiagCursor() );
+ }
+ else if ( dir.x() < 0 && dir.y() > 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingBottomLeft)
+ {
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingBottomLeft;
+ d->regionSelection.setTopRight( opp );
+ setCursor( KCursor::sizeBDiagCursor() );
+ }
+ else if ( dir.x() < 0 && dir.y() < 0 && d->currentResizing != ImageSelectionWidgetPriv::ResizingTopLeft)
+ {
+ d->currentResizing = ImageSelectionWidgetPriv::ResizingTopLeft;
+ d->regionSelection.setBottomRight( opp );
+ setCursor( KCursor::sizeFDiagCursor() );
+ }
+ else
+ {
+ if ( dir.x() == 0 && dir.y() == 0 )
+ setCursor( KCursor::sizeAllCursor() );
+ else if ( dir.x() == 0 )
+ setCursor( KCursor::sizeHorCursor() );
+ else if ( dir.y() == 0 )
+ setCursor( KCursor::sizeVerCursor() );
+ }
+
+ placeSelection(pmVirtual, symmetric, center);
+ }
+ }
+ else
+ {
+ if ( d->localTopLeftCorner.contains( e->x(), e->y() ) ||
+ d->localBottomRightCorner.contains( e->x(), e->y() ) )
+ setCursor( KCursor::sizeFDiagCursor() );
+ else if ( d->localTopRightCorner.contains( e->x(), e->y() ) ||
+ d->localBottomLeftCorner.contains( e->x(), e->y() ) )
+ setCursor( KCursor::sizeBDiagCursor() );
+ else if ( d->localRegionSelection.contains( e->x(), e->y() ) )
+ setCursor( KCursor::handCursor() );
+ else
+ setCursor( KCursor::arrowCursor() );
+ }
+}
+
+} // NameSpace DigikamImagesPluginCore