+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();
+ }
+ else
+ {
+ canvas->view_orthographic();
+ }
+}
+
+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();
+ }
+}
+
+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::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)