Merge branch 'new_cooling_logic'

This commit is contained in:
bubnikv 2018-04-26 19:00:49 +02:00
commit 7a8f68cfe6
64 changed files with 5906 additions and 1363 deletions

View File

@ -278,5 +278,6 @@ sub system_info
# this package declaration prevents an ugly fatal warning to be emitted when
# spawning a new thread
package GLUquadricObjPtr;
package Wx::Printout;
1;

View File

@ -7,9 +7,7 @@ use File::Basename qw(basename);
use FindBin;
use List::Util qw(first);
use Slic3r::GUI::2DBed;
use Slic3r::GUI::AboutDialog;
use Slic3r::GUI::BedShapeDialog;
use Slic3r::GUI::ConfigWizard;
use Slic3r::GUI::Controller;
use Slic3r::GUI::Controller::ManualControlDialog;
use Slic3r::GUI::Controller::PrinterPanel;
@ -70,6 +68,8 @@ our $grey = Wx::Colour->new(200,200,200);
our $LANGUAGE_CHANGE_EVENT = Wx::NewEventType;
# 2) To inform about a change of Preferences.
our $PREFERENCES_EVENT = Wx::NewEventType;
# To inform AppConfig about Slic3r version available online
our $VERSION_ONLINE_EVENT = Wx::NewEventType;
sub OnInit {
my ($self) = @_;
@ -87,6 +87,7 @@ sub OnInit {
$self->{app_config} = Slic3r::GUI::AppConfig->new;
$self->{preset_bundle} = Slic3r::GUI::PresetBundle->new;
Slic3r::GUI::set_app_config($self->{app_config});
# just checking for existence of Slic3r::data_dir is not enough: it may be an empty directory
# supplied as argument to --datadir; in that case we should still run the wizard
@ -95,13 +96,20 @@ sub OnInit {
warn $@ . "\n";
fatal_error(undef, $@);
}
my $run_wizard = ! $self->{app_config}->exists;
my $app_conf_exists = $self->{app_config}->exists;
# load settings
$self->{app_config}->load if ! $run_wizard;
$self->{app_config}->load if $app_conf_exists;
$self->{app_config}->set('version', $Slic3r::VERSION);
$self->{app_config}->save;
Slic3r::GUI::set_app_config($self->{app_config});
$self->{preset_updater} = Slic3r::PresetUpdater->new($VERSION_ONLINE_EVENT);
Slic3r::GUI::set_preset_updater($self->{preset_updater});
eval { $self->{preset_updater}->config_update(); };
if ($@) {
warn $@ . "\n";
fatal_error(undef, $@);
}
Slic3r::GUI::load_language();
# Suppress the '- default -' presets.
@ -111,11 +119,11 @@ sub OnInit {
warn $@ . "\n";
show_error(undef, $@);
}
$run_wizard = 1 if $self->{preset_bundle}->has_defauls_only;
Slic3r::GUI::set_preset_bundle($self->{preset_bundle});
# application frame
print STDERR "Creating main frame...\n";
Wx::Image::FindHandlerType(wxBITMAP_TYPE_PNG) || Wx::Image::AddHandler(Wx::PNGHandler->new);
$self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new(
# If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
@ -126,7 +134,6 @@ sub OnInit {
);
$self->SetTopWindow($frame);
#EVT_IDLE($frame, sub {
EVT_IDLE($self->{mainframe}, sub {
while (my $cb = shift @cb) {
$cb->();
@ -134,17 +141,17 @@ sub OnInit {
$self->{app_config}->save if $self->{app_config}->dirty;
});
if ($run_wizard) {
# On OSX the UI was not initialized correctly if the wizard was called
# before the UI was up and running.
$self->CallAfter(sub {
# Run the config wizard, don't offer the "reset user profile" checkbox.
$self->{mainframe}->config_wizard(1);
});
}
# On OSX the UI was not initialized correctly if the wizard was called
# before the UI was up and running.
$self->CallAfter(sub {
Slic3r::GUI::config_wizard_startup($app_conf_exists);
$self->{preset_updater}->slic3r_update_notify();
$self->{preset_updater}->sync($self->{preset_bundle});
});
# The following event is emited by the C++ menu implementation of application language change.
EVT_COMMAND($self, -1, $LANGUAGE_CHANGE_EVENT, sub{
print STDERR "LANGUAGE_CHANGE_EVENT\n";
$self->recreate_GUI;
});
@ -153,10 +160,19 @@ sub OnInit {
$self->update_ui_from_settings;
});
# The following event is emited by PresetUpdater (C++)
EVT_COMMAND($self, -1, $VERSION_ONLINE_EVENT, sub {
my ($self, $event) = @_;
my $version = $event->GetString;
$self->{app_config}->set('version_online', $version);
$self->{app_config}->save;
});
return 1;
}
sub recreate_GUI{
print STDERR "recreate_GUI\n";
my ($self) = @_;
my $topwindow = $self->GetTopWindow();
$self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new(
@ -180,22 +196,12 @@ sub recreate_GUI{
$self->{app_config}->save if $self->{app_config}->dirty;
});
my $run_wizard = 1 if $self->{preset_bundle}->has_defauls_only;
if ($run_wizard) {
# On OSX the UI was not initialized correctly if the wizard was called
# before the UI was up and running.
$self->CallAfter(sub {
# Run the config wizard, don't offer the "reset user profile" checkbox.
$self->{mainframe}->config_wizard(1);
});
}
}
sub about {
my ($self) = @_;
my $about = Slic3r::GUI::AboutDialog->new(undef);
$about->ShowModal;
$about->Destroy;
# On OSX the UI was not initialized correctly if the wizard was called
# before the UI was up and running.
$self->CallAfter(sub {
# Run the config wizard, don't offer the "reset user profile" checkbox.
Slic3r::GUI::config_wizard_startup(1);
});
}
sub system_info {

View File

@ -1,122 +0,0 @@
package Slic3r::GUI::AboutDialog;
use strict;
use warnings;
use utf8;
use Wx qw(:font :html :misc :dialog :sizer :systemsettings :frame :id);
use Wx::Event qw(EVT_HTML_LINK_CLICKED EVT_LEFT_DOWN EVT_BUTTON);
use Wx::Print;
use Wx::Html;
use base 'Wx::Dialog';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, -1, 'About Slic3r', wxDefaultPosition, [600, 340], wxCAPTION);
$self->SetBackgroundColour(Wx::wxWHITE);
my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
$self->SetSizer($hsizer);
# logo
my $logo = Slic3r::GUI::AboutDialog::Logo->new($self, -1, wxDefaultPosition, wxDefaultSize);
$logo->SetBackgroundColour(Wx::wxWHITE);
$hsizer->Add($logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 30);
my $vsizer = Wx::BoxSizer->new(wxVERTICAL);
$hsizer->Add($vsizer, 1, wxEXPAND, 0);
# title
my $title = Wx::StaticText->new($self, -1, $Slic3r::FORK_NAME, wxDefaultPosition, wxDefaultSize);
my $title_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
$title_font->SetWeight(wxFONTWEIGHT_BOLD);
$title_font->SetFamily(wxFONTFAMILY_ROMAN);
$title_font->SetPointSize(24);
$title->SetFont($title_font);
$vsizer->Add($title, 0, wxALIGN_LEFT | wxTOP, 30);
# version
my $version = Wx::StaticText->new($self, -1, "Version $Slic3r::VERSION", wxDefaultPosition, wxDefaultSize);
my $version_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
$version_font->SetPointSize(&Wx::wxMSW ? 9 : 11);
$version->SetFont($version_font);
$vsizer->Add($version, 0, wxALIGN_LEFT | wxBOTTOM, 10);
# text
my $text =
'<html>' .
'<body bgcolor="#ffffff" link="#808080">' .
'<font color="#808080">' .
'Copyright &copy; 2016 Vojtech Bubnik, Prusa Research. <br />' .
'Copyright &copy; 2011-2016 Alessandro Ranellucci. <br />' .
'<a href="http://slic3r.org/">Slic3r</a> is licensed under the ' .
'<a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License, version 3</a>.' .
'<br /><br /><br />' .
'Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Y. Sapir, Mike Sheldrake and numerous others. ' .
'Manual by Gary Hodgson. Inspired by the RepRap community. <br />' .
'Slic3r logo designed by Corey Daniels, <a href="http://www.famfamfam.com/lab/icons/silk/">Silk Icon Set</a> designed by Mark James. ' .
'</font>' .
'</body>' .
'</html>';
my $html = Wx::HtmlWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER);
my $font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
my $size = &Wx::wxMSW ? 8 : 10;
$html->SetFonts($font->GetFaceName, $font->GetFaceName, [$size, $size, $size, $size, $size, $size, $size]);
$html->SetBorders(2);
$html->SetPage($text);
$vsizer->Add($html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 20);
EVT_HTML_LINK_CLICKED($self, $html, \&link_clicked);
my $buttons = $self->CreateStdDialogButtonSizer(wxOK);
$self->SetEscapeId(wxID_CLOSE);
EVT_BUTTON($self, wxID_CLOSE, sub {
$self->EndModal(wxID_CLOSE);
$self->Close;
});
$vsizer->Add($buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
EVT_LEFT_DOWN($self, sub { $self->Close });
EVT_LEFT_DOWN($logo, sub { $self->Close });
return $self;
}
sub link_clicked {
my ($self, $event) = @_;
Wx::LaunchDefaultBrowser($event->GetLinkInfo->GetHref);
$event->Skip(0);
}
package Slic3r::GUI::AboutDialog::Logo;
use Wx qw(:bitmap :dc);
use Wx::Event qw(EVT_PAINT);
use base 'Wx::Panel';
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->{logo} = Wx::Bitmap->new(Slic3r::var("Slic3r_192px.png"), wxBITMAP_TYPE_PNG);
$self->SetMinSize(Wx::Size->new($self->{logo}->GetWidth, $self->{logo}->GetHeight));
EVT_PAINT($self, \&repaint);
return $self;
}
sub repaint {
my ($self, $event) = @_;
my $dc = Wx::PaintDC->new($self);
$dc->SetBackgroundMode(wxTRANSPARENT);
my $size = $self->GetSize;
my $logo_w = $self->{logo}->GetWidth;
my $logo_h = $self->{logo}->GetHeight;
$dc->DrawBitmap($self->{logo}, ($size->GetWidth - $logo_w) / 2, ($size->GetHeight - $logo_h) / 2, 1);
$event->Skip;
}
1;

View File

@ -1,458 +0,0 @@
# The config wizard is executed when the Slic3r is first started.
# The wizard helps the user to specify the 3D printer properties.
package Slic3r::GUI::ConfigWizard;
use strict;
use warnings;
use utf8;
use Wx;
use base 'Wx::Wizard';
# adhere to various human interface guidelines
our $wizard = 'Wizard';
$wizard = 'Assistant' if &Wx::wxMAC || &Wx::wxGTK;
sub new {
my ($class, $parent, $presets, $fresh_start) = @_;
my $self = $class->SUPER::new($parent, -1, "Configuration $wizard");
# initialize an empty repository
$self->{config} = Slic3r::Config->new;
my $welcome_page = Slic3r::GUI::ConfigWizard::Page::Welcome->new($self, $fresh_start);
$self->add_page($welcome_page);
$self->add_page(Slic3r::GUI::ConfigWizard::Page::Firmware->new($self));
$self->add_page(Slic3r::GUI::ConfigWizard::Page::Bed->new($self));
$self->add_page(Slic3r::GUI::ConfigWizard::Page::Nozzle->new($self));
$self->add_page(Slic3r::GUI::ConfigWizard::Page::Filament->new($self));
$self->add_page(Slic3r::GUI::ConfigWizard::Page::Temperature->new($self));
$self->add_page(Slic3r::GUI::ConfigWizard::Page::BedTemperature->new($self));
$self->add_page(Slic3r::GUI::ConfigWizard::Page::Finished->new($self));
$_->build_index for @{$self->{pages}};
$welcome_page->set_selection_presets([@{$presets}, 'Other']);
return $self;
}
sub add_page {
my ($self, $page) = @_;
my $n = push @{$self->{pages}}, $page;
# add first page to the page area sizer
$self->GetPageAreaSizer->Add($page) if $n == 1;
# link pages
$self->{pages}[$n-2]->set_next_page($page) if $n >= 2;
$page->set_previous_page($self->{pages}[$n-2]) if $n >= 2;
}
sub run {
my ($self) = @_;
my $result;
if (Wx::Wizard::RunWizard($self, $self->{pages}[0])) {
my $preset_name = $self->{pages}[0]->{preset_name};
$result = {
preset_name => $preset_name,
reset_user_profile => $self->{pages}[0]->{reset_user_profile}
};
if ($preset_name eq 'Other') {
# it would be cleaner to have these defined inside each page class,
# in some event getting called before leaving the page
# set first_layer_height + layer_height based on nozzle_diameter
my $nozzle = $self->{config}->nozzle_diameter;
$self->{config}->set('first_layer_height', $nozzle->[0]);
$self->{config}->set('layer_height', $nozzle->[0] - 0.1);
# set first_layer_temperature to temperature + 5
$self->{config}->set('first_layer_temperature', [$self->{config}->temperature->[0] + 5]);
# set first_layer_bed_temperature to temperature + 5
$self->{config}->set('first_layer_bed_temperature',
[ ($self->{config}->bed_temperature->[0] > 0) ? ($self->{config}->bed_temperature->[0] + 5) : 0 ]);
$result->{config} = $self->{config};
}
}
$self->Destroy;
return $result;
}
package Slic3r::GUI::ConfigWizard::Index;
use Wx qw(:bitmap :dc :font :misc :sizer :systemsettings :window);
use Wx::Event qw(EVT_ERASE_BACKGROUND EVT_PAINT);
use base 'Wx::Panel';
sub new {
my $class = shift;
my ($parent, $title) = @_;
my $self = $class->SUPER::new($parent);
push @{$self->{titles}}, $title;
$self->{own_index} = 0;
$self->{bullets}->{before} = Wx::Bitmap->new(Slic3r::var("bullet_black.png"), wxBITMAP_TYPE_PNG);
$self->{bullets}->{own} = Wx::Bitmap->new(Slic3r::var("bullet_blue.png"), wxBITMAP_TYPE_PNG);
$self->{bullets}->{after} = Wx::Bitmap->new(Slic3r::var("bullet_white.png"), wxBITMAP_TYPE_PNG);
$self->{background} = Wx::Bitmap->new(Slic3r::var("Slic3r_192px_transparent.png"), wxBITMAP_TYPE_PNG);
$self->SetMinSize(Wx::Size->new($self->{background}->GetWidth, $self->{background}->GetHeight));
EVT_PAINT($self, \&repaint);
return $self;
}
sub repaint {
my ($self, $event) = @_;
my $size = $self->GetClientSize;
my $gap = 5;
my $dc = Wx::PaintDC->new($self);
$dc->SetBackgroundMode(wxTRANSPARENT);
$dc->SetFont($self->GetFont);
$dc->SetTextForeground($self->GetForegroundColour);
my $background_h = $self->{background}->GetHeight;
my $background_w = $self->{background}->GetWidth;
$dc->DrawBitmap($self->{background}, ($size->GetWidth - $background_w) / 2, ($size->GetHeight - $background_h) / 2, 1);
my $label_h = $self->{bullets}->{own}->GetHeight;
$label_h = $dc->GetCharHeight if $dc->GetCharHeight > $label_h;
my $label_w = $size->GetWidth;
my $i = 0;
foreach (@{$self->{titles}}) {
my $bullet = $self->{bullets}->{own};
$bullet = $self->{bullets}->{before} if $i < $self->{own_index};
$bullet = $self->{bullets}->{after} if $i > $self->{own_index};
$dc->SetTextForeground(Wx::Colour->new(128, 128, 128)) if $i > $self->{own_index};
$dc->DrawLabel($_, $bullet, Wx::Rect->new(0, $i * ($label_h + $gap), $label_w, $label_h));
# Only show the first bullet if this is the only wizard page to be displayed.
last if $i == 0 && $self->{just_welcome};
$i++;
}
$event->Skip;
}
sub prepend_title {
my $self = shift;
my ($title) = @_;
unshift @{$self->{titles}}, $title;
$self->{own_index}++;
$self->Refresh;
}
sub append_title {
my $self = shift;
my ($title) = @_;
push @{$self->{titles}}, $title;
$self->Refresh;
}
package Slic3r::GUI::ConfigWizard::Page;
use Wx qw(:font :misc :sizer :staticline :systemsettings);
use base 'Wx::WizardPage';
sub new {
my $class = shift;
my ($parent, $title, $short_title) = @_;
my $self = $class->SUPER::new($parent);
my $sizer = Wx::FlexGridSizer->new(0, 2, 10, 10);
$sizer->AddGrowableCol(1, 1);
$sizer->AddGrowableRow(1, 1);
$sizer->AddStretchSpacer(0);
$self->SetSizer($sizer);
# title
my $text = Wx::StaticText->new($self, -1, $title, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
my $bold_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
$bold_font->SetWeight(wxFONTWEIGHT_BOLD);
$bold_font->SetPointSize(14);
$text->SetFont($bold_font);
$sizer->Add($text, 0, wxALIGN_LEFT, 0);
# index
$self->{short_title} = $short_title ? $short_title : $title;
$self->{index} = Slic3r::GUI::ConfigWizard::Index->new($self, $self->{short_title});
$sizer->Add($self->{index}, 1, wxEXPAND | wxTOP | wxRIGHT, 10);
# contents
$self->{width} = 430;
$self->{vsizer} = Wx::BoxSizer->new(wxVERTICAL);
$sizer->Add($self->{vsizer}, 1);
return $self;
}
sub append_text {
my $self = shift;
my ($text) = @_;
my $para = Wx::StaticText->new($self, -1, $text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
$para->Wrap($self->{width});
$para->SetMinSize([$self->{width}, -1]);
$self->{vsizer}->Add($para, 0, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10);
}
sub append_option {
my $self = shift;
my ($full_key) = @_;
# populate repository with the factory default
my ($opt_key, $opt_index) = split /#/, $full_key, 2;
$self->config->apply(Slic3r::Config::new_from_defaults_keys([$opt_key]));
# draw the control
my $optgroup = Slic3r::GUI::ConfigOptionsGroup->new(
parent => $self,
title => '',
config => $self->config,
full_labels => 1,
);
$optgroup->append_single_option_line($opt_key, $opt_index);
$self->{vsizer}->Add($optgroup->sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
}
sub append_panel {
my ($self, $panel) = @_;
$self->{vsizer}->Add($panel, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
}
sub set_previous_page {
my $self = shift;
my ($previous_page) = @_;
$self->{previous_page} = $previous_page;
}
sub GetPrev {
my $self = shift;
return $self->{previous_page};
}
sub set_next_page {
my $self = shift;
my ($next_page) = @_;
$self->{next_page} = $next_page;
}
sub GetNext {
my $self = shift;
return $self->{next_page};
}
sub get_short_title {
my $self = shift;
return $self->{short_title};
}
sub build_index {
my $self = shift;
my $page = $self;
$self->{index}->prepend_title($page->get_short_title) while ($page = $page->GetPrev);
$page = $self;
$self->{index}->append_title($page->get_short_title) while ($page = $page->GetNext);
}
sub config {
my ($self) = @_;
return $self->GetParent->{config};
}
package Slic3r::GUI::ConfigWizard::Page::Welcome;
use base 'Slic3r::GUI::ConfigWizard::Page';
use Wx qw(:misc :sizer wxID_FORWARD);
use Wx::Event qw(EVT_ACTIVATE EVT_CHOICE EVT_CHECKBOX);
sub new {
my ($class, $parent, $fresh_start) = @_;
my $self = $class->SUPER::new($parent, "Welcome to the Slic3r Configuration $wizard", 'Welcome');
$self->{full_wizard_workflow} = 1;
$self->{reset_user_profile} = 0;
# Test for the existence of the old config path.
my $message_has_legacy;
{
my $datadir = Slic3r::data_dir;
if ($datadir =~ /Slic3rPE/) {
# Check for existence of the legacy Slic3r directory.
my $datadir_legacy = substr $datadir, 0, -2;
my $dir_enc = Slic3r::encode_path($datadir_legacy);
if (-e $dir_enc && -d $dir_enc &&
-e ($dir_enc . '/print') && -d ($dir_enc . '/print') &&
-e ($dir_enc . '/filament') && -d ($dir_enc . '/filament') &&
-e ($dir_enc . '/printer') && -d ($dir_enc . '/printer') &&
-e ($dir_enc . '/slic3r.ini')) {
$message_has_legacy = "Starting with Slic3r 1.38.4, the user profile directory has been renamed to $datadir. You may consider closing Slic3r and renaming $datadir_legacy to $datadir.";
}
}
}
$self->append_text('Hello, welcome to Slic3r Prusa Edition! This '.lc($wizard).' helps you with the initial configuration; just a few settings and you will be ready to print.');
$self->append_text('Please select your printer vendor and printer type. If your printer is not listed, you may try your luck and select a similar one. If you select "Other", this ' . lc($wizard) . ' will let you set the basic 3D printer parameters.');
$self->append_text($message_has_legacy) if defined $message_has_legacy;
# To import an existing configuration instead, cancel this '.lc($wizard).' and use the Open Config menu item found in the File menu.');
$self->append_text('If you received a configuration file or a config bundle from your 3D printer vendor, cancel this '.lc($wizard).' and use the "File->Load Config" or "File->Load Config Bundle" menu.');
$self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, []);
$self->{vsizer}->Add($choice, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
if (! $fresh_start) {
$self->{reset_checkbox} = Wx::CheckBox->new($self, -1, "Reset user profile, install from scratch");
$self->{vsizer}->Add($self->{reset_checkbox}, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
}
EVT_CHOICE($parent, $choice, sub {
my $sel = $self->{choice}->GetStringSelection;
$self->{preset_name} = $sel;
$self->set_full_wizard_workflow(($sel eq 'Other') || ($sel eq ''));
});
if (! $fresh_start) {
EVT_CHECKBOX($self, $self->{reset_checkbox}, sub {
$self->{reset_user_profile} = $self->{reset_checkbox}->GetValue();
});
}
EVT_ACTIVATE($parent, sub {
$self->set_full_wizard_workflow($self->{preset_name} eq 'Other');
});
return $self;
}
sub set_full_wizard_workflow {
my ($self, $full_workflow) = @_;
$self->{full_wizard_workflow} = $full_workflow;
$self->{index}->{just_welcome} = !$full_workflow;
$self->{index}->Refresh;
my $next_button = $self->GetParent->FindWindow(wxID_FORWARD);
$next_button->SetLabel($full_workflow ? "&Next >" : "&Finish");
}
# Set the preset names, select the first item.
sub set_selection_presets {
my ($self, $names) = @_;
$self->{choice}->Append($names);
$self->{choice}->SetSelection(0);
$self->{preset_name} = $names->[0];
}
sub GetNext {
my $self = shift;
return $self->{full_wizard_workflow} ? $self->{next_page} : undef;
}
package Slic3r::GUI::ConfigWizard::Page::Firmware;
use base 'Slic3r::GUI::ConfigWizard::Page';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Firmware Type');
$self->append_text('Choose the type of firmware used by your printer, then click Next.');
$self->append_option('gcode_flavor');
return $self;
}
package Slic3r::GUI::ConfigWizard::Page::Bed;
use base 'Slic3r::GUI::ConfigWizard::Page';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Bed Size');
$self->append_text('Set the shape of your printer\'s bed, then click Next.');
$self->config->apply(Slic3r::Config::new_from_defaults_keys(['bed_shape']));
$self->{bed_shape_panel} = my $panel = Slic3r::GUI::BedShapePanel->new($self, $self->config->bed_shape);
$self->{bed_shape_panel}->on_change(sub {
$self->config->set('bed_shape', $self->{bed_shape_panel}->GetValue);
});
$self->append_panel($self->{bed_shape_panel});
return $self;
}
package Slic3r::GUI::ConfigWizard::Page::Nozzle;
use base 'Slic3r::GUI::ConfigWizard::Page';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Nozzle Diameter');
$self->append_text('Enter the diameter of your printer\'s hot end nozzle, then click Next.');
$self->append_option('nozzle_diameter#0');
return $self;
}
package Slic3r::GUI::ConfigWizard::Page::Filament;
use base 'Slic3r::GUI::ConfigWizard::Page';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Filament Diameter');
$self->append_text('Enter the diameter of your filament, then click Next.');
$self->append_text('Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.');
$self->append_option('filament_diameter#0');
return $self;
}
package Slic3r::GUI::ConfigWizard::Page::Temperature;
use base 'Slic3r::GUI::ConfigWizard::Page';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Extrusion Temperature');
$self->append_text('Enter the temperature needed for extruding your filament, then click Next.');
$self->append_text('A rule of thumb is 160 to 230 °C for PLA, and 215 to 250 °C for ABS.');
$self->append_option('temperature#0');
return $self;
}
package Slic3r::GUI::ConfigWizard::Page::BedTemperature;
use base 'Slic3r::GUI::ConfigWizard::Page';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Bed Temperature');
$self->append_text('Enter the bed temperature needed for getting your filament to stick to your heated bed, then click Next.');
$self->append_text('A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed.');
$self->append_option('bed_temperature#0');
return $self;
}
package Slic3r::GUI::ConfigWizard::Page::Finished;
use base 'Slic3r::GUI::ConfigWizard::Page';
sub new {
my $class = shift;
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Congratulations!', 'Finish');
$self->append_text("You have successfully completed the Slic3r Configuration $wizard. " .
'Slic3r is now configured for your printer and filament.');
$self->append_text('To close this '.lc($wizard).' and apply the newly created configuration, click Finish.');
return $self;
}
1;

View File

