/***************************************************************************
 *   Copyright (C) 2005 by Thierry CHARLES   *
 *   thierry@les-charles.net   *
 *                                                                         *
 *   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 of the License, 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.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "color_dlg.h"

#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/statbmp.h>
#include <wx/thread.h>
#include <wx/tokenzr.h>

#include "lib/tprocess.h"

#include "components/stdgui/tbitmap.h"
#include "xpe_components/res_id.h"

#include "color_link.xpm"

BEGIN_EVENT_TABLE(ColorDlg, wxDialog)
END_EVENT_TABLE()

ColorDlg::ColorDlg(wxWindow * owner)
    : wxDialog(owner,-1,wxT("Color ..."), wxDefaultPosition,wxDefaultSize,wxDEFAULT_DIALOG_STYLE|wxSTAY_ON_TOP|wxRESIZE_BORDER),
        hueSatMap(NULL),
        valueSlider(NULL),
        stdColorLbl(NULL),
        hueField(NULL),
        saturationField(NULL),
        valueField(NULL),
        redField(NULL),
        greenField(NULL),
        blueField(NULL),
        decRedField(NULL),
        decGreenField(NULL),
        decBlueField(NULL),
        useGammaCorrectionChk(NULL),
        correctedColorLbl(NULL),
        linkGammaCorrectionChk(NULL),
        gammaRedField(NULL),
        gammaGreenField(NULL),
        gammaBlueField(NULL),
        correctedRedField(NULL),
        correctedGreenField(NULL),
        correctedBlueField(NULL),
        decCorrectedRedField(NULL),
        decCorrectedGreenField(NULL),
        decCorrectedBlueField(NULL),
        btnOk(NULL),
        btnCancel(NULL),
        btnReset(NULL)
{
    this->SetTitle(wxTr("Choose color ..."));
    wxSizer * mainSizer = new wxBoxSizer(wxVERTICAL);
    mainSizer->AddSpacer(5);

    TPanel * cmpsPanel = new TPanel(this);
    wxSizer * cmpsSizer = new wxBoxSizer(wxHORIZONTAL);

    this->hueSatMap = new THueSaturationMap(cmpsPanel);
    cmpsSizer->Add(this->hueSatMap, wxALIGN_CENTER_VERTICAL);
    this->hueSatMap->Connect(wxEVT_MOTION, wxMouseEventHandler(ColorDlg::hueSaturationMapClicked), NULL, this);
    this->hueSatMap->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(ColorDlg::hueSaturationMapClicked), NULL, this);
    cmpsSizer->AddSpacer(3);

    this->valueSlider = new wxSlider(cmpsPanel, -1, 127, 0, 1275, wxDefaultPosition, wxDefaultSize, wxSL_INVERSE | wxSL_VERTICAL);
    cmpsSizer->Add(this->valueSlider, 0, wxEXPAND);
    this->valueSlider->Connect(wxEVT_SCROLL_THUMBTRACK,wxScrollEventHandler(ColorDlg::sliderMoved), NULL, this);
    cmpsSizer->AddSpacer(5);

    TPanel * rightPanel = new TPanel(cmpsPanel);
    wxSizer * rightSizer = new wxBoxSizer(wxVERTICAL);

    TPanel * hsvRgbPanel = new TPanel(rightPanel);
    wxSizer * hsvRgbSizer = new wxBoxSizer(wxHORIZONTAL);

    this->stdColorLbl = new TLabel(hsvRgbPanel);
    this->stdColorLbl->SetMinSize(wxSize(40,25));
    this->stdColorLbl->SetSize(wxSize(40,25));
    this->stdColorLbl->SetMaxSize(wxSize(40,25));
    this->stdColorLbl->SetBackgroundColour(*wxBLACK);
    hsvRgbSizer->Add(this->stdColorLbl, 0, wxALIGN_CENTER_VERTICAL);
    hsvRgbSizer->AddSpacer(5);

    TPanel * hsvPanel = new TPanel(hsvRgbPanel);
    wxSizer * hsvSizer = new wxFlexGridSizer(3,2,3,5);

    wxStaticText * label = new wxStaticText(hsvPanel,-1,wxTr("Hue"));
    hsvSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->hueField = new wxSpinCtrl(hsvPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->hueField->SetRange(0,360);
    this->hueField->SetMaxSize(wxSize(60,-1));
    hsvSizer->Add(this->hueField);
    this->hueField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);


    label = new wxStaticText(hsvPanel,-1,wxTr("Saturation"));
    hsvSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->saturationField = new wxSpinCtrl(hsvPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->saturationField->SetRange(0,1000);
    this->saturationField->SetMaxSize(wxSize(60,-1));
    hsvSizer->Add(this->saturationField);
    this->saturationField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    label = new wxStaticText(hsvPanel,-1,wxTr("Value"));
    hsvSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->valueField = new wxSpinCtrl(hsvPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->valueField->SetRange(0,1275);
    this->valueField->SetMaxSize(wxSize(60,-1));
    hsvSizer->Add(this->valueField);
    this->valueField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    hsvPanel->SetSizer(hsvSizer);
    hsvRgbSizer->Add(hsvPanel);

    hsvRgbSizer->AddSpacer(5);

    TPanel * rgbPanel = new TPanel(hsvRgbPanel);
    wxSizer * rgbSizer = new wxFlexGridSizer(3,2,3,5);

    label = new wxStaticText(rgbPanel,-1,wxTr("Red"));
    rgbSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->redField = new wxSpinCtrl(rgbPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->redField->SetRange(0,1275);
    this->redField->SetMaxSize(wxSize(60,-1));
    rgbSizer->Add(this->redField);
    this->redField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    label = new wxStaticText(rgbPanel,-1,wxTr("Green"));
    rgbSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->greenField = new wxSpinCtrl(rgbPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->greenField->SetRange(0,1275);
    this->greenField->SetMaxSize(wxSize(60,-1));
    rgbSizer->Add(this->greenField);
    this->greenField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    label = new wxStaticText(rgbPanel,-1,wxTr("Blue"));
    rgbSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->blueField = new wxSpinCtrl(rgbPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->blueField->SetRange(0,1275);
    this->blueField->SetMaxSize(wxSize(60,-1));
    rgbSizer->Add(this->blueField);
    this->blueField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    rgbPanel->SetSizer(rgbSizer);
    hsvRgbSizer->Add(rgbPanel);

    TPanel * rgbFPanel = new TPanel(hsvRgbPanel);
    wxSizer * rgbFSizer = new wxFlexGridSizer(3,2,3,5);

    label = new wxStaticText(rgbFPanel,-1,wxTr("-"));
    rgbFSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->decRedField = new wxTextCtrl(rgbFPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(65,-1), wxTE_READONLY);
    this->decRedField->SetMaxSize(wxSize(65,-1));
    rgbFSizer->Add(this->decRedField);

    label = new wxStaticText(rgbFPanel,-1,wxTr("-"));
    rgbFSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->decGreenField = new wxTextCtrl(rgbFPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(65,-1), wxTE_READONLY);
    this->decGreenField->SetMaxSize(wxSize(65,-1));
    rgbFSizer->Add(this->decGreenField);

    label = new wxStaticText(rgbFPanel,-1,wxTr("-"));
    rgbFSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->decBlueField = new wxTextCtrl(rgbFPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(65,-1), wxTE_READONLY);
    this->decBlueField->SetMaxSize(wxSize(65,-1));
    rgbFSizer->Add(this->decBlueField);

    rgbFPanel->SetSizer(rgbFSizer);
    hsvRgbSizer->Add(rgbFPanel);
    hsvRgbSizer->AddStretchSpacer(10);

    hsvRgbPanel->SetSizer(hsvRgbSizer);
    rightSizer->Add(hsvRgbPanel);

    rightSizer->AddSpacer(3);

    this->useGammaCorrectionChk = new wxCheckBox(rightPanel, -1, wxTr("Use gamma correction"));
    rightSizer->Add(this->useGammaCorrectionChk);
    this->useGammaCorrectionChk->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,wxCommandEventHandler(ColorDlg::checkboxClicked), NULL, this);

    rightSizer->AddSpacer(3);

    TPanel * fullGammaPanel = new TPanel(rightPanel);
    wxSizer * fullGammaSizer = new wxBoxSizer(wxHORIZONTAL);

    this->correctedColorLbl = new TLabel(fullGammaPanel);
    this->correctedColorLbl->SetMinSize(wxSize(40,25));
    this->correctedColorLbl->SetSize(wxSize(40,25));
    this->correctedColorLbl->SetMaxSize(wxSize(40,25));
    this->correctedColorLbl->SetBackgroundColour(*wxBLACK);
    fullGammaSizer->Add(this->correctedColorLbl, 0, wxALIGN_CENTER_VERTICAL);
    fullGammaSizer->AddSpacer(5);

    this->linkGammaCorrectionChk = new wxCheckBox(fullGammaPanel, -1, wxTr("Link"));
    fullGammaSizer->Add(this->linkGammaCorrectionChk,0,wxALIGN_CENTER_VERTICAL|wxEXPAND);
    this->linkGammaCorrectionChk->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,wxCommandEventHandler(ColorDlg::checkboxClicked), NULL, this);

    wxStaticBitmap * linkLine = new  wxStaticBitmap(fullGammaPanel, -1, TBitmap((const char **) color_link_xpm ));
    fullGammaSizer->Add(linkLine,0,wxALIGN_CENTER_VERTICAL);

    TPanel * gammaPanel = new TPanel(fullGammaPanel);
    wxSizer * gammaSizer = new wxFlexGridSizer(3,2,3,5);

    label = new wxStaticText(gammaPanel,-1,wxTr("Red"));
    gammaSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->gammaRedField = new wxSpinCtrl(gammaPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->gammaRedField->SetMaxSize(wxSize(60,-1));
    this->gammaRedField->SetRange(0,1000);
    gammaSizer->Add(this->gammaRedField);
    this->gammaRedField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    label = new wxStaticText(gammaPanel,-1,wxTr("Green"));
    gammaSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->gammaGreenField = new wxSpinCtrl(gammaPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->gammaGreenField->SetRange(0,1000);
    this->gammaGreenField->SetMaxSize(wxSize(60,-1));
    gammaSizer->Add(this->gammaGreenField);
    this->gammaGreenField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    label = new wxStaticText(gammaPanel,-1,wxTr("Blue"));
    gammaSizer->Add(label,0,wxALIGN_CENTER_VERTICAL);
    this->gammaBlueField = new wxSpinCtrl(gammaPanel,-1,wxEmptyString,wxDefaultPosition,wxSize(60,-1));
    this->gammaBlueField->SetRange(0,1000);
    this->gammaBlueField->SetMaxSize(wxSize(60,-1));
    gammaSizer->Add(this->gammaBlueField);
    this->gammaBlueField->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED,wxSpinEventHandler(ColorDlg::spinctrlUpdated), NULL, this);

    gammaPanel->SetSizer(gammaSizer);
    fullGammaSizer->Add(gammaPanel);

//    fullGammaSizer->AddSpacer(3);

    TPanel * correctedPanel = new TPanel(fullGammaPanel);
    wxSizer * correctedSizer = new wxFlexGridSizer(3,2,3,5);

    label = new wxStaticText(correctedPanel,-1,wxT("% ->"));
    correctedSizer->Add(label, 0, wxALIGN_CENTER_VERTICAL);
    this->correctedRedField = new wxTextCtrl(correctedPanel,-1, wxT("0"), wxDefaultPosition, wxSize(55,-1), wxTE_READONLY);
    this->correctedRedField->SetMaxSize(wxSize(55,-1));
    correctedSizer->Add(this->correctedRedField);

    label = new wxStaticText(correctedPanel,-1,wxT("% ->"));
    correctedSizer->Add(label, 0, wxALIGN_CENTER_VERTICAL);
    this->correctedGreenField = new wxTextCtrl(correctedPanel,-1, wxT("0"), wxDefaultPosition, wxSize(55,-1), wxTE_READONLY);
    this->correctedGreenField->SetMaxSize(wxSize(55,-1));
    correctedSizer->Add(this->correctedGreenField);

    label = new wxStaticText(correctedPanel,-1,wxT("% ->"));
    correctedSizer->Add(label, 0, wxALIGN_CENTER_VERTICAL);
    this->correctedBlueField = new wxTextCtrl(correctedPanel,-1, wxT("0"), wxDefaultPosition, wxSize(55,-1), wxTE_READONLY);
    this->correctedBlueField->SetMaxSize(wxSize(55,-1));
    correctedSizer->Add(this->correctedBlueField);

    correctedPanel->SetSizer(correctedSizer);
    fullGammaSizer->Add(correctedPanel);

    TPanel * correctedFPanel = new TPanel(fullGammaPanel);
    wxSizer * correctedFSizer = new wxFlexGridSizer(3,2,3,5);

    label = new wxStaticText(correctedFPanel,-1,wxT("-"));
    correctedFSizer->Add(label, 0, wxALIGN_CENTER_VERTICAL);
    this->decCorrectedRedField = new wxTextCtrl(correctedFPanel,-1, wxT("0.0"), wxDefaultPosition, wxSize(55,-1), wxTE_READONLY);
    this->decCorrectedRedField->SetMaxSize(wxSize(55,-1));
    correctedFSizer->Add(this->decCorrectedRedField);

    label = new wxStaticText(correctedFPanel,-1,wxT("-"));
    correctedFSizer->Add(label, 0, wxALIGN_CENTER_VERTICAL);
    this->decCorrectedGreenField = new wxTextCtrl(correctedFPanel,-1, wxT("0.0"), wxDefaultPosition, wxSize(55,-1), wxTE_READONLY);
    this->decCorrectedGreenField->SetMaxSize(wxSize(55,-1));
    correctedFSizer->Add(this->decCorrectedGreenField);

    label = new wxStaticText(correctedFPanel,-1,wxT("-"));
    correctedFSizer->Add(label, 0, wxALIGN_CENTER_VERTICAL);
    this->decCorrectedBlueField = new wxTextCtrl(correctedFPanel,-1, wxT("0.0"), wxDefaultPosition, wxSize(55,-1), wxTE_READONLY);
    this->decCorrectedBlueField->SetMaxSize(wxSize(55,-1));
    correctedFSizer->Add(this->decCorrectedBlueField);

    correctedFPanel->SetSizer(correctedFSizer);
    fullGammaSizer->Add(correctedFPanel);

    fullGammaSizer->AddStretchSpacer(10);

    fullGammaPanel->SetSizer(fullGammaSizer);
    rightSizer->Add(fullGammaPanel);

    rightSizer->AddStretchSpacer(10);

    wxPanel * buttonsPanel = new wxPanel(rightPanel,-1);
    wxSizer * buttonsSizer = new wxBoxSizer(wxHORIZONTAL);

    this->btnReset = new TGenButton(buttonsPanel);
    this->btnReset->setText(wxTr("Reset GC"));
    this->btnReset->SetToolTip(wxTr("Reset gamma correction to screen value"));
    this->btnReset->addButtonListener(this);
    buttonsSizer->Add(this->btnReset,0,wxLEFT|wxEXPAND,5);

    buttonsSizer->AddStretchSpacer(10);

    this->btnOk = new TGenButton(buttonsPanel);
    this->btnOk->setText(wxTr("Ok"));
    this->btnOk->addButtonListener(this);
    buttonsSizer->Add(this->btnOk,0,wxLEFT|wxEXPAND,5);

    this->btnCancel = new TGenButton(buttonsPanel);
    this->btnCancel->setText(wxTr("Cancel"));
    this->btnCancel->addButtonListener(this);
    buttonsSizer->Add(this->btnCancel,0,wxLEFT|wxEXPAND,5);

    buttonsPanel->SetSizer(buttonsSizer);
    rightSizer->Add(buttonsPanel,0,wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND,5);

    rightPanel->SetSizer(rightSizer);
    cmpsSizer->Add(rightPanel, 0, wxEXPAND);

    cmpsPanel->SetSizer(cmpsSizer);
    mainSizer->Add(cmpsPanel);

    this->SetSizerAndFit(mainSizer);

    ColorDlgRes * res = static_cast<ColorDlgRes *>(CurrentApplication()->getRessource(COLOR_DLG_RES_ID));
    if(!res)
    {
        res = new ColorDlgRes();
        CurrentApplication()->publishRessource( COLOR_DLG_RES_ID , res );
    }
    this->useGammaCorrectionChk->SetValue(res->useGammaCorrection());
    double r,g,b;
    res->getGammaCorrection(&r,&g,&b);
    this->gammaRedField->SetValue(int(r*100));
    this->gammaGreenField->SetValue(int(g*100));
    this->gammaBlueField->SetValue(int(b*100));
}

/**
 * affiche le dialogue de recherche
 * @param sInitialSearch valeur recherchée
 * @return false si annule
 */
