Refactor simple mode definitions to dedicated SimpleTab classes

This commit is contained in:
Alessandro Ranellucci 2013-03-09 16:27:18 +01:00
parent 5477d66902
commit af50272b3b
5 changed files with 375 additions and 293 deletions

View File

@ -34,6 +34,7 @@ lib/Slic3r/GUI/OptionsGroup.pm
lib/Slic3r/GUI/Plater.pm lib/Slic3r/GUI/Plater.pm
lib/Slic3r/GUI/Preferences.pm lib/Slic3r/GUI/Preferences.pm
lib/Slic3r/GUI/SkeinPanel.pm lib/Slic3r/GUI/SkeinPanel.pm
lib/Slic3r/GUI/SimpleTab.pm
lib/Slic3r/GUI/Tab.pm lib/Slic3r/GUI/Tab.pm
lib/Slic3r/Layer.pm lib/Slic3r/Layer.pm
lib/Slic3r/Layer/Region.pm lib/Slic3r/Layer/Region.pm

View File

@ -10,6 +10,7 @@ use Slic3r::GUI::Plater;
use Slic3r::GUI::Preferences; use Slic3r::GUI::Preferences;
use Slic3r::GUI::OptionsGroup; use Slic3r::GUI::OptionsGroup;
use Slic3r::GUI::SkeinPanel; use Slic3r::GUI::SkeinPanel;
use Slic3r::GUI::SimpleTab;
use Slic3r::GUI::Tab; use Slic3r::GUI::Tab;
use Wx 0.9901 qw(:bitmap :dialog :frame :icon :id :misc :systemsettings :toplevelwindow); use Wx 0.9901 qw(:bitmap :dialog :frame :icon :id :misc :systemsettings :toplevelwindow);

224
lib/Slic3r/GUI/SimpleTab.pm Normal file
View File