@ -7,7 +7,7 @@ use strict;
use warnings;
use utf8;
use Wx qw(wxTheApp :frame :id :misc :sizer :bitmap :button :icon :dialog);
use Wx qw(wxTheApp :frame :id :misc :sizer :bitmap :button :icon :dialog wxBORDER_NONE);
use Wx::Event qw(EVT_CLOSE EVT_LEFT_DOWN EVT_MENU);
use base qw(Wx::ScrolledWindow Class::Accessor);
use List::Util qw(first);
@ -34,7 +34,7 @@ sub new {
# button for adding new printer panels
{
my $btn = $self->{btn_add} = Wx::BitmapButton->new($self, -1, Wx::Bitmap->new(Slic3r::var("add.png"), wxBITMAP_TYPE_PNG),
wxDefaultPosition, wxDefaultSize, Wx::wxBORDER_NONE);
wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
$btn->SetToolTipString("Add printer…")
if $btn->can('SetToolTipString');

View File

@ -81,7 +81,7 @@ sub new {
# declare events
EVT_CLOSE($self, sub {
my (undef, $event) = @_;
if ($event->CanVeto && !$self->check_unsaved_changes) {
if ($event->CanVeto && !Slic3r::GUI::check_unsaved_changes) {
$event->Veto;
return;
}
@ -95,7 +95,7 @@ sub new {
});
$self->update_ui_from_settings;
return $self;
}
@ -237,12 +237,6 @@ sub _init_menubar {
$self->repair_stl;
}, undef, 'wrench.png');
$fileMenu->AppendSeparator();
# Cmd+, is standard on OS X - what about other operating systems?
$self->_append_menu_item($fileMenu, L("Preferences…\tCtrl+,"), L('Application preferences'), sub {
# Opening the C++ preferences dialog.
Slic3r::GUI::open_preferences_dialog($self->{preferences_event});
}, wxID_PREFERENCES);
$fileMenu->AppendSeparator();
$self->_append_menu_item($fileMenu, L("&Quit"), L('Quit Slic3r'), sub {
$self->Close(0);
}, wxID_EXIT);
@ -319,11 +313,6 @@ sub _init_menubar {
# Help menu
my $helpMenu = Wx::Menu->new;
{
$self->_append_menu_item($helpMenu, L("&Configuration ").$Slic3r::GUI::ConfigWizard::wizard."…", L("Run Configuration ").$Slic3r::GUI::ConfigWizard::wizard, sub {
# Run the config wizard, offer the "reset user profile" checkbox.
$self->config_wizard(0);
});
$helpMenu->AppendSeparator();
$self->_append_menu_item($helpMenu, L("Prusa 3D Drivers"), L('Open the Prusa3D drivers download page in your browser'), sub {
Wx::LaunchDefaultBrowser('http://www.prusa3d.com/drivers/');
});
@ -348,7 +337,7 @@ sub _init_menubar {
Wx::LaunchDefaultBrowser('http://github.com/prusa3d/slic3r/issues/new');
});
$self->_append_menu_item($helpMenu, L("&About Slic3r"), L('Show about dialog'), sub {
wxTheApp->about;
Slic3r::GUI::about;
});
}
@ -362,11 +351,9 @@ sub _init_menubar {
$menubar->Append($self->{object_menu}, L("&Object")) if $self->{object_menu};
$menubar->Append($windowMenu, L("&Window"));
$menubar->Append($self->{viewMenu}, L("&View")) if $self->{viewMenu};
# Add an optional debug menu
# (Select application language from the list of installed languages)
Slic3r::GUI::add_debug_menu($menubar, $self->{lang_ch_event});
# Add a configuration menu.
Slic3r::GUI::add_config_menu($menubar, $self->{preferences_event}, $self->{lang_ch_event});
$menubar->Append($helpMenu, L("&Help"));
# Add an optional debug menu. In production code, the add_debug_menu() call should do nothing.
$self->SetMenuBar($menubar);
}
}
@ -562,7 +549,7 @@ sub export_config {
sub load_config_file {
my ($self, $file) = @_;
if (!$file) {
return unless $self->check_unsaved_changes;
return unless Slic3r::GUI::check_unsaved_changes;
my $dlg = Wx::FileDialog->new($self, L('Select configuration to load:'),
$last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
"config.ini",
@ -581,7 +568,7 @@ sub load_config_file {
sub export_configbundle {
my ($self) = @_;
return unless $self->check_unsaved_changes;
return unless Slic3r::GUI::check_unsaved_changes;
# validate current configuration in case it's dirty
eval { wxTheApp->{preset_bundle}->full_config->validate; };
Slic3r::GUI::catch_error($self) and return;
@ -605,7 +592,7 @@ sub export_configbundle {
# but that behavior was not documented and likely buggy.
sub load_configbundle {
my ($self, $file, $reset_user_profile) = @_;
return unless $self->check_unsaved_changes;
return unless Slic3r::GUI::check_unsaved_changes;
if (!$file) {
my $dlg = Wx::FileDialog->new($self, L('Select configuration to load:'),
$last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
@ -639,70 +626,6 @@ sub load_config {
$self->{plater}->on_config_change($config) if $self->{plater};
}
sub config_wizard {
my ($self, $fresh_start) = @_;
# Exit wizard if there are unsaved changes and the user cancels the action.
return unless $self->check_unsaved_changes;
# Enumerate the profiles bundled with the Slic3r installation under resources/profiles.
my $directory = Slic3r::resources_dir() . "/profiles";
my @profiles = ();
if (opendir(DIR, Slic3r::encode_path($directory))) {
while (my $file = readdir(DIR)) {
if ($file =~ /\.ini$/) {
$file =~ s/\.ini$//;
push @profiles, Slic3r::decode_path($file);
}
}
closedir(DIR);
}
# Open the wizard.
if (my $result = Slic3r::GUI::ConfigWizard->new($self, \@profiles, $fresh_start)->run) {
eval {
if ($result->{reset_user_profile}) {
wxTheApp->{preset_bundle}->reset(1);
}
if (defined $result->{config}) {
# Load and save the settings into print, filament and printer presets.
wxTheApp->{preset_bundle}->load_config('My Settings', $result->{config});
} else {
# Wizard returned a name of a preset bundle bundled with the installation. Unpack it.
wxTheApp->{preset_bundle}->install_vendor_configbundle($directory . '/' . $result->{preset_name} . '.ini');
# Reset the print / filament / printer selections, so that following line will select some sensible defaults.
if ($fresh_start) {
wxTheApp->{app_config}->reset_selections;
}
# Reload all presets after the vendor config bundle has been installed.
wxTheApp->{preset_bundle}->load_presets(wxTheApp->{app_config});
}
};
Slic3r::GUI::catch_error($self) and return;
# Load the currently selected preset into the GUI, update the preset selection box.
foreach my $tab (values %{$self->{options_tabs}}) {
$tab->load_current_preset;
}
}
}
# This is called when closing the application, when loading a config file or when starting the config wizard
# to notify the user whether he is aware that some preset changes will be lost.
sub check_unsaved_changes {
my $self = shift;
my @dirty = ();
foreach my $tab (values %{$self->{options_tabs}}) {
push @dirty, $tab->title if $tab->current_preset_is_dirty;
}
if (@dirty) {
my $titles = join ', ', @dirty;
my $confirm = Wx::MessageDialog->new($self, L("You have unsaved changes ").($titles).L(". Discard changes and continue anyway?"),
L('Unsaved Presets'), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT);
return $confirm->ShowModal == wxID_YES;
}
return 1;
}
sub select_tab {
my ($self, $tab) = @_;
$self->{tabpanel}->SetSelection($tab);

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -0,0 +1,985 @@
# Print profiles for the BarBaz Research printers.
[vendor]
# Vendor name will be shown by the Config Wizard.
name = Bar Baz
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the Slic3r configuration to be downgraded.
config_version = 0.1.0
# Where to get the updates from?
config_update_url = https://example.com
# The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install.
#TODO: One day we may differentiate variants of the nozzles / hot ends,
#for example by the melt zone size, or whether the nozzle is hardened.
[printer_model:M1]
name = Bar Baz Model 1
variants = 0.4; 0.25; 0.6
[printer_model:M2]
name = Bar Baz Model 2
variants = 0.4; 0.25; 0.6
[printer_model:M3]
# Printer model name will be shown by the installation wizard.
name = Bar Baz Model 3
variants = 0.4; 0.6
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
# Common print preset, mostly derived from MK2 single material with a 0.4mm nozzle.
# All other print presets will derive from the *common* print preset.
[print:*common*]
avoid_crossing_perimeters = 0
bridge_acceleration = 1000
bridge_angle = 0
bridge_flow_ratio = 0.8
bridge_speed = 20
brim_width = 0
clip_multipart_objects = 1
compatible_printers =
complete_objects = 0
default_acceleration = 1000
dont_support_bridges = 1
elefant_foot_compensation = 0
ensure_vertical_shell_thickness = 1
external_fill_pattern = rectilinear
external_perimeters_first = 0
external_perimeter_extrusion_width = 0.45
extra_perimeters = 0
extruder_clearance_height = 20
extruder_clearance_radius = 20
extrusion_width = 0.45
fill_angle = 45
fill_density = 20%
fill_pattern = cubic
first_layer_acceleration = 1000
first_layer_extrusion_width = 0.42
first_layer_height = 0.2
first_layer_speed = 30
gap_fill_speed = 40
gcode_comments = 0
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0.45
infill_first = 0
infill_only_where_needed = 0
infill_overlap = 25%
interface_shells = 0
max_print_speed = 100
max_volumetric_extrusion_rate_slope_negative = 0
max_volumetric_extrusion_rate_slope_positive = 0
max_volumetric_speed = 0
min_skirt_length = 4
notes =
overhangs = 0
only_retract_when_crossing_perimeters = 0
ooze_prevention = 0
output_filename_format = [input_filename_base].gcode
perimeters = 2
perimeter_extruder = 1
perimeter_extrusion_width = 0.45
post_process =
print_settings_id =
raft_layers = 0
resolution = 0
seam_position = nearest
skirts = 1
skirt_distance = 2
skirt_height = 3
small_perimeter_speed = 20
solid_infill_below_area = 0
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_extrusion_width = 0.45
spiral_vase = 0
standby_temperature_delta = -5
support_material = 0
support_material_extruder = 0
support_material_extrusion_width = 0.35
support_material_interface_extruder = 0
support_material_angle = 0
support_material_buildplate_only = 0
support_material_enforce_layers = 0
support_material_contact_distance = 0.15
support_material_interface_contact_loops = 0
support_material_interface_layers = 2
support_material_interface_spacing = 0.2
support_material_interface_speed = 100%
support_material_pattern = rectilinear
support_material_spacing = 2
support_material_speed = 50
support_material_synchronize_layers = 0
support_material_threshold = 45
support_material_with_sheath = 0
support_material_xy_spacing = 60%
thin_walls = 0
top_infill_extrusion_width = 0.45
top_solid_infill_speed = 40
travel_speed = 180
wipe_tower = 0
wipe_tower_per_color_wipe = 20
wipe_tower_width = 60
wipe_tower_x = 180
wipe_tower_y = 140
xy_size_compensation = 0
# Print parameters common to a 0.25mm diameter nozzle.
[print:*0.25nozzle*]
external_perimeter_extrusion_width = 0.25
extrusion_width = 0.25
first_layer_extrusion_width = 0.25
infill_extrusion_width = 0.25
perimeter_extrusion_width = 0.25
solid_infill_extrusion_width = 0.25
top_infill_extrusion_width = 0.25
support_material_extrusion_width = 0.18
support_material_interface_layers = 0
support_material_interface_spacing = 0.15
support_material_spacing = 1
support_material_xy_spacing = 150%
# Print parameters common to a 0.6mm diameter nozzle.
[print:*0.6nozzle*]
external_perimeter_extrusion_width = 0.61
extrusion_width = 0.67
first_layer_extrusion_width = 0.65
infill_extrusion_width = 0.7
perimeter_extrusion_width = 0.65
solid_infill_extrusion_width = 0.65
top_infill_extrusion_width = 0.6
[print:*soluble_support*]
overhangs = 1
skirts = 0
support_material = 1
support_material_contact_distance = 0
support_material_extruder = 4
support_material_extrusion_width = 0.45
support_material_interface_extruder = 4
support_material_interface_spacing = 0.1
support_material_synchronize_layers = 1
support_material_threshold = 80
support_material_with_sheath = 1
wipe_tower = 1
[print:*0.05mm*]
inherits = *common*
bottom_solid_layers = 10
bridge_acceleration = 300
bridge_flow_ratio = 0.7
default_acceleration = 500
external_perimeter_speed = 20
fill_density = 20%
first_layer_acceleration = 500
gap_fill_speed = 20
infill_acceleration = 800
infill_speed = 30
max_print_speed = 80
small_perimeter_speed = 15
solid_infill_speed = 30
support_material_extrusion_width = 0.3
support_material_spacing = 1.5
layer_height = 0.05
perimeter_acceleration = 300
perimeter_speed = 30
perimeters = 3
support_material_speed = 30
top_solid_infill_speed = 20
top_solid_layers = 15
[print:0.05mm ULTRADETAIL]
inherits = *0.05mm*
infill_extrusion_width = 0.5
[print:0.05mm ULTRADETAIL MK3]
inherits = *0.05mm*
fill_pattern = grid
top_infill_extrusion_width = 0.4
[print:0.05mm ULTRADETAIL 0.25 nozzle]
inherits = *0.05mm*
external_perimeter_extrusion_width = 0
extrusion_width = 0.28
fill_density = 20%
first_layer_extrusion_width = 0.3
infill_extrusion_width = 0
infill_speed = 20
max_print_speed = 100
perimeter_extrusion_width = 0
perimeter_speed = 20
small_perimeter_speed = 10
solid_infill_extrusion_width = 0
solid_infill_speed = 20
support_material_speed = 20
top_infill_extrusion_width = 0
[print:0.05mm ULTRADETAIL 0.25 nozzle MK3]
inherits = *0.05mm*; *0.25nozzle*
fill_pattern = grid
top_infill_extrusion_width = 0.4
[print:*0.10mm*]
inherits = *common*
bottom_solid_layers = 7
bridge_flow_ratio = 0.7
layer_height = 0.1
perimeter_acceleration = 800
top_solid_layers = 9
[print:0.10mm DETAIL]
inherits = *0.10mm*
external_perimeter_speed = 40
infill_acceleration = 2000
infill_speed = 60
perimeter_speed = 50
solid_infill_speed = 50
[print:0.10mm DETAIL MK3]
inherits = *0.10mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 200
perimeter_speed = 45
solid_infill_speed = 170
top_infill_extrusion_width = 0.4
top_solid_infill_speed = 50
[print:0.10mm DETAIL 0.25 nozzle]
inherits = *0.10mm*
bridge_acceleration = 600
external_perimeter_speed = 20
infill_acceleration = 1600
infill_speed = 40
perimeter_acceleration = 600
perimeter_speed = 25
small_perimeter_speed = 10
solid_infill_speed = 40
top_solid_infill_speed = 30
[print:0.10mm DETAIL 0.25 nozzle MK3]
inherits = *0.10mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 200
perimeter_speed = 45
solid_infill_speed = 170
top_infill_extrusion_width = 0.4
top_solid_infill_speed = 50
[print:0.10mm DETAIL 0.6 nozzle MK3]
inherits = *0.10mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 200
perimeter_speed = 45
solid_infill_speed = 170
top_infill_extrusion_width = 0.4
top_solid_infill_speed = 50
[print:*0.15mm*]
inherits = *common*
bottom_solid_layers = 5
external_perimeter_speed = 40
infill_acceleration = 2000
infill_speed = 60
layer_height = 0.15
perimeter_acceleration = 800
perimeter_speed = 50
solid_infill_speed = 50
top_infill_extrusion_width = 0.4
top_solid_layers = 7
[print:0.15mm 100mms Linear Advance]
inherits = *0.15mm*
bridge_flow_ratio = 0.95
external_perimeter_speed = 50
infill_speed = 100
max_print_speed = 150
perimeter_speed = 60
small_perimeter_speed = 30
solid_infill_speed = 100
support_material_speed = 60
top_solid_infill_speed = 70
[print:0.15mm OPTIMAL]
inherits = *0.15mm*
top_infill_extrusion_width = 0.45
[print:0.15mm OPTIMAL 0.25 nozzle]
inherits = *0.15mm*; *0.25nozzle*
bridge_acceleration = 600
bridge_flow_ratio = 0.7
external_perimeter_speed = 20
infill_acceleration = 1600
infill_speed = 40
perimeter_acceleration = 600
perimeter_speed = 25
small_perimeter_speed = 10
solid_infill_speed = 40
support_material_extrusion_width = 0.2
top_solid_infill_speed = 30
[print:0.15mm OPTIMAL 0.6 nozzle]
inherits = *0.15mm*; *0.6nozzle*
[print:0.15mm OPTIMAL MK3]
inherits = *0.15mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:0.15mm OPTIMAL SOLUBLE FULL]
inherits = *0.15mm*; *soluble_support*
external_perimeter_speed = 25
notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
perimeter_speed = 40
solid_infill_speed = 40
top_infill_extrusion_width = 0.45
top_solid_infill_speed = 30
wipe_tower = 1
[print:0.15mm OPTIMAL SOLUBLE INTERFACE]
inherits = 0.15mm OPTIMAL SOLUBLE FULL
notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
support_material_extruder = 0
support_material_interface_layers = 3
support_material_with_sheath = 0
support_material_xy_spacing = 80%
[print:0.15mm OPTIMAL 0.25 nozzle MK3]
inherits = *0.15mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:*0.20mm*]
inherits = *common*
bottom_solid_layers = 4
bridge_flow_ratio = 0.95
external_perimeter_speed = 40
infill_acceleration = 2000
infill_speed = 60
layer_height = 0.2
perimeter_acceleration = 800
perimeter_speed = 50
solid_infill_speed = 50
top_infill_extrusion_width = 0.4
top_solid_layers = 5
[print:0.15mm OPTIMAL 0.6 nozzle MK3]
inherits = *0.15mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:0.20mm 100mms Linear Advance]
inherits = *0.20mm*
external_perimeter_speed = 50
infill_speed = 100
max_print_speed = 150
perimeter_speed = 60
small_perimeter_speed = 30
solid_infill_speed = 100
support_material_speed = 60
top_solid_infill_speed = 70
[print:0.20mm FAST MK3]
inherits = *0.20mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:0.20mm NORMAL]
inherits = *0.20mm*
[print:0.20mm NORMAL 0.6 nozzle]
inherits = *0.20mm*; *0.6nozzle*
[print:0.20mm NORMAL SOLUBLE FULL]
inherits = *0.20mm*; *soluble_support*
external_perimeter_speed = 30
notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
perimeter_speed = 40
solid_infill_speed = 40
top_solid_infill_speed = 30
[print:0.20mm NORMAL SOLUBLE INTERFACE]
inherits = 0.20mm NORMAL SOLUBLE FULL
notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
support_material_extruder = 0
support_material_interface_layers = 3
support_material_with_sheath = 0
support_material_xy_spacing = 80%
[print:0.20mm FAST 0.6 nozzle MK3]
inherits = *0.20mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:*0.35mm*]
inherits = *common*
bottom_solid_layers = 3
external_perimeter_extrusion_width = 0.6
external_perimeter_speed = 40
first_layer_extrusion_width = 0.75
infill_acceleration = 2000
infill_speed = 60
layer_height = 0.35
perimeter_acceleration = 800
perimeter_extrusion_width = 0.65
perimeter_speed = 50
solid_infill_extrusion_width = 0.65
solid_infill_speed = 60
top_solid_infill_speed = 50
top_solid_layers = 4
[print:0.35mm FAST]
inherits = *0.35mm*
bridge_flow_ratio = 0.95
first_layer_extrusion_width = 0.42
perimeter_extrusion_width = 0.43
solid_infill_extrusion_width = 0.7
top_infill_extrusion_width = 0.43
[print:0.35mm FAST 0.6 nozzle]
inherits = *0.35mm*; *0.6nozzle*
[print:0.35mm FAST sol full 0.6 nozzle]
inherits = *0.35mm*; *0.6nozzle*; *soluble_support*
external_perimeter_extrusion_width = 0.6
external_perimeter_speed = 30
notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
perimeter_speed = 40
support_material_extrusion_width = 0.55
support_material_interface_layers = 3
support_material_xy_spacing = 120%
top_infill_extrusion_width = 0.57
[print:0.35mm FAST sol int 0.6 nozzle]
inherits = 0.35mm FAST sol full 0.6 nozzle
support_material_extruder = 0
support_material_interface_layers = 2
support_material_with_sheath = 0
support_material_xy_spacing = 150%
[filament:*common*]
cooling = 1
compatible_printers =
end_filament_gcode = "; Filament-specific end gcode"
extrusion_multiplier = 1
filament_cost = 0
filament_density = 0
filament_diameter = 1.75
filament_notes = ""
filament_settings_id =
filament_soluble = 0
min_print_speed = 5
slowdown_below_layer_time = 20
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
[filament:*PLA*]
inherits = *common*
bed_temperature = 60
bridge_fan_speed = 100
disable_fan_first_layers = 1
fan_always_on = 1
fan_below_layer_time = 100
filament_colour = #FF3232
filament_max_volumetric_speed = 15
filament_type = PLA
first_layer_bed_temperature = 60
first_layer_temperature = 215
max_fan_speed = 100
min_fan_speed = 100
temperature = 210
[filament:*PET*]
inherits = *common*
bed_temperature = 90
bridge_fan_speed = 50
disable_fan_first_layers = 3
fan_always_on = 1
fan_below_layer_time = 20
filament_colour = #FF8000
filament_max_volumetric_speed = 8
filament_type = PET
first_layer_bed_temperature = 85
first_layer_temperature = 230
max_fan_speed = 50
min_fan_speed = 30
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
temperature = 240
[filament:*ABS*]
inherits = *common*
bed_temperature = 110
bridge_fan_speed = 30
cooling = 0
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 20
filament_colour = #3A80CA
filament_max_volumetric_speed = 11
filament_type = ABS
first_layer_bed_temperature = 100
first_layer_temperature = 255
max_fan_speed = 30
min_fan_speed = 20
temperature = 255
[filament:*FLEX*]
inherits = *common*
bridge_fan_speed = 100
cooling = 0
disable_fan_first_layers = 1
extrusion_multiplier = 1.2
fan_always_on = 0
fan_below_layer_time = 100
filament_colour = #00CA0A
filament_max_volumetric_speed = 1.5
filament_type = FLEX
first_layer_bed_temperature = 50
first_layer_temperature = 240
max_fan_speed = 90
min_fan_speed = 70
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 240
[filament:ColorFabb Brass Bronze]
inherits = *PLA*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 10
[filament:ColorFabb HT]
inherits = *PET*
bed_temperature = 110
bridge_fan_speed = 30
cooling = 1
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 10
first_layer_bed_temperature = 105
first_layer_temperature = 270
max_fan_speed = 20
min_fan_speed = 10
min_print_speed = 5
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
temperature = 270
[filament:ColorFabb PLA-PHA]
inherits = *PLA*
[filament:ColorFabb Woodfil]
inherits = *PLA*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 10
first_layer_temperature = 200
min_print_speed = 5
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 200
[filament:ColorFabb XT]
inherits = *PET*
filament_type = PLA
first_layer_bed_temperature = 90
first_layer_temperature = 260
temperature = 270
[filament:ColorFabb XT-CF20]
inherits = *PET*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 1
first_layer_bed_temperature = 90
first_layer_temperature = 260
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
temperature = 260
[filament:ColorFabb nGen]
inherits = *PET*
bridge_fan_speed = 40
fan_always_on = 0
fan_below_layer_time = 10
filament_type = NGEN
first_layer_temperature = 240
max_fan_speed = 35
min_fan_speed = 20
[filament:ColorFabb nGen flex]
inherits = *FLEX*
bed_temperature = 85
bridge_fan_speed = 40
cooling = 1
disable_fan_first_layers = 3
extrusion_multiplier = 1
fan_below_layer_time = 10
filament_max_volumetric_speed = 5
first_layer_bed_temperature = 85
first_layer_temperature = 260
max_fan_speed = 35
min_fan_speed = 20
temperature = 260
[filament:E3D Edge]
inherits = *PET*
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:E3D PC-ABS]
inherits = *ABS*
first_layer_temperature = 270
temperature = 270
[filament:Fillamentum ABS]
inherits = *ABS*
first_layer_temperature = 240
temperature = 240
[filament:Fillamentum ASA]
inherits = *ABS*
fan_always_on = 1
first_layer_temperature = 265
temperature = 265
[filament:Fillamentum CPE HG100 HM100]
inherits = *PET*
filament_notes = "CPE HG100 , CPE HM100"
first_layer_bed_temperature = 90
first_layer_temperature = 275
max_fan_speed = 50
min_fan_speed = 50
temperature = 275
[filament:Fillamentum Timberfil]
inherits = *PLA*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 10
first_layer_temperature = 190
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 190
[filament:Generic ABS]
inherits = *ABS*
filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS"
[filament:Generic PET]
inherits = *PET*
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:Generic PLA]
inherits = *PLA*
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
[filament:Polymaker PC-Max]
inherits = *ABS*
bed_temperature = 115
filament_colour = #3A80CA
first_layer_bed_temperature = 100
first_layer_temperature = 270
temperature = 270
[filament:Primavalue PVA]
inherits = *PLA*
cooling = 0
fan_always_on = 0
filament_colour = #FFFFD7
filament_max_volumetric_speed = 10
filament_notes = "List of materials tested with standart PVA print settings for MK2:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'\nVerbatim BVOH"
filament_soluble = 1
filament_type = PVA
first_layer_temperature = 195
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 195
[filament:BarBaz ABS]
inherits = *ABS*
filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS"
[filament:BarBaz HIPS]
inherits = *ABS*
bridge_fan_speed = 50
cooling = 1
extrusion_multiplier = 0.9
fan_always_on = 1
fan_below_layer_time = 10
filament_colour = #FFFFD7
filament_soluble = 1
filament_type = HIPS
first_layer_temperature = 220
max_fan_speed = 20
min_fan_speed = 20
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 220
[filament:BarBaz PET]
inherits = *PET*
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:BarBaz PLA]
inherits = *PLA*
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
[filament:SemiFlex or Flexfill 98A]
inherits = *FLEX*
[filament:Taulman Bridge]
inherits = *common*
bed_temperature = 90
bridge_fan_speed = 40
cooling = 0
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 20
filament_colour = #DEE0E6
filament_max_volumetric_speed = 10
filament_soluble = 0
filament_type = PET
first_layer_bed_temperature = 60
first_layer_temperature = 240
max_fan_speed = 5
min_fan_speed = 0
min_print_speed = 5
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 250
[filament:Taulman T-Glase]
inherits = *PET*
bridge_fan_speed = 40
cooling = 0
fan_always_on = 0
first_layer_bed_temperature = 90
first_layer_temperature = 240
max_fan_speed = 5
min_fan_speed = 0
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
[filament:Verbatim BVOH]
inherits = *common*
bed_temperature = 60
bridge_fan_speed = 100
cooling = 0
disable_fan_first_layers = 1
extrusion_multiplier = 1
fan_always_on = 0
fan_below_layer_time = 100
filament_colour = #FFFFD7
filament_max_volumetric_speed = 10
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
filament_soluble = 1
filament_type = PLA
first_layer_bed_temperature = 60
first_layer_temperature = 215
max_fan_speed = 100
min_fan_speed = 100
min_print_speed = 15
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 210
[filament:Verbatim PP]
inherits = *common*
bed_temperature = 100
bridge_fan_speed = 100
cooling = 1
disable_fan_first_layers = 2
extrusion_multiplier = 1
fan_always_on = 1
fan_below_layer_time = 100
filament_colour = #DEE0E6
filament_max_volumetric_speed = 5
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA"
filament_type = PLA
first_layer_bed_temperature = 100
first_layer_temperature = 220
max_fan_speed = 100
min_fan_speed = 100
min_print_speed = 15
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 220
[printer:*common*]
bed_shape = 0x0,250x0,250x210,0x210
before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n
between_objects_gcode =
deretract_speed = 0
end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
extruder_colour = #FFFF00
extruder_offset = 0x0
gcode_flavor = marlin
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
max_layer_height = 0.25
min_layer_height = 0.07
nozzle_diameter = 0.4
octoprint_apikey =
octoprint_host =
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_BarBaz3D\nPRINTER_MODEL_MK2\n
printer_settings_id =
retract_before_travel = 1
retract_before_wipe = 0%
retract_layer_change = 1
retract_length = 0.8
retract_length_toolchange = 4
retract_lift = 0.6
retract_lift_above = 0
retract_lift_below = 199
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 35
serial_port =
serial_speed = 250000
single_extruder_multi_material = 0
start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
toolchange_gcode =
use_firmware_retraction = 0
use_relative_e_distances = 1
use_volumetric_e = 0
variable_layer_height = 1
wipe = 1
z_offset = 0
printer_model = M2
printer_variant = 0.4
default_print_profile = 0.15mm OPTIMAL
default_filament_profile = BarBaz PLA
[printer:*multimaterial*]
inherits = *common*
deretract_speed = 50
retract_before_travel = 3
retract_before_wipe = 60%
retract_layer_change = 0
retract_length = 4
retract_lift = 0.6
retract_lift_above = 0
retract_lift_below = 199
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 80
single_extruder_multi_material = 1
printer_model = M3
[printer:*mm-single*]
inherits = *multimaterial*
end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_BarBaz3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN
start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\nG92 E0.0
[printer:*mm-multi*]
inherits = *multimaterial*
end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes.\nG1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\n{endif}\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors
extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259
nozzle_diameter = 0.4,0.4,0.4,0.4
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_BarBaz3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN
start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0
variable_layer_height = 0
[printer:BarBaz i3 MK2]
inherits = *common*
[printer:BarBaz i3 MK2 0.25 nozzle]
inherits = *common*
max_layer_height = 0.1
min_layer_height = 0.05
nozzle_diameter = 0.25
retract_length = 1
retract_speed = 50
variable_layer_height = 0
printer_variant = 0.25
default_print_profile = 0.10mm DETAIL 0.25 nozzle
[printer:BarBaz i3 MK2 0.6 nozzle]
inherits = *common*
max_layer_height = 0.35
min_layer_height = 0.1
nozzle_diameter = 0.6
printer_variant = 0.6
[printer:BarBaz i3 MK2 MM Single Mode]
inherits = *mm-single*
[printer:BarBaz i3 MK2 MM Single Mode 0.6 nozzle]
inherits = *mm-single*
nozzle_diameter = 0.6
printer_variant = 0.6
[printer:BarBaz i3 MK2 MultiMaterial]
inherits = *mm-multi*
nozzle_diameter = 0.4,0.4,0.4,0.4
[printer:BarBaz i3 MK2 MultiMaterial 0.6 nozzle]
inherits = *mm-multi*
nozzle_diameter = 0.6,0.6,0.6,0.6
printer_variant = 0.6
[printer:BarBaz i3 MK3]
inherits = *common*
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_BarBaz3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = M1
default_print_profile = 0.15mm OPTIMAL MK3
[printer:BarBaz i3 MK3 0.25 nozzle]
inherits = *common*
nozzle_diameter = 0.25
printer_variant = 0.25
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_BarBaz3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = M1
default_print_profile = 0.10mm DETAIL MK3
[printer:BarBaz i3 MK3 0.6 nozzle]
inherits = *common*
nozzle_diameter = 0.6
printer_variant = 0.6
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_BarBaz3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = M1
default_print_profile = 0.15mm OPTIMAL MK3

View File

@ -0,0 +1,985 @@
# Print profiles for the Foobar Research printers.
[vendor]
# Vendor name will be shown by the Config Wizard.
name = Foo Bar
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the Slic3r configuration to be downgraded.
config_version = 0.1.0
# Where to get the updates from?
config_update_url = https://example.com
# The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install.
#TODO: One day we may differentiate variants of the nozzles / hot ends,
#for example by the melt zone size, or whether the nozzle is hardened.
[printer_model:M1]
name = Foo Bar Model 1
variants = 0.4; 0.25; 0.6
[printer_model:M2]
name = Foo Bar Model 2
variants = 0.4; 0.25; 0.6
[printer_model:M3]
# Printer model name will be shown by the installation wizard.
name = Foo Bar Model 3
variants = 0.4; 0.6
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
# Common print preset, mostly derived from MK2 single material with a 0.4mm nozzle.
# All other print presets will derive from the *common* print preset.
[print:*common*]
avoid_crossing_perimeters = 0
bridge_acceleration = 1000
bridge_angle = 0
bridge_flow_ratio = 0.8
bridge_speed = 20
brim_width = 0
clip_multipart_objects = 1
compatible_printers =
complete_objects = 0
default_acceleration = 1000
dont_support_bridges = 1
elefant_foot_compensation = 0
ensure_vertical_shell_thickness = 1
external_fill_pattern = rectilinear
external_perimeters_first = 0
external_perimeter_extrusion_width = 0.45
extra_perimeters = 0
extruder_clearance_height = 20
extruder_clearance_radius = 20
extrusion_width = 0.45
fill_angle = 45
fill_density = 20%
fill_pattern = cubic
first_layer_acceleration = 1000
first_layer_extrusion_width = 0.42
first_layer_height = 0.2
first_layer_speed = 30
gap_fill_speed = 40
gcode_comments = 0
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0.45
infill_first = 0
infill_only_where_needed = 0
infill_overlap = 25%
interface_shells = 0
max_print_speed = 100
max_volumetric_extrusion_rate_slope_negative = 0
max_volumetric_extrusion_rate_slope_positive = 0
max_volumetric_speed = 0
min_skirt_length = 4
notes =
overhangs = 0
only_retract_when_crossing_perimeters = 0
ooze_prevention = 0
output_filename_format = [input_filename_base].gcode
perimeters = 2
perimeter_extruder = 1
perimeter_extrusion_width = 0.45
post_process =
print_settings_id =
raft_layers = 0
resolution = 0
seam_position = nearest
skirts = 1
skirt_distance = 2
skirt_height = 3
small_perimeter_speed = 20
solid_infill_below_area = 0
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_extrusion_width = 0.45
spiral_vase = 0
standby_temperature_delta = -5
support_material = 0
support_material_extruder = 0
support_material_extrusion_width = 0.35
support_material_interface_extruder = 0
support_material_angle = 0
support_material_buildplate_only = 0
support_material_enforce_layers = 0
support_material_contact_distance = 0.15
support_material_interface_contact_loops = 0
support_material_interface_layers = 2
support_material_interface_spacing = 0.2
support_material_interface_speed = 100%
support_material_pattern = rectilinear
support_material_spacing = 2
support_material_speed = 50
support_material_synchronize_layers = 0
support_material_threshold = 45
support_material_with_sheath = 0
support_material_xy_spacing = 60%
thin_walls = 0
top_infill_extrusion_width = 0.45
top_solid_infill_speed = 40
travel_speed = 180
wipe_tower = 0
wipe_tower_per_color_wipe = 20
wipe_tower_width = 60
wipe_tower_x = 180
wipe_tower_y = 140
xy_size_compensation = 0
# Print parameters common to a 0.25mm diameter nozzle.
[print:*0.25nozzle*]
external_perimeter_extrusion_width = 0.25
extrusion_width = 0.25
first_layer_extrusion_width = 0.25
infill_extrusion_width = 0.25
perimeter_extrusion_width = 0.25
solid_infill_extrusion_width = 0.25
top_infill_extrusion_width = 0.25
support_material_extrusion_width = 0.18
support_material_interface_layers = 0
support_material_interface_spacing = 0.15
support_material_spacing = 1
support_material_xy_spacing = 150%
# Print parameters common to a 0.6mm diameter nozzle.
[print:*0.6nozzle*]
external_perimeter_extrusion_width = 0.61
extrusion_width = 0.67
first_layer_extrusion_width = 0.65
infill_extrusion_width = 0.7
perimeter_extrusion_width = 0.65
solid_infill_extrusion_width = 0.65
top_infill_extrusion_width = 0.6
[print:*soluble_support*]
overhangs = 1
skirts = 0
support_material = 1
support_material_contact_distance = 0
support_material_extruder = 4
support_material_extrusion_width = 0.45
support_material_interface_extruder = 4
support_material_interface_spacing = 0.1
support_material_synchronize_layers = 1
support_material_threshold = 80
support_material_with_sheath = 1
wipe_tower = 1
[print:*0.05mm*]
inherits = *common*
bottom_solid_layers = 10
bridge_acceleration = 300
bridge_flow_ratio = 0.7
default_acceleration = 500
external_perimeter_speed = 20
fill_density = 20%
first_layer_acceleration = 500
gap_fill_speed = 20
infill_acceleration = 800
infill_speed = 30
max_print_speed = 80
small_perimeter_speed = 15
solid_infill_speed = 30
support_material_extrusion_width = 0.3
support_material_spacing = 1.5
layer_height = 0.05
perimeter_acceleration = 300
perimeter_speed = 30
perimeters = 3
support_material_speed = 30
top_solid_infill_speed = 20
top_solid_layers = 15
[print:0.05mm ULTRADETAIL]
inherits = *0.05mm*
infill_extrusion_width = 0.5
[print:0.05mm ULTRADETAIL MK3]
inherits = *0.05mm*
fill_pattern = grid
top_infill_extrusion_width = 0.4
[print:0.05mm ULTRADETAIL 0.25 nozzle]
inherits = *0.05mm*
external_perimeter_extrusion_width = 0
extrusion_width = 0.28
fill_density = 20%
first_layer_extrusion_width = 0.3
infill_extrusion_width = 0
infill_speed = 20
max_print_speed = 100
perimeter_extrusion_width = 0
perimeter_speed = 20
small_perimeter_speed = 10
solid_infill_extrusion_width = 0
solid_infill_speed = 20
support_material_speed = 20
top_infill_extrusion_width = 0
[print:0.05mm ULTRADETAIL 0.25 nozzle MK3]
inherits = *0.05mm*; *0.25nozzle*
fill_pattern = grid
top_infill_extrusion_width = 0.4
[print:*0.10mm*]
inherits = *common*
bottom_solid_layers = 7
bridge_flow_ratio = 0.7
layer_height = 0.1
perimeter_acceleration = 800
top_solid_layers = 9
[print:0.10mm DETAIL]
inherits = *0.10mm*
external_perimeter_speed = 40
infill_acceleration = 2000
infill_speed = 60
perimeter_speed = 50
solid_infill_speed = 50
[print:0.10mm DETAIL MK3]
inherits = *0.10mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 200
perimeter_speed = 45
solid_infill_speed = 170
top_infill_extrusion_width = 0.4
top_solid_infill_speed = 50
[print:0.10mm DETAIL 0.25 nozzle]
inherits = *0.10mm*
bridge_acceleration = 600
external_perimeter_speed = 20
infill_acceleration = 1600
infill_speed = 40
perimeter_acceleration = 600
perimeter_speed = 25
small_perimeter_speed = 10
solid_infill_speed = 40
top_solid_infill_speed = 30
[print:0.10mm DETAIL 0.25 nozzle MK3]
inherits = *0.10mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 200
perimeter_speed = 45
solid_infill_speed = 170
top_infill_extrusion_width = 0.4
top_solid_infill_speed = 50
[print:0.10mm DETAIL 0.6 nozzle MK3]
inherits = *0.10mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 200
perimeter_speed = 45
solid_infill_speed = 170
top_infill_extrusion_width = 0.4
top_solid_infill_speed = 50
[print:*0.15mm*]
inherits = *common*
bottom_solid_layers = 5
external_perimeter_speed = 40
infill_acceleration = 2000
infill_speed = 60
layer_height = 0.15
perimeter_acceleration = 800
perimeter_speed = 50
solid_infill_speed = 50
top_infill_extrusion_width = 0.4
top_solid_layers = 7
[print:0.15mm 100mms Linear Advance]
inherits = *0.15mm*
bridge_flow_ratio = 0.95
external_perimeter_speed = 50
infill_speed = 100
max_print_speed = 150
perimeter_speed = 60
small_perimeter_speed = 30
solid_infill_speed = 100
support_material_speed = 60
top_solid_infill_speed = 70
[print:0.15mm OPTIMAL]
inherits = *0.15mm*
top_infill_extrusion_width = 0.45
[print:0.15mm OPTIMAL 0.25 nozzle]
inherits = *0.15mm*; *0.25nozzle*
bridge_acceleration = 600
bridge_flow_ratio = 0.7
external_perimeter_speed = 20
infill_acceleration = 1600
infill_speed = 40
perimeter_acceleration = 600
perimeter_speed = 25
small_perimeter_speed = 10
solid_infill_speed = 40
support_material_extrusion_width = 0.2
top_solid_infill_speed = 30
[print:0.15mm OPTIMAL 0.6 nozzle]
inherits = *0.15mm*; *0.6nozzle*
[print:0.15mm OPTIMAL MK3]
inherits = *0.15mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:0.15mm OPTIMAL SOLUBLE FULL]
inherits = *0.15mm*; *soluble_support*
external_perimeter_speed = 25
notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
perimeter_speed = 40
solid_infill_speed = 40
top_infill_extrusion_width = 0.45
top_solid_infill_speed = 30
wipe_tower = 1
[print:0.15mm OPTIMAL SOLUBLE INTERFACE]
inherits = 0.15mm OPTIMAL SOLUBLE FULL
notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
support_material_extruder = 0
support_material_interface_layers = 3
support_material_with_sheath = 0
support_material_xy_spacing = 80%
[print:0.15mm OPTIMAL 0.25 nozzle MK3]
inherits = *0.15mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:*0.20mm*]
inherits = *common*
bottom_solid_layers = 4
bridge_flow_ratio = 0.95
external_perimeter_speed = 40
infill_acceleration = 2000
infill_speed = 60
layer_height = 0.2
perimeter_acceleration = 800
perimeter_speed = 50
solid_infill_speed = 50
top_infill_extrusion_width = 0.4
top_solid_layers = 5
[print:0.15mm OPTIMAL 0.6 nozzle MK3]
inherits = *0.15mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:0.20mm 100mms Linear Advance]
inherits = *0.20mm*
external_perimeter_speed = 50
infill_speed = 100
max_print_speed = 150
perimeter_speed = 60
small_perimeter_speed = 30
solid_infill_speed = 100
support_material_speed = 60
top_solid_infill_speed = 70
[print:0.20mm FAST MK3]
inherits = *0.20mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:0.20mm NORMAL]
inherits = *0.20mm*
[print:0.20mm NORMAL 0.6 nozzle]
inherits = *0.20mm*; *0.6nozzle*
[print:0.20mm NORMAL SOLUBLE FULL]
inherits = *0.20mm*; *soluble_support*
external_perimeter_speed = 30
notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
perimeter_speed = 40
solid_infill_speed = 40
top_solid_infill_speed = 30
[print:0.20mm NORMAL SOLUBLE INTERFACE]
inherits = 0.20mm NORMAL SOLUBLE FULL
notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
support_material_extruder = 0
support_material_interface_layers = 3
support_material_with_sheath = 0
support_material_xy_spacing = 80%
[print:0.20mm FAST 0.6 nozzle MK3]
inherits = *0.20mm*
bridge_speed = 30
external_perimeter_speed = 35
fill_pattern = grid
infill_acceleration = 1500
infill_speed = 170
max_print_speed = 170
perimeter_speed = 45
solid_infill_speed = 170
top_solid_infill_speed = 50
[print:*0.35mm*]
inherits = *common*
bottom_solid_layers = 3
external_perimeter_extrusion_width = 0.6
external_perimeter_speed = 40
first_layer_extrusion_width = 0.75
infill_acceleration = 2000
infill_speed = 60
layer_height = 0.35
perimeter_acceleration = 800
perimeter_extrusion_width = 0.65
perimeter_speed = 50
solid_infill_extrusion_width = 0.65
solid_infill_speed = 60
top_solid_infill_speed = 50
top_solid_layers = 4
[print:0.35mm FAST]
inherits = *0.35mm*
bridge_flow_ratio = 0.95
first_layer_extrusion_width = 0.42
perimeter_extrusion_width = 0.43
solid_infill_extrusion_width = 0.7
top_infill_extrusion_width = 0.43
[print:0.35mm FAST 0.6 nozzle]
inherits = *0.35mm*; *0.6nozzle*
[print:0.35mm FAST sol full 0.6 nozzle]
inherits = *0.35mm*; *0.6nozzle*; *soluble_support*
external_perimeter_extrusion_width = 0.6
external_perimeter_speed = 30
notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
perimeter_speed = 40
support_material_extrusion_width = 0.55
support_material_interface_layers = 3
support_material_xy_spacing = 120%
top_infill_extrusion_width = 0.57
[print:0.35mm FAST sol int 0.6 nozzle]
inherits = 0.35mm FAST sol full 0.6 nozzle
support_material_extruder = 0
support_material_interface_layers = 2
support_material_with_sheath = 0
support_material_xy_spacing = 150%
[filament:*common*]
cooling = 1
compatible_printers =
end_filament_gcode = "; Filament-specific end gcode"
extrusion_multiplier = 1
filament_cost = 0
filament_density = 0
filament_diameter = 1.75
filament_notes = ""
filament_settings_id =
filament_soluble = 0
min_print_speed = 5
slowdown_below_layer_time = 20
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
[filament:*PLA*]
inherits = *common*
bed_temperature = 60
bridge_fan_speed = 100
disable_fan_first_layers = 1
fan_always_on = 1
fan_below_layer_time = 100
filament_colour = #FF3232
filament_max_volumetric_speed = 15
filament_type = PLA
first_layer_bed_temperature = 60
first_layer_temperature = 215
max_fan_speed = 100
min_fan_speed = 100
temperature = 210
[filament:*PET*]
inherits = *common*
bed_temperature = 90
bridge_fan_speed = 50
disable_fan_first_layers = 3
fan_always_on = 1
fan_below_layer_time = 20
filament_colour = #FF8000
filament_max_volumetric_speed = 8
filament_type = PET
first_layer_bed_temperature = 85
first_layer_temperature = 230
max_fan_speed = 50
min_fan_speed = 30
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
temperature = 240
[filament:*ABS*]
inherits = *common*
bed_temperature = 110
bridge_fan_speed = 30
cooling = 0
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 20
filament_colour = #3A80CA
filament_max_volumetric_speed = 11
filament_type = ABS
first_layer_bed_temperature = 100
first_layer_temperature = 255
max_fan_speed = 30
min_fan_speed = 20
temperature = 255
[filament:*FLEX*]
inherits = *common*
bridge_fan_speed = 100
cooling = 0
disable_fan_first_layers = 1
extrusion_multiplier = 1.2
fan_always_on = 0
fan_below_layer_time = 100
filament_colour = #00CA0A
filament_max_volumetric_speed = 1.5
filament_type = FLEX
first_layer_bed_temperature = 50
first_layer_temperature = 240
max_fan_speed = 90
min_fan_speed = 70
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 240
[filament:ColorFabb Brass Bronze]
inherits = *PLA*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 10
[filament:ColorFabb HT]
inherits = *PET*
bed_temperature = 110
bridge_fan_speed = 30
cooling = 1
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 10
first_layer_bed_temperature = 105
first_layer_temperature = 270
max_fan_speed = 20
min_fan_speed = 10
min_print_speed = 5
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
temperature = 270
[filament:ColorFabb PLA-PHA]
inherits = *PLA*
[filament:ColorFabb Woodfil]
inherits = *PLA*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 10
first_layer_temperature = 200
min_print_speed = 5
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 200
[filament:ColorFabb XT]
inherits = *PET*
filament_type = PLA
first_layer_bed_temperature = 90
first_layer_temperature = 260
temperature = 270
[filament:ColorFabb XT-CF20]
inherits = *PET*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 1
first_layer_bed_temperature = 90
first_layer_temperature = 260
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
temperature = 260
[filament:ColorFabb nGen]
inherits = *PET*
bridge_fan_speed = 40
fan_always_on = 0
fan_below_layer_time = 10
filament_type = NGEN
first_layer_temperature = 240
max_fan_speed = 35
min_fan_speed = 20
[filament:ColorFabb nGen flex]
inherits = *FLEX*
bed_temperature = 85
bridge_fan_speed = 40
cooling = 1
disable_fan_first_layers = 3
extrusion_multiplier = 1
fan_below_layer_time = 10
filament_max_volumetric_speed = 5
first_layer_bed_temperature = 85
first_layer_temperature = 260
max_fan_speed = 35
min_fan_speed = 20
temperature = 260
[filament:E3D Edge]
inherits = *PET*
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:E3D PC-ABS]
inherits = *ABS*
first_layer_temperature = 270
temperature = 270
[filament:Fillamentum ABS]
inherits = *ABS*
first_layer_temperature = 240
temperature = 240
[filament:Fillamentum ASA]
inherits = *ABS*
fan_always_on = 1
first_layer_temperature = 265
temperature = 265
[filament:Fillamentum CPE HG100 HM100]
inherits = *PET*
filament_notes = "CPE HG100 , CPE HM100"
first_layer_bed_temperature = 90
first_layer_temperature = 275
max_fan_speed = 50
min_fan_speed = 50
temperature = 275
[filament:Fillamentum Timberfil]
inherits = *PLA*
extrusion_multiplier = 1.2
filament_colour = #804040
filament_max_volumetric_speed = 10
first_layer_temperature = 190
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 190
[filament:Generic ABS]
inherits = *ABS*
filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS"
[filament:Generic PET]
inherits = *PET*
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:Generic PLA]
inherits = *PLA*
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
[filament:Polymaker PC-Max]
inherits = *ABS*
bed_temperature = 115
filament_colour = #3A80CA
first_layer_bed_temperature = 100
first_layer_temperature = 270
temperature = 270
[filament:Primavalue PVA]
inherits = *PLA*
cooling = 0
fan_always_on = 0
filament_colour = #FFFFD7
filament_max_volumetric_speed = 10
filament_notes = "List of materials tested with standart PVA print settings for MK2:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'\nVerbatim BVOH"
filament_soluble = 1
filament_type = PVA
first_layer_temperature = 195
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 195
[filament:Foobar ABS]
inherits = *ABS*
filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS"
[filament:Foobar HIPS]
inherits = *ABS*
bridge_fan_speed = 50
cooling = 1
extrusion_multiplier = 0.9
fan_always_on = 1
fan_below_layer_time = 10
filament_colour = #FFFFD7
filament_soluble = 1
filament_type = HIPS
first_layer_temperature = 220
max_fan_speed = 20
min_fan_speed = 20
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 220
[filament:Foobar PET]
inherits = *PET*
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:Foobar PLA]
inherits = *PLA*
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
[filament:SemiFlex or Flexfill 98A]
inherits = *FLEX*
[filament:Taulman Bridge]
inherits = *common*
bed_temperature = 90
bridge_fan_speed = 40
cooling = 0
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 20
filament_colour = #DEE0E6
filament_max_volumetric_speed = 10
filament_soluble = 0
filament_type = PET
first_layer_bed_temperature = 60
first_layer_temperature = 240
max_fan_speed = 5
min_fan_speed = 0
min_print_speed = 5
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 250
[filament:Taulman T-Glase]
inherits = *PET*
bridge_fan_speed = 40
cooling = 0
fan_always_on = 0
first_layer_bed_temperature = 90
first_layer_temperature = 240
max_fan_speed = 5
min_fan_speed = 0
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
[filament:Verbatim BVOH]
inherits = *common*
bed_temperature = 60
bridge_fan_speed = 100
cooling = 0
disable_fan_first_layers = 1
extrusion_multiplier = 1
fan_always_on = 0
fan_below_layer_time = 100
filament_colour = #FFFFD7
filament_max_volumetric_speed = 10
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
filament_soluble = 1
filament_type = PLA
first_layer_bed_temperature = 60
first_layer_temperature = 215
max_fan_speed = 100
min_fan_speed = 100
min_print_speed = 15
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 210
[filament:Verbatim PP]
inherits = *common*
bed_temperature = 100
bridge_fan_speed = 100
cooling = 1
disable_fan_first_layers = 2
extrusion_multiplier = 1
fan_always_on = 1
fan_below_layer_time = 100
filament_colour = #DEE0E6
filament_max_volumetric_speed = 5
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA"
filament_type = PLA
first_layer_bed_temperature = 100
first_layer_temperature = 220
max_fan_speed = 100
min_fan_speed = 100
min_print_speed = 15
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 220
[printer:*common*]
bed_shape = 0x0,250x0,250x210,0x210
before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n
between_objects_gcode =
deretract_speed = 0
end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
extruder_colour = #FFFF00
extruder_offset = 0x0
gcode_flavor = marlin
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
max_layer_height = 0.25
min_layer_height = 0.07
nozzle_diameter = 0.4
octoprint_apikey =
octoprint_host =
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_Foobar3D\nPRINTER_MODEL_MK2\n
printer_settings_id =
retract_before_travel = 1
retract_before_wipe = 0%
retract_layer_change = 1
retract_length = 0.8
retract_length_toolchange = 4
retract_lift = 0.6
retract_lift_above = 0
retract_lift_below = 199
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 35
serial_port =
serial_speed = 250000
single_extruder_multi_material = 0
start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0
toolchange_gcode =
use_firmware_retraction = 0
use_relative_e_distances = 1
use_volumetric_e = 0
variable_layer_height = 1
wipe = 1
z_offset = 0
printer_model = M2
printer_variant = 0.4
default_print_profile = 0.15mm OPTIMAL
default_filament_profile = Foobar PLA
[printer:*multimaterial*]
inherits = *common*
deretract_speed = 50
retract_before_travel = 3
retract_before_wipe = 60%
retract_layer_change = 0
retract_length = 4
retract_lift = 0.6
retract_lift_above = 0
retract_lift_below = 199
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 80
single_extruder_multi_material = 1
printer_model = M3
[printer:*mm-single*]
inherits = *multimaterial*
end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_Foobar3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN
start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\nG92 E0.0
[printer:*mm-multi*]
inherits = *multimaterial*
end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes.\nG1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\n{endif}\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors
extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259
nozzle_diameter = 0.4,0.4,0.4,0.4
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_Foobar3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN
start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0
variable_layer_height = 0
[printer:Foobar i3 MK2]
inherits = *common*
[printer:Foobar i3 MK2 0.25 nozzle]
inherits = *common*
max_layer_height = 0.1
min_layer_height = 0.05
nozzle_diameter = 0.25
retract_length = 1
retract_speed = 50
variable_layer_height = 0
printer_variant = 0.25
default_print_profile = 0.10mm DETAIL 0.25 nozzle
[printer:Foobar i3 MK2 0.6 nozzle]
inherits = *common*
max_layer_height = 0.35
min_layer_height = 0.1
nozzle_diameter = 0.6
printer_variant = 0.6
[printer:Foobar i3 MK2 MM Single Mode]
inherits = *mm-single*
[printer:Foobar i3 MK2 MM Single Mode 0.6 nozzle]
inherits = *mm-single*
nozzle_diameter = 0.6
printer_variant = 0.6
[printer:Foobar i3 MK2 MultiMaterial]
inherits = *mm-multi*
nozzle_diameter = 0.4,0.4,0.4,0.4
[printer:Foobar i3 MK2 MultiMaterial 0.6 nozzle]
inherits = *mm-multi*
nozzle_diameter = 0.6,0.6,0.6,0.6
printer_variant = 0.6
[printer:Foobar i3 MK3]
inherits = *common*
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_Foobar3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = M1
default_print_profile = 0.15mm OPTIMAL MK3
[printer:Foobar i3 MK3 0.25 nozzle]
inherits = *common*
nozzle_diameter = 0.25
printer_variant = 0.25
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_Foobar3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = M1
default_print_profile = 0.10mm DETAIL MK3
[printer:Foobar i3 MK3 0.6 nozzle]
inherits = *common*
nozzle_diameter = 0.6
printer_variant = 0.6
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_Foobar3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = M1
default_print_profile = 0.15mm OPTIMAL MK3

