This commit is contained in:
YuSanka 2019-08-21 08:45:22 +02:00
commit 2cc2c02a9c
15 changed files with 405 additions and 104 deletions

View file

@ -60,21 +60,25 @@ PrinterTechnology get_printer_technology(const DynamicConfig &config)
int CLI::run(int argc, char **argv)
{
#ifdef _WIN32
// Switch boost::filesystem to utf8.
try {
boost::nowide::nowide_filesystem();
} catch (const std::runtime_error& ex) {
std::string caption = std::string(SLIC3R_APP_NAME) + " Error";
std::string text = std::string("An error occured while setting up locale.\n") + SLIC3R_APP_NAME + " will now terminate.\n\n" + ex.what();
#ifdef SLIC3R_GUI
std::string text = std::string("An error occured while setting up locale.\n") + (
#if !defined(_WIN32) && !defined(__APPLE__)
// likely some linux system
"You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n"
#endif
SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what();
#if defined(_WIN32) && defined(SLIC3R_GUI)
if (m_actions.empty())
// Empty actions means Slicer is executed in the GUI mode. Show a GUI message.
MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR);
#endif
boost::nowide::cerr << text.c_str() << std::endl;
return 1;
}
#endif
if (! this->setup(argc, argv))
return 1;
@ -426,7 +430,7 @@ int CLI::run(int argc, char **argv)
outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
sla_print.export_raster(outfile_final);
}
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) {
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) {
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
return 1;
}

View file

@ -607,7 +607,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
m_analyzer.reset();
}
if (rename_file(path_tmp, path) != 0)
if (rename_file(path_tmp, path))
throw std::runtime_error(
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
"Is " + path_tmp + " locked?" + '\n');

View file

@ -390,7 +390,7 @@ namespace Slic3r {
fclose(out);
in.close();
if (rename_file(path_tmp, filename) != 0)
if (rename_file(path_tmp, filename))
throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
"Is " + path_tmp + " locked?" + '\n');

View file

