Merge with bibnikv.

Added some functions to TabIface.
Added BedShapeDialog & Bed2D classes.
Added new_scale to Polygon.
In class Field: Point renamed to PointCtrl and added set_value for PointCtrl, extended get_value for Choice.
This commit is contained in:
YuSanka 2018-01-25 13:46:04 +01:00
parent a1705c093b
commit f0b035059a
18 changed files with 774 additions and 95 deletions

View File

@ -161,24 +161,60 @@ sub _init_tabpanel {
# The following event is emited by the C++ Tab implementation on config value change.
EVT_COMMAND($self, -1, $VALUE_CHANGE_EVENT, sub {
my ($self, $event) = @_;
print "VALUE_CHANGE_EVENT: ", $event->GetString, "\n";
my $str = $event->GetString;
my ($opt_key, $title) = ($str =~ /(.*) (.*)/);
#print "VALUE_CHANGE_EVENT: ", $opt_key, "\n";
my $tab = Slic3r::GUI::get_preset_tab($title);
my $config = $tab->get_config;
if ($self->{plater}) {
$self->{plater}->on_config_change($config); # propagate config change events to the plater
if ($opt_key eq 'extruders_count'){
my $value = $event->GetInt();
$self->{plater}->on_extruders_change($value);
}
}
# don't save while loading for the first time
$self->config->save($Slic3r::GUI::autosave) if $Slic3r::GUI::autosave && $self->{loaded};
});
# The following event is emited by the C++ Tab implementation on preset selection,
# or when the preset's "modified" status changes.
EVT_COMMAND($self, -1, $PRESETS_CHANGED_EVENT, sub {
my ($self, $event) = @_;
print "PRESETS_CHANGED_EVENT: ", $event->GetString, "\n";
my $title = $event->GetString;
my $tab_name = lc($title);
#print "PRESETS_CHANGED_EVENT: ", $tab_name , "\n";
my $tab = Slic3r::GUI::get_preset_tab($title);
if ($self->{plater}) {
# Update preset combo boxes (Print settings, Filament, Printer) from their respective tabs.
my $presets = $tab->get_presets;
my $reload_dependent_tabs = $tab->get_dependent_tabs;
$self->{plater}->update_presets($tab_name, $reload_dependent_tabs, $presets);
if ($tab_name eq 'printer') {
# Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
for my $tab_name_other (qw(print filament)) {
# If the printer tells us that the print or filament preset has been switched or invalidated,
# refresh the print or filament tab page. Otherwise just refresh the combo box.
my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs})))
? 'load_current_preset' : 'update_tab_ui';
$self->{options_tabs2}{$tab_name_other}->$update_action;
}
# Update the controller printers.
$self->{controller}->update_presets($presets) if $self->{controller};
}
$self->{plater}->on_config_change($tab->get_config);
}
});
Slic3r::GUI::create_preset_tabs(wxTheApp->{preset_bundle}, wxTheApp->{app_config}, $VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT);
$self->{options_tabs2}{print} = Slic3r::GUI::get_preset_tab("Print");
$self->{options_tabs2}{filament} = Slic3r::GUI::get_preset_tab("Filament");
$self->{options_tabs2}{printer} = Slic3r::GUI::get_preset_tab("Printer");
# $self->{options_tabs2}{print}->rebuild_page_tree();
if ($self->{plater}) {
$self->{plater}->on_select_preset(sub {
my ($group, $name) = @_;
$self->{options_tabs}{$group}->select_preset($name);
$self->{options_tabs2}{$group}->select_preset($name);#!
});
# load initial config
my $full_config = wxTheApp->{preset_bundle}->full_config;
@ -573,6 +609,7 @@ sub load_config_file {
# Dont proceed further if the config file cannot be loaded.
return if Slic3r::GUI::catch_error($self);
$_->load_current_preset for (values %{$self->{options_tabs}});
$_->load_current_preset for (values %{$self->{options_tabs2}});#!
wxTheApp->{app_config}->update_config_dir(dirname($file));
$last_config = $file;
}
@ -624,6 +661,11 @@ sub load_configbundle {
foreach my $tab (values %{$self->{options_tabs}}) {
$tab->load_current_preset;
}
#! Load the currently selected preset into the GUI, update the preset selection box.
foreach my $tab (values %{$self->{options_tabs2}}) {
$tab->load_current_preset;
}
my $message = sprintf "%d presets successfully imported.", $presets_imported;
Slic3r::GUI::show_info($self, $message);
@ -632,8 +674,9 @@ sub load_configbundle {
# Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
# Also update the platter with the new presets.
sub load_config {
my ($self, $config) = @_;
my ($self, $config) = @_;
$_->load_config($config) foreach values %{$self->{options_tabs}};
$_->load_config($config) foreach values %{$self->{options_tabs2}};#!
$self->{plater}->on_config_change($config) if $self->{plater};
}
@ -672,6 +715,11 @@ sub config_wizard {
foreach my $tab (values %{$self->{options_tabs}}) {
$tab->load_current_preset;
}
#! Load the currently selected preset into the GUI, update the preset selection box.
foreach my $tab (values %{$self->{options_tabs2}}) {
$tab->load_current_preset;
}
}
}
@ -684,6 +732,9 @@ sub check_unsaved_changes {
foreach my $tab (values %{$self->{options_tabs}}) {
push @dirty, $tab->title if $tab->{presets}->current_is_dirty;
}
foreach my $tab (values %{$self->{options_tabs2}}) { #!
push @dirty, $tab->title if $tab->current_preset_is_dirty;
}
if (@dirty) {
my $titles = join ', ', @dirty;
@ -734,6 +785,9 @@ sub update_ui_from_settings {
for my $tab_name (qw(print filament printer)) {
$self->{options_tabs}{$tab_name}->update_ui_from_settings;
}
for my $tab_name (qw(print filament printer)) {
$self->{options_tabs2}{$tab_name}->update_ui_from_settings;#!
}
}
1;

View File

@ -113,6 +113,7 @@ sub new {
$cfg->set('wipe_tower_x', $new_pos_3f->x);
$cfg->set('wipe_tower_y', $new_pos_3f->y);
$self->GetFrame->{options_tabs}{print}->load_config($cfg);
$self->GetFrame->{options_tabs2}{print}->load_config($cfg);#!
});
$self->{canvas3D}->set_on_model_update(sub {
if (wxTheApp->{app_config}->get("background_processing")) {
@ -1747,6 +1748,7 @@ sub filament_color_box_lmouse_down
$colors->[$extruder_idx] = $dialog->GetColourData->GetColour->GetAsString(wxC2S_HTML_SYNTAX);
$cfg->set('extruder_colour', $colors);
$self->GetFrame->{options_tabs}{printer}->load_config($cfg);
$self->GetFrame->{options_tabs2}{printer}->load_config($cfg);#!
wxTheApp->{preset_bundle}->update_platter_filament_ui($extruder_idx, $combobox);
}
$dialog->Destroy();

View File

@ -185,6 +185,10 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/GUI/Field.hpp
${LIBDIR}/slic3r/GUI/OptionsGroup.cpp
${LIBDIR}/slic3r/GUI/OptionsGroup.hpp
${LIBDIR}/slic3r/GUI/BedShapeDialog.cpp
${LIBDIR}/slic3r/GUI/BedShapeDialog.hpp
${LIBDIR}/slic3r/GUI/2DBed.cpp
${LIBDIR}/slic3r/GUI/2DBed.hpp
)
add_library(admesh STATIC

View File

@ -24,6 +24,12 @@ public:
explicit Polygon(const Points &points): MultiPoint(points) {}
Polygon(const Polygon &other) : MultiPoint(other.points) {}
Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {}
static Polygon new_scale(std::vector<Pointf> points) {
Points int_points;
for (auto pt : points)
int_points.push_back(Point::new_scale(pt.x, pt.y));
return Polygon(int_points);
}
Polygon& operator=(const Polygon &other) { points = other.points; return *this; }
Polygon& operator=(Polygon &&other) { points = std::move(other.points); return *this; }

167
xs/src/slic3r/GUI/2DBed.cpp Normal file
View File

@ -0,0 +1,167 @@
#include "2DBed.hpp";
#include <wx/dcbuffer.h>
#include "BoundingBox.hpp"
#include "Geometry.hpp"
namespace Slic3r {
namespace GUI {
void Bed_2D::repaint()
{
// auto dc = new wxAutoBufferedPaintDC(this);
wxClientDC dc(this);
auto cw = GetSize().GetWidth();
auto ch = GetSize().GetHeight();
// when canvas is not rendered yet, size is 0, 0
if (cw == 0) return ;
if (m_user_drawn_background) {
// On all systems the AutoBufferedPaintDC() achieves double buffering.
// On MacOS the background is erased, on Windows the background is not erased
// and on Linux / GTK the background is erased to gray color.
// Fill DC with the background on Windows & Linux / GTK.
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); //GetSystemColour
dc.SetPen(/**new wxPen(color, 1, wxPENSTYLE_SOLID)*/*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID));
dc.SetBrush(*new wxBrush(color, wxBRUSHSTYLE_SOLID));
auto rect = GetUpdateRegion().GetBox();
dc.DrawRectangle(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
}
// turn cw and ch from sizes to max coordinates
/* cw--;
ch--;
auto cbb = BoundingBoxf(Pointf(0, 0),Pointf(cw, ch));
// leave space for origin point
cbb.min.translate(4, 0); // cbb.set_x_min(cbb.min.x + 4);
cbb.max.translate(-4, -4); // cbb.set_x_max(cbb.max.x - 4);cbb.set_y_max(cbb.max.y - 4);
// leave space for origin label
cbb.max.translate(0, -13); // $cbb->set_y_max($cbb->y_max - 13);
// read new size
cw = cbb.size().x;
ch = cbb.size().y;
auto ccenter = cbb.center();
// get bounding box of bed shape in G - code coordinates
auto bed_shape = m_bed_shape;
auto bed_polygon = Polygon::new_scale(m_bed_shape);
auto bb = BoundingBoxf(m_bed_shape);
bb.merge(Pointf(0, 0)); // origin needs to be in the visible area
auto bw = bb.size().x;
auto bh = bb.size().y;
auto bcenter = bb.center();
// calculate the scaling factor for fitting bed shape in canvas area
auto sfactor = std::min(cw/bw, ch/bh);
auto shift = Pointf(
ccenter.x - bcenter.x * sfactor,
ccenter.y - bcenter.y * sfactor
);
m_scale_factor = sfactor;
m_shift = Pointf(shift.x + cbb.min.x,
shift.y - (cbb.max.y - GetSize().GetHeight()));
// draw bed fill
// {
dc->SetPen(*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID));
dc->SetBrush(*new wxBrush(*new wxColour(255, 255, 255), wxSOLID));
wxPointList pt_list;
for (auto pt: m_bed_shape)
{
Point pt_pix = to_pixels(pt);
pt_list.push_back(new wxPoint(pt_pix.x, pt_pix.y));
}
dc->DrawPolygon(&pt_list, 0, 0);
// }
*/
// draw grid
// {
// auto step = 10; // 1cm grid
// Polylines polylines;
// for (auto x = bb.min.x - (bb.min.x % step) + step; x < bb.max.x; x += step) {
// // push @polylines, Slic3r::Polyline->new_scale([$x, $bb->y_min], [$x, $bb->y_max]);
// }
// for (auto y = bb.min.y - (bb.min.y % step) + step; y < bb.max.y; y += step) {
// // push @polylines, Slic3r::Polyline->new_scale([$bb->x_min, $y], [$bb->x_max, $y]);
// }
// // @polylines = @{intersection_pl(\@polylines, [$bed_polygon])};
//
// dc->SetPen(*new wxPen(*new wxColour(230, 230, 230), 1, wxSOLID));
// // for (auto pl: polylines)
// // dc->DrawLine(map @{$self->to_pixels([map unscale($_), @$_])}, @$_[0, -1]);
// }
//
// // draw bed contour
// {
// dc->SetPen(*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID));
// dc->SetBrush(*new wxBrush(*new wxColour(255, 255, 255), wxTRANSPARENT));
// // dc->DrawPolygon([map $self->to_pixels($_), @$bed_shape], 0, 0);
// }
// auto origin_px = to_pixels(Pointf(0, 0));
//
// // draw axes
// {
// auto axes_len = 50;
// auto arrow_len = 6;
// auto arrow_angle = Geometry::deg2rad(45);
// dc->SetPen(*new wxPen(*new wxColour(255, 0, 0), 2, wxSOLID)); // red
// auto x_end = Pointf(origin_px.x + axes_len, origin_px.y);
// dc->DrawLine(wxPoint(origin_px), wxPoint(x_end));
// foreach my $angle(-$arrow_angle, +$arrow_angle) {
// auto end = x_end.clone;
// end->translate(-arrow_len, 0);
// end->rotate(angle, x_end);
// dc->DrawLine(x_end, end);
// }
//
// dc->SetPen(*new wxPen(*new wxColour(0, 255, 0), 2, wxSOLID)); // green
// auto y_end = Pointf(origin_px.x, origin_px.y - axes_len);
// dc->DrawLine(origin_px, y_end);
// foreach my $angle(-$arrow_angle, +$arrow_angle) {
// auto end = y_end->clone;
// end->translate(0, +arrow_len);
// end->rotate(angle, y_end);
// dc->DrawLine(y_end, end);
// }
// }
//
// // draw origin
// {
// dc->SetPen(*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID));
// dc->SetBrush(*new wxBrush(*new wxColour(0, 0, 0), wxSOLID));
// dc->DrawCircle(origin_px.x, origin_px.y, 3);
//
// dc->SetTextForeground(*new wxColour(0, 0, 0));
// dc->SetFont(*new wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
// dc->DrawText("(0,0)", origin_px.x + 1, origin_px.y + 2);
// }
//
// // draw current position
// if (m_pos) {
// auto pos_px = to_pixels(m_pos);
// dc->SetPen(*new wxPen(*new wxColour(200, 0, 0), 2, wxSOLID));
// dc->SetBrush(*new wxBrush(*new wxColour(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);
// }
m_painted = true;
}
// convert G - code coordinates into pixels
Point Bed_2D::to_pixels(Pointf point){
auto p = Pointf(point);
p.scale(m_scale_factor);
p.translate(m_shift);
return Point(p.x, GetSize().GetHeight() - p.y);
}
} // GUI
} // Slic3r

View File

@ -0,0 +1,40 @@
#include <wx/wx.h>
#include "Config.hpp"
namespace Slic3r {
namespace GUI {
class Bed_2D : public wxPanel
{
bool m_user_drawn_background = false;
bool m_painted = false;
double m_scale_factor;
Pointf m_shift;
Point m_pos;
Point to_pixels(Pointf point);
void repaint();
public:
Bed_2D(wxWindow* parent)
{
Create(parent, wxID_ANY, wxDefaultPosition, wxSize(250, -1), wxTAB_TRAVERSAL);
// m_user_drawn_background = $^O ne 'darwin';
m_user_drawn_background = true;
Bind(wxEVT_PAINT, ([this](wxPaintEvent e)
{
repaint();
}));
// EVT_ERASE_BACKGROUND($self, sub{}) if $self->{user_drawn_background};
// Bind(wxEVT_MOUSE_EVENTS, ([this](wxCommandEvent){/*mouse_event()*/; }));
Bind(wxEVT_SIZE, ([this](wxSizeEvent){Refresh(); }));
}
~Bed_2D(){}
std::vector<Pointf> m_bed_shape;
};
} // GUI
} // Slic3r

View File

@ -0,0 +1,314 @@
#include "BedShapeDialog.hpp"
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/wx.h>
#include "Polygon.hpp"
#include "BoundingBox.hpp"
#include <wx/numformatter.h>
namespace Slic3r {
namespace GUI {
void BedShapeDialog::build_dialog(ConfigOptionPoints* default_pt)
{
m_panel = new BedShapePanel(this);
m_panel->build_panel(default_pt);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(m_panel, 1, wxEXPAND);
main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, /*wxEXPAND*/wxALIGN_CENTER_HORIZONTAL | wxBOTTOM/*ALL*/, 10);
SetSizer(main_sizer);
SetMinSize(GetSize());
main_sizer->SetSizeHints(this);
// needed to actually free memory
this->Bind(wxEVT_CLOSE_WINDOW, ([this](wxCloseEvent e){
EndModal(wxID_OK);
Destroy();
}));
}
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
{
// on_change(nullptr);
auto box = new wxStaticBox(this, wxID_ANY, "Shape");
auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL);
// shape options
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxSize(300, -1), wxCHB_TOP);
sbsizer->Add(m_shape_options_book);
auto optgroup = init_shape_options_page("Rectangular");
ConfigOptionDef def;
def.type = coPoints;
def.default_value = new ConfigOptionPoints{ Pointf(200, 200) };
def.label = "Size";
def.tooltip = "Size in X and Y of the rectangular plate.";
Option option(def, "rect_size");
optgroup->append_single_option_line(option);
def.type = coPoints;
def.default_value = new ConfigOptionPoints{ Pointf(0, 0) };
def.label = "Origin";
def.tooltip = "Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.";
option = Option(def, "rect_origin");
optgroup->append_single_option_line(option);
optgroup = init_shape_options_page("Circular");
def.type = coFloat;
def.default_value = new ConfigOptionFloat(200);
def.sidetext = "mm";
def.label = "Diameter";
def.tooltip = "Diameter of the print bed. It is assumed that origin (0,0) is located in the center.";
option = Option(def, "diameter");
optgroup->append_single_option_line(option);
optgroup = init_shape_options_page("Custom");
Line line{ "", "" };
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
auto btn = new wxButton(parent, wxID_ANY, "Load shape from STL...", wxDefaultPosition, wxDefaultSize);
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
{
load_stl();
}));
return sizer;
};
optgroup->append_line(line);
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent e)
{
update_shape();
}));
// right pane with preview canvas
m_canvas = new Bed_2D(this);
m_canvas->m_bed_shape = default_pt->values;
// main sizer
auto top_sizer = new wxBoxSizer(wxHORIZONTAL);
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLeft | wxTOP | wxBOTTOM, 10);
if (m_canvas)
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ;
SetSizerAndFit(top_sizer);
set_shape(default_pt);
update_preview();
}
#define SHAPE_RECTANGULAR 0
#define SHAPE_CIRCULAR 1
#define SHAPE_CUSTOM 2
// Called from the constructor.
// Create a panel for a rectangular / circular / custom bed shape.
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(std::string title){
auto panel = new wxPanel(m_shape_options_book);
ConfigOptionsGroupShp optgroup;
optgroup = std::make_shared<ConfigOptionsGroup>(panel, "Settings");
optgroup->label_width = 100;
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
update_shape();
};
m_optgroups.push_back(optgroup);
panel->SetSizerAndFit(optgroup->sizer);
m_shape_options_book->AddPage(panel, title);
return optgroup;
}
// Called from the constructor.
// Set the initial bed shape from a list of points.
// Deduce the bed shape type(rect, circle, custom)
// This routine shall be smart enough if the user messes up
// with the list of points in the ini file directly.
void BedShapePanel::set_shape(ConfigOptionPoints* points)
{
auto polygon = Polygon::new_scale(points->values);
// is this a rectangle ?
if (points->size() == 4) {
auto lines = polygon.lines();
if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) {
// okay, it's a rectangle
// find origin
// the || 0 hack prevents "-0" which might confuse the user
int x_min, x_max, y_min, y_max;
x_max = x_min = points->values[0].x;
y_max = y_min = points->values[0].y;
for (auto pt : points->values){
if (x_min > pt.x) x_min = pt.x;
if (x_max < pt.x) x_max = pt.x;
if (y_min > pt.y) y_min = pt.y;
if (y_max < pt.y) y_max = pt.y;
}
if (x_min < 0) x_min = 0;
if (x_max < 0) x_max = 0;
if (y_min < 0) y_min = 0;
if (y_max < 0) y_max = 0;
// auto x_min = min(map $_->[X], @$points) || 0;
// auto x_max = max(map $_->[X], @$points) || 0;
// auto y_min = min(map $_->[Y], @$points) || 0;
// auto y_max = max(map $_->[Y], @$points) || 0;
// auto origin = [-x_min, -y_min];
auto origin = new ConfigOptionPoints{ Pointf(-x_min, -y_min) };
m_shape_options_book->SetSelection(SHAPE_RECTANGULAR);
auto optgroup = m_optgroups[SHAPE_RECTANGULAR];
optgroup->set_value("rect_size", new ConfigOptionPoints{ Pointf(x_max - x_min, y_max - y_min) });//[x_max - x_min, y_max - y_min]);
optgroup->set_value("rect_origin", origin);
update_shape();
return;
}
}
// is this a circle ?
{
// Analyze the array of points.Do they reside on a circle ?
// auto polygon;// = Slic3r::Polygon->new_scale(@$points);
auto center = polygon.bounding_box().center();// ->bounding_box->center;
// auto /*@*/vertex_distances;// = map $center->distance_to($_), @$polygon;
// auto avg_dist = sum(/*@*/vertex_distances) / /*@*/vertex_distances;
std::vector<double> vertex_distances;// = map $center->distance_to($_), @$polygon;
double avg_dist = 0;
for (auto pt: polygon.points)
{
double distance = center.distance_to(pt);
vertex_distances.push_back(distance);
avg_dist += distance;
}
bool defined_value = true;
for (auto el: vertex_distances)
{
if (abs(el - avg_dist) > 10 * SCALED_EPSILON/*scaled_epsilon*/)
defined_value = false;
break;
}
if (defined_value/*!defined first{ abs($_ - $avg_dist) > 10 * scaled_epsilon } @vertex_distances*/) {
// all vertices are equidistant to center
m_shape_options_book->SetSelection(SHAPE_CIRCULAR);
auto optgroup = m_optgroups[SHAPE_CIRCULAR];
boost::any ret = wxNumberFormatter::ToString(unscale(avg_dist * 2), 0);
optgroup->set_value("diameter", ret /*sprintf("%.0f", unscale(avg_dist * 2))*/);
update_shape();
return;
}
}
if (points->size() < 3) {
// Invalid polygon.Revert to default bed dimensions.
m_shape_options_book->SetSelection(SHAPE_RECTANGULAR);
auto optgroup = m_optgroups[SHAPE_RECTANGULAR];
optgroup->set_value("rect_size", new ConfigOptionPoints{ Pointf(200, 200) });
optgroup->set_value("rect_origin", new ConfigOptionPoints{ Pointf(0, 0) });
update_shape();
return;
}
// This is a custom bed shape, use the polygon provided.
m_shape_options_book->SetSelection(SHAPE_CUSTOM);
// Copy the polygon to the canvas, make a copy of the array.
m_canvas->m_bed_shape = points->values;
update_shape();
}
void BedShapePanel::update_preview()
{
if (m_canvas) m_canvas->Refresh();
Refresh();
}
// Update the bed shape from the dialog fields.
void BedShapePanel::update_shape()
{
auto page_idx = m_shape_options_book->GetSelection();
if (page_idx == SHAPE_RECTANGULAR) {
auto rect_size = m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_size");
auto rect_origin = m_optgroups[SHAPE_RECTANGULAR]->get_value("rect_origin");
/* auto x = rect_size->x;
auto y = rect_size->y;
// empty strings or '-' or other things
// if (!looks_like_number(x) || !looks_like_number(y)) return;
if ((!x || !y) || x == 0 || y == 0) return;
// my($x0, $y0) = (0, 0);
// my($x1, $y1) = ($x, $y);
// {
// my($dx, $dy) = @$rect_origin;
// return if !looks_like_number($dx) || !looks_like_number($dy); # empty strings or '-' or other things
// $x0 -= $dx;
// $x1 -= $dx;
// $y0 -= $dy;
// $y1 -= $dy;
// }
// m_canvas->bed_shape([
// [$x0, $y0],
// [$x1, $y0],
// [$x1, $y1],
// [$x0, $y1],
// ]);
}
else if(page_idx == SHAPE_CIRCULAR) {
// auto diameter = m_optgroups[SHAPE_CIRCULAR]->get_value("diameter");
// if (!diameter || diameter == 0) return ;
// r = diameter / 2;
// twopi = 2 * PI;
// edges = 60;
// polygon = Slic3r::Polygon->new_scale(
// map[$r * cos $_, $r * sin $_],
// map{ $twopi / $edges*$_ } 1..$edges
// );
// m_canvas->bed_shape([
// map[unscale($_->x), unscale($_->y)], @$polygon #))
// ]);
*/ }
// $self->{on_change}->();
update_preview();
}
// Loads an stl file, projects it to the XY plane and calculates a polygon.
void BedShapePanel::load_stl()
{
auto dialog = new wxFileDialog(this, "Choose a file to import bed shape from (STL/OBJ/AMF/PRUSA):", "", "",
wxFileSelectorDefaultWildcardStr/* &Slic3r::GUI::MODEL_WILDCARD*/, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dialog->ShowModal() != wxID_OK) {
dialog->Destroy();
return;
}
wxArrayString input_file;
dialog->GetPaths(input_file);
dialog->Destroy();
// auto model = Slic3r::Model->read_from_file(input_file);
// auto mesh = model->mesh;
// auto expolygons = mesh->horizontal_projection;
//
// if (expolygons.size() == 0) {
// show_error(this, "The selected file contains no geometry.");
// return;
// }
// if (expolygons.size() > 1) {
// show_error(this, "The selected file contains several disjoint areas. This is not supported.");
// return;
// }
//
// auto polygon = expolygons[0]->contour;
// m_canvas->bed_shape([map[unscale($_->x), unscale($_->y)], @$polygon]);
update_preview();
}
} // GUI
} // Slic3r