View File

@ -0,0 +1,15 @@
# This is an example configuration version index.
# The index contains version numbers
min_slic3r_version =1.39.0
1.1.1
1.1.0
0.2.0-alpha "some test comment"
max_slic3r_version= 1.39.4
0.1.0 another test comment
# some empty lines
# version without a comment
min_slic3r_version = 1.0.0
max_slic3r_version = 1.1.0
0.0.1

View File

@ -5,23 +5,26 @@
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the Slic3r configuration to be downgraded.
config_version = 0.1
config_version = 0.1.0
# Where to get the updates from?
config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch.ini
# TODO: proper URL
config_update_url = https://raw.githubusercontent.com/vojtechkral/slic3r-settings-tmp/master/PrusaResearch
# The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install.
#TODO: One day we may differentiate variants of the nozzles / hot ends,
#for example by the melt zone size, or whether the nozzle is hardened.
[printer_model:MK3]
name = Original Prusa i3 MK3
variants = 0.4; 0.25; 0.6
[printer_model:MK2S]
name = Original Prusa i3 MK2S
variants = 0.4; 0.25; 0.6
[printer_model:MK2SMM]
# Printer model name will be shown by the installation wizard.
name = MK2S Multi Material
name = Original Prusa i3 MK2SMM
variants = 0.4; 0.6
# All presets starting with asterisk, for example *common*, are intermediate and they will
@ -999,6 +1002,7 @@ default_print_profile = 0.15mm OPTIMAL MK3
[printer:Original Prusa i3 MK3 0.25 nozzle]
inherits = *common*
nozzle_diameter = 0.25
printer_variant = 0.25
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
@ -1009,14 +1013,10 @@ default_print_profile = 0.10mm DETAIL MK3
[printer:Original Prusa i3 MK3 0.6 nozzle]
inherits = *common*
nozzle_diameter = 0.6
printer_variant = 0.6
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = MK3
default_print_profile = 0.15mm OPTIMAL MK3
[presets]
print = 0.15mm OPTIMAL MK3
printer = Original Prusa i3 MK3
filament = Prusa PLA

View File

@ -2,7 +2,7 @@ use Test::More;
use strict;
use warnings;
plan tests => 15;
plan tests => 14;
BEGIN {
use FindBin;
@ -79,6 +79,7 @@ $config->set('disable_fan_first_layers', [ 0 ]);
"G1 X50 F2500\n" .
"G1 F3000;_EXTRUDE_SET_SPEED\n" .
"G1 X100 E1\n" .
";_EXTRUDE_END\n" .
"G1 E4 F400",
# Print time of $gcode.
my $print_time = 50 / (2500 / 60) + 100 / (3000 / 60) + 4 / (400 / 60);
@ -203,8 +204,8 @@ $config->set('disable_fan_first_layers', [ 0 ]);
ok $all_below, 'slowdown_below_layer_time is honored';
# check that all layers have at least one unaltered external perimeter speed
my $external = all { $_ > 0 } values %layer_external;
ok $external, 'slowdown_below_layer_time does not alter external perimeters';
# my $external = all { $_ > 0 } values %layer_external;
# ok $external, 'slowdown_below_layer_time does not alter external perimeters';
}
__END__

View File

