Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
LO21_Pin_Noir_Boucher_Bouri_Detree
CellulutLO21
Commits
03f5f426
Commit
03f5f426
authored
May 24, 2021
by
Yann Boucher
Browse files
Implemented dialog for loading a model, and behavior for customizing it
parent
0cb352ba
Changes
8
Show whitespace changes
Inline
Side-by-side
forms/interface.ui
View file @
03f5f426
...
...
@@ -6,8 +6,8 @@
<rect>
<x>
0
</x>
<y>
0
</y>
<width>
1
101
</width>
<height>
7
06
</height>
<width>
1
092
</width>
<height>
7
54
</height>
</rect>
</property>
<property
name=
"windowTitle"
>
...
...
@@ -51,7 +51,7 @@
</widget>
</item>
<item>
<widget
class=
"QGroupBox"
name=
"
groupBox
"
>
<widget
class=
"QGroupBox"
name=
"
simulation_tab
"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Preferred"
vsizetype=
"Fixed"
>
<horstretch>
0
</horstretch>
...
...
@@ -395,15 +395,28 @@ pattern recorded :</string>
<property
name=
"title"
>
<string>
Rules
</string>
</property>
<layout
class=
"QVBoxLayout"
name=
"verticalLayout_4"
>
<layout
class=
"QGridLayout"
name=
"gridLayout_3"
>
<item
row=
"4"
column=
"0"
colspan=
"3"
>
<widget
class=
"QGroupBox"
name=
"rule_settings"
>
<property
name=
"enabled"
>
<bool>
false
</bool>
</property>
<property
name=
"title"
>
<string>
Settings
</string>
</property>
<layout
class=
"QFormLayout"
name=
"formLayout"
>
<item
row=
"2"
column=
"0"
>
<layout
class=
"QHBoxLayout"
name=
"horizontalLayout_2"
>
<item>
<widget
class=
"Q
PushButton"
name=
"openRuleButton
"
>
<widget
class=
"Q
Label"
name=
"transitionFunctionLabel
"
>
<property
name=
"text"
>
<string>
(file) Open rule
</string>
<string>
Transition function :
</string>
</property>
</widget>
</item>
<item>
</layout>
</item>
<item
row=
"0"
column=
"0"
colspan=
"2"
>
<layout
class=
"QGridLayout"
name=
"statesNeighborhoodLayout_3"
>
<item
row=
"1"
column=
"0"
>
<widget
class=
"QLabel"
name=
"neighborhoodLabel"
>
...
...
@@ -507,35 +520,24 @@ pattern recorded :</string>
</item>
</layout>
</item>
<item>
<layout
class=
"QHBoxLayout"
name=
"horizontalLayout_2"
>
<item>
<widget
class=
"QLabel"
name=
"transitionFunctionLabel"
>
<property
name=
"text"
>
<string>
Transition function :
</string>
</property>
</widget>
</item>
<item>
<item
row=
"2"
column=
"1"
>
<widget
class=
"QComboBox"
name=
"transition_list"
/>
</item>
</layout>
</item>
<item>
<item
row=
"3"
column=
"0"
colspan=
"2"
>
<widget
class=
"QGroupBox"
name=
"rule_settings_area"
>
<property
name=
"title"
>
<string>
Transition rule settings
</string>
</property>
</widget>
</item>
<item>
<item
row=
"4"
column=
"0"
colspan=
"2"
>
<widget
class=
"QLabel"
name=
"informationLabel"
>
<property
name=
"text"
>
<string>
New rule must be saved before running simulation
</string>
</property>
</widget>
</item>
<item>
<item
row=
"5"
column=
"0"
colspan=
"2"
>
<widget
class=
"QPushButton"
name=
"saveRuleButton"
>
<property
name=
"text"
>
<string>
Save rule
</string>
...
...
@@ -545,6 +547,47 @@ pattern recorded :</string>
</layout>
</widget>
</item>
<item
row=
"0"
column=
"0"
colspan=
"3"
>
<widget
class=
"QPushButton"
name=
"openRuleButton"
>
<property
name=
"text"
>
<string>
Load rule
</string>
</property>
</widget>
</item>
<item
row=
"1"
column=
"2"
>
<widget
class=
"QPushButton"
name=
"customize_button"
>
<property
name=
"text"
>
<string>
Customize...
</string>
</property>
</widget>
</item>
<item
row=
"1"
column=
"0"
colspan=
"2"
>
<layout
class=
"QFormLayout"
name=
"formLayout_2"
>
<property
name=
"labelAlignment"
>
<set>
Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
</set>
</property>
<property
name=
"formAlignment"
>
<set>
Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
</set>
</property>
<item
row=
"0"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label"
>
<property
name=
"text"
>
<string>
Name :
</string>
</property>
</widget>
</item>
<item
row=
"0"
column=
"1"
>
<widget
class=
"QLabel"
name=
"rule_name"
>
<property
name=
"text"
>
<string>
RuleName
</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
...
...
@@ -577,7 +620,7 @@ pattern recorded :</string>
<rect>
<x>
0
</x>
<y>
0
</y>
<width>
1
101
</width>
<width>
1
092
</width>
<height>
25
</height>
</rect>
</property>
...
...
forms/modelloadingdialog.ui
0 → 100644
View file @
03f5f426
<?xml version="1.0" encoding="UTF-8"?>
<ui
version=
"4.0"
>
<class>
ModelLoadingDialog
</class>
<widget
class=
"QDialog"
name=
"ModelLoadingDialog"
>
<property
name=
"geometry"
>
<rect>
<x>
0
</x>
<y>
0
</y>
<width>
385
</width>
<height>
639
</height>
</rect>
</property>
<property
name=
"windowTitle"
>
<string>
Dialog
</string>
</property>
<layout
class=
"QVBoxLayout"
name=
"verticalLayout"
>
<item>
<widget
class=
"QTreeWidget"
name=
"tree"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Expanding"
vsizetype=
"Expanding"
>
<horstretch>
0
</horstretch>
<verstretch>
5
</verstretch>
</sizepolicy>
</property>
<attribute
name=
"headerVisible"
>
<bool>
false
</bool>
</attribute>
<column>
<property
name=
"text"
>
<string
notr=
"true"
>
1
</string>
</property>
</column>
</widget>
</item>
<item>
<widget
class=
"QFrame"
name=
"frame"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Preferred"
vsizetype=
"Preferred"
>
<horstretch>
0
</horstretch>
<verstretch>
3
</verstretch>
</sizepolicy>
</property>
<property
name=
"frameShape"
>
<enum>
QFrame::StyledPanel
</enum>
</property>
<property
name=
"frameShadow"
>
<enum>
QFrame::Raised
</enum>
</property>
<layout
class=
"QFormLayout"
name=
"formLayout"
>
<item
row=
"0"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label"
>
<property
name=
"text"
>
<string>
Title :
</string>
</property>
</widget>
</item>
<item
row=
"0"
column=
"1"
>
<widget
class=
"QLabel"
name=
"title"
>
<property
name=
"text"
>
<string/>
</property>
</widget>
</item>
<item
row=
"1"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label_struct_author"
>
<property
name=
"text"
>
<string>
Author :
</string>
</property>
</widget>
</item>
<item
row=
"1"
column=
"1"
>
<widget
class=
"QLabel"
name=
"author"
>
<property
name=
"text"
>
<string/>
</property>
</widget>
</item>
<item
row=
"2"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label_2"
>
<property
name=
"text"
>
<string>
Date :
</string>
</property>
</widget>
</item>
<item
row=
"2"
column=
"1"
>
<widget
class=
"QLabel"
name=
"date"
>
<property
name=
"text"
>
<string/>
</property>
</widget>
</item>
<item
row=
"3"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label_3"
>
<property
name=
"text"
>
<string>
Description :
</string>
</property>
<property
name=
"buddy"
>
<cstring>
desc
</cstring>
</property>
</widget>
</item>
<item
row=
"3"
column=
"1"
>
<widget
class=
"QPlainTextEdit"
name=
"desc"
>
<property
name=
"enabled"
>
<bool>
true
</bool>
</property>
<property
name=
"readOnly"
>
<bool>
true
</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget
class=
"QDialogButtonBox"
name=
"buttonBox"
>
<property
name=
"enabled"
>
<bool>
true
</bool>
</property>
<property
name=
"orientation"
>
<enum>
Qt::Horizontal
</enum>
</property>
<property
name=
"standardButtons"
>
<set>
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>
buttonBox
</sender>
<signal>
accepted()
</signal>
<receiver>
ModelLoadingDialog
</receiver>
<slot>
accept()
</slot>
<hints>
<hint
type=
"sourcelabel"
>
<x>
229
</x>
<y>
617
</y>
</hint>
<hint
type=
"destinationlabel"
>
<x>
157
</x>
<y>
274
</y>
</hint>
</hints>
</connection>
<connection>
<sender>
buttonBox
</sender>
<signal>
rejected()
</signal>
<receiver>
ModelLoadingDialog
</receiver>
<slot>
reject()
</slot>
<hints>
<hint
type=
"sourcelabel"
>
<x>
297
</x>
<y>
623
</y>
</hint>
<hint
type=
"destinationlabel"
>
<x>
286
</x>
<y>
274
</y>
</hint>
</hints>
</connection>
</connections>
</ui>
include/interface.hpp
View file @
03f5f426
...
...
@@ -66,6 +66,8 @@ private slots:
void
on_saveRuleButton_clicked
();
void
on_customize_button_clicked
();
private:
//! \brief Initialiser la liste des transitions et voisinages disponibles
void
init_transition_neighborhood_list
();
...
...
@@ -73,6 +75,20 @@ private:
//! \brief Mets à jour le widget contenant les paramètres pour la règle de transition choisie
void
update_transition_settings
();
//! \brief Configure pour activer la customisation d'une règle actuelle
void
enable_rule_customization
();
//! \brief Configure pour désactiver la customisation d'une règle actuelle
void
disable_rule_customization
();
//! \brief Charge un modèle d'automate à partir d'un objet JSON
void
load_model
(
const
QJsonObject
&
obj
);
//! \brief Déclenche la confirmation et la sauvegarde du modèle édité actuel
void
save_model
();
//! \brief Retourne le modèle par défaut à charger
QJsonObject
default_model
()
const
;
private:
Ui
::
MainWindow
*
ui
;
};
...
...
include/modelloadingdialog.hpp
0 → 100644
View file @
03f5f426
#ifndef MODELLOADINGDIALOG_HPP
#define MODELLOADINGDIALOG_HPP
#include <QDialog>
#include <QDir>
#include <QTreeWidgetItem>
#include <QFileSystemWatcher>
#include <QJsonObject>
namespace
Ui
{
class
ModelLoadingDialog
;
}
class
ModelLoadingException
:
public
std
::
exception
{
std
::
string
_msg
;
public:
ModelLoadingException
(
const
std
::
string
&
msg
)
:
_msg
(
msg
){}
virtual
const
char
*
what
()
const
noexcept
override
{
return
_msg
.
c_str
();
}
};
class
ModelLoadingDialog
:
public
QDialog
{
Q_OBJECT
public:
explicit
ModelLoadingDialog
(
QWidget
*
parent
=
nullptr
);
~
ModelLoadingDialog
();
//! \brief Retoure le modèle choisi en tant qu'objet JSON.
QJsonObject
model
()
const
;
protected:
void
done
(
int
r
);
private:
void
load_models
();
QTreeWidgetItem
*
add_directory_contents
(
const
QDir
&
dir
);
private
slots
:
void
update_info
(
QTreeWidgetItem
*
item
,
int
column
);
private:
Ui
::
ModelLoadingDialog
*
ui
;
QFileSystemWatcher
m_watcher
;
QJsonObject
m_current_model
;
};
#endif // MODELLOADINGDIALOG_HPP
include/property.hpp
View file @
03f5f426
...
...
@@ -159,7 +159,7 @@ struct IntegerProperty : public PropertyImpl<IntegerProperty>
public:
//! \brief Construit un objet IntegerProperty avec une valeur min et une valeur max, non borné par défaut.
IntegerProperty
(
int
min_value
=
std
::
numeric_limits
<
int
>::
min
(),
int
max_value
=
std
::
numeric_limits
<
int
>::
max
())
:
prop_min
(
min_value
),
prop_max
(
max_value
)
:
val
(
min_value
),
prop_min
(
min_value
),
prop_max
(
max_value
)
{}
public:
...
...
src/interface.cpp
View file @
03f5f426
...
...
@@ -7,6 +7,7 @@
#include "transitionrule.hpp"
#include "neighborhoodrule.hpp"
#include "propertyvisitors.hpp"
#include "modelloadingdialog.hpp"
#include <QJsonArray>
...
...
@@ -26,6 +27,8 @@ MainWindow::MainWindow(QWidget *parent)
{
update_transition_settings
();
});
ui
->
struct_library
->
update_cell_pixel_size
(
ui
->
grid_view
->
cell_pixel_size
());
load_model
(
default_model
());
}
MainWindow
::~
MainWindow
()
...
...
@@ -47,20 +50,23 @@ void MainWindow::on_simSpeedSlider_valueChanged(int value)
void
MainWindow
::
on_openPatternButton_clicked
()
{
QString
fileName
=
QFileDialog
::
getOpenFileName
(
this
,
tr
(
"Open File"
),
"
/home
"
,
tr
(
"Pattern
F
ile (*.
pat
)"
));
QString
fileName
=
QFileDialog
::
getOpenFileName
(
this
,
tr
(
"Open File"
),
""
,
tr
(
"Pattern
f
ile (*.
json
)"
));
if
(
fileName
==
""
){
// L'utilisateur a annulé la recherche
return
;
}
// Indiquer qu'un nouveau pattern vient d'être ouvert
}
void
MainWindow
::
on_openRuleButton_clicked
()
{
QString
fileName
=
QFileDialog
::
getOpenFileName
(
this
,
tr
(
"Open File"
),
"/home"
,
tr
(
"RuleFile (*.rule)"
));
if
(
fileName
==
""
){
// L'utilisateur a annulé la recherche
}
// Indiquer qu'une nouvelle règle vient d'être ouverte. La règle est sauvegardé, donc on peut lancer la simulation
ModelLoadingDialog
dialog
(
this
);
if
(
!
dialog
.
exec
())
return
;
load_model
(
dialog
.
model
());
}
void
MainWindow
::
on_neighborhood_list_currentTextChanged
(
const
QString
&
arg1
)
...
...
@@ -253,25 +259,54 @@ static std::unique_ptr<TransitionRule> transition_rule;
void
MainWindow
::
update_transition_settings
()
{
std
::
string
selected
=
ui
->
transition_list
->
currentText
().
toStdString
();
auto
rule
=
Factory
<
TransitionRule
>::
make
(
selected
);
if
(
!
rule
)
transition_
rule
=
Factory
<
TransitionRule
>::
make
(
selected
);
if
(
!
transition_
rule
)
return
;
if
(
rule
->
get_properties
().
size
()
==
0
)
if
(
transition_
rule
->
get_properties
().
size
()
==
0
)
ui
->
rule_settings_area
->
hide
();
else
{
ui
->
rule_settings_area
->
show
();
UIBuilderVisitor
visit
(
ui
->
rule_settings_area
);
for
(
auto
&
prop
:
rule
->
get_properties
())
for
(
auto
&
prop
:
transition_
rule
->
get_properties
())
prop
->
accept
(
visit
);
}
}
transition_rule
=
std
::
move
(
rule
);
void
MainWindow
::
enable_rule_customization
()
{
ui
->
simulation_tab
->
setEnabled
(
false
);
ui
->
customize_button
->
setEnabled
(
false
);
ui
->
rule_settings
->
setEnabled
(
true
);
}
void
MainWindow
::
on_saveRuleButton_clicked
()
void
MainWindow
::
disable_rule_customization
()
{
ui
->
simulation_tab
->
setEnabled
(
true
);
ui
->
customize_button
->
setEnabled
(
true
);
ui
->
rule_settings
->
setEnabled
(
false
);
}
void
MainWindow
::
load_model
(
const
QJsonObject
&
obj
)
{
ui
->
rule_name
->
setText
(
obj
.
value
(
"title"
).
toString
());
// TODO : load alphabet
ui
->
transition_list
->
setCurrentText
(
obj
.
value
(
"transition_name"
).
toString
());
update_transition_settings
();
disable_rule_customization
();
PropertyLoaderVisitor
loader
(
obj
.
value
(
"transition_data"
).
toObject
());
for
(
auto
&
prop
:
transition_rule
->
get_properties
())
prop
->
accept
(
loader
);
UIBuilderVisitor
visit
(
ui
->
rule_settings_area
);
for
(
auto
&
prop
:
transition_rule
->
get_properties
())
prop
->
accept
(
visit
);
}
void
MainWindow
::
save_model
()
{
SavingDialog
dialog
(
this
);
if
(
!
dialog
.
exec
())
...
...
@@ -304,4 +339,27 @@ void MainWindow::on_saveRuleButton_clicked()
file
.
open
(
QFile
::
WriteOnly
|
QFile
::
Text
|
QFile
::
Truncate
);
file
.
write
(
doc
.
toJson
());
file
.
close
();
ui
->
rule_name
->
setText
(
dialog
.
titre
());
disable_rule_customization
();
}
QJsonObject
MainWindow
::
default_model
()
const
{
QJsonObject
obj
;
obj
[
"title"
]
=
"Game of Life"
;
obj
[
"transition_name"
]
=
"Game of Life"
;
obj
[
"transition_data"
]
=
QJsonObject
();
return
obj
;
}
void
MainWindow
::
on_saveRuleButton_clicked
()
{
save_model
();
}
void
MainWindow
::
on_customize_button_clicked
()
{
enable_rule_customization
();
}
src/modelloadingdialog.cpp
0 → 100644
View file @
03f5f426
#include "modelloadingdialog.hpp"
#include "ui_modelloadingdialog.h"
#include <QJsonDocument>
#include <QMessageBox>
ModelLoadingDialog
::
ModelLoadingDialog
(
QWidget
*
parent
)
:
QDialog
(
parent
),
ui
(
new
Ui
::
ModelLoadingDialog
)
{
ui
->
setupUi
(
this
);
load_models
();
connect
(
ui
->
tree
,
&
QTreeWidget
::
itemClicked
,
this
,
&
ModelLoadingDialog
::
update_info
);
connect
(
&
m_watcher
,
&
QFileSystemWatcher
::
directoryChanged
,
this
,
[
this
](
const
QString
&
)
{
load_models
();
});
}
ModelLoadingDialog
::~
ModelLoadingDialog
()
{
delete
ui
;
}
QJsonObject
ModelLoadingDialog
::
model
()
const
{
return
m_current_model
;
}
void
ModelLoadingDialog
::
load_models
()
{
// clear the previously watched directories
m_watcher
.
removePaths
(
m_watcher
.
directories
());
QTreeWidgetItem
*
model_list
=
add_directory_contents
(
QDir
(
"models/"
));
model_list
->
setText
(
0
,
"Models"
);
ui
->
tree
->
clear
();
ui
->
tree
->
addTopLevelItem
(
model_list
);
model_list
->
setExpanded
(
true
);
}
QTreeWidgetItem
*
ModelLoadingDialog
::
add_directory_contents
(
const
QDir
&
dir
)
{
QTreeWidgetItem
*
root
=
new
QTreeWidgetItem
;
QFileInfoList
dirs
=
dir
.
entryInfoList
(
QStringList
(),
QDir
::
Dirs
|
QDir
::
NoDotAndDotDot
);
Q_FOREACH
(
QFileInfo
dir
,
dirs
)
{
QTreeWidgetItem
*
child
=
add_directory_contents
(
QDir
(
dir
.
absoluteFilePath
()));
// empty directory
if
(
child
->
childCount
()
==
0
)
continue
;
child
->
setText
(
0
,
dir
.
fileName
());
root
->
addChild
(
child
);
}
QFileInfoList
files
=
dir
.
entryInfoList
(
QStringList
()
<<
"*.json"
,
QDir
::
Files
);
Q_FOREACH
(
QFileInfo
file
,
files
)
{
QTreeWidgetItem
*
child
=
new
QTreeWidgetItem
();
child
->
setText
(
0
,
file
.
fileName
());
// data is the complete filepath of the structure, store it so it can be easily accessed when an item is selected
child
->
setData
(
0
,
Qt
::
UserRole
,
file
.
absoluteFilePath
());
root
->
addChild
(
child
);
}
// register this directory for filesystem watching
m_watcher
.
addPath
(
dir
.
absolutePath
());
return
root
;
}
void
ModelLoadingDialog
::
update_info
(
QTreeWidgetItem
*
item
,
int
column
)
{
(
void
)
column
;