Skip to content

Commit 5f89e80

Browse files
committed
add undo/redo GUI support
1 parent eb73dfc commit 5f89e80

10 files changed

Lines changed: 399 additions & 135 deletions

File tree

src/app/openemsh.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ void OpenEMSH::run(std::set<Step> const& steps) {
130130

131131
//******************************************************************************
132132
void OpenEMSH::run_all_steps() {
133+
Caretaker::singleton().remember_current_timepoint();
133134
run({
134135
Step::DETECT_CONFLICT_EIP,
135136
Step::DETECT_CONFLICT_CE,

src/ui/qt/main_window.cpp

Lines changed: 124 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "domain/geometrics/space.hpp"
1111
#include "processing_view/processing_view.hpp"
1212
#include "structure_view/structure_view.hpp"
13+
#include "utils/state_management.hpp"
1314
#include "about_dialog.hpp"
1415

1516
#include "ui_main_window.h"
@@ -38,38 +39,35 @@ MainWindow::MainWindow(app::OpenEMSH& oemsh, QWidget* parent)
3839
ui->m_style->addAction(action);
3940
}
4041

41-
for(domain::Plane const plane : domain::AllPlane) {
42-
connect(
43-
ui->processing_view->processing_scene, &ProcessingScene::selection_changed,
44-
ui->structure_view->scenes[plane], &StructureScene::select_counterparts);
45-
connect(
46-
ui->structure_view->scenes[plane], &StructureScene::selection_changed,
47-
ui->processing_view->processing_scene, &ProcessingScene::select_counterparts);
48-
}
49-
5042
oemsh.parse();
5143
oemsh.run_all_steps();
5244

53-
ui->structure_view->populate(&oemsh.get_board());
54-
ui->processing_view->populate(&oemsh.get_board());
45+
ui->structure_view->init(&oemsh.get_board());
46+
ui->processing_view->init(&oemsh.get_board());
47+
handle_edition();
5548

56-
ui->structure_view->setScene(ui->structure_view->scenes[domain::XY]);
57-
ui->processing_view->processing_scene->set_display_plane(domain::XY);
58-
ui->processing_view->processing_scene->set_display_view_axes({ true, true });
49+
ui->structure_view->set_display_plane(domain::XY);
50+
ui->processing_view->get_current_state().scene->set_display_plane(domain::XY);
51+
ui->processing_view->get_current_state().scene->set_display_view_axes({ true, true });
52+
// ui->structure_view->setup_scale_max(ui->structure_view->scenes[domain::XY].polygons->boundingRect());
53+
// on_tb_reset_clicked();
5954
}
6055

6156
//******************************************************************************
6257
MainWindow::~MainWindow() = default;
6358

59+
//******************************************************************************
60+
void MainWindow::do_after_show() {
61+
// TODO use QGraphicsView::showEvent()
62+
ui->processing_view->fit();
63+
}
64+
6465
//******************************************************************************
6566
void MainWindow::set_style(Style const& style) {
6667
ui->processing_view->setBackgroundBrush(style.processing.background);
6768
ui->structure_view->setBackgroundBrush(style.structure.background);
68-
ui->processing_view->processing_scene->style_selector = style.processing;
69+
ui->processing_view->style_selector = style.processing;
6970
ui->structure_view->style_selector = style.structure;
70-
ui->processing_view->processing_scene->update();
71-
if(auto* scene = ui->structure_view->scene(); scene)
72-
scene->update();
7371
}
7472

7573
//******************************************************************************
@@ -79,7 +77,7 @@ void MainWindow::on_a_about_triggered() {
7977
}
8078

8179
//******************************************************************************
82-
void MainWindow::on_a_doc_oems_meshing_triggered() {
80+
void MainWindow::on_a_doc_oems_meshing_triggered() const {
8381
QDesktopServices::openUrl(QUrl(OEMSH_OEMS_MESHING));
8482
}
8583

@@ -93,27 +91,24 @@ void MainWindow::on_ag_styles_triggered(QAction* const action) {
9391
//******************************************************************************
9492
void MainWindow::on_rb_plane_xy_toggled(bool const is_checked) {
9593
if(is_checked) {
96-
ui->structure_view->setScene(ui->structure_view->scenes[domain::XY]);
97-
ui->structure_view->centerOn(ui->structure_view->scenes[domain::XY]->polygons->boundingRect().center());
98-
ui->processing_view->processing_scene->set_display_plane(domain::XY);
94+
ui->structure_view->set_display_plane(domain::XY);
95+
ui->processing_view->get_current_state().scene->set_display_plane(domain::XY);
9996
}
10097
}
10198

10299
//******************************************************************************
103100
void MainWindow::on_rb_plane_yz_toggled(bool const is_checked) {
104101
if(is_checked) {
105-
ui->structure_view->setScene(ui->structure_view->scenes[domain::YZ]);
106-
ui->structure_view->centerOn(ui->structure_view->scenes[domain::YZ]->polygons->boundingRect().center());
107-
ui->processing_view->processing_scene->set_display_plane(domain::YZ);
102+
ui->structure_view->set_display_plane(domain::YZ);
103+
ui->processing_view->get_current_state().scene->set_display_plane(domain::YZ);
108104
}
109105
}
110106

111107
//******************************************************************************
112108
void MainWindow::on_rb_plane_zx_toggled(bool const is_checked) {
113109
if(is_checked) {
114-
ui->structure_view->setScene(ui->structure_view->scenes[domain::ZX]);
115-
ui->structure_view->centerOn(ui->structure_view->scenes[domain::ZX]->polygons->boundingRect().center());
116-
ui->processing_view->processing_scene->set_display_plane(domain::ZX);
110+
ui->structure_view->set_display_plane(domain::ZX);
111+
ui->processing_view->get_current_state().scene->set_display_plane(domain::ZX);
117112
}
118113
}
119114

@@ -127,17 +122,17 @@ void MainWindow::on_tb_anchor_clicked(bool const is_checked) {
127122
}
128123

129124
//******************************************************************************
130-
void MainWindow::on_tb_reset_clicked() {
131-
ui->processing_view->processing_scene->fit_containers();
132-
ui->processing_view->processing_scene->fit_scene();
125+
void MainWindow::on_a_reset_triggered() {
126+
ui->processing_view->get_current_state().scene->fit_containers();
127+
ui->processing_view->get_current_state().scene->fit_scene();
133128
ui->processing_view->fit();
134129

135130
ui->structure_view->reset_rotation();
136131
ui->structure_view->fit();
137132
}
138133

139134
//******************************************************************************
140-
void MainWindow::on_tb_horizontal_layout_clicked() {
135+
void MainWindow::on_a_horizontal_layout_triggered() {
141136
if(dock_layout_order) {
142137
addDockWidget(Qt::BottomDockWidgetArea, ui->dw_structure);
143138
addDockWidget(Qt::TopDockWidgetArea, ui->dw_processing);
@@ -149,7 +144,7 @@ void MainWindow::on_tb_horizontal_layout_clicked() {
149144
}
150145

151146
//******************************************************************************
152-
void MainWindow::on_tb_vertical_layout_clicked() {
147+
void MainWindow::on_a_vertical_layout_triggered() {
153148
if(dock_layout_order) {
154149
addDockWidget(Qt::RightDockWidgetArea, ui->dw_structure);
155150
addDockWidget(Qt::LeftDockWidgetArea, ui->dw_processing);
@@ -163,57 +158,57 @@ void MainWindow::on_tb_vertical_layout_clicked() {
163158
//******************************************************************************
164159
void MainWindow::on_tb_show_all_mesh_clicked() {
165160
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::FULL);
166-
ui->processing_view->processing_scene->set_display_view_axes({ true, true });
161+
ui->processing_view->get_current_state().scene->set_display_view_axes({ true, true });
167162
ui->processing_view->fit();
168163
}
169164

170165
//******************************************************************************
171166
void MainWindow::on_tb_show_horizontal_mesh_clicked() {
172167
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::HORIZONTAL);
173-
ui->processing_view->processing_scene->set_display_view_axes({ true, false });
168+
ui->processing_view->get_current_state().scene->set_display_view_axes({ true, false });
174169
ui->processing_view->fit();
175170
}
176171

177172
//******************************************************************************
178173
void MainWindow::on_tb_show_vertical_mesh_clicked() {
179174
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::VERTICAL);
180-
ui->processing_view->processing_scene->set_display_view_axes({ false, true });
175+
ui->processing_view->get_current_state().scene->set_display_view_axes({ false, true });
181176
ui->processing_view->fit();
182177
}
183178

184179
//******************************************************************************
185180
void MainWindow::on_tb_show_no_mesh_clicked() {
186181
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::NONE);
187-
ui->processing_view->processing_scene->set_display_view_axes({ false, false });
182+
ui->processing_view->get_current_state().scene->set_display_view_axes({ false, false });
188183
ui->processing_view->fit();
189184
}
190185

191186
//******************************************************************************
192187
void MainWindow::on_tb_show_selected_clicked() {
193-
ui->processing_view->processing_scene->set_display(ProcessingScene::DisplayMode::SELECTED_CHAIN);
188+
ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::SELECTED_CHAIN);
194189
ui->processing_view->fit();
195190
}
196191

197192
//******************************************************************************
198193
void MainWindow::on_tb_show_displayed_clicked() {
199-
ui->processing_view->processing_scene->set_display(ProcessingScene::DisplayMode::STRUCTURE_VIEW);
194+
ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::STRUCTURE_VIEW);
200195
ui->processing_view->fit();
201196
}
202197

203198
//******************************************************************************
204199
void MainWindow::on_tb_show_everything_clicked() {
205-
ui->processing_view->processing_scene->set_display(ProcessingScene::DisplayMode::EVERYTHING);
200+
ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::EVERYTHING);
206201
ui->processing_view->fit();
207202
}
208203

209204
//******************************************************************************
210205
void MainWindow::on_tb_curved_wires_clicked() {
211-
ui->processing_view->processing_scene->set_wire_style(nodegraph::Wire::Style::CURVED);
206+
ui->processing_view->get_current_state().scene->set_wire_style(nodegraph::Wire::Style::CURVED);
212207
}
213208

214209
//******************************************************************************
215210
void MainWindow::on_tb_direct_wires_clicked() {
216-
ui->processing_view->processing_scene->set_wire_style(nodegraph::Wire::Style::DIRECT);
211+
ui->processing_view->get_current_state().scene->set_wire_style(nodegraph::Wire::Style::DIRECT);
217212
}
218213

219214
//******************************************************************************
@@ -246,4 +241,91 @@ void MainWindow::on_tb_processing_zoom_out_clicked() {
246241
ui->processing_view->scale(1 / 1.2, 1 / 1.2);
247242
}
248243

244+
//******************************************************************************
245+
void MainWindow::on_a_mesh_prev_triggered() {
246+
setCursor(Qt::WaitCursor);
247+
oemsh.go_before_previous_step();
248+
go_to_or_make_current_state();
249+
unsetCursor();
250+
}
251+
252+
// TODO require some processing fit()
253+
//******************************************************************************
254+
void MainWindow::on_a_mesh_next_triggered() {
255+
setCursor(Qt::WaitCursor);
256+
oemsh.run_next_step();
257+
go_to_or_make_current_state();
258+
unsetCursor();
259+
}
260+
261+
//******************************************************************************
262+
void MainWindow::on_a_undo_triggered() {
263+
setCursor(Qt::WaitCursor);
264+
Caretaker::singleton().undo();
265+
go_to_or_make_current_state();
266+
unsetCursor();
267+
}
268+
269+
//******************************************************************************
270+
void MainWindow::on_a_redo_triggered() {
271+
setCursor(Qt::WaitCursor);
272+
Caretaker::singleton().redo();
273+
go_to_or_make_current_state();
274+
unsetCursor();
275+
}
276+
277+
//******************************************************************************
278+
void MainWindow::go_to_or_make_current_state() {
279+
auto* t = Caretaker::singleton().get_current_timepoint();
280+
if(ui->structure_view->states.contains(t)
281+
&& ui->processing_view->states.contains(t))
282+
go_to_current_state();
283+
else
284+
make_current_state_view();
285+
}
286+
287+
//******************************************************************************
288+
void MainWindow::go_to_current_state() {
289+
ui->structure_view->go_to_current_state();
290+
ui->processing_view->go_to_current_state();
291+
update_undo_redo_visibility();
292+
// TODO handle passing selection from a scene to its own future couterpart
293+
}
294+
295+
//******************************************************************************
296+
void MainWindow::make_current_state_view() {
297+
Caretaker::singleton().pin_current_timepoint();
298+
ui->structure_view->make_current_state();
299+
ui->processing_view->make_current_state();
300+
301+
auto* t = Caretaker::singleton().get_current_timepoint();
302+
for(domain::Plane const plane : domain::AllPlane) {
303+
connect(
304+
ui->processing_view->states[t].scene, &ProcessingScene::selection_changed,
305+
ui->structure_view->states[t].scenes[plane], &StructureScene::select_counterparts);
306+
connect(
307+
ui->structure_view->states[t].scenes[plane], &StructureScene::selection_changed,
308+
ui->processing_view->states[t].scene, &ProcessingScene::select_counterparts);
309+
}
310+
311+
update_undo_redo_visibility();
312+
}
313+
314+
//******************************************************************************
315+
void MainWindow::handle_edition(std::set<app::Step> const& to_redo) {
316+
// Caretaker::singleton().remember_current_timepoint();
317+
318+
// if(ui->a_mesh_auto->is_checked()) // TODO may not be that useful since editing at once two things from different steps will discard newer objects edits??
319+
oemsh.run(to_redo);
320+
Caretaker::singleton().remember_current_timepoint();
321+
322+
make_current_state_view();
323+
}
324+
325+
//******************************************************************************
326+
void MainWindow::update_undo_redo_visibility() { // TODO rename
327+
ui->a_undo->setEnabled(Caretaker::singleton().can_undo());
328+
ui->a_redo->setEnabled(Caretaker::singleton().can_redo());
329+
};
330+
249331
} // namespace ui::qt

src/ui/qt/main_window.hpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,22 @@ class MainWindow : public QMainWindow {
3131

3232
void set_style(Style const& style);
3333

34+
void update_undo_redo_visibility();
35+
void go_to_current_state();
36+
void make_current_state_view();
37+
void go_to_or_make_current_state();
38+
3439
private slots:
3540
void on_a_about_triggered();
36-
void on_a_doc_oems_meshing_triggered();
41+
void on_a_doc_oems_meshing_triggered() const;
3742
void on_ag_styles_triggered(QAction* const action);
3843
void on_rb_plane_xy_toggled(bool const is_checked);
3944
void on_rb_plane_yz_toggled(bool const is_checked);
4045
void on_rb_plane_zx_toggled(bool const is_checked);
4146
void on_tb_anchor_clicked(bool const is_checked);
42-
void on_tb_reset_clicked();
43-
void on_tb_horizontal_layout_clicked();
44-
void on_tb_vertical_layout_clicked();
47+
void on_a_reset_triggered();
48+
void on_a_horizontal_layout_triggered();
49+
void on_a_vertical_layout_triggered();
4550
void on_tb_show_all_mesh_clicked();
4651
void on_tb_show_horizontal_mesh_clicked();
4752
void on_tb_show_vertical_mesh_clicked();
@@ -57,6 +62,12 @@ private slots:
5762
void on_tb_structure_zoom_out_clicked();
5863
void on_tb_processing_zoom_in_clicked();
5964
void on_tb_processing_zoom_out_clicked();
65+
void on_a_mesh_prev_triggered();
66+
void on_a_mesh_next_triggered();
67+
void on_a_undo_triggered();
68+
void on_a_redo_triggered();
69+
70+
void handle_edition(std::set<app::Step> const& to_redo = {}); // TODO handle_edition / on_edition
6071

6172
public:
6273
MainWindow(app::OpenEMSH& oemsh, QWidget* parent = nullptr);

0 commit comments

Comments
 (0)