@ -0,0 +1,224 @@
package Slic3r::GUI::SimpleTab;
use strict;
use warnings;
use utf8;
use File::Basename qw(basename);
use List::Util qw(first);
use Wx qw(:bookctrl :dialog :keycode :icon :id :misc :panel :sizer :window :systemsettings);
use Wx::Event qw(EVT_BUTTON EVT_CHOICE EVT_KEY_DOWN EVT_TREE_SEL_CHANGED);
use base 'Wx::ScrolledWindow';
sub new {
my $class = shift;
my ($parent, %params) = @_;
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL);
$self->{options} = []; # array of option names handled by this tab
$self->{$_} = $params{$_} for qw(on_value_change);
$self->SetScrollbars(1, 1, 1, 1);
$self->{config} = Slic3r::Config->new;
$self->{optgroups} = [];
$self->{vsizer} = Wx::BoxSizer->new(wxVERTICAL);
$self->SetSizer($self->{vsizer});
$self->build;
{
my $label = Wx::StaticText->new($self, -1, "Want more options? Switch to the Expert Mode.", wxDefaultPosition, wxDefaultSize);
$label->SetFont(Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
$self->{vsizer}->Add($label, 0, wxEXPAND | wxALL, 10);
}
return $self;
}
sub append_optgroup {
my $self = shift;
my %params = @_;
# apply default values
{
my @options = @{$params{options}};
$_ =~ s/#.+// for @options;
my $config = Slic3r::Config->new_from_defaults(@options);
$self->{config}->apply($config);
}
my $class = $params{class} || 'Slic3r::GUI::ConfigOptionsGroup';
my $optgroup = $class->new(
parent => $self,
config => $self->{config},
label_width => 200,
on_change => sub { $self->on_value_change(@_) },
%params,
);
push @{$self->{optgroups}}, $optgroup;
($params{sizer} || $self->{vsizer})->Add($optgroup->sizer, 0, wxEXPAND | wxALL, 10);
}
sub load_config_file {
my $self = shift;
my ($file) = @_;
my $config = Slic3r::Config->load($file);
$self->load_config($config);
}
sub load_config {
my $self = shift;
my ($config) = @_;
foreach my $opt_key (grep $self->{config}->has($_), keys %$config) {
my $value = $config->get($opt_key);
$self->{config}->set($opt_key, $value);
$_->set_value($opt_key, $value) for @{$self->{optgroups}};
}
}
sub is_dirty { 0 }
sub config { $_[0]->{config}->clone }
# propagate event to the parent
sub on_value_change {
my $self = shift;
$self->{on_value_change}->(@_) if $self->{on_value_change};
}
package Slic3r::GUI::SimpleTab::Print;
use base 'Slic3r::GUI::SimpleTab';
use Wx qw(:sizer);
sub name { 'print' }
sub title { 'Print Settings' }
sub build {
my $self = shift;
$self->append_optgroup(
title => 'General',
options => [qw(layer_height perimeters top_solid_layers bottom_solid_layers)],
lines => [
Slic3r::GUI::OptionsGroup->single_option_line('layer_height'),
Slic3r::GUI::OptionsGroup->single_option_line('perimeters'),
{
label => 'Solid layers',
options => [qw(top_solid_layers bottom_solid_layers)],
},
],
);
$self->append_optgroup(
title => 'Infill',
options => [qw(fill_density fill_pattern)],
);
$self->append_optgroup(
title => 'Support material',
options => [qw(support_material support_material_spacing raft_layers)],
);
$self->append_optgroup(
title => 'Speed',
options => [qw(perimeter_speed infill_speed travel_speed)],
);
$self->append_optgroup(
title => 'Brim',
options => [qw(brim_width)],
);
$self->append_optgroup(
title => 'Sequential printing',
options => [qw(complete_objects extruder_clearance_radius extruder_clearance_height)],
lines => [
Slic3r::GUI::OptionsGroup->single_option_line('complete_objects'),
{
label => 'Extruder clearance (mm)',
options => [qw(extruder_clearance_radius extruder_clearance_height)],
},
],
);
}
package Slic3r::GUI::SimpleTab::Filament;
use base 'Slic3r::GUI::SimpleTab';
sub name { 'filament' }
sub title { 'Filament Settings' }
sub build {
my $self = shift;
$self->append_optgroup(
title => 'Filament',
options => ['filament_diameter#0', 'extrusion_multiplier#0'],
);
$self->append_optgroup(
title => 'Temperature (°C)',
options => ['temperature#0', 'first_layer_temperature#0', qw(bed_temperature first_layer_bed_temperature)],
lines => [
{
label => 'Extruder',
options => ['first_layer_temperature#0', 'temperature#0'],
},
{
label => 'Bed',
options => [qw(first_layer_bed_temperature bed_temperature)],
},
],
);
$self->append_optgroup(
title => 'Cooling',
options => [qw(cooling)],
);
}
package Slic3r::GUI::SimpleTab::Printer;
use base 'Slic3r::GUI::SimpleTab';
sub name { 'printer' }
sub title { 'Printer Settings' }
sub build {
my $self = shift;
$self->append_optgroup(
title => 'Size and coordinates',
options => [qw(bed_size print_center z_offset)],
);
$self->append_optgroup(
title => 'Firmware',
options => [qw(gcode_flavor)],
);
$self->append_optgroup(
title => 'Extruder',
options => ['nozzle_diameter#0'],
);
$self->append_optgroup(
title => 'Retraction',
options => ['retract_length#0', 'retract_lift#0'],
);
$self->append_optgroup(
title => 'Start G-code',
no_labels => 1,
options => [qw(start_gcode)],
);
$self->append_optgroup(
title => 'End G-code',
no_labels => 1,
options => [qw(end_gcode)],
);
}
1;

View File

