Mentions légales du service

Skip to content
Snippets Groups Projects
view.cpp 68.30 KiB
#include "view.h"
#include "ui_view.h"
#include "view.h"


#include "renderarea.h"
#include "pole.h"
#include "layerviewer.h"
#include "layergroup.h"
#include <QGridLayout>
#include <QApplication>
#include <QColorDialog>
#include <QFileDialog>
#include <QImageWriter>
#include <QInputDialog>
#include <QMenuBar>
#include <QSpinBox>
#include <QMessageBox>
#include <QCloseEvent>
#include <QGraphicsView>
#include <QMouseEvent>					  
#include <QDialogButtonBox>
#include <QLabel>
#include <QGroupBox>
#include <QComboBox>
#include <QToolBox>
#include <QToolBar>
#include <QButtonGroup>
#include <QToolButton>
#include <QTextEdit>
#include <QPushButton>
#include <QCheckBox>

// writing on a text file
#include <iostream>
#include <fstream>
#include <QFileInfo>					



using namespace std;

/**
 * @brief create main view
 * add cener widget, tool bar, layer bar, object bar and matrix bar and paramtric slider
 *
 * @param parent
 */
View::View(QWidget *parent)
     : QMainWindow(parent)
    , ui(new Ui::View)

{

    ui->setupUi(this);
    tabWidget = new QTabWidget;

;


    RenderArea *renderAreaVel = new RenderArea(itemMenu=nullptr, this);
    //renderAreaVel->scene()->setSceneRect(0, 0, 40., 40.);
    RenderArea *renderAreaOr = new RenderArea(itemMenu=nullptr, this);
    //renderAreaOr->scene()->setSceneRect(0, 0, 40., 40.);

    renderAreaVel->setMyItemMenu(itemMenu);
    renderAreaOr->setMyItemMenu(itemMenu);
    renderAreaVel->setType(1);
    renderAreaOr->setType(1);
    tabWidget = new QTabWidget;
    tabWidget->addTab(renderAreaVel, "Velocity");
    tabWidget->addTab(renderAreaOr, "Orientation");
    createActions();
    createMenus();
    createToolBox();
    createSliderToolBox();
    createCentralView();




    createToolbars();
    /*
    QWidget * wdg = new QWidget(this);
    QBoxLayout *hlay = new QHBoxLayout(wdg);
    QBoxLayout *vlay = new QVBoxLayout();
    vlay->addWidget(sliderToolBox);
    hlay->addWidget(toolBox);
    hlay->addLayout(vlay);
    wdg->setLayout(hlay);
    setCentralWidget(wdg);*/
    setWindowTitle(tr("InteractionFields"));
    setUnifiedTitleAndToolBarOnMac(true);




}

/**
 * @brief
 *
 */
View::~View()
{
    delete ui;
}

//! [1]
/**
 * @brief close window
 *
 * @param event
 */
void View::closeEvent(QCloseEvent *event)
//! [1] //! [2]
{
    if (maybeSave())
        event->accept();
    else
        event->ignore();
}

/**
 * @brief
 *
 * @param event
 */
void View::resizeEvent(QResizeEvent *event)
{


    QWidget::resizeEvent(event);
}
//! [2]

//! [3]
/**
 * @brief
 *
 */
void View::open()
//! [3] //! [4]
{
    if (maybeSave()) {
        QString initialPath = "C:/Users/acolas/Documents/Present/UMANS/examples/interactionFields/matrix/";



        const QString fileName = QFileDialog::getOpenFileName(this,
                                   tr("Open File"),initialPath);

        if (!fileName.isEmpty()){

            static_cast<RenderArea *>(tabWidget->currentWidget())->loadField(fileName);
        }

    }
}

void View::save(bool isExpended){
    saveFile("txt", isExpended);
}

/**
 * @brief save the current field as a grid, recommanded for the 2D simulation. The magnitude of the vectors can be colored according to the speed of the impacted object object and the interpolation is realized beforehand.
 *
 * @param isExpended
 */
void View::saveAsGrid(bool isExpended)
{
    isContinuus= false;
    saveFile("txt", isExpended);
}
//! [4]
/**
 * @brief save the current field as a list of guidelines, recommanded for the VR on Unity. The magnitude of the vectors cannot be colored according to the speed (will be computed during interpolation) of the impacted object object and the interpolation is at runtine.
 *
 * @param isExpended
 */
void View::saveAsCurves(bool isExpended)
{
    isContinuus= true;
    saveFile("txt", isExpended);
}
//! [4]
//! [7]
/**
 * @brief
 *
 */
void View::penColor()
//! [7] //! [8]
{
 QColor newColor = QColorDialog::getColor(static_cast<RenderArea *>(tabWidget->currentWidget())->penColor());
    if (newColor.isValid())
        static_cast<RenderArea *>(tabWidget->currentWidget())->setPenColor(newColor);
}
//! [8]

//! [9]
/**
 * @brief
 *
 */
void View::penWidth()
//! [9] //! [10]
{
    bool ok;
    int newWidth = QInputDialog::getInt(this, tr("Brush Width"),
                                        tr("Select brush width:"),
                                        static_cast<RenderArea *>(tabWidget->currentWidget())->penWidth(),
                                        1, 100, 1, &ok);

    if (ok)

        static_cast<RenderArea *>(tabWidget->currentWidget())->setPenWidth(newWidth);

}


/**
 * @brief create the central widget the velocity and orientation render Area + gui widget
 *
 */
void View::createCentralView()
{
//    this->setContextMenuPolicy(Qt::CustomContextMenu);
//    connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
//        this, SLOT(ShowContextMenu(const QPoint&)));
    /*
    ui->graphicsView->setScene(renderArea);


//    ui->graphicsView->setSceneRect(0,0 , 500, 500);
    ui->graphicsView->fitInView(0, 0, 500,500, Qt::KeepAspectRatio);
    ui->graphicsView->setSceneRect(0,0 , 500, 500);
    ui->graphicsView->setFixedSize(500,500);
    ui->graphicsView->scale(1,-1);
    */
    //ui->graphicsView->setFixedSize(500+2*ui->graphicsView->frameWidth(),500+2*ui->graphicsView->frameWidth());
    /*
    ui->id->setPlaceholderText("source id");
    ui->id->setValidator(new QIntValidator(0, 100, this) );
    ui->agentRadButt->setChecked(true);*/


    //view = new QGraphicsView(renderArea);
    /*

    QPushButton *saveButt = new QPushButton("Save");
    hlay->addWidget(saveButt);
    */
    QWidget * wdg = new QWidget(this);
    QBoxLayout *hrenderUp = new QHBoxLayout();
    QBoxLayout *hlay = new QHBoxLayout(wdg);
    QBoxLayout *vlay = new QVBoxLayout();
    vlay->addLayout(hrenderUp);
    vlay->addWidget(tabWidget);
    scaleLabel = new QLabel(this);
    scaleLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);

    scaleLabel->setText(QString::number(static_cast<RenderArea *>(tabWidget->currentWidget())->sceneRect().height()) + "m x " + QString::number(static_cast<RenderArea *>(tabWidget->currentWidget())->sceneRect().width()) + "m");
    scaleLabel->setAlignment(Qt::AlignBottom | Qt::AlignRight);
    //Here is how to change position:
    vlay->addWidget(scaleLabel);

    QFont font2 = scaleLabel->font();
    font2. setPointSize(14);

    scaleLabel->setFont(font2);
    vlay->addWidget(sliderToolBox);
    hlay->addWidget(toolBox);
    hlay->addLayout(vlay);
    wdg->setLayout(hlay);

    setCentralWidget(wdg);
    wdg->update();
    setWindowTitle(tr("InteractionFields"));






}

//! [11]
/**
 * @brief change the scale of the view (central widget)
 *
 * @param scale
 */
void View::sceneScaleChanged(const QString &scale)
{
    double newScale = scale.left(scale.indexOf(tr("%"))).toDouble() / 100.0;
    QMatrix oldMatrix = view->matrix();
    view->resetMatrix();
    view->translate(oldMatrix.dx(), oldMatrix.dy());
    view->scale(newScale, newScale);
}




//! [1]
/**
 * @brief activated when one button of the layer group is clicked
 *
 * select the group layer according to id and make it the current grouplayer
 * @param id id of layer
 */
