+void Window::set_watched(const QString& filename)
+{
+ const auto files = watcher->files();
+ if (files.size())
+ {
+ watcher->removePaths(watcher->files());
+ }
+ watcher->addPath(filename);
+
+ QSettings settings;
+ auto recent = settings.value(RECENT_FILE_KEY).toStringList();
+ const auto f = QFileInfo(filename).absoluteFilePath();
+ recent.removeAll(f);
+ recent.prepend(f);
+ while (recent.size() > MAX_RECENT_FILES)
+ {
+ recent.pop_back();
+ }
+ settings.setValue(RECENT_FILE_KEY, recent);
+ rebuild_recent_files();
+}
+
+void Window::on_projection(QAction* proj)
+{
+ if (proj == perspective_action)
+ {
+ canvas->view_perspective(Canvas::P_PERSPECTIVE, true);
+ QSettings().setValue(PROJECTION_KEY, "perspective");
+ }
+ else
+ {
+ canvas->view_perspective(Canvas::P_ORTHOGRAPHIC, true);
+ QSettings().setValue(PROJECTION_KEY, "orthographic");
+ }
+}
+
+void Window::on_drawMode(QAction* act)
+{
+ DrawMode mode;
+ if (act == shaded_action)
+ {
+ mode = shaded;
+ }
+ else if (act == wireframe_action)
+ {
+ mode = wireframe;
+ }
+ else
+ {
+ mode = surfaceangle;
+ }
+ canvas->set_drawMode(mode);
+ QSettings().setValue(DRAW_MODE_KEY, mode);
+}
+
+void Window::on_drawAxes(bool d)
+{
+ canvas->draw_axes(d);
+ QSettings().setValue(DRAW_AXES_KEY, d);
+}
+
+void Window::on_invertZoom(bool d)
+{
+ canvas->invert_zoom(d);
+ QSettings().setValue(INVERT_ZOOM_KEY, d);
+}
+
+void Window::on_watched_change(const QString& filename)
+{
+ if (autoreload_action->isChecked())
+ {
+ load_stl(filename, true);
+ }
+}
+
+void Window::on_autoreload_triggered(bool b)
+{
+ if (b)
+ {
+ on_reload();
+ }
+ QSettings().setValue(AUTORELOAD_KEY, b);
+}
+
+void Window::on_clear_recent()
+{
+ QSettings settings;
+ settings.setValue(RECENT_FILE_KEY, QStringList());
+ rebuild_recent_files();
+}
+
+void Window::on_load_recent(QAction* a)
+{
+ load_stl(a->data().toString());
+}
+
+void Window::on_loaded(const QString& filename)
+{
+ current_file = filename;
+}
+
+void Window::on_save_screenshot()
+{
+ const auto image = canvas->grabFramebuffer();
+ auto file_name = QFileDialog::getSaveFileName(
+ this,
+ tr("Save Screenshot Image"),
+ QStandardPaths::standardLocations(QStandardPaths::StandardLocation::PicturesLocation).first(),
+ "Images (*.png *.jpg)");
+
+ auto get_file_extension = [](const std::string& file_name) -> std::string
+ {
+ const auto location = std::find(file_name.rbegin(), file_name.rend(), '.');
+ if (location == file_name.rend())
+ {
+ return "";
+ }
+
+ const auto index = std::distance(file_name.rbegin(), location);
+ return file_name.substr(file_name.size() - index);
+ };
+
+ const auto extension = get_file_extension(file_name.toStdString());
+ if(extension.empty() || (extension != "png" && extension != "jpg"))
+ {
+ file_name.append(".png");
+ }
+
+ const auto save_ok = image.save(file_name);
+ if(!save_ok)
+ {
+ QMessageBox::warning(this, tr("Error Saving Image"), tr("Unable to save screen shot image."));
+ }
+}
+
+void Window::on_hide_menuBar()
+{
+ menuBar()->setVisible(!hide_menuBar_action->isChecked());
+}
+
+void Window::rebuild_recent_files()
+{
+ QSettings settings;
+ QStringList files = settings.value(RECENT_FILE_KEY).toStringList();
+
+ const auto actions = recent_files_group->actions();
+ for (auto a : actions)
+ {
+ recent_files_group->removeAction(a);
+ }
+ recent_files->clear();
+
+ for (auto f : files)
+ {
+ const auto a = new QAction(f, recent_files);
+ a->setData(f);
+ recent_files_group->addAction(a);
+ recent_files->addAction(a);
+ }
+ if (files.size() == 0)
+ {
+ auto a = new QAction("No recent files", recent_files);
+ recent_files->addAction(a);
+ a->setEnabled(false);
+ }
+ recent_files->addSeparator();
+ recent_files->addAction(recent_files_clear_action);
+}
+
+void Window::on_reload()
+{
+ auto fs = watcher->files();
+ if (fs.size() == 1)
+ {
+ load_stl(fs[0], true);
+ }
+}
+
+bool Window::load_stl(const QString& filename, bool is_reload)