This commit is contained in:
bubnikv 2019-01-21 17:02:40 +01:00
commit 3366ce51e5
52 changed files with 67202 additions and 38567 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,32 +1,37 @@
xs/src/slic3r/GUI/AboutDialog.cpp
xs/src/slic3r/GUI/BedShapeDialog.cpp
xs/src/slic3r/GUI/BedShapeDialog.hpp
xs/src/slic3r/GUI/BonjourDialog.cpp
xs/src/slic3r/GUI/ButtonsDescription.cpp
xs/src/slic3r/GUI/ConfigSnapshotDialog.cpp
xs/src/slic3r/GUI/ConfigWizard.cpp
xs/src/slic3r/GUI/FirmwareDialog.cpp
xs/src/slic3r/GUI/GLCanvas3D.cpp
xs/src/slic3r/GUI/GUI.cpp
xs/src/slic3r/GUI/MsgDialog.cpp
xs/src/slic3r/GUI/Tab.cpp
xs/src/slic3r/GUI/Tab.hpp
xs/src/slic3r/GUI/Field.cpp
xs/src/slic3r/GUI/OptionsGroup.cpp
xs/src/slic3r/GUI/Preset.cpp
xs/src/slic3r/GUI/PresetBundle.cpp
xs/src/slic3r/GUI/PresetHints.cpp
xs/src/slic3r/GUI/Preferences.cpp
xs/src/slic3r/GUI/RammingChart.cpp
xs/src/slic3r/GUI/UpdateDialogs.cpp
xs/src/slic3r/GUI/WipeTowerDialog.cpp
xs/src/slic3r/Utils/OctoPrint.cpp
xs/src/slic3r/Utils/PresetUpdater.cpp
xs/src/libslic3r/Print.cpp
xs/src/libslic3r/PrintConfig.cpp
xs/src/libslic3r/GCode/PreviewData.cpp
lib/Slic3r/GUI.pm
lib/Slic3r/GUI/MainFrame.pm
lib/Slic3r/GUI/Plater.pm
lib/Slic3r/GUI/Plater/2D.pm
lib/Slic3r/GUI/Plater/3DPreview.pm
src/slic3r/GUI/AboutDialog.cpp
src/slic3r/GUI/BedShapeDialog.cpp
src/slic3r/GUI/BedShapeDialog.hpp
src/slic3r/GUI/BonjourDialog.cpp
src/slic3r/GUI/ButtonsDescription.cpp
src/slic3r/GUI/ConfigSnapshotDialog.cpp
src/slic3r/GUI/ConfigWizard.cpp
src/slic3r/GUI/Field.cpp
src/slic3r/GUI/FirmwareDialog.cpp
src/slic3r/GUI/GLCanvas3D.cpp
src/slic3r/GUI/GLGizmo.cpp
src/slic3r/GUI/GUI.cpp
src/slic3r/GUI/GUI_App.cpp
src/slic3r/GUI/GUI_ObjectList.cpp
src/slic3r/GUI/GUI_ObjectManipulation.cpp
src/slic3r/GUI/GUI_Preview.cpp
src/slic3r/GUI/KBShortcutsDialog.cpp
src/slic3r/GUI/MainFrame.cpp
src/slic3r/GUI/MsgDialog.cpp
src/slic3r/GUI/Plater.cpp
src/slic3r/GUI/Preferences.cpp
src/slic3r/GUI/Preset.cpp
src/slic3r/GUI/PresetBundle.cpp
src/slic3r/GUI/PresetHints.cpp
src/slic3r/GUI/PrintHostDialogs.cpp
src/slic3r/GUI/RammingChart.cpp
src/slic3r/GUI/SysInfoDialog.cpp
src/slic3r/GUI/Tab.cpp
src/slic3r/GUI/Tab.hpp
src/slic3r/GUI/UpdateDialogs.cpp
src/slic3r/GUI/WipeTowerDialog.cpp
src/slic3r/Utils/OctoPrint.cpp
src/slic3r/Utils/PresetUpdater.cpp
src/slic3r/Utils/FixModelByWin10.cpp
src/libslic3r/Print.cpp
src/libslic3r/PrintConfig.cpp
src/libslic3r/GCode/PreviewData.cpp

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -38,6 +38,7 @@ struct FillParams
// in this case we don't try to make more continuous paths
bool complete;
};
static_assert(std::is_trivially_copyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
class Fill
{

View file

@ -1589,9 +1589,11 @@ void GCode::process_layer(
auto objects_by_extruder_it = by_extruder.find(extruder_id);
if (objects_by_extruder_it == by_extruder.end())
continue;
// We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature):
for (int print_wipe_extrusions=const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden(); print_wipe_extrusions>=0; --print_wipe_extrusions) {
if (print_wipe_extrusions == 0)
bool is_anything_overridden = const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden();
for (int print_wipe_extrusions = is_anything_overridden; print_wipe_extrusions>=0; --print_wipe_extrusions) {
if (is_anything_overridden && print_wipe_extrusions == 0)
gcode+="; PURGING FINISHED\n";
for (ObjectByExtruder &object_by_extruder : objects_by_extruder_it->second) {
@ -1628,7 +1630,7 @@ void GCode::process_layer(
m_layer = layers[layer_id].layer();
}
for (ObjectByExtruder::Island &island : object_by_extruder.islands) {
const auto& by_region_specific = const_cast<LayerTools&>(layer_tools).wiping_extrusions().is_anything_overridden() ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region;
const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(copy_id, extruder_id, print_wipe_extrusions) : island.by_region;
if (print.config().infill_first) {
gcode += this->extrude_infill(print, by_region_specific);

View file

@ -315,6 +315,9 @@ public:
// Extruder ID is only valid for FFF. Returns -1 for SLA or if the extruder ID is not applicable (support volumes).
int extruder_id() const;
void set_splittable(const int val) { m_is_splittable = val; }
int is_splittable() const { return m_is_splittable; }
// Split this volume, append the result to the object owning this volume.
// Return the number of volumes created from this one.
// This is useful to assign different materials to different volumes of an object.
@ -387,6 +390,12 @@ private:
TriangleMesh m_convex_hull;
Geometry::Transformation m_transformation;
// flag to optimize the checking if the volume is splittable
// -1 -> is unknown value (before first cheking)
// 0 -> is not splittable
// 1 -> is splittable
int m_is_splittable {-1};
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object)
{
if (mesh.stl.stats.number_of_facets > 1)

View file

@ -15,6 +15,7 @@ namespace arr {
using namespace libnest2d;
// Only for debugging. Prints the model object vertices on stdout.
std::string toString(const Model& model, bool holes = true) {
std::stringstream ss;
@ -78,6 +79,7 @@ std::string toString(const Model& model, bool holes = true) {
return ss.str();
}
// Debugging: Save model to svg file.
void toSVG(SVG& svg, const Model& model) {
for(auto objptr : model.objects) {
if(!objptr) continue;
@ -121,6 +123,10 @@ Box boundingBox(const Box& pilebb, const Box& ibb ) {
return Box(minc, maxc);
}
// This is "the" object function which is evaluated many times for each vertex
// (decimated with the accuracy parameter) of each object. Therefore it is
// upmost crucial for this function to be as efficient as it possibly can be but
// at the same time, it has to provide reasonable results.
std::tuple<double /*score*/, Box /*farthest point from bin center*/>
objfunc(const PointImpl& bincenter,
const shapelike::Shapes<PolygonImpl>& merged_pile,
@ -253,6 +259,8 @@ objfunc(const PointImpl& bincenter,
return std::make_tuple(score, fullbb);
}
// Fill in the placer algorithm configuration with values carefully chosen for
// Slic3r.
template<class PConf>
void fillConfig(PConf& pcfg) {
@ -274,13 +282,19 @@ void fillConfig(PConf& pcfg) {
pcfg.parallel = true;
}
// Type trait for an arranger class for different bin types (box, circle,
// polygon, etc...)
template<class TBin>
class AutoArranger {};
// A class encapsulating the libnest2d Nester class and extending it with other
// management and spatial index structures for acceleration.
template<class TBin>
class _ArrBase {
protected:
// Useful type shortcuts...
using Placer = TPacker<TBin>;
using Selector = FirstFitSelection;
using Packer = Nester<Placer, Selector>;
@ -289,15 +303,15 @@ protected:
using Pile = sl::Shapes<PolygonImpl>;
Packer m_pck;
PConfig m_pconf; // Placement configuration
PConfig m_pconf; // Placement configuration
double m_bin_area;
SpatIndex m_rtree;
SpatIndex m_smallsrtree;
double m_norm;
Pile m_merged_pile;
Box m_pilebb;
ItemGroup m_remaining;
ItemGroup m_items;
SpatIndex m_rtree; // spatial index for the normal (bigger) objects
SpatIndex m_smallsrtree; // spatial index for only the smaller items
double m_norm; // A coefficient to scale distances
Pile m_merged_pile; // The already merged pile (vector of items)
Box m_pilebb; // The bounding box of the merged pile.
ItemGroup m_remaining; // Remaining items (m_items at the beginning)
ItemGroup m_items; // The items to be packed
public:
_ArrBase(const TBin& bin, Distance dist,
@ -308,6 +322,8 @@ public:
{
fillConfig(m_pconf);
// Set up a callback that is called just before arranging starts
// This functionality is provided by the Nester class (m_pack).
m_pconf.before_packing =
[this](const Pile& merged_pile, // merged pile
const ItemGroup& items, // packed items
@ -344,8 +360,8 @@ public:
}
};
template<>
class AutoArranger<Box>: public _ArrBase<Box> {
// Arranger specialization for a Box shaped bin.
template<> class AutoArranger<Box>: public _ArrBase<Box> {
public:
AutoArranger(const Box& bin, Distance dist,
@ -354,6 +370,9 @@ public:
_ArrBase<Box>(bin, dist, progressind, stopcond)
{
// Here we set up the actual object function that calls the common
// object function for all bin shapes than does an additional inside
// check for the arranged pile.
m_pconf.object_function = [this, bin] (const Item &item) {
auto result = objfunc(bin.center(),
@ -387,8 +406,8 @@ inline lnCircle to_lnCircle(const Circle& circ) {
return lnCircle({circ.center()(0), circ.center()(1)}, circ.radius());
}
template<>
class AutoArranger<lnCircle>: public _ArrBase<lnCircle> {
// Arranger specialization for circle shaped bin.
template<> class AutoArranger<lnCircle>: public _ArrBase<lnCircle> {
public:
AutoArranger(const lnCircle& bin, Distance dist,
@ -396,6 +415,7 @@ public:
std::function<bool(void)> stopcond):
_ArrBase<lnCircle>(bin, dist, progressind, stopcond) {
// As with the box, only the inside check is different.
m_pconf.object_function = [this, &bin] (const Item &item) {
auto result = objfunc(bin.center(),
@ -431,8 +451,9 @@ public:
}
};
template<>
class AutoArranger<PolygonImpl>: public _ArrBase<PolygonImpl> {
// Arranger specialization for a generalized polygon.
// Warning: this is unfinished business. It may or may not work.
template<> class AutoArranger<PolygonImpl>: public _ArrBase<PolygonImpl> {
public:
AutoArranger(const PolygonImpl& bin, Distance dist,
std::function<void(unsigned)> progressind,
@ -461,8 +482,10 @@ public:
}
};
template<> // Specialization with no bin
class AutoArranger<bool>: public _ArrBase<Box> {
// Specialization with no bin. In this case the arranger should just arrange
// all objects into a minimum sized pile but it is not limited by a bin. A
// consequence is that only one pile should be created.
template<> class AutoArranger<bool>: public _ArrBase<Box> {
public:
AutoArranger(Distance dist, std::function<void(unsigned)> progressind,
@ -490,14 +513,15 @@ public:
// A container which stores a pointer to the 3D object and its projected
// 2D shape from top view.
using ShapeData2D =
std::vector<std::pair<Slic3r::ModelInstance*, Item>>;
using ShapeData2D = std::vector<std::pair<Slic3r::ModelInstance*, Item>>;
ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
ShapeData2D ret;
auto s = std::accumulate(model.objects.begin(), model.objects.end(), size_t(0),
[](size_t s, ModelObject* o){
// Count all the items on the bin (all the object's instances)
auto s = std::accumulate(model.objects.begin(), model.objects.end(),
size_t(0), [](size_t s, ModelObject* o)
{
return s + o->instances.size();
});
@ -517,7 +541,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
rmesh.rotate_x(float(finst->get_rotation()(X)));
rmesh.rotate_y(float(finst->get_rotation()(Y)));
// TODO export the exact 2D projection
// TODO export the exact 2D projection. Cannot do it as libnest2d
// does not support concave shapes (yet).
auto p = rmesh.convex_hull();
p.make_clockwise();
@ -549,6 +574,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
return ret;
}
// Apply the calculated translations and rotations (currently disabled) to the
// Model object instances.
void applyResult(
IndexedPackGroup::value_type& group,
Coord batch_offset,
@ -576,6 +603,7 @@ void applyResult(
}
}
// Get the type of bed geometry from a simple vector of points.
BedShapeHint bedShape(const Polyline &bed) {
BedShapeHint ret;
@ -654,11 +682,15 @@ BedShapeHint bedShape(const Polyline &bed) {
return ret;
}
bool arrange(Model &model,
coord_t min_obj_distance,
const Polyline &bed,
BedShapeHint bedhint,
bool first_bin_only,
// The final client function to arrange the Model. A progress indicator and
// a stop predicate can be also be passed to control the process.
bool arrange(Model &model, // The model with the geometries
coord_t min_obj_distance, // Has to be in scaled (clipper) measure
const Polyline &bed, // The bed geometry.
BedShapeHint bedhint, // Hint about the bed geometry type.
bool first_bin_only, // What to do is not all items fit.
// Controlling callbacks.
std::function<void (unsigned)> progressind,
std::function<bool ()> stopcondition)
{

View file

@ -2487,7 +2487,6 @@ void PrintConfigDef::init_sla_params()
def->label = L("Generate supports");
def->category = L("Supports");
def->tooltip = L("Generate supports for the models");
def->sidetext = L("");
def->cli = "";
def->default_value = new ConfigOptionBool(true);
@ -2549,7 +2548,6 @@ void PrintConfigDef::init_sla_params()
def->tooltip = L("Merging bridges or pillars into another pillars can "
"increase the radius. Zero means no increase, one means "
"full increase.");
def->sidetext = L("");
def->cli = "";
def->min = 0;
def->max = 1;
@ -2631,14 +2629,13 @@ void PrintConfigDef::init_sla_params()
def->label = L("Use pad");
def->category = L("Pad");
def->tooltip = L("Add a pad underneath the supported model");
def->sidetext = L("");
def->cli = "";
def->default_value = new ConfigOptionBool(true);
def = this->add("pad_wall_thickness", coFloat);
def->label = L("Pad wall thickness");
def->category = L("Pad");
def->tooltip = L("");
// def->tooltip = L("");
def->sidetext = L("mm");
def->cli = "";
def->min = 0;
@ -2647,7 +2644,7 @@ void PrintConfigDef::init_sla_params()
def = this->add("pad_wall_height", coFloat);
def->label = L("Pad wall height");
def->category = L("Pad");
def->tooltip = L("");
// def->tooltip = L("");
def->sidetext = L("mm");
def->cli = "";
def->min = 0;
@ -2656,7 +2653,7 @@ void PrintConfigDef::init_sla_params()
def = this->add("pad_max_merge_distance", coFloat);
def->label = L("Max merge distance");
def->category = L("Pad");
def->tooltip = L("");
// def->tooltip = L("");
def->sidetext = L("mm");
def->cli = "";
def->min = 0;
@ -2665,7 +2662,7 @@ void PrintConfigDef::init_sla_params()
def = this->add("pad_edge_radius", coFloat);
def->label = L("Pad edge radius");
def->category = L("Pad");
def->tooltip = L("");
// def->tooltip = L("");
def->sidetext = L("mm");
def->cli = "";
def->min = 0;

View file

@ -6,6 +6,7 @@
#include <set>
#include <vector>
#include <map>
#include <cstring>
#include "libslic3r.h"
namespace Slic3r
@ -91,6 +92,8 @@ struct SlicingParameters
coordf_t object_print_z_min;
coordf_t object_print_z_max;
};
static_assert(std::is_trivially_copyable<SlicingParameters>::value, "SlicingParameters class is not POD (and it should be - see constructor).");
// The two slicing parameters lead to the same layering as long as the variable layer thickness is not in action.
inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters &sp2)

View file

@ -115,7 +115,7 @@ AboutDialog::AboutDialog()
vsizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
// this->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this);
logo->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this);
// logo->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);

View file

@ -89,8 +89,8 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, cons
bool default_variant = true; // Mark the first variant as default in the GUI
for (const auto &variant : model.variants) {
const auto label = wxString::Format("%s %s %s %s", variant.name, _(L("mm")), _(L("nozzle")),
(default_variant ? _(L("(default)")) : wxString()));
const auto label = wxString::Format("%s %s %s %s", variant.name, _(L("mm")), _(L("nozzle")),
(default_variant ? "(" + _(L("default")) + ")" : wxString()));
default_variant = false;
auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name);
const size_t idx = cboxes.size();
@ -803,7 +803,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
// Public
ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) :
wxDialog(parent, wxID_ANY, name(), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
wxDialog(parent, wxID_ANY, _(name().ToStdString()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
p(new priv(this))
{
p->run_reason = reason;
@ -899,15 +899,17 @@ bool ConfigWizard::run(PresetBundle *preset_bundle, const PresetUpdater *updater
}
const wxString& ConfigWizard::name()
const wxString& ConfigWizard::name(const bool from_menu/* = false*/)
{
// A different naming convention is used for the Wizard on Windows vs. OSX & GTK.
#if WIN32
static const wxString config_wizard_name = L("Configuration Wizard");
static const wxString config_wizard_name = L("Configuration Wizard");
static const wxString config_wizard_name_menu = L("Configuration &Wizard");
#else
static const wxString config_wizard_name = L("Configuration Assistant");
static const wxString config_wizard_name = L("Configuration Assistant");
static const wxString config_wizard_name_menu = L("Configuration &Assistant");
#endif
return config_wizard_name;
return from_menu ? config_wizard_name_menu : config_wizard_name;
}
}

View file

@ -34,7 +34,7 @@ public:
// Run the Wizard. Return whether it was completed.
bool run(PresetBundle *preset_bundle, const PresetUpdater *updater);
static const wxString& name();
static const wxString& name(const bool from_menu = false);
private:
struct priv;
std::unique_ptr<priv> p;

View file

@ -1049,10 +1049,6 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
::glBindTexture(GL_TEXTURE_2D, m_z_texture_id);
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data());
::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4);
// Render the color bar
float l = bar_rect.get_left();
@ -1061,6 +1057,7 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
float b = bar_rect.get_bottom();
::glBegin(GL_QUADS);
::glNormal3f(0.0f, 0.0f, 1.0f);
::glVertex3f(l, b, 0.0f);
::glVertex3f(r, b, 0.0f);
::glVertex3f(r, t, m_object_max_z);
@ -1770,11 +1767,14 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal)
for (unsigned int i : m_list)
{
Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_volume_scale_matrix();
Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix();
Vec3d scaling_factor = Vec3d(1./wst(0,0), 1./wst(1,1), 1./wst(2,2));
Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_volume_rotation_matrix());
Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor) * normal;
Transform3d wmt = m_cache.volumes_data[i].get_instance_mirror_matrix();
Vec3d mirror(wmt(0,0), wmt(1,1), wmt(2,2));
Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix());
Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor, mirror) * normal;
transformed_normal.normalize();
Vec3d axis = transformed_normal(2) > 0.999f ? Vec3d(1., 0., 0.) : Vec3d(transformed_normal.cross(Vec3d(0., 0., -1.)));

View file

@ -1526,10 +1526,9 @@ void GLGizmoFlatten::update_planes()
vol_ch.transform(vol->get_matrix());
ch.merge(vol_ch);
}
ch = ch.convex_hull_3d();
m_planes.clear();
const Transform3d& inst_matrix = m_model_object->instances.front()->get_matrix();
const Transform3d& inst_matrix = m_model_object->instances.front()->get_matrix(true);
// Following constants are used for discarding too small polygons.
const float minimal_area = 5.f; // in square mm (world coordinates)
@ -1696,10 +1695,6 @@ void GLGizmoFlatten::update_planes()
// Transform back to 3D (and also back to mesh coordinates)
polygon = transform(polygon, inst_matrix.inverse() * m.inverse());
// make sure the points are in correct order:
if ( ((inst_matrix.inverse() * m.inverse()) * Vec3d(0., 0., 1.)).dot(normal) > 0.)
std::reverse(polygon.begin(),polygon.end());
}
// We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations):
@ -1714,6 +1709,7 @@ void GLGizmoFlatten::update_planes()
m_volumes_types.push_back(vol->type());
}
m_first_instance_scale = m_model_object->instances.front()->get_scaling_factor();
m_first_instance_mirror = m_model_object->instances.front()->get_mirror();
}
@ -1726,7 +1722,8 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
return true;
// We want to recalculate when the scale changes - some planes could (dis)appear.
if (! m_model_object->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale))
if (! m_model_object->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale)
|| ! m_model_object->instances.front()->get_mirror().isApprox(m_first_instance_mirror))
return true;
for (unsigned int i=0; i < m_model_object->volumes.size(); ++i)

View file

@ -405,6 +405,7 @@ private:
std::vector<Transform3d> m_volumes_matrices;
std::vector<ModelVolume::Type> m_volumes_types;
Vec3d m_first_instance_scale;
Vec3d m_first_instance_mirror;
std::vector<PlaneData> m_planes;
mutable Vec3d m_starting_center;

View file

@ -348,50 +348,6 @@ bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height
return true;
}
void save_window_size(wxTopLevelWindow *window, const std::string &name)
{
const wxSize size = window->GetSize();
const wxPoint pos = window->GetPosition();
const auto maximized = window->IsMaximized() ? "1" : "0";
get_app_config()->set((boost::format("window_%1%_size") % name).str(), (boost::format("%1%;%2%") % size.GetWidth() % size.GetHeight()).str());
get_app_config()->set((boost::format("window_%1%_maximized") % name).str(), maximized);
}
void restore_window_size(wxTopLevelWindow *window, const std::string &name)
{
// XXX: This still doesn't behave nicely in some situations (mostly on Linux).
// The problem is that it's hard to obtain window position with respect to screen geometry reliably
// from wxWidgets. Sometimes wxWidgets claim a window is located on a different screen than on which
// it's actually visible. I suspect this has something to do with window initialization (maybe we
// restore window geometry too early), but haven't yet found a workaround.
const auto display_idx = wxDisplay::GetFromWindow(window);
if (display_idx == wxNOT_FOUND) { return; }
const auto display = wxDisplay(display_idx).GetClientArea();
std::vector<std::string> pair;
try {
const auto key_size = (boost::format("window_%1%_size") % name).str();
if (get_app_config()->has(key_size)) {
if (unescape_strings_cstyle(get_app_config()->get(key_size), pair) && pair.size() == 2) {
auto width = boost::lexical_cast<int>(pair[0]);
auto height = boost::lexical_cast<int>(pair[1]);
window->SetSize(width, height);
}
}
} catch(const boost::bad_lexical_cast &) {}
// Maximizing should be the last thing to do.
// This ensure the size and position are sane when the user un-maximizes the window.
const auto key_maximized = (boost::format("window_%1%_maximized") % name).str();
if (get_app_config()->get(key_maximized) == "1") {
window->Maximize(true);
}
}
void about()
{
AboutDialog dlg;

View file

@ -70,11 +70,6 @@ boost::filesystem::path into_path(const wxString &str);
// Returns the dimensions of the screen on which the main frame is displayed
bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height);
// Save window size and maximized status into AppConfig
void save_window_size(wxTopLevelWindow *window, const std::string &name);
// Restore the above
void restore_window_size(wxTopLevelWindow *window, const std::string &name);
// Display an About dialog
extern void about();
// Ask the destop to open the datadir using the default file explorer.

View file

@ -143,7 +143,6 @@ bool GUI_App::OnInit()
init_fonts();
// application frame
std::cerr << "Creating main frame..." << std::endl;
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler());
mainframe = new MainFrame();
@ -165,27 +164,8 @@ bool GUI_App::OnInit()
// to correct later layouts
});
// This makes CallAfter() work
Bind(wxEVT_IDLE, [this](wxIdleEvent& event)
{
std::function<void()> cur_cb{ nullptr };
// try to get the mutex. If we can't, just skip this idle event and get the next one.
if (!callback_register.try_lock()) return;
// pop callback
if (m_cb.size() != 0) {
cur_cb = m_cb.top();
m_cb.pop();
}
// unlock mutex
this->callback_register.unlock();
try { // call the function if it's not nullptr;
if (cur_cb != nullptr) cur_cb();
}
catch (std::exception& e) {
std::cerr << "Exception thrown: " << e.what() << std::endl;
}
if (app_config->dirty())
app_config->save();
@ -370,6 +350,33 @@ void GUI_App::update_ui_from_settings()
mainframe->update_ui_from_settings();
}
void GUI_App::persist_window_geometry(wxTopLevelWindow *window)
{
const std::string name = into_u8(window->GetName());
window->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent &event) {
window_pos_save(window, name);
event.Skip();
});
window_pos_restore(window, name);
#ifdef _WIN32
// On windows, the wxEVT_SHOW is not received if the window is created maximized
// cf. https://groups.google.com/forum/#!topic/wx-users/c7ntMt6piRI
// so we sanitize the position right away
window_pos_sanitize(window);
#else
// On other platforms on the other hand it's needed to wait before the window is actually on screen
// and some initial round of events is complete otherwise position / display index is not reported correctly.
window->Bind(wxEVT_SHOW, [=](wxShowEvent &event) {
CallAfter([=]() {
window_pos_sanitize(window);
});
event.Skip();
});
#endif
}
void GUI_App::load_project(wxWindow *parent, wxString& input_file)
{
input_file.Clear();
@ -394,55 +401,6 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files)
dialog.GetPaths(input_files);
}
void GUI_App::CallAfter(std::function<void()> cb)
{
// set mutex
callback_register.lock();
// push function onto stack
m_cb.emplace(cb);
// unset mutex
callback_register.unlock();
}
void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name)
{
if (name.empty()) { return; }
const auto config_key = (boost::format("window_%1%") % name).str();
WindowMetrics metrics = WindowMetrics::from_window(window);
app_config->set(config_key, metrics.serialize());
app_config->save();
}
void GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &name)
{
if (name.empty()) { return; }
const auto config_key = (boost::format("window_%1%") % name).str();
if (! app_config->has(config_key)) { return; }
auto metrics = WindowMetrics::deserialize(app_config->get(config_key));
if (! metrics) { return; }
window->SetSize(metrics->get_rect());
window->Maximize(metrics->get_maximized());
}
void GUI_App::window_pos_sanitize(wxTopLevelWindow* window)
{
const auto display_idx = wxDisplay::GetFromWindow(window);
if (display_idx == wxNOT_FOUND) { return; }
const auto display = wxDisplay(display_idx).GetClientArea();
auto metrics = WindowMetrics::from_window(window);
metrics.sanitize_for_display(display);
if (window->GetScreenRect() != metrics.get_rect()) {
window->SetSize(metrics.get_rect());
}
}
// select language from the list of installed languages
bool GUI_App::select_language( wxArrayString & names,
wxArrayLong & identifiers)
@ -602,15 +560,15 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
auto local_menu = new wxMenu();
wxWindowID config_id_base = wxWindow::NewControlId((int)ConfigMenuCnt);
const auto config_wizard_name = _(ConfigWizard::name().wx_str());
const auto config_wizard_name = _(ConfigWizard::name(true).wx_str());
const auto config_wizard_tooltip = wxString::Format(_(L("Run %s")), config_wizard_name);
// Cmd+, is standard on OS X - what about other operating systems?
local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip);
local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("Configuration Snapshots")) + dots, _(L("Inspect / activate configuration snapshots")));
local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _(L("Take Configuration Snapshot")), _(L("Capture a configuration snapshot")));
local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("&Configuration Snapshots")) + dots, _(L("Inspect / activate configuration snapshots")));
local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _(L("Take Configuration &Snapshot")), _(L("Capture a configuration snapshot")));
// local_menu->Append(config_id_base + ConfigMenuUpdate, _(L("Check for updates")), _(L("Check for configuration updates")));
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("Preferences")) + dots + "\tCtrl+P", _(L("Application preferences")));
local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("&Preferences")) + dots + "\tCtrl+P", _(L("Application preferences")));
local_menu->AppendSeparator();
auto mode_menu = new wxMenu();
mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple, _(L("Simple")), _(L("Simple View Mode")));
@ -619,9 +577,9 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
mode_menu->Check(config_id_base + ConfigMenuModeSimple + get_mode(), true);
local_menu->AppendSubMenu(mode_menu, _(L("Mode")), _(L("Slic3r View Mode")));
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application Language")));
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application &Language")));
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _(L("Flash printer firmware")), _(L("Upload a firmware image into an Arduino based printer")));
local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _(L("Flash printer &firmware")), _(L("Upload a firmware image into an Arduino based printer")));
// TODO: for when we're able to flash dictionaries
// local_menu->Append(config_id_base + FirmwareMenuDict, _(L("Flash language file")), _(L("Upload a language dictionary file into a Prusa printer")));
@ -789,6 +747,48 @@ wxNotebook* GUI_App::tab_panel() const
return mainframe->m_tabpanel;
}
void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name)
{
if (name.empty()) { return; }
const auto config_key = (boost::format("window_%1%") % name).str();
WindowMetrics metrics = WindowMetrics::from_window(window);
app_config->set(config_key, metrics.serialize());
app_config->save();
}
void GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &name)
{
if (name.empty()) { return; }
const auto config_key = (boost::format("window_%1%") % name).str();
if (! app_config->has(config_key)) { return; }
auto metrics = WindowMetrics::deserialize(app_config->get(config_key));
if (! metrics) { return; }
window->SetSize(metrics->get_rect());
window->Maximize(metrics->get_maximized());
}
void GUI_App::window_pos_sanitize(wxTopLevelWindow* window)
{
unsigned display_idx = wxDisplay::GetFromWindow(window);
wxRect display;
if (display_idx == wxNOT_FOUND) {
display = wxDisplay(0u).GetClientArea();
window->Move(display.GetTopLeft());
} else {
display = wxDisplay(display_idx).GetClientArea();
}
auto metrics = WindowMetrics::from_window(window);
metrics.sanitize_for_display(display);
if (window->GetScreenRect() != metrics.get_rect()) {
window->SetSize(metrics.get_rect());
}
}
// static method accepting a wxWindow object as first parameter
// void warning_catcher{
// my($self, $message_dialog) = @_;

