/* ============================================================
 *
 * 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.
 *
 * ============================================================ */

#include "ratiocroptool.h"
#include "ratiocroptool.moc"

// Qt includes

#include <QCheckBox>
#include <QFrame>
#include <QGridLayout>
#include <QGroupBox>
#include <QImage>
#include <QLabel>
#include <QPixmap>
#include <QRect>
#include <QSpinBox>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>

// KDE includes

#include <kapplication.h>
#include <kcolorbutton.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kcursor.h>
#include <klocale.h>
#include <kpushbutton.h>
#include <kstandarddirs.h>
#include <kstandardguiitem.h>

// LibKDcraw includes

#include <libkdcraw/rcombobox.h>
#include <libkdcraw/rnuminput.h>

// Local includes

#include "editortoolsettings.h"
#include "imageiface.h"
#include "imageselectionwidget.h"
#include "rexpanderbox.h"

using namespace KDcrawIface;
using namespace Digikam;

namespace DigikamImagesPluginCore
{

class RatioCropToolPriv
{
public:

    RatioCropToolPriv()
    {
        originalIsLandscape       = false;
        customLabel               = 0;
        orientLabel               = 0;
        colorGuideLabel           = 0;
        centerWidth               = 0;
        centerHeight              = 0;
        goldenSectionBox          = 0;
        goldenSpiralSectionBox    = 0;
        goldenSpiralBox           = 0;
        goldenTriangleBox         = 0;
        flipHorBox                = 0;
        flipVerBox                = 0;
        autoOrientation           = 0;
        preciseCrop               = 0;
        ratioCB                   = 0;
        orientCB                  = 0;
        guideLinesCB              = 0;
        customRatioDInput         = 0;
        customRatioNInput         = 0;
        guideSize                 = 0;
        heightInput               = 0;
        widthInput                = 0;
        xInput                    = 0;
        yInput                    = 0;
        guideColorBt              = 0;
        imageSelectionWidget      = 0;
        expbox                    = 0;
        gboxSettings              = 0;
    }

    bool                  originalIsLandscape;

    QLabel*               customLabel;
    QLabel*               orientLabel;
    QLabel*               colorGuideLabel;

    QToolButton*          centerWidth;
    QToolButton*          centerHeight;

    QCheckBox*            goldenSectionBox;
    QCheckBox*            goldenSpiralSectionBox;
    QCheckBox*            goldenSpiralBox;
    QCheckBox*            goldenTriangleBox;
    QCheckBox*            flipHorBox;
    QCheckBox*            flipVerBox;
    QCheckBox*            autoOrientation;
    QCheckBox*            preciseCrop;

    RComboBox*            ratioCB;
    RComboBox*            orientCB;
    RComboBox*            guideLinesCB;

    RIntNumInput*         customRatioDInput;
    RIntNumInput*         customRatioNInput;
    RIntNumInput*         guideSize;
    RIntNumInput*         heightInput;
    RIntNumInput*         widthInput;
    RIntNumInput*         xInput;
    RIntNumInput*         yInput;

    KColorButton*         guideColorBt;

    ImageSelectionWidget* imageSelectionWidget;
    RExpanderBox*         expbox;
    EditorToolSettings*   gboxSettings;
};

RatioCropTool::RatioCropTool(QObject* parent)
             : EditorTool(parent),
               d(new RatioCropToolPriv)
{
    setObjectName("aspectratiocrop");
    setToolName(i18n("Aspect Ratio Crop"));
    setToolIcon(SmallIcon("ratiocrop"));
    setToolHelp("ratiocroptool.anchor");

    // -------------------------------------------------------------

    d->imageSelectionWidget = new ImageSelectionWidget(480, 320);
    d->imageSelectionWidget->setWhatsThis(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.</p>"
                                               "<p>Press and hold the <b>CTRL</b> key to move the opposite corner too.</p>"
                                               "<p>Press and hold the <b>SHIFT</b> key to move the closest corner to the "
                                               "mouse pointer.</p>"));

    d->originalIsLandscape = ((d->imageSelectionWidget->getOriginalImageWidth()) >
    (d->imageSelectionWidget->getOriginalImageHeight()));

    setToolView(d->imageSelectionWidget);

    // -------------------------------------------------------------

    d->gboxSettings = new EditorToolSettings(EditorToolSettings::Default|
                                             EditorToolSettings::Ok|
                                             EditorToolSettings::Try|
                                             EditorToolSettings::Cancel);

    // -------------------------------------------------------------

    // need to set the button to a KStdGuiItem that has no icon
    KPushButton *tryBtn = d->gboxSettings->button(EditorToolSettings::Try);
    tryBtn->setGuiItem(KStandardGuiItem::Test);
    tryBtn->setText(i18n("Max. Aspect"));
    tryBtn->setToolTip(i18n("Set selection area to the maximum size according "
                            "to the current ratio."));