void View::layerButtonGroupClicked(int id)
{
	const QList<QAbstractButton *> buttons = layerButtonGroup->buttons();
    for (QAbstractButton *button : buttons) {
        if (layerButtonGroup->button(id) != button){
            layerButtonGroup->setExclusive(false);
            button->setChecked(false);
            layerButtonGroup->setExclusive(true);
         }
    }

    //QString text = button->text();

        static_cast<RenderArea *>(tabWidget->currentWidget())->setLayerID(id);
        static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->setSelected(true);
        static_cast<RenderArea *>(tabWidget->currentWidget())->update();


}

/**
 * @brief activated when one of the matrix button is cliked
 * activate horizontal, vertical or angular symetry
 * @param id: id of the symetry
 */
void View::matrixButtonGroupClicked(int id)
{
    const QList<QAbstractButton *> buttons = buttonGroup->buttons();
    for (QAbstractButton *button : buttons) {
        if (matrixButtonGroup->button(id) != button)
            button->setChecked(false);
    }

    if(id ==0){
        static_cast<RenderArea *>(tabWidget->currentWidget())->verticalSymetry();
    }
    else if(id ==1){
        static_cast<RenderArea *>(tabWidget->currentWidget())->horizontalSymetry();
    }
    else{
        angularSymetry();
    }
    return;
}
//! [1]

//! [2]
/**
 * @brief activated when one of the object group is clicked
 * obstalce or agent pole is selected to be added to the scene
 * @param id id of the type of the pole
 */
void View::buttonGroupClicked(int id)
{
    const QList<QAbstractButton *> buttons = buttonGroup->buttons();
    for (QAbstractButton *button : buttons) {
        if (buttonGroup->button(id) != button)
            button->setChecked(false);
    }
        static_cast<RenderArea *>(tabWidget->currentWidget())->setItemType(Pole::Pole_Type(id));
        static_cast<RenderArea *>(tabWidget->currentWidget())->setMode(RenderArea::InsertItem);

}
//! [2]

/**
 * @brief activated when one of the link group is clicked
 * for now only the rotation link is working
 * @param id of the type of link
 */
void View::buttonGroupLinkClicked(int id)
{
//    const QList<QAbstractButton*> buttonsPointer = pointerTypeGroup->buttons();
//    buttonsPointer.back()->setChecked(true);

    const QList<QAbstractButton*> buttons = linkTypeGroup->buttons();

    static_cast<RenderArea *>(tabWidget->currentWidget())->setMode(RenderArea::Mode(linkTypeGroup->checkedId()));
    QAbstractButton *checked = pointerTypeGroup->checkedButton();
    if(checked){
        pointerTypeGroup->setExclusive(false);
        checked->setChecked(false);
        pointerTypeGroup->setExclusive(true);
    }
    /*
    for (QAbstractButton *button : buttons) {
        if (buttonGroup->button(id) != button)
            button->setChecked(false);
    }*/

        static_cast<RenderArea *>(tabWidget->currentWidget())->setLinkType(Link::LinkType(id));
    static_cast<RenderArea *>(tabWidget->currentWidget())->setMode(RenderArea::InsertLink);
}

/**
 * @brief activated when one of the erase blank area button is clicked
 * erase the blank area of the current layer group
 * @param id id of the current layer group
 */
void View::blankButtonGroupClicked(size_t id)
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->getCurrentLayer()->removeZeroArea();
    static_cast<RenderArea *>(tabWidget->currentWidget())->drawMatrix();
}

/**
 * @brief activated when the hideVector group is clicked
 * hide or show the control vectors of the current layer
 */
void View::hideButtonGroupClicked()
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->showVector();
}

/**
 * @brief clear the current group layer
 *
 */
void View::clearButtonGroupClicked()
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->clearImage();
}

//! [3]
/**
 * @brief delete the selected item
 * items can be: poles, curves, lines or links
 */
void View::deleteItem()
{
    QList<QGraphicsItem *> selectedItems = static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems();
    for (QGraphicsItem *item : qAsConst(selectedItems)) {
        if (item->type() == Link::Type) {
            static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->removeItem(item);
            Link *link = qgraphicsitem_cast<Link *>(item);
            link->startItem()->removeLink(link);
            link->endItem()->removeLink(link);
            delete item;
        }
        /*
         else if(item->type()== VectorLine::Type){
            static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->removeItem(item);
            VectorLine *line = qgraphicsitem_cast<VectorLine *>(item);
            static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->removeVectorLine(line);
            delete item;

        }*/
        else if (item->type() == VectorCurve::Type){
            static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->removeItem(item);
            VectorCurve *curve = qgraphicsitem_cast<VectorCurve *>(item);

             static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->removeVectorCurve(curve);

            //QList<VectorCurve *> vect = static_cast<RenderArea *>(tabWidget->currentWidget())->getVectCurves();

            delete item;
            //static_cast<RenderArea *>(tabWidget->currentWidget())->generate();to update the matrix each time we add an item
        }

    }


    selectedItems = static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems();
    for (QGraphicsItem *item : qAsConst(selectedItems)) {
         if (item->type() == Pole::Type)
             //static_cast<RenderArea *>(tabWidget->currentWidget())->getPoles().remove((qgraphicsitem_cast<Pole *>(item)->scenePos()));
             qgraphicsitem_cast<Pole *>(item)->removeLinks();
         static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->removeItem(item);
         delete item;
     }
    selectedItems = static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems();

}
//! [3]

//! [3]
/**
 * @brief make or unmake the selected pole the source of the field
 *
 */
void View::makeSource()
{
    QList<QGraphicsItem *> selectedItems = static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems();

     if (selectedItems.size()==1){
         QGraphicsItem *item = selectedItems[0];
         if (item->type() == Pole::Type){
             sourceAction->setEnabled(true);

             if (qgraphicsitem_cast<Pole *>(item)->getIsSource()){
                 qgraphicsitem_cast<Pole *>(item)->setIsSource(false);
                 qgraphicsitem_cast<Pole *>(item)->setBrush(QColor(255, 180, 0));
             }
             else{
                 for (QGraphicsItem *itembis : static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->items()){
                     if(itembis->type() == Pole::Type){
                          if (qgraphicsitem_cast<Pole *>(itembis)->getIsSource()){
                              qgraphicsitem_cast<Pole *>(itembis)->setIsSource(false);
                               qgraphicsitem_cast<Pole *>(itembis)->setBrush(QColor(255, 180, 0));
                          }
                     }
                    }
                     qgraphicsitem_cast<Pole *>(item)->setIsSource(true);
                     qgraphicsitem_cast<Pole *>(item)->setBrush(QColor(220, 14, 21));


             }

        }
         else{
             sourceAction->setEnabled(false);
         }

    }
     else{
         //sourceAction->setEnabled(false);
     }

}

/**
 * @brief show or hide the current layer
 *
 * @param id id of the layergroup
 */
void View::showLayer(size_t id)
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->hideLayer();
}

/**
 * @brief show or hide the control vector of a layergroup
 *
 * @param id of the layergroup
 */
void View::showVector(size_t id)
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->hideVectors();
}

/**
 * @brief show or hide the grid of a layer group
 *
 * @param id of the layer group
 */
void View::showGrid(size_t id)
{
    bool isGrid= !static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->getIsGridVisible();
    static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->setIsGridVisible(isGrid);
    static_cast<RenderArea *>(tabWidget->currentWidget())->drawMatrix();

}
/**
 * @brief make possible or not to move a layer group
 *
 * @param id of the layer group
 */
void View::moveLayer(size_t id)
{
    if( static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->flags()& static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->ItemIsMovable)
          static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->setFlag(QGraphicsItem::ItemIsMovable, false);
    else{
         static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->setFlag(QGraphicsItem::ItemIsMovable, true);
    }
    static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->update();
}
//! [3]

//! [4]
/**
 * @brief activate when one button of the pointer group is clicked
 *
 * @param int id of the pointer selected
 */
