interface.cpp 20.7 KB
Newer Older
1
2
3
#include "interface.hpp"
#include "ui_interface.h"

4
#include "savingdialog.hpp"
5
#include "structurewriter.hpp"
6
#include "structurereader.hpp"
7
8
9
10
#include "factory.hpp"
#include "transitionrule.hpp"
#include "neighborhoodrule.hpp"
#include "propertyvisitors.hpp"
11
#include "modelloadingdialog.hpp"
12
#include "configurationloadingdialog.hpp"
13
#include "neighborhoodDialog.hpp"
Yann Boucher's avatar
Yann Boucher committed
14
#include "colorlabel.h"
15

16
#include <QJsonArray>
Merwane Bouri's avatar
Merwane Bouri committed
17
18
#include <QDate>
#include <QTextStream>
19
#include <QInputDialog>
Anthony Noir's avatar
Anthony Noir committed
20
#include <QTimer>
21

22
23
24
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
      , ui(new Ui::MainWindow)
Anthony Noir's avatar
Anthony Noir committed
25
26
27
      , simulation()
      , timer(new QTimer(this))
      , m_customizing(false)
28
29
{
    ui->setupUi(this);
30

31
32
33
    m_transition_rule = nullptr;
    m_neighborhood_rule = nullptr;

34
35
    init_transition_neighborhood_list();
    update_transition_settings();
36
    update_neighborhood_settings();
37

38
    connect(ui->action_save_struct, &QAction::triggered, this, &MainWindow::afficher_interface_sauvegarde_structure);
39
    connect(ui->struct_library, &StructureLibraryView::structure_copied, this, &MainWindow::copy_structure_clicked);
40
    connect(ui->grid_view, &GridView::zoom_changed, ui->struct_library, &StructureLibraryView::update_cell_pixel_size);
Yann Boucher's avatar
Yann Boucher committed
41
42
43
44
45
    connect(ui->statesSettingsButton, &QPushButton::clicked, this, [this]
            {
                ColorLabel* dialog = new ColorLabel(simulation.getAlphabet(), this);
                if (dialog->exec())
                {
Yann Boucher's avatar
Yann Boucher committed
46
                    ui_update_alphabet(dialog->getAlphabet());
Yann Boucher's avatar
Yann Boucher committed
47
48
                }
            });
49
50
    connect(ui->transition_list, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int)
            { update_transition_settings(); });
51
52
53
54
55
56
57
58
59
60
    connect(ui->action_propos_de_Cellulut, &QAction::triggered, this, [this](bool)
            {
                QMessageBox::about(this, "À propos de Cellulut",
                                   "Projet de C++ réalisé dans le cadre de l'UV LO21 de l'UTC.\n\n"
                                   "Contributeurs : Anthony Noir, Eugène Pin, Merwane Bouri, Arthur Detree, Yann Boucher");
            });
    connect(ui->action_propos_de_Qt, &QAction::triggered, this, [this](bool)
            {
                QMessageBox::aboutQt(this, "À propos de Qt");
            });
61
62
63
64
    connect(ui->actionCharger_depuis_une_image, &QAction::triggered, this, [this](bool)
            {
                load_from_image();
            });
65

66
    ui->struct_library->update_cell_pixel_size(ui->grid_view->cell_screen_size());
67
68

    load_model(default_model());
Anthony Noir's avatar
Anthony Noir committed
69
70
71
72
73

    connect(timer, &QTimer::timeout, this, [this](){
        on_nextButton_clicked();
        timer->start();
    });
74
75
76
77
78
}

MainWindow::~MainWindow()
{
    delete ui;
79
    // FIXME : il y a un risque de fuite de mémoire avec la gestion de pointeurs de m_transition_rule et m_neighborhood_rule, si l'application est quitée alors que ils pointent vers de la mémoire non transférée vers Simulation
80
81
}

82
83
/// Connections

84
85
86
87
88
89
90
91
92
void MainWindow::on_simSpeedSpinbox_valueChanged(int arg1)
{
    ui->simSpeedSlider->setValue(arg1);
}

void MainWindow::on_simSpeedSlider_valueChanged(int value)
{
    ui->simSpeedSpinbox->setValue(value);
}
93
94
95

void MainWindow::on_openPatternButton_clicked()
{
96
    load_grid_configuration();
97
98
99
100
101
}