bool ColorDlg::show(const TColor & initialColor)
{
    if(this->useGammaCorrection())
    {
        this->correctedColor = initialColor;
        this->stdColor.setRed(this->correctedColor.getRed() * this->gammaRedField->GetValue() / 100);
        this->stdColor.setGreen(this->correctedColor.getGreen() * this->gammaGreenField->GetValue() / 100);
        this->stdColor.setBlue(this->correctedColor.getBlue() * this->gammaBlueField->GetValue() / 100);
    }
    else
    {
        this->stdColor = initialColor;
    }
    return this->show();
}

/**
 * affiche le dialogue de recherche
 * @return false si annule
 */
bool ColorDlg::show()
{
    this->updateFields();
    return this->ShowModal() == wxID_OK;
}

/** click bouton */
void ColorDlg::buttonActivated(TGenButton * btn)
{
    if(btn == this->btnOk)
    {
        this->EndModal(wxID_OK);
    }
    else if(btn == this->btnCancel)
    {
        this->EndModal(wxID_CANCEL);
    }
    else
    {
        ColorDlgRes * res = static_cast<ColorDlgRes *>(CurrentApplication()->getRessource(COLOR_DLG_RES_ID));
        if(!res)
        {
            res = new ColorDlgRes();
            CurrentApplication()->publishRessource( COLOR_DLG_RES_ID , res );
        }
        res->resetGammaCorrection();

        double r,g,b;
        res->getGammaCorrection(&r,&g,&b);
        this->gammaRedField->SetValue(int(r*100));
        this->gammaGreenField->SetValue(int(g*100));
        this->gammaBlueField->SetValue(int(b*100));

        this->updateFields();
    }
}