void View::pointerGroupClicked(int)
{

    static_cast<RenderArea *>(tabWidget->currentWidget())->setMode(RenderArea::Mode(pointerTypeGroup->checkedId()));
    QAbstractButton *checked = linkTypeGroup->checkedButton();
    if(checked){
        linkTypeGroup->setExclusive(false);
        checked->setChecked(false);
        linkTypeGroup->setExclusive(true);
    }

//    const QList<QAbstractButton*> buttons = linkTypeGroup->buttons();
//    buttons.back()->setChecked(true);



}
//! [4]

//! [5]
/**
 * @brief put the slected layer up front
 *
 */
void View::bringToFront()
{
    if (static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems().isEmpty())
        return;

    QGraphicsItem *selectedItem = static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems().first();
    const QList<QGraphicsItem *> overlapItems = selectedItem->collidingItems();

    qreal zValue = 0;
    for (const QGraphicsItem *item : overlapItems) {
        if (item->zValue() >= zValue && item->type() == Pole::Type)
            zValue = item->zValue() + 0.1;
    }
    selectedItem->setZValue(zValue);
}
//! [5]

//! [6]
/**
 * @brief put the selected layer behind all the others
 *
 */
void View::sendToBack()
{
    if (static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems().isEmpty())
        return;

    QGraphicsItem *selectedItem = static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems().first();
    const QList<QGraphicsItem *> overlapItems = selectedItem->collidingItems();

    qreal zValue = 0;
    for (const QGraphicsItem *item : overlapItems) {
        if (item->zValue() <= zValue && item->type() == Pole::Type)
            zValue = item->zValue() - 0.1;
    }
    selectedItem->setZValue(zValue);
}
//! [6]

//! [7]
/**
 * @brief
 *
 * @param item
 */
void View::itemInserted(Pole *item)
{
    pointerTypeGroup->button(int(RenderArea::MoveItem))->setChecked(true);
    static_cast<RenderArea *>(tabWidget->currentWidget())->setMode(RenderArea::Mode(pointerTypeGroup->checkedId()));
    buttonGroup->button(int(item->PoleType()))->setChecked(false);
}
//! [7]



//! [28]
/**
 * @brief create a new layergroup buttons with its menu
 *
 * @param text name of the layergroup
 * @param height height of the layergroup
 * @param width width of the layergroup
 * @param weight weight of the layer group (for later combination)
 * @param id id of the layer
 * @param render if the layer is in the orientation or the velocity renderarea
 * @return QWidget return the Widget of the layer to be added to the menu
 */
QWidget *View::createLayerCellWidget(const QString &text, const double height, const double width, const double weight,size_t id, RenderArea *render)
{
    QToolButton *button = new QToolButton;
    QVBoxLayout *cellLayout = new QVBoxLayout();

    //option for each layer: hide, move, hide vectors, delete, resize
    QHBoxLayout *optionLayer = new QHBoxLayout();
    QToolButton *grid = new QToolButton();
    grid->setCheckable(true);
    grid->setIcon(QIcon("..\\images\\background2.png"));
    grid->setToolTip("drow the grid of the field or not");
    grid->setChecked(true);
    connect(grid, &QToolButton::released, this, [=] (){
        showGrid(id);
    });
    QToolButton *hide = new QToolButton();// show or hide the layer
    hide->setCheckable(true);
    hide->setIcon(QIcon("..\\images\\hide.png"));
    hide->setAutoExclusive(false);
    hide->setToolTip("hide the layer");
    connect(hide, &QToolButton::released, this, [=] (){
        showLayer(id);
    });
    QToolButton *hideVector = new QToolButton();// show or hide the layer
    hideVector->setCheckable(true);
    hideVector->setIcon(QIcon("..\\images\\hideVector.png"));
    hideVector->setAutoExclusive(false);
    hideVector->setToolTip("hide the control curves only");
    connect(hideVector, &QToolButton::released, this, [=] (){
        showVector(id);
    });
    QPushButton *blanck = new QPushButton(); // reset the blanck area to none
    blanck->setIcon(QIcon("..\\images\\eraserNull.png"));
    blanck->setToolTip("delete the erased area");
    connect(blanck, &QPushButton::released, this, [=] (){
        blankButtonGroupClicked(id);
    });

    QToolButton *move = new QToolButton();//unlocked the layer that can be moved around

    move->setCheckable(true);
    move->setIcon(QIcon("..\\images\\move.png"));
    move->setAutoExclusive(false);
    move->setToolTip("unlock the layer and make it movable");
    connect(move, &QToolButton::released, this, [=] (){
       moveLayer(id);
    });
    QPushButton *clear = new QPushButton();
    clear->setIcon(QIcon("..\\images\\clear.png"));
    clear->setToolTip("clear the layer");
    connect(clear, &QToolButton::released, this, [=] (){
        static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->clear();
        static_cast<RenderArea *>(tabWidget->currentWidget())->setLayerID(id);
        //static_cast<RenderArea *>(tabWidget->currentWidget())->generate();to update the matrix each time we add an item

    });
    QPushButton *resize = new QPushButton();
    resize->setIcon(QIcon("..\\images\\resize.png"));
    connect(resize, &QPushButton::released, this, [=] (){
       matrixSize(id);
    });
    QPushButton *delLayer = new QPushButton(); //delete the layer
    delLayer->setIcon(QIcon("..\\images\\delete.png"));
    delLayer->setToolTip("delete the layer");

    optionLayer->addWidget(blanck);
    optionLayer->addWidget(hide);
    optionLayer->addWidget(hideVector);
    optionLayer->addWidget(move);
    optionLayer->addWidget(resize);
    optionLayer->addWidget(grid);
    optionLayer->addWidget(clear);
    optionLayer->addWidget(delLayer);



    button->setText(text);
    LayerGroup *layer = new LayerGroup(text, weight, id);
    LayerViewer *lv = new LayerViewer(width, height);
    lv->setBorder(QRectF((float(render->width())/2.f- float(width)/2.f),(float(render->height())/2.f+float(height)), width, height));
    layer->addInteractionFields(0.f,lv );

    layer->setParameter(0.0f);
    render->setLayerID(id);
    render->addLayer(layer);


   //button->setIcon(QIcon(image));
    button->setIconSize(QSize(50, 50));
    button->setCheckable(true);
    layerButtonGroup->addButton(button);
    layerButtonGroup->setId(button, id);

    QVBoxLayout *layout = new QVBoxLayout;

    layout->addWidget(button, Qt::AlignHCenter);
    layout->addWidget(new QLabel(text+ " weight: "+ QString::number(weight)), Qt::AlignHCenter);
    cellLayout->addLayout(layout);
    cellLayout->addLayout(optionLayer);

    QWidget *widget = new QWidget;
    widget->setLayout(cellLayout);

    return widget;
}
//! [28]

//! [29]
/**
 * @brief create the pole buttons
 *
 * @param text name of the pole
 * @param type type of the pole
 * @return QWidget return the widget menu
 */
QWidget *View::createCellWidget(const QString &text, Pole::Pole_Type type)
{

    Pole item(type, itemMenu, false);
    QPixmap p = item.image().scaled(500,500);
    QIcon icon(p);

    QToolButton *button = new QToolButton;
    button->setIcon(icon);

    button->setIconSize(QSize(50, 50));
    button->setCheckable(true);
    buttonGroup->addButton(button, int(type));

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(button, 0, 0, Qt::AlignHCenter);
    layout->addWidget(new QLabel(text), 1, 0, Qt::AlignCenter);

    QWidget *widget = new QWidget;
    widget->setLayout(layout);

    return widget;
}
//! [29]
/**
 * @brief create the matrix buttons of the symetrical options
 *
 * @param id id of the option
 * @return QWidget return the widget
 */
QWidget *View::createMatrixCellWidget(int id )
{
    QToolButton *button = new QToolButton;
    QIcon icon;
    QString text;
    if(id ==0){
       icon.addFile("..\\images\\symetryVerticale.png");
        text = "Vertical Symetry";
    }
    else if (id ==1){
        icon.addFile("..\\images\\symetryHorizontal.png");
        text = "Horizontal Symetry";
    }
    else{
        icon.addFile("..\\images\\symetryAngular.png");
        text = "Angular Symetry";


    }


    button->setIcon(icon);

    button->setIconSize(QSize(50, 50));
    button->setCheckable(false);
    matrixButtonGroup->addButton(button);
    matrixButtonGroup->setId(button,id);
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(button, 0, 0, Qt::AlignHCenter);
    layout->addWidget(new QLabel(text), 1, 0, Qt::AlignCenter);
    layout->setRowStretch(20, 20);
    QWidget *widget = new QWidget;
    widget->setLayout(layout);

    return widget;
}