View File

@ -0,0 +1,50 @@
// The bed shape dialog.
// The dialog opens from Print Settins tab->Bed Shape : Set...
#include "OptionsGroup.hpp"
#include "2DBed.hpp"
#include <wx/dialog.h>
#include <wx/choicebk.h>
namespace Slic3r {
namespace GUI {
using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
class BedShapePanel : public wxPanel
{
wxChoicebook* m_shape_options_book;
Bed_2D* m_canvas;
std::vector <ConfigOptionsGroupShp> m_optgroups;
public:
BedShapePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY){}
~BedShapePanel(){}
void build_panel(ConfigOptionPoints* default_pt);
// Returns the resulting bed shape polygon. This value will be stored to the ini file.
int GetValue() { return 1/*m_canvas->bed_shape*/; }
ConfigOptionsGroupShp init_shape_options_page(std::string title);
void set_shape(ConfigOptionPoints* points);
void update_preview();
void update_shape();
void load_stl();
};
class BedShapeDialog : public wxDialog
{
BedShapePanel* m_panel;
public:
BedShapeDialog(wxWindow* parent) : wxDialog(parent, wxID_ANY, "Bed Shape",
wxDefaultPosition, wxSize(350, 700), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER){}
~BedShapeDialog(){}
void build_dialog(ConfigOptionPoints* default_pt);
int GetValue() { return m_panel->GetValue(); }
};
} // GUI
} // Slic3r

View File

@ -404,8 +404,19 @@ boost::any Choice::get_value()
else
{
int ret_enum = static_cast<wxComboBox*>(window)->GetSelection();
if (m_opt_id.compare("external_fill_pattern") == 0 ||
m_opt_id.compare("fill_pattern") == 0)
if (m_opt_id.compare("external_fill_pattern") == 0)
{
if (!m_opt.enum_values.empty()){
std::string key = m_opt.enum_values[ret_enum];
t_config_enum_values map_names = ConfigOptionEnum<InfillPattern>::get_enum_values();
int value = map_names.at(key);
ret_val = static_cast<InfillPattern>(value);
}
else
ret_val = static_cast<InfillPattern>(0);
}
if (m_opt_id.compare("fill_pattern") == 0)
ret_val = static_cast<InfillPattern>(ret_enum);
else if (m_opt_id.compare("gcode_flavor") == 0)
ret_val = static_cast<GCodeFlavor>(ret_enum);
@ -436,7 +447,7 @@ void ColourPicker::BUILD()
}
void Point::BUILD()
void PointCtrl::BUILD()
{
auto size = wxSize(wxDefaultSize);
if (m_opt.height >= 0) size.SetHeight(m_opt.height);
@ -456,9 +467,9 @@ void Point::BUILD()
x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size);
y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size);
temp->Add(new wxStaticText(m_parent, wxID_ANY, "x:")/*, 0, wxALIGN_CENTER_VERTICAL, 0*/);
temp->Add(new wxStaticText(m_parent, wxID_ANY, "x : ")/*, 0, wxALIGN_CENTER_VERTICAL, 0*/);
temp->Add(x_textctrl);
temp->Add(new wxStaticText(m_parent, wxID_ANY, " y:")/*, 0, wxALIGN_CENTER_VERTICAL, 0*/);
temp->Add(new wxStaticText(m_parent, wxID_ANY, " y : ")/*, 0, wxALIGN_CENTER_VERTICAL, 0*/);
temp->Add(y_textctrl);
x_textctrl->Bind(wxEVT_TEXT, ([=](wxCommandEvent e) { on_change_field(e/*$self->option->opt_id*/); }), x_textctrl->GetId());
@ -474,7 +485,7 @@ void Point::BUILD()
}
}
void Point::set_value(const Pointf value)
void PointCtrl::set_value(const Pointf value)
{
m_disable_change_event = true;
@ -486,7 +497,27 @@ void Point::set_value(const Pointf value)
m_disable_change_event = false;
}
boost::any Point::get_value()
void PointCtrl::set_value(boost::any value)
{
Pointf pt;
try
{
pt = boost::any_cast<ConfigOptionPoints*>(value)->values.at(0);
}
catch (const std::exception &e)
{
try{
pt = boost::any_cast<Pointf>(value);
}
catch (const std::exception &e)
{
int i=0;
}
}
set_value(pt);
}
boost::any PointCtrl::get_value()
{
Pointf ret_point;
double val;

View File

@ -80,7 +80,7 @@ public:
virtual wxWindow* getWindow() { return nullptr; }
bool is_matched(std::string string, std::string pattern);
boost::any get_value_by_opt_type(wxString str, ConfigOptionType type);
boost::any get_value_by_opt_type(wxString str, ConfigOptionType type);
/// Factory method for generating new derived classes.
template<class T>
@ -226,11 +226,11 @@ public:
void set_tooltip(const wxString& tip) override {}; //! Redundant
};
class Point : public Field {
class PointCtrl : public Field {
using Field::Field;
public:
Point(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
Point(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
PointCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
PointCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
wxSizer* sizer{ nullptr };
wxTextCtrl* x_textctrl;
@ -239,9 +239,7 @@ public:
void BUILD() override;
void set_value(const Pointf value);
void set_value(boost::any value) {
// dynamic_cast<wxColourPickerCtrl*>(sizer)->SetColour(boost::any_cast<std::string>(value));
}
void set_value(boost::any value);
boost::any get_value() override;
void enable() override {

View File

@ -246,13 +246,13 @@ void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, b
break;
case coStrings:{
if (opt_key.compare("compatible_printers") == 0){
config.option<ConfigOptionStrings>(opt_key)->values.resize(0);
for (auto el : boost::any_cast<std::vector<std::string>>(value))
config.option<ConfigOptionStrings>(opt_key)->values.push_back(el);
config.option<ConfigOptionStrings>(opt_key)->values.resize(0);
for (auto el : boost::any_cast<std::vector<std::string>>(value))
config.option<ConfigOptionStrings>(opt_key)->values.push_back(el);
}
else{
ConfigOptionStrings* vec_new = new ConfigOptionStrings{ boost::any_cast<std::string>(value) };
config.option<ConfigOptionStrings>(opt_key)->set_at(vec_new, 0, 0);
ConfigOptionStrings* vec_new = new ConfigOptionStrings{ boost::any_cast<std::string>(value) };
config.option<ConfigOptionStrings>(opt_key)->set_at(vec_new, 0, 0);
}
}
break;
@ -302,39 +302,6 @@ void add_created_tab(Tab* panel, PresetBundle *preset_bundle, AppConfig *app_con
panel->m_no_controller = app_config->get("no_controller").empty();
panel->m_show_btn_incompatible_presets = app_config->get("show_incompatible_presets").empty();
panel->create_preset_tab(preset_bundle);
// Callback to be executed after any of the configuration fields(Perl class Slic3r::GUI::OptionsGroup::Field) change their value.
// panel->m_on_value_change = [/*this*/](std::string opt_key, boost::any value){
//! plater & loaded - variables of MainFrame
// if (plater) {
// plater->on_config_change(m_config); //# propagate config change events to the plater
// if (opt_key.compare("extruders_count") plater->on_extruders_change(value);
// }
// don't save while loading for the first time
// if (loaded && Slic3r::GUI::autosave) m_config->save(Slic3r::GUI::autosave) ;
// };
// Install a callback for the tab to update the platter and print controller presets, when
// a preset changes at Slic3r::GUI::Tab.
// panel->m_on_presets_changed = [](){
// if ($self->{plater}) {
// # Update preset combo boxes(Print settings, Filament, Printer) from their respective tabs.
// $self->{plater}->update_presets($tab_name, @_);
// if ($tab_name eq 'printer') {
// # Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
// my($presets, $reload_dependent_tabs) = @_;
// for my $tab_name_other(qw(print filament)) {
// # If the printer tells us that the print or filament preset has been switched or invalidated,
// # refresh the print or filament tab page.Otherwise just refresh the combo box.
// my $update_action = ($reload_dependent_tabs && (first{ $_ eq $tab_name_other } (@{$reload_dependent_tabs})))
// ? 'load_current_preset' : 'update_tab_ui';
// $self->{options_tabs}{$tab_name_other}->$update_action;
// }
// # Update the controller printers.
// $self->{controller}->update_presets(@_) if $self->{controller};
// }
// $self->{plater}->on_config_change($tab->{presets}->get_current_preset->config);
// }
// };
// Load the currently selected preset into the GUI, update the preset selection box.
panel->load_current_preset();

View File

@ -52,7 +52,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(m_parent, opt, id)));
break;
case coPoints:
m_fields.emplace(id, STDMOVE(Point::Create<Point>(m_parent, opt, id)));
m_fields.emplace(id, STDMOVE(PointCtrl::Create<PointCtrl>(m_parent, opt, id)));
break;
case coNone: break;
default:

View File

@ -98,8 +98,8 @@ public:
inline void enable() { for (auto& field : m_fields) field.second->enable(); }
inline void disable() { for (auto& field : m_fields) field.second->disable(); }
OptionsGroup(wxWindow* _parent, std::string title, const ConfigDef& configs) :
m_optiondefs(configs.options), m_parent(_parent), title(wxString(title)) {
OptionsGroup(wxWindow* _parent, std::string title) :
m_parent(_parent), title(wxString(title)) {
sizer = (staticbox ? new wxStaticBoxSizer(new wxStaticBox(_parent, wxID_ANY, title), wxVERTICAL) : new wxBoxSizer(wxVERTICAL));
auto num_columns = 1U;
if (label_width != 0) num_columns++;
@ -112,7 +112,6 @@ public:
}
protected:
const t_optiondef_map& m_optiondefs; //#WHY
std::map<t_config_option_key, Option> m_options;
wxWindow* m_parent {nullptr};
@ -136,8 +135,8 @@ protected:
class ConfigOptionsGroup: public OptionsGroup {
public:
ConfigOptionsGroup(wxWindow* parent, std::string title, DynamicPrintConfig* _config) :
OptionsGroup(parent, title, *_config->def()), m_config(_config) {}
ConfigOptionsGroup(wxWindow* parent, std::string title, DynamicPrintConfig* _config = nullptr) :
OptionsGroup(parent, title), m_config(_config) {}
/// reference to libslic3r config, non-owning pointer (?).
DynamicPrintConfig* m_config {nullptr};

View File

@ -1,4 +1,9 @@
#include "../../libslic3r/GCodeSender.hpp"
#include "Tab.hpp"
#include "PresetBundle.hpp"
#include "PresetHints.hpp"
#include "../../libslic3r/Utils.hpp"
#include <wx/app.h>
#include <wx/button.h>
#include <wx/scrolwin.h>
@ -11,10 +16,6 @@
#include <wx/imaglist.h>
#include <wx/settings.h>
#include "Tab.hpp"
#include "PresetBundle.hpp"
#include "PresetHints.hpp"
#include "../../libslic3r/Utils.hpp"
#include <boost/algorithm/string/predicate.hpp>
namespace Slic3r {
@ -86,7 +87,7 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
m_treectrl->Bind(wxEVT_COMBOBOX, &Tab::OnComboBox, this);
m_presets_choice->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent e){
select_preset(static_cast<const wxComboBox*>(m_presets_choice)->GetStringSelection());
select_preset(static_cast<const wxComboBox*>(m_presets_choice)->GetStringSelection().ToStdString());
}));
m_btn_save_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e){ save_preset(); }));
@ -273,15 +274,20 @@ extern wxFrame *g_wxMainFrame;
void Tab::on_value_change(std::string opt_key, boost::any value)
{
// if (m_on_value_change != nullptr)
// m_on_value_change(opt_key, value);
if (m_event_value_change > 0) {
wxCommandEvent event(m_event_value_change);
event.SetString(opt_key);
std::string str_out = opt_key + " " + m_title;
event.SetString(str_out);
if (opt_key == "extruders_count")
{
int val = boost::any_cast<size_t>(value);
event.SetInt(val);
}
g_wxMainFrame->ProcessWindowEvent(event);
}
update();
};
}
// Call a callback to update the selection of presets on the platter:
// To update the content of the selection boxes,
@ -290,11 +296,9 @@ void Tab::on_value_change(std::string opt_key, boost::any value)
// to uddate number of "filament" selection boxes when the number of extruders change.
void Tab::on_presets_changed(/*std::vector<std::string> reload_dependent_tabs*/)
{
// if (m_on_presets_changed != nullptr)
// m_on_presets_changed(/*m_presets, reload_dependent_tabs*/);
if (m_event_presets_changed > 0) {
wxCommandEvent event(m_event_presets_changed);
//event.SetString(opt_key);
event.SetString(m_title);
g_wxMainFrame->ProcessWindowEvent(event);
}
}
@ -919,6 +923,11 @@ wxSizer* Tab::description_line_widget(wxWindow* parent, ogStaticText* *StaticTex
return sizer;
}
bool Tab::current_preset_is_dirty()
{
return m_presets->current_is_dirty();
}
void TabPrinter::build()
{
m_presets = &m_preset_bundle->printers;
@ -932,7 +941,7 @@ void TabPrinter::build()
auto optgroup = page->new_optgroup("Size and coordinates");
Line line = { "Bed shape", "" };
line.widget = [](wxWindow* parent){
line.widget = [this](wxWindow* parent){
auto btn = new wxButton(parent, wxID_ANY, "Set\u2026", wxDefaultPosition, wxDefaultSize,
wxBU_LEFT | wxBU_EXACTFIT);
// btn->SetFont(Slic3r::GUI::small_font);
@ -941,11 +950,13 @@ void TabPrinter::build()
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
btn->Bind(wxEVT_BUTTON, ([](wxCommandEvent e)
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
{
// auto dlg = new BedShapeDialog->new($self, $self->{config}->bed_shape);
// if (dlg->ShowModal == wxID_OK)
;// load_key_value_("bed_shape", dlg->GetValue);
auto dlg = new BedShapeDialog(this);
dlg->build_dialog(m_config->option<ConfigOptionPoints>("bed_shape"));
if (dlg->ShowModal() == wxID_OK)
// load_key_value("bed_shape", dlg->GetValue());
;
}));
return sizer;
@ -1336,10 +1347,10 @@ void Tab::load_current_preset()
// and we don't want them to be called after this update_dirty() as they would mark the
// preset dirty again
// (not sure this is true anymore now that update_dirty is idempotent)
wxTheApp->CallAfter([this]{
// wxTheApp->CallAfter([this]{
update_tab_ui();
on_presets_changed();
});
// });
}
//Regerenerate content of the page tree.
@ -1372,9 +1383,9 @@ void Tab::rebuild_page_tree()
// Called by the UI combo box when the user switches profiles.
// Select a preset by a name.If !defined(name), then the default preset is selected.
// If the current profile is modified, user is asked to save the changes.
void Tab::select_preset(wxString preset_name)
void Tab::select_preset(std::string preset_name /*= ""*/)
{
std::string name = preset_name.ToStdString();
std::string name = preset_name/*.ToStdString()*/;
auto force = false;
auto presets = m_presets;
// If no name is provided, select the "-- default --" preset.
@ -1407,12 +1418,12 @@ void Tab::select_preset(wxString preset_name)
if (!canceled) {
if (!print_preset_compatible) {
// The preset will be switched to a different, compatible preset, or the '-- default --'.
m_reload_dependent_tabs.push_back("Print");
m_reload_dependent_tabs.push_back("print");
if (print_preset_dirty) print_presets->discard_current_changes();
}
if (!filament_preset_compatible) {
// The preset will be switched to a different, compatible preset, or the '-- default --'.
m_reload_dependent_tabs.push_back("Filament");
m_reload_dependent_tabs.push_back("filament");
if (filament_preset_dirty) filament_presets->discard_current_changes();
}
}

View File

@ -26,7 +26,7 @@
#include <vector>
#include <memory>
#include "OptionsGroup.hpp"
#include "BedShapeDialog.hpp"
//!enum { ID_TAB_TREE = wxID_HIGHEST + 1 };
@ -128,7 +128,7 @@ public:
void create_preset_tab(PresetBundle *preset_bundle);
void load_current_preset();
void rebuild_page_tree();
void select_preset(wxString preset_name = "");
void select_preset(std::string preset_name = "");
bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, std::string new_printer_name = "");
wxSizer* compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn);
@ -137,7 +137,8 @@ public:
void OnTreeSelChange(wxTreeEvent& event);
void OnKeyDown(wxKeyEvent& event);
void OnComboBox(wxCommandEvent& event) { select_preset(static_cast<const wxComboBox*>(m_presets_choice)->GetStringSelection()); }
void OnComboBox(wxCommandEvent& event) {
select_preset(static_cast<const wxComboBox*>(m_presets_choice)->GetStringSelection().ToStdString()); }
void save_preset(std::string name = "");
void delete_preset();
void toggle_show_hide_incompatible();
@ -157,6 +158,11 @@ public:
Field* get_field(t_config_option_key opt_key, int opt_index = -1) const;
bool set_value(t_config_option_key opt_key, boost::any value);
wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText);
bool current_preset_is_dirty();
DynamicPrintConfig* get_config() { return m_config; }
PresetCollection* get_presets() { return m_presets; }
std::vector<std::string> get_dependent_tabs() {
return m_reload_dependent_tabs; }
void on_value_change(std::string opt_key, boost::any value);