/**
 * renvoie la couleur selectionnee
 */
TColor ColorDlg::getColor() const
{
    if(this->useGammaCorrection())
        return this->correctedColor;
    else
        return this->stdColor;
}

/**
 * indique si on doit utiliser la couleur corrigee
 */
bool ColorDlg::useGammaCorrection() const
{
    if(this->useGammaCorrectionChk)
        return this->useGammaCorrectionChk->IsChecked();
    return false;
}

/** changement d'état d'une checkbox */
void ColorDlg::checkboxClicked(wxCommandEvent& event)
{
    if(event.GetEventObject() == this->useGammaCorrectionChk)
    {
        ColorDlgRes * res = static_cast<ColorDlgRes *>(CurrentApplication()->getRessource(COLOR_DLG_RES_ID));
        if(!res)
        {
            res = new ColorDlgRes();
            CurrentApplication()->publishRessource( COLOR_DLG_RES_ID , res );
        }
        res->setUseGammaCorrection(this->useGammaCorrection());

        this->updateFields();
    }
}

/** changement de valeur d'un spinctrl */
void ColorDlg::spinctrlUpdated(wxSpinEvent& event)
{
    if(event.GetEventObject() == this->hueField)
    {
        this->stdColor.setHue(this->hueField->GetValue());
    }
    else if(event.GetEventObject() == this->saturationField)
    {
        this->stdColor.setSaturation(this->saturationField->GetValue());
    }
    else if(event.GetEventObject() == this->valueField)
    {
        this->stdColor.setValue(this->valueField->GetValue());
    }
    else if(event.GetEventObject() == this->redField)
    {
        this->stdColor.setRed(static_cast<uint>(this->redField->GetValue()));
    }
    else if(event.GetEventObject() == this->greenField)
    {
        this->stdColor.setGreen(static_cast<uint>(this->greenField->GetValue()));
    }
    else if(event.GetEventObject() == this->blueField)
    {
        this->stdColor.setBlue(static_cast<uint>(this->blueField->GetValue()));
    }

    if(this->linkGammaCorrectionChk && this->linkGammaCorrectionChk->IsChecked())
    {
        if(event.GetEventObject() == this->gammaRedField)
        {
            this->gammaGreenField->SetValue(this->gammaRedField->GetValue());
            this->gammaBlueField->SetValue(this->gammaRedField->GetValue());
        }
        else if(event.GetEventObject() == this->gammaGreenField)
        {
            this->gammaRedField->SetValue(this->gammaGreenField->GetValue());
            this->gammaBlueField->SetValue(this->gammaGreenField->GetValue());
        }
        else if(event.GetEventObject() == this->gammaBlueField)
        {
            this->gammaGreenField->SetValue(this->gammaBlueField->GetValue());
            this->gammaRedField->SetValue(this->gammaBlueField->GetValue());
        }
    }

    if(event.GetEventObject() == this->gammaRedField
       || event.GetEventObject() == this->gammaGreenField
       || event.GetEventObject() == this->gammaBlueField)
    {
        ColorDlgRes * res = static_cast<ColorDlgRes *>(CurrentApplication()->getRessource(COLOR_DLG_RES_ID));
        if(!res)
        {
            res = new ColorDlgRes();
            CurrentApplication()->publishRessource( COLOR_DLG_RES_ID , res );
        }
        res->storeGammaCorrection(this->gammaRedField->GetValue() / 100.0,
                                  this->gammaGreenField->GetValue() / 100.0,
                                  this->gammaBlueField->GetValue() / 100.0);
    }

    this->updateFields();
}