@ -170,10 +170,14 @@ add_library(libslic3r STATIC
)
add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/GUI/AboutDialog.cpp
${LIBDIR}/slic3r/GUI/AboutDialog.hpp
${LIBDIR}/slic3r/GUI/AppConfig.cpp
${LIBDIR}/slic3r/GUI/AppConfig.hpp
${LIBDIR}/slic3r/GUI/BitmapCache.cpp
${LIBDIR}/slic3r/GUI/BitmapCache.hpp
${LIBDIR}/slic3r/GUI/ConfigSnapshotDialog.cpp
${LIBDIR}/slic3r/GUI/ConfigSnapshotDialog.hpp
${LIBDIR}/slic3r/GUI/3DScene.cpp
${LIBDIR}/slic3r/GUI/3DScene.hpp
${LIBDIR}/slic3r/GUI/GLShader.cpp
@ -214,12 +218,18 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/Config/Version.hpp
${LIBDIR}/slic3r/Utils/ASCIIFolding.cpp
${LIBDIR}/slic3r/Utils/ASCIIFolding.hpp
${LIBDIR}/slic3r/GUI/ConfigWizard.cpp
${LIBDIR}/slic3r/GUI/ConfigWizard.hpp
${LIBDIR}/slic3r/Utils/Http.cpp
${LIBDIR}/slic3r/Utils/Http.hpp
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
${LIBDIR}/slic3r/Utils/Bonjour.cpp
${LIBDIR}/slic3r/Utils/Bonjour.hpp
${LIBDIR}/slic3r/Utils/PresetUpdater.cpp
${LIBDIR}/slic3r/Utils/PresetUpdater.hpp
${LIBDIR}/slic3r/Utils/Time.cpp
${LIBDIR}/slic3r/Utils/Time.hpp
)
add_library(admesh STATIC
@ -365,6 +375,7 @@ set(XS_XSP_FILES
${XSP_DIR}/SurfaceCollection.xsp
${XSP_DIR}/TriangleMesh.xsp
${XSP_DIR}/Utils_OctoPrint.xsp
${XSP_DIR}/Utils_PresetUpdater.xsp
${XSP_DIR}/XS.xsp
)
foreach (file ${XS_XSP_FILES})
@ -410,7 +421,7 @@ if(APPLE)
# Ignore undefined symbols of the perl interpreter, they will be found in the caller image.
target_link_libraries(XS "-undefined dynamic_lookup")
endif()
target_link_libraries(XS libslic3r libslic3r_gui admesh miniz clipper nowide polypartition poly2tri)
target_link_libraries(XS libslic3r libslic3r_gui admesh miniz clipper nowide polypartition poly2tri semver)
if(SLIC3R_PROFILE)
target_link_libraries(XS Shiny)
endif()
@ -537,13 +548,13 @@ if (SLIC3R_PRUSACONTROL)
set(wxWidgets_UseAlienWx 1)
if (wxWidgets_UseAlienWx)
set(AlienWx_DEBUG 1)
find_package(AlienWx REQUIRED COMPONENTS base core adv)
find_package(AlienWx REQUIRED COMPONENTS base core adv html)
include_directories(${AlienWx_INCLUDE_DIRS})
#add_compile_options(${AlienWx_CXX_FLAGS})
add_definitions(${AlienWx_DEFINITIONS})
set(wxWidgets_LIBRARIES ${AlienWx_LIBRARIES})
else ()
find_package(wxWidgets REQUIRED COMPONENTS base core adv)
find_package(wxWidgets REQUIRED COMPONENTS base core adv html)
include(${wxWidgets_USE_FILE})
endif ()
add_definitions(-DSLIC3R_GUI -DSLIC3R_PRUS)

View File

@ -12,7 +12,7 @@ our $VERSION = '0.01';
BEGIN {
if ($^O eq 'MSWin32') {
eval "use Wx";
# eval "use Wx::Html";
eval "use Wx::Html";
eval "use Wx::Print"; # because of some Wx bug, thread creation fails if we don't have this (looks like Wx::Printout is hard-coded in some thread cleanup code)
}
}

View File

@ -659,6 +659,7 @@ public:
ConfigOptionPoints() : ConfigOptionVector<Pointf>() {}
explicit ConfigOptionPoints(size_t n, const Pointf &value) : ConfigOptionVector<Pointf>(n, value) {}
explicit ConfigOptionPoints(std::initializer_list<Pointf> il) : ConfigOptionVector<Pointf>(std::move(il)) {}
explicit ConfigOptionPoints(const std::vector<Pointf> &values) : ConfigOptionVector<Pointf>(values) {}
static ConfigOptionType static_type() { return coPoints; }
ConfigOptionType type() const override { return static_type(); }

View File

@ -4,6 +4,7 @@
#include "libslic3r.h"
#include <string>
#include <boost/filesystem/path.hpp>
#include <stdexcept>
namespace Slic3r {
@ -15,6 +16,9 @@ public:
file_parser_error(const std::string &msg, const std::string &file, unsigned long line = 0) :
std::runtime_error(format_what(msg, file, line)),
m_message(msg), m_filename(file), m_line(line) {}
file_parser_error(const std::string &msg, const boost::filesystem::path &file, unsigned long line = 0) :
std::runtime_error(format_what(msg, file.string(), line)),
m_message(msg), m_filename(file.string()), m_line(line) {}
// gcc 3.4.2 complains about lack of throw specifier on compiler
// generated dtor
~file_parser_error() throw() {}

File diff suppressed because it is too large Load Diff

View File

@ -9,13 +9,17 @@ namespace Slic3r {
class GCode;
class Layer;
class PerExtruderAdjustments;
/*
A standalone G-code filter, to control cooling of the print.
The G-code is processed per layer. Once a layer is collected, fan start / stop commands are edited
and the print is modified to stretch over a minimum layer time.
*/
// A standalone G-code filter, to control cooling of the print.
// The G-code is processed per layer. Once a layer is collected, fan start / stop commands are edited
// and the print is modified to stretch over a minimum layer time.
//
// The simple it sounds, the actual implementation is significantly more complex.
// Namely, for a multi-extruder print, each material may require a different cooling logic.
// For example, some materials may not like to print too slowly, while with some materials
// we may slow down significantly.
//
class CoolingBuffer {
public:
CoolingBuffer(GCode &gcodegen);
@ -25,7 +29,12 @@ public:
GCode* gcodegen() { return &m_gcodegen; }
private:
CoolingBuffer& operator=(const CoolingBuffer&);
CoolingBuffer& operator=(const CoolingBuffer&) = delete;
std::vector<PerExtruderAdjustments> parse_layer_gcode(const std::string &gcode, std::vector<float> &current_pos) const;
float calculate_layer_slowdown(std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
// Apply slow down over G-code lines stored in per_extruder_adjustments, enable fan if needed.
// Returns the adjusted G-code.
std::string apply_layer_cooldown(const std::string &gcode, size_t layer_id, float layer_time, std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
GCode& m_gcodegen;
std::string m_gcode;
@ -34,6 +43,9 @@ private:
std::vector<char> m_axis;
std::vector<float> m_current_pos;
unsigned int m_current_extruder;
// Old logic: proportional.
bool m_cooling_logic_proportional = false;
};
}

View File

@ -1679,7 +1679,7 @@ PrintConfigDef::PrintConfigDef()
"temperature control commands in the output.");
def->cli = "temperature=i@";
def->full_label = L("Temperature");
def->max = 0;
def->min = 0;
def->max = max_temp;
def->default_value = new ConfigOptionInts { 200 };

View File

@ -3,6 +3,8 @@
#include <locale>
#include "libslic3r.h"
namespace Slic3r {
extern void set_logging_level(unsigned int level);

View File

@ -14,7 +14,7 @@
#include <boost/thread.hpp>
#define SLIC3R_FORK_NAME "Slic3r Prusa Edition"
#define SLIC3R_VERSION "1.39.0"
#define SLIC3R_VERSION "1.40.0"
#define SLIC3R_BUILD "UNKNOWN"
typedef int32_t coord_t;

View File

@ -62,8 +62,8 @@ REGISTER_CLASS(GLVolumeCollection, "GUI::_3DScene::GLVolume::Collection");
REGISTER_CLASS(Preset, "GUI::Preset");
REGISTER_CLASS(PresetCollection, "GUI::PresetCollection");
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
REGISTER_CLASS(PresetHints, "GUI::PresetHints");
REGISTER_CLASS(TabIface, "GUI::Tab");
REGISTER_CLASS(PresetUpdater, "PresetUpdater");
REGISTER_CLASS(OctoPrint, "OctoPrint");
SV* ConfigBase__as_hash(ConfigBase* THIS)

View File

@ -175,6 +175,9 @@ semver_parse_version (const char *str, semver_t *ver) {
slice = (char *) str;
index = 0;
// non mandatory
ver->patch = 0;
while (slice != NULL && index++ < 4) {
next = strchr(slice, DELIMITER[0]);
if (next == NULL)
@ -200,7 +203,8 @@ semver_parse_version (const char *str, semver_t *ver) {
slice = next + 1;
}
return 0;
// Major and minor versions are mandatory, patch version is not mandatory.
return (index == 2 || index == 3) ? 0 : -1;
}
static int
@ -615,3 +619,22 @@ semver_numeric (semver_t *x) {
return num;
}
static char *semver_strdup(const char *src) {
if (src == NULL) return NULL;
size_t len = strlen(src) + 1;
char *res = malloc(len);
return res != NULL ? (char *) memcpy(res, src, len) : NULL;
}
semver_t
semver_copy(const semver_t *ver) {
semver_t res = *ver;
if (ver->metadata != NULL) {
res.metadata = strdup(ver->metadata);
}
if (ver->prerelease != NULL) {
res.prerelease = strdup(ver->prerelease);
}
return res;
}

View File

@ -98,6 +98,9 @@ semver_is_valid (const char *s);
int
semver_clean (char *s);
semver_t
semver_copy(const semver_t *ver);
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +1,13 @@
#include "Snapshot.hpp"
#include "../GUI/AppConfig.hpp"
#include "../GUI/PresetBundle.hpp"
#include "../Utils/Time.hpp"
#include <time.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
@ -56,6 +58,7 @@ void Snapshot::load_ini(const std::string &path)
// Parse snapshot.ini
std::string group_name_vendor = "Vendor:";
std::string key_filament = "filament";
std::string key_prefix_model = "model_";
for (auto &section : tree) {
if (section.first == "snapshot") {
// Parse the common section.
@ -79,6 +82,8 @@ void Snapshot::load_ini(const std::string &path)
this->reason = SNAPSHOT_UPGRADE;
else if (rsn == "downgrade")
this->reason = SNAPSHOT_DOWNGRADE;
else if (rsn == "before_rollback")
this->reason = SNAPSHOT_BEFORE_ROLLBACK;
else if (rsn == "user")
this->reason = SNAPSHOT_USER;
else
@ -106,10 +111,7 @@ void Snapshot::load_ini(const std::string &path)
VendorConfig vc;
vc.name = section.first.substr(group_name_vendor.size());
for (auto &kvp : section.second) {
if (boost::starts_with(kvp.first, "model_")) {
//model:MK2S = 0.4;xxx
//model:MK3 = 0.4;xxx
} else if (kvp.first == "version" || kvp.first == "min_slic3r_version" || kvp.first == "max_slic3r_version") {
if (kvp.first == "version" || kvp.first == "min_slic3r_version" || kvp.first == "max_slic3r_version") {
// Version of the vendor specific config bundle bundled with this snapshot.
auto semver = Semver::parse(kvp.second.data());
if (! semver)
@ -120,10 +122,38 @@ void Snapshot::load_ini(const std::string &path)
vc.min_slic3r_version = *semver;
else
vc.max_slic3r_version = *semver;
}
} else if (boost::starts_with(kvp.first, key_prefix_model) && kvp.first.size() > key_prefix_model.size()) {
// Parse the printer variants installed for the current model.
auto &set_variants = vc.models_variants_installed[kvp.first.substr(key_prefix_model.size())];
std::vector<std::string> variants;
if (unescape_strings_cstyle(kvp.second.data(), variants))
for (auto &variant : variants)
set_variants.insert(std::move(variant));
}
}
this->vendor_configs.emplace_back(std::move(vc));
}
}
// Sort the vendors lexicographically.
std::sort(this->vendor_configs.begin(), this->vendor_configs.begin(),
[](const VendorConfig &cfg1, const VendorConfig &cfg2) { return cfg1.name < cfg2.name; });
}
static std::string reason_string(const Snapshot::Reason reason)
{
switch (reason) {
case Snapshot::SNAPSHOT_UPGRADE:
return "upgrade";
case Snapshot::SNAPSHOT_DOWNGRADE:
return "downgrade";
case Snapshot::SNAPSHOT_BEFORE_ROLLBACK:
return "before_rollback";
case Snapshot::SNAPSHOT_USER:
return "user";
case Snapshot::SNAPSHOT_UNKNOWN:
default:
return "unknown";
}
}
void Snapshot::save_ini(const std::string &path)
@ -138,7 +168,7 @@ void Snapshot::save_ini(const std::string &path)
c << "time_captured = " << Slic3r::Utils::format_time_ISO8601Z(this->time_captured) << std::endl;
c << "slic3r_version_captured = " << this->slic3r_version_captured.to_string() << std::endl;
c << "comment = " << this->comment << std::endl;
c << "reason = " << this->reason << std::endl;
c << "reason = " << reason_string(this->reason) << std::endl;
// Export the active presets at the time of the snapshot.
c << std::endl << "[presets]" << std::endl;
@ -154,6 +184,14 @@ void Snapshot::save_ini(const std::string &path)
c << "version = " << vc.version.to_string() << std::endl;
c << "min_slic3r_version = " << vc.min_slic3r_version.to_string() << std::endl;
c << "max_slic3r_version = " << vc.max_slic3r_version.to_string() << std::endl;
// Export installed printer models and their variants.
for (const auto &model : vc.models_variants_installed) {
if (model.second.size() == 0)
continue;
const std::vector<std::string> variants(model.second.begin(), model.second.end());
const auto escaped = escape_strings_cstyle(variants);
c << "model_" << model.first << " = " << escaped << std::endl;
}
}
c.close();
}
@ -172,6 +210,82 @@ void Snapshot::export_selections(AppConfig &config) const
config.set("presets", "printer", printer);
}
void Snapshot::export_vendor_configs(AppConfig &config) const
{
std::map<std::string, std::map<std::string, std::set<std::string>>> vendors;
for (const VendorConfig &vc : vendor_configs)
vendors[vc.name] = vc.models_variants_installed;
config.set_vendors(std::move(vendors));
}
// Perform a deep compare of the active print / filament / printer / vendor directories.
// Return true if the content of the current print / filament / printer / vendor directories
// matches the state stored in this snapshot.
bool Snapshot::equal_to_active(const AppConfig &app_config) const
{
// 1) Check, whether this snapshot contains the same set of active vendors, printer models and variants
// as app_config.
{
std::set<std::string> matched;
for (const VendorConfig &vc : this->vendor_configs) {
auto it_vendor_models_variants = app_config.vendors().find(vc.name);
if (it_vendor_models_variants == app_config.vendors().end() ||
it_vendor_models_variants->second != vc.models_variants_installed)
// There are more vendors enabled in the snapshot than currently installed.
return false;
matched.insert(vc.name);
}
for (const std::pair<std::string, std::map<std::string, std::set<std::string>>> &v : app_config.vendors())
if (matched.find(v.first) == matched.end() && ! v.second.empty())
// There are more vendors currently installed than enabled in the snapshot.
return false;
}
// 2) Check, whether this snapshot references the same set of ini files as the current state.
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
boost::filesystem::path snapshot_dir = boost::filesystem::path(Slic3r::data_dir()) / SLIC3R_SNAPSHOTS_DIR / this->id;
for (const char *subdir : { "print", "filament", "printer", "vendor" }) {
boost::filesystem::path path1 = data_dir / subdir;
boost::filesystem::path path2 = snapshot_dir / subdir;
std::vector<std::string> files1, files2;
for (auto &dir_entry : boost::filesystem::directory_iterator(path1))
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
files1.emplace_back(dir_entry.path().filename().string());
for (auto &dir_entry : boost::filesystem::directory_iterator(path2))
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
files2.emplace_back(dir_entry.path().filename().string());
std::sort(files1.begin(), files1.end());
std::sort(files2.begin(), files2.end());
if (files1 != files2)
return false;
for (const std::string &filename : files1) {
FILE *f1 = boost::nowide::fopen((path1 / filename).string().c_str(), "rb");
FILE *f2 = boost::nowide::fopen((path2 / filename).string().c_str(), "rb");
bool same = true;
if (f1 && f2) {
char buf1[4096];
char buf2[4096];
do {
size_t r1 = fread(buf1, 1, 4096, f1);
size_t r2 = fread(buf2, 1, 4096, f2);
if (r1 != r2 || memcmp(buf1, buf2, r1)) {
same = false;
break;
}
} while (! feof(f1) || ! feof(f2));
} else
same = false;
if (f1)
fclose(f1);
if (f2)
fclose(f2);
if (! same)
return false;
}
}
return true;
}
size_t SnapshotDB::load_db()
{
boost::filesystem::path snapshots_dir = SnapshotDB::create_db_dir();
@ -199,12 +313,29 @@ size_t SnapshotDB::load_db()
}
m_snapshots.emplace_back(std::move(snapshot));
}
// Sort the snapshots by their date/time.
std::sort(m_snapshots.begin(), m_snapshots.end(), [](const Snapshot &s1, const Snapshot &s2) { return s1.time_captured < s2.time_captured; });
if (! errors_cummulative.empty())
throw std::runtime_error(errors_cummulative);
return m_snapshots.size();
}
void SnapshotDB::update_slic3r_versions(std::vector<Index> &index_db)
{
for (Snapshot &snapshot : m_snapshots) {
for (Snapshot::VendorConfig &vendor_config : snapshot.vendor_configs) {
auto it = std::find_if(index_db.begin(), index_db.end(), [&vendor_config](const Index &idx) { return idx.vendor() == vendor_config.name; });
if (it != index_db.end()) {
Index::const_iterator it_version = it->find(vendor_config.version);
if (it_version != it->end()) {
vendor_config.min_slic3r_version = it_version->min_slic3r_version;
vendor_config.max_slic3r_version = it_version->max_slic3r_version;
}
}
}
}
}
static void copy_config_dir_single_level(const boost::filesystem::path &path_src, const boost::filesystem::path &path_dst)
{
if (! boost::filesystem::is_directory(path_dst) &&
@ -225,7 +356,7 @@ static void delete_existing_ini_files(const boost::filesystem::path &path)
boost::filesystem::remove(dir_entry.path());
}
const Snapshot& SnapshotDB::make_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment)
const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment)
{
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
boost::filesystem::path snapshot_db_dir = SnapshotDB::create_db_dir();
@ -235,7 +366,7 @@ const Snapshot& SnapshotDB::make_snapshot(const AppConfig &app_config, Snapshot:
// Snapshot header.
snapshot.time_captured = Slic3r::Utils::get_current_time_utc();
snapshot.id = Slic3r::Utils::format_time_ISO8601Z(snapshot.time_captured);
snapshot.slic3r_version_captured = *Semver::parse(SLIC3R_VERSION);
snapshot.slic3r_version_captured = *Semver::parse(SLIC3R_VERSION); // XXX: have Semver Slic3r version
snapshot.comment = comment;
snapshot.reason = reason;
// Active presets at the time of the snapshot.
@ -250,22 +381,54 @@ const Snapshot& SnapshotDB::make_snapshot(const AppConfig &app_config, Snapshot:
snapshot.filaments.emplace_back(app_config.get("presets", name));
}
// Vendor specific config bundles and installed printers.
for (const std::pair<std::string, std::map<std::string, std::set<std::string>>> &vendor : app_config.vendors()) {
Snapshot::VendorConfig cfg;
cfg.name = vendor.first;
cfg.models_variants_installed = vendor.second;
for (auto it = cfg.models_variants_installed.begin(); it != cfg.models_variants_installed.end();)
if (it->second.empty())
cfg.models_variants_installed.erase(it ++);
else
++ it;
// Read the active config bundle, parse the config version.
PresetBundle bundle;
bundle.load_configbundle((data_dir / "vendor" / (cfg.name + ".ini")).string(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY);
for (const VendorProfile &vp : bundle.vendors)
if (vp.id == cfg.name)
cfg.version = vp.config_version;
// Fill-in the min/max slic3r version from the config index, if possible.
try {
// Load the config index for the vendor.
Index index;
index.load(data_dir / "vendor" / (cfg.name + ".idx"));
auto it = index.find(cfg.version);
if (it != index.end()) {
cfg.min_slic3r_version = it->min_slic3r_version;
cfg.max_slic3r_version = it->max_slic3r_version;
}
} catch (const std::runtime_error &err) {
}
snapshot.vendor_configs.emplace_back(std::move(cfg));
}
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
boost::filesystem::create_directory(snapshot_dir);
// Backup the presets.
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
for (const char *subdir : { "print", "filament", "printer", "vendor" })
copy_config_dir_single_level(data_dir / subdir, snapshot_dir / subdir);
snapshot.save_ini((snapshot_dir / "snapshot.ini").string());
assert(m_snapshots.empty() || m_snapshots.back().time_captured <= snapshot.time_captured);
m_snapshots.emplace_back(std::move(snapshot));
return m_snapshots.back();
}
void SnapshotDB::restore_snapshot(const std::string &id, AppConfig &app_config)
const Snapshot& SnapshotDB::restore_snapshot(const std::string &id, AppConfig &app_config)
{
for (const Snapshot &snapshot : m_snapshots)
if (snapshot.id == id) {
this->restore_snapshot(snapshot, app_config);
return;
return snapshot;
}
throw std::runtime_error(std::string("Snapshot with id " + id + " was not found."));
}
@ -275,18 +438,59 @@ void SnapshotDB::restore_snapshot(const Snapshot &snapshot, AppConfig &app_confi
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
boost::filesystem::path snapshot_db_dir = SnapshotDB::create_db_dir();
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 : { "print", "filament", "printer", "vendor" }) {
delete_existing_ini_files(data_dir / subdir);
copy_config_dir_single_level(snapshot_dir / subdir, data_dir / subdir);
}
// Update app_config from the snapshot.
// Update AppConfig with the selections of the print / filament / printer profiles
// and about the installed printer types and variants.
snapshot.export_selections(app_config);
snapshot.export_vendor_configs(app_config);
}
// Store information about the snapshot.
bool SnapshotDB::is_on_snapshot(AppConfig &app_config) const
{
// Is the "on_snapshot" configuration value set?
std::string on_snapshot = app_config.get("on_snapshot");
if (on_snapshot.empty())
// No, we are not on a snapshot.
return false;
// Is the "on_snapshot" equal to the current configuration state?
auto it_snapshot = this->snapshot(on_snapshot);
if (it_snapshot != this->end() && it_snapshot->equal_to_active(app_config))
// Yes, we are on the snapshot.
return true;
// No, we are no more on a snapshot. Reset the state.
app_config.set("on_snapshot", "");
return false;
}
SnapshotDB::const_iterator SnapshotDB::snapshot_with_vendor_preset(const std::string &vendor_name, const Semver &config_version)
{
auto it_found = m_snapshots.end();
Snapshot::VendorConfig key;
key.name = vendor_name;
for (auto it = m_snapshots.begin(); it != m_snapshots.end(); ++ it) {
const Snapshot &snapshot = *it;
auto it_vendor_config = std::lower_bound(snapshot.vendor_configs.begin(), snapshot.vendor_configs.end(),
key, [](const Snapshot::VendorConfig &cfg1, const Snapshot::VendorConfig &cfg2) { return cfg1.name < cfg2.name; });
if (it_vendor_config != snapshot.vendor_configs.end() && it_vendor_config->name == vendor_name &&
config_version == it_vendor_config->version) {
// Vendor config found with the correct version.
// Save it, but continue searching, as we want the newest snapshot.
it_found = it;
}
}
return it_found;
}
SnapshotDB::const_iterator SnapshotDB::snapshot(const std::string &id) const
{
for (const_iterator it = m_snapshots.begin(); it != m_snapshots.end(); ++ it)
if (it->id == id)
return it;
return m_snapshots.end();
}
boost::filesystem::path SnapshotDB::create_db_dir()
@ -303,6 +507,26 @@ boost::filesystem::path SnapshotDB::create_db_dir()
return snapshots_dir;
}
SnapshotDB& SnapshotDB::singleton()
{
static SnapshotDB instance;
static bool loaded = false;
if (! loaded) {
try {
loaded = true;
// Load the snapshot database.
instance.load_db();
// Load the vendor specific configuration indices.
std::vector<Index> index_db = Index::load_db();
// Update the min / max slic3r versions compatible with the configurations stored inside the snapshots
// based on the min / max slic3r versions defined by the vendor specific config indices.
instance.update_slic3r_versions(index_db);
} catch (std::exception &ex) {
}
}
return instance;
}
} // namespace Config
} // namespace GUI
} // namespace Slic3r

View File

@ -1,11 +1,14 @@
#ifndef slic3r_GUI_Snapshot_
#define slic3r_GUI_Snapshot_
#include <map>
#include <set>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include "Version.hpp"
#include "../Utils/Semver.hpp"
namespace Slic3r {
@ -15,6 +18,9 @@ class AppConfig;
namespace GUI {
namespace Config {
class Version;
class Index;
// A snapshot contains:
// Slic3r.ini
// vendor/
@ -28,6 +34,7 @@ public:
SNAPSHOT_UNKNOWN,
SNAPSHOT_UPGRADE,
SNAPSHOT_DOWNGRADE,
SNAPSHOT_BEFORE_ROLLBACK,
SNAPSHOT_USER,
};
@ -39,6 +46,12 @@ public:
// Export the print / filament / printer selections to be activated into the AppConfig.
void export_selections(AppConfig &config) const;
void export_vendor_configs(AppConfig &config) const;
// Perform a deep compare of the active print / filament / printer / vendor directories.
// Return true if the content of the current print / filament / printer / vendor directories
// matches the state stored in this snapshot.
bool equal_to_active(const AppConfig &app_config) const;
// ID of a snapshot should equal to the name of the snapshot directory.
// The ID contains the date/time, reason and comment to be human readable.
@ -50,6 +63,8 @@ public:
std::string comment;
Reason reason;
std::string format_reason() const;
// Active presets at the time of the snapshot.
std::string print;
std::vector<std::string> filaments;
@ -67,35 +82,48 @@ public:
Semver min_slic3r_version = Semver::zero();
// Maximum Slic3r version compatible with this vendor configuration, or empty.
Semver max_slic3r_version = Semver::inf();
// Which printer models of this vendor were installed, and which variants of the models?
std::map<std::string, std::set<std::string>> models_variants_installed;
};
// List of vendor configs contained in this snapshot.
// List of vendor configs contained in this snapshot, sorted lexicographically.
std::vector<VendorConfig> vendor_configs;
};
class SnapshotDB
{
public:
// Initialize the SnapshotDB singleton instance. Load the database if it has not been loaded yet.
static SnapshotDB& singleton();
typedef std::vector<Snapshot>::const_iterator const_iterator;
// Load the snapshot database from the snapshots directory.
// If the snapshot directory or its parent does not exist yet, it will be created.
// Returns a number of snapshots loaded.
size_t load_db();
void update_slic3r_versions(std::vector<Index> &index_db);
// Create a snapshot directory, copy the vendor config bundles, user print/filament/printer profiles,
// create an index.
const Snapshot& make_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment);
void restore_snapshot(const std::string &id, AppConfig &app_config);
const Snapshot& take_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment = "");
const Snapshot& restore_snapshot(const std::string &id, AppConfig &app_config);
void restore_snapshot(const Snapshot &snapshot, AppConfig &app_config);
// Test whether the AppConfig's on_snapshot variable points to an existing snapshot, and the existing snapshot
// matches the current state. If it does not match the current state, the AppConfig's "on_snapshot" ID is reset.
bool is_on_snapshot(AppConfig &app_config) const;
// Finds the newest snapshot, which contains a config bundle for vendor_name with config_version.
const_iterator snapshot_with_vendor_preset(const std::string &vendor_name, const Semver &config_version);
const_iterator begin() const { return m_snapshots.begin(); }
const_iterator end() const { return m_snapshots.end(); }
const_iterator snapshot(const std::string &id) const;
const std::vector<Snapshot>& snapshots() const { return m_snapshots; }
private:
// Create the snapshots directory if it does not exist yet.
static boost::filesystem::path create_db_dir();
// Snapshots are sorted by their date/time, oldest first.
std::vector<Snapshot> m_snapshots;
};

View File

@ -6,6 +6,8 @@
#include "../../libslic3r/libslic3r.h"
#include "../../libslic3r/Config.hpp"
#include "../../libslic3r/FileParserError.hpp"
#include "../../libslic3r/Utils.hpp"
namespace Slic3r {
namespace GUI {
@ -13,11 +15,131 @@ namespace Config {
static boost::optional<Semver> s_current_slic3r_semver = Semver::parse(SLIC3R_VERSION);
// Optimized lexicographic compare of two pre-release versions, ignoring the numeric suffix.
static int compare_prerelease(const char *p1, const char *p2)
{
for (;;) {
char c1 = *p1 ++;
char c2 = *p2 ++;
bool a1 = std::isalpha(c1) && c1 != 0;
bool a2 = std::isalpha(c2) && c2 != 0;
if (a1) {
if (a2) {
if (c1 != c2)
return (c1 < c2) ? -1 : 1;
} else
return 1;
} else {
if (a2)
return -1;
else
return 0;
}
}
// This shall never happen.
return 0;
}
bool Version::is_slic3r_supported(const Semver &slic3r_version) const
{
if (! slic3r_version.in_range(min_slic3r_version, max_slic3r_version))
return false;
// Now verify, whether the configuration pre-release status is compatible with the Slic3r's pre-release status.
// Alpha Slic3r will happily load any configuration, while beta Slic3r will ignore alpha configurations etc.
const char *prerelease_slic3r = slic3r_version.prerelease();
const char *prerelease_config = this->config_version.prerelease();
if (prerelease_config == nullptr)
// Released config is always supported.
return true;
else if (prerelease_slic3r == nullptr)
// Released slic3r only supports released configs.
return false;
// Compare the pre-release status of Slic3r against the config.
// If the prerelease status of slic3r is lexicographically lower or equal
// to the prerelease status of the config, accept it.
return compare_prerelease(prerelease_slic3r, prerelease_config) != 1;
}
bool Version::is_current_slic3r_supported() const
{
return this->is_slic3r_supported(*s_current_slic3r_semver);
}
#if 0
//TODO: This test should be moved to a unit test, once we have C++ unit tests in place.
static int version_test()
{
Version v;
v.config_version = *Semver::parse("1.1.2");
v.min_slic3r_version = *Semver::parse("1.38.0");
v.max_slic3r_version = Semver::inf();
assert(v.is_slic3r_supported(*Semver::parse("1.38.0")));
assert(! v.is_slic3r_supported(*Semver::parse("1.38.0-alpha")));
assert(! v.is_slic3r_supported(*Semver::parse("1.37.0-alpha")));
// Test the prerelease status.
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-rc2")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0")));
v.config_version = *Semver::parse("1.1.2-alpha");
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-beta")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-rc2")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0")));
v.config_version = *Semver::parse("1.1.2-alpha1");
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-beta")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-rc2")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0")));
v.config_version = *Semver::parse("1.1.2-beta");
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-rc")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0-rc2")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0")));
v.config_version = *Semver::parse("1.1.2-rc");
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-rc")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-rc2")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0")));
v.config_version = *Semver::parse("1.1.2-rc2");
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-alpha1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-beta1")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-rc")));
assert(v.is_slic3r_supported(*Semver::parse("1.39.0-rc2")));
assert(! v.is_slic3r_supported(*Semver::parse("1.39.0")));
// Test the upper boundary.
v.config_version = *Semver::parse("1.1.2");
v.max_slic3r_version = *Semver::parse("1.39.3-beta1");
assert(v.is_slic3r_supported(*Semver::parse("1.38.0")));
assert(! v.is_slic3r_supported(*Semver::parse("1.38.0-alpha")));
assert(! v.is_slic3r_supported(*Semver::parse("1.38.0-alpha1")));
assert(! v.is_slic3r_supported(*Semver::parse("1.37.0-alpha")));
return 0;
}
static int version_test_run = version_test();
#endif
inline char* left_trim(char *c)
{
for (; *c == ' ' || *c == '\t'; ++ c);
@ -38,12 +160,13 @@ inline std::string unquote_value(char *value, char *end, const std::string &path
if (value == end) {
// Empty string is a valid string.
} else if (*value == '"') {
if (++ value < -- end || *end != '"')
if (++ value > -- end || *end != '"')
throw file_parser_error("String not enquoted correctly", path, idx_line);
*end = 0;
if (! unescape_string_cstyle(value, svalue))
throw file_parser_error("Invalid escape sequence inside a quoted string", path, idx_line);
}
} else
svalue.assign(value, end);
return svalue;
}
@ -53,20 +176,22 @@ inline std::string unquote_version_comment(char *value, char *end, const std::st
if (value == end) {
// Empty string is a valid string.
} else if (*value == '"') {
if (++ value < -- end || *end != '"')
if (++ value > -- end || *end != '"')
throw file_parser_error("Version comment not enquoted correctly", path, idx_line);
*end = 0;
if (! unescape_string_cstyle(value, svalue))
throw file_parser_error("Invalid escape sequence inside a quoted version comment", path, idx_line);
}
} else
svalue.assign(value, end);
return svalue;
}
size_t Index::load(const std::string &path)
size_t Index::load(const boost::filesystem::path &path)
{
m_configs.clear();
m_vendor = path.stem().string();
boost::nowide::ifstream ifs(path);
boost::nowide::ifstream ifs(path.string());
std::string line;
size_t idx_line = 0;
Version ver;
@ -74,63 +199,121 @@ size_t Index::load(const std::string &path)
++ idx_line;
// Skip the initial white spaces.
char *key = left_trim(const_cast<char*>(line.data()));
if (*key == '#')
// Skip a comment line.
continue;
// Right trim the line.
char *end = right_trim(key);
if (key == end)
// Skip an empty line.
continue;
// Keyword may only contain alphanumeric characters. Semantic version may in addition contain "+.-".
char *key_end = key;
bool maybe_semver = false;
for (;; ++ key) {
if (strchr("+.-", *key) != nullptr)
maybe_semver = true;
else if (! std::isalnum(*key))
break;
bool maybe_semver = true;
for (; *key_end != 0; ++ key_end) {
if (std::isalnum(*key_end) || strchr("+.-", *key_end) != nullptr) {
// It may be a semver.
} else if (*key_end == '_') {
// Cannot be a semver, but it may be a key.
maybe_semver = false;
} else
// End of semver or keyword.
break;
}
if (*key != 0 && *key != ' ' && *key != '\t' && *key != '=')
if (*key_end != 0 && *key_end != ' ' && *key_end != '\t' && *key_end != '=')
throw file_parser_error("Invalid keyword or semantic version", path, idx_line);
*key_end = 0;
char *value = left_trim(key_end);
bool key_value_pair = *value == '=';
if (key_value_pair)
value = left_trim(value + 1);
*key_end = 0;
boost::optional<Semver> semver;
if (maybe_semver)
semver = Semver::parse(key);
char *value = left_trim(key_end);
if (*value == '=') {
if (key_value_pair) {
if (semver)
throw file_parser_error("Key cannot be a semantic version", path, idx_line);
throw file_parser_error("Key cannot be a semantic version", path, idx_line);\
// Verify validity of the key / value pair.
std::string svalue = unquote_value(left_trim(++ value), end, path, idx_line);
if (key == "min_sic3r_version" || key == "max_slic3r_version") {
std::string svalue = unquote_value(value, end, path.string(), idx_line);
if (strcmp(key, "min_slic3r_version") == 0 || strcmp(key, "max_slic3r_version") == 0) {
if (! svalue.empty())
semver = Semver::parse(key);
semver = Semver::parse(svalue);
if (! semver)
throw file_parser_error(std::string(key) + " must referece a valid semantic version", path, idx_line);
if (key == "min_sic3r_version")
if (strcmp(key, "min_slic3r_version") == 0)
ver.min_slic3r_version = *semver;
else
ver.max_slic3r_version = *semver;
} else {
// Ignore unknown keys, as there may come new keys in the future.
}
continue;
}
if (! semver)
throw file_parser_error("Invalid semantic version", path, idx_line);
ver.config_version = *semver;
ver.comment = (end <= key_end) ? "" : unquote_version_comment(value, end, path, idx_line);
ver.comment = (end <= key_end) ? "" : unquote_version_comment(value, end, path.string(), idx_line);
m_configs.emplace_back(ver);
}
// Sort the configs by their version.
std::sort(m_configs.begin(), m_configs.end(), [](const Version &v1, const Version &v2) { return v1.config_version < v2.config_version; });
return m_configs.size();
}
Semver Index::version() const
{
Semver ver = Semver::zero();
for (const Version &cv : m_configs)
if (cv.config_version >= ver)
ver = cv.config_version;
return ver;
}
Index::const_iterator Index::find(const Semver &ver) const
{
Version key;
key.config_version = ver;
auto it = std::lower_bound(m_configs.begin(), m_configs.end(), key,
[](const Version &v1, const Version &v2) { return v1.config_version < v2.config_version; });
return (it == m_configs.end() || it->config_version == ver) ? it : m_configs.end();
}
Index::const_iterator Index::recommended() const
{
int idx = -1;
const_iterator highest = m_configs.end();
const_iterator highest = this->end();
for (const_iterator it = this->begin(); it != this->end(); ++ it)
if (it->is_current_slic3r_supported() &&
(highest == this->end() || highest->max_slic3r_version < it->max_slic3r_version))
(highest == this->end() || highest->config_version < it->config_version))
highest = it;
return highest;
}
std::vector<Index> Index::load_db()
{
boost::filesystem::path cache_dir = boost::filesystem::path(Slic3r::data_dir()) / "cache";
std::vector<Index> index_db;
std::string errors_cummulative;
for (auto &dir_entry : boost::filesystem::directory_iterator(cache_dir))
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".idx")) {
Index idx;
try {
idx.load(dir_entry.path());
} catch (const std::runtime_error &err) {
errors_cummulative += err.what();
errors_cummulative += "\n";
continue;
}
index_db.emplace_back(std::move(idx));
}
if (! errors_cummulative.empty())
throw std::runtime_error(errors_cummulative);
return index_db;
}
} // namespace Config
} // namespace GUI
} // namespace Slic3r

View File

@ -4,6 +4,8 @@
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include "../../libslic3r/FileParserError.hpp"
#include "../Utils/Semver.hpp"
@ -25,7 +27,7 @@ struct Version
// Single comment line.
std::string comment;
bool is_slic3r_supported(const Semver &slicer_version) const { return slicer_version.in_range(min_slic3r_version, max_slic3r_version); }
bool is_slic3r_supported(const Semver &slicer_version) const;
bool is_current_slic3r_supported() const;
};
@ -54,17 +56,28 @@ public:
typedef std::vector<Version>::const_iterator const_iterator;
// Read a config index file in the simple format described in the Index class comment.
// Throws Slic3r::file_parser_error and the standard std file access exceptions.
size_t load(const std::string &path);
size_t load(const boost::filesystem::path &path);
const std::string& vendor() const { return m_vendor; }
// Returns version of the index as the highest version of all the configs.
// If there is no config, Semver::zero() is returned.
Semver version() const;
const_iterator begin() const { return m_configs.begin(); }
const_iterator end() const { return m_configs.end(); }
const_iterator find(const Semver &ver) const;
const std::vector<Version>& configs() const { return m_configs; }
// Finds a recommended config to be installed for the current Slic3r version.
// Returns configs().end() if such version does not exist in the index. This shall never happen
// if the index is valid.
const_iterator recommended() const;
// Load all vendor specific indices.
// Throws Slic3r::file_parser_error and the standard std file access exceptions.
static std::vector<Index> load_db();
private:
std::string m_vendor;
std::vector<Version> m_configs;
};

