Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
commit
1532e02b74
@ -124,45 +124,33 @@ intermediate files, which are not handled correctly by either `b2.exe` or possib
|
||||
|
||||
# Noob guide (step by step)
|
||||
|
||||
Install Visual Studio Community 2019 from
|
||||
[visualstudio.microsoft.com/vs/](https://visualstudio.microsoft.com/vs/)
|
||||
Select all workload options for C++
|
||||
- Install Visual Studio Community 2019 from [visualstudio.microsoft.com/vs/](https://visualstudio.microsoft.com/vs/)
|
||||
- Select all workload options for C++
|
||||
- Install git for Windows from [gitforwindows.org](https://gitforwindows.org/)
|
||||
- download and run the exe accepting all defaults
|
||||
- Download `PrusaSlicer-master.zip` from github
|
||||
- This example will use the directory c:\PrusaSlicer and unzipped to `c:\PrusaSlicer\PrusaSlicer-master\` so this will be the prefix for all the steps. Substitute your as required prefix.
|
||||
- Go to the Windows Start Menu and Click on "Visual Studio 2019" folder, then select the ->"x64 Native Tools Command Prompt" to open a command window
|
||||
|
||||
Install git for Windows from
|
||||
[gitforwindows.org](https://gitforwindows.org/)
|
||||
download and run the exe accepting all defaults
|
||||
cd c:\PrusaSlicer\PrusaSlicer-master\deps
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 16 2019" -DDESTDIR="c:\PrusaSlicer\PrusaSlicer-master"
|
||||
msbuild /m ALL_BUILD.vcxproj // This took 13.5 minutes on the following machine: core I7-7700K @ 4.2Ghz with 32GB main memory and 20min on an average laptop
|
||||
cd c:\PrusaSlicer\PrusaSlicer-master\
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 16 2019" -DCMAKE_PREFIX_PATH="c:\PrusaSlicer\PrusaSlicer-master\usr\local"
|
||||
|
||||
download PrusaSlicer-master.zip from github
|
||||
I downloaded this to c:\PrusaSlicer and unzipped to c:\PrusaSlicer\PrusaSlicer-master\ so this will be my prefix for all my steps. Substitute your prefix.
|
||||
- Open Visual Studio for c++ development (VS asks this the first time you start it)
|
||||
|
||||
Go to the Windows Start Menu and Click on "Visual Studio 2019" folder, then select the ->"x64 Native Tools Command Prompt" to open a command window
|
||||
`Open->Project/Solution` or `File->Open->Project/Solution` (depending on which dialog comes up first)
|
||||
|
||||
cd c:\PrusaSlicer\PrusaSlicer-master\deps
|
||||
- Click on `c:\PrusaSlicer\PrusaSlicer-master\build\PrusaSlicer.sln`
|
||||
|
||||
mkdir build
|
||||
`Debug->Start Debugging` or `Debug->Start Without debugging`
|
||||
|
||||
cd build
|
||||
- PrusaSlicer should start.
|
||||
- You're up and running!
|
||||
|
||||
cmake .. -G "Visual Studio 16 2019" -DDESTDIR="c:\PrusaSlicer\PrusaSlicer-master"
|
||||
|
||||
msbuild /m ALL_BUILD.vcxproj // This took 13.5 minutes on my machine: core I7-7700K @ 4.2Ghz with 32GB main memory and 20min on a average laptop
|
||||
|
||||
cd c:\PrusaSlicer\PrusaSlicer-master\
|
||||
|
||||
mkdir build
|
||||
|
||||
cd build
|
||||
|
||||
cmake .. -G "Visual Studio 16 2019" -DCMAKE_PREFIX_PATH="c:\PrusaSlicer\PrusaSlicer-master\usr\local"
|
||||
|
||||
open Visual Studio for c++ development (VS asks this the first time you start it)
|
||||
|
||||
Open->Project/Solution or File->Open->Project/Solution (depending on which dialog comes up first)
|
||||
|
||||
click on c:\PrusaSlicer\PrusaSlicer-master\build\PrusaSlicer.sln
|
||||
|
||||
Debug->Start Debugging or Debug->Start Without debugging
|
||||
PrusaSlicer should start. You're up and running!
|
||||
|
||||
|
||||
note: Thanks to @douggorgen for the original guide, as an answer for a issue
|
||||
Note: Thanks to @douggorgen for the original guide, as an answer for a issue
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/GCode/PostProcessor.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
@ -483,6 +484,12 @@ int CLI::run(int argc, char **argv)
|
||||
if (printer_technology == ptFFF) {
|
||||
for (auto* mo : model.objects)
|
||||
fff_print.auto_assign_extruders(mo);
|
||||
} else {
|
||||
// The default for "output_filename_format" is good for FDM: "[input_filename_base].gcode"
|
||||
// Replace it with a reasonable SLA default.
|
||||
std::string &format = m_print_config.opt_string("output_filename_format", true);
|
||||
if (format == static_cast<const ConfigOptionString*>(m_print_config.def()->get("output_filename_format")->default_value.get())->value)
|
||||
format = "[input_filename_base].SL1";
|
||||
}
|
||||
print->apply(model, m_print_config);
|
||||
std::string err = print->validate();
|
||||
@ -513,6 +520,8 @@ int CLI::run(int argc, char **argv)
|
||||
}
|
||||
outfile = outfile_final;
|
||||
}
|
||||
// Run the post-processing scripts if defined.
|
||||
run_post_process_scripts(outfile, fff_print.full_print_config());
|
||||
boost::nowide::cout << "Slicing result exported to " << outfile << std::endl;
|
||||
} catch (const std::exception &ex) {
|
||||
boost::nowide::cerr << ex.what() << std::endl;
|
||||
|
@ -1237,7 +1237,7 @@ static void pinch_contours_insert_phony_outer_intersections(std::vector<Segmente
|
||||
for (SegmentIntersection &ip : segs[i_vline - 1].intersections)
|
||||
if (ip.has_right_horizontal())
|
||||
ip.next_on_contour = map[ip.next_on_contour];
|
||||
if (i_vline < segs.size()) {
|
||||
if (i_vline + 1 < segs.size()) {
|
||||
// Reindex references on next intersection line.
|
||||
for (SegmentIntersection &ip : segs[i_vline + 1].intersections)
|
||||
if (ip.has_left_horizontal())
|
||||
|
@ -179,17 +179,22 @@ static int run_script(const std::string &script, const std::string &gcode, std::
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void run_post_process_scripts(const std::string &path, const PrintConfig &config)
|
||||
void run_post_process_scripts(const std::string &path, const DynamicPrintConfig &config)
|
||||
{
|
||||
if (config.post_process.values.empty())
|
||||
const auto* post_process = config.opt<ConfigOptionStrings>("post_process");
|
||||
if (// likely running in SLA mode
|
||||
post_process == nullptr ||
|
||||
// no post-processing script
|
||||
post_process->values.empty())
|
||||
return;
|
||||
|
||||
// Store print configuration into environment variables.
|
||||
config.setenv_();
|
||||
auto gcode_file = boost::filesystem::path(path);
|
||||
if (! boost::filesystem::exists(gcode_file))
|
||||
throw Slic3r::RuntimeError(std::string("Post-processor can't find exported gcode file"));
|
||||
|
||||
for (const std::string &scripts : config.post_process.values) {
|
||||
for (const std::string &scripts : post_process->values) {
|
||||
std::vector<std::string> lines;
|
||||
boost::split(lines, scripts, boost::is_any_of("\r\n"));
|
||||
for (std::string script : lines) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
extern void run_post_process_scripts(const std::string &path, const PrintConfig &config);
|
||||
extern void run_post_process_scripts(const std::string &path, const DynamicPrintConfig &config);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -991,7 +991,15 @@ const Preset* PresetCollection::get_preset_parent(const Preset& child) const
|
||||
if (it != m_presets.end())
|
||||
preset = &(*it);
|
||||
}
|
||||
return (preset == nullptr/* || preset->is_default */|| preset->is_external) ? nullptr : preset;
|
||||
return
|
||||
// not found
|
||||
(preset == nullptr/* || preset->is_default */||
|
||||
// this should not happen, user profile should not derive from an external profile
|
||||
preset->is_external ||
|
||||
// this should not happen, however people are creative, see GH #4996
|
||||
preset == &child) ?
|
||||
nullptr :
|
||||
preset;
|
||||
}
|
||||
|
||||
// Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist.
|
||||
|
@ -1095,7 +1095,11 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
||||
namespace pt = boost::property_tree;
|
||||
pt::ptree tree;
|
||||
boost::nowide::ifstream ifs(path);
|
||||
try {
|
||||
pt::read_ini(ifs, tree);
|
||||
} catch (const boost::property_tree::ini_parser::ini_parser_error &err) {
|
||||
throw Slic3r::RuntimeError(format("Failed loading config bundle \"%1%\"\nError: \"%2%\" at line %3%", path, err.message(), err.line()).c_str());
|
||||
}
|
||||
|
||||
const VendorProfile *vendor_profile = nullptr;
|
||||
if (flags & (LOAD_CFGBNDLE_SYSTEM | LOAD_CFGBUNDLE_VENDOR_ONLY)) {
|
||||
|
@ -63,8 +63,10 @@ void PrintConfigDef::init_common_params()
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("thumbnails", coPoints);
|
||||
def->label = L("Picture sizes to be stored into a .gcode and .sl1 files");
|
||||
def->label = L("G-code thumbnails");
|
||||
def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 files");
|
||||
def->mode = comExpert;
|
||||
def->gui_type = "one_string";
|
||||
def->set_default_value(new ConfigOptionPoints());
|
||||
|
||||
def = this->add("layer_height", coFloat);
|
||||
@ -1981,7 +1983,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"in order to remove any visible seam. This option requires a single perimeter, "
|
||||
"no infill, no top solid layers and no support material. You can still set "
|
||||
"any number of bottom solid layers as well as skirt/brim loops. "
|
||||
"It won't work when printing more than an object.");
|
||||
"It won't work when printing more than one single object.");
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("standby_temperature_delta", coInt);
|
||||
|
@ -264,9 +264,11 @@ bool Snapshot::equal_to_active(const AppConfig &app_config) const
|
||||
boost::filesystem::path path1 = data_dir / subdir;
|
||||
boost::filesystem::path path2 = snapshot_dir / subdir;
|
||||
std::vector<std::string> files1, files2;
|
||||
if (boost::filesystem::is_directory(path1))
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(path1))
|
||||
if (Slic3r::is_ini_file(dir_entry))
|
||||
files1.emplace_back(dir_entry.path().filename().string());
|
||||
if (boost::filesystem::is_directory(path2))
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(path2))
|
||||
if (Slic3r::is_ini_file(dir_entry))
|
||||
files2.emplace_back(dir_entry.path().filename().string());
|
||||
@ -459,8 +461,11 @@ void SnapshotDB::restore_snapshot(const Snapshot &snapshot, AppConfig &app_confi
|
||||
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
|
||||
// Remove existing ini files and restore the ini files from the snapshot.
|
||||
for (const char *subdir : snapshot_subdirs) {
|
||||
delete_existing_ini_files(data_dir / subdir);
|
||||
copy_config_dir_single_level(snapshot_dir / subdir, data_dir / subdir);
|
||||
boost::filesystem::path src = snapshot_dir / subdir;
|
||||
boost::filesystem::path dst = data_dir / subdir;
|
||||
delete_existing_ini_files(dst);
|
||||
if (boost::filesystem::is_directory(src))
|
||||
copy_config_dir_single_level(src, dst);
|
||||
}
|
||||
// Update AppConfig with the selections of the print / sla_print / filament / sla_material / printer profiles
|
||||
// and about the installed printer types and variants.
|
||||
|
@ -298,6 +298,11 @@ AboutDialog::AboutDialog()
|
||||
buttons->Insert(0, copy_rights_btn, 0, wxLEFT, 5);
|
||||
copy_rights_btn->Bind(wxEVT_BUTTON, &AboutDialog::onCopyrightBtn, this);
|
||||
|
||||
m_copy_version_btn_id = NewControlId();
|
||||
auto copy_version_btn = new wxButton(this, m_copy_version_btn_id, _L("Copy Version Info"));
|
||||
buttons->Insert(1, copy_version_btn, 0, wxLEFT, 5);
|
||||
copy_version_btn->Bind(wxEVT_BUTTON, &AboutDialog::onCopyToClipboard, this);
|
||||
|
||||
this->SetEscapeId(wxID_CLOSE);
|
||||
this->Bind(wxEVT_BUTTON, &AboutDialog::onCloseDialog, this, wxID_CLOSE);
|
||||
vsizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
|
||||
@ -348,5 +353,12 @@ void AboutDialog::onCopyrightBtn(wxEvent &)
|
||||
dlg.ShowModal();
|
||||
}
|
||||
|
||||
void AboutDialog::onCopyToClipboard(wxEvent&)
|
||||
{
|
||||
wxTheClipboard->Open();
|
||||
wxTheClipboard->SetData(new wxTextDataObject(_L("Version") + " " + std::string(SLIC3R_VERSION)));
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
@ -60,6 +60,7 @@ class AboutDialog : public DPIDialog
|
||||
wxHtmlWindow* m_html;
|
||||
wxStaticBitmap* m_logo;
|
||||
int m_copy_rights_btn_id { wxID_ANY };
|
||||
int m_copy_version_btn_id { wxID_ANY };
|
||||
public:
|
||||
AboutDialog();
|
||||
|
||||
@ -70,6 +71,7 @@ private:
|
||||
void onLinkClicked(wxHtmlLinkEvent &event);
|
||||
void onCloseDialog(wxEvent &);
|
||||
void onCopyrightBtn(wxEvent &);
|
||||
void onCopyToClipboard(wxEvent&);
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
@ -185,7 +185,7 @@ void BackgroundSlicingProcess::process_fff()
|
||||
break;
|
||||
}
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
run_post_process_scripts(export_path, m_fff_print->full_print_config());
|
||||
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
|
||||
} else if (! m_upload_job.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
@ -538,7 +538,7 @@ void BackgroundSlicingProcess::prepare_upload()
|
||||
if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS) {
|
||||
throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
|
||||
}
|
||||
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
||||
run_post_process_scripts(source_path.string(), m_fff_print->full_print_config());
|
||||
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
} else {
|
||||
m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "ConfigManipulation.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "format.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
@ -184,30 +185,21 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
}
|
||||
|
||||
if (config->option<ConfigOptionPercent>("fill_density")->value == 100) {
|
||||
auto fill_pattern = config->option<ConfigOptionEnum<InfillPattern>>("fill_pattern")->value;
|
||||
std::string str_fill_pattern = "";
|
||||
t_config_enum_values map_names = config->option<ConfigOptionEnum<InfillPattern>>("fill_pattern")->get_enum_values();
|
||||
for (auto it : map_names) {
|
||||
if (fill_pattern == it.second) {
|
||||
str_fill_pattern = it.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!str_fill_pattern.empty()) {
|
||||
const std::vector<std::string>& external_fill_pattern = config->def()->get("top_fill_pattern")->enum_values;
|
||||
bool correct_100p_fill = false;
|
||||
for (const std::string& fill : external_fill_pattern)
|
||||
{
|
||||
if (str_fill_pattern == fill)
|
||||
correct_100p_fill = true;
|
||||
}
|
||||
// get fill_pattern name from enum_labels for using this one at dialog_msg
|
||||
str_fill_pattern = _utf8(config->def()->get("fill_pattern")->enum_labels[fill_pattern]);
|
||||
std::string fill_pattern = config->option<ConfigOptionEnum<InfillPattern>>("fill_pattern")->serialize();
|
||||
const auto &top_fill_pattern_values = config->def()->get("top_fill_pattern")->enum_values;
|
||||
bool correct_100p_fill = std::find(top_fill_pattern_values.begin(), top_fill_pattern_values.end(), fill_pattern) != top_fill_pattern_values.end();
|
||||
if (!correct_100p_fill) {
|
||||
wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density."))) % str_fill_pattern).str());
|
||||
// get fill_pattern name from enum_labels for using this one at dialog_msg
|
||||
const ConfigOptionDef *fill_pattern_def = config->def()->get("fill_pattern");
|
||||
assert(fill_pattern_def != nullptr);
|
||||
auto it_pattern = std::find(fill_pattern_def->enum_values.begin(), fill_pattern_def->enum_values.end(), fill_pattern);
|
||||
assert(it_pattern != fill_pattern_def->enum_values.end());
|
||||
if (it_pattern != fill_pattern_def->enum_values.end()) {
|
||||
wxString msg_text = GUI::format_wxstr(_L("The %1% infill pattern is not supposed to work at 100%% density."),
|
||||
_(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()]));
|
||||
if (is_global_config)
|
||||
msg_text += "\n\n" + _(L("Shall I switch to rectilinear fill pattern?"));
|
||||
wxMessageDialog dialog(nullptr, msg_text, _(L("Infill")),
|
||||
msg_text += "\n\n" + _L("Shall I switch to rectilinear fill pattern?");
|
||||
wxMessageDialog dialog(nullptr, msg_text, _L("Infill"),
|
||||
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) );
|
||||
DynamicPrintConfig new_conf = *config;
|
||||
auto answer = dialog.ShowModal();
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "wxExtensions.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "format.hpp"
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
@ -12,6 +13,7 @@
|
||||
#include <wx/numformatter.h>
|
||||
#include <wx/tooltip.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/tokenzr.h>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "OG_CustomCtrl.hpp"
|
||||
|
||||
@ -52,6 +54,16 @@ wxString double_to_string(double const value, const int max_precision /*= 4*/)
|
||||
return s;
|
||||
}
|
||||
|
||||
wxString get_thumbnails_string(const std::vector<Vec2d>& values)
|
||||
{
|
||||
wxString ret_str;
|
||||
if (!values.empty())
|
||||
for (auto el : values)
|
||||
ret_str += wxString::Format("%ix%i, ", int(el[0]), int(el[1]));
|
||||
return ret_str;
|
||||
}
|
||||
|
||||
|
||||
Field::~Field()
|
||||
{
|
||||
if (m_on_kill_focus)
|
||||
@ -304,6 +316,43 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
|
||||
m_value = std::string(str.ToUTF8().data());
|
||||
break; }
|
||||
|
||||
case coPoints: {
|
||||
std::vector<Vec2d> out_values;
|
||||
str.Replace(" ", wxEmptyString, true);
|
||||
if (!str.IsEmpty()) {
|
||||
bool invalid_val = false;
|
||||
wxStringTokenizer thumbnails(str, ",");
|
||||
while (thumbnails.HasMoreTokens()) {
|
||||
wxString token = thumbnails.GetNextToken();
|
||||
double x, y;
|
||||
wxStringTokenizer thumbnail(token, "x");
|
||||
if (thumbnail.HasMoreTokens()) {
|
||||
wxString x_str = thumbnail.GetNextToken();
|
||||
if (x_str.ToDouble(&x) && thumbnail.HasMoreTokens()) {
|
||||
wxString y_str = thumbnail.GetNextToken();
|
||||
if (y_str.ToDouble(&y) && !thumbnail.HasMoreTokens()) {
|
||||
out_values.push_back(Vec2d(x, y));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
invalid_val = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (invalid_val) {
|
||||
wxString text_value;
|
||||
if (!m_value.empty())
|
||||
text_value = get_thumbnails_string(boost::any_cast<std::vector<Vec2d>>(m_value));
|
||||
set_value(text_value, true);
|
||||
show_error(m_parent, format_wxstr(_L("Invalid input format. It must be represented like \"%1%\""),"XxY, XxY, ..." ));
|
||||
}
|
||||
}
|
||||
|
||||
m_value = out_values;
|
||||
break; }
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -371,6 +420,9 @@ void TextCtrl::BUILD() {
|
||||
text_value = vec->get_at(m_opt_idx);
|
||||
break;
|
||||
}
|
||||
case coPoints:
|
||||
text_value = get_thumbnails_string(m_opt.get_default_value<ConfigOptionPoints>()->values);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ using t_change = std::function<void(const t_config_option_key&, const boost::any
|
||||
using t_back_to_init = std::function<void(const std::string&)>;
|
||||
|
||||
wxString double_to_string(double const value, const int max_precision = 4);
|
||||
wxString get_thumbnails_string(const std::vector<Vec2d>& values);
|
||||
|
||||
class Field {
|
||||
protected:
|
||||
|
@ -3775,7 +3775,7 @@ GLCanvas3D::WipeTowerInfo GLCanvas3D::get_wipe_tower_info() const
|
||||
m_config->opt_float("wipe_tower_y"));
|
||||
wti.m_rotation = (M_PI/180.) * m_config->opt_float("wipe_tower_rotation_angle");
|
||||
const BoundingBoxf3& bb = vol->bounding_box();
|
||||
wti.m_bb_size = Vec2d(bb.size().x(), bb.size().y());
|
||||
wti.m_bb = BoundingBoxf{to_2d(bb.min), to_2d(bb.max)};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -676,8 +676,8 @@ public:
|
||||
class WipeTowerInfo {
|
||||
protected:
|
||||
Vec2d m_pos = {std::nan(""), std::nan("")};
|
||||
Vec2d m_bb_size = {0., 0.};
|
||||
double m_rotation = 0.;
|
||||
BoundingBoxf m_bb;
|
||||
friend class GLCanvas3D;
|
||||
public:
|
||||
|
||||
@ -688,7 +688,7 @@ public:
|
||||
|
||||
inline const Vec2d& pos() const { return m_pos; }
|
||||
inline double rotation() const { return m_rotation; }
|
||||
inline const Vec2d bb_size() const { return m_bb_size; }
|
||||
inline const Vec2d bb_size() const { return m_bb.size(); }
|
||||
|
||||
void apply_wipe_tower() const;
|
||||
};
|
||||
|
@ -201,7 +201,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
||||
}
|
||||
break;
|
||||
case coPoints:{
|
||||
if (opt_key.compare("bed_shape") == 0) {
|
||||
if (opt_key == "bed_shape" || opt_key == "thumbnails") {
|
||||
config.option<ConfigOptionPoints>(opt_key)->values = boost::any_cast<std::vector<Vec2d>>(value);
|
||||
break;
|
||||
}
|
||||
|
@ -933,13 +933,7 @@ bool GUI_App::on_init_inner()
|
||||
load_current_presets();
|
||||
mainframe->Show(true);
|
||||
|
||||
/* Temporary workaround for the correct behavior of the Scrolled sidebar panel:
|
||||
* change min hight of object list to the normal min value (15 * wxGetApp().em_unit())
|
||||
* after first whole Mainframe updating/layouting
|
||||
*/
|
||||
const int list_min_height = 15 * em_unit();
|
||||
if (obj_list()->GetMinSize().GetY() > list_min_height)
|
||||
obj_list()->SetMinSize(wxSize(-1, list_min_height));
|
||||
obj_list()->set_min_height();
|
||||
|
||||
update_mode(); // update view mode after fix of the object_list size
|
||||
|
||||
@ -1150,13 +1144,8 @@ void GUI_App::recreate_GUI(const wxString& msg_name)
|
||||
mainframe->Show(true);
|
||||
|
||||
dlg.Update(90, _L("Loading of a mode view") + dots);
|
||||
/* Temporary workaround for the correct behavior of the Scrolled sidebar panel:
|
||||
* change min hight of object list to the normal min value (15 * wxGetApp().em_unit())
|
||||
* after first whole Mainframe updating/layouting
|
||||
*/
|
||||
const int list_min_height = 15 * em_unit();
|
||||
if (obj_list()->GetMinSize().GetY() > list_min_height)
|
||||
obj_list()->SetMinSize(wxSize(-1, list_min_height));
|
||||
|
||||
obj_list()->set_min_height();
|
||||
update_mode();
|
||||
|
||||
// #ys_FIXME_delete_after_testing Do we still need this ?
|
||||
@ -1582,13 +1571,16 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
ConfigSnapshotDialog dlg(Slic3r::GUI::Config::SnapshotDB::singleton(), on_snapshot);
|
||||
dlg.ShowModal();
|
||||
if (!dlg.snapshot_to_activate().empty()) {
|
||||
if (!Config::SnapshotDB::singleton().is_on_snapshot(*app_config))
|
||||
if (! Config::SnapshotDB::singleton().is_on_snapshot(*app_config))
|
||||
Config::SnapshotDB::singleton().take_snapshot(*app_config, Config::Snapshot::SNAPSHOT_BEFORE_ROLLBACK);
|
||||
app_config->set("on_snapshot",
|
||||
Config::SnapshotDB::singleton().restore_snapshot(dlg.snapshot_to_activate(), *app_config).id);
|
||||
try {
|
||||
app_config->set("on_snapshot", Config::SnapshotDB::singleton().restore_snapshot(dlg.snapshot_to_activate(), *app_config).id);
|
||||
preset_bundle->load_presets(*app_config);
|
||||
// Load the currently selected preset into the GUI, update the preset selection box.
|
||||
load_current_presets();
|
||||
} catch (std::exception &ex) {
|
||||
GUI::show_error(nullptr, _L("Failed to activate configuration snapshot.") + "\n" + into_u8(ex.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -191,7 +191,7 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||
// Bind(wxEVT_KEY_DOWN, &ObjectList::OnChar, this);
|
||||
{
|
||||
// Accelerators
|
||||
wxAcceleratorEntry entries[8];
|
||||
wxAcceleratorEntry entries[10];
|
||||
entries[0].Set(wxACCEL_CTRL, (int) 'C', wxID_COPY);
|
||||
entries[1].Set(wxACCEL_CTRL, (int) 'X', wxID_CUT);
|
||||
entries[2].Set(wxACCEL_CTRL, (int) 'V', wxID_PASTE);
|
||||
@ -200,7 +200,9 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||
entries[5].Set(wxACCEL_CTRL, (int) 'Y', wxID_REDO);
|
||||
entries[6].Set(wxACCEL_NORMAL, WXK_DELETE, wxID_DELETE);
|
||||
entries[7].Set(wxACCEL_NORMAL, WXK_BACK, wxID_DELETE);
|
||||
wxAcceleratorTable accel(8, entries);
|
||||
entries[8].Set(wxACCEL_NORMAL, int('+'), wxID_ADD);
|
||||
entries[9].Set(wxACCEL_NORMAL, int('-'), wxID_REMOVE);
|
||||
wxAcceleratorTable accel(10, entries);
|
||||
SetAcceleratorTable(accel);
|
||||
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->copy(); }, wxID_COPY);
|
||||
@ -209,6 +211,8 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->undo(); }, wxID_UNDO);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->redo(); }, wxID_REDO);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->increase_instances(); }, wxID_ADD);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->decrease_instances(); }, wxID_REMOVE);
|
||||
}
|
||||
#else //__WXOSX__
|
||||
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
|
||||
@ -254,6 +258,18 @@ ObjectList::~ObjectList()
|
||||
{
|
||||
}
|
||||
|
||||
void ObjectList::set_min_height()
|
||||
{
|
||||
/* Temporary workaround for the correct behavior of the Scrolled sidebar panel:
|
||||
* change min hight of object list to the normal min value (35 * wxGetApp().em_unit())
|
||||
* after first whole Mainframe updating/layouting
|
||||
*/
|
||||
const int list_min_height = 35 * wxGetApp().em_unit();
|
||||
if (this->GetMinSize().GetY() > list_min_height)
|
||||
this->SetMinSize(wxSize(-1, list_min_height));
|
||||
}
|
||||
|
||||
|
||||
void ObjectList::create_objects_ctrl()
|
||||
{
|
||||
/* Temporary workaround for the correct behavior of the Scrolled sidebar panel:
|
||||
@ -1092,6 +1108,16 @@ void ObjectList::redo()
|
||||
wxGetApp().plater()->redo();
|
||||
}
|
||||
|
||||
void ObjectList::increase_instances()
|
||||
{
|
||||
wxGetApp().plater()->increase_instances(1);
|
||||
}
|
||||
|
||||
void ObjectList::decrease_instances()
|
||||
{
|
||||
wxGetApp().plater()->decrease_instances(1);
|
||||
}
|
||||
|
||||
#ifndef __WXOSX__
|
||||
void ObjectList::key_event(wxKeyEvent& event)
|
||||
{
|
||||
@ -1116,6 +1142,10 @@ void ObjectList::key_event(wxKeyEvent& event)
|
||||
redo();
|
||||
else if (wxGetKeyState(wxKeyCode('Z')) && wxGetKeyState(WXK_CONTROL))
|
||||
undo();
|
||||
else if (event.GetUnicodeKey() == '+')
|
||||
increase_instances();
|
||||
else if (event.GetUnicodeKey() == '-')
|
||||
decrease_instances();
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
@ -207,6 +207,7 @@ public:
|
||||
ObjectList(wxWindow* parent);
|
||||
~ObjectList();
|
||||
|
||||
void set_min_height();
|
||||
|
||||
std::map<std::string, wxBitmap> CATEGORY_ICON;
|
||||
|
||||
@ -257,6 +258,8 @@ public:
|
||||
bool paste_from_clipboard();
|
||||
void undo();
|
||||
void redo();
|
||||
void increase_instances();
|
||||
void decrease_instances();
|
||||
|
||||
void get_settings_choice(const wxString& category_name);
|
||||
void get_freq_settings_choice(const wxString& bundle_name);
|
||||
|
@ -30,11 +30,10 @@ public:
|
||||
ArrangePolygon get_arrange_polygon() const
|
||||
{
|
||||
Polygon ap({
|
||||
{coord_t(0), coord_t(0)},
|
||||
{scaled(m_bb_size(X)), coord_t(0)},
|
||||
{scaled(m_bb_size)},
|
||||
{coord_t(0), scaled(m_bb_size(Y))},
|
||||
{coord_t(0), coord_t(0)},
|
||||
{scaled(m_bb.min)},
|
||||
{scaled(m_bb.max.x()), scaled(m_bb.min.y())},
|
||||
{scaled(m_bb.max)},
|
||||
{scaled(m_bb.min.x()), scaled(m_bb.max.y())}
|
||||
});
|
||||
|
||||
ArrangePolygon ret;
|
||||
|
@ -132,6 +132,7 @@ void KBShortcutsDialog::fill_shortcuts()
|
||||
{ ctrl + "5", L("Switch to 3D") },
|
||||
{ ctrl + "6", L("Switch to Preview") },
|
||||
{ ctrl + "J", L("Print host upload queue") },
|
||||
{ ctrl + "Shift+" + "I", L("Open new instance") },
|
||||
// View
|
||||
{ "0-6", L("Camera view") },
|
||||
{ "E", L("Show/Hide object/instance labels") },
|
||||
|
@ -1191,9 +1191,8 @@ void MainFrame::init_menubar_as_editor()
|
||||
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr, []() {return true; }, this);
|
||||
|
||||
windowMenu->AppendSeparator();
|
||||
append_menu_item(windowMenu, wxID_ANY, _L("Open new instance") + "\tCtrl+I", _L("Open a new PrusaSlicer instance"),
|
||||
append_menu_item(windowMenu, wxID_ANY, _L("Open new instance") + "\tCtrl+Shift+I", _L("Open a new PrusaSlicer instance"),
|
||||
[this](wxCommandEvent&) { start_new_slicer(); }, "", nullptr, [this]() {return m_plater != nullptr && wxGetApp().app_config->get("single_instance") != "1"; }, this);
|
||||
|
||||
}
|
||||
|
||||
// View menu
|
||||
|
@ -178,7 +178,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
|
||||
#ifdef __WXMSW__
|
||||
// when we use 2 monitors with different DPIs, GetTextExtent() return value for the primary display
|
||||
// so, use dc.GetMultiLineTextExtent on Windows
|
||||
wxPaintDC dc(this);
|
||||
wxClientDC dc(this);
|
||||
dc.SetFont(m_font);
|
||||
dc.GetMultiLineTextExtent(label, &label_w, &label_h);
|
||||
#else
|
||||
|
@ -25,20 +25,22 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id) {
|
||||
const t_field& OptionsGroup::build_field(const t_config_option_key& id, const ConfigOptionDef& opt) {
|
||||
// Check the gui_type field first, fall through
|
||||
// is the normal type.
|
||||
if (opt.gui_type.compare("select") == 0) {
|
||||
} else if (opt.gui_type.compare("select_open") == 0) {
|
||||
if (opt.gui_type == "select") {
|
||||
} else if (opt.gui_type == "select_open") {
|
||||
m_fields.emplace(id, std::move(Choice::Create<Choice>(this->ctrl_parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("color") == 0) {
|
||||
} else if (opt.gui_type == "color") {
|
||||
m_fields.emplace(id, std::move(ColourPicker::Create<ColourPicker>(this->ctrl_parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("f_enum_open") == 0 ||
|
||||
opt.gui_type.compare("i_enum_open") == 0 ||
|
||||
opt.gui_type.compare("i_enum_closed") == 0) {
|
||||
} else if (opt.gui_type == "f_enum_open" ||
|
||||
opt.gui_type == "i_enum_open" ||
|
||||
opt.gui_type == "i_enum_closed") {
|
||||
m_fields.emplace(id, std::move(Choice::Create<Choice>(this->ctrl_parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("slider") == 0) {
|
||||
} else if (opt.gui_type == "slider") {
|
||||
m_fields.emplace(id, std::move(SliderCtrl::Create<SliderCtrl>(this->ctrl_parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("i_spin") == 0) { // Spinctrl
|
||||
} else if (opt.gui_type.compare("legend") == 0) { // StaticText
|
||||
} else if (opt.gui_type == "i_spin") { // Spinctrl
|
||||
} else if (opt.gui_type == "legend") { // StaticText
|
||||
m_fields.emplace(id, std::move(StaticText::Create<StaticText>(this->ctrl_parent(), opt, id)));
|
||||
} else if (opt.gui_type == "one_string") {
|
||||
m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(this->ctrl_parent(), opt, id)));
|
||||
} else {
|
||||
switch (opt.type) {
|
||||
case coFloatOrPercent:
|
||||
@ -837,9 +839,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
||||
}
|
||||
if (config.option<ConfigOptionStrings>(opt_key)->values.empty())
|
||||
ret = text_value;
|
||||
else if (opt->gui_flags.compare("serialized") == 0) {
|
||||
else if (opt->gui_flags == "serialized") {
|
||||
std::vector<std::string> values = config.option<ConfigOptionStrings>(opt_key)->values;
|
||||
if (!values.empty() && values[0].compare("") != 0)
|
||||
if (!values.empty() && !values[0].empty())
|
||||
for (auto el : values)
|
||||
text_value += el + ";";
|
||||
ret = text_value;
|
||||
@ -897,6 +899,8 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
||||
case coPoints:
|
||||
if (opt_key == "bed_shape")
|
||||
ret = config.option<ConfigOptionPoints>(opt_key)->values;
|
||||
if (opt_key == "thumbnails")
|
||||
ret = get_thumbnails_string(config.option<ConfigOptionPoints>(opt_key)->values);
|
||||
else
|
||||
ret = config.option<ConfigOptionPoints>(opt_key)->get_at(idx);
|
||||
break;
|
||||
|
@ -2399,6 +2399,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
wxGetApp().sidebar().update_ui_from_settings();
|
||||
};
|
||||
|
||||
if (!is_project_file) {
|
||||
if (imperial_units)
|
||||
convert_from_imperial_units(model);
|
||||
else if (model.looks_like_imperial_units()) {
|
||||
@ -2410,7 +2411,6 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
convert_from_imperial_units(model);
|
||||
}
|
||||
|
||||
if (! is_project_file) {
|
||||
if (model.looks_like_multipart_object()) {
|
||||
wxMessageDialog msg_dlg(q, _L(
|
||||
"This file contains several objects positioned at multiple heights.\n"
|
||||
|
@ -94,7 +94,7 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
if ( (type == Preset::TYPE_SLA_MATERIAL || type == Preset::TYPE_PRINTER) && opt_key != "bed_shape")
|
||||
if ( (type == Preset::TYPE_SLA_MATERIAL || type == Preset::TYPE_PRINTER) && opt_key != "bed_shape" && opt_key != "thumbnails")
|
||||
switch (config->option(opt_key)->type())
|
||||
{
|
||||
case coInts: change_opt_key<ConfigOptionInts >(opt_key, config, cnt); break;
|
||||
|
@ -109,14 +109,14 @@ Tab::Tab(wxNotebook* parent, const wxString& title, Preset::Type type) :
|
||||
m_compatible_printers.type = Preset::TYPE_PRINTER;
|
||||
m_compatible_printers.key_list = "compatible_printers";
|
||||
m_compatible_printers.key_condition = "compatible_printers_condition";
|
||||
m_compatible_printers.dialog_title = _(L("Compatible printers")).ToUTF8();
|
||||
m_compatible_printers.dialog_label = _(L("Select the printers this profile is compatible with.")).ToUTF8();
|
||||
m_compatible_printers.dialog_title = _L("Compatible printers");
|
||||
m_compatible_printers.dialog_label = _L("Select the printers this profile is compatible with.");
|
||||
|
||||
m_compatible_prints.type = Preset::TYPE_PRINT;
|
||||
m_compatible_prints.key_list = "compatible_prints";
|
||||
m_compatible_prints.key_condition = "compatible_prints_condition";
|
||||
m_compatible_prints.dialog_title = _(L("Compatible print profiles")).ToUTF8();
|
||||
m_compatible_prints.dialog_label = _(L("Select the print profiles this profile is compatible with.")).ToUTF8();
|
||||
m_compatible_prints.dialog_title = _L("Compatible print profiles");
|
||||
m_compatible_prints.dialog_label = _L("Select the print profiles this profile is compatible with.");
|
||||
|
||||
wxGetApp().tabs_list.push_back(this);
|
||||
|
||||
@ -653,7 +653,7 @@ void TabPrinter::init_options_list()
|
||||
|
||||
for (const auto opt_key : m_config->keys())
|
||||
{
|
||||
if (opt_key == "bed_shape") {
|
||||
if (opt_key == "bed_shape" || opt_key == "thumbnails") {
|
||||
m_options_list.emplace(opt_key, m_opt_status_value);
|
||||
continue;
|
||||
}
|
||||
@ -2173,6 +2173,11 @@ void TabPrinter::build_fff()
|
||||
|
||||
optgroup = page->new_optgroup(L("Firmware"));
|
||||
optgroup->append_single_option_line("gcode_flavor");
|
||||
|
||||
option = optgroup->get_option("thumbnails");
|
||||
option.opt.full_width = true;
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
optgroup->append_single_option_line("silent_mode");
|
||||
optgroup->append_single_option_line("remaining_times");
|
||||
|
||||
|
@ -136,8 +136,8 @@ protected:
|
||||
ScalableButton *btn = nullptr;
|
||||
std::string key_list; // "compatible_printers"
|
||||
std::string key_condition;
|
||||
std::string dialog_title;
|
||||
std::string dialog_label;
|
||||
wxString dialog_title;
|
||||
wxString dialog_label;
|
||||
};
|
||||
PresetDependencies m_compatible_printers;
|
||||
PresetDependencies m_compatible_prints;
|
||||
|
@ -968,6 +968,9 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig&
|
||||
BedShape shape(*config.option<ConfigOptionPoints>(opt_key));
|
||||
return shape.get_full_name_with_params();
|
||||
}
|
||||
if (opt_key == "thumbnails")
|
||||
return get_thumbnails_string(config.option<ConfigOptionPoints>(opt_key)->values);
|
||||
|
||||
Vec2d val = config.opt<ConfigOptionPoints>(opt_key)->get_at(opt_idx);
|
||||
return from_u8((boost::format("[%1%]") % ConfigOptionPoint(val).serialize()).str());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user