Merge branch 'dk_remote_devices' into dk_copy_file

This commit is contained in:
David Kocik 2019-12-18 13:14:14 +01:00
commit 11f07f277f
16 changed files with 1079 additions and 31 deletions

View File

@ -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
View File

@ -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})

View 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

View File

@ -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 ()

View File

@ -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");

View File

@ -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);
});
}
});

View File

@ -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()

View File

@ -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 ;

View File

@ -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(); }

View File

@ -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);

View 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

View 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

View 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

View 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

View File

@ -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)
{

View File

@ -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 };
};