Skip to content

Commit c8062a6

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

11 files changed

Lines changed: 394 additions & 136 deletions

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: 118 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,24 +39,18 @@ 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
//******************************************************************************
@@ -65,11 +60,8 @@ MainWindow::~MainWindow() = default;
6560
void MainWindow::set_style(Style const& style) {
6661
ui->processing_view->setBackgroundBrush(style.processing.background);
6762
ui->structure_view->setBackgroundBrush(style.structure.background);
68-
ui->processing_view->processing_scene->style_selector = style.processing;
63+
ui->processing_view->style_selector = style.processing;
6964
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();
7365
}
7466

7567
//******************************************************************************
@@ -79,7 +71,7 @@ void MainWindow::on_a_about_triggered() {
7971
}
8072

8173
//******************************************************************************
82-
void MainWindow::on_a_doc_oems_meshing_triggered() {
74+
void MainWindow::on_a_doc_oems_meshing_triggered() const {
8375
QDesktopServices::openUrl(QUrl(OEMSH_OEMS_MESHING));
8476
}
8577

@@ -93,27 +85,24 @@ void MainWindow::on_ag_styles_triggered(QAction* const action) {
9385
//******************************************************************************
9486
void MainWindow::on_rb_plane_xy_toggled(bool const is_checked) {
9587
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);
88+
ui->structure_view->set_display_plane(domain::XY);
89+
ui->processing_view->get_current_state().scene->set_display_plane(domain::XY);
9990
}
10091
}
10192

10293
//******************************************************************************
10394
void MainWindow::on_rb_plane_yz_toggled(bool const is_checked) {
10495
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);
96+
ui->structure_view->set_display_plane(domain::YZ);
97+
ui->processing_view->get_current_state().scene->set_display_plane(domain::YZ);
10898
}
10999
}
110100

111101
//******************************************************************************
112102
void MainWindow::on_rb_plane_zx_toggled(bool const is_checked) {
113103
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);
104+
ui->structure_view->set_display_plane(domain::ZX);
105+
ui->processing_view->get_current_state().scene->set_display_plane(domain::ZX);
117106
}
118107
}
119108

@@ -127,17 +116,17 @@ void MainWindow::on_tb_anchor_clicked(bool const is_checked) {
127116
}
128117

129118
//******************************************************************************
130-
void MainWindow::on_tb_reset_clicked() {
131-
ui->processing_view->processing_scene->fit_containers();
132-
ui->processing_view->processing_scene->fit_scene();
119+
void MainWindow::on_a_reset_triggered() {
120+
ui->processing_view->get_current_state().scene->fit_containers();
121+
ui->processing_view->get_current_state().scene->fit_scene();
133122
ui->processing_view->fit();
134123

135124
ui->structure_view->reset_rotation();
136125
ui->structure_view->fit();
137126
}
138127

139128
//******************************************************************************
140-
void MainWindow::on_tb_horizontal_layout_clicked() {
129+
void MainWindow::on_a_horizontal_layout_triggered() {
141130
if(dock_layout_order) {
142131
addDockWidget(Qt::BottomDockWidgetArea, ui->dw_structure);
143132
addDockWidget(Qt::TopDockWidgetArea, ui->dw_processing);
@@ -149,7 +138,7 @@ void MainWindow::on_tb_horizontal_layout_clicked() {
149138
}
150139

151140
//******************************************************************************
152-
void MainWindow::on_tb_vertical_layout_clicked() {
141+
void MainWindow::on_a_vertical_layout_triggered() {
153142
if(dock_layout_order) {
154143
addDockWidget(Qt::RightDockWidgetArea, ui->dw_structure);
155144
addDockWidget(Qt::LeftDockWidgetArea, ui->dw_processing);
@@ -163,57 +152,57 @@ void MainWindow::on_tb_vertical_layout_clicked() {
163152
//******************************************************************************
164153
void MainWindow::on_tb_show_all_mesh_clicked() {
165154
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::FULL);
166-
ui->processing_view->processing_scene->set_display_view_axes({ true, true });
155+
ui->processing_view->get_current_state().scene->set_display_view_axes({ true, true });
167156
ui->processing_view->fit();
168157
}
169158

170159
//******************************************************************************
171160
void MainWindow::on_tb_show_horizontal_mesh_clicked() {
172161
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::HORIZONTAL);
173-
ui->processing_view->processing_scene->set_display_view_axes({ true, false });
162+
ui->processing_view->get_current_state().scene->set_display_view_axes({ true, false });
174163
ui->processing_view->fit();
175164
}
176165

177166
//******************************************************************************
178167
void MainWindow::on_tb_show_vertical_mesh_clicked() {
179168
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::VERTICAL);
180-
ui->processing_view->processing_scene->set_display_view_axes({ false, true });
169+
ui->processing_view->get_current_state().scene->set_display_view_axes({ false, true });
181170
ui->processing_view->fit();
182171
}
183172

184173
//******************************************************************************
185174
void MainWindow::on_tb_show_no_mesh_clicked() {
186175
ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::NONE);
187-
ui->processing_view->processing_scene->set_display_view_axes({ false, false });
176+
ui->processing_view->get_current_state().scene->set_display_view_axes({ false, false });
188177
ui->processing_view->fit();
189178
}
190179

191180
//******************************************************************************
192181
void MainWindow::on_tb_show_selected_clicked() {
193-
ui->processing_view->processing_scene->set_display(ProcessingScene::DisplayMode::SELECTED_CHAIN);
182+
ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::SELECTED_CHAIN);
194183
ui->processing_view->fit();
195184
}
196185

197186
//******************************************************************************
198187
void MainWindow::on_tb_show_displayed_clicked() {
199-
ui->processing_view->processing_scene->set_display(ProcessingScene::DisplayMode::STRUCTURE_VIEW);
188+
ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::STRUCTURE_VIEW);
200189
ui->processing_view->fit();
201190
}
202191

203192
//******************************************************************************
204193
void MainWindow::on_tb_show_everything_clicked() {
205-
ui->processing_view->processing_scene->set_display(ProcessingScene::DisplayMode::EVERYTHING);
194+
ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::EVERYTHING);
206195
ui->processing_view->fit();
207196
}
208197

209198
//******************************************************************************
210199
void MainWindow::on_tb_curved_wires_clicked() {
211-
ui->processing_view->processing_scene->set_wire_style(nodegraph::Wire::Style::CURVED);
200+
ui->processing_view->get_current_state().scene->set_wire_style(nodegraph::Wire::Style::CURVED);
212201
}
213202

214203
//******************************************************************************
215204
void MainWindow::on_tb_direct_wires_clicked() {
216-
ui->processing_view->processing_scene->set_wire_style(nodegraph::Wire::Style::DIRECT);
205+
ui->processing_view->get_current_state().scene->set_wire_style(nodegraph::Wire::Style::DIRECT);
217206
}
218207

219208
//******************************************************************************
@@ -246,4 +235,91 @@ void MainWindow::on_tb_processing_zoom_out_clicked() {
246235
ui->processing_view->scale(1 / 1.2, 1 / 1.2);
247236
}
248237

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