    // -------------------------------------------------------------

    QVBoxLayout* vlay      = new QVBoxLayout(d->gboxSettings->plainPage());
    d->expbox              = new RExpanderBox(d->gboxSettings->plainPage());
    QWidget *cropSelection = new QWidget(d->expbox);
    QGridLayout* grid      = new QGridLayout(cropSelection);

    QLabel *label = new QLabel(i18n("Aspect ratio:"), cropSelection);
    d->ratioCB    = new RComboBox(cropSelection);
    d->ratioCB->addItem(i18nc("custom aspect ratio crop settings", "Custom"));
    d->ratioCB->addItem("1:1");
    d->ratioCB->addItem("2:3");
    d->ratioCB->addItem("3:4");
    d->ratioCB->addItem("4:5");
    d->ratioCB->addItem("5:7");
    d->ratioCB->addItem("7:10");
    d->ratioCB->addItem(i18n("Golden Ratio"));
    d->ratioCB->addItem(i18nc("no crop mode", "None"));
    d->ratioCB->setDefaultIndex(ImageSelectionWidget::RATIO03X04);
    setRatioCBText(ImageSelectionWidget::Landscape);
    d->ratioCB->setWhatsThis( 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 does not "
                                   "specify the physical size.</p>"
                                   "<p>You can see below a correspondence list of traditional photographic "
                                   "paper sizes and aspect ratio crop:</p>"
                                   "<p><b>2:3</b>: 10x15cm, 20x30cm, 30x45cm, 4x6\", 8x12\", "
                                   "12x18\", 16x24\", 20x30\"</p>"
                                   "<p><b>3:4</b>: 6x8cm, 15x20cm, 18x24cm, 30x40cm, 3.75x5\", 4.5x6\", "
                                   "6x8\", 7.5x10\", 9x12\"</p>"
                                   "<p><b>4:5</b>: 20x25cm, 40x50cm, 8x10\", 16x20\"</p>"
                                   "<p><b>5:7</b>: 15x21cm, 30x42cm, 5x7\"</p>"
                                   "<p><b>7:10</b>: 21x30cm, 42x60cm, 3.5x5\"</p>"
                                   "<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.</p>"));

    d->preciseCrop = new QCheckBox(cropSelection);
    d->preciseCrop->setToolTip(i18n("Exact aspect"));
    d->preciseCrop->setWhatsThis(i18n("Enable this option to force exact aspect ratio crop."));

    d->orientLabel = new QLabel(i18n("Orientation:"), cropSelection);
    d->orientCB    = new RComboBox( cropSelection );
    d->orientCB->addItem( i18n("Landscape") );
    d->orientCB->addItem( i18n("Portrait") );
    d->orientCB->setWhatsThis(i18n("Select constrained aspect ratio orientation."));

    d->autoOrientation = new QCheckBox(cropSelection);
    d->autoOrientation->setToolTip(i18n("Auto"));
    d->autoOrientation->setWhatsThis( i18n("Enable this option to automatically set the orientation."));

    // -------------------------------------------------------------

    d->customLabel = new QLabel(i18n("Custom ratio:"), cropSelection);
    d->customLabel->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
    d->customRatioNInput = new RIntNumInput(cropSelection);
    d->customRatioNInput->setRange(1, 10000, 1);
    d->customRatioNInput->setDefaultValue(1);
    d->customRatioNInput->setSliderEnabled(false);
    d->customRatioNInput->setWhatsThis( i18n("Set here the desired custom aspect numerator value."));

    d->customRatioDInput = new RIntNumInput(cropSelection);
    d->customRatioDInput->setRange(1, 10000, 1);
    d->customRatioDInput->setDefaultValue(1);
    d->customRatioDInput->setSliderEnabled(false);
    d->customRatioDInput->setWhatsThis( i18n("Set here the desired custom aspect denominator value."));

    // -------------------------------------------------------------

    d->xInput = new RIntNumInput(cropSelection);
    d->xInput->setWhatsThis( i18n("Set here the top left selection corner position for cropping."));
    d->xInput->input()->setLabel(i18nc("top left corner position for cropping", "X:"), Qt::AlignLeft|Qt::AlignVCenter);
    d->xInput->setRange(0, d->imageSelectionWidget->getOriginalImageWidth(), 1);
    d->xInput->setSliderEnabled(true);
    d->xInput->setDefaultValue(50);

    d->widthInput = new RIntNumInput(cropSelection);
    d->widthInput->input()->setLabel(i18n("Width:"), Qt::AlignLeft|Qt::AlignVCenter);
    d->widthInput->setWhatsThis( i18n("Set here the width selection for cropping."));
    d->widthInput->setRange(d->imageSelectionWidget->getMinWidthRange(),
                           d->imageSelectionWidget->getMaxWidthRange(),
                           d->imageSelectionWidget->getWidthStep());
    d->widthInput->setSliderEnabled(true);
    d->widthInput->setDefaultValue(800);

    d->centerWidth = new QToolButton(cropSelection);
    d->centerWidth->setIcon(QPixmap(KStandardDirs::locate("data", "digikam/data/centerwidth.png")));
    d->centerWidth->setWhatsThis( i18n("Set width position to center."));

    // -------------------------------------------------------------

    d->yInput = new RIntNumInput(cropSelection);
    d->yInput->input()->setLabel(i18n("Y:"), Qt::AlignLeft|Qt::AlignVCenter);
    d->yInput->setWhatsThis( i18n("Set here the top left selection corner position for cropping."));
    d->yInput->setRange(0, d->imageSelectionWidget->getOriginalImageWidth(), 1);
    d->yInput->setSliderEnabled(true);
    d->yInput->setDefaultValue(50);

    d->heightInput = new RIntNumInput(cropSelection);
    d->heightInput->input()->setLabel(i18n("Height:"), Qt::AlignLeft|Qt::AlignVCenter);
    d->heightInput->setWhatsThis( i18n("Set here the height selection for cropping."));
    d->heightInput->setRange(d->imageSelectionWidget->getMinHeightRange(),
                             d->imageSelectionWidget->getMaxHeightRange(),
                             d->imageSelectionWidget->getHeightStep());
    d->heightInput->setSliderEnabled(true);
    d->heightInput->setDefaultValue(600);

    d->centerHeight = new QToolButton(cropSelection);
    d->centerHeight->setIcon(QPixmap(KStandardDirs::locate("data", "digikam/data/centerheight.png")));
    d->centerHeight->setWhatsThis( i18n("Set height position to center."));

    // -------------------------------------------------------------

    grid->addWidget(label,                0, 0, 1, 1);
    grid->addWidget(d->ratioCB,           0, 1, 1, 3);
    grid->addWidget(d->preciseCrop,       0, 4, 1, 1);
    grid->addWidget(d->customLabel,       1, 0, 1, 1);
    grid->addWidget(d->customRatioNInput, 1, 1, 1, 1);
    grid->addWidget(d->customRatioDInput, 2, 1, 1, 1);
    grid->addWidget(d->orientLabel,       3, 0, 1, 1);
    grid->addWidget(d->orientCB,          3, 1, 1, 3);
    grid->addWidget(d->autoOrientation,   3, 4, 1, 1);
    grid->addWidget(d->xInput,            4, 0, 1, 4);
    grid->addWidget(d->widthInput,        5, 0, 1, 4);
    grid->addWidget(d->centerWidth,       5, 4, 1, 1);
    grid->addWidget(d->yInput,            6, 0, 1, 4);
    grid->addWidget(d->heightInput,       7, 0, 1, 4);
    grid->addWidget(d->centerHeight,      7, 4, 1, 1);
    grid->setMargin(d->gboxSettings->spacingHint());
    grid->setSpacing(d->gboxSettings->spacingHint());

    d->expbox->addItem(cropSelection, SmallIcon("transform-crop-and-resize"),
                      i18n("Crop Settings"), QString("CropSelection"), true);

    // -------------------------------------------------------------

    QWidget* compositionGuide = new QWidget(d->expbox);
    QGridLayout* grid2        = new QGridLayout(compositionGuide);

    QLabel *labelGuideLines = new QLabel(i18n("Geometric form:"), compositionGuide);
    d->guideLinesCB         = new RComboBox(compositionGuide);
    d->guideLinesCB->addItem(i18n("Rules of Thirds"));
    d->guideLinesCB->addItem(i18n("Diagonal Method"));
    d->guideLinesCB->addItem(i18n("Harmonious Triangles"));
    d->guideLinesCB->addItem(i18n("Golden Mean"));
    d->guideLinesCB->addItem(i18nc("no geometric form", "None"));
    d->guideLinesCB->setDefaultIndex(ImageSelectionWidget::GuideNone);
    d->guideLinesCB->setCurrentIndex(3);
    d->guideLinesCB->setWhatsThis( i18n("With this option, you can display guide lines "
                                        "to help compose your photograph."));

    d->goldenSectionBox = new QCheckBox(i18n("Golden sections"), compositionGuide);
    d->goldenSectionBox->setWhatsThis(i18n("Enable this option to show golden sections."));

    d->goldenSpiralSectionBox = new QCheckBox(i18n("Golden spiral sections"), compositionGuide);
    d->goldenSpiralSectionBox->setWhatsThis(i18n("Enable this option to show golden spiral sections."));

    d->goldenSpiralBox = new QCheckBox(i18n("Golden spiral"), compositionGuide);
    d->goldenSpiralBox->setWhatsThis(i18n("Enable this option to show a golden spiral guide."));

    d->goldenTriangleBox = new QCheckBox(i18n("Golden triangles"), compositionGuide);
    d->goldenTriangleBox->setWhatsThis(i18n("Enable this option to show golden triangles."));

    d->flipHorBox = new QCheckBox(i18n("Flip horizontally"), compositionGuide);
    d->flipHorBox->setWhatsThis(i18n("Enable this option to flip the guidelines horizontally."));

    d->flipVerBox = new QCheckBox(i18n("Flip vertically"), compositionGuide);
    d->flipVerBox->setWhatsThis(i18n("Enable this option to flip the guidelines vertically."));

    d->colorGuideLabel = new QLabel(i18n("Color and width:"), compositionGuide);
    d->guideColorBt    = new KColorButton( QColor( 250, 250, 255 ), compositionGuide );
    d->guideSize       = new RIntNumInput(compositionGuide);
    d->guideSize->setRange(1, 5, 1);
    d->guideSize->setSliderEnabled(false);
    d->guideSize->setDefaultValue(1);
    d->guideColorBt->setWhatsThis(i18n("Set here the color used to draw composition guides."));
    d->guideSize->setWhatsThis(i18n("Set here the width in pixels used to draw composition guides."));

    // -------------------------------------------------------------

    grid2->addWidget(labelGuideLines,           0, 0, 1, 1);
    grid2->addWidget(d->guideLinesCB,           0, 1, 1, 2);
    grid2->addWidget(d->goldenSectionBox,       1, 0, 1, 3);
    grid2->addWidget(d->goldenSpiralSectionBox, 2, 0, 1, 3);
    grid2->addWidget(d->goldenSpiralBox,        3, 0, 1, 3);
    grid2->addWidget(d->goldenTriangleBox,      4, 0, 1, 3);
    grid2->addWidget(d->flipHorBox,             5, 0, 1, 3);
    grid2->addWidget(d->flipVerBox,             6, 0, 1, 3);
    grid2->addWidget(d->colorGuideLabel,        7, 0, 1, 1);
    grid2->addWidget(d->guideColorBt,           7, 1, 1, 1);
    grid2->addWidget(d->guideSize,              7, 2, 1, 1);
    grid2->setMargin(d->gboxSettings->spacingHint());
    grid2->setSpacing(d->gboxSettings->spacingHint());

    d->expbox->addItem(compositionGuide, SmallIcon("tools-wizard"),
                      i18n("Composition Guides"), QString("CompositionGuide"), true);
    d->expbox->addStretch();

    // -------------------------------------------------------------

    vlay->addWidget(d->expbox, 10);
    vlay->addStretch();
    vlay->setMargin(0);
    vlay->setSpacing(0);
    setToolSettings(d->gboxSettings);

    init();

    // Sets current region selection
    slotSelectionChanged(d->imageSelectionWidget->getRegionSelection());
    readSettings();

    // -------------------------------------------------------------

    connect(d->ratioCB, SIGNAL(activated(int)),
            this, SLOT(slotRatioChanged(int)));

    connect(d->preciseCrop, SIGNAL(toggled(bool)),
            this, SLOT(slotPreciseCropChanged(bool)));

    connect(d->orientCB, SIGNAL(activated(int)),
            this, SLOT(slotOrientChanged(int)));

    connect(d->autoOrientation, SIGNAL(toggled(bool)),
            this, SLOT(slotAutoOrientChanged(bool)));

    connect(d->xInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotXChanged(int)));

    connect(d->yInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotYChanged(int)));

    connect(d->customRatioNInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotCustomRatioChanged()));

    connect(d->customRatioDInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotCustomRatioChanged()));

    connect(d->guideLinesCB, SIGNAL(activated(int)),
            this, SLOT(slotGuideTypeChanged(int)));

    connect(d->goldenSectionBox, SIGNAL(toggled(bool)),
            this, SLOT(slotGoldenGuideTypeChanged()));

    connect(d->goldenSpiralSectionBox, SIGNAL(toggled(bool)),
            this, SLOT(slotGoldenGuideTypeChanged()));

    connect(d->goldenSpiralBox, SIGNAL(toggled(bool)),
            this, SLOT(slotGoldenGuideTypeChanged()));

    connect(d->goldenTriangleBox, SIGNAL(toggled(bool)),
            this, SLOT(slotGoldenGuideTypeChanged()));

    connect(d->flipHorBox, SIGNAL(toggled(bool)),
            this, SLOT(slotGoldenGuideTypeChanged()));

    connect(d->flipVerBox, SIGNAL(toggled(bool)),
            this, SLOT(slotGoldenGuideTypeChanged()));

    connect(d->guideColorBt, SIGNAL(changed(const QColor&)),
            d->imageSelectionWidget, SLOT(slotChangeGuideColor(const QColor&)));

    connect(d->guideSize, SIGNAL(valueChanged(int)),
            d->imageSelectionWidget, SLOT(slotChangeGuideSize(int)));

    connect(d->widthInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotWidthChanged(int)));

    connect(d->heightInput, SIGNAL(valueChanged(int)),
            this, SLOT(slotHeightChanged(int)));

    connect(d->imageSelectionWidget, SIGNAL(signalSelectionChanged(const QRect&)),
            this, SLOT(slotSelectionChanged(const QRect&)));

    connect(d->imageSelectionWidget, SIGNAL(signalSelectionMoved(const QRect&)),
            this, SLOT(slotSelectionChanged(const QRect&)));

    connect(d->imageSelectionWidget, SIGNAL(signalSelectionOrientationChanged(int)),
            this, SLOT(slotSelectionOrientationChanged(int)));

    connect(d->centerWidth, SIGNAL(clicked()),
            this, SLOT(slotCenterWidth()));

    connect(d->centerHeight, SIGNAL(clicked()),
            this, SLOT(slotCenterHeight()));

    // we need to disconnect the standard connection of the Try button first
    disconnect(d->gboxSettings, SIGNAL(signalTryClicked()),
               this, SLOT(slotEffect()));

    connect(d->gboxSettings, SIGNAL(signalTryClicked()),
            this, SLOT(slotMaxAspectRatio()));
}

