/* * bigintmandelwidget.cpp * * This file is covered by the LICENSE file in the root of this project. */ #include #include #include #include #include #include #include "bigintmandelwidget.h" #include "mandellabel.h" #include "menubar.h" #include "settingswidget.h" 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 ); 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()); start(); } BigintMandelWidget::~BigintMandelWidget() { stop(); } void BigintMandelWidget::finished_cell(int num) { QSize size = settings.get_params().get_size(); int y = num / size.width() + 1; mandel_label->set_draw_progress(y < size.height() - 1 ? y + 1 : -1); settings.finished_cell(num, fw->resultAt(num)); update(); } void BigintMandelWidget::finished() { mandel_label->set_draw_progress(-1); 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 if (settings.get_zoom_factor() == -1) ss << "Choose a zoom factor from the \"Zoom\" menu."; else ss << "Click the rendering to zoom."; status_bar->showMessage(*ss.string()); prev_num_threads = num_threads; } void BigintMandelWidget::start() { stop(); fw->setFuture( QtConcurrent::mapped( settings.get_cells(), [](const MandelCell &cell){ return cell.iterate(); } ) ); settings.set_zoom_factor(-1); update(); } void BigintMandelWidget::stop() { fw->cancel(); fw->waitForFinished(); } void BigintMandelWidget::mousePressEvent(QMouseEvent *event) { QSize size(settings.get_params().get_size()); QPoint pos(event->pos()); QWidget *w; int zoom_factor = settings.get_zoom_factor(); 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() || zoom_factor == -1) return; settings.zoom(get_ideal_size(), zoom_factor, pos); start(); } 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; ss << filter_title << " (" << ext_list.join(" ") << ")"; file_name = QFileDialog::getSaveFileName( parent, caption, dir, *ss.string() ); if (file_name.isEmpty()) return file_name; ss.string()->clear(); ss << file_name; for ( ext_list_iter = ext_list.constBegin(); ext_list_iter != ext_list.constEnd(); ext_list_iter++ ) if (file_name.endsWith(*ext_list_iter)) break; if (ext_list_iter == ext_list.constEnd()) 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_params(settings.get_params()); settings_widget->exec(); } void BigintMandelWidget::reset() { settings.reset(128, get_ideal_size()); start(); } void BigintMandelWidget::settings_widget_accepted() { if (settings_widget->is_clear_image_checked()) { settings.set_params(settings_widget->get_params()); settings.clear(); } else { quint64 max_iter = settings_widget->get_max_iter(); if (max_iter <= settings.get_max_iter()) return; settings.set_max_iter(max_iter); } start(); } 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(); } void BigintMandelWidget::resize_to_window() { QSize size = get_ideal_size(); if (size == settings.get_params().get_size()) return; settings.set_size(size); settings.clear(); start(); }