/**
 * @brief pop up to ask for the angle of the angular symetry
 *
 */
void View::angularSymetry(){
    QDialog * d = new QDialog();
    QVBoxLayout * vbox = new QVBoxLayout();

    QLabel *angularText = new QLabel();
    angularText->setText("Select Angle Symetry:");

    QDoubleSpinBox* angle = new QDoubleSpinBox();
    angle->setMinimum(0);
    angle->setMaximum(360);
    vbox->addWidget(angularText);
    vbox->addWidget(angle);



    QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
    | QDialogButtonBox::Cancel);
    QObject::connect(buttonBox, SIGNAL(accepted()), d, SLOT(accept()));
    QObject::connect(buttonBox, SIGNAL(rejected()), d, SLOT(reject()));
    vbox->addWidget(buttonBox);
    d->setLayout(vbox);
    int result = d->exec();

    if(result == QDialog::Accepted)
        static_cast<RenderArea *>(tabWidget->currentWidget())->angularSymetry(angle->value());

}
/**
 * @brief tool box with the matrix, pole and layer menus
 *
 */
void View::createToolBox()
{
    buttonGroup = new QButtonGroup(this);
    buttonGroup->setExclusive(false);
    connect(buttonGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
            this, &View::buttonGroupClicked);
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(createCellWidget(tr("Agent"), Pole::Agent), 0, 0);
    layout->addWidget(createCellWidget(tr("Obstacle"), Pole::Obstacle_square),0, 1);

//! [21]
/*
    QToolButton *textButton = new QToolButton;
    textButton->setCheckable(true);
    textButton->setIcon(QIcon(QPixmap("..\\images\\textpointer.png")));
    textButton->setIconSize(QSize(50, 50));
    QGridLayout *textLayout = new QGridLayout;
    textLayout->addWidget(textButton, 0, 0, Qt::AlignHCenter);
    textLayout->addWidget(new QLabel(tr("Text")), 1, 0, Qt::AlignCenter);
    QWidget *textWidget = new QWidget;
    textWidget->setLayout(textLayout);
    layout->addWidget(textWidget, 1, 1);
*/

    layout->setRowStretch(3, 10);
    layout->setColumnStretch(2, 10);

    QWidget *itemWidget = new QWidget;
    itemWidget->setLayout(layout);



    layerButtonGroup = new QButtonGroup(this);

    connect(layerButtonGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
            this, &View::layerButtonGroupClicked);


    layerButtonGroup->setExclusive(true);
    QVBoxLayout *layerLayout = new QVBoxLayout();
    QPushButton *newLayer = new QPushButton();
    newLayer->setIcon(QIcon("..\\images\\newLayer.png"));
    connect(newLayer, &QPushButton::released,this, &View::addLayer);

    //layerLayout->addWidget(matrixButt);
    layerLayout->addWidget(newLayer, Qt::AlignRight);
    layerLayout->addWidget(createLayerCellWidget("Fond", 20., 20.,0.5, idGroup, static_cast<RenderArea *>(tabWidget->widget(0))));
    layerLayout->addWidget(createLayerCellWidget("Fond", 20., 20., 0.5,idGroup, static_cast<RenderArea *>(tabWidget->widget(1))));

    layerWidget = new QWidget;
    layerWidget->setLayout(layerLayout);

    matrixButtonGroup = new QButtonGroup(this);
    matrixButtonGroup->setExclusive(false);
    connect(matrixButtonGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
            this, &View::matrixButtonGroupClicked);
    QPushButton *matrixButt = new QPushButton("&Generate", this);
    connect(matrixButt, &QPushButton::released, this, &View::on_pushButtonMatrix_clicked);
    QVBoxLayout *matrixLayout = new QVBoxLayout;


    matrixLayout->addWidget(matrixButt);
    matrixLayout->addWidget(createMatrixCellWidget(0));
    matrixLayout->addWidget(createMatrixCellWidget(1));
    matrixLayout->addWidget(createMatrixCellWidget(2));
    QWidget *matrixWidget = new QWidget();
    matrixWidget->setLayout(matrixLayout);





//! [22]
    toolBox = new QToolBox;

    toolBox->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Ignored));

    toolBox->setMinimumWidth(itemWidget->sizeHint().width());
    toolBox->addItem(matrixWidget, tr("Matrix"));
    toolBox->addItem(itemWidget, tr("Object"));
    toolBox->addItem(layerWidget, tr("Layers"));


}

/**
 * @brief create the slider tool box
 * the slider allows to create parametric field and to check its value for different paramter
 */
void View::createSliderToolBox()
{

    QPushButton *addKeyFrame = new QPushButton("add or remove key Frame");
    connect(addKeyFrame, &QPushButton::clicked , this, &View::on_paramButton_clilcked);
    interpolationSlider = new QSlider();

    /*
    keyFrameLayout->setContentsMargins(0, 0, 0, 0);
    keyFrameLayout->setSpacing(0);
    keyFrameLayout->addWidget(interpolationSlider);
    */

    interpolationSlider->setOrientation(Qt::Horizontal);
    interpolationSlider->setTickPosition(QSlider::TicksAbove);
    interpolationSlider->setTickInterval(1);
    interpolationSlider->setMinimum(0);
    interpolationSlider->setMaximum(100);

    keyFrameWidget = new QStackedWidget();

    connect(interpolationSlider, &QSlider::valueChanged, this, &View::sliderValueChange);
    //interpolationSlider->setRange(0,10);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(addKeyFrame);
    layout->addWidget(interpolationSlider);
    layout->addWidget(keyFrameWidget);




    QWidget *sliderWidget = new QWidget;
    sliderWidget->setLayout(layout);

    sliderToolBox = new QToolBox;

    sliderToolBox->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum));

    sliderToolBox->setMinimumHeight(sliderWidget->sizeHint().height());
    sliderToolBox->addItem(sliderWidget, tr("Slider"));




}

/**
 * @brief create all the tools bars
 *  the pointer tool bar (eraser, brush, arrow), the link toolbar, the pole option tool bar (source)
 *
 */
