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
parentf60ff1c7ce02a577003910902a27414612b8de14 (diff)
Separate Job, ProgressStatusBar and ProgressIndicator
* Separate GUI::Job * make use of ProgressIndicator interface * make ProgressStatusbar independent from GUI::App
-rw-r--r--src/slic3r/CMakeLists.txt1
-rw-r--r--src/slic3r/GUI/Job.hpp154
-rw-r--r--src/slic3r/GUI/MainFrame.cpp3
-rw-r--r--src/slic3r/GUI/MainFrame.hpp2
-rw-r--r--src/slic3r/GUI/Plater.cpp143
-rw-r--r--src/slic3r/GUI/ProgressIndicator.hpp63
-rw-r--r--src/slic3r/GUI/ProgressStatusBar.cpp12
-rw-r--r--src/slic3r/GUI/ProgressStatusBar.hpp20
8 files changed, 206 insertions, 192 deletions
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index eec2b6a01..5ce464eb1 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -140,6 +140,7 @@ set(SLIC3R_GUI_SOURCES
GUI/ProgressStatusBar.cpp
GUI/PrintHostDialogs.cpp
GUI/PrintHostDialogs.hpp
+ GUI/Job.hpp
GUI/Mouse3DController.cpp
GUI/Mouse3DController.hpp
Utils/Http.cpp
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
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index e613e6915..9e70fbaa2 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -58,7 +58,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
#endif // _WIN32
// initialize status bar
- m_statusbar.reset(new ProgressStatusBar(this));
+ m_statusbar = std::make_shared<ProgressStatusBar>(this);
+ m_statusbar->set_font(GUI::wxGetApp().normal_font());
m_statusbar->embed(this);
m_statusbar->set_status_text(_(L("Version")) + " " +
SLIC3R_VERSION +
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index 28bd0242b..1a7568092 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -135,7 +135,7 @@ public:
Plater* m_plater { nullptr };
wxNotebook* m_tabpanel { nullptr };
wxProgressDialog* m_progress_dialog { nullptr };
- std::unique_ptr<ProgressStatusBar> m_statusbar;
+ std::shared_ptr<ProgressStatusBar> m_statusbar;
};
} // GUI
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index df705f25f..43d2f06a5 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -69,6 +69,7 @@
#include "Camera.hpp"
#include "Mouse3DController.hpp"
#include "Tab.hpp"
+#include "Job.hpp"
#include "PresetBundle.hpp"
#include "BackgroundSlicingProcess.hpp"
#include "ProgressStatusBar.hpp"
@@ -1457,136 +1458,30 @@ struct Plater::priv
// 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
+ class PlaterJob: public Job
{
- int m_range = 100;
- boost::thread m_thread;
- priv * m_plater = nullptr;
- std::atomic<bool> m_running{false}, m_canceled{false};
- bool m_finalized = false;
-
- 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(), "");
- }
-
+ priv *m_plater;
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);
- }
priv & plater() { return *m_plater; }
const priv &plater() const { return *m_plater; }
- 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()
+ void finalize() override
{
// Do a full refresh of scene tree, including regenerating
// all the GLVolumes. FIXME The update function shall just
// reload the modified matrices.
- if (!was_canceled())
+ if (!Job::was_canceled())
plater().update(unsigned(UpdateParams::FORCE_FULL_SCREEN_REFRESH));
- }
-
- public:
- Job(priv *_plater) : m_plater(_plater)
- {
- Bind(wxEVT_THREAD, [this](const wxThreadEvent &evt) {
- auto msg = evt.GetString();
- if (!msg.empty())
- plater().statusbar()->set_status_text(msg);
-
- if (m_finalized) return;
-
- plater().statusbar()->set_progress(evt.GetInt());
- if (evt.GetInt() == status_range()) {
- // set back the original range and cancel callback
- plater().statusbar()->set_range(m_range);
- plater().statusbar()->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 = plater().statusbar()->get_range();
- plater().statusbar()->set_range(status_range());
-
- // init cancellation flag and set the cancel callback
- m_canceled.store(false);
- plater().statusbar()->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;
+ Job::finalize();
}
- bool is_running() const { return m_running.load(); }
- void cancel() { m_canceled.store(true); }
+ public:
+ PlaterJob(priv *_plater)
+ : Job(_plater->statusbar()), m_plater(_plater)
+ {}
};
enum class Jobs : size_t {
@@ -1595,7 +1490,7 @@ struct Plater::priv
Hollow
};
- class ArrangeJob : public Job
+ class ArrangeJob : public PlaterJob
{
using ArrangePolygon = arrangement::ArrangePolygon;
using ArrangePolygons = arrangement::ArrangePolygons;
@@ -1712,7 +1607,7 @@ struct Plater::priv
}
public:
- using Job::Job;
+ using PlaterJob::PlaterJob;
int status_range() const override { return int(m_selected.size()); }
@@ -1729,17 +1624,17 @@ struct Plater::priv
}
};
- class RotoptimizeJob : public Job
+ class RotoptimizeJob : public PlaterJob
{
public:
- using Job::Job;
+ using PlaterJob::PlaterJob;
void process() override;
};
- class HollowJob : public Job
+ class HollowJob : public PlaterJob
{
public:
- using Job::Job;
+ using PlaterJob::PlaterJob;
void prepare() override;
void process() override;
void finalize() override;
@@ -1847,7 +1742,7 @@ struct Plater::priv
void reset_all_gizmos();
void update_ui_from_settings();
- ProgressStatusBar* statusbar();
+ std::shared_ptr<ProgressStatusBar> statusbar();
std::string get_config(const std::string &key) const;
BoundingBoxf bed_shape_bb() const;
BoundingBox scaled_bed_shape_bb() const;
@@ -2266,9 +2161,9 @@ void Plater::priv::update_ui_from_settings()
preview->get_canvas3d()->update_ui_from_settings();
}
-ProgressStatusBar* Plater::priv::statusbar()
+std::shared_ptr<ProgressStatusBar> Plater::priv::statusbar()
{
- return main_frame->m_statusbar.get();
+ return main_frame->m_statusbar;
}
std::string Plater::priv::get_config(const std::string &key) const
diff --git a/src/slic3r/GUI/ProgressIndicator.hpp b/src/slic3r/GUI/ProgressIndicator.hpp
index 280ba63ac..674a81ba2 100644
--- a/src/slic3r/GUI/ProgressIndicator.hpp
+++ b/src/slic3r/GUI/ProgressIndicator.hpp
@@ -11,58 +11,17 @@ namespace Slic3r {
*/
class ProgressIndicator {
public:
- using CancelFn = std::function<void(void)>; // Cancel function signature.
-
-private:
- float m_state = .0f, m_max = 1.f, m_step;
- CancelFn m_cancelfunc = [](){};
-
-public:
-
- inline virtual ~ProgressIndicator() {}
-
- /// Get the maximum of the progress range.
- float max() const { return m_max; }
-
- /// Get the current progress state
- float state() const { return m_state; }
-
- /// Set the maximum of the progress range
- virtual void max(float maxval) { m_max = maxval; }
-
- /// Set the current state of the progress.
- virtual void state(float val) { m_state = val; }
-
- /**
- * @brief Number of states int the progress. Can be used instead of giving a
- * maximum value.
- */
- virtual void states(unsigned statenum) {
- m_step = m_max / statenum;
- }
-
- /// Message shown on the next status update.
- virtual void message(const std::string&) = 0;
-
- /// Title of the operation.
- virtual void title(const std::string&) = 0;
-
- /// Formatted message for the next status update. Works just like sprintf.
- virtual void message_fmt(const std::string& fmt, ...);
-
- /// Set up a cancel callback for the operation if feasible.
- virtual void on_cancel(CancelFn func = CancelFn()) { m_cancelfunc = func; }
-
- /**
- * Explicitly shut down the progress indicator and call the associated
- * callback.
- */
- virtual void cancel() { m_cancelfunc(); }
-
- /// Convenience function to call message and status update in one function.
- void update(float st, const std::string& msg) {
- message(msg); state(st);
- }
+
+ /// Cancel callback function type
+ using CancelFn = std::function<void()>;
+
+ virtual ~ProgressIndicator() = default;
+
+ virtual void set_range(int range) = 0;
+ virtual void set_cancel_callback(CancelFn = CancelFn()) = 0;
+ virtual void set_progress(int pr) = 0;
+ virtual void set_status_text(const char *) = 0; // utf8 char array
+ virtual int get_range() const = 0;
};
}
diff --git a/src/slic3r/GUI/ProgressStatusBar.cpp b/src/slic3r/GUI/ProgressStatusBar.cpp
index 33e4855cd..1ec2b8193 100644
--- a/src/slic3r/GUI/ProgressStatusBar.cpp
+++ b/src/slic3r/GUI/ProgressStatusBar.cpp
@@ -15,8 +15,7 @@
namespace Slic3r {
ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id)
- : self{new wxStatusBar(parent ? parent : GUI::wxGetApp().mainframe,
- id == -1 ? wxID_ANY : id)}
+ : self{new wxStatusBar(parent, id == -1 ? wxID_ANY : id)}
, m_prog{new wxGauge(self,
wxGA_HORIZONTAL,
100,
@@ -32,7 +31,6 @@ ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id)
m_prog->Hide();
m_cancelbutton->Hide();
- self->SetFont(GUI::wxGetApp().normal_font());
self->SetFieldsCount(3);
int w[] = {-1, 150, 155};
self->SetStatusWidths(3, w);
@@ -149,8 +147,7 @@ void ProgressStatusBar::run(int rate)
void ProgressStatusBar::embed(wxFrame *frame)
{
- wxFrame* mf = frame ? frame : GUI::wxGetApp().mainframe;
- if(mf) mf->SetStatusBar(self);
+ if(frame) frame->SetStatusBar(self);
}
void ProgressStatusBar::set_status_text(const wxString& txt)
@@ -173,6 +170,11 @@ wxString ProgressStatusBar::get_status_text() const
return self->GetStatusText();
}
+void ProgressStatusBar::set_font(const wxFont &font)
+{
+ self->SetFont(font);
+}
+
void ProgressStatusBar::show_cancel_button()
{
if(m_cancelbutton) m_cancelbutton->Show();
diff --git a/src/slic3r/GUI/ProgressStatusBar.hpp b/src/slic3r/GUI/ProgressStatusBar.hpp
index 1aab67d5a..faeb7a34e 100644
--- a/src/slic3r/GUI/ProgressStatusBar.hpp
+++ b/src/slic3r/GUI/ProgressStatusBar.hpp
@@ -6,6 +6,8 @@
#include <functional>
#include <string>
+#include "ProgressIndicator.hpp"
+
class wxTimer;
class wxGauge;
class wxButton;
@@ -14,6 +16,7 @@ class wxStatusBar;
class wxWindow;
class wxFrame;
class wxString;
+class wxFont;
namespace Slic3r {
@@ -22,7 +25,7 @@ namespace Slic3r {
* of the Slicer main window. It consists of a message area to the left and a
* progress indication area to the right with an optional cancel button.
*/
-class ProgressStatusBar
+class ProgressStatusBar : public ProgressIndicator
{
wxStatusBar *self; // we cheat! It should be the base class but: perl!
wxGauge *m_prog;
@@ -30,30 +33,29 @@ class ProgressStatusBar
std::unique_ptr<wxTimer> m_timer;
public:
- /// Cancel callback function type
- using CancelFn = std::function<void()>;
ProgressStatusBar(wxWindow *parent = nullptr, int id = -1);
- ~ProgressStatusBar();
+ ~ProgressStatusBar() override;
int get_progress() const;
// if the argument is less than 0 it shows the last state or
// pulses if no state was set before.
- void set_progress(int);
- int get_range() const;
- void set_range(int = 100);
+ void set_progress(int) override;
+ int get_range() const override;
+ void set_range(int = 100) override;
void show_progress(bool);
void start_busy(int = 100);
void stop_busy();
inline bool is_busy() const { return m_busy; }
- void set_cancel_callback(CancelFn = CancelFn());
+ void set_cancel_callback(CancelFn = CancelFn()) override;
inline void reset_cancel_callback() { set_cancel_callback(); }
void run(int rate);
void embed(wxFrame *frame = nullptr);
void set_status_text(const wxString& txt);
void set_status_text(const std::string& txt);
- void set_status_text(const char *txt);
+ void set_status_text(const char *txt) override;
wxString get_status_text() const;
+ void set_font(const wxFont &font);
// Temporary methods to satisfy Perl side
void show_cancel_button();