diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index f87edc6074..28afc91c22 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -66,7 +66,7 @@ sub new { $self->SetStatusBar($self->{statusbar}); # Make the global status bar and its progress indicator available in C++ - $appController->set_global_progress_indicator_id( + $appController->set_global_progress_indicator( $self->{statusbar}->{prog}->GetId(), $self->{statusbar}->GetId(), ); diff --git a/xs/src/slic3r/AppController.hpp b/xs/src/slic3r/AppController.hpp index 6cec1b706d..7839113872 100644 --- a/xs/src/slic3r/AppController.hpp +++ b/xs/src/slic3r/AppController.hpp @@ -15,13 +15,27 @@ class Model; class Print; class PrintObject; +/** + * @brief A boilerplate class for creating application logic. It should provide + * features as issue reporting, gauge and progress indication, etc... + * + * The lower lever UI independent classes should be manipulated with a subclass + * of this controller class. We can also catch any exceptions that lower level + * methods could throw and display appropriate errors and warnings. + * + * Note that even the inner interface of this class free from any UI toolkit. + * We can implement it with any UI framework or make it a cli client. + */ class AppControllerBoilerplate { - class PriMap; - + class PriMap; // Some structure to store progress indication data public: + + /// A Progress indicator object smart pointer using ProgresIndicatorPtr = std::shared_ptr; private: + + // Pimpl data for thread safe progress indication features std::unique_ptr progressind_; public: @@ -32,6 +46,7 @@ public: using Path = std::string; using PathList = std::vector; + /// Common runtime issue types enum class IssueType { INFO, WARN, @@ -39,43 +54,102 @@ public: FATAL }; + /** + * @brief Query some paths from the user. + * + * It should display a file chooser dialog in case of a UI application. + * @param title Title of a possible query dialog. + * @param extensions Recognized file extensions. + * @return Returns a list of paths choosed by the user. + */ PathList query_destination_paths( const std::string& title, const std::string& extensions) const; + /** + * @brief Same as query_destination_paths but works for directories only. + */ PathList query_destination_dirs( const std::string& title) const; + /** + * @brief Same as query_destination_path but returns only one path. + */ Path query_destination_path( const std::string& title, const std::string& extensions, const std::string& hint = "") const; + /** + * @brief Report an issue to the user be it fatal or recoverable. + * + * In a UI app this should display some message dialog. + * + * @param issuetype The type of the runtime issue. + * @param description A somewhat longer description of the issue. + * @param brief A very brief description. Can be used for message dialog + * title. + */ void report_issue(IssueType issuetype, const std::string& description, const std::string& brief = ""); + /** + * @brief Set up a progress indicator for the current thread. + * @param progrind An already created progress indicator object. + */ void progress_indicator(ProgresIndicatorPtr progrind); + /** + * @brief Create and set up a new progress indicator for the current thread. + * @param statenum The number of states for the given procedure. + * @param title The title of the procedure. + * @param firstmsg The message for the first subtask to be displayed. + */ void progress_indicator(unsigned statenum, const std::string& title, const std::string& firstmsg = ""); + /** + * @brief Return the progress indicator set up for the current thread. This + * can be empty as well. + * @return A progress indicator object implementing IProgressIndicator. If + * a global progress indicator is available for the current implementation + * than this will be set up for the current thread and returned. + */ ProgresIndicatorPtr progress_indicator(); + /** + * @brief A predicate telling the caller whether it is the thread that + * created the AppConroller object itself. This probably means that the + * execution is in the UI thread. Otherwise it returns false meaning that + * some worker thread called this function. + * @return Return true if for the same caller thread that created this + * object and false for every other. + */ bool is_main_thread() const; protected: + /** + * @brief Create a new progress indicator and retirn a smart pointer to it. + * @param statenum The number of states for the given procedure. + * @param title The title of the procedure. + * @param firstmsg The message for the first subtask to be displayed. + * @return Smart pointer to the created object. + */ ProgresIndicatorPtr create_progress_indicator( unsigned statenum, const std::string& title, const std::string& firstmsg = "") const; - + // This is a global ProgresIndicatorPtr global_progressind_; }; +/** + * @brief Implementation of the printing logic. + */ class PrintController: public AppControllerBoilerplate { Print *print_ = nullptr; protected: @@ -102,35 +176,85 @@ protected: public: - using Ptr = std::unique_ptr; - + // Must be public for perl to use it explicit inline PrintController(Print *print): print_(print) {} + PrintController(const PrintController&) = delete; + PrintController(PrintController&&) = delete; + + using Ptr = std::unique_ptr; + inline static Ptr create(Print *print) { return PrintController::Ptr( new PrintController(print) ); } + /** + * @brief Slice one pront object. + * @param pobj The print object. + */ void slice(PrintObject *pobj); + /** + * @brief Slice the loaded print scene. + */ void slice(); + + /** + * @brief Slice the print into zipped png files. + */ void slice_to_png(); }; +/** + * @brief Top level controller. + */ class AppController: public AppControllerBoilerplate { Model *model_ = nullptr; PrintController::Ptr printctl; public: + /** + * @brief Get the print controller object. + * + * @return Return a raw pointer instead of a smart one for perl to be able + * to use this function and access the print controller. + */ PrintController * print_ctl() { return printctl.get(); } + /** + * @brief Set a model object. + * + * @param model A raw pointer to the model object. This can be used from + * perl. + */ void set_model(Model *model) { model_ = model; } + /** + * @brief Set the print object from perl. + * + * This will create a print controller that will then be accessible from + * perl. + * @param print A print object which can be a perl-ish extension as well. + */ void set_print(Print *print) { printctl = PrintController::create(print); printctl->progress_indicator(progress_indicator()); } - void set_global_progress_indicator_id(unsigned gauge_id, + /** + * @brief Set up a global progress indicator. + * + * In perl we have a progress indicating status bar on the bottom of the + * window which is defined and created in perl. We can pass the ID-s of the + * gauge and the statusbar id and make a wrapper implementation of the + * IProgressIndicator interface so we can use this GUI widget from C++. + * + * This function should be called from perl. + * + * @param gauge_id The ID of the gague widget of the status bar. + * @param statusbar_id The ID of the status bar. + */ + void set_global_progress_indicator(unsigned gauge_id, unsigned statusbar_id); }; diff --git a/xs/src/slic3r/AppControllerWx.cpp b/xs/src/slic3r/AppControllerWx.cpp index f968f08281..583506b9a5 100644 --- a/xs/src/slic3r/AppControllerWx.cpp +++ b/xs/src/slic3r/AppControllerWx.cpp @@ -133,7 +133,7 @@ public: if( val >= 1.0) state(static_cast(val)); } - virtual void state(unsigned st) override { + void state(unsigned st) { // send status update event if(is_asynch_) { auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_); @@ -225,7 +225,7 @@ public: if(val >= 1.0) state(unsigned(val)); } - virtual void state(unsigned st) override { + void state(unsigned st) { if(!ctl_.is_main_thread()) { auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_); evt->SetInt(st); @@ -249,7 +249,7 @@ public: }; } -void AppController::set_global_progress_indicator_id( +void AppController::set_global_progress_indicator( unsigned gid, unsigned sid) { diff --git a/xs/src/slic3r/IProgressIndicator.hpp b/xs/src/slic3r/IProgressIndicator.hpp index d71c506538..1c7c612363 100644 --- a/xs/src/slic3r/IProgressIndicator.hpp +++ b/xs/src/slic3r/IProgressIndicator.hpp @@ -6,40 +6,72 @@ namespace Slic3r { +/** + * @brief Generic progress indication interface. + */ class IProgressIndicator { public: - using CancelFn = std::function; + using CancelFn = std::function; // Cancel functio signature. private: float state_ = .0f, max_ = 1.f, step_; std::function cancelfunc_ = [](){}; unsigned proc_count_ = 1; + public: inline virtual ~IProgressIndicator() {} + /// Get the maximum of the progress range. float max() const { return max_; } + + /// Get the current progress state float state() const { return state_; } + /// Set the maximum of hte progress range virtual void max(float maxval) { max_ = maxval; } + + /// Set the current state of the progress. virtual void state(float val) { state_ = val; } - virtual void state(unsigned st) { state_ = st * step_; } + + /** + * @brief Number of states int the progress. Can be used insted of giving a + * maximum value. + */ virtual void states(unsigned statenum) { step_ = max_ / statenum; } + /// Message shown on the next status update. virtual void message(const std::string&) = 0; + + /// Title of the operaton. virtual void title(const std::string&) = 0; + /// Formatted message for the next status update. Works just like sprinf. virtual void message_fmt(const std::string& fmt, ...); + /// Set up a cancel callback for the operation if feasible. inline void on_cancel(CancelFn func) { cancelfunc_ = func; } + + /// Call a previously specified cancel callback. inline void on_cancel() { cancelfunc_(); } + /** + * \brief Set up how many subprocedures does the whole operation contain. + * + * This was neccesary from practical reasons. If the progress indicator is + * a dialog and we want to show the progress of a few sub operations than + * the dialog wont be closed and reopened each time a new sub operation is + * started. This is not a mandatory feature and can be ignored completely. + */ inline void procedure_count(unsigned pc) { proc_count_ = pc; } + + /// Get the current procedure count inline unsigned procedure_count() const { return proc_count_; } - template void update(T st, const std::string& msg) { + /// Convinience function to call message and status update in one function. + void update(float st, const std::string& msg) { message(msg); state(st); } }; diff --git a/xs/xsp/AppController.xsp b/xs/xsp/AppController.xsp index 0cb0b169ff..d8429fda11 100644 --- a/xs/xsp/AppController.xsp +++ b/xs/xsp/AppController.xsp @@ -22,5 +22,5 @@ PrintController *print_ctl(); void set_model(Model *model); void set_print(Print *print); - void set_global_progress_indicator_id(unsigned gauge_id, unsigned statusbar_id); + void set_global_progress_indicator(unsigned gauge_id, unsigned statusbar_id); }; \ No newline at end of file