Controller.pm 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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 List::Util qw(any);
  9. use Wx qw(wxTheApp :frame :id :misc :sizer :bitmap :button :icon :dialog);
  10. use Wx::Event qw(EVT_CLOSE EVT_LEFT_DOWN EVT_MENU);
  11. use base qw(Wx::ScrolledWindow Class::Accessor);
  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, Wx::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 %presets = map { $_->name => $_ } @{wxTheApp->presets->{printer}};
  35. # remove printers that already exist
  36. my @panels = $self->print_panels;
  37. delete $presets{$_} for map $_->printer_name, @panels;
  38. foreach my $preset_name (sort keys %presets) {
  39. my $preset = $presets{$preset_name};
  40. next if !$preset->dirty_config->serial_port;
  41. my $id = &Wx::NewId();
  42. $menu->Append($id, $preset_name);
  43. EVT_MENU($menu, $id, sub {
  44. $self->add_printer($preset);
  45. });
  46. }
  47. $self->PopupMenu($menu, $btn->GetPosition);
  48. $menu->Destroy;
  49. });
  50. $self->{sizer}->Add($btn, 0, wxTOP | wxLEFT, 10);
  51. }
  52. $self->SetSizer($sizer);
  53. $self->SetMinSize($self->GetSize);
  54. #$sizer->SetSizeHints($self);
  55. EVT_CLOSE($self, sub {
  56. my (undef, $event) = @_;
  57. if ($event->CanVeto) {
  58. foreach my $panel ($self->print_panels) {
  59. if ($panel->printing) {
  60. my $confirm = Wx::MessageDialog->new(
  61. $self, "Printer '" . $panel->printer_name . "' is printing.\n\nDo you want to stop printing?",
  62. 'Unfinished Print', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION,
  63. );
  64. if ($confirm->ShowModal == wxID_NO) {
  65. $event->Veto;
  66. return;
  67. }
  68. }
  69. }
  70. }
  71. foreach my $panel ($self->print_panels) {
  72. $panel->disconnect;
  73. }
  74. $event->Skip;
  75. });
  76. $self->Layout;
  77. return $self;
  78. }
  79. sub OnActivate {
  80. my ($self) = @_;
  81. # get all available presets
  82. my %presets = ();
  83. foreach my $preset (@{wxTheApp->presets->{printer}}) {
  84. $preset->load_config;
  85. next if !$preset->dirty_config->serial_port;
  86. $presets{$preset->name} = $preset;
  87. }
  88. # decide which ones we want to keep
  89. my %active = ();
  90. # keep the ones that are currently connected or have jobs in queue
  91. $active{$_} = 1 for map $_->printer_name,
  92. grep { $_->is_connected || @{$_->jobs} > 0 }
  93. $self->print_panels;
  94. if (%presets) {
  95. # if there are no active panels, use sensible defaults
  96. if (!%active && keys %presets <= 2) {
  97. # if only one or two presets exist, load them
  98. $active{$_} = 1 for keys %presets;
  99. }
  100. if (!%active) {
  101. # enable printers whose port is available
  102. my %ports = map { $_ => 1 } wxTheApp->scan_serial_ports;
  103. $active{$_} = 1
  104. for grep exists $ports{$presets{$_}->dirty_config->serial_port}, keys %presets;
  105. }
  106. if (!%active && $self->_selected_printer_preset) {
  107. # enable currently selected printer if it is configured
  108. $active{$self->_selected_printer_preset} = 1
  109. if $presets{$self->_selected_printer_preset};
  110. }
  111. }
  112. # apply changes
  113. for my $panel ($self->print_panels) {
  114. next if $active{$panel->printer_name};
  115. $self->{sizer}->DetachWindow($panel);
  116. $panel->Destroy;
  117. }
  118. $self->add_printer($presets{$_}) for sort keys %active;
  119. # show/hide the warning about no printers
  120. $self->{text_no_printers}->Show(!%presets);
  121. # show/hide the Add button
  122. $self->{btn_add}->Show(keys %presets != keys %active);
  123. $self->Layout;
  124. # we need this in order to trigger the OnSize event of wxScrolledWindow which
  125. # recalculates the virtual size
  126. Wx::GetTopLevelParent($self)->SendSizeEvent;
  127. }
  128. sub add_printer {
  129. my ($self, $preset) = @_;
  130. # check that printer doesn't exist already
  131. foreach my $panel ($self->print_panels) {
  132. if ($panel->printer_name eq $preset->name) {
  133. return $panel;
  134. }
  135. }
  136. my $printer_panel = Slic3r::GUI::Controller::PrinterPanel->new($self, $preset);
  137. $self->{sizer}->Prepend($printer_panel, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10);
  138. $self->Layout;
  139. return $printer_panel;
  140. }
  141. sub print_panels {
  142. my ($self) = @_;
  143. return grep $_->isa('Slic3r::GUI::Controller::PrinterPanel'),
  144. map $_->GetWindow, $self->{sizer}->GetChildren;
  145. }
  146. sub printing {
  147. my ($self) = @_;
  148. return any { $_->printing } $self->print_panels;
  149. }
  150. sub update_presets {
  151. my $self = shift;
  152. my ($group, $presets, $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;