RatioCropTool::~RatioCropTool()
{
    delete d;
}

void RatioCropTool::readSettings()
{
    QColor defaultGuideColor(250, 250, 255);
    KSharedConfig::Ptr config = KGlobal::config();
    KConfigGroup group        = config->group("aspectratiocrop Tool");

    // --------------------------------------------------------

    blockWidgetSignals(true);

    d->expbox->readSettings(group);

    // No guide lines per default.
    d->guideLinesCB->setCurrentIndex(group.readEntry("Guide Lines Type",
                                    (int)ImageSelectionWidget::GuideNone));
    d->goldenSectionBox->setChecked(group.readEntry("Golden Section", true));
    d->goldenSpiralSectionBox->setChecked(group.readEntry("Golden Spiral Section", false));
    d->goldenSpiralBox->setChecked(group.readEntry("Golden Spiral", false));
    d->goldenTriangleBox->setChecked(group.readEntry("Golden Triangle", false));
    d->flipHorBox->setChecked(group.readEntry("Golden Flip Horizontal", false));
    d->flipVerBox->setChecked(group.readEntry("Golden Flip Vertical", false));
    d->guideColorBt->setColor(group.readEntry("Guide Color", defaultGuideColor));
    d->guideSize->setValue(group.readEntry("Guide Width", d->guideSize->defaultValue()));
    d->imageSelectionWidget->slotGuideLines(d->guideLinesCB->currentIndex());
    d->imageSelectionWidget->slotChangeGuideColor(d->guideColorBt->color());

    d->preciseCrop->setChecked( group.readEntry("Precise Aspect Ratio Crop", false) );
    d->imageSelectionWidget->setPreciseCrop( d->preciseCrop->isChecked() );

    // Empty selection so it can be moved w/out size constraint
    d->widthInput->setValue(0);
    d->heightInput->setValue(0);

    d->xInput->setValue(group.readEntry("Hor.Oriented Custom Aspect Ratio Xpos",
                        d->xInput->defaultValue()));
    d->yInput->setValue(group.readEntry("Hor.Oriented Custom Aspect Ratio Ypos",
                        d->yInput->defaultValue()));

    d->widthInput->setValue(group.readEntry("Hor.Oriented Custom Aspect Ratio Width",
                            d->widthInput->defaultValue()));
    d->heightInput->setValue(group.readEntry("Hor.Oriented Custom Aspect Ratio Height",
                             d->heightInput->defaultValue()));

    d->imageSelectionWidget->setSelectionOrientation(d->orientCB->currentIndex());

    d->customRatioNInput->setValue(group.readEntry("Hor.Oriented Custom Aspect Ratio Num",
                                   d->customRatioNInput->defaultValue()));
    d->customRatioDInput->setValue(group.readEntry("Hor.Oriented Custom Aspect Ratio Den",
                                   d->customRatioDInput->defaultValue()));
    d->ratioCB->setCurrentIndex(group.readEntry("Hor.Oriented Aspect Ratio",
                                d->ratioCB->defaultIndex()));

    if (d->originalIsLandscape)
    {
        d->orientCB->setCurrentIndex(group.readEntry("Hor.Oriented Aspect Ratio Orientation",
                                    (int)ImageSelectionWidget::Landscape));
        d->orientCB->setDefaultIndex(ImageSelectionWidget::Landscape);
    }
    else
    {
        d->orientCB->setCurrentIndex(group.readEntry("Ver.Oriented Aspect Ratio Orientation",
                                    (int)ImageSelectionWidget::Portrait));
        d->orientCB->setDefaultIndex(ImageSelectionWidget::Portrait);
    }

    applyRatioChanges(d->ratioCB->currentIndex());
    d->autoOrientation->setChecked(group.readEntry("Auto Orientation", false));
    slotAutoOrientChanged( d->autoOrientation->isChecked() );
    slotGuideTypeChanged(d->guideLinesCB->currentIndex());

    blockWidgetSignals(false);
}

