Slic3r/src/GUI/Plater/Plate2D.cpp
2018-05-01 22:32:42 -05:00

262 lines
9.4 KiB
C++

#include "Plater/Plate2D.hpp"
// libslic3r includes
#include "Geometry.hpp"
#include "Point.hpp"
#include "Log.hpp"
#include "ClipperUtils.hpp"
// wx includes
#include <wx/colour.h>
#include <wx/dcbuffer.h>
namespace Slic3r { namespace GUI {
Plate2D::Plate2D(wxWindow* parent, const wxSize& size, std::vector<PlaterObject>& _objects, std::shared_ptr<Model> _model, std::shared_ptr<Config> _config, std::shared_ptr<Settings> _settings) :
wxPanel(parent, wxID_ANY, wxDefaultPosition, size, wxTAB_TRAVERSAL), objects(_objects), model(_model), config(_config), settings(_settings)
{
this->Bind(wxEVT_PAINT, [=](wxPaintEvent &e) { this->repaint(e); });
this->Bind(wxEVT_MOTION, [=](wxMouseEvent &e) { this->mouse_drag(e); });
this->Bind(wxEVT_LEFT_DOWN, [=](wxMouseEvent &e) { this->mouse_down(e); });
this->Bind(wxEVT_LEFT_UP, [=](wxMouseEvent &e) { this->mouse_up(e); });
this->Bind(wxEVT_LEFT_DCLICK, [=](wxMouseEvent &e) { this->mouse_dclick(e); });
if (user_drawn_background) {
this->Bind(wxEVT_ERASE_BACKGROUND, [=](wxEraseEvent& e){ });
}
this->Bind(wxEVT_SIZE, [=](wxSizeEvent &e) { this->update_bed_size(); this->Refresh(); });
// Bind the varying mouse events
// Set the brushes
set_colors();
this->SetBackgroundStyle(wxBG_STYLE_PAINT);
}
void Plate2D::repaint(wxPaintEvent& e) {
// Need focus to catch keyboard events.
this->SetFocus();
auto dc {new wxAutoBufferedPaintDC(this)};
const auto& size {wxSize(this->GetSize().GetWidth(), this->GetSize().GetHeight())};
if (this->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.
const auto& brush_background {wxBrush(this->settings->color->BACKGROUND255(), wxBRUSHSTYLE_SOLID)};
const auto& pen_background {wxPen(this->settings->color->BACKGROUND255(), 1, wxPENSTYLE_SOLID)};
dc->SetPen(pen_background);
dc->SetBrush(brush_background);
const auto& rect {this->GetUpdateRegion().GetBox()};
dc->DrawRectangle(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
}
// Draw bed
{
dc->SetPen(this->print_center_pen);
dc->SetBrush(this->bed_brush);
auto tmp {scaled_points_to_pixel(this->bed_polygon, true)};
dc->DrawPolygon(this->bed_polygon.points.size(), tmp.data(), 0, 0);
}
// draw print center
{
if (this->objects.size() > 0 && settings->autocenter) {
const auto center = this->unscaled_point_to_pixel(this->print_center);
dc->SetPen(print_center_pen);
dc->DrawLine(center.x, 0, center.x, size.y);
dc->DrawLine(0, center.y, size.x, center.y);
dc->SetTextForeground(wxColor(0,0,0));
dc->SetFont(wxFont(10, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
wxString val {};
val.Printf("X = %.0f", this->print_center.x);
dc->DrawLabel(val , wxRect(0,0, center.x*2, this->GetSize().GetHeight()), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM);
val.Printf("Y = %.0f", this->print_center.y);
dc->DrawRotatedText(val, 0, center.y + 15, 90);
}
}
// draw text if plate is empty
if (this->objects.size() == 0) {
dc->SetTextForeground(settings->color->BED_OBJECTS());
dc->SetFont(wxFont(14, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
dc->DrawLabel(CANVAS_TEXT, wxRect(0,0, this->GetSize().GetWidth(), this->GetSize().GetHeight()), wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL);
} else {
// draw grid
dc->SetPen(grid_pen);
// Assumption: grid of lines is arranged
// as adjacent pairs of wxPoints
for (auto i = 0U; i < grid.size(); i+=2) {
dc->DrawLine(grid[i], grid[i+1]);
}
}
}
void Plate2D::mouse_drag(wxMouseEvent& e) {
const auto pos {e.GetPosition()};
const auto& point {this->point_to_model_units(e.GetPosition())};
if (e.Dragging()) {
Slic3r::Log::info(LogChannel, L"Mouse dragging");
} else {
auto cursor = wxSTANDARD_CURSOR;
/*
if (find_first_of(this->objects.begin(), this->objects.end(); [=](const PlaterObject& o) { return o.contour->contains_point(point);} ) == this->object.end()) {
cursor = wxCursor(wxCURSOR_HAND);
}
*/
this->SetCursor(*cursor);
}
}
void Plate2D::mouse_down(wxMouseEvent& e) {
}
void Plate2D::mouse_up(wxMouseEvent& e) {
}
void Plate2D::mouse_dclick(wxMouseEvent& e) {
}
void Plate2D::set_colors() {
this->SetBackgroundColour(settings->color->BACKGROUND255());
this->objects_brush.SetColour(settings->color->BED_OBJECTS());
this->objects_brush.SetStyle(wxBRUSHSTYLE_SOLID);
this->instance_brush.SetColour(settings->color->BED_INSTANCE());
this->instance_brush.SetStyle(wxBRUSHSTYLE_SOLID);
this->selected_brush.SetColour(settings->color->BED_SELECTED());
this->selected_brush.SetStyle(wxBRUSHSTYLE_SOLID);
this->dragged_brush.SetColour(settings->color->BED_DRAGGED());
this->dragged_brush.SetStyle(wxBRUSHSTYLE_SOLID);
this->bed_brush.SetColour(settings->color->BED_COLOR());
this->bed_brush.SetStyle(wxBRUSHSTYLE_SOLID);
this->transparent_brush.SetColour(wxColour(0,0,0));
this->transparent_brush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
this->grid_pen.SetColour(settings->color->BED_GRID());
this->grid_pen.SetWidth(1);
this->grid_pen.SetStyle(wxPENSTYLE_SOLID);
this->print_center_pen.SetColour(settings->color->BED_CENTER());
this->print_center_pen.SetWidth(1);
this->print_center_pen.SetStyle(wxPENSTYLE_SOLID);
this->clearance_pen.SetColour(settings->color->BED_CLEARANCE());
this->clearance_pen.SetWidth(1);
this->clearance_pen.SetStyle(wxPENSTYLE_SOLID);
this->skirt_pen.SetColour(settings->color->BED_SKIRT());
this->skirt_pen.SetWidth(1);
this->skirt_pen.SetStyle(wxPENSTYLE_SOLID);
this->dark_pen.SetColour(settings->color->BED_DARK());
this->dark_pen.SetWidth(1);
this->dark_pen.SetStyle(wxPENSTYLE_SOLID);
}
void Plate2D::nudge_key(wxKeyEvent& e) {
const auto key = e.GetKeyCode();
switch( key ) {
case WXK_LEFT:
this->nudge(MoveDirection::Left);
case WXK_RIGHT:
this->nudge(MoveDirection::Right);
case WXK_DOWN:
this->nudge(MoveDirection::Down);
case WXK_UP:
this->nudge(MoveDirection::Up);
default:
break; // do nothing
}
}
void Plate2D::nudge(MoveDirection dir) {
if (this->selected_instance < this->objects.size()) {
auto i = 0U;
for (auto& obj : this->objects) {
if (obj.selected) {
if (obj.selected_instance != -1) {
}
}
i++;
}
}
if (selected_instance >= this->objects.size()) {
Slic3r::Log::warn(LogChannel, L"Nudge failed because there is no selected instance.");
return; // Abort
}
}
void Plate2D::update_bed_size() {
const auto& canvas_size {this->GetSize()};
const auto& canvas_w {canvas_size.GetWidth()};
const auto& canvas_h {canvas_size.GetHeight()};
if (canvas_w == 0) return; // Abort early if we haven't drawn canvas yet.
this->bed_polygon = Slic3r::Polygon(scale(dynamic_cast<ConfigOptionPoints*>(config->optptr("bed_shape"))->values));
const auto& polygon = bed_polygon;
const auto& bb = bed_polygon.bounding_box();
const auto& size = bb.size();
this->scaling_factor = std::min(canvas_w / unscale(size.x), canvas_h / unscale(size.y));
this->bed_origin = wxPoint(
canvas_w / 2 - (unscale(bb.max.x + bb.min.x)/2 * this->scaling_factor),
canvas_h - (canvas_h / 2 - (unscale(bb.max.y + bb.min.y)/2 * this->scaling_factor))
);
const auto& center = bb.center();
this->print_center = wxPoint(unscale(center.x), unscale(center.y));
// Cache bed contours and grid
{
const auto& step { scale_(10) };
auto grid {Polylines()};
for (coord_t x = (bb.min.x - (bb.min.x % step) + step); x < bb.max.x; x += step) {
grid.push_back(Polyline());
grid.back().append(Point(x, bb.min.y));
grid.back().append(Point(x, bb.max.y));
};
for (coord_t y = (bb.min.y - (bb.min.y % step) + step); y < bb.max.y; y += step) {
grid.push_back(Polyline());
grid.back().append(Point(bb.min.x, y));
grid.back().append(Point(bb.max.x, y));
};
grid = intersection_pl(grid, polygon);
for (auto& i : grid) {
const auto& tmpline { this->scaled_points_to_pixel(i, 1) };
this->grid.insert(this->grid.end(), tmpline.begin(), tmpline.end());
}
}
}
std::vector<wxPoint> Plate2D::scaled_points_to_pixel(const Slic3r::Polygon& poly, bool unscale) {
return this->scaled_points_to_pixel(Polyline(poly), unscale);
}
std::vector<wxPoint> Plate2D::scaled_points_to_pixel(const Slic3r::Polyline& poly, bool unscale) {
std::vector<wxPoint> result;
for (const auto& pt : poly.points) {
const auto tmp {wxPoint(pt.x, pt.y)};
result.push_back( (unscale ? unscaled_point_to_pixel(tmp) : tmp) );
}
return result;
}
} } // Namespace Slic3r::GUI