Merge remote-tracking branch 'origin/dev2' into dev_native

This commit is contained in:
bubnikv 2018-09-20 16:48:40 +02:00
commit 20d0f046d2
34 changed files with 1300 additions and 694 deletions

View file

@ -18,13 +18,10 @@
#include <Model.hpp>
#include <Utils.hpp>
#include <wx/stdstream.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
namespace Slic3r {
class AppControllerBoilerplate::PriData {
class AppControllerGui::PriData {
public:
std::mutex m;
std::thread::id ui_thread;
@ -32,16 +29,16 @@ public:
inline explicit PriData(std::thread::id uit): ui_thread(uit) {}
};
AppControllerBoilerplate::AppControllerBoilerplate()
:pri_data_(new PriData(std::this_thread::get_id())) {}
AppControllerGui::AppControllerGui()
:m_pri_data(new PriData(std::this_thread::get_id())) {}
AppControllerBoilerplate::~AppControllerBoilerplate() {
pri_data_.reset();
AppControllerGui::~AppControllerGui() {
m_pri_data.reset();
}
bool AppControllerBoilerplate::is_main_thread() const
bool AppControllerGui::is_main_thread() const
{
return pri_data_->ui_thread == std::this_thread::get_id();
return m_pri_data->ui_thread == std::this_thread::get_id();
}
namespace GUI {
@ -57,172 +54,32 @@ static const PrintStep STEP_SKIRT = psSkirt;
static const PrintStep STEP_BRIM = psBrim;
static const PrintStep STEP_WIPE_TOWER = psWipeTower;
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::global_progress_indicator() {
ProgresIndicatorPtr AppControllerGui::global_progress_indicator() {
ProgresIndicatorPtr ret;
pri_data_->m.lock();
ret = global_progressind_;
pri_data_->m.unlock();
m_pri_data->m.lock();
ret = m_global_progressind;
m_pri_data->m.unlock();
return ret;
}
void AppControllerBoilerplate::global_progress_indicator(
AppControllerBoilerplate::ProgresIndicatorPtr gpri)
void AppControllerGui::global_progress_indicator(ProgresIndicatorPtr gpri)
{
pri_data_->m.lock();
global_progressind_ = gpri;
pri_data_->m.unlock();
m_pri_data->m.lock();
m_global_progressind = gpri;
m_pri_data->m.unlock();
}
//void PrintController::make_skirt()
//{
// assert(print_ != nullptr);
// // prerequisites
// for(auto obj : print_->objects) make_perimeters(obj);
// for(auto obj : print_->objects) infill(obj);
// for(auto obj : print_->objects) gen_support_material(obj);
// if(!print_->state.is_done(STEP_SKIRT)) {
// print_->state.set_started(STEP_SKIRT);
// print_->skirt.clear();
// if(print_->has_skirt()) print_->_make_skirt();
// print_->state.set_done(STEP_SKIRT);
// }
//}
//void PrintController::make_brim()
//{
// assert(print_ != nullptr);
// // prerequisites
// for(auto obj : print_->objects) make_perimeters(obj);
// for(auto obj : print_->objects) infill(obj);
// for(auto obj : print_->objects) gen_support_material(obj);
// make_skirt();
// if(!print_->state.is_done(STEP_BRIM)) {
// print_->state.set_started(STEP_BRIM);
// // since this method must be idempotent, we clear brim paths *before*
// // checking whether we need to generate them
// print_->brim.clear();
// if(print_->config.brim_width > 0) print_->_make_brim();
// print_->state.set_done(STEP_BRIM);
// }
//}
//void PrintController::make_wipe_tower()
//{
// assert(print_ != nullptr);
// // prerequisites
// for(auto obj : print_->objects) make_perimeters(obj);
// for(auto obj : print_->objects) infill(obj);
// for(auto obj : print_->objects) gen_support_material(obj);
// make_skirt();
// make_brim();
// if(!print_->state.is_done(STEP_WIPE_TOWER)) {
// print_->state.set_started(STEP_WIPE_TOWER);
// // since this method must be idempotent, we clear brim paths *before*
// // checking whether we need to generate them
// print_->brim.clear();
// if(print_->has_wipe_tower()) print_->_make_wipe_tower();
// print_->state.set_done(STEP_WIPE_TOWER);
// }
//}
//void PrintController::slice(PrintObject *pobj)
//{
// assert(pobj != nullptr && print_ != nullptr);
// if(pobj->state.is_done(STEP_SLICE)) return;
// pobj->state.set_started(STEP_SLICE);
// pobj->_slice();
// auto msg = pobj->_fix_slicing_errors();
// if(!msg.empty()) report_issue(IssueType::WARN, msg);
// // simplify slices if required
// if (print_->config.resolution)
// pobj->_simplify_slices(scale_(print_->config.resolution));
// if(pobj->layers.empty())
// report_issue(IssueType::ERR,
// L("No layers were detected. You might want to repair your "
// "STL file(s) or check their size or thickness and retry")
// );
// pobj->state.set_done(STEP_SLICE);
//}
//void PrintController::make_perimeters(PrintObject *pobj)
//{
// assert(pobj != nullptr);
// slice(pobj);
// if (!pobj->state.is_done(STEP_PERIMETERS)) {
// pobj->_make_perimeters();
// }
//}
//void PrintController::infill(PrintObject *pobj)
//{
// assert(pobj != nullptr);
// make_perimeters(pobj);
// if (!pobj->state.is_done(STEP_PREPARE_INFILL)) {
// pobj->state.set_started(STEP_PREPARE_INFILL);
// pobj->_prepare_infill();
// pobj->state.set_done(STEP_PREPARE_INFILL);
// }
// pobj->_infill();
//}
//void PrintController::gen_support_material(PrintObject *pobj)
//{
// assert(pobj != nullptr);
// // prerequisites
// slice(pobj);
// if(!pobj->state.is_done(STEP_SUPPORTMATERIAL)) {
// pobj->state.set_started(STEP_SUPPORTMATERIAL);
// pobj->clear_support_layers();
// if((pobj->config.support_material || pobj->config.raft_layers > 0)
// && pobj->layers.size() > 1) {
// pobj->_generate_support_material();
// }
// pobj->state.set_done(STEP_SUPPORTMATERIAL);
// }
//}
PrintController::PngExportData
PrintController::query_png_export_data(const DynamicPrintConfig& conf)
{
PngExportData ret;
auto zippath = query_destination_path("Output zip file", "*.zip", "out");
auto c = GUI::get_appctl();
auto zippath = c->query_destination_path("Output zip file", "*.zip",
"export-png",
"out");
ret.zippath = zippath;
@ -246,98 +103,53 @@ PrintController::query_png_export_data(const DynamicPrintConfig& conf)
return ret;
}
void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri)
void PrintController::slice(ProgresIndicatorPtr pri)
{
auto st = pri->state();
m_print->set_status_callback([pri](int st, const std::string& msg){
pri->update(unsigned(st), msg);
});
Slic3r::trace(3, "Starting the slicing process.");
pri->update(st+20, L("Generating perimeters"));
// for(auto obj : print_->objects) make_perimeters(obj);
pri->update(st+60, L("Infilling layers"));
// for(auto obj : print_->objects) infill(obj);
pri->update(st+70, L("Generating support material"));
// for(auto obj : print_->objects) gen_support_material(obj);
// pri->message_fmt(L("Weight: %.1fg, Cost: %.1f"),
// print_->total_weight, print_->total_cost);
pri->state(st+85);
pri->update(st+88, L("Generating skirt"));
make_skirt();
pri->update(st+90, L("Generating brim"));
make_brim();
pri->update(st+95, L("Generating wipe tower"));
make_wipe_tower();
pri->update(st+100, L("Done"));
// time to make some statistics..
Slic3r::trace(3, L("Slicing process finished."));
m_print->process();
}
void PrintController::slice()
{
auto pri = global_progress_indicator();
if(!pri) pri = create_progress_indicator(100, L("Slicing"));
auto ctl = GUI::get_appctl();
auto pri = ctl->global_progress_indicator();
if(!pri) pri = ctl->create_progress_indicator(100, L("Slicing"));
slice(pri);
}
struct wxZipper {};
template<> class Zipper<wxZipper> {
wxFileName m_fpath;
wxFFileOutputStream m_zipfile;
wxZipOutputStream m_zipstream;
wxStdOutputStream m_pngstream;
template<> class LayerWriter<Zipper> {
Zipper m_zip;
public:
Zipper(const std::string& zipfile_path):
m_fpath(zipfile_path),
m_zipfile(zipfile_path),
m_zipstream(m_zipfile),
m_pngstream(m_zipstream)
{
if(!m_zipfile.IsOk())
throw std::runtime_error(L("Cannot create zip file."));
inline LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {}
inline void next_entry(const std::string& fname) { m_zip.next_entry(fname); }
inline std::string get_name() const { return m_zip.get_name(); }
template<class T> inline LayerWriter& operator<<(const T& arg) {
m_zip.stream() << arg; return *this;
}
void next_entry(const std::string& fname) {
m_zipstream.PutNextEntry(fname);
}
std::string get_name() {
return m_fpath.GetName().ToStdString();
}
template<class T> Zipper& operator<<(const T& arg) {
m_pngstream << arg; return *this;
}
void close() {
m_zipstream.Close();
m_zipfile.Close();
}
inline void close() { m_zip.close(); }
};
void PrintController::slice_to_png()
{
using Pointf3 = Vec3d;
auto ctl = GUI::get_appctl();
auto presetbundle = GUI::get_preset_bundle();
assert(presetbundle);
// FIXME: this crashes in command line mode
auto pt = presetbundle->printers.get_selected_preset().printer_technology();
if(pt != ptSLA) {
report_issue(IssueType::ERR, L("Printer technology is not SLA!"),
ctl->report_issue(IssueType::ERR, L("Printer technology is not SLA!"),
L("Error"));
return;
}
@ -348,13 +160,13 @@ void PrintController::slice_to_png()
auto exd = query_png_export_data(conf);
if(exd.zippath.empty()) return;
Print *print = print_;
Print *print = m_print;
try {
print->apply_config(conf);
print->validate();
} catch(std::exception& e) {
report_issue(IssueType::ERR, e.what(), "Error");
ctl->report_issue(IssueType::ERR, e.what(), "Error");
return;
}
@ -400,13 +212,13 @@ void PrintController::slice_to_png()
<< L("Width needed: ") << px(punsc) << " mm\n"
<< L("Height needed: ") << py(punsc) << " mm\n";
if(!report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) {
if(!ctl->report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) {
scale_back();
return;
}
}
auto pri = create_progress_indicator(
auto pri = ctl->create_progress_indicator(
200, L("Slicing to zipped png files..."));
pri->on_cancel([&print](){ print->cancel(); });
@ -415,7 +227,7 @@ void PrintController::slice_to_png()
pri->update(0, L("Slicing..."));
slice(pri);
} catch (std::exception& e) {
report_issue(IssueType::ERR, e.what(), L("Exception occurred"));
ctl->report_issue(IssueType::ERR, e.what(), L("Exception occurred"));
scale_back();
if(print->canceled()) print->restart();
return;
@ -428,22 +240,23 @@ void PrintController::slice_to_png()
});
try {
print_to<FilePrinterFormat::PNG, wxZipper>( *print, exd.zippath,
print_to<FilePrinterFormat::PNG, Zipper>( *print, exd.zippath,
exd.width_mm, exd.height_mm,
exd.width_px, exd.height_px,
exd.exp_time_s, exd.exp_time_first_s);
} catch (std::exception& e) {
report_issue(IssueType::ERR, e.what(), L("Exception occurred"));
ctl->report_issue(IssueType::ERR, e.what(), L("Exception occurred"));
}
scale_back();
if(print->canceled()) print->restart();
print->set_status_default();
}
const PrintConfig &PrintController::config() const
{
return print_->config();
return m_print->config();
}
void ProgressIndicator::message_fmt(
@ -477,15 +290,17 @@ void AppController::arrange_model()
{
using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
if(arranging_.load()) return;
auto ctl = GUI::get_appctl();
if(m_arranging.load()) return;
// to prevent UI reentrancies
arranging_.store(true);
m_arranging.store(true);
unsigned count = 0;
for(auto obj : model_->objects) count += obj->instances.size();
for(auto obj : m_model->objects) count += obj->instances.size();
auto pind = global_progress_indicator();
auto pind = ctl->global_progress_indicator();
float pmax = 1.0;
@ -496,7 +311,7 @@ void AppController::arrange_model()
pind->max(count);
pind->on_cancel([this](){
arranging_.store(false);
m_arranging.store(false);
});
}
@ -517,20 +332,20 @@ void AppController::arrange_model()
// TODO: from Sasha from GUI
hint.type = arr::BedShapeType::WHO_KNOWS;
arr::arrange(*model_,
arr::arrange(*m_model,
min_obj_distance,
bed,
hint,
false, // create many piles not just one pile
[this, pind, count](unsigned rem) {
[this, pind, &ctl, count](unsigned rem) {
if(pind)
pind->update(count - rem, L("Arranging objects..."));
process_events();
}, [this] () { return !arranging_.load(); });
ctl->process_events();
}, [this] () { return !m_arranging.load(); });
} catch(std::exception& e) {
std::cerr << e.what() << std::endl;
report_issue(IssueType::ERR,
ctl->report_issue(IssueType::ERR,
L("Could not arrange model objects! "
"Some geometries may be invalid."),
L("Exception occurred"));
@ -539,13 +354,13 @@ void AppController::arrange_model()
// Restore previous max value
if(pind) {
pind->max(pmax);
pind->update(0, arranging_.load() ? L("Arranging done.") :
pind->update(0, m_arranging.load() ? L("Arranging done.") :
L("Arranging canceled."));
pind->on_cancel(/*remove cancel function*/);
}
arranging_.store(false);
m_arranging.store(false);
}
}

View file

@ -20,6 +20,21 @@ class PrintConfig;
class ProgressStatusBar;
class DynamicPrintConfig;
/// A Progress indicator object smart pointer
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
using FilePath = std::string;
using FilePathList = std::vector<FilePath>;
/// Common runtime issue types
enum class IssueType {
INFO,
WARN,
WARN_Q, // Warning with a question to continue
ERR,
FATAL
};
/**
* @brief A boilerplate class for creating application logic. It should provide
* features as issue reporting and progress indication, etc...
@ -32,34 +47,12 @@ class DynamicPrintConfig;
* UI toolkit dependencies. We can implement it with any UI framework or make it
* a cli client.
*/
class AppControllerBoilerplate {
class AppControllerBase {
public:
/// A Progress indicator object smart pointer
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
using Ptr = std::shared_ptr<AppControllerBase>;
private:
class PriData; // Some structure to store progress indication data
// Pimpl data for thread safe progress indication features
std::unique_ptr<PriData> pri_data_;
public:
AppControllerBoilerplate();
~AppControllerBoilerplate();
using Path = std::string;
using PathList = std::vector<Path>;
/// Common runtime issue types
enum class IssueType {
INFO,
WARN,
WARN_Q, // Warning with a question to continue
ERR,
FATAL
};
inline virtual ~AppControllerBase() {}
/**
* @brief Query some paths from the user.
@ -67,25 +60,30 @@ public:
* 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.
* @return Returns a list of paths chosen by the user.
*/
PathList query_destination_paths(
virtual FilePathList query_destination_paths(
const std::string& title,
const std::string& extensions) const;
const std::string& extensions,
const std::string& functionid = "",
const std::string& hint = "") const = 0;
/**
* @brief Same as query_destination_paths but works for directories only.
*/
PathList query_destination_dirs(
const std::string& title) const;
virtual FilePathList query_destination_dirs(
const std::string& title,
const std::string& functionid = "",
const std::string& hint = "") const = 0;
/**
* @brief Same as query_destination_paths but returns only one path.
*/
Path query_destination_path(
virtual FilePath query_destination_path(
const std::string& title,
const std::string& extensions,
const std::string& hint = "") const;
const std::string& functionid = "",
const std::string& hint = "") const = 0;
/**
* @brief Report an issue to the user be it fatal or recoverable.
@ -97,12 +95,9 @@ public:
* @param brief A very brief description. Can be used for message dialog
* title.
*/
bool report_issue(IssueType issuetype,
const std::string& description,
const std::string& brief);
bool report_issue(IssueType issuetype,
const std::string& description);
virtual bool report_issue(IssueType issuetype,
const std::string& description,
const std::string& brief) = 0;
/**
* @brief Return the global progress indicator for the current controller.
@ -110,9 +105,9 @@ public:
*
* Only one thread should use the global indicator at a time.
*/
ProgresIndicatorPtr global_progress_indicator();
virtual ProgresIndicatorPtr global_progress_indicator() = 0;
void global_progress_indicator(ProgresIndicatorPtr gpri);
virtual void global_progress_indicator(ProgresIndicatorPtr gpri) = 0;
/**
* @brief A predicate telling the caller whether it is the thread that
@ -122,7 +117,7 @@ public:
* @return Return true for the same caller thread that created this
* object and false for every other.
*/
bool is_main_thread() const;
virtual bool is_main_thread() const = 0;
/**
* @brief The frontend supports asynch execution.
@ -138,11 +133,9 @@ public:
* @return true if a job or method can be executed asynchronously, false
* otherwise.
*/
bool supports_asynch() const;
virtual bool supports_asynch() const = 0;
void process_events();
protected:
virtual void process_events() = 0;
/**
* @brief Create a new progress indicator and return a smart pointer to it.
@ -151,36 +144,169 @@ protected:
* @param firstmsg The message for the first subtask to be displayed.
* @return Smart pointer to the created object.
*/
ProgresIndicatorPtr create_progress_indicator(
virtual ProgresIndicatorPtr create_progress_indicator(
unsigned statenum,
const std::string& title,
const std::string& firstmsg) const;
const std::string& firstmsg = "") const = 0;
};
ProgresIndicatorPtr create_progress_indicator(
/**
* @brief Implementation of AppControllerBase for the GUI app
*/
class AppControllerGui: public AppControllerBase {
private:
class PriData; // Some structure to store progress indication data
// Pimpl data for thread safe progress indication features
std::unique_ptr<PriData> m_pri_data;
public:
AppControllerGui();
virtual ~AppControllerGui();
virtual FilePathList query_destination_paths(
const std::string& title,
const std::string& extensions,
const std::string& functionid,
const std::string& hint) const override;
virtual FilePathList query_destination_dirs(
const std::string& /*title*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return {}; }
virtual FilePath query_destination_path(
const std::string& title,
const std::string& extensions,
const std::string& functionid,
const std::string& hint) const override;
virtual bool report_issue(IssueType issuetype,
const std::string& description,
const std::string& brief = std::string()) override;
virtual ProgresIndicatorPtr global_progress_indicator() override;
virtual void global_progress_indicator(ProgresIndicatorPtr gpri) override;
virtual bool is_main_thread() const override;
virtual bool supports_asynch() const override;
virtual void process_events() override;
virtual ProgresIndicatorPtr create_progress_indicator(
unsigned statenum,
const std::string& title) const;
const std::string& title,
const std::string& firstmsg) const override;
protected:
// This is a global progress indicator placeholder. In the Slic3r UI it can
// contain the progress indicator on the statusbar.
ProgresIndicatorPtr global_progressind_;
ProgresIndicatorPtr m_global_progressind;
};
class AppControllerCli: public AppControllerBase {
class CliProgress : public ProgressIndicator {
std::string m_msg, m_title;
public:
virtual void message(const std::string& msg) override {
m_msg = msg;
}
virtual void title(const std::string& title) override {
m_title = title;
}
};
public:
AppControllerCli() {
std::cout << "Cli AppController ready..." << std::endl;
m_global_progressind = std::make_shared<CliProgress>();
}
virtual ~AppControllerCli() {}
virtual FilePathList query_destination_paths(
const std::string& /*title*/,
const std::string& /*extensions*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return {}; }
virtual FilePathList query_destination_dirs(
const std::string& /*title*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return {}; }
virtual FilePath query_destination_path(
const std::string& /*title*/,
const std::string& /*extensions*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return "out.zip"; }
virtual bool report_issue(IssueType /*issuetype*/,
const std::string& description,
const std::string& brief) override {
std::cerr << brief << ": " << description << std::endl;
return true;
}
virtual ProgresIndicatorPtr global_progress_indicator() override {
return m_global_progressind;
}
virtual void global_progress_indicator(ProgresIndicatorPtr) override {}
virtual bool is_main_thread() const override { return true; }
virtual bool supports_asynch() const override { return false; }
virtual void process_events() override {}
virtual ProgresIndicatorPtr create_progress_indicator(
unsigned /*statenum*/,
const std::string& /*title*/,
const std::string& /*firstmsg*/) const override {
return std::make_shared<CliProgress>();
}
protected:
// This is a global progress indicator placeholder. In the Slic3r UI it can
// contain the progress indicator on the statusbar.
ProgresIndicatorPtr m_global_progressind;
};
class Zipper {
struct Impl;
std::unique_ptr<Impl> m_impl;
public:
Zipper(const std::string& zipfilepath);
~Zipper();
void next_entry(const std::string& fname);
std::string get_name() const;
std::ostream& stream();
void close();
};
/**
* @brief Implementation of the printing logic.
*/
class PrintController: public AppControllerBoilerplate {
Print *print_ = nullptr;
std::function<void()> rempools_;
class PrintController {
Print *m_print = nullptr;
std::function<void()> m_rempools;
protected:
void make_skirt() {}
void make_brim() {}
void make_wipe_tower() {}
void make_perimeters(PrintObject *pobj) {}
void infill(PrintObject *pobj) {}
void gen_support_material(PrintObject *pobj) {}
// Data structure with the png export input data
struct PngExportData {
std::string zippath; // output zip file
@ -198,20 +324,14 @@ protected:
PngExportData query_png_export_data(const DynamicPrintConfig&);
// The previous export data, to pre-populate the dialog
PngExportData prev_expdata_;
/**
* @brief Slice one pront object.
* @param pobj The print object.
*/
void slice(PrintObject *pobj);
PngExportData m_prev_expdata;
void slice(ProgresIndicatorPtr pri);
public:
// Must be public for perl to use it
explicit inline PrintController(Print *print): print_(print) {}
explicit inline PrintController(Print *print): m_print(print) {}
PrintController(const PrintController&) = delete;
PrintController(PrintController&&) = delete;
@ -238,10 +358,10 @@ public:
/**
* @brief Top level controller.
*/
class AppController: public AppControllerBoilerplate {
Model *model_ = nullptr;
class AppController {
Model *m_model = nullptr;
PrintController::Ptr printctl;
std::atomic<bool> arranging_;
std::atomic<bool> m_arranging;
public:
/**
@ -258,7 +378,7 @@ public:
* @param model A raw pointer to the model object. This can be used from
* perl.
*/
void set_model(Model *model) { model_ = model; }
void set_model(Model *model) { m_model = model; }
/**
* @brief Set the print object from perl.

View file

@ -1,5 +1,9 @@
#include "AppController.hpp"
#include <wx/stdstream.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <thread>
#include <future>
@ -21,40 +25,43 @@
namespace Slic3r {
bool AppControllerBoilerplate::supports_asynch() const
bool AppControllerGui::supports_asynch() const
{
return true;
}
void AppControllerBoilerplate::process_events()
void AppControllerGui::process_events()
{
wxYieldIfNeeded();
}
AppControllerBoilerplate::PathList
AppControllerBoilerplate::query_destination_paths(
FilePathList AppControllerGui::query_destination_paths(
const std::string &title,
const std::string &extensions) const
const std::string &extensions,
const std::string &/*functionid*/,
const std::string& hint) const
{
wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
dlg.SetWildcard(extensions);
dlg.ShowModal();
dlg.SetFilename(hint);
wxArrayString paths;
dlg.GetPaths(paths);
FilePathList ret;
PathList ret(paths.size(), "");
for(auto& p : paths) ret.push_back(p.ToStdString());
if(dlg.ShowModal() == wxID_OK) {
wxArrayString paths;
dlg.GetPaths(paths);
for(auto& p : paths) ret.push_back(p.ToStdString());
}
return ret;
}
AppControllerBoilerplate::Path
AppControllerBoilerplate::query_destination_path(
FilePath AppControllerGui::query_destination_path(
const std::string &title,
const std::string &extensions,
const std::string &/*functionid*/,
const std::string& hint) const
{
wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
@ -62,16 +69,16 @@ AppControllerBoilerplate::query_destination_path(
dlg.SetFilename(hint);
Path ret;
FilePath ret;
if(dlg.ShowModal() == wxID_OK) {
ret = Path(dlg.GetPath());
ret = FilePath(dlg.GetPath());
}
return ret;
}
bool AppControllerBoilerplate::report_issue(IssueType issuetype,
bool AppControllerGui::report_issue(IssueType issuetype,
const std::string &description,
const std::string &brief)
{
@ -89,14 +96,52 @@ bool AppControllerBoilerplate::report_issue(IssueType issuetype,
return ret != wxCANCEL;
}
bool AppControllerBoilerplate::report_issue(
AppControllerBoilerplate::IssueType issuetype,
const std::string &description)
wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent);
struct Zipper::Impl {
wxFileName fpath;
wxFFileOutputStream zipfile;
wxZipOutputStream zipstream;
wxStdOutputStream pngstream;
Impl(const std::string& zipfile_path):
fpath(zipfile_path),
zipfile(zipfile_path),
zipstream(zipfile),
pngstream(zipstream)
{
if(!zipfile.IsOk())
throw std::runtime_error(L("Cannot create zip file."));
}
};
Zipper::Zipper(const std::string &zipfilepath)
{
return report_issue(issuetype, description, std::string());
m_impl.reset(new Impl(zipfilepath));
}
wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent);
Zipper::~Zipper() {}
void Zipper::next_entry(const std::string &fname)
{
m_impl->zipstream.PutNextEntry(fname);
}
std::string Zipper::get_name() const
{
return m_impl->fpath.GetName().ToStdString();
}
std::ostream &Zipper::stream()
{
return m_impl->pngstream;
}
void Zipper::close()
{
m_impl->zipstream.Close();
m_impl->zipfile.Close();
}
namespace {
@ -107,26 +152,26 @@ namespace {
class GuiProgressIndicator:
public ProgressIndicator, public wxEvtHandler {
wxProgressDialog gauge_;
wxProgressDialog m_gauge;
using Base = ProgressIndicator;
wxString message_;
int range_; wxString title_;
bool is_asynch_ = false;
wxString m_message;
int m_range; wxString m_title;
bool m_is_asynch = false;
const int id_ = wxWindow::NewControlId();
const int m_id = wxWindow::NewControlId();
// status update handler
void _state( wxCommandEvent& evt) {
unsigned st = evt.GetInt();
message_ = evt.GetString();
m_message = evt.GetString();
_state(st);
}
// Status update implementation
void _state( unsigned st) {
if(!gauge_.IsShown()) gauge_.ShowModal();
if(!m_gauge.IsShown()) m_gauge.ShowModal();
Base::state(st);
if(!gauge_.Update(static_cast<int>(st), message_)) {
if(!m_gauge.Update(static_cast<int>(st), m_message)) {
cancel();
}
}
@ -134,25 +179,25 @@ class GuiProgressIndicator:
public:
/// Setting whether it will be used from the UI thread or some worker thread
inline void asynch(bool is) { is_asynch_ = is; }
inline void asynch(bool is) { m_is_asynch = is; }
/// Get the mode of parallel operation.
inline bool asynch() const { return is_asynch_; }
inline bool asynch() const { return m_is_asynch; }
inline GuiProgressIndicator(int range, const wxString& title,
const wxString& firstmsg) :
gauge_(title, firstmsg, range, wxTheApp->GetTopWindow(),
m_gauge(title, firstmsg, range, wxTheApp->GetTopWindow(),
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT),
message_(firstmsg),
range_(range), title_(title)
m_message(firstmsg),
m_range(range), m_title(title)
{
Base::max(static_cast<float>(range));
Base::states(static_cast<unsigned>(range));
Bind(PROGRESS_STATUS_UPDATE_EVENT,
&GuiProgressIndicator::_state,
this, id_);
this, m_id);
}
virtual void state(float val) override {
@ -161,33 +206,32 @@ public:
void state(unsigned st) {
// send status update event
if(is_asynch_) {
auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_);
if(m_is_asynch) {
auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, m_id);
evt->SetInt(st);
evt->SetString(message_);
evt->SetString(m_message);
wxQueueEvent(this, evt);
} else _state(st);
}
virtual void message(const std::string & msg) override {
message_ = _(msg);
m_message = _(msg);
}
virtual void messageFmt(const std::string& fmt, ...) {
va_list arglist;
va_start(arglist, fmt);
message_ = wxString::Format(_(fmt), arglist);
m_message = wxString::Format(_(fmt), arglist);
va_end(arglist);
}
virtual void title(const std::string & title) override {
title_ = _(title);
m_title = _(title);
}
};
}
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::create_progress_indicator(
ProgresIndicatorPtr AppControllerGui::create_progress_indicator(
unsigned statenum,
const std::string& title,
const std::string& firstmsg) const
@ -202,30 +246,23 @@ AppControllerBoilerplate::create_progress_indicator(
return pri;
}
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::create_progress_indicator(
unsigned statenum, const std::string &title) const
{
return create_progress_indicator(statenum, title, std::string());
}
namespace {
class Wrapper: public ProgressIndicator, public wxEvtHandler {
ProgressStatusBar *sbar_;
ProgressStatusBar *m_sbar;
using Base = ProgressIndicator;
wxString message_;
AppControllerBoilerplate& ctl_;
wxString m_message;
AppControllerBase& m_ctl;
void showProgress(bool show = true) {
sbar_->show_progress(show);
m_sbar->show_progress(show);
}
void _state(unsigned st) {
if( st <= ProgressIndicator::max() ) {
Base::state(st);
sbar_->set_status_text(message_);
sbar_->set_progress(st);
m_sbar->set_status_text(m_message);
m_sbar->set_progress(st);
}
}
@ -239,11 +276,11 @@ class Wrapper: public ProgressIndicator, public wxEvtHandler {
public:
inline Wrapper(ProgressStatusBar *sbar,
AppControllerBoilerplate& ctl):
sbar_(sbar), ctl_(ctl)
AppControllerBase& ctl):
m_sbar(sbar), m_ctl(ctl)
{
Base::max(static_cast<float>(sbar_->get_range()));
Base::states(static_cast<unsigned>(sbar_->get_range()));
Base::max(static_cast<float>(m_sbar->get_range()));
Base::states(static_cast<unsigned>(m_sbar->get_range()));
Bind(PROGRESS_STATUS_UPDATE_EVENT,
&Wrapper::_state,
@ -256,13 +293,13 @@ public:
virtual void max(float val) override {
if(val > 1.0) {
sbar_->set_range(static_cast<int>(val));
m_sbar->set_range(static_cast<int>(val));
ProgressIndicator::max(val);
}
}
void state(unsigned st) {
if(!ctl_.is_main_thread()) {
if(!m_ctl.is_main_thread()) {
auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_);
evt->SetInt(st);
wxQueueEvent(this, evt);
@ -272,20 +309,20 @@ public:
}
virtual void message(const std::string & msg) override {
message_ = _(msg);
m_message = _(msg);
}
virtual void message_fmt(const std::string& fmt, ...) override {
va_list arglist;
va_start(arglist, fmt);
message_ = wxString::Format(_(fmt), arglist);
m_message = wxString::Format(_(fmt), arglist);
va_end(arglist);
}
virtual void title(const std::string & /*title*/) override {}
virtual void on_cancel(CancelFn fn) override {
sbar_->set_cancel_callback(fn);
m_sbar->set_cancel_callback(fn);
Base::on_cancel(fn);
}
@ -295,7 +332,8 @@ public:
void AppController::set_global_progress_indicator(ProgressStatusBar *prsb)
{
if(prsb) {
global_progress_indicator(std::make_shared<Wrapper>(prsb, *this));
auto ctl = GUI::get_appctl();
ctl->global_progress_indicator(std::make_shared<Wrapper>(prsb, *ctl));
}
}

View file

@ -196,7 +196,11 @@ const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
GLVolume::GLVolume(float r, float g, float b, float a)
: m_offset(Vec3d::Zero())
#if ENABLE_MODELINSTANCE_3D_ROTATION
, m_rotation(Vec3d::Zero())
#else
, m_rotation(0.0)
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
, m_scaling_factor(1.0)
, m_world_matrix(Transform3f::Identity())
, m_world_matrix_dirty(true)
@ -255,7 +259,24 @@ void GLVolume::set_render_color()
set_render_color(color, 4);
}
double GLVolume::get_rotation()
#if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& GLVolume::get_rotation() const
{
return m_rotation;
}
void GLVolume::set_rotation(const Vec3d& rotation)
{
if (m_rotation != rotation)
{
m_rotation = rotation;
m_world_matrix_dirty = true;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
#else
double GLVolume::get_rotation() const
{
return m_rotation;
}
@ -270,6 +291,7 @@ void GLVolume::set_rotation(double rotation)
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& GLVolume::get_offset() const
{
@ -327,7 +349,13 @@ const Transform3f& GLVolume::world_matrix() const
{
m_world_matrix = Transform3f::Identity();
m_world_matrix.translate(m_offset.cast<float>());
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(2), Vec3f::UnitZ()));
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(1), Vec3f::UnitY()));
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(0), Vec3f::UnitX()));
#else
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation, Vec3f::UnitZ()));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_world_matrix.scale((float)m_scaling_factor);
m_world_matrix_dirty = false;
}
@ -403,7 +431,13 @@ void GLVolume::render() const
::glCullFace(GL_BACK);
::glPushMatrix();
::glTranslated(m_offset(0), m_offset(1), m_offset(2));
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
#else
::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
if (this->indexed_vertex_array.indexed())
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
@ -529,7 +563,13 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
::glPushMatrix();
::glTranslated(m_offset(0), m_offset(1), m_offset(2));
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
#else
::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
if (n_triangles > 0)
@ -574,7 +614,13 @@ void GLVolume::render_legacy() const
::glPushMatrix();
::glTranslated(m_offset(0), m_offset(1), m_offset(2));
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
#else
::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
if (n_triangles > 0)
@ -698,7 +744,11 @@ std::vector<int> GLVolumeCollection::load_object(
#else
v.set_offset(Vec3d(instance->offset(0), instance->offset(1), 0.0));
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
v.set_rotation(instance->get_rotation());
#else
v.set_rotation(instance->rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
v.set_scaling_factor(instance->scaling_factor);
}
}
@ -2067,12 +2117,30 @@ void _3DScene::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, vo
void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback)
{
#if !ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
}
void _3DScene::register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback)
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_rotate_3D_callback(canvas, callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
}
void _3DScene::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback)
{
#if !ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_flatten_callback(canvas, callback);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
}
void _3DScene::register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback)
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_flatten_3D_callback(canvas, callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
}
void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback)

View file

@ -256,8 +256,13 @@ public:
private:
// Offset of the volume to be rendered.
Vec3d m_offset;
#if ENABLE_MODELINSTANCE_3D_ROTATION
// Rotation around three axes of the volume to be rendered.
Vec3d m_rotation;
#else
// Rotation around Z axis of the volume to be rendered.
double m_rotation;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
// Scale factor of the volume to be rendered.
double m_scaling_factor;
// World matrix of the volume to be rendered.
@ -327,8 +332,13 @@ public:
// Sets render color in dependence of current state
void set_render_color();
double get_rotation();
#if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& get_rotation() const;
void set_rotation(const Vec3d& rotation);
#else
double get_rotation() const;
void set_rotation(double rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& get_offset() const;
void set_offset(const Vec3d& offset);
@ -558,7 +568,9 @@ public:
static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback);
static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
static void register_action_add_callback(wxGLCanvas* canvas, void* callback);

View file

@ -1095,6 +1095,9 @@ GLCanvas3D::Mouse::Drag::Drag()
GLCanvas3D::Mouse::Mouse()
: dragging(false)
, position(DBL_MAX, DBL_MAX)
#if ENABLE_GIZMOS_RESET
, ignore_up_event(false)
#endif // ENABLE_GIZMOS_RESET
{
}
@ -1181,9 +1184,11 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
return false;
}
#if !ENABLE_MODELINSTANCE_3D_ROTATION
// temporary disable x and y grabbers
gizmo->disable_grabber(0);
gizmo->disable_grabber(1);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
@ -1349,6 +1354,18 @@ void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray)
curr->update(mouse_ray);
}
#if ENABLE_GIZMOS_RESET
void GLCanvas3D::Gizmos::process_double_click()
{
if (!m_enabled)
return;
GLGizmoBase* curr = _get_current();
if (curr != nullptr)
curr->process_double_click();
}
#endif // ENABLE_GIZMOS_RESET
GLCanvas3D::Gizmos::EType GLCanvas3D::Gizmos::get_current_type() const
{
return m_current;
@ -1421,6 +1438,35 @@ void GLCanvas3D::Gizmos::set_scale(float scale)
reinterpret_cast<GLGizmoScale3D*>(it->second)->set_scale(scale);
}
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d GLCanvas3D::Gizmos::get_rotation() const
{
if (!m_enabled)
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate3D*>(it->second)->get_rotation() : Vec3d::Zero();
}
void GLCanvas3D::Gizmos::set_rotation(const Vec3d& rotation)
{
if (!m_enabled)
return;
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoRotate3D*>(it->second)->set_rotation(rotation);
}
Vec3d GLCanvas3D::Gizmos::get_flattening_rotation() const
{
if (!m_enabled)
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Flatten);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_rotation() : Vec3d::Zero();
}
#else
float GLCanvas3D::Gizmos::get_angle_z() const
{
if (!m_enabled)
@ -1448,6 +1494,7 @@ Vec3d GLCanvas3D::Gizmos::get_flattening_normal() const
GizmosMap::const_iterator it = m_gizmos.find(Flatten);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_normal() : Vec3d::Zero();
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object)
{
@ -2385,7 +2432,11 @@ void GLCanvas3D::update_gizmos_data()
m_gizmos.set_position(Vec3d(model_instance->offset(0), model_instance->offset(1), 0.0));
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
m_gizmos.set_scale(model_instance->scaling_factor);
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_rotation(model_instance->get_rotation());
#else
m_gizmos.set_angle_z(model_instance->rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_flattening_data(model_object);
}
}
@ -2394,7 +2445,11 @@ void GLCanvas3D::update_gizmos_data()
{
m_gizmos.set_position(Vec3d::Zero());
m_gizmos.set_scale(1.0f);
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_rotation(Vec3d::Zero());
#else
m_gizmos.set_angle_z(0.0f);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_flattening_data(nullptr);
}
}
@ -2757,6 +2812,19 @@ void GLCanvas3D::register_on_gizmo_scale_uniformly_callback(void* callback)
m_on_gizmo_scale_uniformly_callback.register_callback(callback);
}
#if ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3D::register_on_gizmo_rotate_3D_callback(void* callback)
{
if (callback != nullptr)
m_on_gizmo_rotate_3D_callback.register_callback(callback);
}
void GLCanvas3D::register_on_gizmo_flatten_3D_callback(void* callback)
{
if (callback != nullptr)
m_on_gizmo_flatten_3D_callback.register_callback(callback);
}
#else
void GLCanvas3D::register_on_gizmo_rotate_callback(void* callback)
{
if (callback != nullptr)
@ -2768,6 +2836,7 @@ void GLCanvas3D::register_on_gizmo_flatten_callback(void* callback)
if (callback != nullptr)
m_on_gizmo_flatten_callback.register_callback(callback);
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3D::register_on_update_geometry_info_callback(void* callback)
{
@ -3043,6 +3112,41 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_toolbar_action_running = true;
m_toolbar.do_action((unsigned int)toolbar_contains_mouse);
}
#if ENABLE_GIZMOS_RESET
else if (evt.LeftDClick() && m_gizmos.grabber_contains_mouse())
{
#if ENABLE_GIZMOS_RESET
m_mouse.ignore_up_event = true;
#endif // ENABLE_GIZMOS_RESET
m_gizmos.process_double_click();
switch (m_gizmos.get_current_type())
{
case Gizmos::Scale:
{
m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale());
update_scale_values();
m_dirty = true;
break;
}
case Gizmos::Rotate:
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& rotation = m_gizmos.get_rotation();
m_on_gizmo_rotate_3D_callback.call(rotation(0), rotation(1), rotation(2));
#else
m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z());
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
update_rotation_values();
m_dirty = true;
break;
}
default:
{
break;
}
}
}
#endif // ENABLE_GIZMOS_RESET
else if (evt.LeftDown() || evt.RightDown())
{
// If user pressed left or right button we first check whether this happened
@ -3083,6 +3187,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx);
if (m_gizmos.get_current_type() == Gizmos::Flatten) {
#if ENABLE_MODELINSTANCE_3D_ROTATION
// Rotate the object so the normal points downward:
const Vec3d& rotation = m_gizmos.get_flattening_rotation();
m_on_gizmo_flatten_3D_callback.call(rotation(0), rotation(1), rotation(2));
#else
// Rotate the object so the normal points downward:
Vec3d normal = m_gizmos.get_flattening_normal();
if (normal(0) != 0.0 || normal(1) != 0.0 || normal(2) != 0.0) {
@ -3090,6 +3199,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
float angle = acos(clamp(-1.0, 1.0, -normal(2)));
m_on_gizmo_flatten_callback.call(angle, (float)axis(0), (float)axis(1), (float)axis(2));
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
}
m_dirty = true;
@ -3272,6 +3382,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
case Gizmos::Rotate:
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
// Apply new temporary rotation
Vec3d rotation = m_gizmos.get_rotation();
for (GLVolume* v : volumes)
{
v->set_rotation(rotation);
}
update_rotation_value(rotation);
#else
// Apply new temporary angle_z
float angle_z = m_gizmos.get_angle_z();
for (GLVolume* v : volumes)
@ -3279,6 +3398,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
v->set_rotation((double)angle_z);
}
update_rotation_value((double)angle_z, Z);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
break;
}
default:
@ -3377,12 +3497,20 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled())
{
// deselect and propagate event through callback
#if ENABLE_GIZMOS_RESET
if (!m_mouse.ignore_up_event && m_picking_enabled && !m_toolbar_action_running)
#else
if (m_picking_enabled && !m_toolbar_action_running)
#endif // ENABLE_GIZMOS_RESET
{
deselect_volumes();
_on_select(-1, -1);
update_gizmos_data();
}
#if ENABLE_GIZMOS_RESET
else if (m_mouse.ignore_up_event)
m_mouse.ignore_up_event = false;
#endif // ENABLE_GIZMOS_RESET
}
else if (evt.LeftUp() && m_gizmos.is_dragging())
{
@ -3416,14 +3544,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
case Gizmos::Rotate:
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& rotation = m_gizmos.get_rotation();
m_on_gizmo_rotate_3D_callback.call(rotation(0), rotation(1), rotation(2));
#else
m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z());
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
break;
}
default:
break;
}
m_gizmos.stop_dragging();
Slic3r::GUI::update_settings_value();
update_settings_value();
}
m_mouse.drag.move_volume_idx = -1;
@ -3863,8 +3996,13 @@ void GLCanvas3D::_deregister_callbacks()
m_on_wipe_tower_moved_callback.deregister_callback();
m_on_enable_action_buttons_callback.deregister_callback();
m_on_gizmo_scale_uniformly_callback.deregister_callback();
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_on_gizmo_rotate_3D_callback.deregister_callback();
m_on_gizmo_flatten_3D_callback.deregister_callback();
#else
m_on_gizmo_rotate_callback.deregister_callback();
m_on_gizmo_flatten_callback.deregister_callback();
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_on_update_geometry_info_callback.deregister_callback();
m_action_add_callback.deregister_callback();

