This commit is contained in:
enricoturri1966 2020-12-08 11:43:14 +01:00
commit 1532e02b74
31 changed files with 255 additions and 139 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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