]> git.mar77i.info Git - bigintmandel/blob - bigintmandelwidget.cpp
break out draw_progress to mandellabel
[bigintmandel] / bigintmandelwidget.cpp
1
2 // bigintmandelwidget.cpp
3
4 #include <QFileDialog>
5 #include <QLayout>
6 #include <QMouseEvent>
7 #include <QPainter>
8 #include <QPushButton>
9 #include <QtConcurrent/QtConcurrent>
10
11 #include "bigintmandelwidget.h"
12 #include "mandellabel.h"
13 #include "menubar.h"
14
15 static inline void start_calculation(
16 QFutureWatcher<MandelResultCell> *fw, QVector<MandelCell> cells
17 ) {
18 fw->setFuture(
19 QtConcurrent::mapped(
20 cells,
21 [](const MandelCell &cell){ return cell.iterate(); }
22 )
23 );
24 }
25
26 BigintMandelWidget::BigintMandelWidget(QWidget *parent)
27 : QWidget(parent),
28 fw(new QFutureWatcher<MandelResultCell>(this)),
29 settings(128, QSize(502, 334)),
30 menu_bar(new MenuBar(this)),
31 scroll_area(new QScrollArea(this)),
32 mandel_label(new MandelLabel(this)),
33 status_bar(new QStatusBar(this)),
34 settings_widget(new SettingsWidget(this))
35 {
36 scroll_area->setWidget(mandel_label);
37 connect(
38 settings_widget,
39 &QDialog::accepted,
40 this,
41 &BigintMandelWidget::settings_widget_accepted
42 );
43 connect(
44 fw,
45 &QFutureWatcher<MandelResultCell>::resultReadyAt,
46 this,
47 &BigintMandelWidget::finished_cell
48 );
49 connect(
50 fw,
51 &QFutureWatcher<MandelResultCell>::finished,
52 this,
53 &BigintMandelWidget::finished
54 );
55 start_calculation(fw, settings.get_cells());
56 setLayout(new QVBoxLayout());
57 layout()->addWidget(menu_bar);
58 layout()->addWidget(scroll_area);
59 status_bar->setSizeGripEnabled(false);
60 layout()->addWidget(status_bar);
61 mandel_label->resize(settings.get_params().get_size());
62 }
63
64 BigintMandelWidget::~BigintMandelWidget() {
65 fw->cancel();
66 fw->waitForFinished();
67 }
68
69 void BigintMandelWidget::finished_cell(int num) {
70 int y = num / settings.get_params().get_size().width();
71 mandel_label->set_draw_progress(y);
72 settings.finished_cell(num, fw->resultAt(num));
73 update();
74 }
75
76 void BigintMandelWidget::finished() {
77 mandel_label->set_draw_progress(-1);
78 settings_widget->set_finished(true);
79 update();
80 }
81
82 void BigintMandelWidget::update_status_bar() {
83 QTextStream ss;
84 static int prev_num_threads = -1;
85 int num_threads;
86 if (fw->isFinished())
87 num_threads = -1;
88 else
89 num_threads = QThreadPool::globalInstance()->activeThreadCount();
90 if (num_threads == prev_num_threads)
91 return;
92 ss.setString(new QString());
93 if (num_threads != -1)
94 ss << "Calculating with " << num_threads << " threads ...";
95 else
96 ss << "Click the rendering to zoom.";
97 status_bar->showMessage(*ss.string());
98 prev_num_threads = num_threads;
99 }
100
101 void BigintMandelWidget::mousePressEvent(QMouseEvent *event) {
102 QSize size(settings.get_params().get_size());
103 QPoint pos(event->pos());
104 QWidget *w;
105 for (w = mandel_label; w != this; w = w->parentWidget())
106 pos = w->mapFromParent(pos);
107 if (event->button() != Qt::MouseButton::LeftButton
108 || !fw->isFinished()
109 || pos.x() < 0
110 || pos.x() >= size.width()
111 || pos.y() < 0
112 || pos.y() >= size.height())
113 return;
114 settings.zoom(get_ideal_size(), menu_bar->get_zoom_factor(), pos);
115 start_calculation(fw, settings.get_cells());
116 update();
117 }
118
119 static inline QString get_save_file_name(
120 QWidget *parent = nullptr,
121 const QString &caption = QString(),
122 const QString &dir = QString(),
123 const QString &filter_title = QString(),
124 const QStringList &ext_list = QStringList{},
125 const QString default_ext = QString()
126 ) {
127 QTextStream ss(new QString());
128 QStringList::const_iterator ext_list_iter;
129 QString file_name;
130 qsizetype pos;
131 ss << filter_title << " (" << ext_list.join(" ") << ")";
132 file_name = QFileDialog::getSaveFileName(
133 parent, caption, dir, *ss.string()
134 );
135 if (file_name.isEmpty())
136 return file_name;
137 ss.seek(0);
138 ss.string()->clear();
139 ss << file_name;
140 pos = file_name.lastIndexOf(".");
141 if (pos < 0 || !ext_list.contains(file_name.mid(pos)))
142 ss << default_ext;
143 return *ss.string();
144 }
145
146 void BigintMandelWidget::export_img() {
147 QString file_name = get_save_file_name(
148 this,
149 "Save image",
150 "",
151 "Images",
152 QStringList{".png", ".xpm", ".jpg"},
153 ".png"
154 );
155 if (!file_name.isEmpty())
156 settings.save_img(file_name);
157 }
158
159 void BigintMandelWidget::exec_settings_widget() {
160 settings_widget->update_fields(settings.get_params(), fw->isFinished());
161 settings_widget->exec();
162 }
163
164 void BigintMandelWidget::reset() {
165 fw->cancel();
166 fw->waitForFinished();
167 settings.reset(128, get_ideal_size());
168 start_calculation(fw, settings.get_cells());
169 update();
170 }
171
172 void BigintMandelWidget::settings_widget_accepted() {
173 settings.set_max_iter(settings_widget->get_max_iter().toULongLong());
174 start_calculation(fw, settings.get_cells());
175 update();
176 }
177
178 void BigintMandelWidget::load_data() {
179 QFile file;
180 QJsonObject json;
181 QByteArray qba;
182 QString file_name = QFileDialog::getOpenFileName(
183 this, "Load Data", "", "BigintMandel Data (*.json *.json.qcompress)"
184 );
185 if (file_name.isEmpty())
186 return;
187 file.setFileName(file_name);
188 if (!file.open(QIODevice::ReadOnly)) {
189 qWarning("Couldn't open save file.");
190 return;
191 }
192 qba = file.readAll();
193 file.close();
194 if (file_name.endsWith(".qcompress"))
195 qba = qUncompress(qba);
196 settings.from_json(QJsonDocument::fromJson(qba).object());
197 update();
198 }
199
200 void BigintMandelWidget::save_data() {
201 QFile file;
202 QByteArray qba;
203 QString file_name = get_save_file_name(
204 this,
205 "Save data",
206 "",
207 "Bigintmandel Data",
208 QStringList{".json", ".json.qcompress"},
209 ".json.qcompress"
210 );
211 if (file_name.isEmpty())
212 return;
213 qba = QJsonDocument(settings.to_json()).toJson();
214 if (file_name.endsWith(".qcompress"))
215 qba = qCompress(qba, 9);
216 file.setFileName(file_name);
217 if (!file.open(QIODevice::WriteOnly)) {
218 qWarning("Couldn't open save file.");
219 return;
220 }
221 file.write(qba);
222 file.close();
223 }
224
225 void BigintMandelWidget::update() {
226 update_status_bar();
227 QWidget::update();
228 }