Merge branch 'dk_remote_devices' into dk_copy_file
This commit is contained in:
commit
11f07f277f
@ -203,20 +203,50 @@ if(UNIX AND OPENVDB_USE_STATIC_LIBS)
|
||||
endif()
|
||||
|
||||
set(OpenVDB_LIB_COMPONENTS "")
|
||||
set(OpenVDB_DEBUG_SUFFIX "d" CACHE STRING "Suffix for the debug libraries")
|
||||
|
||||
get_property(_is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS})
|
||||
set(LIB_NAME ${COMPONENT})
|
||||
find_library(OpenVDB_${COMPONENT}_LIBRARY ${LIB_NAME} lib${LIB_NAME}
|
||||
|
||||
find_library(OpenVDB_${COMPONENT}_LIBRARY_RELEASE ${LIB_NAME} lib${LIB_NAME}
|
||||
PATHS ${_OPENVDB_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${OPENVDB_PATH_SUFFIXES}
|
||||
)
|
||||
list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY})
|
||||
|
||||
if(OpenVDB_${COMPONENT}_LIBRARY)
|
||||
set(OpenVDB_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(OpenVDB_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
find_library(OpenVDB_${COMPONENT}_LIBRARY_DEBUG ${LIB_NAME}${OpenVDB_DEBUG_SUFFIX} lib${LIB_NAME}${OpenVDB_DEBUG_SUFFIX}
|
||||
PATHS ${_OPENVDB_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${OPENVDB_PATH_SUFFIXES}
|
||||
)
|
||||
|
||||
if (_is_multi)
|
||||
list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY_RELEASE} ${OpenVDB_${COMPONENT}_LIBRARY_DEBUG})
|
||||
|
||||
list(FIND CMAKE_CONFIGURATION_TYPES "Debug" _has_debug)
|
||||
|
||||
if(OpenVDB_${COMPONENT}_LIBRARY_RELEASE AND (_has_debug LESS 0 OR OpenVDB_${COMPONENT}_LIBRARY_DEBUG))
|
||||
set(OpenVDB_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(OpenVDB_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
else ()
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" _BUILD_TYPE)
|
||||
|
||||
set(OpenVDB_${COMPONENT}_LIBRARY ${OpenVDB_${COMPONENT}_LIBRARY_${_BUILD_TYPE}})
|
||||
|
||||
if (NOT MSVC AND NOT OpenVDB_${COMPONENT}_LIBRARY)
|
||||
set(OpenVDB_${COMPONENT}_LIBRARY ${OpenVDB_${COMPONENT}_LIBRARY_RELEASE})
|
||||
endif ()
|
||||
|
||||
list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY})
|
||||
|
||||
if(OpenVDB_${COMPONENT}_LIBRARY)
|
||||
set(OpenVDB_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(OpenVDB_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
if(UNIX AND OPENVDB_USE_STATIC_LIBS)
|
||||
@ -465,7 +495,6 @@ foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS})
|
||||
if(NOT TARGET OpenVDB::${COMPONENT})
|
||||
add_library(OpenVDB::${COMPONENT} UNKNOWN IMPORTED)
|
||||
set_target_properties(OpenVDB::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LOCATION "${OpenVDB_${COMPONENT}_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${OpenVDB_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_INCLUDE_DIR}"
|
||||
IMPORTED_LINK_DEPENDENT_LIBRARIES "${_OPENVDB_HIDDEN_DEPENDENCIES}" # non visible deps
|
||||
@ -473,6 +502,17 @@ foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS})
|
||||
INTERFACE_COMPILE_FEATURES cxx_std_11
|
||||
)
|
||||
|
||||
if (_is_multi)
|
||||
set_target_properties(OpenVDB::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LOCATION_RELEASE "${OpenVDB_${COMPONENT}_LIBRARY_RELEASE}"
|
||||
IMPORTED_LOCATION_DEBUG "${OpenVDB_${COMPONENT}_LIBRARY_DEBUG}"
|
||||
)
|
||||
else ()
|
||||
set_target_properties(OpenVDB::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LOCATION "${OpenVDB_${COMPONENT}_LIBRARY}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (OPENVDB_USE_STATIC_LIBS)
|
||||
set_target_properties(OpenVDB::${COMPONENT} PROPERTIES
|
||||
INTERFACE_COMPILE_DEFINITIONS "OPENVDB_STATICLIB;OPENVDB_OPENEXR_STATICLIB"
|
||||
|
1
deps/CMakeLists.txt
vendored
1
deps/CMakeLists.txt
vendored
@ -47,6 +47,7 @@ message(STATUS "PrusaSlicer deps debug build: ${DEP_DEBUG}")
|
||||
|
||||
find_package(Git REQUIRED)
|
||||
|
||||
get_property(_is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
function(prusaslicer_add_cmake_project projectname)
|
||||
cmake_parse_arguments(P_ARGS "" "INSTALL_DIR;BUILD_COMMAND;INSTALL_COMMAND" "CMAKE_ARGS" ${ARGN})
|
||||
|
9
resources/icons/revert_all_.svg
Normal file
9
resources/icons/revert_all_.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M59.7,265.7c0,0,89.2-138.9,230.3-213.4C431.1-22.2,605-0.7,719,71.5c114,72.3,152.4,133.2,152.4,133.2l98.2-56.5c0,0,20.3-10.2,20.3,13.5v354.5c0,0,0,31.6-23.7,20.3c-19.9-9.5-235.7-133.3-303.6-172.3c-37.3-16.8-4.5-30.4-4.5-30.4l94.8-54.7c0,0-54.1-68.3-133.2-104.5C535,130.3,455.7,125,358.6,162c-63.3,24.1-137.9,85.9-191.6,177.2L59.7,265.7L59.7,265.7z"/>
|
||||
<path fill="#ED6B21" d="M940.3,734.3c0,0-89.2,138.9-230.3,213.4c-141.1,74.5-315,53.1-429-19.2c-114-72.3-152.4-133.2-152.4-133.2l-98.2,56.4c0,0-20.3,10.2-20.3-13.5V483.6c0,0,0-31.6,23.7-20.3c19.9,9.5,235.7,133.3,303.6,172.3c37.3,16.8,4.5,30.4,4.5,30.4l-94.8,54.7c0,0,54.1,68.3,133.2,104.5c84.7,44.5,164,49.8,261.1,12.8c63.3-24.1,137.9-85.9,191.6-177.2L940.3,734.3L940.3,734.3z"/></g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -111,6 +111,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/WipeTowerDialog.hpp
|
||||
GUI/RammingChart.cpp
|
||||
GUI/RammingChart.hpp
|
||||
GUI/RemovableDriveManager.cpp
|
||||
GUI/RemovableDriveManager.hpp
|
||||
GUI/BonjourDialog.cpp
|
||||
GUI/BonjourDialog.hpp
|
||||
GUI/ButtonsDescription.cpp
|
||||
@ -167,7 +169,12 @@ if (APPLE)
|
||||
list(APPEND SLIC3R_GUI_SOURCES
|
||||
Utils/RetinaHelperImpl.mm
|
||||
Utils/MacDarkMode.mm
|
||||
GUI/RemovableDriveManagerMM.mm
|
||||
GUI/RemovableDriveManagerMM.h
|
||||
)
|
||||
#DK
|
||||
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
|
||||
|
||||
endif ()
|
||||
|
||||
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
|
||||
@ -175,6 +182,11 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
|
||||
encoding_check(libslic3r_gui)
|
||||
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi)
|
||||
#DK
|
||||
if(APPLE)
|
||||
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
||||
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
|
||||
endif ()
|
||||
|
@ -357,6 +357,7 @@ void AppConfig::update_skein_dir(const std::string &dir)
|
||||
|
||||
std::string AppConfig::get_last_output_dir(const std::string &alt) const
|
||||
{
|
||||
|
||||
const auto it = m_storage.find("");
|
||||
if (it != m_storage.end()) {
|
||||
const auto it2 = it->second.find("last_output_path");
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "SysInfoDialog.hpp"
|
||||
#include "KBShortcutsDialog.hpp"
|
||||
#include "UpdateDialogs.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#include <Shlobj.h>
|
||||
@ -261,6 +262,8 @@ bool GUI_App::on_init_inner()
|
||||
|
||||
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
|
||||
|
||||
RemovableDriveManager::get_instance().init();
|
||||
|
||||
Bind(wxEVT_IDLE, [this](wxIdleEvent& event)
|
||||
{
|
||||
if (! plater_)
|
||||
@ -271,6 +274,10 @@ bool GUI_App::on_init_inner()
|
||||
|
||||
this->obj_manipul()->update_if_dirty();
|
||||
|
||||
#if !__APPLE__
|
||||
RemovableDriveManager::get_instance().update(wxGetLocalTime(), true);
|
||||
#endif
|
||||
|
||||
// Preset updating & Configwizard are done after the above initializations,
|
||||
// and after MainFrame is created & shown.
|
||||
// The extra CallAfter() is needed because of Mac, where this is the only way
|
||||
@ -298,6 +305,7 @@ bool GUI_App::on_init_inner()
|
||||
preset_updater->slic3r_update_notify();
|
||||
preset_updater->sync(preset_bundle);
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3874,8 +3874,8 @@ void ObjectList::show_multi_selection_menu()
|
||||
GetSelections(sels);
|
||||
|
||||
for (const wxDataViewItem& item : sels)
|
||||
if (!(m_objects_model->GetItemType(item) & (itVolume | itObject)))
|
||||
// show this menu only for Object(s)/Volume(s) selection
|
||||
if (!(m_objects_model->GetItemType(item) & (itVolume | itObject | itInstance)))
|
||||
// show this menu only for Objects(Instances mixed with Objects)/Volumes selection
|
||||
return;
|
||||
|
||||
wxMenu* menu = new wxMenu();
|
||||
@ -3885,7 +3885,12 @@ void ObjectList::show_multi_selection_menu()
|
||||
_(L("Select extruder number for selected objects and/or parts")),
|
||||
[this](wxCommandEvent&) { extruder_selection(); }, "", menu);
|
||||
|
||||
PopupMenu(menu);
|
||||
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());
|
||||
|
||||
wxGetApp().plater()->PopupMenu(menu);
|
||||
}
|
||||
|
||||
void ObjectList::extruder_selection()
|
||||
|
@ -366,6 +366,8 @@ public:
|
||||
void update_printable_state(int obj_idx, int instance_idx);
|
||||
void toggle_printable_state(wxDataViewItem item);
|
||||
|
||||
void show_multi_selection_menu();
|
||||
|
||||
private:
|
||||
#ifdef __WXOSX__
|
||||
// void OnChar(wxKeyEvent& event);
|
||||
@ -384,8 +386,6 @@ private:
|
||||
void OnEditingStarted(wxDataViewEvent &event);
|
||||
#endif /* __WXMSW__ */
|
||||
void OnEditingDone(wxDataViewEvent &event);
|
||||
|
||||
void show_multi_selection_menu();
|
||||
void extruder_selection();
|
||||
void set_extruder_for_selected_items(const int extruder) const ;
|
||||
|
||||
|
@ -77,6 +77,7 @@
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "../Utils/Thread.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
|
||||
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
|
||||
#include "WipeTowerDialog.hpp"
|
||||
@ -698,7 +699,8 @@ struct Sidebar::priv
|
||||
|
||||
wxButton *btn_export_gcode;
|
||||
wxButton *btn_reslice;
|
||||
wxButton *btn_send_gcode;
|
||||
ScalableButton *btn_send_gcode;
|
||||
ScalableButton *btn_remove_device;
|
||||
|
||||
priv(Plater *plater) : plater(plater) {}
|
||||
~priv();
|
||||
@ -847,22 +849,47 @@ Sidebar::Sidebar(Plater *parent)
|
||||
|
||||
// Buttons underneath the scrolled area
|
||||
|
||||
auto init_btn = [this](wxButton **btn, wxString label) {
|
||||
// rescalable bitmap buttons "Send to printer" and "Remove device"
|
||||
|
||||
auto init_scalable_btn = [this](ScalableButton** btn, const std::string& icon_name, wxString tooltip = wxEmptyString)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
int bmp_px_cnt = 16;
|
||||
#else
|
||||
int bmp_px_cnt = 32;
|
||||
#endif //__APPLE__
|
||||
ScalableBitmap bmp = ScalableBitmap(this, icon_name, bmp_px_cnt);
|
||||
*btn = new ScalableButton(this, wxID_ANY, bmp, "", wxBU_EXACTFIT);
|
||||
(*btn)->SetToolTip(tooltip);
|
||||
(*btn)->Hide();
|
||||
};
|
||||
|
||||
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")));
|
||||
init_scalable_btn(&p->btn_remove_device, "cross" , _(L("Remove device")));
|
||||
|
||||
// regular buttons "Slice now" and "Export G-code"
|
||||
|
||||
const int scaled_height = p->btn_remove_device->GetBitmapHeight() + 4;
|
||||
auto init_btn = [this](wxButton **btn, wxString label, const int button_height) {
|
||||
*btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition,
|
||||
wxDefaultSize, wxBU_EXACTFIT);
|
||||
wxSize(-1, button_height), wxBU_EXACTFIT);
|
||||
(*btn)->SetFont(wxGetApp().bold_font());
|
||||
};
|
||||
|
||||
init_btn(&p->btn_send_gcode, _(L("Send to printer")));
|
||||
p->btn_send_gcode->Hide();
|
||||
init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots);
|
||||
init_btn(&p->btn_reslice, _(L("Slice now")));
|
||||
init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots , scaled_height);
|
||||
init_btn(&p->btn_reslice , _(L("Slice now")) , scaled_height);
|
||||
|
||||
enable_buttons(false);
|
||||
|
||||
auto *btns_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
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_remove_device);
|
||||
|
||||
btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5);
|
||||
btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, margin_5);
|
||||
btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, margin_5);
|
||||
btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
||||
auto *sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(p->scrolled, 1, wxEXPAND);
|
||||
@ -881,6 +908,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||
p->plater->select_view_3D("Preview");
|
||||
});
|
||||
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(); });
|
||||
}
|
||||
|
||||
Sidebar::~Sidebar() {}
|
||||
@ -1026,6 +1054,12 @@ void Sidebar::msw_rescale()
|
||||
|
||||
p->object_info->msw_rescale();
|
||||
|
||||
p->btn_send_gcode->msw_rescale();
|
||||
p->btn_remove_device->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));
|
||||
|
||||
p->scrolled->Layout();
|
||||
}
|
||||
|
||||
@ -1254,11 +1288,13 @@ void Sidebar::enable_buttons(bool enable)
|
||||
p->btn_reslice->Enable(enable);
|
||||
p->btn_export_gcode->Enable(enable);
|
||||
p->btn_send_gcode->Enable(enable);
|
||||
p->btn_remove_device->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::is_multifilament()
|
||||
{
|
||||
@ -3154,6 +3190,7 @@ void Plater::priv::update_fff_scene()
|
||||
this->preview->reload_print();
|
||||
// In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth:
|
||||
view3D->reload_scene(true);
|
||||
|
||||
}
|
||||
|
||||
void Plater::priv::update_sla_scene()
|
||||
@ -3559,6 +3596,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
if (canceled) {
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
@ -3567,6 +3605,19 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||
}
|
||||
else if (wxGetApp().get_mode() == comSimple)
|
||||
show_action_buttons(false);
|
||||
if(RemovableDriveManager::get_instance().get_is_writing())
|
||||
{
|
||||
RemovableDriveManager::get_instance().set_is_writing(false);
|
||||
RemovableDriveManager::get_instance().verify_last_save_path();
|
||||
if (!RemovableDriveManager::get_instance().is_last_drive_removed())
|
||||
{
|
||||
|
||||
RemovableDriveManager::get_instance().erase_callbacks();
|
||||
RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, q));
|
||||
show_action_buttons(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::priv::on_layer_editing_toggled(bool enable)
|
||||
@ -3615,7 +3666,10 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
|
||||
if (evt.data.second) // right button was clicked on empty space
|
||||
menu = &default_menu;
|
||||
else
|
||||
{
|
||||
sidebar->obj_list()->show_multi_selection_menu();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4132,20 +4186,23 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||
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
|
||||
// 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_send(send_gcode_shown) |
|
||||
sidebar->show_disconnect(disconnect_shown))
|
||||
sidebar->Layout();
|
||||
}
|
||||
else
|
||||
{
|
||||
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_send(send_gcode_shown && !is_ready_to_slice) |
|
||||
sidebar->show_disconnect(disconnect_shown && !is_ready_to_slice))
|
||||
sidebar->Layout();
|
||||
}
|
||||
}
|
||||
@ -4386,7 +4443,7 @@ void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& lab
|
||||
{
|
||||
case ActionButtonType::abReslice: p->btn_reslice->SetLabelText(label); break;
|
||||
case ActionButtonType::abExport: p->btn_export_gcode->SetLabelText(label); break;
|
||||
case ActionButtonType::abSendGCode: p->btn_send_gcode->SetLabelText(label); break;
|
||||
case ActionButtonType::abSendGCode: /*p->btn_send_gcode->SetLabelText(label);*/ break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4669,7 +4726,13 @@ 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())
|
||||
{
|
||||
if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir))
|
||||
{
|
||||
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:")),
|
||||
start_dir,
|
||||
from_path(default_output_file.filename()),
|
||||
@ -4684,7 +4747,21 @@ void Plater::export_gcode()
|
||||
output_path = std::move(path);
|
||||
}
|
||||
if (! output_path.empty())
|
||||
{
|
||||
std::string path = output_path.string();
|
||||
RemovableDriveManager::get_instance().set_is_writing(true);
|
||||
RemovableDriveManager::get_instance().update(0, true);
|
||||
p->export_gcode(std::move(output_path), PrintHostJob());
|
||||
RemovableDriveManager::get_instance().set_last_save_path(path);
|
||||
/*
|
||||
if(!RemovableDriveManager::get_instance().is_last_drive_removed())
|
||||
{
|
||||
RemovableDriveManager::get_instance().erase_callbacks();
|
||||
RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Plater::export_stl(bool extended, bool selection_only)
|
||||
@ -4964,6 +5041,27 @@ 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().eject_drive(RemovableDriveManager::get_instance().get_last_save_path());
|
||||
|
||||
}
|
||||
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.";
|
||||
wxMessageBox(message);
|
||||
}
|
||||
p->show_action_buttons(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||
void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||
void Plater::suppress_snapshots() { p->suppress_snapshots(); }
|
||||
|
@ -119,6 +119,7 @@ public:
|
||||
bool show_reslice(bool show) const;
|
||||
bool show_export(bool show) const;
|
||||
bool show_send(bool show) const;
|
||||
bool show_disconnect(bool show)const;
|
||||
bool is_multifilament();
|
||||
void update_mode();
|
||||
|
||||
@ -201,6 +202,8 @@ public:
|
||||
void suppress_background_process(const bool stop_background_process) ;
|
||||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
||||
void send_gcode();
|
||||
void eject_drive();
|
||||
void drive_ejected_callback();
|
||||
|
||||
void take_snapshot(const std::string &snapshot_name);
|
||||
void take_snapshot(const wxString &snapshot_name);
|
||||
|
579
src/slic3r/GUI/RemovableDriveManager.cpp
Normal file
579
src/slic3r/GUI/RemovableDriveManager.cpp
Normal file
@ -0,0 +1,579 @@
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include <iostream>
|
||||
#include "boost/nowide/convert.hpp"
|
||||
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <winioctl.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include <Dbt.h>
|
||||
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72,
|
||||
0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
|
||||
|
||||
#else
|
||||
//linux includes
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <glob.h>
|
||||
#include <libgen.h>
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if _WIN32
|
||||
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void RemovableDriveManager::search_for_drives()
|
||||
{
|
||||
m_current_drives.clear();
|
||||
//get logical drives flags by letter in alphabetical order
|
||||
DWORD drives_mask = GetLogicalDrives();
|
||||
for (size_t i = 0; i < 26; i++)
|
||||
{
|
||||
if(drives_mask & (1 << i))
|
||||
{
|
||||
std::string path (1,(char)('A' + i));
|
||||
path+=":";
|
||||
UINT drive_type = GetDriveTypeA(path.c_str());
|
||||
// DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives)
|
||||
if (drive_type == DRIVE_REMOVABLE)
|
||||
{
|
||||
// get name of drive
|
||||
std::wstring wpath = boost::nowide::widen(path);//std::wstring(path.begin(), path.end());
|
||||
std::wstring volume_name;
|
||||
volume_name.resize(1024);
|
||||
std::wstring file_system_name;
|
||||
file_system_name.resize(1024);
|
||||
LPWSTR lp_volume_name_buffer = new wchar_t;
|
||||
BOOL error = GetVolumeInformationW(wpath.c_str(), &volume_name[0], sizeof(volume_name), NULL, NULL, NULL, &file_system_name[0], sizeof(file_system_name));
|
||||
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;
|
||||
GetDiskFreeSpaceExA(path.c_str(), &free_space, NULL, NULL);
|
||||
if (free_space.QuadPart > 0)
|
||||
{
|
||||
path += "\\";
|
||||
m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void RemovableDriveManager::eject_drive(const std::string &path)
|
||||
{
|
||||
if(m_current_drives.empty())
|
||||
return;
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if ((*it).path == path)
|
||||
{
|
||||
// get handle to device
|
||||
std::string mpath = "\\\\.\\" + path;
|
||||
mpath = mpath.substr(0, mpath.size() - 1);
|
||||
HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n";
|
||||
return;
|
||||
}
|
||||
DWORD deviceControlRetVal(0);
|
||||
//these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger.
|
||||
//sd cards does trigger WM_DEVICECHANGE messege, usb drives dont
|
||||
|
||||
DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
// some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here but it returns error to me
|
||||
BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
if (error == 0)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n";
|
||||
return;
|
||||
}
|
||||
CloseHandle(handle);
|
||||
m_did_eject = true;
|
||||
m_current_drives.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
|
||||
{
|
||||
if (m_current_drives.empty())
|
||||
return false;
|
||||
int letter = PathGetDriveNumberA(path.c_str());
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
char drive = (*it).path[0];
|
||||
if (drive == ('A' + letter))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string RemovableDriveManager::get_drive_from_path(const std::string& path)
|
||||
{
|
||||
int letter = PathGetDriveNumberA(path.c_str());
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
char drive = (*it).path[0];
|
||||
if (drive == ('A' + letter))
|
||||
return (*it).path;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
void RemovableDriveManager::register_window()
|
||||
{
|
||||
//creates new unvisible window that is recieving callbacks from system
|
||||
// structure to register
|
||||
WNDCLASSEX wndClass;
|
||||
wndClass.cbSize = sizeof(WNDCLASSEX);
|
||||
wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
||||
wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
|
||||
wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(WinProcCallback);//this is callback
|
||||
wndClass.cbClsExtra = 0;
|
||||
wndClass.cbWndExtra = 0;
|
||||
wndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192));
|
||||
wndClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wndClass.lpszClassName = L"PrusaSlicer_aux_class";
|
||||
wndClass.lpszMenuName = NULL;
|
||||
wndClass.hIconSm = wndClass.hIcon;
|
||||
if(!RegisterClassEx(&wndClass))
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
return;
|
||||
}
|
||||
|
||||
HWND hWnd = CreateWindowEx(
|
||||
WS_EX_NOACTIVATE,
|
||||
L"PrusaSlicer_aux_class",
|
||||
L"PrusaSlicer_aux_wnd",
|
||||
WS_DISABLED, // style
|
||||
CW_USEDEFAULT, 0,
|
||||
640, 480,
|
||||
NULL, NULL,
|
||||
GetModuleHandle(NULL),
|
||||
NULL);
|
||||
if(hWnd == NULL)
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
}
|
||||
//ShowWindow(hWnd, SW_SHOWNORMAL);
|
||||
UpdateWindow(hWnd);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
|
||||
|
||||
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
|
||||
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
|
||||
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||
NotificationFilter.dbcc_classguid = WceusbshGUID;
|
||||
|
||||
hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
break;
|
||||
|
||||
case WM_DEVICECHANGE:
|
||||
{
|
||||
// here is the important
|
||||
if(wParam == DBT_DEVICEREMOVECOMPLETE)
|
||||
{
|
||||
- RemovableDriveManager::get_instance().update(0, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Send all other messages on to the default windows handler.
|
||||
lRet = DefWindowProc(hWnd, message, wParam, lParam);
|
||||
break;
|
||||
}
|
||||
return lRet;
|
||||
}
|
||||
|
||||
#else
|
||||
void RemovableDriveManager::search_for_drives()
|
||||
{
|
||||
|
||||
m_current_drives.clear();
|
||||
|
||||
#if __APPLE__
|
||||
// if on macos obj-c class will enumerate
|
||||
if(m_rdmmm)
|
||||
{
|
||||
m_rdmmm->list_devices();
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
//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;
|
||||
path = "/media/" + path + "/*";
|
||||
search_path(path, pp);
|
||||
|
||||
//search /run/media/USERNAME/* folder
|
||||
path = "/run" + path;
|
||||
pp = "/run"+pp;
|
||||
search_path(path, pp);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void RemovableDriveManager::search_path(const std::string &path,const std::string &parent_path)
|
||||
{
|
||||
glob_t globbuf;
|
||||
globbuf.gl_offs = 2;
|
||||
int error = glob(path.c_str(), GLOB_TILDE, NULL, &globbuf);
|
||||
if(error == 0)
|
||||
{
|
||||
for(size_t i = 0; i < globbuf.gl_pathc; i++)
|
||||
{
|
||||
inspect_file(globbuf.gl_pathv[i], parent_path);
|
||||
}
|
||||
}else
|
||||
{
|
||||
//if error - path probably doesnt exists so function just exits
|
||||
//std::cout<<"glob error "<< error<< "\n";
|
||||
}
|
||||
|
||||
globfree(&globbuf);
|
||||
}
|
||||
void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path)
|
||||
{
|
||||
//confirms if the file is removable drive and adds it to vector
|
||||
|
||||
//if not same file system - could be removable drive
|
||||
if(!compare_filesystem_id(path, parent_path))
|
||||
{
|
||||
//user id
|
||||
struct stat buf;
|
||||
stat(path.c_str(), &buf);
|
||||
uid_t uid = buf.st_uid;
|
||||
std::string username(std::getenv("USER"));
|
||||
struct passwd *pw = getpwuid(uid);
|
||||
if(pw != 0)
|
||||
{
|
||||
if(pw->pw_name == username)
|
||||
{
|
||||
std::string name = basename(const_cast<char*>(path.c_str()));
|
||||
m_current_drives.push_back(DriveData(name,path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool RemovableDriveManager::compare_filesystem_id(const std::string &path_a, const std::string &path_b)
|
||||
{
|
||||
struct stat buf;
|
||||
stat(path_a.c_str() ,&buf);
|
||||
dev_t id_a = buf.st_dev;
|
||||
stat(path_b.c_str() ,&buf);
|
||||
dev_t id_b = buf.st_dev;
|
||||
return id_a == id_b;
|
||||
}
|
||||
void RemovableDriveManager::eject_drive(const std::string &path)
|
||||
{
|
||||
if (m_current_drives.empty())
|
||||
return;
|
||||
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if((*it).path == path)
|
||||
{
|
||||
|
||||
std::string correct_path(path);
|
||||
for (size_t i = 0; i < correct_path.size(); ++i)
|
||||
{
|
||||
if(correct_path[i]==' ')
|
||||
{
|
||||
correct_path = correct_path.insert(i,1,'\\');
|
||||
i++;
|
||||
}
|
||||
}
|
||||
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 = "";
|
||||
#if __APPLE__
|
||||
//m_rdmmm->eject_device(path);
|
||||
command = "diskutil unmount ";
|
||||
#else
|
||||
command = "umount ";
|
||||
#endif
|
||||
command += correct_path;
|
||||
int err = system(command.c_str());
|
||||
if(err)
|
||||
{
|
||||
std::cerr<<"Ejecting failed\n";
|
||||
return;
|
||||
}
|
||||
|
||||
m_did_eject = true;
|
||||
m_current_drives.erase(it);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
|
||||
{
|
||||
if (m_current_drives.empty())
|
||||
return false;
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if(compare_filesystem_id(path, (*it).path))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string RemovableDriveManager::get_drive_from_path(const std::string& path)
|
||||
{
|
||||
//check if same filesystem
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if (compare_filesystem_id(path, (*it).path))
|
||||
return (*it).path;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
RemovableDriveManager::RemovableDriveManager():
|
||||
m_drives_count(0),
|
||||
m_last_update(0),
|
||||
m_last_save_path(""),
|
||||
m_last_save_name(""),
|
||||
m_last_save_path_verified(false),
|
||||
m_is_writing(false),
|
||||
m_did_eject(false)
|
||||
#if __APPLE__
|
||||
, m_rdmmm(new RDMMMWrapper())
|
||||
#endif
|
||||
{}
|
||||
RemovableDriveManager::~RemovableDriveManager()
|
||||
{
|
||||
#if __APPLE__
|
||||
delete m_rdmmm;
|
||||
#endif
|
||||
}
|
||||
void RemovableDriveManager::init()
|
||||
{
|
||||
//add_callback([](void) { RemovableDriveManager::get_instance().print(); });
|
||||
#if _WIN32
|
||||
//register_window();
|
||||
#elif __APPLE__
|
||||
m_rdmmm->register_window();
|
||||
#endif
|
||||
update(0, true);
|
||||
}
|
||||
bool RemovableDriveManager::update(const long time,const bool check)
|
||||
{
|
||||
if(time != 0) //time = 0 is forced update
|
||||
{
|
||||
long diff = m_last_update - time;
|
||||
if(diff <= -2)
|
||||
{
|
||||
m_last_update = time;
|
||||
}else
|
||||
{
|
||||
return false; // return value shouldnt matter if update didnt run
|
||||
}
|
||||
}
|
||||
search_for_drives();
|
||||
if(check)check_and_notify();
|
||||
return !m_current_drives.empty();
|
||||
}
|
||||
|
||||
bool RemovableDriveManager::is_drive_mounted(const std::string &path)
|
||||
{
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if ((*it).path == path)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string RemovableDriveManager::get_drive_path()
|
||||
{
|
||||
if (m_current_drives.size() == 0)
|
||||
{
|
||||
reset_last_save_path();
|
||||
return "";
|
||||
}
|
||||
if (m_last_save_path_verified)
|
||||
return m_last_save_path;
|
||||
return m_current_drives.back().path;
|
||||
}
|
||||
std::string RemovableDriveManager::get_last_save_path()
|
||||
{
|
||||
if (!m_last_save_path_verified)
|
||||
return "";
|
||||
return m_last_save_path;
|
||||
}
|
||||
std::string RemovableDriveManager::get_last_save_name()
|
||||
{
|
||||
return m_last_save_name;
|
||||
}
|
||||
std::vector<DriveData> RemovableDriveManager::get_all_drives()
|
||||
{
|
||||
return m_current_drives;
|
||||
}
|
||||
void RemovableDriveManager::check_and_notify()
|
||||
{
|
||||
if(m_drives_count != m_current_drives.size())
|
||||
{
|
||||
if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path_verified && !is_drive_mounted(m_last_save_path))
|
||||
{
|
||||
for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it)
|
||||
{
|
||||
(*it)();
|
||||
}
|
||||
}
|
||||
m_drives_count = m_current_drives.size();
|
||||
}
|
||||
}
|
||||
void RemovableDriveManager::add_callback(std::function<void()> callback)
|
||||
{
|
||||
m_callbacks.push_back(callback);
|
||||
}
|
||||
void RemovableDriveManager::erase_callbacks()
|
||||
{
|
||||
m_callbacks.clear();
|
||||
}
|
||||
void RemovableDriveManager::set_last_save_path(const std::string& path)
|
||||
{
|
||||
m_last_save_path_verified = false;
|
||||
m_last_save_path = path;
|
||||
}
|
||||
void RemovableDriveManager::verify_last_save_path()
|
||||
{
|
||||
std::string last_drive = get_drive_from_path(m_last_save_path);
|
||||
if (last_drive != "")
|
||||
{
|
||||
m_last_save_path_verified = true;
|
||||
m_last_save_path = last_drive;
|
||||
m_last_save_name = get_drive_name(last_drive);
|
||||
}
|
||||
}
|
||||
std::string RemovableDriveManager::get_drive_name(const std::string& path)
|
||||
{
|
||||
if (m_current_drives.size() == 0)
|
||||
return "";
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if ((*it).path == path)
|
||||
{
|
||||
return (*it).name;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
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";
|
||||
return r;
|
||||
}
|
||||
bool RemovableDriveManager::is_last_drive_removed_with_update(const long time)
|
||||
{
|
||||
update(time, false);
|
||||
return is_last_drive_removed();
|
||||
}
|
||||
void RemovableDriveManager::reset_last_save_path()
|
||||
{
|
||||
m_last_save_path_verified = false;
|
||||
m_last_save_path = "";
|
||||
m_last_save_name = "";
|
||||
}
|
||||
void RemovableDriveManager::set_is_writing(const bool b)
|
||||
{
|
||||
m_is_writing = b;
|
||||
if (b)
|
||||
{
|
||||
m_did_eject = false;
|
||||
}
|
||||
}
|
||||
bool RemovableDriveManager::get_is_writing()
|
||||
{
|
||||
return m_is_writing;
|
||||
}
|
||||
bool RemovableDriveManager::get_did_eject()
|
||||
{
|
||||
return m_did_eject;
|
||||
}
|
||||
void RemovableDriveManager::set_did_eject(const bool b)
|
||||
{
|
||||
m_did_eject = b;
|
||||
}
|
||||
}}//namespace Slicer::Gui
|
109
src/slic3r/GUI/RemovableDriveManager.hpp
Normal file
109
src/slic3r/GUI/RemovableDriveManager.hpp
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef slic3r_GUI_RemovableDriveManager_hpp_
|
||||
#define slic3r_GUI_RemovableDriveManager_hpp_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
#if __APPLE__
|
||||
class RDMMMWrapper;
|
||||
#endif
|
||||
|
||||
struct DriveData
|
||||
{
|
||||
std::string name;
|
||||
std::string path;
|
||||
DriveData(std::string n, std::string p):name(n),path(p){}
|
||||
};
|
||||
class RemovableDriveManager
|
||||
{
|
||||
#if __APPLE__
|
||||
friend class RDMMMWrapper;
|
||||
#endif
|
||||
public:
|
||||
static RemovableDriveManager& get_instance()
|
||||
{
|
||||
static RemovableDriveManager instance;
|
||||
return instance;
|
||||
}
|
||||
RemovableDriveManager(RemovableDriveManager const&) = delete;
|
||||
void operator=(RemovableDriveManager const&) = delete;
|
||||
~RemovableDriveManager();
|
||||
//call only once. on apple register for unmnount callbacks. on windows register for device notification is prepared but not called (eject usb drive on widnows doesnt trigger the callback, sdc ard does), also enumerates devices for first time so init shoud be called on linux too.
|
||||
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);
|
||||
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();
|
||||
//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();
|
||||
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 erase_callbacks();
|
||||
// marks one of the eveices in vector as last used
|
||||
void set_last_save_path(const std::string &path);
|
||||
void verify_last_save_path();
|
||||
bool is_last_drive_removed();
|
||||
// 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();
|
||||
void set_did_eject(const bool b);
|
||||
std::string get_drive_name(const std::string& path);
|
||||
private:
|
||||
RemovableDriveManager();
|
||||
void search_for_drives();
|
||||
//triggers callbacks if last used drive was removed
|
||||
void check_and_notify();
|
||||
//returns drive path (same as path in DriveData) if exists otherwise empty string ""
|
||||
std::string get_drive_from_path(const std::string& path);
|
||||
void reset_last_save_path();
|
||||
|
||||
std::vector<DriveData> m_current_drives;
|
||||
std::vector<std::function<void()>> m_callbacks;
|
||||
size_t m_drives_count;
|
||||
long m_last_update;
|
||||
std::string m_last_save_path;
|
||||
bool m_last_save_path_verified;
|
||||
std::string m_last_save_name;
|
||||
bool m_is_writing;//on device
|
||||
bool m_did_eject;
|
||||
#if _WIN32
|
||||
//registers for notifications by creating invisible window
|
||||
void register_window();
|
||||
#else
|
||||
#if __APPLE__
|
||||
RDMMMWrapper * m_rdmmm;
|
||||
#endif
|
||||
void search_path(const std::string &path, const std::string &parent_path);
|
||||
bool compare_filesystem_id(const std::string &path_a, const std::string &path_b);
|
||||
void inspect_file(const std::string &path, const std::string &parent_path);
|
||||
#endif
|
||||
};
|
||||
// apple wrapper for RemovableDriveManagerMM which searches for drives and/or ejects them
|
||||
#if __APPLE__
|
||||
class RDMMMWrapper
|
||||
{
|
||||
public:
|
||||
RDMMMWrapper();
|
||||
~RDMMMWrapper();
|
||||
void register_window();
|
||||
void list_devices();
|
||||
void eject_device(const std::string &path);
|
||||
void log(const std::string &msg);
|
||||
protected:
|
||||
void *m_imp;
|
||||
//friend void RemovableDriveManager::inspect_file(const std::string &path, const std::string &parent_path);
|
||||
};
|
||||
#endif
|
||||
}}
|
||||
#endif
|
||||
|
10
src/slic3r/GUI/RemovableDriveManagerMM.h
Normal file
10
src/slic3r/GUI/RemovableDriveManagerMM.h
Normal file
@ -0,0 +1,10 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface RemovableDriveManagerMM : NSObject
|
||||
|
||||
-(instancetype) init;
|
||||
-(void) add_unmount_observer;
|
||||
-(void) on_device_unmount: (NSNotification*) notification;
|
||||
-(NSArray*) list_dev;
|
||||
-(void)eject_drive:(NSString *)path;
|
||||
@end
|
157
src/slic3r/GUI/RemovableDriveManagerMM.mm
Normal file
157
src/slic3r/GUI/RemovableDriveManagerMM.mm
Normal file
@ -0,0 +1,157 @@
|
||||
#import "RemovableDriveManager.hpp"
|
||||
#import "RemovableDriveManagerMM.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <DiskArbitration/DiskArbitration.h>
|
||||
|
||||
@implementation RemovableDriveManagerMM
|
||||
|
||||
|
||||
|
||||
-(instancetype) init
|
||||
{
|
||||
self = [super init];
|
||||
if(self)
|
||||
{
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void) on_device_unmount: (NSNotification*) notification
|
||||
{
|
||||
NSLog(@"on device change");
|
||||
Slic3r::GUI::RemovableDriveManager::get_instance().update(0,true);
|
||||
}
|
||||
-(void) add_unmount_observer
|
||||
{
|
||||
NSLog(@"add unmount observer");
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidUnmountNotification object:nil];
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(on_device_unmount:) name:NSWorkspaceDidMountNotification object:nil];
|
||||
}
|
||||
-(NSArray*) list_dev
|
||||
{
|
||||
// DEPRICATED:
|
||||
//NSArray* devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia];
|
||||
//return devices;
|
||||
|
||||
NSArray *mountedRemovableMedia = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes];
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
for(NSURL *volURL in mountedRemovableMedia)
|
||||
{
|
||||
int err = 0;
|
||||
DADiskRef disk;
|
||||
DASessionRef session;
|
||||
CFDictionaryRef descDict;
|
||||
session = DASessionCreate(NULL);
|
||||
if (session == NULL) {
|
||||
err = EINVAL;
|
||||
}
|
||||
if (err == 0) {
|
||||
disk = DADiskCreateFromVolumePath(NULL,session,(CFURLRef)volURL);
|
||||
if (session == NULL) {
|
||||
err = EINVAL;
|
||||
}
|
||||
}
|
||||
if (err == 0) {
|
||||
descDict = DADiskCopyDescription(disk);
|
||||
if (descDict == NULL) {
|
||||
err = EINVAL;
|
||||
}
|
||||
}
|
||||
if (err == 0) {
|
||||
CFTypeRef mediaEjectableKey = CFDictionaryGetValue(descDict,kDADiskDescriptionMediaEjectableKey);
|
||||
BOOL ejectable = [mediaEjectableKey boolValue];
|
||||
CFTypeRef deviceProtocolName = CFDictionaryGetValue(descDict,kDADiskDescriptionDeviceProtocolKey);
|
||||
CFTypeRef deviceModelKey = CFDictionaryGetValue(descDict, kDADiskDescriptionDeviceModelKey);
|
||||
if (mediaEjectableKey != NULL)
|
||||
{
|
||||
BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader")));
|
||||
//!CFEqual(deviceModelKey, CFSTR("Disk Image"));
|
||||
//
|
||||
if (op) {
|
||||
[result addObject:volURL.path];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (descDict != NULL) {
|
||||
CFRelease(descDict);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
-(void)eject_drive:(NSString *)path
|
||||
{
|
||||
DADiskRef disk;
|
||||
DASessionRef session;
|
||||
NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
|
||||
int err = 0;
|
||||
session = DASessionCreate(NULL);
|
||||
if (session == NULL) {
|
||||
err = EINVAL;
|
||||
}
|
||||
if (err == 0) {
|
||||
disk = DADiskCreateFromVolumePath(NULL,session,(CFURLRef)url);
|
||||
}
|
||||
if( err == 0)
|
||||
{
|
||||
DADiskUnmount(disk, kDADiskUnmountOptionDefault,
|
||||
NULL, NULL);
|
||||
}
|
||||
if (disk != NULL) {
|
||||
CFRelease(disk);
|
||||
}
|
||||
if (session != NULL) {
|
||||
CFRelease(session);
|
||||
}
|
||||
}
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
RDMMMWrapper::RDMMMWrapper():m_imp(nullptr){
|
||||
m_imp = [[RemovableDriveManagerMM alloc] init];
|
||||
}
|
||||
RDMMMWrapper::~RDMMMWrapper()
|
||||
{
|
||||
if(m_imp)
|
||||
{
|
||||
[m_imp release];
|
||||
}
|
||||
}
|
||||
void RDMMMWrapper::register_window()
|
||||
{
|
||||
if(m_imp)
|
||||
{
|
||||
[m_imp add_unmount_observer];
|
||||
}
|
||||
}
|
||||
void RDMMMWrapper::list_devices()
|
||||
{
|
||||
if(m_imp)
|
||||
{
|
||||
NSArray* devices = [m_imp list_dev];
|
||||
for (NSString* volumePath in devices)
|
||||
{
|
||||
NSLog(@"%@", volumePath);
|
||||
Slic3r::GUI::RemovableDriveManager::get_instance().inspect_file(std::string([volumePath UTF8String]), "/Volumes");
|
||||
}
|
||||
}
|
||||
}
|
||||
void RDMMMWrapper::log(const std::string &msg)
|
||||
{
|
||||
NSLog(@"%s", msg.c_str());
|
||||
}
|
||||
void RDMMMWrapper::eject_device(const std::string &path)
|
||||
{
|
||||
if(m_imp)
|
||||
{
|
||||
NSString * pth = [NSString stringWithCString:path.c_str()
|
||||
encoding:[NSString defaultCStringEncoding]];
|
||||
[m_imp eject_drive:pth];
|
||||
}
|
||||
}
|
||||
}}//namespace Slicer::GUI
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
@end
|
@ -3935,8 +3935,10 @@ ScalableButton::ScalableButton( wxWindow * parent,
|
||||
const ScalableBitmap& bitmap,
|
||||
const wxString& label /*= wxEmptyString*/,
|
||||
long style /*= wxBU_EXACTFIT | wxNO_BORDER*/) :
|
||||
m_parent(parent),
|
||||
m_current_icon_name(bitmap.name()),
|
||||
m_parent(parent)
|
||||
m_px_cnt(bitmap.px_cnt()),
|
||||
m_is_horizontal(bitmap.is_horizontal())
|
||||
{
|
||||
Create(parent, id, label, wxDefaultPosition, wxDefaultSize, style);
|
||||
#ifdef __WXMSW__
|
||||
@ -3959,11 +3961,17 @@ void ScalableButton::SetBitmapDisabled_(const ScalableBitmap& bmp)
|
||||
m_disabled_icon_name = bmp.name();
|
||||
}
|
||||
|
||||
int ScalableButton::GetBitmapHeight()
|
||||
{
|
||||
const float scale_factor = get_svg_scale_factor(m_parent);
|
||||
return int((float)GetBitmap().GetHeight() / scale_factor);
|
||||
}
|
||||
|
||||
void ScalableButton::msw_rescale()
|
||||
{
|
||||
SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name));
|
||||
SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name, m_px_cnt, m_is_horizontal));
|
||||
if (!m_disabled_icon_name.empty())
|
||||
SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name));
|
||||
SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name, m_px_cnt, m_is_horizontal));
|
||||
|
||||
if (m_width > 0 || m_height>0)
|
||||
{
|
||||
|
@ -730,6 +730,9 @@ public:
|
||||
wxBitmap& bmp() { return m_bmp; }
|
||||
const std::string& name() const{ return m_icon_name; }
|
||||
|
||||
int px_cnt()const {return m_px_cnt;}
|
||||
bool is_horizontal()const {return m_is_horizontal;}
|
||||
|
||||
private:
|
||||
wxWindow* m_parent{ nullptr };
|
||||
wxBitmap m_bmp = wxBitmap();
|
||||
@ -962,7 +965,7 @@ private:
|
||||
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;
|
||||
int tick = 0;
|
||||
std::string gcode = Slic3r::ColorChangeCode;
|
||||
int extruder = 0;
|
||||
std::string color;
|
||||
@ -1096,6 +1099,7 @@ public:
|
||||
|
||||
void SetBitmap_(const ScalableBitmap& bmp);
|
||||
void SetBitmapDisabled_(const ScalableBitmap &bmp);
|
||||
int GetBitmapHeight();
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
@ -1105,6 +1109,10 @@ private:
|
||||
std::string m_disabled_icon_name = "";
|
||||
int m_width {-1}; // should be multiplied to em_unit
|
||||
int m_height{-1}; // should be multiplied to em_unit
|
||||
|
||||
// bitmap dimensions
|
||||
int m_px_cnt{ 16 };
|
||||
bool m_is_horizontal{ false };
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user