From 4295d65115e0509eb7ae8fff06d1712e2195ca30 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 2 Nov 2015 20:16:37 +0100 Subject: [PATCH] Manual control --- lib/Slic3r/GUI.pm | 2 + lib/Slic3r/GUI/2DBed.pm | 196 ++++++++++++++++++ lib/Slic3r/GUI/BedShapeDialog.pm | 143 +------------ .../GUI/Controller/ManualControlDialog.pm | 144 +++++++++++++ lib/Slic3r/GUI/Controller/PrinterPanel.pm | 19 ++ var/arrow_down.png | Bin 0 -> 379 bytes var/arrow_left.png | Bin 0 -> 345 bytes var/arrow_right.png | Bin 0 -> 349 bytes var/house.png | Bin 0 -> 806 bytes 9 files changed, 369 insertions(+), 135 deletions(-) create mode 100644 lib/Slic3r/GUI/2DBed.pm create mode 100644 lib/Slic3r/GUI/Controller/ManualControlDialog.pm create mode 100644 var/arrow_down.png create mode 100644 var/arrow_left.png create mode 100644 var/arrow_right.png create mode 100644 var/house.png diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 743493815..b1f2d8f6b 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -5,11 +5,13 @@ use utf8; use File::Basename qw(basename); use FindBin; +use Slic3r::GUI::2DBed; use Slic3r::GUI::AboutDialog; use Slic3r::GUI::BedShapeDialog; use Slic3r::GUI::BonjourBrowser; use Slic3r::GUI::ConfigWizard; use Slic3r::GUI::Controller; +use Slic3r::GUI::Controller::ManualControlDialog; use Slic3r::GUI::Controller::PrinterPanel; use Slic3r::GUI::MainFrame; use Slic3r::GUI::Notifier; diff --git a/lib/Slic3r/GUI/2DBed.pm b/lib/Slic3r/GUI/2DBed.pm new file mode 100644 index 000000000..52bafad11 --- /dev/null +++ b/lib/Slic3r/GUI/2DBed.pm @@ -0,0 +1,196 @@ +package Slic3r::GUI::2DBed; +use strict; +use warnings; + +use List::Util qw(min max); +use Slic3r::Geometry qw(PI X Y unscale deg2rad); +use Slic3r::Geometry::Clipper qw(intersection_pl); +use Wx qw(:misc :pen :brush :font wxTAB_TRAVERSAL); +use Wx::Event qw(EVT_PAINT EVT_MOUSE_EVENTS); +use base qw(Wx::Panel Class::Accessor); + +__PACKAGE__->mk_accessors(qw(bed_shape interactive pos _scale_factor _shift on_move)); + +sub new { + my ($class, $parent, $bed_shape) = @_; + + my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, [250,-1], wxTAB_TRAVERSAL); + $self->bed_shape($bed_shape // []); + EVT_PAINT($self, \&_repaint); + EVT_MOUSE_EVENTS($self, \&_mouse_event); + + return $self; +} + +sub _repaint { + my ($self) = @_; + + my $dc = Wx::PaintDC->new($self); + my ($cw, $ch) = $self->GetSizeWH; + return if $cw == 0; # when canvas is not rendered yet, size is 0,0 + + # turn $cw and $ch from sizes to max coordinates + $cw--; + $ch--; + + my $cbb = Slic3r::Geometry::BoundingBoxf->new_from_points([ + Slic3r::Pointf->new(0, 0), + Slic3r::Pointf->new($cw, $ch), + ]); + + # leave space for origin point + $cbb->set_x_min($cbb->x_min + 2); + $cbb->set_y_max($cbb->y_max - 2); + + # leave space for origin label + $cbb->set_y_max($cbb->y_max - 10); + + # read new size + ($cw, $ch) = @{$cbb->size}; + my $ccenter = $cbb->center; + + # get bounding box of bed shape in G-code coordinates + my $bed_shape = $self->bed_shape; + my $bed_polygon = Slic3r::Polygon->new_scale(@$bed_shape); + my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($bed_shape); + $bb->merge_point(Slic3r::Pointf->new(0,0)); # origin needs to be in the visible area + my ($bw, $bh) = @{$bb->size}; + my $bcenter = $bb->center; + + # calculate the scaling factor for fitting bed shape in canvas area + my $sfactor = min($cw/$bw, $ch/$bh); + my $shift = Slic3r::Pointf->new( + $ccenter->x - $bcenter->x * $sfactor, + $ccenter->y - $bcenter->y * $sfactor, #- + ); + $self->_scale_factor($sfactor); + $self->_shift(Slic3r::Pointf->new( + $shift->x + $cbb->x_min, + $shift->y - ($cbb->y_max-$self->GetSize->GetHeight), #++ + )); + + # draw bed fill + { + $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,0,0), 1, wxSOLID)); + $dc->SetBrush(Wx::Brush->new(Wx::Colour->new(255,255,255), wxSOLID)); + $dc->DrawPolygon([ map $self->to_pixels($_), @$bed_shape ], 0, 0); + } + + # draw grid + { + my $step = 10; # 1cm grid + my @polylines = (); + for (my $x = $bb->x_min - ($bb->x_min % $step) + $step; $x < $bb->x_max; $x += $step) { + push @polylines, Slic3r::Polyline->new_scale([$x, $bb->y_min], [$x, $bb->y_max]); + } + for (my $y = $bb->y_min - ($bb->y_min % $step) + $step; $y < $bb->y_max; $y += $step) { + push @polylines, Slic3r::Polyline->new_scale([$bb->x_min, $y], [$bb->x_max, $y]); + } + @polylines = @{intersection_pl(\@polylines, [$bed_polygon])}; + + $dc->SetPen(Wx::Pen->new(Wx::Colour->new(230,230,230), 1, wxSOLID)); + $dc->DrawLine(map @{$self->to_pixels([map unscale($_), @$_])}, @$_[0,-1]) for @polylines; + } + + # draw bed contour + { + $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,0,0), 1, wxSOLID)); + $dc->SetBrush(Wx::Brush->new(Wx::Colour->new(255,255,255), wxTRANSPARENT)); + $dc->DrawPolygon([ map $self->to_pixels($_), @$bed_shape ], 0, 0); + } + + my $origin_px = $self->to_pixels(Slic3r::Pointf->new(0,0)); + + # draw axes + { + my $axes_len = 50; + my $arrow_len = 6; + my $arrow_angle = deg2rad(45); + $dc->SetPen(Wx::Pen->new(Wx::Colour->new(255,0,0), 2, wxSOLID)); # red + my $x_end = Slic3r::Pointf->new($origin_px->[X] + $axes_len, $origin_px->[Y]); + $dc->DrawLine(@$origin_px, @$x_end); + foreach my $angle (-$arrow_angle, +$arrow_angle) { + my $end = $x_end->clone; + $end->translate(-$arrow_len, 0); + $end->rotate($angle, $x_end); + $dc->DrawLine(@$x_end, @$end); + } + + $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,255,0), 2, wxSOLID)); # green + my $y_end = Slic3r::Pointf->new($origin_px->[X], $origin_px->[Y] - $axes_len); + $dc->DrawLine(@$origin_px, @$y_end); + foreach my $angle (-$arrow_angle, +$arrow_angle) { + my $end = $y_end->clone; + $end->translate(0, +$arrow_len); + $end->rotate($angle, $y_end); + $dc->DrawLine(@$y_end, @$end); + } + } + + # draw origin + { + $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,0,0), 1, wxSOLID)); + $dc->SetBrush(Wx::Brush->new(Wx::Colour->new(0,0,0), wxSOLID)); + $dc->DrawCircle(@$origin_px, 3); + + $dc->SetTextForeground(Wx::Colour->new(0,0,0)); + $dc->SetFont(Wx::Font->new(10, wxDEFAULT, wxNORMAL, wxNORMAL)); + $dc->DrawText("(0,0)", $origin_px->[X] + 1, $origin_px->[Y] + 2); + } + + # draw current position + if (defined $self->pos) { + my $pos_px = $self->to_pixels($self->pos); + $dc->SetPen(Wx::Pen->new(Wx::Colour->new(200,0,0), 2, wxSOLID)); + $dc->SetBrush(Wx::Brush->new(Wx::Colour->new(200,0,0), wxTRANSPARENT)); + $dc->DrawCircle(@$pos_px, 5); + + $dc->DrawLine($pos_px->[X]-15, $pos_px->[Y], $pos_px->[X]+15, $pos_px->[Y]); + $dc->DrawLine($pos_px->[X], $pos_px->[Y]-15, $pos_px->[X], $pos_px->[Y]+15); + } +} + +sub _mouse_event { + my ($self, $event) = @_; + + return if !$self->interactive; + + my $pos = $event->GetPosition; + my $point = $self->to_units([ $pos->x, $pos->y ]); #]] + if ($event->LeftDown || $event->Dragging) { + $self->on_move->($point) if $self->on_move; + $self->Refresh; + } +} + +# convert G-code coordinates into pixels +sub to_pixels { + my ($self, $point) = @_; + + my $p = Slic3r::Pointf->new(@$point); + $p->scale($self->_scale_factor); + $p->translate(@{$self->_shift}); + return [$p->x, $self->GetSize->GetHeight - $p->y]; #]] +} + +# convert pixels into G-code coordinates +sub to_units { + my ($self, $point) = @_; + + my $p = Slic3r::Pointf->new( + $point->[X], + $self->GetSize->GetHeight - $point->[Y], + ); + $p->translate(@{$self->_shift->negative}); + $p->scale(1/$self->_scale_factor); + return $p; +} + +sub set_pos { + my ($self, $pos) = @_; + + $self->pos($pos); + $self->Refresh; +} + +1; diff --git a/lib/Slic3r/GUI/BedShapeDialog.pm b/lib/Slic3r/GUI/BedShapeDialog.pm index fa6429023..deae8327e 100644 --- a/lib/Slic3r/GUI/BedShapeDialog.pm +++ b/lib/Slic3r/GUI/BedShapeDialog.pm @@ -42,9 +42,8 @@ package Slic3r::GUI::BedShapePanel; use List::Util qw(min max sum first); use Slic3r::Geometry qw(PI X Y scale unscale scaled_epsilon deg2rad); -use Slic3r::Geometry::Clipper qw(intersection_pl); use Wx qw(:font :id :misc :sizer :choicebook :filedialog :pen :brush wxTAB_TRAVERSAL); -use Wx::Event qw(EVT_CLOSE EVT_CHOICEBOOK_PAGE_CHANGED EVT_BUTTON EVT_PAINT); +use Wx::Event qw(EVT_CLOSE EVT_CHOICEBOOK_PAGE_CHANGED EVT_BUTTON); use base 'Wx::Panel'; use constant SHAPE_RECTANGULAR => 0; @@ -113,10 +112,7 @@ sub new { }); # right pane with preview canvas - my $canvas = $self->{canvas} = Wx::Panel->new($self, -1, wxDefaultPosition, [250,-1], wxTAB_TRAVERSAL); - EVT_PAINT($canvas, sub { - $self->_repaint_canvas; - }); + my $canvas = $self->{canvas} = Slic3r::GUI::2DBed->new($self); # main sizer my $top_sizer = Wx::BoxSizer->new(wxHORIZONTAL); @@ -204,12 +200,12 @@ sub _update_shape { $y0 -= $dy; $y1 -= $dy; } - $self->{bed_shape} = [ + $self->{canvas}->bed_shape([ [$x0,$y0], [$x1,$y0], [$x1,$y1], [$x0,$y1], - ]; + ]); } elsif ($page_idx == SHAPE_CIRCULAR) { my $diameter = $self->{optgroups}[SHAPE_CIRCULAR]->get_value('diameter'); return if !$diameter; @@ -220,9 +216,9 @@ sub _update_shape { map [ $r * cos $_, $r * sin $_ ], map { $twopi/$edges*$_ } 1..$edges ); - $self->{bed_shape} = [ + $self->{canvas}->bed_shape([ map [ unscale($_->x), unscale($_->y) ], @$polygon #)) - ]; + ]); } $self->{on_change}->(); @@ -234,129 +230,6 @@ sub _update_preview { $self->{canvas}->Refresh if $self->{canvas}; } -sub _repaint_canvas { - my ($self) = @_; - - my $canvas = $self->{canvas}; - my $dc = Wx::PaintDC->new($canvas); - my ($cw, $ch) = $canvas->GetSizeWH; - return if $cw == 0; # when canvas is not rendered yet, size is 0,0 - - # turn $cw and $ch from sizes to max coordinates - $cw--; - $ch--; - - my $cbb = Slic3r::Geometry::BoundingBoxf->new_from_points([ - Slic3r::Pointf->new(0, 0), - Slic3r::Pointf->new($cw, $ch), - ]); - - # leave space for origin point - $cbb->set_x_min($cbb->x_min + 2); - $cbb->set_y_max($cbb->y_max - 2); - - # leave space for origin label - $cbb->set_y_max($cbb->y_max - 10); - - # read new size - ($cw, $ch) = @{$cbb->size}; - my $ccenter = $cbb->center; - - # get bounding box of bed shape in G-code coordinates - my $bed_shape = $self->{bed_shape}; - my $bed_polygon = Slic3r::Polygon->new_scale(@$bed_shape); - my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($bed_shape); - $bb->merge_point(Slic3r::Pointf->new(0,0)); # origin needs to be in the visible area - my ($bw, $bh) = @{$bb->size}; - my $bcenter = $bb->center; - - # calculate the scaling factor for fitting bed shape in canvas area - my $sfactor = min($cw/$bw, $ch/$bh); - my $shift = [ - $ccenter->x - $bcenter->x * $sfactor, - $ccenter->y - $bcenter->y * $sfactor, #- - ]; - - # prepare function to convert G-code coordinates into pixels - my $to_pixel = sub { - my ($point) = @_; - - my $p = Slic3r::Pointf->new(@$point); - $p->scale($sfactor); - $p->translate(@$shift); - return [ $p->x + $cbb->x_min, $ch-$p->y + $cbb->y_min ]; #++ - }; - - # draw bed fill - { - $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,0,0), 1, wxSOLID)); - $dc->SetBrush(Wx::Brush->new(Wx::Colour->new(255,255,255), wxSOLID)); - $dc->DrawPolygon([ map $to_pixel->($_), @$bed_shape ], 0, 0); - } - - # draw grid - { - my $step = 10; # 1cm grid - my @polylines = (); - for (my $x = $bb->x_min - ($bb->x_min % $step) + $step; $x < $bb->x_max; $x += $step) { - push @polylines, Slic3r::Polyline->new_scale([$x, $bb->y_min], [$x, $bb->y_max]); - } - for (my $y = $bb->y_min - ($bb->y_min % $step) + $step; $y < $bb->y_max; $y += $step) { - push @polylines, Slic3r::Polyline->new_scale([$bb->x_min, $y], [$bb->x_max, $y]); - } - @polylines = @{intersection_pl(\@polylines, [$bed_polygon])}; - - $dc->SetPen(Wx::Pen->new(Wx::Colour->new(230,230,230), 1, wxSOLID)); - $dc->DrawLine(map @{$to_pixel->([map unscale($_), @$_])}, @$_[0,-1]) for @polylines; - } - - # draw bed contour - { - $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,0,0), 1, wxSOLID)); - $dc->SetBrush(Wx::Brush->new(Wx::Colour->new(255,255,255), wxTRANSPARENT)); - $dc->DrawPolygon([ map $to_pixel->($_), @$bed_shape ], 0, 0); - } - - my $origin_px = $to_pixel->(Slic3r::Pointf->new(0,0)); - - # draw axes - { - my $axes_len = 50; - my $arrow_len = 6; - my $arrow_angle = deg2rad(45); - $dc->SetPen(Wx::Pen->new(Wx::Colour->new(255,0,0), 2, wxSOLID)); # red - my $x_end = Slic3r::Pointf->new($origin_px->[X] + $axes_len, $origin_px->[Y]); - $dc->DrawLine(@$origin_px, @$x_end); - foreach my $angle (-$arrow_angle, +$arrow_angle) { - my $end = $x_end->clone; - $end->translate(-$arrow_len, 0); - $end->rotate($angle, $x_end); - $dc->DrawLine(@$x_end, @$end); - } - - $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,255,0), 2, wxSOLID)); # green - my $y_end = Slic3r::Pointf->new($origin_px->[X], $origin_px->[Y] - $axes_len); - $dc->DrawLine(@$origin_px, @$y_end); - foreach my $angle (-$arrow_angle, +$arrow_angle) { - my $end = $y_end->clone; - $end->translate(0, +$arrow_len); - $end->rotate($angle, $y_end); - $dc->DrawLine(@$y_end, @$end); - } - } - - # draw origin - { - $dc->SetPen(Wx::Pen->new(Wx::Colour->new(0,0,0), 1, wxSOLID)); - $dc->SetBrush(Wx::Brush->new(Wx::Colour->new(0,0,0), wxSOLID)); - $dc->DrawCircle(@$origin_px, 3); - - $dc->SetTextForeground(Wx::Colour->new(0,0,0)); - $dc->SetFont(Wx::Font->new(10, wxDEFAULT, wxNORMAL, wxNORMAL)); - $dc->DrawText("(0,0)", $origin_px->[X] + 1, $origin_px->[Y] + 2); - } -} - sub _init_shape_options_page { my ($self, $title) = @_; @@ -403,12 +276,12 @@ sub _load_stl { } my $polygon = $expolygons->[0]->contour; - $self->{bed_shape} = [ map [ unscale($_->x), unscale($_->y) ], @$polygon ]; #)) + $self->{canvas}->bed_shape([ map [ unscale($_->x), unscale($_->y) ], @$polygon ]); #)) } sub GetValue { my ($self) = @_; - return $self->{bed_shape}; + return $self->{canvas}->bed_shape; } 1; diff --git a/lib/Slic3r/GUI/Controller/ManualControlDialog.pm b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm new file mode 100644 index 000000000..d8d165beb --- /dev/null +++ b/lib/Slic3r/GUI/Controller/ManualControlDialog.pm @@ -0,0 +1,144 @@ +package Slic3r::GUI::Controller::ManualControlDialog; +use strict; +use warnings; +use utf8; + +use Slic3r::Geometry qw(PI X Y unscale); +use Wx qw(:dialog :id :misc :sizer :choicebook :button :bitmap + wxBORDER_NONE wxTAB_TRAVERSAL); +use Wx::Event qw(EVT_CLOSE EVT_BUTTON); +use base qw(Wx::Dialog Class::Accessor); + +__PACKAGE__->mk_accessors(qw(sender)); + +use constant TRAVEL_SPEED => 130*60; # TODO: make customizable? + +sub new { + my ($class, $printer_panel) = @_; + + my $self = $class->SUPER::new($printer_panel, -1, "Manual Control", wxDefaultPosition, + [430,380], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + $self->sender($printer_panel->sender); + + my $bed_sizer = Wx::FlexGridSizer->new(2, 3, 1, 1); + $bed_sizer->AddGrowableCol(1, 1); + $bed_sizer->AddGrowableRow(0, 1); + + my $move_button = sub { + my ($sizer, $label, $icon, $bold, $pos, $handler) = @_; + + my $btn = Wx::Button->new($self, -1, $label, wxDefaultPosition, wxDefaultSize, + wxBU_LEFT | wxBU_EXACTFIT); + $btn->SetFont($bold ? $Slic3r::GUI::small_bold_font : $Slic3r::GUI::small_font); + if ($Slic3r::GUI::have_button_icons) { + $btn->SetBitmap(Wx::Bitmap->new("$Slic3r::var/$icon.png", wxBITMAP_TYPE_PNG)); + $btn->SetBitmapPosition($pos); + } + EVT_BUTTON($self, $btn, $handler); + $sizer->Add($btn, 1, wxEXPAND | wxALL, 0); + }; + + # Y buttons + { + my $sizer = Wx::BoxSizer->new(wxVERTICAL); + for my $d (qw(+10 +1 +0.1)) { + $move_button->($sizer, $d, 'arrow_up', 0, wxLEFT, sub { $self->rel_move('Y', $d) }); + } + $move_button->($sizer, 'Y', 'house', 1, wxLEFT, sub { $self->home('Y') }); + for my $d (qw(-0.1 -1 -10)) { + $move_button->($sizer, $d, 'arrow_down', 0, wxLEFT, sub { $self->rel_move('Y', $d) }); + }; + $bed_sizer->Add($sizer, 1, wxEXPAND, 0); + } + + # Bed canvas + { + my $bed_shape = $printer_panel->config->bed_shape; + $self->{canvas} = my $canvas = Slic3r::GUI::2DBed->new($self, $bed_shape); + $canvas->interactive(1); + $canvas->on_move(sub { + my ($pos) = @_; + $self->abs_xy_move($pos); + }); + $bed_sizer->Add($canvas, 0, wxEXPAND | wxRIGHT, 3); + } + + # Z buttons + { + my $sizer = Wx::BoxSizer->new(wxVERTICAL); + for my $d (qw(+10 +1 +0.1)) { + $move_button->($sizer, $d, 'arrow_up', 0, wxLEFT, sub { $self->rel_move('Z', $d) }); + } + $move_button->($sizer, 'Z', 'house', 1, wxLEFT, sub { $self->home('Z') }); + for my $d (qw(-0.1 -1 -10)) { + $move_button->($sizer, $d, 'arrow_down', 0, wxLEFT, sub { $self->rel_move('Z', $d) }); + }; + $bed_sizer->Add($sizer, 1, wxEXPAND, 0); + } + + $bed_sizer->AddSpacer(0); + + # X buttons + { + my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); + for my $d (qw(-0.1 -1 -10)) { + $move_button->($sizer, $d, 'arrow_left', 0, wxTOP, sub { $self->rel_move('X', $d) }); + } + $move_button->($sizer, 'X', 'house', 1, wxTOP, sub { $self->home('X') }); + for my $d (qw(+10 +1 +0.1)) { + $move_button->($sizer, $d, 'arrow_right', 0, wxTOP, sub { $self->rel_move('X', $d) }); + } + $bed_sizer->Add($sizer, 1, wxEXPAND, 0); + } + + my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); + $main_sizer->Add($bed_sizer, 1, wxEXPAND | wxALL, 10); + $main_sizer->Add($self->CreateButtonSizer(wxCLOSE), 0, wxEXPAND); + + $self->SetSizer($main_sizer); + $self->SetMinSize($self->GetSize); + #$main_sizer->SetSizeHints($self); + $self->Layout; + + # needed to actually free memory + EVT_CLOSE($self, sub { + $self->EndModal(wxID_OK); + $self->Destroy; + }); + + return $self; +} + +sub abs_xy_move { + my ($self, $pos) = @_; + + $self->sender->send("G90", 1); # set absolute positioning + $self->sender->send(sprintf("G1 X%.1f Y%.1f F%d", @$pos, TRAVEL_SPEED), 1); + $self->{canvas}->set_pos($pos); +} + +sub rel_move { + my ($self, $axis, $distance) = @_; + + $self->sender->send("G91", 1); # set relative positioning + $self->sender->send(sprintf("G1 %s%.1f F%d", $axis, $distance, TRAVEL_SPEED), 1); + $self->sender->send("G90", 1); # set absolute positioning + + if (my $pos = $self->{canvas}->pos) { + if ($axis eq 'X') { + $pos->translate($distance, 0); + } elsif ($axis eq 'Y') { + $pos->translate(0, $distance); + } + $self->{canvas}->set_pos($pos); + } +} + +sub home { + my ($self, $axis) = @_; + + $self->sender->send(sprintf("G28 %s", $axis), 1); + $self->{canvas}->set_pos(undef); +} + +1; diff --git a/lib/Slic3r/GUI/Controller/PrinterPanel.pm b/lib/Slic3r/GUI/Controller/PrinterPanel.pm index 09d092bd1..eaff5756f 100644 --- a/lib/Slic3r/GUI/Controller/PrinterPanel.pm +++ b/lib/Slic3r/GUI/Controller/PrinterPanel.pm @@ -160,6 +160,21 @@ sub new { $self->{status_text} = Wx::StaticText->new($box, -1, "", wxDefaultPosition, [200,-1]); $left_sizer->Add($self->{status_text}, 1, wxEXPAND | wxTOP, 15); + # manual control + { + $self->{btn_manual_control} = my $btn = Wx::Button->new($box, -1, "Manual control", wxDefaultPosition, wxDefaultSize); + $btn->SetFont($Slic3r::GUI::small_font); + if ($Slic3r::GUI::have_button_icons) { + $btn->SetBitmap(Wx::Bitmap->new("$Slic3r::var/cog.png", wxBITMAP_TYPE_PNG)); + } + $btn->Hide; + $left_sizer->Add($btn, 0, wxTOP, 15); + EVT_BUTTON($self, $btn, sub { + my $dlg = Slic3r::GUI::Controller::ManualControlDialog->new($self); + $dlg->ShowModal; + }); + } + # temperature { my $temp_panel = $self->{temp_panel} = Wx::Panel->new($box, -1); @@ -246,11 +261,15 @@ sub _update_connection_controls { $self->{serial_port_combobox}->Enable; $self->{serial_speed_combobox}->Enable; $self->{btn_rescan_serial}->Enable; + $self->{btn_manual_control}->Hide; + $self->{btn_manual_control}->Disable; if ($self->is_connected) { $self->{btn_connect}->Hide; + $self->{btn_manual_control}->Show; if (!$self->printing || $self->printing->paused) { $self->{btn_disconnect}->Show; + $self->{btn_manual_control}->Enable; } $self->{serial_port_combobox}->Disable; $self->{serial_speed_combobox}->Disable; diff --git a/var/arrow_down.png b/var/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..2c4e279377bf348f9cf53894e76bb673ccf067bd GIT binary patch literal 379 zcmV->0fhdEP)RB*?~^j!LKVQ>(O&A{Xr%)RXLn#U zs4LtZ6rCMFY5|B2$)yG$6aaIFq$gGR5;6H z{Qv(y10{fofkH6I3@AO3$p*x`Nil#0jeqs;pT9Ds7{CaN1)$9r#n~kE{`~pF@bLXZ zhF?E_GyM7i!oL`P0x_8Wj$ni2F7#hzWPxfvDaIo>#A+qW*AYQLZl(!&BX$x7Ik;qO170ssEM z@$bKXf%rGW?|(r27bf-TSv zD}TdX0CM*JhkLO)8|Y^+n~Q^sK~hqR;q|N647YFGy>NTZJsWr!5CaSfwJm@a><8NX v2&h?|1KIqEP)v;U&v3%|^C`Ga3?LtY&4dQB4Oz;1v;J%z!D&%WRH@BZ?x; z3)8@IUIv@hG|@IwyHLC`l{1<4BK>wam95g|i|?Cfzt876&-Zx_0f5*l-9`IJI&mHu zE6$@xB)6N}7VeR;!X8D!TAw;;&0Bsj?A071cO>X3K0wl7WZ1;Tg!4LHyNcnzoeQ7t zNW`aSlm8WXYkek&ir$13=ngczvf zV0vnjNpCF&K8px}dunv+`LIb-sOC$_jD(;IBI$xC|7`(+9cA>Vir_V#z{?k7SX^Ah z^71m~W@q439Ycqfhi7+gp#A14n1n1!e>$EdeATG|f798Y=ggzwEKH2Q!qU2QA(Se?dwqG69%>n$6rtE z%F(845Az8c{w(XgimJg96!jLMz?zS6I1HUm2baqQx7&@nx;lhHA!r6vs2|fqJETOu zLxeu2OQ(3(au%dg>AcZsWI(zXn9XJg1cLe8k~0h0wOL=&HK}7X k{AKr*U4z7Szv)i%9gTgghwgU$Q~&?~07*qoM6N<$g31kYk^lez literal 0 HcmV?d00001