Separate Job, ProgressStatusBar and ProgressIndicator

* Separate GUI::Job
* make use of ProgressIndicator interface
* make ProgressStatusbar independent from GUI::App
This commit is contained in:
tamasmeszaros 2019-12-16 09:47:31 +01:00
parent f60ff1c7ce
commit a9403319b7
8 changed files with 206 additions and 192 deletions

View file

@ -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));
Job::finalize();
}
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;
}
bool is_running() const { return m_running.load(); }
void cancel() { m_canceled.store(true); }
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