// bigintmandelwidget.cpp #include #include #include #include #include #include #include "bigintmandelwidget.h" #include "mandellabel.h" #include "menubar.h" static inline void start_calculation( QFutureWatcher *fw, QVector cells ) { fw->setFuture( QtConcurrent::mapped( cells, [](const MandelCell &cell){ return cell.iterate(); } ) ); } BigintMandelWidget::BigintMandelWidget(QWidget *parent) : QWidget(parent), fw(new QFutureWatcher(this)), settings(128, QSize(502, 334)), menu_bar(new MenuBar(this)), scroll_area(new QScrollArea(this)), mandel_label(new MandelLabel(this)), status_bar(new QStatusBar(this)), settings_widget(new SettingsWidget(this)) { scroll_area->setWidget(mandel_label); connect( settings_widget, &QDialog::accepted, this, &BigintMandelWidget::settings_widget_accepted ); connect( fw, &QFutureWatcher::resultReadyAt, this, &BigintMandelWidget::finished_cell ); connect( fw, &QFutureWatcher::finished, this, &BigintMandelWidget::finished ); start_calculation(fw, settings.get_cells()); setLayout(new QVBoxLayout()); layout()->addWidget(menu_bar); layout()->addWidget(scroll_area); status_bar->setSizeGripEnabled(false); layout()->addWidget(status_bar); mandel_label->resize(settings.get_params().get_size()); } BigintMandelWidget::~BigintMandelWidget() { fw->cancel(); fw->waitForFinished(); } void BigintMandelWidget::finished_cell(int num) { int y = num / settings.get_params().get_size().width(); mandel_label->set_draw_progress(y); settings.finished_cell(num, fw->resultAt(num)); update(); } void BigintMandelWidget::finished() { mandel_label->set_draw_progress(-1); settings_widget->set_finished(true); update(); } void BigintMandelWidget::update_status_bar() { QTextStream ss; static int prev_num_threads = -1; int num_threads; if (fw->isFinished()) num_threads = -1; else num_threads = QThreadPool::globalInstance()->activeThreadCount(); if (num_threads == prev_num_threads) return; ss.setString(new QString()); if (num_threads != -1) ss << "Calculating with " << num_threads << " threads ..."; else ss << "Click the rendering to zoom."; status_bar->showMessage(*ss.string()); prev_num_threads = num_threads; } void BigintMandelWidget::mousePressEvent(QMouseEvent *event) { QSize size(settings.get_params().get_size()); QPoint pos(event->pos()); QWidget *w; for (w = mandel_label; w != this; w = w->parentWidget()) pos = w->mapFromParent(pos); if (event->button() != Qt::MouseButton::LeftButton || !fw->isFinished() || pos.x() < 0 || pos.x() >= size.width() || pos.y() < 0 || pos.y() >= size.height()) return; settings.zoom(get_ideal_size(), menu_bar->get_zoom_factor(), pos); start_calculation(fw, settings.get_cells()); update(); } static inline QString get_save_file_name( QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter_title = QString(), const QStringList &ext_list = QStringList{}, const QString default_ext = QString() ) { QTextStream ss(new QString()); QStringList::const_iterator ext_list_iter; QString file_name; qsizetype pos; ss << filter_title << " (" << ext_list.join(" ") << ")"; file_name = QFileDialog::getSaveFileName( parent, caption, dir, *ss.string() ); if (file_name.isEmpty()) return file_name; ss.seek(0); ss.string()->clear(); ss << file_name; pos = file_name.lastIndexOf("."); if (pos < 0 || !ext_list.contains(file_name.mid(pos))) ss << default_ext; return *ss.string(); } void BigintMandelWidget::export_img() { QString file_name = get_save_file_name( this, "Save image", "", "Images", QStringList{".png", ".xpm", ".jpg"}, ".png" ); if (!file_name.isEmpty()) settings.save_img(file_name); } void BigintMandelWidget::exec_settings_widget() { settings_widget->update_fields(settings.get_params(), fw->isFinished()); settings_widget->exec(); } void BigintMandelWidget::reset() { fw->cancel(); fw->waitForFinished(); settings.reset(128, get_ideal_size()); start_calculation(fw, settings.get_cells()); update(); } void BigintMandelWidget::settings_widget_accepted() { settings.set_max_iter(settings_widget->get_max_iter().toULongLong()); start_calculation(fw, settings.get_cells()); update(); } void BigintMandelWidget::load_data() { QFile file; QJsonObject json; QByteArray qba; QString file_name = QFileDialog::getOpenFileName( this, "Load Data", "", "BigintMandel Data (*.json *.json.qcompress)" ); if (file_name.isEmpty()) return; file.setFileName(file_name); if (!file.open(QIODevice::ReadOnly)) { qWarning("Couldn't open save file."); return; } qba = file.readAll(); file.close(); if (file_name.endsWith(".qcompress")) qba = qUncompress(qba); settings.from_json(QJsonDocument::fromJson(qba).object()); update(); } void BigintMandelWidget::save_data() { QFile file; QByteArray qba; QString file_name = get_save_file_name( this, "Save data", "", "Bigintmandel Data", QStringList{".json", ".json.qcompress"}, ".json.qcompress" ); if (file_name.isEmpty()) return; qba = QJsonDocument(settings.to_json()).toJson(); if (file_name.endsWith(".qcompress")) qba = qCompress(qba, 9); file.setFileName(file_name); if (!file.open(QIODevice::WriteOnly)) { qWarning("Couldn't open save file."); return; } file.write(qba); file.close(); } void BigintMandelWidget::update() { update_status_bar(); QWidget::update(); }