View file

@ -73,11 +73,6 @@ class GUI_App : public wxApp
{
bool app_conf_exists{ false };
// Lock to guard the callback stack
std::mutex callback_register;
// callbacks registered to run during idle event.
std::stack<std::function<void()>> m_cb{};
wxColour m_color_label_modified;
wxColour m_color_label_sys;
wxColour m_color_label_default;
@ -121,12 +116,9 @@ public:
// wxMessageDialog* message_dialog,
const std::string& err);
// void notify(/*message*/);
void update_ui_from_settings();
void CallAfter(std::function<void()> cb);
void window_pos_save(wxTopLevelWindow* window, const std::string &name);
void window_pos_restore(wxTopLevelWindow* window, const std::string &name);
void window_pos_sanitize(wxTopLevelWindow* window);
void persist_window_geometry(wxTopLevelWindow *window);
void update_ui_from_settings();
bool select_language(wxArrayString & names, wxArrayLong & identifiers);
bool load_language();
@ -172,6 +164,10 @@ public:
PrintHostJobQueue& printhost_job_queue() { return *m_printhost_job_queue.get(); }
private:
void window_pos_save(wxTopLevelWindow* window, const std::string &name);
void window_pos_restore(wxTopLevelWindow* window, const std::string &name);
void window_pos_sanitize(wxTopLevelWindow* window);
};
DECLARE_APP(GUI_App)

