Commit 0dee1e4d authored by Yann Boucher's avatar Yann Boucher
Browse files

Ajout du support de la sauvegarde/chargement des paramètres de l'application lors du démarrage

parent 4df9b921
Pipeline #79343 canceled with stage
......@@ -115,13 +115,20 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="simSpeedSpinbox"/>
<widget class="QSpinBox" name="simSpeedSpinbox">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
......
......@@ -59,8 +59,6 @@ private slots:
//! \brief Créer une nouvelle grille ayant des états aléatoire
void on_randomPatternButton_clicked();
void on_nbrStatesComboBox_currentTextChanged(const QString &arg1);
//! \brief Applique l'état sélectionné aux cellules sélectionnées de la GridView
void on_drawCellButton_clicked();
......@@ -111,14 +109,25 @@ private:
//! \brief Charge un nouvel alphabet et met à jour l'UI.
void ui_update_alphabet(const Alphabet& alph);
//! \brief Essaie de charger l'état de l'application si il a été sauvegardé.
//! \returns True si le chargement a été réussi, false sinon.
bool try_load_saved_state();
//! \brief Sauvegarde la configuration actuelle.
void save_grid_configuration();
//! \brief Charge une configuration liée au modèle donné.
void load_grid_configuration();
void load_grid_configuration(const QJsonObject &configuration);
//! \brief Retourne le modèle par défaut à charger
QJsonObject default_model() const;
//! \brief Retourne la configuration par défaut à charger
QJsonObject default_configuration() const;
protected:
void closeEvent(QCloseEvent* e) override;
private:
Ui::MainWindow *ui;
Simulation simulation;
......
......@@ -6,7 +6,7 @@
\brief Structure
Fichier contenant la classe Structure, représentant un ensemble de cellules constituant une structure.
**/
**/
#ifndef STRUCTURE_HPP
#define STRUCTURE_HPP
......@@ -18,13 +18,13 @@ Fichier contenant la classe Structure, représentant un ensemble de cellules con
#include "coord.hpp"
/**
/**
\class Structure
\brief Représente une structure
Cette classe permet de représenter un ensemble de cellules constituant une structure, comme un oscillateur ou un glider.
**/
class Structure
Cette classe permet de représenter un ensemble de cellules constituant une structure, comme un oscillateur ou un glider.
**/
class Structure
{
public:
//! Titre de la structure
......@@ -40,7 +40,10 @@ public:
public:
//! \brief Constructeur par défaut, représente une structure vide.
Structure() = default;
Structure()
{
top_left = {0, 0};
}
//! \brief Constructeur acceptant deux itérateurs en argument, pointant vers des std::pair de coordonées et de valeur d'état. Appelle 'load<It>(begin, end)'.
//! \pre It doit pointer vers un std::pair<Coord, int>.
......@@ -56,12 +59,13 @@ public:
void load(It begin, It end)
{
static_assert (std::is_same<typename std::remove_reference<decltype(*begin)>::type, std::pair<Coord, unsigned>>::value ||
std::is_same<typename std::remove_reference<decltype(*begin)>::type, std::pair<const Coord, unsigned>>::value,
"Iterator value type must be std::pair<Coord, unsigned>");
std::is_same<typename std::remove_reference<decltype(*begin)>::type, std::pair<const Coord, unsigned>>::value,
"Iterator value type must be std::pair<Coord, unsigned>");
int min_x, min_y, max_x, max_y;
min_x = min_y = std::numeric_limits<int>::max();
max_x = max_y = std::numeric_limits<int>::min();
bool empty = true;
// Première passe pour calculer les positions minimales et maximales
for (auto it = begin; it != end; ++it)
{
......@@ -69,13 +73,20 @@ public:
if (it->second == 0)
continue;
empty = false;
if (it->first.x > max_x) max_x = it->first.x;
if (it->first.x < min_x) min_x = it->first.x;
if (it->first.y > max_y) max_y = it->first.y;
if (it->first.y < min_y) min_y = it->first.y;
}
top_left.x = min_x; top_left.y = min_y;
if (empty)
top_left = {0, 0};
else
{
top_left.x = min_x; top_left.y = min_y;
}
m_width = max_x - min_x + 1;
m_height = max_y - min_y + 1;
......
......@@ -65,7 +65,11 @@ MainWindow::MainWindow(QWidget *parent)
ui->struct_library->update_cell_pixel_size(ui->grid_view->cell_screen_size());
load_model(default_model());
if (!try_load_saved_state())
{
load_model(default_model());
load_grid_configuration(default_configuration());
}
connect(timer, &QTimer::timeout, this, [this](){
on_nextButton_clicked();
......@@ -93,7 +97,11 @@ void MainWindow::on_simSpeedSlider_valueChanged(int value)
void MainWindow::on_openPatternButton_clicked()
{
load_grid_configuration();
ConfigurationLoadingDialog dialog(m_loaded_model.value("title").toString(), this);
if (!dialog.exec())
return;
load_grid_configuration(dialog.configuration());
}
void MainWindow::on_openRuleButton_clicked()
......@@ -203,7 +211,8 @@ void MainWindow::on_validateGridDim_clicked()
}
ui->grid_view->copy_grid(newGrid);
simulation.reset();
simulation.setGrid(newGrid);
ui->validateGridDim->setEnabled(false);
}
......@@ -236,32 +245,6 @@ void MainWindow::on_randomPatternButton_clicked()
ui->grid_view->copy_grid(newGrid);
}
void MainWindow::on_nbrStatesComboBox_currentTextChanged(const QString &arg1)
{
// A mettre dans la fonction valider
/*
// 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);
}
}
}
*/
}
void MainWindow::on_drawCellButton_clicked()
{
ui->grid_view->fill_selection(ui->nbrStateComboBox->currentIndex());
......@@ -523,6 +506,33 @@ void MainWindow::ui_update_alphabet(const Alphabet &alpha)
}
}
bool MainWindow::try_load_saved_state()
{
QFile file("saved_state.json");
if (!file.open(QFile::ReadOnly | QFile::Text))
{
return false;
}
QTextStream in(&file);
QJsonParseError parseError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(in.readAll().toUtf8(), &parseError);
if(parseError.error != QJsonParseError::NoError)
{
return false;
}
QJsonObject data = jsonDoc.object();
QJsonObject model = data.value("model").toObject();
QJsonObject config = data.value("config").toObject();
if (model.isEmpty() || config.isEmpty())
return false;
load_model(model);
load_grid_configuration(config);
return true;
}
void MainWindow::save_grid_configuration()
{
const Grid& grid = ui->grid_view->get_grid();
......@@ -560,25 +570,23 @@ void MainWindow::save_grid_configuration()
file.close();
}
void MainWindow::load_grid_configuration()
void MainWindow::load_grid_configuration(const QJsonObject& configuration)
{
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));
Grid g(configuration.value("width").toInt(10),
configuration.value("height").toInt(10));
Coord origin;
origin.x = dialog.configuration().value("left").toInt(0);
origin.y = dialog.configuration().value("top").toInt(0);
origin.x = configuration.value("left").toInt(0);
origin.y = configuration.value("top").toInt(0);
RLEStructureReader reader(dialog.configuration().value("data").toString().toStdString());
RLEStructureReader reader(configuration.value("data").toString().toStdString());
Structure s = reader.read_structure();
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());
simulation.reset();
simulation.setGrid(g);
}
QJsonObject MainWindow::default_model() const
......@@ -601,6 +609,63 @@ QJsonObject MainWindow::default_model() const
return doc.object();
}
QJsonObject MainWindow::default_configuration() const
{
const char* json = R"(
{
"data": "x = 2, y = 2\n!",
"height": 50,
"left": 0,
"model": "Game of Life",
"title": "Game of Life Default",
"top": 0,
"width": 50
}
)";
QJsonDocument doc = QJsonDocument::fromJson(QByteArray(json));
return doc.object();
}
void MainWindow::closeEvent(QCloseEvent *e)
{
// Sauvegarder l'état actuel de l'application
const Grid& grid = ui->grid_view->get_grid();
Structure grid_data = grid.to_structure();
RLEStructureWriter writer;
std::string structure_data = writer.save_structure(grid_data);
QJsonObject config_data;
config_data["width"] = (int)grid.get_col();
config_data["height"] = (int)grid.get_rows();
config_data["title"] = "Saved configuration";
config_data["model"] = m_loaded_model.value("title");
config_data["left"] = grid_data.top_left.x;
config_data["top"] = grid_data.top_left.y;
config_data["data"] = QString::fromStdString(structure_data);
QJsonObject model = m_loaded_model;
QJsonObject save_data;
save_data["config"] = config_data;
save_data["model"] = model;
QFile file("saved_state.json");
if (!file.open(QIODevice::WriteOnly | QFile::Text | QFile::Truncate))
{
return;
}
QJsonDocument doc(save_data);
file.write(doc.toJson());
file.close();
QMainWindow::closeEvent(e);
}
void MainWindow::on_saveRuleButton_clicked()
{
save_model();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment