OverrideSettingsPanel.pm 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. # Maintains, displays, adds and removes overrides of slicing parameters.
  2. package Slic3r::GUI::Plater::OverrideSettingsPanel;
  3. use strict;
  4. use warnings;
  5. use utf8;
  6. use List::Util qw(first);
  7. use Wx qw(:misc :sizer :button wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG
  8. wxTheApp);
  9. use Wx::Event qw(EVT_BUTTON EVT_LEFT_DOWN EVT_MENU);
  10. use base 'Wx::ScrolledWindow';
  11. use constant ICON_MATERIAL => 0;
  12. use constant ICON_SOLIDMESH => 1;
  13. use constant ICON_MODIFIERMESH => 2;
  14. my %icons = (
  15. 'Advanced' => 'wand.png',
  16. 'Extruders' => 'funnel.png',
  17. 'Extrusion Width' => 'funnel.png',
  18. 'Infill' => 'infill.png',
  19. 'Layers and Perimeters' => 'layers.png',
  20. 'Skirt and brim' => 'box.png',
  21. 'Speed' => 'time.png',
  22. 'Speed > Acceleration' => 'time.png',
  23. 'Support material' => 'building.png',
  24. );
  25. sub new {
  26. my $class = shift;
  27. my ($parent, %params) = @_;
  28. my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, $params{size} // wxDefaultSize, wxTAB_TRAVERSAL);
  29. $self->{default_config} = Slic3r::Config->new;
  30. $self->{config} = Slic3r::Config->new;
  31. $self->{on_change} = $params{on_change};
  32. $self->{can_add} = 1;
  33. $self->{can_delete} = 1;
  34. $self->{fixed_options} = {};
  35. $self->{sizer} = Wx::BoxSizer->new(wxVERTICAL);
  36. $self->{options_sizer} = Wx::BoxSizer->new(wxVERTICAL);
  37. $self->{sizer}->Add($self->{options_sizer}, 0, wxEXPAND | wxALL, 0);
  38. # option selector
  39. {
  40. # create the button
  41. my $btn = $self->{btn_add} = Wx::BitmapButton->new($self, -1, Wx::Bitmap->new($Slic3r::var->("add.png"), wxBITMAP_TYPE_PNG),
  42. wxDefaultPosition, wxDefaultSize, Wx::wxBORDER_NONE);
  43. $btn->SetToolTipString("Override one more option")
  44. if $btn->can('SetToolTipString');
  45. EVT_LEFT_DOWN($btn, sub {
  46. my $menu = Wx::Menu->new;
  47. my $last_cat = '';
  48. # create category submenus
  49. my %categories = (); # category => submenu
  50. foreach my $opt_key (@{$self->{options}}) {
  51. if (my $cat = $Slic3r::Config::Options->{$opt_key}{category}) {
  52. $categories{$cat} //= Wx::Menu->new;
  53. }
  54. }
  55. # append submenus to main menu
  56. foreach my $cat (sort keys %categories) {
  57. wxTheApp->append_submenu($menu, $cat, "", $categories{$cat}, undef, $icons{$cat});
  58. }
  59. # append options to submenus
  60. foreach my $opt_key (@{$self->{options}}) {
  61. my $cat = $Slic3r::Config::Options->{$opt_key}{category} or next;
  62. my $cb = sub {
  63. $self->{config}->set($opt_key, $self->{default_config}->get($opt_key));
  64. $self->update_optgroup;
  65. $self->{on_change}->($opt_key) if $self->{on_change};
  66. };
  67. wxTheApp->append_menu_item($categories{$cat}, $self->{option_labels}{$opt_key},
  68. $Slic3r::Config::Options->{$opt_key}{tooltip}, $cb);
  69. }
  70. $self->PopupMenu($menu, $btn->GetPosition);
  71. $menu->Destroy;
  72. });
  73. my $h_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
  74. $h_sizer->Add($btn, 0, wxALL, 0);
  75. $self->{sizer}->Add($h_sizer, 0, wxEXPAND | wxBOTTOM, 10);
  76. }
  77. $self->SetSizer($self->{sizer});
  78. # http://docs.wxwidgets.org/3.0/classwx_scrolled.html#details
  79. $self->SetScrollRate(0, $Slic3r::GUI::scroll_step);
  80. $self->set_opt_keys($params{opt_keys}) if $params{opt_keys};
  81. $self->update_optgroup;
  82. return $self;
  83. }
  84. # Sets the config used to get the default values for user-added options.
  85. sub set_default_config {
  86. my ($self, $config) = @_;
  87. $self->{default_config} = $config;
  88. }
  89. # Sets the target config, whose options will be displayed in the OptionsGroup.
  90. sub set_config {
  91. my ($self, $config) = @_;
  92. $self->{config} = $config;
  93. $self->update_optgroup;
  94. }
  95. # Sets the options listed in the Add button.
  96. sub set_opt_keys {
  97. my ($self, $opt_keys) = @_;
  98. # sort options by label
  99. $self->{option_labels} = {};
  100. foreach my $opt_key (@$opt_keys) {
  101. my $def = $Slic3r::Config::Options->{$opt_key} or next;
  102. $self->{option_labels}{$opt_key} = $def->{full_label} // $def->{label};
  103. };
  104. $self->{options} = [ sort { $self->{option_labels}{$a} cmp $self->{option_labels}{$b} } keys %{$self->{option_labels}} ];
  105. }
  106. # Sets the options that user can't remove.
  107. sub set_fixed_options {
  108. my ($self, $opt_keys) = @_;
  109. $self->{fixed_options} = { map {$_ => 1} @$opt_keys };
  110. $self->update_optgroup;
  111. }
  112. sub fixed_options {
  113. my ($self) = @_;
  114. return keys %{$self->{fixed_options}};
  115. }
  116. sub update_optgroup {
  117. my $self = shift;
  118. $self->{options_sizer}->Clear(1);
  119. return if !defined $self->{config};
  120. $self->{btn_add}->Show($self->{can_add});
  121. my %categories = ();
  122. foreach my $opt_key (@{$self->{config}->get_keys}) {
  123. my $category = $Slic3r::Config::Options->{$opt_key}{category};
  124. $categories{$category} ||= [];
  125. push @{$categories{$category}}, $opt_key;
  126. }
  127. foreach my $category (sort keys %categories) {
  128. my $optgroup;
  129. $optgroup = Slic3r::GUI::ConfigOptionsGroup->new(
  130. parent => $self,
  131. title => $category,
  132. config => $self->{config},
  133. full_labels => 1,
  134. label_font => $Slic3r::GUI::small_font,
  135. sidetext_font => $Slic3r::GUI::small_font,
  136. label_width => 120,
  137. on_change => sub {
  138. my ($opt_key) = @_;
  139. $self->{on_change}->($opt_key) if $self->{on_change};
  140. },
  141. extra_column => sub {
  142. my ($line) = @_;
  143. my $opt_id = $line->get_options->[0]->opt_id; # we assume that we have one option per line
  144. my ($opt_key, $opt_index) = @{ $optgroup->_opt_map->{$opt_id} };
  145. # disallow deleting fixed options
  146. return undef if $self->{fixed_options}{$opt_key} || !$self->{can_delete};
  147. my $btn = Wx::BitmapButton->new($self, -1, Wx::Bitmap->new($Slic3r::var->("delete.png"), wxBITMAP_TYPE_PNG),
  148. wxDefaultPosition, wxDefaultSize, Wx::wxBORDER_NONE);
  149. EVT_BUTTON($self, $btn, sub {
  150. $self->{config}->erase($opt_key);
  151. $self->{on_change}->($opt_key) if $self->{on_change};
  152. wxTheApp->CallAfter(sub { $self->update_optgroup });
  153. });
  154. return $btn;
  155. },
  156. );
  157. foreach my $opt_key (sort @{$categories{$category}}) {
  158. # For array options we override the first value.
  159. my $opt_index = (ref($self->{config}->get($opt_key)) eq 'ARRAY') ? 0 : -1;
  160. $optgroup->append_single_option_line($opt_key, $opt_index);
  161. }
  162. $self->{options_sizer}->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM, 0);
  163. }
  164. $self->GetParent->Layout; # we need this for showing scrollbars
  165. }
  166. # work around a wxMAC bug causing controls not being disabled when calling Disable() on a Window
  167. sub enable {
  168. my ($self) = @_;
  169. $self->{btn_add}->Enable;
  170. $self->Enable;
  171. }
  172. sub disable {
  173. my ($self) = @_;
  174. $self->{btn_add}->Disable;
  175. $self->Disable;
  176. }
  177. # Shows or hides the Add/Delete buttons.
  178. sub set_editable {
  179. my ($self, $editable) = @_;
  180. $self->{can_add} = $self->{can_delete} = $editable;
  181. }
  182. # Shows or hides the Add button.
  183. sub can_add {
  184. my ($self, $can) = @_;
  185. $self->{can_add} = $can if defined $can;
  186. return $can;
  187. }
  188. # Shows or hides the Delete button.
  189. sub can_delete {
  190. my ($self, $can) = @_;
  191. $self->{can_delete} = $can if defined $can;
  192. return $can;
  193. }
  194. 1;