Controller.pm 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. # The "Controller" tab to control the printer using serial / USB.
  2. # This feature is rarely used. Much more often, the firmware reads the G-codes from a SD card.
  3. # May there be multiple subtabs per each printer connected?
  4. package Slic3r::GUI::Controller;
  5. use strict;
  6. use warnings;
  7. use utf8;
  8. use Wx qw(wxTheApp :frame :id :misc :sizer :bitmap :button :icon :dialog);
  9. use Wx::Event qw(EVT_CLOSE EVT_LEFT_DOWN EVT_MENU);
  10. use base qw(Wx::ScrolledWindow Class::Accessor);
  11. __PACKAGE__->mk_accessors(qw(_selected_printer_preset));
  12. our @ConfigOptions = qw(bed_shape serial_port serial_speed);
  13. sub new {
  14. my ($class, $parent) = @_;
  15. my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, [600,350]);
  16. $self->SetScrollbars(0, 1, 0, 1);
  17. $self->{sizer} = my $sizer = Wx::BoxSizer->new(wxVERTICAL);
  18. # warning to show when there are no printers configured
  19. {
  20. $self->{text_no_printers} = Wx::StaticText->new($self, -1,
  21. "No printers were configured for USB/serial control.",
  22. wxDefaultPosition, wxDefaultSize);
  23. $self->{sizer}->Add($self->{text_no_printers}, 0, wxTOP | wxLEFT, 30);
  24. }
  25. # button for adding new printer panels
  26. {
  27. my $btn = $self->{btn_add} = Wx::BitmapButton->new($self, -1, Wx::Bitmap->new($Slic3r::var->("add.png"), wxBITMAP_TYPE_PNG),
  28. wxDefaultPosition, wxDefaultSize, Wx::wxBORDER_NONE);
  29. $btn->SetToolTipString("Add printer…")
  30. if $btn->can('SetToolTipString');
  31. EVT_LEFT_DOWN($btn, sub {
  32. my $menu = Wx::Menu->new;
  33. my %presets = wxTheApp->presets('printer');
  34. # remove printers that already exist
  35. my @panels = $self->print_panels;
  36. delete $presets{$_} for map $_->printer_name, @panels;
  37. foreach my $preset_name (sort keys %presets) {
  38. my $config = Slic3r::Config->load($presets{$preset_name});
  39. next if !$config->serial_port;
  40. my $id = &Wx::NewId();
  41. $menu->Append($id, $preset_name);
  42. EVT_MENU($menu, $id, sub {
  43. $self->add_printer($preset_name, $config);
  44. });
  45. }
  46. $self->PopupMenu($menu, $btn->GetPosition);
  47. $menu->Destroy;
  48. });
  49. $self->{sizer}->Add($btn, 0, wxTOP | wxLEFT, 10);
  50. }
  51. $self->SetSizer($sizer);
  52. $self->SetMinSize($self->GetSize);
  53. #$sizer->SetSizeHints($self);
  54. EVT_CLOSE($self, sub {
  55. my (undef, $event) = @_;
  56. if ($event->CanVeto) {
  57. foreach my $panel ($self->print_panels) {
  58. if ($panel->printing) {
  59. my $confirm = Wx::MessageDialog->new(
  60. $self, "Printer '" . $panel->printer_name . "' is printing.\n\nDo you want to stop printing?",
  61. 'Unfinished Print', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION,
  62. );
  63. if ($confirm->ShowModal == wxID_NO) {
  64. $event->Veto;
  65. return;
  66. }
  67. }
  68. }
  69. }
  70. foreach my $panel ($self->print_panels) {
  71. $panel->disconnect;
  72. }
  73. $event->Skip;
  74. });
  75. $self->Layout;
  76. return $self;
  77. }
  78. sub OnActivate {
  79. my ($self) = @_;
  80. # get all available presets
  81. my %presets = ();
  82. {
  83. my %all = wxTheApp->presets('printer');
  84. my %configs = map { my $name = $_; $name => Slic3r::Config->load($all{$name}) } keys %all;
  85. %presets = map { $_ => $configs{$_} } grep $configs{$_}->serial_port, keys %all;
  86. }
  87. # decide which ones we want to keep
  88. my %active = ();
  89. # keep the ones that are currently connected or have jobs in queue
  90. $active{$_} = 1 for map $_->printer_name,
  91. grep { $_->is_connected || @{$_->jobs} > 0 }
  92. $self->print_panels;
  93. if (%presets) {
  94. # if there are no active panels, use sensible defaults
  95. if (!%active && keys %presets <= 2) {
  96. # if only one or two presets exist, load them
  97. $active{$_} = 1 for keys %presets;
  98. }
  99. if (!%active) {
  100. # enable printers whose port is available
  101. my %ports = map { $_ => 1 } wxTheApp->scan_serial_ports;
  102. $active{$_} = 1
  103. for grep exists $ports{$presets{$_}->serial_port}, keys %presets;
  104. }
  105. if (!%active && $self->_selected_printer_preset) {
  106. # enable currently selected printer if it is configured
  107. $active{$self->_selected_printer_preset} = 1
  108. if $presets{$self->_selected_printer_preset};
  109. }
  110. }
  111. # apply changes
  112. for my $panel ($self->print_panels) {
  113. next if $active{$panel->printer_name};
  114. $self->{sizer}->DetachWindow($panel);
  115. $panel->Destroy;
  116. }
  117. $self->add_printer($_, $presets{$_}) for sort keys %active;
  118. # show/hide the warning about no printers
  119. $self->{text_no_printers}->Show(!%presets);
  120. # show/hide the Add button
  121. $self->{btn_add}->Show(keys %presets != keys %active);
  122. $self->Layout;
  123. # we need this in order to trigger the OnSize event of wxScrolledWindow which
  124. # recalculates the virtual size
  125. Wx::GetTopLevelParent($self)->SendSizeEvent;
  126. }
  127. sub add_printer {
  128. my ($self, $printer_name, $config) = @_;
  129. # check that printer doesn't exist already
  130. foreach my $panel ($self->print_panels) {
  131. if ($panel->printer_name eq $printer_name) {
  132. return $panel;
  133. }
  134. }
  135. my $printer_panel = Slic3r::GUI::Controller::PrinterPanel->new($self, $printer_name, $config);
  136. $self->{sizer}->Prepend($printer_panel, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10);
  137. $self->Layout;
  138. return $printer_panel;
  139. }
  140. sub print_panels {
  141. my ($self) = @_;
  142. return grep $_->isa('Slic3r::GUI::Controller::PrinterPanel'),
  143. map $_->GetWindow, $self->{sizer}->GetChildren;
  144. }
  145. # Called by
  146. # Slic3r::GUI::Tab::Print::_on_presets_changed
  147. # Slic3r::GUI::Tab::Filament::_on_presets_changed
  148. # Slic3r::GUI::Tab::Printer::_on_presets_changed
  149. # when the presets are loaded or the user select another preset.
  150. sub update_presets {
  151. my $self = shift;
  152. my ($group, $presets, $default_suppressed, $selected, $is_dirty) = @_;
  153. # update configs of currently loaded print panels
  154. foreach my $panel ($self->print_panels) {
  155. foreach my $preset (@$presets) {
  156. if ($panel->printer_name eq $preset->name) {
  157. my $config = $preset->config(\@ConfigOptions);
  158. $panel->config->apply($config);
  159. }
  160. }
  161. }
  162. $self->_selected_printer_preset($presets->[$selected]->name);
  163. }
  164. 1;