mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-22 22:24:01 -06:00
Merge branch 'master' into lm_tm_hollowing
This commit is contained in:
commit
b45e95877e
59 changed files with 3532 additions and 2470 deletions
|
@ -78,6 +78,9 @@ void AppConfig::set_defaults()
|
|||
if (get("remember_output_path").empty())
|
||||
set("remember_output_path", "1");
|
||||
|
||||
if (get("remember_output_path_removable").empty())
|
||||
set("remember_output_path_removable", "1");
|
||||
|
||||
if (get("use_custom_toolbar_size").empty())
|
||||
set("use_custom_toolbar_size", "0");
|
||||
|
||||
|
@ -388,7 +391,7 @@ void AppConfig::update_skein_dir(const std::string &dir)
|
|||
{
|
||||
this->set("recent", "skein_directory", dir);
|
||||
}
|
||||
|
||||
/*
|
||||
std::string AppConfig::get_last_output_dir(const std::string &alt) const
|
||||
{
|
||||
|
||||
|
@ -406,6 +409,26 @@ void AppConfig::update_last_output_dir(const std::string &dir)
|
|||
{
|
||||
this->set("", "last_output_path", dir);
|
||||
}
|
||||
*/
|
||||
std::string AppConfig::get_last_output_dir(const std::string& alt, const bool removable) const
|
||||
{
|
||||
std::string s1 = (removable ? "last_output_path_removable" : "last_output_path");
|
||||
std::string s2 = (removable ? "remember_output_path_removable" : "remember_output_path");
|
||||
const auto it = m_storage.find("");
|
||||
if (it != m_storage.end()) {
|
||||
const auto it2 = it->second.find(s1);
|
||||
const auto it3 = it->second.find(s2);
|
||||
if (it2 != it->second.end() && it3 != it->second.end() && !it2->second.empty() && it3->second == "1")
|
||||
return it2->second;
|
||||
}
|
||||
return alt;
|
||||
}
|
||||
|
||||
void AppConfig::update_last_output_dir(const std::string& dir, const bool removable)
|
||||
{
|
||||
this->set("", (removable ? "last_output_path_removable" : "last_output_path"), dir);
|
||||
}
|
||||
|
||||
|
||||
void AppConfig::reset_selections()
|
||||
{
|
||||
|
|
|
@ -102,8 +102,10 @@ public:
|
|||
void update_config_dir(const std::string &dir);
|
||||
void update_skein_dir(const std::string &dir);
|
||||
|
||||
std::string get_last_output_dir(const std::string &alt) const;
|
||||
void update_last_output_dir(const std::string &dir);
|
||||
//std::string get_last_output_dir(const std::string &alt) const;
|
||||
//void update_last_output_dir(const std::string &dir);
|
||||
std::string get_last_output_dir(const std::string& alt, const bool removable = false) const;
|
||||
void update_last_output_dir(const std::string &dir, const bool removable = false);
|
||||
|
||||
// reset the current print / filament / printer selections, so that
|
||||
// the PresetBundle::load_selections(const AppConfig &config) call will select
|
||||
|
|
|
@ -100,8 +100,23 @@ void BackgroundSlicingProcess::process_fff()
|
|||
//FIXME localize the messages
|
||||
// Perform the final post-processing of the export path by applying the print statistics over the file name.
|
||||
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
|
||||
if (copy_file(m_temp_output_path, export_path, GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path)) != 0)
|
||||
GUI::RemovableDriveManager::get_instance().update();
|
||||
bool with_check = GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path);
|
||||
int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check);
|
||||
if (with_check && copy_ret_val == -2)
|
||||
{
|
||||
std::string err_msg = "Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at " + export_path + ".tmp.";
|
||||
throw std::runtime_error(_utf8(L(err_msg)));
|
||||
}
|
||||
else if (copy_ret_val == -3)
|
||||
{
|
||||
std::string err_msg = "Renaming of the G-code after copying to the selected destination folder has failed. Current path is " + export_path + ".tmp. Please try exporting again.";
|
||||
throw std::runtime_error(_utf8(L(err_msg)));
|
||||
}
|
||||
else if ( copy_ret_val != 0)
|
||||
{
|
||||
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
|
||||
}
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
|
||||
|
|
|
@ -1702,6 +1702,9 @@ void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool i
|
|||
if (page->install && !install)
|
||||
page->select_all(false);
|
||||
page->install = install;
|
||||
// if some 3rd vendor is selected, select first printer for them
|
||||
if (install)
|
||||
page->printer_pickers[0]->select_one(0, true);
|
||||
page->Layout();
|
||||
}
|
||||
|
||||
|
@ -2020,7 +2023,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
|
|||
p->add_page(p->page_temps = new PageTemperatures(this));
|
||||
|
||||
// Pages for 3rd party vendors
|
||||
p->create_3rdparty_pages(); // Needs to ne done _before_ creating PageVendors
|
||||
p->create_3rdparty_pages(); // Needs to be done _before_ creating PageVendors
|
||||
p->add_page(p->page_vendors = new PageVendors(this));
|
||||
|
||||
p->load_pages();
|
||||
|
|
1766
src/slic3r/GUI/DoubleSlider.cpp
Normal file
1766
src/slic3r/GUI/DoubleSlider.cpp
Normal file
File diff suppressed because it is too large
Load diff
337
src/slic3r/GUI/DoubleSlider.hpp
Normal file
337
src/slic3r/GUI/DoubleSlider.hpp
Normal file
|
@ -0,0 +1,337 @@
|
|||
#ifndef slic3r_GUI_DoubleSlider_hpp_
|
||||
#define slic3r_GUI_DoubleSlider_hpp_
|
||||
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/window.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/dc.h>
|
||||
#include <wx/slider.h>
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
class wxMenu;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace DoubleSlider {
|
||||
|
||||
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
|
||||
* So, let use same value as a permissible error for layer height.
|
||||
*/
|
||||
static double epsilon() { return 0.0011;}
|
||||
|
||||
// custom message the slider sends to its parent to notify a tick-change:
|
||||
wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
|
||||
|
||||
enum SelectedSlider {
|
||||
ssUndef,
|
||||
ssLower,
|
||||
ssHigher
|
||||
};
|
||||
|
||||
enum IconFocus {
|
||||
ifNone,
|
||||
ifRevert,
|
||||
ifCog
|
||||
};
|
||||
|
||||
using t_mode = CustomGCode::Mode;
|
||||
|
||||
struct TickCode
|
||||
{
|
||||
bool operator<(const TickCode& other) const { return other.tick > this->tick; }
|
||||
bool operator>(const TickCode& other) const { return other.tick < this->tick; }
|
||||
|
||||
int tick = 0;
|
||||
std::string gcode = ColorChangeCode;
|
||||
int extruder = 0;
|
||||
std::string color;
|
||||
};
|
||||
|
||||
class TickCodeInfo
|
||||
{
|
||||
std::string custom_gcode;
|
||||
std::string pause_print_msg;
|
||||
bool m_suppress_plus = false;
|
||||
bool m_suppress_minus = false;
|
||||
|
||||
std::string get_color_for_tick(TickCode tick, const std::string& code, const int extruder);
|
||||
|
||||
public:
|
||||
std::set<TickCode> ticks {};
|
||||
t_mode mode = t_mode::SingleExtruder;
|
||||
|
||||
bool empty() const { return ticks.empty(); }
|
||||
void set_pause_print_msg(const std::string& message) { pause_print_msg = message; }
|
||||
|
||||
bool add_tick(const int tick, std::string& code, int extruder, double print_z);
|
||||
bool edit_tick(std::set<TickCode>::iterator it, double print_z);
|
||||
void switch_code(const std::string& code_from, const std::string& code_to);
|
||||
bool switch_code_for_tick(std::set<TickCode>::iterator it, const std::string& code_to, const int extruder);
|
||||
void erase_all_ticks_with_code(const std::string& gcode);
|
||||
bool has_tick_with_code(const std::string& gcode);
|
||||
|
||||
void suppress_plus (bool suppress) { m_suppress_plus = suppress; }
|
||||
void suppress_minus(bool suppress) { m_suppress_minus = suppress; }
|
||||
bool suppressed_plus () { return m_suppress_plus; }
|
||||
bool suppressed_minus() { return m_suppress_minus; }
|
||||
};
|
||||
|
||||
|
||||
struct ExtrudersSequence
|
||||
{
|
||||
bool is_mm_intervals = true;
|
||||
double interval_by_mm = 3.0;
|
||||
int interval_by_layers = 10;
|
||||
std::vector<size_t> extruders = { 0 };
|
||||
|
||||
bool operator==(const ExtrudersSequence& other) const
|
||||
{
|
||||
return (other.is_mm_intervals == this->is_mm_intervals ) &&
|
||||
(other.interval_by_mm == this->interval_by_mm ) &&
|
||||
(other.interval_by_layers == this->interval_by_layers ) &&
|
||||
(other.extruders == this->extruders ) ;
|
||||
}
|
||||
bool operator!=(const ExtrudersSequence& other) const
|
||||
{
|
||||
return (other.is_mm_intervals != this->is_mm_intervals ) &&
|
||||
(other.interval_by_mm != this->interval_by_mm ) &&
|
||||
(other.interval_by_layers != this->interval_by_layers ) &&
|
||||
(other.extruders != this->extruders ) ;
|
||||
}
|
||||
|
||||
void add_extruder(size_t pos)
|
||||
{
|
||||
extruders.insert(extruders.begin() + pos+1, size_t(0));
|
||||
}
|
||||
|
||||
void delete_extruder(size_t pos)
|
||||
{
|
||||
if (extruders.size() == 1)
|
||||
return;// last item can't be deleted
|
||||
extruders.erase(extruders.begin() + pos);
|
||||
}
|
||||
};
|
||||
|
||||
class Control : public wxControl
|
||||
{
|
||||
public:
|
||||
Control(
|
||||
wxWindow *parent,
|
||||
wxWindowID id,
|
||||
int lowerValue,
|
||||
int higherValue,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxSL_VERTICAL,
|
||||
const wxValidator& val = wxDefaultValidator,
|
||||
const wxString& name = wxEmptyString);
|
||||
~Control() {}
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
int GetMinValue() const { return m_min_value; }
|
||||
int GetMaxValue() const { return m_max_value; }
|
||||
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value]; }
|
||||
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value]; }
|
||||
int GetLowerValue() const { return m_lower_value; }
|
||||
int GetHigherValue() const { return m_higher_value; }
|
||||
int GetActiveValue() const;
|
||||
double GetLowerValueD() { return get_double_value(ssLower); }
|
||||
double GetHigherValueD() { return get_double_value(ssHigher); }
|
||||
wxSize DoGetBestSize() const override;
|
||||
wxSize get_min_size() const ;
|
||||
|
||||
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
|
||||
void SetLowerValue (const int lower_val);
|
||||
void SetHigherValue(const int higher_val);
|
||||
void SetSelectionSpan(const int lower_val, const int higher_val);
|
||||
|
||||
void SetMaxValue(const int max_value);
|
||||
void SetKoefForLabels(const double koef) { m_label_koef = koef; }
|
||||
void SetSliderValues(const std::vector<double>& values) { m_values = values; }
|
||||
void ChangeOneLayerLock();
|
||||
|
||||
CustomGCode::Info GetTicksValues() const;
|
||||
void SetTicksValues(const Slic3r::CustomGCode::Info &custom_gcode_per_print_z);
|
||||
|
||||
void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; }
|
||||
void DisableTickManipulation() { EnableTickManipulation(false); }
|
||||
|
||||
void SetManipulationMode(t_mode mode) { m_mode = mode; }
|
||||
t_mode GetManipulationMode() const { return m_mode; }
|
||||
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
|
||||
{
|
||||
m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder :
|
||||
only_extruder < 0 ? t_mode::SingleExtruder :
|
||||
t_mode::MultiAsSingle;
|
||||
m_only_extruder = only_extruder;
|
||||
}
|
||||
|
||||
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
|
||||
bool is_one_layer() const { return m_is_one_layer; }
|
||||
bool is_lower_at_min() const { return m_lower_value == m_min_value; }
|
||||
bool is_higher_at_max() const { return m_higher_value == m_max_value; }
|
||||
bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); }
|
||||
|
||||
void OnPaint(wxPaintEvent& ) { render();}
|
||||
void OnLeftDown(wxMouseEvent& event);
|
||||
void OnMotion(wxMouseEvent& event);
|
||||
void OnLeftUp(wxMouseEvent& event);
|
||||
void OnEnterWin(wxMouseEvent& event) { enter_window(event, true); }
|
||||
void OnLeaveWin(wxMouseEvent& event) { enter_window(event, false); }
|
||||
void OnWheel(wxMouseEvent& event);
|
||||
void OnKeyDown(wxKeyEvent &event);
|
||||
void OnKeyUp(wxKeyEvent &event);
|
||||
void OnChar(wxKeyEvent &event);
|
||||
void OnRightDown(wxMouseEvent& event);
|
||||
void OnRightUp(wxMouseEvent& event);
|
||||
|
||||
void add_code_as_tick(std::string code, int selected_extruder = -1);
|
||||
// add default action for tick, when press "+"
|
||||
void add_current_tick(bool call_from_keyboard = false);
|
||||
// delete current tick, when press "-"
|
||||
void delete_current_tick();
|
||||
void edit_tick();
|
||||
void edit_extruder_sequence();
|
||||
|
||||
ExtrudersSequence m_extruders_sequence;
|
||||
|
||||
protected:
|
||||
|
||||
void render();
|
||||
void draw_focus_rect();
|
||||
void draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end);
|
||||
void draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos);
|
||||
void draw_thumb(wxDC& dc, const wxCoord& pos_coord, const SelectedSlider& selection);
|
||||
void draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& higher_pos);
|
||||
void draw_ticks(wxDC& dc);
|
||||
void draw_colored_band(wxDC& dc);
|
||||
void draw_one_layer_icon(wxDC& dc);
|
||||
void draw_revert_icon(wxDC& dc);
|
||||
void draw_cog_icon(wxDC &dc);
|
||||
void draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection);
|
||||
void draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection);
|
||||
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
|
||||
|
||||
void update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection);
|
||||
void detect_selected_slider(const wxPoint& pt);
|
||||
void correct_lower_value();
|
||||
void correct_higher_value();
|
||||
void move_current_thumb(const bool condition);
|
||||
void enter_window(wxMouseEvent& event, const bool enter);
|
||||
|
||||
private:
|
||||
|
||||
bool is_point_in_rect(const wxPoint& pt, const wxRect& rect);
|
||||
int is_point_near_tick(const wxPoint& pt);
|
||||
|
||||
double get_scroll_step();
|
||||
wxString get_label(const SelectedSlider& selection) const;
|
||||
void get_lower_and_higher_position(int& lower_pos, int& higher_pos);
|
||||
int get_value_from_position(const wxCoord x, const wxCoord y);
|
||||
wxCoord get_position_from_value(const int value);
|
||||
wxSize get_size();
|
||||
void get_size(int *w, int *h);
|
||||
double get_double_value(const SelectedSlider& selection);
|
||||
wxString get_tooltip(IconFocus icon_focus);
|
||||
|
||||
std::string get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const;
|
||||
std::string get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const;
|
||||
|
||||
// Get active extruders for tick.
|
||||
// Means one current extruder for not existing tick OR
|
||||
// 2 extruders - for existing tick (extruder before ToolChangeCode and extruder of current existing tick)
|
||||
// Use those values to disable selection of active extruders
|
||||
std::array<int, 2> get_active_extruders_for_tick(int tick) const;
|
||||
|
||||
// Get used extruders for tick.
|
||||
// Means all extruders(toools) will be used during printing from current tick to the end
|
||||
std::set<int> get_used_extruders_for_tick(int tick) const;
|
||||
|
||||
void post_ticks_changed_event(const std::string& gcode = "");
|
||||
bool check_ticks_changed_event(const std::string& gcode);
|
||||
|
||||
void append_change_extruder_menu_item (wxMenu*, bool switch_current_code = false);
|
||||
void append_add_color_change_menu_item(wxMenu*, bool switch_current_code = false);
|
||||
|
||||
bool is_osx { false };
|
||||
wxFont m_font;
|
||||
int m_min_value;
|
||||
int m_max_value;
|
||||
int m_lower_value;
|
||||
int m_higher_value;
|
||||
ScalableBitmap m_bmp_thumb_higher;
|
||||
ScalableBitmap m_bmp_thumb_lower;
|
||||
ScalableBitmap m_bmp_add_tick_on;
|
||||
ScalableBitmap m_bmp_add_tick_off;
|
||||
ScalableBitmap m_bmp_del_tick_on;
|
||||
ScalableBitmap m_bmp_del_tick_off;
|
||||
ScalableBitmap m_bmp_one_layer_lock_on;
|
||||
ScalableBitmap m_bmp_one_layer_lock_off;
|
||||
ScalableBitmap m_bmp_one_layer_unlock_on;
|
||||
ScalableBitmap m_bmp_one_layer_unlock_off;
|
||||
ScalableBitmap m_bmp_revert;
|
||||
ScalableBitmap m_bmp_cog;
|
||||
SelectedSlider m_selection;
|
||||
bool m_is_left_down = false;
|
||||
bool m_is_right_down = false;
|
||||
bool m_is_one_layer = false;
|
||||
bool m_is_focused = false;
|
||||
bool m_is_action_icon_focesed = false;
|
||||
bool m_is_one_layer_icon_focesed = false;
|
||||
bool m_is_enabled_tick_manipulation = true;
|
||||
bool m_show_context_menu = false;
|
||||
bool m_show_edit_menu = false;
|
||||
bool m_force_edit_extruder_sequence = false;
|
||||
bool m_force_mode_apply = true;
|
||||
bool m_force_add_tick = false;
|
||||
bool m_force_delete_tick = false;
|
||||
t_mode m_mode = t_mode::SingleExtruder;
|
||||
int m_only_extruder = -1;
|
||||
|
||||
wxRect m_rect_lower_thumb;
|
||||
wxRect m_rect_higher_thumb;
|
||||
wxRect m_rect_tick_action;
|
||||
wxRect m_rect_one_layer_icon;
|
||||
wxRect m_rect_revert_icon;
|
||||
wxRect m_rect_cog_icon;
|
||||
wxSize m_thumb_size;
|
||||
int m_tick_icon_dim;
|
||||
int m_lock_icon_dim;
|
||||
int m_revert_icon_dim;
|
||||
int m_cog_icon_dim;
|
||||
long m_style;
|
||||
float m_label_koef = 1.0;
|
||||
|
||||
std::vector<double> m_values;
|
||||
TickCodeInfo m_ticks;
|
||||
|
||||
// control's view variables
|
||||
wxCoord SLIDER_MARGIN; // margin around slider
|
||||
|
||||
wxPen DARK_ORANGE_PEN;
|
||||
wxPen ORANGE_PEN;
|
||||
wxPen LIGHT_ORANGE_PEN;
|
||||
|
||||
wxPen DARK_GREY_PEN;
|
||||
wxPen GREY_PEN;
|
||||
wxPen LIGHT_GREY_PEN;
|
||||
|
||||
std::vector<wxPen*> m_line_pens;
|
||||
std::vector<wxPen*> m_segm_pens;
|
||||
};
|
||||
|
||||
} // DoubleSlider;
|
||||
|
||||
} // Slic3r
|
||||
|
||||
|
||||
|
||||
#endif // slic3r_GUI_DoubleSlider_hpp_
|
|
@ -2,7 +2,7 @@
|
|||
#define slic3r_GUI_ExtruderSequenceDialog_hpp_
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "DoubleSlider.hpp"
|
||||
|
||||
class wxTextCtrl;
|
||||
class wxFlexGridSizer;
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#include <float.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "DoubleSlider.hpp"
|
||||
#if ENABLE_RENDER_STATISTICS
|
||||
#include <chrono>
|
||||
#endif // ENABLE_RENDER_STATISTICS
|
||||
|
@ -892,7 +893,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
|
|||
std::vector<float>& colors,
|
||||
std::vector<std::string>& cp_legend_items)
|
||||
{
|
||||
std::vector<Model::CustomGCode> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
|
||||
std::vector<CustomGCode::Item> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
|
||||
|
||||
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
|
||||
if (extruders_cnt == 1)
|
||||
|
@ -910,7 +911,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
|
|||
{
|
||||
if (custom_code.gcode != ColorChangeCode)
|
||||
continue;
|
||||
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.print_z - DoubleSlider::epsilon());
|
||||
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.print_z - Slic3r::DoubleSlider::epsilon());
|
||||
|
||||
if (lower_b == print_zs.end())
|
||||
continue;
|
||||
|
@ -2410,7 +2411,7 @@ void GLCanvas3D::load_sla_preview()
|
|||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<Model::CustomGCode>& color_print_values)
|
||||
void GLCanvas3D::load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
|
||||
{
|
||||
const Print *print = this->fff_print();
|
||||
if (print == nullptr)
|
||||
|
@ -5245,13 +5246,13 @@ void GLCanvas3D::_load_print_toolpaths()
|
|||
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors, const std::vector<Model::CustomGCode>& color_print_values)
|
||||
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
|
||||
{
|
||||
std::vector<float> tool_colors = _parse_colors(str_tool_colors);
|
||||
|
||||
struct Ctxt
|
||||
{
|
||||
const Points *shifted_copies;
|
||||
const PrintInstances *shifted_copies;
|
||||
std::vector<const Layer*> layers;
|
||||
bool has_perimeters;
|
||||
bool has_infill;
|
||||
|
@ -5259,7 +5260,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
const std::vector<float>* tool_colors;
|
||||
bool is_single_material_print;
|
||||
int extruders_cnt;
|
||||
const std::vector<Model::CustomGCode>* color_print_values;
|
||||
const std::vector<CustomGCode::Item>* color_print_values;
|
||||
|
||||
static const float* color_perimeters() { static float color[4] = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow
|
||||
static const float* color_infill() { static float color[4] = { 1.0f, 0.5f, 0.5f, 1.f }; return color; } // redish
|
||||
|
@ -5274,7 +5275,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
// For coloring by a color_print(M600), return a parsed color.
|
||||
bool color_by_color_print() const { return color_print_values!=nullptr; }
|
||||
const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const {
|
||||
const Model::CustomGCode value{layers[layer_idx]->print_z + EPSILON, "", 0, ""};
|
||||
const CustomGCode::Item value{layers[layer_idx]->print_z + EPSILON, "", 0, ""};
|
||||
auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
|
||||
return (it - color_print_values->begin()) % number_tools();
|
||||
}
|
||||
|
@ -5284,7 +5285,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
const coordf_t print_z = layers[layer_idx]->print_z;
|
||||
|
||||
auto it = std::find_if(color_print_values->begin(), color_print_values->end(),
|
||||
[print_z](const Model::CustomGCode& code)
|
||||
[print_z](const CustomGCode::Item& code)
|
||||
{ return fabs(code.print_z - print_z) < EPSILON; });
|
||||
if (it != color_print_values->end())
|
||||
{
|
||||
|
@ -5305,7 +5306,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
}
|
||||
}
|
||||
|
||||
const Model::CustomGCode value{print_z + EPSILON, "", 0, ""};
|
||||
const CustomGCode::Item value{print_z + EPSILON, "", 0, ""};
|
||||
it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
|
||||
while (it != color_print_values->begin())
|
||||
{
|
||||
|
@ -5325,7 +5326,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
}
|
||||
|
||||
private:
|
||||
int get_m600_color_idx(std::vector<Model::CustomGCode>::const_iterator it) const
|
||||
int get_m600_color_idx(std::vector<CustomGCode::Item>::const_iterator it) const
|
||||
{
|
||||
int shift = 0;
|
||||
while (it != color_print_values->begin()) {
|
||||
|
@ -5336,7 +5337,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
return extruders_cnt + shift;
|
||||
}
|
||||
|
||||
int get_color_idx_for_tool_change(std::vector<Model::CustomGCode>::const_iterator it, const int extruder) const
|
||||
int get_color_idx_for_tool_change(std::vector<CustomGCode::Item>::const_iterator it, const int extruder) const
|
||||
{
|
||||
const int current_extruder = it->extruder == 0 ? extruder : it->extruder;
|
||||
if (number_tools() == extruders_cnt + 1) // there is no one "M600"
|
||||
|
@ -5352,7 +5353,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
return std::min<int>(extruders_cnt - 1, std::max<int>(current_extruder - 1, 0));
|
||||
}
|
||||
|
||||
int get_color_idx_for_color_change(std::vector<Model::CustomGCode>::const_iterator it, const int extruder) const
|
||||
int get_color_idx_for_color_change(std::vector<CustomGCode::Item>::const_iterator it, const int extruder) const
|
||||
{
|
||||
if (extruders_cnt == 1)
|
||||
return get_m600_color_idx(it);
|
||||
|
@ -5384,7 +5385,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
ctxt.is_single_material_print = this->fff_print()->extruders().size()==1;
|
||||
ctxt.extruders_cnt = wxGetApp().extruders_edited_cnt();
|
||||
|
||||
ctxt.shifted_copies = &print_object.copies();
|
||||
ctxt.shifted_copies = &print_object.instances();
|
||||
|
||||
// order layers by print_z
|
||||
{
|
||||
|
@ -5473,7 +5474,8 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
vol->offsets.push_back(vol->indexed_vertex_array.quad_indices.size());
|
||||
vol->offsets.push_back(vol->indexed_vertex_array.triangle_indices.size());
|
||||
}
|
||||
for (const Point © : *ctxt.shifted_copies) {
|
||||
for (const PrintInstance &instance : *ctxt.shifted_copies) {
|
||||
const Point © = instance.shift;
|
||||
for (const LayerRegion *layerm : layer->regions()) {
|
||||
if (is_selected_separate_extruder)
|
||||
{
|
||||
|
|
|
@ -558,7 +558,7 @@ public:
|
|||
|
||||
void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector<std::string>& str_tool_colors);
|
||||
void load_sla_preview();
|
||||
void load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<Model::CustomGCode>& color_print_values);
|
||||
void load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values);
|
||||
void bind_event_handlers();
|
||||
void unbind_event_handlers();
|
||||
|
||||
|
@ -721,7 +721,7 @@ private:
|
|||
// Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes,
|
||||
// one for perimeters, one for infill and one for supports.
|
||||
void _load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors,
|
||||
const std::vector<Model::CustomGCode>& color_print_values);
|
||||
const std::vector<CustomGCode::Item>& color_print_values);
|
||||
// Create 3D thick extrusion lines for wipe tower extrusions
|
||||
void _load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors);
|
||||
|
||||
|
|
|
@ -1623,9 +1623,14 @@ void ObjectList::append_menu_item_export_stl(wxMenu* menu) const
|
|||
|
||||
void ObjectList::append_menu_item_reload_from_disk(wxMenu* menu) const
|
||||
{
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
|
||||
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu);
|
||||
#else
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
|
||||
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu,
|
||||
[]() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater());
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
}
|
||||
|
||||
void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const
|
||||
|
@ -3892,10 +3897,15 @@ void ObjectList::show_multi_selection_menu()
|
|||
_(L("Select extruder number for selected objects and/or parts")),
|
||||
[this](wxCommandEvent&) { extruder_selection(); }, "", menu);
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
|
||||
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu);
|
||||
#else
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
|
||||
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu, []() {
|
||||
return wxGetApp().plater()->can_reload_from_disk();
|
||||
}, wxGetApp().plater());
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
wxGetApp().plater()->PopupMenu(menu);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "GLCanvas3DManager.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "DoubleSlider.hpp"
|
||||
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/glcanvas.h>
|
||||
|
@ -584,7 +584,7 @@ void Preview::update_view_type(bool slice_completed)
|
|||
|
||||
void Preview::create_double_slider()
|
||||
{
|
||||
m_slider = new DoubleSlider(this, wxID_ANY, 0, 0, 0, 100);
|
||||
m_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100);
|
||||
m_slider->EnableTickManipulation(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF);
|
||||
|
||||
m_double_slider_sizer->Add(m_slider, 0, wxEXPAND, 0);
|
||||
|
@ -595,7 +595,7 @@ void Preview::create_double_slider()
|
|||
m_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_sliders_scroll_changed, this);
|
||||
|
||||
|
||||
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
|
||||
Bind(DoubleSlider::wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
|
||||
Model& model = wxGetApp().plater()->model();
|
||||
model.custom_gcode_per_print_z = m_slider->GetTicksValues();
|
||||
m_schedule_background_process();
|
||||
|
@ -633,7 +633,7 @@ static int find_close_layer_idx(const std::vector<double>& zs, double &z, double
|
|||
return -1;
|
||||
}
|
||||
|
||||
void Preview::check_slider_values(std::vector<Model::CustomGCode>& ticks_from_model,
|
||||
void Preview::check_slider_values(std::vector<CustomGCode::Item>& ticks_from_model,
|
||||
const std::vector<double>& layers_z)
|
||||
{
|
||||
// All ticks that would end up outside the slider range should be erased.
|
||||
|
@ -641,7 +641,7 @@ void Preview::check_slider_values(std::vector<Model::CustomGCode>& ticks_from_mo
|
|||
// this function is e.g. not called when the last object is deleted
|
||||
unsigned int old_size = ticks_from_model.size();
|
||||
ticks_from_model.erase(std::remove_if(ticks_from_model.begin(), ticks_from_model.end(),
|
||||
[layers_z](Model::CustomGCode val)
|
||||
[layers_z](CustomGCode::Item val)
|
||||
{
|
||||
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.print_z - DoubleSlider::epsilon());
|
||||
return it == layers_z.end();
|
||||
|
@ -669,7 +669,7 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
|
|||
// Detect and set manipulation mode for double slider
|
||||
update_double_slider_mode();
|
||||
|
||||
Model::CustomGCodeInfo &ticks_info_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
|
||||
CustomGCode::Info &ticks_info_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
|
||||
check_slider_values(ticks_info_from_model.gcodes, layers_z);
|
||||
|
||||
m_slider->SetSliderValues(layers_z);
|
||||
|
@ -830,7 +830,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
|||
bool gcode_preview_data_valid = print->is_step_done(psGCodeExport) && ! m_gcode_preview_data->empty();
|
||||
// Collect colors per extruder.
|
||||
std::vector<std::string> colors;
|
||||
std::vector<Model::CustomGCode> color_print_values = {};
|
||||
std::vector<CustomGCode::Item> color_print_values = {};
|
||||
// set color print values, if it si selected "ColorPrint" view type
|
||||
if (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint)
|
||||
{
|
||||
|
|
|
@ -15,7 +15,6 @@ class wxChoice;
|
|||
class wxComboCtrl;
|
||||
class wxBitmapComboBox;
|
||||
class wxCheckBox;
|
||||
class DoubleSlider;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -25,6 +24,10 @@ class BackgroundSlicingProcess;
|
|||
class GCodePreviewData;
|
||||
class Model;
|
||||
|
||||
namespace DoubleSlider {
|
||||
class Control;
|
||||
};
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class GLCanvas3D;
|
||||
|
@ -103,7 +106,7 @@ class Preview : public wxPanel
|
|||
bool m_loaded;
|
||||
bool m_enabled;
|
||||
|
||||
DoubleSlider* m_slider {nullptr};
|
||||
DoubleSlider::Control* m_slider {nullptr};
|
||||
|
||||
public:
|
||||
Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
|
||||
|
@ -155,7 +158,7 @@ private:
|
|||
|
||||
// Create/Update/Reset double slider on 3dPreview
|
||||
void create_double_slider();
|
||||
void check_slider_values(std::vector<Model::CustomGCode> &ticks_from_model,
|
||||
void check_slider_values(std::vector<CustomGCode::Item> &ticks_from_model,
|
||||
const std::vector<double> &layers_z);
|
||||
void reset_double_slider();
|
||||
void update_double_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
#include <bitset>
|
||||
|
||||
//unofficial linux lib
|
||||
//#include <spnav.h>
|
||||
|
||||
// WARN: If updating these lists, please also update resources/udev/90-3dconnexion.rules
|
||||
|
||||
static const std::vector<int> _3DCONNEXION_VENDORS =
|
||||
|
@ -204,7 +207,11 @@ Mouse3DController::Mouse3DController()
|
|||
, m_device_str("")
|
||||
, m_running(false)
|
||||
, m_show_settings_dialog(false)
|
||||
, m_mac_mouse_connected(false)
|
||||
, m_settings_dialog_closed_by_user(false)
|
||||
#if __APPLE__
|
||||
,m_handler_mac(new Mouse3DHandlerMac(this))
|
||||
#endif //__APPLE__
|
||||
{
|
||||
m_last_time = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
@ -244,7 +251,7 @@ bool Mouse3DController::apply(Camera& camera)
|
|||
return false;
|
||||
|
||||
// check if the user unplugged the device
|
||||
if (!m_running && is_device_connected())
|
||||
if (!is_running() && is_device_connected())
|
||||
{
|
||||
disconnect_device();
|
||||
// hides the settings dialog if the user un-plug the device
|
||||
|
@ -261,7 +268,7 @@ bool Mouse3DController::apply(Camera& camera)
|
|||
|
||||
void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
||||
{
|
||||
if (!m_running || !m_show_settings_dialog)
|
||||
if (!is_running() || !m_show_settings_dialog)
|
||||
return;
|
||||
|
||||
// when the user clicks on [X] or [Close] button we need to trigger
|
||||
|
@ -397,6 +404,9 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
|||
|
||||
bool Mouse3DController::connect_device()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return false;
|
||||
#endif//__APPLE__
|
||||
static const long long DETECTION_TIME_MS = 2000; // two seconds
|
||||
|
||||
if (is_device_connected())
|
||||
|
@ -405,7 +415,7 @@ bool Mouse3DController::connect_device()
|
|||
// check time since last detection took place
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_last_time).count() < DETECTION_TIME_MS)
|
||||
return false;
|
||||
|
||||
|
||||
m_last_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Enumerates devices
|
||||
|
@ -528,7 +538,7 @@ bool Mouse3DController::connect_device()
|
|||
{
|
||||
if (device.second.size() == 1)
|
||||
{
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__)
|
||||
hid_device* test_device = hid_open(device.first.first, device.first.second, nullptr);
|
||||
if (test_device != nullptr)
|
||||
{
|
||||
|
@ -536,7 +546,7 @@ bool Mouse3DController::connect_device()
|
|||
#else
|
||||
if (device.second.front().has_valid_usage())
|
||||
{
|
||||
#endif // __linux__
|
||||
#endif // __linux__
|
||||
vendor_id = device.first.first;
|
||||
product_id = device.first.second;
|
||||
break;
|
||||
|
@ -553,6 +563,7 @@ bool Mouse3DController::connect_device()
|
|||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
std::cout << "Test device: " << std::hex << device.first.first << std::dec << "/" << std::hex << device.first.second << std::dec << " \"" << data.path << "\"";
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
|
||||
#ifdef __linux__
|
||||
hid_device* test_device = hid_open_path(data.path.c_str());
|
||||
if (test_device != nullptr)
|
||||
|
@ -567,7 +578,7 @@ bool Mouse3DController::connect_device()
|
|||
hid_close(test_device);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
#else // !__linux__
|
||||
if (data.has_valid_usage())
|
||||
{
|
||||
path = data.path;
|
||||
|
@ -632,7 +643,9 @@ bool Mouse3DController::connect_device()
|
|||
BOOST_LOG_TRIVIAL(info) << "Product id..........: " << product_id << " (" << std::hex << product_id << std::dec << ")";
|
||||
if (!path.empty())
|
||||
BOOST_LOG_TRIVIAL(info) << "Path................: '" << path << "'";
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
std::cout << "Opened device." << std::endl;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
// get device parameters from the config, if present
|
||||
double translation_speed = 4.0;
|
||||
float rotation_speed = 4.0;
|
||||
|
@ -717,7 +730,7 @@ void Mouse3DController::run()
|
|||
}
|
||||
void Mouse3DController::collect_input()
|
||||
{
|
||||
DataPacket packet = { 0 };
|
||||
DataPacketRaw packet = { 0 };
|
||||
int res = hid_read_timeout(m_device, packet.data(), packet.size(), 100);
|
||||
if (res < 0)
|
||||
{
|
||||
|
@ -725,10 +738,47 @@ void Mouse3DController::collect_input()
|
|||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
handle_input(packet, res);
|
||||
}
|
||||
|
||||
void Mouse3DController::handle_input_axis(const DataPacketAxis& packet)
|
||||
{
|
||||
if (!wxGetApp().IsActive())
|
||||
return;
|
||||
bool appended = false;
|
||||
//translation
|
||||
double deadzone = m_state.get_translation_deadzone();
|
||||
Vec3d translation(std::abs(packet[0]) > deadzone ? -packet[0] : 0.0,
|
||||
std::abs(packet[1]) > deadzone ? packet[1] : 0.0,
|
||||
std::abs(packet[2]) > deadzone ? packet[2] : 0.0);
|
||||
if (!translation.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
m_state.append_translation(translation);
|
||||
appended = true;
|
||||
}
|
||||
//rotation
|
||||
deadzone = m_state.get_rotation_deadzone();
|
||||
Vec3f rotation(std::abs(packet[3]) > deadzone ? (float)packet[3] : 0.0,
|
||||
std::abs(packet[4]) > deadzone ? (float)packet[4] : 0.0,
|
||||
std::abs(packet[5]) > deadzone ? (float)packet[5] : 0.0);
|
||||
if (!rotation.isApprox(Vec3f::Zero()))
|
||||
{
|
||||
m_state.append_rotation(rotation);
|
||||
appended = true;
|
||||
}
|
||||
if (appended)
|
||||
{
|
||||
wxGetApp().plater()->set_current_canvas_as_dirty();
|
||||
// ask for an idle event to update 3D scene
|
||||
wxWakeUpIdle();
|
||||
}
|
||||
}
|
||||
void Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_lenght)
|
||||
{
|
||||
if (!wxGetApp().IsActive())
|
||||
return;
|
||||
|
||||
int res = packet_lenght;
|
||||
bool updated = false;
|
||||
|
||||
if (res == 7)
|
||||
|
@ -751,7 +801,7 @@ void Mouse3DController::collect_input()
|
|||
}
|
||||
}
|
||||
|
||||
bool Mouse3DController::handle_packet(const DataPacket& packet)
|
||||
bool Mouse3DController::handle_packet(const DataPacketRaw& packet)
|
||||
{
|
||||
switch (packet[0])
|
||||
{
|
||||
|
@ -795,7 +845,7 @@ bool Mouse3DController::handle_packet(const DataPacket& packet)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Mouse3DController::handle_wireless_packet(const DataPacket& packet)
|
||||
bool Mouse3DController::handle_wireless_packet(const DataPacketRaw& packet)
|
||||
{
|
||||
switch (packet[0])
|
||||
{
|
||||
|
@ -842,7 +892,7 @@ double convert_input(unsigned char first, unsigned char second, double deadzone)
|
|||
return (std::abs(ret) > deadzone) ? ret : 0.0;
|
||||
}
|
||||
|
||||
bool Mouse3DController::handle_packet_translation(const DataPacket& packet)
|
||||
bool Mouse3DController::handle_packet_translation(const DataPacketRaw& packet)
|
||||
{
|
||||
double deadzone = m_state.get_translation_deadzone();
|
||||
Vec3d translation(-convert_input(packet[1], packet[2], deadzone),
|
||||
|
@ -858,7 +908,7 @@ bool Mouse3DController::handle_packet_translation(const DataPacket& packet)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Mouse3DController::handle_packet_rotation(const DataPacket& packet, unsigned int first_byte)
|
||||
bool Mouse3DController::handle_packet_rotation(const DataPacketRaw& packet, unsigned int first_byte)
|
||||
{
|
||||
double deadzone = (double)m_state.get_rotation_deadzone();
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
|
@ -880,7 +930,7 @@ bool Mouse3DController::handle_packet_rotation(const DataPacket& packet, unsigne
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Mouse3DController::handle_packet_button(const DataPacket& packet, unsigned int packet_size)
|
||||
bool Mouse3DController::handle_packet_button(const DataPacketRaw& packet, unsigned int packet_size)
|
||||
{
|
||||
unsigned int data = 0;
|
||||
for (unsigned int i = 1; i < packet_size; ++i)
|
||||
|
|
|
@ -14,9 +14,15 @@
|
|||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if __APPLE__
|
||||
class Mouse3DHandlerMac;
|
||||
#endif//__APPLE__
|
||||
|
||||
struct Camera;
|
||||
class GLCanvas3D;
|
||||
|
||||
|
@ -141,6 +147,7 @@ class Mouse3DController
|
|||
hid_device* m_device;
|
||||
std::string m_device_str;
|
||||
bool m_running;
|
||||
bool m_mac_mouse_connected;
|
||||
mutable bool m_show_settings_dialog;
|
||||
// set to true when ther user closes the dialog by clicking on [X] or [Close] buttons
|
||||
mutable bool m_settings_dialog_closed_by_user;
|
||||
|
@ -152,9 +159,11 @@ public:
|
|||
void init();
|
||||
void shutdown();
|
||||
|
||||
bool is_device_connected() const { return m_device != nullptr; }
|
||||
bool is_running() const { return m_running; }
|
||||
bool is_device_connected() const { return m_device != nullptr || m_mac_mouse_connected; }
|
||||
bool is_running() const { return m_running || m_mac_mouse_connected; }
|
||||
|
||||
void set_mac_mouse_connected(bool b){m_mac_mouse_connected = b;};
|
||||
|
||||
bool process_mouse_wheel() { return m_state.process_mouse_wheel(); }
|
||||
|
||||
bool apply(Camera& camera);
|
||||
|
@ -163,26 +172,43 @@ public:
|
|||
void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); }
|
||||
void render_settings_dialog(GLCanvas3D& canvas) const;
|
||||
|
||||
typedef std::array<double, 6> DataPacketAxis;
|
||||
void handle_input_axis(const DataPacketAxis& packet);
|
||||
private:
|
||||
bool connect_device();
|
||||
void disconnect_device();
|
||||
void start();
|
||||
void stop() { m_running = false; }
|
||||
|
||||
typedef std::array<unsigned char, 13> DataPacketRaw;
|
||||
// secondary thread methods
|
||||
void run();
|
||||
void collect_input();
|
||||
void handle_input(const DataPacketRaw& packet, const int packet_lenght);
|
||||
bool handle_packet(const DataPacketRaw& packet);
|
||||
bool handle_wireless_packet(const DataPacketRaw& packet);
|
||||
bool handle_packet_translation(const DataPacketRaw& packet);
|
||||
bool handle_packet_rotation(const DataPacketRaw& packet, unsigned int first_byte);
|
||||
bool handle_packet_button(const DataPacketRaw& packet, unsigned int packet_size);
|
||||
|
||||
typedef std::array<unsigned char, 13> DataPacket;
|
||||
bool handle_packet(const DataPacket& packet);
|
||||
bool handle_wireless_packet(const DataPacket& packet);
|
||||
bool handle_packet_translation(const DataPacket& packet);
|
||||
bool handle_packet_rotation(const DataPacket& packet, unsigned int first_byte);
|
||||
bool handle_packet_button(const DataPacket& packet, unsigned int packet_size);
|
||||
#if __APPLE__
|
||||
Mouse3DHandlerMac* m_handler_mac;
|
||||
#endif//__APPLE__
|
||||
};
|
||||
|
||||
#if __APPLE__
|
||||
class Mouse3DHandlerMac{
|
||||
public:
|
||||
Mouse3DHandlerMac(Mouse3DController* controller);
|
||||
~Mouse3DHandlerMac();
|
||||
|
||||
bool available();
|
||||
};
|
||||
#endif//__APPLE__
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
#endif // slic3r_Mouse3DController_hpp_
|
||||
|
||||
|
|
255
src/slic3r/GUI/Mouse3DHandlerMac.mm
Normal file
255
src/slic3r/GUI/Mouse3DHandlerMac.mm
Normal file
|
@ -0,0 +1,255 @@
|
|||
|
||||
#include "Mouse3DController.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
static Slic3r::GUI::Mouse3DController* mouse_3d_controller = NULL;
|
||||
|
||||
static uint16_t clientID = 0;
|
||||
|
||||
static bool driver_loaded = false;
|
||||
static bool has_new_driver = false; // drivers >= 10.2.2 are "new", and can process events on a separate thread
|
||||
|
||||
// replicate just enough of the 3Dx API for our uses, not everything the driver provides
|
||||
|
||||
#define kConnexionClientModeTakeOver 1
|
||||
#define kConnexionMaskAxis 0x3f00
|
||||
#define kConnexionMaskAll 0x3fff
|
||||
#define kConnexionMaskAllButtons 0xffffffff
|
||||
#define kConnexionCmdHandleButtons 2
|
||||
#define kConnexionCmdHandleAxis 3
|
||||
#define kConnexionCmdAppSpecific 10
|
||||
#define kConnexionMsgDeviceState '3dSR'
|
||||
#define kConnexionCtlGetDeviceID '3did'
|
||||
|
||||
#pragma pack(push, 2)
|
||||
struct ConnexionDeviceState {
|
||||
uint16_t version;
|
||||
uint16_t client;
|
||||
uint16_t command;
|
||||
int16_t param;
|
||||
int32_t value;
|
||||
uint64_t time;
|
||||
uint8_t report[8];
|
||||
uint16_t buttons8; // obsolete! (pre-10.x drivers)
|
||||
int16_t axis[6]; // tx, ty, tz, rx, ry, rz
|
||||
uint16_t address;
|
||||
uint32_t buttons;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// callback functions:
|
||||
typedef void (*AddedHandler)(uint32_t);
|
||||
typedef void (*RemovedHandler)(uint32_t);
|
||||
typedef void (*MessageHandler)(uint32_t, uint32_t msg_type, void *msg_arg);
|
||||
|
||||
// driver functions:
|
||||
typedef int16_t (*SetConnexionHandlers_ptr)(MessageHandler, AddedHandler, RemovedHandler, bool);
|
||||
typedef int16_t (*InstallConnexionHandlers_ptr)(MessageHandler, AddedHandler, RemovedHandler);
|
||||
typedef void (*CleanupConnexionHandlers_ptr)();
|
||||
typedef uint16_t (*RegisterConnexionClient_ptr)(uint32_t signature,
|
||||
const char *name,
|
||||
uint16_t mode,
|
||||
uint32_t mask);
|
||||
typedef void (*SetConnexionClientButtonMask_ptr)(uint16_t clientID, uint32_t buttonMask);
|
||||
typedef void (*UnregisterConnexionClient_ptr)(uint16_t clientID);
|
||||
typedef int16_t (*ConnexionClientControl_ptr)(uint16_t clientID,
|
||||
uint32_t message,
|
||||
int32_t param,
|
||||
int32_t *result);
|
||||
|
||||
#define DECLARE_FUNC(name) name##_ptr name = NULL
|
||||
|
||||
DECLARE_FUNC(SetConnexionHandlers);
|
||||
DECLARE_FUNC(InstallConnexionHandlers);
|
||||
DECLARE_FUNC(CleanupConnexionHandlers);
|
||||
DECLARE_FUNC(RegisterConnexionClient);
|
||||
DECLARE_FUNC(SetConnexionClientButtonMask);
|
||||
DECLARE_FUNC(UnregisterConnexionClient);
|
||||
DECLARE_FUNC(ConnexionClientControl);
|
||||
|
||||
static void *load_func(void *module, const char *func_name)
|
||||
{
|
||||
void *func = dlsym(module, func_name);
|
||||
|
||||
//#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
if (func) {
|
||||
BOOST_LOG_TRIVIAL(info) << func_name <<" loaded";
|
||||
}
|
||||
else {
|
||||
//printf("<!> %s\n", dlerror());
|
||||
BOOST_LOG_TRIVIAL(error) <<"loading 3dx drivers dlsym error: "<< dlerror();
|
||||
}
|
||||
//#endif
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
#define LOAD_FUNC(name) name = (name##_ptr)load_func(module, #name)
|
||||
|
||||
static void *module; // handle to the whole driver
|
||||
|
||||
static bool load_driver_functions()
|
||||
{
|
||||
if (driver_loaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
module = dlopen("/Library/Frameworks/3DconnexionClient.framework/3DconnexionClient",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
|
||||
if (module) {
|
||||
BOOST_LOG_TRIVIAL(info) << "loading 3dx drivers";
|
||||
LOAD_FUNC(SetConnexionHandlers);
|
||||
|
||||
if (SetConnexionHandlers != NULL) {
|
||||
driver_loaded = true;
|
||||
has_new_driver = true;
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(info) << "installing 3dx drivers";
|
||||
LOAD_FUNC(InstallConnexionHandlers);
|
||||
|
||||
driver_loaded = (InstallConnexionHandlers != NULL);
|
||||
}
|
||||
|
||||
if (driver_loaded) {
|
||||
LOAD_FUNC(CleanupConnexionHandlers);
|
||||
LOAD_FUNC(RegisterConnexionClient);
|
||||
LOAD_FUNC(SetConnexionClientButtonMask);
|
||||
LOAD_FUNC(UnregisterConnexionClient);
|
||||
LOAD_FUNC(ConnexionClientControl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "3dx drivers module loading error: "<< dlerror() ;
|
||||
#if DENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
printf("<!> %s\n", dlerror());
|
||||
#endif
|
||||
}
|
||||
#if DENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
printf("loaded: %s\n", driver_loaded ? "YES" : "NO");
|
||||
printf("new: %s\n", has_new_driver ? "YES" : "NO");
|
||||
#endif
|
||||
BOOST_LOG_TRIVIAL(info) << "3dx drivers loaded: "<< driver_loaded ? "YES" : "NO" ;
|
||||
return driver_loaded;
|
||||
}
|
||||
|
||||
static void unload_driver()
|
||||
{
|
||||
dlclose(module);
|
||||
}
|
||||
|
||||
static void DeviceAdded(uint32_t unused)
|
||||
{
|
||||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
std::cout<<"3D device added"<<std::endl;
|
||||
#endif
|
||||
BOOST_LOG_TRIVIAL(info)<<"3dx device added";
|
||||
// determine exactly which device is plugged in
|
||||
int32_t result;
|
||||
ConnexionClientControl(clientID, kConnexionCtlGetDeviceID, 0, &result);
|
||||
int16_t vendorID = result >> 16;
|
||||
int16_t productID = result & 0xffff;
|
||||
|
||||
//TODO: verify device
|
||||
|
||||
|
||||
mouse_3d_controller->set_mac_mouse_connected(true);
|
||||
}
|
||||
|
||||
static void DeviceRemoved(uint32_t unused)
|
||||
{
|
||||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
printf("3d device removed\n");
|
||||
#endif
|
||||
BOOST_LOG_TRIVIAL(info) << "3dx device removed\n";
|
||||
mouse_3d_controller->set_mac_mouse_connected(true);
|
||||
}
|
||||
|
||||
static void DeviceEvent(uint32_t unused, uint32_t msg_type, void *msg_arg)
|
||||
{
|
||||
if (msg_type == kConnexionMsgDeviceState) {
|
||||
ConnexionDeviceState *s = (ConnexionDeviceState *)msg_arg;
|
||||
if (s->client == clientID) {
|
||||
switch (s->command) {
|
||||
case kConnexionCmdHandleAxis: {
|
||||
/*
|
||||
The axis field is an array of 6 signed 16-bit integers corresponding to the 6 device axes. Data is ordered as Tx, Tz, Ty, Rx, Rz, Ry. The values reported are scaled by the driver according to the speed slider settings on the 3Dconnexion preference panel. At maximum speed, the range is - 1024 to 1024. Typical range that you should optimize your application for should be -500 to 500.
|
||||
*/
|
||||
//Actually we are getting values way over 1024. Max is probably 2048 now.
|
||||
std::array<double, 6> packet;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
packet[i] = (double)s->axis[i]/350.0;//wanted to divide by 500 but 350 is used at raw input so i used same value.
|
||||
}
|
||||
mouse_3d_controller->handle_input_axis(packet);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case kConnexionCmdHandleButtons:
|
||||
break;
|
||||
case kConnexionCmdAppSpecific:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
Mouse3DHandlerMac::Mouse3DHandlerMac(Mouse3DController* controller)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "3dx mac handler starts";
|
||||
if (load_driver_functions()) {
|
||||
mouse_3d_controller = controller;
|
||||
|
||||
uint16_t error;
|
||||
if (has_new_driver) {
|
||||
error = SetConnexionHandlers(DeviceEvent, DeviceAdded, DeviceRemoved, false);
|
||||
}
|
||||
else {
|
||||
error = InstallConnexionHandlers(DeviceEvent, DeviceAdded, DeviceRemoved);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Registration is done either by 4letter constant (CFBundleSignature - obsolete
|
||||
//and we dont have that) or Executable name in pascal string(first byte is string lenght).
|
||||
//If no packets are recieved the name might be different - check cmake. If debugging try commenting
|
||||
// set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
|
||||
|
||||
clientID = RegisterConnexionClient(
|
||||
0, "\013PrusaSlicer", kConnexionClientModeTakeOver, kConnexionMaskAxis);
|
||||
BOOST_LOG_TRIVIAL(info) << "3dx mac handler registered";
|
||||
}
|
||||
}
|
||||
|
||||
Mouse3DHandlerMac::~Mouse3DHandlerMac()
|
||||
{
|
||||
if (driver_loaded) {
|
||||
UnregisterConnexionClient(clientID);
|
||||
CleanupConnexionHandlers();
|
||||
unload_driver();
|
||||
}
|
||||
mouse_3d_controller = nullptr;
|
||||
}
|
||||
|
||||
bool Mouse3DHandlerMac::available()
|
||||
{
|
||||
return driver_loaded;
|
||||
}
|
||||
|
||||
}}//namespace Slic3r::GUI
|
|
@ -26,6 +26,9 @@
|
|||
#include <wx/colordlg.h>
|
||||
#include <wx/numdlg.h>
|
||||
#include <wx/debug.h>
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
#include <wx/busyinfo.h>
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
|
@ -84,6 +87,7 @@
|
|||
|
||||
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
|
||||
#include "WipeTowerDialog.hpp"
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
|
||||
using boost::optional;
|
||||
namespace fs = boost::filesystem;
|
||||
|
@ -704,6 +708,7 @@ struct Sidebar::priv
|
|||
wxButton *btn_reslice;
|
||||
ScalableButton *btn_send_gcode;
|
||||
ScalableButton *btn_remove_device;
|
||||
ScalableButton* btn_export_gcode_removable; //exports to removable drives (appears only if removable drive is connected)
|
||||
|
||||
priv(Plater *plater) : plater(plater) {}
|
||||
~priv();
|
||||
|
@ -869,6 +874,7 @@ Sidebar::Sidebar(Plater *parent)
|
|||
|
||||
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")));
|
||||
init_scalable_btn(&p->btn_remove_device, "cross" , _(L("Remove device")));
|
||||
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card/ USB thumb drive")));
|
||||
|
||||
// regular buttons "Slice now" and "Export G-code"
|
||||
|
||||
|
@ -889,7 +895,9 @@ Sidebar::Sidebar(Plater *parent)
|
|||
auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND);
|
||||
complect_btns_sizer->Add(p->btn_send_gcode);
|
||||
complect_btns_sizer->Add(p->btn_export_gcode_removable);
|
||||
complect_btns_sizer->Add(p->btn_remove_device);
|
||||
|
||||
|
||||
btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5);
|
||||
btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
@ -900,7 +908,7 @@ Sidebar::Sidebar(Plater *parent)
|
|||
SetSizer(sizer);
|
||||
|
||||
// Events
|
||||
p->btn_export_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(); });
|
||||
p->btn_export_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(false); });
|
||||
p->btn_reslice->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
|
||||
{
|
||||
const bool export_gcode_after_slicing = wxGetKeyState(WXK_SHIFT);
|
||||
|
@ -912,6 +920,7 @@ Sidebar::Sidebar(Plater *parent)
|
|||
});
|
||||
p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); });
|
||||
p->btn_remove_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
|
||||
p->btn_export_gcode_removable->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(true); });
|
||||
}
|
||||
|
||||
Sidebar::~Sidebar() {}
|
||||
|
@ -1059,6 +1068,7 @@ void Sidebar::msw_rescale()
|
|||
|
||||
p->btn_send_gcode->msw_rescale();
|
||||
p->btn_remove_device->msw_rescale();
|
||||
p->btn_export_gcode_removable->msw_rescale();
|
||||
const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4;
|
||||
p->btn_export_gcode->SetMinSize(wxSize(-1, scaled_height));
|
||||
p->btn_reslice ->SetMinSize(wxSize(-1, scaled_height));
|
||||
|
@ -1292,12 +1302,14 @@ void Sidebar::enable_buttons(bool enable)
|
|||
p->btn_export_gcode->Enable(enable);
|
||||
p->btn_send_gcode->Enable(enable);
|
||||
p->btn_remove_device->Enable(enable);
|
||||
p->btn_export_gcode_removable->Enable(enable);
|
||||
}
|
||||
|
||||
bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); }
|
||||
bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); }
|
||||
bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); }
|
||||
bool Sidebar::show_disconnect(bool show)const { return p->btn_remove_device->Show(show); }
|
||||
bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); }
|
||||
bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); }
|
||||
bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); }
|
||||
bool Sidebar::show_disconnect(bool show) const { return p->btn_remove_device->Show(show); }
|
||||
bool Sidebar::show_export_removable(bool show)const { return p->btn_export_gcode_removable->Show(show); }
|
||||
|
||||
bool Sidebar::is_multifilament()
|
||||
{
|
||||
|
@ -1773,6 +1785,9 @@ struct Plater::priv
|
|||
bool is_view3D_shown() const { return current_panel == view3D; }
|
||||
|
||||
void set_current_canvas_as_dirty();
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
GLCanvas3D* get_current_canvas3D();
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
bool init_view_toolbar();
|
||||
|
||||
|
@ -1902,7 +1917,9 @@ struct Plater::priv
|
|||
bool can_fix_through_netfabb() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_mirror() const;
|
||||
#if !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
bool can_reload_from_disk() const;
|
||||
#endif // !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||
|
@ -2110,6 +2127,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
|
||||
// Initialize the Undo / Redo stack with a first snapshot.
|
||||
this->take_snapshot(_(L("New Project")));
|
||||
|
||||
//void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||
RemovableDriveManager::get_instance().set_drive_count_changed_callback(std::bind(&Plater::priv::show_action_buttons, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
Plater::priv::~priv()
|
||||
|
@ -3230,6 +3250,10 @@ void Plater::priv::reload_from_disk()
|
|||
else
|
||||
missing_input_paths.push_back(volume->source.input_file);
|
||||
}
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
else if (!volume->name.empty())
|
||||
missing_input_paths.push_back(volume->name);
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
}
|
||||
|
||||
std::sort(missing_input_paths.begin(), missing_input_paths.end());
|
||||
|
@ -3241,10 +3265,9 @@ void Plater::priv::reload_from_disk()
|
|||
fs::path search = missing_input_paths.back();
|
||||
wxString title = _(L("Please select the file to reload"));
|
||||
#if defined(__APPLE__)
|
||||
title += " (" + from_u8(search.filename().string()) + "):";
|
||||
#else
|
||||
title += ":";
|
||||
title += " (" + from_u8(search.filename().string()) + ")";
|
||||
#endif // __APPLE__
|
||||
title += ":";
|
||||
wxFileDialog dialog(q, title, "", from_u8(search.filename().string()), file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
@ -3285,10 +3308,20 @@ void Plater::priv::reload_from_disk()
|
|||
std::sort(input_paths.begin(), input_paths.end());
|
||||
input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), input_paths.end());
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
std::vector<wxString> fail_list;
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
// load one file at a time
|
||||
for (size_t i = 0; i < input_paths.size(); ++i)
|
||||
{
|
||||
const auto& path = input_paths[i].string();
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
wxBusyCursor wait;
|
||||
wxBusyInfo info(_(L("Reload from: ")) + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
Model new_model;
|
||||
try
|
||||
{
|
||||
|
@ -3306,18 +3339,70 @@ void Plater::priv::reload_from_disk()
|
|||
}
|
||||
|
||||
// update the selected volumes whose source is the current file
|
||||
for (const SelectedVolume& old_v : selected_volumes)
|
||||
for (const SelectedVolume& sel_v : selected_volumes)
|
||||
{
|
||||
ModelObject* old_model_object = model.objects[old_v.object_idx];
|
||||
ModelVolume* old_volume = old_model_object->volumes[old_v.volume_idx];
|
||||
ModelObject* old_model_object = model.objects[sel_v.object_idx];
|
||||
ModelVolume* old_volume = old_model_object->volumes[sel_v.volume_idx];
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string());
|
||||
bool has_name = !old_volume->name.empty() && boost::algorithm::iequals(old_volume->name, fs::path(path).filename().string());
|
||||
if (has_source || has_name)
|
||||
#else
|
||||
int new_volume_idx = old_volume->source.volume_idx;
|
||||
int new_object_idx = old_volume->source.object_idx;
|
||||
|
||||
if (boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(),
|
||||
fs::path(path).filename().string()))
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
{
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
int new_volume_idx = -1;
|
||||
int new_object_idx = -1;
|
||||
if (has_source)
|
||||
{
|
||||
// take idxs from source
|
||||
new_volume_idx = old_volume->source.volume_idx;
|
||||
new_object_idx = old_volume->source.object_idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
// take idxs from the 1st matching volume
|
||||
for (size_t o = 0; o < new_model.objects.size(); ++o)
|
||||
{
|
||||
ModelObject* obj = new_model.objects[o];
|
||||
bool found = false;
|
||||
for (size_t v = 0; v < obj->volumes.size(); ++v)
|
||||
{
|
||||
if (obj->volumes[v]->name == old_volume->name)
|
||||
{
|
||||
new_volume_idx = (int)v;
|
||||
new_object_idx = (int)o;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((new_object_idx < 0) && ((int)new_model.objects.size() <= new_object_idx))
|
||||
{
|
||||
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
assert(new_object_idx < (int)new_model.objects.size());
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
ModelObject* new_model_object = new_model.objects[new_object_idx];
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
if ((new_volume_idx < 0) && ((int)new_model.objects.size() <= new_volume_idx))
|
||||
{
|
||||
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
|
||||
continue;
|
||||
}
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
if (new_volume_idx < (int)new_model_object->volumes.size())
|
||||
{
|
||||
old_model_object->add_volume(*new_model_object->volumes[new_volume_idx]);
|
||||
|
@ -3328,8 +3413,10 @@ void Plater::priv::reload_from_disk()
|
|||
new_volume->set_material_id(old_volume->material_id());
|
||||
new_volume->set_transformation(old_volume->get_transformation() * old_volume->source.transform);
|
||||
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
|
||||
#if !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
new_volume->source.input_file = path;
|
||||
std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back());
|
||||
#endif // !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
std::swap(old_model_object->volumes[sel_v.volume_idx], old_model_object->volumes.back());
|
||||
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
|
||||
old_model_object->ensure_on_bed();
|
||||
}
|
||||
|
@ -3337,6 +3424,19 @@ void Plater::priv::reload_from_disk()
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
if (!fail_list.empty())
|
||||
{
|
||||
wxString message = _(L("Unable to reload:")) + "\n";
|
||||
for (const wxString& s : fail_list)
|
||||
{
|
||||
message += s + "\n";
|
||||
}
|
||||
wxMessageDialog dlg(q, message, _(L("Error during reload")), wxOK | wxOK_DEFAULT | wxICON_WARNING);
|
||||
dlg.ShowModal();
|
||||
}
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
// update 3D scene
|
||||
update();
|
||||
|
||||
|
@ -3582,12 +3682,8 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
|||
|
||||
if(!canceled && RemovableDriveManager::get_instance().get_is_writing())
|
||||
{
|
||||
//if (!RemovableDriveManager::get_instance().is_last_drive_removed())
|
||||
//{
|
||||
RemovableDriveManager::get_instance().set_is_writing(false);
|
||||
show_action_buttons(false);
|
||||
//}
|
||||
|
||||
RemovableDriveManager::get_instance().set_is_writing(false);
|
||||
show_action_buttons(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3817,8 +3913,13 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
|
|||
append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")),
|
||||
[this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q);
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
|
||||
[this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu);
|
||||
#else
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
|
||||
[this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu, [this]() { return can_reload_from_disk(); }, q);
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
sidebar->obj_list()->append_menu_item_export_stl(menu);
|
||||
}
|
||||
|
@ -3846,8 +3947,13 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
|
|||
wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q);
|
||||
menu->AppendSeparator();
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected object from disk")),
|
||||
[this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr);
|
||||
#else
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected object from disk")),
|
||||
[this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q);
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")),
|
||||
[this](wxCommandEvent&) { q->export_stl(false, true); }, "", nullptr,
|
||||
|
@ -3950,6 +4056,13 @@ void Plater::priv::set_current_canvas_as_dirty()
|
|||
preview->set_as_dirty();
|
||||
}
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
GLCanvas3D* Plater::priv::get_current_canvas3D()
|
||||
{
|
||||
return (current_panel == view3D) ? view3D->get_canvas3d() : ((current_panel == preview) ? preview->get_canvas3d() : nullptr);
|
||||
}
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
bool Plater::priv::init_view_toolbar()
|
||||
{
|
||||
if (view_toolbar.get_items_count() > 0)
|
||||
|
@ -4020,6 +4133,7 @@ bool Plater::priv::can_mirror() const
|
|||
return get_selection().is_from_single_instance();
|
||||
}
|
||||
|
||||
#if !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
bool Plater::priv::can_reload_from_disk() const
|
||||
{
|
||||
// struct to hold selected ModelVolumes by their indices
|
||||
|
@ -4065,6 +4179,7 @@ bool Plater::priv::can_reload_from_disk() const
|
|||
|
||||
return !paths.empty();
|
||||
}
|
||||
#endif // !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
void Plater::priv::set_bed_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model)
|
||||
{
|
||||
|
@ -4142,18 +4257,21 @@ void Plater::priv::update_object_menu()
|
|||
|
||||
void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||
{
|
||||
RemovableDriveManager::get_instance().set_plater_ready_to_slice(is_ready_to_slice);
|
||||
wxWindowUpdateLocker noUpdater(sidebar);
|
||||
const auto prin_host_opt = config->option<ConfigOptionString>("print_host");
|
||||
const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty();
|
||||
|
||||
bool disconnect_shown = !RemovableDriveManager::get_instance().is_last_drive_removed() ; // #dk_FIXME
|
||||
bool disconnect_shown = !RemovableDriveManager::get_instance().is_last_drive_removed();
|
||||
bool export_removable_shown = RemovableDriveManager::get_instance().get_drives_count() > 0;
|
||||
// when a background processing is ON, export_btn and/or send_btn are showing
|
||||
if (wxGetApp().app_config->get("background_processing") == "1")
|
||||
{
|
||||
if (sidebar->show_reslice(false) |
|
||||
sidebar->show_export(true) |
|
||||
sidebar->show_send(send_gcode_shown) |
|
||||
sidebar->show_disconnect(disconnect_shown))
|
||||
if (sidebar->show_reslice(false) |
|
||||
sidebar->show_export(true) |
|
||||
sidebar->show_send(send_gcode_shown) |
|
||||
sidebar->show_export_removable(export_removable_shown) |
|
||||
sidebar->show_disconnect(disconnect_shown))
|
||||
sidebar->Layout();
|
||||
}
|
||||
else
|
||||
|
@ -4161,6 +4279,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
|||
if (sidebar->show_reslice(is_ready_to_slice) |
|
||||
sidebar->show_export(!is_ready_to_slice) |
|
||||
sidebar->show_send(send_gcode_shown && !is_ready_to_slice) |
|
||||
sidebar->show_export_removable(export_removable_shown && !is_ready_to_slice) |
|
||||
sidebar->show_disconnect(disconnect_shown && !is_ready_to_slice))
|
||||
sidebar->Layout();
|
||||
}
|
||||
|
@ -4537,7 +4656,7 @@ void Plater::remove(size_t obj_idx) { p->remove(obj_idx); }
|
|||
void Plater::reset() { p->reset(); }
|
||||
void Plater::reset_with_confirm()
|
||||
{
|
||||
if (wxMessageDialog((wxWindow*)this, _(L("All objects will be removed, continue ?")), wxString(SLIC3R_APP_NAME) + " - " + _(L("Delete all")), wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTRE).ShowModal() == wxID_YES)
|
||||
if (wxMessageDialog((wxWindow*)this, _(L("All objects will be removed, continue?")), wxString(SLIC3R_APP_NAME) + " - " + _(L("Delete all")), wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTRE).ShowModal() == wxID_YES)
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -4670,7 +4789,7 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
|
|||
}
|
||||
}
|
||||
|
||||
void Plater::export_gcode()
|
||||
void Plater::export_gcode(bool prefer_removable)
|
||||
{
|
||||
if (p->model.objects.empty())
|
||||
return;
|
||||
|
@ -4692,11 +4811,19 @@ void Plater::export_gcode()
|
|||
}
|
||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
||||
auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string());
|
||||
if (GUI::RemovableDriveManager::get_instance().update())
|
||||
bool removable_drives_connected = GUI::RemovableDriveManager::get_instance().update();
|
||||
if(prefer_removable)
|
||||
{
|
||||
if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir))
|
||||
if(removable_drives_connected)
|
||||
{
|
||||
start_dir = RemovableDriveManager::get_instance().get_drive_path();
|
||||
auto start_dir_removable = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string(), true);
|
||||
if (RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir_removable))
|
||||
{
|
||||
start_dir = start_dir_removable;
|
||||
}else
|
||||
{
|
||||
start_dir = RemovableDriveManager::get_instance().get_drive_path();
|
||||
}
|
||||
}
|
||||
}
|
||||
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")),
|
||||
|
@ -4709,7 +4836,7 @@ void Plater::export_gcode()
|
|||
fs::path output_path;
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fs::path path = into_path(dlg.GetPath());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string(), RemovableDriveManager::get_instance().is_path_on_removable_drive(path.parent_path().string()));
|
||||
output_path = std::move(path);
|
||||
}
|
||||
if (! output_path.empty())
|
||||
|
@ -4725,7 +4852,7 @@ void Plater::export_gcode()
|
|||
{
|
||||
RemovableDriveManager::get_instance().set_is_writing(true);
|
||||
RemovableDriveManager::get_instance().erase_callbacks();
|
||||
RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
RemovableDriveManager::get_instance().add_remove_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5032,8 +5159,8 @@ void Plater::send_gcode()
|
|||
void Plater::eject_drive()
|
||||
{
|
||||
RemovableDriveManager::get_instance().update(0, true);
|
||||
//RemovableDriveManager::get_instance().erase_callbacks();
|
||||
//RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
RemovableDriveManager::get_instance().erase_callbacks();
|
||||
RemovableDriveManager::get_instance().add_remove_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path());
|
||||
|
||||
}
|
||||
|
@ -5042,7 +5169,7 @@ void Plater::drive_ejected_callback()
|
|||
if (RemovableDriveManager::get_instance().get_did_eject())
|
||||
{
|
||||
RemovableDriveManager::get_instance().set_did_eject(false);
|
||||
wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer.";
|
||||
wxString message = "Unmounting successful. The device " + RemovableDriveManager::get_instance().get_ejected_name() + "(" + RemovableDriveManager::get_instance().get_ejected_path() + ")" + " can now be safely removed from the computer.";
|
||||
wxMessageBox(message);
|
||||
}
|
||||
p->show_action_buttons(false);
|
||||
|
@ -5288,7 +5415,7 @@ std::vector<std::string> Plater::get_colors_for_color_print() const
|
|||
std::vector<std::string> colors = get_extruder_colors_from_plater_config();
|
||||
colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size());
|
||||
|
||||
for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z.gcodes)
|
||||
for (const CustomGCode::Item& code : p->model.custom_gcode_per_print_z.gcodes)
|
||||
if (code.gcode == ColorChangeCode)
|
||||
colors.emplace_back(code.color);
|
||||
|
||||
|
@ -5325,6 +5452,13 @@ GLCanvas3D* Plater::canvas3D()
|
|||
return p->view3D->get_canvas3d();
|
||||
}
|
||||
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
GLCanvas3D* Plater::get_current_canvas3D()
|
||||
{
|
||||
return p->get_current_canvas3D();
|
||||
}
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
BoundingBoxf Plater::bed_shape_bb() const
|
||||
{
|
||||
return p->bed_shape_bb();
|
||||
|
@ -5517,7 +5651,9 @@ bool Plater::can_copy_to_clipboard() const
|
|||
|
||||
bool Plater::can_undo() const { return p->undo_redo_stack().has_undo_snapshot(); }
|
||||
bool Plater::can_redo() const { return p->undo_redo_stack().has_redo_snapshot(); }
|
||||
#if !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
|
||||
#endif // !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); }
|
||||
void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); }
|
||||
void Plater::leave_gizmos_stack() { p->leave_gizmos_stack(); }
|
||||
|
|
|
@ -120,6 +120,7 @@ public:
|
|||
bool show_export(bool show) const;
|
||||
bool show_send(bool show) const;
|
||||
bool show_disconnect(bool show)const;
|
||||
bool show_export_removable(bool show) const;
|
||||
bool is_multifilament();
|
||||
void update_mode();
|
||||
|
||||
|
@ -186,7 +187,7 @@ public:
|
|||
|
||||
void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false);
|
||||
|
||||
void export_gcode();
|
||||
void export_gcode(bool prefer_removable = true);
|
||||
void export_stl(bool extended = false, bool selection_only = false);
|
||||
void export_amf();
|
||||
void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
|
||||
|
@ -239,6 +240,9 @@ public:
|
|||
int get_selected_object_idx();
|
||||
bool is_single_full_object_selection() const;
|
||||
GLCanvas3D* canvas3D();
|
||||
#if ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
GLCanvas3D* get_current_canvas3D();
|
||||
#endif // ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
BoundingBoxf bed_shape_bb() const;
|
||||
|
||||
void set_current_canvas_as_dirty();
|
||||
|
@ -263,7 +267,9 @@ public:
|
|||
bool can_copy_to_clipboard() const;
|
||||
bool can_undo() const;
|
||||
bool can_redo() const;
|
||||
#if !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
bool can_reload_from_disk() const;
|
||||
#endif // !ENABLE_BACKWARD_COMPATIBLE_RELOAD_FROM_DISK
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
|
|
|
@ -604,6 +604,7 @@ void PresetCollection::reset(bool delete_files)
|
|||
m_presets.erase(m_presets.begin() + m_num_default_presets, m_presets.end());
|
||||
this->select_preset(0);
|
||||
}
|
||||
m_map_alias_to_profile_name.clear();
|
||||
m_map_system_profile_renamed.clear();
|
||||
}
|
||||
|
||||
|
@ -948,15 +949,15 @@ PresetWithVendorProfile PresetCollection::get_preset_with_vendor_profile(const P
|
|||
|
||||
const std::string& PresetCollection::get_preset_name_by_alias(const std::string& alias) const
|
||||
{
|
||||
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) {
|
||||
const Preset& preset = this->m_presets[i];
|
||||
if (!preset.is_visible || (!preset.is_compatible && i != m_idx_selected))
|
||||
continue;
|
||||
|
||||
if (preset.alias == alias)
|
||||
return preset.name;
|
||||
}
|
||||
|
||||
for (
|
||||
// Find the 1st profile name with the alias.
|
||||
auto it = Slic3r::lower_bound_by_predicate(m_map_alias_to_profile_name.begin(), m_map_alias_to_profile_name.end(), [&alias](auto &l){ return l.first < alias; });
|
||||
// Continue over all profile names with the same alias.
|
||||
it != m_map_alias_to_profile_name.end() && it->first == alias; ++ it)
|
||||
if (auto it_preset = this->find_preset_internal(it->second);
|
||||
it_preset != m_presets.end() && it_preset->name == it->second &&
|
||||
it_preset->is_visible && (it_preset->is_compatible || (it_preset - m_presets.begin()) == m_idx_selected))
|
||||
return it_preset->name;
|
||||
return alias;
|
||||
}
|
||||
|
||||
|
@ -1430,6 +1431,14 @@ std::vector<std::string> PresetCollection::merge_presets(PresetCollection &&othe
|
|||
return duplicates;
|
||||
}
|
||||
|
||||
void PresetCollection::update_map_alias_to_profile_name()
|
||||
{
|
||||
m_map_alias_to_profile_name.clear();
|
||||
for (const Preset &preset : m_presets)
|
||||
m_map_alias_to_profile_name.emplace_back(preset.alias, preset.name);
|
||||
std::sort(m_map_alias_to_profile_name.begin(), m_map_alias_to_profile_name.end(), [](auto &l, auto &r) { return l.first < r.first; });
|
||||
}
|
||||
|
||||
void PresetCollection::update_map_system_profile_renamed()
|
||||
{
|
||||
m_map_system_profile_renamed.clear();
|
||||
|
|
|
@ -166,7 +166,7 @@ public:
|
|||
DynamicPrintConfig config;
|
||||
|
||||
// Alias of the preset
|
||||
std::string alias = "";
|
||||
std::string alias;
|
||||
// List of profile names, from which this profile was renamed at some point of time.
|
||||
// This list is then used to match profiles by their names when loaded from .gcode, .3mf, .amf,
|
||||
// and to match the "inherits" field of user profiles with updated system profiles.
|
||||
|
@ -356,7 +356,7 @@ public:
|
|||
|
||||
// used to update preset_choice from Tab
|
||||
const std::deque<Preset>& get_presets() const { return m_presets; }
|
||||
int get_idx_selected() { return m_idx_selected; }
|
||||
int get_idx_selected() { return m_idx_selected; }
|
||||
static const std::string& get_suffix_modified();
|
||||
|
||||
// Return a preset possibly with modifications.
|
||||
|
@ -475,6 +475,9 @@ protected:
|
|||
// Merge one vendor's presets with the other vendor's presets, report duplicates.
|
||||
std::vector<std::string> merge_presets(PresetCollection &&other, const VendorMap &new_vendors);
|
||||
|
||||
// Update m_map_alias_to_profile_name from loaded system profiles.
|
||||
void update_map_alias_to_profile_name();
|
||||
|
||||
// Update m_map_system_profile_renamed from loaded system profiles.
|
||||
void update_map_system_profile_renamed();
|
||||
|
||||
|
@ -522,6 +525,8 @@ private:
|
|||
// Use deque to force the container to allocate an object per each entry,
|
||||
// so that the addresses of the presets don't change during resizing of the container.
|
||||
std::deque<Preset> m_presets;
|
||||
// System profiles may have aliases. Map to the full profile name.
|
||||
std::vector<std::pair<std::string, std::string>> m_map_alias_to_profile_name;
|
||||
// Map from old system profile name to a current system profile name.
|
||||
std::map<std::string, std::string> m_map_system_profile_renamed;
|
||||
// Initially this preset contains a copy of the selected preset. Later on, this copy may be modified by the user.
|
||||
|
|
|
@ -288,11 +288,18 @@ std::string PresetBundle::load_system_presets()
|
|||
// No config bundle loaded, reset.
|
||||
this->reset(false);
|
||||
}
|
||||
|
||||
this->prints .update_map_system_profile_renamed();
|
||||
this->sla_prints .update_map_system_profile_renamed();
|
||||
this->filaments .update_map_system_profile_renamed();
|
||||
this->sla_materials.update_map_system_profile_renamed();
|
||||
this->printers .update_map_system_profile_renamed();
|
||||
|
||||
this->prints .update_map_alias_to_profile_name();
|
||||
this->sla_prints .update_map_alias_to_profile_name();
|
||||
this->filaments .update_map_alias_to_profile_name();
|
||||
this->sla_materials.update_map_alias_to_profile_name();
|
||||
|
||||
return errors_cummulative;
|
||||
}
|
||||
|
||||
|
@ -877,7 +884,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
|||
// 4) Load the project config values (the per extruder wipe matrix etc).
|
||||
this->project_config.apply_only(config, s_project_options);
|
||||
|
||||
update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes, &this->project_config);
|
||||
update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,9 @@ namespace Slic3r {
|
|||
namespace GUI {
|
||||
|
||||
#if _WIN32
|
||||
/* currently not used, left for possible future use
|
||||
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
*/
|
||||
void RemovableDriveManager::search_for_drives()
|
||||
{
|
||||
m_current_drives.clear();
|
||||
|
@ -44,7 +46,7 @@ void RemovableDriveManager::search_for_drives()
|
|||
if (drive_type == DRIVE_REMOVABLE)
|
||||
{
|
||||
// get name of drive
|
||||
std::wstring wpath = boost::nowide::widen(path);//std::wstring(path.begin(), path.end());
|
||||
std::wstring wpath = boost::nowide::widen(path);
|
||||
std::wstring volume_name;
|
||||
volume_name.resize(1024);
|
||||
std::wstring file_system_name;
|
||||
|
@ -54,12 +56,6 @@ void RemovableDriveManager::search_for_drives()
|
|||
if(error != 0)
|
||||
{
|
||||
volume_name.erase(std::find(volume_name.begin(), volume_name.end(), '\0'), volume_name.end());
|
||||
/*
|
||||
if (volume_name == L"")
|
||||
{
|
||||
volume_name = L"REMOVABLE DRIVE";
|
||||
}
|
||||
*/
|
||||
if (file_system_name != L"")
|
||||
{
|
||||
ULARGE_INTEGER free_space;
|
||||
|
@ -109,6 +105,8 @@ void RemovableDriveManager::eject_drive(const std::string &path)
|
|||
CloseHandle(handle);
|
||||
m_did_eject = true;
|
||||
m_current_drives.erase(it);
|
||||
m_ejected_path = m_last_save_path;
|
||||
m_ejected_name = m_last_save_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +143,7 @@ void RemovableDriveManager::register_window()
|
|||
{
|
||||
//creates new unvisible window that is recieving callbacks from system
|
||||
// structure to register
|
||||
/* currently not used, left for possible future use
|
||||
WNDCLASSEX wndClass;
|
||||
wndClass.cbSize = sizeof(WNDCLASSEX);
|
||||
wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
||||
|
@ -180,13 +179,15 @@ void RemovableDriveManager::register_window()
|
|||
}
|
||||
//ShowWindow(hWnd, SW_SHOWNORMAL);
|
||||
UpdateWindow(hWnd);
|
||||
*/
|
||||
}
|
||||
|
||||
/* currently not used, left for possible future use
|
||||
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// here we need to catch messeges about device removal
|
||||
// problem is that when ejecting usb (how is it implemented above) there is no messege dispached. Only after physical removal of the device.
|
||||
//uncomment register_window() in init() to register and comment update() in GUI_App.cpp (only for windows!) to stop recieving periodical updates
|
||||
|
||||
LRESULT lRet = 1;
|
||||
static HDEVNOTIFY hDeviceNotify;
|
||||
|
||||
|
@ -219,8 +220,9 @@ INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP
|
|||
break;
|
||||
}
|
||||
return lRet;
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
#else
|
||||
void RemovableDriveManager::search_for_drives()
|
||||
{
|
||||
|
@ -239,35 +241,10 @@ void RemovableDriveManager::search_for_drives()
|
|||
//search /media/* folder
|
||||
search_path("/media/*", "/media");
|
||||
|
||||
//search /Volumes/* folder (OSX)
|
||||
//search_path("/Volumes/*", "/Volumes");
|
||||
std::string path(std::getenv("USER"));
|
||||
std::string pp(path);
|
||||
//std::cout << "user: "<< path << "\n";
|
||||
//if program is run with sudo, we have to search for all users
|
||||
// but do we want that?
|
||||
/*
|
||||
if(path == "root"){
|
||||
while (true) {
|
||||
passwd* entry = getpwent();
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
path = entry->pw_name;
|
||||
pp = path;
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
path = "/media/" + path + "/*";
|
||||
search_path(path, pp);
|
||||
|
||||
//search /run/media/USERNAME/* folder
|
||||
path = "/run" + path;
|
||||
pp = "/run"+pp;
|
||||
search_path(path, pp);
|
||||
}
|
||||
endpwent();
|
||||
}else
|
||||
*/
|
||||
{
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
|
@ -310,7 +287,6 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str
|
|||
{
|
||||
//free space
|
||||
boost::filesystem::space_info si = boost::filesystem::space(path);
|
||||
//std::cout << "Free space: " << fs_si.free << "Available space: " << fs_si.available << " " << path << '\n';
|
||||
if(si.available != 0)
|
||||
{
|
||||
//user id
|
||||
|
@ -353,7 +329,7 @@ void RemovableDriveManager::eject_drive(const std::string &path)
|
|||
i++;
|
||||
}
|
||||
}
|
||||
std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
|
||||
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
|
||||
// there is no usable command in c++ so terminal command is used instead
|
||||
// but neither triggers "succesful safe removal messege"
|
||||
std::string command = "";
|
||||
|
@ -373,7 +349,8 @@ void RemovableDriveManager::eject_drive(const std::string &path)
|
|||
|
||||
m_did_eject = true;
|
||||
m_current_drives.erase(it);
|
||||
|
||||
m_ejected_path = m_last_save_path;
|
||||
m_ejected_name = m_last_save_name;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -385,7 +362,7 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
|
|||
if (m_current_drives.empty())
|
||||
return false;
|
||||
std::size_t found = path.find_last_of("/");
|
||||
std::string new_path = path.substr(0,found);
|
||||
std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if(compare_filesystem_id(new_path, (*it).path))
|
||||
|
@ -393,10 +370,10 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
std::string RemovableDriveManager::get_drive_from_path(const std::string& path)
|
||||
std::string RemovableDriveManager::get_drive_from_path(const std::string& path)
|
||||
{
|
||||
std::size_t found = path.find_last_of("/");
|
||||
std::string new_path = path.substr(0, found);
|
||||
std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
|
||||
//check if same filesystem
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
|
@ -414,7 +391,10 @@ RemovableDriveManager::RemovableDriveManager():
|
|||
m_last_save_name(""),
|
||||
m_last_save_path_verified(false),
|
||||
m_is_writing(false),
|
||||
m_did_eject(false)
|
||||
m_did_eject(false),
|
||||
m_plater_ready_to_slice(true),
|
||||
m_ejected_path(""),
|
||||
m_ejected_name("")
|
||||
#if __APPLE__
|
||||
, m_rdmmm(new RDMMMWrapper())
|
||||
#endif
|
||||
|
@ -451,13 +431,16 @@ bool RemovableDriveManager::update(const long time,const bool check)
|
|||
search_for_drives();
|
||||
if (m_drives_count != m_current_drives.size())
|
||||
{
|
||||
if (check)check_and_notify();
|
||||
if (check)
|
||||
{
|
||||
check_and_notify();
|
||||
}
|
||||
m_drives_count = m_current_drives.size();
|
||||
}
|
||||
return !m_current_drives.empty();
|
||||
}
|
||||
|
||||
bool RemovableDriveManager::is_drive_mounted(const std::string &path)
|
||||
bool RemovableDriveManager::is_drive_mounted(const std::string &path) const
|
||||
{
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
|
@ -468,7 +451,7 @@ bool RemovableDriveManager::is_drive_mounted(const std::string &path)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
std::string RemovableDriveManager::get_drive_path()
|
||||
std::string RemovableDriveManager::get_drive_path()
|
||||
{
|
||||
if (m_current_drives.size() == 0)
|
||||
{
|
||||
|
@ -479,23 +462,27 @@ std::string RemovableDriveManager::get_drive_path()
|
|||
return m_last_save_path;
|
||||
return m_current_drives.back().path;
|
||||
}
|
||||
std::string RemovableDriveManager::get_last_save_path()
|
||||
std::string RemovableDriveManager::get_last_save_path() const
|
||||
{
|
||||
if (!m_last_save_path_verified)
|
||||
return "";
|
||||
return m_last_save_path;
|
||||
}
|
||||
std::string RemovableDriveManager::get_last_save_name()
|
||||
std::string RemovableDriveManager::get_last_save_name() const
|
||||
{
|
||||
return m_last_save_name;
|
||||
}
|
||||
std::vector<DriveData> RemovableDriveManager::get_all_drives()
|
||||
std::vector<DriveData> RemovableDriveManager::get_all_drives() const
|
||||
{
|
||||
return m_current_drives;
|
||||
}
|
||||
void RemovableDriveManager::check_and_notify()
|
||||
{
|
||||
if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path_verified && !is_drive_mounted(m_last_save_path))
|
||||
if(m_drive_count_changed_callback)
|
||||
{
|
||||
m_drive_count_changed_callback(m_plater_ready_to_slice);
|
||||
}
|
||||
if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && !is_drive_mounted(m_last_save_path))
|
||||
{
|
||||
for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it)
|
||||
{
|
||||
|
@ -503,18 +490,35 @@ void RemovableDriveManager::check_and_notify()
|
|||
}
|
||||
}
|
||||
}
|
||||
void RemovableDriveManager::add_callback(std::function<void()> callback)
|
||||
void RemovableDriveManager::add_remove_callback(std::function<void()> callback)
|
||||
{
|
||||
m_callbacks.push_back(callback);
|
||||
}
|
||||
void RemovableDriveManager::erase_callbacks()
|
||||
void RemovableDriveManager::erase_callbacks()
|
||||
{
|
||||
m_callbacks.clear();
|
||||
}
|
||||
void RemovableDriveManager::set_drive_count_changed_callback(std::function<void(const bool)> callback)
|
||||
{
|
||||
m_drive_count_changed_callback = callback;
|
||||
}
|
||||
void RemovableDriveManager::set_plater_ready_to_slice(bool b)
|
||||
{
|
||||
m_plater_ready_to_slice = b;
|
||||
}
|
||||
void RemovableDriveManager::set_last_save_path(const std::string& path)
|
||||
{
|
||||
m_last_save_path_verified = false;
|
||||
m_last_save_path = path;
|
||||
if(m_last_save_path_verified)// if old path is on drive
|
||||
{
|
||||
if(get_drive_from_path(path) != "") //and new is too, rewrite the path
|
||||
{
|
||||
m_last_save_path_verified = false;
|
||||
m_last_save_path = path;
|
||||
}//else do nothing
|
||||
}else
|
||||
{
|
||||
m_last_save_path = path;
|
||||
}
|
||||
}
|
||||
void RemovableDriveManager::verify_last_save_path()
|
||||
{
|
||||
|
@ -529,7 +533,7 @@ void RemovableDriveManager::verify_last_save_path()
|
|||
reset_last_save_path();
|
||||
}
|
||||
}
|
||||
std::string RemovableDriveManager::get_drive_name(const std::string& path)
|
||||
std::string RemovableDriveManager::get_drive_name(const std::string& path) const
|
||||
{
|
||||
if (m_current_drives.size() == 0)
|
||||
return "";
|
||||
|
@ -542,18 +546,17 @@ std::string RemovableDriveManager::get_drive_name(const std::string& path)
|
|||
}
|
||||
return "";
|
||||
}
|
||||
bool RemovableDriveManager::is_last_drive_removed()
|
||||
bool RemovableDriveManager::is_last_drive_removed()
|
||||
{
|
||||
//std::cout<<"is last: "<<m_last_save_path;
|
||||
//m_drives_count = m_current_drives.size();
|
||||
if(!m_last_save_path_verified)
|
||||
{
|
||||
//std::cout<<"\n";
|
||||
return true;
|
||||
}
|
||||
bool r = !is_drive_mounted(m_last_save_path);
|
||||
if (r) reset_last_save_path();
|
||||
//std::cout<<" "<< r <<"\n";
|
||||
if (r)
|
||||
{
|
||||
reset_last_save_path();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
bool RemovableDriveManager::is_last_drive_removed_with_update(const long time)
|
||||
|
@ -575,16 +578,28 @@ void RemovableDriveManager::set_is_writing(const bool b)
|
|||
m_did_eject = false;
|
||||
}
|
||||
}
|
||||
bool RemovableDriveManager::get_is_writing()
|
||||
bool RemovableDriveManager::get_is_writing() const
|
||||
{
|
||||
return m_is_writing;
|
||||
}
|
||||
bool RemovableDriveManager::get_did_eject()
|
||||
bool RemovableDriveManager::get_did_eject() const
|
||||
{
|
||||
return m_did_eject;
|
||||
}
|
||||
void RemovableDriveManager::set_did_eject(const bool b)
|
||||
void RemovableDriveManager::set_did_eject(const bool b)
|
||||
{
|
||||
m_did_eject = b;
|
||||
}
|
||||
size_t RemovableDriveManager::get_drives_count() const
|
||||
{
|
||||
return m_current_drives.size();
|
||||
}
|
||||
std::string RemovableDriveManager::get_ejected_path() const
|
||||
{
|
||||
return m_ejected_path;
|
||||
}
|
||||
std::string RemovableDriveManager::get_ejected_name() const
|
||||
{
|
||||
return m_ejected_name;
|
||||
}
|
||||
}}//namespace Slicer::Gui
|
||||
|
|
|
@ -35,19 +35,23 @@ public:
|
|||
void init();
|
||||
//update() searches for removable devices, returns false if empty. /time = 0 is forced update, time expects wxGetLocalTime()
|
||||
bool update(const long time = 0,const bool check = false);
|
||||
bool is_drive_mounted(const std::string &path);
|
||||
bool is_drive_mounted(const std::string &path) const;
|
||||
void eject_drive(const std::string &path);
|
||||
//returns path to last drive which was used, if none was used, returns device that was enumerated last
|
||||
std::string get_last_save_path();
|
||||
std::string get_last_save_name();
|
||||
std::string get_last_save_path() const;
|
||||
std::string get_last_save_name() const;
|
||||
//returns path to last drive which was used, if none was used, returns empty string
|
||||
std::string get_drive_path();
|
||||
std::vector<DriveData> get_all_drives();
|
||||
std::vector<DriveData> get_all_drives() const;
|
||||
bool is_path_on_removable_drive(const std::string &path);
|
||||
// callback will notify only if device with last save path was removed
|
||||
void add_callback(std::function<void()> callback);
|
||||
// erases all callbacks added by add_callback()
|
||||
void add_remove_callback(std::function<void()> callback);
|
||||
// erases all remove callbacks added by add_remove_callback()
|
||||
void erase_callbacks();
|
||||
//drive_count_changed callback is called on every added or removed device
|
||||
void set_drive_count_changed_callback(std::function<void(const bool)> callback);
|
||||
//thi serves to set correct value for drive_count_changed callback
|
||||
void set_plater_ready_to_slice(bool b);
|
||||
// marks one of the eveices in vector as last used
|
||||
void set_last_save_path(const std::string &path);
|
||||
void verify_last_save_path();
|
||||
|
@ -55,10 +59,13 @@ public:
|
|||
// param as update()
|
||||
bool is_last_drive_removed_with_update(const long time = 0);
|
||||
void set_is_writing(const bool b);
|
||||
bool get_is_writing();
|
||||
bool get_did_eject();
|
||||
bool get_is_writing() const;
|
||||
bool get_did_eject() const;
|
||||
void set_did_eject(const bool b);
|
||||
std::string get_drive_name(const std::string& path);
|
||||
std::string get_drive_name(const std::string& path) const;
|
||||
size_t get_drives_count() const;
|
||||
std::string get_ejected_path() const;
|
||||
std::string get_ejected_name() const;
|
||||
private:
|
||||
RemovableDriveManager();
|
||||
void search_for_drives();
|
||||
|
@ -70,6 +77,7 @@ private:
|
|||
|
||||
std::vector<DriveData> m_current_drives;
|
||||
std::vector<std::function<void()>> m_callbacks;
|
||||
std::function<void(const bool)> m_drive_count_changed_callback;
|
||||
size_t m_drives_count;
|
||||
long m_last_update;
|
||||
std::string m_last_save_path;
|
||||
|
@ -77,6 +85,9 @@ private:
|
|||
std::string m_last_save_name;
|
||||
bool m_is_writing;//on device
|
||||
bool m_did_eject;
|
||||
bool m_plater_ready_to_slice;
|
||||
std::string m_ejected_path;
|
||||
std::string m_ejected_name;
|
||||
#if _WIN32
|
||||
//registers for notifications by creating invisible window
|
||||
void register_window();
|
||||
|
|
|
@ -3033,9 +3033,9 @@ void Tab::save_preset(std::string name /*= ""*/)
|
|||
show_error(this, _(L("Cannot overwrite an external profile.")));
|
||||
return;
|
||||
}
|
||||
if (existing/* && name != preset.name*/)
|
||||
if (existing && name != preset.name)
|
||||
{
|
||||
wxString msg_text = GUI::from_u8((boost::format(_utf8(L("Preset with name \"%1%\" already exist."))) % name).str());
|
||||
wxString msg_text = GUI::from_u8((boost::format(_utf8(L("Preset with name \"%1%\" already exists."))) % name).str());
|
||||
msg_text += "\n" + _(L("Replace?"));
|
||||
wxMessageDialog dialog(nullptr, msg_text, _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,19 +5,15 @@
|
|||
#include <wx/combo.h>
|
||||
#include <wx/dataview.h>
|
||||
#include <wx/dc.h>
|
||||
#include <wx/collpane.h>
|
||||
#include <wx/wupdlock.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/GCodeWriter.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
enum class ModelVolumeType : int;
|
||||
|
@ -49,12 +45,15 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string,
|
|||
wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
|
||||
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
|
||||
|
||||
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item, wxWindow* win);
|
||||
|
||||
class wxDialog;
|
||||
class wxBitmapComboBox;
|
||||
|
||||
void edit_tooltip(wxString& tooltip);
|
||||
void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids);
|
||||
int em_unit(wxWindow* win);
|
||||
float get_svg_scale_factor(wxWindow* win);
|
||||
|
||||
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name,
|
||||
const int px_cnt = 16, const bool is_horizontal = false, const bool grayscale = false);
|
||||
|
@ -742,308 +741,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DoubleSlider
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// custom message the slider sends to its parent to notify a tick-change:
|
||||
wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
|
||||
|
||||
enum SelectedSlider {
|
||||
ssUndef,
|
||||
ssLower,
|
||||
ssHigher
|
||||
};
|
||||
enum TicksAction{
|
||||
taOnIcon,
|
||||
taAdd,
|
||||
taDel
|
||||
};
|
||||
|
||||
class DoubleSlider : public wxControl
|
||||
{
|
||||
enum IconFocus {
|
||||
ifNone,
|
||||
ifRevert,
|
||||
ifCog
|
||||
};
|
||||
public:
|
||||
DoubleSlider(
|
||||
wxWindow *parent,
|
||||
wxWindowID id,
|
||||
int lowerValue,
|
||||
int higherValue,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxSL_VERTICAL,
|
||||
const wxValidator& val = wxDefaultValidator,
|
||||
const wxString& name = wxEmptyString);
|
||||
~DoubleSlider() {}
|
||||
|
||||
using t_mode = Slic3r::Model::CustomGCodeInfo::MODE;
|
||||
|
||||
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
|
||||
* So, let use same value as a permissible error for layer height.
|
||||
*/
|
||||
static double epsilon() { return 0.0011;}
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
int GetMinValue() const { return m_min_value; }
|
||||
int GetMaxValue() const { return m_max_value; }
|
||||
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value]; }
|
||||
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value]; }
|
||||
int GetLowerValue() const { return m_lower_value; }
|
||||
int GetHigherValue() const { return m_higher_value; }
|
||||
int GetActiveValue() const;
|
||||
wxSize get_min_size() const ;
|
||||
double GetLowerValueD() { return get_double_value(ssLower); }
|
||||
double GetHigherValueD() { return get_double_value(ssHigher); }
|
||||
wxSize DoGetBestSize() const override;
|
||||
void SetLowerValue(const int lower_val);
|
||||
void SetHigherValue(const int higher_val);
|
||||
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
|
||||
void SetSelectionSpan(const int lower_val, const int higher_val);
|
||||
void SetMaxValue(const int max_value);
|
||||
void SetKoefForLabels(const double koef) { m_label_koef = koef; }
|
||||
void SetSliderValues(const std::vector<double>& values) { m_values = values; }
|
||||
void ChangeOneLayerLock();
|
||||
Slic3r::Model::CustomGCodeInfo GetTicksValues() const;
|
||||
void SetTicksValues(const Slic3r::Model::CustomGCodeInfo &custom_gcode_per_print_z);
|
||||
void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; }
|
||||
void DisableTickManipulation() { EnableTickManipulation(false); }
|
||||
|
||||
void SetManipulationMode(t_mode mode) { m_mode = mode; }
|
||||
t_mode GetManipulationMode() const { return m_mode; }
|
||||
|
||||
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
|
||||
{
|
||||
m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder :
|
||||
only_extruder < 0 ? t_mode::SingleExtruder :
|
||||
t_mode::MultiAsSingle;
|
||||
m_only_extruder = only_extruder;
|
||||
}
|
||||
|
||||
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
|
||||
bool is_one_layer() const { return m_is_one_layer; }
|
||||
bool is_lower_at_min() const { return m_lower_value == m_min_value; }
|
||||
bool is_higher_at_max() const { return m_higher_value == m_max_value; }
|
||||
bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); }
|
||||
|
||||
void OnPaint(wxPaintEvent& ) { render();}
|
||||
void OnLeftDown(wxMouseEvent& event);
|
||||
void OnMotion(wxMouseEvent& event);
|
||||
void OnLeftUp(wxMouseEvent& event);
|
||||
void OnEnterWin(wxMouseEvent& event) { enter_window(event, true); }
|
||||
void OnLeaveWin(wxMouseEvent& event) { enter_window(event, false); }
|
||||
void OnWheel(wxMouseEvent& event);
|
||||
void OnKeyDown(wxKeyEvent &event);
|
||||
void OnKeyUp(wxKeyEvent &event);
|
||||
void OnChar(wxKeyEvent &event);
|
||||
void OnRightDown(wxMouseEvent& event);
|
||||
void OnRightUp(wxMouseEvent& event);
|
||||
|
||||
void add_code_as_tick(std::string code, int selected_extruder = -1);
|
||||
// add default action for tick, when press "+"
|
||||
void add_current_tick(bool call_from_keyboard = false);
|
||||
// delete current tick, when press "-"
|
||||
void delete_current_tick();
|
||||
void edit_tick();
|
||||
void edit_extruder_sequence();
|
||||
|
||||
struct TICK_CODE
|
||||
{
|
||||
bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; }
|
||||
bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; }
|
||||
|
||||
int tick = 0;
|
||||
std::string gcode = Slic3r::ColorChangeCode;
|
||||
int extruder = 0;
|
||||
std::string color;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
void render();
|
||||
void draw_focus_rect();
|
||||
void draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end);
|
||||
void draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos);
|
||||
void draw_thumb(wxDC& dc, const wxCoord& pos_coord, const SelectedSlider& selection);
|
||||
void draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& higher_pos);
|
||||
void draw_ticks(wxDC& dc);
|
||||
void draw_colored_band(wxDC& dc);
|
||||
void draw_one_layer_icon(wxDC& dc);
|
||||
void draw_revert_icon(wxDC& dc);
|
||||
void draw_cog_icon(wxDC &dc);
|
||||
void draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection);
|
||||
void draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection);
|
||||
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
|
||||
|
||||
void update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection);
|
||||
void detect_selected_slider(const wxPoint& pt);
|
||||
void correct_lower_value();
|
||||
void correct_higher_value();
|
||||
void move_current_thumb(const bool condition);
|
||||
void enter_window(wxMouseEvent& event, const bool enter);
|
||||
|
||||
private:
|
||||
|
||||
bool is_point_in_rect(const wxPoint& pt, const wxRect& rect);
|
||||
int is_point_near_tick(const wxPoint& pt);
|
||||
|
||||
double get_scroll_step();
|
||||
wxString get_label(const SelectedSlider& selection) const;
|
||||
void get_lower_and_higher_position(int& lower_pos, int& higher_pos);
|
||||
int get_value_from_position(const wxCoord x, const wxCoord y);
|
||||
wxCoord get_position_from_value(const int value);
|
||||
wxSize get_size();
|
||||
void get_size(int *w, int *h);
|
||||
double get_double_value(const SelectedSlider& selection);
|
||||
wxString get_tooltip(IconFocus icon_focus);
|
||||
|
||||
std::string get_color_for_tool_change_tick(std::set<TICK_CODE>::const_iterator it) const;
|
||||
std::string get_color_for_color_change_tick(std::set<TICK_CODE>::const_iterator it) const;
|
||||
int get_extruder_for_tick(int tick);
|
||||
std::set<int> get_used_extruders_for_tick(int tick);
|
||||
|
||||
void post_ticks_changed_event(const std::string& gcode = "");
|
||||
bool check_ticks_changed_event(const std::string& gcode);
|
||||
void append_change_extruder_menu_item(wxMenu*);
|
||||
void append_add_color_change_menu_item(wxMenu*);
|
||||
|
||||
bool is_osx { false };
|
||||
wxFont m_font;
|
||||
int m_min_value;
|
||||
int m_max_value;
|
||||
int m_lower_value;
|
||||
int m_higher_value;
|
||||
ScalableBitmap m_bmp_thumb_higher;
|
||||
ScalableBitmap m_bmp_thumb_lower;
|
||||
ScalableBitmap m_bmp_add_tick_on;
|
||||
ScalableBitmap m_bmp_add_tick_off;
|
||||
ScalableBitmap m_bmp_del_tick_on;
|
||||
ScalableBitmap m_bmp_del_tick_off;
|
||||
ScalableBitmap m_bmp_one_layer_lock_on;
|
||||
ScalableBitmap m_bmp_one_layer_lock_off;
|
||||
ScalableBitmap m_bmp_one_layer_unlock_on;
|
||||
ScalableBitmap m_bmp_one_layer_unlock_off;
|
||||
ScalableBitmap m_bmp_revert;
|
||||
ScalableBitmap m_bmp_cog;
|
||||
SelectedSlider m_selection;
|
||||
bool m_is_left_down = false;
|
||||
bool m_is_right_down = false;
|
||||
bool m_is_one_layer = false;
|
||||
bool m_is_focused = false;
|
||||
bool m_is_action_icon_focesed = false;
|
||||
bool m_is_one_layer_icon_focesed = false;
|
||||
bool m_is_enabled_tick_manipulation = true;
|
||||
bool m_show_context_menu = false;
|
||||
bool m_show_edit_menu = false;
|
||||
bool m_force_edit_extruder_sequence = false;
|
||||
bool m_force_mode_apply = true;
|
||||
bool m_force_add_tick = false;
|
||||
bool m_force_delete_tick = false;
|
||||
t_mode m_mode = t_mode::SingleExtruder;
|
||||
int m_only_extruder = -1;
|
||||
|
||||
wxRect m_rect_lower_thumb;
|
||||
wxRect m_rect_higher_thumb;
|
||||
wxRect m_rect_tick_action;
|
||||
wxRect m_rect_one_layer_icon;
|
||||
wxRect m_rect_revert_icon;
|
||||
wxRect m_rect_cog_icon;
|
||||
wxSize m_thumb_size;
|
||||
int m_tick_icon_dim;
|
||||
int m_lock_icon_dim;
|
||||
int m_revert_icon_dim;
|
||||
int m_cog_icon_dim;
|
||||
long m_style;
|
||||
float m_label_koef = 1.0;
|
||||
|
||||
// control's view variables
|
||||
wxCoord SLIDER_MARGIN; // margin around slider
|
||||
|
||||
wxPen DARK_ORANGE_PEN;
|
||||
wxPen ORANGE_PEN;
|
||||
wxPen LIGHT_ORANGE_PEN;
|
||||
|
||||
wxPen DARK_GREY_PEN;
|
||||
wxPen GREY_PEN;
|
||||
wxPen LIGHT_GREY_PEN;
|
||||
|
||||
std::vector<wxPen*> m_line_pens;
|
||||
std::vector<wxPen*> m_segm_pens;
|
||||
std::vector<double> m_values;
|
||||
|
||||
struct TICK_CODE_INFO
|
||||
{
|
||||
std::set<TICK_CODE> ticks;
|
||||
t_mode mode = t_mode::SingleExtruder;
|
||||
|
||||
bool empty() const { return ticks.empty(); }
|
||||
void set_pause_print_msg(const std::string& message) { pause_print_msg = message; }
|
||||
|
||||
bool add_tick (const int tick, std::string &code, int extruder, double print_z);
|
||||
bool edit_tick (std::set<TICK_CODE>::iterator it, double print_z);
|
||||
void switch_code(const std::string& code_from, const std::string& code_to);
|
||||
void erase_all_ticks_with_code (const std::string& gcode);
|
||||
bool has_tick_with_code (const std::string& gcode);
|
||||
|
||||
void suppress_plus (bool suppress) { m_suppress_plus = suppress;}
|
||||
void suppress_minus(bool suppress) { m_suppress_minus = suppress;}
|
||||
bool suppressed_plus () { return m_suppress_plus ; }
|
||||
bool suppressed_minus() { return m_suppress_minus; }
|
||||
|
||||
private:
|
||||
|
||||
std::string custom_gcode = "";
|
||||
std::string pause_print_msg = "";
|
||||
bool m_suppress_plus = false;
|
||||
bool m_suppress_minus = false;
|
||||
}
|
||||
m_ticks;
|
||||
|
||||
public:
|
||||
struct ExtrudersSequence
|
||||
{
|
||||
bool is_mm_intervals = true;
|
||||
double interval_by_mm = 3.0;
|
||||
int interval_by_layers = 10;
|
||||
std::vector<size_t> extruders = { 0 };
|
||||
|
||||
bool operator==(const ExtrudersSequence& other) const
|
||||
{
|
||||
return (other.is_mm_intervals == this->is_mm_intervals ) &&
|
||||
(other.interval_by_mm == this->interval_by_mm ) &&
|
||||
(other.interval_by_layers == this->interval_by_layers ) &&
|
||||
(other.extruders == this->extruders ) ;
|
||||
}
|
||||
bool operator!=(const ExtrudersSequence& other) const
|
||||
{
|
||||
return (other.is_mm_intervals != this->is_mm_intervals ) &&
|
||||
(other.interval_by_mm != this->interval_by_mm ) &&
|
||||
(other.interval_by_layers != this->interval_by_layers ) &&
|
||||
(other.extruders != this->extruders ) ;
|
||||
}
|
||||
|
||||
void add_extruder(size_t pos)
|
||||
{
|
||||
extruders.insert(extruders.begin() + pos+1, size_t(0));
|
||||
}
|
||||
|
||||
void delete_extruder(size_t pos)
|
||||
{
|
||||
if (extruders.size() == 1)
|
||||
return;// last item can't be deleted
|
||||
extruders.erase(extruders.begin() + pos);
|
||||
}
|
||||
}
|
||||
m_extruders_sequence;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// LockButton
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue