2016-09-14 09:22:41 +00:00
|
|
|
|
# A dialog group object. Used by the Tab, SimpleTab, Preferences dialog, ManualControlDialog etc.
|
|
|
|
|
|
2011-10-03 09:55:32 +00:00
|
|
|
|
package Slic3r::GUI::OptionsGroup;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
use Moo;
|
2011-10-03 09:55:32 +00:00
|
|
|
|
|
2012-07-27 19:13:03 +00:00
|
|
|
|
use List::Util qw(first);
|
2014-06-14 17:59:59 +00:00
|
|
|
|
use Wx qw(:combobox :font :misc :sizer :systemsettings :textctrl wxTheApp);
|
2014-04-25 16:36:08 +00:00
|
|
|
|
use Wx::Event qw(EVT_CHECKBOX EVT_COMBOBOX EVT_SPINCTRL EVT_TEXT EVT_KILL_FOCUS EVT_SLIDER);
|
2011-10-03 09:55:32 +00:00
|
|
|
|
|
2012-07-24 13:30:50 +00:00
|
|
|
|
has 'parent' => (is => 'ro', required => 1);
|
|
|
|
|
has 'title' => (is => 'ro', required => 1);
|
2014-07-01 14:40:56 +00:00
|
|
|
|
has 'on_change' => (is => 'rw', default => sub { sub {} });
|
2014-06-15 23:49:49 +00:00
|
|
|
|
has 'staticbox' => (is => 'ro', default => sub { 1 });
|
2014-07-01 14:40:56 +00:00
|
|
|
|
has 'label_width' => (is => 'rw', default => sub { 180 });
|
|
|
|
|
has 'extra_column' => (is => 'rw', default => sub { undef });
|
|
|
|
|
has 'label_font' => (is => 'rw');
|
|
|
|
|
has 'sidetext_font' => (is => 'rw', default => sub { Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) });
|
2012-07-24 13:30:50 +00:00
|
|
|
|
has 'sizer' => (is => 'rw');
|
2014-07-01 14:40:56 +00:00
|
|
|
|
has '_disabled' => (is => 'rw', default => sub { 0 });
|
|
|
|
|
has '_grid_sizer' => (is => 'rw');
|
|
|
|
|
has '_options' => (is => 'ro', default => sub { {} });
|
|
|
|
|
has '_fields' => (is => 'ro', default => sub { {} });
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
|
|
|
|
sub BUILD {
|
|
|
|
|
my $self = shift;
|
2011-10-03 09:55:32 +00:00
|
|
|
|
|
2014-06-15 23:49:49 +00:00
|
|
|
|
if ($self->staticbox) {
|
2012-07-24 13:30:50 +00:00
|
|
|
|
my $box = Wx::StaticBox->new($self->parent, -1, $self->title);
|
|
|
|
|
$self->sizer(Wx::StaticBoxSizer->new($box, wxVERTICAL));
|
2014-06-15 23:49:49 +00:00
|
|
|
|
} else {
|
|
|
|
|
$self->sizer(Wx::BoxSizer->new(wxVERTICAL));
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
2011-10-03 09:55:32 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my $num_columns = 1;
|
|
|
|
|
++$num_columns if $self->label_width != 0;
|
|
|
|
|
++$num_columns if $self->extra_column;
|
|
|
|
|
$self->_grid_sizer(Wx::FlexGridSizer->new(0, $num_columns, 0, 0));
|
|
|
|
|
$self->_grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
|
|
|
|
$self->_grid_sizer->AddGrowableCol($self->label_width != 0);
|
2012-06-18 09:26:21 +00:00
|
|
|
|
|
2012-10-25 09:24:56 +00:00
|
|
|
|
# TODO: border size may be related to wxWidgets 2.8.x vs. 2.9.x instead of wxMAC specific
|
2014-07-01 14:40:56 +00:00
|
|
|
|
$self->sizer->Add($self->_grid_sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 5);
|
2012-10-25 09:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# this method accepts a Slic3r::GUI::OptionsGroup::Line object
|
|
|
|
|
sub append_line {
|
|
|
|
|
my ($self, $line) = @_;
|
2012-10-25 09:24:56 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
if ($line->sizer || ($line->widget && $line->full_width)) {
|
|
|
|
|
# full-width widgets are appended *after* the grid sizer, so after all the non-full-width lines
|
|
|
|
|
my $sizer = $line->sizer // $line->widget->($self->parent);
|
|
|
|
|
$self->sizer->Add($sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
|
|
|
|
|
return;
|
2012-10-25 09:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my $grid_sizer = $self->_grid_sizer;
|
|
|
|
|
|
|
|
|
|
# if we have an extra column, build it
|
2013-08-25 12:37:50 +00:00
|
|
|
|
if ($self->extra_column) {
|
2014-03-23 14:25:26 +00:00
|
|
|
|
if (defined (my $item = $self->extra_column->($line))) {
|
2014-03-23 14:18:08 +00:00
|
|
|
|
$grid_sizer->Add($item, 0, wxALIGN_CENTER_VERTICAL, 0);
|
|
|
|
|
} else {
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# if the callback provides no sizer for the extra cell, put a spacer
|
2014-03-23 14:18:08 +00:00
|
|
|
|
$grid_sizer->AddSpacer(1);
|
|
|
|
|
}
|
2013-08-25 12:37:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# build label if we have it
|
2012-10-25 09:24:56 +00:00
|
|
|
|
my $label;
|
2014-07-01 14:40:56 +00:00
|
|
|
|
if ($self->label_width != 0) {
|
|
|
|
|
$label = Wx::StaticText->new($self->parent, -1, $line->label ? $line->label . ":" : "", wxDefaultPosition, [$self->label_width, -1]);
|
2014-03-23 14:18:08 +00:00
|
|
|
|
$label->SetFont($self->label_font) if $self->label_font;
|
2012-10-25 09:24:56 +00:00
|
|
|
|
$label->Wrap($self->label_width) ; # needed to avoid Linux/GTK bug
|
|
|
|
|
$grid_sizer->Add($label, 0, wxALIGN_CENTER_VERTICAL, 0);
|
2014-07-01 14:40:56 +00:00
|
|
|
|
$label->SetToolTipString($line->label_tooltip) if $line->label_tooltip;
|
2012-10-25 09:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# if we have a widget, add it to the sizer
|
|
|
|
|
if ($line->widget) {
|
|
|
|
|
my $widget_sizer = $line->widget->($self->parent);
|
|
|
|
|
$grid_sizer->Add($widget_sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
|
|
|
|
|
return;
|
2012-10-25 09:24:56 +00:00
|
|
|
|
}
|
2014-07-01 14:40:56 +00:00
|
|
|
|
|
|
|
|
|
# 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;
|
2015-01-04 18:14:54 +00:00
|
|
|
|
if (@options == 1 && !$options[0]->sidetext && !$options[0]->side_widget && !@{$line->get_extra_widgets}) {
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my $option = $options[0];
|
|
|
|
|
my $field = $self->_build_field($option);
|
|
|
|
|
$grid_sizer->Add($field, 0, ($option->full_width ? wxEXPAND : 0) | wxALIGN_CENTER_VERTICAL, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# if we're here, we have more than one option or a single option with sidetext
|
|
|
|
|
# so we need a horizontal sizer to arrange these things
|
|
|
|
|
my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
|
|
|
|
$grid_sizer->Add($sizer, 0, 0, 0);
|
|
|
|
|
|
2015-01-04 18:14:54 +00:00
|
|
|
|
foreach my $i (0..$#options) {
|
|
|
|
|
my $option = $options[$i];
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# add label if any
|
|
|
|
|
if ($option->label) {
|
|
|
|
|
my $field_label = Wx::StaticText->new($self->parent, -1, $option->label . ":", wxDefaultPosition, wxDefaultSize);
|
|
|
|
|
$field_label->SetFont($self->sidetext_font);
|
|
|
|
|
$sizer->Add($field_label, 0, wxALIGN_CENTER_VERTICAL, 0);
|
2012-10-25 10:21:04 +00:00
|
|
|
|
}
|
2014-07-01 14:40:56 +00:00
|
|
|
|
|
|
|
|
|
# add field
|
|
|
|
|
my $field = $self->_build_field($option);
|
|
|
|
|
$sizer->Add($field, 0, wxALIGN_CENTER_VERTICAL, 0);
|
|
|
|
|
|
|
|
|
|
# add sidetext if any
|
|
|
|
|
if ($option->sidetext) {
|
|
|
|
|
my $sidetext = Wx::StaticText->new($self->parent, -1, $option->sidetext, wxDefaultPosition, wxDefaultSize);
|
2014-03-23 14:18:08 +00:00
|
|
|
|
$sidetext->SetFont($self->sidetext_font);
|
2015-01-04 18:14:54 +00:00
|
|
|
|
$sizer->Add($sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# add side widget if any
|
|
|
|
|
if ($option->side_widget) {
|
|
|
|
|
$sizer->Add($option->side_widget->($self->parent), 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($option != $#options) {
|
|
|
|
|
$sizer->AddSpacer(4);
|
2012-10-25 10:21:04 +00:00
|
|
|
|
}
|
2012-10-25 09:24:56 +00:00
|
|
|
|
}
|
2014-12-28 17:49:13 +00:00
|
|
|
|
|
|
|
|
|
# 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);
|
|
|
|
|
}
|
2012-10-25 09:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-28 17:49:13 +00:00
|
|
|
|
sub create_single_option_line {
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my ($self, $option) = @_;
|
|
|
|
|
|
|
|
|
|
my $line = Slic3r::GUI::OptionsGroup::Line->new(
|
|
|
|
|
label => $option->label,
|
|
|
|
|
label_tooltip => $option->tooltip,
|
|
|
|
|
);
|
|
|
|
|
$option->label("");
|
|
|
|
|
$line->append_option($option);
|
|
|
|
|
|
|
|
|
|
return $line;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-28 17:49:13 +00:00
|
|
|
|
sub append_single_option_line {
|
|
|
|
|
my ($self, $option) = @_;
|
|
|
|
|
return $self->append_line($self->create_single_option_line($option));
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-25 09:24:56 +00:00
|
|
|
|
sub _build_field {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
my ($opt) = @_;
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my $opt_id = $opt->opt_id;
|
|
|
|
|
my $on_change = sub {
|
|
|
|
|
my ($opt_id, $value) = @_;
|
|
|
|
|
$self->_on_change($opt_id, $value)
|
|
|
|
|
unless $self->_disabled;
|
|
|
|
|
};
|
2014-04-19 16:16:34 +00:00
|
|
|
|
my $on_kill_focus = sub {
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my ($opt_id) = @_;
|
|
|
|
|
$self->_on_kill_focus($opt_id);
|
2014-04-19 16:16:34 +00:00
|
|
|
|
};
|
|
|
|
|
|
2014-06-19 18:07:16 +00:00
|
|
|
|
my $type = $opt->{gui_type} || $opt->{type};
|
2014-07-01 14:40:56 +00:00
|
|
|
|
|
|
|
|
|
my $field;
|
|
|
|
|
if ($type eq 'bool') {
|
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::Checkbox->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
|
|
|
|
);
|
|
|
|
|
} elsif ($type eq 'i') {
|
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::SpinCtrl->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
|
|
|
|
);
|
2015-05-26 00:01:43 +00:00
|
|
|
|
} elsif ($type eq 'color') {
|
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::ColourPicker->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
|
|
|
|
);
|
2014-07-01 14:40:56 +00:00
|
|
|
|
} elsif ($type =~ /^(f|s|s@|percent)$/) {
|
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::TextCtrl->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
2012-10-25 09:24:56 +00:00
|
|
|
|
);
|
2015-01-04 18:14:54 +00:00
|
|
|
|
} elsif ($type eq 'select' || $type eq 'select_open') {
|
2014-07-01 14:40:56 +00:00
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::Choice->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
|
|
|
|
);
|
|
|
|
|
} elsif ($type eq 'f_enum_open' || $type eq 'i_enum_open' || $type eq 'i_enum_closed') {
|
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::NumericChoice->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
|
|
|
|
);
|
|
|
|
|
} elsif ($type eq 'point') {
|
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::Point->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
|
|
|
|
);
|
|
|
|
|
} elsif ($type eq 'slider') {
|
|
|
|
|
$field = Slic3r::GUI::OptionsGroup::Field::Slider->new(
|
|
|
|
|
parent => $self->parent,
|
|
|
|
|
option => $opt,
|
|
|
|
|
);
|
2013-01-29 22:52:38 +00:00
|
|
|
|
}
|
2014-07-01 14:40:56 +00:00
|
|
|
|
return undef if !$field;
|
|
|
|
|
|
|
|
|
|
$field->on_change($on_change);
|
|
|
|
|
$field->on_kill_focus($on_kill_focus);
|
|
|
|
|
$self->_fields->{$opt_id} = $field;
|
|
|
|
|
|
|
|
|
|
return $field->isa('Slic3r::GUI::OptionsGroup::Field::wxWindow')
|
|
|
|
|
? $field->wxWindow
|
|
|
|
|
: $field->wxSizer;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 16:18:23 +00:00
|
|
|
|
sub get_option {
|
|
|
|
|
my ($self, $opt_id) = @_;
|
|
|
|
|
return undef if !exists $self->_options->{$opt_id};
|
|
|
|
|
return $self->_options->{$opt_id};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub get_field {
|
|
|
|
|
my ($self, $opt_id) = @_;
|
|
|
|
|
return undef if !exists $self->_fields->{$opt_id};
|
|
|
|
|
return $self->_fields->{$opt_id};
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub get_value {
|
|
|
|
|
my ($self, $opt_id) = @_;
|
2012-07-27 19:13:03 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
return if !exists $self->_fields->{$opt_id};
|
|
|
|
|
return $self->_fields->{$opt_id}->get_value;
|
2012-07-27 19:13:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub set_value {
|
|
|
|
|
my ($self, $opt_id, $value) = @_;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
return if !exists $self->_fields->{$opt_id};
|
|
|
|
|
$self->_fields->{$opt_id}->set_value($value);
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub _on_change {
|
2015-11-15 20:08:14 +00:00
|
|
|
|
my ($self, $opt_id, $value) = @_;
|
|
|
|
|
$self->on_change->($opt_id, $value);
|
2014-07-01 14:40:56 +00:00
|
|
|
|
}
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2015-12-04 17:52:53 +00:00
|
|
|
|
sub enable {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
|
|
$_->enable for values %{$self->_fields};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub disable {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
|
|
$_->disable for values %{$self->_fields};
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub _on_kill_focus {
|
|
|
|
|
my ($self, $opt_id) = @_;
|
|
|
|
|
# nothing
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-24 00:07:30 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
package Slic3r::GUI::OptionsGroup::Line;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
use Moo;
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
has 'label' => (is => 'rw', default => sub { "" });
|
|
|
|
|
has 'full_width' => (is => 'rw', default => sub { 0 });
|
|
|
|
|
has 'label_tooltip' => (is => 'rw', default => sub { "" });
|
|
|
|
|
has 'sizer' => (is => 'rw');
|
|
|
|
|
has 'widget' => (is => 'rw');
|
|
|
|
|
has '_options' => (is => 'ro', default => sub { [] });
|
2017-05-24 13:20:20 +00:00
|
|
|
|
# Extra UI components after the label and the edit widget of the option.
|
2014-12-28 17:49:13 +00:00
|
|
|
|
has '_extra_widgets' => (is => 'ro', default => sub { [] });
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# this method accepts a Slic3r::GUI::OptionsGroup::Option object
|
|
|
|
|
sub append_option {
|
|
|
|
|
my ($self, $option) = @_;
|
|
|
|
|
push @{$self->_options}, $option;
|
|
|
|
|
}
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-12-28 17:49:13 +00:00
|
|
|
|
sub append_widget {
|
|
|
|
|
my ($self, $widget) = @_;
|
|
|
|
|
push @{$self->_extra_widgets}, $widget;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub get_options {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
return [ @{$self->_options} ];
|
|
|
|
|
}
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-12-28 17:49:13 +00:00
|
|
|
|
sub get_extra_widgets {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
return [ @{$self->_extra_widgets} ];
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2017-05-24 13:20:20 +00:00
|
|
|
|
# Configuration of an option.
|
|
|
|
|
# This very much reflects the content of the C++ ConfigOptionDef class.
|
2014-07-01 14:40:56 +00:00
|
|
|
|
package Slic3r::GUI::OptionsGroup::Option;
|
|
|
|
|
use Moo;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
has 'opt_id' => (is => 'rw', required => 1);
|
|
|
|
|
has 'type' => (is => 'rw', required => 1);
|
|
|
|
|
has 'default' => (is => 'rw', required => 1);
|
|
|
|
|
has 'gui_type' => (is => 'rw', default => sub { undef });
|
|
|
|
|
has 'gui_flags' => (is => 'rw', default => sub { "" });
|
|
|
|
|
has 'label' => (is => 'rw', default => sub { "" });
|
|
|
|
|
has 'sidetext' => (is => 'rw', default => sub { "" });
|
|
|
|
|
has 'tooltip' => (is => 'rw', default => sub { "" });
|
|
|
|
|
has 'multiline' => (is => 'rw', default => sub { 0 });
|
|
|
|
|
has 'full_width' => (is => 'rw', default => sub { 0 });
|
|
|
|
|
has 'width' => (is => 'rw', default => sub { undef });
|
|
|
|
|
has 'height' => (is => 'rw', default => sub { undef });
|
|
|
|
|
has 'min' => (is => 'rw', default => sub { undef });
|
|
|
|
|
has 'max' => (is => 'rw', default => sub { undef });
|
|
|
|
|
has 'labels' => (is => 'rw', default => sub { [] });
|
|
|
|
|
has 'values' => (is => 'rw', default => sub { [] });
|
|
|
|
|
has 'readonly' => (is => 'rw', default => sub { 0 });
|
2015-01-04 18:14:54 +00:00
|
|
|
|
has 'side_widget' => (is => 'rw', default => sub { undef });
|
2012-07-28 09:53:10 +00:00
|
|
|
|
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
package Slic3r::GUI::ConfigOptionsGroup;
|
|
|
|
|
use Moo;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 16:18:23 +00:00
|
|
|
|
use List::Util qw(first);
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
extends 'Slic3r::GUI::OptionsGroup';
|
|
|
|
|
has 'config' => (is => 'ro', required => 1);
|
|
|
|
|
has 'full_labels' => (is => 'ro', default => sub { 0 });
|
|
|
|
|
has '_opt_map' => (is => 'ro', default => sub { {} });
|
2012-07-28 09:53:10 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub get_option {
|
|
|
|
|
my ($self, $opt_key, $opt_index) = @_;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
$opt_index //= -1;
|
2012-07-27 19:13:03 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
if (!$self->config->has($opt_key)) {
|
|
|
|
|
die "No $opt_key in ConfigOptionsGroup config";
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my $opt_id = ($opt_index == -1 ? $opt_key : "${opt_key}#${opt_index}");
|
|
|
|
|
$self->_opt_map->{$opt_id} = [ $opt_key, $opt_index ];
|
2014-06-16 20:45:13 +00:00
|
|
|
|
|
2017-05-24 13:20:20 +00:00
|
|
|
|
# Slic3r::Config::Options is a C++ Slic3r::PrintConfigDef exported as a Perl hash of hashes.
|
|
|
|
|
# The C++ counterpart is a constant singleton.
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my $optdef = $Slic3r::Config::Options->{$opt_key}; # we should access this from $self->config
|
|
|
|
|
my $default_value = $self->_get_config_value($opt_key, $opt_index, $optdef->{gui_flags} =~ /\bserialized\b/);
|
|
|
|
|
|
|
|
|
|
return Slic3r::GUI::OptionsGroup::Option->new(
|
|
|
|
|
opt_id => $opt_id,
|
|
|
|
|
type => $optdef->{type},
|
|
|
|
|
default => $default_value,
|
|
|
|
|
gui_type => $optdef->{gui_type},
|
|
|
|
|
gui_flags => $optdef->{gui_flags},
|
|
|
|
|
label => ($self->full_labels && defined $optdef->{full_label}) ? $optdef->{full_label} : $optdef->{label},
|
|
|
|
|
sidetext => $optdef->{sidetext},
|
2015-11-04 18:13:11 +00:00
|
|
|
|
# calling serialize() ensures we get a stringified value
|
|
|
|
|
tooltip => $optdef->{tooltip} . " (default: " . $self->config->serialize($opt_key) . ")",
|
2014-07-01 14:40:56 +00:00
|
|
|
|
multiline => $optdef->{multiline},
|
|
|
|
|
width => $optdef->{width},
|
|
|
|
|
min => $optdef->{min},
|
|
|
|
|
max => $optdef->{max},
|
|
|
|
|
labels => $optdef->{labels},
|
|
|
|
|
values => $optdef->{values},
|
|
|
|
|
readonly => $optdef->{readonly},
|
|
|
|
|
);
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-28 17:49:13 +00:00
|
|
|
|
sub create_single_option_line {
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my ($self, $opt_key, $opt_index) = @_;
|
2014-03-24 00:07:30 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
my $option;
|
|
|
|
|
if (ref($opt_key)) {
|
|
|
|
|
$option = $opt_key;
|
|
|
|
|
} else {
|
|
|
|
|
$option = $self->get_option($opt_key, $opt_index);
|
|
|
|
|
}
|
2014-12-28 17:49:13 +00:00
|
|
|
|
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));
|
2014-03-24 00:07:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 17:28:53 +00:00
|
|
|
|
# Initialize UI components with the config values.
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub reload_config {
|
|
|
|
|
my ($self) = @_;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
foreach my $opt_id (keys %{ $self->_opt_map }) {
|
|
|
|
|
my ($opt_key, $opt_index) = @{ $self->_opt_map->{$opt_id} };
|
|
|
|
|
my $option = $self->_options->{$opt_id};
|
|
|
|
|
$self->set_value($opt_id, $self->_get_config_value($opt_key, $opt_index, $option->gui_flags =~ /\bserialized\b/));
|
|
|
|
|
}
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 16:18:23 +00:00
|
|
|
|
sub get_fieldc {
|
|
|
|
|
my ($self, $opt_key, $opt_index) = @_;
|
|
|
|
|
|
|
|
|
|
$opt_index //= -1;
|
|
|
|
|
my $opt_id = first { $self->_opt_map->{$_}[0] eq $opt_key && $self->_opt_map->{$_}[1] == $opt_index }
|
|
|
|
|
keys %{$self->_opt_map};
|
|
|
|
|
return defined($opt_id) ? $self->get_field($opt_id) : undef;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub _get_config_value {
|
|
|
|
|
my ($self, $opt_key, $opt_index, $deserialize) = @_;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
if ($deserialize) {
|
2017-02-08 09:35:21 +00:00
|
|
|
|
# Want to edit a vector value (currently only multi-strings) in a single edit box.
|
|
|
|
|
# Aggregate the strings the old way.
|
|
|
|
|
# Currently used for the post_process config value only.
|
2014-07-01 14:40:56 +00:00
|
|
|
|
die "Can't deserialize option indexed value" if $opt_index != -1;
|
2017-02-08 09:35:21 +00:00
|
|
|
|
return join(';', @{$self->config->get($opt_key)});
|
2014-07-01 14:40:56 +00:00
|
|
|
|
} else {
|
|
|
|
|
return $opt_index == -1
|
|
|
|
|
? $self->config->get($opt_key)
|
|
|
|
|
: $self->config->get_at($opt_key, $opt_index);
|
2012-07-27 19:13:03 +00:00
|
|
|
|
}
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub _on_change {
|
2015-11-15 20:08:14 +00:00
|
|
|
|
my ($self, $opt_id, $value) = @_;
|
2012-07-24 13:30:50 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
if (exists $self->_opt_map->{$opt_id}) {
|
|
|
|
|
my ($opt_key, $opt_index) = @{ $self->_opt_map->{$opt_id} };
|
|
|
|
|
my $option = $self->_options->{$opt_id};
|
2014-04-19 16:16:34 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# get value
|
|
|
|
|
my $field_value = $self->get_value($opt_id);
|
|
|
|
|
if ($option->gui_flags =~ /\bserialized\b/) {
|
|
|
|
|
die "Can't set serialized option indexed value" if $opt_index != -1;
|
2017-02-08 09:35:21 +00:00
|
|
|
|
# Split a string to multiple strings by a semi-colon. This is the old way of storing multi-string values.
|
|
|
|
|
# Currently used for the post_process config value only.
|
|
|
|
|
my @values = split /;/, $field_value;
|
|
|
|
|
$self->config->set($opt_key, \@values);
|
2014-07-01 14:40:56 +00:00
|
|
|
|
} else {
|
|
|
|
|
if ($opt_index == -1) {
|
|
|
|
|
$self->config->set($opt_key, $field_value);
|
|
|
|
|
} else {
|
|
|
|
|
my $value = $self->config->get($opt_key);
|
|
|
|
|
$value->[$opt_index] = $field_value;
|
|
|
|
|
$self->config->set($opt_key, $value);
|
|
|
|
|
}
|
2013-12-22 00:27:09 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-01 14:40:56 +00:00
|
|
|
|
|
2015-11-15 20:08:14 +00:00
|
|
|
|
$self->SUPER::_on_change($opt_id, $value);
|
2012-07-24 13:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
sub _on_kill_focus {
|
|
|
|
|
my ($self, $opt_id) = @_;
|
2011-10-03 09:55:32 +00:00
|
|
|
|
|
2014-07-01 14:40:56 +00:00
|
|
|
|
# when a field loses focus, reapply the config value to it
|
|
|
|
|
# (thus discarding any invalid input and reverting to the last
|
|
|
|
|
# accepted value)
|
|
|
|
|
$self->reload_config;
|
2011-10-03 09:55:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-24 13:20:20 +00:00
|
|
|
|
# Static text shown among the options.
|
|
|
|
|
# Currently used for the filament cooling legend only.
|
2014-07-01 14:40:56 +00:00
|
|
|
|
package Slic3r::GUI::OptionsGroup::StaticText;
|
2012-10-28 11:43:41 +00:00
|
|
|
|
use Wx qw(:misc :systemsettings);
|
2014-06-15 23:49:49 +00:00
|
|
|
|
use base 'Wx::StaticText';
|
2012-10-28 11:43:41 +00:00
|
|
|
|
|
2014-06-15 23:49:49 +00:00
|
|
|
|
sub new {
|
|
|
|
|
my ($class, $parent) = @_;
|
2012-10-28 11:43:41 +00:00
|
|
|
|
|
2014-06-15 23:49:49 +00:00
|
|
|
|
my $self = $class->SUPER::new($parent, -1, "", wxDefaultPosition, wxDefaultSize);
|
2012-10-28 11:43:41 +00:00
|
|
|
|
my $font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
2014-06-15 23:49:49 +00:00
|
|
|
|
$self->SetFont($font);
|
|
|
|
|
return $self;
|
2012-10-28 11:43:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub SetText {
|
2014-06-15 23:49:49 +00:00
|
|
|
|
my ($self, $value) = @_;
|
2012-10-28 11:43:41 +00:00
|
|
|
|
|
2014-06-15 23:49:49 +00:00
|
|
|
|
$self->SetLabel($value);
|
|
|
|
|
$self->Wrap(400);
|
|
|
|
|
$self->GetParent->Layout;
|
2012-10-28 11:43:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-03 09:55:32 +00:00
|
|
|
|
1;
|