From d3718bde005fcaea34640211078aec4c19d473e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Thu, 5 Jul 2012 11:37:50 +0000 Subject: [PATCH] paysages : Layer sorting (WIP). git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@377 b1fd45b6-86a6-48da-8261-f70d1f35bdcc --- gui_qt/baseform.cpp | 289 ++++++++++++++++++++++++---------------- gui_qt/baseform.h | 37 ++--- gui_qt/formclouds.cpp | 2 + gui_qt/formtextures.cpp | 2 + images/layer_add.png | Bin 0 -> 3746 bytes images/layer_del.png | Bin 0 -> 3682 bytes images/layer_down.png | Bin 0 -> 3847 bytes images/layer_up.png | Bin 0 -> 3833 bytes 8 files changed, 199 insertions(+), 131 deletions(-) create mode 100644 images/layer_add.png create mode 100644 images/layer_del.png create mode 100644 images/layer_down.png create mode 100644 images/layer_up.png diff --git a/gui_qt/baseform.cpp b/gui_qt/baseform.cpp index 702ec37..7708ead 100644 --- a/gui_qt/baseform.cpp +++ b/gui_qt/baseform.cpp @@ -20,8 +20,8 @@ BaseForm::BaseForm(QWidget* parent, bool auto_apply, bool with_layers) : QWidget QWidget* layers; QLabel* label; - this->auto_apply = auto_apply; - this->with_layers = with_layers; + this->_auto_apply = auto_apply; + this->_with_layers = with_layers; setLayout(new QHBoxLayout()); setObjectName("_base_form_"); @@ -31,6 +31,8 @@ BaseForm::BaseForm(QWidget* parent, bool auto_apply, bool with_layers) : QWidget control->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); layout()->addWidget(control); + _layer_count = 0; + if (with_layers) { layers = new QWidget(this); @@ -41,58 +43,74 @@ BaseForm::BaseForm(QWidget* parent, bool auto_apply, bool with_layers) : QWidget label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); layers->layout()->addWidget(label); - layer_list = new QComboBox(layers); - layers->layout()->addWidget(layer_list); - QObject::connect(layer_list, SIGNAL(currentIndexChanged(int)), this, SLOT(layerListChanged())); + _layer_list = new QComboBox(layers); + layers->layout()->addWidget(_layer_list); + QObject::connect(_layer_list, SIGNAL(currentIndexChanged(int)), this, SLOT(layerListChanged())); - layer_new = new QPushButton(tr("Add layer"), layers); - layers->layout()->addWidget(layer_new); - QObject::connect(layer_new, SIGNAL(clicked()), this, SLOT(layerAddClicked())); + _layer_new = new QPushButton(QIcon("images/layer_add.png"), "", layers); + _layer_new->setToolTip(tr("Add layer")); + _layer_new->setMaximumSize(30, 30); + layers->layout()->addWidget(_layer_new); + QObject::connect(_layer_new, SIGNAL(clicked()), this, SLOT(layerAddClicked())); - layer_del = new QPushButton(tr("Delete layer"), layers); - layers->layout()->addWidget(layer_del); - QObject::connect(layer_del, SIGNAL(clicked()), this, SLOT(layerDelClicked())); + _layer_del = new QPushButton(QIcon("images/layer_del.png"), "", layers); + _layer_del->setToolTip(tr("Delete layer")); + _layer_del->setMaximumSize(30, 30); + layers->layout()->addWidget(_layer_del); + QObject::connect(_layer_del, SIGNAL(clicked()), this, SLOT(layerDelClicked())); + + _layer_up = new QPushButton(QIcon("images/layer_up.png"), "", layers); + _layer_up->setToolTip(tr("Move layer upward")); + _layer_up->setMaximumSize(30, 30); + layers->layout()->addWidget(_layer_up); + QObject::connect(_layer_up, SIGNAL(clicked()), this, SLOT(layerUpClicked())); + + _layer_down = new QPushButton(QIcon("images/layer_down.png"), "", layers); + _layer_down->setToolTip(tr("Move layer downward")); + _layer_down->setMaximumSize(30, 30); + layers->layout()->addWidget(_layer_down); + QObject::connect(_layer_down, SIGNAL(clicked()), this, SLOT(layerDownClicked())); control->layout()->addWidget(layers); - control->layout()->setAlignment(buttons, Qt::AlignTop); + control->layout()->setAlignment(_buttons, Qt::AlignTop); } - previews = new QWidget(this); - previews->setLayout(new QVBoxLayout()); - previews->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - layout()->addWidget(previews); - layout()->setAlignment(previews, Qt::AlignTop); + _previews = new QWidget(this); + _previews->setLayout(new QVBoxLayout()); + _previews->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + layout()->addWidget(_previews); + layout()->setAlignment(_previews, Qt::AlignTop); - form = new QWidget(this); - form->setLayout(new QHBoxLayout()); - control->layout()->addWidget(form); - control->layout()->setAlignment(form, Qt::AlignTop); + _form = new QWidget(this); + _form->setLayout(new QHBoxLayout()); + control->layout()->addWidget(_form); + control->layout()->setAlignment(_form, Qt::AlignTop); - form_labels = new QWidget(form); - form_labels->setLayout(new QVBoxLayout()); - form->layout()->addWidget(form_labels); + _form_labels = new QWidget(_form); + _form_labels->setLayout(new QVBoxLayout()); + _form->layout()->addWidget(_form_labels); - form_previews = new QWidget(form); - form_previews->setLayout(new QVBoxLayout()); - form->layout()->addWidget(form_previews); + _form_previews = new QWidget(_form); + _form_previews->setLayout(new QVBoxLayout()); + _form->layout()->addWidget(_form_previews); - form_controls = new QWidget(form); - form_controls->setLayout(new QVBoxLayout()); - form->layout()->addWidget(form_controls); + _form_controls = new QWidget(_form); + _form_controls->setLayout(new QVBoxLayout()); + _form->layout()->addWidget(_form_controls); - buttons = new QWidget(this); - buttons->setLayout(new QHBoxLayout()); - control->layout()->addWidget(buttons); - control->layout()->setAlignment(buttons, Qt::AlignBottom); + _buttons = new QWidget(this); + _buttons->setLayout(new QHBoxLayout()); + control->layout()->addWidget(_buttons); + control->layout()->setAlignment(_buttons, Qt::AlignBottom); - button_apply = addButton(tr("Apply")); - button_apply->setEnabled(false); - connect(button_apply, SIGNAL(clicked()), this, SLOT(applyConfig())); - button_revert = addButton(tr("Revert")); - button_revert->setEnabled(false); - connect(button_revert, SIGNAL(clicked()), this, SLOT(revertConfig())); + _button_apply = addButton(tr("Apply")); + _button_apply->setEnabled(false); + connect(_button_apply, SIGNAL(clicked()), this, SLOT(applyConfig())); + _button_revert = addButton(tr("Revert")); + _button_revert->setEnabled(false); + connect(_button_revert, SIGNAL(clicked()), this, SLOT(revertConfig())); - auto_update_previews = true; + _auto_update_previews = true; if (auto_apply) { @@ -102,15 +120,15 @@ BaseForm::BaseForm(QWidget* parent, bool auto_apply, bool with_layers) : QWidget void BaseForm::hideButtons() { - button_apply->hide(); - button_revert->hide(); + _button_apply->hide(); + _button_revert->hide(); } void BaseForm::savePack(PackStream* stream) { // Save previews status // TODO Ensure same order in save and load - QList list_previews = previews->findChildren("_form_preview_"); + QList list_previews = _previews->findChildren("_form_preview_"); for (int i = 0; i < list_previews.size(); i++) { list_previews[i]->savePack(stream); @@ -121,7 +139,7 @@ void BaseForm::loadPack(PackStream* stream) { // Load previews status // TODO Ensure same order in save and load - QList list_previews = previews->findChildren("_form_preview_"); + QList list_previews = _previews->findChildren("_form_preview_"); for (int i = 0; i < list_previews.size(); i++) { list_previews[i]->loadPack(stream); @@ -130,20 +148,20 @@ void BaseForm::loadPack(PackStream* stream) void BaseForm::configChangeEvent() { - if (auto_apply) + if (_auto_apply) { applyConfig(); } else { - button_apply->setEnabled(true); - button_revert->setEnabled(true); + _button_apply->setEnabled(true); + _button_revert->setEnabled(true); } - QList inputs = form->findChildren("_form_input_"); + QList inputs = _form->findChildren("_form_input_"); for (int i = 0; i < inputs.size(); i++) { - if (with_layers && layer_list->count() == 0) + if (_with_layers && _layer_list->count() == 0) { inputs[i]->checkVisibility(false); } @@ -153,7 +171,7 @@ void BaseForm::configChangeEvent() } } - if (auto_update_previews) + if (_auto_update_previews) { updatePreviews(); } @@ -161,70 +179,129 @@ void BaseForm::configChangeEvent() void BaseForm::revertConfig() { - QList inputs = form->findChildren("_form_input_"); + QList inputs = _form->findChildren("_form_input_"); for (int i = 0; i < inputs.size(); i++) { inputs[i]->revert(); } - if (with_layers) + if (_with_layers) { - if (layer_list->currentIndex() < 0 && layer_list->count() > 0) + if (_layer_list->currentIndex() < 0 && _layer_list->count() > 0) { - layer_list->setCurrentIndex(0); + _layer_list->setCurrentIndex(0); } } updatePreviews(); //configChangeEvent(); - button_apply->setEnabled(false); - button_revert->setEnabled(false); + _button_apply->setEnabled(false); + _button_revert->setEnabled(false); } void BaseForm::applyConfig() { - button_apply->setEnabled(false); - button_revert->setEnabled(false); + _button_apply->setEnabled(false); + _button_revert->setEnabled(false); emit(configApplied()); } +void BaseForm::rebuildLayerList() +{ + if (_with_layers) + { + int selected = _layer_list->currentIndex(); + _layer_list->clear(); + + for (int i = 0; i < _layer_count; i++) + { + _layer_list->addItem(QString(tr("Layer %1")).arg(i + 1)); + } + if (selected >= 0) + { + if (selected >= _layer_count) + { + _layer_list->setCurrentIndex(_layer_count - 1); + } + else + { + _layer_list->setCurrentIndex(selected); + } + } + } +} + void BaseForm::layerAddClicked() { layerAddedEvent(); - button_apply->setEnabled(true); - button_revert->setEnabled(true); + rebuildLayerList(); + _layer_list->setCurrentIndex(_layer_list->count() - 1); + + _button_apply->setEnabled(true); + _button_revert->setEnabled(true); } void BaseForm::layerDelClicked() { - layerDeletedEvent(layer_list->currentIndex()); + if (_layer_list->currentIndex() >= 0) + { + layerDeletedEvent(_layer_list->currentIndex()); + + rebuildLayerList(); + + _button_apply->setEnabled(true); + _button_revert->setEnabled(true); + } +} - button_apply->setEnabled(true); - button_revert->setEnabled(true); +void BaseForm::layerUpClicked() +{ + if (_layer_list->currentIndex() < _layer_count - 1) + { + layerMovedEvent(_layer_list->currentIndex(), _layer_list->currentIndex() + 1); + + rebuildLayerList(); + + _button_apply->setEnabled(true); + _button_revert->setEnabled(true); + } +} + +void BaseForm::layerDownClicked() +{ + if (_layer_list->currentIndex() > 0) + { + layerMovedEvent(_layer_list->currentIndex(), _layer_list->currentIndex() - 1); + + rebuildLayerList(); + + _button_apply->setEnabled(true); + _button_revert->setEnabled(true); + } } void BaseForm::layerListChanged() { - bool changed = button_apply->isEnabled(); + bool changed = _button_apply->isEnabled(); - layerSelectedEvent(layer_list->currentIndex()); + layerSelectedEvent(_layer_list->currentIndex()); - button_apply->setEnabled(changed); - button_revert->setEnabled(changed); + _button_apply->setEnabled(changed); + _button_revert->setEnabled(changed); } void BaseForm::addPreview(BasePreview* preview, QString label) { QLabel* label_widget; - label_widget = new QLabel(label, previews); + label_widget = new QLabel(label, _previews); label_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); - previews->layout()->addWidget(label_widget); - previews->layout()->addWidget(preview); + _previews->layout()->addWidget(label_widget); + _previews->layout()->addWidget(preview); preview->setObjectName("_form_preview_"); } @@ -232,7 +309,7 @@ void BaseForm::addPreview(BasePreview* preview, QString label) QPushButton* BaseForm::addButton(QString label) { QPushButton* button = new QPushButton(label); - buttons->layout()->addWidget(button); + _buttons->layout()->addWidget(button); return button; } @@ -240,9 +317,9 @@ BaseInput* BaseForm::addInput(BaseInput* input) { int row_height = 30; - form_labels->layout()->addWidget(input->label()); - form_previews->layout()->addWidget(input->preview()); - form_controls->layout()->addWidget(input->control()); + _form_labels->layout()->addWidget(input->label()); + _form_previews->layout()->addWidget(input->preview()); + _form_controls->layout()->addWidget(input->control()); input->label()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); input->label()->setMinimumSize(150, row_height); @@ -266,52 +343,52 @@ BaseInput* BaseForm::addInput(BaseInput* input) BaseInput* BaseForm::addInputInt(QString label, int* value, int min, int max, int small_step, int large_step) { - return addInput(new InputInt(form, label, value, min, max, small_step, large_step)); + return addInput(new InputInt(_form, label, value, min, max, small_step, large_step)); } BaseInput* BaseForm::addInputDouble(QString label, double* value, double min, double max, double small_step, double large_step) { - return addInput(new InputDouble(form, label, value, min, max, small_step, large_step)); + return addInput(new InputDouble(_form, label, value, min, max, small_step, large_step)); } BaseInput* BaseForm::addInputBoolean(QString label, int* value) { - return addInput(new InputBoolean(form, label, value)); + return addInput(new InputBoolean(_form, label, value)); } BaseInput* BaseForm::addInputColor(QString label, Color* value) { - return addInput(new InputColor(form, label, value)); + return addInput(new InputColor(_form, label, value)); } BaseInput* BaseForm::addInputColorGradation(QString label, ColorGradation* value) { - return addInput(new InputColorGradation(form, label, value)); + return addInput(new InputColorGradation(_form, label, value)); } BaseInput* BaseForm::addInputNoise(QString label, NoiseGenerator* value) { - return addInput(new InputNoise(form, label, value)); + return addInput(new InputNoise(_form, label, value)); } BaseInput* BaseForm::addInputCurve(QString label, Curve* value, double xmin, double xmax, double ymin, double ymax, QString xlabel, QString ylabel) { - return addInput(new InputCurve(form, label, value, xmin, xmax, ymin, ymax, xlabel, ylabel)); + return addInput(new InputCurve(_form, label, value, xmin, xmax, ymin, ymax, xlabel, ylabel)); } BaseInput* BaseForm::addInputMaterial(QString label, SurfaceMaterial* material) { - return addInput(new InputMaterial(form, label, material)); + return addInput(new InputMaterial(_form, label, material)); } BaseInput* BaseForm::addInputEnum(QString label, int* value, const QStringList& values) { - return addInput(new InputEnum(form, label, value, values)); + return addInput(new InputEnum(_form, label, value, values)); } void BaseForm::updatePreviews() { - QList list_previews = previews->findChildren("_form_preview_"); + QList list_previews = _previews->findChildren("_form_preview_"); for (int i = 0; i < list_previews.size(); i++) { list_previews[i]->redraw(); @@ -320,14 +397,14 @@ void BaseForm::updatePreviews() void BaseForm::disablePreviewsUpdate() { - auto_update_previews = false; + _auto_update_previews = false; } int BaseForm::currentLayer() { - if (with_layers) + if (_with_layers) { - return layer_list->currentIndex(); + return _layer_list->currentIndex(); } else { @@ -337,52 +414,32 @@ int BaseForm::currentLayer() void BaseForm::setLayerCount(int layer_count) { - int i, selected; - - if (with_layers) - { - selected = layer_list->currentIndex(); - layer_list->clear(); - - for (i = 0; i < layer_count; i++) - { - layer_list->addItem(QString(tr("Layer %1")).arg(i + 1)); - } - if (selected >= 0) - { - if (selected > layer_count) - { - layer_list->setCurrentIndex(layer_count - 1); - } - else - { - layer_list->setCurrentIndex(selected); - } - } - } + this->_layer_count = layer_count; + rebuildLayerList(); } void BaseForm::layerAddedEvent() { - setLayerCount(layer_list->count() + 1); - layer_list->setCurrentIndex(layer_list->count() - 1); } void BaseForm::layerDeletedEvent(int layer) { - layer_list->removeItem(layer); +} + +void BaseForm::layerMovedEvent(int layer, int new_position) +{ } void BaseForm::layerSelectedEvent(int layer) { - QList inputs = form->findChildren("_form_input_"); + QList inputs = _form->findChildren("_form_input_"); for (int i = 0; i < inputs.size(); i++) { inputs[i]->revert(); inputs[i]->checkVisibility(layer >= 0); } - QList list_previews = previews->findChildren("_form_preview_"); + QList list_previews = _previews->findChildren("_form_preview_"); for (int i = 0; i < list_previews.size(); i++) { list_previews[i]->redraw(); diff --git a/gui_qt/baseform.h b/gui_qt/baseform.h index 8315a5b..708653e 100644 --- a/gui_qt/baseform.h +++ b/gui_qt/baseform.h @@ -33,8 +33,11 @@ protected slots: virtual void configChangeEvent(); private slots: + void rebuildLayerList(); void layerAddClicked(); void layerDelClicked(); + void layerUpClicked(); + void layerDownClicked(); void layerListChanged(); protected: @@ -59,23 +62,27 @@ protected: virtual void layerAddedEvent(); virtual void layerDeletedEvent(int layer); + virtual void layerMovedEvent(int layer, int new_position); virtual void layerSelectedEvent(int layer); private: - bool auto_update_previews; - bool auto_apply; - bool with_layers; - QComboBox* layer_list; - QPushButton* layer_new; - QPushButton* layer_del; - QWidget* previews; - QWidget* form; - QWidget* form_labels; - QWidget* form_previews; - QWidget* form_controls; - QWidget* buttons; - QPushButton* button_apply; - QPushButton* button_revert; + bool _auto_update_previews; + bool _auto_apply; + bool _with_layers; + QComboBox* _layer_list; + int _layer_count; + QPushButton* _layer_new; + QPushButton* _layer_del; + QPushButton* _layer_up; + QPushButton* _layer_down; + QWidget* _previews; + QWidget* _form; + QWidget* _form_labels; + QWidget* _form_previews; + QWidget* _form_controls; + QWidget* _buttons; + QPushButton* _button_apply; + QPushButton* _button_revert; }; -#endif // _PAYSAGES_QT_BASEFORM_H_ +#endif diff --git a/gui_qt/formclouds.cpp b/gui_qt/formclouds.cpp index 65cacf6..fbd33e1 100644 --- a/gui_qt/formclouds.cpp +++ b/gui_qt/formclouds.cpp @@ -196,6 +196,7 @@ void FormClouds::layerAddedEvent() { if (cloudsAddLayer(&_definition) >= 0) { + setLayerCount(cloudsGetLayerCount(&_definition)); BaseForm::layerAddedEvent(); } } @@ -203,6 +204,7 @@ void FormClouds::layerAddedEvent() void FormClouds::layerDeletedEvent(int layer) { cloudsDeleteLayer(&_definition, layer); + setLayerCount(cloudsGetLayerCount(&_definition)); BaseForm::layerDeletedEvent(layer); } diff --git a/gui_qt/formtextures.cpp b/gui_qt/formtextures.cpp index 4b4bb06..df663ab 100644 --- a/gui_qt/formtextures.cpp +++ b/gui_qt/formtextures.cpp @@ -185,6 +185,7 @@ void FormTextures::layerAddedEvent() { if (texturesAddLayer(&_definition) >= 0) { + setLayerCount(texturesGetLayerCount(&_definition)); BaseForm::layerAddedEvent(); } } @@ -192,6 +193,7 @@ void FormTextures::layerAddedEvent() void FormTextures::layerDeletedEvent(int layer) { texturesDeleteLayer(&_definition, layer); + setLayerCount(texturesGetLayerCount(&_definition)); BaseForm::layerDeletedEvent(layer); } diff --git a/images/layer_add.png b/images/layer_add.png new file mode 100644 index 0000000000000000000000000000000000000000..ca17c094bb2669c951f2fde57287cf783937abcc GIT binary patch literal 3746 zcmeHJ`8O1P7yj7Fk|o<%k}X=0CHl%TSu->kgF%rk>x_LYW6P3KvSrJfP#O&(Wtt3A z*~ii-l6{vfV+mP%egA>?=l6&AIp?|0x#!*=p7Wgh!+n4-GvZ_yVFv(k8p8~bM=JC$ zS(%RNcYJr}k+Av0?1BK`ApJ`QUHEVj0PLn-`uYfjrytfY$kWeX!dPEl!avZ@-3#Le zK-f^BWvFe&wjgwT+l?EgH@I4pgNX%F(gfCa9=j5r$H4h653f#3LLxhgU*Kc`%(^+Q zpB+}1I8}U(=%M>C@kWxhz50syNcr2SaQgD{-uJzR`GWcV9$YVX%t>C^^tlpma0Qv5 zr7D6sX_?OTUewEMO3yF#-XDC8zML zAejN=o-;bbsPh3hS;r#f87ZGYF+oS_A~U6mA;#{ViVL30P_w#ouJ>KyCuV&S30+^En3A0OgsIVUhMebd zXPc2K$jO)HgUvI+drkl#vP1iLsD3qVer{%R&V3$3|J_n@h+g%Rf=aH9A2vK~?W_jOJeJwvo>iJfBS;8>P% zc}7;6PJ;fuH0d{y6uoscJsb{S1p#?Fxs{aC_=5mv-;gR~$~=`>PuX{SUiz>t;m$$I zdD@g}jlI0U!!_FnM1+)S8}2?*N_5oW)C?_D?GpCrnJN}l6p+v7R zFeY)?_JshQ=naKOA{^;}$3s;Gw+%o>(@v_690TaiDVqkM;ir)O%S;Hol@$Pk;@At- zy2np^L9M3`+H|LUL1>rJP}^k7LRt783a_ zq*~eo%NX%`-sui7>2-xb{wvA$I=gAZ?Gh>v_a8PGDQCvkS}=WM4Ay!7Qe5O=YjF?_ ztIF*VlU;(QiPW9ej(Jy7PP_gy7z?5vrntt?l)2m={cyH_bl=eFfvt#ao1p8gtr{v- z%~j0ypAZ32N|7_2^$cTD4Bry#t-Cy*FmY*VMz(NU{g*OJ(sjHfRvWhXyUL%=N@ct> zuagPq-DwVU(WptYy+)8-kvuI~By;O57oTGW>dNt}YSm7GDAW%8P+xm}%Qe*RQN zFSoeDq8nfIjkO|C^Ug_U)X_0@h{1&7ruYwlOKP*E?gS-(L{k zSGre5SN<~;KGZnmvK+W9xV$(-5B4wADU>hV)bP>R4rU`=CRvaYNW;Oszo1`T7jX-0 zo1L3n3!^lnO`qSTn~-1h0Xj|mA0<`R%W1+GWp&rpt~A%5=qFx8+UniOmnW&7r1WOb zQkrq;S)%O9eUE9iFbLG0;CIS}pgQI@g4S|&@lqKsYc6Y<5^JQh8pC>^)xDPPDl>K z(x?1kx$o0(YSygC3aRhy*Ui%W5BVdNKYYH8c4@anz1lOqm@nGl@L8L#`+IfUb}FE2 zy0ARI{L@C-yyC5pTXwhh$fwQU6v!40DEYJxH{YBfQzM)-pxSP`Jqt|GRw(1s@Td11 zUo=XMYd1R< zlFahqnBobjfZho~qNbi` zqV;&L5S6v1KB^g|zw3F={9179B{p-U94=k>@q6hFQBhnFW~zrASV% z>^iycO7-XJ&E4hXGB{^&b3UD-8TUK4XQX$6HiiW-32<6z9kL3+B?wo1DHnEA=w=uZ zMuy$^c4^%G@YjwsN1R|JIjtH&tbQ{{46|FCkZLmgASj(=2?@QZ?0_WQ4)a>=i=ui` zYqJj!Q?^L!b#L6rdI~bW@A-3mxi}luEPQ4M)wk;RjrXns&RMsu>E1d0H&J&kK(ZVO z{)CrRf2yw$=ca7T9Qz|TaXv#sVT%ZsqZvPECQwq4U}6SB8%|Cf8KoRy+$$+M!4 zJ|<(>XW`zPDcyD5o!v}o&T7jyyWSCo*PmT3-3l+f<3L3nRKBWj{2@Cu&@>tvvB4ED zCZIV+&s=JFD;H*iCL2a=`u45Fji!pYh?1J-qDP5Fq2?_`sS(d3j&B*#7rn85n32~_ zO|@)3$jiy6VH*Ck`7wS&`OA5sZ~bpv;QFLH`|<4fi^zy+#Ls6vpGQ7-kLTX0-(+2c z;pF->nt}-mr9Q>l&&c$jk4g*0ZiyK+*8h#BD^I%yx2dJt6crbq(_Y(|iOZNSzg=Eb zXm(ZmTkZ&M8@`{5cCc_Dd+7HTU4>v*;PsB%9UEiwsSc|R{=cQRU4~`quUBeUX&XiR zA56kt-}GB_+omqtXjNf7z|{5rnN{p(KMVT~KbXX1|&#i{qR9XFke?S9c==HIXPC;N=L zjQXXoNhhZkii?YKijdcD_hd|#*Ov43c1ENA;ueEm&5s{U?OpG+-5*@#*h%Vbs>0zn z0_m^tuQl4F+r%4saN27x_A7gaqv%9BX}paro_lUz=Mb?$+jVU#|6;xkosT@+SKPk4 zu_x2_^wQC{$?TzPstZ6(O5~nJ#!)Zf3PYL#5H15iOgsQPe~)wlfM6v6emMc4@dN;f z-($y?YXC3-1l-DyJ&&Co&3=V+L4$Mw+9(et%R?I#3_dCud{ow_C>cE+oiq=fL59v)M$B2G zshW9v=)ZrDT>KyZPvCzsfs5uW%}2hZut+n@qeK1g0GwYw2OMoD7#rwXg$>oEU+0Ze z;xTX}j7YB?=G0Cw6Pf##8FibT&%Vj4u*p3C}1`Ip3NQl1R=`cLKMnEX69WA6x?l~|QOIQW>11U{hM0)j@_vwe-^ nt-gYRm+|KW(HMyPI3PME9K|# literal 0 HcmV?d00001 diff --git a/images/layer_del.png b/images/layer_del.png new file mode 100644 index 0000000000000000000000000000000000000000..e911407e831a6f9c942bf92d6d2997c2fbb8fbca GIT binary patch literal 3682 zcmeHJ`8O1P7yj5{$dYX=*`vk2^)3673=PKElWf@yVk{#xl2XFRmNlUm4N=M@d-kzJ zkx+KhVC)lPd3}F>|AF_M_c{08=iGDeIrpCD+#l{Egt;+0s}L&yfZYUk1$oQ@|2hl9 zar}<&>p3P!5X>P20Jge+olYM|lAzM288C;?pLeV6^Boo&_Y) zf$Vd}XXy1l0T-KCq#S*7D<~xBNh&ZlSJGh}KBySeV;h)2Sh78iQ_lrpvkl~Wf%qkQ zU?|Gd#~==8C{!A1n!-B=#S>w4pqZ4>mvwDOm6w?DMJRk@ZE8khrq#dNz!iF)%M&su znU|F-#RFSpfcKvSKxlWcf?H0#8CM5bPm=+2noUb?HYE|z%!NegEOga;PQ<{y~fll+@wR_W*y zIqZkRfL_d|{1YLzRKVq>rh=gYkk+)Dq9;oS`m#!90jU2iaHA|83h!V6;7Vcag(`jK zlP$c2W{$iTk@{vRz3Yi9dMD2`YjGKzn8TiCeIbykFKFGYG0OP9ib1IGRL(S4O^fm+ z_Qfgg8?odd=m{5rf>we02M|X6E*2hF35|qPZpovP{VdSzWJXC>nA%fpiTF|iucc&r zS8xeE-oQ822`056AIy6>>4x4OZoEreSS^s-b9cO8ozB<{X)>siUPGK(7N zNbcRX2se#toc&dT%<_M1l0pvm89mX|OXK-B0JtStX=#Dkf|uez0+ve2GP#lv56e7t<9-ik};I>^sBQKPIc zSwnumnU@xq;x8+T6Z8|jBUma>E2x+af5r4QE4#~D>AQ+>w%0SxXMr~M z7j`a0@ul`~XJ};DX2fJHmRs9|*ys*p%Gs=6+i*u^d@DRF zVk-U_iyUhlb6W{s;a?$-Q9^_A_44KNw>3~2)KEy>#X8Hn_`31Xfj>H5-N~3G$ac>* z$I{P1<89Pd@iz1iWrQ*)_K%Vp%SD`^zw#ybwO*Y2Z@*_g#KE=u(`Bbf-gT*M-o=9^ z#b=2!s}H?q)gz!fo`k^DZUnVo9ut0Au5Lam<0Wk+?Q@Oi`_lb#JnIH)zM^}3yW}Pa zqlE6|mcl*5#b#6DyZ@Tz8~* zP&)%6y{EZFMl{iyQNifY-Z1~5dUDCM+Gl(l{_~QZm$281ko-+`=&Nfu5_eWu7Ssw= z`nWXUc_b-gUTC#$=>6C2;@nTU6BR#D-+uOLw@1IGnJMH7cRPL7rs!|2QSE1L_s-^* z=9ac@;uaNehTU|yNox?bc$X(rFrtL&8gFx)Y9QTl(a_QM*y~?n(CN^je;)b#VdJYt z$w}=-shE+N>=@?#0-EL?=^*8A(==v-f8CtPg|3Beo~|KQDE1wLAA=ZUHsecXb*3by zPbU;l>hKwygs?k^1*ZizLpOwX-Bl;N+X!?4Ljs^AXI3?nd*Tzo1gC@W-;o3Vj<*l^Y?$jF6vVJGw!Uny7O`31_(s~i}}(3GZCJR`?>KJMvX;DMV8gIL{qJ& z3;DJgJC}ZHMjP&VKd`tO+Mx=uK+0lL1)qMD+BCDhGV+Ts@Z3PLScAv}| z+3!lV=V~oHWo6UY=P(PX9^tfyJ=8g=-H^?3KL2?5U~vty62ZX_S1gl_a1?NiAi^48 z*T1PwdLI7Sm14WcAJu@XLJ+IojS?dq)~6(!j6U&8C0aql6_lNjb+;mX)`p@<-lVsg z2Z$Maq|JseW?~~588`IurJ?LSJGBgadN(Pca_jm>cRtsQTQ(HmtYJsnyBDAt&V(RB zS>@lVtHgyFJ9FpZsBH{tZ0wh5ZO;lBMlK--5U37KZ%i9}^@qPaSYxjcUQe1Ac1D^0 zLcfUg-A?YS>FeoZP)*>p*!eXWMQ;ZTt={{YBIG7q*R&AxlV}`n(O!^p=j9#d9U}_a7aiz7@usQi zEd+(Um?R3*2%68u29D*fIyHD14ixA@(W~%UXKMH6uf-InwfdkfNvhkpbnUeY?MiLqn4p7c z*c-<{vImv4Vy9J!-ZCR=4pP3}-Scf84*CA~yMohmOarB3S-3Vp=I3dmblvvfu$>iX zIO{5W!YMK(;>~{J*ufv>J}u`2T6?xoCRaG<{y00WZyvpJoW986BGd%~*(L za++o;Lc1nTGn1rQNYgCOtts;7u(BQ<9nbkc{;$CQo&xCRx=j-vIh} z6#g9dSeRVVw~iQ_c-jKN>Txl=b7L0uI@(6Ddq$m4Brtgw2pWi=3ERHD#aU&_&8ezT zNZ3ixlt5uyn8W(%K^5IO5uqPhvYwnXG;+sybUz&k#|wvh{L)SNS2PnN^DC7GF8BTe D{L8M_ literal 0 HcmV?d00001 diff --git a/images/layer_down.png b/images/layer_down.png new file mode 100644 index 0000000000000000000000000000000000000000..c464ede80674b04a2202d21d63c5c243ed16c715 GIT binary patch literal 3847 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 WPih!9r_SFC0CctV?^I~mg#8C!U5EGp literal 0 HcmV?d00001 diff --git a/images/layer_up.png b/images/layer_up.png new file mode 100644 index 0000000000000000000000000000000000000000..5f500b965df06608d2d3c688b80ff5bece07dbbe GIT binary patch literal 3833 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