/** mets a jour les champs en fonction des couleurs stockées */
void ColorDlg::updateFields()
{
    this->linkGammaCorrectionChk->Enable(this->useGammaCorrection());
    this->gammaRedField->Enable(this->useGammaCorrection());
    this->gammaGreenField->Enable(this->useGammaCorrection());
    this->gammaBlueField->Enable(this->useGammaCorrection());
    this->correctedRedField->Enable(this->useGammaCorrection());
    this->correctedGreenField->Enable(this->useGammaCorrection());
    this->correctedBlueField->Enable(this->useGammaCorrection());
    this->decCorrectedRedField->Enable(this->useGammaCorrection());
    this->decCorrectedGreenField->Enable(this->useGammaCorrection());
    this->decCorrectedBlueField->Enable(this->useGammaCorrection());

    this->hueField->SetValue(this->stdColor.getHue());
    this->saturationField->SetValue(this->stdColor.getSaturation());
    this->valueField->SetValue(this->stdColor.getValue());
    this->valueSlider->SetValue(this->stdColor.getValue());

    this->redField->SetValue(this->stdColor.getRed());
    this->greenField->SetValue(this->stdColor.getGreen());
    this->blueField->SetValue(this->stdColor.getBlue());

    this->decRedField->SetValue(wxString::Format(wxT("%.3f"), this->stdColor.getDecimalRed()));
    this->decGreenField->SetValue(wxString::Format(wxT("%.3f"), this->stdColor.getDecimalGreen()));
    this->decBlueField->SetValue(wxString::Format(wxT("%.3f"), this->stdColor.getDecimalBlue()));

    this->stdColorLbl->SetBackgroundColour(this->stdColor.toWxColour());

    if(this->useGammaCorrection())
    {
        this->correctedColor.setRed(this->stdColor.getRed() * 100 / this->gammaRedField->GetValue());
        this->correctedColor.setGreen(this->stdColor.getGreen() * 100 / this->gammaGreenField->GetValue());
        this->correctedColor.setBlue(this->stdColor.getBlue() * 100 / this->gammaBlueField->GetValue());
    }
    else
        this->correctedColor = this->stdColor;

    this->correctedRedField->SetValue(wxString::Format(wxT("%d"), this->correctedColor.getRed()));
    this->correctedGreenField->SetValue(wxString::Format(wxT("%d"), this->correctedColor.getGreen()));
    this->correctedBlueField->SetValue(wxString::Format(wxT("%d"), this->correctedColor.getBlue()));

    this->decCorrectedRedField->SetValue(wxString::Format(wxT("%.3f"), this->correctedColor.getDecimalRed()));
    this->decCorrectedGreenField->SetValue(wxString::Format(wxT("%.3f"), this->correctedColor.getDecimalGreen()));
    this->decCorrectedBlueField->SetValue(wxString::Format(wxT("%.3f"), this->correctedColor.getDecimalBlue()));

    this->correctedColorLbl->SetBackgroundColour(this->correctedColor.toWxColour());
}