@ -2412,6 +2412,22 @@ void PrintConfigDef::init_sla_params()
def->mode = comExpert;
def->set_default_value(new ConfigOptionInt(10));
def = this->add("min_exposure_time", coFloat);
def->label = L("Minimum exposure time");
def->tooltip = L("Minimum exposure time");
def->sidetext = L("s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("max_exposure_time", coFloat);
def->label = L("Maximum exposure time");
def->tooltip = L("Maximum exposure time");
def->sidetext = L("s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(100));
def = this->add("exposure_time", coFloat);
def->label = L("Exposure time");
def->tooltip = L("Exposure time");
@ -2419,6 +2435,22 @@ void PrintConfigDef::init_sla_params()
def->min = 0;
def->set_default_value(new ConfigOptionFloat(10));
def = this->add("min_initial_exposure_time", coFloat);
def->label = L("Minimum initial exposure time");
def->tooltip = L("Minimum initial exposure time");
def->sidetext = L("s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("max_initial_exposure_time", coFloat);
def->label = L("Maximum initial exposure time");
def->tooltip = L("Maximum initial exposure time");
def->sidetext = L("s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(150));
def = this->add("initial_exposure_time", coFloat);
def->label = L("Initial exposure time");
def->tooltip = L("Initial exposure time");

View file

@ -1131,6 +1131,10 @@ public:
ConfigOptionFloat fast_tilt_time;
ConfigOptionFloat slow_tilt_time;
ConfigOptionFloat area_fill;
ConfigOptionFloat min_exposure_time;
ConfigOptionFloat max_exposure_time;
ConfigOptionFloat min_initial_exposure_time;
ConfigOptionFloat max_initial_exposure_time;
protected:
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
@ -1150,6 +1154,10 @@ protected:
OPT_PTR(fast_tilt_time);
OPT_PTR(slow_tilt_time);
OPT_PTR(area_fill);
OPT_PTR(min_exposure_time);
OPT_PTR(max_exposure_time);
OPT_PTR(min_initial_exposure_time);
OPT_PTR(max_initial_exposure_time);
}
};

View file

@ -692,6 +692,20 @@ std::string SLAPrint::validate() const
}
}
double expt_max = m_printer_config.max_exposure_time.getFloat();
double expt_min = m_printer_config.min_exposure_time.getFloat();
double expt_cur = m_material_config.exposure_time.getFloat();
if (expt_cur < expt_min || expt_cur > expt_max)
return L("Exposition time is out of printer profile bounds.");
double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat();
double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat();
double iexpt_cur = m_material_config.initial_exposure_time.getFloat();
if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max)
return L("Initial exposition time is out of printer profile bounds.");
return "";
}
@ -1586,7 +1600,11 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
// Cache the plenty of parameters, which influence the final rasterization only,
// or they are only notes not influencing the rasterization step.
static std::unordered_set<std::string> steps_rasterize = {
"min_exposure_time",
"max_exposure_time",
"exposure_time",
"min_initial_exposure_time",
"max_initial_exposure_time",
"initial_exposure_time",
"display_width",
"display_height",

View file

@ -61,7 +61,7 @@ extern std::string normalize_utf8_nfc(const char *src);
// Safely rename a file even if the target exists.
// On Windows, the file explorer (or anti-virus or whatever else) often locks the file
// for a short while, so the file may not be movable. Retry while we see recoverable errors.
extern int rename_file(const std::string &from, const std::string &to);
extern std::error_code rename_file(const std::string &from, const std::string &to);
// Copy a file, adjust the access attributes, so that the target is writable.
extern int copy_file(const std::string &from, const std::string &to);

View file

@ -173,67 +173,247 @@ const std::string& data_dir()
return g_data_dir;
}
#ifdef _WIN32
// The following helpers are borrowed from the LLVM project https://github.com/llvm
namespace WindowsSupport
{
template <typename HandleTraits>
class ScopedHandle {
typedef typename HandleTraits::handle_type handle_type;
handle_type Handle;
ScopedHandle(const ScopedHandle &other) = delete;
void operator=(const ScopedHandle &other) = delete;
public:
ScopedHandle() : Handle(HandleTraits::GetInvalid()) {}
explicit ScopedHandle(handle_type h) : Handle(h) {}
~ScopedHandle() { if (HandleTraits::IsValid(Handle)) HandleTraits::Close(Handle); }
handle_type take() {
handle_type t = Handle;
Handle = HandleTraits::GetInvalid();
return t;
}
ScopedHandle &operator=(handle_type h) {
if (HandleTraits::IsValid(Handle))
HandleTraits::Close(Handle);
Handle = h;
return *this;
}
// True if Handle is valid.
explicit operator bool() const { return HandleTraits::IsValid(Handle) ? true : false; }
operator handle_type() const { return Handle; }
};
struct CommonHandleTraits {
typedef HANDLE handle_type;
static handle_type GetInvalid() { return INVALID_HANDLE_VALUE; }
static void Close(handle_type h) { ::CloseHandle(h); }
static bool IsValid(handle_type h) { return h != GetInvalid(); }
};
typedef ScopedHandle<CommonHandleTraits> ScopedFileHandle;
std::error_code map_windows_error(unsigned windows_error_code)
{
#define MAP_ERR_TO_COND(x, y) case x: return std::make_error_code(std::errc::y)
switch (windows_error_code) {
MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
MAP_ERR_TO_COND(ERROR_SEEK, io_error);
MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
MAP_ERR_TO_COND(WSAEACCES, permission_denied);
MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
MAP_ERR_TO_COND(WSAEFAULT, bad_address);
MAP_ERR_TO_COND(WSAEINTR, interrupted);
MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
default:
return std::error_code(windows_error_code, std::system_category());
}
#undef MAP_ERR_TO_COND
}
static std::error_code rename_internal(HANDLE from_handle, const std::wstring &wide_to, bool replace_if_exists)
{
std::vector<char> rename_info_buf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + (wide_to.size() * sizeof(wchar_t)));
FILE_RENAME_INFO &rename_info = *reinterpret_cast<FILE_RENAME_INFO*>(rename_info_buf.data());
rename_info.ReplaceIfExists = replace_if_exists;
rename_info.RootDirectory = 0;
rename_info.FileNameLength = DWORD(wide_to.size() * sizeof(wchar_t));
std::copy(wide_to.begin(), wide_to.end(), &rename_info.FileName[0]);
::SetLastError(ERROR_SUCCESS);
if (! ::SetFileInformationByHandle(from_handle, FileRenameInfo, &rename_info, (DWORD)rename_info_buf.size())) {
unsigned Error = GetLastError();
if (Error == ERROR_SUCCESS)
Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code.
return map_windows_error(Error);
}
return std::error_code();
}
static std::error_code real_path_from_handle(HANDLE H, std::wstring &buffer)
{
buffer.resize(MAX_PATH + 1);
DWORD CountChars = ::GetFinalPathNameByHandleW(H, (LPWSTR)buffer.data(), (DWORD)buffer.size() - 1, FILE_NAME_NORMALIZED);
if (CountChars > buffer.size()) {
// The buffer wasn't big enough, try again. In this case the return value *does* indicate the size of the null terminator.
buffer.resize((size_t)CountChars);
CountChars = ::GetFinalPathNameByHandleW(H, (LPWSTR)buffer.data(), (DWORD)buffer.size() - 1, FILE_NAME_NORMALIZED);
}
if (CountChars == 0)
return map_windows_error(GetLastError());
buffer.resize(CountChars);
return std::error_code();
}
std::error_code rename(const std::string &from, const std::string &to)
{
// Convert to utf-16.
std::wstring wide_from = boost::nowide::widen(from);
std::wstring wide_to = boost::nowide::widen(to);
ScopedFileHandle from_handle;
// Retry this a few times to defeat badly behaved file system scanners.
for (unsigned retry = 0; retry != 200; ++ retry) {
if (retry != 0)
::Sleep(10);
from_handle = ::CreateFileW((LPWSTR)wide_from.data(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (from_handle)
break;
}
if (! from_handle)
return map_windows_error(GetLastError());
// We normally expect this loop to succeed after a few iterations. If it
// requires more than 200 tries, it's more likely that the failures are due to
// a true error, so stop trying.
for (unsigned retry = 0; retry != 200; ++ retry) {
auto errcode = rename_internal(from_handle, wide_to, true);
if (errcode == std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) {
// Wine doesn't support SetFileInformationByHandle in rename_internal.
// Fall back to MoveFileEx.
if (std::error_code errcode2 = real_path_from_handle(from_handle, wide_from))
return errcode2;
if (::MoveFileExW((LPCWSTR)wide_from.data(), (LPCWSTR)wide_to.data(), MOVEFILE_REPLACE_EXISTING))
return std::error_code();
return map_windows_error(GetLastError());
}
if (! errcode || errcode != std::errc::permission_denied)
return errcode;
// The destination file probably exists and is currently open in another
// process, either because the file was opened without FILE_SHARE_DELETE or
// it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to
// move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE
// to arrange for the destination file to be deleted when the other process
// closes it.
ScopedFileHandle to_handle(::CreateFileW((LPCWSTR)wide_to.data(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL));
if (! to_handle) {
auto errcode = map_windows_error(GetLastError());
// Another process might have raced with us and moved the existing file
// out of the way before we had a chance to open it. If that happens, try
// to rename the source file again.
if (errcode == std::errc::no_such_file_or_directory)
continue;
return errcode;
}
BY_HANDLE_FILE_INFORMATION FI;
if (! ::GetFileInformationByHandle(to_handle, &FI))
return map_windows_error(GetLastError());
// Try to find a unique new name for the destination file.
for (unsigned unique_id = 0; unique_id != 200; ++ unique_id) {
std::wstring tmp_filename = wide_to + L".tmp" + std::to_wstring(unique_id);
std::error_code errcode = rename_internal(to_handle, tmp_filename, false);
if (errcode) {
if (errcode == std::make_error_code(std::errc::file_exists) || errcode == std::make_error_code(std::errc::permission_denied)) {
// Again, another process might have raced with us and moved the file
// before we could move it. Check whether this is the case, as it
// might have caused the permission denied error. If that was the
// case, we don't need to move it ourselves.
ScopedFileHandle to_handle2(::CreateFileW((LPCWSTR)wide_to.data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
if (! to_handle2) {
auto errcode = map_windows_error(GetLastError());
if (errcode == std::errc::no_such_file_or_directory)
break;
return errcode;
}
BY_HANDLE_FILE_INFORMATION FI2;
if (! ::GetFileInformationByHandle(to_handle2, &FI2))
return map_windows_error(GetLastError());
if (FI.nFileIndexHigh != FI2.nFileIndexHigh || FI.nFileIndexLow != FI2.nFileIndexLow || FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber)
break;
continue;
}
return errcode;
}
break;
}
// Okay, the old destination file has probably been moved out of the way at
// this point, so try to rename the source file again. Still, another
// process might have raced with us to create and open the destination
// file, so we need to keep doing this until we succeed.
}
// The most likely root cause.
return std::make_error_code(std::errc::permission_denied);
}
} // namespace WindowsSupport
#endif /* _WIN32 */
// borrowed from LVVM lib/Support/Windows/Path.inc
int rename_file(const std::string &from, const std::string &to)
std::error_code rename_file(const std::string &from, const std::string &to)
{
int ec = 0;
#ifdef _WIN32
// Convert to utf-16.
std::wstring wide_from = boost::nowide::widen(from);
std::wstring wide_to = boost::nowide::widen(to);
// Retry while we see recoverable errors.
// System scanners (eg. indexer) might open the source file when it is written
// and closed.
bool TryReplace = true;
// This loop may take more than 2000 x 1ms to finish.
for (int i = 0; i < 2000; ++ i) {
if (i > 0)
// Sleep 1ms
::Sleep(1);
if (TryReplace) {
// Try ReplaceFile first, as it is able to associate a new data stream
// with the destination even if the destination file is currently open.
if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL))
return 0;
DWORD ReplaceError = ::GetLastError();
ec = -1; // ReplaceError
// If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or
// ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW().
if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT ||
ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) {
TryReplace = false;
continue;
}
// If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry
// using ReplaceFileW().
if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED)
continue;
// We get ERROR_FILE_NOT_FOUND if the destination file is missing.
// MoveFileEx can handle this case.
if (ReplaceError != ERROR_ACCESS_DENIED && ReplaceError != ERROR_FILE_NOT_FOUND && ReplaceError != ERROR_SHARING_VIOLATION)
break;
}
if (::MoveFileExW(wide_from.c_str(), wide_to.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
return 0;
DWORD MoveError = ::GetLastError();
ec = -1; // MoveError
if (MoveError != ERROR_ACCESS_DENIED && MoveError != ERROR_SHARING_VIOLATION)
break;
}
return WindowsSupport::rename(from, to);
#else
boost::nowide::remove(to.c_str());
ec = boost::nowide::rename(from.c_str(), to.c_str());
return std::make_error_code(static_cast<std::errc>(boost::nowide::rename(from.c_str(), to.c_str())));
#endif
return ec;
}
int copy_file(const std::string &from, const std::string &to)

View file

@ -98,9 +98,10 @@ void AppConfig::load()
pt::read_ini(ifs, tree);
} catch (pt::ptree_error& ex) {
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
throw std::runtime_error(wxString::Format(_(L("Error parsing config file, it is probably corrupted. "
"Try to manualy delete the file. Your user profiles will not be affected.\n\n%s\n\n%s")),
AppConfig::config_path(), ex.what()).ToStdString());
throw std::runtime_error(
_utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. "
"Try to manualy delete the file to recover from the error. Your user profiles will not be affected.")) +
"\n\n" + AppConfig::config_path() + "\n\n" + ex.what());
}
// 2) Parse the property_tree, extract the sections and key / value pairs.

View file

@ -293,6 +293,20 @@ bool GUI_App::on_init_inner()
config_wizard_startup(app_conf_exists);
preset_updater->slic3r_update_notify();
preset_updater->sync(preset_bundle);
const GLCanvas3DManager::GLInfo &glinfo = GLCanvas3DManager::get_gl_info();
if (! glinfo.is_version_greater_or_equal_to(2, 0)) {
// Complain about the OpenGL version.
wxString message = wxString::Format(
_(L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n"
"while OpenGL version %s, render %s, vendor %s was detected.")), wxString(glinfo.get_version()), wxString(glinfo.get_renderer()), wxString(glinfo.get_vendor()));
message += "\n";
message += _(L("You may need to update your graphics card driver."));
#ifdef _WIN32
message += "\n";
message += _(L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter."));
#endif
wxMessageBox(message, wxString("PrusaSlicer - ") + _(L("Unsupported OpenGL version")), wxOK | wxICON_ERROR);
}
});
}
});

View file

@ -153,8 +153,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
auto manifold_warning_icon = [this](wxWindow* parent) {
m_fix_throught_netfab_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap);
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_fix_throught_netfab_bitmap);
// auto sizer = new wxBoxSizer(wxHORIZONTAL);
// sizer->Add(m_fix_throught_netfab_bitmap);
if (is_windows10())
m_fix_throught_netfab_bitmap->Bind(wxEVT_CONTEXT_MENU, [this](wxCommandEvent &e)
@ -167,17 +167,19 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list());
});
return sizer;
// return sizer;
return m_fix_throught_netfab_bitmap;
};
line.append_widget(manifold_warning_icon);
// line.append_widget(manifold_warning_icon);
line.near_label_widget = manifold_warning_icon;
def.label = "";
def.gui_type = "legend";
def.tooltip = L("Object name");
#ifdef __APPLE__
def.width = 19;
def.width = 20;
#else
def.width = 21;
def.width = 22;
#endif
def.set_default_value(new ConfigOptionString{ " " });
line.append_option(Option(def, "object_name"));
@ -392,10 +394,19 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
// call back for a rescale of button "Set uniform scale"
m_og->rescale_near_label_widget = [this](wxWindow* win) {
// rescale lock icon
auto *ctrl = dynamic_cast<LockButton*>(win);
if (ctrl == nullptr)
if (ctrl != nullptr) {
ctrl->msw_rescale();
return;
ctrl->msw_rescale();
}
if (win == m_fix_throught_netfab_bitmap)
return;
// rescale "place" of the empty icon (to correct layout of the "Size" and "Scale")
if (dynamic_cast<wxStaticBitmap*>(win) != nullptr)
win->SetMinSize(create_scaled_bitmap(m_parent, "one_layer_lock_on.png").GetSize());
};
}
@ -685,6 +696,7 @@ void ObjectManipulation::emulate_kill_focus()
void ObjectManipulation::update_warning_icon_state(const wxString& tooltip)
{
m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp());
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.bmp().GetSize());
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
}
@ -919,7 +931,10 @@ void ObjectManipulation::msw_rescale()
{
msw_rescale_word_local_combo(m_word_local_combo);
m_manifold_warning_bmp.msw_rescale();
m_fix_throught_netfab_bitmap->SetBitmap(m_manifold_warning_bmp.bmp());
const wxString& tooltip = m_fix_throught_netfab_bitmap->GetToolTipText();
m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp());
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0, 0) : m_manifold_warning_bmp.bmp().GetSize());
m_mirror_bitmap_on.msw_rescale();
m_mirror_bitmap_off.msw_rescale();