void MainWindow::on_openRuleButton_clicked()
{
    // Indiquer qu'une nouvelle règle vient d'être ouverte. La règle est sauvegardé, donc on peut lancer la simulation
102
103
104
105
106
107

    ModelLoadingDialog dialog(this);
    if (!dialog.exec())
        return;

    load_model(dialog.model());
108
109
}

110
void MainWindow::on_neighborhood_list_currentTextChanged(const QString &)
111
{
112
    update_neighborhood_settings();
113
114
}

115
void MainWindow::on_widthSpinBox_valueChanged(int)
116
117
118
119
{
    ui->validateGridDim->setEnabled(true);
}

120
void MainWindow::on_heightSpinBox_valueChanged(int)
121
122
123
124
{
    ui->validateGridDim->setEnabled(true);
}

125
QString MainWindow::afficher_interface_sauvegarde_structure()
126
{
127
    SavingDialog dialog(this);
128
    if (!dialog.exec())
129
        return "";
130

131
    QString filename = QFileDialog::getSaveFileName(this, "Choisir un nom de fichier", "", "Format Cellulut (*.json);;Format Golly RLE (*.rle)");
132
    QFileInfo info(filename);
133
    //printf("%s\n", info.suffix().toStdString().c_str());
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    // on pourrait utiliser un Factory ici, mais c'est possiblement overkill, les possibilités d'évolution de format de fichier sont faibles et ne justifient pas l'effort

    Structure s = ui->grid_view->selected_cells();
    s.author = dialog.auteur().toStdString();
    s.title = dialog.titre().toStdString();
    s.desc = dialog.desc().toStdString();
    s.date = dialog.date().toString().toStdString();

    std::string save_data;
    if (info.suffix() == "json")
    {
        JSONStructureWriter writer;
        save_data = writer.save_structure(s);
    }
    else if (info.suffix() == "rle")
    {
        RLEStructureWriter writer;
        save_data = writer.save_structure(s);
    }

    QFile file(filename);
    if (!file.open(QIODevice::WriteOnly))
    {
        QMessageBox::information(this, "Impossible de créer le fichier",
                                 file.errorString());
159
        return "";
160
161
162
163
    }

    QTextStream stream(&file);
    stream << QString::fromStdString(save_data);
164
165

    return filename;
166
167
}

168

169
170
void MainWindow::on_validateGridDim_clicked()
{
171
172
    Grid oldGrid = ui->grid_view->get_grid();

173

174
175
176
    unsigned int nbrRow = ui->heightSpinBox->value(); // nbr de lignes => axe y
    unsigned int nbrCol = ui->widthSpinBox->value(); // nbr de colonne => axe x
    Grid newGrid(nbrRow, nbrCol);
177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    unsigned oldNbrRow = oldGrid.get_rows(); // rows = nbr de lignes => axe y
    unsigned oldNbrCol = oldGrid.get_col(); // col = nbr de colonne => axe x

    if(oldNbrRow <= nbrRow && oldNbrCol <= nbrCol) {
        //std::cout << "superieur\n";
        fflush(stdout);
        for (unsigned y = 0; y < oldNbrRow ; y++) {
            for (unsigned x = 0; x < oldNbrCol ; x++) {
                Coord pos = {static_cast<int>(x), static_cast<int>(y)};
                newGrid.set_cell(pos, oldGrid.get_state(pos));
                //std::cout << "oldState : " << oldGrid.get_state(pos) << endl;
            }
        }
    }
    else
    {
194
195
        //std::cout << "superieur\n";
        fflush(stdout);
196
197
198
        for (unsigned y = 0; y < nbrRow ; y++) {
            for (unsigned x = 0; x < nbrCol ; x++) {
                Coord pos = {static_cast<int>(x), static_cast<int>(y)};
199
200
201
202
203
204
                newGrid.set_cell(pos, oldGrid.get_state(pos));
                //std::cout << "oldState : " << oldGrid.get_state(pos) << endl;
            }
        }
    }

205
    ui->grid_view->copy_grid(newGrid);
206

207
208
    ui->validateGridDim->setEnabled(false);
}
209
210
211
212
213
214
215

void MainWindow::on_nbrStateComboBox_currentTextChanged(const QString &arg1)
{
    unsigned val = arg1.toInt();

    ui->grid_view->set_current_pen(val);
}
216
217
218

