diff options
Diffstat (limited to 'src/imageplugins/coreplugin/ratiocrop')
7 files changed, 3528 insertions, 0 deletions
diff --git a/src/imageplugins/coreplugin/ratiocrop/CMakeLists.txt b/src/imageplugins/coreplugin/ratiocrop/CMakeLists.txt new file mode 100644 index 00000000..ca24d31f --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + + +##### ratiocrop (static) + +tde_add_library( ratiocrop STATIC_PIC AUTOMOC + SOURCES ratiocroptool.cpp imageselectionwidget.cpp +) diff --git a/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.cpp b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.cpp new file mode 100644 index 00000000..6ed0a9c7 --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.cpp @@ -0,0 +1,799 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqframe.h> +#include <tqrect.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqcombobox.h> +#include <tqspinbox.h> +#include <tqimage.h> +#include <tqpushbutton.h> +#include <tqtimer.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <knuminput.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdestandarddirs.h> +#include <kcolorbutton.h> + +// Digikam includes. + +#include "imageiface.h" +#include "imageselectionwidget.h" + +// Local includes. + +#include "imageeffect_ratiocrop.h" +#include "imageeffect_ratiocrop.moc" + +namespace DigikamImagesPluginCore +{ + +ImageEffect_RatioCrop::ImageEffect_RatioCrop(TQWidget* parent) + : Digikam::ImageDlgBase(parent, i18n("Aspect Ratio Crop & Composition Guide"), + "aspectratiocrop", false) +{ + setHelp("ratiocroptool.anchor", "digikam"); + setButtonWhatsThis ( User1, i18n("<p>Set selection area to the maximum size according " + "to the current ratio.") ); + setButtonText(User1, i18n("&Max. Aspect")); + showButton(User1, true); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(plainPage()); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + m_imageSelectionWidget = new ImageSelectionWidget(480, 320, frame); + l->addWidget(m_imageSelectionWidget); + TQWhatsThis::add( m_imageSelectionWidget, i18n("<p>Here you can see the aspect ratio selection preview " + "used for cropping. You can use the mouse to move and " + "resize the crop area. " + "Press and hold the CTRL key to move the opposite corner too. " + "Press and hold the SHIFT key to move the closest corner to the " + "mouse pointer.")); + setPreviewAreaWidget(frame); + + m_originalIsLandscape = m_imageSelectionWidget->getOriginalImageWidth() > + m_imageSelectionWidget->getOriginalImageHeight(); + + // ------------------------------------------------------------- + + TQWidget *gbox2 = new TQWidget(plainPage()); + TQGridLayout *gridBox2 = new TQGridLayout( gbox2, 2, 0); + + TQFrame *cropSelection = new TQFrame( gbox2 ); + cropSelection->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQGridLayout* grid = new TQGridLayout( cropSelection, 6, 4, spacingHint()); + + TQLabel *label = new TQLabel(i18n("Aspect ratio:"), cropSelection); + m_ratioCB = new TQComboBox( false, cropSelection ); + setRatioCBText(ImageSelectionWidget::Landscape); + TQWhatsThis::add( m_ratioCB, i18n("<p>Select your constrained aspect ratio for cropping. " + "Aspect Ratio Crop tool uses a relative ratio. That means it " + "is the same if you use centimeters or inches and it doesn't " + "specify the physical size.<p>" + "You can see below a correspondence list of traditional photographic " + "paper sizes and aspect ratio crop:<p>" + "<b>2:3</b>: 10x15cm, 20x30cm, 30x45cm, 4x6\", 8x12\", " + "12x18\", 16x24\", 20x30\"<p>" + "<b>3:4</b>: 6x8cm, 15x20cm, 18x24cm, 30x40cm, 3.75x5\", 4.5x6\", " + "6x8\", 7.5x10\", 9x12\"<p>" + "<b>4:5</b>: 20x25cm, 40x50cm, 8x10\", 16x20\"<p>" + "<b>5:7</b>: 15x21cm, 30x42cm, 5x7\"<p>" + "<b>7:10</b>: 21x30cm, 42x60cm, 3.5x5\"<p>" + "The <b>Golden Ratio</b> is 1:1.618. A composition following this rule " + "is considered visually harmonious but can be unadapted to print on " + "standard photographic paper.")); + + m_preciseCrop = new TQCheckBox(i18n("Exact"), cropSelection); + TQWhatsThis::add( m_preciseCrop, i18n("<p>Enable this option to force exact aspect ratio crop.")); + + m_orientLabel = new TQLabel(i18n("Orientation:"), cropSelection); + m_orientCB = new TQComboBox( false, cropSelection ); + m_orientCB->insertItem( i18n("Landscape") ); + m_orientCB->insertItem( i18n("Portrait") ); + TQWhatsThis::add( m_orientCB, i18n("<p>Select constrained aspect ratio orientation.")); + + m_autoOrientation = new TQCheckBox(i18n("Auto"), cropSelection); + TQWhatsThis::add( m_autoOrientation, i18n("<p>Enable this option to automatically set the orientation.")); + + grid->addMultiCellWidget(label, 0, 0, 0, 0); + grid->addMultiCellWidget(m_ratioCB, 0, 0, 1, 3); + grid->addMultiCellWidget(m_preciseCrop, 0, 0, 4, 4); + grid->addMultiCellWidget(m_orientLabel, 2, 2, 0, 0); + grid->addMultiCellWidget(m_orientCB, 2, 2, 1, 3); + grid->addMultiCellWidget(m_autoOrientation, 2, 2, 4, 4); + + // ------------------------------------------------------------- + + m_customLabel1 = new TQLabel(i18n("Custom ratio:"), cropSelection); + m_customLabel1->setAlignment(AlignLeft|AlignVCenter); + m_customRatioNInput = new KIntSpinBox(1, 10000, 1, 1, 10, cropSelection); + TQWhatsThis::add( m_customRatioNInput, i18n("<p>Set here the desired custom aspect numerator value.")); + m_customLabel2 = new TQLabel(" : ", cropSelection); + m_customLabel2->setAlignment(AlignCenter|AlignVCenter); + m_customRatioDInput = new KIntSpinBox(1, 10000, 1, 1, 10, cropSelection); + TQWhatsThis::add( m_customRatioDInput, i18n("<p>Set here the desired custom aspect denominator value.")); + + grid->addMultiCellWidget(m_customLabel1, 1, 1, 0, 0); + grid->addMultiCellWidget(m_customRatioNInput, 1, 1, 1, 1); + grid->addMultiCellWidget(m_customLabel2, 1, 1, 2, 2); + grid->addMultiCellWidget(m_customRatioDInput, 1, 1, 3, 3); + + // ------------------------------------------------------------- + + m_xInput = new KIntNumInput(cropSelection); + TQWhatsThis::add( m_xInput, i18n("<p>Set here the top left selection corner position for cropping.")); + m_xInput->setLabel(i18n("X:"), AlignLeft|AlignVCenter); + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth(), 1, true); + + m_widthInput = new KIntNumInput(cropSelection); + m_widthInput->setLabel(i18n("Width:"), AlignLeft|AlignVCenter); + TQWhatsThis::add( m_widthInput, i18n("<p>Set here the width selection for cropping.")); + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep(), true); + + m_centerWidth = new TQPushButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerwidth", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("centerwidth", "centerwidth.png"); + m_centerWidth->setPixmap( TQPixmap( directory + "centerwidth.png" ) ); + TQWhatsThis::add( m_centerWidth, i18n("<p>Set width position to center.")); + + grid->addMultiCellWidget(m_xInput, 3, 3, 0, 3); + grid->addMultiCellWidget(m_widthInput, 4, 4, 0, 3); + grid->addMultiCellWidget(m_centerWidth, 3, 3, 4, 4); + + // ------------------------------------------------------------- + + m_yInput = new KIntNumInput(cropSelection); + m_yInput->setLabel(i18n("Y:"), AlignLeft|AlignVCenter); + TQWhatsThis::add( m_yInput, i18n("<p>Set here the top left selection corner position for cropping.")); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight(), 1, true); + + m_heightInput = new KIntNumInput(cropSelection); + m_heightInput->setLabel(i18n("Height:"), AlignLeft|AlignVCenter); + TQWhatsThis::add( m_heightInput, i18n("<p>Set here the height selection for cropping.")); + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep(), true); + + m_centerHeight = new TQPushButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerheight", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("centerheight", "centerheight.png"); + m_centerHeight->setPixmap( TQPixmap( directory + "centerheight.png" ) ); + TQWhatsThis::add( m_centerHeight, i18n("<p>Set height position to center.")); + + grid->addMultiCellWidget(m_yInput, 5, 5, 0, 3); + grid->addMultiCellWidget(m_heightInput, 6, 6, 0, 3); + grid->addMultiCellWidget(m_centerHeight, 5, 5, 4, 4); + + gridBox2->addMultiCellWidget(cropSelection, 0, 0, 0, 0); + + // ------------------------------------------------------------- + + TQFrame* compositionGuide = new TQFrame( gbox2 ); + TQGridLayout* grid2 = new TQGridLayout( compositionGuide, 7, 2, spacingHint()); + compositionGuide->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + + TQLabel *labelGuideLines = new TQLabel(i18n("Composition guide:"), compositionGuide); + m_guideLinesCB = new TQComboBox( false, compositionGuide ); + m_guideLinesCB->insertItem( i18n("Rules of Thirds") ); + m_guideLinesCB->insertItem( i18n("Harmonious Triangles") ); + m_guideLinesCB->insertItem( i18n("Golden Mean") ); + m_guideLinesCB->insertItem( i18n("None") ); + m_guideLinesCB->setCurrentText( i18n("None") ); + TQWhatsThis::add( m_guideLinesCB, i18n("<p>With this option, you can display guide lines " + "which help you to compose your photograph.")); + + m_goldenSectionBox = new TQCheckBox(i18n("Golden sections"), compositionGuide); + TQWhatsThis::add( m_goldenSectionBox, i18n("<p>Enable this option to show golden sections.")); + + m_goldenSpiralSectionBox = new TQCheckBox(i18n("Golden spiral sections"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralSectionBox, i18n("<p>Enable this option to show golden spiral sections.")); + + m_goldenSpiralBox = new TQCheckBox(i18n("Golden spiral"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralBox, i18n("<p>Enable this option to show golden spiral guide.")); + + m_goldenTriangleBox = new TQCheckBox(i18n("Golden triangles"), compositionGuide); + TQWhatsThis::add( m_goldenTriangleBox, i18n("<p>Enable this option to show golden triangles.")); + + m_flipHorBox = new TQCheckBox(i18n("Flip horizontally"), compositionGuide); + TQWhatsThis::add( m_flipHorBox, i18n("<p>Enable this option to flip horizontally guidelines.")); + + m_flipVerBox = new TQCheckBox(i18n("Flip vertically"), compositionGuide); + TQWhatsThis::add( m_flipVerBox, i18n("<p>Enable this option to flip vertically guidelines.")); + + m_colorGuideLabel = new TQLabel(i18n("Color and width:"), compositionGuide); + m_guideColorBt = new KColorButton( TQColor( 250, 250, 255 ), compositionGuide ); + m_guideSize = new TQSpinBox( 1, 5, 1, compositionGuide); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw composition guides.")); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw composition guides.")); + + grid2->addMultiCellWidget(labelGuideLines, 0, 0, 0, 0); + grid2->addMultiCellWidget(m_guideLinesCB, 0, 0, 1, 2); + grid2->addMultiCellWidget(m_goldenSectionBox, 1, 1, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralSectionBox, 2, 2, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralBox, 3, 3, 0, 2); + grid2->addMultiCellWidget(m_goldenTriangleBox, 4, 4, 0, 2); + grid2->addMultiCellWidget(m_flipHorBox, 5, 5, 0, 2); + grid2->addMultiCellWidget(m_flipVerBox, 6, 6, 0, 2); + grid2->addMultiCellWidget(m_colorGuideLabel, 7, 7, 0, 0); + grid2->addMultiCellWidget(m_guideColorBt, 7, 7, 1, 1); + grid2->addMultiCellWidget(m_guideSize, 7, 7, 2, 2); + + gridBox2->addMultiCellWidget(compositionGuide, 1, 1, 0, 0); + gridBox2->setRowStretch(2, 10); + + setUserAreaWidget(gbox2); + + // ------------------------------------------------------------- + + connect(m_ratioCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotRatioChanged(int))); + + connect(m_preciseCrop, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotPreciseCropChanged(bool))); + + connect(m_orientCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotOrientChanged(int))); + + connect(m_autoOrientation, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotAutoOrientChanged(bool))); + + connect(m_xInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotXChanged(int))); + + connect(m_yInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotYChanged(int))); + + connect(m_customRatioNInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomNRatioChanged(int))); + + connect(m_customRatioDInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomDRatioChanged(int))); + + connect(m_guideLinesCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotGuideTypeChanged(int))); + + connect(m_goldenSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenTriangleBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipHorBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipVerBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor &)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideColor(const TQColor &))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideSize(int))); + + connect(m_widthInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotWidthChanged(int))); + + connect(m_heightInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotHeightChanged(int))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionChanged(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionMoved(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionOrientationChanged(int)), + this, TQ_SLOT(slotSelectionOrientationChanged(int))); + + connect(m_centerWidth, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterWidth())); + + connect(m_centerHeight, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterHeight())); + + // ------------------------------------------------------------- + + // Sets current region selection + slotSelectionChanged(m_imageSelectionWidget->getRegionSelection()); + + readSettings(); +} + +ImageEffect_RatioCrop::~ImageEffect_RatioCrop() +{ +} + +void ImageEffect_RatioCrop::readSettings() +{ + TQColor defaultGuideColor(250, 250, 255); + TDEConfig *config = tdeApp->config(); + config->setGroup("aspectratiocrop Tool Dialog"); + + // No guide lines per default. + m_guideLinesCB->setCurrentItem( config->readNumEntry("Guide Lines Type", + ImageSelectionWidget::GuideNone) ); + m_goldenSectionBox->setChecked( config->readBoolEntry("Golden Section", true) ); + m_goldenSpiralSectionBox->setChecked( config->readBoolEntry("Golden Spiral Section", false) ); + m_goldenSpiralBox->setChecked( config->readBoolEntry("Golden Spiral", false) ); + m_goldenTriangleBox->setChecked( config->readBoolEntry("Golden Triangle", false) ); + m_flipHorBox->setChecked( config->readBoolEntry("Golden Flip Horizontal", false) ); + m_flipVerBox->setChecked( config->readBoolEntry("Golden Flip Vertical", false) ); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", 1)); + m_imageSelectionWidget->slotGuideLines(m_guideLinesCB->currentItem()); + m_imageSelectionWidget->slotChangeGuideColor(m_guideColorBt->color()); + + m_preciseCrop->setChecked( config->readBoolEntry("Precise Aspect Ratio Crop", false) ); + m_imageSelectionWidget->setPreciseCrop( m_preciseCrop->isChecked() ); + + if (m_originalIsLandscape) + { + m_orientCB->setCurrentItem( config->readNumEntry("Hor.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Landscape) ); + + m_imageSelectionWidget->setSelectionOrientation(m_orientCB->currentItem()); + + m_customRatioNInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Num", 1) ); + m_customRatioDInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Den", 1) ); + m_ratioCB->setCurrentItem( config->readNumEntry("Hor.Oriented Aspect Ratio", + ImageSelectionWidget::RATIO03X04) ); + + applyRatioChanges(m_ratioCB->currentItem()); + + // Empty selection so it can be moved w/out size constraint + m_widthInput->setValue( 0 ); + m_heightInput->setValue( 0 ); + + m_xInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Xpos", 50) ); + m_yInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Ypos", 50) ); + + m_widthInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Width", 800) ); + m_heightInput->setValue( config->readNumEntry("Hor.Oriented Custom Aspect Ratio Height", 600) ); + } + else + { + m_orientCB->setCurrentItem( config->readNumEntry("Ver.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Portrait) ); + + m_imageSelectionWidget->setSelectionOrientation(m_orientCB->currentItem()); + + m_customRatioNInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Num", 1) ); + m_customRatioDInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Den", 1) ); + m_ratioCB->setCurrentItem( config->readNumEntry("Ver.Oriented Aspect Ratio", + ImageSelectionWidget::RATIO03X04) ); + + applyRatioChanges(m_ratioCB->currentItem()); + + // Empty selection so it can be moved w/out size constraint + m_widthInput->setValue( 0 ); + m_heightInput->setValue( 0 ); + + m_xInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Xpos", 50) ); + m_yInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Ypos", 50) ); + + m_widthInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Width", 800) ); + m_heightInput->setValue( config->readNumEntry("Ver.Oriented Custom Aspect Ratio Height", 600) ); + } + + m_autoOrientation->setChecked( config->readBoolEntry("Auto Orientation", false) ); + slotAutoOrientChanged( m_autoOrientation->isChecked() ); +} + +void ImageEffect_RatioCrop::writeSettings() +{ + TDEConfig *config = tdeApp->config(); + config->setGroup("aspectratiocrop Tool Dialog"); + + if (m_originalIsLandscape) + { + config->writeEntry( "Hor.Oriented Aspect Ratio", m_ratioCB->currentItem() ); + config->writeEntry( "Hor.Oriented Aspect Ratio Orientation", m_orientCB->currentItem() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value() ); + + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Xpos", m_xInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Ypos", m_yInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Width", m_widthInput->value() ); + config->writeEntry( "Hor.Oriented Custom Aspect Ratio Height", m_heightInput->value() ); + } + else + { + config->writeEntry( "Ver.Oriented Aspect Ratio", m_ratioCB->currentItem() ); + config->writeEntry( "Ver.Oriented Aspect Ratio Orientation", m_orientCB->currentItem() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value() ); + + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Xpos", m_xInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Ypos", m_yInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Width", m_widthInput->value() ); + config->writeEntry( "Ver.Oriented Custom Aspect Ratio Height", m_heightInput->value() ); + } + + config->writeEntry( "Precise Aspect Ratio Crop", m_preciseCrop->isChecked() ); + config->writeEntry( "Auto Orientation", m_autoOrientation->isChecked() ); + config->writeEntry( "Guide Lines Type", m_guideLinesCB->currentItem() ); + config->writeEntry( "Golden Section", m_goldenSectionBox->isChecked() ); + config->writeEntry( "Golden Spiral Section", m_goldenSpiralSectionBox->isChecked() ); + config->writeEntry( "Golden Spiral", m_goldenSpiralBox->isChecked() ); + config->writeEntry( "Golden Triangle", m_goldenTriangleBox->isChecked() ); + config->writeEntry( "Golden Flip Horizontal", m_flipHorBox->isChecked() ); + config->writeEntry( "Golden Flip Vertical", m_flipVerBox->isChecked() ); + config->writeEntry( "Guide Color", m_guideColorBt->color() ); + config->writeEntry( "Guide Width", m_guideSize->value() ); + config->sync(); +} + +void ImageEffect_RatioCrop::slotDefault() +{ + m_imageSelectionWidget->resetSelection(); +} + +void ImageEffect_RatioCrop::slotUser1() +{ + m_imageSelectionWidget->maxAspectSelection(); +} + +void ImageEffect_RatioCrop::slotCenterWidth() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterWidth); +} + +void ImageEffect_RatioCrop::slotCenterHeight() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterHeight); +} + +void ImageEffect_RatioCrop::slotSelectionChanged(TQRect rect) +{ + m_xInput->blockSignals(true); + m_yInput->blockSignals(true); + m_widthInput->blockSignals(true); + m_heightInput->blockSignals(true); + + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth() - rect.width(), 1, true); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight() - rect.height(), 1, true); + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep(), true); + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep(), true); + + m_xInput->setValue(rect.x()); + m_yInput->setValue(rect.y()); + m_widthInput->setValue(rect.width()); + m_heightInput->setValue(rect.height()); + + enableButtonOK( rect.isValid() ); + m_preciseCrop->setEnabled(m_imageSelectionWidget->preciseCropAvailable()); + + m_xInput->blockSignals(false); + m_yInput->blockSignals(false); + m_widthInput->blockSignals(false); + m_heightInput->blockSignals(false); +} + +void ImageEffect_RatioCrop::setRatioCBText(int orientation) +{ + int item = m_ratioCB->currentItem(); + + m_ratioCB->blockSignals(true); + m_ratioCB->clear(); + m_ratioCB->insertItem( i18n("Custom") ); + m_ratioCB->insertItem( "1:1" ); + if ( orientation == ImageSelectionWidget::Landscape ) + { + m_ratioCB->insertItem( "3:2" ); + m_ratioCB->insertItem( "4:3" ); + m_ratioCB->insertItem( "5:4" ); + m_ratioCB->insertItem( "7:5" ); + m_ratioCB->insertItem( "10:7" ); + } + else + { + m_ratioCB->insertItem( "2:3" ); + m_ratioCB->insertItem( "3:4" ); + m_ratioCB->insertItem( "4:5" ); + m_ratioCB->insertItem( "5:7" ); + m_ratioCB->insertItem( "7:10" ); + } + m_ratioCB->insertItem( i18n("Golden Ratio") ); + m_ratioCB->insertItem( i18n("None") ); + m_ratioCB->setCurrentItem( item ); + m_ratioCB->blockSignals(false); +} + +void ImageEffect_RatioCrop::slotSelectionOrientationChanged(int newOrientation) +{ + // Change text for Aspect ratio ComboBox + + setRatioCBText(newOrientation); + + // Change Orientation ComboBox + + m_orientCB->setCurrentItem(newOrientation); + + // Reverse custom values + + if ( ( m_customRatioNInput->value() < m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Landscape ) || + ( m_customRatioNInput->value() > m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Portrait ) ) + { + m_customRatioNInput->blockSignals(true); + m_customRatioDInput->blockSignals(true); + + int tmp = m_customRatioNInput->value(); + m_customRatioNInput->setValue( m_customRatioDInput->value() ); + m_customRatioDInput->setValue( tmp ); + + m_customRatioNInput->blockSignals(false); + m_customRatioDInput->blockSignals(false); + } +} + +void ImageEffect_RatioCrop::slotXChanged(int x) +{ + m_imageSelectionWidget->setSelectionX(x); +} + +void ImageEffect_RatioCrop::slotYChanged(int y) +{ + m_imageSelectionWidget->setSelectionY(y); +} + +void ImageEffect_RatioCrop::slotWidthChanged(int w) +{ + m_imageSelectionWidget->setSelectionWidth(w); +} + +void ImageEffect_RatioCrop::slotHeightChanged(int h) +{ + m_imageSelectionWidget->setSelectionHeight(h); +} + +void ImageEffect_RatioCrop::slotPreciseCropChanged(bool a) +{ + m_imageSelectionWidget->setPreciseCrop(a); +} + +void ImageEffect_RatioCrop::slotOrientChanged(int o) +{ + m_imageSelectionWidget->setSelectionOrientation(o); + + // Reset selection area. + slotDefault(); +} + +void ImageEffect_RatioCrop::slotAutoOrientChanged(bool a) +{ + m_orientCB->setEnabled(!a /*|| m_ratioCB->currentItem() == ImageSelectionWidget::RATIONONE*/); + m_imageSelectionWidget->setAutoOrientation(a); +} + +void ImageEffect_RatioCrop::slotRatioChanged(int a) +{ + applyRatioChanges(a); + + // Reset selection area. + slotDefault(); +} + +void ImageEffect_RatioCrop::applyRatioChanges(int a) +{ + m_imageSelectionWidget->setSelectionAspectRatioType(a); + + if ( a == ImageSelectionWidget::RATIOCUSTOM ) + { + m_customLabel1->setEnabled(true); + m_customLabel2->setEnabled(true); + m_customRatioNInput->setEnabled(true); + m_customRatioDInput->setEnabled(true); + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(! m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + slotCustomRatioChanged(); + } + else if ( a == ImageSelectionWidget::RATIONONE ) + { + m_orientLabel->setEnabled(false); + m_orientCB->setEnabled(false); + m_autoOrientation->setEnabled(false); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } + else // Pre-config ratio selected. + { + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(! m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } +} + +void ImageEffect_RatioCrop::slotGuideTypeChanged(int t) +{ + if ( t == ImageSelectionWidget::GuideNone ) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(false); + m_guideColorBt->setEnabled(false); + m_guideSize->setEnabled(false); + } + else if ( t == ImageSelectionWidget::RulesOfThirds ) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else if ( t == ImageSelectionWidget::HarmoniousTriangles ) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else + { + m_goldenSectionBox->setEnabled(true); + m_goldenSpiralSectionBox->setEnabled(true); + m_goldenSpiralBox->setEnabled(true); + m_goldenTriangleBox->setEnabled(true); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + + m_imageSelectionWidget->setGoldenGuideTypes(m_goldenSectionBox->isChecked(), + m_goldenSpiralSectionBox->isChecked(), + m_goldenSpiralBox->isChecked(), + m_goldenTriangleBox->isChecked(), + m_flipHorBox->isChecked(), + m_flipVerBox->isChecked()); + m_imageSelectionWidget->slotGuideLines(t); +} + +void ImageEffect_RatioCrop::slotGoldenGuideTypeChanged() +{ + slotGuideTypeChanged(m_guideLinesCB->currentItem()); +} + +void ImageEffect_RatioCrop::slotCustomNRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioDInput->value() < a ) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioDInput->value() > a ) ) + { + m_customRatioDInput->blockSignals(true); + m_customRatioDInput->setValue(a); + m_customRatioDInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void ImageEffect_RatioCrop::slotCustomDRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioNInput->value() < a ) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioNInput->value() > a ) ) + { + m_customRatioNInput->blockSignals(true); + m_customRatioNInput->setValue(a); + m_customRatioNInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void ImageEffect_RatioCrop::slotCustomRatioChanged() +{ + m_imageSelectionWidget->setSelectionAspectRatioValue( + m_customRatioNInput->value(), m_customRatioDInput->value() ); + + // Reset selection area. + slotDefault(); +} + +void ImageEffect_RatioCrop::slotOk() +{ + tdeApp->setOverrideCursor( KCursor::waitCursor() ); + + TQRect currentRegion = m_imageSelectionWidget->getRegionSelection(); + Digikam::ImageIface* iface = m_imageSelectionWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool a = iface->originalHasAlpha(); + bool sb = iface->originalSixteenBit(); + + TQRect normalizedRegion = currentRegion.normalize(); + if (normalizedRegion.right() > w) normalizedRegion.setRight(w); + if (normalizedRegion.bottom() > h) normalizedRegion.setBottom(h); + + Digikam::DImg imOrg(w, h, sb, a, data); + delete [] data; + imOrg.crop(normalizedRegion); + + iface->putOriginalImage(i18n("Aspect Ratio Crop"), imOrg.bits(), imOrg.width(), imOrg.height()); + + tdeApp->restoreOverrideCursor(); + writeSettings(); + accept(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.h b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.h new file mode 100644 index 00000000..ca24eeac --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/imageeffect_ratiocrop.h @@ -0,0 +1,132 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot cz> + * Copyright (C) 2008 by Roberto Castagnola <roberto dot castagnola at gmail dot com> + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_RATIOCROP_H +#define IMAGEEFFECT_RATIOCROP_H + +// Digikam include. + +#include "imagedlgbase.h" + +class TQLabel; +class TQComboBox; +class TQPushButton; +class TQCheckBox; +class TQSpinBox; + +class KIntNumInput; +class KIntSpinBox; +class KColorButton; + +namespace DigikamImagesPluginCore +{ + +class ImageSelectionWidget; + +class ImageEffect_RatioCrop : public Digikam::ImageDlgBase +{ + TQ_OBJECT + + +public: + + ImageEffect_RatioCrop(TQWidget *parent); + ~ImageEffect_RatioCrop(); + +private: + + void readSettings(); + void writeSettings(); + + void applyRatioChanges(int a); + void setRatioCBText(int orientation); + +private slots: + + void slotUser1(); + void slotDefault(); + void slotOk(); + + void slotCenterWidth(); + void slotCenterHeight(); + void slotXChanged(int x); + void slotYChanged(int y); + void slotWidthChanged(int w); + void slotHeightChanged(int h); + void slotCustomRatioChanged(); + void slotCustomNRatioChanged(int a); + void slotCustomDRatioChanged(int a); + void slotPreciseCropChanged(bool a); + void slotOrientChanged(int o); + void slotAutoOrientChanged(bool a); + void slotRatioChanged(int a); + void slotSelectionChanged(TQRect rect ); + void slotSelectionOrientationChanged(int); + void slotGuideTypeChanged(int t); + void slotGoldenGuideTypeChanged(); + +private: + + bool m_originalIsLandscape; + + TQLabel *m_customLabel1; + TQLabel *m_customLabel2; + TQLabel *m_orientLabel; + TQLabel *m_colorGuideLabel; + + TQComboBox *m_ratioCB; + TQComboBox *m_orientCB; + TQComboBox *m_guideLinesCB; + + TQPushButton *m_centerWidth; + TQPushButton *m_centerHeight; + + TQCheckBox *m_goldenSectionBox; + TQCheckBox *m_goldenSpiralSectionBox; + TQCheckBox *m_goldenSpiralBox; + TQCheckBox *m_goldenTriangleBox; + TQCheckBox *m_flipHorBox; + TQCheckBox *m_flipVerBox; + TQCheckBox *m_autoOrientation; + TQCheckBox *m_preciseCrop; + + TQSpinBox *m_guideSize; + + KIntNumInput *m_widthInput; + KIntNumInput *m_heightInput; + KIntNumInput *m_xInput; + KIntNumInput *m_yInput; + + KIntSpinBox *m_customRatioNInput; + KIntSpinBox *m_customRatioDInput; + + KColorButton *m_guideColorBt; + + ImageSelectionWidget *m_imageSelectionWidget; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGEEFFECT_RATIOCROP_H */ diff --git a/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.cpp new file mode 100644 index 00000000..e920da6e --- /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 <tdestandarddirs.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 diff --git a/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.h b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.h new file mode 100644 index 00000000..0d2bd4fd --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/imageselectionwidget.h @@ -0,0 +1,176 @@ +/* ============================================================ + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGESELECTIONWIDGET_H +#define IMAGESELECTIONWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqrect.h> +#include <tqcolor.h> + +namespace Digikam +{ +class ImageIface; +} + +namespace DigikamImagesPluginCore +{ + +class ImageSelectionWidgetPriv; + +class ImageSelectionWidget : public TQWidget +{ + +TQ_OBJECT + + +public: + + enum RatioAspect // Constrained Aspect Ratio list. + { + RATIOCUSTOM=0, // Custom aspect ratio. + RATIO01X01, // 1:1 + RATIO02x03, // 2:3 + RATIO03X04, // 3:4 + RATIO04X05, // 4:5 + RATIO05x07, // 5:7 + RATIO07x10, // 7:10 + RATIOGOLDEN, // Golden ratio : 1:1.618 + RATIONONE // No aspect ratio. + }; + + enum Orient + { + Landscape = 0, + Portrait + }; + + enum CenterType + { + CenterWidth = 0, // Center selection to the center of image width. + CenterHeight, // Center selection to the center of image height. + CenterImage // Center selection to the center of image. + }; + + // Proportion : Golden Ratio and Rule of Thirds. More information at this url: + // http://photoinf.com/General/Robert_Berdan/Composition_and_the_Elements_of_Visual_Design.htm + + enum GuideLineType + { + RulesOfThirds = 0, // Line guides position to 1/3 width and height. + DiagonalMethod, // Diagonal Method to improve composition. + HarmoniousTriangles, // Harmonious Triangle to improve composition. + GoldenMean, // Guides tools using Phi ratio (1.618). + GuideNone // No guide line. + }; + +public: + + ImageSelectionWidget(int width, int height, TQWidget *parent=0, + int widthRatioValue=1, int heightRatioValue=1, + int aspectRatio=RATIO01X01, int orient=Landscape, + int guideLinesType=GuideNone); + ~ImageSelectionWidget(); + + void setCenterSelection(int centerType=CenterImage); + void setSelectionX(int x); + void setSelectionY(int y); + void setSelectionWidth(int w); + void setSelectionHeight(int h); + void setSelectionOrientation(int orient); + void setPreciseCrop(bool precise); + void setAutoOrientation(bool orientation); + void setSelectionAspectRatioType(int aspectRatioType); + void setSelectionAspectRatioValue(int widthRatioValue, int heightRatioValue); + void setGoldenGuideTypes(bool drawGoldenSection, bool drawGoldenSpiralSection, + bool drawGoldenSpiral, bool drawGoldenTriangle, + bool flipHorGoldenGuide, bool flipVerGoldenGuide); + + int getOriginalImageWidth(); + int getOriginalImageHeight(); + TQRect getRegionSelection(); + + int getMinWidthRange(); + int getMinHeightRange(); + int getMaxWidthRange(); + int getMaxHeightRange(); + int getWidthStep(); + int getHeightStep(); + + bool preciseCropAvailable(); + + void resetSelection(); + void maxAspectSelection(); + + Digikam::ImageIface* imageIface(); + +public slots: + + void slotGuideLines(int guideLinesType); + void slotChangeGuideColor(const TQColor &color); + void slotChangeGuideSize(int size); + +signals: + + void signalSelectionMoved( TQRect rect ); + void signalSelectionChanged( TQRect rect ); + void signalSelectionOrientationChanged( int newOrientation ); + +protected: + + void paintEvent( TQPaintEvent *e ); + void mousePressEvent ( TQMouseEvent * e ); + void mouseReleaseEvent ( TQMouseEvent * e ); + void mouseMoveEvent ( TQMouseEvent * e ); + void resizeEvent(TQResizeEvent * e); + +private: + + // Recalculate the target selection position and emit 'signalSelectionMoved'. + void regionSelectionMoved(); + + void regionSelectionChanged(); + TQPoint convertPoint(const TQPoint pm, bool localToReal=true); + TQPoint convertPoint(int x, int y, bool localToReal=true); + void normalizeRegion(); + void reverseRatioValues(); + int computePreciseSize(int size, int step); + void applyAspectRatio(bool useHeight, bool repaintWidget=true); + void updatePixmap(); + TQPoint opposite(); + float distance(TQPoint a, TQPoint b); + void placeSelection(TQPoint pm, bool symetric, TQPoint center); + void setCursorResizing(); + +private: + + ImageSelectionWidgetPriv* d; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* IMAGESELECTIONWIDGET_H */ diff --git a/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.cpp b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.cpp new file mode 100644 index 00000000..41df2b47 --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.cpp @@ -0,0 +1,853 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcheckbox.h> +#include <tqframe.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqrect.h> +#include <tqspinbox.h> +#include <tqtimer.h> +#include <tqtoolbutton.h> +#include <tqtooltip.h> +#include <tqvgroupbox.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kcolorbutton.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kpushbutton.h> +#include <tdestandarddirs.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Digikam includes. + +#include "editortoolsettings.h" +#include "imageiface.h" +#include "imageselectionwidget.h" + +// Local includes. + +#include "ratiocroptool.h" +#include "ratiocroptool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamImagesPluginCore +{ + +RatioCropTool::RatioCropTool(TQObject* parent) + : EditorTool(parent) +{ + setName("aspectratiocrop"); + setToolName(i18n("Aspect Ratio Crop")); + setToolIcon(SmallIcon("ratiocrop")); + setToolHelp("ratiocroptool.anchor"); + + // ------------------------------------------------------------- + + m_imageSelectionWidget = new ImageSelectionWidget(480, 320); + TQWhatsThis::add(m_imageSelectionWidget, + i18n("<p>Here you can see the aspect ratio selection preview " + "used for cropping. You can use the mouse to move and " + "resize the crop area. " + "Press and hold the CTRL key to move the opposite corner too. " + "Press and hold the SHIFT key to move the closest corner to the " + "mouse pointer.")); + + m_originalIsLandscape = ((m_imageSelectionWidget->getOriginalImageWidth()) > + (m_imageSelectionWidget->getOriginalImageHeight())); + + setToolView(m_imageSelectionWidget); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Try| + EditorToolSettings::Cancel); + + // ------------------------------------------------------------- + + // need to set the button to a KStdGuiItem that has no icon + m_gboxSettings->button(EditorToolSettings::Try)->setGuiItem(KStdGuiItem::Test); + // now we can set the correct text for the button + m_gboxSettings->button(EditorToolSettings::Try)->setText(i18n("Max. Aspect")); + + TQToolTip::add(m_gboxSettings->button(EditorToolSettings::Try), + i18n("<p>Set selection area to the maximum size according " + "to the current ratio.")); + + // ------------------------------------------------------------- + + TQGridLayout *gboxLayout = new TQGridLayout(m_gboxSettings->plainPage(), 3, 2); + + TQFrame *cropSelection = new TQFrame(m_gboxSettings->plainPage()); + cropSelection->setFrameStyle(TQFrame::Panel | TQFrame::Sunken); + + TQGridLayout* grid = new TQGridLayout(cropSelection, 7, 5); + + TQLabel *label = new TQLabel(i18n("Ratio:"), cropSelection); + m_ratioCB = new RComboBox(cropSelection); + m_ratioCB->setDefaultItem(ImageSelectionWidget::RATIO03X04); + setRatioCBText(ImageSelectionWidget::Landscape); + TQWhatsThis::add( m_ratioCB, i18n("<p>Select your constrained aspect ratio for cropping. " + "Aspect Ratio Crop tool uses a relative ratio. That means it " + "is the same if you use centimeters or inches and it doesn't " + "specify the physical size.<p>" + "You can see below a correspondence list of traditional photographic " + "paper sizes and aspect ratio crop:<p>" + "<b>2:3</b>: 10x15cm, 20x30cm, 30x45cm, 4x6\", 8x12\", " + "12x18\", 16x24\", 20x30\"<p>" + "<b>3:4</b>: 6x8cm, 15x20cm, 18x24cm, 30x40cm, 3.75x5\", 4.5x6\", " + "6x8\", 7.5x10\", 9x12\"<p>" + "<b>4:5</b>: 20x25cm, 40x50cm, 8x10\", 16x20\"<p>" + "<b>5:7</b>: 15x21cm, 30x42cm, 5x7\"<p>" + "<b>7:10</b>: 21x30cm, 42x60cm, 3.5x5\"<p>" + "The <b>Golden Ratio</b> is 1:1.618. A composition following this rule " + "is considered visually harmonious but can be unadapted to print on " + "standard photographic paper.")); + + m_preciseCrop = new TQCheckBox(i18n("Exact"), cropSelection); + TQWhatsThis::add( m_preciseCrop, i18n("<p>Enable this option to force exact aspect ratio crop.")); + + m_orientLabel = new TQLabel(i18n("Orientation:"), cropSelection); + m_orientCB = new RComboBox(cropSelection); + m_orientCB->insertItem( i18n("Landscape")); + m_orientCB->insertItem( i18n("Portrait")); + m_orientCB->setDefaultItem(ImageSelectionWidget::Landscape); + TQWhatsThis::add( m_orientCB, i18n("<p>Select constrained aspect ratio orientation.")); + + m_autoOrientation = new TQCheckBox(i18n("Auto"), cropSelection); + TQWhatsThis::add( m_autoOrientation, i18n("<p>Enable this option to automatically set the orientation.")); + + // ------------------------------------------------------------- + + m_customLabel1 = new TQLabel(i18n("Custom:"), cropSelection); + m_customLabel1->setAlignment(AlignLeft|AlignVCenter); + m_customRatioNInput = new RIntNumInput(cropSelection); + m_customRatioNInput->input()->setRange(1, 10000, 1, false); + m_customRatioNInput->setDefaultValue(1); + TQWhatsThis::add( m_customRatioNInput, i18n("<p>Set here the desired custom aspect numerator value.")); + + m_customLabel2 = new TQLabel(" : ", cropSelection); + m_customLabel2->setAlignment(AlignCenter|AlignVCenter); + m_customRatioDInput = new RIntNumInput(cropSelection); + m_customRatioDInput->input()->setRange(1, 10000, 1, false); + m_customRatioDInput->setDefaultValue(1); + TQWhatsThis::add( m_customRatioDInput, i18n("<p>Set here the desired custom aspect denominator value.")); + + // ------------------------------------------------------------- + + m_xInput = new RIntNumInput(cropSelection); + m_xInput->input()->setLabel(i18n("X:"), AlignLeft|AlignVCenter); + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth(), 1); + m_xInput->setDefaultValue(50); + TQWhatsThis::add( m_xInput, i18n("<p>Set here the top left selection corner position for cropping.")); + + m_widthInput = new RIntNumInput(cropSelection); + m_widthInput->input()->setLabel(i18n("Width:"), AlignLeft|AlignVCenter); + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep()); + m_widthInput->setDefaultValue(800); + TQWhatsThis::add( m_widthInput, i18n("<p>Set here the width selection for cropping.")); + + m_centerWidth = new TQToolButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerwidth", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("centerwidth", "centerwidth.png"); + m_centerWidth->setPixmap(TQPixmap(directory + "centerwidth.png")); + TQWhatsThis::add(m_centerWidth, i18n("<p>Set width position to center.")); + + // ------------------------------------------------------------- + + m_yInput = new RIntNumInput(cropSelection); + m_yInput->input()->setLabel(i18n("Y:"), AlignLeft | AlignVCenter); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight(), 1); + m_yInput->setDefaultValue(50); + TQWhatsThis::add(m_yInput, i18n("<p>Set here the top left selection corner position for cropping.")); + + m_heightInput = new RIntNumInput(cropSelection); + m_heightInput->input()->setLabel(i18n("Height:"), AlignLeft | AlignVCenter); + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep()); + m_heightInput->setDefaultValue(600); + TQWhatsThis::add( m_heightInput, i18n("<p>Set here the height selection for cropping.")); + + m_centerHeight = new TQToolButton(cropSelection); + TDEGlobal::dirs()->addResourceType("centerheight", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("centerheight", "centerheight.png"); + m_centerHeight->setPixmap(TQPixmap(directory + "centerheight.png")); + TQWhatsThis::add(m_centerHeight, i18n("<p>Set height position to center.")); + + grid->addMultiCellWidget(label, 0, 0, 0, 0); + grid->addMultiCellWidget(m_ratioCB, 0, 0, 1, 3); + grid->addMultiCellWidget(m_preciseCrop, 0, 0, 4, 4); + grid->addMultiCellWidget(m_customLabel1, 1, 1, 0, 0); + grid->addMultiCellWidget(m_customRatioNInput, 1, 1, 1, 1); + grid->addMultiCellWidget(m_customLabel2, 1, 1, 2, 2); + grid->addMultiCellWidget(m_customRatioDInput, 1, 1, 3, 3); + grid->addMultiCellWidget(m_orientLabel, 2, 2, 0, 0); + grid->addMultiCellWidget(m_orientCB, 2, 2, 1, 3); + grid->addMultiCellWidget(m_autoOrientation, 2, 2, 4, 4); + grid->addMultiCellWidget(m_xInput, 3, 3, 0, 3); + grid->addMultiCellWidget(m_widthInput, 4, 4, 0, 3); + grid->addMultiCellWidget(m_centerWidth, 4, 4, 4, 4); + grid->addMultiCellWidget(m_yInput, 5, 5, 0, 3); + grid->addMultiCellWidget(m_heightInput, 6, 6, 0, 3); + grid->addMultiCellWidget(m_centerHeight, 6, 6, 4, 4); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + // ------------------------------------------------------------- + + TQFrame* compositionGuide = new TQFrame(m_gboxSettings->plainPage()); + TQGridLayout* grid2 = new TQGridLayout(compositionGuide, 8, 3); + compositionGuide->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + + TQLabel *labelGuideLines = new TQLabel(i18n("Composition guide:"), compositionGuide); + m_guideLinesCB = new RComboBox(compositionGuide); + m_guideLinesCB->insertItem( i18n("Rules of Thirds")); + m_guideLinesCB->insertItem( i18n("Diagonal Method")); + m_guideLinesCB->insertItem( i18n("Harmonious Triangles")); + m_guideLinesCB->insertItem( i18n("Golden Mean")); + m_guideLinesCB->insertItem( i18n("None")); + m_guideLinesCB->setDefaultItem(ImageSelectionWidget::GuideNone); + TQWhatsThis::add( m_guideLinesCB, i18n("<p>With this option, you can display guide lines " + "which help you to compose your photograph.")); + + m_goldenSectionBox = new TQCheckBox(i18n("Golden sections"), compositionGuide); + TQWhatsThis::add( m_goldenSectionBox, i18n("<p>Enable this option to show golden sections.")); + + m_goldenSpiralSectionBox = new TQCheckBox(i18n("Golden spiral sections"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralSectionBox, i18n("<p>Enable this option to show golden spiral sections.")); + + m_goldenSpiralBox = new TQCheckBox(i18n("Golden spiral"), compositionGuide); + TQWhatsThis::add( m_goldenSpiralBox, i18n("<p>Enable this option to show golden spiral guide.")); + + m_goldenTriangleBox = new TQCheckBox(i18n("Golden triangles"), compositionGuide); + TQWhatsThis::add( m_goldenTriangleBox, i18n("<p>Enable this option to show golden triangles.")); + + m_flipHorBox = new TQCheckBox(i18n("Flip horizontally"), compositionGuide); + TQWhatsThis::add( m_flipHorBox, i18n("<p>Enable this option to flip horizontally guidelines.")); + + m_flipVerBox = new TQCheckBox(i18n("Flip vertically"), compositionGuide); + TQWhatsThis::add( m_flipVerBox, i18n("<p>Enable this option to flip vertically guidelines.")); + + m_colorGuideLabel = new TQLabel(i18n("Color and width:"), compositionGuide); + m_guideColorBt = new KColorButton(TQColor(250, 250, 255), compositionGuide); + m_guideSize = new RIntNumInput(compositionGuide); + m_guideSize->input()->setRange(1, 5, 1, false); + m_guideSize->setDefaultValue(1); + TQWhatsThis::add( m_guideColorBt, i18n("<p>Set here the color used to draw composition guides.")); + TQWhatsThis::add( m_guideSize, i18n("<p>Set here the width in pixels used to draw composition guides.")); + + grid2->addMultiCellWidget(labelGuideLines, 0, 0, 0, 0); + grid2->addMultiCellWidget(m_guideLinesCB, 0, 0, 1, 2); + grid2->addMultiCellWidget(m_goldenSectionBox, 1, 1, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralSectionBox, 2, 2, 0, 2); + grid2->addMultiCellWidget(m_goldenSpiralBox, 3, 3, 0, 2); + grid2->addMultiCellWidget(m_goldenTriangleBox, 4, 4, 0, 2); + grid2->addMultiCellWidget(m_flipHorBox, 5, 5, 0, 2); + grid2->addMultiCellWidget(m_flipVerBox, 6, 6, 0, 2); + grid2->addMultiCellWidget(m_colorGuideLabel, 7, 7, 0, 0); + grid2->addMultiCellWidget(m_guideColorBt, 7, 7, 1, 1); + grid2->addMultiCellWidget(m_guideSize, 7, 7, 2, 2); + grid2->setMargin(m_gboxSettings->spacingHint()); + grid2->setSpacing(m_gboxSettings->spacingHint()); + + + // ------------------------------------------------------------- + + gboxLayout->addMultiCellWidget(cropSelection, 0, 0, 0, 1); + gboxLayout->addMultiCellWidget(compositionGuide, 1, 1, 0, 1); + gboxLayout->setRowStretch(2, 10); + gboxLayout->setMargin(m_gboxSettings->spacingHint()); + gboxLayout->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + init(); + + // ------------------------------------------------------------- + + connect(m_ratioCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotRatioChanged(int))); + + connect(m_preciseCrop, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotPreciseCropChanged(bool))); + + connect(m_orientCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotOrientChanged(int))); + + connect(m_autoOrientation, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotAutoOrientChanged(bool))); + + connect(m_xInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotXChanged(int))); + + connect(m_yInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotYChanged(int))); + + connect(m_customRatioNInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomNRatioChanged(int))); + + connect(m_customRatioDInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotCustomDRatioChanged(int))); + + connect(m_guideLinesCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotGuideTypeChanged(int))); + + connect(m_goldenSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralSectionBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenSpiralBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_goldenTriangleBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipHorBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_flipVerBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotGoldenGuideTypeChanged())); + + connect(m_guideColorBt, TQ_SIGNAL(changed(const TQColor&)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideColor(const TQColor&))); + + connect(m_guideSize, TQ_SIGNAL(valueChanged(int)), + m_imageSelectionWidget, TQ_SLOT(slotChangeGuideSize(int))); + + connect(m_widthInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotWidthChanged(int))); + + connect(m_heightInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotHeightChanged(int))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionChanged(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionMoved(TQRect)), + this, TQ_SLOT(slotSelectionChanged(TQRect))); + + connect(m_imageSelectionWidget, TQ_SIGNAL(signalSelectionOrientationChanged(int)), + this, TQ_SLOT(slotSelectionOrientationChanged(int))); + + connect(m_centerWidth, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterWidth())); + + connect(m_centerHeight, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCenterHeight())); + + // we need to disconnect the standard connection of the Try button first + disconnect(m_gboxSettings, TQ_SIGNAL(signalTryClicked()), + this, TQ_SLOT(slotEffect())); + + connect(m_gboxSettings, TQ_SIGNAL(signalTryClicked()), + this, TQ_SLOT(slotMaxAspectRatio())); + + // ------------------------------------------------------------- + + // Sets current region selection + slotSelectionChanged(m_imageSelectionWidget->getRegionSelection()); +} + +RatioCropTool::~RatioCropTool() +{ +} + +void RatioCropTool::readSettings() +{ + TQColor defaultGuideColor(250, 250, 255); + TDEConfig *config = tdeApp->config(); + config->setGroup("aspectratiocrop Tool"); + + // No guide lines per default. + m_guideLinesCB->setCurrentItem(config->readNumEntry("Guide Lines Type", ImageSelectionWidget::GuideNone)); + m_goldenSectionBox->setChecked(config->readBoolEntry("Golden Section", true)); + m_goldenSpiralSectionBox->setChecked(config->readBoolEntry("Golden Spiral Section", false)); + m_goldenSpiralBox->setChecked(config->readBoolEntry("Golden Spiral", false)); + m_goldenTriangleBox->setChecked(config->readBoolEntry("Golden Triangle", false)); + m_flipHorBox->setChecked(config->readBoolEntry("Golden Flip Horizontal", false)); + m_flipVerBox->setChecked(config->readBoolEntry("Golden Flip Vertical", false)); + m_guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); + m_guideSize->setValue(config->readNumEntry("Guide Width", m_guideSize->defaultValue())); + m_imageSelectionWidget->slotGuideLines(m_guideLinesCB->currentItem()); + m_imageSelectionWidget->slotChangeGuideColor(m_guideColorBt->color()); + + m_preciseCrop->setChecked(config->readBoolEntry("Precise Aspect Ratio Crop", false)); + m_imageSelectionWidget->setPreciseCrop(m_preciseCrop->isChecked()); + + // Empty selection so it can be moved w/out size constraint + m_widthInput->setValue(0); + m_heightInput->setValue(0); + + m_xInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Xpos", + m_xInput->defaultValue())); + m_yInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Ypos", + m_yInput->defaultValue())); + + m_widthInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Width", + m_widthInput->defaultValue())); + m_heightInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Height", + m_heightInput->defaultValue())); + + m_imageSelectionWidget->setSelectionOrientation(m_orientCB->currentItem()); + + m_customRatioNInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Num", + m_customRatioNInput->defaultValue())); + m_customRatioDInput->setValue(config->readNumEntry("Hor.Oriented Custom Aspect Ratio Den", + m_customRatioDInput->defaultValue())); + + m_ratioCB->setCurrentItem(config->readNumEntry("Hor.Oriented Aspect Ratio", + m_ratioCB->defaultItem())); + + if (m_originalIsLandscape) + { + m_orientCB->setCurrentItem(config->readNumEntry("Hor.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Landscape)); + m_orientCB->setDefaultItem(ImageSelectionWidget::Landscape); + } + else + { + m_orientCB->setCurrentItem(config->readNumEntry("Ver.Oriented Aspect Ratio Orientation", + ImageSelectionWidget::Portrait)); + m_orientCB->setDefaultItem(ImageSelectionWidget::Portrait); + } + + applyRatioChanges(m_ratioCB->currentItem()); + + m_autoOrientation->setChecked( config->readBoolEntry("Auto Orientation", false) ); + slotAutoOrientChanged( m_autoOrientation->isChecked() ); +} + +void RatioCropTool::writeSettings() +{ + TDEConfig *config = tdeApp->config(); + config->setGroup("aspectratiocrop Tool"); + + if (m_originalIsLandscape) + { + config->writeEntry("Hor.Oriented Aspect Ratio", m_ratioCB->currentItem()); + config->writeEntry("Hor.Oriented Aspect Ratio Orientation", m_orientCB->currentItem()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value()); + + config->writeEntry("Hor.Oriented Custom Aspect Ratio Xpos", m_xInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Ypos", m_yInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Width", m_widthInput->value()); + config->writeEntry("Hor.Oriented Custom Aspect Ratio Height", m_heightInput->value()); + } + else + { + config->writeEntry("Ver.Oriented Aspect Ratio", m_ratioCB->currentItem()); + config->writeEntry("Ver.Oriented Aspect Ratio Orientation", m_orientCB->currentItem()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Num", m_customRatioNInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Den", m_customRatioDInput->value()); + + config->writeEntry("Ver.Oriented Custom Aspect Ratio Xpos", m_xInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Ypos", m_yInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Width", m_widthInput->value()); + config->writeEntry("Ver.Oriented Custom Aspect Ratio Height", m_heightInput->value()); + } + + config->writeEntry("Precise Aspect Ratio Crop", m_preciseCrop->isChecked()); + config->writeEntry("Auto Orientation", m_autoOrientation->isChecked()); + config->writeEntry("Guide Lines Type", m_guideLinesCB->currentItem()); + config->writeEntry("Golden Section", m_goldenSectionBox->isChecked()); + config->writeEntry("Golden Spiral Section", m_goldenSpiralSectionBox->isChecked()); + config->writeEntry("Golden Spiral", m_goldenSpiralBox->isChecked()); + config->writeEntry("Golden Triangle", m_goldenTriangleBox->isChecked()); + config->writeEntry("Golden Flip Horizontal", m_flipHorBox->isChecked()); + config->writeEntry("Golden Flip Vertical", m_flipVerBox->isChecked()); + config->writeEntry("Guide Color", m_guideColorBt->color()); + config->writeEntry("Guide Width", m_guideSize->value()); + config->sync(); +} + +void RatioCropTool::slotResetSettings() +{ + m_imageSelectionWidget->resetSelection(); +} + +void RatioCropTool::slotMaxAspectRatio() +{ + m_imageSelectionWidget->maxAspectSelection(); +} + +void RatioCropTool::slotCenterWidth() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterWidth); +} + +void RatioCropTool::slotCenterHeight() +{ + m_imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterHeight); +} + +void RatioCropTool::slotSelectionChanged(TQRect rect) +{ + m_xInput->blockSignals(true); + m_yInput->blockSignals(true); + m_widthInput->blockSignals(true); + m_heightInput->blockSignals(true); + + m_xInput->setRange(0, m_imageSelectionWidget->getOriginalImageWidth() - rect.width(), 1); + m_yInput->setRange(0, m_imageSelectionWidget->getOriginalImageHeight() - rect.height(), 1); + + m_widthInput->setRange(m_imageSelectionWidget->getMinWidthRange(), + m_imageSelectionWidget->getMaxWidthRange(), + m_imageSelectionWidget->getWidthStep()); + + m_heightInput->setRange(m_imageSelectionWidget->getMinHeightRange(), + m_imageSelectionWidget->getMaxHeightRange(), + m_imageSelectionWidget->getHeightStep()); + + m_xInput->setValue(rect.x()); + m_yInput->setValue(rect.y()); + m_widthInput->setValue(rect.width()); + m_heightInput->setValue(rect.height()); + + m_gboxSettings->enableButton(EditorToolSettings::Ok, rect.isValid()); + m_preciseCrop->setEnabled(m_imageSelectionWidget->preciseCropAvailable()); + + m_xInput->blockSignals(false); + m_yInput->blockSignals(false); + m_widthInput->blockSignals(false); + m_heightInput->blockSignals(false); +} + +void RatioCropTool::setRatioCBText(int orientation) +{ + int item = m_ratioCB->currentItem(); + + m_ratioCB->blockSignals(true); + m_ratioCB->combo()->clear(); + m_ratioCB->insertItem(i18n("Custom")); + m_ratioCB->insertItem("1:1"); + if (orientation == ImageSelectionWidget::Landscape) + { + m_ratioCB->insertItem("3:2"); + m_ratioCB->insertItem("4:3"); + m_ratioCB->insertItem("5:4"); + m_ratioCB->insertItem("7:5"); + m_ratioCB->insertItem("10:7"); + } + else + { + m_ratioCB->insertItem("2:3"); + m_ratioCB->insertItem("3:4"); + m_ratioCB->insertItem("4:5"); + m_ratioCB->insertItem("5:7"); + m_ratioCB->insertItem("7:10"); + } + m_ratioCB->insertItem(i18n("Golden Ratio")); + m_ratioCB->insertItem(i18n("None")); + m_ratioCB->setCurrentItem(item); + m_ratioCB->blockSignals(false); +} + +void RatioCropTool::slotSelectionOrientationChanged(int newOrientation) +{ + // Change text for Aspect ratio ComboBox + + setRatioCBText(newOrientation); + + // Change Orientation ComboBox + + m_orientCB->setCurrentItem(newOrientation); + + // Reverse custom values + + if ( ( m_customRatioNInput->value() < m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Landscape) || + ( m_customRatioNInput->value() > m_customRatioDInput->value() && + newOrientation == ImageSelectionWidget::Portrait)) + { + m_customRatioNInput->blockSignals(true); + m_customRatioDInput->blockSignals(true); + + int tmp = m_customRatioNInput->value(); + m_customRatioNInput->setValue(m_customRatioDInput->value()); + m_customRatioDInput->setValue(tmp); + + m_customRatioNInput->blockSignals(false); + m_customRatioDInput->blockSignals(false); + } +} + +void RatioCropTool::slotXChanged(int x) +{ + m_imageSelectionWidget->setSelectionX(x); +} + +void RatioCropTool::slotYChanged(int y) +{ + m_imageSelectionWidget->setSelectionY(y); +} + +void RatioCropTool::slotWidthChanged(int w) +{ + m_imageSelectionWidget->setSelectionWidth(w); +} + +void RatioCropTool::slotHeightChanged(int h) +{ + m_imageSelectionWidget->setSelectionHeight(h); +} + +void RatioCropTool::slotPreciseCropChanged(bool a) +{ + m_imageSelectionWidget->setPreciseCrop(a); +} + +void RatioCropTool::slotOrientChanged(int o) +{ + m_imageSelectionWidget->setSelectionOrientation(o); + + // Reset selection area. + slotResetSettings(); +} + +void RatioCropTool::slotAutoOrientChanged(bool a) +{ + m_orientCB->setEnabled(!a /*|| m_ratioCB->currentItem() == ImageSelectionWidget::RATIONONE*/); + m_imageSelectionWidget->setAutoOrientation(a); +} + +void RatioCropTool::slotRatioChanged(int a) +{ + applyRatioChanges(a); + + // Reset selection area. + slotResetSettings(); +} + +void RatioCropTool::applyRatioChanges(int a) +{ + m_imageSelectionWidget->setSelectionAspectRatioType(a); + + if (a == ImageSelectionWidget::RATIOCUSTOM) + { + m_customLabel1->setEnabled(true); + m_customLabel2->setEnabled(true); + m_customRatioNInput->setEnabled(true); + m_customRatioDInput->setEnabled(true); + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(!m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + slotCustomRatioChanged(); + } + else if (a == ImageSelectionWidget::RATIONONE) + { + m_orientLabel->setEnabled(false); + m_orientCB->setEnabled(false); + m_autoOrientation->setEnabled(false); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } + else // Pre-config ratio selected. + { + m_orientLabel->setEnabled(true); + m_orientCB->setEnabled(!m_autoOrientation->isChecked()); + m_autoOrientation->setEnabled(true); + m_customLabel1->setEnabled(false); + m_customLabel2->setEnabled(false); + m_customRatioNInput->setEnabled(false); + m_customRatioDInput->setEnabled(false); + } +} + +void RatioCropTool::slotGuideTypeChanged(int t) +{ + if (t == ImageSelectionWidget::GuideNone) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(false); + m_guideColorBt->setEnabled(false); + m_guideSize->setEnabled(false); + } + else if (t == ImageSelectionWidget::RulesOfThirds) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else if (t == ImageSelectionWidget::DiagonalMethod) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(false); + m_flipVerBox->setEnabled(false); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else if (t == ImageSelectionWidget::HarmoniousTriangles) + { + m_goldenSectionBox->setEnabled(false); + m_goldenSpiralSectionBox->setEnabled(false); + m_goldenSpiralBox->setEnabled(false); + m_goldenTriangleBox->setEnabled(false); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + else + { + m_goldenSectionBox->setEnabled(true); + m_goldenSpiralSectionBox->setEnabled(true); + m_goldenSpiralBox->setEnabled(true); + m_goldenTriangleBox->setEnabled(true); + m_flipHorBox->setEnabled(true); + m_flipVerBox->setEnabled(true); + m_colorGuideLabel->setEnabled(true); + m_guideColorBt->setEnabled(true); + m_guideSize->setEnabled(true); + } + + m_imageSelectionWidget->setGoldenGuideTypes(m_goldenSectionBox->isChecked(), + m_goldenSpiralSectionBox->isChecked(), + m_goldenSpiralBox->isChecked(), + m_goldenTriangleBox->isChecked(), + m_flipHorBox->isChecked(), + m_flipVerBox->isChecked()); + m_imageSelectionWidget->slotGuideLines(t); +} + +void RatioCropTool::slotGoldenGuideTypeChanged() +{ + slotGuideTypeChanged(m_guideLinesCB->currentItem()); +} + +void RatioCropTool::slotCustomNRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioDInput->value() < a) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioDInput->value() > a)) + { + m_customRatioDInput->blockSignals(true); + m_customRatioDInput->setValue(a); + m_customRatioDInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void RatioCropTool::slotCustomDRatioChanged(int a) +{ + if ( ! m_autoOrientation->isChecked() ) + { + if ( ( m_orientCB->currentItem() == ImageSelectionWidget::Landscape && + m_customRatioNInput->value() < a) || + ( m_orientCB->currentItem() == ImageSelectionWidget::Portrait && + m_customRatioNInput->value() > a)) + { + m_customRatioNInput->blockSignals(true); + m_customRatioNInput->setValue(a); + m_customRatioNInput->blockSignals(false); + } + } + + slotCustomRatioChanged(); +} + +void RatioCropTool::slotCustomRatioChanged() +{ + m_imageSelectionWidget->setSelectionAspectRatioValue(m_customRatioNInput->value(), + m_customRatioDInput->value()); + + // Reset selection area. + slotResetSettings(); +} + +void RatioCropTool::finalRendering() +{ + tdeApp->setOverrideCursor( KCursor::waitCursor() ); + + TQRect currentRegion = m_imageSelectionWidget->getRegionSelection(); + ImageIface* iface = m_imageSelectionWidget->imageIface(); + uchar *data = iface->getOriginalImage(); + int w = iface->originalWidth(); + int h = iface->originalHeight(); + bool a = iface->originalHasAlpha(); + bool sb = iface->originalSixteenBit(); + + TQRect normalizedRegion = currentRegion.normalize(); + if (normalizedRegion.right() > w) + normalizedRegion.setRight(w); + + if (normalizedRegion.bottom() > h) + normalizedRegion.setBottom(h); + + DImg imOrg(w, h, sb, a, data); + delete [] data; + imOrg.crop(normalizedRegion); + + iface->putOriginalImage(i18n("Aspect Ratio Crop"), imOrg.bits(), imOrg.width(), imOrg.height()); + + tdeApp->restoreOverrideCursor(); + writeSettings(); +} + +} // NameSpace DigikamImagesPluginCore diff --git a/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.h b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.h new file mode 100644 index 00000000..833677da --- /dev/null +++ b/src/imageplugins/coreplugin/ratiocrop/ratiocroptool.h @@ -0,0 +1,135 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-06 + * Description : digiKam image editor Ratio Crop tool + * + * Copyright (C) 2007 by Jaromir Malenko <malenko at email dot 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. + * + * ============================================================ */ + +#ifndef RATIOCROPTOOL_H +#define RATIOCROPTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQCheckBox; +class TQLabel; +class TQToolButton; + +class KColorButton; + +namespace KDcrawIface +{ +class RComboBox; +class RIntNumInput; +} + +namespace DigikamImagesPluginCore +{ + +class ImageSelectionWidget; + +class RatioCropTool : public Digikam::EditorTool +{ + TQ_OBJECT + + +public: + + RatioCropTool(TQObject *parent); + ~RatioCropTool(); + +private: + + void readSettings(); + void writeSettings(); + void finalRendering(); + + void applyRatioChanges(int a); + void setRatioCBText(int orientation); + +private slots: + + void slotMaxAspectRatio(); + void slotResetSettings(); + + void slotCenterWidth(); + void slotCenterHeight(); + void slotXChanged(int x); + void slotYChanged(int y); + void slotWidthChanged(int w); + void slotHeightChanged(int h); + void slotCustomRatioChanged(); + void slotCustomNRatioChanged(int a); + void slotCustomDRatioChanged(int a); + void slotPreciseCropChanged(bool a); + void slotOrientChanged(int o); + void slotAutoOrientChanged(bool a); + void slotRatioChanged(int a); + void slotSelectionChanged(TQRect rect ); + void slotSelectionOrientationChanged(int); + void slotGuideTypeChanged(int t); + void slotGoldenGuideTypeChanged(); + +private: + + bool m_originalIsLandscape; + + TQLabel *m_customLabel1; + TQLabel *m_customLabel2; + TQLabel *m_orientLabel; + TQLabel *m_colorGuideLabel; + + + TQToolButton *m_centerWidth; + TQToolButton *m_centerHeight; + + TQCheckBox *m_goldenSectionBox; + TQCheckBox *m_goldenSpiralSectionBox; + TQCheckBox *m_goldenSpiralBox; + TQCheckBox *m_goldenTriangleBox; + TQCheckBox *m_flipHorBox; + TQCheckBox *m_flipVerBox; + TQCheckBox *m_autoOrientation; + TQCheckBox *m_preciseCrop; + + KDcrawIface::RComboBox *m_guideLinesCB; + KDcrawIface::RComboBox *m_orientCB; + KDcrawIface::RComboBox *m_ratioCB; + + KDcrawIface::RIntNumInput *m_customRatioDInput; + KDcrawIface::RIntNumInput *m_customRatioNInput; + KDcrawIface::RIntNumInput *m_guideSize; + KDcrawIface::RIntNumInput *m_heightInput; + KDcrawIface::RIntNumInput *m_widthInput; + KDcrawIface::RIntNumInput *m_xInput; + KDcrawIface::RIntNumInput *m_yInput; + + KColorButton *m_guideColorBt; + + ImageSelectionWidget *m_imageSelectionWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamImagesPluginCore + +#endif /* RATIOCROPTOOL_H */ |