View file

@ -315,6 +315,9 @@ class GLCanvas3D
bool dragging;
Vec2d position;
Drag drag;
#if ENABLE_GIZMOS_RESET
bool ignore_up_event;
#endif // ENABLE_GIZMOS_RESET
Mouse();
@ -366,6 +369,9 @@ class GLCanvas3D
bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
bool grabber_contains_mouse() const;
void update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
void process_double_click();
#endif // ENABLE_GIZMOS_RESET
EType get_current_type() const;
@ -381,11 +387,20 @@ class GLCanvas3D
float get_scale() const;
void set_scale(float scale);
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_rotation() const;
void set_rotation(const Vec3d& rotation);
#else
float get_angle_z() const;
void set_angle_z(float angle_z);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_flattening_data(const ModelObject* model_object);
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_flattening_rotation() const;
#else
Vec3d get_flattening_normal() const;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_flattening_data(const ModelObject* model_object);
void render_current_gizmo(const BoundingBoxf3& box) const;
@ -501,8 +516,13 @@ class GLCanvas3D
PerlCallback m_on_wipe_tower_moved_callback;
PerlCallback m_on_enable_action_buttons_callback;
PerlCallback m_on_gizmo_scale_uniformly_callback;
#if ENABLE_MODELINSTANCE_3D_ROTATION
PerlCallback m_on_gizmo_rotate_3D_callback;
PerlCallback m_on_gizmo_flatten_3D_callback;
#else
PerlCallback m_on_gizmo_rotate_callback;
PerlCallback m_on_gizmo_flatten_callback;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
PerlCallback m_on_update_geometry_info_callback;
PerlCallback m_action_add_callback;
@ -626,8 +646,13 @@ public:
void register_on_wipe_tower_moved_callback(void* callback);
void register_on_enable_action_buttons_callback(void* callback);
void register_on_gizmo_scale_uniformly_callback(void* callback);
#if ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_gizmo_rotate_3D_callback(void* callback);
void register_on_gizmo_flatten_3D_callback(void* callback);
#else
void register_on_gizmo_rotate_callback(void* callback);
void register_on_gizmo_flatten_callback(void* callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_update_geometry_info_callback(void* callback);
void register_action_add_callback(void* callback);

View file

@ -699,6 +699,21 @@ void GLCanvas3DManager::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* c
it->second->register_on_gizmo_scale_uniformly_callback(callback);
}
#if ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3DManager::register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_on_gizmo_rotate_3D_callback(callback);
}
void GLCanvas3DManager::register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_on_gizmo_flatten_3D_callback(callback);
}
#else
void GLCanvas3DManager::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
@ -712,6 +727,7 @@ void GLCanvas3DManager::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, v
if (it != m_canvases.end())
it->second->register_on_gizmo_flatten_callback(callback);
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback)
{

View file

@ -163,8 +163,13 @@ public:
void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback);
void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
#if ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback);
#else
void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
void register_action_add_callback(wxGLCanvas* canvas, void* callback);