View file

@ -64,6 +64,12 @@ public:
m_prev_scale_factor = m_scale_factor;
m_normal_font = get_default_font_for_dpi(dpi);
/* Because of default window font is a primary display font,
* We should set correct font for window before getting em_unit value.
*/
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
this->SetFont(m_normal_font);
#endif
// initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window.
m_em_unit = std::max<size_t>(10, this->GetTextExtent("m").x - 1);
@ -72,6 +78,8 @@ public:
this->Bind(EVT_DPI_CHANGED, [this](const DpiChangedEvent &evt) {
m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT;
m_new_font_point_size = get_default_font_for_dpi(evt.dpi).GetPointSize();
if (!m_can_rescale)
return;
@ -124,6 +132,8 @@ private:
float m_prev_scale_factor;
bool m_can_rescale{ true };
int m_new_font_point_size;
// void recalc_font()
// {
// wxClientDC dc(this);
@ -135,14 +145,22 @@ private:
// check if new scale is differ from previous
bool is_new_scale_factor() const { return fabs(m_scale_factor - m_prev_scale_factor) > 0.001; }
// function for a font scaling of the window
void scale_win_font(wxWindow *window, const int font_point_size)
{
wxFont new_font(window->GetFont());
new_font.SetPointSize(font_point_size);
window->SetFont(new_font);
}
// recursive function for scaling fonts for all controls in Window
void scale_controls_fonts(wxWindow *window, const float scale_f)
void scale_controls_fonts(wxWindow *window, const int font_point_size)
{
auto children = window->GetChildren();
for (auto child : children) {
scale_controls_fonts(child, scale_f);
child->SetFont(child->GetFont().Scaled(scale_f));
scale_controls_fonts(child, font_point_size);
scale_win_font(child, font_point_size);
}
window->Layout();
@ -151,18 +169,18 @@ private:
void rescale(const wxRect &suggested_rect)
{
this->Freeze();
const float relative_scale_factor = m_scale_factor / m_prev_scale_factor;
// rescale fonts of all controls
scale_controls_fonts(this, relative_scale_factor);
this->SetFont(this->GetFont().Scaled(relative_scale_factor));
scale_controls_fonts(this, m_new_font_point_size);
// rescale current window font
scale_win_font(this, m_new_font_point_size);
// rescale normal_font value
m_normal_font = m_normal_font.Scaled(relative_scale_factor);
// set normal application font as a current window font
m_normal_font = this->GetFont();
// An analog of em_unit value from GUI_App.
m_em_unit = std::max<size_t>(10, 10 * m_scale_factor);
// update em_unit value for new window font
m_em_unit = std::max<size_t>(10, this->GetTextExtent("m").x - 1);
// rescale missed controls sizes and images
on_dpi_changed(suggested_rect);

View file

@ -39,10 +39,12 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
{
// Fonts were created by the DPIFrame constructor for the monitor, on which the window opened.
wxGetApp().update_fonts(this);
/*
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
this->SetFont(this->normal_font());
#endif
// Font is already set in DPIFrame constructor
*/
// Load the icon either from the exe, or from the ico file.
#if _WIN32
{

View file

@ -500,7 +500,8 @@ const std::vector<std::string>& Preset::sla_material_options()
if (s_opts.empty()) {
s_opts = {
"initial_layer_height",
"exposure_time", "initial_exposure_time",
"exposure_time",
"initial_exposure_time",
"material_correction",
"material_notes",
"default_sla_material_profile",
@ -526,6 +527,8 @@ const std::vector<std::string>& Preset::sla_printer_options()
"relative_correction",
"absolute_correction",
"gamma_correction",
"min_exposure_time", "max_exposure_time",
"min_initial_exposure_time", "max_initial_exposure_time",
"print_host", "printhost_apikey", "printhost_cafile",
"printer_notes",
"inherits"

View file

@ -838,7 +838,7 @@ static wxString support_combo_value_for_config(const DynamicPrintConfig &config,
static wxString pad_combo_value_for_config(const DynamicPrintConfig &config)
{
return config.opt_bool("pad_enable") ? (config.opt_bool("pad_zero_elevation") ? _("Around object") : _("Below object")) : _("None");
return config.opt_bool("pad_enable") ? (config.opt_bool("pad_zero_elevation") ? _("Around object") : _("Below object")) : _("None");
}
void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
@ -860,8 +860,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
(opt_key == "supports_enable" || opt_key == "support_buildplate_only"))
og_freq_chng_params->set_value("support", support_combo_value_for_config(*m_config, is_fff));
if (! is_fff && (opt_key == "pad_enable" || opt_key == "pad_zero_elevation"))
og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config));
if (! is_fff && (opt_key == "pad_enable" || opt_key == "pad_zero_elevation"))
og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config));
if (opt_key == "brim_width")
{
@ -998,7 +998,7 @@ void Tab::update_frequently_changed_parameters()
og_freq_chng_params->set_value("support", support_combo_value_for_config(*m_config, is_fff));
if (! is_fff)
og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config));
og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config));
const std::string updated_value_key = is_fff ? "fill_density" : "pad_enable";
@ -1772,13 +1772,13 @@ void TabFilament::reload_config()
void TabFilament::update_volumetric_flow_preset_hints()
{
wxString text;
try {
text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle));
} catch (std::exception &ex) {
text = _(L("Volumetric flow hints not available\n\n")) + from_u8(ex.what());
}
m_volumetric_speed_description_line->SetText(text);
wxString text;
try {
text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle));
} catch (std::exception &ex) {
text = _(L("Volumetric flow hints not available\n\n")) + from_u8(ex.what());
}
m_volumetric_speed_description_line->SetText(text);
}
void TabFilament::update()
@ -1788,9 +1788,9 @@ void TabFilament::update()
m_update_cnt++;
wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset()));
m_cooling_description_line->SetText(text);
this->update_volumetric_flow_preset_hints();
wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset()));
m_cooling_description_line->SetText(text);
this->update_volumetric_flow_preset_hints();
Layout();
bool cooling = m_config->opt_bool("cooling", 0);
@ -1812,8 +1812,8 @@ void TabFilament::update()
void TabFilament::OnActivate()
{
this->update_volumetric_flow_preset_hints();
Tab::OnActivate();
this->update_volumetric_flow_preset_hints();
Tab::OnActivate();
}
wxSizer* Tab::description_line_widget(wxWindow* parent, ogStaticText* *StaticText)
@ -2290,6 +2290,12 @@ void TabPrinter::build_sla()
optgroup->append_single_option_line("absolute_correction");
optgroup->append_single_option_line("gamma_correction");
optgroup = page->new_optgroup(_(L("Exposure")));
optgroup->append_single_option_line("min_exposure_time");
optgroup->append_single_option_line("max_exposure_time");
optgroup->append_single_option_line("min_initial_exposure_time");
optgroup->append_single_option_line("max_initial_exposure_time");
optgroup = page->new_optgroup(_(L("Print Host upload")));
build_printhost(optgroup.get());
@ -2560,7 +2566,7 @@ void TabPrinter::build_unregular_pages()
optgroup = page->new_optgroup(_(L("Preview")));
auto reset_to_filament_color = [this, extruder_idx](wxWindow* parent) {
add_scaled_button(parent, &m_reset_to_filament_color, "undo",
add_scaled_button(parent, &m_reset_to_filament_color, "undo",
_(L("Reset to Filament Color")), wxBU_LEFT | wxBU_EXACTFIT);
ScalableButton* btn = m_reset_to_filament_color;
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
@ -2571,7 +2577,7 @@ void TabPrinter::build_unregular_pages()
{
std::vector<std::string> colors = static_cast<const ConfigOptionStrings*>(m_config->option("extruder_colour"))->values;
colors[extruder_idx] = "";
DynamicPrintConfig new_conf = *m_config;
new_conf.set_key_value("extruder_colour", new ConfigOptionStrings(colors));
load_config(new_conf);