void RatioCropTool::writeSettings()
{
    KSharedConfig::Ptr config = KGlobal::config();
    KConfigGroup group = config->group("aspectratiocrop Tool");

    d->expbox->writeSettings(group);

    if (d->originalIsLandscape)
    {
        group.writeEntry("Hor.Oriented Aspect Ratio", d->ratioCB->currentIndex());
        group.writeEntry("Hor.Oriented Aspect Ratio Orientation", d->orientCB->currentIndex());
        group.writeEntry("Hor.Oriented Custom Aspect Ratio Num", d->customRatioNInput->value());
        group.writeEntry("Hor.Oriented Custom Aspect Ratio Den", d->customRatioDInput->value());

        group.writeEntry("Hor.Oriented Custom Aspect Ratio Xpos", d->xInput->value());
        group.writeEntry("Hor.Oriented Custom Aspect Ratio Ypos", d->yInput->value());
        group.writeEntry("Hor.Oriented Custom Aspect Ratio Width", d->widthInput->value());
        group.writeEntry("Hor.Oriented Custom Aspect Ratio Height", d->heightInput->value());
    }
    else
    {
        group.writeEntry("Ver.Oriented Aspect Ratio", d->ratioCB->currentIndex());
        group.writeEntry("Ver.Oriented Aspect Ratio Orientation", d->orientCB->currentIndex());
        group.writeEntry("Ver.Oriented Custom Aspect Ratio Num", d->customRatioNInput->value());
        group.writeEntry("Ver.Oriented Custom Aspect Ratio Den", d->customRatioDInput->value());

        group.writeEntry("Ver.Oriented Custom Aspect Ratio Xpos", d->xInput->value());
        group.writeEntry("Ver.Oriented Custom Aspect Ratio Ypos", d->yInput->value());
        group.writeEntry("Ver.Oriented Custom Aspect Ratio Width", d->widthInput->value());
        group.writeEntry("Ver.Oriented Custom Aspect Ratio Height", d->heightInput->value());
    }

    group.writeEntry("Precise Aspect Ratio Crop", d->preciseCrop->isChecked());
    group.writeEntry("Auto Orientation", d->autoOrientation->isChecked());
    group.writeEntry("Guide Lines Type", d->guideLinesCB->currentIndex());
    group.writeEntry("Golden Section", d->goldenSectionBox->isChecked());
    group.writeEntry("Golden Spiral Section", d->goldenSpiralSectionBox->isChecked());
    group.writeEntry("Golden Spiral", d->goldenSpiralBox->isChecked());
    group.writeEntry("Golden Triangle", d->goldenTriangleBox->isChecked());
    group.writeEntry("Golden Flip Horizontal", d->flipHorBox->isChecked());
    group.writeEntry("Golden Flip Vertical", d->flipVerBox->isChecked());
    group.writeEntry("Guide Color", d->guideColorBt->color());
    group.writeEntry("Guide Width", d->guideSize->value());
    group.sync();
}