void ColorDlg::sliderMoved(wxScrollEvent& event)
{
    this->stdColor.setValue(this->valueSlider->GetValue());
    this->updateFields();
}

/** click sur la map de hue/saturation */
void ColorDlg::hueSaturationMapClicked(wxMouseEvent & event)
{
    if(event.Dragging() || event.LeftDown())
    {
        wxPoint pos = event.GetPosition();
        this->stdColor.setHue(pos.x*360/255);
        this->stdColor.setSaturation((255 - pos.y)*1000/255);
        this->updateFields();
    }
}

ColorDlgRes::ColorDlgRes()
    : bUseGammaCorrection(false), bLinkGammaCorrection(false), fGCRed(-1.0), fGCGreen(-1.0), fGCBlue(-1.0),
    bHasDefaultGC(false), fDefaultGCRed(-1.0), fDefaultGCGreen(-1.0), fDefaultGCBlue(-1.0)
{
#ifndef __WXMSW__
    wxArrayString output;
    wxArrayString errors;
    static const wxString sDECIMAL_POINT = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,wxLOCALE_CAT_NUMBER);

    long iRet = wxExecute(wxT("xgamma"), output, errors, wxEXEC_SYNC);

    if(iRet == 0 && errors.Count())
    {
        wxStringTokenizer tkz(errors[0], wxT(","));
        if(tkz.CountTokens() == 3)
        {
            wxString sR = tkz.GetNextToken();
            sR.Replace(wxT("-> Red"), wxT(""));
            sR.Replace(wxT("."),sDECIMAL_POINT);
            sR = sR.Strip(wxString::both);
            wxString sG = tkz.GetNextToken();
            sG.Replace(wxT("Green"), wxT(""));
            sG.Replace(wxT("."),sDECIMAL_POINT);
            sG = sG.Strip(wxString::both);
            wxString sB = tkz.GetNextToken();
            sB.Replace(wxT("Blue"), wxT(""));
            sB.Replace(wxT("."),sDECIMAL_POINT);
            sB = sB.Strip(wxString::both);

            if(sR.ToDouble(&this->fDefaultGCRed) && sG.ToDouble(&this->fDefaultGCGreen) && sB.ToDouble(&this->fDefaultGCBlue))
            {
                this->bHasDefaultGC = true;
                this->bUseGammaCorrection = true;
            }
        }
    }