void View::createToolbars()
{
//! [25]
    editToolBar = addToolBar(tr("Edit"));
    editToolBar->addAction(deleteAction);
    editToolBar->addAction(toFrontAction);
    editToolBar->addAction(sendBackAction);
    editToolBar->addAction(sourceAction);



//! [26]
    QToolButton *pointerButton = new QToolButton();
    pointerButton->setCheckable(true);
    pointerButton->setChecked(true);
    pointerButton->setIcon(QIcon("..\\images\\pointer.png"));
    pointerButton->setAutoExclusive(true);

    QToolButton *eraserButton = new QToolButton();
    eraserButton->setCheckable(true);
    eraserButton->setIcon(QIcon("..\\images\\eraser.png"));
    eraserButton->setMenu(eraserMenu);
    eraserButton->setPopupMode(QToolButton::MenuButtonPopup);
    eraserButton->setAutoExclusive(true);

    QToolButton *brushButton = new QToolButton();
    brushButton->setCheckable(true);
    brushButton->setIcon(QIcon("..\\images\\brushcolor.png"));
    brushButton->setAutoExclusive(true);
    brushButton->setMenu(brushMenu);
    brushButton->setPopupMode(QToolButton::MenuButtonPopup);

    QToolButton *lineVectorButton = new QToolButton;
    lineVectorButton->setCheckable(true);
    lineVectorButton->setIcon(QIcon("..\\images\\lineVector.png"));
    lineVectorButton->setAutoExclusive(true);

    QToolButton *curveVectorButton = new QToolButton;
    curveVectorButton->setCheckable(true);
    curveVectorButton->setIcon(QIcon("..\\images\\curveVector.png"));
    curveVectorButton->setAutoExclusive(true);

    QToolButton *linkRotationButton = new QToolButton();
    linkRotationButton->setCheckable(true);
    linkRotationButton->setIcon(QIcon("..\\images\\linkRotation.png"));
    linkRotationButton->setAutoExclusive(true);

    QToolButton *linkScalingButton = new QToolButton();
    linkScalingButton->setCheckable(true);
    linkScalingButton->setIcon(QIcon("..\\images\\linkScaling.png"));
    linkScalingButton->setAutoExclusive(true);

    QToolButton *linkTranslationButton = new QToolButton();
    linkTranslationButton->setCheckable(true);
    linkTranslationButton->setIcon(QIcon("..\\images\\linkTranslation.png"));
    linkTranslationButton->setAutoExclusive(true);


    pointerTypeGroup = new QButtonGroup(this);
   //hidden button to get the group button of the pointerunchecked when the link group is check and vis versa

    pointerTypeGroup->addButton(pointerButton, int(RenderArea::MoveItem));
    pointerTypeGroup->addButton(eraserButton, int(RenderArea::EraseItem));
    pointerTypeGroup->addButton(brushButton, int(RenderArea::ColorBrush));
    pointerTypeGroup->addButton(lineVectorButton, int(RenderArea::InsertLine));
    pointerTypeGroup->addButton(curveVectorButton, int(RenderArea::InsertCurve));

    connect(pointerTypeGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
            this, &View::pointerGroupClicked);

    linkTypeGroup = new QButtonGroup(this);
    linkTypeGroup->addButton(linkRotationButton, int(Link::Rotation));
    linkTypeGroup->addButton(linkScalingButton, int(Link::Scaling));
    linkTypeGroup->addButton(linkTranslationButton, int(Link::Translation));

    connect(linkTypeGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
            this, &View::buttonGroupLinkClicked);

    pointerToolbar = addToolBar(tr("Pointer type"));
    pointerToolbar->addWidget(pointerButton);
    pointerToolbar->addWidget(eraserButton);
    pointerToolbar->addWidget(brushButton);
    pointerToolbar->addSeparator();
    pointerToolbar->addWidget(lineVectorButton);
    pointerToolbar->addWidget(curveVectorButton);
    pointerToolbar->addSeparator();
    pointerToolbar->addWidget(linkRotationButton);
    pointerToolbar->addWidget(linkScalingButton);
    pointerToolbar->addWidget(linkTranslationButton);
    //! [27]
}

/**
 * @brief create the layer tool bar: all the grouplayer are listed in one menu
 *
 */
void View::createLayerbars()
{


    layerButtonGroup = new QButtonGroup(this);
    connect(layerButtonGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
            this, &View::layerButtonGroupClicked);
    layerButtonGroup->setExclusive(true);
    QHBoxLayout *layerLayout = new QHBoxLayout();
    //layerLayout->addWidget(matrixButt);


    QWidget *backgroundWidget = new QWidget;
    backgroundWidget->setLayout(layerLayout);


//! [22]
    layerToolbar = new QToolBar();
    layerToolbar->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Ignored));
    layerToolbar->addWidget(backgroundWidget);
}
//! [27]

/**
 * @brief pop up to change the grouplayer current viewer matrix's size and resolution
 *
 * @param id of the grouplayer
 */
void View::matrixSize(size_t id)
{
    QDialog * d = new QDialog();
    QVBoxLayout * vbox = new QVBoxLayout();
    QHBoxLayout *hboxHeight = new QHBoxLayout();
    QLabel *height = new QLabel();
    height->setText("Number of rows");
    QSpinBox * matrixHeight = new QSpinBox();

    matrixHeight->setMinimum(1);
    matrixHeight->setValue(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->getCurrentLayer()->getMatrix()->getRows());
    hboxHeight->addWidget(height);
    hboxHeight->addWidget(matrixHeight);
    QDoubleSpinBox* rectangleHeight = new QDoubleSpinBox();
    QLabel *rectangleHeightText = new QLabel("Layer height in meter: ");

    rectangleHeight->setMinimum(1);
    rectangleHeight->setMaximum(100);


    rectangleHeight->setValue(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[id]->getCurrentLayer()->getBorder().height());
    hboxHeight->addWidget(rectangleHeightText);
    hboxHeight->addWidget(rectangleHeight);



    QHBoxLayout *hboxWidth = new QHBoxLayout();
    QLabel *width = new QLabel();
    width->setText("Number of columns");
    QSpinBox* matrixWidth = new QSpinBox();


    matrixWidth->setMinimum(1);
    matrixWidth->setValue(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->getMatrix()->getCols());

    QDoubleSpinBox * rectangleWidth = new QDoubleSpinBox();
    QLabel *rectangleWidthText = new QLabel("Layer width in meter: ");

    rectangleWidth->setMinimum(1);
    rectangleWidth->setMaximum(100);

    rectangleWidth->setValue(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->getBorder().width());


    hboxWidth->addWidget(width);
    hboxWidth->addWidget(matrixWidth);
    hboxWidth->addWidget(rectangleWidthText);
    hboxWidth->addWidget(rectangleWidth);

    QGroupBox *horizontalGroupBoxH = new QGroupBox(tr("Height"));
    horizontalGroupBoxH->setLayout(hboxHeight);
    QGroupBox *horizontalGroupBoxW = new QGroupBox(tr("Width"));
    horizontalGroupBoxW->setLayout(hboxWidth);
    QLabel *title = new QLabel();
    title->setText("Change matrix size:");

    QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
    | QDialogButtonBox::Cancel);
    QObject::connect(buttonBox, SIGNAL(accepted()), d, SLOT(accept()));
    QObject::connect(buttonBox, SIGNAL(rejected()), d, SLOT(reject()));
    vbox->addWidget(title);
    vbox->addWidget(horizontalGroupBoxH);
    vbox->addWidget(horizontalGroupBoxW);
    vbox->addWidget(buttonBox);
    d->setLayout(vbox);
    int result = d->exec();

    if(result == QDialog::Accepted)
    {
    // handle values from d
    qDebug() << "The user clicked:"
    << "matrix height" << matrixHeight->value()
    << "matrix width" << matrixWidth->value();
     static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->setMatrixSize(matrixHeight->value(), matrixWidth->value());
     static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->setBorder(QRectF( static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->getBorder().center()-QPointF(rectangleWidth->value()/2., rectangleHeight->value()/2.),QSizeF(rectangleWidth->value(), rectangleHeight->value())));
     static_cast<RenderArea *>(tabWidget->currentWidget())->drawMatrix();
    }
}

/**
 * @brief pop up to change th size of the scene i.e of the render area
 *
 */
void View::sceneSize()
{
    QDialog * d = new QDialog();
    QVBoxLayout * vbox = new QVBoxLayout();
    QHBoxLayout *hboxHeight = new QHBoxLayout();
    QDoubleSpinBox* rectangleHeight = new QDoubleSpinBox();
    QLabel *rectangleHeightText = new QLabel("Scene height in meter: ");

    rectangleHeight->setMinimum(1);
    rectangleHeight->setMaximum(100);


    rectangleHeight->setValue(static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->sceneRect().height());
    hboxHeight->addWidget(rectangleHeightText);
    hboxHeight->addWidget(rectangleHeight);



    QHBoxLayout *hboxWidth = new QHBoxLayout();


    QDoubleSpinBox * rectangleWidth = new QDoubleSpinBox();
    QLabel *rectangleWidthText = new QLabel("Scene width in meter: ");

    rectangleWidth->setMinimum(1);
    rectangleWidth->setMaximum(100);

    rectangleWidth->setValue(static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->sceneRect().width());
    hboxWidth->addWidget(rectangleWidthText);
    hboxWidth->addWidget(rectangleWidth);

    QGroupBox *horizontalGroupBoxH = new QGroupBox(tr("Height"));
    horizontalGroupBoxH->setLayout(hboxHeight);
    QGroupBox *horizontalGroupBoxW = new QGroupBox(tr("Width"));
    horizontalGroupBoxW->setLayout(hboxWidth);
    QLabel *title = new QLabel();
    title->setText("Change Scene size:");

    QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
    | QDialogButtonBox::Cancel);
    QObject::connect(buttonBox, SIGNAL(accepted()), d, SLOT(accept()));
    QObject::connect(buttonBox, SIGNAL(rejected()), d, SLOT(reject()));
    vbox->addWidget(title);
    vbox->addWidget(horizontalGroupBoxH);
    vbox->addWidget(horizontalGroupBoxW);
    vbox->addWidget(buttonBox);
    d->setLayout(vbox);
    int result = d->exec();

    if(result == QDialog::Accepted)
    {

    static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->setSceneRect(0,0, rectangleWidth->value(), rectangleHeight->value());

    static_cast<RenderArea *>(tabWidget->currentWidget())->sceneRect().setWidth(rectangleWidth->value());
    static_cast<RenderArea *>(tabWidget->currentWidget())->sceneRect().setHeight(rectangleHeight->value());
    static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->sceneRect().setWidth(rectangleWidth->value());
    static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->sceneRect().setHeight(rectangleHeight->value());


    }

}