void RatioCropTool::slotResetSettings()
{
    d->imageSelectionWidget->resetSelection();
}

void RatioCropTool::slotMaxAspectRatio()
{
    d->imageSelectionWidget->maxAspectSelection();
}

void RatioCropTool::slotCenterWidth()
{
    d->imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterWidth);
}

void RatioCropTool::slotCenterHeight()
{
    d->imageSelectionWidget->setCenterSelection(ImageSelectionWidget::CenterHeight);
}

void RatioCropTool::slotSelectionChanged(const QRect& rect)
{
    blockWidgetSignals(true);

    d->xInput->setRange(0, d->imageSelectionWidget->getOriginalImageWidth() - rect.width(), 1);
    d->yInput->setRange(0, d->imageSelectionWidget->getOriginalImageHeight() - rect.height(), 1);
    d->widthInput->setRange(d->imageSelectionWidget->getMinWidthRange(),
                            d->imageSelectionWidget->getMaxWidthRange(),
                            d->imageSelectionWidget->getWidthStep());
    d->heightInput->setRange(d->imageSelectionWidget->getMinHeightRange(),
                             d->imageSelectionWidget->getMaxHeightRange(),
                             d->imageSelectionWidget->getHeightStep());

    d->xInput->setValue(rect.x());
    d->yInput->setValue(rect.y());
    d->widthInput->setValue(rect.width());
    d->heightInput->setValue(rect.height());

    d->gboxSettings->enableButton(EditorToolSettings::Ok,
                                 rect.isValid());

    d->preciseCrop->setEnabled(d->imageSelectionWidget->preciseCropAvailable());

    blockWidgetSignals(false);
}