void MainWindow::on_randomPatternButton_clicked()
{
219
    int alphabetSize = simulation.getAlphabet().taille();
220
221
222
223
224
225
226
227
228
229

    Grid oldGrid = ui->grid_view->get_grid();
    unsigned nbrRow = oldGrid.get_rows(); // rows = nbr de lignes => axe y
    unsigned nbrCol = oldGrid.get_col(); // col = nbr de colonne => axe x
    Grid newGrid(nbrRow, nbrCol);

    for (unsigned y = 0; y < nbrRow; ++y)
    {
        for (unsigned x = 0; x < nbrCol; ++x)
        {
230
            unsigned state = rand() % alphabetSize;
231
232
233
234
235
            Coord pos = {static_cast<int>(x), static_cast<int>(y)};
            newGrid.set_cell(pos, state);
        }
    }

236
    ui->grid_view->copy_grid(newGrid);
237
}
238
239
240

void MainWindow::on_nbrStatesComboBox_currentTextChanged(const QString &arg1)
{
241
242
    // A mettre dans la fonction valider
    /*
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    // Nombre d'états possibles
    int val = arg1.toInt();
    // Nombre de valeurs dans le comboxBox (en partant de 0)
    int currentNbrValue = ui->nbrStateComboBox->count();
    // Si on change le nbr d'états
    if (val != currentNbrValue) {
        // Si on ajoute des états
        if (val > currentNbrValue) {
            for(int i = currentNbrValue; i < val; i++ ) {
                ui->nbrStateComboBox->addItem(QString::number(i));
            }
        }
        // Si on retire des états
        else {
            for(int i = currentNbrValue - 1; i >= val; i-- ) {
                ui->nbrStateComboBox->removeItem(i);
            }
        }
    }
262
    */
263
}
264

265
266
267
268
269
void MainWindow::on_drawCellButton_clicked()
{
    ui->grid_view->fill_selection(ui->nbrStateComboBox->currentIndex());
}

270
271
272
273
274
void MainWindow::copy_structure_clicked(const Structure &s)
{
    ui->grid_view->set_clipboard(s);
    statusBar()->showMessage("Structure copied.", 5000);
}
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291

void MainWindow::init_transition_neighborhood_list()
{
    for (const auto& transition : Factory<TransitionRule>::list_choices())
    {
        ui->transition_list->addItem(QString::fromStdString(transition));
    }

    for (const auto& rule : Factory<NeighborhoodRule>::list_choices())
    {
        ui->neighborhood_list->addItem(QString::fromStdString(rule));
    }
}

void MainWindow::update_transition_settings()
{
    std::string selected = ui->transition_list->currentText().toStdString();
292
293
    m_transition_rule = Factory<TransitionRule>::make(selected).release();
    if (!m_transition_rule)
294
295
        return;

296
    if (m_transition_rule->get_properties().size() == 0)
297
298
299
300
301
302
        ui->rule_settings_area->hide();
    else
    {
        ui->rule_settings_area->show();

        UIBuilderVisitor visit(ui->rule_settings_area);
303
        for (auto& prop : m_transition_rule->get_properties())
304
305
            prop->accept(visit);
    }
306
}
307
308
309
void MainWindow::update_neighborhood_settings()
{
    std::string selected = ui->neighborhood_list->currentText().toStdString();
310
311
    m_neighborhood_rule = Factory<NeighborhoodRule>::make(selected).release();
    if (!m_neighborhood_rule)
312
313
        return;

314
    if (m_neighborhood_rule->get_properties().size() == 0)
315
316
317
318
319
320
        ui->neighborhood_settings_area->hide();
    else
    {
        ui->neighborhood_settings_area->show();

        UIBuilderVisitor visit(ui->neighborhood_settings_area);
321
        for (auto& prop : m_neighborhood_rule->get_properties())
322
323
324
            prop->accept(visit);
    }
}
325

326
327
void MainWindow::enable_rule_customization()
{
Yann Boucher's avatar
Yann Boucher committed
328
    //ui->simulation_tab->setEnabled(false);
Yann Boucher's avatar
Yann Boucher committed
329
    ui->savePatternButton->setEnabled(false);
330
    ui->customize_button->setText("Cancel customization");
331
    ui->rule_settings->setEnabled(true);
332
    m_customizing = true;
333
334
}

