Merge branch 'master' of https://github.com/Prusa3d/Slic3r
This commit is contained in:
commit
487ccdd2be
@ -156,6 +156,7 @@ add_library(libslic3r STATIC
|
||||
TriangleMesh.hpp
|
||||
utils.cpp
|
||||
Utils.hpp
|
||||
MTUtils.hpp
|
||||
SLA/SLABoilerPlate.hpp
|
||||
SLA/SLABasePool.hpp
|
||||
SLA/SLABasePool.cpp
|
||||
|
63
src/libslic3r/MTUtils.hpp
Normal file
63
src/libslic3r/MTUtils.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef MTUTILS_HPP
|
||||
#define MTUTILS_HPP
|
||||
|
||||
#include <atomic> // for std::atomic_flag and memory orders
|
||||
#include <mutex> // for std::lock_guard
|
||||
#include <functional> // for std::function
|
||||
#include <utility> // for std::forward
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// TODO: these classes are untested
|
||||
|
||||
/// Handy little spin mutex for the cached meshes.
|
||||
/// Implements the "Lockable" concept
|
||||
class SpinMutex {
|
||||
std::atomic_flag m_flg;
|
||||
static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire;
|
||||
static const /*constexpr*/ auto MO_REL = std::memory_order_release;
|
||||
public:
|
||||
inline SpinMutex() { m_flg.clear(MO_REL); }
|
||||
inline void lock() { while(m_flg.test_and_set(MO_ACQ)); }
|
||||
inline bool try_lock() { return !m_flg.test_and_set(MO_ACQ); }
|
||||
inline void unlock() { m_flg.clear(MO_REL); }
|
||||
};
|
||||
|
||||
/// A wrapper class around arbitrary object that needs thread safe caching.
|
||||
template<class T> class CachedObject {
|
||||
public:
|
||||
// Method type which refreshes the object when it has been invalidated
|
||||
using Setter = std::function<void(T&)>;
|
||||
private:
|
||||
T m_obj; // the object itself
|
||||
bool m_valid; // invalidation flag
|
||||
SpinMutex m_lck; // to make the caching thread safe
|
||||
|
||||
// the setter will be called just before the object's const value is about
|
||||
// to be retrieved.
|
||||
std::function<void(T&)> m_setter;
|
||||
public:
|
||||
|
||||
// Forwarded constructor
|
||||
template<class...Args> inline CachedObject(Setter fn, Args&&...args):
|
||||
m_obj(std::forward<Args>(args)...), m_valid(false), m_setter(fn) {}
|
||||
|
||||
// invalidate the value of the object. The object will be refreshed at the
|
||||
// next retrieval (Setter will be called). The data that is used in
|
||||
// the setter function should be guarded as well during modification so the
|
||||
// modification has to take place in fn.
|
||||
inline void invalidate(std::function<void()> fn) {
|
||||
std::lock_guard<SpinMutex> lck(m_lck); fn(); m_valid = false;
|
||||
}
|
||||
|
||||
// Get the const object properly updated.
|
||||
inline const T& get() {
|
||||
std::lock_guard<SpinMutex> lck(m_lck);
|
||||
if(!m_valid) { m_setter(m_obj); m_valid = true; }
|
||||
return m_obj;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MTUTILS_HPP
|
@ -1051,9 +1051,6 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
ModelVolume* volume = this->volumes.front();
|
||||
TriangleMeshPtrs meshptrs = volume->mesh.split();
|
||||
for (TriangleMesh *mesh : meshptrs) {
|
||||
// Snap the mesh to Z=0.
|
||||
float z0 = FLT_MAX;
|
||||
|
||||
mesh->repair();
|
||||
|
||||
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
||||
@ -1063,7 +1060,20 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
new_object->instances.reserve(this->instances.size());
|
||||
for (const ModelInstance *model_instance : this->instances)
|
||||
new_object->add_instance(*model_instance);
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
|
||||
new_vol->center_geometry();
|
||||
|
||||
for (ModelInstance* model_instance : new_object->instances)
|
||||
{
|
||||
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
|
||||
model_instance->set_offset(model_instance->get_offset() + shift);
|
||||
}
|
||||
|
||||
new_vol->set_offset(Vec3d::Zero());
|
||||
#else
|
||||
new_object->add_volume(*volume, std::move(*mesh));
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
new_objects->emplace_back(new_object);
|
||||
delete mesh;
|
||||
}
|
||||
|
@ -20,9 +20,6 @@ public:
|
||||
inline double radius() const { return radius_; }
|
||||
inline const Point& center() const { return center_; }
|
||||
inline operator bool() { return !std::isnan(radius_); }
|
||||
// inline operator lnCircle() {
|
||||
// return lnCircle({center_(0), center_(1)}, radius_);
|
||||
// }
|
||||
};
|
||||
|
||||
enum class BedShapeType {
|
||||
|
@ -730,6 +730,9 @@ public:
|
||||
meshcache.merge(mesh(bs.mesh));
|
||||
}
|
||||
|
||||
// TODO: Is this necessary?
|
||||
meshcache.repair();
|
||||
|
||||
BoundingBoxf3&& bb = meshcache.bounding_box();
|
||||
model_height = bb.max(Z) - bb.min(Z);
|
||||
|
||||
@ -1616,13 +1619,13 @@ bool SLASupportTree::generate(const PointSet &points,
|
||||
return pc == ABORT;
|
||||
}
|
||||
|
||||
void SLASupportTree::merged_mesh(TriangleMesh &outmesh) const
|
||||
const TriangleMesh &SLASupportTree::merged_mesh() const
|
||||
{
|
||||
outmesh.merge(get().merged_mesh());
|
||||
return get().merged_mesh();
|
||||
}
|
||||
|
||||
void SLASupportTree::merged_mesh_with_pad(TriangleMesh &outmesh) const {
|
||||
merged_mesh(outmesh);
|
||||
outmesh.merge(merged_mesh());
|
||||
outmesh.merge(get_pad());
|
||||
}
|
||||
|
||||
@ -1658,14 +1661,12 @@ const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
|
||||
double max_merge_distance_mm,
|
||||
double edge_radius_mm) const
|
||||
{
|
||||
TriangleMesh mm;
|
||||
merged_mesh(mm);
|
||||
PoolConfig pcfg;
|
||||
pcfg.min_wall_thickness_mm = min_wall_thickness_mm;
|
||||
pcfg.min_wall_height_mm = min_wall_height_mm;
|
||||
pcfg.max_merge_distance_mm = max_merge_distance_mm;
|
||||
pcfg.edge_radius_mm = edge_radius_mm;
|
||||
return m_impl->create_pad(mm, baseplate, pcfg).tmesh;
|
||||
return m_impl->create_pad(merged_mesh(), baseplate, pcfg).tmesh;
|
||||
}
|
||||
|
||||
const TriangleMesh &SLASupportTree::get_pad() const
|
||||
|
@ -144,7 +144,7 @@ public:
|
||||
|
||||
/// Get the whole mesh united into the output TriangleMesh
|
||||
/// WITHOUT THE PAD
|
||||
void merged_mesh(TriangleMesh& outmesh) const;
|
||||
const TriangleMesh& merged_mesh() const;
|
||||
|
||||
void merged_mesh_with_pad(TriangleMesh&) const;
|
||||
|
||||
|
@ -798,7 +798,10 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
|
||||
|
||||
SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
|
||||
Inherited(print, model_object),
|
||||
m_stepmask(slaposCount, true)
|
||||
m_stepmask(slaposCount, true),
|
||||
m_transformed_rmesh( [this](TriangleMesh& obj){
|
||||
obj = m_model_object->raw_mesh(); obj.transform(m_trafo);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
@ -893,28 +896,29 @@ double SLAPrintObject::get_elevation() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
||||
//{
|
||||
// // I don't want to return a copy but the points may not exist, so ...
|
||||
// static const std::vector<ExPolygons> dummy_empty;
|
||||
namespace { // dummy empty static containers for return values in some methods
|
||||
const std::vector<ExPolygons> EMPTY_SLICES;
|
||||
const TriangleMesh EMPTY_MESH;
|
||||
}
|
||||
|
||||
// if(!m_supportdata) return dummy_empty;
|
||||
// return m_supportdata->support_slices;
|
||||
//}
|
||||
const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
||||
{
|
||||
if(!is_step_done(slaposSliceSupports) || !m_supportdata) return EMPTY_SLICES;
|
||||
return m_supportdata->support_slices;
|
||||
}
|
||||
|
||||
//const std::vector<ExPolygons> &SLAPrintObject::get_model_slices() const
|
||||
//{
|
||||
// return m_model_slices;
|
||||
//}
|
||||
const std::vector<ExPolygons> &SLAPrintObject::get_model_slices() const
|
||||
{
|
||||
if(!is_step_done(slaposObjectSlice)) return EMPTY_SLICES;
|
||||
return m_model_slices;
|
||||
}
|
||||
|
||||
bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const
|
||||
{
|
||||
switch (step) {
|
||||
case slaposSupportTree:
|
||||
// return m_supportdata && m_supportdata->support_tree_ptr && ! m_supportdata->support_tree_ptr->get().merged_mesh().empty();
|
||||
return ! this->support_mesh().empty();
|
||||
case slaposBasePool:
|
||||
// return m_supportdata && m_supportdata->support_tree_ptr && ! m_supportdata->support_tree_ptr->get_pad().empty();
|
||||
return ! this->pad_mesh().empty();
|
||||
default:
|
||||
return false;
|
||||
@ -933,22 +937,19 @@ TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const
|
||||
}
|
||||
}
|
||||
|
||||
TriangleMesh SLAPrintObject::support_mesh() const
|
||||
|
||||
|
||||
const TriangleMesh& SLAPrintObject::support_mesh() const
|
||||
{
|
||||
TriangleMesh trm;
|
||||
|
||||
if(m_supportdata && m_supportdata->support_tree_ptr)
|
||||
m_supportdata->support_tree_ptr->merged_mesh(trm);
|
||||
return m_supportdata->support_tree_ptr->merged_mesh();
|
||||
|
||||
// TODO: is this necessary?
|
||||
trm.repair();
|
||||
|
||||
return trm;
|
||||
return EMPTY_MESH;
|
||||
}
|
||||
|
||||
TriangleMesh SLAPrintObject::pad_mesh() const
|
||||
const TriangleMesh& SLAPrintObject::pad_mesh() const
|
||||
{
|
||||
if(!m_supportdata || !m_supportdata->support_tree_ptr) return {};
|
||||
if(!m_supportdata || !m_supportdata->support_tree_ptr) return EMPTY_MESH;
|
||||
|
||||
return m_supportdata->support_tree_ptr->get_pad();
|
||||
}
|
||||
@ -963,11 +964,7 @@ const TriangleMesh &SLAPrintObject::transformed_mesh() const {
|
||||
// or apply an inverse transformation on the support structure after it
|
||||
// has been created.
|
||||
|
||||
if(m_trmesh_valid) return m_transformed_rmesh;
|
||||
m_transformed_rmesh = m_model_object->raw_mesh();
|
||||
m_transformed_rmesh.transform(m_trafo);
|
||||
m_trmesh_valid = true;
|
||||
return m_transformed_rmesh;
|
||||
return m_transformed_rmesh.get();
|
||||
}
|
||||
|
||||
std::vector<Vec3d> SLAPrintObject::transformed_support_points() const
|
||||
|
@ -1,9 +1,12 @@
|
||||
#ifndef slic3r_SLAPrint_hpp_
|
||||
#define slic3r_SLAPrint_hpp_
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "PrintBase.hpp"
|
||||
#include "PrintExport.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "MTUtils.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -55,10 +58,10 @@ public:
|
||||
|
||||
// Get a support mesh centered around origin in XY, and with zero rotation around Z applied.
|
||||
// Support mesh is only valid if this->is_step_done(slaposSupportTree) is true.
|
||||
TriangleMesh support_mesh() const;
|
||||
const TriangleMesh& support_mesh() const;
|
||||
// Get a pad mesh centered around origin in XY, and with zero rotation around Z applied.
|
||||
// Support mesh is only valid if this->is_step_done(slaposPad) is true.
|
||||
TriangleMesh pad_mesh() const;
|
||||
const TriangleMesh& pad_mesh() const;
|
||||
|
||||
// This will return the transformed mesh which is cached
|
||||
const TriangleMesh& transformed_mesh() const;
|
||||
@ -71,8 +74,9 @@ public:
|
||||
// as the pad height also needs to be considered.
|
||||
double get_elevation() const;
|
||||
|
||||
// const std::vector<ExPolygons>& get_support_slices() const;
|
||||
// const std::vector<ExPolygons>& get_model_slices() const;
|
||||
// Should be obvious
|
||||
const std::vector<ExPolygons>& get_support_slices() const;
|
||||
const std::vector<ExPolygons>& get_model_slices() const;
|
||||
|
||||
// I refuse to grantee copying (Tamas)
|
||||
SLAPrintObject(const SLAPrintObject&) = delete;
|
||||
@ -88,7 +92,10 @@ protected:
|
||||
void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); }
|
||||
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false)
|
||||
{ this->m_config.apply_only(other, keys, ignore_nonexistent); }
|
||||
void set_trafo(const Transform3d& trafo) { m_trafo = trafo; m_trmesh_valid = false; }
|
||||
|
||||
void set_trafo(const Transform3d& trafo) {
|
||||
m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; });
|
||||
}
|
||||
|
||||
void set_instances(const std::vector<Instance> &instances) { m_instances = instances; }
|
||||
// Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint.
|
||||
@ -109,8 +116,7 @@ private:
|
||||
std::vector<ExPolygons> m_model_slices;
|
||||
|
||||
// Caching the transformed (m_trafo) raw mesh of the object
|
||||
mutable TriangleMesh m_transformed_rmesh;
|
||||
mutable bool m_trmesh_valid = false;
|
||||
mutable CachedObject<TriangleMesh> m_transformed_rmesh;
|
||||
|
||||
class SupportData;
|
||||
std::unique_ptr<SupportData> m_supportdata;
|
||||
|
@ -2041,6 +2041,11 @@ void _3DScene::render(wxGLCanvas* canvas)
|
||||
s_canvas_mgr.render(canvas);
|
||||
}
|
||||
|
||||
void _3DScene::select_all(wxGLCanvas* canvas)
|
||||
{
|
||||
s_canvas_mgr.select_all(canvas);
|
||||
}
|
||||
|
||||
void _3DScene::delete_selected(wxGLCanvas* canvas)
|
||||
{
|
||||
s_canvas_mgr.delete_selected(canvas);
|
||||
|
@ -633,6 +633,7 @@ public:
|
||||
|
||||
static void render(wxGLCanvas* canvas);
|
||||
|
||||
static void select_all(wxGLCanvas* canvas);
|
||||
static void delete_selected(wxGLCanvas* canvas);
|
||||
static void ensure_on_bed(wxGLCanvas* canvas, unsigned int object_idx);
|
||||
|
||||
|
@ -161,6 +161,13 @@ void Field::get_value_by_opt_type(wxString& str)
|
||||
}
|
||||
}
|
||||
|
||||
bool TextCtrl::is_defined_input_value()
|
||||
{
|
||||
if (static_cast<wxTextCtrl*>(window)->GetValue().empty() && m_opt.type != coString && m_opt.type != coStrings)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextCtrl::BUILD() {
|
||||
auto size = wxSize(wxDefaultSize);
|
||||
if (m_opt.height >= 0) size.SetHeight(m_opt.height);
|
||||
@ -226,16 +233,21 @@ void TextCtrl::BUILD() {
|
||||
temp->GetToolTip()->Enable(flag);
|
||||
}), temp->GetId());
|
||||
|
||||
#if !defined(__WXGTK__)
|
||||
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
|
||||
{
|
||||
e.Skip();// on_kill_focus(e);
|
||||
#if !defined(__WXGTK__)
|
||||
e.Skip();
|
||||
temp->GetToolTip()->Enable(true);
|
||||
}), temp->GetId());
|
||||
#endif // __WXGTK__
|
||||
if (!is_defined_input_value())
|
||||
on_kill_focus(e);
|
||||
}), temp->GetId());
|
||||
|
||||
if (m_process_enter) {
|
||||
temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent& evt) { on_change_field(); }), temp->GetId());
|
||||
temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent& evt) {
|
||||
if(is_defined_input_value())
|
||||
on_change_field();
|
||||
}), temp->GetId());
|
||||
}
|
||||
else {
|
||||
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt)
|
||||
@ -243,6 +255,7 @@ void TextCtrl::BUILD() {
|
||||
#ifdef __WXGTK__
|
||||
if (bChangedValueEvent)
|
||||
#endif //__WXGTK__
|
||||
if(is_defined_input_value())
|
||||
on_change_field();
|
||||
}), temp->GetId());
|
||||
|
||||
@ -357,7 +370,7 @@ void SpinCtrl::BUILD() {
|
||||
0, min_val, max_val, default_value);
|
||||
|
||||
// temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { tmp_value = undef_spin_val; on_change_field(); }), temp->GetId());
|
||||
// temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { tmp_value = undef_spin_val; on_kill_focus(e); }), temp->GetId());
|
||||
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { on_kill_focus(e); }), temp->GetId());
|
||||
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
|
||||
{
|
||||
// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value
|
||||
|
@ -265,6 +265,7 @@ public:
|
||||
}
|
||||
|
||||
boost::any& get_value() override;
|
||||
bool is_defined_input_value();
|
||||
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
|
@ -1315,6 +1315,22 @@ void GLCanvas3D::Selection::remove_volume(unsigned int object_idx, unsigned int
|
||||
m_bounding_box_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::add_all()
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
m_mode = Instance;
|
||||
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
_add_volume(i);
|
||||
}
|
||||
|
||||
_update_type();
|
||||
m_bounding_box_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::clear()
|
||||
{
|
||||
if (!m_valid)
|
||||
@ -3687,6 +3703,11 @@ void GLCanvas3D::render()
|
||||
m_canvas->SwapBuffers();
|
||||
}
|
||||
|
||||
void GLCanvas3D::select_all()
|
||||
{
|
||||
m_selection.add_all();
|
||||
}
|
||||
|
||||
void GLCanvas3D::delete_selected()
|
||||
{
|
||||
m_selection.erase();
|
||||
|
@ -485,6 +485,8 @@ public:
|
||||
void add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_idx, bool as_single_selection = true);
|
||||
void remove_volume(unsigned int object_idx, unsigned int volume_idx);
|
||||
|
||||
void add_all();
|
||||
|
||||
// Update the selection based on the map from old indices to new indices after m_volumes changed.
|
||||
// If the current selection is by instance, this call may select newly added volumes, if they belong to already selected instances.
|
||||
void volumes_changed(const std::vector<size_t> &map_volume_old_to_new);
|
||||
@ -813,6 +815,7 @@ public:
|
||||
|
||||
void render();
|
||||
|
||||
void select_all();
|
||||
void delete_selected();
|
||||
void ensure_on_bed(unsigned int object_idx);
|
||||
|
||||
|
@ -454,6 +454,13 @@ void GLCanvas3DManager::render(wxGLCanvas* canvas) const
|
||||
it->second->render();
|
||||
}
|
||||
|
||||
void GLCanvas3DManager::select_all(wxGLCanvas* canvas)
|
||||
{
|
||||
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||
if (it != m_canvases.end())
|
||||
it->second->select_all();
|
||||
}
|
||||
|
||||
void GLCanvas3DManager::delete_selected(wxGLCanvas* canvas)
|
||||
{
|
||||
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||
|
@ -130,6 +130,7 @@ public:
|
||||
|
||||
void render(wxGLCanvas* canvas) const;
|
||||
|
||||
void select_all(wxGLCanvas* canvas);
|
||||
void delete_selected(wxGLCanvas* canvas);
|
||||
void ensure_on_bed(wxGLCanvas* canvas, unsigned int object_idx);
|
||||
|
||||
|
@ -201,6 +201,16 @@ bool MainFrame::can_change_view() const
|
||||
int page_id = m_tabpanel->GetSelection();
|
||||
return (page_id != wxNOT_FOUND) ? m_tabpanel->GetPageText((size_t)page_id).Lower() == "plater" : false;
|
||||
}
|
||||
|
||||
bool MainFrame::can_select() const
|
||||
{
|
||||
return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false;
|
||||
}
|
||||
|
||||
bool MainFrame::can_delete() const
|
||||
{
|
||||
return (m_plater != nullptr) ? !m_plater->is_selection_empty() : false;
|
||||
}
|
||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||
|
||||
void MainFrame::init_menubar()
|
||||
@ -301,6 +311,22 @@ void MainFrame::init_menubar()
|
||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||
}
|
||||
|
||||
#if ENABLE_NEW_MENU_LAYOUT
|
||||
// Edit menu
|
||||
wxMenu* editMenu = nullptr;
|
||||
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"),
|
||||
[this](wxCommandEvent&) { m_plater->select_all(); }, "");
|
||||
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(); }, "");
|
||||
|
||||
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId());
|
||||
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete()); }, item_delete_sel->GetId());
|
||||
}
|
||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||
|
||||
#if !ENABLE_NEW_MENU_LAYOUT
|
||||
// Plater menu
|
||||
if (m_plater) {
|
||||
@ -321,18 +347,18 @@ void MainFrame::init_menubar()
|
||||
{
|
||||
size_t tab_offset = 0;
|
||||
if (m_plater) {
|
||||
append_menu_item(windowMenu, wxID_ANY, L("Select &Plater Tab\tCtrl+1"), L("Show the plater"),
|
||||
append_menu_item(windowMenu, wxID_ANY, L("Select 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_ANY, L("Select P&rint Settings Tab\tCtrl+2"), L("Show the print settings"),
|
||||
append_menu_item(windowMenu, wxID_ANY, L("Select Print 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_ANY, L("Select &Filament Settings Tab\tCtrl+3"), L("Show the filament settings"),
|
||||
append_menu_item(windowMenu, wxID_ANY, L("Select 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_ANY, L("Select Print&er Settings Tab\tCtrl+4"), L("Show the printer settings"),
|
||||
append_menu_item(windowMenu, wxID_ANY, L("Select Printer Settings Tab\tCtrl+4"), L("Show the printer settings"),
|
||||
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer_empty.png");
|
||||
}
|
||||
|
||||
@ -389,18 +415,18 @@ void MainFrame::init_menubar()
|
||||
//# 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")),
|
||||
[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")),
|
||||
[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(); });
|
||||
}
|
||||
|
||||
@ -410,6 +436,9 @@ void MainFrame::init_menubar()
|
||||
{
|
||||
auto menubar = new wxMenuBar();
|
||||
menubar->Append(fileMenu, L("&File"));
|
||||
#if ENABLE_NEW_MENU_LAYOUT
|
||||
if (editMenu) menubar->Append(editMenu, L("&Edit"));
|
||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||
#if !ENABLE_NEW_MENU_LAYOUT
|
||||
if (m_plater_menu) menubar->Append(m_plater_menu, L("&Plater"));
|
||||
#endif // !ENABLE_NEW_MENU_LAYOUT
|
||||
|
@ -71,6 +71,8 @@ class MainFrame : public wxFrame
|
||||
bool can_export_model() const;
|
||||
bool can_export_gcode() const;
|
||||
bool can_change_view() const;
|
||||
bool can_select() const;
|
||||
bool can_delete() const;
|
||||
#endif // ENABLE_NEW_MENU_LAYOUT
|
||||
|
||||
public:
|
||||
|
@ -951,6 +951,7 @@ struct Plater::priv
|
||||
void selection_changed();
|
||||
void object_list_changed();
|
||||
|
||||
void select_all();
|
||||
void remove(size_t obj_idx);
|
||||
void delete_object_from_model(size_t obj_idx);
|
||||
void reset();
|
||||
@ -1529,6 +1530,11 @@ void Plater::priv::object_list_changed()
|
||||
sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits);
|
||||
}
|
||||
|
||||
void Plater::priv::select_all()
|
||||
{
|
||||
_3DScene::select_all(canvas3D);
|
||||
}
|
||||
|
||||
void Plater::priv::remove(size_t obj_idx)
|
||||
{
|
||||
// Prevent toolpaths preview from rendering while we modify the Print object
|
||||
@ -2272,6 +2278,8 @@ void Plater::update() { p->update(); }
|
||||
|
||||
void Plater::select_view(const std::string& direction) { p->select_view(direction); }
|
||||
|
||||
void Plater::select_all() { p->select_all(); }
|
||||
|
||||
void Plater::remove(size_t obj_idx) { p->remove(obj_idx); }
|
||||
void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); }
|
||||
|
||||
@ -2358,6 +2366,11 @@ void Plater::set_number_of_copies(/*size_t num*/)
|
||||
decrease_instances(-diff);
|
||||
}
|
||||
|
||||
bool Plater::is_selection_empty() const
|
||||
{
|
||||
return p->get_selection().is_empty();
|
||||
}
|
||||
|
||||
void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z)
|
||||
{
|
||||
wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds");
|
||||
|
@ -128,12 +128,14 @@ public:
|
||||
void update();
|
||||
void select_view(const std::string& direction);
|
||||
|
||||
void select_all();
|
||||
void remove(size_t obj_idx);
|
||||
void delete_object_from_model(size_t obj_idx);
|
||||
void remove_selected();
|
||||
void increase_instances(size_t num = 1);
|
||||
void decrease_instances(size_t num = 1);
|
||||
void set_number_of_copies(/*size_t num*/);
|
||||
bool is_selection_empty() const;
|
||||
|
||||
void cut(size_t obj_idx, size_t instance_idx, coordf_t z);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user