void RatioCropTool::setRatioCBText(int orientation)
{
    int item = d->ratioCB->currentIndex();
    d->ratioCB->blockSignals(true);
    d->ratioCB->combo()->clear();
    d->ratioCB->addItem(i18nc("custom ratio crop settings", "Custom"));
    d->ratioCB->addItem("1:1");
    if (orientation == ImageSelectionWidget::Landscape)
    {
        d->ratioCB->addItem("3:2");
        d->ratioCB->addItem("4:3");
        d->ratioCB->addItem("5:4");
        d->ratioCB->addItem("7:5");
        d->ratioCB->addItem("10:7");
    }
    else
    {
        d->ratioCB->addItem("2:3");
        d->ratioCB->addItem("3:4");
        d->ratioCB->addItem("4:5");
        d->ratioCB->addItem("5:7");
        d->ratioCB->addItem("7:10");
    }
    d->ratioCB->addItem(i18n("Golden Ratio"));
    d->ratioCB->addItem(i18nc("no aspect ratio", "None"));
    d->ratioCB->setCurrentIndex(item);
    d->ratioCB->blockSignals(false);
}

void RatioCropTool::slotSelectionOrientationChanged(int newOrientation)
{
    // Change text for Aspect ratio ComboBox

    setRatioCBText(newOrientation);

    // Change Orientation ComboBox

    d->orientCB->setCurrentIndex(newOrientation);

    // Reverse custom values

    if ( ( d->customRatioNInput->value() < d->customRatioDInput->value() &&
           newOrientation == ImageSelectionWidget::Landscape ) ||
         ( d->customRatioNInput->value() > d->customRatioDInput->value() &&
           newOrientation == ImageSelectionWidget::Portrait ) )
    {
        d->customRatioNInput->blockSignals(true);
        d->customRatioDInput->blockSignals(true);

        int tmp = d->customRatioNInput->value();
        d->customRatioNInput->setValue(d->customRatioDInput->value());
        d->customRatioDInput->setValue(tmp);

        d->customRatioNInput->blockSignals(false);
        d->customRatioDInput->blockSignals(false);
    }
}