View file

@ -1105,10 +1105,14 @@ bool ObjectList::is_splittable()
if (!get_volume_by_item(item, volume) || !volume)
return false;
if (volume->is_splittable() != -1) // if is_splittable value is already known
return volume->is_splittable() == 0 ? false : true;
TriangleMeshPtrs meshptrs = volume->mesh.split();
bool splittable = meshptrs.size() > 1;
for (TriangleMesh* m : meshptrs) { delete m; }
volume->set_splittable(splittable ? 1 : 0);
return splittable;
}

View file

@ -249,9 +249,9 @@ void ObjectManipulation::UpdateAndShow(const bool show)
void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection)
{
m_new_move_label_string = L("Position:");
m_new_rotate_label_string = L("Rotation:");
m_new_scale_label_string = L("Scale factors:");
m_new_move_label_string = L("Position");
m_new_rotate_label_string = L("Rotation");
m_new_scale_label_string = L("Scale factors");
if (selection.is_single_full_instance())
{
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
@ -297,8 +297,8 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
m_new_rotation = Vec3d::Zero();
m_new_scale = Vec3d(1.0, 1.0, 1.0);
m_new_size = box.size();
m_new_rotate_label_string = L("Rotate:");
m_new_scale_label_string = L("Scale:");
m_new_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale");
m_new_enabled = true;
}
else if (selection.is_single_modifier() || selection.is_single_volume())
@ -318,9 +318,9 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
else if (wxGetApp().obj_list()->multiple_selection())
{
reset_settings_value();
m_new_move_label_string = L("Translate:");
m_new_rotate_label_string = L("Rotate:");
m_new_scale_label_string = L("Scale:");
m_new_move_label_string = L("Translate");
m_new_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale");
m_new_size = selection.get_bounding_box().size();
m_new_enabled = true;
}
@ -337,21 +337,21 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
void ObjectManipulation::update_if_dirty()
{
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
if (m_cache.move_label_string != _(m_new_move_label_string))
if (m_cache.move_label_string != _(m_new_move_label_string)+ ":")
{
m_cache.move_label_string = _(m_new_move_label_string);
m_cache.move_label_string = _(m_new_move_label_string)+ ":";
m_move_Label->SetLabel(m_cache.move_label_string);
}
if (m_cache.rotate_label_string != _(m_new_rotate_label_string))
if (m_cache.rotate_label_string != _(m_new_rotate_label_string)+ ":")
{
m_cache.rotate_label_string = _(m_new_rotate_label_string);
m_cache.rotate_label_string = _(m_new_rotate_label_string)+ ":";
m_rotate_Label->SetLabel(m_cache.rotate_label_string);
}
if (m_cache.scale_label_string != _(m_new_scale_label_string))
if (m_cache.scale_label_string != _(m_new_scale_label_string)+ ":")
{
m_cache.scale_label_string = _(m_new_scale_label_string);
m_cache.scale_label_string = _(m_new_scale_label_string)+ ":";
m_scale_Label->SetLabel(m_cache.scale_label_string);
}

View file

@ -120,19 +120,28 @@ boost::optional<WindowMetrics> WindowMetrics::deserialize(const std::string &str
void WindowMetrics::sanitize_for_display(const wxRect &screen_rect)
{
rect = rect.Intersect(screen_rect);
// Prevent the window from going too far towards the right and/or bottom edge
// It's hardcoded here that the threshold is 80% of the screen size
rect.x = std::min(rect.x, screen_rect.x + 4*screen_rect.width/5);
rect.y = std::min(rect.y, screen_rect.y + 4*screen_rect.height/5);
}
std::string WindowMetrics::serialize()
std::string WindowMetrics::serialize() const
{
return (boost::format("%1%; %2%; %3%; %4%; %5%")
% rect.GetX()
% rect.GetY()
% rect.GetWidth()
% rect.GetHeight()
% rect.x
% rect.y
% rect.width
% rect.height
% static_cast<int>(maximized)
).str();
}
std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics)
{
return os << '(' << metrics.serialize() << ')';
}
}

View file

@ -3,6 +3,7 @@
#include <memory>
#include <string>
#include <ostream>
#include <boost/optional.hpp>
@ -149,9 +150,11 @@ public:
bool get_maximized() const { return maximized; }
void sanitize_for_display(const wxRect &screen_rect);
std::string serialize();
std::string serialize() const;
};
std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics);
}}

View file

@ -101,7 +101,7 @@ void KBShortcutsDialog::fill_shortcuts()
main_shortcuts.push_back(Shortcut(ctrl+"O" ,L("Open project STL/OBJ/AMF/3MF with config, delete bed")));
main_shortcuts.push_back(Shortcut(ctrl+"I" ,L("Import STL/OBJ/AMF/3MF without config, keep bed")));
main_shortcuts.push_back(Shortcut(ctrl+"L" ,L("Load Config from .ini/amf/3mf/gcode")));
main_shortcuts.push_back(Shortcut(ctrl+"G" ,L("Export Gcode")));
main_shortcuts.push_back(Shortcut(ctrl+"G" ,L("Export G-code")));
main_shortcuts.push_back(Shortcut(ctrl+"S" ,L("Save project (3MF)")));
main_shortcuts.push_back(Shortcut(ctrl+alt+"L" ,L("Load Config from .ini/amf/3mf/gcode and merge")));
main_shortcuts.push_back(Shortcut(ctrl+"R" ,L("(Re)slice")));
@ -110,8 +110,8 @@ void KBShortcutsDialog::fill_shortcuts()
main_shortcuts.push_back(Shortcut(ctrl+"1" ,L("Select Plater Tab")));
main_shortcuts.push_back(Shortcut(ctrl+alt+"U" ,L("Quick slice and Save as")));
main_shortcuts.push_back(Shortcut(ctrl+"2" ,L("Select Print Settings Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"3" ,L("Select Filament Setting Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"4" ,L("Select Printer Setting Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"3" ,L("Select Filament Settings Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"4" ,L("Select Printer Settings Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"5" ,L("Switch to 3D")));
main_shortcuts.push_back(Shortcut(ctrl+"6" ,L("Switch to Preview")));
main_shortcuts.push_back(Shortcut(ctrl+"P" ,L("Preferences")));
@ -131,7 +131,7 @@ void KBShortcutsDialog::fill_shortcuts()
plater_shortcuts.push_back(Shortcut("A", L("Arrange")));
plater_shortcuts.push_back(Shortcut(ctrl+"A", L("Select All objects")));
plater_shortcuts.push_back(Shortcut("Del", L("Delete selected")));
plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete all")));
plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete All")));
plater_shortcuts.push_back(Shortcut("M", L("Gizmo move")));
plater_shortcuts.push_back(Shortcut("S", L("Gizmo scale")));
plater_shortcuts.push_back(Shortcut("R", L("Gizmo rotate")));

View file

@ -31,7 +31,7 @@ namespace Slic3r {
namespace GUI {
MainFrame::MainFrame() :
wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE),
wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"),
m_printhost_queue_dlg(new PrintHostQueueDialog(this))
{
// Load the icon either from the exe, or from the ico file.
@ -48,7 +48,7 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL
// initialize status bar
m_statusbar = new ProgressStatusBar(this);
m_statusbar->embed(this);
m_statusbar->set_status_text(_(L("Version ")) +
m_statusbar->set_status_text(_(L("Version")) + " " +
SLIC3R_VERSION +
_(L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases")));
@ -80,8 +80,7 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL
event.Veto();
return;
}
// save window size
wxGetApp().window_pos_save(this, "mainframe");
// Save the slic3r.ini.Usually the ini file is saved from "on idle" callback,
// but in rare cases it may not have been called yet.
wxGetApp().app_config->save();
@ -93,18 +92,9 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL
event.Skip();
});
// NB: Restoring the window position is done in a two-phase manner here,
// first the saved position is restored as-is and validation is done after the window is shown
// and initial round of events is complete, because on some platforms that is the only way
// to get an accurate window position & size.
wxGetApp().window_pos_restore(this, "mainframe");
Bind(wxEVT_SHOW, [this](wxShowEvent&) {
CallAfter([this]() {
wxGetApp().window_pos_sanitize(this);
});
});
wxGetApp().persist_window_geometry(this);
update_ui_from_settings();
update_ui_from_settings(); // FIXME (?)
}
void MainFrame::init_tabpanel()
@ -198,6 +188,12 @@ bool MainFrame::can_export_gcode() const
return true;
}
bool MainFrame::can_slice() const
{
bool bg_proc = wxGetApp().app_config->get("background_processing") == "1";
return (m_plater != nullptr) ? !m_plater->model().objects.empty() && !bg_proc : false;
}
bool MainFrame::can_change_view() const
{
int page_id = m_tabpanel->GetSelection();
@ -228,60 +224,60 @@ void MainFrame::init_menubar()
// File menu
wxMenu* fileMenu = new wxMenu;
{
wxMenuItem* item_open = append_menu_item(fileMenu, wxID_ANY, _(L("Open…\tCtrl+O")), _(L("Open a project file")),
wxMenuItem* item_open = append_menu_item(fileMenu, wxID_ANY, _(L("&Open")) + dots + "\tCtrl+O", _(L("Open a project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "brick_add.png");
wxMenuItem* item_save = append_menu_item(fileMenu, wxID_ANY, _(L("Save\tCtrl+S")), _(L("Save current project file")),
wxMenuItem* item_save = append_menu_item(fileMenu, wxID_ANY, _(L("&Save")) + "\tCtrl+S", _(L("Save current project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, "disk.png");
wxMenuItem* item_save_as = append_menu_item(fileMenu, wxID_ANY, _(L("Save as…\tCtrl+Alt+S")), _(L("Save current project file as")),
wxMenuItem* item_save_as = append_menu_item(fileMenu, wxID_ANY, _(L("Save &as")) + dots + "\tCtrl+Alt+S", _(L("Save current project file as")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "disk.png");
fileMenu->AppendSeparator();
wxMenu* import_menu = new wxMenu();
wxMenuItem* item_import_model = append_menu_item(import_menu, wxID_ANY, _(L("Import STL/OBJ/AMF/3MF…\tCtrl+I")), _(L("Load a model")),
wxMenuItem* item_import_model = append_menu_item(import_menu, wxID_ANY, _(L("Import STL/OBJ/AM&F/3MF")) + dots + "\tCtrl+I", _(L("Load a model")),
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, "brick_add.png");
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _(L("Import Config…\tCtrl+L")), _(L("Load exported configuration file")),
append_menu_item(import_menu, wxID_ANY, _(L("Import &Config")) + dots + "\tCtrl+L", _(L("Load exported configuration file")),
[this](wxCommandEvent&) { load_config_file(); }, "plugin_add.png");
append_menu_item(import_menu, wxID_ANY, _(L("Import Config from project…\tCtrl+Alt+L")), _(L("Load configuration from project file")),
append_menu_item(import_menu, wxID_ANY, _(L("Import Config from &project")) + dots +"\tCtrl+Alt+L", _(L("Load configuration from project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, "plugin_add.png");
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _(L("Import Config Bundle")), _(L("Load presets from a bundle")),
append_menu_item(import_menu, wxID_ANY, _(L("Import Config &Bundle")) + dots, _(L("Load presets from a bundle")),
[this](wxCommandEvent&) { load_configbundle(); }, "lorry_add.png");
append_submenu(fileMenu, import_menu, wxID_ANY, _(L("Import")), _(L("")));
append_submenu(fileMenu, import_menu, wxID_ANY, _(L("&Import")), "");
wxMenu* export_menu = new wxMenu();
wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _(L("Export G-code…\tCtrl+G")), _(L("Export current plate as G-code")),
wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _(L("Export &G-code")) + dots +"\tCtrl+G", _(L("Export current plate as G-code")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, "cog_go.png");
export_menu->AppendSeparator();
wxMenuItem* item_export_stl = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as STL")), _(L("Export current plate as STL")),
wxMenuItem* item_export_stl = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "brick_go.png");
wxMenuItem* item_export_amf = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as AMF")), _(L("Export current plate as AMF")),
wxMenuItem* item_export_amf = append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &AMF")) + dots, _(L("Export current plate as AMF")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, "brick_go.png");
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export Config…\tCtrl+E")), _(L("Export current configuration to file")),
append_menu_item(export_menu, wxID_ANY, _(L("Export &Config")) +dots +"\tCtrl+E", _(L("Export current configuration to file")),
[this](wxCommandEvent&) { export_config(); }, "plugin_go.png");
append_menu_item(export_menu, wxID_ANY, _(L("Export Config Bundle")), _(L("Export all presets to file")),
append_menu_item(export_menu, wxID_ANY, _(L("Export Config &Bundle")) + dots, _(L("Export all presets to file")),
[this](wxCommandEvent&) { export_configbundle(); }, "lorry_go.png");
append_submenu(fileMenu, export_menu, wxID_ANY, _(L("Export")), _(L("")));
append_submenu(fileMenu, export_menu, wxID_ANY, _(L("&Export")), "");
fileMenu->AppendSeparator();
#if 0
m_menu_item_repeat = nullptr;
append_menu_item(fileMenu, wxID_ANY, _(L("Quick Slice\tCtrl+U")), _(L("Slice a file into a G-code")),
append_menu_item(fileMenu, wxID_ANY, _(L("Quick Slice")) +dots+ "\tCtrl+U", _(L("Slice a file into a G-code")),
[this](wxCommandEvent&) {
wxTheApp->CallAfter([this]() {
quick_slice();
m_menu_item_repeat->Enable(is_last_input_file());
}); }, "cog_go.png");
append_menu_item(fileMenu, wxID_ANY, _(L("Quick Slice and Save As\tCtrl+Alt+U")), _(L("Slice a file into a G-code, save as")),
append_menu_item(fileMenu, wxID_ANY, _(L("Quick Slice and Save As")) +dots +"\tCtrl+Alt+U", _(L("Slice a file into a G-code, save as")),
[this](wxCommandEvent&) {
wxTheApp->CallAfter([this]() {
quick_slice(qsSaveAs);
m_menu_item_repeat->Enable(is_last_input_file());
}); }, "cog_go.png");
m_menu_item_repeat = append_menu_item(fileMenu, wxID_ANY, _(L("Repeat Last Quick Slice\tCtrl+Shift+U")), _(L("Repeat last quick slice")),
m_menu_item_repeat = append_menu_item(fileMenu, wxID_ANY, _(L("Repeat Last Quick Slice")) +"\tCtrl+Shift+U", _(L("Repeat last quick slice")),
[this](wxCommandEvent&) {
wxTheApp->CallAfter([this]() {
quick_slice(qsReslice);
@ -289,13 +285,13 @@ void MainFrame::init_menubar()
m_menu_item_repeat->Enable(false);
fileMenu->AppendSeparator();
#endif
m_menu_item_reslice_now = append_menu_item(fileMenu, wxID_ANY, _(L("(Re)Slice Now\tCtrl+R")), _(L("Start new slicing process")),
m_menu_item_reslice_now = append_menu_item(fileMenu, wxID_ANY, _(L("(Re)Slice &Now")) + "\tCtrl+R", _(L("Start new slicing process")),
[this](wxCommandEvent&) { reslice_now(); }, "shape_handles.png");
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_ANY, _(L("Repair STL file")), _(L("Automatically repair an STL file")),
append_menu_item(fileMenu, wxID_ANY, _(L("&Repair STL file")) + dots, _(L("Automatically repair an STL file")),
[this](wxCommandEvent&) { repair_stl(); }, "wrench.png");
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_EXIT, _(L("Quit")), _(L("Quit Slic3r")),
append_menu_item(fileMenu, wxID_EXIT, _(L("&Quit")), _(L("Quit Slic3r")),
[this](wxCommandEvent&) { Close(false); });
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater != nullptr); }, item_open->GetId());
@ -305,6 +301,7 @@ void MainFrame::init_menubar()
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_gcode()); }, item_export_gcode->GetId());
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_model()); }, item_export_stl->GetId());
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_export_model()); }, item_export_amf->GetId());
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable((m_plater != nullptr) && can_slice()); }, m_menu_item_reslice_now->GetId());
}
// Edit menu
@ -312,12 +309,12 @@ void MainFrame::init_menubar()
if (m_plater != nullptr)
{
editMenu = new wxMenu();
wxMenuItem* item_select_all = append_menu_item(editMenu, wxID_ANY, L("Select all\tCtrl+A"), L("Selects all objects"),
wxMenuItem* item_select_all = append_menu_item(editMenu, wxID_ANY, _(L("&Select all")) + "\tCtrl+A", _(L("Selects all objects")),
[this](wxCommandEvent&) { m_plater->select_all(); }, "");
editMenu->AppendSeparator();
wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, L("Delete selected\tDel"), L("Deletes the current selection"),
wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + "\tDel", _(L("Deletes the current selection")),
[this](wxCommandEvent&) { m_plater->remove_selected(); }, "");
wxMenuItem* item_delete_all = append_menu_item(editMenu, wxID_ANY, L("Delete all\tCtrl+Del"), L("Deletes all objects"),
wxMenuItem* item_delete_all = append_menu_item(editMenu, wxID_ANY, _(L("Delete &all")) + "\tCtrl+Del", _(L("Deletes all objects")),
[this](wxCommandEvent&) { m_plater->reset(); }, "");
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId());
@ -330,24 +327,24 @@ void MainFrame::init_menubar()
{
size_t tab_offset = 0;
if (m_plater) {
append_menu_item(windowMenu, wxID_HIGHEST + 1, L("Plater Tab\tCtrl+1"), L("Show the plater"),
append_menu_item(windowMenu, wxID_HIGHEST + 1, _(L("&Plater Tab")) + "\tCtrl+1", _(L("Show the plater")),
[this](wxCommandEvent&) { select_tab(0); }, "application_view_tile.png");
tab_offset += 1;
}
if (tab_offset > 0) {
windowMenu->AppendSeparator();
}
append_menu_item(windowMenu, wxID_HIGHEST + 2, L("Print Settings Tab\tCtrl+2"), L("Show the print settings"),
append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog.png");
append_menu_item(windowMenu, wxID_HIGHEST + 3, L("Filament Settings Tab\tCtrl+3"), L("Show the filament settings"),
append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool.png");
append_menu_item(windowMenu, wxID_HIGHEST + 4, L("Printer Settings Tab\tCtrl+4"), L("Show the printer settings"),
append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer_empty.png");
if (m_plater) {
windowMenu->AppendSeparator();
wxMenuItem* item_3d = append_menu_item(windowMenu, wxID_HIGHEST + 5, L("3D\tCtrl+5"), L("Show the 3D editing view"),
wxMenuItem* item_3d = append_menu_item(windowMenu, wxID_HIGHEST + 5, _(L("3&D")) + "\tCtrl+5", _(L("Show the 3D editing view")),
[this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, "");
wxMenuItem* item_preview = append_menu_item(windowMenu, wxID_HIGHEST + 6, L("Preview\tCtrl+6"), L("Show the 3D slices preview"),
wxMenuItem* item_preview = append_menu_item(windowMenu, wxID_HIGHEST + 6, _(L("Pre&view")) + "\tCtrl+6", _(L("Show the 3D slices preview")),
[this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, "");
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_3d->GetId());
@ -368,7 +365,7 @@ void MainFrame::init_menubar()
#endif // _WIN32
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_ANY, L("Print Host Upload Queue\tCtrl+J"), L("Display the Print Host Upload Queue window"),
append_menu_item(windowMenu, wxID_ANY, _(L("Print &Host Upload Queue")) + "\tCtrl+J", _(L("Display the Print Host Upload Queue window")),
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "arrow_up.png");
}
@ -379,14 +376,14 @@ void MainFrame::init_menubar()
// \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators,
// as the simple numeric accelerators spoil all numeric data entry.
// The camera control accelerators are captured by GLCanvas3D::on_char().
wxMenuItem* item_iso = append_menu_item(viewMenu, wxID_ANY, _(L("Iso")) + "\t\xA0" + "0", _(L("Iso View")), [this](wxCommandEvent&) { select_view("iso"); });
wxMenuItem* item_iso = append_menu_item(viewMenu, wxID_ANY, _(L("&Iso")) + "\t\xA0" + "0", _(L("Iso View")), [this](wxCommandEvent&) { select_view("iso"); });
viewMenu->AppendSeparator();
wxMenuItem* item_top = append_menu_item(viewMenu, wxID_ANY, _(L("Top")) + "\t\xA0" + "1", _(L("Top View")), [this](wxCommandEvent&) { select_view("top"); });
wxMenuItem* item_bottom = append_menu_item(viewMenu, wxID_ANY, _(L("Bottom")) + "\t\xA0" + "2", _(L("Bottom View")), [this](wxCommandEvent&) { select_view("bottom"); });
wxMenuItem* item_front = append_menu_item(viewMenu, wxID_ANY, _(L("Front")) + "\t\xA0" + "3", _(L("Front View")), [this](wxCommandEvent&) { select_view("front"); });
wxMenuItem* item_rear = append_menu_item(viewMenu, wxID_ANY, _(L("Rear")) + "\t\xA0" + "4", _(L("Rear View")), [this](wxCommandEvent&) { select_view("rear"); });
wxMenuItem* item_left = append_menu_item(viewMenu, wxID_ANY, _(L("Left")) + "\t\xA0" + "5", _(L("Left View")), [this](wxCommandEvent&) { select_view("left"); });
wxMenuItem* item_right = append_menu_item(viewMenu, wxID_ANY, _(L("Right")) + "\t\xA0" + "6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); });
wxMenuItem* item_top = append_menu_item(viewMenu, wxID_ANY, _(L("&Top")) + "\t\xA0" + "1", _(L("Top View")), [this](wxCommandEvent&) { select_view("top"); });
wxMenuItem* item_bottom = append_menu_item(viewMenu, wxID_ANY, _(L("&Bottom")) + "\t\xA0" + "2", _(L("Bottom View")), [this](wxCommandEvent&) { select_view("bottom"); });
wxMenuItem* item_front = append_menu_item(viewMenu, wxID_ANY, _(L("&Front")) + "\t\xA0" + "3", _(L("Front View")), [this](wxCommandEvent&) { select_view("front"); });
wxMenuItem* item_rear = append_menu_item(viewMenu, wxID_ANY, _(L("R&ear")) + "\t\xA0" + "4", _(L("Rear View")), [this](wxCommandEvent&) { select_view("rear"); });
wxMenuItem* item_left = append_menu_item(viewMenu, wxID_ANY, _(L("&Left")) + "\t\xA0" + "5", _(L("Left View")), [this](wxCommandEvent&) { select_view("left"); });
wxMenuItem* item_right = append_menu_item(viewMenu, wxID_ANY, _(L("&Right")) + "\t\xA0" + "6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); });
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_iso->GetId());
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_top->GetId());
@ -400,29 +397,29 @@ void MainFrame::init_menubar()
// Help menu
auto helpMenu = new wxMenu();
{
append_menu_item(helpMenu, wxID_ANY, _(L("Prusa 3D Drivers")), _(L("Open the Prusa3D drivers download page in your browser")),
append_menu_item(helpMenu, wxID_ANY, _(L("Prusa 3D &Drivers")), _(L("Open the Prusa3D drivers download page in your browser")),
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://www.prusa3d.com/drivers/"); });
append_menu_item(helpMenu, wxID_ANY, _(L("Prusa Edition Releases")), _(L("Open the Prusa Edition releases page in your browser")),
append_menu_item(helpMenu, wxID_ANY, _(L("Prusa Edition &Releases")), _(L("Open the Prusa Edition releases page in your browser")),
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://github.com/prusa3d/slic3r/releases"); });
//# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", "Check for new Slic3r versions", sub{
//# wxTheApp->check_version(1);
//# });
//# $versioncheck->Enable(wxTheApp->have_version_check);
append_menu_item(helpMenu, wxID_ANY, _(L("Slic3r Website")), _(L("Open the Slic3r website in your browser")),
append_menu_item(helpMenu, wxID_ANY, _(L("Slic3r &Website")), _(L("Open the Slic3r website in your browser")),
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://slic3r.org/"); });
append_menu_item(helpMenu, wxID_ANY, _(L("Slic3r Manual")), _(L("Open the Slic3r manual in your browser")),
append_menu_item(helpMenu, wxID_ANY, _(L("Slic3r &Manual")), _(L("Open the Slic3r manual in your browser")),
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://manual.slic3r.org/"); });
helpMenu->AppendSeparator();
append_menu_item(helpMenu, wxID_ANY, _(L("System Info")), _(L("Show system information")),
append_menu_item(helpMenu, wxID_ANY, _(L("System &Info")), _(L("Show system information")),
[this](wxCommandEvent&) { wxGetApp().system_info(); });
append_menu_item(helpMenu, wxID_ANY, _(L("Show Configuration Folder")), _(L("Show user configuration folder (datadir)")),
append_menu_item(helpMenu, wxID_ANY, _(L("Show &Configuration Folder")), _(L("Show user configuration folder (datadir)")),
[this](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); });
append_menu_item(helpMenu, wxID_ANY, _(L("Report an Issue")), _(L("Report an issue on the Slic3r Prusa Edition")),
append_menu_item(helpMenu, wxID_ANY, _(L("Report an I&ssue")), _(L("Report an issue on the Slic3r Prusa Edition")),
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://github.com/prusa3d/slic3r/issues/new"); });
append_menu_item(helpMenu, wxID_ANY, _(L("About Slic3r")), _(L("Show about dialog")),
append_menu_item(helpMenu, wxID_ANY, _(L("&About Slic3r")), _(L("Show about dialog")),
[this](wxCommandEvent&) { Slic3r::GUI::about(); });
helpMenu->AppendSeparator();
append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + "\t\xA0?", _(L("Show the list of the keyboard shortcuts")),
append_menu_item(helpMenu, wxID_ANY, _(L("&Keyboard Shortcuts")) + "\t\xA0?", _(L("Show the list of the keyboard shortcuts")),
[this](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); });
}
@ -430,17 +427,18 @@ void MainFrame::init_menubar()
// assign menubar to frame after appending items, otherwise special items
// will not be handled correctly
auto menubar = new wxMenuBar();
menubar->Append(fileMenu, L("&File"));
if (editMenu) menubar->Append(editMenu, L("&Edit"));
menubar->Append(windowMenu, L("&Window"));
if (viewMenu) menubar->Append(viewMenu, L("&View"));
menubar->Append(fileMenu, _(L("&File")));
if (editMenu) menubar->Append(editMenu, _(L("&Edit")));
menubar->Append(windowMenu, _(L("&Window")));
if (viewMenu) menubar->Append(viewMenu, _(L("&View")));
// Add additional menus from C++
wxGetApp().add_config_menu(menubar);
menubar->Append(helpMenu, L("&Help"));
menubar->Append(helpMenu, _(L("&Help")));
SetMenuBar(menubar);
#ifdef __APPLE__
// This fixes a bug (?) on Mac OS where the quit command doesn't emit window close events
// This fixes a bug on Mac OS where the quit command doesn't emit window close events
// wx bug: https://trac.wxwidgets.org/ticket/18328
wxMenu *apple_menu = menubar->OSXGetAppleMenu();
if (apple_menu != nullptr) {
apple_menu->Bind(wxEVT_MENU, [this](wxCommandEvent &) {
@ -551,7 +549,7 @@ void MainFrame::quick_slice(const int qs)
}
// show processbar dialog
m_progress_dialog = new wxProgressDialog(_(L("Slicing")), _(L("Processing ")) + input_file_basename + "",
m_progress_dialog = new wxProgressDialog(_(L("Slicing")) + dots, _(L("Processing ")) + input_file_basename + "",
100, this, 4);
m_progress_dialog->Pulse();
{
@ -847,7 +845,7 @@ void MainFrame::on_value_changed(wxCommandEvent& event)
void MainFrame::update_ui_from_settings()
{
bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
m_menu_item_reslice_now->Enable(!bp_on);
// m_menu_item_reslice_now->Enable(!bp_on);
m_plater->sidebar().show_reslice(!bp_on);
m_plater->sidebar().Layout();
if (m_plater)

View file

@ -62,6 +62,7 @@ class MainFrame : public wxFrame
bool can_save() const;
bool can_export_model() const;
bool can_export_gcode() const;
bool can_slice() const;
bool can_change_view() const;
bool can_select() const;
bool can_delete() const;

View file

@ -231,11 +231,11 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
wxSizer* sizer_tmp = sizer;
// add label if any
if (option.label != "") {
wxString str_label = _(option.label);
// wxString str_label = _(option.label);
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
// wxString str_label = (option.label == "Top" || option.label == "Bottom") ?
// wxGETTEXT_IN_CONTEXT("Layers", wxString(option.label.c_str()):
// L_str(option.label);
wxString str_label = (option.label == "Top" || option.label == "Bottom") ?
wxGETTEXT_IN_CONTEXT("Layers", wxString(option.label)) :
_(option.label);
label = new wxStaticText(parent(), wxID_ANY, str_label + ":", wxDefaultPosition, wxDefaultSize);
label->SetFont(label_font);
sizer_tmp->Add(label, 0, /*wxALIGN_RIGHT |*/ wxALIGN_CENTER_VERTICAL, 0);

View file

@ -1,7 +1,7 @@
#ifndef slic3r_OptionsGroup_hpp_
#define slic3r_OptionsGroup_hpp_
#include <wx/wx.h>
//#include <wx/wx.h>
#include <wx/stattext.h>
#include <wx/settings.h>
//#include <wx/window.h>
@ -11,7 +11,7 @@
#include "libslic3r/Config.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/libslic3r.h"
// #include "libslic3r/libslic3r.h"
#include "Field.hpp"
#include "GUI_App.hpp"

View file

@ -114,7 +114,7 @@ ObjectInfo::ObjectInfo(wxWindow *parent) :
grid_sizer->AddGrowableCol(3, 1);
auto init_info_label = [parent, grid_sizer](wxStaticText **info_label, wxString text_label) {
auto *text = new wxStaticText(parent, wxID_ANY, text_label);
auto *text = new wxStaticText(parent, wxID_ANY, text_label+":");
text->SetFont(wxGetApp().small_font());
*info_label = new wxStaticText(parent, wxID_ANY, "");
(*info_label)->SetFont(wxGetApp().small_font());
@ -122,13 +122,13 @@ ObjectInfo::ObjectInfo(wxWindow *parent) :
grid_sizer->Add(*info_label, 0);
};
init_info_label(&info_size, _(L("Size:")));
init_info_label(&info_volume, _(L("Volume:")));
init_info_label(&info_facets, _(L("Facets:")));
init_info_label(&info_materials, _(L("Materials:")));
init_info_label(&info_size, _(L("Size")));
init_info_label(&info_volume, _(L("Volume")));
init_info_label(&info_facets, _(L("Facets")));
init_info_label(&info_materials, _(L("Materials")));
Add(grid_sizer, 0, wxEXPAND);
auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _(L("Manifold:")));
auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _(L("Manifold")));
info_manifold_text->SetFont(wxGetApp().small_font());
info_manifold = new wxStaticText(parent, wxID_ANY, "");
info_manifold->SetFont(wxGetApp().small_font());
@ -602,7 +602,7 @@ Sidebar::Sidebar(Plater *parent)
scrolled_sizer->Add(p->sliced_info, 0, wxEXPAND | wxTOP | wxLEFT, 20);
// Buttons underneath the scrolled area
p->btn_export_gcode = new wxButton(this, wxID_ANY, _(L("Export G-code")));
p->btn_export_gcode = new wxButton(this, wxID_ANY, _(L("Export G-code")) + dots);
p->btn_export_gcode->SetFont(wxGetApp().bold_font());
p->btn_reslice = new wxButton(this, wxID_ANY, _(L("Slice now")));
p->btn_reslice->SetFont(wxGetApp().bold_font());
@ -792,7 +792,7 @@ void Sidebar::show_info_sizer()
wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors)")), errors);
p->object_info->info_manifold->SetLabel(tooltip);
tooltip += wxString::Format(_(L(":\n%d degenerate facets, %d edges fixed, %d facets removed, "
tooltip += ":\n" + wxString::Format(_(L("%d degenerate facets, %d edges fixed, %d facets removed, "
"%d facets added, %d facets reversed, %d backwards edges")),
stats.degenerate_facets, stats.edges_fixed, stats.facets_removed,
stats.facets_added, stats.facets_reversed, stats.backwards_edges);
@ -849,7 +849,7 @@ void Sidebar::show_sliced_info_sizer(const bool show)
if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A")
p->sliced_info->SetTextAndShow(siEstimatedTime, "N/A");
else {
new_label = "Estimated printing time :";
new_label = _(L("Estimated printing time")) +" :";
info_text = "";
if (ps.estimated_normal_print_time != "N/A") {
new_label += wxString::Format("\n - %s", _(L("normal mode")));
@ -1306,7 +1306,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
}
const auto loading = _(L("Loading"));
const auto loading = _(L("Loading")) + dots;
wxProgressDialog dlg(loading, loading);
dlg.Pulse();
@ -1367,14 +1367,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// The model should now be initialized
if (model.looks_like_multipart_object()) {
// wxMessageDialog dlg(q, _(L(
// "This file contains several objects positioned at multiple heights. "
// "Instead of considering them as multiple objects, should I consider\n"
// "this file as a single object having multiple parts?\n"
// )), _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO);
// if (dlg.ShowModal() == wxID_YES) {
wxMessageDialog dlg(q, _(L(
"This file contains several objects positioned at multiple heights. "
"Instead of considering them as multiple objects, should I consider\n"
"this file as a single object having multiple parts?\n"
)), _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES) {
model.convert_multipart_object(nozzle_dmrs->values.size());
// }
}
}
if (type_3mf || type_any_amf) {
@ -2350,14 +2350,14 @@ bool Plater::priv::init_object_menu()
bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/)
{
wxMenuItem* item_delete = append_menu_item(menu, wxID_ANY, _(L("Delete\tDel")), _(L("Remove the selected object")),
wxMenuItem* item_delete = append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")),
[this](wxCommandEvent&) { q->remove_selected(); }, "brick_delete.png");
if (!is_part){
wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _(L("Increase copies\t+")), _(L("Place one more copy of the selected object")),
wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _(L("Increase copies")) + "\t+", _(L("Place one more copy of the selected object")),
[this](wxCommandEvent&) { q->increase_instances(); }, "add.png");
wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _(L("Decrease copies\t-")), _(L("Remove one copy of the selected object")),
wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _(L("Decrease copies")) + "\t-", _(L("Remove one copy of the selected object")),
[this](wxCommandEvent&) { q->decrease_instances(); }, "delete.png");
wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _(L("Set number of copies")), _(L("Change the number of copies of the selected object")),
wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _(L("Set number of copies")) + dots, _(L("Change the number of copies of the selected object")),
[this](wxCommandEvent&) { q->set_number_of_copies(); }, "textfield.png");
if (q != nullptr)
{
@ -2370,7 +2370,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
append_menu_item(menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")),
[this](wxCommandEvent&) { reload_from_disk(); });
append_menu_item(menu, wxID_ANY, _(L("Export object as STL")), _(L("Export this single object as STL file")),
append_menu_item(menu, wxID_ANY, _(L("Export object as STL")) + dots, _(L("Export this single object as STL file")),
[this](wxCommandEvent&) { q->export_stl(true); });
}
menu->AppendSeparator();
@ -2414,7 +2414,7 @@ bool Plater::priv::complit_init_object_menu()
// append_menu_item(&object_menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")),
// [this](wxCommandEvent&) { reload_from_disk(); });
//
// append_menu_item(&object_menu, wxID_ANY, _(L("Export object as STL")), _(L("Export this single object as STL file")),
// append_menu_item(&object_menu, wxID_ANY, _(L("Export object as STL")) + dots, _(L("Export this single object as STL file")),
// [this](wxCommandEvent&) { q->export_stl(true); });
// Append "Add..." popupmenu

View file

@ -1153,11 +1153,11 @@ std::vector<std::string> PresetCollection::merge_presets(PresetCollection &&othe
std::string PresetCollection::name() const
{
switch (this->type()) {
case Preset::TYPE_PRINT: return "print";
case Preset::TYPE_FILAMENT: return "filament";
case Preset::TYPE_SLA_PRINT: return "SLA print";
case Preset::TYPE_SLA_MATERIAL: return "SLA material";
case Preset::TYPE_PRINTER: return "printer";
case Preset::TYPE_PRINT: return L("print");
case Preset::TYPE_FILAMENT: return L("filament");
case Preset::TYPE_SLA_PRINT: return L("SLA print");
case Preset::TYPE_SLA_MATERIAL: return L("SLA material");
case Preset::TYPE_PRINTER: return L("printer");
default: return "invalid";
}
}

View file

@ -121,7 +121,7 @@ SysInfoDialog::SysInfoDialog()
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
// this->Bind(wxEVT_LEFT_DOWN, &SysInfoDialog::onCloseDialog, this);
logo->Bind(wxEVT_LEFT_DOWN, &SysInfoDialog::onCloseDialog, this);
// logo->Bind(wxEVT_LEFT_DOWN, &SysInfoDialog::onCloseDialog, this);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);

View file

@ -2009,7 +2009,7 @@ PageShp TabPrinter::build_kinematics_page()
if (m_use_silent_mode) {
// Legend for OptionsGroups
auto optgroup = page->new_optgroup(_(L("")));
auto optgroup = page->new_optgroup("");
optgroup->set_show_modified_btns_val(false);
optgroup->label_width = 230;
auto line = Line{ "", "" };
@ -2559,19 +2559,20 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr
std::string type_name = presets->name();
wxString tab = " ";
wxString name = old_preset.is_default ?
_(L("Default ")) + type_name + _(L(" preset")) :
(type_name + _(L(" preset\n")) + tab + old_preset.name);
wxString::Format(_(L("Default preset (%s)")), _(type_name)) : //_(L("Default ")) + type_name + _(L(" preset")) :
wxString::Format(_(L("Preset (%s)")), _(type_name)) + "\n" + tab + old_preset.name; //type_name + _(L(" preset\n")) + tab + old_preset.name;
// Collect descriptions of the dirty options.
wxString changes;
for (const std::string &opt_key : presets->current_dirty_options()) {
const ConfigOptionDef &opt = m_config->def()->options.at(opt_key);
std::string name = "";
/*std::string*/wxString name = "";
if (! opt.category.empty())
name += opt.category + " > ";
name += _(opt.category) + " > ";
name += !opt.full_label.empty() ?
opt.full_label :
opt.label;
changes += tab + from_u8(name) + "\n";
_(opt.full_label) :
_(opt.label);
changes += tab + /*from_u8*/(name) + "\n";
}
// Show a confirmation dialog with the list of dirty options.
wxString message = name + "\n\n";
@ -2585,7 +2586,7 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr
message += _(L("and it has the following unsaved changes:"));
}
auto confirm = new wxMessageDialog(parent(),
message + "\n" + changes + _(L("\n\nDiscard changes and continue anyway?")),
message + "\n" + changes + "\n\n" + _(L("Discard changes and continue anyway?")),
_(L("Unsaved Changes")), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
return confirm->ShowModal() == wxID_YES;
}
@ -2597,8 +2598,8 @@ bool Tab::may_switch_to_SLA_preset()
if (wxGetApp().obj_list()->has_multi_part_objects())
{
show_info( parent(),
_(L("It's impossible to print multi-part object(s) with SLA technology.")) +
_(L("\n\nPlease check your object list before preset changing.")),
_(L("It's impossible to print multi-part object(s) with SLA technology.")) + "\n\n" +
_(L("Please check your object list before preset changing.")),
_(L("Attention!")) );
return false;
}