From e409259abf54c2bda9403b965e0b62b59e5ec4ef Mon Sep 17 00:00:00 2001 From: mar77i Date: Mon, 1 Apr 2024 16:50:13 +0200 Subject: [PATCH] extend user interface a bit --- .gitignore | 1 + bigintwidget.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++-- bigintwidget.h | 5 ++++ mandel.cpp | 44 +++++++++++++-------------- mandel.h | 19 +++++++----- 5 files changed, 113 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index 0c9e5c7..95e8349 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,4 @@ CMakeLists.txt.user* # Build directories # ----------------- build-*/ +build/ diff --git a/bigintwidget.cpp b/bigintwidget.cpp index 88a3889..5ae07ce 100644 --- a/bigintwidget.cpp +++ b/bigintwidget.cpp @@ -1,6 +1,7 @@ // bigintwidget.cpp +#include #include #include #include @@ -10,9 +11,10 @@ BigintWidget::BigintWidget(QWidget *parent) : QWidget(parent), fw(new QFutureWatcher(this)), - meta(8192, QSize(1800, 1000)), + meta(8192, QSize(1800, 900)), img_label(new QLabel(this)), - img_dirty(true) + img_dirty(true), + status_bar(new QStatusBar(this)) { connect( fw, @@ -28,7 +30,10 @@ BigintWidget::BigintWidget(QWidget *parent) ); fw->setFuture(QtConcurrent::mapped(meta.get_cells(), MandelMeta::iterate)); setLayout(new QVBoxLayout()); + layout()->addWidget(setup_menu_bar()); layout()->addWidget(img_label); + status_bar->setSizeGripEnabled(false); + layout()->addWidget(status_bar); img_label->setMinimumSize(meta.get_size()); } @@ -37,6 +42,42 @@ BigintWidget::~BigintWidget() { fw->waitForFinished(); } +QMenuBar *BigintWidget::setup_menu_bar() { + QMenuBar *menu_bar = new QMenuBar(this); + QMenu *menu = new QMenu("&File", this); + menu_bar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect( + menu->addAction("&Export"), + &QAction::triggered, + this, + &BigintWidget::export_img + ); + menu->addSeparator(); + connect( + menu->addAction("E&xit"), + &QAction::triggered, + this, + &BigintWidget::close + ); + menu_bar->addMenu(menu); +/* + menu = new QMenu("&Calcluation", this); + connect( + menu->addAction("&Double Max Iterations"), + &QAction::triggered, + this, + &meta.double_max_iter + ); + connect( + menu->addAction("&Halve Max Iterations"), + &QAction::triggered, + this, + &meta.halve_max_iter + ); +*/ + return menu_bar; +} + void BigintWidget::finished_cell(int num) { meta.finished_cell(num, fw->resultAt(num)); img_dirty = true; @@ -48,10 +89,33 @@ void BigintWidget::finished() { update(); } +static inline void calculating_status( + QStatusBar *status_bar, int &prev_num_threads +) { + QTextStream ss(new QString()); + int num_threads = QThreadPool::globalInstance()->activeThreadCount(); + if (prev_num_threads == num_threads) + return; + ss << "Calculating with " << num_threads << " threads ..."; + status_bar->showMessage(ss.readAll()); + prev_num_threads = num_threads; +} + +static inline void finished_status(QStatusBar *status_bar) { + status_bar->showMessage("Click the rendering to zoom."); +} + void BigintWidget::paintEvent(QPaintEvent *event) { + static int prev_num_threads = -1; if (img_dirty) { img_label->setPixmap(meta.get_pixmap()); img_dirty = false; + if (fw->isFinished()) + finished_status(status_bar); + else { + calculating_status(status_bar, prev_num_threads); + prev_num_threads = -1; + } } } @@ -62,8 +126,16 @@ void BigintWidget::mousePressEvent(QMouseEvent *event) { if (pos.x() < 0 || pos.x() >= meta.get_width() || pos.y() < 0 || pos.y() >= meta.get_height()) return; - meta.zoom2x(pos); + meta.zoom(pos); fw->setFuture(QtConcurrent::mapped(meta.get_cells(), MandelMeta::iterate)); img_dirty = true; update(); } + +void BigintWidget::export_img() { + meta.save_img( + QFileDialog::getSaveFileName( + this, "Save image", "", "Images (*.png *.xpm *.jpg)" + ) + ); +} diff --git a/bigintwidget.h b/bigintwidget.h index 5d1964b..6952bb2 100644 --- a/bigintwidget.h +++ b/bigintwidget.h @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include "mandel.h" @@ -17,14 +19,17 @@ class BigintWidget : public QWidget { MandelMeta meta; QLabel *img_label; bool img_dirty; + QStatusBar *status_bar; public: BigintWidget(QWidget *parent = nullptr); ~BigintWidget(); + QMenuBar *setup_menu_bar(); void finished_cell(int num); void finished(); void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); + void export_img(); }; #endif // BIGINTWIDGET_H diff --git a/mandel.cpp b/mandel.cpp index 795b4e4..10e6b4d 100644 --- a/mandel.cpp +++ b/mandel.cpp @@ -1,8 +1,6 @@ // mandel.cpp -#include - #include "colors.h" #include "mandel.h" @@ -10,7 +8,7 @@ MpzPoint::MpzPoint() : x(), y() {} MpzPoint::MpzPoint(mpz_class x, mpz_class y) : x(x), y(y) {} MpzPoint::MpzPoint(const MpzPoint &other) : x(other.x), y(other.y) {} -MandelResultCell::MandelResultCell() {} +MandelResultCell::MandelResultCell() : iter(0) {} MandelResultCell::MandelResultCell(size_t iter, MpzPoint rpos) : iter(iter), rpos(rpos) {} @@ -46,12 +44,11 @@ MandelMeta::MandelMeta(size_t max_iter, const QSize size) center_f = MpzPoint(one * -3 / 4, 0); for (i = cells.begin(); i != cells.end(); incrpos(pos, size.width()), i++) { - i->set_meta(this); i->set_pos(pos); } } -void MandelMeta::zoom2x(QPoint pos) { +void MandelMeta::zoom(QPoint pos) { QVector::iterator i; MpzPoint p = cells[img.width() * pos.y() + pos.x()].get_rpos0(); center_f = MpzPoint(p.get_x() * 8, p.get_y() * 8); @@ -61,11 +58,13 @@ void MandelMeta::zoom2x(QPoint pos) { i->reset_iter_and_rpos(); } -void MandelMeta::finished_cell(int num, const MandelResultCell &cell) { +void MandelMeta::finished_cell(int num, const MandelResultCell &result) { + size_t iter = result.get_iter(); + cells[num].set_result(result); img.setPixelColor( - cells[num].update_result(cell.iter, cell.rpos), - cell.iter < max_iter - ? colors[cell.iter % colors.size()] + cells[num].get_pos(), + iter < max_iter + ? colors[iter % colors.size()] : Qt::GlobalColor::black ); } @@ -74,6 +73,10 @@ MandelResultCell MandelMeta::iterate(const MandelCell &cell) { return cell.iterate(); } +void MandelMeta::save_img(QString file_name) { + img.save(file_name); +} + void MandelCell::reset_rpos0() { MpzPoint center_f = meta->get_center_f(); rpos0 = MpzPoint( @@ -82,38 +85,31 @@ void MandelCell::reset_rpos0() { ); } -MandelCell::MandelCell(MandelMeta *meta) : meta(meta), iter(0) {} +MandelCell::MandelCell(MandelMeta *meta) : meta(meta) {} MandelCell::MandelCell(const MandelCell &cell) -: meta(cell.meta), pos(cell.pos), iter(cell.iter), - rpos(cell.rpos), rpos0(cell.rpos0) {} +: meta(cell.meta), pos(cell.pos), result(cell.result), + rpos0(cell.rpos0) {} -QPoint MandelCell::update_result(size_t iter, const MpzPoint &rpos) { - this->iter = iter; - this->rpos = rpos; - return pos; +void MandelCell::set_result(const MandelResultCell &result) { + this->result = result; } void MandelCell::reset_iter_and_rpos() { - iter = 0; - rpos = MpzPoint(); + result = MandelResultCell(); reset_rpos0(); } -void MandelCell::set_meta(MandelMeta *meta) { - this->meta = meta; -} - void MandelCell::set_pos(QPoint pos) { this->pos = pos; reset_rpos0(); } MandelResultCell MandelCell::iterate() const { - MpzPoint rpos = this->rpos, sq; + MpzPoint rpos = this->result.rpos, sq; mpz_class one = meta->get_one(), four = one * one * 4; mpz_class sqx, sqy; - size_t iter = this->iter; + size_t iter = this->result.iter; for (; iter < meta->get_max_iter(); iter++) { sqx = rpos.get_x() * rpos.get_x(); sqy = rpos.get_y() * rpos.get_y(); diff --git a/mandel.h b/mandel.h index 99ff14c..7876ec4 100644 --- a/mandel.h +++ b/mandel.h @@ -22,16 +22,20 @@ public: }; class MandelResultCell { - friend class MandelMeta; + friend class MandelCell; size_t iter; MpzPoint rpos; public: MandelResultCell(); MandelResultCell(size_t iter, MpzPoint rpos); + const size_t get_iter() const { return iter; } }; class MandelMeta { + /* max_iter, img size, center_f and one are parameters + * that we may want to adjust for our next calculation. + */ size_t max_iter; QImage img; QVector cells; @@ -49,16 +53,17 @@ public: const MpzPoint get_center_f() const { return center_f; } const mpz_class get_one() const { return one; } - void zoom2x(QPoint pos); + void zoom(QPoint pos); void finished_cell(int num, const MandelResultCell &cell); static MandelResultCell iterate(const MandelCell &cell); + void save_img(QString file_name); }; class MandelCell { MandelMeta *meta; QPoint pos; - size_t iter; - MpzPoint rpos, rpos0; + MpzPoint rpos0; + MandelResultCell result; protected: void reset_rpos0(); @@ -66,12 +71,12 @@ protected: public: MandelCell(MandelMeta *meta); MandelCell(const MandelCell &cell); - inline const size_t get_iter() const { return iter; } + inline const QPoint get_pos() const { return pos; } + inline const size_t get_iter() const { return result.iter; } inline const MpzPoint get_rpos0() const { return rpos0; } - QPoint update_result(size_t iter, const MpzPoint &rpos); void reset_iter_and_rpos(); - void set_meta(MandelMeta *meta); + void set_result(const MandelResultCell &result); void set_pos(const QPoint pos); MandelResultCell iterate() const; }; -- 2.47.0