View File

@ -1,4 +1,4 @@
#include "2DBed.hpp";
#include "2DBed.hpp"
#include <wx/dcbuffer.h>
#include "BoundingBox.hpp"
@ -66,7 +66,7 @@ void Bed_2D::repaint()
shift.y - (cbb.max.y - GetSize().GetHeight()));
// draw bed fill
dc.SetBrush(*new wxBrush(*new wxColour(255, 255, 255), wxSOLID));
dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxSOLID));
wxPointList pt_list;
for (auto pt: m_bed_shape)
{
@ -87,7 +87,7 @@ void Bed_2D::repaint()
}
polylines = intersection_pl(polylines, bed_polygon);
dc.SetPen(*new wxPen(*new wxColour(230, 230, 230), 1, wxSOLID));
dc.SetPen(wxPen(wxColour(230, 230, 230), 1, wxSOLID));
for (auto pl : polylines)
{
for (size_t i = 0; i < pl.points.size()-1; i++){
@ -98,8 +98,8 @@ void Bed_2D::repaint()
}
// draw bed contour
dc.SetPen(*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID));
dc.SetBrush(*new wxBrush(*new wxColour(0, 0, 0), wxTRANSPARENT));
dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxSOLID));
dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxTRANSPARENT));
dc.DrawPolygon(&pt_list, 0, 0);
auto origin_px = to_pixels(Pointf(0, 0));
@ -108,7 +108,7 @@ void Bed_2D::repaint()
auto axes_len = 50;
auto arrow_len = 6;
auto arrow_angle = Geometry::deg2rad(45.0);
dc.SetPen(*new wxPen(*new wxColour(255, 0, 0), 2, wxSOLID)); // red
dc.SetPen(wxPen(wxColour(255, 0, 0), 2, wxSOLID)); // red
auto x_end = Pointf(origin_px.x + axes_len, origin_px.y);
dc.DrawLine(wxPoint(origin_px.x, origin_px.y), wxPoint(x_end.x, x_end.y));
for (auto angle : { -arrow_angle, arrow_angle }){
@ -118,7 +118,7 @@ void Bed_2D::repaint()
dc.DrawLine(wxPoint(x_end.x, x_end.y), wxPoint(end.x, end.y));
}
dc.SetPen(*new wxPen(*new wxColour(0, 255, 0), 2, wxSOLID)); // green
dc.SetPen(wxPen(wxColour(0, 255, 0), 2, wxSOLID)); // green
auto y_end = Pointf(origin_px.x, origin_px.y - axes_len);
dc.DrawLine(wxPoint(origin_px.x, origin_px.y), wxPoint(y_end.x, y_end.y));
for (auto angle : { -arrow_angle, arrow_angle }) {
@ -129,19 +129,23 @@ void Bed_2D::repaint()
}
// draw origin
dc.SetPen(*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID));
dc.SetBrush(*new wxBrush(*new wxColour(0, 0, 0), wxSOLID));
dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxSOLID));
dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxSOLID));
dc.DrawCircle(origin_px.x, origin_px.y, 3);
dc.SetTextForeground(*new wxColour(0, 0, 0));
dc.SetFont(*new wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
dc.DrawText("(0,0)", origin_px.x + 1, origin_px.y + 2);
static const auto origin_label = wxString("(0,0)");
dc.SetTextForeground(wxColour(0, 0, 0));
dc.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
auto extent = dc.GetTextExtent(origin_label);
const auto origin_label_x = origin_px.x <= cw / 2 ? origin_px.x + 1 : origin_px.x - 1 - extent.GetWidth();
const auto origin_label_y = origin_px.y <= ch / 2 ? origin_px.y + 1 : origin_px.y - 1 - extent.GetHeight();
dc.DrawText(origin_label, origin_label_x, origin_label_y);
// draw current position
if (m_pos!= Pointf(0, 0)) {
auto pos_px = to_pixels(m_pos);
dc.SetPen(*new wxPen(*new wxColour(200, 0, 0), 2, wxSOLID));
dc.SetBrush(*new wxBrush(*new wxColour(200, 0, 0), wxTRANSPARENT));
dc.SetPen(wxPen(wxColour(200, 0, 0), 2, wxSOLID));
dc.SetBrush(wxBrush(wxColour(200, 0, 0), wxTRANSPARENT));
dc.DrawCircle(pos_px.x, pos_px.y, 5);
dc.DrawLine(pos_px.x - 15, pos_px.y, pos_px.x + 15, pos_px.y);

View File

@ -0,0 +1,125 @@
#include "AboutDialog.hpp"
#include "../../libslic3r/Utils.hpp"
namespace Slic3r {
namespace GUI {
AboutDialogLogo::AboutDialogLogo(wxWindow* parent)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
{
this->SetBackgroundColour(*wxWHITE);
this->logo = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG);
this->SetMinSize(this->logo.GetSize());
this->Bind(wxEVT_PAINT, &AboutDialogLogo::onRepaint, this);
}
void AboutDialogLogo::onRepaint(wxEvent &event)
{
wxPaintDC dc(this);
dc.SetBackgroundMode(wxTRANSPARENT);
wxSize size = this->GetSize();
int logo_w = this->logo.GetWidth();
int logo_h = this->logo.GetHeight();
dc.DrawBitmap(this->logo, (size.GetWidth() - logo_w)/2, (size.GetHeight() - logo_h)/2, true);
event.Skip();
}
AboutDialog::AboutDialog()
: wxDialog(NULL, wxID_ANY, _(L("About Slic3r")), wxDefaultPosition, wxSize(600, 340), wxCAPTION)
{
this->SetBackgroundColour(*wxWHITE);
wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL);
this->SetSizer(hsizer);
// logo
AboutDialogLogo* logo = new AboutDialogLogo(this);
hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 30);
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
hsizer->Add(vsizer, 1, wxEXPAND, 0);
// title
{
wxStaticText* title = new wxStaticText(this, wxID_ANY, "Slic3r Prusa Edition", wxDefaultPosition, wxDefaultSize);
wxFont title_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
title_font.SetWeight(wxFONTWEIGHT_BOLD);
title_font.SetFamily(wxFONTFAMILY_ROMAN);
title_font.SetPointSize(24);
title->SetFont(title_font);
vsizer->Add(title, 0, wxALIGN_LEFT | wxTOP, 30);
}
// version
{
auto version_string = _(L("Version ")) + std::string(SLIC3R_VERSION);
wxStaticText* version = new wxStaticText(this, wxID_ANY, version_string.c_str(), wxDefaultPosition, wxDefaultSize);
wxFont version_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
#ifdef __WXMSW__
version_font.SetPointSize(9);
#else
version_font.SetPointSize(11);
#endif
version->SetFont(version_font);
vsizer->Add(version, 0, wxALIGN_LEFT | wxBOTTOM, 10);
}
// text
wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER);
{
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
#ifdef __WXMSW__
int size[] = {8,8,8,8,8,8,8};
#else
int size[] = {11,11,11,11,11,11,11};
#endif
html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
html->SetBorders(2);
const char* text =
"<html>"
"<body bgcolor=\"#ffffff\" link=\"#808080\">"
"<font color=\"#808080\">"
"Copyright &copy; 2016-2018 Prusa Research. <br />"
"Copyright &copy; 2011-2017 Alessandro Ranellucci. <br />"
"<a href=\"http://slic3r.org/\">Slic3r</a> is licensed under the "
"<a href=\"http://www.gnu.org/licenses/agpl-3.0.html\">GNU Affero General Public License, version 3</a>."
"<br /><br /><br />"
"Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others. "
"Manual by Gary Hodgson. Inspired by the RepRap community. <br />"
"Slic3r logo designed by Corey Daniels, <a href=\"http://www.famfamfam.com/lab/icons/silk/\">Silk Icon Set</a> designed by Mark James. "
"</font>"
"</body>"
"</html>";
html->SetPage(text);
vsizer->Add(html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 20);
html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this);
}
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCLOSE);
this->SetEscapeId(wxID_CLOSE);
this->Bind(wxEVT_BUTTON, &AboutDialog::onCloseDialog, this, wxID_CLOSE);
vsizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
this->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this);
logo->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this);
html->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this);
}
void AboutDialog::onLinkClicked(wxHtmlLinkEvent &event)
{
wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref());
event.Skip(false);
}
void AboutDialog::onCloseDialog(wxEvent &)
{
this->EndModal(wxID_CLOSE);
this->Close();
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,36 @@
#ifndef slic3r_GUI_AboutDialog_hpp_
#define slic3r_GUI_AboutDialog_hpp_
#include "GUI.hpp"
#include <wx/wx.h>
#include <wx/intl.h>
#include <wx/html/htmlwin.h>
namespace Slic3r {
namespace GUI {
class AboutDialogLogo : public wxPanel
{
public:
AboutDialogLogo(wxWindow* parent);
private:
wxBitmap logo;
void onRepaint(wxEvent &event);
};
class AboutDialog : public wxDialog
{
public:
AboutDialog();
private:
void onLinkClicked(wxHtmlLinkEvent &event);
void onCloseDialog(wxEvent &);
};
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -1,5 +1,3 @@
#include <GL/glew.h>
#include "../../libslic3r/libslic3r.h"
#include "../../libslic3r/Utils.hpp"
#include "AppConfig.hpp"
@ -9,15 +7,21 @@
#include <string.h>
#include <utility>
#include <assert.h>
#include <vector>
#include <stdexcept>
#include <boost/filesystem.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/algorithm/string/predicate.hpp>
namespace Slic3r {
static const std::string VENDOR_PREFIX = "vendor:";
static const std::string MODEL_PREFIX = "model:";
void AppConfig::reset()
{
m_storage.clear();
@ -42,9 +46,15 @@ void AppConfig::set_defaults()
set("no_defaults", "1");
if (get("show_incompatible_presets").empty())
set("show_incompatible_presets", "0");
// Version check is enabled by default in the config, but it is not implemented yet.
if (get("version_check").empty())
set("version_check", "1");
// TODO: proper URL
if (get("version_check_url").empty())
set("version_check_url", "https://gist.githubusercontent.com/vojtechkral/4d8fd4a3b8699a01ec892c264178461c/raw/2f05a64db19e45a7f8fe2cedeff555d544af679b/slic3rPE.version");
if (get("preset_update").empty())
set("preset_update", "1");
// Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers.
// https://github.com/prusa3d/Slic3r/issues/233
if (get("use_legacy_opengl").empty())
@ -67,6 +77,19 @@ void AppConfig::load()
if (! data.empty())
// If there is a non-empty data, then it must be a top-level (without a section) config entry.
m_storage[""][section.first] = data;
} else if (boost::starts_with(section.first, VENDOR_PREFIX)) {
// This is a vendor section listing enabled model / variants
const auto vendor_name = section.first.substr(VENDOR_PREFIX.size());
auto &vendor = m_vendors[vendor_name];
for (const auto &kvp : section.second) {
if (! boost::starts_with(kvp.first, MODEL_PREFIX)) { continue; }
const auto model_name = kvp.first.substr(MODEL_PREFIX.size());
std::vector<std::string> variants;
if (! unescape_strings_cstyle(kvp.second.data(), variants)) { continue; }
for (const auto &variant : variants) {
vendor[model_name].insert(variant);
}
}
} else {
// This must be a section name. Read the entries of a section.
std::map<std::string, std::string> &storage = m_storage[section.first];
@ -75,6 +98,10 @@ void AppConfig::load()
}
}
// Figure out if datadir has legacy presets
auto ini_ver = Semver::parse(get("version"));
m_legacy_datadir = ini_ver ? *ini_ver < Semver(1, 40, 0) : true;
// Override missing or keys with their defaults.
this->set_defaults();
m_dirty = false;
@ -96,10 +123,57 @@ void AppConfig::save()
for (const std::pair<std::string, std::string> &kvp : category.second)
c << kvp.first << " = " << kvp.second << std::endl;
}
// Write vendor sections
for (const auto &vendor : m_vendors) {
size_t size_sum = 0;
for (const auto &model : vendor.second) { size_sum += model.second.size(); }
if (size_sum == 0) { continue; }
c << std::endl << "[" << VENDOR_PREFIX << vendor.first << "]" << std::endl;
for (const auto &model : vendor.second) {
if (model.second.size() == 0) { continue; }
const std::vector<std::string> variants(model.second.begin(), model.second.end());
const auto escaped = escape_strings_cstyle(variants);
c << MODEL_PREFIX << model.first << " = " << escaped << std::endl;
}
}
c.close();
m_dirty = false;
}
bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const
{
const auto it_v = m_vendors.find(vendor);
if (it_v == m_vendors.end()) { return false; }
const auto it_m = it_v->second.find(model);
return it_m == it_v->second.end() ? false : it_m->second.find(variant) != it_m->second.end();
}
void AppConfig::set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable)
{
if (enable) {
if (get_variant(vendor, model, variant)) { return; }
m_vendors[vendor][model].insert(variant);
} else {
auto it_v = m_vendors.find(vendor);
if (it_v == m_vendors.end()) { return; }
auto it_m = it_v->second.find(model);
if (it_m == it_v->second.end()) { return; }
auto it_var = it_m->second.find(variant);
if (it_var == it_m->second.end()) { return; }
it_m->second.erase(it_var);
}
// If we got here, there was an update
m_dirty = true;
}
void AppConfig::set_vendors(const AppConfig &from)
{
m_vendors = from.m_vendors;
m_dirty = true;
}
std::string AppConfig::get_last_dir() const
{
const auto it = m_storage.find("recent");

View File

@ -1,15 +1,19 @@
#ifndef slic3r_AppConfig_hpp_
#define slic3r_AppConfig_hpp_
#include <set>
#include <map>
#include <string>
#include "libslic3r/Config.hpp"
#include "slic3r/Utils/Semver.hpp"
namespace Slic3r {
class AppConfig
{
public:
AppConfig() : m_dirty(false) { this->reset(); }
AppConfig() : m_dirty(false), m_legacy_datadir(false) { this->reset(); }
// Clear and reset to defaults.
void reset();
@ -65,6 +69,14 @@ public:
void clear_section(const std::string &section)
{ m_storage[section].clear(); }
typedef std::map<std::string, std::map<std::string, std::set<std::string>>> VendorMap;
bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const;
void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable);
void set_vendors(const AppConfig &from);
void set_vendors(const VendorMap &vendors) { m_vendors = vendors; m_dirty = true; }
void set_vendors(VendorMap &&vendors) { m_vendors = std::move(vendors); m_dirty = true; }
const VendorMap& vendors() const { return m_vendors; }
// return recent/skein_directory or recent/config_directory or empty string.
std::string get_last_dir() const;
void update_config_dir(const std::string &dir);
@ -80,6 +92,8 @@ public:
// Get the default config path from Slic3r::data_dir().
static std::string config_path();
bool legacy_datadir() const { return m_legacy_datadir; }
// Does the config file exist?
static bool exists();
@ -87,8 +101,12 @@ public:
private:
// Map of section, name -> value
std::map<std::string, std::map<std::string, std::string>> m_storage;
// Map of enabled vendors / models / variants
VendorMap m_vendors;
// Has any value been modified since the config.ini has been last saved or loaded?
bool m_dirty;
// Whether the existing version is before system profiles & configuration updating
bool m_legacy_datadir;
};
}; // namespace Slic3r

View File

