Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortamasmeszaros <meszaros.q@gmail.com>2019-12-16 11:47:31 +0300
committertamasmeszaros <meszaros.q@gmail.com>2019-12-16 13:07:43 +0300
commita9403319b7767e920d7d993e91bf0623c91c7b4b (patch)
tree42efc2962f4992a229a15bd76772973e9f34ed6a /src/slic3r/GUI/Job.hpp
parentf60ff1c7ce02a577003910902a27414612b8de14 (diff)
Separate Job, ProgressStatusBar and ProgressIndicator
* Separate GUI::Job * make use of ProgressIndicator interface * make ProgressStatusbar independent from GUI::App
Diffstat (limited to 'src/slic3r/GUI/Job.hpp')
-rw-r--r--src/slic3r/GUI/Job.hpp154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/slic3r/GUI/Job.hpp b/src/slic3r/GUI/Job.hpp
new file mode 100644
index 000000000..9accd0ef3
--- /dev/null
+++ b/src/slic3r/GUI/Job.hpp
@@ -0,0 +1,154 @@
+#ifndef JOB_HPP
+#define JOB_HPP
+
+#include <atomic>
+
+#include <slic3r/Utils/Thread.hpp>
+#include <slic3r/GUI/I18N.hpp>
+#include <slic3r/GUI/ProgressIndicator.hpp>
+
+#include <wx/event.h>
+
+#include <boost/thread.hpp>
+
+namespace Slic3r { namespace GUI {
+
+// A class to handle UI jobs like arranging and optimizing rotation.
+// These are not instant jobs, the user has to be informed about their
+// state in the status progress indicator. On the other hand they are
+// separated from the background slicing process. Ideally, these jobs should
+// run when the background process is not running.
+//
+// TODO: A mechanism would be useful for blocking the plater interactions:
+// objects would be frozen for the user. In case of arrange, an animation
+// could be shown, or with the optimize orientations, partial results
+// could be displayed.
+class Job : public wxEvtHandler
+{
+ int m_range = 100;
+ boost::thread m_thread;
+ std::atomic<bool> m_running{false}, m_canceled{false};
+ bool m_finalized = false;
+ std::shared_ptr<ProgressIndicator> m_progress;
+
+ void run()
+ {
+ m_running.store(true);
+ process();
+ m_running.store(false);
+
+ // ensure to call the last status to finalize the job
+ update_status(status_range(), "");
+ }
+
+protected:
+ // status range for a particular job
+ virtual int status_range() const { return 100; }
+
+ // status update, to be used from the work thread (process() method)
+ void update_status(int st, const wxString &msg = "")
+ {
+ auto evt = new wxThreadEvent();
+ evt->SetInt(st);
+ evt->SetString(msg);
+ wxQueueEvent(this, evt);
+ }
+
+ bool was_canceled() const { return m_canceled.load(); }
+
+ // Launched just before start(), a job can use it to prepare internals
+ virtual void prepare() {}
+
+ // Launched when the job is finished. It refreshes the 3Dscene by def.
+ virtual void finalize() { m_finalized = true; }
+
+ bool is_finalized() const { return m_finalized; }
+
+public:
+ Job(std::shared_ptr<ProgressIndicator> pri) : m_progress(pri)
+ {
+ Bind(wxEVT_THREAD, [this](const wxThreadEvent &evt) {
+ auto msg = evt.GetString();
+ if (!msg.empty())
+ m_progress->set_status_text(msg.ToUTF8().data());
+
+ if (m_finalized) return;
+
+ m_progress->set_progress(evt.GetInt());
+ if (evt.GetInt() == status_range()) {
+ // set back the original range and cancel callback
+ m_progress->set_range(m_range);
+ m_progress->set_cancel_callback();
+ wxEndBusyCursor();
+
+ finalize();
+
+ // dont do finalization again for the same process
+ m_finalized = true;
+ }
+ });
+ }
+
+ Job(const Job &) = delete;
+ Job(Job &&) = delete;
+ Job &operator=(const Job &) = delete;
+ Job &operator=(Job &&) = delete;
+
+ virtual void process() = 0;
+
+ void start()
+ { // Start the job. No effect if the job is already running
+ if (!m_running.load()) {
+ prepare();
+
+ // Save the current status indicatior range and push the new one
+ m_range = m_progress->get_range();
+ m_progress->set_range(status_range());
+
+ // init cancellation flag and set the cancel callback
+ m_canceled.store(false);
+ m_progress->set_cancel_callback(
+ [this]() { m_canceled.store(true); });
+
+ m_finalized = false;
+
+ // Changing cursor to busy
+ wxBeginBusyCursor();
+
+ try { // Execute the job
+ m_thread = create_thread([this] { this->run(); });
+ } catch (std::exception &) {
+ update_status(status_range(),
+ _(L("ERROR: not enough resources to "
+ "execute a new job.")));
+ }
+
+ // The state changes will be undone when the process hits the
+ // last status value, in the status update handler (see ctor)
+ }
+ }
+
+ // To wait for the running job and join the threads. False is
+ // returned if the timeout has been reached and the job is still
+ // running. Call cancel() before this fn if you want to explicitly
+ // end the job.
+ bool join(int timeout_ms = 0)
+ {
+ if (!m_thread.joinable()) return true;
+
+ if (timeout_ms <= 0)
+ m_thread.join();
+ else if (!m_thread.try_join_for(boost::chrono::milliseconds(timeout_ms)))
+ return false;
+
+ return true;
+ }
+
+ bool is_running() const { return m_running.load(); }
+ void cancel() { m_canceled.store(true); }
+};
+
+}
+}
+
+#endif // JOB_HPP