/**
 * @brief brush tool pop up
 * display a slider to choose a magnitude intensity (slow, medium, fast) to attribute to vectors
 *
 */
void View::colorMagnitude(){

    QDialog * d = new QDialog();
    QVBoxLayout * vbox = new QVBoxLayout();
    QHBoxLayout *hboxHeight = new QHBoxLayout();
    QLabel *title = new QLabel();
    title->setText("value");
    QLabel *magnitude = new QLabel();
    magnitude->setText("Vector Magnitude: ");
    QSlider * colorValue = new QSlider();

    QVBoxLayout *labels =  new QVBoxLayout();
    QHBoxLayout *slider = new QHBoxLayout();
    QLabel * low= new QLabel("Low speed");
    QLabel * medium = new QLabel("Medium speed");
    QLabel * fast = new QLabel("fast speed");
    labels->addWidget(fast);
    labels->addWidget(medium);
    labels->addWidget(low);
    slider->addLayout(labels);
    slider->addWidget(colorValue);
    colorValue->setMinimum(10);
    colorValue->setMaximum(100);
    colorValue->setValue(static_cast<RenderArea *>(tabWidget->currentWidget())->getBrushIntensity()*100.0);
    changeSliderColor(colorValue);
    hboxHeight->addWidget(magnitude);
    hboxHeight->addLayout(slider);
    QColor from(250, 0, 0);
    QColor to(64, 150, 214);

    //QColor c = QColor(from.red()*rv + to.red()*(1.0-rv),from.green()*rv + to.green()*(1.0-rv), from.blue()*rv + to.blue()*(1.0-rv) );

    QObject::connect(colorValue, &QSlider::valueChanged, this, [=] (){
        changeSliderColor(colorValue);
    });

    QObject::connect(colorValue, &QSlider::valueChanged, this, [=] () {
        magnitude->setText(QString::number(colorValue->value()/(float)100));
    });






    /*xchange the color of the selected curve
    QObject::connect(colorValue, &QSlider::valueChanged, this, [=] () {
        QList<QGraphicsItem *> selectedItems = static_cast<RenderArea *>(tabWidget->currentWidget())->scene()->selectedItems();
        for (QGraphicsItem *item : qAsConst(selectedItems)) {
            if(item->type()== VectorLine::Type){
                VectorLine *line = qgraphicsitem_cast<VectorLine *>(item);
                //line->setBrush(QColor(0, 40, colorValue->value()));
                line->setCoeffColor(colorValue->value());
                line->update();

            }
            if (item->type() == VectorCurve::Type){
                VectorCurve *curve = qgraphicsitem_cast<VectorCurve *>(item);
                //curve->setBrush(QColor(0, 40, colorValue->value()));
                curve->setCoeffColor(colorValue->value());
                curve->update();
            }
        }
     });*/

    QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
    | QDialogButtonBox::Cancel);
    QObject::connect(buttonBox, SIGNAL(accepted()), d, SLOT(accept()));
    QObject::connect(buttonBox, SIGNAL(rejected()), d, SLOT(reject()));
    vbox->addWidget(title);
    QGroupBox *horizontalGroupBox = new QGroupBox(tr("Change the speed"));
    horizontalGroupBox->setLayout(hboxHeight);
    vbox->addWidget(horizontalGroupBox);
    vbox->addWidget(buttonBox);
    d->setLayout(vbox);
    int result = d->exec();

    if(result == QDialog::Accepted)
    {
    static_cast<RenderArea *>(tabWidget->currentWidget())->setBrushIntensity(float(colorValue->value())/100.f);
    }
}

/**
 * @brief change the color of the rbush pop up slider
 *
 * @param s: the style of the slider
 */
void View::changeSliderColor(QSlider *s){

    QColor from(250, 0, 0);
    QColor to(64, 150, 214);
    int v = s->value();
    v = v - s->minimum();
    qreal rv = qreal(v) / (s->maximum() - s->minimum());
    //QColor c = QColor(from.red()*rv + to.red()*(1.0-rv),from.green()*rv + to.green()*(1.0-rv), from.blue()*rv + to.blue()*(1.0-rv) );
    QColor c = QColor::fromHsl(205 - 205 * rv, 200, 135);
    s->setStyleSheet(QString("QSlider::handle:vertical {background-color: %1;}").arg(c.name()));
}

/**
 * @brief add a new groulayer to the group layer menu
 *
 */
void View::addLayer()
{
    QDialog * d = new QDialog();
    QVBoxLayout * vbox = new QVBoxLayout();
    QLabel *fieldNameLabel  = new QLabel("New Field name:");
    QLineEdit *name = new QLineEdit("untitled");
    QHBoxLayout *hboxHeight = new QHBoxLayout();
    QDoubleSpinBox* rectangleHeight = new QDoubleSpinBox();
    QLabel *rectangleHeightText = new QLabel("Layer height in meter: ");

    rectangleHeight->setMinimum(1);
    rectangleHeight->setMaximum(100);
    rectangleHeight->setValue(20);
    hboxHeight->addWidget(rectangleHeightText);
    hboxHeight->addWidget(rectangleHeight);

    QHBoxLayout *hboxWidth = new QHBoxLayout();
    QDoubleSpinBox * rectangleWidth = new QDoubleSpinBox();
    QLabel *rectangleWidthText = new QLabel("Layer width in meter: ");

    rectangleWidth->setMinimum(1);
    rectangleWidth->setMaximum(100);

    rectangleWidth->setValue(20);
    hboxWidth->addWidget(rectangleWidthText);
    hboxWidth->addWidget(rectangleWidth);

    QHBoxLayout *hboxWeight = new QHBoxLayout();
    QDoubleSpinBox * rectangleWeight = new QDoubleSpinBox();
    QLabel *rectangleWeightText = new QLabel("Combination Weight: ");

    rectangleWeight->setMinimum(1);
    rectangleWeight->setMaximum(100);

    rectangleWeight->setValue(50);
    hboxWeight->addWidget(rectangleWidthText);
    hboxWeight->addWidget(rectangleWidth);


    QGroupBox *horizontalGroupBoxH = new QGroupBox(tr("Height"));
    horizontalGroupBoxH->setLayout(hboxHeight);
    QGroupBox *horizontalGroupBoxW = new QGroupBox(tr("Width"));
    horizontalGroupBoxW->setLayout(hboxWidth);
    QGroupBox *horizontalGroupBoxWeight = new QGroupBox(tr("Combination Weight"));
    horizontalGroupBoxWeight->setLayout(hboxWeight);
    QLabel *title = new QLabel();
    title->setText("Add a new field:");

    QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
    | QDialogButtonBox::Cancel);
    QObject::connect(buttonBox, SIGNAL(accepted()), d, SLOT(accept()));
    QObject::connect(buttonBox, SIGNAL(rejected()), d, SLOT(reject()));
    vbox->addWidget(title);
    vbox->addWidget(fieldNameLabel);
    vbox->addWidget(name);
    vbox->addWidget(horizontalGroupBoxH);
    vbox->addWidget(horizontalGroupBoxW);
    vbox->addWidget(horizontalGroupBoxWeight);
    vbox->addWidget(buttonBox);
    d->setLayout(vbox);
    int result = d->exec();

    if(result == QDialog::Accepted){

    double layerH =rectangleHeight->value();
    double layerW =rectangleWidth->value();
    double layerWeight = rectangleWeight->value();
    idGroup ++;
    layerWidget->layout()->addWidget(createLayerCellWidget(name->text(), layerH, layerW, layerWeight/(float)100, idGroup,static_cast<RenderArea *>(tabWidget->currentWidget()) ));
    //layerToolbar->addWidget(createLayerCellWidget(name->text(), layerH, layerW, idGroup));
    layerWidget->update();

    }

}
//! [10]