#endif
}

/** defini la correction gamma a utiliser */
void ColorDlgRes::storeGammaCorrection(double fRed, double fGreen, double fBlue)
{
    if(this->bHasDefaultGC && fabs(fRed - this->fDefaultGCRed) < 0.01)
        this->fGCRed = -1.0;
    else
        this->fGCRed = fRed;
    if(this->bHasDefaultGC && fabs(fGreen - this->fDefaultGCGreen) < 0.01)
        this->fGCGreen = -1.0;
    else
        this->fGCGreen = fGreen;
    if(this->bHasDefaultGC && fabs(fBlue - this->fDefaultGCBlue) < 0.01)
        this->fGCBlue = -1.0;
    else
        this->fGCBlue = fBlue;
}

/** renvoie la correction gamma a utiliser */
void ColorDlgRes::getGammaCorrection(double * fRed, double * fGreen, double * fBlue)
{
    (*fRed) = this->fGCRed;
    (*fGreen) = this->fGCGreen;
    (*fBlue) = this->fGCBlue;

    if(this->bHasDefaultGC)
    {
        if((*fRed) < 0.0)
            (*fRed) = this->fDefaultGCRed;
        if((*fGreen) < 0.0)
            (*fGreen) = this->fDefaultGCGreen;
        if((*fBlue) < 0.0)
            (*fBlue) = this->fDefaultGCBlue;
    }

    if((*fRed) < 0.0)
        (*fRed) = 1.0;
    if((*fGreen) < 0.0)
        (*fGreen) = 1.0;
    if((*fBlue) < 0.0)
        (*fBlue) = 1.0;
}