void RatioCropTool::slotXChanged(int x)
{
    d->imageSelectionWidget->setSelectionX(x);
}

void RatioCropTool::slotYChanged(int y)
{
    d->imageSelectionWidget->setSelectionY(y);
}

void RatioCropTool::slotWidthChanged(int w)
{
    d->imageSelectionWidget->setSelectionWidth(w);
}

void RatioCropTool::slotHeightChanged(int h)
{
    d->imageSelectionWidget->setSelectionHeight(h);
}

void RatioCropTool::slotPreciseCropChanged(bool a)
{
    d->imageSelectionWidget->setPreciseCrop(a);
}

void RatioCropTool::slotOrientChanged(int o)
{
    d->imageSelectionWidget->setSelectionOrientation(o);

    // Reset selection area.
    slotResetSettings();
}

void RatioCropTool::slotAutoOrientChanged(bool a)
{
    d->orientCB->setEnabled(!a /*|| d->ratioCB->currentIndex() == ImageSelectionWidget::RATIONONE*/);
    d->imageSelectionWidget->setAutoOrientation(a);
}

void RatioCropTool::slotRatioChanged(int a)
{
    applyRatioChanges(a);

    // Reset selection area.
    slotResetSettings();
}

void RatioCropTool::applyRatioChanges(int a)
{
    d->imageSelectionWidget->setSelectionAspectRatioType(a);

    if (a == ImageSelectionWidget::RATIOCUSTOM)
    {
        d->customLabel->setEnabled(true);
        d->customRatioNInput->setEnabled(true);
        d->customRatioDInput->setEnabled(true);
        d->orientLabel->setEnabled(true);
        d->orientCB->setEnabled(!d->autoOrientation->isChecked());
        d->autoOrientation->setEnabled(true);
        slotCustomRatioChanged();
    }
    else if (a == ImageSelectionWidget::RATIONONE)
    {
        d->orientLabel->setEnabled(false);
        d->orientCB->setEnabled(false);
        d->autoOrientation->setEnabled(false);
        d->customLabel->setEnabled(false);
        d->customRatioNInput->setEnabled(false);
        d->customRatioDInput->setEnabled(false);
    }
    else // Pre-config ratio selected.
    {
        d->orientLabel->setEnabled(true);
        d->orientCB->setEnabled(!d->autoOrientation->isChecked());
        d->autoOrientation->setEnabled(true);
        d->customLabel->setEnabled(false);
        d->customRatioNInput->setEnabled(false);
        d->customRatioDInput->setEnabled(false);
    }
}

