menubar.h
mandellabel.cpp
mandellabel.h
+ uint64validator.cpp
+ uint64validator.h
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
}
BigintMandelWidget::~BigintMandelWidget() {
- fw->cancel();
- fw->waitForFinished();
+ stop();
}
void BigintMandelWidget::finished_cell(int num) {
void BigintMandelWidget::finished() {
mandel_label->set_draw_progress(-1);
- settings_widget->set_finished(true);
update();
}
}
void BigintMandelWidget::start() {
+ stop();
fw->setFuture(
QtConcurrent::mapped(
settings.get_cells(),
update();
}
+void BigintMandelWidget::stop() {
+ fw->cancel();
+ fw->waitForFinished();
+}
+
void BigintMandelWidget::mousePressEvent(QMouseEvent *event) {
QSize size(settings.get_params().get_size());
QPoint pos(event->pos());
}
void BigintMandelWidget::exec_settings_widget() {
- settings_widget->update_fields(settings.get_params(), fw->isFinished());
+ settings_widget->update_fields(settings.get_params());
settings_widget->exec();
}
void BigintMandelWidget::reset() {
- fw->cancel();
- fw->waitForFinished();
settings.reset(128, get_ideal_size());
start();
}
void BigintMandelWidget::settings_widget_accepted() {
- settings.set_max_iter(settings_widget->get_max_iter().toULongLong());
+ if (settings_widget->clear_image()) {
+ 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();
}
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();
+}
void update_status_bar();
void start();
+ void stop();
inline const QSize get_ideal_size() const {
return scroll_area->size().shrunkBy(scroll_area->contentsMargins());
}
void load_data();
void save_data();
void update();
+ void resize_to_window();
};
#endif // BIGINTMANDELWIDGET_H
#include "colors.h"
#include "mandel.h"
+static inline const MpzPoint calculate_offset(
+ const MpzPoint center_f, const QSize size
+) {
+ return MpzPoint(
+ center_f.get_x() - size.width() / 2,
+ center_f.get_y() + size.height() / 2
+ );
+}
+
MandelParams::MandelParams() {}
MandelParams::MandelParams(
- size_t max_iter,
+ quint64 max_iter,
QSize size,
MpzPoint center_f,
mpz_class one
) : max_iter(max_iter),
size(size),
center_f(center_f),
- one(one),
- left(center_f.get_x() - size.width() / 2.),
- top(center_f.get_y() + size.height() / 2.) {}
+ offset(calculate_offset(center_f, size)),
+ one(one) {}
MandelParams::MandelParams(const MandelParams &other)
: max_iter(other.max_iter),
size(other.size),
center_f(other.center_f),
- one(other.one),
- left(center_f.get_x() - size.width() / 2.),
- top(center_f.get_y() + size.height() / 2.) {}
+ offset(calculate_offset(other.center_f, other.size)),
+ one(other.one) {}
+
+void MandelParams::set_size(const QSize &size) {
+ this->size = size;
+ this->offset = calculate_offset(center_f, size);
+}
MandelParams MandelParams::from_json(const QJsonObject &json) {
return MandelParams(
return img;
}
-MandelSettings::MandelSettings(size_t max_iter, const QSize size)
+MandelSettings::MandelSettings(quint64 max_iter, const QSize size)
: img(nullptr) {
reset(max_iter, size);
}
+void MandelSettings::clear() {
+ img = setup_image(img, params.get_size());
+ img->fill(Qt::GlobalColor::black);
+ setup_cells(cells, ¶ms);
+}
+
void MandelSettings::zoom(const QSize size, int zoom_factor, const QPoint pos) {
MpzPoint p = cells[img->width() * pos.y() + pos.x()].get_rpos0();
params = MandelParams(
MpzPoint(p.get_x() * zoom_factor, p.get_y() * zoom_factor),
params.get_one() * zoom_factor
);
- img = setup_image(img, size);
- img->fill(Qt::GlobalColor::black);
- setup_cells(cells, ¶ms);
+ clear();
}
void MandelSettings::finished_cell(int num, const MandelResultCell &result) {
img->save(file_name);
}
-void MandelSettings::reset(size_t max_iter, const QSize size) {
+void MandelSettings::reset(quint64 max_iter, const QSize size) {
mpz_class one;
MpzPoint center_f;
int ione = std::min(size.width(), size.height()) / 3;
one = mpz_class(ione + 1);
center_f = MpzPoint(one * -3 / 4, 0);
params = MandelParams(max_iter, size, center_f, one);
- img = setup_image(img, size);
- setup_cells(cells, ¶ms);
+ clear();
}
void MandelSettings::from_json(const QJsonObject &json) {
rpos0(cell.rpos0) {}
void MandelCell::setup(const QPoint pos) {
+ const MpzPoint &offset = params->get_offset();
this->pos = pos;
- rpos0 = MpzPoint(params->get_left() + pos.x(), params->get_top() - pos.y());
+ rpos0 = MpzPoint(offset.get_x() + pos.x(), offset.get_y() - pos.y());
result = MandelResultCell();
}
MpzPoint rpos = result.get_rpos(), sq;
mpz_class one = params->get_one(), four = one * one * 4;
mpz_class sqx, sqy;
- size_t iter = result.get_iter();
+ quint64 iter = result.get_iter();
for (; iter < params->get_max_iter(); iter++) {
sqx = rpos.get_x() * rpos.get_x();
sqy = rpos.get_y() * rpos.get_y();
};
class MandelResultCell {
- size_t iter;
+ quint64 iter;
MpzPoint rpos;
public:
MandelResultCell() : iter(0) {}
- explicit MandelResultCell(size_t iter, MpzPoint rpos)
+ explicit MandelResultCell(quint64 iter, MpzPoint rpos)
: iter(iter), rpos(rpos) {}
- inline const size_t get_iter() const { return iter; }
+ inline const quint64 get_iter() const { return iter; }
inline const MpzPoint get_rpos() const { return rpos; }
};
class MandelParams {
private:
- size_t max_iter;
+ quint64 max_iter;
QSize size;
- MpzPoint center_f;
- mpz_class left, top, one;
+ MpzPoint center_f, offset;
+ mpz_class one;
public:
// required by the MandelSettings constructor
MandelParams();
explicit MandelParams(
- size_t max_iter,
+ quint64 max_iter,
QSize size,
MpzPoint center_f,
mpz_class one
);
MandelParams(const MandelParams &other);
- inline const size_t get_max_iter() const { return max_iter; }
- inline void set_max_iter(const size_t max_iter) { this->max_iter = max_iter; }
+ inline const quint64 get_max_iter() const { return max_iter; }
+ inline void set_max_iter(const quint64 max_iter) {
+ this->max_iter = max_iter;
+ }
inline const QSize get_size() const { return size; }
+ void set_size(const QSize &size);
inline const MpzPoint get_center_f() const { return center_f; }
- inline const mpz_class get_left() const { return left; }
- inline const mpz_class get_top() const { return top; }
+ inline const MpzPoint &get_offset() const {
+ return offset;
+ }
inline const mpz_class get_one() const { return one; }
static MandelParams from_json(const QJsonObject &json);
QVector<MandelCell> cells;
public:
- explicit MandelSettings(size_t max_iter, QSize size);
+ explicit MandelSettings(quint64 max_iter, QSize size);
+ void clear();
inline QPixmap get_pixmap() const { return QPixmap::fromImage(*img); }
inline const QVector<MandelCell> get_cells() const { return cells; }
inline const MandelParams &get_params() const { return params; }
- inline void set_max_iter(size_t max_iter) { params.set_max_iter(max_iter); }
+ inline void set_params(const MandelParams ¶ms) {
+ this->params = params;
+ }
+ inline quint64 get_max_iter() const { return params.get_max_iter(); }
+ inline void set_max_iter(quint64 max_iter) {
+ params.set_max_iter(max_iter);
+ }
+ inline void set_size(const QSize &size) {
+ params.set_size(size);
+ }
void zoom(const QSize size, int zoom_factor, const QPoint pos);
void finished_cell(int num, const MandelResultCell &cell);
void save_img(QString file_name);
- void reset(size_t max_iter, QSize size);
+ void reset(quint64 max_iter, QSize size);
void from_json(const QJsonObject &json);
QJsonObject to_json();
};
inline const QPoint get_pos() const { return pos; }
inline const MpzPoint get_rpos0() const { return rpos0; }
inline const QColor get_color() const {
- size_t iter = result.get_iter();
+ quint64 iter = result.get_iter();
return iter < params->get_max_iter()
? colors[iter % colors.size()]
: Qt::GlobalColor::black;
reset_action = calc_menu->addAction(
"&Reset", no_key, parent, &BigintMandelWidget::reset
);
+ resize_action = calc_menu->addAction(
+ "Resi&ze to Window",
+ no_key,
+ parent,
+ &BigintMandelWidget::resize_to_window
+ );
settings_action = calc_menu->addAction(
"&Settings", no_key, parent, &BigintMandelWidget::exec_settings_widget
);
QAction *load_action, *save_action;
QAction *export_action, *exit_action;
QMenu *calc_menu;
- QAction *reset_action, *settings_action;
+ QAction *reset_action, *resize_action, *settings_action;
QMenu *zoom_menu;
QAction *no_action, *two_action, *four_action;
QAction *eight_action, *sixteen_action;
// settingswidget.cpp
+#include <gmpxx.h>
#include <QPushButton>
#include <QLabel>
-#include <QLayout>
#include <QIntValidator>
#include "settingswidget.h"
+#include "uint64validator.h"
+
+SettingsWidgetFieldBase::SettingsWidgetFieldBase(
+ const QString &label, QWidget *parent
+) : edit(new QLineEdit("", parent)),
+ label(label)
+{
+ edit->setMinimumWidth(256);
+}
+
+void SettingsWidgetFieldBase::add_to_layout(QGridLayout *grid_layout) {
+ int row_count = grid_layout->rowCount();
+ grid_layout->addWidget(
+ new QLabel(label, edit->parentWidget()), row_count, 0
+ );
+ grid_layout->addWidget(edit, row_count, 1);
+}
+
+void SettingsWidgetFieldBase::add_on_editing_finished(
+ SettingsWidget *settings_widget, const char *method_name
+) {
+ QObject::connect(edit, SIGNAL(editingFinished()), settings_widget, method_name);
+}
+
+void SettingsWidgetFieldBase::reset() {
+ edit->setText(orig_value);
+}
+
+SettingsWidgetField<quint64>::SettingsWidgetField(
+ const QString &label, QWidget *parent
+) : SettingsWidgetFieldBase(label, parent) {
+ edit->setValidator(new UInt64Validator(edit));
+}
+
+void SettingsWidgetField<quint64>::set_value(quint64 value) {
+ orig_value = QString::number(value);
+ reset();
+}
+
+SettingsWidgetField<int>::SettingsWidgetField(
+ const QString &label, QWidget *parent
+) : SettingsWidgetFieldBase(label, parent) {
+ edit->setValidator(new QIntValidator(edit));
+}
+
+void SettingsWidgetField<int>::set_value(int value) {
+ orig_value = QString::number(value);
+ reset();
+}
+
+SettingsWidgetField<mpz_class>::SettingsWidgetField(
+ const QString &label, QWidget *parent
+) : SettingsWidgetFieldBase(label, parent) {
+ static QRegularExpression number_re("^\\d+$");
+ edit->setValidator(new QRegularExpressionValidator(number_re));
+}
+
+void SettingsWidgetField<mpz_class>::set_value(const mpz_class &value) {
+ orig_value = QString::QString::fromStdString(value.get_str());
+ reset();
+}
SettingsWidget::SettingsWidget(QWidget *parent)
: QDialog(parent),
- max_iter(new QLineEdit("", this)),
- width(new QLineEdit("", this)),
- height(new QLineEdit("", this)),
- center_f_x(new QLineEdit("", this)),
- center_f_y(new QLineEdit("", this)),
- one(new QLineEdit("", this))
+ max_iter("max_iter", this),
+ width("width", this),
+ height("height", this),
+ center_f_x("x", this),
+ center_f_y("y", this),
+ one("one", this),
+ clear_image_checkbox(new QCheckBox("Clear image", this))
{
- static QStringList labels = {
- "max_iter", "width", "height", "x", "y", "one"
- };
- static QList<QLineEdit*> line_edits = {
- max_iter, width, height, center_f_x, center_f_y, one
- };
- QPushButton *apply_button = new QPushButton("Apply");
+ QPushButton *accept_button = new QPushButton("&Accept");
+ QPushButton *reject_button = new QPushButton("&Reject");
QGridLayout *grid_layout = new QGridLayout(this);
+ QBoxLayout *button_row = new QBoxLayout(QBoxLayout::Direction::RightToLeft);
int i;
- setLayout(grid_layout);
- for (i = 0; i < line_edits.size(); i++) {
- grid_layout->addWidget(new QLabel(labels[i], this), i, 0);
- if (i == 0)
- line_edits[i]->setValidator(
- new QIntValidator(0, INT_MAX, line_edits[i])
- );
- else
- line_edits[i]->setReadOnly(true);
- line_edits[i]->setMinimumWidth(256);
- grid_layout->addWidget(line_edits[i], i, 1);
- }
+ max_iter.add_to_layout(grid_layout);
+ width.add_to_layout(grid_layout);
+ width.add_on_editing_finished(this, SLOT(update_form()));
+ height.add_to_layout(grid_layout);
+ height.add_on_editing_finished(this, SLOT(update_form()));
+ center_f_x.add_to_layout(grid_layout);
+ center_f_x.add_on_editing_finished(this, SLOT(update_form()));
+ center_f_y.add_to_layout(grid_layout);
+ center_f_y.add_on_editing_finished(this, SLOT(update_form()));
+ one.add_to_layout(grid_layout);
+ one.add_on_editing_finished(this, SLOT(update_form()));
+ connect(
+ clear_image_checkbox,
+ &QCheckBox::checkStateChanged,
+ this,
+ &SettingsWidget::clear_image_checkbox_changed
+ );
+ grid_layout->addWidget(clear_image_checkbox, grid_layout->rowCount(), 1);
connect(
- apply_button,
+ accept_button,
&QPushButton::clicked,
this,
- &SettingsWidget::apply
+ &SettingsWidget::accept
);
- grid_layout->addWidget(apply_button, i, 1);
+ button_row->addWidget(accept_button);
+ connect(
+ reject_button,
+ &QPushButton::clicked,
+ this,
+ &SettingsWidget::reject
+ );
+ button_row->addWidget(reject_button);
+ grid_layout->addLayout(button_row, grid_layout->rowCount(), 0, 1, 2);
}
-void SettingsWidget::update_fields(
- const MandelParams ¶ms, const bool is_finished
-) {
+void SettingsWidget::update_fields(const MandelParams ¶ms) {
QSize size = params.get_size();
MpzPoint center_f = params.get_center_f();
- max_iter->setText(QString::number(params.get_max_iter()));
- width->setText(QString::number(size.width()));
- height->setText(QString::number(size.height()));
- center_f_x->setText(QString::fromStdString(center_f.get_x().get_str()));
- center_f_y->setText(QString::fromStdString(center_f.get_y().get_str()));
- one->setText(QString::fromStdString(params.get_one().get_str()));
- set_finished(is_finished);
+ max_iter.set_value(params.get_max_iter());
+ width.set_value(size.width());
+ height.set_value(size.height());
+ center_f_x.set_value(center_f.get_x());
+ center_f_y.set_value(center_f.get_y());
+ one.set_value(params.get_one());
+ clear_image_checkbox->setChecked(false);
+}
+
+void SettingsWidget::update_form() {
+ if (
+ width.is_edited()
+ || height.is_edited()
+ || center_f_x.is_edited()
+ || center_f_y.is_edited()
+ || one.is_edited()
+ )
+ // todo: add a messagebox that we do this
+ clear_image_checkbox->setChecked(true);
}
-void SettingsWidget::apply() {
- if (is_finished)
- accept();
- else
- reject();
+void SettingsWidget::clear_image_checkbox_changed(Qt::CheckState state) {
+ if (state == Qt::Unchecked) {
+ // todo: add a messagebox if we should do this
+ width.reset();
+ height.reset();
+ center_f_x.reset();
+ center_f_y.reset();
+ one.reset();
+ }
}
#ifndef SETTINGSWIDGET_H
#define SETTINGSWIDGET_H
+#include <QCheckBox>
#include <QDialog>
#include <QLabel>
+#include <QLayout>
#include <QLineEdit>
#include "mandel.h"
+class SettingsWidget;
+
+class SettingsWidgetFieldBase {
+protected:
+ QLineEdit *edit;
+ const QString label;
+ QString orig_value;
+
+public:
+ SettingsWidgetFieldBase(const QString &label, QWidget *parent = nullptr);
+ inline bool is_edited() const { return edit->text() != orig_value; }
+ void add_to_layout(QGridLayout *grid_layout);
+ void add_on_editing_finished(
+ SettingsWidget *settings_widget, const char *method_name
+ );
+ void reset();
+};
+
+template <typename T> class SettingsWidgetField;
+template <>
+class SettingsWidgetField<quint64> : public SettingsWidgetFieldBase {
+public:
+ explicit SettingsWidgetField(
+ const QString &label, QWidget *parent = nullptr
+ );
+ void set_value(quint64 value);
+ inline const quint64 get_value() const {
+ return edit->text().toULongLong();
+ }
+};
+
+template <>
+class SettingsWidgetField<int> : public SettingsWidgetFieldBase {
+public:
+ explicit SettingsWidgetField(
+ const QString &label, QWidget *parent = nullptr
+ );
+ void set_value(int value);
+ inline const int get_value() const {
+ return edit->text().toInt();
+ }
+};
+
+template <>
+class SettingsWidgetField<mpz_class> : public SettingsWidgetFieldBase {
+public:
+ explicit SettingsWidgetField(
+ const QString &label, QWidget *parent = nullptr
+ );
+ void set_value(const mpz_class &value);
+ inline const mpz_class get_value() const {
+ return mpz_class(edit->text().toStdString());
+ }
+};
+
class SettingsWidget : public QDialog {
Q_OBJECT
- QLineEdit *max_iter, *width, *height, *center_f_x, *center_f_y, *one;
- bool is_finished;
+ SettingsWidgetField<quint64> max_iter;
+ SettingsWidgetField<int> width, height;
+ SettingsWidgetField<mpz_class> center_f_x, center_f_y, one;
+ QCheckBox *clear_image_checkbox;
public:
explicit SettingsWidget(QWidget *parent = nullptr);
- void update_fields(const MandelParams ¶ms, const bool is_finished);
- inline const QString get_max_iter() const { return max_iter->text(); };
-
- inline void set_finished(const bool is_finished) {
- this->is_finished = is_finished;
- max_iter->setReadOnly(!is_finished);
+ void update_fields(const MandelParams ¶ms);
+ inline const quint64 get_max_iter() const { return max_iter.get_value(); }
+ inline const MandelParams get_params() {
+ return MandelParams(
+ max_iter.get_value(),
+ QSize(width.get_value(), height.get_value()),
+ MpzPoint(center_f_x.get_value(), center_f_y.get_value()),
+ one.get_value()
+ );
+ }
+ inline bool clear_image() const {
+ return clear_image_checkbox->isChecked();
}
public Q_SLOTS:
- void apply();
+ void update_form();
+ void clear_image_checkbox_changed(Qt::CheckState state);
};
#endif // SETTINGSWIDGET_H
--- /dev/null
+
+// uint64validator.cpp
+
+#include "uint64validator.h"
+
+UInt64Validator::UInt64Validator(
+ quint64 bottom, quint64 top, QObject *parent
+) : QValidator(parent), bottom(bottom), top(top) {}
+UInt64Validator::UInt64Validator(QObject *parent)
+: UInt64Validator(
+ std::numeric_limits<quint64>::min(),
+ std::numeric_limits<quint64>::max(),
+ parent
+ ) {}
+
+QValidator::State UInt64Validator::validate(QString &input, int&) const {
+ bool ok = false;
+ quint64 num = input.toULongLong(&ok);
+ if (!ok)
+ return QValidator::Invalid;
+ if (num < bottom)
+ return QValidator::Intermediate;
+ if (num > top)
+ return QValidator::Invalid;
+ return QValidator::Acceptable;
+}
--- /dev/null
+
+// uint64validator.h
+
+#ifndef UINT64VALIDATOR_H
+#define UINT64VALIDATOR_H
+
+#include <QValidator>
+
+class UInt64Validator : public QValidator {
+ Q_OBJECT
+ quint64 bottom;
+ quint64 top;
+
+public:
+ UInt64Validator(quint64 bottom, quint64 top, QObject *parent = nullptr);
+ UInt64Validator(QObject *parent = nullptr);
+ inline quint64 get_bottom() const { return bottom; }
+ inline quint64 get_top() const { return top; }
+ inline void set_bottom(quint64 bottom) {
+ set_range(bottom, get_top());
+ }
+ inline void set_top(quint64 top) {
+ set_range(get_bottom(), top);
+ }
+ void set_range(quint64 bottom, quint64 top) {
+ if(this->bottom == bottom && this->top == top)
+ return;
+ this->bottom = bottom;
+ this->top = top;
+ emit changed();
+ }
+ QValidator::State validate(QString &input, int&) const override;
+};
+
+#endif // UINT64VALIDATOR_H