#define XML_PARAM_NODE_USE_GAMMA_CORRECTION "UseGC"
#define XML_PARAM_NODE_LINK_GAMMA_CORRECTION "LinkGC"
#define XML_PARAM_NODE_GC_RED "GCRed"
#define XML_PARAM_NODE_GC_GREEN "GCGreen"
#define XML_PARAM_NODE_GC_BLUE "GCBlue"
/** charge les parametres du composant a partir des informations contenues dans le noeud passé en paramètre */
bool ColorDlgRes::loadParameters(TiXmlElement * parametersNode)
{
    if(!parametersNode)
        return false;

    TiXmlElement * elt = parametersNode->FirstChildElement( XML_PARAM_NODE_USE_GAMMA_CORRECTION );
    if(elt)
    {
        const char * szUseGC = elt->GetText();
        if(szUseGC && szUseGC[0])
        {
            this->bUseGammaCorrection = strcmp(szUseGC,"true") == 0;
        }
    }

    elt = parametersNode->FirstChildElement( XML_PARAM_NODE_LINK_GAMMA_CORRECTION );
    if(elt)
    {
        const char * szLinkGC = elt->GetText();
        if(szLinkGC && szLinkGC[0])
        {
            this->bLinkGammaCorrection = strcmp(szLinkGC,"true") == 0;
        }
    }

    elt = parametersNode->FirstChildElement( XML_PARAM_NODE_GC_RED );
    if(elt)
    {
        const char * szChannel = elt->GetText();
        if(szChannel && szChannel[0])
        {
            ISO2WX( szChannel ).ToDouble(&this->fGCRed);
        }
    }

    elt = parametersNode->FirstChildElement( XML_PARAM_NODE_GC_GREEN );
    if(elt)
    {
        const char * szChannel = elt->GetText();
        if(szChannel && szChannel[0])
        {
            ISO2WX( szChannel ).ToDouble(&this->fGCGreen);
        }
    }

    elt = parametersNode->FirstChildElement( XML_PARAM_NODE_GC_BLUE );
    if(elt)
    {
        const char * szChannel = elt->GetText();
        if(szChannel && szChannel[0])
        {
            ISO2WX( szChannel ).ToDouble(&this->fGCBlue);
        }
    }

    return true;
}

