diff --git a/Build.PL b/Build.PL index 3921e37f9..117b0aeeb 100644 --- a/Build.PL +++ b/Build.PL @@ -28,6 +28,7 @@ my %prereqs = qw( my %recommends = qw( Class::XSAccessor 0 LWP::UserAgent 0 + Net::Bonjour 0 XML::SAX::ExpatXS 0 ); diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index e9e1ff387..e08e6362d 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -7,6 +7,7 @@ use File::Basename qw(basename); use FindBin; use Slic3r::GUI::AboutDialog; use Slic3r::GUI::BedShapeDialog; +use Slic3r::GUI::BonjourBrowser; use Slic3r::GUI::ConfigWizard; use Slic3r::GUI::MainFrame; use Slic3r::GUI::Notifier; diff --git a/lib/Slic3r/GUI/BonjourBrowser.pm b/lib/Slic3r/GUI/BonjourBrowser.pm new file mode 100644 index 000000000..bb2282e59 --- /dev/null +++ b/lib/Slic3r/GUI/BonjourBrowser.pm @@ -0,0 +1,51 @@ +package Slic3r::GUI::BonjourBrowser; +use strict; +use warnings; +use utf8; + +use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL); +use Wx::Event qw(EVT_CLOSE); +use base 'Wx::Dialog'; + +sub new { + my $class = shift; + my ($parent) = @_; + my $self = $class->SUPER::new($parent, -1, "Device Browser", wxDefaultPosition, [350,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + # look for devices + eval "use Net::Bonjour; 1"; + my $res = Net::Bonjour->new('http'); + $res->discover; + $self->{devices} = [ $res->entries ]; + + # label + my $text = Wx::StaticText->new($self, -1, "Choose an Octoprint device in your network:", wxDefaultPosition, wxDefaultSize); + + # selector + $self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, + [ map $_->name, @{$self->{devices}} ]); + + my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); + $main_sizer->Add($text, 1, wxEXPAND | wxALL, 10); + $main_sizer->Add($choice, 1, wxEXPAND | wxALL, 10); + $main_sizer->Add($self->CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND); + + $self->SetSizer($main_sizer); + $self->SetMinSize($self->GetSize); + $main_sizer->SetSizeHints($self); + + # needed to actually free memory + EVT_CLOSE($self, sub { + $self->EndModal(wxID_OK); + $self->Destroy; + }); + + return $self; +} + +sub GetValue { + my ($self) = @_; + return $self->{devices}[ $self->{choice}->GetSelection ]->address; +} + +1; diff --git a/lib/Slic3r/GUI/OptionsGroup.pm b/lib/Slic3r/GUI/OptionsGroup.pm index 46d8aa678..d6a486828 100644 --- a/lib/Slic3r/GUI/OptionsGroup.pm +++ b/lib/Slic3r/GUI/OptionsGroup.pm @@ -83,7 +83,7 @@ sub append_line { # if we have a single option with no sidetext just add it directly to the grid sizer my @options = @{$line->get_options}; $self->_options->{$_->opt_id} = $_ for @options; - if (@options == 1 && !$options[0]->sidetext) { + if (@options == 1 && !$options[0]->sidetext && !@{$line->get_extra_widgets}) { my $option = $options[0]; my $field = $self->_build_field($option); $grid_sizer->Add($field, 0, ($option->full_width ? wxEXPAND : 0) | wxALIGN_CENTER_VERTICAL, 0); @@ -114,9 +114,14 @@ sub append_line { $sizer->Add($sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL , 4); } } + + # add extra sizers if any + foreach my $extra_widget (@{$line->get_extra_widgets}) { + $sizer->Add($extra_widget->($self->parent), 0, wxLEFT | wxALIGN_CENTER_VERTICAL , 4); + } } -sub append_single_option_line { +sub create_single_option_line { my ($self, $option) = @_; my $line = Slic3r::GUI::OptionsGroup::Line->new( @@ -125,11 +130,15 @@ sub append_single_option_line { ); $option->label(""); $line->append_option($option); - $self->append_line($line); return $line; } +sub append_single_option_line { + my ($self, $option) = @_; + return $self->append_line($self->create_single_option_line($option)); +} + sub _build_field { my $self = shift; my ($opt) = @_; @@ -241,6 +250,7 @@ has 'label_tooltip' => (is => 'rw', default => sub { "" }); has 'sizer' => (is => 'rw'); has 'widget' => (is => 'rw'); has '_options' => (is => 'ro', default => sub { [] }); +has '_extra_widgets' => (is => 'ro', default => sub { [] }); # this method accepts a Slic3r::GUI::OptionsGroup::Option object sub append_option { @@ -248,11 +258,21 @@ sub append_option { push @{$self->_options}, $option; } +sub append_widget { + my ($self, $widget) = @_; + push @{$self->_extra_widgets}, $widget; +} + sub get_options { my ($self) = @_; return [ @{$self->_options} ]; } +sub get_extra_widgets { + my ($self) = @_; + return [ @{$self->_extra_widgets} ]; +} + package Slic3r::GUI::OptionsGroup::Option; use Moo; @@ -320,7 +340,7 @@ sub get_option { ); } -sub append_single_option_line { +sub create_single_option_line { my ($self, $opt_key, $opt_index) = @_; my $option; @@ -329,7 +349,12 @@ sub append_single_option_line { } else { $option = $self->get_option($opt_key, $opt_index); } - return $self->SUPER::append_single_option_line($option); + return $self->SUPER::create_single_option_line($option); +} + +sub append_single_option_line { + my ($self, $option, $opt_index) = @_; + return $self->append_line($self->create_single_option_line($option, $opt_index)); } sub reload_config { diff --git a/lib/Slic3r/GUI/OptionsGroup/Field.pm b/lib/Slic3r/GUI/OptionsGroup/Field.pm index fcf97eb3f..13b86cdfc 100644 --- a/lib/Slic3r/GUI/OptionsGroup/Field.pm +++ b/lib/Slic3r/GUI/OptionsGroup/Field.pm @@ -347,6 +347,7 @@ sub BUILD { $self->wxSizer($sizer); my $field_size = Wx::Size->new(40, -1); + $self->x_textctrl(Wx::TextCtrl->new($self->parent, -1, $self->option->default->[X], wxDefaultPosition, $field_size)); $self->y_textctrl(Wx::TextCtrl->new($self->parent, -1, $self->option->default->[Y], wxDefaultPosition, $field_size)); diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index a1b4768b5..b5250f047 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -999,7 +999,40 @@ sub build { } { my $optgroup = $page->new_optgroup('Octoprint upload'); - $optgroup->append_single_option_line('octoprint_host'); + + # append a button to the Host line + my $octoprint_host_widget = sub { + my ($parent) = @_; + + my $btn = Wx::Button->new($parent, -1, "Browse…", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + $btn->SetFont($Slic3r::GUI::small_font); + if ($Slic3r::GUI::have_button_icons) { + $btn->SetBitmap(Wx::Bitmap->new("$Slic3r::var/cog.png", wxBITMAP_TYPE_PNG)); + } + + if (!eval "use Net::Bonjour; 1") { + $btn->Disable; + } + + my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); + $sizer->Add($btn); + + EVT_BUTTON($self, $btn, sub { + my $dlg = Slic3r::GUI::BonjourBrowser->new($self); + if ($dlg->ShowModal == wxID_OK) { + my $value = $dlg->GetValue; + $self->{config}->set('octoprint_host', $value); + $self->update_dirty; + $self->_on_value_change('octoprint_host', $value); + } + }); + + return $sizer; + }; + + my $host_line = $optgroup->create_single_option_line('octoprint_host'); + $host_line->append_widget($octoprint_host_widget); + $optgroup->append_line($host_line); $optgroup->append_single_option_line('octoprint_apikey'); } {