//! [11]
/**
 * @brief
 *
 */
void View::about()
//! [11] //! [12]
{
    QMessageBox::about(this, tr("About Scribble"),
            tr("<p>The <b>Scribble</b> example shows how to use QMainWindow as the "
               "base widget for an application, and how to reimplement some of "
               "QWidget's event handlers to receive the events generated for "
               "the application's widgets:</p><p> We reimplement the mouse event "
               "handlers to facilitate drawing, the paint event handler to "
               "update the application and the resize event handler to optimize "
               "the application's appearance. In addition we reimplement the "
               "close event handler to intercept the close events before "
               "terminating the application.</p><p> The example also demonstrates "
               "how to use QPainter to draw an image in real time, as well as "
               "to repaint widgets.</p>"));
}
//! [12]

//! [13]
/**
 * @brief create all the actions
 *
 */
void View::createActions()
//! [13] //! [14]
{
    openAct = new QAction(tr("&Open..."), this);
    openAct->setShortcuts(QKeySequence::Open);
    connect(openAct, &QAction::triggered, this, &View::open);

    /*
    const QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats();
    for (const QByteArray &format : imageFormats) {
        QString text = tr("%1...").arg(QString::fromLatin1(format).toUpper());

        QAction *action = new QAction(text, this);
        action->setData(format);
        connect(action, &QAction::triggered, this, &View::save);
        saveAsActs.append(action);
    }
    */

    /*
    QString text = tr("Text files (*.txt);");
    QAction *action = new QAction (text, this);
    connect(action, &QAction::trigger, this, &View::save);
    action->setData("txt");
    saveAsActs.append(action);
    */

    saveAsGridAct = new QAction(tr("Save entire grid as"), this);
    saveAsCurveAct = new QAction(tr("Save the guide lines as"), this);
    bool expended = true;

    connect(saveAsGridAct,  &QAction::triggered, [this, expended] {saveAsGrid(expended);});
    connect(saveAsCurveAct,  &QAction::triggered, [this, expended] {saveAsCurves(expended);});
    saveAct = new QAction(tr("Save"), this);
    saveAct->setShortcut((tr("Ctrl+S")));
    expended = false;
    connect(saveAct,  &QAction::triggered, [this, expended] {save(expended);});

    poleAct = new QAction(tr("Pole"), this);
    connect(poleAct, &QAction::triggered, this, &View::makeSource);


    sourceAct = new QAction(tr("Source"), this);
    connect(poleAct, &QAction::triggered, this, &View::makeSource);

    exitAct = new QAction(tr("E&xit"), this);
    exitAct->setShortcuts(QKeySequence::Quit);
    connect(exitAct, &QAction::triggered, this, &View::close);



    penColorAct = new QAction(tr("&Pen Color..."), this);
    connect(penColorAct, &QAction::triggered, this, &View::colorMagnitude);

    penWidthAct = new QAction(tr("Pen &Width..."), this);
    connect(penWidthAct, &QAction::triggered, this, &View::penWidth);


    matrixSizeAct = new QAction(tr("Matrix Size..."), this);
    connect(matrixSizeAct, &QAction::triggered, this, &View::matrixSize);


    sceneSizeAct = new QAction(tr("Scene Size..."), this);
    connect(sceneSizeAct, &QAction::triggered, this, &View::sceneSize);

    addLayerAct = new QAction(tr("Add layer.."), this);
    connect(addLayerAct, &QAction::triggered, this, &View::addLayer);

    showLayerAct = new QAction(tr("hide"), this);
    connect(showLayerAct, &QAction::triggered, this, &View::showLayer);

    showVectorAct = new QAction(tr("hide Vectors"), this);
    connect(showVectorAct, &QAction::triggered, this, &View::showVector);

    moveLayerAct = new QAction(tr("move"), this);
    connect(moveLayerAct, &QAction::triggered, this, &View::moveLayer);

    clearScreenAct = new QAction(tr("&Clear Screen"), this);
    clearScreenAct->setShortcut(tr("Ctrl+L"));
    connect(clearScreenAct, &QAction::triggered,
            static_cast<RenderArea *>(tabWidget->currentWidget()),&RenderArea::clearImage);

    eraseNullAct = new QAction(tr("&remove zero cells"),this);
    connect(eraseNullAct, &QAction::triggered, this, [=]() {
         blankButtonGroupClicked(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID());
    });


    aboutAct = new QAction(tr("&About"), this);
    connect(aboutAct, &QAction::triggered, this, &View::about);

    aboutQtAct = new QAction(tr("About &Qt"), this);
    connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);



    //2nd part
    toFrontAction = new QAction(QIcon("..\\images\\bringtofront.png"),
                                tr("Bring to &Front"), this);
    toFrontAction->setShortcut(tr("Ctrl+F"));
    toFrontAction->setStatusTip(tr("Bring item to front"));
    connect(toFrontAction, &QAction::triggered, this, &View::bringToFront);
//! [23]

    sendBackAction = new QAction(QIcon("..\\images\\sendtoback.png"), tr("Send to &Back"), this);
    sendBackAction->setShortcut(tr("Ctrl+T"));
    sendBackAction->setStatusTip(tr("Send item to back"));
    connect(sendBackAction, &QAction::triggered, this, &View::sendToBack);

    deleteAction = new QAction(QIcon("..\\images\\delete.png"), tr("&Delete"), this);
    deleteAction->setShortcut(tr("Delete"));
    deleteAction->setStatusTip(tr("Delete item from diagram"));
    connect(deleteAction, &QAction::triggered, this, &View::deleteItem);

    sourceAction = new QAction(QIcon("..\\images\\source.png"), tr("&Make Source"), this);
    sourceAction->setShortcut(tr("Ctrl+Shift+S"));
    sourceAction->setStatusTip(tr("Make the selected pole the source"));
    connect(sourceAction, &QAction::triggered, this, &View::makeSource);

    makeParametricAction = new QAction(QIcon("..\\images\\parametric.png"), tr("&make associtaed field parametric"), this);
    makeParametricAction->setStatusTip(tr("The associated field of this source will become parametric"));
    connect(makeParametricAction, &QAction::triggered, this, &View::on_paramButton_clilcked);

    exitAction = new QAction(tr("E&xit"), this);
    exitAction->setShortcuts(QKeySequence::Quit);
    exitAction->setStatusTip(tr("Quit Scenediagram example"));
    connect(exitAction, &QAction::triggered, this, &QWidget::close);

    aboutAction = new QAction(tr("A&bout"), this);
    aboutAction->setShortcut(tr("F1"));
    connect(aboutAction, &QAction::triggered, this, &View::about);


}
//! [14]


//! [15]
/**
 * @brief create all the menus
 *
 */
void View::createMenus()
//! [15] //! [16]
{
    /* to keep the save as as a list of action
    saveAsMenu = new QMenu(tr("&Save As"), this);
    for (QAction *action : qAsConst(saveAsActs))
        saveAsMenu->addAction(action);
    */
    itemMenu = menuBar()->addMenu(tr("&Item"));
    itemMenu->addAction(deleteAction);
    itemMenu->addSeparator();
    itemMenu->addAction(toFrontAction);
    itemMenu->addAction(sendBackAction);
    itemMenu->addSeparator();
    itemMenu->addAction(sourceAction);
    itemMenu->addAction(makeParametricAction);

    fileMenu = new QMenu(tr("&File"), this);
    fileMenu->addAction(openAct);
    fileMenu->addAction(saveAct);
    //fileMenu->addMenu(saveAsMenu); to keep the save as as a list of action
    fileMenu->addAction(saveAsGridAct);
    fileMenu->addAction(saveAsCurveAct);

    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    toolMenu = new QMenu(tr("Tool"), this);

    toolMenu->addAction(poleAct);

    brushMenu = new QMenu(tr("&brush"),this);
    brushMenu->addAction(penColorAct);
    brushMenu->addAction(penWidthAct);

    eraserMenu =  new QMenu(tr("&brush"),this);
    eraserMenu->addAction(penWidthAct);

    optionMenu = new QMenu(tr("&Options"), this);

    optionMenu->addAction(sceneSizeAct);


    optionMenu->addSeparator();
    optionMenu->addAction(clearScreenAct);

    helpMenu = new QMenu(tr("&Help"), this);
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
/*now layer menu is below each layer in th elayer panel
    layerMenu = new QMenu(tr("&Layer"), this);
    layerMenu->addAction(deleteAction);
    layerMenu->addAction(matrixSizeAct);
    layerMenu->addAction(addLayerAct);
    layerMenu->addAction(moveLayerAct);
    layerMenu->addAction(showLayerAct);
    layerMenu->addAction(showVectorAct);*/




    menuBar()->addMenu(fileMenu);
    menuBar()->addMenu(optionMenu);
    menuBar()->addMenu(helpMenu);
//    menuBar()->addMenu(layerMenu);
/*
    menuBar()->addSeparator();
    menuBar()->addAction(deleteAction);
    menuBar()->addSeparator();
    menuBar()->addAction(toFrontAction);
    menuBar()->addAction(sendBackAction);
   */

}
//! [16]