@ -0,0 +1,137 @@
#include "ConfigSnapshotDialog.hpp"
#include "../Config/Snapshot.hpp"
#include "../Utils/Time.hpp"
#include "../../libslic3r/Utils.hpp"
namespace Slic3r {
namespace GUI {
static std::string format_reason(const Config::Snapshot::Reason reason)
{
switch (reason) {
case Config::Snapshot::SNAPSHOT_UPGRADE:
return std::string(_(L("Upgrade")));
case Config::Snapshot::SNAPSHOT_DOWNGRADE:
return std::string(_(L("Downgrade")));
case Config::Snapshot::SNAPSHOT_BEFORE_ROLLBACK:
return std::string(_(L("Before roll back")));
case Config::Snapshot::SNAPSHOT_USER:
return std::string(_(L("User")));
case Config::Snapshot::SNAPSHOT_UNKNOWN:
default:
return std::string(_(L("Unknown")));
}
}
static std::string generate_html_row(const Config::Snapshot &snapshot, bool row_even, bool snapshot_active)
{
// Start by declaring a row with an alternating background color.
std::string text = "<tr bgcolor=\"";
text += snapshot_active ? "#B3FFCB" : (row_even ? "#FFFFFF" : "#D5D5D5");
text += "\">";
text += "<td>";
// Format the row header.
text += std::string("<font size=\"5\"><b>") + (snapshot_active ? _(L("Active: ")) : "") +
Utils::format_local_date_time(snapshot.time_captured) + ": " + format_reason(snapshot.reason);
if (! snapshot.comment.empty())
text += " (" + snapshot.comment + ")";
text += "</b></font><br>";
// End of row header.
// text += _(L("ID:")) + " " + snapshot.id + "<br>";
// text += _(L("time captured:")) + " " + Utils::format_local_date_time(snapshot.time_captured) + "<br>";
text += _(L("slic3r version")) + ": " + snapshot.slic3r_version_captured.to_string() + "<br>";
// text += "reason: " + snapshot.reason + "<br>";
text += _(L("print")) + ": " + snapshot.print + "<br>";
text += _(L("filaments")) + ": " + snapshot.filaments.front() + "<br>";
text += _(L("printer")) + ": " + snapshot.printer + "<br>";
for (const Config::Snapshot::VendorConfig &vc : snapshot.vendor_configs) {
text += _(L("vendor")) + ": " + vc.name + ", ver: " + vc.version.to_string() + ", min slic3r ver: " + vc.min_slic3r_version.to_string();
if (vc.max_slic3r_version != Semver::inf())
text += ", max slic3r ver: " + vc.max_slic3r_version.to_string();
text += "<br>";
for (const std::pair<std::string, std::set<std::string>> &model : vc.models_variants_installed) {
text += _(L("model")) + ": " + model.first + ", " + _(L("variants")) + ": ";
for (const std::string &variant : model.second) {
if (&variant != &*model.second.begin())
text += ", ";
text += variant;
}
text += "<br>";
}
}
if (! snapshot_active)
text += "<p align=\"right\"><a href=\"" + snapshot.id + "\">" + _(L("Activate")) + "</a></p>";
text += "</td>";
text += "</tr>";
return text;
}
static std::string generate_html_page(const Config::SnapshotDB &snapshot_db, const std::string &on_snapshot)
{
std::string text =
"<html>"
"<body bgcolor=\"#ffffff\" cellspacing=\"2\" cellpadding=\"0\" border=\"0\" link=\"#800000\">"
"<font color=\"#000000\">";
text += "<table style=\"width:100%\">";
for (size_t i_row = 0; i_row < snapshot_db.snapshots().size(); ++ i_row) {
const Config::Snapshot &snapshot = snapshot_db.snapshots()[snapshot_db.snapshots().size() - i_row - 1];
text += generate_html_row(snapshot, i_row & 1, snapshot.id == on_snapshot);
}
text +=
"</table>"
"</font>"
"</body>"
"</html>";
return text;
}
ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db, const std::string &on_snapshot)
: wxDialog(NULL, wxID_ANY, _(L("Configuration Snapshots")), wxDefaultPosition, wxSize(600, 500), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
{
this->SetBackgroundColour(*wxWHITE);
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
this->SetSizer(vsizer);
// text
wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
{
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
#ifdef __WXMSW__
int size[] = {8,8,8,8,11,11,11};
#else
int size[] = {11,11,11,11,14,14,14};
#endif
html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
html->SetBorders(2);
std::string text = generate_html_page(snapshot_db, on_snapshot);
html->SetPage(text.c_str());
vsizer->Add(html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 0);
html->Bind(wxEVT_HTML_LINK_CLICKED, &ConfigSnapshotDialog::onLinkClicked, this);
}
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCLOSE);
this->SetEscapeId(wxID_CLOSE);
this->Bind(wxEVT_BUTTON, &ConfigSnapshotDialog::onCloseDialog, this, wxID_CLOSE);
vsizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
}
void ConfigSnapshotDialog::onLinkClicked(wxHtmlLinkEvent &event)
{
m_snapshot_to_activate = event.GetLinkInfo().GetHref();
this->EndModal(wxID_CLOSE);
this->Close();
}
void ConfigSnapshotDialog::onCloseDialog(wxEvent &)
{
this->EndModal(wxID_CLOSE);
this->Close();
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,34 @@
#ifndef slic3r_GUI_ConfigSnapshotDialog_hpp_
#define slic3r_GUI_ConfigSnapshotDialog_hpp_
#include "GUI.hpp"
#include <wx/wx.h>
#include <wx/intl.h>
#include <wx/html/htmlwin.h>
namespace Slic3r {
namespace GUI {
namespace Config {
class SnapshotDB;
}
class ConfigSnapshotDialog : public wxDialog
{
public:
ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db, const std::string &id);
const std::string& snapshot_to_activate() const { return m_snapshot_to_activate; }
private:
void onLinkClicked(wxHtmlLinkEvent &event);
void onCloseDialog(wxEvent &);
// If set, it contains a snapshot ID to be restored after the dialog closes.
std::string m_snapshot_to_activate;
};
} // namespace GUI
} // namespace Slic3r
#endif /* slic3r_GUI_ConfigSnapshotDialog_hpp_ */

View File

@ -0,0 +1,844 @@
#include "ConfigWizard_private.hpp"
#include <algorithm>
#include <utility>
#include <unordered_map>
#include <wx/settings.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/dcclient.h>
#include <wx/statbmp.h>
#include <wx/checkbox.h>
#include <wx/statline.h>
#include "libslic3r/Utils.hpp"
#include "PresetBundle.hpp"
#include "GUI.hpp"
#include "slic3r/Utils/PresetUpdater.hpp"
namespace Slic3r {
namespace GUI {
// Printer model picker GUI control
struct PrinterPickerEvent : public wxEvent
{
std::string vendor_id;
std::string model_id;
std::string variant_name;
bool enable;
PrinterPickerEvent(wxEventType eventType, int winid, std::string vendor_id, std::string model_id, std::string variant_name, bool enable) :
wxEvent(winid, eventType),
vendor_id(std::move(vendor_id)),
model_id(std::move(model_id)),
variant_name(std::move(variant_name)),
enable(enable)
{}
virtual wxEvent *Clone() const
{
return new PrinterPickerEvent(*this);
}
};
wxDEFINE_EVENT(EVT_PRINTER_PICK, PrinterPickerEvent);
PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, const AppConfig &appconfig_vendors) :
wxPanel(parent),
vendor_id(vendor.id),
variants_checked(0)
{
const auto &models = vendor.models;
auto *sizer = new wxBoxSizer(wxVERTICAL);
auto *printer_grid = new wxFlexGridSizer(models.size(), 0, 20);
printer_grid->SetFlexibleDirection(wxVERTICAL);
sizer->Add(printer_grid);
auto namefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
namefont.SetWeight(wxFONTWEIGHT_BOLD);
for (const auto &model : models) {
auto *panel = new wxPanel(this);
auto *col_sizer = new wxBoxSizer(wxVERTICAL);
panel->SetSizer(col_sizer);
auto *title = new wxStaticText(panel, wxID_ANY, model.name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
title->SetFont(namefont);
col_sizer->Add(title, 0, wxBOTTOM, 3);
auto bitmap_file = wxString::Format("printers/%s_%s.png", vendor.id, model.id);
wxBitmap bitmap(GUI::from_u8(Slic3r::var(bitmap_file.ToStdString())), wxBITMAP_TYPE_PNG);
auto *bitmap_widget = new wxStaticBitmap(panel, wxID_ANY, bitmap);
col_sizer->Add(bitmap_widget, 0, wxBOTTOM, 3);
col_sizer->AddSpacer(20);
const auto model_id = model.id;
for (const auto &variant : model.variants) {
const auto label = wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle")));
auto *cbox = new Checkbox(panel, label, model_id, variant.name);
const size_t idx = cboxes.size();
cboxes.push_back(cbox);
bool enabled = appconfig_vendors.get_variant("PrusaResearch", model_id, variant.name);
variants_checked += enabled;
cbox->SetValue(enabled);
col_sizer->Add(cbox, 0, wxBOTTOM, 3);
cbox->Bind(wxEVT_CHECKBOX, [this, idx](wxCommandEvent &event) {
if (idx >= this->cboxes.size()) { return; }
this->on_checkbox(this->cboxes[idx], event.IsChecked());
});
}
printer_grid->Add(panel);
}
auto *all_none_sizer = new wxBoxSizer(wxHORIZONTAL);
auto *sel_all = new wxButton(this, wxID_ANY, _(L("Select all")));
auto *sel_none = new wxButton(this, wxID_ANY, _(L("Select none")));
sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(true); });
sel_none->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(false); });
all_none_sizer->AddStretchSpacer();
all_none_sizer->Add(sel_all);
all_none_sizer->Add(sel_none);
sizer->AddStretchSpacer();
sizer->Add(all_none_sizer, 0, wxEXPAND);
SetSizer(sizer);
}
void PrinterPicker::select_all(bool select)
{
for (const auto &cb : cboxes) {
if (cb->GetValue() != select) {
cb->SetValue(select);
on_checkbox(cb, select);
}
}
}
void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked)
{
variants_checked += checked ? 1 : -1;
PrinterPickerEvent evt(EVT_PRINTER_PICK, GetId(), vendor_id, cbox->model, cbox->variant, checked);
AddPendingEvent(evt);
}
// Wizard page base
ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname) :
wxPanel(parent),
parent(parent),
shortname(std::move(shortname)),
p_prev(nullptr),
p_next(nullptr)
{
auto *sizer = new wxBoxSizer(wxVERTICAL);
auto *text = new wxStaticText(this, wxID_ANY, std::move(title), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
auto font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
font.SetWeight(wxFONTWEIGHT_BOLD);
font.SetPointSize(14);
text->SetFont(font);
sizer->Add(text, 0, wxALIGN_LEFT, 0);
sizer->AddSpacer(10);
content = new wxBoxSizer(wxVERTICAL);
sizer->Add(content, 1);
SetSizer(sizer);
this->Hide();
Bind(wxEVT_SIZE, [this](wxSizeEvent &event) {
this->Layout();
event.Skip();
});
}
ConfigWizardPage::~ConfigWizardPage() {}
ConfigWizardPage* ConfigWizardPage::chain(ConfigWizardPage *page)
{
if (p_next != nullptr) { p_next->p_prev = nullptr; }
p_next = page;
if (page != nullptr) {
if (page->p_prev != nullptr) { page->p_prev->p_next = nullptr; }
page->p_prev = this;
}
return page;
}
void ConfigWizardPage::append_text(wxString text)
{
auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
widget->Wrap(CONTENT_WIDTH);
widget->SetMinSize(wxSize(CONTENT_WIDTH, -1));
append(widget);
}
void ConfigWizardPage::append_spacer(int space)
{
content->AddSpacer(space);
}
bool ConfigWizardPage::Show(bool show)
{
if (extra_buttons() != nullptr) { extra_buttons()->Show(show); }
return wxPanel::Show(show);
}
void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable); }
// Wizard pages
PageWelcome::PageWelcome(ConfigWizard *parent) :
ConfigWizardPage(parent, wxString::Format(_(L("Welcome to the Slic3r %s")), ConfigWizard::name()), _(L("Welcome"))),
printer_picker(nullptr),
others_buttons(new wxPanel(parent)),
cbox_reset(new wxCheckBox(this, wxID_ANY, _(L("Remove user profiles - install from scratch (a snapshot will be taken beforehand)"))))
{
if (wizard_p()->flag_startup && wizard_p()->flag_empty_datadir) {
wxString::Format(_(L("Run %s")), ConfigWizard::name());
append_text(wxString::Format(
_(L("Hello, welcome to Slic3r Prusa Edition! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")),
ConfigWizard::name())
);
} else {
append(cbox_reset);
}
const auto &vendors = wizard_p()->vendors;
const auto vendor_prusa = vendors.find("PrusaResearch");
if (vendor_prusa != vendors.cend()) {
AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors;
printer_picker = new PrinterPicker(this, vendor_prusa->second, appconfig_vendors);
printer_picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) {
appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable);
this->on_variant_checked();
});
append(printer_picker);
}
const size_t num_other_vendors = vendors.size() - (vendor_prusa != vendors.cend());
auto *sizer = new wxBoxSizer(wxHORIZONTAL);
auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors")));
other_vendors->Enable(num_other_vendors > 0);
auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup")));
sizer->Add(other_vendors);
sizer->AddSpacer(BTN_SPACING);
sizer->Add(custom_setup);
other_vendors->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_other_vendors(); });
custom_setup->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_custom_setup(); });
others_buttons->SetSizer(sizer);
}
void PageWelcome::on_page_set()
{
chain(wizard_p()->page_update);
on_variant_checked();
}
void PageWelcome::on_variant_checked()
{
enable_next(printer_picker != nullptr ? printer_picker->variants_checked > 0 : false);
}
PageUpdate::PageUpdate(ConfigWizard *parent) :
ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))),
version_check(true),
preset_update(true)
{
const AppConfig *app_config = GUI::get_app_config();
auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
boldfont.SetWeight(wxFONTWEIGHT_BOLD);
auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for application updates")));
box_slic3r->SetValue(app_config->get("version_check") == "1");
append(box_slic3r);
append_text(_(L("If enabled, Slic3r checks for new versions of Slic3r PE online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.")));
append_spacer(VERTICAL_SPACING);
auto *box_presets = new wxCheckBox(this, wxID_ANY, _(L("Update built-in Presets automatically")));
box_presets->SetValue(app_config->get("preset_update") == "1");
append(box_presets);
append_text(_(L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup.")));
const auto text_bold = _(L("Updates are never applied without user's consent and never overwrite user's customized settings."));
auto *label_bold = new wxStaticText(this, wxID_ANY, text_bold);
label_bold->SetFont(boldfont);
label_bold->Wrap(CONTENT_WIDTH);
append(label_bold);
append_text(_(L("Additionally a backup snapshot of the whole configuration is created before an update is applied.")));
box_slic3r->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->version_check = event.IsChecked(); });
box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); });
}
PageVendors::PageVendors(ConfigWizard *parent) :
ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors")))
{
append_text(_(L("Pick another vendor supported by Slic3r PE:")));
auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
boldfont.SetWeight(wxFONTWEIGHT_BOLD);
AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors;
wxArrayString choices_vendors;
for (const auto vendor_pair : wizard_p()->vendors) {
const auto &vendor = vendor_pair.second;
if (vendor.id == "PrusaResearch") { continue; }
auto *picker = new PrinterPicker(this, vendor, appconfig_vendors);
picker->Hide();
pickers.push_back(picker);
choices_vendors.Add(vendor.name);
picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) {
appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable);
this->on_variant_checked();
});
}
auto *vendor_picker = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices_vendors);
if (choices_vendors.GetCount() > 0) {
vendor_picker->SetSelection(0);
on_vendor_pick(0);
}
vendor_picker->Bind(wxEVT_CHOICE, [this](wxCommandEvent &evt) {
this->on_vendor_pick(evt.GetInt());
});
append(vendor_picker);
for (PrinterPicker *picker : pickers) { this->append(picker); }
}
void PageVendors::on_page_set()
{
on_variant_checked();
}
void PageVendors::on_vendor_pick(size_t i)
{
for (PrinterPicker *picker : pickers) { picker->Hide(); }
if (i < pickers.size()) {
pickers[i]->Show();
wizard_p()->layout_fit();
}
}
void PageVendors::on_variant_checked()
{
size_t variants_checked = 0;
for (const PrinterPicker *picker : pickers) { variants_checked += picker->variants_checked; }
enable_next(variants_checked > 0);
}
PageFirmware::PageFirmware(ConfigWizard *parent) :
ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))),
gcode_opt(print_config_def.options["gcode_flavor"]),
gcode_picker(nullptr)
{
append_text(_(L("Choose the type of firmware used by your printer.")));
append_text(gcode_opt.tooltip);
wxArrayString choices;
choices.Alloc(gcode_opt.enum_labels.size());
for (const auto &label : gcode_opt.enum_labels) {
choices.Add(label);
}
gcode_picker = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
const auto &enum_values = gcode_opt.enum_values;
auto needle = enum_values.cend();
if (gcode_opt.default_value != nullptr) {
needle = std::find(enum_values.cbegin(), enum_values.cend(), gcode_opt.default_value->serialize());
}
if (needle != enum_values.cend()) {
gcode_picker->SetSelection(needle - enum_values.cbegin());
} else {
gcode_picker->SetSelection(0);
}
append(gcode_picker);
}
void PageFirmware::apply_custom_config(DynamicPrintConfig &config)
{
ConfigOptionEnum<GCodeFlavor> opt;
auto sel = gcode_picker->GetSelection();
if (sel != wxNOT_FOUND && opt.deserialize(gcode_picker->GetString(sel).ToStdString())) {
config.set_key_value("gcode_flavor", &opt);
}
}
PageBedShape::PageBedShape(ConfigWizard *parent) :
ConfigWizardPage(parent, _(L("Bed Shape and Size")), _(L("Bed Shape"))),
shape_panel(new BedShapePanel(this))
{
append_text(_(L("Set the shape of your printer's bed.")));
shape_panel->build_panel(wizard_p()->custom_config->option<ConfigOptionPoints>("bed_shape"));
append(shape_panel);
}
void PageBedShape::apply_custom_config(DynamicPrintConfig &config)
{
const auto points(shape_panel->GetValue());
auto *opt = new ConfigOptionPoints(points);
config.set_key_value("bed_shape", opt);
}
PageDiameters::PageDiameters(ConfigWizard *parent) :
ConfigWizardPage(parent, _(L("Filament and Nozzle Diameters")), _(L("Print Diameters"))),
spin_nozzle(new wxSpinCtrlDouble(this, wxID_ANY)),
spin_filam(new wxSpinCtrlDouble(this, wxID_ANY))
{
spin_nozzle->SetDigits(2);
spin_nozzle->SetIncrement(0.1);
const auto &def_nozzle = print_config_def.options["nozzle_diameter"];
auto *default_nozzle = dynamic_cast<const ConfigOptionFloats*>(def_nozzle.default_value);
spin_nozzle->SetValue(default_nozzle != nullptr && default_nozzle->size() > 0 ? default_nozzle->get_at(0) : 0.5);
spin_filam->SetDigits(2);
spin_filam->SetIncrement(0.25);
const auto &def_filam = print_config_def.options["filament_diameter"];
auto *default_filam = dynamic_cast<const ConfigOptionFloats*>(def_filam.default_value);
spin_filam->SetValue(default_filam != nullptr && default_filam->size() > 0 ? default_filam->get_at(0) : 3.0);
append_text(_(L("Enter the diameter of your printer's hot end nozzle.")));
auto *sizer_nozzle = new wxFlexGridSizer(3, 5, 5);
auto *text_nozzle = new wxStaticText(this, wxID_ANY, _(L("Nozzle Diameter:")));
auto *unit_nozzle = new wxStaticText(this, wxID_ANY, _(L("mm")));
sizer_nozzle->AddGrowableCol(0, 1);
sizer_nozzle->Add(text_nozzle, 0, wxALIGN_CENTRE_VERTICAL);
sizer_nozzle->Add(spin_nozzle);
sizer_nozzle->Add(unit_nozzle, 0, wxALIGN_CENTRE_VERTICAL);
append(sizer_nozzle);
append_spacer(VERTICAL_SPACING);
append_text(_(L("Enter the diameter of your filament.")));
append_text(_(L("Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.")));
auto *sizer_filam = new wxFlexGridSizer(3, 5, 5);
auto *text_filam = new wxStaticText(this, wxID_ANY, _(L("Filament Diameter:")));
auto *unit_filam = new wxStaticText(this, wxID_ANY, _(L("mm")));
sizer_filam->AddGrowableCol(0, 1);
sizer_filam->Add(text_filam, 0, wxALIGN_CENTRE_VERTICAL);
sizer_filam->Add(spin_filam);
sizer_filam->Add(unit_filam, 0, wxALIGN_CENTRE_VERTICAL);
append(sizer_filam);
}
void PageDiameters::apply_custom_config(DynamicPrintConfig &config)
{
auto *opt_nozzle = new ConfigOptionFloats(1, spin_nozzle->GetValue());
config.set_key_value("nozzle_diameter", opt_nozzle);
auto *opt_filam = new ConfigOptionFloats(1, spin_filam->GetValue());
config.set_key_value("filament_diameter", opt_filam);
}
PageTemperatures::PageTemperatures(ConfigWizard *parent) :
ConfigWizardPage(parent, _(L("Extruder and Bed Temperatures")), _(L("Temperatures"))),
spin_extr(new wxSpinCtrlDouble(this, wxID_ANY)),
spin_bed(new wxSpinCtrlDouble(this, wxID_ANY))
{
spin_extr->SetIncrement(5.0);
const auto &def_extr = print_config_def.options["temperature"];
spin_extr->SetRange(def_extr.min, def_extr.max);
auto *default_extr = dynamic_cast<const ConfigOptionInts*>(def_extr.default_value);
spin_extr->SetValue(default_extr != nullptr && default_extr->size() > 0 ? default_extr->get_at(0) : 200);
spin_bed->SetIncrement(5.0);
const auto &def_bed = print_config_def.options["bed_temperature"];
spin_bed->SetRange(def_bed.min, def_bed.max);
auto *default_bed = dynamic_cast<const ConfigOptionInts*>(def_bed.default_value);
spin_bed->SetValue(default_bed != nullptr && default_bed->size() > 0 ? default_bed->get_at(0) : 0);
append_text(_(L("Enter the temperature needed for extruding your filament.")));
append_text(_(L("A rule of thumb is 160 to 230 °C for PLA, and 215 to 250 °C for ABS.")));
auto *sizer_extr = new wxFlexGridSizer(3, 5, 5);
auto *text_extr = new wxStaticText(this, wxID_ANY, _(L("Extrusion Temperature:")));
auto *unit_extr = new wxStaticText(this, wxID_ANY, _(L("°C")));
sizer_extr->AddGrowableCol(0, 1);
sizer_extr->Add(text_extr, 0, wxALIGN_CENTRE_VERTICAL);
sizer_extr->Add(spin_extr);
sizer_extr->Add(unit_extr, 0, wxALIGN_CENTRE_VERTICAL);
append(sizer_extr);
append_spacer(VERTICAL_SPACING);
append_text(_(L("Enter the bed temperature needed for getting your filament to stick to your heated bed.")));
append_text(_(L("A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed.")));
auto *sizer_bed = new wxFlexGridSizer(3, 5, 5);
auto *text_bed = new wxStaticText(this, wxID_ANY, _(L("Bed Temperature:")));
auto *unit_bed = new wxStaticText(this, wxID_ANY, _(L("°C")));
sizer_bed->AddGrowableCol(0, 1);
sizer_bed->Add(text_bed, 0, wxALIGN_CENTRE_VERTICAL);
sizer_bed->Add(spin_bed);
sizer_bed->Add(unit_bed, 0, wxALIGN_CENTRE_VERTICAL);
append(sizer_bed);
}
void PageTemperatures::apply_custom_config(DynamicPrintConfig &config)
{
auto *opt_extr = new ConfigOptionInts(1, spin_extr->GetValue());
config.set_key_value("temperature", opt_extr);
auto *opt_extr1st = new ConfigOptionInts(1, spin_extr->GetValue());
config.set_key_value("first_layer_temperature", opt_extr1st);
auto *opt_bed = new ConfigOptionInts(1, spin_bed->GetValue());
config.set_key_value("bed_temperature", opt_bed);
auto *opt_bed1st = new ConfigOptionInts(1, spin_bed->GetValue());
config.set_key_value("first_layer_bed_temperature", opt_bed1st);
}
// Index
ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) :
wxPanel(parent),
bg(GUI::from_u8(Slic3r::var("Slic3r_192px_transparent.png")), wxBITMAP_TYPE_PNG),
bullet_black(GUI::from_u8(Slic3r::var("bullet_black.png")), wxBITMAP_TYPE_PNG),
bullet_blue(GUI::from_u8(Slic3r::var("bullet_blue.png")), wxBITMAP_TYPE_PNG),
bullet_white(GUI::from_u8(Slic3r::var("bullet_white.png")), wxBITMAP_TYPE_PNG)
{
SetMinSize(bg.GetSize());
wxClientDC dc(this);
text_height = dc.GetCharHeight();
// Add logo bitmap.
// This could be done in on_paint() along with the index labels, but I've found it tricky
// to get the bitmap rendered well on all platforms with transparent background.
// In some cases it didn't work at all. And so wxStaticBitmap is used here instead,
// because it has all the platform quirks figured out.
auto *sizer = new wxBoxSizer(wxVERTICAL);
auto *logo = new wxStaticBitmap(this, wxID_ANY, bg);
sizer->AddStretchSpacer();
sizer->Add(logo);
SetSizer(sizer);
Bind(wxEVT_PAINT, &ConfigWizardIndex::on_paint, this);
}
void ConfigWizardIndex::load_items(ConfigWizardPage *firstpage)
{
items.clear();
item_active = items.cend();
for (auto *page = firstpage; page != nullptr; page = page->page_next()) {
items.emplace_back(page->shortname);
}
Refresh();
}
void ConfigWizardIndex::set_active(ConfigWizardPage *page)
{
item_active = std::find(items.cbegin(), items.cend(), page->shortname);
Refresh();
}
void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
{
enum {
MARGIN = 10,
SPACING = 5,
};
const auto size = GetClientSize();
if (size.GetHeight() == 0 || size.GetWidth() == 0) { return; }
wxPaintDC dc(this);
const auto bullet_w = bullet_black.GetSize().GetWidth();
const auto bullet_h = bullet_black.GetSize().GetHeight();
const int yoff_icon = bullet_h < text_height ? (text_height - bullet_h) / 2 : 0;
const int yoff_text = bullet_h > text_height ? (bullet_h - text_height) / 2 : 0;
const int yinc = std::max(bullet_h, text_height) + SPACING;
unsigned y = 0;
for (auto it = items.cbegin(); it != items.cend(); ++it) {
if (it < item_active) { dc.DrawBitmap(bullet_black, MARGIN, y + yoff_icon, false); }
if (it == item_active) { dc.DrawBitmap(bullet_blue, MARGIN, y + yoff_icon, false); }
if (it > item_active) { dc.DrawBitmap(bullet_white, MARGIN, y + yoff_icon, false); }
dc.DrawText(*it, MARGIN + bullet_w + SPACING, y + yoff_text);
y += yinc;
}
}
// priv
static const std::unordered_map<std::string, std::pair<std::string, std::string>> legacy_preset_map {{
{ "Original Prusa i3 MK2.ini", std::make_pair("MK2S", "0.4") },
{ "Original Prusa i3 MK2 MM Single Mode.ini", std::make_pair("MK2S", "0.4") },
{ "Original Prusa i3 MK2 MM Single Mode 0.6 nozzle.ini", std::make_pair("MK2S", "0.6") },
{ "Original Prusa i3 MK2 MultiMaterial.ini", std::make_pair("MK2S", "0.4") },
{ "Original Prusa i3 MK2 MultiMaterial 0.6 nozzle.ini", std::make_pair("MK2S", "0.6") },
{ "Original Prusa i3 MK2 0.25 nozzle.ini", std::make_pair("MK2S", "0.25") },
{ "Original Prusa i3 MK2 0.6 nozzle.ini", std::make_pair("MK2S", "0.6") },
{ "Original Prusa i3 MK3.ini", std::make_pair("MK3", "0.4") },
}};
void ConfigWizard::priv::load_vendors()
{
const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor";
const auto rsrc_vendor_dir = fs::path(resources_dir()) / "profiles";
// Load vendors from the "vendors" directory in datadir
for (fs::directory_iterator it(vendor_dir); it != fs::directory_iterator(); ++it) {
if (it->path().extension() == ".ini") {
auto vp = VendorProfile::from_ini(it->path());
vendors[vp.id] = std::move(vp);
}
}
// Additionally load up vendors from the application resources directory, but only those not seen in the datadir
for (fs::directory_iterator it(rsrc_vendor_dir); it != fs::directory_iterator(); ++it) {
if (it->path().extension() == ".ini") {
const auto id = it->path().stem().string();
if (vendors.find(id) == vendors.end()) {
auto vp = VendorProfile::from_ini(it->path());
vendors_rsrc[vp.id] = it->path().filename().string();
vendors[vp.id] = std::move(vp);
}
}
}
// Load up the set of vendors / models / variants the user has had enabled up till now
const AppConfig *app_config = GUI::get_app_config();
if (! app_config->legacy_datadir()) {
appconfig_vendors.set_vendors(*app_config);
} else {
// In case of legacy datadir, try to guess the preference based on the printer preset files that are present
const auto printer_dir = fs::path(Slic3r::data_dir()) / "printer";
for (fs::directory_iterator it(printer_dir); it != fs::directory_iterator(); ++it) {
auto needle = legacy_preset_map.find(it->path().filename().string());
if (needle == legacy_preset_map.end()) { continue; }
const auto &model = needle->second.first;
const auto &variant = needle->second.second;
appconfig_vendors.set_variant("PrusaResearch", model, variant, true);
}
}
}
void ConfigWizard::priv::index_refresh()
{
index->load_items(page_welcome);
}
void ConfigWizard::priv::add_page(ConfigWizardPage *page)
{
topsizer->Add(page, 0, wxEXPAND);
auto *extra_buttons = page->extra_buttons();
if (extra_buttons != nullptr) {
btnsizer->Prepend(extra_buttons, 0);
}
}
void ConfigWizard::priv::set_page(ConfigWizardPage *page)
{
if (page == nullptr) { return; }
if (page_current != nullptr) { page_current->Hide(); }
page_current = page;
enable_next(true);
page->on_page_set();
index->load_items(page_welcome);
index->set_active(page);
page->Show();
btn_prev->Enable(page->page_prev() != nullptr);
btn_next->Show(page->page_next() != nullptr);
btn_finish->Show(page->page_next() == nullptr);
layout_fit();
}
void ConfigWizard::priv::layout_fit()
{
q->Layout();
q->Fit();
}
void ConfigWizard::priv::enable_next(bool enable)
{
btn_next->Enable(enable);
btn_finish->Enable(enable);
}
void ConfigWizard::priv::on_other_vendors()
{
page_welcome
->chain(page_vendors)
->chain(page_update);
set_page(page_vendors);
}
void ConfigWizard::priv::on_custom_setup()
{
page_welcome->chain(page_firmware);
page_temps->chain(page_update);
set_page(page_firmware);
}
void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, PresetUpdater *updater)
{
const bool is_custom_setup = page_welcome->page_next() == page_firmware;
if (! is_custom_setup) {
const auto enabled_vendors = appconfig_vendors.vendors();
// Install bundles from resources if needed:
std::vector<std::string> install_bundles;
for (const auto &vendor_rsrc : vendors_rsrc) {
const auto vendor = enabled_vendors.find(vendor_rsrc.first);
if (vendor == enabled_vendors.end()) { continue; }
size_t size_sum = 0;
for (const auto &model : vendor->second) { size_sum += model.second.size(); }
if (size_sum == 0) { continue; }
// This vendor needs to be installed
install_bundles.emplace_back(vendor_rsrc.second);
}
// If the datadir was empty don't take a snapshot (it would just be an empty snapshot)
const bool snapshot = !flag_empty_datadir || page_welcome->reset_user_profile();
if (install_bundles.size() > 0) {
// Install bundles from resources.
updater->install_bundles_rsrc(std::move(install_bundles), snapshot);
}
if (page_welcome->reset_user_profile()) {
preset_bundle->reset(true);
}
app_config->set_vendors(appconfig_vendors);
app_config->set("version_check", page_update->version_check ? "1" : "0");
app_config->set("preset_update", page_update->preset_update ? "1" : "0");
if (flag_startup)
app_config->reset_selections();
// ^ TODO: replace with appropriate printer selection
preset_bundle->load_presets(*app_config);
} else {
for (ConfigWizardPage *page = page_firmware; page != nullptr; page = page->page_next()) {
page->apply_custom_config(*custom_config);
}
preset_bundle->load_config("My Settings", *custom_config);
}
// Update the selections from the compatibilty.
preset_bundle->export_selections(*app_config);
}
// Public
ConfigWizard::ConfigWizard(wxWindow *parent, bool startup, bool empty_datadir) :
wxDialog(parent, wxID_ANY, name(), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
p(new priv(this))
{
p->flag_startup = startup;
p->flag_empty_datadir = empty_datadir;
p->load_vendors();
p->custom_config.reset(DynamicPrintConfig::new_from_defaults_keys({
"gcode_flavor", "bed_shape", "nozzle_diameter", "filament_diameter", "temperature", "bed_temperature",
}));
p->index = new ConfigWizardIndex(this);
auto *vsizer = new wxBoxSizer(wxVERTICAL);
p->topsizer = new wxBoxSizer(wxHORIZONTAL);
auto *hline = new wxStaticLine(this);
p->btnsizer = new wxBoxSizer(wxHORIZONTAL);
p->topsizer->Add(p->index, 0, wxEXPAND);
p->topsizer->AddSpacer(INDEX_MARGIN);
p->btn_prev = new wxButton(this, wxID_BACKWARD);
p->btn_next = new wxButton(this, wxID_FORWARD);
p->btn_finish = new wxButton(this, wxID_APPLY, _(L("&Finish")));
p->btn_cancel = new wxButton(this, wxID_CANCEL);
p->btnsizer->AddStretchSpacer();
p->btnsizer->Add(p->btn_prev, 0, wxLEFT, BTN_SPACING);
p->btnsizer->Add(p->btn_next, 0, wxLEFT, BTN_SPACING);
p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING);
p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING);
p->add_page(p->page_welcome = new PageWelcome(this));
p->add_page(p->page_update = new PageUpdate(this));
p->add_page(p->page_vendors = new PageVendors(this));
p->add_page(p->page_firmware = new PageFirmware(this));
p->add_page(p->page_bed = new PageBedShape(this));
p->add_page(p->page_diams = new PageDiameters(this));
p->add_page(p->page_temps = new PageTemperatures(this));
p->index_refresh();
p->page_welcome->chain(p->page_update);
p->page_firmware
->chain(p->page_bed)
->chain(p->page_diams)
->chain(p->page_temps);
vsizer->Add(p->topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN);
vsizer->Add(hline, 0, wxEXPAND);
vsizer->Add(p->btnsizer, 0, wxEXPAND | wxALL, DIALOG_MARGIN);
p->set_page(p->page_welcome);
SetSizerAndFit(vsizer);
SetMinSize(GetSize());
p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); });
p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); });
p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->EndModal(wxID_OK); });
}
ConfigWizard::~ConfigWizard() {}
void ConfigWizard::run(PresetBundle *preset_bundle, PresetUpdater *updater)
{
if (ShowModal() == wxID_OK) {
p->apply_config(GUI::get_app_config(), preset_bundle, updater);
}
}
const wxString& ConfigWizard::name()
{
// A different naming convention is used for the Wizard on Windows vs. OSX & GTK.
#if WIN32
static const wxString config_wizard_name = _(L("Configuration Wizard"));
#else
static const wxString config_wizard_name = _(L("Configuration Assistant"));
#endif
return config_wizard_name;
}
}
}

View File

@ -0,0 +1,41 @@
#ifndef slic3r_ConfigWizard_hpp_
#define slic3r_ConfigWizard_hpp_
#include <memory>
#include <wx/dialog.h>
namespace Slic3r {
class PresetBundle;
class PresetUpdater;
namespace GUI {
class ConfigWizard: public wxDialog
{
public:
ConfigWizard(wxWindow *parent, bool startup, bool empty_datadir);
ConfigWizard(ConfigWizard &&) = delete;
ConfigWizard(const ConfigWizard &) = delete;
ConfigWizard &operator=(ConfigWizard &&) = delete;
ConfigWizard &operator=(const ConfigWizard &) = delete;
~ConfigWizard();
void run(PresetBundle *preset_bundle, PresetUpdater *updater);
static const wxString& name();
private:
struct priv;
std::unique_ptr<priv> p;
friend class ConfigWizardPage;
};
}
}
#endif

View File

@ -0,0 +1,239 @@
#ifndef slic3r_ConfigWizard_private_hpp_
#define slic3r_ConfigWizard_private_hpp_
#include "ConfigWizard.hpp"
#include <vector>
#include <set>
#include <unordered_map>
#include <boost/filesystem.hpp>
#include <wx/sizer.h>
#include <wx/panel.h>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/spinctrl.h>
#include "libslic3r/PrintConfig.hpp"
#include "slic3r/Utils/PresetUpdater.hpp"
#include "AppConfig.hpp"
#include "Preset.hpp"
#include "BedShapeDialog.hpp"
namespace fs = boost::filesystem;
namespace Slic3r {
namespace GUI {
enum {
CONTENT_WIDTH = 500,
DIALOG_MARGIN = 15,
INDEX_MARGIN = 40,
BTN_SPACING = 10,
INDENT_SPACING = 30,
VERTICAL_SPACING = 10,
};
struct PrinterPicker: wxPanel
{
struct Checkbox : wxCheckBox
{
Checkbox(wxWindow *parent, const wxString &label, const std::string &model, const std::string &variant) :
wxCheckBox(parent, wxID_ANY, label),
model(model),
variant(variant)
{}
std::string model;
std::string variant;
};
const std::string vendor_id;
std::vector<Checkbox*> cboxes;
unsigned variants_checked;
PrinterPicker(wxWindow *parent, const VendorProfile &vendor, const AppConfig &appconfig_vendors);
void select_all(bool select);
void on_checkbox(const Checkbox *cbox, bool checked);
};
struct ConfigWizardPage: wxPanel
{
ConfigWizard *parent;
const wxString shortname;
wxBoxSizer *content;
ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname);
virtual ~ConfigWizardPage();
ConfigWizardPage* page_prev() const { return p_prev; }
ConfigWizardPage* page_next() const { return p_next; }
ConfigWizardPage* chain(ConfigWizardPage *page);
template<class T>
void append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10)
{
content->Add(thing, proportion, flag, border);
}
void append_text(wxString text);
void append_spacer(int space);
ConfigWizard::priv *wizard_p() const { return parent->p.get(); }
virtual bool Show(bool show = true);
virtual bool Hide() { return Show(false); }
virtual wxPanel* extra_buttons() { return nullptr; }
virtual void on_page_set() {}
virtual void apply_custom_config(DynamicPrintConfig &config) {}
void enable_next(bool enable);
private:
ConfigWizardPage *p_prev;
ConfigWizardPage *p_next;
};
struct PageWelcome: ConfigWizardPage
{
PrinterPicker *printer_picker;
wxPanel *others_buttons;
wxCheckBox *cbox_reset;
PageWelcome(ConfigWizard *parent);
virtual wxPanel* extra_buttons() { return others_buttons; }
virtual void on_page_set();
bool reset_user_profile() const { return cbox_reset->GetValue(); }
void on_variant_checked();
};
struct PageUpdate: ConfigWizardPage
{
bool version_check;
bool preset_update;
PageUpdate(ConfigWizard *parent);
};
struct PageVendors: ConfigWizardPage
{
std::vector<PrinterPicker*> pickers;
PageVendors(ConfigWizard *parent);
virtual void on_page_set();
void on_vendor_pick(size_t i);
void on_variant_checked();
};
struct PageFirmware: ConfigWizardPage
{
const ConfigOptionDef &gcode_opt;
wxChoice *gcode_picker;
PageFirmware(ConfigWizard *parent);
virtual void apply_custom_config(DynamicPrintConfig &config);
};
struct PageBedShape: ConfigWizardPage
{
BedShapePanel *shape_panel;
PageBedShape(ConfigWizard *parent);
virtual void apply_custom_config(DynamicPrintConfig &config);
};
struct PageDiameters: ConfigWizardPage
{
wxSpinCtrlDouble *spin_nozzle;
wxSpinCtrlDouble *spin_filam;
PageDiameters(ConfigWizard *parent);
virtual void apply_custom_config(DynamicPrintConfig &config);
};
struct PageTemperatures: ConfigWizardPage
{
wxSpinCtrlDouble *spin_extr;
wxSpinCtrlDouble *spin_bed;
PageTemperatures(ConfigWizard *parent);
virtual void apply_custom_config(DynamicPrintConfig &config);
};
class ConfigWizardIndex: public wxPanel
{
public:
ConfigWizardIndex(wxWindow *parent);
void load_items(ConfigWizardPage *firstpage);
void set_active(ConfigWizardPage *page);
private:
const wxBitmap bg;
const wxBitmap bullet_black;
const wxBitmap bullet_blue;
const wxBitmap bullet_white;
int text_height;
std::vector<wxString> items;
std::vector<wxString>::const_iterator item_active;
void on_paint(wxPaintEvent &evt);
};
struct ConfigWizard::priv
{
ConfigWizard *q;
bool flag_startup;
bool flag_empty_datadir;
AppConfig appconfig_vendors;
std::unordered_map<std::string, VendorProfile> vendors;
std::unordered_map<std::string, std::string> vendors_rsrc;
std::unique_ptr<DynamicPrintConfig> custom_config;
wxBoxSizer *topsizer = nullptr;
wxBoxSizer *btnsizer = nullptr;
ConfigWizardPage *page_current = nullptr;
ConfigWizardIndex *index = nullptr;
wxButton *btn_prev = nullptr;
wxButton *btn_next = nullptr;
wxButton *btn_finish = nullptr;
wxButton *btn_cancel = nullptr;
PageWelcome *page_welcome = nullptr;
PageUpdate *page_update = nullptr;
PageVendors *page_vendors = nullptr;
PageFirmware *page_firmware = nullptr;
PageBedShape *page_bed = nullptr;
PageDiameters *page_diams = nullptr;
PageTemperatures *page_temps = nullptr;
priv(ConfigWizard *q) : q(q) {}
void load_vendors();
void add_page(ConfigWizardPage *page);
void index_refresh();
void set_page(ConfigWizardPage *page);
void layout_fit();
void go_prev() { if (page_current != nullptr) { set_page(page_current->page_prev()); } }
void go_next() { if (page_current != nullptr) { set_page(page_current->page_next()); } }
void enable_next(bool enable);
void on_other_vendors();
void on_custom_setup();
void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, PresetUpdater *updater);
};
}
}
#endif

View File