View file

@ -759,6 +759,20 @@ void GLGizmoScale3D::on_update(const Linef3& mouse_ray)
do_scale_uniform(mouse_ray);
}
#if ENABLE_GIZMOS_RESET
void GLGizmoScale3D::on_process_double_click()
{
if ((m_hover_id == 0) || (m_hover_id == 1))
m_scale(0) = 1.0;
else if ((m_hover_id == 2) || (m_hover_id == 3))
m_scale(1) = 1.0;
else if ((m_hover_id == 4) || (m_hover_id == 5))
m_scale(2) = 1.0;
else if (m_hover_id >= 6)
m_scale = Vec3d::Ones();
}
#endif // ENABLE_GIZMOS_RESET
void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
{
if (m_grabbers[0].dragging || m_grabbers[1].dragging)
@ -1237,15 +1251,28 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const
::glColor4f(0.9f, 0.9f, 0.9f, 0.5f);
#if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
for (const InstanceData& inst : m_instances) {
Vec3d position = inst.position + dragged_offset;
#else
for (Vec3d offset : m_instances_positions) {
offset += dragged_offset;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else
for (Vec2d offset : m_instances_positions) {
offset += to_2d(dragged_offset);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
::glPushMatrix();
#if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glTranslated(position(0), position(1), position(2));
::glRotated(inst.rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(inst.rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(inst.rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
::glScaled(inst.scaling_factor, inst.scaling_factor, inst.scaling_factor);
#else
::glTranslated(offset(0), offset(1), offset(2));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else
::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -1268,13 +1295,25 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const
{
::glColor3f(1.0f, 1.0f, picking_color_component(i));
#if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
for (const InstanceData& inst : m_instances) {
#else
for (const Vec3d& offset : m_instances_positions) {
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else
for (const Vec2d& offset : m_instances_positions) {
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
::glPushMatrix();
#if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glTranslated(inst.position(0), inst.position(1), inst.position(2));
::glRotated(inst.rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(inst.rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(inst.rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
::glScaled(inst.scaling_factor, inst.scaling_factor, inst.scaling_factor);
#else
::glTranslated(offset(0), offset(1), offset(2));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else
::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -1293,10 +1332,18 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
// ...and save the updated positions of the object instances:
if (m_model_object && !m_model_object->instances.empty()) {
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_instances.clear();
#else
m_instances_positions.clear();
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
for (const auto* instance : m_model_object->instances)
#if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_instances.emplace_back(instance->get_offset(), instance->get_rotation(), instance->scaling_factor);
#else
m_instances_positions.emplace_back(instance->get_offset());
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else
m_instances_positions.emplace_back(instance->offset);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -1312,8 +1359,10 @@ void GLGizmoFlatten::update_planes()
for (const ModelVolume* vol : m_model_object->volumes)
ch.merge(vol->get_convex_hull());
ch = ch.convex_hull_3d();
#if !ENABLE_MODELINSTANCE_3D_ROTATION
ch.scale(m_model_object->instances.front()->scaling_factor);
ch.rotate_z(m_model_object->instances.front()->rotation);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
m_planes.clear();
@ -1358,8 +1407,8 @@ void GLGizmoFlatten::update_planes()
// if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected anyway):
if (m_planes.back().vertices.size() == 3 &&
(m_planes.back().vertices[0] - m_planes.back().vertices[1]).norm() < 1.f
|| (m_planes.back().vertices[0] - m_planes.back().vertices[2]).norm() < 1.f)
m_planes.pop_back();
|| (m_planes.back().vertices[0] - m_planes.back().vertices[2]).norm() < 1.f)
m_planes.pop_back();
}
// Now we'll go through all the polygons, transform the points into xy plane to process them:
@ -1462,8 +1511,10 @@ void GLGizmoFlatten::update_planes()
m_source_data.bounding_boxes.clear();
for (const auto& vol : m_model_object->volumes)
m_source_data.bounding_boxes.push_back(vol->get_convex_hull().bounding_box());
#if !ENABLE_MODELINSTANCE_3D_ROTATION
m_source_data.scaling_factor = m_model_object->instances.front()->scaling_factor;
m_source_data.rotation = m_model_object->instances.front()->rotation;
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex();
m_source_data.mesh_first_point = Vec3d((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]);
}
@ -1475,10 +1526,14 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
if (m_state != On || !m_model_object || m_model_object->instances.empty())
return false;
#if ENABLE_MODELINSTANCE_3D_ROTATION
if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size())
#else
if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size()
|| m_model_object->instances.front()->scaling_factor != m_source_data.scaling_factor
|| m_model_object->instances.front()->rotation != m_source_data.rotation)
return true;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
return true;
// now compare the bounding boxes:
for (unsigned int i=0; i<m_model_object->volumes.size(); ++i)
@ -1493,11 +1548,22 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
return false;
}
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d GLGizmoFlatten::get_flattening_rotation() const
{
// calculates the rotations in model space
Eigen::Quaterniond q;
Vec3d angles = q.setFromTwoVectors(m_normal, -Vec3d::UnitZ()).toRotationMatrix().eulerAngles(2, 1, 0);
m_normal = Vec3d::Zero();
return Vec3d(angles(2), angles(1), angles(0));
}
#else
Vec3d GLGizmoFlatten::get_flattening_normal() const {
Vec3d normal = m_model_object->instances.front()->world_matrix(true).matrix().block(0, 0, 3, 3).inverse() * m_normal;
m_normal = Vec3d::Zero();
return normal.normalized();
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
} // namespace GUI
} // namespace Slic3r

View file

@ -94,6 +94,10 @@ public:
void update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
void process_double_click() { on_process_double_click(); }
#endif // ENABLE_GIZMOS_RESET
void render(const BoundingBoxf3& box) const { on_render(box); }
void render_for_picking(const BoundingBoxf3& box) const { on_render_for_picking(box); }
@ -106,6 +110,9 @@ protected:
virtual void on_start_dragging(const BoundingBoxf3& box) {}
virtual void on_stop_dragging() {}
virtual void on_update(const Linef3& mouse_ray) = 0;
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click() {}
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const = 0;
virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0;
@ -155,6 +162,9 @@ protected:
virtual bool on_init();
virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click() { m_angle = 0.0; }
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
@ -178,6 +188,10 @@ class GLGizmoRotate3D : public GLGizmoBase
public:
explicit GLGizmoRotate3D(GLCanvas3D& parent);
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
#else
double get_angle_x() const { return m_gizmos[X].get_angle(); }
void set_angle_x(double angle) { m_gizmos[X].set_angle(angle); }
@ -186,6 +200,7 @@ public:
double get_angle_z() const { return m_gizmos[Z].get_angle(); }
void set_angle_z(double angle) { m_gizmos[Z].set_angle(angle); }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
protected:
virtual bool on_init();
@ -222,6 +237,13 @@ protected:
g.update(mouse_ray);
}
}
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click()
{
if (m_hover_id != -1)
m_gizmos[m_hover_id].process_double_click();
}
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const
{
@ -265,6 +287,9 @@ protected:
virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_stop_dragging() { m_show_starting_box = false; }
virtual void on_update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click();
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
@ -320,8 +345,10 @@ private:
};
struct SourceDataSummary {
std::vector<BoundingBoxf3> bounding_boxes; // bounding boxes of convex hulls of individual volumes
#if !ENABLE_MODELINSTANCE_3D_ROTATION
float scaling_factor;
float rotation;
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d mesh_first_point;
};
@ -330,7 +357,19 @@ private:
std::vector<PlaneData> m_planes;
#if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
struct InstanceData
{
Vec3d position;
Vec3d rotation;
double scaling_factor;
InstanceData(const Vec3d& position, const Vec3d& rotation, double scaling_factor) : position(position), rotation(rotation), scaling_factor(scaling_factor) {}
};
std::vector<InstanceData> m_instances;
#else
Pointf3s m_instances_positions;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else
std::vector<Vec2d> m_instances_positions;
#endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -344,7 +383,11 @@ public:
explicit GLGizmoFlatten(GLCanvas3D& parent);
void set_flattening_data(const ModelObject* model_object);
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_flattening_rotation() const;
#else
Vec3d get_flattening_normal() const;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
protected:
virtual bool on_init();

View file

@ -1,4 +1,5 @@
#include "GUI.hpp"
#include "../AppController.hpp"
#include "WipeTowerDialog.hpp"
#include <assert.h>
@ -1405,4 +1406,23 @@ void desktop_open_datadir_folder()
#endif
}
namespace {
AppControllerPtr g_appctl;
}
AppControllerPtr get_appctl()
{
return g_appctl;
}
void set_cli_appctl()
{
g_appctl = std::make_shared<AppControllerCli>();
}
void set_gui_appctl()
{
g_appctl = std::make_shared<AppControllerGui>();
}
} }

View file

@ -42,6 +42,9 @@ class TabIface;
class PreviewIface;
class Print;
class GCodePreviewData;
class AppControllerBase;
using AppControllerPtr = std::shared_ptr<AppControllerBase>;
#define _(s) Slic3r::GUI::I18N::translate((s))
@ -129,6 +132,10 @@ ProgressStatusBar* get_progress_status_bar();
wxNotebook * get_tab_panel();
wxNotebook* get_tab_panel();
AppControllerPtr get_appctl();
void set_cli_appctl();
void set_gui_appctl();
const wxColour& get_label_clr_modified();
const wxColour& get_label_clr_sys();
const wxColour& get_label_clr_default();

View file

@ -1802,11 +1802,15 @@ void update_scale_values(double scaling_factor)
void update_rotation_values()
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
update_rotation_value((*m_objects)[m_selected_object_id]->instances.front()->get_rotation());
#else
auto og = get_optgroup(ogFrequentlyObjectSettings);
auto instance = (*m_objects)[m_selected_object_id]->instances.front();
og->set_value("rotation_x", 0);
og->set_value("rotation_y", 0);
og->set_value("rotation_z", int(Geometry::rad2deg(instance->rotation)));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
}
void update_rotation_value(double angle, Axis axis)
@ -1836,6 +1840,16 @@ void update_rotation_value(double angle, Axis axis)
og->set_value(axis_str, int(Geometry::rad2deg(angle)));
}
#if ENABLE_MODELINSTANCE_3D_ROTATION
void update_rotation_value(const Vec3d& rotation)
{
auto og = get_optgroup(ogFrequentlyObjectSettings);
og->set_value("rotation_x", int(Geometry::rad2deg(rotation(0))));
og->set_value("rotation_y", int(Geometry::rad2deg(rotation(1))));
og->set_value("rotation_z", int(Geometry::rad2deg(rotation(2))));
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_uniform_scaling(const bool uniform_scale)
{
g_is_uniform_scale = uniform_scale;

View file

@ -124,6 +124,9 @@ void update_scale_values(double scaling_factor);
void update_rotation_values();
// update rotation value after "gizmos"
void update_rotation_value(double angle, Axis axis);
#if ENABLE_MODELINSTANCE_3D_ROTATION
void update_rotation_value(const Vec3d& rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_uniform_scaling(const bool uniform_scale);
void on_begin_drag(wxDataViewEvent &event);

View file

@ -152,20 +152,20 @@ bool Preview::init(wxNotebook* notebook, DynamicPrintConfig* config, Print* prin
bind_event_handlers();
// sets colors for gcode preview extrusion roles
std::vector<std::string> extrusion_roles_colors = {
"FFFF66", // Perimeter
"FFA500", // External perimeter
"0000FF", // Overhang perimeter
"B1302A", // Internal infill
"D732D7", // Solid infill
"FF1A1A", // Top solid infill
"9999FF", // Bridge infill
"FFFFFF", // Gap fill
"845321", // Skirt
"00FF00", // Support material
"008000", // Support material interface
"B3E3AB", // Wipe tower
"28CC94" // Custom
std::vector<std::string> extrusion_roles_colors = {
"Perimeter", "FFFF66",
"External perimeter", "FFA500",
"Overhang perimeter", "0000FF",
"Internal infill", "B1302A",
"Solid infill", "D732D7",
"Top solid infill", "FF1A1A",
"Bridge infill", "9999FF",
"Gap fill", "FFFFFF",
"Skirt", "845321",
"Support material", "00FF00",
"Support material interface", "008000",
"Wipe tower", "B3E3AB",
"Custom", "28CC94"
};
m_gcode_preview_data->set_extrusion_paths_colors(extrusion_roles_colors);

View file

@ -14,31 +14,31 @@ public:
using CancelFn = std::function<void(void)>; // Cancel function signature.
private:
float state_ = .0f, max_ = 1.f, step_;
CancelFn cancelfunc_ = [](){};
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 max_; }
float max() const { return m_max; }
/// Get the current progress state
float state() const { return state_; }
float state() const { return m_state; }
/// Set the maximum of the progress range
virtual void max(float maxval) { max_ = maxval; }
virtual void max(float maxval) { m_max = maxval; }
/// Set the current state of the progress.
virtual void state(float val) { state_ = val; }
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) {
step_ = max_ / statenum;
m_step = m_max / statenum;
}
/// Message shown on the next status update.
@ -51,13 +51,13 @@ public:
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()) { cancelfunc_ = func; }
virtual void on_cancel(CancelFn func = CancelFn()) { m_cancelfunc = func; }
/**
* Explicitly shut down the progress indicator and call the associated
* callback.
*/
virtual void cancel() { cancelfunc_(); }
virtual void cancel() { m_cancelfunc(); }
/// Convenience function to call message and status update in one function.
void update(float st, const std::string& msg) {

View file

@ -14,117 +14,117 @@ namespace Slic3r {
ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id):
self(new wxStatusBar(parent ? parent : GUI::get_main_frame(),
id == -1? wxID_ANY : id)),
timer_(new wxTimer(self)),
prog_ (new wxGauge(self,
m_timer(new wxTimer(self)),
m_prog (new wxGauge(self,
wxGA_HORIZONTAL,
100,
wxDefaultPosition,
wxDefaultSize)),
cancelbutton_(new wxButton(self,
m_cancelbutton(new wxButton(self,
-1,
"Cancel",
wxDefaultPosition,
wxDefaultSize))
{
prog_->Hide();
cancelbutton_->Hide();
m_prog->Hide();
m_cancelbutton->Hide();
self->SetFieldsCount(3);
int w[] = {-1, 150, 155};
self->SetStatusWidths(3, w);
self->Bind(wxEVT_TIMER, [this](const wxTimerEvent&) {
if (prog_->IsShown()) timer_->Stop();
if(is_busy()) prog_->Pulse();
if (m_prog->IsShown()) m_timer->Stop();
if(is_busy()) m_prog->Pulse();
});
self->Bind(wxEVT_SIZE, [this](wxSizeEvent& event){
wxRect rect;
self->GetFieldRect(1, rect);
auto offset = 0;
cancelbutton_->Move(rect.GetX() + offset, rect.GetY() + offset);
cancelbutton_->SetSize(rect.GetWidth() - offset, rect.GetHeight());
m_cancelbutton->Move(rect.GetX() + offset, rect.GetY() + offset);
m_cancelbutton->SetSize(rect.GetWidth() - offset, rect.GetHeight());
self->GetFieldRect(2, rect);
prog_->Move(rect.GetX() + offset, rect.GetY() + offset);
prog_->SetSize(rect.GetWidth() - offset, rect.GetHeight());
m_prog->Move(rect.GetX() + offset, rect.GetY() + offset);
m_prog->SetSize(rect.GetWidth() - offset, rect.GetHeight());
event.Skip();
});
cancelbutton_->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) {
if(cancel_cb_) cancel_cb_();
m_cancelbutton->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) {
if(m_cancel_cb) m_cancel_cb();
m_perl_cancel_callback.call();
cancelbutton_->Hide();
m_cancelbutton->Hide();
});
}
ProgressStatusBar::~ProgressStatusBar() {
if(timer_->IsRunning()) timer_->Stop();
if(m_timer->IsRunning()) m_timer->Stop();
}
int ProgressStatusBar::get_progress() const
{
return prog_->GetValue();
return m_prog->GetValue();
}
void ProgressStatusBar::set_progress(int val)
{
if(!prog_->IsShown()) show_progress(true);
if(!m_prog->IsShown()) show_progress(true);
if(val == prog_->GetRange()) {
prog_->SetValue(0);
if(val == m_prog->GetRange()) {
m_prog->SetValue(0);
show_progress(false);
} else {
prog_->SetValue(val);
m_prog->SetValue(val);
}
}
int ProgressStatusBar::get_range() const
{
return prog_->GetRange();
return m_prog->GetRange();
}
void ProgressStatusBar::set_range(int val)
{
if(val != prog_->GetRange()) {
prog_->SetRange(val);
if(val != m_prog->GetRange()) {
m_prog->SetRange(val);
}
}
void ProgressStatusBar::show_progress(bool show)
{
prog_->Show(show);
prog_->Pulse();
m_prog->Show(show);
m_prog->Pulse();
}
void ProgressStatusBar::start_busy(int rate)
{
busy_ = true;
m_busy = true;
show_progress(true);
if (!timer_->IsRunning()) {
timer_->Start(rate);
if (!m_timer->IsRunning()) {
m_timer->Start(rate);
}
}
void ProgressStatusBar::stop_busy()
{
timer_->Stop();
m_timer->Stop();
show_progress(false);
prog_->SetValue(0);
busy_ = false;
m_prog->SetValue(0);
m_busy = false;
}
void ProgressStatusBar::set_cancel_callback(ProgressStatusBar::CancelFn ccb) {
cancel_cb_ = ccb;
if(ccb) cancelbutton_->Show();
else cancelbutton_->Hide();
m_cancel_cb = ccb;
if(ccb) m_cancelbutton->Show();
else m_cancelbutton->Hide();
}
void ProgressStatusBar::run(int rate)
{
if(!timer_->IsRunning()) {
timer_->Start(rate);
if(!m_timer->IsRunning()) {
m_timer->Start(rate);
}
}
@ -141,12 +141,12 @@ void ProgressStatusBar::set_status_text(const wxString& txt)
void ProgressStatusBar::show_cancel_button()
{
cancelbutton_->Show();
m_cancelbutton->Show();
}
void ProgressStatusBar::hide_cancel_button()
{
cancelbutton_->Hide();
m_cancelbutton->Hide();
}
}

View file

@ -24,9 +24,9 @@ namespace Slic3r {
*/
class ProgressStatusBar {
wxStatusBar *self; // we cheat! It should be the base class but: perl!
wxTimer *timer_;
wxGauge *prog_;
wxButton *cancelbutton_;
wxTimer *m_timer;
wxGauge *m_prog;
wxButton *m_cancelbutton;
public:
/// Cancel callback function type
@ -42,7 +42,7 @@ public:
void show_progress(bool);
void start_busy(int = 100);
void stop_busy();
inline bool is_busy() const { return busy_; }
inline bool is_busy() const { return m_busy; }
void set_cancel_callback(CancelFn = CancelFn());
inline void remove_cancel_callback() { set_cancel_callback(); }
void run(int rate);
@ -55,8 +55,8 @@ public:
PerlCallback m_perl_cancel_callback;
private:
bool busy_ = false;
CancelFn cancel_cb_;
bool m_busy = false;
CancelFn m_cancel_cb;
};
namespace GUI {