mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-21 07:41:09 -06:00
Merge remote-tracking branch 'origin/master' into ys_hdpi
This commit is contained in:
commit
e2b8c3e33c
49 changed files with 1198 additions and 760 deletions
|
@ -249,10 +249,10 @@ bool Snapshot::equal_to_active(const AppConfig &app_config) const
|
|||
boost::filesystem::path path2 = snapshot_dir / subdir;
|
||||
std::vector<std::string> files1, files2;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(path1))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
|
||||
if (Slic3r::is_ini_file(dir_entry))
|
||||
files1.emplace_back(dir_entry.path().filename().string());
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(path2))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
|
||||
if (Slic3r::is_ini_file(dir_entry))
|
||||
files2.emplace_back(dir_entry.path().filename().string());
|
||||
std::sort(files1.begin(), files1.end());
|
||||
std::sort(files2.begin(), files2.end());
|
||||
|
@ -343,7 +343,7 @@ static void copy_config_dir_single_level(const boost::filesystem::path &path_src
|
|||
throw std::runtime_error(std::string("Slic3r was unable to create a directory at ") + path_dst.string());
|
||||
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(path_src))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
|
||||
if (Slic3r::is_ini_file(dir_entry))
|
||||
boost::filesystem::copy_file(dir_entry.path(), path_dst / dir_entry.path().filename(), boost::filesystem::copy_option::overwrite_if_exists);
|
||||
}
|
||||
|
||||
|
|
|
@ -297,7 +297,7 @@ std::vector<Index> Index::load_db()
|
|||
std::vector<Index> index_db;
|
||||
std::string errors_cummulative;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(cache_dir))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".idx")) {
|
||||
if (Slic3r::is_idx_file(dir_entry)) {
|
||||
Index idx;
|
||||
try {
|
||||
idx.load(dir_entry.path());
|
||||
|
|
|
@ -252,6 +252,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
|||
, is_modifier(false)
|
||||
, is_wipe_tower(false)
|
||||
, is_extrusion_path(false)
|
||||
, force_transparent(false)
|
||||
, tverts_range(0, size_t(-1))
|
||||
, qverts_range(0, size_t(-1))
|
||||
{
|
||||
|
@ -293,6 +294,9 @@ void GLVolume::set_render_color()
|
|||
set_render_color(OUTSIDE_COLOR, 4);
|
||||
else
|
||||
set_render_color(color, 4);
|
||||
|
||||
if (force_transparent)
|
||||
render_color[3] = color[3];
|
||||
}
|
||||
|
||||
void GLVolume::set_color_from_model_volume(const ModelVolume *model_volume)
|
||||
|
|
|
@ -295,6 +295,8 @@ public:
|
|||
bool is_wipe_tower;
|
||||
// Wheter or not this volume has been generated from an extrusion path
|
||||
bool is_extrusion_path;
|
||||
// Wheter or not to always render this volume using its own alpha
|
||||
bool force_transparent;
|
||||
|
||||
// Interleaved triangles & normals with indexed triangles & quads.
|
||||
GLIndexedVertexArray indexed_vertex_array;
|
||||
|
|
|
@ -635,35 +635,32 @@ void ConfigWizard::priv::load_vendors()
|
|||
const auto rsrc_vendor_dir = fs::path(resources_dir()) / "profiles";
|
||||
|
||||
// Load vendors from the "vendors" directory in datadir
|
||||
for (fs::directory_iterator it(vendor_dir); it != fs::directory_iterator(); ++it) {
|
||||
if (it->path().extension() == ".ini") {
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(vendor_dir))
|
||||
if (Slic3r::is_ini_file(dir_entry)) {
|
||||
try {
|
||||
auto vp = VendorProfile::from_ini(it->path());
|
||||
auto vp = VendorProfile::from_ini(dir_entry.path());
|
||||
vendors[vp.id] = std::move(vp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % it->path() % e.what();
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Additionally load up vendors from the application resources directory, but only those not seen in the datadir
|
||||
for (fs::directory_iterator it(rsrc_vendor_dir); it != fs::directory_iterator(); ++it) {
|
||||
if (it->path().extension() == ".ini") {
|
||||
const auto id = it->path().stem().string();
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(rsrc_vendor_dir))
|
||||
if (Slic3r::is_ini_file(dir_entry)) {
|
||||
const auto id = dir_entry.path().stem().string();
|
||||
if (vendors.find(id) == vendors.end()) {
|
||||
try {
|
||||
auto vp = VendorProfile::from_ini(it->path());
|
||||
vendors_rsrc[vp.id] = it->path().filename().string();
|
||||
auto vp = VendorProfile::from_ini(dir_entry.path());
|
||||
vendors_rsrc[vp.id] = dir_entry.path().filename().string();
|
||||
vendors[vp.id] = std::move(vp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % it->path() % e.what();
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load up the set of vendors / models / variants the user has had enabled up till now
|
||||
const AppConfig *app_config = GUI::get_app_config();
|
||||
|
@ -672,14 +669,15 @@ void ConfigWizard::priv::load_vendors()
|
|||
} else {
|
||||
// In case of legacy datadir, try to guess the preference based on the printer preset files that are present
|
||||
const auto printer_dir = fs::path(Slic3r::data_dir()) / "printer";
|
||||
for (fs::directory_iterator it(printer_dir); it != fs::directory_iterator(); ++it) {
|
||||
auto needle = legacy_preset_map.find(it->path().filename().string());
|
||||
if (needle == legacy_preset_map.end()) { continue; }
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(printer_dir))
|
||||
if (Slic3r::is_ini_file(dir_entry)) {
|
||||
auto needle = legacy_preset_map.find(dir_entry.path().filename().string());
|
||||
if (needle == legacy_preset_map.end()) { continue; }
|
||||
|
||||
const auto &model = needle->second.first;
|
||||
const auto &variant = needle->second.second;
|
||||
appconfig_vendors.set_variant("PrusaResearch", model, variant, true);
|
||||
}
|
||||
const auto &model = needle->second.first;
|
||||
const auto &variant = needle->second.second;
|
||||
appconfig_vendors.set_variant("PrusaResearch", model, variant, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1617,6 +1617,9 @@ void GLCanvas3D::Selection::clear()
|
|||
|
||||
_update_type();
|
||||
m_bounding_box_dirty = true;
|
||||
|
||||
// resets the cache in the sidebar
|
||||
wxGetApp().obj_manipul()->reset_cache();
|
||||
}
|
||||
|
||||
// Update the selection based on the map from old indices to new indices after m_volumes changed.
|
||||
|
@ -1817,7 +1820,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
|
|||
if (rot_axis_max != 2 && first_volume_idx != -1) {
|
||||
// Generic rotation, but no rotation around the Z axis.
|
||||
// Always do a local rotation (do not consider the selection to be a rigid body).
|
||||
assert(rotation.z() == 0);
|
||||
assert(is_approx(rotation.z(), 0.0));
|
||||
const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
|
||||
const Vec3d &rotation = first_volume.get_instance_rotation();
|
||||
double z_diff = rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
|
||||
|
@ -1842,7 +1845,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
|
|||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
if (local)
|
||||
volume.set_volume_rotation(rotation);
|
||||
volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
|
||||
else
|
||||
{
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
|
@ -2259,7 +2262,7 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel
|
|||
}
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true) * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
::glTranslated(center(0), center(1), center(2));
|
||||
::glMultMatrixd(orient_matrix.data());
|
||||
}
|
||||
|
@ -3992,13 +3995,12 @@ wxDEFINE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent);
|
|||
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>);
|
||||
|
@ -4286,6 +4288,13 @@ bool GLCanvas3D::is_reload_delayed() const
|
|||
void GLCanvas3D::enable_layers_editing(bool enable)
|
||||
{
|
||||
m_layers_editing.set_enabled(enable);
|
||||
const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
|
||||
for (unsigned int idx : idxs)
|
||||
{
|
||||
GLVolume* v = m_volumes.volumes[idx];
|
||||
if (v->is_modifier)
|
||||
v->force_transparent = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::enable_warning_texture(bool enable)
|
||||
|
@ -4420,6 +4429,7 @@ void GLCanvas3D::update_toolbar_items_visibility()
|
|||
ConfigOptionMode mode = wxGetApp().get_mode();
|
||||
m_toolbar.set_item_visible("more", mode != comSimple);
|
||||
m_toolbar.set_item_visible("fewer", mode != comSimple);
|
||||
m_toolbar.set_item_visible("splitvolumes", mode != comSimple);
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_MODE_AWARE_TOOLBAR_ITEMS
|
||||
|
@ -5046,7 +5056,6 @@ void GLCanvas3D::bind_event_handlers()
|
|||
m_canvas->Bind(wxEVT_MIDDLE_DCLICK, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Bind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Bind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
|
||||
m_canvas->Bind(wxEVT_KEY_DOWN, &GLCanvas3D::on_key_down, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5060,7 +5069,7 @@ void GLCanvas3D::unbind_event_handlers()
|
|||
m_canvas->Unbind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this);
|
||||
m_canvas->Unbind(wxEVT_TIMER, &GLCanvas3D::on_timer, this);
|
||||
m_canvas->Unbind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Unbind(wxEVT_LEFT_UP, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Unbind(wxEVT_LEFT_UP, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Unbind(wxEVT_MIDDLE_DOWN, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Unbind(wxEVT_MIDDLE_UP, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Unbind(wxEVT_RIGHT_DOWN, &GLCanvas3D::on_mouse, this);
|
||||
|
@ -5072,7 +5081,6 @@ void GLCanvas3D::unbind_event_handlers()
|
|||
m_canvas->Unbind(wxEVT_MIDDLE_DCLICK, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Unbind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
|
||||
m_canvas->Unbind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
|
||||
m_canvas->Unbind(wxEVT_KEY_DOWN, &GLCanvas3D::on_key_down, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5091,71 +5099,67 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
|||
|
||||
void GLCanvas3D::on_char(wxKeyEvent& evt)
|
||||
{
|
||||
if (evt.HasModifiers())
|
||||
// see include/wx/defs.h enum wxKeyCode
|
||||
int keyCode = evt.GetKeyCode();
|
||||
int ctrlMask = wxMOD_CONTROL;
|
||||
//#ifdef __APPLE__
|
||||
// ctrlMask |= wxMOD_RAW_CONTROL;
|
||||
//#endif /* __APPLE__ */
|
||||
if ((evt.GetModifiers() & ctrlMask) != 0) {
|
||||
switch (keyCode) {
|
||||
#ifndef __APPLE__
|
||||
// Even though Control+A is captured by the accelerator on OSX/wxWidgets in Slic3r, it works in text edit lines.
|
||||
case WXK_CONTROL_A: post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); break;
|
||||
#endif /* __APPLE__ */
|
||||
#ifdef __APPLE__
|
||||
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
|
||||
#endif /* __APPLE__ */
|
||||
case WXK_DELETE: post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); break;
|
||||
default: evt.Skip();
|
||||
}
|
||||
} else if (evt.HasModifiers()) {
|
||||
evt.Skip();
|
||||
else
|
||||
{
|
||||
int keyCode = evt.GetKeyCode();
|
||||
switch (keyCode - 48)
|
||||
} else {
|
||||
switch (keyCode)
|
||||
{
|
||||
// numerical input
|
||||
case 0: { select_view("iso"); break; }
|
||||
case 1: { select_view("top"); break; }
|
||||
case 2: { select_view("bottom"); break; }
|
||||
case 3: { select_view("front"); break; }
|
||||
case 4: { select_view("rear"); break; }
|
||||
case 5: { select_view("left"); break; }
|
||||
case 6: { select_view("right"); break; }
|
||||
// key ESC
|
||||
case WXK_ESCAPE: { m_gizmos.reset_all_states(); m_dirty = true; break; }
|
||||
#ifdef __APPLE__
|
||||
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
|
||||
#endif /* __APPLE__ */
|
||||
case WXK_DELETE: post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE)); break;
|
||||
case '0': { select_view("iso"); break; }
|
||||
case '1': { select_view("top"); break; }
|
||||
case '2': { select_view("bottom"); break; }
|
||||
case '3': { select_view("front"); break; }
|
||||
case '4': { select_view("rear"); break; }
|
||||
case '5': { select_view("left"); break; }
|
||||
case '6': { select_view("right"); break; }
|
||||
case '+': { post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, +1)); break; }
|
||||
case '-': { post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); break; }
|
||||
case '?': { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; }
|
||||
case 'A':
|
||||
case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; }
|
||||
case 'B':
|
||||
case 'b': { zoom_to_bed(); break; }
|
||||
case 'I':
|
||||
case 'i': { set_camera_zoom(1.0f); break; }
|
||||
case 'O':
|
||||
case 'o': { set_camera_zoom(-1.0f); break; }
|
||||
case 'Z':
|
||||
case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; }
|
||||
default:
|
||||
{
|
||||
if (m_gizmos.handle_shortcut(keyCode, m_selection))
|
||||
{
|
||||
// text input
|
||||
switch (keyCode)
|
||||
{
|
||||
// key ESC
|
||||
case 27: { m_gizmos.reset_all_states(); m_dirty = true; break; }
|
||||
// key +
|
||||
case 43: { post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, +1)); break; }
|
||||
// key -
|
||||
case 45: { post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); break; }
|
||||
// key ?
|
||||
case 63: { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; }
|
||||
// key A/a
|
||||
case 65:
|
||||
case 97: { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; }
|
||||
// key B/b
|
||||
case 66:
|
||||
case 98: { zoom_to_bed(); break; }
|
||||
// key I/i
|
||||
case 73:
|
||||
case 105: { set_camera_zoom(1.0f); break; }
|
||||
// key O/o
|
||||
case 79:
|
||||
case 111: { set_camera_zoom(-1.0f); break; }
|
||||
// key Z/z
|
||||
case 90:
|
||||
case 122:
|
||||
{
|
||||
if (m_selection.is_empty())
|
||||
zoom_to_volumes();
|
||||
else
|
||||
zoom_to_selection();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (m_gizmos.handle_shortcut(keyCode, m_selection))
|
||||
{
|
||||
_update_gizmos_data();
|
||||
m_dirty = true;
|
||||
}
|
||||
else
|
||||
evt.Skip();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
_update_gizmos_data();
|
||||
m_dirty = true;
|
||||
}
|
||||
else
|
||||
evt.Skip();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5354,9 +5358,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
bool already_selected = m_selection.contains_volume(m_hover_volume_id);
|
||||
bool shift_down = evt.ShiftDown();
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
Selection::IndicesList curr_idxs = m_selection.get_volume_idxs();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
if (already_selected && shift_down)
|
||||
m_selection.remove(m_hover_volume_id);
|
||||
|
@ -5373,21 +5375,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
#endif // ENABLE_MOVE_MIN_THRESHOLD
|
||||
}
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
if (curr_idxs != m_selection.get_volume_idxs())
|
||||
{
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
m_gizmos.update_on_off_state(m_selection);
|
||||
_update_gizmos_data();
|
||||
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
wxGetApp().obj_manipul()->update_settings_value(m_selection);
|
||||
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
|
||||
m_dirty = true;
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5679,24 +5674,6 @@ void GLCanvas3D::on_paint(wxPaintEvent& evt)
|
|||
this->render();
|
||||
}
|
||||
|
||||
void GLCanvas3D::on_key_down(wxKeyEvent& evt)
|
||||
{
|
||||
if (evt.HasModifiers())
|
||||
evt.Skip();
|
||||
else
|
||||
{
|
||||
int key = evt.GetKeyCode();
|
||||
#ifdef __WXOSX__
|
||||
if (key == WXK_BACK)
|
||||
#else
|
||||
if (key == WXK_DELETE)
|
||||
#endif // __WXOSX__
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_REMOVE_OBJECT));
|
||||
else
|
||||
evt.Skip();
|
||||
}
|
||||
}
|
||||
|
||||
Size GLCanvas3D::get_canvas_size() const
|
||||
{
|
||||
int w = 0;
|
||||
|
@ -5782,7 +5759,6 @@ void GLCanvas3D::do_move()
|
|||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr)
|
||||
{
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
else if (selection_mode == Selection::Volume)
|
||||
|
@ -5790,20 +5766,6 @@ void GLCanvas3D::do_move()
|
|||
|
||||
object_moved = true;
|
||||
model_object->invalidate_bounding_box();
|
||||
#else
|
||||
if (selection_mode == Selection::Instance)
|
||||
{
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
object_moved = true;
|
||||
}
|
||||
else if (selection_mode == Selection::Volume)
|
||||
{
|
||||
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
|
||||
object_moved = true;
|
||||
}
|
||||
if (object_moved)
|
||||
model_object->invalidate_bounding_box();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
}
|
||||
else if (object_idx == 1000)
|
||||
|
@ -5874,12 +5836,8 @@ void GLCanvas3D::do_rotate()
|
|||
m->translate_instance(i.second, shift);
|
||||
}
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
if (!done.empty())
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
|
||||
#else
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_scale()
|
||||
|
@ -5930,12 +5888,8 @@ void GLCanvas3D::do_scale()
|
|||
m->translate_instance(i.second, shift);
|
||||
}
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
if (!done.empty())
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
|
||||
#else
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_flatten()
|
||||
|
@ -6097,7 +6051,7 @@ bool GLCanvas3D::_init_toolbar()
|
|||
GLToolbarItem::Data item;
|
||||
|
||||
item.name = "add";
|
||||
item.tooltip = GUI::L_str("Add... [Ctrl+I]");
|
||||
item.tooltip = GUI::L_str("Add...") + " [" + GUI::shortkey_ctrl_prefix() + "I]";
|
||||
item.sprite_id = 0;
|
||||
item.is_toggable = false;
|
||||
item.action_event = EVT_GLTOOLBAR_ADD;
|
||||
|
@ -6105,7 +6059,7 @@ bool GLCanvas3D::_init_toolbar()
|
|||
return false;
|
||||
|
||||
item.name = "delete";
|
||||
item.tooltip = GUI::L_str("Delete [Del]");
|
||||
item.tooltip = GUI::L_str("Delete") + " [Del]";
|
||||
item.sprite_id = 1;
|
||||
item.is_toggable = false;
|
||||
item.action_event = EVT_GLTOOLBAR_DELETE;
|
||||
|
@ -6113,7 +6067,7 @@ bool GLCanvas3D::_init_toolbar()
|
|||
return false;
|
||||
|
||||
item.name = "deleteall";
|
||||
item.tooltip = GUI::L_str("Delete all [Ctrl+Del]");
|
||||
item.tooltip = GUI::L_str("Delete all") + " [" + GUI::shortkey_ctrl_prefix() + "Del]";
|
||||
item.sprite_id = 2;
|
||||
item.is_toggable = false;
|
||||
item.action_event = EVT_GLTOOLBAR_DELETE_ALL;
|
||||
|
|
|
@ -121,14 +121,13 @@ wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent);
|
|||
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>); // data: +1 => increase, -1 => decrease
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
|
||||
|
@ -1044,7 +1043,6 @@ public:
|
|||
void on_timer(wxTimerEvent& evt);
|
||||
void on_mouse(wxMouseEvent& evt);
|
||||
void on_paint(wxPaintEvent& evt);
|
||||
void on_key_down(wxKeyEvent& evt);
|
||||
|
||||
Size get_canvas_size() const;
|
||||
Point get_local_mouse_position() const;
|
||||
|
|
|
@ -75,6 +75,30 @@ void break_to_debugger()
|
|||
#endif /* _WIN32 */
|
||||
}
|
||||
|
||||
const std::string& shortkey_ctrl_prefix()
|
||||
{
|
||||
static const std::string str =
|
||||
#ifdef __APPLE__
|
||||
"⌘"
|
||||
#else
|
||||
"Ctrl+"
|
||||
#endif
|
||||
;
|
||||
return str;
|
||||
}
|
||||
|
||||
const std::string& shortkey_alt_prefix()
|
||||
{
|
||||
static const std::string str =
|
||||
#ifdef __APPLE__
|
||||
"⌥"
|
||||
#else
|
||||
"Alt+"
|
||||
#endif
|
||||
;
|
||||
return str;
|
||||
}
|
||||
|
||||
bool config_wizard_startup(bool app_config_exists)
|
||||
{
|
||||
if (!app_config_exists || wxGetApp().preset_bundle->printers.size() <= 1) {
|
||||
|
|
|
@ -27,7 +27,11 @@ void enable_screensaver();
|
|||
bool debugged();
|
||||
void break_to_debugger();
|
||||
|
||||
AppConfig* get_app_config();
|
||||
// Platform specific Ctrl+/Alt+ (Windows, Linux) vs. ⌘/⌥ (OSX) prefixes
|
||||
extern const std::string& shortkey_ctrl_prefix();
|
||||
extern const std::string& shortkey_alt_prefix();
|
||||
|
||||
extern AppConfig* get_app_config();
|
||||
|
||||
extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change);
|
||||
|
||||
|
|
|
@ -562,7 +562,13 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
|||
local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _(L("Take Configuration &Snapshot")), _(L("Capture a configuration snapshot")));
|
||||
// local_menu->Append(config_id_base + ConfigMenuUpdate, _(L("Check for updates")), _(L("Check for configuration updates")));
|
||||
local_menu->AppendSeparator();
|
||||
local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("&Preferences")) + dots + "\tCtrl+P", _(L("Application preferences")));
|
||||
local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("&Preferences")) + dots +
|
||||
#ifdef __APPLE__
|
||||
"\tCtrl+,",
|
||||
#else
|
||||
"\tCtrl+P",
|
||||
#endif
|
||||
_(L("Application preferences")));
|
||||
local_menu->AppendSeparator();
|
||||
auto mode_menu = new wxMenu();
|
||||
mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple, _(L("Simple")), _(L("Simple View Mode")));
|
||||
|
|
|
@ -66,6 +66,12 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||
|
||||
// describe control behavior
|
||||
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) {
|
||||
#ifndef __APPLE__
|
||||
// On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called
|
||||
// before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object
|
||||
// manipulator cache with the following call to selection_changed()
|
||||
wxGetApp().obj_manipul()->emulate_kill_focus();
|
||||
#endif // __APPLE__
|
||||
selection_changed();
|
||||
#ifndef __WXMSW__
|
||||
set_tooltip_for_item(get_mouse_position_in_control());
|
||||
|
|
|
@ -17,103 +17,24 @@ namespace GUI
|
|||
|
||||
ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
OG_Settings(parent, true)
|
||||
#ifndef __APPLE__
|
||||
, m_focused_option("")
|
||||
#endif // __APPLE__
|
||||
{
|
||||
m_og->set_name(_(L("Object Manipulation")));
|
||||
m_og->label_width = 9 * wxGetApp().em_unit();//125;
|
||||
m_og->set_grid_vgap(5);
|
||||
|
||||
m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) {
|
||||
std::vector<std::string> axes{ "_x", "_y", "_z" };
|
||||
|
||||
std::string param;
|
||||
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
|
||||
|
||||
size_t i = 0;
|
||||
Vec3d new_value;
|
||||
for (auto axis : axes)
|
||||
new_value(i++) = boost::any_cast<double>(m_og->get_value(param+axis));
|
||||
|
||||
if (param == "position")
|
||||
change_position_value(new_value);
|
||||
else if (param == "rotation")
|
||||
change_rotation_value(new_value);
|
||||
else if (param == "scale")
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
change_scale_value(new_value);
|
||||
#else
|
||||
change_scale_value(new_value);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
else if (param == "size")
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
change_size_value(new_value);
|
||||
#else
|
||||
change_size_value(new_value);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false);
|
||||
};
|
||||
|
||||
m_og->m_fill_empty_value = [this](const std::string& opt_key)
|
||||
{
|
||||
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
this->update_if_dirty();
|
||||
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
std::string param;
|
||||
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
|
||||
|
||||
double value = 0.0;
|
||||
|
||||
if (param == "position") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
value = m_cache.position(axis);
|
||||
#else
|
||||
value = m_cache_position(axis);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
else if (param == "rotation") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
value = m_cache.rotation(axis);
|
||||
#else
|
||||
value = m_cache_rotation(axis);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
else if (param == "scale") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
value = m_cache.scale(axis);
|
||||
#else
|
||||
value = m_cache_scale(axis);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
else if (param == "size") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
value = m_cache.size(axis);
|
||||
#else
|
||||
value = m_cache_size(axis);
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
|
||||
m_og->set_value(opt_key, double_to_string(value));
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false);
|
||||
};
|
||||
m_og->m_on_change = std::bind(&ObjectManipulation::on_change, this, std::placeholders::_1, std::placeholders::_2);
|
||||
m_og->m_fill_empty_value = std::bind(&ObjectManipulation::on_fill_empty_value, this, std::placeholders::_1);
|
||||
|
||||
m_og->m_set_focus = [this](const std::string& opt_key)
|
||||
{
|
||||
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
this->update_if_dirty();
|
||||
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
#ifndef __APPLE__
|
||||
m_focused_option = opt_key;
|
||||
#endif // __APPLE__
|
||||
|
||||
// needed to show the visual hints in 3D scene
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, true);
|
||||
};
|
||||
|
||||
|
@ -233,9 +154,6 @@ void ObjectManipulation::UpdateAndShow(const bool show)
|
|||
{
|
||||
if (show) {
|
||||
update_settings_value(wxGetApp().plater()->canvas3D()->get_selection());
|
||||
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
update_if_dirty();
|
||||
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
|
||||
OG_Settings::UpdateAndShow(show);
|
||||
|
@ -254,7 +172,6 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
m_new_rotation = volume->get_instance_rotation();
|
||||
m_new_scale = volume->get_instance_scaling_factor();
|
||||
int obj_idx = volume->object_idx();
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
int instance_idx = volume->instance_idx();
|
||||
if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size()))
|
||||
{
|
||||
|
@ -270,21 +187,12 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
else
|
||||
// this should never happen
|
||||
m_new_size = Vec3d::Zero();
|
||||
#else
|
||||
if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size()))
|
||||
m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size();
|
||||
else
|
||||
// this should never happen
|
||||
m_new_size = Vec3d::Zero();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else if (selection.is_single_full_object())
|
||||
{
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
m_cache.instance.reset();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
m_new_position = box.center();
|
||||
|
@ -297,9 +205,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
}
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume())
|
||||
{
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
m_cache.instance.reset();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
// the selection contains a single volume
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
|
@ -329,7 +235,6 @@ void ObjectManipulation::update_if_dirty()
|
|||
if (!m_dirty)
|
||||
return;
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
if (m_cache.move_label_string != _(m_new_move_label_string)+ ":")
|
||||
{
|
||||
m_cache.move_label_string = _(m_new_move_label_string)+ ":";
|
||||
|
@ -382,16 +287,22 @@ void ObjectManipulation::update_if_dirty()
|
|||
|
||||
m_cache.size = m_new_size;
|
||||
|
||||
Vec3d deg_rotation;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
deg_rotation(i) = Geometry::rad2deg(m_new_rotation(i));
|
||||
}
|
||||
|
||||
if (m_cache.rotation(0) != m_new_rotation(0))
|
||||
m_og->set_value("rotation_x", double_to_string(Geometry::rad2deg(m_new_rotation(0)), 2));
|
||||
m_og->set_value("rotation_x", double_to_string(deg_rotation(0), 2));
|
||||
|
||||
if (m_cache.rotation(1) != m_new_rotation(1))
|
||||
m_og->set_value("rotation_y", double_to_string(Geometry::rad2deg(m_new_rotation(1)), 2));
|
||||
m_og->set_value("rotation_y", double_to_string(deg_rotation(1), 2));
|
||||
|
||||
if (m_cache.rotation(2) != m_new_rotation(2))
|
||||
m_og->set_value("rotation_z", double_to_string(Geometry::rad2deg(m_new_rotation(2)), 2));
|
||||
m_og->set_value("rotation_z", double_to_string(deg_rotation(2), 2));
|
||||
|
||||
m_cache.rotation = m_new_rotation;
|
||||
m_cache.rotation = deg_rotation;
|
||||
|
||||
if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) {
|
||||
m_lock_bnt->SetLock(true);
|
||||
|
@ -406,41 +317,27 @@ void ObjectManipulation::update_if_dirty()
|
|||
m_og->enable();
|
||||
else
|
||||
m_og->disable();
|
||||
#else
|
||||
m_move_Label->SetLabel(_(m_new_move_label_string));
|
||||
m_rotate_Label->SetLabel(_(m_new_rotate_label_string));
|
||||
m_scale_Label->SetLabel(_(m_new_scale_label_string));
|
||||
|
||||
m_og->set_value("position_x", double_to_string(m_new_position(0), 2));
|
||||
m_og->set_value("position_y", double_to_string(m_new_position(1), 2));
|
||||
m_og->set_value("position_z", double_to_string(m_new_position(2), 2));
|
||||
m_cache_position = m_new_position;
|
||||
|
||||
auto scale = m_new_scale * 100.0;
|
||||
m_og->set_value("scale_x", double_to_string(scale(0), 2));
|
||||
m_og->set_value("scale_y", double_to_string(scale(1), 2));
|
||||
m_og->set_value("scale_z", double_to_string(scale(2), 2));
|
||||
m_cache_scale = scale;
|
||||
|
||||
m_og->set_value("size_x", double_to_string(m_new_size(0), 2));
|
||||
m_og->set_value("size_y", double_to_string(m_new_size(1), 2));
|
||||
m_og->set_value("size_z", double_to_string(m_new_size(2), 2));
|
||||
m_cache_size = m_new_size;
|
||||
|
||||
m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(0)), 0), 2));
|
||||
m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(1)), 0), 2));
|
||||
m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(2)), 0), 2));
|
||||
m_cache_rotation = m_new_rotation;
|
||||
|
||||
if (m_new_enabled)
|
||||
m_og->enable();
|
||||
else
|
||||
m_og->disable();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
void ObjectManipulation::emulate_kill_focus()
|
||||
{
|
||||
if (m_focused_option.empty())
|
||||
return;
|
||||
|
||||
// we need to use a copy because the value of m_focused_option is modified inside on_change() and on_fill_empty_value()
|
||||
std::string option = m_focused_option;
|
||||
|
||||
// see TextCtrl::propagate_value()
|
||||
if (static_cast<wxTextCtrl*>(m_og->get_fieldc(option, 0)->getWindow())->GetValue().empty())
|
||||
on_fill_empty_value(option);
|
||||
else
|
||||
on_change(option, 0);
|
||||
}
|
||||
#endif // __APPLE__
|
||||
|
||||
void ObjectManipulation::reset_settings_value()
|
||||
{
|
||||
m_new_position = Vec3d::Zero();
|
||||
|
@ -448,9 +345,7 @@ void ObjectManipulation::reset_settings_value()
|
|||
m_new_scale = Vec3d::Ones();
|
||||
m_new_size = Vec3d::Zero();
|
||||
m_new_enabled = false;
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
m_cache.instance.reset();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
|
@ -459,18 +354,10 @@ void ObjectManipulation::change_position_value(const Vec3d& position)
|
|||
auto canvas = wxGetApp().plater()->canvas3D();
|
||||
GLCanvas3D::Selection& selection = canvas->get_selection();
|
||||
selection.start_dragging();
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
selection.translate(position - m_cache.position, selection.requires_local_axes());
|
||||
#else
|
||||
selection.translate(position - m_cache_position, selection.requires_local_axes());
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
canvas->do_move();
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
m_cache.position = position;
|
||||
#else
|
||||
m_cache_position = position;
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
|
||||
void ObjectManipulation::change_rotation_value(const Vec3d& rotation)
|
||||
|
@ -478,23 +365,19 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation)
|
|||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
const GLCanvas3D::Selection& selection = canvas->get_selection();
|
||||
|
||||
Vec3d delta_rotation = rotation - m_cache.rotation;
|
||||
|
||||
Vec3d rad_rotation;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
rad_rotation(i) = Geometry::deg2rad(rotation(i));
|
||||
rad_rotation(i) = Geometry::deg2rad(delta_rotation(i));
|
||||
}
|
||||
|
||||
canvas->get_selection().start_dragging();
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance() || selection.requires_local_axes());
|
||||
#else
|
||||
canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance());
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
canvas->do_rotate();
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
m_cache.rotation = rotation;
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
|
||||
void ObjectManipulation::change_scale_value(const Vec3d& scale)
|
||||
|
@ -503,11 +386,7 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale)
|
|||
const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
if (m_uniform_scale || selection.requires_uniform_scale())
|
||||
{
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs();
|
||||
#else
|
||||
Vec3d abs_scale_diff = (scale - m_cache_scale).cwiseAbs();
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
double max_diff = abs_scale_diff(X);
|
||||
Axis max_diff_axis = X;
|
||||
if (max_diff < abs_scale_diff(Y))
|
||||
|
@ -530,12 +409,10 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale)
|
|||
canvas->get_selection().scale(scaling_factor, false);
|
||||
canvas->do_scale();
|
||||
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
if (!m_cache.scale.isApprox(scale))
|
||||
m_cache.instance.instance_idx = -1;
|
||||
|
||||
m_cache.scale = scale;
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
}
|
||||
|
||||
void ObjectManipulation::change_size_value(const Vec3d& size)
|
||||
|
@ -543,7 +420,6 @@ void ObjectManipulation::change_size_value(const Vec3d& size)
|
|||
const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
|
||||
Vec3d ref_size = m_cache.size;
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
{
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
|
@ -581,15 +457,81 @@ void ObjectManipulation::change_size_value(const Vec3d& size)
|
|||
canvas->do_scale();
|
||||
|
||||
m_cache.size = size;
|
||||
#else
|
||||
if (selection.is_single_full_instance())
|
||||
{
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
ref_size = volume->bounding_box.size();
|
||||
}
|
||||
|
||||
void ObjectManipulation::on_change(const t_config_option_key& opt_key, const boost::any& value)
|
||||
{
|
||||
// needed to hide the visual hints in 3D scene
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false);
|
||||
#ifndef __APPLE__
|
||||
m_focused_option = "";
|
||||
#endif // __APPLE__
|
||||
|
||||
if (!m_cache.is_valid())
|
||||
return;
|
||||
|
||||
std::vector<std::string> axes{ "_x", "_y", "_z" };
|
||||
|
||||
std::string param;
|
||||
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
|
||||
|
||||
size_t i = 0;
|
||||
Vec3d new_value;
|
||||
for (auto axis : axes)
|
||||
new_value(i++) = boost::any_cast<double>(m_og->get_value(param + axis));
|
||||
|
||||
if (param == "position")
|
||||
change_position_value(new_value);
|
||||
else if (param == "rotation")
|
||||
change_rotation_value(new_value);
|
||||
else if (param == "scale")
|
||||
change_scale_value(new_value);
|
||||
else if (param == "size")
|
||||
change_size_value(new_value);
|
||||
}
|
||||
|
||||
void ObjectManipulation::on_fill_empty_value(const std::string& opt_key)
|
||||
{
|
||||
// needed to hide the visual hints in 3D scene
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false);
|
||||
#ifndef __APPLE__
|
||||
m_focused_option = "";
|
||||
#endif // __APPLE__
|
||||
|
||||
if (!m_cache.is_valid())
|
||||
return;
|
||||
|
||||
std::string param;
|
||||
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
|
||||
|
||||
double value = 0.0;
|
||||
|
||||
if (param == "position") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
value = m_cache.position(axis);
|
||||
}
|
||||
else if (param == "rotation") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
value = m_cache.rotation(axis);
|
||||
}
|
||||
else if (param == "scale") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
value = m_cache.scale(axis);
|
||||
}
|
||||
else if (param == "size") {
|
||||
int axis = opt_key.back() == 'x' ? 0 :
|
||||
opt_key.back() == 'y' ? 1 : 2;
|
||||
|
||||
value = m_cache.size(axis);
|
||||
}
|
||||
|
||||
change_scale_value(100.0 * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)));
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
m_og->set_value(opt_key, double_to_string(value));
|
||||
}
|
||||
|
||||
} //namespace GUI
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace GUI {
|
|||
|
||||
class ObjectManipulation : public OG_Settings
|
||||
{
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
struct Cache
|
||||
{
|
||||
Vec3d position;
|
||||
|
@ -43,20 +42,22 @@ class ObjectManipulation : public OG_Settings
|
|||
|
||||
Instance instance;
|
||||
|
||||
Cache() : position(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , rotation(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))
|
||||
, scale(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , size(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))
|
||||
, move_label_string("") , rotate_label_string("") , scale_label_string("")
|
||||
Cache() { reset(); }
|
||||
void reset()
|
||||
{
|
||||
position = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
rotation = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
scale = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
size = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
move_label_string = "";
|
||||
rotate_label_string = "";
|
||||
scale_label_string = "";
|
||||
instance.reset();
|
||||
}
|
||||
bool is_valid() const { return position != Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); }
|
||||
};
|
||||
|
||||
Cache m_cache;
|
||||
#else
|
||||
Vec3d m_cache_position{ 0., 0., 0. };
|
||||
Vec3d m_cache_rotation{ 0., 0., 0. };
|
||||
Vec3d m_cache_scale{ 100., 100., 100. };
|
||||
Vec3d m_cache_size{ 0., 0., 0. };
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
|
||||
wxStaticText* m_move_Label = nullptr;
|
||||
wxStaticText* m_scale_Label = nullptr;
|
||||
|
@ -76,6 +77,11 @@ class ObjectManipulation : public OG_Settings
|
|||
bool m_uniform_scale {true};
|
||||
PrusaLockButton* m_lock_bnt{ nullptr };
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Currently focused option name (empty if none)
|
||||
std::string m_focused_option;
|
||||
#endif // __APPLE__
|
||||
|
||||
public:
|
||||
ObjectManipulation(wxWindow* parent);
|
||||
~ObjectManipulation() {}
|
||||
|
@ -92,6 +98,14 @@ public:
|
|||
void set_uniform_scaling(const bool uniform_scale) { m_uniform_scale = uniform_scale;}
|
||||
bool get_uniform_scaling() const { return m_uniform_scale; }
|
||||
|
||||
void reset_cache() { m_cache.reset(); }
|
||||
#ifndef __APPLE__
|
||||
// On Windows and Linux, emulates a kill focus event on the currently focused option (if any)
|
||||
// Used only in ObjectList wxEVT_DATAVIEW_SELECTION_CHANGED handler which is called before the regular kill focus event
|
||||
// bound to this class when changing selection in the objects list
|
||||
void emulate_kill_focus();
|
||||
#endif // __APPLE__
|
||||
|
||||
private:
|
||||
void reset_settings_value();
|
||||
|
||||
|
@ -105,6 +119,9 @@ private:
|
|||
void change_rotation_value(const Vec3d& rotation);
|
||||
void change_scale_value(const Vec3d& scale);
|
||||
void change_size_value(const Vec3d& size);
|
||||
|
||||
void on_change(const t_config_option_key& opt_key, const boost::any& value);
|
||||
void on_fill_empty_value(const std::string& opt_key);
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -88,13 +88,8 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
|
||||
void KBShortcutsDialog::fill_shortcuts()
|
||||
{
|
||||
#ifdef __WXOSX__
|
||||
const std::string ctrl = "⌘";
|
||||
const std::string alt = "⌥";
|
||||
#else
|
||||
const std::string ctrl = "Ctrl+";
|
||||
const std::string alt = "Alt+";
|
||||
#endif // __WXOSX__
|
||||
const std::string &ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const std::string &alt = GUI::shortkey_alt_prefix();
|
||||
|
||||
m_full_shortcuts.reserve(4);
|
||||
|
||||
|
|
|
@ -329,7 +329,19 @@ void MainFrame::init_menubar()
|
|||
if (m_plater != nullptr)
|
||||
{
|
||||
editMenu = new wxMenu();
|
||||
wxMenuItem* item_select_all = append_menu_item(editMenu, wxID_ANY, _(L("&Select all")) + "\tCtrl+A", _(L("Selects all objects")),
|
||||
// \xA0 is a non-breaking space. It is entered here to spoil the automatic accelerators,
|
||||
// as the simple numeric accelerators spoil all numeric data entry.
|
||||
wxMenuItem* item_select_all = append_menu_item(editMenu, wxID_ANY, _(L("&Select all")) +
|
||||
#ifdef _MSC_VER
|
||||
"\t\xA0" + "Ctrl+\xA0" + "A"
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
"\tCtrl+A"
|
||||
#else
|
||||
" - Ctrl+A"
|
||||
#endif
|
||||
#endif
|
||||
, _(L("Selects all objects")),
|
||||
[this](wxCommandEvent&) { m_plater->select_all(); }, "");
|
||||
editMenu->AppendSeparator();
|
||||
wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + "\tDel", _(L("Deletes the current selection")),
|
||||
|
@ -391,19 +403,23 @@ void MainFrame::init_menubar()
|
|||
|
||||
// View menu
|
||||
wxMenu* viewMenu = nullptr;
|
||||
wxString sep =
|
||||
#ifdef _MSC_VER
|
||||
"\t";
|
||||
#else
|
||||
" - ";
|
||||
#endif
|
||||
if (m_plater) {
|
||||
viewMenu = new wxMenu();
|
||||
// \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators,
|
||||
// as the simple numeric accelerators spoil all numeric data entry.
|
||||
// The camera control accelerators are captured by GLCanvas3D::on_char().
|
||||
wxMenuItem* item_iso = append_menu_item(viewMenu, wxID_ANY, _(L("&Iso")) + "\t\xA0" + "0", _(L("Iso View")), [this](wxCommandEvent&) { select_view("iso"); });
|
||||
wxMenuItem* item_iso = append_menu_item(viewMenu, wxID_ANY, _(L("Iso")) + sep + "&0", _(L("Iso View")), [this](wxCommandEvent&) { select_view("iso"); });
|
||||
viewMenu->AppendSeparator();
|
||||
wxMenuItem* item_top = append_menu_item(viewMenu, wxID_ANY, _(L("&Top")) + "\t\xA0" + "1", _(L("Top View")), [this](wxCommandEvent&) { select_view("top"); });
|
||||
wxMenuItem* item_bottom = append_menu_item(viewMenu, wxID_ANY, _(L("&Bottom")) + "\t\xA0" + "2", _(L("Bottom View")), [this](wxCommandEvent&) { select_view("bottom"); });
|
||||
wxMenuItem* item_front = append_menu_item(viewMenu, wxID_ANY, _(L("&Front")) + "\t\xA0" + "3", _(L("Front View")), [this](wxCommandEvent&) { select_view("front"); });
|
||||
wxMenuItem* item_rear = append_menu_item(viewMenu, wxID_ANY, _(L("R&ear")) + "\t\xA0" + "4", _(L("Rear View")), [this](wxCommandEvent&) { select_view("rear"); });
|
||||
wxMenuItem* item_left = append_menu_item(viewMenu, wxID_ANY, _(L("&Left")) + "\t\xA0" + "5", _(L("Left View")), [this](wxCommandEvent&) { select_view("left"); });
|
||||
wxMenuItem* item_right = append_menu_item(viewMenu, wxID_ANY, _(L("&Right")) + "\t\xA0" + "6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); });
|
||||
wxMenuItem* item_top = append_menu_item(viewMenu, wxID_ANY, _(L("Top")) + sep + "&1", _(L("Top View")), [this](wxCommandEvent&) { select_view("top"); });
|
||||
wxMenuItem* item_bottom = append_menu_item(viewMenu, wxID_ANY, _(L("Bottom")) + sep + "&2", _(L("Bottom View")), [this](wxCommandEvent&) { select_view("bottom"); });
|
||||
wxMenuItem* item_front = append_menu_item(viewMenu, wxID_ANY, _(L("Front")) + sep + "&3", _(L("Front View")), [this](wxCommandEvent&) { select_view("front"); });
|
||||
wxMenuItem* item_rear = append_menu_item(viewMenu, wxID_ANY, _(L("Rear")) + sep + "&4", _(L("Rear View")), [this](wxCommandEvent&) { select_view("rear"); });
|
||||
wxMenuItem* item_left = append_menu_item(viewMenu, wxID_ANY, _(L("Left")) + sep + "&5", _(L("Left View")), [this](wxCommandEvent&) { select_view("left"); });
|
||||
wxMenuItem* item_right = append_menu_item(viewMenu, wxID_ANY, _(L("Right")) + sep + "&6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); });
|
||||
|
||||
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_iso->GetId());
|
||||
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_top->GetId());
|
||||
|
@ -439,7 +455,7 @@ void MainFrame::init_menubar()
|
|||
append_menu_item(helpMenu, wxID_ANY, _(L("&About Slic3r")), _(L("Show about dialog")),
|
||||
[this](wxCommandEvent&) { Slic3r::GUI::about(); });
|
||||
helpMenu->AppendSeparator();
|
||||
append_menu_item(helpMenu, wxID_ANY, _(L("&Keyboard Shortcuts")) + "\t\xA0?", _(L("Show the list of the keyboard shortcuts")),
|
||||
append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + sep + "&?", _(L("Show the list of the keyboard shortcuts")),
|
||||
[this](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); });
|
||||
}
|
||||
|
||||
|
|
|
@ -896,7 +896,7 @@ std::vector<PresetComboBox*>& Sidebar::combos_filament()
|
|||
class PlaterDropTarget : public wxFileDropTarget
|
||||
{
|
||||
public:
|
||||
PlaterDropTarget(Plater *plater) : plater(plater) {}
|
||||
PlaterDropTarget(Plater *plater) : plater(plater) { this->SetDefaultAction(wxDragCopy); }
|
||||
|
||||
virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames);
|
||||
|
||||
|
@ -1028,7 +1028,8 @@ struct Plater::priv
|
|||
unsigned int update_background_process(bool force_validation = false);
|
||||
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
|
||||
bool restart_background_process(unsigned int state);
|
||||
void update_restart_background_process(bool force_scene_update, bool force_preview_update);
|
||||
// returns bit mask of UpdateBackgroundProcessReturnState
|
||||
unsigned int update_restart_background_process(bool force_scene_update, bool force_preview_update);
|
||||
void export_gcode(fs::path output_path, PrintHostJob upload_job);
|
||||
void reload_from_disk();
|
||||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
||||
|
@ -1170,15 +1171,14 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
view3D_canvas->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this);
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_SELECT_ALL, [this](SimpleEvent&) { this->q->select_all(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [this](Event<int> &evt)
|
||||
{ if (evt.data == 1) this->q->increase_instances(); else if (this->can_decrease_instances()) this->q->decrease_instances(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this);
|
||||
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); });
|
||||
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event<bool> &evt) { this->sidebar->enable_buttons(evt.data); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this);
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, &priv::on_3dcanvas_mouse_dragging_finished, this);
|
||||
|
@ -1577,7 +1577,7 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
|
|||
// Update printbility state of each of the ModelInstances.
|
||||
this->update_print_volume_state();
|
||||
// Find the file name of the first printable object.
|
||||
fs::path output_file = this->model.propose_export_file_name();
|
||||
fs::path output_file = this->model.propose_export_file_name_and_path();
|
||||
|
||||
switch (file_type) {
|
||||
case FT_STL: output_file.replace_extension("stl"); break;
|
||||
|
@ -1737,6 +1737,8 @@ void Plater::priv::arrange()
|
|||
// Guard the arrange process
|
||||
arranging.store(true);
|
||||
|
||||
wxBusyCursor wait;
|
||||
|
||||
// Disable the arrange button (to prevent reentrancies, we will call wxYied)
|
||||
view3D->enable_toolbar_item("arrange", can_arrange());
|
||||
|
||||
|
@ -2047,7 +2049,7 @@ void Plater::priv::export_gcode(fs::path output_path, PrintHostJob upload_job)
|
|||
this->restart_background_process(priv::UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT);
|
||||
}
|
||||
|
||||
void Plater::priv::update_restart_background_process(bool force_update_scene, bool force_update_preview)
|
||||
unsigned int Plater::priv::update_restart_background_process(bool force_update_scene, bool force_update_preview)
|
||||
{
|
||||
// bitmask of UpdateBackgroundProcessReturnState
|
||||
unsigned int state = this->update_background_process(false);
|
||||
|
@ -2057,6 +2059,7 @@ void Plater::priv::update_restart_background_process(bool force_update_scene, bo
|
|||
if (force_update_preview)
|
||||
this->preview->reload_print();
|
||||
this->restart_background_process(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
void Plater::priv::update_fff_scene()
|
||||
|
@ -2110,31 +2113,10 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* =
|
|||
{
|
||||
if (obj_idx < 0)
|
||||
return;
|
||||
|
||||
const auto model_object = model.objects[obj_idx];
|
||||
Model model_fixed;// = new Model();
|
||||
fix_model_by_win10_sdk_gui(*model_object, this->fff_print, model_fixed);
|
||||
|
||||
auto new_obj_idxs = load_model_objects(model_fixed.objects);
|
||||
if (new_obj_idxs.empty())
|
||||
return;
|
||||
|
||||
for(auto new_obj_idx : new_obj_idxs) {
|
||||
auto o = model.objects[new_obj_idx];
|
||||
o->clear_instances();
|
||||
for (auto instance: model_object->instances)
|
||||
o->add_instance(*instance);
|
||||
o->invalidate_bounding_box();
|
||||
|
||||
if (o->volumes.size() == model_object->volumes.size()) {
|
||||
for (int i = 0; i < o->volumes.size(); i++) {
|
||||
o->volumes[i]->config.apply(model_object->volumes[i]->config);
|
||||
}
|
||||
}
|
||||
// FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile
|
||||
}
|
||||
|
||||
remove(obj_idx);
|
||||
fix_model_by_win10_sdk_gui(*model.objects[obj_idx], vol_idx);
|
||||
this->object_list_changed();
|
||||
this->update();
|
||||
this->schedule_background_process();
|
||||
}
|
||||
|
||||
void Plater::priv::set_current_panel(wxPanel* panel)
|
||||
|
@ -2555,7 +2537,7 @@ void Plater::priv::init_view_toolbar()
|
|||
GLToolbarItem::Data item;
|
||||
|
||||
item.name = "3D";
|
||||
item.tooltip = GUI::L_str("3D editor view [Ctrl+5]");
|
||||
item.tooltip = GUI::L_str("3D editor view") + " [" + GUI::shortkey_ctrl_prefix() + "5]";
|
||||
item.sprite_id = 0;
|
||||
item.action_event = EVT_GLVIEWTOOLBAR_3D;
|
||||
item.is_toggable = false;
|
||||
|
@ -2563,7 +2545,7 @@ void Plater::priv::init_view_toolbar()
|
|||
return;
|
||||
|
||||
item.name = "Preview";
|
||||
item.tooltip = GUI::L_str("Preview [Ctrl+6]");
|
||||
item.tooltip = GUI::L_str("Preview") + " [" + GUI::shortkey_ctrl_prefix() + "6]";
|
||||
item.sprite_id = 1;
|
||||
item.action_event = EVT_GLVIEWTOOLBAR_PREVIEW;
|
||||
item.is_toggable = false;
|
||||
|
@ -2848,51 +2830,43 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
|
|||
p->load_model_objects(new_objects);
|
||||
}
|
||||
|
||||
void Plater::export_gcode(fs::path output_path)
|
||||
void Plater::export_gcode()
|
||||
{
|
||||
if (p->model.objects.empty())
|
||||
return;
|
||||
|
||||
// select output file
|
||||
if (output_path.empty()) {
|
||||
// XXX: take output path from CLI opts? Ancient Slic3r versions used to do that...
|
||||
|
||||
// If possible, remove accents from accented latin characters.
|
||||
// This function is useful for generating file names to be processed by legacy firmwares.
|
||||
fs::path default_output_file;
|
||||
try {
|
||||
default_output_file = this->p->background_process.current_print()->output_filepath(output_path.string());
|
||||
} catch (const std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
return;
|
||||
}
|
||||
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());
|
||||
|
||||
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")),
|
||||
start_dir,
|
||||
from_path(default_output_file.filename()),
|
||||
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()),
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
||||
);
|
||||
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fs::path path = into_path(dlg.GetPath());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||
output_path = std::move(path);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
output_path = this->p->background_process.current_print()->output_filepath(output_path.string());
|
||||
} catch (const std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
return;
|
||||
}
|
||||
// If possible, remove accents from accented latin characters.
|
||||
// This function is useful for generating file names to be processed by legacy firmwares.
|
||||
fs::path default_output_file;
|
||||
try {
|
||||
// Update the background processing, so that the placeholder parser will get the correct values for the ouput file template.
|
||||
// Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed.
|
||||
unsigned int state = this->p->update_restart_background_process(false, false);
|
||||
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
|
||||
return;
|
||||
default_output_file = this->p->background_process.current_print()->output_filepath("");
|
||||
} catch (const std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
return;
|
||||
}
|
||||
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 (! output_path.empty()) {
|
||||
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")),
|
||||
start_dir,
|
||||
from_path(default_output_file.filename()),
|
||||
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()),
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
||||
);
|
||||
|
||||
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());
|
||||
output_path = std::move(path);
|
||||
}
|
||||
if (! output_path.empty())
|
||||
p->export_gcode(std::move(output_path), PrintHostJob());
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::export_stl(bool selection_only)
|
||||
|
@ -2993,7 +2967,12 @@ void Plater::send_gcode()
|
|||
// Obtain default output path
|
||||
fs::path default_output_file;
|
||||
try {
|
||||
default_output_file = this->p->background_process.current_print()->output_filepath("");
|
||||
// Update the background processing, so that the placeholder parser will get the correct values for the ouput file template.
|
||||
// Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed.
|
||||
unsigned int state = this->p->update_restart_background_process(false, false);
|
||||
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
|
||||
return;
|
||||
default_output_file = this->p->background_process.current_print()->output_filepath("");
|
||||
} catch (const std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
return;
|
||||
|
|
|
@ -140,8 +140,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);
|
||||
|
||||
// Note: empty path means "use the default"
|
||||
void export_gcode(boost::filesystem::path output_path = boost::filesystem::path());
|
||||
void export_gcode();
|
||||
void export_stl(bool selection_only = false);
|
||||
void export_amf();
|
||||
void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
|
||||
|
|
|
@ -336,7 +336,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers",
|
||||
"support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",
|
||||
"support_material_buildplate_only", "dont_support_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
||||
"extruder_clearance_height", "gcode_comments", "output_filename_format", "post_process", "perimeter_extruder",
|
||||
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
|
||||
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
|
@ -517,16 +517,6 @@ void PresetCollection::add_default_preset(const std::vector<std::string> &keys,
|
|||
++ m_num_default_presets;
|
||||
}
|
||||
|
||||
bool is_file_plain(const std::string &path)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
DWORD attributes = GetFileAttributesW(boost::nowide::widen(path).c_str());
|
||||
return (attributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) == 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Load all presets found in dir_path.
|
||||
// Throws an exception on error.
|
||||
void PresetCollection::load_presets(const std::string &dir_path, const std::string &subdir)
|
||||
|
@ -538,10 +528,7 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
|
|||
// (see the "Preset already present, not loading" message).
|
||||
std::deque<Preset> presets_loaded;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini") &&
|
||||
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
|
||||
// https://github.com/prusa3d/Slic3r/issues/1298
|
||||
is_file_plain(dir_entry.path().string())) {
|
||||
if (Slic3r::is_ini_file(dir_entry)) {
|
||||
std::string name = dir_entry.path().filename().string();
|
||||
// Remove the .ini suffix.
|
||||
name.erase(name.size() - 4);
|
||||
|
@ -1163,12 +1150,24 @@ std::string PresetCollection::name() const
|
|||
case Preset::TYPE_PRINT: return L("print");
|
||||
case Preset::TYPE_FILAMENT: return L("filament");
|
||||
case Preset::TYPE_SLA_PRINT: return L("SLA print");
|
||||
case Preset::TYPE_SLA_MATERIAL: return L("SLA material");
|
||||
case Preset::TYPE_SLA_MATERIAL: return L("SLA material");
|
||||
case Preset::TYPE_PRINTER: return L("printer");
|
||||
default: return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
std::string PresetCollection::section_name() const
|
||||
{
|
||||
switch (this->type()) {
|
||||
case Preset::TYPE_PRINT: return "print";
|
||||
case Preset::TYPE_FILAMENT: return "filament";
|
||||
case Preset::TYPE_SLA_PRINT: return "sla_print";
|
||||
case Preset::TYPE_SLA_MATERIAL: return "sla_material";
|
||||
case Preset::TYPE_PRINTER: return "printer";
|
||||
default: return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> PresetCollection::system_preset_names() const
|
||||
{
|
||||
size_t num = 0;
|
||||
|
|
|
@ -230,7 +230,10 @@ public:
|
|||
void reset(bool delete_files);
|
||||
|
||||
Preset::Type type() const { return m_type; }
|
||||
// Name, to be used on the screen and in error messages. Not localized.
|
||||
std::string name() const;
|
||||
// Name, to be used as a section name in config bundle, and as a folder name for presets.
|
||||
std::string section_name() const;
|
||||
const std::deque<Preset>& operator()() const { return m_presets; }
|
||||
|
||||
// Add default preset at the start of the collection, increment the m_default_preset counter.
|
||||
|
|
|
@ -243,7 +243,7 @@ std::string PresetBundle::load_system_presets()
|
|||
std::string errors_cummulative;
|
||||
bool first = true;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini")) {
|
||||
if (Slic3r::is_ini_file(dir_entry)) {
|
||||
std::string name = dir_entry.path().filename().string();
|
||||
// Remove the .ini suffix.
|
||||
name.erase(name.size() - 4);
|
||||
|
@ -1208,7 +1208,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
#else
|
||||
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
|
||||
#endif
|
||||
/ presets->name() / file_name).make_preferred();
|
||||
/ presets->section_name() / file_name).make_preferred();
|
||||
// Load the preset into the list of presets, save it to disk.
|
||||
Preset &loaded = presets->load_preset(file_path.string(), preset_name, std::move(config), false);
|
||||
if (flags & LOAD_CFGBNDLE_SAVE)
|
||||
|
@ -1365,7 +1365,7 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
|
|||
if (preset.is_default || preset.is_external || (preset.is_system && ! export_system_settings))
|
||||
// Only export the common presets, not external files or the default preset.
|
||||
continue;
|
||||
c << std::endl << "[" << presets->name() << ":" << preset.name << "]" << std::endl;
|
||||
c << std::endl << "[" << presets->section_name() << ":" << preset.name << "]" << std::endl;
|
||||
for (const std::string &opt_key : preset.config.keys())
|
||||
c << opt_key << " = " << preset.config.serialize(opt_key) << std::endl;
|
||||
}
|
||||
|
|
|
@ -1097,6 +1097,7 @@ void TabPrint::build()
|
|||
|
||||
optgroup = page->new_optgroup(_(L("Output file")));
|
||||
optgroup->append_single_option_line("gcode_comments");
|
||||
optgroup->append_single_option_line("gcode_label_objects");
|
||||
option = optgroup->get_option("output_filename_format");
|
||||
option.opt.full_width = true;
|
||||
optgroup->append_single_option_line(option);
|
||||
|
|
|
@ -216,7 +216,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
|
|||
|
||||
HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
|
||||
{
|
||||
on_progress(L("Exporting the source model"), 20);
|
||||
on_progress(L("Exporting source model"), 20);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> fileStream;
|
||||
hr = winrt_open_file_stream(boost::nowide::widen(path_src), ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf(), throw_on_cancel);
|
||||
|
@ -239,7 +239,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
|
|||
unsigned num_meshes = 0;
|
||||
hr = meshes->get_Size(&num_meshes);
|
||||
|
||||
on_progress(L("Repairing the model by the Netfabb service"), 40);
|
||||
on_progress(L("Repairing model by the Netfabb service"), 40);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> repairAsync;
|
||||
hr = model->RepairAsync(repairAsync.GetAddressOf());
|
||||
|
@ -248,7 +248,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
|
|||
throw std::runtime_error(L("Mesh repair failed."));
|
||||
repairAsync->GetResults();
|
||||
|
||||
on_progress(L("Loading the repaired model"), 60);
|
||||
on_progress(L("Loading repaired model"), 60);
|
||||
|
||||
// Verify the number of meshes returned after the repair action.
|
||||
meshes.Reset();
|
||||
|
@ -316,7 +316,7 @@ public:
|
|||
const char* what() const throw() { return "Model repair has been canceled"; }
|
||||
};
|
||||
|
||||
void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result)
|
||||
void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
|
@ -329,6 +329,12 @@ void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &pr
|
|||
std::atomic<bool> canceled = false;
|
||||
std::atomic<bool> finished = false;
|
||||
|
||||
std::vector<ModelVolume*> volumes;
|
||||
if (volume_idx == -1)
|
||||
volumes = model_object.volumes;
|
||||
else
|
||||
volumes.emplace_back(model_object.volumes[volume_idx]);
|
||||
|
||||
// Open a progress dialog.
|
||||
wxProgressDialog progress_dialog(
|
||||
_(L("Model fixing")),
|
||||
|
@ -336,43 +342,64 @@ void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &pr
|
|||
100, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
|
||||
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
|
||||
bool success = false;
|
||||
auto on_progress = [&mutex, &condition, &progress](const char *msg, unsigned prcnt) {
|
||||
bool success = false;
|
||||
size_t ivolume = 0;
|
||||
auto on_progress = [&mutex, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
progress.message = msg;
|
||||
progress.percent = prcnt;
|
||||
progress.percent = (int)floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size()));
|
||||
progress.updated = true;
|
||||
condition.notify_all();
|
||||
};
|
||||
auto worker_thread = boost::thread([&model_object, &print, &result, on_progress, &success, &canceled, &finished]() {
|
||||
auto worker_thread = boost::thread([&model_object, &volumes, &ivolume, on_progress, &success, &canceled, &finished]() {
|
||||
try {
|
||||
on_progress(L("Exporting the source model"), 0);
|
||||
boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_src += ".3mf";
|
||||
Model model;
|
||||
DynamicPrintConfig config;
|
||||
model.add_object(model_object);
|
||||
if (! Slic3r::store_3mf(path_src.string().c_str(), &model, &config)) {
|
||||
std::vector<TriangleMesh> meshes_repaired;
|
||||
meshes_repaired.reserve(volumes.size());
|
||||
for (; ivolume < volumes.size(); ++ ivolume) {
|
||||
on_progress(L("Exporting source model"), 0);
|
||||
boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_src += ".3mf";
|
||||
Model model;
|
||||
ModelObject *model_object = model.add_object();
|
||||
model_object->add_volume(*volumes[ivolume]);
|
||||
model_object->add_instance();
|
||||
if (! Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr)) {
|
||||
boost::filesystem::remove(path_src);
|
||||
throw std::runtime_error(L("Export of a temporary 3mf file failed"));
|
||||
}
|
||||
model.clear_objects();
|
||||
model.clear_materials();
|
||||
boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_dst += ".3mf";
|
||||
fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress,
|
||||
[&canceled]() { if (canceled) throw RepairCanceledException(); });
|
||||
boost::filesystem::remove(path_src);
|
||||
throw std::runtime_error(L("Export of a temporary 3mf file failed"));
|
||||
// PresetBundle bundle;
|
||||
on_progress(L("Loading repaired model"), 80);
|
||||
DynamicPrintConfig config;
|
||||
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config, &model);
|
||||
boost::filesystem::remove(path_dst);
|
||||
if (! loaded)
|
||||
throw std::runtime_error(L("Import of the repaired 3mf file failed"));
|
||||
if (model.objects.size() == 0)
|
||||
throw std::runtime_error(L("Repaired 3MF file does not contain any object"));
|
||||
if (model.objects.size() > 1)
|
||||
throw std::runtime_error(L("Repaired 3MF file contains more than one object"));
|
||||
if (model.objects.front()->volumes.size() == 0)
|
||||
throw std::runtime_error(L("Repaired 3MF file does not contain any volume"));
|
||||
if (model.objects.front()->volumes.size() > 1)
|
||||
throw std::runtime_error(L("Repaired 3MF file contains more than one volume"));
|
||||
meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh));
|
||||
}
|
||||
model.clear_objects();
|
||||
model.clear_materials();
|
||||
boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_dst += ".3mf";
|
||||
fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress,
|
||||
[&canceled]() { if (canceled) throw RepairCanceledException(); });
|
||||
boost::filesystem::remove(path_src);
|
||||
// PresetBundle bundle;
|
||||
on_progress(L("Loading the repaired model"), 80);
|
||||
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config, &result);
|
||||
result.objects[0]->name = boost::filesystem::path(model_object.name).filename().stem().string() + "_fixed";
|
||||
boost::filesystem::remove(path_dst);
|
||||
if (! loaded)
|
||||
throw std::runtime_error(L("Import of the repaired 3mf file failed"));
|
||||
for (size_t i = 0; i < volumes.size(); ++ i) {
|
||||
volumes[i]->mesh = std::move(meshes_repaired[i]);
|
||||
volumes[i]->set_new_unique_id();
|
||||
}
|
||||
model_object.invalidate_bounding_box();
|
||||
-- ivolume;
|
||||
on_progress(L("Model repair finished"), 100);
|
||||
success = true;
|
||||
finished = true;
|
||||
on_progress(L("Model repair finished"), 100);
|
||||
} catch (RepairCanceledException & /* ex */) {
|
||||
canceled = true;
|
||||
finished = true;
|
||||
|
|
|
@ -12,12 +12,12 @@ class Print;
|
|||
#ifdef HAS_WIN10SDK
|
||||
|
||||
extern bool is_windows10();
|
||||
extern void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result);
|
||||
extern void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx);
|
||||
|
||||
#else /* HAS_WIN10SDK */
|
||||
|
||||
inline bool is_windows10() { return false; }
|
||||
inline void fix_model_by_win10_sdk_gui(const ModelObject &, const Print &, Model &) {}
|
||||
inline void fix_model_by_win10_sdk_gui(ModelObject &, int) {}
|
||||
|
||||
#endif /* HAS_WIN10SDK */
|
||||
|
||||
|
|
|
@ -180,12 +180,11 @@ bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &targe
|
|||
// Remove leftover paritally downloaded files, if any.
|
||||
void PresetUpdater::priv::prune_tmps() const
|
||||
{
|
||||
for (fs::directory_iterator it(cache_path); it != fs::directory_iterator(); ++it) {
|
||||
if (it->path().extension() == TMP_EXTENSION) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Cache prune: " << it->path().string();
|
||||
fs::remove(it->path());
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(cache_path))
|
||||
if (is_plain_file(dir_entry) && dir_entry.path().extension() == TMP_EXTENSION) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Cache prune: " << dir_entry.path().string();
|
||||
fs::remove(dir_entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Slic3rPE version available online, save in AppConfig.
|
||||
|
@ -299,9 +298,9 @@ void PresetUpdater::priv::check_install_indices() const
|
|||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "Checking if indices need to be installed from resources...";
|
||||
|
||||
for (fs::directory_iterator it(rsrc_path); it != fs::directory_iterator(); ++it) {
|
||||
const auto &path = it->path();
|
||||
if (path.extension() == ".idx") {
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(rsrc_path))
|
||||
if (is_idx_file(dir_entry)) {
|
||||
const auto &path = dir_entry.path();
|
||||
const auto path_in_cache = cache_path / path.filename();
|
||||
|
||||
if (! fs::exists(path_in_cache)) {
|
||||
|
@ -318,7 +317,6 @@ void PresetUpdater::priv::check_install_indices() const
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a list of bundle updates that are to be performed
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue