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 @@ ...@@ -115,13 +115,20 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimum">
<number>1</number>
</property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QSpinBox" name="simSpeedSpinbox"/> <widget class="QSpinBox" name="simSpeedSpinbox">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
......
...@@ -59,8 +59,6 @@ private slots: ...@@ -59,8 +59,6 @@ private slots:
//! \brief Créer une nouvelle grille ayant des états aléatoire //! \brief Créer une nouvelle grille ayant des états aléatoire
void on_randomPatternButton_clicked(); 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 //! \brief Applique l'état sélectionné aux cellules sélectionnées de la GridView
void on_drawCellButton_clicked(); void on_drawCellButton_clicked();
...@@ -111,14 +109,25 @@ private: ...@@ -111,14 +109,25 @@ private:
//! \brief Charge un nouvel alphabet et met à jour l'UI. //! \brief Charge un nouvel alphabet et met à jour l'UI.
void ui_update_alphabet(const Alphabet& alph); 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. //! \brief Sauvegarde la configuration actuelle.
void save_grid_configuration(); void save_grid_configuration();
//! \brief Charge une configuration liée au modèle donné. //! \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 //! \brief Retourne le modèle par défaut à charger
QJsonObject default_model() const; QJsonObject default_model() const;
//! \brief Retourne la configuration par défaut à charger
QJsonObject default_configuration() const;
protected:
void closeEvent(QCloseEvent* e) override;
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
Simulation simulation; Simulation simulation;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
\brief Structure \brief Structure
Fichier contenant la classe Structure, représentant un ensemble de cellules constituant une structure. Fichier contenant la classe Structure, représentant un ensemble de cellules constituant une structure.
**/ **/
#ifndef STRUCTURE_HPP #ifndef STRUCTURE_HPP
#define STRUCTURE_HPP #define STRUCTURE_HPP
...@@ -18,13 +18,13 @@ Fichier contenant la classe Structure, représentant un ensemble de cellules con ...@@ -18,13 +18,13 @@ Fichier contenant la classe Structure, représentant un ensemble de cellules con
#include "coord.hpp" #include "coord.hpp"
/** /**
\class Structure \class Structure
\brief Représente une 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. Cette classe permet de représenter un ensemble de cellules constituant une structure, comme un oscillateur ou un glider.
**/ **/
class Structure class Structure
{ {
public: public:
//! Titre de la structure //! Titre de la structure
...@@ -40,7 +40,10 @@ public: ...@@ -40,7 +40,10 @@ public:
public: public:
//! \brief Constructeur par défaut, représente une structure vide. //! \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)'. //! \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>. //! \pre It doit pointer vers un std::pair<Coord, int>.
...@@ -56,12 +59,13 @@ public: ...@@ -56,12 +59,13 @@ public:
void load(It begin, It end) void load(It begin, It end)
{ {
static_assert (std::is_same<typename std::remove_reference<decltype(*begin)>::type, std::pair<Coord, unsigned>>::value || 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, 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>"); "Iterator value type must be std::pair<Coord, unsigned>");
int min_x, min_y, max_x, max_y; int min_x, min_y, max_x, max_y;
min_x = min_y = std::numeric_limits<int>::max(); min_x = min_y = std::numeric_limits<int>::max();
max_x = max_y = std::numeric_limits<int>::min(); max_x = max_y = std::numeric_limits<int>::min();
bool empty = true;
// Première passe pour calculer les positions minimales et maximales // Première passe pour calculer les positions minimales et maximales
for (auto it = begin; it != end; ++it) for (auto it = begin; it != end; ++it)
{ {
...@@ -69,13 +73,20 @@ public: ...@@ -69,13 +73,20 @@ public:
if (it->second == 0) if (it->second == 0)
continue; continue;
empty = false;
if (it->first.x > max_x) max_x = it->first.x; 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.x < min_x) min_x = it->first.x;
if (it->first.y > max_y) max_y = it->first.y; if (it->first.y > max_y) max_y = it->first.y;
if (it->first.y < min_y) min_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_width = max_x - min_x + 1;
m_height = max_y - min_y + 1; m_height = max_y - min_y + 1;
......
...@@ -65,7 +65,11 @@ MainWindow::MainWindow(QWidget *parent) ...@@ -65,7 +65,11 @@ MainWindow::MainWindow(QWidget *parent)
ui->struct_library->update_cell_pixel_size(ui->grid_view->cell_screen_size()); 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](){ connect(timer, &QTimer::timeout, this, [this](){
on_nextButton_clicked(); on_nextButton_clicked();
...@@ -93,7 +97,11 @@ void MainWindow::on_simSpeedSlider_valueChanged(int value) ...@@ -93,7 +97,11 @@ void MainWindow::on_simSpeedSlider_valueChanged(int value)
void MainWindow::on_openPatternButton_clicked() 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() void MainWindow::on_openRuleButton_clicked()
...@@ -203,7 +211,8 @@ void MainWindow::on_validateGridDim_clicked() ...@@ -203,7 +211,8 @@ void MainWindow::on_validateGridDim_clicked()
} }
ui->grid_view->copy_grid(newGrid); ui->grid_view->copy_grid(newGrid);
simulation.reset();
simulation.setGrid(newGrid);
ui->validateGridDim->setEnabled(false); ui->validateGridDim->setEnabled(false);
} }
...@@ -236,32 +245,6 @@ void MainWindow::on_randomPatternButton_clicked() ...@@ -236,32 +245,6 @@ void MainWindow::on_randomPatternButton_clicked()
ui->grid_view->copy_grid(newGrid); 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() void MainWindow::on_drawCellButton_clicked()
{ {
ui->grid_view->fill_selection(ui->nbrStateComboBox->currentIndex()); ui->grid_view->fill_selection(ui->nbrStateComboBox->currentIndex());
...@@ -523,6 +506,33 @@ void MainWindow::ui_update_alphabet(const Alphabet &alpha) ...@@ -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() void MainWindow::save_grid_configuration()
{ {
const Grid& grid = ui->grid_view->get_grid(); const Grid& grid = ui->grid_view->get_grid();
...@@ -560,25 +570,23 @@ void MainWindow::save_grid_configuration() ...@@ -560,25 +570,23 @@ void MainWindow::save_grid_configuration()
file.close(); file.close();
} }
void MainWindow::load_grid_configuration() void MainWindow::load_grid_configuration(const QJsonObject& configuration)
{ {
ConfigurationLoadingDialog dialog(m_loaded_model.value("title").toString(), this); Grid g(configuration.value("width").toInt(10),
if (!dialog.exec()) configuration.value("height").toInt(10));
return;
Grid g(dialog.configuration().value("width").toInt(10),
dialog.configuration().value("height").toInt(10));
Coord origin; Coord origin;
origin.x = dialog.configuration().value("left").toInt(0); origin.x = configuration.value("left").toInt(0);
origin.y = dialog.configuration().value("top").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(); Structure s = reader.read_structure();
ui->grid_view->copy_grid(g); ui->grid_view->copy_grid(g);
ui->grid_view->paste_structure_at(origin, s); ui->grid_view->paste_structure_at(origin, s);
ui->widthSpinBox->setValue(g.get_col()); ui->widthSpinBox->setValue(g.get_col());
ui->heightSpinBox->setValue(g.get_rows()); ui->heightSpinBox->setValue(g.get_rows());
simulation.reset();
simulation.setGrid(g);
} }
QJsonObject MainWindow::default_model() const QJsonObject MainWindow::default_model() const
...@@ -601,6 +609,63 @@ QJsonObject MainWindow::default_model() const ...@@ -601,6 +609,63 @@ QJsonObject MainWindow::default_model() const
return doc.object(); 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() void MainWindow::on_saveRuleButton_clicked()
{ {
save_model(); save_model();
......
Supports Markdown
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