335
336
void MainWindow::disable_rule_customization()
{
Yann Boucher's avatar
Yann Boucher committed
337
    //ui->simulation_tab->setEnabled(true);
Yann Boucher's avatar
Yann Boucher committed
338
    ui->savePatternButton->setEnabled(true);
339
340
    ui->customize_button->setEnabled(true);
    ui->rule_settings->setEnabled(false);
341
342
    ui->customize_button->setText("Customize...");
    m_customizing = false;
343
344
345
346
347
}

void MainWindow::load_model(const QJsonObject &obj)
{
    ui->rule_name->setText(obj.value("title").toString());
348

349
    ui->transition_list->setCurrentText(obj.value("transition_name").toString());
350
    ui->neighborhood_list->setCurrentText(obj.value("neighborhood_name").toString());
351

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    bool alpha_initialise = false;
    Alphabet alpha;
    if (obj.value("alphabet").isArray())
    {
        for (auto entry : obj.value("alphabet").toArray())
        {
            if (!entry.isObject())
                continue;

            auto entry_obj = entry.toObject();
            std::string name = entry_obj.value("name").toString().toStdString();

            if (!entry_obj.value("color").isArray())
                continue;

            auto color_array = entry_obj.value("color").toArray();
            stateColor color(color_array[0].toInt(), color_array[1].toInt(), color_array[2].toInt());

            // Initialisation avec le premier élement
            if (!alpha_initialise)
            {
                alpha = Alphabet(state(color, name));
                alpha_initialise = true;
            }
            else
                alpha.newEtat(state(color, name));
        }
    }


382
    update_transition_settings();
383
    update_neighborhood_settings();
384
385
    disable_rule_customization();

386
387
    {
        PropertyLoaderVisitor loader(obj.value("transition_data").toObject());
388
        for (auto& prop : m_transition_rule->get_properties())
389
390
            prop->accept(loader);
        UIBuilderVisitor visit(ui->rule_settings_area);
391
        for (auto& prop : m_transition_rule->get_properties())
392
393
394
395
396
            prop->accept(visit);
    }

    {
        PropertyLoaderVisitor loader(obj.value("neighborhood_data").toObject());
397
        for (auto& prop : m_neighborhood_rule->get_properties())
398
399
            prop->accept(loader);
        UIBuilderVisitor visit(ui->neighborhood_settings_area);
400
        for (auto& prop : m_neighborhood_rule->get_properties())
401
402
            prop->accept(visit);
    }
403
404

    // On transfère la propriété de ces pointeurs vers Simulation, qui en est désormais propriétaire pour l'exécution de l'automate
405
406
    simulation.setNeighborhoodRule(m_neighborhood_rule);
    simulation.setTransitionRule(m_transition_rule);
Yann Boucher's avatar
Yann Boucher committed
407
    ui_update_alphabet(alpha);
408
409

    m_loaded_model = obj;
410
411
412
}

void MainWindow::save_model()
413
414
415
416
417
418
419
{
    SavingDialog dialog(this);
    if (!dialog.exec())
        return;

    QString filename = QFileDialog::getSaveFileName(this, "Choisir un nom de fichier", QString(), "Modèle d'automate (*.json)");

420
    PropertySaverVisitor trans_saver;
421
    for (auto& prop : m_transition_rule->get_properties())
422
423
424
        prop->accept(trans_saver);

    PropertySaverVisitor neighborhood_saver;
425
    for (auto& prop : m_neighborhood_rule->get_properties())
426
        prop->accept(neighborhood_saver);
427
428
429
430
431
432
433
434

    QJsonObject root;
    root["title"] = dialog.titre();
    root["author"] = dialog.auteur();
    root["desc"] = dialog.desc();
    root["date"] = dialog.date().toString();

    root["transition_name"] = ui->transition_list->currentText();
435
436
437
438
    root["transition_data"] = trans_saver.save();

    root["neighborhood_name"] = ui->neighborhood_list->currentText();
    root["neighborhood_data"] = neighborhood_saver.save();
439
440
441

    QJsonArray alphabet;

442
443
444
445
446
447
448
449
450
451
452
453
454
    for (unsigned i = 0; i < simulation.getAlphabet().taille(); ++i)
    {
        auto state = simulation.getAlphabet().getState(i);
        QJsonArray color;
        QJsonObject entry;
        entry["name"] = QString::fromStdString(state.getStateLabel());
        color.push_back(state.getColor().getRed());
        color.push_back(state.getColor().getGreen());
        color.push_back(state.getColor().getBlue());
        entry["color"] = color;
        alphabet.push_back(entry);
    }

455
456
457
458
    root["alphabet"] = alphabet;

    QJsonDocument doc(root);
    QFile file(filename);
459
460
461
462
463
    if (!file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate))
    {
        QMessageBox::information(this, "Impossible de créer le fichier",
                                 file.errorString());
    }