@ -39,17 +39,24 @@
#include <wx/sizer.h>
#include <wx/combo.h>
#include <wx/window.h>
#include <wx/msgdlg.h>
#include <wx/settings.h>
#include "wxExtensions.hpp"
#include "Tab.hpp"
#include "TabIface.hpp"
#include "AboutDialog.hpp"
#include "AppConfig.hpp"
#include "ConfigSnapshotDialog.hpp"
#include "Utils.hpp"
#include "ConfigWizard.hpp"
#include "Preferences.hpp"
#include "PresetBundle.hpp"
#include "../Utils/PresetUpdater.hpp"
#include "../Config/Snapshot.hpp"
namespace Slic3r { namespace GUI {
#if __APPLE__
@ -177,6 +184,7 @@ wxFrame *g_wxMainFrame = nullptr;
wxNotebook *g_wxTabPanel = nullptr;
AppConfig *g_AppConfig = nullptr;
PresetBundle *g_PresetBundle= nullptr;
PresetUpdater *g_PresetUpdater = nullptr;
wxColour g_color_label_modified;
wxColour g_color_label_sys;
@ -226,6 +234,11 @@ void set_preset_bundle(PresetBundle *preset_bundle)
g_PresetBundle = preset_bundle;
}
void set_preset_updater(PresetUpdater *updater)
{
g_PresetUpdater = updater;
}
std::vector<Tab *>& get_tabs_list()
{
return g_tabs_list;
@ -349,26 +362,159 @@ void get_installed_languages(wxArrayString & names,
}
}
void add_debug_menu(wxMenuBar *menu, int event_language_change)
enum ConfigMenuIDs {
ConfigMenuWizard,
ConfigMenuSnapshots,
ConfigMenuTakeSnapshot,
ConfigMenuUpdate,
ConfigMenuPreferences,
ConfigMenuLanguage,
ConfigMenuCnt,
};
void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change)
{
//#if 0
auto local_menu = new wxMenu();
local_menu->Append(wxWindow::NewControlId(1), _(L("Change Application Language")));
local_menu->Bind(wxEVT_MENU, [event_language_change](wxEvent&){
wxArrayString names;
wxArrayLong identifiers;
get_installed_languages(names, identifiers);
if (select_language(names, identifiers)){
save_language();
show_info(g_wxTabPanel, _(L("Application will be restarted")), _(L("Attention!")));
if (event_language_change > 0) {
wxCommandEvent event(event_language_change);
g_wxApp->ProcessEvent(event);
wxWindowID config_id_base = wxWindow::NewControlId((int)ConfigMenuCnt);
const auto config_wizard_tooltip = wxString::Format(_(L("Run %s")), ConfigWizard::name());
// Cmd+, is standard on OS X - what about other operating systems?
local_menu->Append(config_id_base + ConfigMenuWizard, ConfigWizard::name() + "\u2026", config_wizard_tooltip);
local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("Configuration Snapshots\u2026")), _(L("Inspect / activate configuration snapshots")));
local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _(L("Take Configuration Snapshot")), _(L("Capture a configuration snapshot")));
local_menu->Append(config_id_base + ConfigMenuUpdate, _(L("Check for updates")), _(L("Check for configuration updates")));
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("Preferences\u2026\tCtrl+,")), _(L("Application preferences")));
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application Language")));
local_menu->Bind(wxEVT_MENU, [config_id_base, event_language_change, event_preferences_changed](wxEvent &event){
switch (event.GetId() - config_id_base) {
case ConfigMenuWizard:
config_wizard(false, false);
break;
case ConfigMenuTakeSnapshot:
// Take a configuration snapshot.
if (check_unsaved_changes()) {
wxTextEntryDialog dlg(nullptr, _(L("Taking configuration snapshot")), _(L("Snapshot name")));
if (dlg.ShowModal() == wxID_OK)
g_AppConfig->set("on_snapshot",
Slic3r::GUI::Config::SnapshotDB::singleton().take_snapshot(
*g_AppConfig, Slic3r::GUI::Config::Snapshot::SNAPSHOT_USER, dlg.GetValue().ToUTF8().data()).id);
}
break;
case ConfigMenuSnapshots:
if (check_unsaved_changes()) {
std::string on_snapshot;
if (Config::SnapshotDB::singleton().is_on_snapshot(*g_AppConfig))
on_snapshot = g_AppConfig->get("on_snapshot");
ConfigSnapshotDialog dlg(Slic3r::GUI::Config::SnapshotDB::singleton(), on_snapshot);
dlg.ShowModal();
if (! dlg.snapshot_to_activate().empty()) {
if (! Config::SnapshotDB::singleton().is_on_snapshot(*g_AppConfig))
Config::SnapshotDB::singleton().take_snapshot(*g_AppConfig, Config::Snapshot::SNAPSHOT_BEFORE_ROLLBACK);
g_AppConfig->set("on_snapshot",
Config::SnapshotDB::singleton().restore_snapshot(dlg.snapshot_to_activate(), *g_AppConfig).id);
g_PresetBundle->load_presets(*g_AppConfig);
// Load the currently selected preset into the GUI, update the preset selection box.
for (Tab *tab : g_tabs_list)
tab->load_current_preset();
}
}
break;
case ConfigMenuPreferences:
{
PreferencesDialog dlg(g_wxMainFrame, event_preferences_changed);
dlg.ShowModal();
break;
}
case ConfigMenuLanguage:
{
wxArrayString names;
wxArrayLong identifiers;
get_installed_languages(names, identifiers);
if (select_language(names, identifiers)) {
save_language();
show_info(g_wxTabPanel, _(L("Application will be restarted")), _(L("Attention!")));
if (event_language_change > 0) {
wxCommandEvent event(event_language_change);
g_wxApp->ProcessEvent(event);
}
}
break;
}
}
});
menu->Append(local_menu, _(L("&Localization")));
//#endif
menu->Append(local_menu, _(L("&Configuration")));
}
// This is called when closing the application, when loading a config file or when starting the config wizard
// to notify the user whether he is aware that some preset changes will be lost.
bool check_unsaved_changes()
{
std::string dirty;
for (Tab *tab : g_tabs_list)
if (tab->current_preset_is_dirty())
if (dirty.empty())
dirty = tab->name();
else
dirty += std::string(", ") + tab->name();
if (dirty.empty())
// No changes, the application may close or reload presets.
return true;
// Ask the user.
auto dialog = new wxMessageDialog(g_wxMainFrame,
_(L("You have unsaved changes ")) + dirty + _(L(". Discard changes and continue anyway?")),
_(L("Unsaved Presets")),
wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT);
return dialog->ShowModal() == wxID_YES;
}
void config_wizard_startup(bool app_config_exists)
{
if (! app_config_exists || g_PresetBundle->has_defauls_only()) {
config_wizard(true, true);
} else if (g_AppConfig->legacy_datadir()) {
// Looks like user has legacy pre-vendorbundle data directory,
// explain what this is and run the wizard
const auto msg = _(L("Configuration update"));
const auto ext_msg = wxString::Format(
_(L(
"Slic3r PE now uses an updated configuration structure.\n\n"
"So called 'System presets' have been introduced, which hold the built-in default settings for various "
"printers. These System presets cannot be modified, instead, users now may create their"
"own presets inheriting settings from one of the System presets.\n"
"An inheriting preset may either inherit a particular value from its parent or override it with a customized value.\n\n"
"Please proceed with the %s that follows to set up the new presets "
"and to choose whether to enable automatic preset updates."
)),
ConfigWizard::name()
);
wxMessageDialog dlg(NULL, msg, _(L("Configuration update")), wxOK|wxCENTRE);
dlg.SetExtendedMessage(ext_msg);
const auto res = dlg.ShowModal();
config_wizard(true, false);
}
}
void config_wizard(bool startup, bool empty_datadir)
{
if (g_wxMainFrame == nullptr)
throw std::runtime_error("Main frame not set");
// Exit wizard if there are unsaved changes and the user cancels the action.
if (! check_unsaved_changes())
return;
ConfigWizard wizard(g_wxMainFrame, startup, empty_datadir);
wizard.run(g_PresetBundle, g_PresetUpdater);
// Load the currently selected preset into the GUI, update the preset selection box.
for (Tab *tab : g_tabs_list)
tab->load_current_preset();
}
void open_preferences_dialog(int event_preferences)
@ -810,6 +956,11 @@ int get_export_option(wxFileDialog* dlg)
}
void about()
{
AboutDialog dlg;
dlg.ShowModal();
dlg.Destroy();
}
} // namespace GUI
} // namespace Slic3r
} }

View File

@ -26,6 +26,7 @@ namespace Slic3r {
class PresetBundle;
class PresetCollection;
class AppConfig;
class PresetUpdater;
class DynamicPrintConfig;
class TabIface;
@ -77,6 +78,7 @@ void set_main_frame(wxFrame *main_frame);
void set_tab_panel(wxNotebook *tab_panel);
void set_app_config(AppConfig *app_config);
void set_preset_bundle(PresetBundle *preset_bundle);
void set_preset_updater(PresetUpdater *updater);
AppConfig* get_app_config();
wxApp* get_app();
@ -85,10 +87,20 @@ const wxColour& get_modified_label_clr();
const wxColour& get_sys_label_clr();
unsigned get_colour_approx_luma(const wxColour &colour);
void add_debug_menu(wxMenuBar *menu, int event_language_change);
extern void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change);
// This is called when closing the application, when loading a config file or when starting the config wizard
// to notify the user whether he is aware that some preset changes will be lost.
extern bool check_unsaved_changes();
// Checks if configuration wizard needs to run, calls config_wizard if so
extern void config_wizard_startup(bool app_config_exists);
// Opens the configuration wizard, returns true if wizard is finished & accepted.
extern void config_wizard(bool startup, bool empty_datadir);
// Create "Preferences" dialog after selecting menu "Preferences" in Perl part
void open_preferences_dialog(int event_preferences);
extern void open_preferences_dialog(int event_preferences);
// Create a new preset tab (print, filament and printer),
void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed);
@ -138,7 +150,11 @@ wxButton* get_wiping_dialog_button();
void add_export_option(wxFileDialog* dlg, const std::string& format);
int get_export_option(wxFileDialog* dlg);
}
}
// Display an About dialog
void about();
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -9,11 +9,12 @@ void PreferencesDialog::build()
{
auto app_config = get_app_config();
m_optgroup = std::make_shared<ConfigOptionsGroup>(this, _(L("General")));
m_optgroup->label_width = 200;
m_optgroup->label_width = 400;
m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
};
// TODO
// $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
// opt_id = > 'version_check',
// type = > 'bool',
@ -48,6 +49,22 @@ void PreferencesDialog::build()
option = Option (def,"background_processing");
m_optgroup->append_single_option_line(option);
// Please keep in sync with ConfigWizard
def.label = L("Check for application updates");
def.type = coBool;
def.tooltip = L("If enabled, Slic3r checks for new versions of Slic3r PE online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
def.default_value = new ConfigOptionBool(app_config->get("version_check") == "1");
option = Option (def, "version_check");
m_optgroup->append_single_option_line(option);
// Please keep in sync with ConfigWizard
def.label = L("Update built-in Presets automatically");
def.type = coBool;
def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup.");
def.default_value = new ConfigOptionBool(app_config->get("preset_update") == "1");
option = Option (def, "preset_update");
m_optgroup->append_single_option_line(option);
def.label = L("Disable USB/serial connection");
def.type = coBool;
def.tooltip = L("Disable communication with the printer over a serial / USB cable. "

View File

@ -2,9 +2,13 @@
#include <cassert>
#include "Preset.hpp"
#include "AppConfig.hpp"
#include <fstream>
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/nowide/cenv.hpp>
@ -23,14 +27,16 @@
#include "../../libslic3r/Utils.hpp"
#include "../../libslic3r/PlaceholderParser.hpp"
using boost::property_tree::ptree;
namespace Slic3r {
ConfigFileType guess_config_file_type(const boost::property_tree::ptree &tree)
ConfigFileType guess_config_file_type(const ptree &tree)
{
size_t app_config = 0;
size_t bundle = 0;
size_t config = 0;
for (const boost::property_tree::ptree::value_type &v : tree) {
for (const ptree::value_type &v : tree) {
if (v.second.empty()) {
if (v.first == "background_processing" ||
v.first == "last_output_path" ||
@ -58,6 +64,79 @@ ConfigFileType guess_config_file_type(const boost::property_tree::ptree &tree)
(bundle > config) ? CONFIG_FILE_TYPE_CONFIG_BUNDLE : CONFIG_FILE_TYPE_CONFIG;
}
VendorProfile VendorProfile::from_ini(const boost::filesystem::path &path, bool load_all)
{
ptree tree;
boost::filesystem::ifstream ifs(path);
boost::property_tree::read_ini(ifs, tree);
return VendorProfile::from_ini(tree, path, load_all);
}
VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem::path &path, bool load_all)
{
static const std::string printer_model_key = "printer_model:";
const std::string id = path.stem().string();
if (! boost::filesystem::exists(path)) {
throw std::runtime_error((boost::format("Cannot load Vendor Config Bundle `%1%`: File not found: `%2%`.") % id % path).str());
}
VendorProfile res(id);
auto get_or_throw = [&](const ptree &tree, const std::string &key) -> ptree::const_assoc_iterator
{
auto res = tree.find(key);
if (res == tree.not_found()) {
throw std::runtime_error((boost::format("Vendor Config Bundle `%1%` is not valid: Missing secion or key: `%2%`.") % id % key).str());
}
return res;
};
const auto &vendor_section = get_or_throw(tree, "vendor")->second;
res.name = get_or_throw(vendor_section, "name")->second.data();
auto config_version_str = get_or_throw(vendor_section, "config_version")->second.data();
auto config_version = Semver::parse(config_version_str);
if (! config_version) {
throw std::runtime_error((boost::format("Vendor Config Bundle `%1%` is not valid: Cannot parse config_version: `%2%`.") % id % config_version_str).str());
} else {
res.config_version = std::move(*config_version);
}
auto config_update_url = vendor_section.find("config_update_url");
if (config_update_url != vendor_section.not_found()) {
res.config_update_url = config_update_url->second.data();
}
if (! load_all) {
return res;
}
for (auto &section : tree) {
if (boost::starts_with(section.first, printer_model_key)) {
VendorProfile::PrinterModel model;
model.id = section.first.substr(printer_model_key.size());
model.name = section.second.get<std::string>("name", model.id);
section.second.get<std::string>("variants", "");
std::vector<std::string> variants;
if (Slic3r::unescape_strings_cstyle(section.second.get<std::string>("variants", ""), variants)) {
for (const std::string &variant_name : variants) {
if (model.variant(variant_name) == nullptr)
model.variants.emplace_back(VendorProfile::PrinterVariant(variant_name));
}
} else {
// Log error? // XXX
}
if (! model.id.empty() && ! model.variants.empty())
res.models.push_back(std::move(model));
}
}
return res;
}
// Suffix to be added to a modified preset name in the combo box.
static std::string g_suffix_modified = " (modified)";
const std::string& Preset::suffix_modified()
@ -175,6 +254,15 @@ bool Preset::update_compatible_with_printer(const Preset &active_printer, const
return this->is_compatible = is_compatible_with_printer(active_printer, extra_config);
}
void Preset::set_visible_from_appconfig(const AppConfig &app_config)
{
if (vendor == nullptr) { return; }
const std::string &model = config.opt_string("printer_model");
const std::string &variant = config.opt_string("printer_variant");
if (model.empty() || variant.empty()) { return; }
is_visible = app_config.get_variant(vendor->id, model, variant);
}
const std::vector<std::string>& Preset::print_options()
{
static std::vector<std::string> s_opts {
@ -453,18 +541,6 @@ size_t PresetCollection::first_visible_idx() const
return idx;
}
// Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible.
size_t PresetCollection::first_compatible_idx() const
{
size_t idx = m_default_suppressed ? 1 : 0;
for (; idx < this->m_presets.size(); ++ idx)
if (m_presets[idx].is_compatible)
break;
if (idx == this->m_presets.size())
idx = 0;
return idx;
}
void PresetCollection::set_default_suppressed(bool default_suppressed)
{
if (m_default_suppressed != default_suppressed) {
@ -473,7 +549,7 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
}
}
void PresetCollection::update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible)
size_t PresetCollection::update_compatible_with_printer_internal(const Preset &active_printer, bool unselect_if_incompatible)
{
DynamicPrintConfig config;
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name));
@ -484,14 +560,12 @@ void PresetCollection::update_compatible_with_printer(const Preset &active_print
Preset &preset_selected = m_presets[idx_preset];
Preset &preset_edited = selected ? m_edited_preset : preset_selected;
if (! preset_edited.update_compatible_with_printer(active_printer, &config) &&
selected && select_other_if_incompatible)
selected && unselect_if_incompatible)
m_idx_selected = (size_t)-1;
if (selected)
preset_selected.is_compatible = preset_edited.is_compatible;
}
if (m_idx_selected == (size_t)-1)
// Find some other compatible preset, or the "-- default --" preset.
this->select_preset(first_compatible_idx());
return m_idx_selected;
}
// Save the preset under a new name. If the name is different from the old one,
@ -677,8 +751,8 @@ bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, b
// 1) Try to find the preset by its name.
auto it = this->find_preset_internal(name);
size_t idx = 0;
if (it != m_presets.end() && it->name == name)
// Preset found by its name.
if (it != m_presets.end() && it->name == name && it->is_visible)
// Preset found by its name and it is visible.
idx = it - m_presets.begin();
else {
// Find the first visible preset.
@ -699,6 +773,46 @@ bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, b
return false;
}
bool PresetCollection::select_preset_by_name_strict(const std::string &name)
{
// 1) Try to find the preset by its name.
auto it = this->find_preset_internal(name);
size_t idx = (size_t)-1;
if (it != m_presets.end() && it->name == name && it->is_visible)
// Preset found by its name.
idx = it - m_presets.begin();
// 2) Select the new preset.
if (idx != (size_t)-1) {
this->select_preset(idx);
return true;
}
m_idx_selected = idx;
return false;
}
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> PresetCollection::merge_presets(PresetCollection &&other, const std::set<VendorProfile> &new_vendors)
{
std::vector<std::string> duplicates;
for (Preset &preset : other.m_presets) {
if (preset.is_default || preset.is_external)
continue;
Preset key(m_type, preset.name);
auto it = std::lower_bound(m_presets.begin() + 1, m_presets.end(), key);
if (it == m_presets.end() || it->name != preset.name) {
if (preset.vendor != nullptr) {
// Re-assign a pointer to the vendor structure in the new PresetBundle.
auto it = new_vendors.find(*preset.vendor);
assert(it != new_vendors.end());
preset.vendor = &(*it);
}
this->m_presets.emplace(it, std::move(preset));
} else
duplicates.emplace_back(std::move(preset.name));
}
return duplicates;
}
std::string PresetCollection::name() const
{
switch (this->type()) {

View File

@ -3,8 +3,12 @@
#include <deque>
#include <boost/filesystem/path.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#include "../../libslic3r/libslic3r.h"
#include "../../libslic3r/PrintConfig.hpp"
#include "slic3r/Utils/Semver.hpp"
class wxBitmap;
class wxChoice;
@ -13,6 +17,9 @@ class wxItemContainer;
namespace Slic3r {
class AppConfig;
class PresetBundle;
enum ConfigFileType
{
CONFIG_FILE_TYPE_UNKNOWN,
@ -28,21 +35,19 @@ class VendorProfile
public:
std::string name;
std::string id;
std::string config_version;
Semver config_version;
std::string config_update_url;
struct PrinterVariant {
PrinterVariant() {}
PrinterVariant(const std::string &name) : name(name) {}
std::string name;
bool enabled = true;
};
struct PrinterModel {
PrinterModel() {}
PrinterModel(const std::string &name) : name(name) {}
std::string id;
std::string name;
bool enabled = true;
std::vector<PrinterVariant> variants;
PrinterVariant* variant(const std::string &name) {
for (auto &v : this->variants)
@ -51,11 +56,14 @@ public:
return nullptr;
}
const PrinterVariant* variant(const std::string &name) const { return const_cast<PrinterModel*>(this)->variant(name); }
bool operator< (const PrinterModel &rhs) const { return this->name < rhs.name; }
bool operator==(const PrinterModel &rhs) const { return this->name == rhs.name; }
};
std::set<PrinterModel> models;
std::vector<PrinterModel> models;
VendorProfile() {}
VendorProfile(std::string id) : id(std::move(id)) {}
static VendorProfile from_ini(const boost::filesystem::path &path, bool load_all=true);
static VendorProfile from_ini(const boost::property_tree::ptree &tree, const boost::filesystem::path &path, bool load_all=true);
size_t num_variants() const { size_t n = 0; for (auto &model : models) n += model.variants.size(); return n; }
@ -86,7 +94,8 @@ public:
bool is_external = false;
// System preset is read-only.
bool is_system = false;
// Preset is visible, if it is compatible with the active Printer.
// Preset is visible, if it is associated with a printer model / variant that is enabled in the AppConfig
// or if it has no printer model / variant association.
// Also the "default" preset is only visible, if it is the only preset in the list.
bool is_visible = true;
// Has this preset been modified?
@ -132,6 +141,9 @@ public:
// Mark this preset as compatible if it is compatible with active_printer.
bool update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config);
// Set is_visible according to application config
void set_visible_from_appconfig(const AppConfig &app_config);
// Resize the extruder specific fields, initialize them with the content of the 1st extruder.
void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); }
@ -163,6 +175,13 @@ public:
PresetCollection(Preset::Type type, const std::vector<std::string> &keys);
~PresetCollection();
typedef std::deque<Preset>::iterator Iterator;
typedef std::deque<Preset>::const_iterator ConstIterator;
Iterator begin() { return m_presets.begin() + 1; }
ConstIterator begin() const { return m_presets.begin() + 1; }
Iterator end() { return m_presets.end(); }
ConstIterator end() const { return m_presets.end(); }
void reset(bool delete_files);
Preset::Type type() const { return m_type; }
@ -234,19 +253,49 @@ public:
{ return const_cast<PresetCollection*>(this)->find_preset(name, first_visible_if_not_found); }
size_t first_visible_idx() const;
size_t first_compatible_idx() const;
// Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible.
// If one of the prefered_alternates is compatible, select it.
template<typename PreferedCondition>
size_t first_compatible_idx(PreferedCondition prefered_condition) const
{
size_t i = m_default_suppressed ? 1 : 0;
size_t n = this->m_presets.size();
size_t i_compatible = n;
for (; i < n; ++ i)
if (m_presets[i].is_compatible) {
if (prefered_condition(m_presets[i].name))
return i;
if (i_compatible == n)
// Store the first compatible profile into i_compatible.
i_compatible = i;
}
return (i_compatible == n) ? 0 : i_compatible;
}
// Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible.
size_t first_compatible_idx() const { return this->first_compatible_idx([](const std::string&){return true;}); }
// Return index of the first visible preset. Certainly at least the '- default -' preset shall be visible.
// Return the first visible preset. Certainly at least the '- default -' preset shall be visible.
Preset& first_visible() { return this->preset(this->first_visible_idx()); }
const Preset& first_visible() const { return this->preset(this->first_visible_idx()); }
Preset& first_compatible() { return this->preset(this->first_compatible_idx()); }
template<typename PreferedCondition>
Preset& first_compatible(PreferedCondition prefered_condition) { return this->preset(this->first_compatible_idx(prefered_condition)); }
const Preset& first_compatible() const { return this->preset(this->first_compatible_idx()); }
// Return number of presets including the "- default -" preset.
size_t size() const { return this->m_presets.size(); }
// For Print / Filament presets, disable those, which are not compatible with the printer.
void update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible);
template<typename PreferedCondition>
void update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible, PreferedCondition prefered_condition)
{
if (this->update_compatible_with_printer_internal(active_printer, select_other_if_incompatible) == (size_t)-1)
// Find some other compatible preset, or the "-- default --" preset.
this->select_preset(this->first_compatible_idx(prefered_condition));
}
void update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible)
{ this->update_compatible_with_printer(active_printer, select_other_if_incompatible, [](const std::string&){return true;}); }
size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); }
@ -282,6 +331,14 @@ public:
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string &new_name) const;
protected:
// Select a preset, if it exists. If it does not exist, select an invalid (-1) index.
// This is a temporary state, which shall be fixed immediately by the following step.
bool select_preset_by_name_strict(const std::string &name);
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> merge_presets(PresetCollection &&other, const std::set<VendorProfile> &new_vendors);
private:
PresetCollection();
PresetCollection(const PresetCollection &other);
@ -299,6 +356,8 @@ private:
std::deque<Preset>::const_iterator find_preset_internal(const std::string &name) const
{ return const_cast<PresetCollection*>(this)->find_preset_internal(name); }
size_t update_compatible_with_printer_internal(const Preset &active_printer, bool unselect_if_incompatible);
static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference);
// Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER.
@ -324,6 +383,9 @@ private:
wxBitmap *m_bitmap_main_frame;
// Path to the directory to store the config files into.
std::string m_dir_path;
// to access select_preset_by_name_strict()
friend class PresetBundle;
};
} // namespace Slic3r

View File

@ -4,6 +4,7 @@
#include "PresetBundle.hpp"
#include "BitmapCache.hpp"
#include <algorithm>
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/algorithm/clamp.hpp>
@ -111,6 +112,7 @@ void PresetBundle::setup_directories()
std::initializer_list<boost::filesystem::path> paths = {
data_dir,
data_dir / "vendor",
data_dir / "cache",
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
// Store the print/filament/printer presets into a "presets" directory.
data_dir / "presets",
@ -176,6 +178,7 @@ std::string PresetBundle::load_system_presets()
// Here the vendor specific read only Config Bundles are stored.
boost::filesystem::path dir = (boost::filesystem::path(data_dir()) / "vendor").make_preferred();
std::string errors_cummulative;
bool first = true;
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini")) {
std::string name = dir_entry.path().filename().string();
@ -183,7 +186,25 @@ std::string PresetBundle::load_system_presets()
name.erase(name.size() - 4);
try {
// Load the config bundle, flatten it.
this->load_configbundle(dir_entry.path().string(), LOAD_CFGBNDLE_SYSTEM);
if (first) {
// Reset this PresetBundle and load the first vendor config.
this->load_configbundle(dir_entry.path().string(), LOAD_CFGBNDLE_SYSTEM);
first = false;
} else {
// Load the other vendor configs, merge them with this PresetBundle.
// Report duplicate profiles.
PresetBundle other;
other.load_configbundle(dir_entry.path().string(), LOAD_CFGBNDLE_SYSTEM);
std::vector<std::string> duplicates = this->merge_presets(std::move(other));
if (! duplicates.empty()) {
errors_cummulative += "Vendor configuration file " + name + " contains the following presets with names used by other vendors: ";
for (size_t i = 0; i < duplicates.size(); ++ i) {
if (i > 0)
errors_cummulative += ", ";
errors_cummulative += duplicates[i];
}
}
}
} catch (const std::runtime_error &err) {
errors_cummulative += err.what();
errors_cummulative += "\n";
@ -192,6 +213,18 @@ std::string PresetBundle::load_system_presets()
return errors_cummulative;
}
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> PresetBundle::merge_presets(PresetBundle &&other)
{
this->vendors.insert(other.vendors.begin(), other.vendors.end());
std::vector<std::string> duplicate_prints = this->prints .merge_presets(std::move(other.prints), this->vendors);
std::vector<std::string> duplicate_filaments = this->filaments.merge_presets(std::move(other.filaments), this->vendors);
std::vector<std::string> duplicate_printers = this->printers .merge_presets(std::move(other.printers), this->vendors);
append(duplicate_prints, std::move(duplicate_filaments));
append(duplicate_prints, std::move(duplicate_printers));
return duplicate_prints;
}
static inline std::string remove_ini_suffix(const std::string &name)
{
std::string out = name;
@ -205,26 +238,44 @@ static inline std::string remove_ini_suffix(const std::string &name)
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
void PresetBundle::load_installed_printers(const AppConfig &config)
{
// m_storage
for (auto &preset : printers) {
preset.set_visible_from_appconfig(config);
}
}
// Load selections (current print, current filaments, current printer) from config.ini
// This is done just once on application start up.
void PresetBundle::load_selections(const AppConfig &config)
{
prints.select_preset_by_name(remove_ini_suffix(config.get("presets", "print")), true);
filaments.select_preset_by_name(remove_ini_suffix(config.get("presets", "filament")), true);
printers.select_preset_by_name(remove_ini_suffix(config.get("presets", "printer")), true);
// Update visibility of presets based on application vendor / model / variant configuration.
this->load_installed_printers(config);
// Parse the initial print / filament / printer profile names.
std::string initial_print_profile_name = remove_ini_suffix(config.get("presets", "print"));
std::vector<std::string> initial_filament_profile_names;
std::string initial_printer_profile_name = remove_ini_suffix(config.get("presets", "printer"));
auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(printers.get_selected_preset().config.option("nozzle_diameter"));
size_t num_extruders = nozzle_diameter->values.size();
this->set_filament_preset(0, filaments.get_selected_preset().name);
initial_filament_profile_names.emplace_back(remove_ini_suffix(config.get("presets", "filament")));
this->set_filament_preset(0, initial_filament_profile_names.back());
for (unsigned int i = 1; i < (unsigned int)num_extruders; ++ i) {
char name[64];
sprintf(name, "filament_%d", i);
if (! config.has("presets", name))
break;
this->set_filament_preset(i, remove_ini_suffix(config.get("presets", name)));
initial_filament_profile_names.emplace_back(remove_ini_suffix(config.get("presets", name)));
this->set_filament_preset(i, initial_filament_profile_names.back());
}
// Activate print / filament / printer profiles from the config.
// If the printer profile enumerated by the config are not visible, select an alternate preset.
// Do not select alternate profiles for the print / filament profiles as those presets
// will be selected by the following call of this->update_compatible_with_printer(true).
prints.select_preset_by_name_strict(initial_print_profile_name);
filaments.select_preset_by_name_strict(initial_filament_profile_names.front());
printers.select_preset_by_name(initial_printer_profile_name, true);
// Update visibility of presets based on their compatibility with the active printer.
// Always try to select a compatible print and filament preset to the current printer preset,
// as the application may have been closed with an active "external" preset, which does not
@ -675,48 +726,6 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree)
flatten_configbundle_hierarchy(tree, "printer");
}
static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorProfile &vendor_profile)
{
const std::string printer_model_key = "printer_model:";
for (auto &section : tree)
if (section.first == "vendor") {
// Load the names of the active presets.
for (auto &kvp : section.second) {
if (kvp.first == "name")
vendor_profile.name = kvp.second.data();
else if (kvp.first == "id")
vendor_profile.id = kvp.second.data();
else if (kvp.first == "config_version")
vendor_profile.config_version = kvp.second.data();
else if (kvp.first == "config_update_url")
vendor_profile.config_update_url = kvp.second.data();
}
} else if (boost::starts_with(section.first, printer_model_key)) {
VendorProfile::PrinterModel model;
model.name = section.first.substr(printer_model_key.size());
section.second.get<std::string>("variants", "");
std::vector<std::string> variants;
if (Slic3r::unescape_strings_cstyle(section.second.get<std::string>("variants", ""), variants)) {
for (const std::string &variant_name : variants) {
if (model.variant(variant_name) == nullptr)
model.variants.emplace_back(VendorProfile::PrinterVariant(variant_name));
}
} else {
// Log error?
}
if (! model.name.empty() && ! model.variants.empty())
vendor_profile.models.insert(model);
}
}
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
void PresetBundle::install_vendor_configbundle(const std::string &src_path0)
{
boost::filesystem::path src_path(src_path0);
boost::filesystem::copy_file(src_path, (boost::filesystem::path(data_dir()) / "vendor" / src_path.filename()).make_preferred(), boost::filesystem::copy_option::overwrite_if_exists);
}
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
size_t PresetBundle::load_configbundle(const std::string &path, unsigned int flags)
@ -730,19 +739,21 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
pt::ptree tree;
boost::nowide::ifstream ifs(path);
pt::read_ini(ifs, tree);
// Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed.
flatten_configbundle_hierarchy(tree);
const VendorProfile *vendor_profile = nullptr;
if (flags & LOAD_CFGBNDLE_SYSTEM) {
VendorProfile vp;
load_vendor_profile(tree, vp);
if (vp.name.empty())
throw std::runtime_error(std::string("Vendor Config Bundle is not valid: Missing vendor name key."));
if (flags & (LOAD_CFGBNDLE_SYSTEM | LOAD_CFGBUNDLE_VENDOR_ONLY)) {
auto vp = VendorProfile::from_ini(tree, path);
if (vp.num_variants() == 0)
return 0;
vendor_profile = &(*this->vendors.insert(vp).first);
}
if (flags & LOAD_CFGBUNDLE_VENDOR_ONLY) {
return 0;
}
// 1.5) Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed.
flatten_configbundle_hierarchy(tree);
// 2) Parse the property_tree, extract the active preset names and the profiles, save them into local config files.
std::vector<std::string> loaded_prints;
@ -814,7 +825,9 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
section.first << "\" defines no printer variant, it will be ignored.";
continue;
}
auto it_model = vendor_profile->models.find(VendorProfile::PrinterModel(printer_model));
auto it_model = std::find_if(vendor_profile->models.cbegin(), vendor_profile->models.cend(),
[&](const VendorProfile::PrinterModel &m) { return m.id == printer_model; }
);
if (it_model == vendor_profile->models.end()) {
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
section.first << "\" defines invalid printer model \"" << printer_model << "\", it will be ignored.";
@ -916,14 +929,35 @@ void PresetBundle::update_multi_material_filament_presets()
void PresetBundle::update_compatible_with_printer(bool select_other_if_incompatible)
{
this->prints.update_compatible_with_printer(this->printers.get_edited_preset(), select_other_if_incompatible);
this->filaments.update_compatible_with_printer(this->printers.get_edited_preset(), select_other_if_incompatible);
const Preset &printer_preset = this->printers.get_edited_preset();
const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile");
const std::vector<std::string> &prefered_filament_profiles = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile")->values;
prefered_print_profile.empty() ?
this->prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible) :
this->prints.update_compatible_with_printer(printer_preset, select_other_if_incompatible,
[&prefered_print_profile](const std::string& profile_name){ return profile_name == prefered_print_profile; });
prefered_filament_profiles.empty() ?
this->filaments.update_compatible_with_printer(printer_preset, select_other_if_incompatible) :
this->filaments.update_compatible_with_printer(printer_preset, select_other_if_incompatible,
[&prefered_filament_profiles](const std::string& profile_name)
{ return std::find(prefered_filament_profiles.begin(), prefered_filament_profiles.end(), profile_name) != prefered_filament_profiles.end(); });
if (select_other_if_incompatible) {
// Verify validity of the current filament presets.
for (std::string &filament_name : this->filament_presets) {
Preset *preset = this->filaments.find_preset(filament_name, false);
if (preset == nullptr || ! preset->is_compatible)
filament_name = this->filaments.first_compatible().name;
this->filament_presets.front() = this->filaments.get_edited_preset().name;
for (size_t idx = 1; idx < this->filament_presets.size(); ++ idx) {
std::string &filament_name = this->filament_presets[idx];
Preset *preset = this->filaments.find_preset(filament_name, false);
if (preset == nullptr || ! preset->is_compatible) {
// Pick a compatible profile. If there are prefered_filament_profiles, use them.
if (prefered_filament_profiles.empty())
filament_name = this->filaments.first_compatible().name;
else {
const std::string &preferred = (idx < prefered_filament_profiles.size()) ?
prefered_filament_profiles[idx] : prefered_filament_profiles.front();
filament_name = this->filaments.first_compatible(
[&preferred](const std::string& profile_name){ return profile_name == preferred; }).name;
}
}
}
}
}

View File

@ -5,6 +5,7 @@
#include "Preset.hpp"
#include <set>
#include <boost/filesystem/path.hpp>
namespace Slic3r {
@ -86,13 +87,11 @@ public:
LOAD_CFGBNDLE_RESET_USER_PROFILE = 2,
// Load a system config bundle.
LOAD_CFGBNDLE_SYSTEM = 4,
LOAD_CFGBUNDLE_VENDOR_ONLY = 8,
};
// Load the config bundle, store it to the user profile directory by default.
size_t load_configbundle(const std::string &path, unsigned int flags = LOAD_CFGBNDLE_SAVE);
// Install the Vendor specific config bundle into user's directory.
void install_vendor_configbundle(const std::string &src_path);
// Export a config bundle file containing all the presets and the names of the active presets.
void export_configbundle(const std::string &path); // , const DynamicPrintConfig &settings);
@ -117,10 +116,12 @@ public:
// preset if the current print or filament preset is not compatible.
void update_compatible_with_printer(bool select_other_if_incompatible);
static bool parse_color(const std::string &scolor, unsigned char *rgb_out);
static bool parse_color(const std::string &scolor, unsigned char *rgb_out);
private:
std::string load_system_presets();
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> merge_presets(PresetBundle &&other);
// Set the "enabled" flag for printer vendors, printer models and printer variants
// based on the user configuration.

View File

@ -641,7 +641,8 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value)
change_opt_value(*m_config, opt_key, value);
// Mark the print & filament enabled if they are compatible with the currently selected preset.
if (opt_key.compare("compatible_printers") == 0) {
m_preset_bundle->update_compatible_with_printer(0);
// Don't select another profile if this profile happens to become incompatible.
m_preset_bundle->update_compatible_with_printer(false);
}
m_presets->update_dirty_ui(m_presets_choice);
on_presets_changed();
@ -2200,9 +2201,9 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox
presets.Add(preset.name);
}
auto dlg = new wxMultiChoiceDialog(parent,
_(L("Select the printers this profile is compatible with.")),
_(L("Compatible printers")), presets);
wxMultiChoiceDialog dlg(parent,
_(L("Select the printers this profile is compatible with.")),
_(L("Compatible printers")), presets);
// # Collect and set indices of printers marked as compatible.
wxArrayInt selections;
auto *compatible_printers = dynamic_cast<const ConfigOptionStrings*>(m_config->option("compatible_printers"));
@ -2214,12 +2215,12 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox
selections.Add(idx);
break;
}
dlg->SetSelections(selections);
dlg.SetSelections(selections);
std::vector<std::string> value;
// Show the dialog.
if (dlg->ShowModal() == wxID_OK) {
if (dlg.ShowModal() == wxID_OK) {
selections.Clear();
selections = dlg->GetSelections();
selections = dlg.GetSelections();
for (auto idx : selections)
value.push_back(presets[idx].ToStdString());
if (value.empty()) {

View File

@ -0,0 +1,477 @@
#include "PresetUpdater.hpp"
#include <iostream> // XXX
#include <algorithm>
#include <thread>
#include <stack>
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/log/trivial.hpp>
#include <wx/app.h>
#include <wx/event.h>
#include <wx/msgdlg.h>
#include <wx/dialog.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/hyperlink.h>
#include <wx/statbmp.h>
#include <wx/checkbox.h>
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/PresetBundle.hpp"
#include "slic3r/Utils/Http.hpp"
#include "slic3r/Config/Version.hpp"
#include "slic3r/Config/Snapshot.hpp"
namespace fs = boost::filesystem;
using Slic3r::GUI::Config::Index;
using Slic3r::GUI::Config::Version;
using Slic3r::GUI::Config::Snapshot;
using Slic3r::GUI::Config::SnapshotDB;
namespace Slic3r {
enum {
SLIC3R_VERSION_BODY_MAX = 256,
};
static const char *INDEX_FILENAME = "index.idx";
static const char *TMP_EXTENSION = ".download";
struct UpdateNotification : wxDialog
{
// If this dialog gets any more complex, it should probably be factored out...
enum {
CONTENT_WIDTH = 400,
BORDER = 30,
SPACING = 15,
};
wxCheckBox *cbox;
UpdateNotification(const Semver &ver_current, const Semver &ver_online) : wxDialog(nullptr, wxID_ANY, _(L("Update available")))
{
auto *topsizer = new wxBoxSizer(wxHORIZONTAL);
auto *sizer = new wxBoxSizer(wxVERTICAL);
const auto url = wxString::Format("https://github.com/prusa3d/Slic3r/releases/tag/version_%s", ver_online.to_string());
auto *link = new wxHyperlinkCtrl(this, wxID_ANY, url, url);
auto *text = new wxStaticText(this, wxID_ANY,
_(L("New version of Slic3r PE is available. To download, follow the link below.")));
const auto link_width = link->GetSize().GetWidth();
text->Wrap(CONTENT_WIDTH > link_width ? CONTENT_WIDTH : link_width);
sizer->Add(text);
sizer->AddSpacer(SPACING);
auto *versions = new wxFlexGridSizer(2, 0, SPACING);
versions->Add(new wxStaticText(this, wxID_ANY, _(L("Current version:"))));
versions->Add(new wxStaticText(this, wxID_ANY, ver_current.to_string()));
versions->Add(new wxStaticText(this, wxID_ANY, _(L("New version:"))));
versions->Add(new wxStaticText(this, wxID_ANY, ver_online.to_string()));
sizer->Add(versions);
sizer->AddSpacer(SPACING);
sizer->Add(link);
sizer->AddSpacer(2*SPACING);
cbox = new wxCheckBox(this, wxID_ANY, _(L("Don't notify about new releases any more")));
sizer->Add(cbox);
sizer->AddSpacer(SPACING);
auto *ok = new wxButton(this, wxID_OK);
ok->SetFocus();
sizer->Add(ok, 0, wxALIGN_CENTRE_HORIZONTAL);
auto *logo = new wxStaticBitmap(this, wxID_ANY, wxBitmap(GUI::from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG));
topsizer->Add(logo, 0, wxALL, BORDER);
topsizer->Add(sizer, 0, wxALL, BORDER);
SetSizerAndFit(topsizer);
}
bool disable_version_check() const { return cbox->GetValue(); }
};
struct Update
{
fs::path source;
fs::path target;
Version version;
Update(fs::path &&source, const fs::path &target, const Version &version) :
source(source),
target(std::move(target)),
version(version)
{}
Update(fs::path &&source, fs::path &&target) :
source(source),
target(std::move(target))
{}
std::string name() { return source.stem().string(); }
};
typedef std::vector<Update> Updates;
struct PresetUpdater::priv
{
int version_online_event;
std::vector<Index> index_db;
bool enabled_version_check;
bool enabled_config_update;
std::string version_check_url;
bool had_config_update;
fs::path cache_path;
fs::path rsrc_path;
fs::path vendor_path;
bool cancel;
std::thread thread;
priv(int version_online_event);
void set_download_prefs(AppConfig *app_config);
bool get_file(const std::string &url, const fs::path &target_path) const;
void prune_tmps() const;
void sync_version() const;
void sync_config(const std::set<VendorProfile> vendors) const;
void check_install_indices() const;
Updates config_update() const;
void perform_updates(Updates &&updates, bool snapshot = true) const;
};
PresetUpdater::priv::priv(int version_online_event) :
version_online_event(version_online_event),
had_config_update(false),
cache_path(fs::path(Slic3r::data_dir()) / "cache"),
rsrc_path(fs::path(resources_dir()) / "profiles"),
vendor_path(fs::path(Slic3r::data_dir()) / "vendor"),
cancel(false)
{
set_download_prefs(GUI::get_app_config());
check_install_indices();
index_db = std::move(Index::load_db());
}
void PresetUpdater::priv::set_download_prefs(AppConfig *app_config)
{
enabled_version_check = app_config->get("version_check") == "1";
version_check_url = app_config->get("version_check_url");
enabled_config_update = app_config->get("preset_update") == "1";
}
bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &target_path) const
{
std::cerr << "get_file(): " << url << " -> " << target_path << std::endl;
bool res = false;
fs::path tmp_path = target_path;
tmp_path += TMP_EXTENSION;
Http::get(url)
.on_progress([this](Http::Progress, bool &cancel) {
if (cancel) { cancel = true; }
})
.on_complete([&](std::string body, unsigned http_status) {
fs::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc);
file.write(body.c_str(), body.size());
file.close();
fs::rename(tmp_path, target_path);
res = true;
})
.perform_sync();
return res;
}
void PresetUpdater::priv::prune_tmps() const
{
for (fs::directory_iterator it(cache_path); it != fs::directory_iterator(); ++it) {
if (it->path().extension() == TMP_EXTENSION) {
fs::remove(it->path());
}
}
}
void PresetUpdater::priv::sync_version() const
{
if (! enabled_version_check) { return; }
Http::get(version_check_url)
.size_limit(SLIC3R_VERSION_BODY_MAX)
.on_progress([this](Http::Progress, bool &cancel) {
cancel = this->cancel;
})
.on_complete([&](std::string body, unsigned http_status) {
boost::trim(body);
wxCommandEvent* evt = new wxCommandEvent(version_online_event);
evt->SetString(body);
GUI::get_app()->QueueEvent(evt);
})
.perform_sync();
}
void PresetUpdater::priv::sync_config(const std::set<VendorProfile> vendors) const
{
std::cerr << "sync_config()" << std::endl;
if (!enabled_config_update) { return; }
// Donwload vendor preset bundles
for (const auto &index : index_db) {
if (cancel) { return; }
std::cerr << "Index: " << index.vendor() << std::endl;
const auto vendor_it = vendors.find(VendorProfile(index.vendor()));
if (vendor_it == vendors.end()) { continue; }
const VendorProfile &vendor = *vendor_it;
if (vendor.config_update_url.empty()) { continue; }
// Download a fresh index
const auto idx_url = vendor.config_update_url + "/" + INDEX_FILENAME;
const auto idx_path = cache_path / (vendor.id + ".idx");
if (! get_file(idx_url, idx_path)) { continue; }
if (cancel) { return; }
std::cerr << "Got a new index: " << idx_path << std::endl;
// Load the fresh index up
Index new_index;
new_index.load(idx_path);
// See if a there's a new version to download
const auto recommended_it = new_index.recommended();
if (recommended_it == new_index.end()) { continue; }
const auto recommended = recommended_it->config_version;
std::cerr << "Current vendor version: " << vendor.config_version.to_string() << std::endl;
std::cerr << "Recommended version:\t" << recommended.to_string() << std::endl;
if (vendor.config_version >= recommended) { continue; }
// Download a fresh bundle
const auto bundle_url = (boost::format("%1%/%2%.ini") % vendor.config_update_url % recommended.to_string()).str();
const auto bundle_path = cache_path / (vendor.id + ".ini");
if (! get_file(bundle_url, bundle_path)) { continue; }
if (cancel) { return; }
std::cerr << "Got a new bundle: " << bundle_path << std::endl;
}
}
void PresetUpdater::priv::check_install_indices() const
{
for (fs::directory_iterator it(rsrc_path); it != fs::directory_iterator(); ++it) {
const auto &path = it->path();
if (path.extension() == ".idx") {
const auto path_in_cache = cache_path / path.filename();
if (! fs::exists(path_in_cache)) {
fs::copy_file(path, path_in_cache, fs::copy_option::overwrite_if_exists);
} else {
Index idx_rsrc, idx_cache;
idx_rsrc.load(path);
idx_cache.load(path_in_cache);
if (idx_cache.version() < idx_rsrc.version()) {
fs::copy_file(path, path_in_cache, fs::copy_option::overwrite_if_exists);
}
}
}
}
}
Updates PresetUpdater::priv::config_update() const
{
Updates updates;
for (const auto idx : index_db) {
const auto bundle_path = vendor_path / (idx.vendor() + ".ini");
if (! fs::exists(bundle_path)) {
continue;
}
// Perform a basic load and check the version
const auto vp = VendorProfile::from_ini(bundle_path, false);
const auto ver_current = idx.find(vp.config_version);
if (ver_current == idx.end()) {
BOOST_LOG_TRIVIAL(warning) << boost::format("Preset bundle (`%1%`) version not found in index: %2%") % idx.vendor() % vp.config_version.to_string();
continue;
}
const auto recommended = idx.recommended();
if (recommended == idx.end()) {
throw std::runtime_error((boost::format("Invalid index: `%1%`") % idx.vendor()).str());
}
if (! ver_current->is_current_slic3r_supported()) {
// TODO: Downgrade situation
} else if (recommended->config_version > ver_current->config_version) {
// Config bundle update situation
auto path_in_cache = cache_path / (idx.vendor() + ".ini");
if (! fs::exists(path_in_cache)) {
continue;
}
const auto cached_vp = VendorProfile::from_ini(path_in_cache, false);
if (cached_vp.config_version == recommended->config_version) {
updates.emplace_back(std::move(path_in_cache), bundle_path, *recommended);
}
}
}
return updates;
}
void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) const
{
if (snapshot) {
SnapshotDB::singleton().take_snapshot(*GUI::get_app_config(), Snapshot::SNAPSHOT_UPGRADE);
}
for (const auto &update : updates) {
fs::copy_file(update.source, update.target, fs::copy_option::overwrite_if_exists);
PresetBundle bundle;
bundle.load_configbundle(update.target.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM);
auto preset_remover = [](const Preset &preset) {
fs::remove(preset.file);
};
for (const auto &preset : bundle.prints) { preset_remover(preset); }
for (const auto &preset : bundle.filaments) { preset_remover(preset); }
for (const auto &preset : bundle.printers) { preset_remover(preset); }
}
}
PresetUpdater::PresetUpdater(int version_online_event) :
p(new priv(version_online_event))
{}
// Public
PresetUpdater::~PresetUpdater()
{
if (p && p->thread.joinable()) {
p->cancel = true;
p->thread.join();
}
}
void PresetUpdater::sync(PresetBundle *preset_bundle)
{
p->set_download_prefs(GUI::get_app_config());
if (!p->enabled_version_check && !p->enabled_config_update) { return; }
// Copy the whole vendors data for use in the background thread
// Unfortunatelly as of C++11, it needs to be copied again
// into the closure (but perhaps the compiler can elide this).
std::set<VendorProfile> vendors = preset_bundle->vendors;
p->thread = std::move(std::thread([this, vendors]() {
this->p->prune_tmps();
this->p->sync_version();
this->p->sync_config(std::move(vendors));
}));
}
void PresetUpdater::slic3r_update_notify()
{
if (! p->enabled_version_check || p->had_config_update) { return; }
// ^ We don't want to bother the user with updates multiple times, put off till next time.
auto* app_config = GUI::get_app_config();
const auto ver_slic3r = Semver::parse(SLIC3R_VERSION);
const auto ver_online = Semver::parse(app_config->get("version_online"));
if (! ver_slic3r) {
throw std::runtime_error("Could not parse Slic3r version string: " SLIC3R_VERSION);
}
if (ver_online && *ver_online > *ver_slic3r) {
UpdateNotification notification(*ver_slic3r, *ver_online);
notification.ShowModal();
if (notification.disable_version_check()) {
app_config->set("version_check", "0");
p->enabled_version_check = false;
}
}
}
void PresetUpdater::config_update() const
{
if (! p->enabled_config_update) { return; }
auto updates = p->config_update();
if (updates.size() > 0) {
const auto msg = _(L("Configuration update is available. Would you like to install it?"));
auto ext_msg = _(L(
"Note that a full configuration snapshot will be created first. It can then be restored at any time "
"should there be a problem with the new version.\n\n"
"Updated configuration bundles:\n"
));
for (const auto &update : updates) {
ext_msg += update.target.stem().string() + " " + update.version.config_version.to_string();
if (! update.version.comment.empty()) {
ext_msg += std::string(" (") + update.version.comment + ")";
}
ext_msg += "\n";
}
wxMessageDialog dlg(NULL, msg, _(L("Configuration update")), wxYES_NO|wxCENTRE);
dlg.SetExtendedMessage(ext_msg);
const auto res = dlg.ShowModal();
std::cerr << "After modal" << std::endl;
if (res == wxID_YES) {
// User gave clearance, updates are go
p->perform_updates(std::move(updates));
}
p->had_config_update = true;
}
}
void PresetUpdater::install_bundles_rsrc(std::vector<std::string> &&bundles, bool snapshot)
{
Updates updates;
for (const auto &bundle : bundles) {
auto path_in_rsrc = p->rsrc_path / bundle;
auto path_in_vendors = p->vendor_path / bundle;
updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors));
}
p->perform_updates(std::move(updates), snapshot);
}
}

View File

@ -0,0 +1,34 @@
#ifndef slic3r_PresetUpdate_hpp_
#define slic3r_PresetUpdate_hpp_
#include <memory>
#include <vector>
namespace Slic3r {
class AppConfig;
class PresetBundle;
class PresetUpdater
{
public:
PresetUpdater(int version_online_event);
PresetUpdater(PresetUpdater &&) = delete;
PresetUpdater(const PresetUpdater &) = delete;
PresetUpdater &operator=(PresetUpdater &&) = delete;
PresetUpdater &operator=(const PresetUpdater &) = delete;
~PresetUpdater();
void sync(PresetBundle *preset_bundle);
void slic3r_update_notify();
void config_update() const;
void install_bundles_rsrc(std::vector<std::string> &&bundles, bool snapshot = true);
private:
struct priv;
std::unique_ptr<priv> p;
};
}
#endif

View File

@ -3,6 +3,7 @@
#include <string>
#include <cstring>
#include <ostream>
#include <boost/optional.hpp>
#include <boost/format.hpp>
@ -18,9 +19,22 @@ public:
struct Minor { const int i; Minor(int i) : i(i) {} };
struct Patch { const int i; Patch(int i) : i(i) {} };
Semver() : ver(semver_zero()) {}
Semver(int major, int minor, int patch,
boost::optional<std::string> metadata = boost::none,
boost::optional<std::string> prerelease = boost::none)
{
ver.major = major;
ver.minor = minor;
ver.patch = patch;
ver.metadata = metadata ? std::strcpy(ver.metadata, metadata->c_str()) : nullptr;
ver.prerelease = prerelease ? std::strcpy(ver.prerelease, prerelease->c_str()) : nullptr;
}
static boost::optional<Semver> parse(const std::string &str)
{
semver_t ver;
semver_t ver = semver_zero();
if (::semver_parse(str.c_str(), &ver) == 0) {
return Semver(ver);
} else {
@ -28,11 +42,7 @@ public:
}
}
static const Semver zero()
{
static semver_t ver = { 0, 0, 0, nullptr, nullptr };
return Semver(ver);
}
static const Semver zero() { return Semver(semver_zero()); }
static const Semver inf()
{
@ -46,28 +56,33 @@ public:
return Semver(ver);
}
Semver(Semver &&other) { *this = std::move(other); }
Semver(const Semver &other) { *this = other; }
Semver(Semver &&other) : ver(other.ver) { other.ver = semver_zero(); }
Semver(const Semver &other) : ver(::semver_copy(&other.ver)) {}
Semver &operator=(Semver &&other)
{
::semver_free(&ver);
ver = other.ver;
other.ver.major = other.ver.minor = other.ver.patch = 0;
other.ver.metadata = other.ver.prerelease = nullptr;
other.ver = semver_zero();
return *this;
}
Semver &operator=(const Semver &other)
{
::semver_free(&ver);
ver = other.ver;
if (other.ver.metadata != nullptr) { std::strcpy(ver.metadata, other.ver.metadata); }
if (other.ver.prerelease != nullptr) { std::strcpy(ver.prerelease, other.ver.prerelease); }
ver = ::semver_copy(&other.ver);
return *this;
}
~Semver() { ::semver_free(&ver); }
// const accessors
int maj() const { return ver.major; }
int min() const { return ver.minor; }
int patch() const { return ver.patch; }
const char* prerelease() const { return ver.prerelease; }
const char* metadata() const { return ver.metadata; }
// Comparison
bool operator<(const Semver &b) const { return ::semver_compare(ver, b.ver) == -1; }
bool operator<=(const Semver &b) const { return ::semver_compare(ver, b.ver) <= 0; }
@ -107,6 +122,8 @@ private:
semver_t ver;
Semver(semver_t ver) : ver(ver) {}
static semver_t semver_zero() { return { 0, 0, 0, nullptr, nullptr }; }
};

View File

@ -1,13 +1,18 @@
#include "Time.hpp"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#endif /* WIN32 */
namespace Slic3r {
namespace Utils {
time_t parse_time_ISO8601Z(const std::string &sdate)
{
int y, M, d, h, m;
float s;
if (sscanf(sdate.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s) != 6)
int y, M, d, h, m, s;
if (sscanf(sdate.c_str(), "%04d%02d%02dT%02d%02d%02dZ", &y, &M, &d, &h, &m, &s) != 6)
return (time_t)-1;
struct tm tms;
tms.tm_year = y - 1900; // Year since 1900
@ -15,7 +20,7 @@ time_t parse_time_ISO8601Z(const std::string &sdate)
tms.tm_mday = d; // 1-31
tms.tm_hour = h; // 0-23
tms.tm_min = m; // 0-59
tms.tm_sec = (int)s; // 0-61 (0-60 in C++11)
tms.tm_sec = s; // 0-61 (0-60 in C++11)
return mktime(&tms);
}
@ -23,21 +28,34 @@ std::string format_time_ISO8601Z(time_t time)
{
struct tm tms;
#ifdef WIN32
gmtime_s(time, &tms);
gmtime_s(&tms, &time);
#else
gmtime_r(&tms, time);
gmtime_r(&time, &tms);
#endif
char buf[128];
sprintf(buf, "%d-%d-%dT%d:%d:%fZ",
tms.tm_year + 1900
tms.tm_mon + 1
tms.tm_mday
tms.tm_hour
tms.tm_min
sprintf(buf, "%04d%02d%02dT%02d%02d%02dZ",
tms.tm_year + 1900,
tms.tm_mon + 1,
tms.tm_mday,
tms.tm_hour,
tms.tm_min,
tms.tm_sec);
return buf;
}
std::string format_local_date_time(time_t time)
{
struct tm tms;
#ifdef WIN32
localtime_s(&tms, &time);
#else
localtime_r(&time, &tms);
#endif
char buf[80];
strftime(buf, 80, "%x %X", &tms);
return buf;
}
time_t get_current_time_utc()
{
#ifdef WIN32
@ -53,11 +71,10 @@ time_t get_current_time_utc()
tm.tm_isdst = -1;
return mktime(&tm);
#else
return gmtime();
const time_t current_local = time(nullptr);
return mktime(gmtime(&current_local));
#endif
}
}; // namespace Utils
}; // namespace Slic3r
#endif /* slic3r_Utils_Time_hpp_ */

View File

@ -13,8 +13,11 @@ namespace Utils {
extern time_t parse_time_ISO8601Z(const std::string &s);
extern std::string format_time_ISO8601Z(time_t time);
// Format the date and time from an UTC time according to the active locales and a local time zone.
extern std::string format_local_date_time(time_t time);
// There is no gmtime() on windows.
time_t get_current_time_utc();
extern time_t get_current_time_utc();
}; // namespace Utils
}; // namespace Slic3r

View File

@ -9,6 +9,9 @@
%package{Slic3r::GUI};
void about()
%code{% Slic3r::GUI::about(); %};
void disable_screensaver()
%code{% Slic3r::GUI::disable_screensaver(); %};
@ -32,9 +35,9 @@ void set_main_frame(SV *ui)
void set_tab_panel(SV *ui)
%code%{ Slic3r::GUI::set_tab_panel((wxNotebook*)wxPli_sv_2_object(aTHX_ ui, "Wx::Notebook")); %};
void add_debug_menu(SV *ui, int event_language_change)
%code%{ Slic3r::GUI::add_debug_menu((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar"), event_language_change); %};
void add_config_menu(SV *ui, int event_preferences_changed, int event_language_change)
%code%{ Slic3r::GUI::add_config_menu((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar"), event_preferences_changed, event_language_change); %};
void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed)
%code%{ Slic3r::GUI::create_preset_tabs(no_controller, event_value_change, event_presets_changed); %};
@ -54,12 +57,27 @@ int combochecklist_get_flags(SV *ui)
void set_app_config(AppConfig *app_config)
%code%{ Slic3r::GUI::set_app_config(app_config); %};
bool check_unsaved_changes()
%code%{ RETVAL=Slic3r::GUI::check_unsaved_changes(); %};
void config_wizard_startup(int app_config_exists)
%code%{
try {
Slic3r::GUI::config_wizard_startup(app_config_exists != 0);
} catch (std::exception& e) {
croak("%s\n", e.what());
}
%};
void open_preferences_dialog(int preferences_event)
%code%{ Slic3r::GUI::open_preferences_dialog(preferences_event); %};
void set_preset_bundle(PresetBundle *preset_bundle)
%code%{ Slic3r::GUI::set_preset_bundle(preset_bundle); %};
void set_preset_updater(PresetUpdater* updater)
%code%{ Slic3r::GUI::set_preset_updater(updater); %};
void add_frequently_changed_parameters(SV *ui_parent, SV *ui_sizer, SV *ui_p_sizer)
%code%{ Slic3r::GUI::add_frequently_changed_parameters((wxWindow*)wxPli_sv_2_object(aTHX_ ui_parent, "Wx::Window"),
(wxBoxSizer*)wxPli_sv_2_object(aTHX_ ui_sizer, "Wx::BoxSizer"),

View File

@ -44,9 +44,6 @@
Ref<Preset> find_preset(char *name, bool first_visible_if_not_found = false) %code%{ RETVAL = THIS->find_preset(name, first_visible_if_not_found); %};
bool current_is_dirty();
std::vector<std::string> current_dirty_options();
void update_tab_ui(SV *ui, bool show_incompatible)
%code%{ auto cb = (wxBitmapComboBox*)wxPli_sv_2_object( aTHX_ ui, "Wx::BitmapComboBox" );
THIS->update_tab_ui(cb, show_incompatible); %};
@ -55,30 +52,6 @@
%code%{ auto cb = (wxBitmapComboBox*)wxPli_sv_2_object( aTHX_ ui, "Wx::BitmapComboBox" );
THIS->update_platter_ui(cb); %};
bool update_dirty_ui(SV *ui)
%code%{ RETVAL = THIS->update_dirty_ui((wxBitmapComboBox*)wxPli_sv_2_object(aTHX_ ui, "Wx::BitmapComboBox")); %};
void select_preset(int idx);
bool select_preset_by_name(char *name) %code%{ RETVAL = THIS->select_preset_by_name(name, true); %};
void discard_current_changes();
void save_current_preset(char *new_name)
%code%{
try {
THIS->save_current_preset(new_name);
} catch (std::exception& e) {
croak("Error saving a preset %s:\n%s\n", new_name, e.what());
}
%};
void delete_current_preset()
%code%{
try {
THIS->delete_current_preset();
} catch (std::exception& e) {
croak("Error deleting a preset file %s:\n%s\n", THIS->get_selected_preset().file.c_str(), e.what());
}
%};
%{
SV*
@ -144,14 +117,6 @@ PresetCollection::arrayref()
croak("Loading of a config bundle %s failed:\n%s\n", path, e.what());
}
%};
void install_vendor_configbundle(const char *path)
%code%{
try {
THIS->install_vendor_configbundle(path);
} catch (std::exception& e) {
croak("Installing a vendor config bundle %s failed:\n%s\n", path, e.what());
}
%};
void export_configbundle(char *path)
%code%{
try {
@ -175,9 +140,6 @@ PresetCollection::arrayref()
std::vector<std::string> filament_presets() %code%{ RETVAL = THIS->filament_presets; %};
void set_filament_preset(int idx, const char *name);
void update_multi_material_filament_presets();
void update_compatible_with_printer(bool select_other_if_incompatible);
Clone<DynamicPrintConfig> full_config() %code%{ RETVAL = THIS->full_config(); %};
@ -185,15 +147,3 @@ PresetCollection::arrayref()
%code%{ auto cb = (wxBitmapComboBox*)wxPli_sv_2_object(aTHX_ ui, "Wx::BitmapComboBox");
THIS->update_platter_filament_ui(extruder_idx, cb); %};
};
%name{Slic3r::GUI::PresetHints} class PresetHints {
PresetHints();
~PresetHints();
static std::string cooling_description(Preset *preset)
%code%{ RETVAL = PresetHints::cooling_description(*preset); %};
static std::string maximum_volumetric_flow_description(PresetBundle *preset)
%code%{ RETVAL = PresetHints::maximum_volumetric_flow_description(*preset); %};
static std::string recommended_thin_wall_thickness(PresetBundle *preset)
%code%{ RETVAL = PresetHints::recommended_thin_wall_thickness(*preset); %};
};

View File

@ -0,0 +1,13 @@
%module{Slic3r::XS};
%{
#include <xsinit.h>
#include "slic3r/Utils/PresetUpdater.hpp"
%}
%name{Slic3r::PresetUpdater} class PresetUpdater {
PresetUpdater(int version_online_event);
void sync(PresetBundle* preset_bundle);
void slic3r_update_notify();
void config_update();
};

View File

@ -231,11 +231,12 @@ PresetCollection* O_OBJECT_SLIC3R
Ref<PresetCollection> O_OBJECT_SLIC3R_T
PresetBundle* O_OBJECT_SLIC3R
Ref<PresetBundle> O_OBJECT_SLIC3R_T
PresetHints* O_OBJECT_SLIC3R
Ref<PresetHints> O_OBJECT_SLIC3R_T
TabIface* O_OBJECT_SLIC3R
Ref<TabIface> O_OBJECT_SLIC3R_T
PresetUpdater* O_OBJECT_SLIC3R
Ref<PresetUpdater> O_OBJECT_SLIC3R_T
OctoPrint* O_OBJECT_SLIC3R
Ref<OctoPrint> O_OBJECT_SLIC3R_T
Clone<OctoPrint> O_OBJECT_SLIC3R_T

View File

@ -208,6 +208,8 @@
%typemap{Ref<PresetCollection>}{simple};
%typemap{PresetBundle*};
%typemap{Ref<PresetBundle>}{simple};
%typemap{PresetUpdater*};
%typemap{Ref<PresetUpdater>}{simple};
%typemap{PresetHints*};
%typemap{Ref<PresetHints>}{simple};
%typemap{TabIface*};