/** renvoie les parametres du composant sous la forme d'un noeud xml */
void ColorDlgRes::fillParameters(TiXmlElement * root)
{
    TiXmlElement * elt = new TiXmlElement(XML_PARAM_NODE_USE_GAMMA_CORRECTION);
    elt->LinkEndChild( new TiXmlText( this->bUseGammaCorrection ? "true" : "false" ) );
    root->LinkEndChild( elt );

    elt = new TiXmlElement(XML_PARAM_NODE_LINK_GAMMA_CORRECTION);
    elt->LinkEndChild( new TiXmlText( this->bLinkGammaCorrection ? "true" : "false" ) );
    root->LinkEndChild( elt );

    elt = new TiXmlElement(XML_PARAM_NODE_GC_RED);
    elt->LinkEndChild( new TiXmlText( (const char *)(wxString::Format(wxT("%f"),this->fGCRed).fn_str()) ) );
    root->LinkEndChild( elt );

    elt = new TiXmlElement(XML_PARAM_NODE_GC_GREEN);
    elt->LinkEndChild( new TiXmlText( (const char *)(wxString::Format(wxT("%f"),this->fGCGreen).fn_str()) ) );
    root->LinkEndChild( elt );

    elt = new TiXmlElement(XML_PARAM_NODE_GC_BLUE);
    elt->LinkEndChild( new TiXmlText( (const char *)(wxString::Format(wxT("%f"),this->fGCBlue).fn_str()) ) );
    root->LinkEndChild( elt );
}