464
465
    file.write(doc.toJson());
    file.close();
466
467
468

    ui->rule_name->setText(dialog.titre());
    disable_rule_customization();
469
470

    load_model(root);
471
472
}

473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
static unsigned closest_state(const Alphabet& alph, const QColor& color)
{
    unsigned best_distance = std::numeric_limits<unsigned>::max();
    unsigned best_match = 0;
    for (unsigned i = 0; i < alph.taille(); ++i)
    {
        state s = alph.getState(i);
        unsigned r_diff = qAbs(color.red() - s.getColor().getRed());
        unsigned g_diff = qAbs(color.green() - s.getColor().getGreen());
        unsigned b_diff = qAbs(color.blue() - s.getColor().getBlue());
        unsigned distance = r_diff*r_diff + g_diff*g_diff + b_diff*b_diff;
        if (distance < best_distance)
        {
            best_distance = distance;
            best_match = i;
        }
    }

    return best_match;
}

void MainWindow::load_from_image()
{
496
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"",tr("Image (*.png *.jpg *.jpeg *.bmp *.gif)"));
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
    QImage img(fileName);
    if (img.isNull())
        return;

    Grid grid = ui->grid_view->get_grid();

    img = img.scaled(grid.get_col(),
                     grid.get_rows());
    for (int x = 0; x < img.width(); ++x)
        for (int y = 0; y < img.height(); ++y)
        {
            unsigned closest = closest_state(ui->grid_view->alphabet(), img.pixelColor(x, y));
            grid.set_cell(Coord{x, y}, closest);
        }

    ui->grid_view->copy_grid(grid);
}

515
516
void MainWindow::ui_update_alphabet(const Alphabet &alpha)
{
Yann Boucher's avatar
Yann Boucher committed
517
    simulation.setAlphabet(alpha);
518
519
520
    ui->grid_view->set_alphabet(alpha);
    ui->nbrStateComboBox->clear();
    for (unsigned i = 0; i < alpha.taille(); ++i)
Yann Boucher's avatar
Yann Boucher committed
521
    {
522
        ui->nbrStateComboBox->addItem(QString::number(i));
Yann Boucher's avatar
Yann Boucher committed
523
    }
524
525
}

526
527
void MainWindow::save_grid_configuration()
{
528
529
530
531
532
533
534
535
536
    const Grid& grid = ui->grid_view->get_grid();
    Structure grid_data = grid.to_structure();

    QString title = QInputDialog::getText(this, "Choisir un titre", "Titre de la configuration : ");
    if (title.isEmpty())
        return;

    RLEStructureWriter writer;
    std::string structure_data = writer.save_structure(grid_data);
537
538

    QJsonObject json_data;
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
    json_data["width"] = (int)grid.get_col();
    json_data["height"] = (int)grid.get_rows();
    json_data["title"] = title;
    json_data["model"] = m_loaded_model.value("title");
    json_data["left"] = grid_data.top_left.x;
    json_data["top"] = grid_data.top_left.y;
    json_data["data"] = QString::fromStdString(structure_data);

    QString filename = QFileDialog::getSaveFileName(this, "Choisir un nom de fichier", "", "Configuration Cellulut (*.json)");
    if (filename.isEmpty())
        return;

    QFile file(filename);
    if (!file.open(QIODevice::WriteOnly | QFile::Text | QFile::Truncate))
    {
        QMessageBox::information(this, "Impossible de créer le fichier",
                                 file.errorString());
    }

    QJsonDocument doc(json_data);
    file.write(doc.toJson());
    file.close();
561
562
563
564
}