//! [17]
/**
 * @brief if the field was modified after last saved, asked if user wants to save it before closing the window
 *
 * @return bool return if the user still wants to close the window or not
 */
bool View::maybeSave()
//! [17] //! [18]
{
    for(auto &layer:static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()){
        if (layer->isModified() && layer->getHasSource()) {
           QMessageBox::StandardButton ret;
           ret = QMessageBox::warning(this, tr("Scribble"),
                              tr("The layer been modified.\n"
                                 "Do you want to save your changes?"),
                              QMessageBox::Save | QMessageBox::Discard
                              | QMessageBox::Cancel);
            if (ret == QMessageBox::Save)
                return saveFile("txt", false);
            else if (ret == QMessageBox::Cancel)
                return false;
        }

    }
     return true;
}
//! [18]

//! [19]
/**
 * @brief save the field as a txt file
 *
 * @param fileFormat file format
 * @param isExtended if we choose the path of the file "save as.." or if we use the previous name of the file "save"
 * @return bool
 */
bool View::saveFile(const QByteArray &fileFormat, bool isExtended)
//! [19] //! [20]
{


    if ( static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getHasSource()!=false )
    {
        QString fileName;
        if(isExtended){
             QString initialPath = "C:/Users/acolas/Documents/Present/UMANS/examples/interactionFields/matrix/untitled." + fileFormat;
              fileName = QFileDialog::getSaveFileName(this, tr("Save As"),
                                        initialPath,
                                        tr("%1 Files (*.%2);;All Files (*)")
                                        .arg(QString::fromLatin1(fileFormat.toUpper()))
                                        .arg(QString::fromLatin1(fileFormat)));


        }


        else{

           fileName = static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getName();
        }

    if (fileName.isEmpty())
            return true;
    else {
        QFile file(fileName);
        if (!file.open(QIODevice::WriteOnly)) {
            QMessageBox::information(this, tr("Unable to open file"),
                file.errorString());
            return false;
        }
        QFileInfo fileInf = QFileInfo(fileName);
        QString name = fileInf.path()+"/"+fileInf.baseName();
        return static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->saveGroup(name,fileFormat, isContinuus);
    }
    }

    else{
        QMessageBox::StandardButton ret;
        ret = QMessageBox::warning(this, tr("Scribble"),
                           tr("There is no object nor source\n"
                              "You have to have a matrix generate"),
                            QMessageBox::Cancel);


    }

}
//! [20]

/**
 * @brief activated when the button "generate" of the matrix menu is clicked
 * generate the matrix
 *
 */
void View::on_pushButtonMatrix_clicked()
{
    //static_cast<RenderArea *>(tabWidget->currentWidget())->generateMatrixFromFile();

    if ( static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->getVectCurves().size()>0) {
         static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->generateMatrix(static_cast<RenderArea *>(tabWidget->currentWidget())->getBrushIntensity());
         static_cast<RenderArea *>(tabWidget->currentWidget())->drawMatrix();

    }

    else{
        QMessageBox::StandardButton ret;
        ret = QMessageBox::warning(this, tr("Scribble"),
                           tr("There is no object\n"
                              "You have to have at least one Vector."),
                            QMessageBox::Cancel);

    }

}
/**
 * @brief save the field
 *
 * @return bool
 */
bool View::saveSimple()
//! [19] //! [20]
{

    for (auto &indices: static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->getZerosArea()){

       static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer()->removeZero(indices);
    }
    on_pushButtonMatrix_clicked();

    if ( static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getHasSource()!=false )
    {
        QString fileName;

      fileName = static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getName();


    if (fileName.isEmpty())
            return true;
    else {
        QFile file(fileName);
        if (!file.open(QIODevice::WriteOnly)) {
            QMessageBox::information(this, tr("Unable to open file"),
                file.errorString());
            return false;
        }
        QFileInfo fileInf = QFileInfo(fileName);
        QString name = "../examples/interactionFields/matrix/"+fileInf.baseName();


        return static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->saveGroup(name,"txt", isContinuus);

    }
    }

    else{
        QMessageBox::StandardButton ret;
        ret = QMessageBox::warning(this, tr("Scribble"),
                           tr("There is no object nor source\n"
                              "You have to have a source to generate"),
                            QMessageBox::Cancel);
        return ret;


    }

    on_pushButtonMatrix_clicked();


}


/**
 * @brief
 *
 */
void View::on_agentRadButt_clicked()
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->setType(1);

}

/**
 * @brief
 *
 */
void View::on_obstacleRadButt_clicked()
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->setType(2);

}


/**
 * @brief
 *
 */
void View::on_rotationButton_clicked()
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->setRotation(!static_cast<RenderArea *>(tabWidget->currentWidget())->getRotation());
}

/**
 * @brief
 *
 */
void View::on_translationButton_clicked()
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->setTranslation(!static_cast<RenderArea *>(tabWidget->currentWidget())->getTranslation());
}

/**
 * @brief
 *
 */
void View::on_scaleButton_clicked()
{
    static_cast<RenderArea *>(tabWidget->currentWidget())->setScaling(!static_cast<RenderArea *>(tabWidget->currentWidget())->getScaling());
}

/**
 * @brief on the slider menu if the button "add or remover key frame" is clicked
 * make the layergroup parametric, add a key frame for this parameter or remove it if already there.
 */
void View::on_paramButton_clilcked(){
    LayerViewer *layer =new LayerViewer(*static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getCurrentLayer());
    if(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getInteractionFields().count(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getParameter())){
        static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getInteractionFields().erase(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getParameter());


        if(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getInteractionFields().size()<2){
            static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->setIsParametric(false);
        }

    }
    else{
        static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->addInteractionFields((float)interpolationSlider->value()/10.f, layer);
        static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->setIsParametric(true);

    }
    QSlider *abstractTick = new QSlider(Qt::Horizontal);

    abstractTick ->setRange(interpolationSlider->minimum(), interpolationSlider->maximum());
    abstractTick->setValue(interpolationSlider->value());
    abstractTick->setTickInterval(1);
    abstractTick->setTickPosition(QSlider::NoTicks);
    //abstractTick->setMinimum(interpolationSlider->value());
    //abstractTick->setMaximum(interpolationSlider->value());
    abstractTick->setStyleSheet("QSlider::handle:horizontal {background-color: red;}");
    keyFrameWidget->addWidget(abstractTick);
    abstractTick->show();



    update();
    sliderToolBox->update();



}

/**
 * @brief activated when the parametric slider changes its value
 * when value changes, thedisplayer layerviewer must changed and the resulting vector matrix is the interpolated matrix of the surrounding keyframes matrix
 */
void View::sliderValueChange(){


    if(static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->getIsParametric()){
        static_cast<RenderArea *>(tabWidget->currentWidget())->removeLayerDisplayed();
        static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->setParameter((float)interpolationSlider->value()/10.f);
        static_cast<RenderArea *>(tabWidget->currentWidget())->addLayerDisplayed();

    }
    else{
        static_cast<RenderArea *>(tabWidget->currentWidget())->getLayers()[static_cast<RenderArea *>(tabWidget->currentWidget())->getLayerID()]->setParameter((float)interpolationSlider->value()/10.f);
    }



}