void RatioCropTool::slotGuideTypeChanged(int t)
{
    d->goldenSectionBox->setEnabled(false);
    d->goldenSpiralSectionBox->setEnabled(false);
    d->goldenSpiralBox->setEnabled(false);
    d->goldenTriangleBox->setEnabled(false);
    d->flipHorBox->setEnabled(false);
    d->flipVerBox->setEnabled(false);
    d->colorGuideLabel->setEnabled(true);
    d->guideColorBt->setEnabled(true);
    d->guideSize->setEnabled(true);

    switch (t)
    {
        case ImageSelectionWidget::GuideNone:
            d->colorGuideLabel->setEnabled(false);
            d->guideColorBt->setEnabled(false);
            d->guideSize->setEnabled(false);
            break;
        case ImageSelectionWidget::HarmoniousTriangles:
            d->flipHorBox->setEnabled(true);
            d->flipVerBox->setEnabled(true);
            break;
        case ImageSelectionWidget::GoldenMean:
            d->flipHorBox->setEnabled(true);
            d->flipVerBox->setEnabled(true);
            d->goldenSectionBox->setEnabled(true);
            d->goldenSpiralSectionBox->setEnabled(true);
            d->goldenSpiralBox->setEnabled(true);
            d->goldenTriangleBox->setEnabled(true);
            break;
    }

    d->imageSelectionWidget->setGoldenGuideTypes(d->goldenSectionBox->isChecked(),
                                                d->goldenSpiralSectionBox->isChecked(),
                                                d->goldenSpiralBox->isChecked(),
                                                d->goldenTriangleBox->isChecked(),
                                                d->flipHorBox->isChecked(),
                                                d->flipVerBox->isChecked());
    d->imageSelectionWidget->slotGuideLines(t);
}

void RatioCropTool::slotGoldenGuideTypeChanged()
{
    slotGuideTypeChanged(d->guideLinesCB->currentIndex());
}

void RatioCropTool::slotCustomNRatioChanged(int a)
{
    if ( ! d->autoOrientation->isChecked() )
    {
        if ( ( d->orientCB->currentIndex() == ImageSelectionWidget::Portrait &&
               d->customRatioDInput->value() < a ) ||
             ( d->orientCB->currentIndex() == ImageSelectionWidget::Landscape &&
               d->customRatioDInput->value() > a ) )
        {
            d->customRatioDInput->blockSignals(true);
            d->customRatioDInput->setValue(a);
            d->customRatioDInput->blockSignals(false);
        }
    }

    slotCustomRatioChanged();
}

void RatioCropTool::slotCustomDRatioChanged(int a)
{
    if ( ! d->autoOrientation->isChecked() )
    {
        if ( ( d->orientCB->currentIndex() == ImageSelectionWidget::Landscape &&
               d->customRatioNInput->value() < a ) ||
             ( d->orientCB->currentIndex() == ImageSelectionWidget::Portrait &&
               d->customRatioNInput->value() > a ) )
        {
            d->customRatioNInput->blockSignals(true);
            d->customRatioNInput->setValue(a);
            d->customRatioNInput->blockSignals(false);
        }
    }

    slotCustomRatioChanged();
}

void RatioCropTool::slotCustomRatioChanged()
{
    d->imageSelectionWidget->setSelectionAspectRatioValue(
            d->customRatioNInput->value(), d->customRatioDInput->value() );

    // Reset selection area.
    slotResetSettings();
}

void RatioCropTool::finalRendering()
{
    kapp->setOverrideCursor( Qt::WaitCursor );

    QRect currentRegion = d->imageSelectionWidget->getRegionSelection();
    ImageIface* iface   = d->imageSelectionWidget->imageIface();
    uchar *data         = iface->getOriginalImage();
    int w               = iface->originalWidth();
    int h               = iface->originalHeight();
    bool a              = iface->originalHasAlpha();
    bool sb             = iface->originalSixteenBit();

    QRect normalizedRegion = currentRegion.normalized();
    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());

    kapp->restoreOverrideCursor();
    writeSettings();
}

void RatioCropTool::blockWidgetSignals(bool b)
{
    d->customRatioDInput->blockSignals(b);
    d->customRatioNInput->blockSignals(b);
    d->flipHorBox->blockSignals(b);
    d->flipVerBox->blockSignals(b);
    d->goldenSectionBox->blockSignals(b);
    d->goldenSpiralBox->blockSignals(b);
    d->goldenSpiralSectionBox->blockSignals(b);
    d->goldenTriangleBox->blockSignals(b);
    d->guideLinesCB->blockSignals(b);
    d->heightInput->blockSignals(b);
    d->imageSelectionWidget->blockSignals(b);
    d->preciseCrop->blockSignals(b);
    d->widthInput->blockSignals(b);
    d->xInput->blockSignals(b);
    d->yInput->blockSignals(b);
}

}  // namespace DigikamImagesPluginCore
