Controller.pm 6.5 KB

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