Merge branch 'master' of https://github.com/Prusa3d/Slic3r
This commit is contained in:
commit
1e325f8374
28 changed files with 447 additions and 257 deletions
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -545,8 +545,8 @@ public:
|
|||
_NofitPolyPlacer& operator=(const _NofitPolyPlacer&) = default;
|
||||
|
||||
#ifndef BP2D_COMPILER_MSVC12 // MSVC2013 does not support default move ctors
|
||||
_NofitPolyPlacer(_NofitPolyPlacer&&) BP2D_NOEXCEPT = default;
|
||||
_NofitPolyPlacer& operator=(_NofitPolyPlacer&&) BP2D_NOEXCEPT = default;
|
||||
_NofitPolyPlacer(_NofitPolyPlacer&&) /*BP2D_NOEXCEPT*/ = default;
|
||||
_NofitPolyPlacer& operator=(_NofitPolyPlacer&&) /*BP2D_NOEXCEPT*/ = default;
|
||||
#endif
|
||||
|
||||
static inline double overfit(const Box& bb, const RawShape& bin) {
|
||||
|
|
|
@ -77,8 +77,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Unlocked observers/hints
|
||||
// Thread unsafe! Keep in mind you need to re-verify the result after locking!
|
||||
// Unlocked observer/hint. Thread unsafe! Keep in mind you need to re-verify the result after locking.
|
||||
size_t size_hint() const noexcept { return m_queue.size(); }
|
||||
|
||||
LockedConstPtr lock_read() const
|
||||
|
|
|
@ -135,11 +135,6 @@ objfunc(const PointImpl& bincenter,
|
|||
const ItemGroup& remaining
|
||||
)
|
||||
{
|
||||
using Coord = TCoord<PointImpl>;
|
||||
|
||||
static const double ROUNDNESS_RATIO = 0.5;
|
||||
static const double DENSITY_RATIO = 1.0 - ROUNDNESS_RATIO;
|
||||
|
||||
// We will treat big items (compared to the print bed) differently
|
||||
auto isBig = [bin_area](double a) {
|
||||
return a/bin_area > BIG_ITEM_TRESHOLD ;
|
||||
|
@ -629,11 +624,12 @@ BedShapeHint bedShape(const Polyline &bed) {
|
|||
avg_dist /= vertex_distances.size();
|
||||
|
||||
Circle ret(center, avg_dist);
|
||||
for (auto el: vertex_distances)
|
||||
for(auto el : vertex_distances)
|
||||
{
|
||||
if (abs(el - avg_dist) > 10 * SCALED_EPSILON)
|
||||
if (std::abs(el - avg_dist) > 10 * SCALED_EPSILON) {
|
||||
ret = Circle();
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -665,8 +661,6 @@ bool arrange(Model &model,
|
|||
std::function<void (unsigned)> progressind,
|
||||
std::function<bool ()> stopcondition)
|
||||
{
|
||||
using ArrangeResult = _IndexedPackGroup<PolygonImpl>;
|
||||
|
||||
bool ret = true;
|
||||
|
||||
// Get the 2D projected shapes with their 3D model instance pointers
|
||||
|
|
|
@ -722,6 +722,10 @@ public:
|
|||
return m_pad;
|
||||
}
|
||||
|
||||
void remove_pad() {
|
||||
m_pad = Pad();
|
||||
}
|
||||
|
||||
const Pad& pad() const { return m_pad; }
|
||||
|
||||
// WITHOUT THE PAD!!!
|
||||
|
@ -1729,6 +1733,11 @@ const TriangleMesh &SLASupportTree::get_pad() const
|
|||
return m_impl->pad().tmesh;
|
||||
}
|
||||
|
||||
void SLASupportTree::remove_pad()
|
||||
{
|
||||
m_impl->remove_pad();
|
||||
}
|
||||
|
||||
SLASupportTree::SLASupportTree(const PointSet &points,
|
||||
const EigenMesh3D& emesh,
|
||||
const SupportConfig &cfg,
|
||||
|
|
|
@ -164,6 +164,8 @@ public:
|
|||
/// Get the pad geometry
|
||||
const TriangleMesh& get_pad() const;
|
||||
|
||||
void remove_pad();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -107,7 +107,8 @@ PointSet normals(const PointSet& points, const EigenMesh3D& emesh,
|
|||
// structure
|
||||
EigenMesh3D mesh;
|
||||
Eigen::VectorXi SVI, SVJ;
|
||||
igl::remove_duplicate_vertices(emesh.V, emesh.F, 1e-6,
|
||||
static const double dEPS = 1e-6;
|
||||
igl::remove_duplicate_vertices(emesh.V, emesh.F, dEPS,
|
||||
mesh.V, SVI, SVJ, mesh.F);
|
||||
|
||||
igl::point_mesh_squared_distance( points, mesh.V, mesh.F, dists, I, C);
|
||||
|
@ -155,6 +156,7 @@ PointSet normals(const PointSet& points, const EigenMesh3D& emesh,
|
|||
ia = trindex(0); ib = trindex(2);
|
||||
}
|
||||
|
||||
// vector for the neigboring triangles including the detected one.
|
||||
std::vector<Vec3i> neigh;
|
||||
if(ic >= 0) { // The point is right on a vertex of the triangle
|
||||
for(int n = 0; n < mesh.F.rows(); ++n) {
|
||||
|
@ -175,17 +177,32 @@ PointSet normals(const PointSet& points, const EigenMesh3D& emesh,
|
|||
}
|
||||
}
|
||||
|
||||
if(!neigh.empty()) { // there were neighbors to count with
|
||||
// Calculate the normals for the neighboring triangles
|
||||
std::vector<Vec3d> neighnorms; neighnorms.reserve(neigh.size());
|
||||
for(const Vec3i& tri : neigh) {
|
||||
const Vec3d& pt1 = mesh.V.row(tri(0));
|
||||
const Vec3d& pt2 = mesh.V.row(tri(1));
|
||||
const Vec3d& pt3 = mesh.V.row(tri(2));
|
||||
Eigen::Vector3d U = pt2 - pt1;
|
||||
Eigen::Vector3d V = pt3 - pt1;
|
||||
neighnorms.emplace_back(U.cross(V).normalized());
|
||||
}
|
||||
|
||||
// Throw out duplicates. They would case trouble with summing.
|
||||
auto lend = std::unique(neighnorms.begin(), neighnorms.end(),
|
||||
[](const Vec3d& n1, const Vec3d& n2) {
|
||||
// Compare normals for equivalence. This is controvers stuff.
|
||||
// We will go for the third significant digit precision.
|
||||
auto deq = [](double a, double b) { return std::abs(a-b) < 1e-3; };
|
||||
return deq(n1(X), n2(X)) && deq(n1(Y), n2(Y)) && deq(n1(Z), n2(Z));
|
||||
});
|
||||
|
||||
if(!neighnorms.empty()) { // there were neighbors to count with
|
||||
// sum up the normals and then normalize the result again.
|
||||
// This unification seems to be enough.
|
||||
Vec3d sumnorm(0, 0, 0);
|
||||
for(const Vec3i& tri : neigh) {
|
||||
const Vec3d& pt1 = mesh.V.row(tri(0));
|
||||
const Vec3d& pt2 = mesh.V.row(tri(1));
|
||||
const Vec3d& pt3 = mesh.V.row(tri(2));
|
||||
Eigen::Vector3d U = pt2 - pt1;
|
||||
Eigen::Vector3d V = pt3 - pt1;
|
||||
sumnorm += U.cross(V).normalized();
|
||||
}
|
||||
sumnorm /= neigh.size();
|
||||
sumnorm = std::accumulate(neighnorms.begin(), lend, sumnorm);
|
||||
sumnorm.normalize();
|
||||
ret.row(i) = sumnorm;
|
||||
}
|
||||
else { // point lies safely within its triangle
|
||||
|
|
|
@ -560,9 +560,13 @@ void SLAPrint::process()
|
|||
// and before the supports had been sliced. (or the slicing has to be
|
||||
// repeated)
|
||||
|
||||
if(po.m_config.pad_enable.getBool() &&
|
||||
po.m_supportdata &&
|
||||
po.m_supportdata->support_tree_ptr)
|
||||
if(!po.m_supportdata || !po.m_supportdata->support_tree_ptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Uninitialized support data at "
|
||||
<< "pad creation.";
|
||||
return;
|
||||
}
|
||||
|
||||
if(po.m_config.pad_enable.getBool())
|
||||
{
|
||||
double wt = po.m_config.pad_wall_thickness.getFloat();
|
||||
double h = po.m_config.pad_wall_height.getFloat();
|
||||
|
@ -586,6 +590,8 @@ void SLAPrint::process()
|
|||
|
||||
pcfg.throw_on_cancel = thrfn;
|
||||
po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg);
|
||||
} else {
|
||||
po.m_supportdata->support_tree_ptr->remove_pad();
|
||||
}
|
||||
|
||||
po.throw_if_canceled();
|
||||
|
@ -866,6 +872,7 @@ void SLAPrint::process()
|
|||
if(po->m_stepmask[currentstep] && po->set_started(currentstep)) {
|
||||
report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]);
|
||||
pobj_program[currentstep](*po);
|
||||
throw_if_canceled();
|
||||
po->set_done(currentstep);
|
||||
}
|
||||
|
||||
|
@ -891,6 +898,7 @@ void SLAPrint::process()
|
|||
{
|
||||
report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]);
|
||||
print_program[currentstep]();
|
||||
throw_if_canceled();
|
||||
set_done(currentstep);
|
||||
}
|
||||
|
||||
|
|
|
@ -1920,8 +1920,7 @@ void GLModel::render() const
|
|||
if (m_useVBOs)
|
||||
render_VBOs();
|
||||
else
|
||||
{
|
||||
}
|
||||
render_legacy();
|
||||
}
|
||||
|
||||
void GLModel::render_VBOs() const
|
||||
|
@ -1949,6 +1948,25 @@ void GLModel::render_VBOs() const
|
|||
::glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void GLModel::render_legacy() const
|
||||
{
|
||||
::glEnable(GL_LIGHTING);
|
||||
::glEnable(GL_BLEND);
|
||||
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
::glCullFace(GL_BACK);
|
||||
::glEnableClientState(GL_VERTEX_ARRAY);
|
||||
::glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
m_volume.render_legacy();
|
||||
|
||||
::glDisableClientState(GL_VERTEX_ARRAY);
|
||||
::glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
::glDisable(GL_BLEND);
|
||||
::glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
bool GLArrow::on_init(bool useVBOs)
|
||||
{
|
||||
Pointf3s vertices;
|
||||
|
|
|
@ -611,6 +611,7 @@ protected:
|
|||
|
||||
private:
|
||||
void render_VBOs() const;
|
||||
void render_legacy() const;
|
||||
};
|
||||
|
||||
class GLArrow : public GLModel
|
||||
|
|
|
@ -84,26 +84,7 @@ void BackgroundSlicingProcess::process_fff()
|
|||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
m_print->set_status(100, "G-code file exported to " + export_path);
|
||||
} else if (! m_upload_job.empty()) {
|
||||
// A print host upload job has been scheduled
|
||||
|
||||
// XXX: is fs::path::string() right?
|
||||
|
||||
// Generate a unique temp path to which the gcode is copied
|
||||
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
|
||||
/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode");
|
||||
|
||||
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
|
||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||
}
|
||||
|
||||
m_print->set_status(95, "Running post-processing scripts");
|
||||
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
||||
m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str());
|
||||
|
||||
m_upload_job.upload_data.source_path = std::move(source_path);
|
||||
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
|
||||
GUI::wxGetApp().printhost_job_queue().enqueue(std::move(m_upload_job));
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, "Slicing complete");
|
||||
}
|
||||
|
@ -170,6 +151,10 @@ void BackgroundSlicingProcess::process_sla()
|
|||
if (! m_export_path.empty()) {
|
||||
m_sla_print->export_raster<SLAZipFmt>(m_export_path);
|
||||
m_print->set_status(100, "Zip file exported to " + m_export_path);
|
||||
} else if (! m_upload_job.empty()) {
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, "Slicing complete");
|
||||
}
|
||||
this->set_step_done(bspsGCodeFinalize);
|
||||
}
|
||||
|
@ -440,4 +425,35 @@ bool BackgroundSlicingProcess::invalidate_all_steps()
|
|||
return m_step_state.invalidate_all([this](){ this->stop_internal(); });
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::prepare_upload()
|
||||
{
|
||||
// A print host upload job has been scheduled, enqueue it to the printhost job queue
|
||||
|
||||
// XXX: is fs::path::string() right?
|
||||
|
||||
// Generate a unique temp path to which the gcode/zip file is copied/exported
|
||||
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
|
||||
/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode");
|
||||
|
||||
if (m_print == m_fff_print) {
|
||||
m_print->set_status(95, "Running post-processing scripts");
|
||||
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
||||
|
||||
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
|
||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||
}
|
||||
|
||||
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
} else {
|
||||
m_sla_print->export_raster<SLAZipFmt>(source_path.string());
|
||||
// TODO: Also finalize upload path like with FFF when there are statistics for SLA print
|
||||
}
|
||||
|
||||
m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str());
|
||||
|
||||
m_upload_job.upload_data.source_path = std::move(source_path);
|
||||
|
||||
GUI::wxGetApp().printhost_job_queue().enqueue(std::move(m_upload_job));
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
@ -167,6 +167,7 @@ private:
|
|||
bool invalidate_all_steps();
|
||||
// If the background processing stop was requested, throw CanceledException.
|
||||
void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); }
|
||||
void prepare_upload();
|
||||
|
||||
// wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue.
|
||||
int m_event_slicing_completed_id = 0;
|
||||
|
|
|
@ -3830,7 +3830,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
|||
, m_legend_texture_enabled(false)
|
||||
, m_picking_enabled(false)
|
||||
, m_moving_enabled(false)
|
||||
, m_shader_enabled(false)
|
||||
, m_dynamic_background_enabled(false)
|
||||
, m_multisample_allowed(false)
|
||||
, m_regenerate_volumes(true)
|
||||
|
@ -4144,11 +4143,6 @@ void GLCanvas3D::enable_toolbar(bool enable)
|
|||
m_toolbar.set_enabled(enable);
|
||||
}
|
||||
|
||||
void GLCanvas3D::enable_shader(bool enable)
|
||||
{
|
||||
m_shader_enabled = enable;
|
||||
}
|
||||
|
||||
void GLCanvas3D::enable_force_zoom_to_bed(bool enable)
|
||||
{
|
||||
m_force_zoom_to_bed_enabled = enable;
|
||||
|
@ -6322,9 +6316,7 @@ void GLCanvas3D::_render_objects() const
|
|||
::glEnable(GL_LIGHTING);
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
|
||||
if (!m_shader_enabled)
|
||||
_render_volumes(false);
|
||||
else if (m_use_VBOs)
|
||||
if (m_use_VBOs)
|
||||
{
|
||||
if (m_picking_enabled)
|
||||
{
|
||||
|
|
|
@ -850,7 +850,6 @@ private:
|
|||
bool m_legend_texture_enabled;
|
||||
bool m_picking_enabled;
|
||||
bool m_moving_enabled;
|
||||
bool m_shader_enabled;
|
||||
bool m_dynamic_background_enabled;
|
||||
bool m_multisample_allowed;
|
||||
bool m_regenerate_volumes;
|
||||
|
@ -950,7 +949,6 @@ public:
|
|||
void enable_moving(bool enable);
|
||||
void enable_gizmos(bool enable);
|
||||
void enable_toolbar(bool enable);
|
||||
void enable_shader(bool enable);
|
||||
void enable_force_zoom_to_bed(bool enable);
|
||||
void enable_dynamic_background(bool enable);
|
||||
void allow_multisample(bool allow);
|
||||
|
|
|
@ -70,7 +70,6 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba
|
|||
m_canvas->set_config(config);
|
||||
m_canvas->enable_gizmos(true);
|
||||
m_canvas->enable_toolbar(true);
|
||||
m_canvas->enable_shader(true);
|
||||
m_canvas->enable_force_zoom_to_bed(true);
|
||||
|
||||
#if !ENABLE_IMGUI
|
||||
|
@ -257,7 +256,6 @@ bool Preview::init(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundS
|
|||
_3DScene::add_canvas(m_canvas_widget);
|
||||
m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
|
||||
m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
|
||||
m_canvas->enable_shader(true);
|
||||
m_canvas->set_config(m_config);
|
||||
m_canvas->set_process(process);
|
||||
m_canvas->enable_legend_texture(true);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "libslic3r/Utils.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include <wx/scrolwin.h>
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -19,41 +20,46 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
|
||||
// fonts
|
||||
wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold();
|
||||
head_font.SetPointSize(19);
|
||||
|
||||
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
font.SetPointSize(10);
|
||||
wxFont bold_font = font.Bold();
|
||||
#ifdef __WXOSX__
|
||||
font.SetPointSize(12);
|
||||
bold_font.SetPointSize(14);
|
||||
#endif /*__WXOSX__*/
|
||||
head_font.SetPointSize(14);
|
||||
#else
|
||||
head_font.SetPointSize(12);
|
||||
#endif // __WXOSX__
|
||||
|
||||
const wxFont& font = wxGetApp().small_font();
|
||||
const wxFont& bold_font = wxGetApp().bold_font();
|
||||
|
||||
fill_shortcuts();
|
||||
|
||||
auto panel = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(500, 600));
|
||||
panel->SetScrollbars(0, 20, 1, 2);
|
||||
auto sizer = new wxBoxSizer(wxVERTICAL);
|
||||
panel->SetSizer(sizer);
|
||||
auto panel = new wxPanel(this);
|
||||
auto main_grid_sizer = new wxFlexGridSizer(2, 10, 10);
|
||||
panel->SetSizer(main_grid_sizer);
|
||||
main_sizer->Add(panel, 1, wxEXPAND | wxALL, 0);
|
||||
|
||||
wxBoxSizer* l_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_grid_sizer->Add(l_sizer, 0);
|
||||
|
||||
wxBoxSizer* r_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_grid_sizer->Add(r_sizer, 0);
|
||||
|
||||
for (auto& sc : m_full_shortcuts)
|
||||
{
|
||||
auto sizer = sc.first == _(L("Main Shortcuts")) ? l_sizer : r_sizer;
|
||||
wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(hsizer, 0, wxEXPAND | wxTOP, 25);
|
||||
sizer->Add(hsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
|
||||
|
||||
// logo
|
||||
auto *logo = new wxStaticBitmap(panel, wxID_ANY, logo_bmp);
|
||||
hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 15);
|
||||
|
||||
// head
|
||||
wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(400,-1));
|
||||
wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(200,-1));
|
||||
head->SetFont(head_font);
|
||||
hsizer->Add(head, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
// Shortcuts list
|
||||
auto grid_sizer = new wxFlexGridSizer(2, 10, 25);
|
||||
sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT | wxTOP, 10);
|
||||
auto grid_sizer = new wxFlexGridSizer(2, 5, 15);
|
||||
sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT| wxRIGHT, 15);
|
||||
|
||||
for (auto pair : sc.second)
|
||||
{
|
||||
|
@ -69,9 +75,9 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
|
||||
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK);
|
||||
|
||||
this->SetEscapeId(wxID_CLOSE);
|
||||
this->SetEscapeId(wxID_OK);
|
||||
this->Bind(wxEVT_BUTTON, &KBShortcutsDialog::onCloseDialog, this, wxID_OK);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 15);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 15);
|
||||
|
||||
this->Bind(wxEVT_LEFT_DOWN, &KBShortcutsDialog::onCloseDialog, this);
|
||||
|
||||
|
@ -81,32 +87,40 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
|
||||
void KBShortcutsDialog::fill_shortcuts()
|
||||
{
|
||||
#ifdef __WXOSX__
|
||||
const std::string ctrl = "Cmd+"; // #ys_FIXME_cmd_smb // Change it for the accorded symbol
|
||||
const std::string alt = "Alt+"; // #ys_FIXME_cmd_smb // Change it for the accorded symbol
|
||||
#else
|
||||
const std::string ctrl = "Ctrl+";
|
||||
const std::string alt = "Alt+";
|
||||
#endif // __WXOSX__
|
||||
|
||||
Shortcuts main_shortcuts;
|
||||
main_shortcuts.reserve(25);
|
||||
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+O", L("Open project STL/OBJ/AMF/3MF with config, delete bed")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+I", L("Import STL//OBJ/AMF/3MF without config, keep bed")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+L", L("Load Config from .ini/amf/3mf/gcode")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+Alt+L", L("Load Config from .ini/amf/3mf/gcode and merge")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+G", L("Export Gcode")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+S", L("Save project (3MF)")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+R", L("(Re)slice")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+U", L("Quick slice")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+Alt+U", L("Quick slice and Save as")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+Shift+U", L("Repeat last quick slice")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+1", L("Select Plater Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+2", L("Select Print Settings Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+3", L("Select Filament Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+4", L("Select Printer Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+5", L("Switch to 3D")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+6", L("Switch to Preview")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+P", L("Preferences")));
|
||||
main_shortcuts.push_back(Shortcut("0-6", L("Camera view ")));
|
||||
main_shortcuts.push_back(Shortcut("+", L("Add Instance to selected object ")));
|
||||
main_shortcuts.push_back(Shortcut("-", L("Remove Instance from selected object")));
|
||||
main_shortcuts.push_back(Shortcut("?", L("Show keyboard shortcuts list")));
|
||||
main_shortcuts.push_back(Shortcut("PgUp/PgDn", L("Switch between 3D and Preview")));
|
||||
main_shortcuts.push_back(Shortcut("Shift+LeftMouse",L("Select multiple object/Move multiple object")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"O" ,L("Open project STL/OBJ/AMF/3MF with config, delete bed")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"I" ,L("Import STL//OBJ/AMF/3MF without config, keep bed")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"L" ,L("Load Config from .ini/amf/3mf/gcode")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"G" ,L("Export Gcode")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"S" ,L("Save project (3MF)")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+alt+"L" ,L("Load Config from .ini/amf/3mf/gcode and merge")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"R" ,L("(Re)slice")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"U" ,L("Quick slice")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"Shift+U" ,L("Repeat last quick slice")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"1" ,L("Select Plater Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+alt+"U" ,L("Quick slice and Save as")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"2" ,L("Select Print Settings Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"3" ,L("Select Filament Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"4" ,L("Select Printer Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"5" ,L("Switch to 3D")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"6" ,L("Switch to Preview")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"P" ,L("Preferences")));
|
||||
main_shortcuts.push_back(Shortcut("0-6" ,L("Camera view ")));
|
||||
main_shortcuts.push_back(Shortcut("+" ,L("Add Instance to selected object ")));
|
||||
main_shortcuts.push_back(Shortcut("-" ,L("Remove Instance from selected object")));
|
||||
main_shortcuts.push_back(Shortcut("?" ,L("Show keyboard shortcuts list")));
|
||||
main_shortcuts.push_back(Shortcut("PgUp/PgDn" ,L("Switch between 3D and Preview")));
|
||||
main_shortcuts.push_back(Shortcut("Shift+LeftMouse" ,L("Select multiple object/Move multiple object")));
|
||||
|
||||
m_full_shortcuts.emplace(_(L("Main Shortcuts")), main_shortcuts);
|
||||
|
||||
|
@ -115,9 +129,9 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||
plater_shortcuts.reserve(20);
|
||||
|
||||
plater_shortcuts.push_back(Shortcut("A", L("Arrange")));
|
||||
plater_shortcuts.push_back(Shortcut("Ctrl+A", L("Select All objects")));
|
||||
plater_shortcuts.push_back(Shortcut(ctrl+"A", L("Select All objects")));
|
||||
plater_shortcuts.push_back(Shortcut("Del", L("Delete selected")));
|
||||
plater_shortcuts.push_back(Shortcut("Ctrl+Del", L("Delete all")));
|
||||
plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete all")));
|
||||
plater_shortcuts.push_back(Shortcut("M", L("Gizmo move")));
|
||||
plater_shortcuts.push_back(Shortcut("S", L("Gizmo scale")));
|
||||
plater_shortcuts.push_back(Shortcut("R", L("Gizmo rotate")));
|
||||
|
|
|
@ -376,7 +376,7 @@ void MainFrame::init_menubar()
|
|||
|
||||
windowMenu->AppendSeparator();
|
||||
append_menu_item(windowMenu, wxID_ANY, L("Print Host Upload Queue"), L("Display the Print Host Upload Queue window"),
|
||||
[this](wxCommandEvent&) { m_printhost_queue_dlg->ShowModal(); }, "arrow_up.png");
|
||||
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "arrow_up.png");
|
||||
}
|
||||
|
||||
// View menu
|
||||
|
|
|
@ -1132,7 +1132,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
this->canvas3D->set_config(config);
|
||||
this->canvas3D->enable_gizmos(true);
|
||||
this->canvas3D->enable_toolbar(true);
|
||||
this->canvas3D->enable_shader(true);
|
||||
this->canvas3D->enable_force_zoom_to_bed(true);
|
||||
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
|
||||
|
@ -1162,9 +1161,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
hsizer->Add(sidebar, 0, wxEXPAND | wxLEFT | wxRIGHT, 0);
|
||||
q->SetSizer(hsizer);
|
||||
|
||||
#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
set_current_panel(view3D);
|
||||
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
//#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
// set_current_panel(view3D);
|
||||
//#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
|
||||
init_object_menu();
|
||||
|
||||
|
@ -1251,6 +1250,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
|
||||
update_ui_from_settings();
|
||||
q->Layout();
|
||||
|
||||
#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
set_current_panel(view3D);
|
||||
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
}
|
||||
|
||||
void Plater::priv::update(bool force_full_scene_refresh)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <wx/debug.h>
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
|
@ -59,7 +60,8 @@ bool PrintHostSendDialog::start_print() const
|
|||
|
||||
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event);
|
||||
|
||||
PrintHostQueueDialog::Event::Event(wxEventType eventType, int winid, size_t job_id)
|
||||
: wxEvent(winid, eventType)
|
||||
|
@ -87,6 +89,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
|
|||
: wxDialog(parent, wxID_ANY, _(L("Print host upload queue")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
, on_progress_evt(this, EVT_PRINTHOST_PROGRESS, &PrintHostQueueDialog::on_progress, this)
|
||||
, on_error_evt(this, EVT_PRINTHOST_ERROR, &PrintHostQueueDialog::on_error, this)
|
||||
, on_cancel_evt(this, EVT_PRINTHOST_CANCEL, &PrintHostQueueDialog::on_cancel, this)
|
||||
{
|
||||
enum { HEIGHT = 800, WIDTH = 400, SPACING = 5 };
|
||||
|
||||
|
@ -95,22 +98,47 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
|
|||
auto *topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
job_list = new wxDataViewListCtrl(this, wxID_ANY);
|
||||
// Note: Keep these in sync with Column
|
||||
job_list->AppendTextColumn("ID", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendProgressColumn("Progress", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("Status", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("Host", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("Filename", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("error_message", wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN);
|
||||
|
||||
auto *btnsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto *btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected"))); // TODO: enable based on status ("show error" for failed jobs)
|
||||
btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected")));
|
||||
btn_cancel->Disable();
|
||||
btn_error = new wxButton(this, wxID_ANY, _(L("Show error message")));
|
||||
btn_error->Disable();
|
||||
auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close")));
|
||||
btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING);
|
||||
btnsizer->Add(btn_error, 0);
|
||||
btnsizer->AddStretchSpacer();
|
||||
btnsizer->Add(btn_close);
|
||||
|
||||
topsizer->Add(job_list, 1, wxEXPAND | wxBOTTOM, SPACING);
|
||||
topsizer->Add(btnsizer, 0, wxEXPAND);
|
||||
SetSizer(topsizer);
|
||||
|
||||
job_list->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent&) { on_list_select(); });
|
||||
|
||||
btn_cancel->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
int selected = job_list->GetSelectedRow();
|
||||
if (selected == wxNOT_FOUND) { return; }
|
||||
|
||||
const JobState state = get_state(selected);
|
||||
if (state < ST_ERROR) {
|
||||
// TODO: cancel
|
||||
GUI::wxGetApp().printhost_job_queue().cancel(selected);
|
||||
}
|
||||
});
|
||||
|
||||
btn_error->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
int selected = job_list->GetSelectedRow();
|
||||
if (selected == wxNOT_FOUND) { return; }
|
||||
GUI::show_error(nullptr, job_list->GetTextValue(selected, COL_ERRORMSG));
|
||||
});
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::append_job(const PrintHostJob &job)
|
||||
|
@ -123,31 +151,83 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job)
|
|||
fields.push_back(wxVariant(_(L("Enqueued"))));
|
||||
fields.push_back(wxVariant(job.printhost->get_host()));
|
||||
fields.push_back(wxVariant(job.upload_data.upload_path.string()));
|
||||
job_list->AppendItem(fields);
|
||||
fields.push_back(wxVariant(""));
|
||||
job_list->AppendItem(fields, static_cast<wxUIntPtr>(ST_NEW));
|
||||
}
|
||||
|
||||
PrintHostQueueDialog::JobState PrintHostQueueDialog::get_state(int idx)
|
||||
{
|
||||
wxCHECK_MSG(idx >= 0 && idx < job_list->GetItemCount(), ST_ERROR, "Out of bounds access to job list");
|
||||
return static_cast<JobState>(job_list->GetItemData(job_list->RowToItem(idx)));
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::set_state(int idx, JobState state)
|
||||
{
|
||||
wxCHECK_RET(idx >= 0 && idx < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
job_list->SetItemData(job_list->RowToItem(idx), static_cast<wxUIntPtr>(state));
|
||||
|
||||
switch (state) {
|
||||
case ST_NEW: job_list->SetValue(_(L("Enqueued")), idx, COL_STATUS); break;
|
||||
case ST_PROGRESS: job_list->SetValue(_(L("Uploading")), idx, COL_STATUS); break;
|
||||
case ST_ERROR: job_list->SetValue(_(L("Error")), idx, COL_STATUS); break;
|
||||
case ST_CANCELLING: job_list->SetValue(_(L("Cancelling")), idx, COL_STATUS); break;
|
||||
case ST_CANCELLED: job_list->SetValue(_(L("Cancelled")), idx, COL_STATUS); break;
|
||||
case ST_COMPLETED: job_list->SetValue(_(L("Completed")), idx, COL_STATUS); break;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_list_select()
|
||||
{
|
||||
int selected = job_list->GetSelectedRow();
|
||||
if (selected != wxNOT_FOUND) {
|
||||
const JobState state = get_state(selected);
|
||||
btn_cancel->Enable(state < ST_ERROR);
|
||||
btn_error->Enable(state == ST_ERROR);
|
||||
Layout();
|
||||
} else {
|
||||
btn_cancel->Disable();
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_progress(Event &evt)
|
||||
{
|
||||
wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
|
||||
const wxVariant status(evt.progress < 100 ? _(L("Uploading")) : _(L("Complete")));
|
||||
if (evt.progress < 100) {
|
||||
set_state(evt.job_id, ST_PROGRESS);
|
||||
job_list->SetValue(wxVariant(evt.progress), evt.job_id, COL_PROGRESS);
|
||||
} else {
|
||||
set_state(evt.job_id, ST_COMPLETED);
|
||||
job_list->SetValue(wxVariant(100), evt.job_id, COL_PROGRESS);
|
||||
}
|
||||
|
||||
job_list->SetValue(wxVariant(evt.progress), evt.job_id, 1);
|
||||
job_list->SetValue(status, evt.job_id, 2);
|
||||
on_list_select();
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_error(Event &evt)
|
||||
{
|
||||
wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
|
||||
job_list->SetValue(wxVariant(0), evt.job_id, 1);
|
||||
job_list->SetValue(wxVariant(_(L("Error"))), evt.job_id, 2);
|
||||
|
||||
// TODO: keep the error for repeated display
|
||||
set_state(evt.job_id, ST_ERROR);
|
||||
|
||||
auto errormsg = wxString::Format("%s\n%s", _(L("Error uploading to print host:")), evt.error);
|
||||
job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS);
|
||||
job_list->SetValue(wxVariant(errormsg), evt.job_id, COL_ERRORMSG); // Stashes the error message into a hidden column for later
|
||||
|
||||
on_list_select();
|
||||
|
||||
GUI::show_error(nullptr, std::move(errormsg));
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_cancel(Event &evt)
|
||||
{
|
||||
wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
|
||||
set_state(evt.job_id, ST_CANCELLED);
|
||||
job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS);
|
||||
|
||||
on_list_select();
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
|
|
@ -13,10 +13,12 @@
|
|||
#include "MsgDialog.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
|
||||
class wxButton;
|
||||
class wxTextCtrl;
|
||||
class wxCheckBox;
|
||||
class wxDataViewListCtrl;
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct PrintHostJob;
|
||||
|
@ -60,17 +62,43 @@ public:
|
|||
|
||||
void append_job(const PrintHostJob &job);
|
||||
private:
|
||||
enum Column {
|
||||
COL_ID,
|
||||
COL_PROGRESS,
|
||||
COL_STATUS,
|
||||
COL_HOST,
|
||||
COL_FILENAME,
|
||||
COL_ERRORMSG,
|
||||
};
|
||||
|
||||
enum JobState {
|
||||
ST_NEW,
|
||||
ST_PROGRESS,
|
||||
ST_ERROR,
|
||||
ST_CANCELLING,
|
||||
ST_CANCELLED,
|
||||
ST_COMPLETED,
|
||||
};
|
||||
|
||||
wxButton *btn_cancel;
|
||||
wxButton *btn_error;
|
||||
wxDataViewListCtrl *job_list;
|
||||
// Note: EventGuard prevents delivery of progress evts to a freed PrintHostQueueDialog
|
||||
EventGuard on_progress_evt;
|
||||
EventGuard on_error_evt;
|
||||
EventGuard on_cancel_evt;
|
||||
|
||||
JobState get_state(int idx);
|
||||
void set_state(int idx, JobState);
|
||||
void on_list_select();
|
||||
void on_progress(Event&);
|
||||
void on_error(Event&);
|
||||
void on_cancel(Event&);
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event);
|
||||
wxDECLARE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
||||
wxDECLARE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event);
|
||||
|
||||
|
||||
}}
|
||||
|
|
|
@ -116,7 +116,7 @@ SysInfoDialog::SysInfoDialog()
|
|||
buttons->Insert(0, btn_copy_to_clipboard, 0, wxLEFT, 5);
|
||||
btn_copy_to_clipboard->Bind(wxEVT_BUTTON, &SysInfoDialog::onCopyToClipboard, this);
|
||||
|
||||
this->SetEscapeId(wxID_CLOSE);
|
||||
this->SetEscapeId(wxID_OK);
|
||||
this->Bind(wxEVT_BUTTON, &SysInfoDialog::onCloseDialog, this, wxID_OK);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
|
||||
|
||||
|
|
|
@ -54,91 +54,46 @@ wxString Duet::get_test_failed_msg (wxString &msg) const
|
|||
return wxString::Format("%s: %s", _(L("Could not connect to Duet")), msg);
|
||||
}
|
||||
|
||||
// bool Duet::send_gcode(const std::string &filename) const
|
||||
// {
|
||||
// enum { PROGRESS_RANGE = 1000 };
|
||||
|
||||
// const auto errortitle = _(L("Error while uploading to the Duet"));
|
||||
// fs::path filepath(filename);
|
||||
|
||||
// GUI::PrintHostSendDialog send_dialog(filepath.filename());
|
||||
// if (send_dialog.ShowModal() != wxID_OK) { return false; }
|
||||
|
||||
// const bool print = send_dialog.start_print();
|
||||
// const auto upload_filepath = send_dialog.filename();
|
||||
// const auto upload_filename = upload_filepath.filename();
|
||||
// const auto upload_parent_path = upload_filepath.parent_path();
|
||||
|
||||
// wxProgressDialog progress_dialog(
|
||||
// _(L("Duet upload")),
|
||||
// _(L("Sending G-code file to Duet...")),
|
||||
// PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||
// progress_dialog.Pulse();
|
||||
|
||||
// wxString connect_msg;
|
||||
// if (!connect(connect_msg)) {
|
||||
// auto errormsg = wxString::Format("%s: %s", errortitle, connect_msg);
|
||||
// GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// bool res = true;
|
||||
|
||||
// auto upload_cmd = get_upload_url(upload_filepath.string());
|
||||
// BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filename: %2%, path: %3%, print: %4%, command: %5%")
|
||||
// % filepath.string()
|
||||
// % upload_filename.string()
|
||||
// % upload_parent_path.string()
|
||||
// % print
|
||||
// % upload_cmd;
|
||||
|
||||
// auto http = Http::post(std::move(upload_cmd));
|
||||
// http.set_post_body(filename)
|
||||
// .on_complete([&](std::string body, unsigned status) {
|
||||
// BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body;
|
||||
// progress_dialog.Update(PROGRESS_RANGE);
|
||||
|
||||
// int err_code = get_err_code_from_body(body);
|
||||
// if (err_code != 0) {
|
||||
// auto msg = format_error(body, L("Unknown error occured"), 0);
|
||||
// GUI::show_error(&progress_dialog, std::move(msg));
|
||||
// res = false;
|
||||
// } else if (print) {
|
||||
// wxString errormsg;
|
||||
// res = start_print(errormsg, upload_filepath.string());
|
||||
// if (!res) {
|
||||
// GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// .on_error([&](std::string body, std::string error, unsigned status) {
|
||||
// BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||
// auto errormsg = wxString::Format("%s: %s", errortitle, format_error(body, error, status));
|
||||
// GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
// res = false;
|
||||
// })
|
||||
// .on_progress([&](Http::Progress progress, bool &cancel) {
|
||||
// if (cancel) {
|
||||
// // Upload was canceled
|
||||
// res = false;
|
||||
// } else if (progress.ultotal > 0) {
|
||||
// int value = PROGRESS_RANGE * progress.ulnow / progress.ultotal;
|
||||
// cancel = !progress_dialog.Update(std::min(value, PROGRESS_RANGE - 1)); // Cap the value to prevent premature dialog closing
|
||||
// } else {
|
||||
// cancel = !progress_dialog.Pulse();
|
||||
// }
|
||||
// })
|
||||
// .perform_sync();
|
||||
|
||||
// disconnect();
|
||||
|
||||
// return res;
|
||||
// }
|
||||
|
||||
bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const
|
||||
{
|
||||
// XXX: TODO
|
||||
throw "unimplemented";
|
||||
wxString connect_msg;
|
||||
if (!connect(connect_msg)) {
|
||||
error_fn(std::move(connect_msg));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
|
||||
auto upload_cmd = get_upload_url(upload_data.upload_path.string());
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, print: %3%, command: %4%")
|
||||
% upload_data.source_path
|
||||
% upload_data.upload_path
|
||||
% upload_data.start_print
|
||||
% upload_cmd;
|
||||
|
||||
auto http = Http::post(std::move(upload_cmd));
|
||||
http.set_post_body(upload_data.source_path)
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body;
|
||||
})
|
||||
.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||
error_fn(format_error(body, error, status));
|
||||
res = false;
|
||||
})
|
||||
.on_progress([&](Http::Progress progress, bool &cancel) {
|
||||
prorgess_fn(std::move(progress), cancel);
|
||||
if (cancel) {
|
||||
// Upload was canceled
|
||||
BOOST_LOG_TRIVIAL(info) << "Duet: Upload canceled";
|
||||
res = false;
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
disconnect();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Duet::has_auto_discovery() const
|
||||
|
@ -241,20 +196,10 @@ std::string Duet::timestamp_str() const
|
|||
return std::string(buffer);
|
||||
}
|
||||
|
||||
wxString Duet::format_error(const std::string &body, const std::string &error, unsigned status)
|
||||
{
|
||||
if (status != 0) {
|
||||
auto wxbody = wxString::FromUTF8(body.data());
|
||||
return wxString::Format("HTTP %u: %s", status, wxbody);
|
||||
} else {
|
||||
return wxString::FromUTF8(error.data());
|
||||
}
|
||||
}
|
||||
|
||||
bool Duet::start_print(wxString &msg, const std::string &filename) const
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
|
||||
auto url = (boost::format("%1%rr_gcode?gcode=M32%%20\"%2%\"")
|
||||
% get_base_url()
|
||||
% Http::url_encode(filename)).str();
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
virtual bool has_auto_discovery() const;
|
||||
virtual bool can_test() const;
|
||||
virtual std::string get_host() const { return host; }
|
||||
|
||||
private:
|
||||
std::string host;
|
||||
std::string password;
|
||||
|
@ -38,7 +39,6 @@ private:
|
|||
void disconnect() const;
|
||||
bool start_print(wxString &msg, const std::string &filename) const;
|
||||
int get_err_code_from_body(const std::string &body) const;
|
||||
static wxString format_error(const std::string &body, const std::string &error, unsigned status);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -149,7 +149,9 @@ int Http::priv::xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_o
|
|||
self->progressfn(progress, cb_cancel);
|
||||
}
|
||||
|
||||
return self->cancel || cb_cancel;
|
||||
if (cb_cancel) { self->cancel = true; }
|
||||
|
||||
return self->cancel;
|
||||
}
|
||||
|
||||
int Http::priv::xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
|
@ -280,7 +282,7 @@ void Http::priv::http_perform()
|
|||
} else {
|
||||
long http_status = 0;
|
||||
::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);
|
||||
|
||||
|
||||
if (http_status >= 400) {
|
||||
if (errorfn) { errorfn(std::move(buffer), std::string(), http_status); }
|
||||
} else {
|
||||
|
|
|
@ -102,7 +102,7 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro
|
|||
auto url = make_url("api/files/local");
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("Octoprint: Uploading file %1% at %2%, filename: %3%, path: %4%, print: %5%")
|
||||
% upload_data.source_path.string()
|
||||
% upload_data.source_path
|
||||
% url
|
||||
% upload_filename.string()
|
||||
% upload_parent_path.string()
|
||||
|
@ -118,7 +118,6 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro
|
|||
})
|
||||
.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Octoprint: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||
// error_fn(std::move(body), std::move(error), status);
|
||||
error_fn(format_error(body, error, status));
|
||||
res = false;
|
||||
})
|
||||
|
@ -126,7 +125,7 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro
|
|||
prorgess_fn(std::move(progress), cancel);
|
||||
if (cancel) {
|
||||
// Upload was canceled
|
||||
BOOST_LOG_TRIVIAL(error) << "Octoprint: Upload canceled";
|
||||
BOOST_LOG_TRIVIAL(info) << "Octoprint: Upload canceled";
|
||||
res = false;
|
||||
}
|
||||
})
|
||||
|
@ -172,16 +171,6 @@ std::string OctoPrint::make_url(const std::string &path) const
|
|||
}
|
||||
}
|
||||
|
||||
wxString OctoPrint::format_error(const std::string &body, const std::string &error, unsigned status)
|
||||
{
|
||||
if (status != 0) {
|
||||
auto wxbody = wxString::FromUTF8(body.data());
|
||||
return wxString::Format("HTTP %u: %s", status, wxbody);
|
||||
} else {
|
||||
return wxString::FromUTF8(error.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SLAHost
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ private:
|
|||
|
||||
void set_auth(Http &http) const;
|
||||
std::string make_url(const std::string &path) const;
|
||||
static wxString format_error(const std::string &body, const std::string &error, unsigned status);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,16 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
|
|||
}
|
||||
}
|
||||
|
||||
wxString PrintHost::format_error(const std::string &body, const std::string &error, unsigned status) const
|
||||
{
|
||||
if (status != 0) {
|
||||
auto wxbody = wxString::FromUTF8(body.data());
|
||||
return wxString::Format("HTTP %u: %s", status, wxbody);
|
||||
} else {
|
||||
return wxString::FromUTF8(error.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct PrintHostJobQueue::priv
|
||||
{
|
||||
|
@ -49,6 +59,7 @@ struct PrintHostJobQueue::priv
|
|||
Channel<size_t> channel_cancels;
|
||||
size_t job_id = 0;
|
||||
int prev_progress = -1;
|
||||
fs::path source_to_remove;
|
||||
|
||||
std::thread bg_thread;
|
||||
bool bg_exit = false;
|
||||
|
@ -57,9 +68,14 @@ struct PrintHostJobQueue::priv
|
|||
|
||||
priv(PrintHostJobQueue *q) : q(q) {}
|
||||
|
||||
void emit_progress(int progress);
|
||||
void emit_error(wxString error);
|
||||
void emit_cancel(size_t id);
|
||||
void start_bg_thread();
|
||||
void bg_thread_main();
|
||||
void progress_fn(Http::Progress progress, bool &cancel);
|
||||
void remove_source(const fs::path &path);
|
||||
void remove_source();
|
||||
void perform_job(PrintHostJob the_job);
|
||||
};
|
||||
|
||||
|
@ -78,6 +94,24 @@ PrintHostJobQueue::~PrintHostJobQueue()
|
|||
}
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::emit_progress(int progress)
|
||||
{
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, progress);
|
||||
wxQueueEvent(queue_dialog, evt);
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::emit_error(wxString error)
|
||||
{
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, std::move(error));
|
||||
wxQueueEvent(queue_dialog, evt);
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::emit_cancel(size_t id)
|
||||
{
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_CANCEL, queue_dialog->GetId(), id);
|
||||
wxQueueEvent(queue_dialog, evt);
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::start_bg_thread()
|
||||
{
|
||||
if (bg_thread.joinable()) { return; }
|
||||
|
@ -96,21 +130,43 @@ void PrintHostJobQueue::priv::bg_thread_main()
|
|||
// Pick up jobs from the job channel:
|
||||
while (! bg_exit) {
|
||||
auto job = channel_jobs.pop(); // Sleeps in a cond var if there are no jobs
|
||||
source_to_remove = job.upload_data.source_path;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Received job: [%1%]: `%2%` -> `%3%`, cancelled: %4%")
|
||||
% job_id
|
||||
% job.upload_data.upload_path
|
||||
% job.printhost->get_host()
|
||||
% job.cancelled;
|
||||
|
||||
if (! job.cancelled) {
|
||||
perform_job(std::move(job));
|
||||
}
|
||||
|
||||
remove_source();
|
||||
job_id++;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, e.what());
|
||||
wxQueueEvent(queue_dialog, evt);
|
||||
emit_error(e.what());
|
||||
} catch (...) {
|
||||
wxTheApp->OnUnhandledException();
|
||||
emit_error("Unknown exception");
|
||||
}
|
||||
|
||||
// Cleanup leftover files, if any
|
||||
remove_source();
|
||||
auto jobs = channel_jobs.lock_rw();
|
||||
for (const PrintHostJob &job : *jobs) {
|
||||
remove_source(job.upload_data.source_path);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel)
|
||||
{
|
||||
if (cancel) {
|
||||
// When cancel is true from the start, Http indicates request has been cancelled
|
||||
emit_cancel(job_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bg_exit) {
|
||||
cancel = true;
|
||||
return;
|
||||
|
@ -125,48 +181,59 @@ void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel)
|
|||
if (cancel_id == job_id) {
|
||||
cancel = true;
|
||||
} else if (cancel_id > job_id) {
|
||||
jobs->at(cancel_id - job_id).cancelled = true;
|
||||
const size_t idx = cancel_id - job_id - 1;
|
||||
if (idx < jobs->size()) {
|
||||
jobs->at(idx).cancelled = true;
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue: Job id %1% cancelled") % cancel_id;
|
||||
emit_cancel(cancel_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cancels->clear();
|
||||
}
|
||||
|
||||
int gui_progress = progress.ultotal > 0 ? 100*progress.ulnow / progress.ultotal : 0;
|
||||
if (gui_progress != prev_progress) {
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, gui_progress);
|
||||
wxQueueEvent(queue_dialog, evt);
|
||||
prev_progress = gui_progress;
|
||||
if (! cancel) {
|
||||
int gui_progress = progress.ultotal > 0 ? 100*progress.ulnow / progress.ultotal : 0;
|
||||
if (gui_progress != prev_progress) {
|
||||
emit_progress(gui_progress);
|
||||
prev_progress = gui_progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::remove_source(const fs::path &path)
|
||||
{
|
||||
if (! path.empty()) {
|
||||
boost::system::error_code ec;
|
||||
fs::remove(path, ec);
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("PrintHostJobQueue: Error removing file `%1%`: %2%") % path % ec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::remove_source()
|
||||
{
|
||||
remove_source(source_to_remove);
|
||||
source_to_remove.clear();
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job)
|
||||
{
|
||||
if (bg_exit || the_job.empty()) { return; }
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Got job: `%1%` -> `%2%`")
|
||||
% the_job.upload_data.upload_path
|
||||
% the_job.printhost->get_host();
|
||||
|
||||
const fs::path gcode_path = the_job.upload_data.source_path;
|
||||
emit_progress(0); // Indicate the upload is starting
|
||||
|
||||
bool success = the_job.printhost->upload(std::move(the_job.upload_data),
|
||||
[this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); },
|
||||
[this](wxString error) {
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, std::move(error));
|
||||
wxQueueEvent(queue_dialog, evt);
|
||||
emit_error(std::move(error));
|
||||
}
|
||||
);
|
||||
|
||||
if (success) {
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, 100);
|
||||
wxQueueEvent(queue_dialog, evt);
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
fs::remove(gcode_path, ec);
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("PrintHostJobQueue: Error removing file `%1%`: %2%") % gcode_path % ec;
|
||||
emit_progress(100);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,5 +244,10 @@ void PrintHostJobQueue::enqueue(PrintHostJob job)
|
|||
p->channel_jobs.push(std::move(job));
|
||||
}
|
||||
|
||||
void PrintHostJobQueue::cancel(size_t id)
|
||||
{
|
||||
p->channel_cancels.push(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ public:
|
|||
virtual std::string get_host() const = 0;
|
||||
|
||||
static PrintHost* get_print_host(DynamicPrintConfig *config);
|
||||
|
||||
protected:
|
||||
virtual wxString format_error(const std::string &body, const std::string &error, unsigned status) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -55,6 +58,7 @@ struct PrintHostJob
|
|||
PrintHostJob(PrintHostJob &&other)
|
||||
: upload_data(std::move(other.upload_data))
|
||||
, printhost(std::move(other.printhost))
|
||||
, cancelled(other.cancelled)
|
||||
{}
|
||||
|
||||
PrintHostJob(DynamicPrintConfig *config)
|
||||
|
@ -66,6 +70,7 @@ struct PrintHostJob
|
|||
{
|
||||
upload_data = std::move(other.upload_data);
|
||||
printhost = std::move(other.printhost);
|
||||
cancelled = other.cancelled;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue