Removed the Perl GUI modules.
This commit is contained in:
parent
4fa2b9e601
commit
586ccad8f0
@ -1,337 +0,0 @@
|
|||||||
package Slic3r::GUI;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use utf8;
|
|
||||||
|
|
||||||
use File::Basename qw(basename);
|
|
||||||
use FindBin;
|
|
||||||
use List::Util qw(first);
|
|
||||||
use Slic3r::GUI::MainFrame;
|
|
||||||
use Slic3r::GUI::Plater;
|
|
||||||
use Slic3r::GUI::Plater::3D;
|
|
||||||
use Slic3r::GUI::Plater::3DPreview;
|
|
||||||
|
|
||||||
use Wx::Locale gettext => 'L';
|
|
||||||
|
|
||||||
our $have_OpenGL = eval "use Slic3r::GUI::3DScene; 1";
|
|
||||||
|
|
||||||
use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow :filedialog :font);
|
|
||||||
use Wx::Event qw(EVT_IDLE EVT_COMMAND EVT_MENU);
|
|
||||||
use base 'Wx::App';
|
|
||||||
|
|
||||||
use constant FILE_WILDCARDS => {
|
|
||||||
known => 'Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.zip.amf;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF;*.prusa;*.PRUSA',
|
|
||||||
stl => 'STL files (*.stl)|*.stl;*.STL',
|
|
||||||
obj => 'OBJ files (*.obj)|*.obj;*.OBJ',
|
|
||||||
amf => 'AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML',
|
|
||||||
threemf => '3MF files (*.3mf)|*.3mf;*.3MF',
|
|
||||||
prusa => 'Prusa Control files (*.prusa)|*.prusa;*.PRUSA',
|
|
||||||
ini => 'INI files *.ini|*.ini;*.INI',
|
|
||||||
gcode => 'G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC',
|
|
||||||
};
|
|
||||||
use constant MODEL_WILDCARD => join '|', @{&FILE_WILDCARDS}{qw(known stl obj amf threemf prusa)};
|
|
||||||
|
|
||||||
# Datadir provided on the command line.
|
|
||||||
our $datadir;
|
|
||||||
our $no_plater;
|
|
||||||
our @cb;
|
|
||||||
|
|
||||||
our $small_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
|
||||||
$small_font->SetPointSize(11) if &Wx::wxMAC;
|
|
||||||
our $small_bold_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
|
||||||
$small_bold_font->SetPointSize(11) if &Wx::wxMAC;
|
|
||||||
$small_bold_font->SetWeight(wxFONTWEIGHT_BOLD);
|
|
||||||
our $medium_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
|
||||||
$medium_font->SetPointSize(12);
|
|
||||||
our $grey = Wx::Colour->new(200,200,200);
|
|
||||||
|
|
||||||
# Events to be sent from a C++ menu implementation:
|
|
||||||
# 1) To inform about a change of the application language.
|
|
||||||
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) = @_;
|
|
||||||
|
|
||||||
$self->SetAppName('Slic3rPE');
|
|
||||||
$self->SetAppDisplayName('Slic3r Prusa Edition');
|
|
||||||
Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
|
|
||||||
|
|
||||||
# Set the Slic3r data directory at the Slic3r XS module.
|
|
||||||
# Unix: ~/.Slic3r
|
|
||||||
# Windows: "C:\Users\username\AppData\Roaming\Slic3r" or "C:\Documents and Settings\username\Application Data\Slic3r"
|
|
||||||
# Mac: "~/Library/Application Support/Slic3r"
|
|
||||||
Slic3r::set_data_dir($datadir || Wx::StandardPaths::Get->GetUserDataDir);
|
|
||||||
Slic3r::GUI::set_wxapp($self);
|
|
||||||
|
|
||||||
$self->{app_config} = Slic3r::GUI::AppConfig->new;
|
|
||||||
Slic3r::GUI::set_app_config($self->{app_config});
|
|
||||||
$self->{preset_bundle} = Slic3r::GUI::PresetBundle->new;
|
|
||||||
Slic3r::GUI::set_preset_bundle($self->{preset_bundle});
|
|
||||||
|
|
||||||
# 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
|
|
||||||
eval { $self->{preset_bundle}->setup_directories() };
|
|
||||||
if ($@) {
|
|
||||||
warn $@ . "\n";
|
|
||||||
fatal_error(undef, $@);
|
|
||||||
}
|
|
||||||
my $app_conf_exists = $self->{app_config}->exists;
|
|
||||||
# load settings
|
|
||||||
$self->{app_config}->load if $app_conf_exists;
|
|
||||||
$self->{app_config}->set('version', $Slic3r::VERSION);
|
|
||||||
$self->{app_config}->save;
|
|
||||||
|
|
||||||
$self->{preset_updater} = Slic3r::PresetUpdater->new($VERSION_ONLINE_EVENT);
|
|
||||||
Slic3r::GUI::set_preset_updater($self->{preset_updater});
|
|
||||||
|
|
||||||
Slic3r::GUI::load_language();
|
|
||||||
|
|
||||||
# Suppress the '- default -' presets.
|
|
||||||
$self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0);
|
|
||||||
eval { $self->{preset_bundle}->load_presets($self->{app_config}); };
|
|
||||||
if ($@) {
|
|
||||||
warn $@ . "\n";
|
|
||||||
show_error(undef, $@);
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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(
|
|
||||||
no_plater => $no_plater,
|
|
||||||
lang_ch_event => $LANGUAGE_CHANGE_EVENT,
|
|
||||||
preferences_event => $PREFERENCES_EVENT,
|
|
||||||
);
|
|
||||||
$self->SetTopWindow($frame);
|
|
||||||
|
|
||||||
# This makes CallAfter() work
|
|
||||||
EVT_IDLE($self->{mainframe}, sub {
|
|
||||||
while (my $cb = shift @cb) {
|
|
||||||
$cb->();
|
|
||||||
}
|
|
||||||
$self->{app_config}->save if $self->{app_config}->dirty;
|
|
||||||
});
|
|
||||||
|
|
||||||
# On OS X the UI tends to freeze in weird ways if modal dialogs (config wizard, update notifications, ...)
|
|
||||||
# are shown before or in the same event callback with the main frame creation.
|
|
||||||
# Therefore we schedule them for later using CallAfter.
|
|
||||||
$self->CallAfter(sub {
|
|
||||||
eval {
|
|
||||||
if (! $self->{preset_updater}->config_update()) {
|
|
||||||
$self->{mainframe}->Close;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if ($@) {
|
|
||||||
show_error(undef, $@);
|
|
||||||
$self->{mainframe}->Close;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$self->CallAfter(sub {
|
|
||||||
if (! Slic3r::GUI::config_wizard_startup($app_conf_exists)) {
|
|
||||||
# Only notify if there was not wizard so as not to bother too much ...
|
|
||||||
$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;
|
|
||||||
});
|
|
||||||
|
|
||||||
# The following event is emited by the C++ menu implementation of preferences change.
|
|
||||||
EVT_COMMAND($self, -1, $PREFERENCES_EVENT, sub{
|
|
||||||
$self->update_ui_from_settings;
|
|
||||||
});
|
|
||||||
|
|
||||||
# The following event is emited by PresetUpdater (C++) to inform about
|
|
||||||
# the newer Slic3r application version avaiable online.
|
|
||||||
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(
|
|
||||||
no_plater => $no_plater,
|
|
||||||
lang_ch_event => $LANGUAGE_CHANGE_EVENT,
|
|
||||||
preferences_event => $PREFERENCES_EVENT,
|
|
||||||
);
|
|
||||||
|
|
||||||
if($topwindow)
|
|
||||||
{
|
|
||||||
$self->SetTopWindow($frame);
|
|
||||||
$topwindow->Destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
EVT_IDLE($self->{mainframe}, sub {
|
|
||||||
while (my $cb = shift @cb) {
|
|
||||||
$cb->();
|
|
||||||
}
|
|
||||||
$self->{app_config}->save if $self->{app_config}->dirty;
|
|
||||||
});
|
|
||||||
|
|
||||||
# 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 {
|
|
||||||
my ($self) = @_;
|
|
||||||
my $slic3r_info = Slic3r::slic3r_info(format => 'html');
|
|
||||||
my $copyright_info = Slic3r::copyright_info(format => 'html');
|
|
||||||
my $system_info = Slic3r::system_info(format => 'html');
|
|
||||||
my $opengl_info;
|
|
||||||
my $opengl_info_txt = '';
|
|
||||||
if (defined($self->{mainframe}) && defined($self->{mainframe}->{plater}) &&
|
|
||||||
defined($self->{mainframe}->{plater}->{canvas3D})) {
|
|
||||||
$opengl_info = Slic3r::GUI::_3DScene::get_gl_info(1, 1);
|
|
||||||
$opengl_info_txt = Slic3r::GUI::_3DScene::get_gl_info(0, 1);
|
|
||||||
}
|
|
||||||
# my $about = Slic3r::GUI::SystemInfo->new(
|
|
||||||
# parent => undef,
|
|
||||||
# slic3r_info => $slic3r_info,
|
|
||||||
# system_info => $system_info,
|
|
||||||
# opengl_info => $opengl_info,
|
|
||||||
# text_info => Slic3r::slic3r_info . Slic3r::system_info . $opengl_info_txt,
|
|
||||||
# );
|
|
||||||
# $about->ShowModal;
|
|
||||||
# $about->Destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
# static method accepting a wxWindow object as first parameter
|
|
||||||
sub catch_error {
|
|
||||||
my ($self, $cb, $message_dialog) = @_;
|
|
||||||
if (my $err = $@) {
|
|
||||||
$cb->() if $cb;
|
|
||||||
$message_dialog
|
|
||||||
? $message_dialog->($err, 'Error', wxOK | wxICON_ERROR)
|
|
||||||
: Slic3r::GUI::show_error($self, $err);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
# static method accepting a wxWindow object as first parameter
|
|
||||||
sub show_error {
|
|
||||||
my ($parent, $message) = @_;
|
|
||||||
Slic3r::GUI::show_error_id($parent ? $parent->GetId() : 0, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
# static method accepting a wxWindow object as first parameter
|
|
||||||
sub show_info {
|
|
||||||
my ($parent, $message, $title) = @_;
|
|
||||||
Wx::MessageDialog->new($parent, $message, $title || 'Notice', wxOK | wxICON_INFORMATION)->ShowModal;
|
|
||||||
}
|
|
||||||
|
|
||||||
# static method accepting a wxWindow object as first parameter
|
|
||||||
sub fatal_error {
|
|
||||||
show_error(@_);
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
# static method accepting a wxWindow object as first parameter
|
|
||||||
sub warning_catcher {
|
|
||||||
my ($self, $message_dialog) = @_;
|
|
||||||
return sub {
|
|
||||||
my $message = shift;
|
|
||||||
return if $message =~ /GLUquadricObjPtr|Attempt to free unreferenced scalar/;
|
|
||||||
my @params = ($message, 'Warning', wxOK | wxICON_WARNING);
|
|
||||||
$message_dialog
|
|
||||||
? $message_dialog->(@params)
|
|
||||||
: Wx::MessageDialog->new($self, @params)->ShowModal;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub notify {
|
|
||||||
my ($self, $message) = @_;
|
|
||||||
|
|
||||||
my $frame = $self->GetTopWindow;
|
|
||||||
# try harder to attract user attention on OS X
|
|
||||||
$frame->RequestUserAttention(&Wx::wxMAC ? wxUSER_ATTENTION_ERROR : wxUSER_ATTENTION_INFO)
|
|
||||||
unless ($frame->IsActive);
|
|
||||||
|
|
||||||
# There used to be notifier using a Growl application for OSX, but Growl is dead.
|
|
||||||
# The notifier also supported the Linux X D-bus notifications, but that support was broken.
|
|
||||||
#TODO use wxNotificationMessage?
|
|
||||||
}
|
|
||||||
|
|
||||||
# Called after the Preferences dialog is closed and the program settings are saved.
|
|
||||||
# Update the UI based on the current preferences.
|
|
||||||
sub update_ui_from_settings {
|
|
||||||
my ($self) = @_;
|
|
||||||
$self->{mainframe}->update_ui_from_settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub open_model {
|
|
||||||
my ($self, $window) = @_;
|
|
||||||
|
|
||||||
my $dlg_title = L('Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):');
|
|
||||||
my $dialog = Wx::FileDialog->new($window // $self->GetTopWindow, $dlg_title,
|
|
||||||
$self->{app_config}->get_last_dir, "",
|
|
||||||
MODEL_WILDCARD, wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST);
|
|
||||||
if ($dialog->ShowModal != wxID_OK) {
|
|
||||||
$dialog->Destroy;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
my @input_files = $dialog->GetPaths;
|
|
||||||
$dialog->Destroy;
|
|
||||||
return @input_files;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub CallAfter {
|
|
||||||
my ($self, $cb) = @_;
|
|
||||||
push @cb, $cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub append_menu_item {
|
|
||||||
my ($self, $menu, $string, $description, $cb, $id, $icon, $kind) = @_;
|
|
||||||
|
|
||||||
$id //= &Wx::NewId();
|
|
||||||
my $item = Wx::MenuItem->new($menu, $id, $string, $description // '', $kind // 0);
|
|
||||||
$self->set_menu_item_icon($item, $icon);
|
|
||||||
$menu->Append($item);
|
|
||||||
|
|
||||||
EVT_MENU($self, $id, $cb);
|
|
||||||
return $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub append_submenu {
|
|
||||||
my ($self, $menu, $string, $description, $submenu, $id, $icon) = @_;
|
|
||||||
|
|
||||||
$id //= &Wx::NewId();
|
|
||||||
my $item = Wx::MenuItem->new($menu, $id, $string, $description // '');
|
|
||||||
$self->set_menu_item_icon($item, $icon);
|
|
||||||
$item->SetSubMenu($submenu);
|
|
||||||
$menu->Append($item);
|
|
||||||
|
|
||||||
return $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_menu_item_icon {
|
|
||||||
my ($self, $menuItem, $icon) = @_;
|
|
||||||
|
|
||||||
# SetBitmap was not available on OS X before Wx 0.9927
|
|
||||||
if ($icon && $menuItem->can('SetBitmap')) {
|
|
||||||
$menuItem->SetBitmap(Wx::Bitmap->new(Slic3r::var($icon), wxBITMAP_TYPE_PNG));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,70 +0,0 @@
|
|||||||
# Implements pure perl packages
|
|
||||||
#
|
|
||||||
# Slic3r::GUI::3DScene::Base;
|
|
||||||
# Slic3r::GUI::3DScene;
|
|
||||||
#
|
|
||||||
# Slic3r::GUI::Plater::3D derives from Slic3r::GUI::3DScene,
|
|
||||||
# Slic3r::GUI::Plater::3DPreview,
|
|
||||||
# Slic3r::GUI::Plater::ObjectCutDialog and Slic3r::GUI::Plater::ObjectPartsPanel
|
|
||||||
# own $self->{canvas} of the Slic3r::GUI::3DScene type.
|
|
||||||
#
|
|
||||||
# Therefore the 3DScene supports renderng of STLs, extrusions and cutting planes,
|
|
||||||
# and camera manipulation.
|
|
||||||
|
|
||||||
package Slic3r::GUI::3DScene::Base;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Wx qw(wxTheApp :timer :bitmap :icon :dialog);
|
|
||||||
# must load OpenGL *before* Wx::GLCanvas
|
|
||||||
use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants);
|
|
||||||
use base qw(Wx::GLCanvas Class::Accessor);
|
|
||||||
use Wx::GLCanvas qw(:all);
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my ($class, $parent) = @_;
|
|
||||||
|
|
||||||
# We can only enable multi sample anti aliasing wih wxWidgets 3.0.3 and with a hacked Wx::GLCanvas,
|
|
||||||
# which exports some new WX_GL_XXX constants, namely WX_GL_SAMPLE_BUFFERS and WX_GL_SAMPLES.
|
|
||||||
my $can_multisample =
|
|
||||||
! wxTheApp->{app_config}->get('use_legacy_opengl') &&
|
|
||||||
Wx::wxVERSION >= 3.000003 &&
|
|
||||||
defined Wx::GLCanvas->can('WX_GL_SAMPLE_BUFFERS') &&
|
|
||||||
defined Wx::GLCanvas->can('WX_GL_SAMPLES');
|
|
||||||
my $attrib = [WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24];
|
|
||||||
if ($can_multisample) {
|
|
||||||
# Request a window with multi sampled anti aliasing. This is a new feature in Wx 3.0.3 (backported from 3.1.0).
|
|
||||||
# Use eval to avoid compilation, if the subs WX_GL_SAMPLE_BUFFERS and WX_GL_SAMPLES are missing.
|
|
||||||
eval 'push(@$attrib, (WX_GL_SAMPLE_BUFFERS, 1, WX_GL_SAMPLES, 4));';
|
|
||||||
}
|
|
||||||
# wxWidgets expect the attrib list to be ended by zero.
|
|
||||||
push(@$attrib, 0);
|
|
||||||
|
|
||||||
# we request a depth buffer explicitely because it looks like it's not created by
|
|
||||||
# default on Linux, causing transparency issues
|
|
||||||
my $self = $class->SUPER::new($parent, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize, 0, "", $attrib);
|
|
||||||
|
|
||||||
Slic3r::GUI::_3DScene::add_canvas($self);
|
|
||||||
Slic3r::GUI::_3DScene::allow_multisample($self, $can_multisample);
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub Destroy {
|
|
||||||
my ($self) = @_;
|
|
||||||
Slic3r::GUI::_3DScene::remove_canvas($self);
|
|
||||||
return $self->SUPER::Destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
# The 3D canvas to display objects and tool paths.
|
|
||||||
package Slic3r::GUI::3DScene;
|
|
||||||
use base qw(Slic3r::GUI::3DScene::Base);
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my $class = shift;
|
|
||||||
|
|
||||||
my $self = $class->SUPER::new(@_);
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,644 +0,0 @@
|
|||||||
# The main frame, the parent of all.
|
|
||||||
|
|
||||||
package Slic3r::GUI::MainFrame;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use utf8;
|
|
||||||
|
|
||||||
use File::Basename qw(basename dirname);
|
|
||||||
use FindBin;
|
|
||||||
use List::Util qw(min first);
|
|
||||||
use Slic3r::Geometry qw(X Y);
|
|
||||||
use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog :dirdialog
|
|
||||||
:font :icon wxTheApp);
|
|
||||||
use Wx::Event qw(EVT_CLOSE EVT_COMMAND EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED);
|
|
||||||
use base 'Wx::Frame';
|
|
||||||
|
|
||||||
use Wx::Locale gettext => 'L';
|
|
||||||
|
|
||||||
our $qs_last_input_file;
|
|
||||||
our $qs_last_output_file;
|
|
||||||
our $last_config;
|
|
||||||
our $appController;
|
|
||||||
|
|
||||||
# Events to be sent from a C++ Tab implementation:
|
|
||||||
# 1) To inform about a change of a configuration value.
|
|
||||||
our $VALUE_CHANGE_EVENT = Wx::NewEventType;
|
|
||||||
# 2) To inform about a preset selection change or a "modified" status change.
|
|
||||||
our $PRESETS_CHANGED_EVENT = Wx::NewEventType;
|
|
||||||
# 3) To update the status bar with the progress information.
|
|
||||||
our $PROGRESS_BAR_EVENT = Wx::NewEventType;
|
|
||||||
# 4) To display an error dialog box from a thread on the UI thread.
|
|
||||||
our $ERROR_EVENT = Wx::NewEventType;
|
|
||||||
# 5) To inform about a change of object selection
|
|
||||||
our $OBJECT_SELECTION_CHANGED_EVENT = Wx::NewEventType;
|
|
||||||
# 6) To inform about a change of object settings
|
|
||||||
our $OBJECT_SETTINGS_CHANGED_EVENT = Wx::NewEventType;
|
|
||||||
# 7) To inform about a remove of object
|
|
||||||
our $OBJECT_REMOVE_EVENT = Wx::NewEventType;
|
|
||||||
# 8) To inform about a update of the scene
|
|
||||||
our $UPDATE_SCENE_EVENT = Wx::NewEventType;
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my ($class, %params) = @_;
|
|
||||||
|
|
||||||
my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE);
|
|
||||||
Slic3r::GUI::set_main_frame($self);
|
|
||||||
|
|
||||||
$appController = Slic3r::AppController->new();
|
|
||||||
|
|
||||||
if ($^O eq 'MSWin32') {
|
|
||||||
# Load the icon either from the exe, or from the ico file.
|
|
||||||
my $iconfile = Slic3r::decode_path($FindBin::Bin) . '\slic3r.exe';
|
|
||||||
$iconfile = Slic3r::var("Slic3r.ico") unless -f $iconfile;
|
|
||||||
$self->SetIcon(Wx::Icon->new($iconfile, wxBITMAP_TYPE_ICO));
|
|
||||||
} else {
|
|
||||||
$self->SetIcon(Wx::Icon->new(Slic3r::var("Slic3r_128px.png"), wxBITMAP_TYPE_PNG));
|
|
||||||
}
|
|
||||||
|
|
||||||
# store input params
|
|
||||||
$self->{no_plater} = $params{no_plater};
|
|
||||||
$self->{loaded} = 0;
|
|
||||||
$self->{lang_ch_event} = $params{lang_ch_event};
|
|
||||||
$self->{preferences_event} = $params{preferences_event};
|
|
||||||
|
|
||||||
# initialize tabpanel and menubar
|
|
||||||
$self->_init_tabpanel;
|
|
||||||
$self->_init_menubar;
|
|
||||||
|
|
||||||
# set default tooltip timer in msec
|
|
||||||
# SetAutoPop supposedly accepts long integers but some bug doesn't allow for larger values
|
|
||||||
# (SetAutoPop is not available on GTK.)
|
|
||||||
eval { Wx::ToolTip::SetAutoPop(32767) };
|
|
||||||
|
|
||||||
# initialize status bar
|
|
||||||
$self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new();
|
|
||||||
$self->{statusbar}->Embed;
|
|
||||||
$self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases"));
|
|
||||||
# Make the global status bar and its progress indicator available in C++
|
|
||||||
Slic3r::GUI::set_progress_status_bar($self->{statusbar});
|
|
||||||
$appController->set_global_progress_indicator($self->{statusbar});
|
|
||||||
|
|
||||||
$appController->set_model($self->{plater}->{model});
|
|
||||||
$appController->set_print($self->{plater}->{print});
|
|
||||||
|
|
||||||
$self->{plater}->{appController} = $appController;
|
|
||||||
|
|
||||||
$self->{loaded} = 1;
|
|
||||||
|
|
||||||
# initialize layout
|
|
||||||
{
|
|
||||||
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
|
||||||
$sizer->Add($self->{tabpanel}, 1, wxEXPAND);
|
|
||||||
$sizer->SetSizeHints($self);
|
|
||||||
$self->SetSizer($sizer);
|
|
||||||
$self->Fit;
|
|
||||||
$self->SetMinSize([760, 490]);
|
|
||||||
$self->SetSize($self->GetMinSize);
|
|
||||||
Slic3r::GUI::restore_window_size($self, "main_frame");
|
|
||||||
$self->Show;
|
|
||||||
$self->Layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
# declare events
|
|
||||||
EVT_CLOSE($self, sub {
|
|
||||||
my (undef, $event) = @_;
|
|
||||||
if ($event->CanVeto && !Slic3r::GUI::check_unsaved_changes) {
|
|
||||||
$event->Veto;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
# save window size
|
|
||||||
Slic3r::GUI::save_window_size($self, "main_frame");
|
|
||||||
# Save the slic3r.ini. Usually the ini file is saved from "on idle" callback,
|
|
||||||
# but in rare cases it may not have been called yet.
|
|
||||||
wxTheApp->{app_config}->save;
|
|
||||||
$self->{statusbar}->ResetCancelCallback();
|
|
||||||
$self->{plater}->{print} = undef if($self->{plater});
|
|
||||||
Slic3r::GUI::_3DScene::remove_all_canvases();
|
|
||||||
Slic3r::GUI::deregister_on_request_update_callback();
|
|
||||||
# propagate event
|
|
||||||
$event->Skip;
|
|
||||||
});
|
|
||||||
|
|
||||||
$self->update_ui_from_settings;
|
|
||||||
|
|
||||||
Slic3r::GUI::update_mode();
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _init_tabpanel {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
$self->{tabpanel} = my $panel = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL);
|
|
||||||
Slic3r::GUI::set_tab_panel($panel);
|
|
||||||
|
|
||||||
EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{tabpanel}, sub {
|
|
||||||
my $panel = $self->{tabpanel}->GetCurrentPage;
|
|
||||||
$panel->OnActivate if $panel->can('OnActivate');
|
|
||||||
|
|
||||||
for my $tab_name (qw(print filament printer)) {
|
|
||||||
Slic3r::GUI::get_preset_tab("$tab_name")->OnActivate if ("$tab_name" eq $panel->GetName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!$self->{no_plater}) {
|
|
||||||
$panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel,
|
|
||||||
event_object_selection_changed => $OBJECT_SELECTION_CHANGED_EVENT,
|
|
||||||
event_object_settings_changed => $OBJECT_SETTINGS_CHANGED_EVENT,
|
|
||||||
event_remove_object => $OBJECT_REMOVE_EVENT,
|
|
||||||
event_update_scene => $UPDATE_SCENE_EVENT,
|
|
||||||
), L("Plater"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#TODO this is an example of a Slic3r XS interface call to add a new preset editor page to the main view.
|
|
||||||
# The following event is emited by the C++ Tab implementation on config value change.
|
|
||||||
EVT_COMMAND($self, -1, $VALUE_CHANGE_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
my $str = $event->GetString;
|
|
||||||
my ($opt_key, $name) = ($str =~ /(.*) (.*)/);
|
|
||||||
#print "VALUE_CHANGE_EVENT: ", $opt_key, "\n";
|
|
||||||
my $tab = Slic3r::GUI::get_preset_tab($name);
|
|
||||||
my $config = $tab->get_config;
|
|
||||||
if ($self->{plater}) {
|
|
||||||
$self->{plater}->on_config_change($config); # propagate config change events to the plater
|
|
||||||
if ($opt_key eq 'extruders_count'){
|
|
||||||
my $value = $event->GetInt();
|
|
||||||
$self->{plater}->on_extruders_change($value);
|
|
||||||
}
|
|
||||||
if ($opt_key eq 'printer_technology'){
|
|
||||||
my $value = $event->GetInt();# 0 ~ "ptFFF"; 1 ~ "ptSLA"
|
|
||||||
$self->{plater}->show_preset_comboboxes($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# don't save while loading for the first time
|
|
||||||
$self->config->save($Slic3r::GUI::autosave) if $Slic3r::GUI::autosave && $self->{loaded};
|
|
||||||
});
|
|
||||||
# The following event is emited by the C++ Tab implementation on preset selection,
|
|
||||||
# or when the preset's "modified" status changes.
|
|
||||||
EVT_COMMAND($self, -1, $PRESETS_CHANGED_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
my $tab_name = $event->GetString;
|
|
||||||
|
|
||||||
my $tab = Slic3r::GUI::get_preset_tab($tab_name);
|
|
||||||
if ($self->{plater}) {
|
|
||||||
# Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs.
|
|
||||||
my $presets = $tab->get_presets;
|
|
||||||
if (defined $presets){
|
|
||||||
my $reload_dependent_tabs = $tab->get_dependent_tabs;
|
|
||||||
$self->{plater}->update_presets($tab_name, $reload_dependent_tabs, $presets);
|
|
||||||
$self->{plater}->{"selected_item_$tab_name"} = $tab->get_selected_preset_item;
|
|
||||||
if ($tab_name eq 'printer') {
|
|
||||||
# Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
|
|
||||||
for my $tab_name_other (qw(print filament sla_material)) {
|
|
||||||
# If the printer tells us that the print or filament preset has been switched or invalidated,
|
|
||||||
# refresh the print or filament tab page. Otherwise just refresh the combo box.
|
|
||||||
my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs})))
|
|
||||||
? 'load_current_preset' : 'update_tab_ui';
|
|
||||||
$self->{options_tabs}{$tab_name_other}->$update_action;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$self->{plater}->on_config_change($tab->get_config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
# The following event is emited by the C++ Tab implementation on object selection change.
|
|
||||||
EVT_COMMAND($self, -1, $OBJECT_SELECTION_CHANGED_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
my $obj_idx = $event->GetId;
|
|
||||||
# my $child = $event->GetInt == 1 ? 1 : undef;
|
|
||||||
# $self->{plater}->select_object($obj_idx < 0 ? undef: $obj_idx, $child);
|
|
||||||
# $self->{plater}->item_changed_selection($obj_idx);
|
|
||||||
|
|
||||||
my $vol_idx = $event->GetInt;
|
|
||||||
$self->{plater}->select_object_from_cpp($obj_idx < 0 ? undef: $obj_idx, $vol_idx<0 ? -1 : $vol_idx);
|
|
||||||
});
|
|
||||||
|
|
||||||
# The following event is emited by the C++ GUI implementation on object settings change.
|
|
||||||
EVT_COMMAND($self, -1, $OBJECT_SETTINGS_CHANGED_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
|
|
||||||
my $line = $event->GetString;
|
|
||||||
my ($obj_idx, $parts_changed, $part_settings_changed) = split('',$line);
|
|
||||||
|
|
||||||
$self->{plater}->changed_object_settings($obj_idx, $parts_changed, $part_settings_changed);
|
|
||||||
});
|
|
||||||
|
|
||||||
# The following event is emited by the C++ GUI implementation on object remove.
|
|
||||||
EVT_COMMAND($self, -1, $OBJECT_REMOVE_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
$self->{plater}->remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
# The following event is emited by the C++ GUI implementation on extruder change for object.
|
|
||||||
EVT_COMMAND($self, -1, $UPDATE_SCENE_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
$self->{plater}->update();
|
|
||||||
});
|
|
||||||
|
|
||||||
Slic3r::GUI::create_preset_tabs($VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT);
|
|
||||||
$self->{options_tabs} = {};
|
|
||||||
for my $tab_name (qw(print filament sla_material printer)) {
|
|
||||||
$self->{options_tabs}{$tab_name} = Slic3r::GUI::get_preset_tab("$tab_name");
|
|
||||||
}
|
|
||||||
|
|
||||||
# Update progress bar with an event sent by the slicing core.
|
|
||||||
EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
if (defined $self->{progress_dialog}) {
|
|
||||||
# If a progress dialog is open, update it.
|
|
||||||
$self->{progress_dialog}->Update($event->GetInt, $event->GetString . "…");
|
|
||||||
} else {
|
|
||||||
# Otherwise update the main window status bar.
|
|
||||||
$self->{statusbar}->SetProgress($event->GetInt);
|
|
||||||
$self->{statusbar}->SetStatusText($event->GetString . "…");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
EVT_COMMAND($self, -1, $ERROR_EVENT, sub {
|
|
||||||
my ($self, $event) = @_;
|
|
||||||
Slic3r::GUI::show_error($self, $event->GetString);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($self->{plater}) {
|
|
||||||
$self->{plater}->on_select_preset(sub {
|
|
||||||
my ($group, $name) = @_;
|
|
||||||
$self->{options_tabs}{$group}->select_preset($name);
|
|
||||||
});
|
|
||||||
# load initial config
|
|
||||||
my $full_config = wxTheApp->{preset_bundle}->full_config;
|
|
||||||
$self->{plater}->on_config_change($full_config);
|
|
||||||
|
|
||||||
# Show a correct number of filament fields.
|
|
||||||
if (defined $full_config->nozzle_diameter){ # nozzle_diameter is undefined when SLA printer is selected
|
|
||||||
$self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter}));
|
|
||||||
}
|
|
||||||
|
|
||||||
# Show correct preset comboboxes according to the printer_technology
|
|
||||||
$self->{plater}->show_preset_comboboxes(($full_config->printer_technology eq "FFF") ? 0 : 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _init_menubar {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
# File menu
|
|
||||||
my $fileMenu = Wx::Menu->new;
|
|
||||||
{
|
|
||||||
wxTheApp->append_menu_item($fileMenu, L("Open STL/OBJ/AMF/3MF…\tCtrl+O"), L('Open a model'), sub {
|
|
||||||
$self->{plater}->add if $self->{plater};
|
|
||||||
}, undef, undef); #'brick_add.png');
|
|
||||||
$self->_append_menu_item($fileMenu, L("&Load Config…\tCtrl+L"), L('Load exported configuration file'), sub {
|
|
||||||
$self->load_config_file;
|
|
||||||
}, undef, 'plugin_add.png');
|
|
||||||
$self->_append_menu_item($fileMenu, L("&Export Config…\tCtrl+E"), L('Export current configuration to file'), sub {
|
|
||||||
$self->export_config;
|
|
||||||
}, undef, 'plugin_go.png');
|
|
||||||
$self->_append_menu_item($fileMenu, L("&Load Config Bundle…"), L('Load presets from a bundle'), sub {
|
|
||||||
$self->load_configbundle;
|
|
||||||
}, undef, 'lorry_add.png');
|
|
||||||
$self->_append_menu_item($fileMenu, L("&Export Config Bundle…"), L('Export all presets to file'), sub {
|
|
||||||
$self->export_configbundle;
|
|
||||||
}, undef, 'lorry_go.png');
|
|
||||||
$fileMenu->AppendSeparator();
|
|
||||||
$self->_append_menu_item($fileMenu, L("Slice to PNG…"), L('Slice file to a set of PNG files'), sub {
|
|
||||||
$self->slice_to_png;
|
|
||||||
}, undef, 'shape_handles.png');
|
|
||||||
$self->{menu_item_reslice_now} = $self->_append_menu_item(
|
|
||||||
$fileMenu, L("(&Re)Slice Now\tCtrl+S"), L('Start new slicing process'),
|
|
||||||
sub { $self->reslice_now; }, undef, 'shape_handles.png');
|
|
||||||
$fileMenu->AppendSeparator();
|
|
||||||
$self->_append_menu_item($fileMenu, L("Repair STL file…"), L('Automatically repair an STL file'), sub {
|
|
||||||
$self->repair_stl;
|
|
||||||
}, undef, 'wrench.png');
|
|
||||||
$fileMenu->AppendSeparator();
|
|
||||||
$self->_append_menu_item($fileMenu, L("&Quit"), L('Quit Slic3r'), sub {
|
|
||||||
$self->Close(0);
|
|
||||||
}, wxID_EXIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Plater menu
|
|
||||||
unless ($self->{no_plater}) {
|
|
||||||
my $plater = $self->{plater};
|
|
||||||
|
|
||||||
$self->{plater_menu} = Wx::Menu->new;
|
|
||||||
$self->_append_menu_item($self->{plater_menu}, L("Export G-code..."), L('Export current plate as G-code'), sub {
|
|
||||||
$plater->export_gcode;
|
|
||||||
}, undef, 'cog_go.png');
|
|
||||||
$self->_append_menu_item($self->{plater_menu}, L("Export plate as STL..."), L('Export current plate as STL'), sub {
|
|
||||||
$plater->export_stl;
|
|
||||||
}, undef, 'brick_go.png');
|
|
||||||
$self->_append_menu_item($self->{plater_menu}, L("Export plate as AMF..."), L('Export current plate as AMF'), sub {
|
|
||||||
$plater->export_amf;
|
|
||||||
}, undef, 'brick_go.png');
|
|
||||||
$self->_append_menu_item($self->{plater_menu}, L("Export plate as 3MF..."), L('Export current plate as 3MF'), sub {
|
|
||||||
$plater->export_3mf;
|
|
||||||
}, undef, 'brick_go.png');
|
|
||||||
|
|
||||||
$self->{object_menu} = $self->{plater}->object_menu;
|
|
||||||
$self->on_plater_selection_changed(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Window menu
|
|
||||||
my $windowMenu = Wx::Menu->new;
|
|
||||||
{
|
|
||||||
my $tab_offset = 0;
|
|
||||||
if (!$self->{no_plater}) {
|
|
||||||
$self->_append_menu_item($windowMenu, L("Select &Plater Tab\tCtrl+1"), L('Show the plater'), sub {
|
|
||||||
$self->select_tab(0);
|
|
||||||
}, undef, 'application_view_tile.png');
|
|
||||||
$tab_offset += 1;
|
|
||||||
}
|
|
||||||
if (!$self->{no_controller}) {
|
|
||||||
$self->_append_menu_item($windowMenu, L("Select &Controller Tab\tCtrl+T"), L('Show the printer controller'), sub {
|
|
||||||
$self->select_tab(1);
|
|
||||||
}, undef, 'printer_empty.png');
|
|
||||||
$tab_offset += 1;
|
|
||||||
}
|
|
||||||
if ($tab_offset > 0) {
|
|
||||||
$windowMenu->AppendSeparator();
|
|
||||||
}
|
|
||||||
$self->_append_menu_item($windowMenu, L("Select P&rint Settings Tab\tCtrl+2"), L('Show the print settings'), sub {
|
|
||||||
$self->select_tab($tab_offset+0);
|
|
||||||
}, undef, 'cog.png');
|
|
||||||
$self->_append_menu_item($windowMenu, L("Select &Filament Settings Tab\tCtrl+3"), L('Show the filament settings'), sub {
|
|
||||||
$self->select_tab($tab_offset+1);
|
|
||||||
}, undef, 'spool.png');
|
|
||||||
$self->_append_menu_item($windowMenu, L("Select Print&er Settings Tab\tCtrl+4"), L('Show the printer settings'), sub {
|
|
||||||
$self->select_tab($tab_offset+2);
|
|
||||||
}, undef, 'printer_empty.png');
|
|
||||||
}
|
|
||||||
|
|
||||||
# View menu
|
|
||||||
if (!$self->{no_plater}) {
|
|
||||||
$self->{viewMenu} = Wx::Menu->new;
|
|
||||||
# \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators,
|
|
||||||
# as the simple numeric accelerators spoil all numeric data entry.
|
|
||||||
# The camera control accelerators are captured by 3DScene Perl module instead.
|
|
||||||
my $accel = ($^O eq 'MSWin32') ? sub { $_[0] . "\t\xA0" . $_[1] } : sub { $_[0] };
|
|
||||||
$self->_append_menu_item($self->{viewMenu}, $accel->(L('Iso'), '0'), L('Iso View') , sub { $self->select_view('iso' ); });
|
|
||||||
$self->_append_menu_item($self->{viewMenu}, $accel->(L('Top'), '1'), L('Top View') , sub { $self->select_view('top' ); });
|
|
||||||
$self->_append_menu_item($self->{viewMenu}, $accel->(L('Bottom'), '2'), L('Bottom View') , sub { $self->select_view('bottom' ); });
|
|
||||||
$self->_append_menu_item($self->{viewMenu}, $accel->(L('Front'), '3'), L('Front View') , sub { $self->select_view('front' ); });
|
|
||||||
$self->_append_menu_item($self->{viewMenu}, $accel->(L('Rear'), '4'), L('Rear View') , sub { $self->select_view('rear' ); });
|
|
||||||
$self->_append_menu_item($self->{viewMenu}, $accel->(L('Left'), '5'), L('Left View') , sub { $self->select_view('left' ); });
|
|
||||||
$self->_append_menu_item($self->{viewMenu}, $accel->(L('Right'), '6'), L('Right View') , sub { $self->select_view('right' ); });
|
|
||||||
}
|
|
||||||
|
|
||||||
# Help menu
|
|
||||||
my $helpMenu = Wx::Menu->new;
|
|
||||||
{
|
|
||||||
$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/');
|
|
||||||
});
|
|
||||||
$self->_append_menu_item($helpMenu, L("Prusa Edition Releases"), L('Open the Prusa Edition releases page in your browser'), sub {
|
|
||||||
Wx::LaunchDefaultBrowser('http://github.com/prusa3d/slic3r/releases');
|
|
||||||
});
|
|
||||||
# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub {
|
|
||||||
# wxTheApp->check_version(1);
|
|
||||||
# });
|
|
||||||
# $versioncheck->Enable(wxTheApp->have_version_check);
|
|
||||||
$self->_append_menu_item($helpMenu, L("Slic3r &Website"), L('Open the Slic3r website in your browser'), sub {
|
|
||||||
Wx::LaunchDefaultBrowser('http://slic3r.org/');
|
|
||||||
});
|
|
||||||
$self->_append_menu_item($helpMenu, L("Slic3r &Manual"), L('Open the Slic3r manual in your browser'), sub {
|
|
||||||
Wx::LaunchDefaultBrowser('http://manual.slic3r.org/');
|
|
||||||
});
|
|
||||||
$helpMenu->AppendSeparator();
|
|
||||||
$self->_append_menu_item($helpMenu, L("System Info"), L('Show system information'), sub {
|
|
||||||
wxTheApp->system_info;
|
|
||||||
});
|
|
||||||
$self->_append_menu_item($helpMenu, L("Show &Configuration Folder"), L('Show user configuration folder (datadir)'), sub {
|
|
||||||
Slic3r::GUI::desktop_open_datadir_folder();
|
|
||||||
});
|
|
||||||
$self->_append_menu_item($helpMenu, L("Report an Issue"), L('Report an issue on the Slic3r Prusa Edition'), sub {
|
|
||||||
Wx::LaunchDefaultBrowser('http://github.com/prusa3d/slic3r/issues/new');
|
|
||||||
});
|
|
||||||
$self->_append_menu_item($helpMenu, L("&About Slic3r"), L('Show about dialog'), sub {
|
|
||||||
Slic3r::GUI::about;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
# menubar
|
|
||||||
# assign menubar to frame after appending items, otherwise special items
|
|
||||||
# will not be handled correctly
|
|
||||||
{
|
|
||||||
my $menubar = Wx::MenuBar->new;
|
|
||||||
$menubar->Append($fileMenu, L("&File"));
|
|
||||||
$menubar->Append($self->{plater_menu}, L("&Plater")) if $self->{plater_menu};
|
|
||||||
$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 additional menus from C++
|
|
||||||
Slic3r::GUI::add_menus($menubar, $self->{preferences_event}, $self->{lang_ch_event});
|
|
||||||
$menubar->Append($helpMenu, L("&Help"));
|
|
||||||
$self->SetMenuBar($menubar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub is_loaded {
|
|
||||||
my ($self) = @_;
|
|
||||||
return $self->{loaded};
|
|
||||||
}
|
|
||||||
|
|
||||||
# Selection of a 3D object changed on the platter.
|
|
||||||
sub on_plater_selection_changed {
|
|
||||||
my ($self, $have_selection) = @_;
|
|
||||||
return if !defined $self->{object_menu};
|
|
||||||
$self->{object_menu}->Enable($_->GetId, $have_selection)
|
|
||||||
for $self->{object_menu}->GetMenuItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub slice_to_png {
|
|
||||||
my $self = shift;
|
|
||||||
$self->{plater}->stop_background_process;
|
|
||||||
$self->{plater}->async_apply_config;
|
|
||||||
$appController->print_ctl()->slice_to_png();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub reslice_now {
|
|
||||||
my ($self) = @_;
|
|
||||||
$self->{plater}->reslice if $self->{plater};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub repair_stl {
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
my $input_file;
|
|
||||||
{
|
|
||||||
my $dialog = Wx::FileDialog->new($self, L('Select the STL file to repair:'),
|
|
||||||
wxTheApp->{app_config}->get_last_dir, "",
|
|
||||||
&Slic3r::GUI::FILE_WILDCARDS->{stl}, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
|
||||||
if ($dialog->ShowModal != wxID_OK) {
|
|
||||||
$dialog->Destroy;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$input_file = $dialog->GetPaths;
|
|
||||||
$dialog->Destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $output_file = $input_file;
|
|
||||||
{
|
|
||||||
$output_file =~ s/\.[sS][tT][lL]$/_fixed.obj/;
|
|
||||||
my $dlg = Wx::FileDialog->new($self, L("Save OBJ file (less prone to coordinate errors than STL) as:"), dirname($output_file),
|
|
||||||
basename($output_file), &Slic3r::GUI::FILE_WILDCARDS->{obj}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
||||||
if ($dlg->ShowModal != wxID_OK) {
|
|
||||||
$dlg->Destroy;
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
$output_file = $dlg->GetPath;
|
|
||||||
$dlg->Destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $tmesh = Slic3r::TriangleMesh->new;
|
|
||||||
$tmesh->ReadSTLFile($input_file);
|
|
||||||
$tmesh->repair;
|
|
||||||
$tmesh->WriteOBJFile($output_file);
|
|
||||||
Slic3r::GUI::show_info($self, L("Your file was repaired."), L("Repair"));
|
|
||||||
}
|
|
||||||
|
|
||||||
sub export_config {
|
|
||||||
my $self = shift;
|
|
||||||
# Generate a cummulative configuration for the selected print, filaments and printer.
|
|
||||||
my $config = wxTheApp->{preset_bundle}->full_config();
|
|
||||||
# Validate the cummulative configuration.
|
|
||||||
eval { $config->validate; };
|
|
||||||
Slic3r::GUI::catch_error($self) and return;
|
|
||||||
# Ask user for the file name for the config file.
|
|
||||||
my $dlg = Wx::FileDialog->new($self, L('Save configuration as:'),
|
|
||||||
$last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
|
|
||||||
$last_config ? basename($last_config) : "config.ini",
|
|
||||||
&Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
||||||
my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef;
|
|
||||||
$dlg->Destroy;
|
|
||||||
if (defined $file) {
|
|
||||||
wxTheApp->{app_config}->update_config_dir(dirname($file));
|
|
||||||
$last_config = $file;
|
|
||||||
$config->save($file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Load a config file containing a Print, Filament & Printer preset.
|
|
||||||
sub load_config_file {
|
|
||||||
my ($self, $file) = @_;
|
|
||||||
if (!$file) {
|
|
||||||
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",
|
|
||||||
'INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g', wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
|
||||||
return unless $dlg->ShowModal == wxID_OK;
|
|
||||||
$file = $dlg->GetPaths;
|
|
||||||
$dlg->Destroy;
|
|
||||||
}
|
|
||||||
eval { wxTheApp->{preset_bundle}->load_config_file($file); };
|
|
||||||
# Dont proceed further if the config file cannot be loaded.
|
|
||||||
return if Slic3r::GUI::catch_error($self);
|
|
||||||
$_->load_current_preset for (values %{$self->{options_tabs}});
|
|
||||||
wxTheApp->{app_config}->update_config_dir(dirname($file));
|
|
||||||
$last_config = $file;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub export_configbundle {
|
|
||||||
my ($self) = @_;
|
|
||||||
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;
|
|
||||||
# Ask user for a file name.
|
|
||||||
my $dlg = Wx::FileDialog->new($self, L('Save presets bundle as:'),
|
|
||||||
$last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
|
|
||||||
"Slic3r_config_bundle.ini",
|
|
||||||
&Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
||||||
my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef;
|
|
||||||
$dlg->Destroy;
|
|
||||||
if (defined $file) {
|
|
||||||
# Export the config bundle.
|
|
||||||
wxTheApp->{app_config}->update_config_dir(dirname($file));
|
|
||||||
eval { wxTheApp->{preset_bundle}->export_configbundle($file); };
|
|
||||||
Slic3r::GUI::catch_error($self) and return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Loading a config bundle with an external file name used to be used
|
|
||||||
# to auto-install a config bundle on a fresh user account,
|
|
||||||
# but that behavior was not documented and likely buggy.
|
|
||||||
sub load_configbundle {
|
|
||||||
my ($self, $file, $reset_user_profile) = @_;
|
|
||||||
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,
|
|
||||||
"config.ini",
|
|
||||||
&Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
|
||||||
return unless $dlg->ShowModal == wxID_OK;
|
|
||||||
$file = $dlg->GetPaths;
|
|
||||||
$dlg->Destroy;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxTheApp->{app_config}->update_config_dir(dirname($file));
|
|
||||||
|
|
||||||
my $presets_imported = 0;
|
|
||||||
eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file); };
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $message = sprintf L("%d presets successfully imported."), $presets_imported;
|
|
||||||
Slic3r::GUI::show_info($self, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
|
|
||||||
# Also update the platter with the new presets.
|
|
||||||
sub load_config {
|
|
||||||
my ($self, $config) = @_;
|
|
||||||
$_->load_config($config) foreach values %{$self->{options_tabs}};
|
|
||||||
$self->{plater}->on_config_change($config) if $self->{plater};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub select_tab {
|
|
||||||
my ($self, $tab) = @_;
|
|
||||||
$self->{tabpanel}->SetSelection($tab);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set a camera direction, zoom to all objects.
|
|
||||||
sub select_view {
|
|
||||||
my ($self, $direction) = @_;
|
|
||||||
if (! $self->{no_plater}) {
|
|
||||||
$self->{plater}->select_view($direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _append_menu_item {
|
|
||||||
my ($self, $menu, $string, $description, $cb, $id, $icon) = @_;
|
|
||||||
$id //= &Wx::NewId();
|
|
||||||
my $item = $menu->Append($id, $string, $description);
|
|
||||||
$self->_set_menu_item_icon($item, $icon);
|
|
||||||
EVT_MENU($self, $id, $cb);
|
|
||||||
return $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _set_menu_item_icon {
|
|
||||||
my ($self, $menuItem, $icon) = @_;
|
|
||||||
# SetBitmap was not available on OS X before Wx 0.9927
|
|
||||||
if ($icon && $menuItem->can('SetBitmap')) {
|
|
||||||
$menuItem->SetBitmap(Wx::Bitmap->new(Slic3r::var($icon), wxBITMAP_TYPE_PNG));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Called after the Preferences dialog is closed and the program settings are saved.
|
|
||||||
# Update the UI based on the current preferences.
|
|
||||||
sub update_ui_from_settings {
|
|
||||||
my ($self) = @_;
|
|
||||||
$self->{menu_item_reslice_now}->Enable(! wxTheApp->{app_config}->get("background_processing"));
|
|
||||||
$self->{plater}->update_ui_from_settings if ($self->{plater});
|
|
||||||
for my $tab_name (qw(print filament printer)) {
|
|
||||||
$self->{options_tabs}{$tab_name}->update_ui_from_settings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,26 +0,0 @@
|
|||||||
package Slic3r::GUI::Plater::3D;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use utf8;
|
|
||||||
|
|
||||||
use List::Util qw();
|
|
||||||
use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL);
|
|
||||||
use base qw(Slic3r::GUI::3DScene Class::Accessor);
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my $class = shift;
|
|
||||||
my ($parent, $objects, $model, $print, $config) = @_;
|
|
||||||
|
|
||||||
my $self = $class->SUPER::new($parent);
|
|
||||||
Slic3r::GUI::_3DScene::enable_picking($self, 1);
|
|
||||||
Slic3r::GUI::_3DScene::enable_moving($self, 1);
|
|
||||||
Slic3r::GUI::_3DScene::set_select_by($self, 'object');
|
|
||||||
Slic3r::GUI::_3DScene::set_drag_by($self, 'instance');
|
|
||||||
Slic3r::GUI::_3DScene::set_model($self, $model);
|
|
||||||
Slic3r::GUI::_3DScene::set_print($self, $print);
|
|
||||||
Slic3r::GUI::_3DScene::set_config($self, $config);
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,555 +0,0 @@
|
|||||||
package Slic3r::GUI::Plater::3DPreview;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use utf8;
|
|
||||||
|
|
||||||
use Slic3r::Print::State ':steps';
|
|
||||||
use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE wxCB_READONLY);
|
|
||||||
use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX EVT_SIZE);
|
|
||||||
use base qw(Wx::Panel Class::Accessor);
|
|
||||||
|
|
||||||
use Wx::Locale gettext => 'L';
|
|
||||||
|
|
||||||
__PACKAGE__->mk_accessors(qw(print gcode_preview_data enabled _loaded canvas slider_low slider_high single_layer double_slider_sizer));
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my $class = shift;
|
|
||||||
my ($parent, $print, $gcode_preview_data, $config) = @_;
|
|
||||||
|
|
||||||
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition);
|
|
||||||
$self->{config} = $config;
|
|
||||||
$self->{number_extruders} = 1;
|
|
||||||
# Show by feature type by default.
|
|
||||||
$self->{preferred_color_mode} = 'feature';
|
|
||||||
|
|
||||||
# init GUI elements
|
|
||||||
my $canvas = Slic3r::GUI::3DScene->new($self);
|
|
||||||
Slic3r::GUI::_3DScene::enable_shader($canvas, 1);
|
|
||||||
Slic3r::GUI::_3DScene::set_config($canvas, $config);
|
|
||||||
$self->canvas($canvas);
|
|
||||||
# my $slider_low = Wx::Slider->new(
|
|
||||||
# $self, -1,
|
|
||||||
# 0, # default
|
|
||||||
# 0, # min
|
|
||||||
# we set max to a bogus non-zero value because the MSW implementation of wxSlider
|
|
||||||
# will skip drawing the slider if max <= min:
|
|
||||||
# 1, # max
|
|
||||||
# wxDefaultPosition,
|
|
||||||
# wxDefaultSize,
|
|
||||||
# wxVERTICAL | wxSL_INVERSE,
|
|
||||||
# );
|
|
||||||
# $self->slider_low($slider_low);
|
|
||||||
# my $slider_high = Wx::Slider->new(
|
|
||||||
# $self, -1,
|
|
||||||
# 0, # default
|
|
||||||
# 0, # min
|
|
||||||
# we set max to a bogus non-zero value because the MSW implementation of wxSlider
|
|
||||||
# will skip drawing the slider if max <= min:
|
|
||||||
# 1, # max
|
|
||||||
# wxDefaultPosition,
|
|
||||||
# wxDefaultSize,
|
|
||||||
# wxVERTICAL | wxSL_INVERSE,
|
|
||||||
# );
|
|
||||||
# $self->slider_high($slider_high);
|
|
||||||
|
|
||||||
# my $z_label_low = $self->{z_label_low} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
|
|
||||||
# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
|
|
||||||
# $z_label_low->SetFont($Slic3r::GUI::small_font);
|
|
||||||
# my $z_label_high = $self->{z_label_high} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
|
|
||||||
# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
|
|
||||||
# $z_label_high->SetFont($Slic3r::GUI::small_font);
|
|
||||||
|
|
||||||
# my $z_label_low_idx = $self->{z_label_low_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
|
|
||||||
# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
|
|
||||||
# $z_label_low_idx->SetFont($Slic3r::GUI::small_font);
|
|
||||||
# my $z_label_high_idx = $self->{z_label_high_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
|
|
||||||
# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
|
|
||||||
# $z_label_high_idx->SetFont($Slic3r::GUI::small_font);
|
|
||||||
|
|
||||||
# $self->single_layer(0);
|
|
||||||
# my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, L("1 Layer"));
|
|
||||||
|
|
||||||
my $label_view_type = $self->{label_view_type} = Wx::StaticText->new($self, -1, L("View"));
|
|
||||||
|
|
||||||
my $choice_view_type = $self->{choice_view_type} = Wx::Choice->new($self, -1);
|
|
||||||
$choice_view_type->Append(L("Feature type"));
|
|
||||||
$choice_view_type->Append(L("Height"));
|
|
||||||
$choice_view_type->Append(L("Width"));
|
|
||||||
$choice_view_type->Append(L("Speed"));
|
|
||||||
$choice_view_type->Append(L("Volumetric flow rate"));
|
|
||||||
$choice_view_type->Append(L("Tool"));
|
|
||||||
$choice_view_type->SetSelection(0);
|
|
||||||
|
|
||||||
# the following value needs to be changed if new items are added into $choice_view_type before "Tool"
|
|
||||||
$self->{tool_idx} = 5;
|
|
||||||
|
|
||||||
my $label_show_features = $self->{label_show_features} = Wx::StaticText->new($self, -1, L("Show"));
|
|
||||||
|
|
||||||
my $combochecklist_features = $self->{combochecklist_features} = Wx::ComboCtrl->new();
|
|
||||||
$combochecklist_features->Create($self, -1, L("Feature types"), wxDefaultPosition, [200, -1], wxCB_READONLY);
|
|
||||||
my $feature_text = L("Feature types");
|
|
||||||
my $feature_items = L("Perimeter")."|"
|
|
||||||
.L("External perimeter")."|"
|
|
||||||
.L("Overhang perimeter")."|"
|
|
||||||
.L("Internal infill")."|"
|
|
||||||
.L("Solid infill")."|"
|
|
||||||
.L("Top solid infill")."|"
|
|
||||||
.L("Bridge infill")."|"
|
|
||||||
.L("Gap fill")."|"
|
|
||||||
.L("Skirt")."|"
|
|
||||||
.L("Support material")."|"
|
|
||||||
.L("Support material interface")."|"
|
|
||||||
.L("Wipe tower")."|"
|
|
||||||
.L("Custom");
|
|
||||||
Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1);
|
|
||||||
|
|
||||||
my $double_slider_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
|
||||||
Slic3r::GUI::create_double_slider($self, $double_slider_sizer, $self->canvas);
|
|
||||||
$self->double_slider_sizer($double_slider_sizer);
|
|
||||||
|
|
||||||
my $checkbox_travel = $self->{checkbox_travel} = Wx::CheckBox->new($self, -1, L("Travel"));
|
|
||||||
my $checkbox_retractions = $self->{checkbox_retractions} = Wx::CheckBox->new($self, -1, L("Retractions"));
|
|
||||||
my $checkbox_unretractions = $self->{checkbox_unretractions} = Wx::CheckBox->new($self, -1, L("Unretractions"));
|
|
||||||
my $checkbox_shells = $self->{checkbox_shells} = Wx::CheckBox->new($self, -1, L("Shells"));
|
|
||||||
|
|
||||||
# my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
|
||||||
# my $vsizer = Wx::BoxSizer->new(wxVERTICAL);
|
|
||||||
# my $vsizer_outer = Wx::BoxSizer->new(wxVERTICAL);
|
|
||||||
# $vsizer->Add($slider_low, 3, wxALIGN_CENTER_HORIZONTAL, 0);
|
|
||||||
# $vsizer->Add($z_label_low_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
|
|
||||||
# $vsizer->Add($z_label_low, 0, wxALIGN_CENTER_HORIZONTAL, 0);
|
|
||||||
# $hsizer->Add($vsizer, 0, wxEXPAND, 0);
|
|
||||||
# $vsizer = Wx::BoxSizer->new(wxVERTICAL);
|
|
||||||
# $vsizer->Add($slider_high, 3, wxALIGN_CENTER_HORIZONTAL, 0);
|
|
||||||
# $vsizer->Add($z_label_high_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
|
|
||||||
# $vsizer->Add($z_label_high, 0, 0, 0);
|
|
||||||
# $hsizer->Add($vsizer, 0, wxEXPAND, 0);
|
|
||||||
# $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0);
|
|
||||||
# $vsizer_outer->Add($double_slider_sizer, 3, wxEXPAND, 0);
|
|
||||||
# $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5);
|
|
||||||
|
|
||||||
my $bottom_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
|
||||||
$bottom_sizer->Add($label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
$bottom_sizer->Add($choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
$bottom_sizer->AddSpacer(10);
|
|
||||||
$bottom_sizer->Add($label_show_features, 0, wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
$bottom_sizer->Add($combochecklist_features, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
$bottom_sizer->AddSpacer(20);
|
|
||||||
$bottom_sizer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
$bottom_sizer->AddSpacer(10);
|
|
||||||
$bottom_sizer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
$bottom_sizer->AddSpacer(10);
|
|
||||||
$bottom_sizer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
$bottom_sizer->AddSpacer(10);
|
|
||||||
$bottom_sizer->Add($checkbox_shells, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
|
|
||||||
my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
|
||||||
$sizer->Add($canvas, 1, wxALL | wxEXPAND, 0);
|
|
||||||
# $sizer->Add($vsizer_outer, 0, wxTOP | wxBOTTOM | wxEXPAND, 5);
|
|
||||||
$sizer->Add($double_slider_sizer, 0, wxEXPAND, 0);#wxTOP | wxBOTTOM | wxEXPAND, 5);
|
|
||||||
|
|
||||||
my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
|
|
||||||
$main_sizer->Add($sizer, 1, wxALL | wxEXPAND, 0);
|
|
||||||
$main_sizer->Add($bottom_sizer, 0, wxALL | wxEXPAND, 0);
|
|
||||||
|
|
||||||
# EVT_SLIDER($self, $slider_low, sub {
|
|
||||||
# $slider_high->SetValue($slider_low->GetValue) if $self->single_layer;
|
|
||||||
# $self->set_z_idx_low ($slider_low ->GetValue)
|
|
||||||
# });
|
|
||||||
# EVT_SLIDER($self, $slider_high, sub {
|
|
||||||
# $slider_low->SetValue($slider_high->GetValue) if $self->single_layer;
|
|
||||||
# $self->set_z_idx_high($slider_high->GetValue)
|
|
||||||
# });
|
|
||||||
# EVT_KEY_DOWN($canvas, sub {
|
|
||||||
# my ($s, $event) = @_;
|
|
||||||
# Slic3r::GUI::update_double_slider_from_canvas($event);
|
|
||||||
# my $key = $event->GetKeyCode;
|
|
||||||
# if ($event->HasModifiers) {
|
|
||||||
# $event->Skip;
|
|
||||||
# } else {
|
|
||||||
# if ($key == ord('U')) {
|
|
||||||
# $slider_high->SetValue($slider_high->GetValue + 1);
|
|
||||||
# $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
|
|
||||||
# $self->set_z_idx_high($slider_high->GetValue);
|
|
||||||
# } elsif ($key == ord('D')) {
|
|
||||||
# $slider_high->SetValue($slider_high->GetValue - 1);
|
|
||||||
# $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
|
|
||||||
# $self->set_z_idx_high($slider_high->GetValue);
|
|
||||||
# } elsif ($key == ord('S')) {
|
|
||||||
# $checkbox_singlelayer->SetValue(! $checkbox_singlelayer->GetValue());
|
|
||||||
# $self->single_layer($checkbox_singlelayer->GetValue());
|
|
||||||
# if ($self->single_layer) {
|
|
||||||
# $slider_low->SetValue($slider_high->GetValue);
|
|
||||||
# $self->set_z_idx_high($slider_high->GetValue);
|
|
||||||
# }
|
|
||||||
# } else {
|
|
||||||
# $event->Skip;
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# });
|
|
||||||
# EVT_KEY_DOWN($slider_low, sub {
|
|
||||||
# my ($s, $event) = @_;
|
|
||||||
# my $key = $event->GetKeyCode;
|
|
||||||
# if ($event->HasModifiers) {
|
|
||||||
# $event->Skip;
|
|
||||||
# } else {
|
|
||||||
# if ($key == WXK_LEFT) {
|
|
||||||
# } elsif ($key == WXK_RIGHT) {
|
|
||||||
# $slider_high->SetFocus;
|
|
||||||
# } else {
|
|
||||||
# $event->Skip;
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# });
|
|
||||||
# EVT_KEY_DOWN($slider_high, sub {
|
|
||||||
# my ($s, $event) = @_;
|
|
||||||
# my $key = $event->GetKeyCode;
|
|
||||||
# if ($event->HasModifiers) {
|
|
||||||
# $event->Skip;
|
|
||||||
# } else {
|
|
||||||
# if ($key == WXK_LEFT) {
|
|
||||||
# $slider_low->SetFocus;
|
|
||||||
# } elsif ($key == WXK_RIGHT) {
|
|
||||||
# } else {
|
|
||||||
# $event->Skip;
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# });
|
|
||||||
# EVT_CHECKBOX($self, $checkbox_singlelayer, sub {
|
|
||||||
# $self->single_layer($checkbox_singlelayer->GetValue());
|
|
||||||
# if ($self->single_layer) {
|
|
||||||
# $slider_low->SetValue($slider_high->GetValue);
|
|
||||||
# $self->set_z_idx_high($slider_high->GetValue);
|
|
||||||
# }
|
|
||||||
# });
|
|
||||||
EVT_CHOICE($self, $choice_view_type, sub {
|
|
||||||
my $selection = $choice_view_type->GetCurrentSelection();
|
|
||||||
$self->{preferred_color_mode} = ($selection == $self->{tool_idx}) ? 'tool' : 'feature';
|
|
||||||
$self->gcode_preview_data->set_type($selection);
|
|
||||||
$self->reload_print;
|
|
||||||
});
|
|
||||||
EVT_CHECKLISTBOX($self, $combochecklist_features, sub {
|
|
||||||
my $flags = Slic3r::GUI::combochecklist_get_flags($combochecklist_features);
|
|
||||||
|
|
||||||
$self->gcode_preview_data->set_extrusion_flags($flags);
|
|
||||||
$self->refresh_print;
|
|
||||||
});
|
|
||||||
EVT_CHECKBOX($self, $checkbox_travel, sub {
|
|
||||||
$self->gcode_preview_data->set_travel_visible($checkbox_travel->IsChecked());
|
|
||||||
$self->refresh_print;
|
|
||||||
});
|
|
||||||
EVT_CHECKBOX($self, $checkbox_retractions, sub {
|
|
||||||
$self->gcode_preview_data->set_retractions_visible($checkbox_retractions->IsChecked());
|
|
||||||
$self->refresh_print;
|
|
||||||
});
|
|
||||||
EVT_CHECKBOX($self, $checkbox_unretractions, sub {
|
|
||||||
$self->gcode_preview_data->set_unretractions_visible($checkbox_unretractions->IsChecked());
|
|
||||||
$self->refresh_print;
|
|
||||||
});
|
|
||||||
EVT_CHECKBOX($self, $checkbox_shells, sub {
|
|
||||||
$self->gcode_preview_data->set_shells_visible($checkbox_shells->IsChecked());
|
|
||||||
$self->refresh_print;
|
|
||||||
});
|
|
||||||
|
|
||||||
EVT_SIZE($self, sub {
|
|
||||||
my ($s, $event) = @_;
|
|
||||||
$event->Skip;
|
|
||||||
$self->Refresh;
|
|
||||||
});
|
|
||||||
|
|
||||||
$self->SetSizer($main_sizer);
|
|
||||||
$self->SetMinSize($self->GetSize);
|
|
||||||
$sizer->SetSizeHints($self);
|
|
||||||
|
|
||||||
# init canvas
|
|
||||||
$self->print($print);
|
|
||||||
$self->gcode_preview_data($gcode_preview_data);
|
|
||||||
|
|
||||||
# sets colors for gcode preview extrusion roles
|
|
||||||
my @extrusion_roles_colors = (
|
|
||||||
'Perimeter' => 'FFFF66',
|
|
||||||
'External perimeter' => 'FFA500',
|
|
||||||
'Overhang perimeter' => '0000FF',
|
|
||||||
'Internal infill' => 'B1302A',
|
|
||||||
'Solid infill' => 'D732D7',
|
|
||||||
'Top solid infill' => 'FF1A1A',
|
|
||||||
'Bridge infill' => '9999FF',
|
|
||||||
'Gap fill' => 'FFFFFF',
|
|
||||||
'Skirt' => '845321',
|
|
||||||
'Support material' => '00FF00',
|
|
||||||
'Support material interface' => '008000',
|
|
||||||
'Wipe tower' => 'B3E3AB',
|
|
||||||
'Custom' => '28CC94',
|
|
||||||
);
|
|
||||||
$self->gcode_preview_data->set_extrusion_paths_colors(\@extrusion_roles_colors);
|
|
||||||
|
|
||||||
$self->show_hide_ui_elements('none');
|
|
||||||
$self->reload_print;
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub reload_print {
|
|
||||||
my ($self, $force) = @_;
|
|
||||||
|
|
||||||
Slic3r::GUI::_3DScene::reset_volumes($self->canvas);
|
|
||||||
$self->_loaded(0);
|
|
||||||
|
|
||||||
if (! $self->IsShown && ! $force) {
|
|
||||||
# $self->{reload_delayed} = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->load_print;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub refresh_print {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
$self->_loaded(0);
|
|
||||||
|
|
||||||
if (! $self->IsShown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->load_print;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub reset_gcode_preview_data {
|
|
||||||
my ($self) = @_;
|
|
||||||
$self->gcode_preview_data->reset;
|
|
||||||
Slic3r::GUI::_3DScene::reset_legend_texture();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub load_print {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
return if $self->_loaded;
|
|
||||||
|
|
||||||
# we require that there's at least one object and the posSlice step
|
|
||||||
# is performed on all of them (this ensures that _shifted_copies was
|
|
||||||
# populated and we know the number of layers)
|
|
||||||
my $n_layers = 0;
|
|
||||||
if ($self->print->object_step_done(STEP_SLICE)) {
|
|
||||||
my %z = (); # z => 1
|
|
||||||
foreach my $object (@{$self->{print}->objects}) {
|
|
||||||
foreach my $layer (@{$object->layers}, @{$object->support_layers}) {
|
|
||||||
$z{$layer->print_z} = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$self->{layers_z} = [ sort { $a <=> $b } keys %z ];
|
|
||||||
$n_layers = scalar(@{$self->{layers_z}});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($n_layers == 0) {
|
|
||||||
$self->reset_sliders;
|
|
||||||
Slic3r::GUI::_3DScene::reset_legend_texture();
|
|
||||||
$self->canvas->Refresh; # clears canvas
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($self->{preferred_color_mode} eq 'tool_or_feature') {
|
|
||||||
# It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature.
|
|
||||||
# Color by feature if it is a single extruder print.
|
|
||||||
my $extruders = $self->{print}->extruders;
|
|
||||||
my $type = (scalar(@{$extruders}) > 1) ? $self->{tool_idx} : 0;
|
|
||||||
$self->gcode_preview_data->set_type($type);
|
|
||||||
$self->{choice_view_type}->SetSelection($type);
|
|
||||||
# If the ->SetSelection changed the following line, revert it to "decide yourself".
|
|
||||||
$self->{preferred_color_mode} = 'tool_or_feature';
|
|
||||||
}
|
|
||||||
|
|
||||||
# Collect colors per extruder.
|
|
||||||
my @colors = ();
|
|
||||||
if (! $self->gcode_preview_data->empty() || $self->gcode_preview_data->type == $self->{tool_idx}) {
|
|
||||||
my @extruder_colors = @{$self->{config}->extruder_colour};
|
|
||||||
my @filament_colors = @{$self->{config}->filament_colour};
|
|
||||||
for (my $i = 0; $i <= $#extruder_colors; $i += 1) {
|
|
||||||
my $color = $extruder_colors[$i];
|
|
||||||
$color = $filament_colors[$i] if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/);
|
|
||||||
$color = '#FFFFFF' if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/);
|
|
||||||
push @colors, $color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($self->IsShown) {
|
|
||||||
# used to set the sliders to the extremes of the current zs range
|
|
||||||
$self->{force_sliders_full_range} = 0;
|
|
||||||
|
|
||||||
if ($self->gcode_preview_data->empty) {
|
|
||||||
# load skirt and brim
|
|
||||||
Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
|
|
||||||
Slic3r::GUI::_3DScene::load_preview($self->canvas, \@colors);
|
|
||||||
$self->show_hide_ui_elements('simple');
|
|
||||||
} else {
|
|
||||||
$self->{force_sliders_full_range} = (Slic3r::GUI::_3DScene::get_volumes_count($self->canvas) == 0);
|
|
||||||
Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
|
|
||||||
Slic3r::GUI::_3DScene::load_gcode_preview($self->canvas, $self->gcode_preview_data, \@colors);
|
|
||||||
$self->show_hide_ui_elements('full');
|
|
||||||
|
|
||||||
# recalculates zs and update sliders accordingly
|
|
||||||
$self->{layers_z} = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 1);
|
|
||||||
$n_layers = scalar(@{$self->{layers_z}});
|
|
||||||
if ($n_layers == 0) {
|
|
||||||
# all layers filtered out
|
|
||||||
$self->reset_sliders;
|
|
||||||
$self->canvas->Refresh; # clears canvas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->update_sliders($n_layers) if ($n_layers > 0);
|
|
||||||
$self->_loaded(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub reset_sliders {
|
|
||||||
my ($self) = @_;
|
|
||||||
$self->enabled(0);
|
|
||||||
# $self->set_z_range(0,0);
|
|
||||||
# $self->slider_low->Hide;
|
|
||||||
# $self->slider_high->Hide;
|
|
||||||
# $self->{z_label_low}->SetLabel("");
|
|
||||||
# $self->{z_label_high}->SetLabel("");
|
|
||||||
# $self->{z_label_low_idx}->SetLabel("");
|
|
||||||
# $self->{z_label_high_idx}->SetLabel("");
|
|
||||||
|
|
||||||
Slic3r::GUI::reset_double_slider();
|
|
||||||
$self->double_slider_sizer->Hide(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub update_sliders
|
|
||||||
{
|
|
||||||
my ($self, $n_layers) = @_;
|
|
||||||
|
|
||||||
# my $z_idx_low = $self->slider_low->GetValue;
|
|
||||||
# my $z_idx_high = $self->slider_high->GetValue;
|
|
||||||
$self->enabled(1);
|
|
||||||
# $self->slider_low->SetRange(0, $n_layers - 1);
|
|
||||||
# $self->slider_high->SetRange(0, $n_layers - 1);
|
|
||||||
|
|
||||||
# if ($self->{force_sliders_full_range}) {
|
|
||||||
# $z_idx_low = 0;
|
|
||||||
# $z_idx_high = $n_layers - 1;
|
|
||||||
# } elsif ($z_idx_high < $n_layers && ($self->single_layer || $z_idx_high != 0)) {
|
|
||||||
# # search new indices for nearest z (size of $self->{layers_z} may change in dependence of what is shown)
|
|
||||||
# if (defined($self->{z_low})) {
|
|
||||||
# for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
|
|
||||||
# if ($self->{layers_z}[$i] <= $self->{z_low}) {
|
|
||||||
# $z_idx_low = $i;
|
|
||||||
# last;
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# if (defined($self->{z_high})) {
|
|
||||||
# for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
|
|
||||||
# if ($self->{layers_z}[$i] <= $self->{z_high}) {
|
|
||||||
# $z_idx_high = $i;
|
|
||||||
# last;
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# } elsif ($z_idx_high >= $n_layers) {
|
|
||||||
# # Out of range. Disable 'single layer' view.
|
|
||||||
# $self->single_layer(0);
|
|
||||||
# $self->{checkbox_singlelayer}->SetValue(0);
|
|
||||||
# $z_idx_low = 0;
|
|
||||||
# $z_idx_high = $n_layers - 1;
|
|
||||||
# } else {
|
|
||||||
# $z_idx_low = 0;
|
|
||||||
# $z_idx_high = $n_layers - 1;
|
|
||||||
# }
|
|
||||||
|
|
||||||
# $self->slider_low->SetValue($z_idx_low);
|
|
||||||
# $self->slider_high->SetValue($z_idx_high);
|
|
||||||
# $self->slider_low->Show;
|
|
||||||
# $self->slider_high->Show;
|
|
||||||
# $self->set_z_range($self->{layers_z}[$z_idx_low], $self->{layers_z}[$z_idx_high]);
|
|
||||||
|
|
||||||
Slic3r::GUI::update_double_slider($self->{force_sliders_full_range});
|
|
||||||
$self->double_slider_sizer->Show(0);
|
|
||||||
|
|
||||||
$self->Layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_z_range
|
|
||||||
{
|
|
||||||
my ($self, $z_low, $z_high) = @_;
|
|
||||||
|
|
||||||
return if !$self->enabled;
|
|
||||||
$self->{z_low} = $z_low;
|
|
||||||
$self->{z_high} = $z_high;
|
|
||||||
$self->{z_label_low}->SetLabel(sprintf '%.2f', $z_low);
|
|
||||||
$self->{z_label_high}->SetLabel(sprintf '%.2f', $z_high);
|
|
||||||
|
|
||||||
my $layers_z = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 0);
|
|
||||||
for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) {
|
|
||||||
if (($z_low - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_low + 1e-6)) {
|
|
||||||
$self->{z_label_low_idx}->SetLabel(sprintf '%d', $i + 1);
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) {
|
|
||||||
if (($z_high - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_high + 1e-6)) {
|
|
||||||
$self->{z_label_high_idx}->SetLabel(sprintf '%d', $i + 1);
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Slic3r::GUI::_3DScene::set_toolpaths_range($self->canvas, $z_low - 1e-6, $z_high + 1e-6);
|
|
||||||
$self->canvas->Refresh if $self->IsShown;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_z_idx_low
|
|
||||||
{
|
|
||||||
my ($self, $idx_low) = @_;
|
|
||||||
if ($self->enabled) {
|
|
||||||
my $idx_high = $self->slider_high->GetValue;
|
|
||||||
if ($idx_low >= $idx_high) {
|
|
||||||
$idx_high = $idx_low;
|
|
||||||
$self->slider_high->SetValue($idx_high);
|
|
||||||
}
|
|
||||||
$self->set_z_range($self->{layers_z}[$idx_low], $self->{layers_z}[$idx_high]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_z_idx_high
|
|
||||||
{
|
|
||||||
my ($self, $idx_high) = @_;
|
|
||||||
if ($self->enabled) {
|
|
||||||
my $idx_low = $self->slider_low->GetValue;
|
|
||||||
if ($idx_low > $idx_high) {
|
|
||||||
$idx_low = $idx_high;
|
|
||||||
$self->slider_low->SetValue($idx_low);
|
|
||||||
}
|
|
||||||
$self->set_z_range($self->{layers_z}[$idx_low], $self->{layers_z}[$idx_high]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_number_extruders {
|
|
||||||
my ($self, $number_extruders) = @_;
|
|
||||||
if ($self->{number_extruders} != $number_extruders) {
|
|
||||||
$self->{number_extruders} = $number_extruders;
|
|
||||||
my $type = ($number_extruders > 1) ?
|
|
||||||
$self->{tool_idx} # color by a tool number
|
|
||||||
: 0; # color by a feature type
|
|
||||||
$self->{choice_view_type}->SetSelection($type);
|
|
||||||
$self->gcode_preview_data->set_type($type);
|
|
||||||
$self->{preferred_color_mode} = ($type == $self->{tool_idx}) ? 'tool_or_feature' : 'feature';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub show_hide_ui_elements {
|
|
||||||
my ($self, $what) = @_;
|
|
||||||
my $method = ($what eq 'full') ? 'Enable' : 'Disable';
|
|
||||||
$self->{$_}->$method for qw(label_show_features combochecklist_features checkbox_travel checkbox_retractions checkbox_unretractions checkbox_shells);
|
|
||||||
$method = ($what eq 'none') ? 'Disable' : 'Enable';
|
|
||||||
$self->{$_}->$method for qw(label_view_type choice_view_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Called by the Platter wxNotebook when this page is activated.
|
|
||||||
sub OnActivate {
|
|
||||||
# my ($self) = @_;
|
|
||||||
# $self->reload_print(1) if ($self->{reload_delayed});
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
Loading…
Reference in New Issue
Block a user