View File

@ -3,7 +3,15 @@
namespace Slic3r {
void TabIface::load_current_preset() { m_tab->load_current_preset(); }
void TabIface::rebuild_page_tree() { m_tab->rebuild_page_tree(); }
void TabIface::load_current_preset() { m_tab->load_current_preset(); }
void TabIface::update_tab_ui() { m_tab->update_tab_ui(); }
void TabIface::update_ui_from_settings() { m_tab->update_ui_from_settings();}
void TabIface::select_preset(char* name) { m_tab->select_preset(name);}
char* TabIface::title() { return (char*)m_tab->title().ToStdString()/*ToUTF8()*/.data();}
void TabIface::load_config(DynamicPrintConfig* config) { m_tab->load_config(*config);}
bool TabIface::current_preset_is_dirty() { return m_tab->current_preset_is_dirty();}
DynamicPrintConfig* TabIface::get_config() { return m_tab->get_config();}
PresetCollection* TabIface::get_presets() { return m_tab->get_presets(); }
std::vector<std::string> TabIface::get_dependent_tabs() { return m_tab->get_dependent_tabs(); }
}; // namespace Slic3r

View File

@ -1,16 +1,30 @@
#include <vector>
namespace Slic3r {
class DynamicPrintConfig;
class PresetCollection;
namespace GUI {
class Tab;
};
}
class TabIface {
public:
TabIface() : m_tab(nullptr) {}
TabIface(GUI::Tab *tab) : m_tab(tab) {}
// TabIface(const TabIface &rhs) : m_tab(rhs.m_tab) {}
void load_current_preset();
void rebuild_page_tree();
void load_current_preset();
void update_tab_ui();
void update_ui_from_settings();
void select_preset(char* name);
char* title();
void load_config(DynamicPrintConfig* config);
bool current_preset_is_dirty();
DynamicPrintConfig* get_config();
PresetCollection* TabIface::get_presets();
std::vector<std::string> TabIface::get_dependent_tabs();
protected:
GUI::Tab *m_tab;
};

View File

@ -8,6 +8,14 @@
%name{Slic3r::GUI::Tab2} class TabIface {
TabIface();
~TabIface();
void load_current_preset();
void rebuild_page_tree();
void load_current_preset();
void update_tab_ui();
void update_ui_from_settings();
void select_preset(char* name);
void load_config(DynamicPrintConfig* config);
bool current_preset_is_dirty();
char* title();
Ref<DynamicPrintConfig> get_config();
Ref<PresetCollection> get_presets();
std::vector<std::string> get_dependent_tabs();
};