void MainWindow::load_grid_configuration()
{
565
566
567
568
569
570
571
572
573
574
575
576
    ConfigurationLoadingDialog dialog(m_loaded_model.value("title").toString(), this);
    if (!dialog.exec())
        return;

    Grid g(dialog.configuration().value("width").toInt(10),
           dialog.configuration().value("height").toInt(10));
    Coord origin;
    origin.x = dialog.configuration().value("left").toInt(0);
    origin.y = dialog.configuration().value("top").toInt(0);

    RLEStructureReader reader(dialog.configuration().value("data").toString().toStdString());
    Structure s = reader.read_structure();
577

578
579
580
581
    ui->grid_view->copy_grid(g);
    ui->grid_view->paste_structure_at(origin, s);
    ui->widthSpinBox->setValue(g.get_col());
    ui->heightSpinBox->setValue(g.get_rows());
582
583
}

584
585
QJsonObject MainWindow::default_model() const
{
586
587
588
    const char* json = R"(
    {
        "title" : "Game of Life",
589
590
        "neighborhood_name" : "Moore",
        "neighborhood_data" : {},
591
592
593
594
595
596
597
598
599
        "transition_name" : "Game of Life",
        "transition_data" : {},
        "alphabet" : [
        {"name" : "Dead", "color" : [255, 255, 255]},
        {"name" : "Alive", "color" : [0, 0, 255]}]
    }
)";

    QJsonDocument doc = QJsonDocument::fromJson(QByteArray(json));
600

601
    return doc.object();
602
603
604
605
606
607
608
609
610
}

void MainWindow::on_saveRuleButton_clicked()
{
    save_model();
}

void MainWindow::on_customize_button_clicked()
{
611
612
613
614
615
616
617
618
619
    if (!m_customizing)
    {
        enable_rule_customization();
    }
    else
    {
        disable_rule_customization();
        load_model(m_loaded_model);
    }
620
}
621

622
623
624

void MainWindow::on_savePatternButton_clicked()
{
625
    save_grid_configuration();
626
}
Anthony Noir's avatar
Anthony Noir committed
627
628
629
630
631
632

void MainWindow::on_nextButton_clicked()
{
    simulation.setGrid(ui->grid_view->get_grid());
    simulation.step();
    ui->grid_view->copy_grid(simulation.getGrid());
Anthony Noir's avatar
Anthony Noir committed
633
    ui->stepsPeriodLabel->setText(QString::number(simulation.getPeriod())+" steps");
Anthony Noir's avatar
Anthony Noir committed
634
    ui->nbStepsLabel->setText(QString::number(simulation.getTime())+" steps");
Anthony Noir's avatar
Anthony Noir committed
635
636
637
638
639
640
641
642
}

void MainWindow::on_prevButton_clicked()
{
    if(!simulation.back()) {
        QMessageBox::critical(this, "Retour arrière impossible", "L'historique est vide : impossible de revenir en arrière.");
    }
    ui->grid_view->copy_grid(simulation.getGrid());
Anthony Noir's avatar
Anthony Noir committed
643
    ui->nbStepsLabel->setText(QString::number(simulation.getTime())+" steps");
Anthony Noir's avatar
Anthony Noir committed
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
}

void MainWindow::on_playPauseButton_clicked()
{
    if(timer->isActive()) {
        //Pause
        timer->stop();
    } else {
        //Play
        int frequence = ui->simSpeedSpinbox->value();
        if(frequence == 0) {
            QMessageBox::critical(this, "Impossible de démarrer", "Impossible de lancer la simulation à une vitesse nulle.");
        } else if(!simulation.runnable()) {
            QMessageBox::critical(this, "Impossible de démarrer", "Impossible de lancer la simulation : les règles ne sont pas définies ou incompatibles.");
        } else {
            timer->setInterval(1000/frequence);
            timer->start();
        }
    }
}
Anthony Noir's avatar
reset    
Anthony Noir committed
664
665
666
667
668
669
670

void MainWindow::on_resetButton_clicked() {
    if(timer->isActive()) {
        timer->stop();
    }
    simulation.reset();
    ui->grid_view->copy_grid(simulation.getGrid());
Anthony Noir's avatar
Anthony Noir committed
671
    ui->stepsPeriodLabel->setText(QString::number(simulation.getPeriod())+" steps");
Anthony Noir's avatar
Anthony Noir committed
672
    ui->nbStepsLabel->setText(QString::number(simulation.getTime())+" steps");
Anthony Noir's avatar
reset    
Anthony Noir committed
673
}
Anthony Noir's avatar
Anthony Noir committed
674
675
676
677

void MainWindow::on_recordSpinBox_valueChanged(int newSize) {
    simulation.setHistorySize(newSize);
}