Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_reload_from_disk
This commit is contained in:
commit
c0576a8770
18 changed files with 342 additions and 159 deletions
|
@ -151,8 +151,8 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label)
|
||||||
memcpy(buffer, &stl->stats.number_of_facets, 4);
|
memcpy(buffer, &stl->stats.number_of_facets, 4);
|
||||||
stl_internal_reverse_quads(buffer, 4);
|
stl_internal_reverse_quads(buffer, 4);
|
||||||
fwrite(buffer, 4, 1, fp);
|
fwrite(buffer, 4, 1, fp);
|
||||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
for (const stl_facet &facet : stl->facet_start) {
|
||||||
memcpy(buffer, stl->facet_start + i, 50);
|
memcpy(buffer, &facet, 50);
|
||||||
// Convert to little endian.
|
// Convert to little endian.
|
||||||
stl_internal_reverse_quads(buffer, 48);
|
stl_internal_reverse_quads(buffer, 48);
|
||||||
fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
|
fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
2018-01-17 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
|
||||||
|
(cherry-picked)
|
||||||
|
Submitted by Reinhard Max
|
||||||
|
patch #8311: Add IPv6 support to the -Pnet:host:port option
|
||||||
|
* ser_posix.c (net_open): Rewrite to use getaddrinfo()
|
||||||
|
rather than gethostbyname()
|
||||||
|
* avrdude.1: Document IPv6 feature
|
||||||
|
* doc/avrdude.texi: (Dito)
|
||||||
|
|
||||||
2016-05-10 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
|
2016-05-10 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
|
||||||
|
|
||||||
Submitted by Hannes Jochriem:
|
Submitted by Hannes Jochriem:
|
||||||
|
|
|
@ -505,12 +505,19 @@ network connection to (TCP)
|
||||||
on
|
on
|
||||||
.Ar host
|
.Ar host
|
||||||
is established.
|
is established.
|
||||||
|
Square brackets may be placed around
|
||||||
|
.Ar host
|
||||||
|
to improve readability, for numeric IPv6 addresses (e.g.
|
||||||
|
.Li net:[2001:db8::42]:1337 ) .
|
||||||
The remote endpoint is assumed to be a terminal or console server
|
The remote endpoint is assumed to be a terminal or console server
|
||||||
that connects the network stream to a local serial port where the
|
that connects the network stream to a local serial port where the
|
||||||
actual programmer has been attached to.
|
actual programmer has been attached to.
|
||||||
The port is assumed to be properly configured, for example using a
|
The port is assumed to be properly configured, for example using a
|
||||||
transparent 8-bit data connection without parity at 115200 Baud
|
transparent 8-bit data connection without parity at 115200 Baud
|
||||||
for a STK500.
|
for a STK500.
|
||||||
|
.Pp
|
||||||
|
Note: The ability to handle IPv6 hostnames and addresses is limited to
|
||||||
|
Posix systems (by now).
|
||||||
.It Fl q
|
.It Fl q
|
||||||
Disable (or quell) output of the progress bar while reading or writing
|
Disable (or quell) output of the progress bar while reading or writing
|
||||||
to the device. Specify it a second time for even quieter operation.
|
to the device. Specify it a second time for even quieter operation.
|
||||||
|
|
|
@ -214,7 +214,7 @@ AC_HEADER_TIME
|
||||||
AC_CHECK_LIB([ws2_32], [puts])
|
AC_CHECK_LIB([ws2_32], [puts])
|
||||||
|
|
||||||
# Checks for library functions.
|
# Checks for library functions.
|
||||||
AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep])
|
AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep getaddrinfo])
|
||||||
|
|
||||||
AC_MSG_CHECKING([for a Win32 HID libray])
|
AC_MSG_CHECKING([for a Win32 HID libray])
|
||||||
SAVED_LIBS="${LIBS}"
|
SAVED_LIBS="${LIBS}"
|
||||||
|
|
|
@ -557,6 +557,9 @@ higher level protocol (as opposed to bit-bang style programmers),
|
||||||
In this case, instead of trying to open a local device, a TCP
|
In this case, instead of trying to open a local device, a TCP
|
||||||
network connection to (TCP) @var{port} on @var{host}
|
network connection to (TCP) @var{port} on @var{host}
|
||||||
is established.
|
is established.
|
||||||
|
Square brackets may be placed around @var{host} to improve
|
||||||
|
readability for numeric IPv6 addresses (e.g.
|
||||||
|
@code{net:[2001:db8::42]:1337}).
|
||||||
The remote endpoint is assumed to be a terminal or console server
|
The remote endpoint is assumed to be a terminal or console server
|
||||||
that connects the network stream to a local serial port where the
|
that connects the network stream to a local serial port where the
|
||||||
actual programmer has been attached to.
|
actual programmer has been attached to.
|
||||||
|
@ -564,6 +567,8 @@ The port is assumed to be properly configured, for example using a
|
||||||
transparent 8-bit data connection without parity at 115200 Baud
|
transparent 8-bit data connection without parity at 115200 Baud
|
||||||
for a STK500.
|
for a STK500.
|
||||||
|
|
||||||
|
Note: The ability to handle IPv6 hostnames and addresses is limited to
|
||||||
|
Posix systems (by now).
|
||||||
|
|
||||||
@item -q
|
@item -q
|
||||||
Disable (or quell) output of the progress bar while reading or writing
|
Disable (or quell) output of the progress bar while reading or writing
|
||||||
|
|
|
@ -150,6 +150,7 @@ static int ser_setspeed(union filedescriptor *fd, long baud)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "ac_cfg.h"
|
||||||
|
|
||||||
// Timeout read & write variants
|
// Timeout read & write variants
|
||||||
// Additionally to the regular -1 on I/O error, they return -2 on timeout
|
// Additionally to the regular -1 on I/O error, they return -2 on timeout
|
||||||
|
@ -221,23 +222,35 @@ ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout)
|
||||||
static int
|
static int
|
||||||
net_open(const char *port, union filedescriptor *fdp)
|
net_open(const char *port, union filedescriptor *fdp)
|
||||||
{
|
{
|
||||||
char *hstr, *pstr, *end;
|
#ifdef HAVE_GETADDRINFO
|
||||||
unsigned int pnum;
|
char *hp, *hstr, *pstr;
|
||||||
int fd;
|
int s, fd, ret = -1;
|
||||||
struct sockaddr_in sockaddr;
|
struct addrinfo hints;
|
||||||
struct hostent *hp;
|
struct addrinfo *result, *rp;
|
||||||
|
|
||||||
if ((hstr = strdup(port)) == NULL) {
|
if ((hstr = hp = strdup(port)) == NULL) {
|
||||||
avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n",
|
avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n",
|
||||||
progname);
|
progname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) {
|
/*
|
||||||
|
* As numeric IPv6 addresses use colons as separators, we need to
|
||||||
|
* look for the last colon here, which separates the port number or
|
||||||
|
* service name from the host or IP address.
|
||||||
|
*/
|
||||||
|
if (((pstr = strrchr(hstr, ':')) == NULL) || (pstr == hstr)) {
|
||||||
avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n",
|
avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n",
|
||||||
progname, hstr);
|
progname, hstr);
|
||||||
free(hstr);
|
goto error;
|
||||||
return -1;
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove brackets from the host part, if present.
|
||||||
|
*/
|
||||||
|
if (*hstr == '[' && *(pstr-1) == ']') {
|
||||||
|
hstr++;
|
||||||
|
*(pstr-1) = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -245,43 +258,49 @@ net_open(const char *port, union filedescriptor *fdp)
|
||||||
*/
|
*/
|
||||||
*pstr++ = '\0';
|
*pstr++ = '\0';
|
||||||
|
|
||||||
pnum = strtoul(pstr, &end, 10);
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
s = getaddrinfo(hstr, pstr, &hints, &result);
|
||||||
|
|
||||||
if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) {
|
if (s != 0) {
|
||||||
avrdude_message(MSG_INFO, "%s: net_open(): Bad port number \"%s\"\n",
|
avrdude_message(MSG_INFO,
|
||||||
progname, pstr);
|
"%s: net_open(): Cannot resolve "
|
||||||
free(hstr);
|
"host=\"%s\", port=\"%s\": %s\n",
|
||||||
return -1;
|
progname, hstr, pstr, gai_strerror(s));
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||||
if ((hp = gethostbyname(hstr)) == NULL) {
|
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
avrdude_message(MSG_INFO, "%s: net_open(): unknown host \"%s\"\n",
|
if (fd == -1) {
|
||||||
progname, hstr);
|
/* This one failed, loop over */
|
||||||
free(hstr);
|
continue;
|
||||||
return -1;
|
}
|
||||||
|
if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
|
||||||
|
/* Success, we are connected */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
}
|
}
|
||||||
|
if (rp == NULL) {
|
||||||
free(hstr);
|
avrdude_message(MSG_INFO, "%s: net_open(): Cannot connect: %s\n",
|
||||||
|
progname, strerror(errno));
|
||||||
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
|
|
||||||
avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n",
|
|
||||||
progname, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
memset(&sockaddr, 0, sizeof(struct sockaddr_in));
|
fdp->ifd = fd;
|
||||||
sockaddr.sin_family = AF_INET;
|
ret = 0;
|
||||||
sockaddr.sin_port = htons(pnum);
|
|
||||||
memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr));
|
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
|
|
||||||
avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n",
|
|
||||||
progname, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
fdp->ifd = fd;
|
error:
|
||||||
return 0;
|
free(hp);
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
avrdude_message(MSG_INFO,
|
||||||
|
"%s: Networking is not supported on your platform.\n"
|
||||||
|
"If you need it, please open a bug report.\n", progname);
|
||||||
|
return -1;
|
||||||
|
#endif /* HAVE_GETADDRINFO */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths
|
||||||
this->append(paths);
|
this->append(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtrusionEntityCollection& ExtrusionEntityCollection::operator= (const ExtrusionEntityCollection &other)
|
ExtrusionEntityCollection& ExtrusionEntityCollection::operator=(const ExtrusionEntityCollection &other)
|
||||||
{
|
{
|
||||||
this->entities = other.entities;
|
this->entities = other.entities;
|
||||||
for (size_t i = 0; i < this->entities.size(); ++i)
|
for (size_t i = 0; i < this->entities.size(); ++i)
|
||||||
|
@ -175,20 +175,20 @@ size_t ExtrusionEntityCollection::items_count() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a single vector of pointers to all non-collection items contained in this one.
|
// Returns a single vector of pointers to all non-collection items contained in this one.
|
||||||
void ExtrusionEntityCollection::flatten(ExtrusionEntityCollection* retval) const
|
|
||||||
{
|
|
||||||
for (const ExtrusionEntity *entity : this->entities)
|
|
||||||
if (entity->is_collection())
|
|
||||||
retval->append(static_cast<const ExtrusionEntityCollection*>(entity)->flatten().entities);
|
|
||||||
else
|
|
||||||
retval->append(*entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtrusionEntityCollection ExtrusionEntityCollection::flatten() const
|
ExtrusionEntityCollection ExtrusionEntityCollection::flatten() const
|
||||||
{
|
{
|
||||||
ExtrusionEntityCollection coll;
|
struct Flatten {
|
||||||
this->flatten(&coll);
|
ExtrusionEntityCollection out;
|
||||||
return coll;
|
void recursive_do(const ExtrusionEntityCollection &collection) {
|
||||||
|
for (const ExtrusionEntity* entity : collection.entities)
|
||||||
|
if (entity->is_collection())
|
||||||
|
this->recursive_do(*static_cast<const ExtrusionEntityCollection*>(entity));
|
||||||
|
else
|
||||||
|
out.append(*entity);
|
||||||
|
}
|
||||||
|
} flatten;
|
||||||
|
flatten.recursive_do(*this);
|
||||||
|
return flatten.out;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ExtrusionEntityCollection::min_mm3_per_mm() const
|
double ExtrusionEntityCollection::min_mm3_per_mm() const
|
||||||
|
|
|
@ -85,7 +85,6 @@ public:
|
||||||
Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
|
Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
|
||||||
{ Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; }
|
{ Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; }
|
||||||
size_t items_count() const;
|
size_t items_count() const;
|
||||||
void flatten(ExtrusionEntityCollection* retval) const;
|
|
||||||
ExtrusionEntityCollection flatten() const;
|
ExtrusionEntityCollection flatten() const;
|
||||||
double min_mm3_per_mm() const;
|
double min_mm3_per_mm() const;
|
||||||
double total_volume() const override { double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; }
|
double total_volume() const override { double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; }
|
||||||
|
|
|
@ -1236,7 +1236,8 @@ std::string Print::validate() const
|
||||||
|
|
||||||
// The comparison of the profiles is not just about element-wise equality, some layers may not be
|
// The comparison of the profiles is not just about element-wise equality, some layers may not be
|
||||||
// explicitely included. Always remember z and height of last reference layer that in the vector
|
// explicitely included. Always remember z and height of last reference layer that in the vector
|
||||||
// and compare to that.
|
// and compare to that. In case some layers are in the vectors multiple times, only the last entry is
|
||||||
|
// taken into account and compared.
|
||||||
size_t i = 0; // index into tested profile
|
size_t i = 0; // index into tested profile
|
||||||
size_t j = 0; // index into reference profile
|
size_t j = 0; // index into reference profile
|
||||||
coordf_t ref_z = -1.;
|
coordf_t ref_z = -1.;
|
||||||
|
@ -1244,8 +1245,12 @@ std::string Print::validate() const
|
||||||
coordf_t ref_height = -1.;
|
coordf_t ref_height = -1.;
|
||||||
while (i < layer_height_profile.size()) {
|
while (i < layer_height_profile.size()) {
|
||||||
coordf_t this_z = layer_height_profile[i];
|
coordf_t this_z = layer_height_profile[i];
|
||||||
|
// find the last entry with this z
|
||||||
|
while (i+2 < layer_height_profile.size() && layer_height_profile[i+2] == this_z)
|
||||||
|
i += 2;
|
||||||
|
|
||||||
coordf_t this_height = layer_height_profile[i+1];
|
coordf_t this_height = layer_height_profile[i+1];
|
||||||
if (next_ref_z < this_z + EPSILON) {
|
if (ref_height < -1. || next_ref_z < this_z + EPSILON) {
|
||||||
ref_z = next_ref_z;
|
ref_z = next_ref_z;
|
||||||
do { // one layer can be in the vector several times
|
do { // one layer can be in the vector several times
|
||||||
ref_height = layer_height_profile_tallest[j+1];
|
ref_height = layer_height_profile_tallest[j+1];
|
||||||
|
|
|
@ -42,7 +42,7 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
|
||||||
text += " (" + wxString::FromUTF8(snapshot.comment.data()) + ")";
|
text += " (" + wxString::FromUTF8(snapshot.comment.data()) + ")";
|
||||||
text += "</b></font><br>";
|
text += "</b></font><br>";
|
||||||
// End of row header.
|
// End of row header.
|
||||||
text += _(L("slic3r version")) + ": " + snapshot.slic3r_version_captured.to_string() + "<br>";
|
text += _(L("PrusaSlicer version")) + ": " + snapshot.slic3r_version_captured.to_string() + "<br>";
|
||||||
text += _(L("print")) + ": " + snapshot.print + "<br>";
|
text += _(L("print")) + ": " + snapshot.print + "<br>";
|
||||||
text += _(L("filaments")) + ": " + snapshot.filaments.front() + "<br>";
|
text += _(L("filaments")) + ": " + snapshot.filaments.front() + "<br>";
|
||||||
text += _(L("printer")) + ": " + snapshot.printer + "<br>";
|
text += _(L("printer")) + ": " + snapshot.printer + "<br>";
|
||||||
|
@ -50,9 +50,9 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
|
||||||
bool compatible = true;
|
bool compatible = true;
|
||||||
for (const Config::Snapshot::VendorConfig &vc : snapshot.vendor_configs) {
|
for (const Config::Snapshot::VendorConfig &vc : snapshot.vendor_configs) {
|
||||||
text += _(L("vendor")) + ": " + vc.name +", " + _(L("version")) + ": " + vc.version.config_version.to_string() +
|
text += _(L("vendor")) + ": " + vc.name +", " + _(L("version")) + ": " + vc.version.config_version.to_string() +
|
||||||
", " + _(L("min slic3r version")) + ": " + vc.version.min_slic3r_version.to_string();
|
", " + _(L("min PrusaSlicer version")) + ": " + vc.version.min_slic3r_version.to_string();
|
||||||
if (vc.version.max_slic3r_version != Semver::inf())
|
if (vc.version.max_slic3r_version != Semver::inf())
|
||||||
text += ", " + _(L("max slic3r version")) + ": " + vc.version.max_slic3r_version.to_string();
|
text += ", " + _(L("max PrusaSlicer version")) + ": " + vc.version.max_slic3r_version.to_string();
|
||||||
text += "<br>";
|
text += "<br>";
|
||||||
for (const std::pair<std::string, std::set<std::string>> &model : vc.models_variants_installed) {
|
for (const std::pair<std::string, std::set<std::string>> &model : vc.models_variants_installed) {
|
||||||
text += _(L("model")) + ": " + model.first + ", " + _(L("variants")) + ": ";
|
text += _(L("model")) + ": " + model.first + ", " + _(L("variants")) + ": ";
|
||||||
|
|
|
@ -1094,7 +1094,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
|
||||||
|
@ -3054,15 +3054,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
wxGetApp().obj_manipul()->set_dirty();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
// forces a frame render to update the view before the context menu is shown
|
// forces a frame render to update the view before the context menu is shown
|
||||||
render();
|
render();
|
||||||
|
|
||||||
Vec2d logical_pos = pos.cast<double>();
|
|
||||||
#if ENABLE_RETINA_GL
|
|
||||||
const float factor = m_retina_helper->get_scale_factor();
|
|
||||||
logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
|
|
||||||
#endif // ENABLE_RETINA_GL
|
|
||||||
post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Vec2d logical_pos = pos.cast<double>();
|
||||||
|
#if ENABLE_RETINA_GL
|
||||||
|
const float factor = m_retina_helper->get_scale_factor();
|
||||||
|
logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
|
||||||
|
#endif // ENABLE_RETINA_GL
|
||||||
|
if (!m_mouse.dragging)
|
||||||
|
// do not post the event if the user is panning the scene
|
||||||
|
post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, { logical_pos, m_hover_volume_idxs.empty() }));
|
||||||
}
|
}
|
||||||
|
|
||||||
mouse_up_cleanup();
|
mouse_up_cleanup();
|
||||||
|
@ -3414,7 +3415,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||||
void GLCanvas3D::set_camera_zoom(double zoom)
|
void GLCanvas3D::set_camera_zoom(double zoom)
|
||||||
{
|
{
|
||||||
const Size& cnv_size = get_canvas_size();
|
const Size& cnv_size = get_canvas_size();
|
||||||
m_camera.set_zoom(zoom, _max_bounding_box(false, false), cnv_size.get_width(), cnv_size.get_height());
|
m_camera.set_zoom(zoom, _max_bounding_box(false, true), cnv_size.get_width(), cnv_size.get_height());
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,8 @@ public:
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
|
||||||
|
|
||||||
using Vec2dEvent = Event<Vec2d>;
|
using Vec2dEvent = Event<Vec2d>;
|
||||||
|
// _bool_ value is used as a indicator of selection in the 3DScene
|
||||||
|
using RBtnEvent = Event<std::pair<Vec2d, bool>>;
|
||||||
template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;
|
template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;
|
||||||
|
|
||||||
using Vec3dEvent = Event<Vec3d>;
|
using Vec3dEvent = Event<Vec3d>;
|
||||||
|
@ -78,7 +80,7 @@ template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
|
||||||
|
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
|
||||||
|
|
|
@ -284,6 +284,9 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
|
||||||
wxSize(8 * em_unit(parent->m_parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
|
wxSize(8 * em_unit(parent->m_parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
|
||||||
{
|
{
|
||||||
this->SetFont(wxGetApp().normal_font());
|
this->SetFont(wxGetApp().normal_font());
|
||||||
|
|
||||||
|
// Reset m_enter_pressed flag to _false_, when value is editing
|
||||||
|
this->Bind(wxEVT_TEXT, [this](wxEvent&) { m_enter_pressed = false; }, this->GetId());
|
||||||
|
|
||||||
this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
|
this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
|
||||||
{
|
{
|
||||||
|
@ -307,7 +310,7 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
|
||||||
if (!m_enter_pressed) {
|
if (!m_enter_pressed) {
|
||||||
#ifndef __WXGTK__
|
#ifndef __WXGTK__
|
||||||
/* Update data for next editor selection.
|
/* Update data for next editor selection.
|
||||||
* But under GTK it lucks like there is no information about selected control at e.GetWindow(),
|
* But under GTK it looks like there is no information about selected control at e.GetWindow(),
|
||||||
* so we'll take it from wxEVT_LEFT_DOWN event
|
* so we'll take it from wxEVT_LEFT_DOWN event
|
||||||
* */
|
* */
|
||||||
LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
|
LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
|
||||||
|
|
|
@ -255,21 +255,30 @@ void ObjectList::create_objects_ctrl()
|
||||||
EnableDropTarget(wxDF_UNICODETEXT);
|
EnableDropTarget(wxDF_UNICODETEXT);
|
||||||
#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
|
#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
|
||||||
|
|
||||||
|
const int em = wxGetApp().em_unit();
|
||||||
|
|
||||||
// column ItemName(Icon+Text) of the view control:
|
// column ItemName(Icon+Text) of the view control:
|
||||||
// And Icon can be consisting of several bitmaps
|
// And Icon can be consisting of several bitmaps
|
||||||
AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(),
|
AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(),
|
||||||
colName, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
|
colName, 20*em, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
|
||||||
|
|
||||||
// column PrintableProperty (Icon) of the view control:
|
// column PrintableProperty (Icon) of the view control:
|
||||||
AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, int(2 * wxGetApp().em_unit()),
|
AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, 3*em,
|
||||||
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
|
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
|
||||||
|
|
||||||
// column Extruder of the view control:
|
// column Extruder of the view control:
|
||||||
AppendColumn(create_objects_list_extruder_column(4));
|
AppendColumn(create_objects_list_extruder_column(4));
|
||||||
|
|
||||||
// column ItemEditing of the view control:
|
// column ItemEditing of the view control:
|
||||||
AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/,
|
AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em,
|
||||||
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
|
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
|
||||||
|
|
||||||
|
if (wxOSX)
|
||||||
|
{
|
||||||
|
GetColumn(colName)->SetWidth(20*em);
|
||||||
|
GetColumn(colPrint)->SetWidth(3*em);
|
||||||
|
GetColumn(colExtruder)->SetWidth(8*em);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::create_popup_menus()
|
void ObjectList::create_popup_menus()
|
||||||
|
@ -279,6 +288,7 @@ void ObjectList::create_popup_menus()
|
||||||
create_part_popupmenu(&m_menu_part);
|
create_part_popupmenu(&m_menu_part);
|
||||||
create_sla_object_popupmenu(&m_menu_sla_object);
|
create_sla_object_popupmenu(&m_menu_sla_object);
|
||||||
create_instance_popupmenu(&m_menu_instance);
|
create_instance_popupmenu(&m_menu_instance);
|
||||||
|
create_default_popupmenu(&m_menu_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(nullptr)*/)
|
void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(nullptr)*/)
|
||||||
|
@ -783,18 +793,34 @@ void ObjectList::OnChar(wxKeyEvent& event)
|
||||||
|
|
||||||
void ObjectList::OnContextMenu(wxDataViewEvent&)
|
void ObjectList::OnContextMenu(wxDataViewEvent&)
|
||||||
{
|
{
|
||||||
list_manipulation();
|
list_manipulation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::list_manipulation()
|
void ObjectList::list_manipulation(bool evt_context_menu/* = false*/)
|
||||||
{
|
{
|
||||||
wxDataViewItem item;
|
wxDataViewItem item;
|
||||||
wxDataViewColumn* col = nullptr;
|
wxDataViewColumn* col = nullptr;
|
||||||
const wxPoint pt = get_mouse_position_in_control();
|
const wxPoint pt = get_mouse_position_in_control();
|
||||||
HitTest(pt, item, col);
|
HitTest(pt, item, col);
|
||||||
|
|
||||||
if (!item || col == nullptr) {
|
/* Note: Under OSX right click doesn't send "selection changed" event.
|
||||||
return;
|
* It means that Selection() will be return still previously selected item.
|
||||||
|
* Thus under OSX we should force UnselectAll(), when item and col are nullptr,
|
||||||
|
* and select new item otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
if (wxOSX && col == nullptr)
|
||||||
|
UnselectAll();
|
||||||
|
if (evt_context_menu) {
|
||||||
|
show_context_menu(evt_context_menu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wxOSX && item && col) {
|
||||||
|
UnselectAll();
|
||||||
|
Select(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxString title = col->GetTitle();
|
const wxString title = col->GetTitle();
|
||||||
|
@ -802,15 +828,21 @@ void ObjectList::list_manipulation()
|
||||||
if (title == " ")
|
if (title == " ")
|
||||||
toggle_printable_state(item);
|
toggle_printable_state(item);
|
||||||
else if (title == _("Editing"))
|
else if (title == _("Editing"))
|
||||||
show_context_menu();
|
show_context_menu(evt_context_menu);
|
||||||
else if (title == _("Name"))
|
else if (title == _("Name"))
|
||||||
{
|
{
|
||||||
int obj_idx, vol_idx;
|
if (wxOSX)
|
||||||
get_selected_item_indexes(obj_idx, vol_idx, item);
|
show_context_menu(evt_context_menu); // return context menu under OSX (related to #2909)
|
||||||
|
|
||||||
if (is_windows10() && get_mesh_errors_count(obj_idx, vol_idx) > 0 &&
|
if (is_windows10())
|
||||||
pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() )
|
{
|
||||||
fix_through_netfabb();
|
int obj_idx, vol_idx;
|
||||||
|
get_selected_item_indexes(obj_idx, vol_idx, item);
|
||||||
|
|
||||||
|
if (get_mesh_errors_count(obj_idx, vol_idx) > 0 &&
|
||||||
|
pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() )
|
||||||
|
fix_through_netfabb();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __WXMSW__
|
#ifndef __WXMSW__
|
||||||
|
@ -818,7 +850,7 @@ void ObjectList::list_manipulation()
|
||||||
#endif //__WXMSW__
|
#endif //__WXMSW__
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::show_context_menu()
|
void ObjectList::show_context_menu(const bool evt_context_menu)
|
||||||
{
|
{
|
||||||
if (multiple_selection())
|
if (multiple_selection())
|
||||||
{
|
{
|
||||||
|
@ -831,22 +863,26 @@ void ObjectList::show_context_menu()
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto item = GetSelection();
|
const auto item = GetSelection();
|
||||||
|
wxMenu* menu {nullptr};
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
const ItemType type = m_objects_model->GetItemType(item);
|
const ItemType type = m_objects_model->GetItemType(item);
|
||||||
if (!(type & (itObject | itVolume | itLayer | itInstance)))
|
if (!(type & (itObject | itVolume | itLayer | itInstance)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxMenu* menu = type & itInstance ? &m_menu_instance :
|
menu = type & itInstance ? &m_menu_instance :
|
||||||
type & itLayer ? &m_menu_layer :
|
type & itLayer ? &m_menu_layer :
|
||||||
m_objects_model->GetParent(item) != wxDataViewItem(nullptr) ? &m_menu_part :
|
m_objects_model->GetParent(item) != wxDataViewItem(nullptr) ? &m_menu_part :
|
||||||
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
|
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
|
||||||
|
|
||||||
if (!(type & itInstance))
|
if (!(type & itInstance))
|
||||||
append_menu_item_settings(menu);
|
append_menu_item_settings(menu);
|
||||||
|
|
||||||
wxGetApp().plater()->PopupMenu(menu);
|
|
||||||
}
|
}
|
||||||
|
else if (evt_context_menu)
|
||||||
|
menu = &m_menu_default;
|
||||||
|
|
||||||
|
if (menu)
|
||||||
|
wxGetApp().plater()->PopupMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::copy()
|
void ObjectList::copy()
|
||||||
|
@ -1286,13 +1322,16 @@ void ObjectList::show_settings(const wxDataViewItem settings_item)
|
||||||
wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type) {
|
wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type) {
|
||||||
auto sub_menu = new wxMenu;
|
auto sub_menu = new wxMenu;
|
||||||
|
|
||||||
if (wxGetApp().get_mode() == comExpert) {
|
if (wxGetApp().get_mode() == comExpert && type != ModelVolumeType::INVALID) {
|
||||||
append_menu_item(sub_menu, wxID_ANY, _(L("Load")) + " " + dots, "",
|
append_menu_item(sub_menu, wxID_ANY, _(L("Load")) + " " + dots, "",
|
||||||
[this, type](wxCommandEvent&) { load_subobject(type); }, "", menu);
|
[this, type](wxCommandEvent&) { load_subobject(type); }, "", menu);
|
||||||
sub_menu->AppendSeparator();
|
sub_menu->AppendSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }) {
|
for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") })
|
||||||
|
{
|
||||||
|
if (type == ModelVolumeType::INVALID && item == "Slab")
|
||||||
|
continue;
|
||||||
append_menu_item(sub_menu, wxID_ANY, _(item), "",
|
append_menu_item(sub_menu, wxID_ANY, _(item), "",
|
||||||
[this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu);
|
[this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu);
|
||||||
}
|
}
|
||||||
|
@ -1600,6 +1639,12 @@ void ObjectList::create_instance_popupmenu(wxMenu*menu)
|
||||||
}, m_menu_item_split_instances->GetId());
|
}, m_menu_item_split_instances->GetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectList::create_default_popupmenu(wxMenu*menu)
|
||||||
|
{
|
||||||
|
wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType::INVALID);
|
||||||
|
append_submenu(menu, sub_menu, wxID_ANY, _(L("Add Shape")), "", "add_part");
|
||||||
|
}
|
||||||
|
|
||||||
wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
|
wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
|
||||||
{
|
{
|
||||||
wxMenu *menu = new wxMenu;
|
wxMenu *menu = new wxMenu;
|
||||||
|
@ -1738,8 +1783,38 @@ void ObjectList::load_part( ModelObject* model_object,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TriangleMesh create_mesh(const std::string& type_name, const BoundingBoxf3& bb)
|
||||||
|
{
|
||||||
|
TriangleMesh mesh;
|
||||||
|
|
||||||
|
const double side = wxGetApp().plater()->canvas3D()->get_size_proportional_to_max_bed_size(0.1);
|
||||||
|
|
||||||
|
if (type_name == "Box")
|
||||||
|
// Sitting on the print bed, left front front corner at (0, 0).
|
||||||
|
mesh = make_cube(side, side, side);
|
||||||
|
else if (type_name == "Cylinder")
|
||||||
|
// Centered around 0, sitting on the print bed.
|
||||||
|
// The cylinder has the same volume as the box above.
|
||||||
|
mesh = make_cylinder(0.564 * side, side);
|
||||||
|
else if (type_name == "Sphere")
|
||||||
|
// Centered around 0, half the sphere below the print bed, half above.
|
||||||
|
// The sphere has the same volume as the box above.
|
||||||
|
mesh = make_sphere(0.62 * side, PI / 18);
|
||||||
|
else if (type_name == "Slab")
|
||||||
|
// Sitting on the print bed, left front front corner at (0, 0).
|
||||||
|
mesh = make_cube(bb.size().x() * 1.5, bb.size().y() * 1.5, bb.size().z() * 0.5);
|
||||||
|
mesh.repair();
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type)
|
void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type)
|
||||||
{
|
{
|
||||||
|
if (type == ModelVolumeType::INVALID) {
|
||||||
|
load_shape_object(type_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const int obj_idx = get_selected_obj_idx();
|
const int obj_idx = get_selected_obj_idx();
|
||||||
if (obj_idx < 0)
|
if (obj_idx < 0)
|
||||||
return;
|
return;
|
||||||
|
@ -1762,26 +1837,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
||||||
// Bounding box of the selected instance in world coordinate system including the translation, without modifiers.
|
// Bounding box of the selected instance in world coordinate system including the translation, without modifiers.
|
||||||
BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx);
|
BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx);
|
||||||
|
|
||||||
const wxString name = _(L("Generic")) + "-" + _(type_name);
|
TriangleMesh mesh = create_mesh(type_name, instance_bb);
|
||||||
TriangleMesh mesh;
|
|
||||||
|
|
||||||
double side = wxGetApp().plater()->canvas3D()->get_size_proportional_to_max_bed_size(0.1);
|
|
||||||
|
|
||||||
if (type_name == "Box")
|
|
||||||
// Sitting on the print bed, left front front corner at (0, 0).
|
|
||||||
mesh = make_cube(side, side, side);
|
|
||||||
else if (type_name == "Cylinder")
|
|
||||||
// Centered around 0, sitting on the print bed.
|
|
||||||
// The cylinder has the same volume as the box above.
|
|
||||||
mesh = make_cylinder(0.564 * side, side);
|
|
||||||
else if (type_name == "Sphere")
|
|
||||||
// Centered around 0, half the sphere below the print bed, half above.
|
|
||||||
// The sphere has the same volume as the box above.
|
|
||||||
mesh = make_sphere(0.62 * side, PI / 18);
|
|
||||||
else if (type_name == "Slab")
|
|
||||||
// Sitting on the print bed, left front front corner at (0, 0).
|
|
||||||
mesh = make_cube(instance_bb.size().x()*1.5, instance_bb.size().y()*1.5, instance_bb.size().z()*0.5);
|
|
||||||
mesh.repair();
|
|
||||||
|
|
||||||
// Mesh will be centered when loading.
|
// Mesh will be centered when loading.
|
||||||
ModelVolume *new_volume = model_object.add_volume(std::move(mesh));
|
ModelVolume *new_volume = model_object.add_volume(std::move(mesh));
|
||||||
|
@ -1803,6 +1859,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
||||||
new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
|
new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wxString name = _(L("Generic")) + "-" + _(type_name);
|
||||||
new_volume->name = into_u8(name);
|
new_volume->name = into_u8(name);
|
||||||
// set a default extruder value, since user can't add it manually
|
// set a default extruder value, since user can't add it manually
|
||||||
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||||
|
@ -1820,6 +1877,57 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
||||||
#endif //no __WXOSX__ //__WXMSW__
|
#endif //no __WXOSX__ //__WXMSW__
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectList::load_shape_object(const std::string& type_name)
|
||||||
|
{
|
||||||
|
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||||
|
assert(selection.get_object_idx() == -1); // Add nothing is something is selected on 3DScene
|
||||||
|
if (selection.get_object_idx() != -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int obj_idx = m_objects->size();
|
||||||
|
if (obj_idx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
take_snapshot(_(L("Add Shape")));
|
||||||
|
|
||||||
|
// Create mesh
|
||||||
|
BoundingBoxf3 bb;
|
||||||
|
TriangleMesh mesh = create_mesh(type_name, bb);
|
||||||
|
|
||||||
|
// Add mesh to model as a new object
|
||||||
|
Model& model = wxGetApp().plater()->model();
|
||||||
|
const wxString name = _(L("Shape")) + "-" + _(type_name);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
check_model_ids_validity(model);
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
|
||||||
|
std::vector<size_t> object_idxs;
|
||||||
|
ModelObject* new_object = model.add_object();
|
||||||
|
new_object->name = into_u8(name);
|
||||||
|
new_object->add_instance(); // each object should have at list one instance
|
||||||
|
|
||||||
|
ModelVolume* new_volume = new_object->add_volume(mesh);
|
||||||
|
new_volume->name = into_u8(name);
|
||||||
|
// set a default extruder value, since user can't add it manually
|
||||||
|
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||||
|
new_object->invalidate_bounding_box();
|
||||||
|
|
||||||
|
const BoundingBoxf bed_shape = wxGetApp().plater()->bed_shape_bb();
|
||||||
|
new_object->instances[0]->set_offset(Slic3r::to_3d(bed_shape.center().cast<double>(), -new_object->origin_translation(2)));
|
||||||
|
|
||||||
|
object_idxs.push_back(model.objects.size() - 1);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
check_model_ids_validity(model);
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
|
||||||
|
paste_objects_into_list(object_idxs);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
check_model_ids_validity(model);
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectList::del_object(const int obj_idx)
|
void ObjectList::del_object(const int obj_idx)
|
||||||
{
|
{
|
||||||
wxGetApp().plater()->delete_object_from_model(obj_idx);
|
wxGetApp().plater()->delete_object_from_model(obj_idx);
|
||||||
|
@ -3606,7 +3714,8 @@ void ObjectList::msw_rescale()
|
||||||
&m_menu_part,
|
&m_menu_part,
|
||||||
&m_menu_sla_object,
|
&m_menu_sla_object,
|
||||||
&m_menu_instance,
|
&m_menu_instance,
|
||||||
&m_menu_layer })
|
&m_menu_layer,
|
||||||
|
&m_menu_default})
|
||||||
msw_rescale_menu(menu);
|
msw_rescale_menu(menu);
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
|
|
|
@ -132,6 +132,7 @@ private:
|
||||||
MenuWithSeparators m_menu_sla_object;
|
MenuWithSeparators m_menu_sla_object;
|
||||||
MenuWithSeparators m_menu_instance;
|
MenuWithSeparators m_menu_instance;
|
||||||
MenuWithSeparators m_menu_layer;
|
MenuWithSeparators m_menu_layer;
|
||||||
|
MenuWithSeparators m_menu_default;
|
||||||
wxMenuItem* m_menu_item_settings { nullptr };
|
wxMenuItem* m_menu_item_settings { nullptr };
|
||||||
wxMenuItem* m_menu_item_split_instances { nullptr };
|
wxMenuItem* m_menu_item_split_instances { nullptr };
|
||||||
|
|
||||||
|
@ -208,7 +209,7 @@ public:
|
||||||
void set_tooltip_for_item(const wxPoint& pt);
|
void set_tooltip_for_item(const wxPoint& pt);
|
||||||
|
|
||||||
void selection_changed();
|
void selection_changed();
|
||||||
void show_context_menu();
|
void show_context_menu(const bool evt_context_menu);
|
||||||
#ifndef __WXOSX__
|
#ifndef __WXOSX__
|
||||||
void key_event(wxKeyEvent& event);
|
void key_event(wxKeyEvent& event);
|
||||||
#endif /* __WXOSX__ */
|
#endif /* __WXOSX__ */
|
||||||
|
@ -243,6 +244,7 @@ public:
|
||||||
void create_sla_object_popupmenu(wxMenu*menu);
|
void create_sla_object_popupmenu(wxMenu*menu);
|
||||||
void create_part_popupmenu(wxMenu*menu);
|
void create_part_popupmenu(wxMenu*menu);
|
||||||
void create_instance_popupmenu(wxMenu*menu);
|
void create_instance_popupmenu(wxMenu*menu);
|
||||||
|
void create_default_popupmenu(wxMenu *menu);
|
||||||
wxMenu* create_settings_popupmenu(wxMenu *parent_menu);
|
wxMenu* create_settings_popupmenu(wxMenu *parent_menu);
|
||||||
void create_freq_settings_popupmenu(wxMenu *parent_menu, const bool is_object_settings = true);
|
void create_freq_settings_popupmenu(wxMenu *parent_menu, const bool is_object_settings = true);
|
||||||
|
|
||||||
|
@ -251,6 +253,7 @@ public:
|
||||||
void load_subobject(ModelVolumeType type);
|
void load_subobject(ModelVolumeType type);
|
||||||
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
|
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
|
||||||
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
|
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
|
||||||
|
void load_shape_object(const std::string &type_name);
|
||||||
void del_object(const int obj_idx);
|
void del_object(const int obj_idx);
|
||||||
void del_subobject_item(wxDataViewItem& item);
|
void del_subobject_item(wxDataViewItem& item);
|
||||||
void del_settings_from_config(const wxDataViewItem& parent_item);
|
void del_settings_from_config(const wxDataViewItem& parent_item);
|
||||||
|
@ -365,7 +368,7 @@ private:
|
||||||
// void OnChar(wxKeyEvent& event);
|
// void OnChar(wxKeyEvent& event);
|
||||||
#endif /* __WXOSX__ */
|
#endif /* __WXOSX__ */
|
||||||
void OnContextMenu(wxDataViewEvent &event);
|
void OnContextMenu(wxDataViewEvent &event);
|
||||||
void list_manipulation();
|
void list_manipulation(bool evt_context_menu = false);
|
||||||
|
|
||||||
void OnBeginDrag(wxDataViewEvent &event);
|
void OnBeginDrag(wxDataViewEvent &event);
|
||||||
void OnDropPossible(wxDataViewEvent &event);
|
void OnDropPossible(wxDataViewEvent &event);
|
||||||
|
|
|
@ -1343,6 +1343,8 @@ struct Plater::priv
|
||||||
MenuWithSeparators part_menu;
|
MenuWithSeparators part_menu;
|
||||||
// SLA-Object popup menu
|
// SLA-Object popup menu
|
||||||
MenuWithSeparators sla_object_menu;
|
MenuWithSeparators sla_object_menu;
|
||||||
|
// Default popup menu (when nothing is selected on 3DScene)
|
||||||
|
MenuWithSeparators default_menu;
|
||||||
|
|
||||||
// Removed/Prepended Items according to the view mode
|
// Removed/Prepended Items according to the view mode
|
||||||
std::vector<wxMenuItem*> items_increase;
|
std::vector<wxMenuItem*> items_increase;
|
||||||
|
@ -1882,7 +1884,7 @@ struct Plater::priv
|
||||||
void on_action_layersediting(SimpleEvent&);
|
void on_action_layersediting(SimpleEvent&);
|
||||||
|
|
||||||
void on_object_select(SimpleEvent&);
|
void on_object_select(SimpleEvent&);
|
||||||
void on_right_click(Vec2dEvent&);
|
void on_right_click(RBtnEvent&);
|
||||||
void on_wipetower_moved(Vec3dEvent&);
|
void on_wipetower_moved(Vec3dEvent&);
|
||||||
void on_wipetower_rotated(Vec3dEvent&);
|
void on_wipetower_rotated(Vec3dEvent&);
|
||||||
void on_update_geometry(Vec3dsEvent<2>&);
|
void on_update_geometry(Vec3dsEvent<2>&);
|
||||||
|
@ -2530,6 +2532,10 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
|
||||||
if (output_file.empty())
|
if (output_file.empty())
|
||||||
// Find the file name of the first printable object.
|
// Find the file name of the first printable object.
|
||||||
output_file = this->model.propose_export_file_name_and_path();
|
output_file = this->model.propose_export_file_name_and_path();
|
||||||
|
|
||||||
|
if (output_file.empty() && !model.objects.empty())
|
||||||
|
// Find the file name of the first object.
|
||||||
|
output_file = this->model.objects[0]->get_export_filename();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString dlg_title;
|
wxString dlg_title;
|
||||||
|
@ -3562,57 +3568,66 @@ void Plater::priv::on_object_select(SimpleEvent& evt)
|
||||||
selection_changed();
|
selection_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_right_click(Vec2dEvent& evt)
|
void Plater::priv::on_right_click(RBtnEvent& evt)
|
||||||
{
|
{
|
||||||
int obj_idx = get_selected_object_idx();
|
int obj_idx = get_selected_object_idx();
|
||||||
|
|
||||||
|
wxMenu* menu = nullptr;
|
||||||
|
|
||||||
if (obj_idx == -1)
|
if (obj_idx == -1)
|
||||||
return;
|
menu = &default_menu;
|
||||||
|
else
|
||||||
wxMenu* menu = printer_technology == ptSLA ? &sla_object_menu :
|
|
||||||
get_selection().is_single_full_instance() ? // show "Object menu" for each FullInstance instead of FullObject
|
|
||||||
&object_menu : &part_menu;
|
|
||||||
|
|
||||||
sidebar->obj_list()->append_menu_item_settings(menu);
|
|
||||||
|
|
||||||
if (printer_technology != ptSLA)
|
|
||||||
sidebar->obj_list()->append_menu_item_change_extruder(menu);
|
|
||||||
|
|
||||||
if (menu != &part_menu)
|
|
||||||
{
|
{
|
||||||
/* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
|
// If in 3DScene is(are) selected volume(s), but right button was clicked on empty space
|
||||||
* Suppress to show those items for a Simple mode
|
if (evt.data.second)
|
||||||
*/
|
return;
|
||||||
const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF;
|
|
||||||
if (wxGetApp().get_mode() == comSimple) {
|
menu = printer_technology == ptSLA ? &sla_object_menu :
|
||||||
if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND)
|
get_selection().is_single_full_instance() ? // show "Object menu" for each FullInstance instead of FullObject
|
||||||
{
|
&object_menu : &part_menu;
|
||||||
/* Detach an items from the menu, but don't delete them
|
|
||||||
* so that they can be added back later
|
sidebar->obj_list()->append_menu_item_settings(menu);
|
||||||
* (after switching to the Advanced/Expert mode)
|
|
||||||
*/
|
if (printer_technology != ptSLA)
|
||||||
menu->Remove(items_increase[id]);
|
sidebar->obj_list()->append_menu_item_change_extruder(menu);
|
||||||
menu->Remove(items_decrease[id]);
|
|
||||||
menu->Remove(items_set_number_of_copies[id]);
|
if (menu != &part_menu)
|
||||||
|
{
|
||||||
|
/* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
|
||||||
|
* Suppress to show those items for a Simple mode
|
||||||
|
*/
|
||||||
|
const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF;
|
||||||
|
if (wxGetApp().get_mode() == comSimple) {
|
||||||
|
if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND)
|
||||||
|
{
|
||||||
|
/* Detach an items from the menu, but don't delete them
|
||||||
|
* so that they can be added back later
|
||||||
|
* (after switching to the Advanced/Expert mode)
|
||||||
|
*/
|
||||||
|
menu->Remove(items_increase[id]);
|
||||||
|
menu->Remove(items_decrease[id]);
|
||||||
|
menu->Remove(items_set_number_of_copies[id]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else {
|
if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND)
|
||||||
if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND)
|
{
|
||||||
{
|
// Prepend items to the menu, if those aren't not there
|
||||||
// Prepend items to the menu, if those aren't not there
|
menu->Prepend(items_set_number_of_copies[id]);
|
||||||
menu->Prepend(items_set_number_of_copies[id]);
|
menu->Prepend(items_decrease[id]);
|
||||||
menu->Prepend(items_decrease[id]);
|
menu->Prepend(items_increase[id]);
|
||||||
menu->Prepend(items_increase[id]);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q != nullptr) {
|
if (q != nullptr && menu) {
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// For some reason on Linux the menu isn't displayed if position is specified
|
// For some reason on Linux the menu isn't displayed if position is specified
|
||||||
// (even though the position is sane).
|
// (even though the position is sane).
|
||||||
q->PopupMenu(menu);
|
q->PopupMenu(menu);
|
||||||
#else
|
#else
|
||||||
q->PopupMenu(menu, (int)evt.data.x(), (int)evt.data.y());
|
q->PopupMenu(menu, (int)evt.data.first.x(), (int)evt.data.first.y());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3664,12 +3679,14 @@ bool Plater::priv::init_object_menu()
|
||||||
init_common_menu(&part_menu, true);
|
init_common_menu(&part_menu, true);
|
||||||
complit_init_part_menu();
|
complit_init_part_menu();
|
||||||
|
|
||||||
|
sidebar->obj_list()->create_default_popupmenu(&default_menu);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::msw_rescale_object_menu()
|
void Plater::priv::msw_rescale_object_menu()
|
||||||
{
|
{
|
||||||
for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu })
|
for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu, &default_menu })
|
||||||
msw_rescale_menu(dynamic_cast<wxMenu*>(menu));
|
msw_rescale_menu(dynamic_cast<wxMenu*>(menu));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4493,14 +4510,14 @@ void Plater::set_number_of_copies(/*size_t num*/)
|
||||||
|
|
||||||
ModelObject* model_object = p->model.objects[obj_idx];
|
ModelObject* model_object = p->model.objects[obj_idx];
|
||||||
|
|
||||||
const auto num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
|
const int num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
|
||||||
_("Copies of the selected object"), model_object->instances.size(), 0, 1000, this );
|
_("Copies of the selected object"), model_object->instances.size(), 0, 1000, this );
|
||||||
if (num < 0)
|
if (num < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num));
|
Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num));
|
||||||
|
|
||||||
int diff = (int)num - (int)model_object->instances.size();
|
int diff = num - (int)model_object->instances.size();
|
||||||
if (diff > 0)
|
if (diff > 0)
|
||||||
increase_instances(diff);
|
increase_instances(diff);
|
||||||
else if (diff < 0)
|
else if (diff < 0)
|
||||||
|
@ -5058,6 +5075,11 @@ GLCanvas3D* Plater::canvas3D()
|
||||||
return p->view3D->get_canvas3d();
|
return p->view3D->get_canvas3d();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BoundingBoxf Plater::bed_shape_bb() const
|
||||||
|
{
|
||||||
|
return p->bed_shape_bb();
|
||||||
|
}
|
||||||
|
|
||||||
PrinterTechnology Plater::printer_technology() const
|
PrinterTechnology Plater::printer_technology() const
|
||||||
{
|
{
|
||||||
return p->printer_technology;
|
return p->printer_technology;
|
||||||
|
|
|
@ -228,6 +228,7 @@ public:
|
||||||
int get_selected_object_idx();
|
int get_selected_object_idx();
|
||||||
bool is_single_full_object_selection() const;
|
bool is_single_full_object_selection() const;
|
||||||
GLCanvas3D* canvas3D();
|
GLCanvas3D* canvas3D();
|
||||||
|
BoundingBoxf bed_shape_bb() const;
|
||||||
|
|
||||||
PrinterTechnology printer_technology() const;
|
PrinterTechnology printer_technology() const;
|
||||||
void set_printer_technology(PrinterTechnology printer_technology);
|
void set_printer_technology(PrinterTechnology printer_technology);
|
||||||
|
|
|
@ -31,13 +31,11 @@
|
||||||
ExtrusionEntityCollection* flatten()
|
ExtrusionEntityCollection* flatten()
|
||||||
%code{%
|
%code{%
|
||||||
RETVAL = new ExtrusionEntityCollection();
|
RETVAL = new ExtrusionEntityCollection();
|
||||||
THIS->flatten(RETVAL);
|
*RETVAL = THIS->flatten();
|
||||||
%};
|
%};
|
||||||
double min_mm3_per_mm();
|
double min_mm3_per_mm();
|
||||||
bool empty()
|
bool empty()
|
||||||
%code{% RETVAL = THIS->entities.empty(); %};
|
%code{% RETVAL = THIS->entities.empty(); %};
|
||||||
std::vector<size_t> orig_indices()
|
|
||||||
%code{% RETVAL = THIS->orig_indices; %};
|
|
||||||
Polygons polygons_covered_by_width();
|
Polygons polygons_covered_by_width();
|
||||||
Polygons polygons_covered_by_spacing();
|
Polygons polygons_covered_by_spacing();
|
||||||
%{
|
%{
|
||||||
|
|
Loading…
Reference in a new issue