@ -33,26 +33,30 @@ sub new {
$self->{tabpanel}->AddPage($self->{plater} = Slic3r::GUI::Plater->new($self->{tabpanel}), "Plater"); $self->{tabpanel}->AddPage($self->{plater} = Slic3r::GUI::Plater->new($self->{tabpanel}), "Plater");
$self->{options_tabs} = {}; $self->{options_tabs} = {};
my $config; my $simple_config;
$config = Slic3r::Config->load("$Slic3r::GUI::datadir/simple.ini") if ($self->{mode} eq 'simple') {
$simple_config = Slic3r::Config->load("$Slic3r::GUI::datadir/simple.ini")
if -e "$Slic3r::GUI::datadir/simple.ini"; if -e "$Slic3r::GUI::datadir/simple.ini";
}
my $class_prefix = $self->{mode} eq 'simple' ? "Slic3r::GUI::SimpleTab::" : "Slic3r::GUI::Tab::";
my $init = 0;
for my $tab_name (qw(print filament printer)) { for my $tab_name (qw(print filament printer)) {
$self->{options_tabs}{$tab_name} = ("Slic3r::GUI::Tab::" . ucfirst $tab_name)->new( my $tab = $self->{options_tabs}{$tab_name} = ($class_prefix . ucfirst $tab_name)->new(
$self->{tabpanel}, $self->{tabpanel},
mode => $self->{mode},
plater => $self->{plater}, plater => $self->{plater},
config => $config,
on_value_change => sub { on_value_change => sub {
$self->{plater}->on_config_change(@_); # propagate config change events to the plater $self->{plater}->on_config_change(@_); # propagate config change events to the plater
if ($self->{mode} eq 'simple') { if ($self->{mode} eq 'simple' && $init) { # don't save while loading for the first time
# save config # save config
$self->config->save("$Slic3r::GUI::datadir/simple.ini"); $self->config->save("$Slic3r::GUI::datadir/simple.ini");
} }
}, },
); );
$self->{tabpanel}->AddPage($self->{options_tabs}{$tab_name}, $self->{options_tabs}{$tab_name}->title); $self->{tabpanel}->AddPage($tab, $tab->title);
$tab->load_config($simple_config);
} }
$init = 1;
my $sizer = Wx::BoxSizer->new(wxVERTICAL); my $sizer = Wx::BoxSizer->new(wxVERTICAL);
$sizer->Add($self->{tabpanel}, 1, wxEXPAND); $sizer->Add($self->{tabpanel}, 1, wxEXPAND);
@ -217,7 +221,7 @@ sub load_config_file {
$Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file); $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file);
Slic3r::GUI->save_settings; Slic3r::GUI->save_settings;
$last_config = $file; $last_config = $file;
$_->load_external_config($file) for values %{$self->{options_tabs}}; $_->load_config_file($file) for values %{$self->{options_tabs}};
} }
sub load_config { sub load_config {

View File

@ -14,14 +14,13 @@ sub new {
my ($parent, %params) = @_; my ($parent, %params) = @_;
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL);
$self->{options} = []; # array of option names handled by this tab $self->{options} = []; # array of option names handled by this tab
$self->{$_} = $params{$_} for qw(mode plater on_value_change); $self->{$_} = $params{$_} for qw(plater on_value_change);
# horizontal sizer # horizontal sizer
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
$self->{sizer}->SetSizeHints($self); $self->{sizer}->SetSizeHints($self);
$self->SetSizer($self->{sizer}); $self->SetSizer($self->{sizer});
if ($self->{mode} eq 'expert') {
# left vertical sizer # left vertical sizer
my $left_sizer = Wx::BoxSizer->new(wxVERTICAL); my $left_sizer = Wx::BoxSizer->new(wxVERTICAL);
$self->{sizer}->Add($left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3); $self->{sizer}->Add($left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3);
@ -127,9 +126,7 @@ sub new {
$self->on_select_preset; $self->on_select_preset;
$self->sync_presets; $self->sync_presets;
}); });
}
if ($self->{mode} eq 'expert') {
$self->{config} = Slic3r::Config->new; $self->{config} = Slic3r::Config->new;
$self->build; $self->build;
if ($self->hidden_options) { if ($self->hidden_options) {
@ -137,10 +134,6 @@ sub new {
push @{$self->{options}}, $self->hidden_options; push @{$self->{options}}, $self->hidden_options;
} }
$self->load_presets; $self->load_presets;
} else {
$self->{config} = $params{config} || Slic3r::Config->new;
$self->build_simple;
}
return $self; return $self;
} }
@ -178,7 +171,6 @@ sub select_preset {
sub on_select_preset { sub on_select_preset {
my $self = shift; my $self = shift;
return if $self->{mode} ne 'expert';
if (defined $self->{dirty}) { if (defined $self->{dirty}) {
my $name = $self->{dirty} == 0 ? 'Default preset' : "Preset \"$self->{presets}[$self->{dirty}]{name}\""; my $name = $self->{dirty} == 0 ? 'Default preset' : "Preset \"$self->{presets}[$self->{dirty}]{name}\"";
@ -224,7 +216,7 @@ sub get_preset_config {
return; return;
} }
# apply preset values on top of defaults # apply preset values on top of defaults
my $external_config = Slic3r::Config->load($preset->{file}); my $external_config = Slic3r::Config->load($preset->{file});
my $config = Slic3r::Config->new; my $config = Slic3r::Config->new;
$config->set($_, $external_config->get($_)) $config->set($_, $external_config->get($_))
@ -238,7 +230,7 @@ sub add_options_page {
my $self = shift; my $self = shift;
my ($title, $icon, %params) = @_; my ($title, $icon, %params) = @_;
if ($icon && $self->{icons}) { if ($icon) {
my $bitmap = Wx::Bitmap->new("$Slic3r::var/$icon", wxBITMAP_TYPE_PNG); my $bitmap = Wx::Bitmap->new("$Slic3r::var/$icon", wxBITMAP_TYPE_PNG);
$self->{icons}->Add($bitmap); $self->{icons}->Add($bitmap);
$self->{iconcount}++; $self->{iconcount}++;
@ -250,7 +242,7 @@ sub add_options_page {
my %defaults_to_set = map { $_ => 1 } @options; my %defaults_to_set = map { $_ => 1 } @options;
# apply default values for the options we don't have already # apply default values for the options we don't have already
delete $defaults_to_set{$_} for @{$self->{options}}, keys %{$self->{config}}; delete $defaults_to_set{$_} for @{$self->{options}};
$self->{config}->apply(Slic3r::Config->new_from_defaults(keys %defaults_to_set)) if %defaults_to_set; $self->{config}->apply(Slic3r::Config->new_from_defaults(keys %defaults_to_set)) if %defaults_to_set;
# append such options to our list # append such options to our list
@ -262,7 +254,7 @@ sub add_options_page {
$self->set_dirty(1); $self->set_dirty(1);
$self->sync_presets; $self->sync_presets;
}); });
$page->Hide if $self->{mode} eq 'expert'; $page->Hide;
$self->{sizer}->Add($page, 1, wxEXPAND | wxLEFT, 5); $self->{sizer}->Add($page, 1, wxEXPAND | wxLEFT, 5);
push @{$self->{pages}}, $page; push @{$self->{pages}}, $page;
$self->update_tree; $self->update_tree;
@ -289,7 +281,6 @@ sub reload_values {
sub update_tree { sub update_tree {
my $self = shift; my $self = shift;
my ($select) = @_; my ($select) = @_;
return if !$self->{treectrl};
$select //= 0; #/ $select //= 0; #/
@ -304,7 +295,6 @@ sub update_tree {
sub set_dirty { sub set_dirty {
my $self = shift; my $self = shift;
my ($dirty) = @_; my ($dirty) = @_;
return if $self->{mode} ne 'expert';
my $selection = $self->{presets_choice}->GetSelection; my $selection = $self->{presets_choice}->GetSelection;
my $i = $self->{dirty} // $selection; #/ my $i = $self->{dirty} // $selection; #/
@ -360,11 +350,10 @@ sub load_presets {
$self->sync_presets; $self->sync_presets;
} }
sub load_external_config { sub load_config_file {
my $self = shift; my $self = shift;
my ($file) = @_; my ($file) = @_;
if ($self->{mode} eq 'expert') {
# look for the loaded config among the existing menu items # look for the loaded config among the existing menu items
my $i = first { $self->{presets}[$_]{file} eq $file && $self->{presets}[$_]{external} } 1..$#{$self->{presets}}; my $i = first { $self->{presets}[$_]{file} eq $file && $self->{presets}[$_]{external} } 1..$#{$self->{presets}};
if (!$i) { if (!$i) {
@ -374,24 +363,16 @@ sub load_external_config {
name => $preset_name, name => $preset_name,
external => 1, external => 1,
}; };
$self->{presets_choice}->Append($preset_name) if $self->{presets_choice}; $self->{presets_choice}->Append($preset_name);
$i = $#{$self->{presets}}; $i = $#{$self->{presets}};
} }
$self->{presets_choice}->SetSelection($i) if $self->{presets_choice}; $self->{presets_choice}->SetSelection($i);
$self->on_select_preset; $self->on_select_preset;
$self->sync_presets; $self->sync_presets;
} else {
my $config = Slic3r::Config->load($file);
foreach my $opt_key (keys %{$self->{config}}) {
$self->{config}->set($opt_key, $config->get($opt_key));
}
$self->reload_values;
}
} }
sub sync_presets { sub sync_presets {
my $self = shift; my $self = shift;
return if $self->{mode} ne 'expert';
$self->{plater}->update_presets($self->name, [$self->{presets_choice}->GetStrings], $self->{presets_choice}->GetSelection); $self->{plater}->update_presets($self->name, [$self->{presets_choice}->GetStrings], $self->{presets_choice}->GetSelection);
} }
@ -401,54 +382,6 @@ use base 'Slic3r::GUI::Tab';
sub name { 'print' } sub name { 'print' }
sub title { 'Print Settings' } sub title { 'Print Settings' }
sub build_simple {
my $self = shift;
$self->add_options_page('', '', optgroups => [
{
title => 'General',
column => 0,
options => [qw(layer_height perimeters top_solid_layers bottom_solid_layers)],
lines => [
Slic3r::GUI::OptionsGroup->single_option_line('layer_height'),
Slic3r::GUI::OptionsGroup->single_option_line('perimeters'),
{
label => 'Solid layers',
options => [qw(top_solid_layers bottom_solid_layers)],
},
],
},
{
title => 'Infill',
column => 0,
options => [qw(fill_density fill_pattern)],
},
{
title => 'Support material',
options => [qw(support_material support_material_spacing raft_layers)],
},
{
title => 'Speed',
options => [qw(perimeter_speed infill_speed travel_speed)],
},
{
title => 'Brim',
options => [qw(brim_width)],
},
{
title => 'Sequential printing',
options => [qw(complete_objects extruder_clearance_radius extruder_clearance_height)],
lines => [
Slic3r::GUI::OptionsGroup->single_option_line('complete_objects'),
{
label => 'Extruder clearance (mm)',
options => [qw(extruder_clearance_radius extruder_clearance_height)],
},
],
},
]);
}
sub build { sub build {
my $self = shift; my $self = shift;
@ -598,35 +531,6 @@ use base 'Slic3r::GUI::Tab';
sub name { 'filament' } sub name { 'filament' }
sub title { 'Filament Settings' } sub title { 'Filament Settings' }
sub build_simple {
my $self = shift;
$self->add_options_page('', '', optgroups => [
{
title => 'Filament',
options => ['filament_diameter#0', 'extrusion_multiplier#0'],
},
{
title => 'Temperature (°C)',
options => ['temperature#0', 'first_layer_temperature#0', qw(bed_temperature first_layer_bed_temperature)],
lines => [
{
label => 'Extruder',
options => ['first_layer_temperature#0', 'temperature#0'],
},
{
label => 'Bed',
options => [qw(first_layer_bed_temperature bed_temperature)],
},
],
},
{
title => 'Cooling',
options => [qw(cooling)],
},
]);
}
sub build { sub build {
my $self = shift; my $self = shift;
@ -703,7 +607,7 @@ sub _update_description {
$msg .= "\nDuring the other layers, fan will be turned off." $msg .= "\nDuring the other layers, fan will be turned off."
} }
} }
$self->{description_line}->SetText($msg) if $self->{description_line}; $self->{description_line}->SetText($msg);
} }
sub on_value_change { sub on_value_change {
@ -720,39 +624,6 @@ use base 'Slic3r::GUI::Tab';
sub name { 'printer' } sub name { 'printer' }
sub title { 'Printer Settings' } sub title { 'Printer Settings' }
sub build_simple {
my $self = shift;
$self->add_options_page('', '', optgroups => [
{
title => 'Size and coordinates',
options => [qw(bed_size print_center z_offset)],
},
{
title => 'Firmware',
options => [qw(gcode_flavor)],
},
{
title => 'Extruder',
options => ['nozzle_diameter#0'],
},
{
title => 'Retraction',
options => ['retract_length#0', 'retract_lift#0'],
},
{
title => 'Start G-code',
no_labels => 1,
options => [qw(start_gcode)],
},
{
title => 'End G-code',
no_labels => 1,
options => [qw(end_gcode)],
},
]);
}
sub build { sub build {
my $self = shift; my $self = shift;
@ -822,12 +693,10 @@ sub config {
my $config = $self->SUPER::config(@_); my $config = $self->SUPER::config(@_);
if ($self->{mode} eq 'expert') {
# remove all unused values # remove all unused values
foreach my $opt_key ($self->_extruder_options) { foreach my $opt_key ($self->_extruder_options) {
splice @{ $config->{$opt_key} }, $self->{extruders_count}; splice @{ $config->{$opt_key} }, $self->{extruders_count};
} }
}
return $config; return $config;
} }
@ -906,9 +775,9 @@ sub on_preset_loaded {
} }
} }
sub load_external_config { sub load_config_file {
my $self = shift; my $self = shift;
$self->SUPER::load_external_config(@_); $self->SUPER::load_config_file(@_);
Slic3r::GUI::warning_catcher($self)->( Slic3r::GUI::warning_catcher($self)->(
"Your configuration was imported. However, Slic3r is currently only able to import settings " "Your configuration was imported. However, Slic3r is currently only able to import settings "
@ -918,11 +787,9 @@ sub load_external_config {
} }
package Slic3r::GUI::Tab::Page; package Slic3r::GUI::Tab::Page;
use Wx qw(:misc :panel :sizer :systemsettings); use Wx qw(:misc :panel :sizer);
use base 'Wx::ScrolledWindow'; use base 'Wx::ScrolledWindow';
use List::Util qw(max);
sub new { sub new {
my $class = shift; my $class = shift;
my ($parent, $title, $iconID, %params) = @_; my ($parent, $title, $iconID, %params) = @_;
@ -936,27 +803,12 @@ sub new {
$self->{vsizer} = Wx::BoxSizer->new(wxVERTICAL); $self->{vsizer} = Wx::BoxSizer->new(wxVERTICAL);
$self->SetSizer($self->{vsizer}); $self->SetSizer($self->{vsizer});
$self->{hsizer} = Wx::BoxSizer->new(wxHORIZONTAL);
$self->{vsizer}->Add($self->{hsizer}, 0, wxEXPAND | wxALL, 0);
if ($params{optgroups}) { if ($params{optgroups}) {
$_->{column} //= 0 for @{$params{optgroups}};
for my $col (0 .. max(map $_->{column}, @{$params{optgroups}})) {
my $vertical_sizer = Wx::BoxSizer->new(wxVERTICAL);
$self->{hsizer}->Add($vertical_sizer, 1, wxEXPAND | wxALL, 0);
$self->append_optgroup( $self->append_optgroup(
%$_, %$_,
sizer => $vertical_sizer,
config => $parent->{config}, config => $parent->{config},
on_change => $params{on_change}, on_change => $params{on_change},
) for grep $_->{column} == $col, @{$params{optgroups}}; ) for @{$params{optgroups}};
}
}
if ($parent->{mode} ne 'expert') {
my $label = Wx::StaticText->new($self, -1, "Want more options? Switch to the Expert Mode.", wxDefaultPosition, wxDefaultSize);
$label->SetFont(Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
$self->{vsizer}->Add($label, 0, wxEXPAND | wxALL, 10);
} }
return $self; return $self;
@ -973,7 +825,7 @@ sub append_optgroup {
label_width => 200, label_width => 200,
%params, %params,
); );
$params{sizer}->Add($optgroup->sizer, 0, wxEXPAND | wxALL, 5); $self->{vsizer}->Add($optgroup->sizer, 0, wxEXPAND | wxALL, 5);
push @{$self->{optgroups}}, $optgroup; push @{$self->{optgroups}}, $optgroup;
} }