diff --git a/serialization b/serialization index 346a0f9..3f841de 160000 --- a/serialization +++ b/serialization @@ -1 +1 @@ -Subproject commit 346a0f92cc8feddfbfc46560b4609ab4a32854fb +Subproject commit 3f841ded4e5e44118c1b129cbd9488cc43943933 diff --git a/src/ImageViewerApplication.cpp b/src/ImageViewerApplication.cpp index c9b6318..6d04079 100644 --- a/src/ImageViewerApplication.cpp +++ b/src/ImageViewerApplication.cpp @@ -144,8 +144,11 @@ class DeserializationException : public std::exception { case DeserializerStream::ErrorType::AllocateAbstractObject: this->message = "The stream contains a concrete object with an abstract class type ID."; break; + case DeserializerStream::ErrorType::AllocateObjectOfUnknownType: + this->message = "The stream contains an object of an unknown type. Did you try to import a configuration created by a newer version of the program?"; + break; default: - this->message = "Unknown."; + this->message = "Unknown error."; break; } } @@ -171,7 +174,7 @@ void ImageViewerApplication::save_settings(bool with_state){ return; Settings settings; settings.main = this->settings; - if (with_state) + if (with_state && this->settings->get_save_state_on_exit()) this->save_current_state(settings.state); settings.shortcuts = this->shortcuts.save_settings(); diff --git a/src/ImageViewport.cpp b/src/ImageViewport.cpp index 0a31218..e737f4d 100644 --- a/src/ImageViewport.cpp +++ b/src/ImageViewport.cpp @@ -40,6 +40,17 @@ QMatrix translate(const QMatrix &m, const QPointF &offset){ void ImageViewport::paintEvent(QPaintEvent *){ QPainter painter(this); + if (!this->pixmap() && !this->movie()){ + painter.setBrush(QBrush(Qt::white)); + auto font = painter.font(); + font.setPixelSize(48); + painter.setFont(font); + QRect rect(0, 0, 800, 600); + painter.fillRect(rect, Qt::black); + painter.drawText(rect, "No image"); + return; + } + painter.setRenderHint(or_flags(QPainter::SmoothPixmapTransform, QPainter::Antialiasing)); painter.setClipping(false); @@ -50,7 +61,7 @@ void ImageViewport::paintEvent(QPaintEvent *){ painter.setMatrix(transform); if (this->pixmap()) painter.drawPixmap(QRect(QPoint(0, 0), this->image_size), *this->pixmap()); - else if (this->movie()) + else painter.drawPixmap(QRect(QPoint(0, 0), this->image_size), this->movie()->currentPixmap()); } diff --git a/src/ImageViewport.h b/src/ImageViewport.h index df0f372..dab78d2 100644 --- a/src/ImageViewport.h +++ b/src/ImageViewport.h @@ -57,6 +57,8 @@ class ImageViewport : public QLabel size = this->compute_quad_no_zoom(size).get_bounding_box().size().toSize(); } QSize get_size() const{ + if (!this->pixmap() && !this->movie()) + return QSize(800, 600); auto ret = this->image_size; this->compute_size(ret); return ret; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index b1619d5..d2e6fc5 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -201,7 +201,7 @@ void MainWindow::set_background(bool force){ QWidget *p1 = this->ui->checkerboard; QWidget *p2 = this->ui->solid; - if (!this->window_state->get_using_checkerboard_pattern()){ + if (!this->window_state->get_using_checkerboard_pattern() && this->displayed_image){ this->set_solid(this->displayed_image->get_background_color()); std::swap(p1, p2); } @@ -222,12 +222,12 @@ void MainWindow::set_background_sizes(){ void MainWindow::show_nothing(){ qDebug() << "MainWindow::show_nothing()"; this->displayed_image.reset(); - this->ui->label->setText("no image"); - this->ui->label->setAlignment(Qt::AlignCenter); - this->set_solid(Qt::black); this->resize(800, 600); + this->ui->label->move(0, 0); this->ui->label->resize(this->size()); this->window_state->reset_border_size(); + this->set_background_sizes(); + this->resize_to_max(); } void MainWindow::resize_to_max(){ @@ -294,7 +294,7 @@ void MainWindow::move_in_direction(bool forward){ this->open_path_and_display_image(**this->directory_iterator); } -void MainWindow::open_path_and_display_image(QString path){ +bool MainWindow::open_path_and_display_image(QString path){ std::shared_ptr li; size_t i = 0; auto &label = this->ui->label; @@ -313,26 +313,27 @@ void MainWindow::open_path_and_display_image(QString path){ }else break; } - if (li->is_null()){ - this->show_nothing(); - return; - } - this->color_calculated = false; - label->move(0, 0); QString current_directory, current_filename; split_path(current_directory, current_filename, path); this->window_state->set_current_directory(current_directory.toStdWString()); this->window_state->set_current_filename(current_filename.toStdWString()); - this->setWindowTitle(current_filename); if (!this->directory_iterator) this->directory_iterator = this->app->request_directory(current_directory); + if (li->is_null()){ + this->show_nothing(); + return false; + } + this->color_calculated = false; + label->move(0, 0); + this->setWindowTitle(current_filename); this->displayed_image = li; label->reset_transform(); this->set_zoom(); this->apply_zoom(true, 1); + return true; } void MainWindow::display_filtered_image(const std::shared_ptr &graphics){ diff --git a/src/MainWindow.h b/src/MainWindow.h index c1bce0d..7e33cda 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -120,7 +120,7 @@ class MainWindow : public QMainWindow{ explicit MainWindow(ImageViewerApplication &app, const QStringList &arguments, QWidget *parent = 0); explicit MainWindow(ImageViewerApplication &app, const std::shared_ptr &state, QWidget *parent = 0); ~MainWindow(); - void open_path_and_display_image(QString path); + bool open_path_and_display_image(QString path); void display_image_in_label(const std::shared_ptr &graphics, bool first_display); void display_filtered_image(const std::shared_ptr &); std::shared_ptr save_state() const; @@ -144,6 +144,9 @@ class MainWindow : public QMainWindow{ } void process_user_script(const QString &path); QImage get_image() const; + ImageViewerApplication &get_app(){ + return *this->app; + } public slots: void label_transform_updated(); diff --git a/src/MainWindowSettings.cpp b/src/MainWindowSettings.cpp index c69c87d..d5dc71c 100644 --- a/src/MainWindowSettings.cpp +++ b/src/MainWindowSettings.cpp @@ -17,12 +17,14 @@ void MainWindow::restore_state(const std::shared_ptr &state){ path += QString::fromStdWString(this->window_state->get_current_filename()); auto temp_zoom_mode = this->window_state->get_zoom_mode(); this->window_state->set_zoom_mode(ZoomMode::Locked); - this->open_path_and_display_image(path); - this->ui->label->load_state(*state); + bool success = this->open_path_and_display_image(path); + this->ui->label->load_state(*this->window_state); this->window_state->set_zoom_mode(temp_zoom_mode); this->ui->label->move(this->window_state->get_label_pos().to_QPoint()); this->move(this->window_state->get_pos().to_QPoint()); + if (!success) + return; this->resize(this->window_state->get_size().to_QSize()); this->fix_positions_and_zoom(); } diff --git a/src/MainWindowShortcuts.cpp b/src/MainWindowShortcuts.cpp index 41e3f2d..a0ace2d 100644 --- a/src/MainWindowShortcuts.cpp +++ b/src/MainWindowShortcuts.cpp @@ -96,10 +96,14 @@ void MainWindow::close_slot(){ } void MainWindow::zoom_in_slot(){ + if (!this->displayed_image) + return; this->change_zoom(true); } void MainWindow::zoom_out_slot(){ + if (!this->displayed_image) + return; this->change_zoom(false); } @@ -144,6 +148,8 @@ void MainWindow::offset_image(const QPoint &offset){ } void MainWindow::reset_zoom_slot(){ + if (!this->displayed_image) + return; int zoom = this->get_current_zoom(); this->set_current_zoom_mode(ZoomMode::Normal); this->ui->label->reset_transform(); @@ -167,6 +173,8 @@ void cycle_zoom_mode(ZoomMode &mode){ } void MainWindow::cycle_zoom_mode_slot(){ + if (!this->displayed_image) + return; auto mode = this->get_current_zoom_mode(); cycle_zoom_mode(mode); this->set_current_zoom_mode(mode); @@ -181,6 +189,8 @@ void toggle_lock_zoom(ZoomMode &mode){ } void MainWindow::toggle_lock_zoom_slot(){ + if (!this->displayed_image) + return; auto mode = this->window_state->get_zoom_mode(); toggle_lock_zoom(mode); this->window_state->set_zoom_mode(mode); @@ -214,13 +224,16 @@ void MainWindow::toggle_fullscreen(){ auto zoom = this->get_current_zoom(); this->window_state->set_fullscreen(!this->window_state->get_fullscreen()); if (!this->window_state->get_fullscreen()){ - this->apply_zoom(false, zoom); + if (this->displayed_image) + this->apply_zoom(false, zoom); this->setGeometry(this->window_rect); this->restore_image_pos(); }else{ this->save_image_pos(true); - this->set_zoom(); - this->apply_zoom(false, zoom); + if (this->displayed_image){ + this->set_zoom(); + this->apply_zoom(false, zoom); + } this->resolution_to_window_size(); this->reposition_image(); //this->move_image(QPoint(0, 0)); diff --git a/src/OptionsDialog.cpp b/src/OptionsDialog.cpp index 382c8e2..04b36c2 100644 --- a/src/OptionsDialog.cpp +++ b/src/OptionsDialog.cpp @@ -9,6 +9,7 @@ Distributed under a permissive license. See COPYING.txt for details. #include "ImageViewerApplication.h" #include #include +#include ShortcutListModel::ShortcutListModel(const ApplicationShortcuts &shortcuts): items(shortcuts.get_current_shortcuts()){ this->sort(); @@ -180,6 +181,8 @@ OptionsDialog::OptionsDialog(ImageViewerApplication &app): this->setup_shortcuts_list_view(); this->setup_general_options(); this->setup_signals(); + auto geom = app.desktop()->availableGeometry(app.desktop()->screenNumber(this)); + this->resize(geom.size() / 2); } void OptionsDialog::setup_command_input(){ @@ -209,6 +212,7 @@ void OptionsDialog::setup_general_options(){ this->ui->center_when_displayed_cb->setChecked(this->options->get_center_when_displayed()); this->ui->use_checkerboard_pattern_cb->setChecked(this->options->get_use_checkerboard_pattern()); this->ui->clamp_to_edges_cb->setChecked(this->options->get_clamp_to_edges()); + this->ui->save_state_on_exit_cb->setChecked(this->options->get_save_state_on_exit()); this->ui->keep_application_running_cb->setChecked(this->options->get_keep_application_in_background()); this->ui->clamp_strength_spinbox->setValue(this->options->get_clamp_strength()); this->ui->zoom_mode_for_new_windows_cb->set_selected_item(this->options->get_zoom_mode_for_new_windows()); @@ -284,6 +288,7 @@ std::shared_ptr OptionsDialog::build_options(){ ret->set_center_when_displayed(this->ui->center_when_displayed_cb->isChecked()); ret->set_use_checkerboard_pattern(this->ui->use_checkerboard_pattern_cb->isChecked()); ret->set_clamp_to_edges(this->ui->clamp_to_edges_cb->isChecked()); + ret->set_save_state_on_exit(this->ui->save_state_on_exit_cb->isChecked()); ret->set_keep_application_in_background(this->ui->keep_application_running_cb->isChecked()); ret->set_clamp_strength(this->ui->clamp_strength_spinbox->value()); ret->set_zoom_mode_for_new_windows(this->ui->zoom_mode_for_new_windows_cb->get_selected_item()); diff --git a/src/OptionsDialog.ui b/src/OptionsDialog.ui index 19b08e4..0413c00 100644 --- a/src/OptionsDialog.ui +++ b/src/OptionsDialog.ui @@ -13,25 +13,16 @@ 494 + + + 0 + 0 + + Options - - 5 - - - 5 - - - 5 - - - 5 - - - 5 - @@ -205,6 +196,13 @@ Misc + + + + Save application state on exit + + + @@ -277,19 +275,38 @@ + + + 0 + 0 + + false - + + + + 0 + 0 + + + false + + + 0 + 0 + + Add @@ -307,6 +324,12 @@ false + + + 0 + 0 + + Remove @@ -322,14 +345,14 @@ - + 0 0 - 120 + 0 0 diff --git a/src/RotateDialog.cpp b/src/RotateDialog.cpp index 24874cd..9c2ac40 100644 --- a/src/RotateDialog.cpp +++ b/src/RotateDialog.cpp @@ -8,6 +8,7 @@ Distributed under a permissive license. See COPYING.txt for details. #include "RotateDialog.h" #include "Misc.h" #include +#include const double log_125 = log(1.25); @@ -26,6 +27,25 @@ RotateDialog::RotateDialog(MainWindow &parent) : this->last_scale = this->original_scale = this->scale = this->main_window.get_image_zoom(); this->rotation_slider_changed(0); this->set_scale(); + this->geometry_set = false; + auto desktop = this->main_window.get_app().desktop(); + auto h = 22 * desktop->logicalDpiY() / 96; + this->ui->rotation_slider->setMinimumHeight(h); + this->ui->scale_slider->setMinimumHeight(h); +} + +void RotateDialog::resizeEvent(QResizeEvent *e){ + if (this->geometry_set){ + QDialog::resizeEvent(e); + return; + } + this->geometry_set = true; + auto size = this->size(); + size.setWidth(size.height() * 400 / 143); + this->setMinimumWidth(size.width()); + this->setMinimumHeight(size.height()); + this->setMaximumHeight(size.height()); + this->updateGeometry(); } void RotateDialog::do_transform(bool set_zoom){ diff --git a/src/RotateDialog.h b/src/RotateDialog.h index 1df1740..37983cf 100644 --- a/src/RotateDialog.h +++ b/src/RotateDialog.h @@ -24,10 +24,12 @@ class RotateDialog : public QDialog{ last_scale, scale; bool in_do_transform; + bool geometry_set; void do_transform(bool = false); void set_scale(); void set_scale_label(); + void resizeEvent(QResizeEvent *) override; public: RotateDialog(MainWindow &parent); bool accepted() const{ diff --git a/src/RotateDialog.ui b/src/RotateDialog.ui index ac5317d..9e1fded 100644 --- a/src/RotateDialog.ui +++ b/src/RotateDialog.ui @@ -14,7 +14,7 @@ - + 0 0 @@ -22,13 +22,13 @@ 400 - 143 + 0 16777215 - 143 + 16777215 @@ -101,7 +101,7 @@ - + 0 0 @@ -109,13 +109,13 @@ 0 - 23 + 0 16777215 - 23 + 16777215 diff --git a/src/serialization/MainSettings.cpp b/src/serialization/MainSettings.cpp index 4e710fe..0647ff0 100644 --- a/src/serialization/MainSettings.cpp +++ b/src/serialization/MainSettings.cpp @@ -16,6 +16,7 @@ MainSettings::MainSettings(){ this->keep_application_in_background = true; this->set_zoom_mode_for_new_windows(ZoomMode::Normal); this->set_fullscreen_zoom_mode_for_new_windows(ZoomMode::AutoFit); + this->set_save_state_on_exit(true); } bool MainSettings::operator==(const MainSettings &other) const{ @@ -27,5 +28,6 @@ bool MainSettings::operator==(const MainSettings &other) const{ CHECK_EQUALITY(zoom_mode_for_new_windows); CHECK_EQUALITY(fullscreen_zoom_mode_for_new_windows); CHECK_EQUALITY(keep_application_in_background); + CHECK_EQUALITY(save_state_on_exit); return true; } diff --git a/src/serialization/MainSettings.h b/src/serialization/MainSettings.h index d0a9ad4..de7ada4 100644 --- a/src/serialization/MainSettings.h +++ b/src/serialization/MainSettings.h @@ -7,6 +7,7 @@ DEFINE_INLINE_SETTER_GETTER(center_when_displayed) DEFINE_ENUM_INLINE_SETTER_GETTER(ZoomMode, zoom_mode_for_new_windows) DEFINE_ENUM_INLINE_SETTER_GETTER(ZoomMode, fullscreen_zoom_mode_for_new_windows) DEFINE_INLINE_SETTER_GETTER(keep_application_in_background) +DEFINE_INLINE_SETTER_GETTER(save_state_on_exit) bool operator==(const MainSettings &other) const; bool operator!=(const MainSettings &other) const{ return !(*this == other); diff --git a/src/serialization/settings.txt b/src/serialization/settings.txt index e9a8036..3b2dc0b 100644 --- a/src/serialization/settings.txt +++ b/src/serialization/settings.txt @@ -41,6 +41,7 @@ cpp settings{ uint32_t zoom_mode_for_new_windows; uint32_t fullscreen_zoom_mode_for_new_windows; bool keep_application_in_background; + bool save_state_on_exit; #include "MainSettings.h" } class ApplicationState{