mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-24 07:03:59 -06:00
Merge remote-tracking branch 'origin/master' into vb_undo_redo
This commit is contained in:
commit
c7cc760067
105 changed files with 3283 additions and 1599 deletions
|
@ -628,12 +628,12 @@ void Bed3D::render_prusa_shader(bool transparent) const
|
|||
if (position_id != -1)
|
||||
{
|
||||
glsafe(::glEnableVertexAttribArray(position_id));
|
||||
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset()));
|
||||
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset()));
|
||||
}
|
||||
if (tex_coords_id != -1)
|
||||
{
|
||||
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
||||
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset()));
|
||||
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset()));
|
||||
}
|
||||
|
||||
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
|
||||
|
|
|
@ -44,8 +44,8 @@ public:
|
|||
const float* get_vertices_data() const;
|
||||
unsigned int get_vertices_data_size() const { return (unsigned int)m_vertices.size() * get_vertex_data_size(); }
|
||||
unsigned int get_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); }
|
||||
unsigned int get_position_offset() const { return 0; }
|
||||
unsigned int get_tex_coords_offset() const { return (unsigned int)(3 * sizeof(float)); }
|
||||
size_t get_position_offset() const { return 0; }
|
||||
size_t get_tex_coords_offset() const { return (size_t)(3 * sizeof(float)); }
|
||||
unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); }
|
||||
#else
|
||||
const float* get_vertices() const { return m_vertices.data(); }
|
||||
|
|
|
@ -54,10 +54,9 @@ void AppConfig::set_defaults()
|
|||
if (get("preset_update").empty())
|
||||
set("preset_update", "1");
|
||||
|
||||
// Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers.
|
||||
// github.com/prusa3d/PrusaSlicer/issues/233
|
||||
if (get("use_legacy_opengl").empty())
|
||||
set("use_legacy_opengl", "0");
|
||||
// remove old 'use_legacy_opengl' parameter from this config, if present
|
||||
if (!get("use_legacy_opengl").empty())
|
||||
erase("", "use_legacy_opengl");
|
||||
|
||||
#if __APPLE__
|
||||
if (get("use_retina_opengl").empty())
|
||||
|
|
|
@ -53,15 +53,12 @@ void BedShapeDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|||
|
||||
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
||||
{
|
||||
// on_change(nullptr);
|
||||
|
||||
auto box = new wxStaticBox(this, wxID_ANY, _(L("Shape")));
|
||||
auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
|
||||
|
||||
// shape options
|
||||
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition,
|
||||
wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP);
|
||||
sbsizer->Add(m_shape_options_book);
|
||||
sbsizer->Add(m_shape_options_book);
|
||||
|
||||
auto optgroup = init_shape_options_page(_(L("Rectangular")));
|
||||
ConfigOptionDef def;
|
||||
|
@ -92,13 +89,15 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
Line line{ "", "" };
|
||||
line.full_width = 1;
|
||||
line.widget = [this](wxWindow* parent) {
|
||||
auto btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")), wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn);
|
||||
auto shape_btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")));
|
||||
wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
shape_sizer->Add(shape_btn, 1, wxEXPAND);
|
||||
|
||||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
||||
{
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(shape_sizer, 1, wxEXPAND);
|
||||
|
||||
shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||
{
|
||||
load_stl();
|
||||
}));
|
||||
|
||||
|
@ -106,8 +105,8 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent e)
|
||||
{
|
||||
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
|
||||
{
|
||||
update_shape();
|
||||
}));
|
||||
|
||||
|
@ -117,8 +116,8 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
|
||||
// main sizer
|
||||
auto top_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLeft | wxTOP | wxBOTTOM, 10);
|
||||
if (m_canvas)
|
||||
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 10);
|
||||
if (m_canvas)
|
||||
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ;
|
||||
|
||||
SetSizerAndFit(top_sizer);
|
||||
|
@ -135,8 +134,7 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
// Create a panel for a rectangular / circular / custom bed shape.
|
||||
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
|
||||
{
|
||||
|
||||
auto panel = new wxPanel(m_shape_options_book);
|
||||
auto panel = new wxPanel(m_shape_options_book);
|
||||
ConfigOptionsGroupShp optgroup;
|
||||
optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
|
||||
|
||||
|
@ -234,8 +232,8 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
|
|||
// This is a custom bed shape, use the polygon provided.
|
||||
m_shape_options_book->SetSelection(SHAPE_CUSTOM);
|
||||
// Copy the polygon to the canvas, make a copy of the array.
|
||||
m_canvas->m_bed_shape = points->values;
|
||||
update_shape();
|
||||
m_loaded_bed_shape = points->values;
|
||||
update_shape();
|
||||
}
|
||||
|
||||
void BedShapePanel::update_preview()
|
||||
|
|
|
@ -171,7 +171,7 @@ void BonjourDialog::on_reply(BonjourReplyEvent &e)
|
|||
// Filter replies based on selected technology
|
||||
const auto model = e.reply.txt_data.find("model");
|
||||
const bool sl1 = model != e.reply.txt_data.end() && model->second == "SL1";
|
||||
if (tech == ptFFF && sl1 || tech == ptSLA && !sl1) {
|
||||
if ((tech == ptFFF && sl1) || (tech == ptSLA && !sl1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace GUI {
|
|||
const double Camera::DefaultDistance = 1000.0;
|
||||
double Camera::FrustrumMinZSize = 50.0;
|
||||
double Camera::FrustrumZMargin = 10.0;
|
||||
double Camera::FovMinDeg = 5.0;
|
||||
double Camera::FovMinDeg = 0.5;
|
||||
double Camera::FovMaxDeg = 75.0;
|
||||
|
||||
Camera::Camera()
|
||||
|
|
|
@ -330,8 +330,8 @@ PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortn
|
|||
const auto families = vendor.families();
|
||||
for (const auto &family : families) {
|
||||
const auto filter = [&](const VendorProfile::PrinterModel &model) {
|
||||
return (model.technology == ptFFF && technology & T_FFF
|
||||
|| model.technology == ptSLA && technology & T_SLA)
|
||||
return ((model.technology == ptFFF && technology & T_FFF)
|
||||
|| (model.technology == ptSLA && technology & T_SLA))
|
||||
&& model.family == family;
|
||||
};
|
||||
|
||||
|
@ -810,7 +810,7 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
|
|||
const Item& item = items[i];
|
||||
unsigned x = em_w/2 + item.indent * em_w;
|
||||
|
||||
if (i == item_active || item_hover >= 0 && i == (size_t)item_hover) {
|
||||
if (i == item_active || (item_hover >= 0 && i == (size_t)item_hover)) {
|
||||
dc.DrawBitmap(bullet_blue.bmp(), x, y + yoff_icon, false);
|
||||
}
|
||||
else if (i < item_active) { dc.DrawBitmap(bullet_black.bmp(), x, y + yoff_icon, false); }
|
||||
|
|
|
@ -113,11 +113,19 @@ wxString Field::get_tooltip_text(const wxString& default_string)
|
|||
wxString tooltip_text("");
|
||||
wxString tooltip = _(m_opt.tooltip);
|
||||
edit_tooltip(tooltip);
|
||||
|
||||
std::string opt_id = m_opt_id;
|
||||
auto hash_pos = opt_id.find("#");
|
||||
if (hash_pos != std::string::npos) {
|
||||
opt_id.replace(hash_pos, 1,"[");
|
||||
opt_id += "]";
|
||||
}
|
||||
|
||||
if (tooltip.length() > 0)
|
||||
tooltip_text = tooltip + "\n" + _(L("default value")) + "\t: " +
|
||||
(boost::iends_with(m_opt_id, "_gcode") ? "\n" : "") + default_string +
|
||||
(boost::iends_with(m_opt_id, "_gcode") ? "" : "\n") +
|
||||
_(L("parameter name")) + "\t: " + m_opt_id;
|
||||
(boost::iends_with(opt_id, "_gcode") ? "\n" : "") + default_string +
|
||||
(boost::iends_with(opt_id, "_gcode") ? "" : "\n") +
|
||||
_(L("parameter name")) + "\t: " + opt_id;
|
||||
|
||||
return tooltip_text;
|
||||
}
|
||||
|
|
|
@ -442,8 +442,7 @@ void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid)
|
|||
auto ports = Utils::scan_serial_ports_extended();
|
||||
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
|
||||
return port.id_vendor != USB_VID_PRUSA ||
|
||||
port.id_product != usb_pid.boot &&
|
||||
port.id_product != usb_pid.app;
|
||||
(port.id_product != usb_pid.boot && port.id_product != usb_pid.app);
|
||||
}), ports.end());
|
||||
|
||||
if (ports.size() == 0) {
|
||||
|
|
|
@ -198,8 +198,7 @@ void GLCanvas3D::Shader::_reset()
|
|||
#endif // !ENABLE_TEXTURES_FROM_SVG
|
||||
|
||||
GLCanvas3D::LayersEditing::LayersEditing()
|
||||
: m_use_legacy_opengl(false)
|
||||
, m_enabled(false)
|
||||
: m_enabled(false)
|
||||
, m_z_texture_id(0)
|
||||
, m_model_object(nullptr)
|
||||
, m_object_max_z(0.f)
|
||||
|
@ -274,12 +273,7 @@ void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
|
|||
|
||||
bool GLCanvas3D::LayersEditing::is_allowed() const
|
||||
{
|
||||
return !m_use_legacy_opengl && m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0;
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::set_use_legacy_opengl(bool use_legacy_opengl)
|
||||
{
|
||||
m_use_legacy_opengl = use_legacy_opengl;
|
||||
return m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0;
|
||||
}
|
||||
|
||||
bool GLCanvas3D::LayersEditing::is_enabled() const
|
||||
|
@ -463,8 +457,10 @@ void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const
|
|||
{
|
||||
//FIXME show some kind of legend.
|
||||
|
||||
if (!m_slicing_parameters)
|
||||
return;
|
||||
|
||||
// Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region.
|
||||
assert(m_slicing_parameters != nullptr);
|
||||
float scale_x = bar_rect.get_width() / (float)(1.12 * m_slicing_parameters->max_layer_height);
|
||||
float scale_y = bar_rect.get_height() / m_object_max_z;
|
||||
float x = bar_rect.get_left() + (float)m_slicing_parameters->layer_height * scale_x;
|
||||
|
@ -916,7 +912,8 @@ GLCanvas3D::LegendTexture::LegendTexture()
|
|||
void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePreviewData& preview_data, const GLCanvas3D& canvas,
|
||||
std::vector<std::pair<double, double>>& cp_legend_values)
|
||||
{
|
||||
if (preview_data.extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint)
|
||||
if (preview_data.extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint &&
|
||||
wxGetApp().extruders_edited_cnt() == 1) // show color change legend only for single-material presets
|
||||
{
|
||||
auto& config = wxGetApp().preset_bundle->project_config;
|
||||
const std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->values;
|
||||
|
@ -1230,6 +1227,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
|
|||
, m_cursor_type(Standard)
|
||||
, m_color_by("volume")
|
||||
, m_reload_delayed(false)
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
, m_show_picking_texture(false)
|
||||
#endif // ENABLE_RENDER_PICKING_PASS
|
||||
, m_render_sla_auxiliaries(true)
|
||||
{
|
||||
if (m_canvas != nullptr) {
|
||||
|
@ -1255,7 +1255,7 @@ void GLCanvas3D::post_event(wxEvent &&event)
|
|||
wxPostEvent(m_canvas, event);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl)
|
||||
bool GLCanvas3D::init(bool useVBOs)
|
||||
{
|
||||
if (m_initialized)
|
||||
return true;
|
||||
|
@ -1313,7 +1313,6 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl)
|
|||
return false;
|
||||
|
||||
m_use_VBOs = useVBOs;
|
||||
m_layers_editing.set_use_legacy_opengl(use_legacy_opengl);
|
||||
|
||||
// on linux the gl context is not valid until the canvas is not shown on screen
|
||||
// we defer the geometry finalization of volumes until the first call to render()
|
||||
|
@ -1634,6 +1633,10 @@ void GLCanvas3D::render()
|
|||
_picking_pass();
|
||||
}
|
||||
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
if (!m_picking_enabled || !m_show_picking_texture)
|
||||
{
|
||||
#endif // ENABLE_RENDER_PICKING_PASS
|
||||
// draw scene
|
||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
_render_background();
|
||||
|
@ -1663,6 +1666,9 @@ void GLCanvas3D::render()
|
|||
|
||||
_render_current_gizmo();
|
||||
_render_selection_sidebar_hints();
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
}
|
||||
#endif // ENABLE_RENDER_PICKING_PASS
|
||||
|
||||
#if ENABLE_SHOW_CAMERA_TARGET
|
||||
_render_camera_target();
|
||||
|
@ -2423,6 +2429,14 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
case 'k': { m_camera.select_next_type(); m_dirty = true; break; }
|
||||
case 'O':
|
||||
case 'o': { set_camera_zoom(-1.0); break; }
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
case 'T':
|
||||
case 't': {
|
||||
m_show_picking_texture = !m_show_picking_texture;
|
||||
m_dirty = true;
|
||||
break;
|
||||
}
|
||||
#endif // ENABLE_RENDER_PICKING_PASS
|
||||
case 'Z':
|
||||
case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; }
|
||||
default: { evt.Skip(); break; }
|
||||
|
@ -3331,6 +3345,12 @@ void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool foc
|
|||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type)
|
||||
{
|
||||
std::string field = "layer_" + std::to_string(type) + "_" + std::to_string(range.first) + "_" + std::to_string(range.second);
|
||||
handle_sidebar_focus_event(field, true);
|
||||
}
|
||||
|
||||
void GLCanvas3D::update_ui_from_settings()
|
||||
{
|
||||
m_camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
|
||||
|
@ -4296,13 +4316,7 @@ void GLCanvas3D::_render_sla_slices() const
|
|||
|
||||
void GLCanvas3D::_render_selection_sidebar_hints() const
|
||||
{
|
||||
if (m_use_VBOs)
|
||||
m_shader.start_using();
|
||||
|
||||
m_selection.render_sidebar_hints(m_sidebar_field);
|
||||
|
||||
if (m_use_VBOs)
|
||||
m_shader.stop_using();
|
||||
m_selection.render_sidebar_hints(m_sidebar_field, m_shader);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Camera.hpp"
|
||||
#include "Selection.hpp"
|
||||
#include "Gizmos/GLGizmosManager.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
|
@ -199,7 +200,6 @@ class GLCanvas3D
|
|||
static const float THICKNESS_BAR_WIDTH;
|
||||
static const float THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
|
||||
bool m_use_legacy_opengl;
|
||||
bool m_enabled;
|
||||
Shader m_shader;
|
||||
unsigned int m_z_texture_id;
|
||||
|
@ -252,7 +252,6 @@ class GLCanvas3D
|
|||
void select_object(const Model &model, int object_id);
|
||||
|
||||
bool is_allowed() const;
|
||||
void set_use_legacy_opengl(bool use_legacy_opengl);
|
||||
|
||||
bool is_enabled() const;
|
||||
void set_enabled(bool enabled);
|
||||
|
@ -481,6 +480,10 @@ private:
|
|||
|
||||
GCodePreviewVolumeIndex m_gcode_preview_volume_index;
|
||||
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
bool m_show_picking_texture;
|
||||
#endif // ENABLE_RENDER_PICKING_PASS
|
||||
|
||||
#if ENABLE_RENDER_STATISTICS
|
||||
RenderStats m_render_stats;
|
||||
#endif // ENABLE_RENDER_STATISTICS
|
||||
|
@ -494,7 +497,7 @@ public:
|
|||
wxGLCanvas* get_wxglcanvas() { return m_canvas; }
|
||||
const wxGLCanvas* get_wxglcanvas() const { return m_canvas; }
|
||||
|
||||
bool init(bool useVBOs, bool use_legacy_opengl);
|
||||
bool init(bool useVBOs);
|
||||
void post_event(wxEvent &&event);
|
||||
|
||||
void set_as_dirty();
|
||||
|
@ -608,6 +611,7 @@ public:
|
|||
void reset_all_gizmos() { m_gizmos.reset_all_states(); }
|
||||
|
||||
void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on);
|
||||
void handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type);
|
||||
|
||||
void update_ui_from_settings();
|
||||
|
||||
|
|
|
@ -192,7 +192,6 @@ GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
|
|||
GLCanvas3DManager::GLCanvas3DManager()
|
||||
: m_context(nullptr)
|
||||
, m_gl_initialized(false)
|
||||
, m_use_legacy_opengl(false)
|
||||
, m_use_VBOs(false)
|
||||
{
|
||||
}
|
||||
|
@ -268,8 +267,7 @@ void GLCanvas3DManager::init_gl()
|
|||
{
|
||||
glewInit();
|
||||
const AppConfig* config = GUI::get_app_config();
|
||||
m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1");
|
||||
m_use_VBOs = !m_use_legacy_opengl && s_gl_info.is_version_greater_or_equal_to(2, 0);
|
||||
m_use_VBOs = s_gl_info.is_version_greater_or_equal_to(2, 0);
|
||||
m_gl_initialized = true;
|
||||
if (GLEW_EXT_texture_compression_s3tc)
|
||||
s_compressed_textures_supported = true;
|
||||
|
@ -325,16 +323,14 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas)
|
|||
if (!m_gl_initialized)
|
||||
init_gl();
|
||||
|
||||
return canvas.init(m_use_VBOs, m_use_legacy_opengl);
|
||||
return canvas.init(m_use_VBOs);
|
||||
}
|
||||
|
||||
void GLCanvas3DManager::detect_multisample(int* attribList)
|
||||
{
|
||||
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
|
||||
const AppConfig* app_config = GUI::get_app_config();
|
||||
bool enable_multisample = app_config != nullptr
|
||||
&& app_config->get("use_legacy_opengl") != "1"
|
||||
&& wxVersion >= 30003;
|
||||
bool enable_multisample = wxVersion >= 30003;
|
||||
|
||||
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled;
|
||||
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
|
||||
|
|
|
@ -75,7 +75,6 @@ private:
|
|||
wxGLContext* m_context;
|
||||
static GLInfo s_gl_info;
|
||||
bool m_gl_initialized;
|
||||
bool m_use_legacy_opengl;
|
||||
bool m_use_VBOs;
|
||||
static EMultisampleState s_multisample;
|
||||
static bool s_compressed_textures_supported;
|
||||
|
|
|
@ -68,7 +68,8 @@ namespace GUI {
|
|||
if (!is_dragging())
|
||||
return;
|
||||
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
const Camera& camera = canvas.get_camera();
|
||||
float zoom = (float)camera.get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
Size cnv_size = canvas.get_canvas_size();
|
||||
|
@ -96,6 +97,11 @@ namespace GUI {
|
|||
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glLoadIdentity());
|
||||
// ensure that the rectangle is renderered inside the frustrum
|
||||
glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5)));
|
||||
// ensure that the overlay fits the frustrum near z plane
|
||||
double gui_scale = camera.get_gui_scale();
|
||||
glsafe(::glScaled(gui_scale, gui_scale, 1.0));
|
||||
|
||||
glsafe(::glPushAttrib(GL_ENABLE_BIT));
|
||||
glsafe(::glLineStipple(4, 0xAAAA));
|
||||
|
|
|
@ -141,6 +141,18 @@ GUI_App::GUI_App()
|
|||
, m_imgui(new ImGuiWrapper())
|
||||
{}
|
||||
|
||||
GUI_App::~GUI_App()
|
||||
{
|
||||
if (app_config != nullptr)
|
||||
delete app_config;
|
||||
|
||||
if (preset_bundle != nullptr)
|
||||
delete preset_bundle;
|
||||
|
||||
if (preset_updater != nullptr)
|
||||
delete preset_updater;
|
||||
}
|
||||
|
||||
bool GUI_App::OnInit()
|
||||
{
|
||||
try {
|
||||
|
@ -922,6 +934,11 @@ ObjectList* GUI_App::obj_list()
|
|||
return sidebar().obj_list();
|
||||
}
|
||||
|
||||
ObjectLayers* GUI_App::obj_layers()
|
||||
{
|
||||
return sidebar().obj_layers();
|
||||
}
|
||||
|
||||
Plater* GUI_App::plater()
|
||||
{
|
||||
return plater_;
|
||||
|
|
|
@ -95,6 +95,7 @@ public:
|
|||
bool initialized() const { return m_initialized; }
|
||||
|
||||
GUI_App();
|
||||
~GUI_App();
|
||||
|
||||
static unsigned get_colour_approx_luma(const wxColour &colour);
|
||||
static bool dark_mode();
|
||||
|
@ -155,6 +156,7 @@ public:
|
|||
ObjectManipulation* obj_manipul();
|
||||
ObjectSettings* obj_settings();
|
||||
ObjectList* obj_list();
|
||||
ObjectLayers* obj_layers();
|
||||
Plater* plater();
|
||||
std::vector<ModelObject*> *model_objects();
|
||||
|
||||
|
|
341
src/slic3r/GUI/GUI_ObjectLayers.cpp
Normal file
341
src/slic3r/GUI/GUI_ObjectLayers.cpp
Normal file
|
@ -0,0 +1,341 @@
|
|||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
|
||||
#include "OptionsGroup.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <wx/wupdlock.h>
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
namespace GUI
|
||||
{
|
||||
|
||||
ObjectLayers::ObjectLayers(wxWindow* parent) :
|
||||
OG_Settings(parent, true)
|
||||
{
|
||||
m_grid_sizer = new wxFlexGridSizer(3, 5, 5); // "Min Z", "Max Z", "Layer height" & buttons sizer
|
||||
m_grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
||||
|
||||
// Legend for object layers
|
||||
for (const std::string col : { "Min Z", "Max Z", "Layer height" }) {
|
||||
auto temp = new wxStaticText(m_parent, wxID_ANY, _(L(col)), wxDefaultPosition, /*size*/wxDefaultSize, wxST_ELLIPSIZE_MIDDLE);
|
||||
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
temp->SetFont(wxGetApp().bold_font());
|
||||
|
||||
m_grid_sizer->Add(temp);
|
||||
}
|
||||
|
||||
m_og->sizer->Clear(true);
|
||||
m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 5);
|
||||
|
||||
m_bmp_delete = ScalableBitmap(parent, "remove_copies"/*"cross"*/);
|
||||
m_bmp_add = ScalableBitmap(parent, "add_copies");
|
||||
}
|
||||
|
||||
void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_edited_range)
|
||||
{
|
||||
if (is_last_edited_range && m_selection_type == editor->type()) {
|
||||
/* Workaround! Under OSX we should use CallAfter() for SetFocus() after LayerEditors "reorganizations",
|
||||
* because of selected control's strange behavior:
|
||||
* cursor is set to the control, but blue border - doesn't.
|
||||
* And as a result we couldn't edit this control.
|
||||
* */
|
||||
#ifdef __WXOSX__
|
||||
wxTheApp->CallAfter([editor]() {
|
||||
#endif
|
||||
editor->SetFocus();
|
||||
editor->SetInsertionPointEnd();
|
||||
#ifdef __WXOSX__
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
|
||||
{
|
||||
const bool is_last_edited_range = range == m_selectable_range;
|
||||
|
||||
auto set_focus_data = [range, this](const EditorType type)
|
||||
{
|
||||
m_selectable_range = range;
|
||||
m_selection_type = type;
|
||||
};
|
||||
|
||||
auto update_focus_data = [range, this](const t_layer_height_range& new_range, EditorType type, bool enter_pressed)
|
||||
{
|
||||
// change selectable range for new one, if enter was pressed or if same range was selected
|
||||
if (enter_pressed || m_selectable_range == range)
|
||||
m_selectable_range = new_range;
|
||||
if (enter_pressed)
|
||||
m_selection_type = type;
|
||||
};
|
||||
|
||||
// Add control for the "Min Z"
|
||||
|
||||
auto editor = new LayerRangeEditor(this, double_to_string(range.first), etMinZ,
|
||||
set_focus_data, [range, update_focus_data, this](coordf_t min_z, bool enter_pressed)
|
||||
{
|
||||
if (fabs(min_z - range.first) < EPSILON) {
|
||||
m_selection_type = etUndef;
|
||||
return false;
|
||||
}
|
||||
|
||||
// data for next focusing
|
||||
coordf_t max_z = min_z < range.second ? range.second : min_z + 0.5;
|
||||
const t_layer_height_range& new_range = { min_z, max_z };
|
||||
update_focus_data(new_range, etMinZ, enter_pressed);
|
||||
|
||||
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
|
||||
});
|
||||
|
||||
select_editor(editor, is_last_edited_range);
|
||||
m_grid_sizer->Add(editor);
|
||||
|
||||
// Add control for the "Max Z"
|
||||
|
||||
editor = new LayerRangeEditor(this, double_to_string(range.second), etMaxZ,
|
||||
set_focus_data, [range, update_focus_data, this](coordf_t max_z, bool enter_pressed)
|
||||
{
|
||||
if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
|
||||
m_selection_type = etUndef;
|
||||
return false; // LayersList would not be updated/recreated
|
||||
}
|
||||
|
||||
// data for next focusing
|
||||
const t_layer_height_range& new_range = { range.first, max_z };
|
||||
update_focus_data(new_range, etMaxZ, enter_pressed);
|
||||
|
||||
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
|
||||
});
|
||||
|
||||
select_editor(editor, is_last_edited_range);
|
||||
m_grid_sizer->Add(editor);
|
||||
|
||||
// Add control for the "Layer height"
|
||||
|
||||
editor = new LayerRangeEditor(this,
|
||||
double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()),
|
||||
etLayerHeight, set_focus_data, [range, this](coordf_t layer_height, bool)
|
||||
{
|
||||
return wxGetApp().obj_list()->edit_layer_range(range, layer_height);
|
||||
});
|
||||
|
||||
select_editor(editor, is_last_edited_range);
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(editor);
|
||||
m_grid_sizer->Add(sizer);
|
||||
|
||||
return sizer;
|
||||
}
|
||||
|
||||
void ObjectLayers::create_layers_list()
|
||||
{
|
||||
for (const auto layer : m_object->layer_config_ranges)
|
||||
{
|
||||
const t_layer_height_range& range = layer.first;
|
||||
auto sizer = create_layer(range);
|
||||
|
||||
auto del_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_delete);
|
||||
del_btn->SetToolTip(_(L("Remove layer")));
|
||||
|
||||
sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
|
||||
|
||||
del_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
|
||||
wxGetApp().obj_list()->del_layer_range(range);
|
||||
});
|
||||
|
||||
auto add_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_add);
|
||||
add_btn->SetToolTip(_(L("Add layer")));
|
||||
|
||||
sizer->Add(add_btn, 0, wxRIGHT, em_unit(m_parent));
|
||||
|
||||
add_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
|
||||
wxGetApp().obj_list()->add_layer_range_after_current(range);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectLayers::update_layers_list()
|
||||
{
|
||||
ObjectList* objects_ctrl = wxGetApp().obj_list();
|
||||
if (objects_ctrl->multiple_selection()) return;
|
||||
|
||||
const auto item = objects_ctrl->GetSelection();
|
||||
if (!item) return;
|
||||
|
||||
const int obj_idx = objects_ctrl->get_selected_obj_idx();
|
||||
if (obj_idx < 0) return;
|
||||
|
||||
const ItemType type = objects_ctrl->GetModel()->GetItemType(item);
|
||||
if (!(type & (itLayerRoot | itLayer))) return;
|
||||
|
||||
m_object = objects_ctrl->object(obj_idx);
|
||||
if (!m_object || m_object->layer_config_ranges.empty()) return;
|
||||
|
||||
// Delete all controls from options group except of the legends
|
||||
|
||||
const int cols = m_grid_sizer->GetEffectiveColsCount();
|
||||
const int rows = m_grid_sizer->GetEffectiveRowsCount();
|
||||
for (int idx = cols*rows-1; idx >= cols; idx--) {
|
||||
wxSizerItem* t = m_grid_sizer->GetItem(idx);
|
||||
if (t->IsSizer())
|
||||
t->GetSizer()->Clear(true);
|
||||
else
|
||||
t->DeleteWindows();
|
||||
m_grid_sizer->Remove(idx);
|
||||
}
|
||||
|
||||
// Add new control according to the selected item
|
||||
|
||||
if (type & itLayerRoot)
|
||||
create_layers_list();
|
||||
else
|
||||
create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item));
|
||||
|
||||
m_parent->Layout();
|
||||
}
|
||||
|
||||
void ObjectLayers::update_scene_from_editor_selection() const
|
||||
{
|
||||
// needed to show the visual hints in 3D scene
|
||||
wxGetApp().plater()->canvas3D()->handle_layers_data_focus_event(m_selectable_range, m_selection_type);
|
||||
}
|
||||
|
||||
void ObjectLayers::UpdateAndShow(const bool show)
|
||||
{
|
||||
if (show)
|
||||
update_layers_list();
|
||||
|
||||
OG_Settings::UpdateAndShow(show);
|
||||
}
|
||||
|
||||
void ObjectLayers::msw_rescale()
|
||||
{
|
||||
m_bmp_delete.msw_rescale();
|
||||
m_bmp_add.msw_rescale();
|
||||
}
|
||||
|
||||
void ObjectLayers::reset_selection()
|
||||
{
|
||||
m_selectable_range = { 0.0, 0.0 };
|
||||
m_selection_type = etLayerHeight;
|
||||
}
|
||||
|
||||
LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
|
||||
const wxString& value,
|
||||
EditorType type,
|
||||
std::function<void(EditorType)> set_focus_data_fn,
|
||||
std::function<bool(coordf_t, bool enter_pressed)> edit_fn
|
||||
) :
|
||||
m_valid_value(value),
|
||||
m_type(type),
|
||||
m_set_focus_data(set_focus_data_fn),
|
||||
wxTextCtrl(parent->m_parent, wxID_ANY, value, wxDefaultPosition,
|
||||
wxSize(8 * em_unit(parent->m_parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
|
||||
{
|
||||
this->SetFont(wxGetApp().normal_font());
|
||||
|
||||
this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
|
||||
{
|
||||
m_enter_pressed = true;
|
||||
// If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
|
||||
if (m_type&etLayerHeight) {
|
||||
if (!edit_fn(get_value(), true))
|
||||
SetValue(m_valid_value);
|
||||
else
|
||||
m_valid_value = double_to_string(get_value());
|
||||
m_call_kill_focus = true;
|
||||
}
|
||||
else if (!edit_fn(get_value(), true)) {
|
||||
SetValue(m_valid_value);
|
||||
m_call_kill_focus = true;
|
||||
}
|
||||
}, this->GetId());
|
||||
|
||||
this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
|
||||
{
|
||||
if (!m_enter_pressed) {
|
||||
#ifndef __WXGTK__
|
||||
/* Update data for next editor selection.
|
||||
* But under GTK it lucks like there is no information about selected control at e.GetWindow(),
|
||||
* so we'll take it from wxEVT_LEFT_DOWN event
|
||||
* */
|
||||
LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
|
||||
if (new_editor)
|
||||
new_editor->set_focus_data();
|
||||
#endif // not __WXGTK__
|
||||
// If LayersList wasn't updated/recreated, we should call e.Skip()
|
||||
if (m_type & etLayerHeight) {
|
||||
if (!edit_fn(get_value(), false))
|
||||
SetValue(m_valid_value);
|
||||
else
|
||||
m_valid_value = double_to_string(get_value());
|
||||
e.Skip();
|
||||
}
|
||||
else if (!edit_fn(get_value(), false)) {
|
||||
SetValue(m_valid_value);
|
||||
e.Skip();
|
||||
}
|
||||
}
|
||||
else if (m_call_kill_focus) {
|
||||
m_call_kill_focus = false;
|
||||
e.Skip();
|
||||
}
|
||||
}, this->GetId());
|
||||
|
||||
this->Bind(wxEVT_SET_FOCUS, [this, parent](wxFocusEvent& e)
|
||||
{
|
||||
set_focus_data();
|
||||
parent->update_scene_from_editor_selection();
|
||||
e.Skip();
|
||||
}, this->GetId());
|
||||
|
||||
#ifdef __WXGTK__ // Workaround! To take information about selectable range
|
||||
this->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e)
|
||||
{
|
||||
set_focus_data();
|
||||
e.Skip();
|
||||
}, this->GetId());
|
||||
#endif //__WXGTK__
|
||||
|
||||
this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
|
||||
{
|
||||
// select all text using Ctrl+A
|
||||
if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
|
||||
this->SetSelection(-1, -1); //select all
|
||||
event.Skip();
|
||||
}));
|
||||
}
|
||||
|
||||
coordf_t LayerRangeEditor::get_value()
|
||||
{
|
||||
wxString str = GetValue();
|
||||
|
||||
coordf_t layer_height;
|
||||
// Replace the first occurence of comma in decimal number.
|
||||
str.Replace(",", ".", false);
|
||||
if (str == ".")
|
||||
layer_height = 0.0;
|
||||
else
|
||||
{
|
||||
if (!str.ToCDouble(&layer_height) || layer_height < 0.0f)
|
||||
{
|
||||
show_error(m_parent, _(L("Invalid numeric input.")));
|
||||
SetValue(double_to_string(layer_height));
|
||||
}
|
||||
}
|
||||
|
||||
return layer_height;
|
||||
}
|
||||
|
||||
} //namespace GUI
|
||||
} //namespace Slic3r
|
88
src/slic3r/GUI/GUI_ObjectLayers.hpp
Normal file
88
src/slic3r/GUI/GUI_ObjectLayers.hpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
#ifndef slic3r_GUI_ObjectLayers_hpp_
|
||||
#define slic3r_GUI_ObjectLayers_hpp_
|
||||
|
||||
#include "GUI_ObjectSettings.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#ifdef __WXOSX__
|
||||
#include "../libslic3r/PrintConfig.hpp"
|
||||
#endif
|
||||
|
||||
class wxBoxSizer;
|
||||
|
||||
namespace Slic3r {
|
||||
class ModelObject;
|
||||
|
||||
namespace GUI {
|
||||
class ConfigOptionsGroup;
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
|
||||
class ObjectLayers;
|
||||
|
||||
enum EditorType
|
||||
{
|
||||
etUndef = 0,
|
||||
etMinZ = 1,
|
||||
etMaxZ = 2,
|
||||
etLayerHeight = 4,
|
||||
};
|
||||
|
||||
class LayerRangeEditor : public wxTextCtrl
|
||||
{
|
||||
bool m_enter_pressed { false };
|
||||
bool m_call_kill_focus { false };
|
||||
wxString m_valid_value;
|
||||
EditorType m_type;
|
||||
|
||||
std::function<void(EditorType)> m_set_focus_data;
|
||||
|
||||
public:
|
||||
LayerRangeEditor( ObjectLayers* parent,
|
||||
const wxString& value = wxEmptyString,
|
||||
EditorType type = etUndef,
|
||||
std::function<void(EditorType)> set_focus_data_fn = [](EditorType) {;},
|
||||
std::function<bool(coordf_t, bool)> edit_fn = [](coordf_t, bool) {return false; }
|
||||
);
|
||||
~LayerRangeEditor() {}
|
||||
|
||||
EditorType type() const {return m_type;}
|
||||
void set_focus_data() const { m_set_focus_data(m_type);}
|
||||
|
||||
private:
|
||||
coordf_t get_value();
|
||||
};
|
||||
|
||||
class ObjectLayers : public OG_Settings
|
||||
{
|
||||
ScalableBitmap m_bmp_delete;
|
||||
ScalableBitmap m_bmp_add;
|
||||
ModelObject* m_object {nullptr};
|
||||
|
||||
wxFlexGridSizer* m_grid_sizer;
|
||||
t_layer_height_range m_selectable_range;
|
||||
EditorType m_selection_type {etUndef};
|
||||
|
||||
public:
|
||||
ObjectLayers(wxWindow* parent);
|
||||
~ObjectLayers() {}
|
||||
|
||||
void select_editor(LayerRangeEditor* editor, const bool is_last_edited_range);
|
||||
wxSizer* create_layer(const t_layer_height_range& range); // without_buttons
|
||||
void create_layers_list();
|
||||
void update_layers_list();
|
||||
|
||||
void update_scene_from_editor_selection() const;
|
||||
|
||||
void UpdateAndShow(const bool show) override;
|
||||
void msw_rescale();
|
||||
void reset_selection();
|
||||
void set_selectable_range(const t_layer_height_range& range) { m_selectable_range = range; }
|
||||
|
||||
friend class LayerRangeEditor;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // slic3r_GUI_ObjectLayers_hpp_
|
|
@ -1,6 +1,7 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
|
@ -152,10 +153,10 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||
wxAcceleratorTable accel(6, entries);
|
||||
SetAcceleratorTable(accel);
|
||||
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY)); }, wxID_COPY);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE)); }, wxID_PASTE);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->copy(); }, wxID_COPY);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->paste(); }, wxID_PASTE);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
|
||||
}
|
||||
#else __WXOSX__
|
||||
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
|
||||
|
@ -355,12 +356,13 @@ DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) cons
|
|||
const ItemType type = m_objects_model->GetItemType(item);
|
||||
|
||||
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
|
||||
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||
|
||||
const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
|
||||
|
||||
assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0));
|
||||
return type & itVolume ?(*m_objects)[obj_idx]->volumes[vol_idx]->config :
|
||||
type & itLayer ?(*m_objects)[obj_idx]->layer_config_ranges[m_objects_model->GetLayerRangeByItem(item)] :
|
||||
(*m_objects)[obj_idx]->config;
|
||||
}
|
||||
|
||||
|
@ -446,16 +448,23 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
|
|||
{
|
||||
if (m_prevent_update_extruder_in_config)
|
||||
return;
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
|
||||
|
||||
const ItemType item_type = m_objects_model->GetItemType(item);
|
||||
if (item_type & itObject) {
|
||||
const int obj_idx = m_objects_model->GetIdByItem(item);
|
||||
m_config = &(*m_objects)[obj_idx]->config;
|
||||
}
|
||||
else {
|
||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
|
||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||
if (item_type & itVolume)
|
||||
{
|
||||
const int volume_id = m_objects_model->GetVolumeIdByItem(item);
|
||||
if (obj_idx < 0 || volume_id < 0)
|
||||
return;
|
||||
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
||||
}
|
||||
else if (item_type & itLayer)
|
||||
m_config = &get_item_config(item);
|
||||
}
|
||||
|
||||
wxVariant variant;
|
||||
|
@ -465,7 +474,7 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
|
|||
if (!m_config || selection.empty())
|
||||
return;
|
||||
|
||||
const int extruder = selection.size() > 1 ? 0 : atoi(selection.c_str());
|
||||
const int extruder = /*selection.size() > 1 ? 0 : */atoi(selection.c_str());
|
||||
m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
|
||||
|
||||
// update scene
|
||||
|
@ -574,9 +583,75 @@ void ObjectList::selection_changed()
|
|||
wxPostEvent(this, event);
|
||||
}
|
||||
|
||||
if (const wxDataViewItem item = GetSelection())
|
||||
{
|
||||
const ItemType type = m_objects_model->GetItemType(item);
|
||||
// to correct visual hints for layers editing on the Scene
|
||||
if (type & (itLayer|itLayerRoot)) {
|
||||
wxGetApp().obj_layers()->reset_selection();
|
||||
|
||||
if (type & itLayerRoot)
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
|
||||
else {
|
||||
wxGetApp().obj_layers()->set_selectable_range(m_objects_model->GetLayerRangeByItem(item));
|
||||
wxGetApp().obj_layers()->update_scene_from_editor_selection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
part_selection_changed();
|
||||
}
|
||||
|
||||
void ObjectList::fill_layer_config_ranges_cache()
|
||||
{
|
||||
wxDataViewItemArray sel_layers;
|
||||
GetSelections(sel_layers);
|
||||
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers[0]);
|
||||
if (obj_idx < 0 || (int)m_objects->size() <= obj_idx)
|
||||
return;
|
||||
|
||||
const t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
m_layer_config_ranges_cache.clear();
|
||||
|
||||
for (const auto layer_item : sel_layers)
|
||||
if (m_objects_model->GetItemType(layer_item) & itLayer) {
|
||||
auto range = m_objects_model->GetLayerRangeByItem(layer_item);
|
||||
auto it = ranges.find(range);
|
||||
if (it != ranges.end())
|
||||
m_layer_config_ranges_cache[it->first] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectList::paste_layers_into_list()
|
||||
{
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(GetSelection());
|
||||
|
||||
if (obj_idx < 0 || (int)m_objects->size() <= obj_idx ||
|
||||
m_layer_config_ranges_cache.empty() || printer_technology() == ptSLA)
|
||||
return;
|
||||
|
||||
const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
|
||||
wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
|
||||
if (layers_item)
|
||||
m_objects_model->Delete(layers_item);
|
||||
|
||||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
||||
// and create Layer item(s) according to the layer_config_ranges
|
||||
for (const auto range : m_layer_config_ranges_cache)
|
||||
ranges.emplace(range);
|
||||
|
||||
layers_item = add_layer_root_item(object_item);
|
||||
|
||||
changed_object(obj_idx);
|
||||
|
||||
select_item(layers_item);
|
||||
#ifndef __WXOSX__
|
||||
selection_changed();
|
||||
#endif //no __WXOSX__
|
||||
}
|
||||
|
||||
void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes)
|
||||
{
|
||||
if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx))
|
||||
|
@ -657,7 +732,7 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
|
|||
const wxPoint pt = get_mouse_position_in_control();
|
||||
HitTest(pt, item, col);
|
||||
if (!item)
|
||||
#ifdef __WXOSX__ // #ys_FIXME temporary workaround for OSX
|
||||
#ifdef __WXOSX__ // temporary workaround for OSX
|
||||
// after Yosemite OS X version, HitTest return undefined item
|
||||
item = GetSelection();
|
||||
if (item)
|
||||
|
@ -703,10 +778,11 @@ void ObjectList::show_context_menu()
|
|||
if (item)
|
||||
{
|
||||
const ItemType type = m_objects_model->GetItemType(item);
|
||||
if (!(type & (itObject | itVolume | itInstance)))
|
||||
if (!(type & (itObject | itVolume | itLayer | itInstance)))
|
||||
return;
|
||||
|
||||
wxMenu* menu = type & itInstance ? &m_menu_instance :
|
||||
type & itLayer ? &m_menu_layer :
|
||||
m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
|
||||
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
|
||||
|
||||
|
@ -717,6 +793,22 @@ void ObjectList::show_context_menu()
|
|||
}
|
||||
}
|
||||
|
||||
void ObjectList::copy()
|
||||
{
|
||||
if (m_selection_mode & smLayer)
|
||||
fill_layer_config_ranges_cache();
|
||||
else
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
|
||||
}
|
||||
|
||||
void ObjectList::paste()
|
||||
{
|
||||
if (!m_layer_config_ranges_cache.empty())
|
||||
paste_layers_into_list();
|
||||
else
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
||||
}
|
||||
|
||||
#ifndef __WXOSX__
|
||||
void ObjectList::key_event(wxKeyEvent& event)
|
||||
{
|
||||
|
@ -731,10 +823,10 @@ void ObjectList::key_event(wxKeyEvent& event)
|
|||
}
|
||||
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
|
||||
select_item_all_children();
|
||||
else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
|
||||
else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
|
||||
copy();
|
||||
else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
||||
paste();
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
@ -1040,7 +1132,17 @@ void ObjectList::get_settings_choice(const wxString& category_name)
|
|||
|
||||
void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
|
||||
{
|
||||
const std::vector<std::string>& options = get_options_for_bundle(bundle_name);
|
||||
std::vector<std::string> options = get_options_for_bundle(bundle_name);
|
||||
|
||||
/* Because of we couldn't edited layer_height for ItVolume from settings list,
|
||||
* correct options according to the selected item type :
|
||||
* remove "layer_height" option
|
||||
*/
|
||||
if ((m_objects_model->GetItemType(GetSelection()) & itVolume) && bundle_name == _("Layers and Perimeters")) {
|
||||
const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height");
|
||||
if (layer_height_it != options.end())
|
||||
options.erase(layer_height_it);
|
||||
}
|
||||
|
||||
assert(m_config);
|
||||
auto opt_keys = m_config->keys();
|
||||
|
@ -1144,6 +1246,12 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu)
|
|||
[this]() { return is_splittable(); }, wxGetApp().plater());
|
||||
}
|
||||
|
||||
wxMenuItem* ObjectList::append_menu_item_layers_editing(wxMenu* menu)
|
||||
{
|
||||
return append_menu_item(menu, wxID_ANY, _(L("Edit Layers")), "",
|
||||
[this](wxCommandEvent&) { layers_editing(); }, "layers", menu);
|
||||
}
|
||||
|
||||
wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
|
||||
{
|
||||
MenuWithSeparators* menu = dynamic_cast<MenuWithSeparators*>(menu_);
|
||||
|
@ -1308,7 +1416,11 @@ void ObjectList::create_object_popupmenu(wxMenu *menu)
|
|||
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
||||
|
||||
// Split object to parts
|
||||
m_menu_item_split = append_menu_item_split(menu);
|
||||
append_menu_item_split(menu);
|
||||
menu->AppendSeparator();
|
||||
|
||||
// Layers Editing for object
|
||||
append_menu_item_layers_editing(menu);
|
||||
menu->AppendSeparator();
|
||||
|
||||
// rest of a object_menu will be added later in:
|
||||
|
@ -1337,7 +1449,7 @@ void ObjectList::create_part_popupmenu(wxMenu *menu)
|
|||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_export_stl(menu);
|
||||
|
||||
m_menu_item_split_part = append_menu_item_split(menu);
|
||||
append_menu_item_split(menu);
|
||||
|
||||
// Append change part type
|
||||
menu->AppendSeparator();
|
||||
|
@ -1587,38 +1699,52 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
|||
ItemType type;
|
||||
|
||||
m_objects_model->GetItemInfo(item, type, obj_idx, idx);
|
||||
if (type == itUndef)
|
||||
if (type & itUndef)
|
||||
return;
|
||||
|
||||
if (type == itSettings)
|
||||
del_settings_from_config();
|
||||
else if (type == itInstanceRoot && obj_idx != -1)
|
||||
if (type & itSettings)
|
||||
del_settings_from_config(m_objects_model->GetParent(item));
|
||||
else if (type & itInstanceRoot && obj_idx != -1)
|
||||
del_instances_from_object(obj_idx);
|
||||
else if (type & itLayerRoot && obj_idx != -1)
|
||||
del_layers_from_object(obj_idx);
|
||||
else if (type & itLayer && obj_idx != -1)
|
||||
del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
|
||||
else if (idx == -1)
|
||||
return;
|
||||
else if (!del_subobject_from_object(obj_idx, idx, type))
|
||||
return;
|
||||
|
||||
// If last volume item with warning was deleted, unmark object item
|
||||
if (type == itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
|
||||
if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
|
||||
m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
|
||||
|
||||
m_objects_model->Delete(item);
|
||||
}
|
||||
|
||||
void ObjectList::del_settings_from_config()
|
||||
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
|
||||
{
|
||||
auto opt_keys = m_config->keys();
|
||||
if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
|
||||
const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
|
||||
|
||||
const int opt_cnt = m_config->keys().size();
|
||||
if (opt_cnt == 1 && m_config->has("extruder") ||
|
||||
is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height"))
|
||||
return;
|
||||
|
||||
int extruder = -1;
|
||||
if (m_config->has("extruder"))
|
||||
extruder = m_config->option<ConfigOptionInt>("extruder")->value;
|
||||
|
||||
coordf_t layer_height = 0.0;
|
||||
if (is_layer_settings)
|
||||
layer_height = m_config->opt_float("layer_height");
|
||||
|
||||
m_config->clear();
|
||||
|
||||
if (extruder >= 0)
|
||||
m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
|
||||
if (is_layer_settings)
|
||||
m_config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
|
||||
}
|
||||
|
||||
void ObjectList::del_instances_from_object(const int obj_idx)
|
||||
|
@ -1637,6 +1763,24 @@ void ObjectList::del_instances_from_object(const int obj_idx)
|
|||
changed_object(obj_idx);
|
||||
}
|
||||
|
||||
void ObjectList::del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range)
|
||||
{
|
||||
const auto del_range = object(obj_idx)->layer_config_ranges.find(layer_range);
|
||||
if (del_range == object(obj_idx)->layer_config_ranges.end())
|
||||
return;
|
||||
|
||||
object(obj_idx)->layer_config_ranges.erase(del_range);
|
||||
|
||||
changed_object(obj_idx);
|
||||
}
|
||||
|
||||
void ObjectList::del_layers_from_object(const int obj_idx)
|
||||
{
|
||||
object(obj_idx)->layer_config_ranges.clear();
|
||||
|
||||
changed_object(obj_idx);
|
||||
}
|
||||
|
||||
bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
|
||||
{
|
||||
if (obj_idx == 1000)
|
||||
|
@ -1738,6 +1882,70 @@ void ObjectList::split()
|
|||
changed_object(obj_idx);
|
||||
}
|
||||
|
||||
void ObjectList::layers_editing()
|
||||
{
|
||||
const auto item = GetSelection();
|
||||
const int obj_idx = get_selected_obj_idx();
|
||||
if (!item || obj_idx < 0)
|
||||
return;
|
||||
|
||||
const wxDataViewItem obj_item = m_objects_model->GetTopParent(item);
|
||||
wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(obj_item);
|
||||
|
||||
// if it doesn't exist now
|
||||
if (!layers_item.IsOk())
|
||||
{
|
||||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
||||
// set some default value
|
||||
if (ranges.empty())
|
||||
ranges[{ 0.0f, 2.0f }] = get_default_layer_config(obj_idx);
|
||||
|
||||
// create layer root item
|
||||
layers_item = add_layer_root_item(obj_item);
|
||||
}
|
||||
if (!layers_item.IsOk())
|
||||
return;
|
||||
|
||||
// to correct visual hints for layers editing on the Scene, reset previous selection
|
||||
wxGetApp().obj_layers()->reset_selection();
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
|
||||
|
||||
// select LayerRoor item and expand
|
||||
select_item(layers_item);
|
||||
Expand(layers_item);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
|
||||
{
|
||||
const int obj_idx = m_objects_model->GetIdByItem(obj_item);
|
||||
if (obj_idx < 0 ||
|
||||
object(obj_idx)->layer_config_ranges.empty() ||
|
||||
printer_technology() == ptSLA)
|
||||
return wxDataViewItem(0);
|
||||
|
||||
// create LayerRoot item
|
||||
wxDataViewItem layers_item = m_objects_model->AddLayersRoot(obj_item);
|
||||
|
||||
// and create Layer item(s) according to the layer_config_ranges
|
||||
for (const auto range : object(obj_idx)->layer_config_ranges)
|
||||
add_layer_item(range.first, layers_item);
|
||||
|
||||
return layers_item;
|
||||
}
|
||||
|
||||
DynamicPrintConfig ObjectList::get_default_layer_config(const int obj_idx)
|
||||
{
|
||||
DynamicPrintConfig config;
|
||||
coordf_t layer_height = object(obj_idx)->config.has("layer_height") ?
|
||||
object(obj_idx)->config.opt_float("layer_height") :
|
||||
wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_float("layer_height");
|
||||
config.set_key_value("layer_height",new ConfigOptionFloat(layer_height));
|
||||
config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
|
||||
{
|
||||
auto obj_idx = get_selected_obj_idx();
|
||||
|
@ -1807,6 +2015,7 @@ void ObjectList::part_selection_changed()
|
|||
|
||||
bool update_and_show_manipulations = false;
|
||||
bool update_and_show_settings = false;
|
||||
bool update_and_show_layers = false;
|
||||
|
||||
const auto item = GetSelection();
|
||||
|
||||
|
@ -1829,36 +2038,47 @@ void ObjectList::part_selection_changed()
|
|||
update_and_show_manipulations = true;
|
||||
}
|
||||
else {
|
||||
auto parent = m_objects_model->GetParent(item);
|
||||
// Take ID of the parent object to "inform" perl-side which object have to be selected on the scene
|
||||
obj_idx = m_objects_model->GetIdByItem(parent);
|
||||
if (m_objects_model->GetItemType(item) == itSettings) {
|
||||
if (m_objects_model->GetParent(parent) == wxDataViewItem(0)) {
|
||||
obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
|
||||
const ItemType type = m_objects_model->GetItemType(item);
|
||||
if (type & itSettings) {
|
||||
const auto parent = m_objects_model->GetParent(item);
|
||||
const ItemType parent_type = m_objects_model->GetItemType(parent);
|
||||
|
||||
if (parent_type & itObject) {
|
||||
og_name = _(L("Object Settings to modify"));
|
||||
m_config = &(*m_objects)[obj_idx]->config;
|
||||
}
|
||||
else {
|
||||
else if (parent_type & itVolume) {
|
||||
og_name = _(L("Part Settings to modify"));
|
||||
auto main_parent = m_objects_model->GetParent(parent);
|
||||
obj_idx = m_objects_model->GetIdByItem(main_parent);
|
||||
const auto volume_id = m_objects_model->GetVolumeIdByItem(parent);
|
||||
volume_id = m_objects_model->GetVolumeIdByItem(parent);
|
||||
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
||||
}
|
||||
else if (parent_type & itLayer) {
|
||||
og_name = _(L("Layer range Settings to modify"));
|
||||
m_config = &get_item_config(parent);
|
||||
}
|
||||
update_and_show_settings = true;
|
||||
}
|
||||
else if (m_objects_model->GetItemType(item) == itVolume) {
|
||||
else if (type & itVolume) {
|
||||
og_name = _(L("Part manipulation"));
|
||||
volume_id = m_objects_model->GetVolumeIdByItem(item);
|
||||
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
||||
update_and_show_manipulations = true;
|
||||
}
|
||||
else if (m_objects_model->GetItemType(item) == itInstance) {
|
||||
else if (type & itInstance) {
|
||||
og_name = _(L("Instance manipulation"));
|
||||
update_and_show_manipulations = true;
|
||||
|
||||
// fill m_config by object's values
|
||||
const int obj_idx_ = m_objects_model->GetObjectIdByItem(item);
|
||||
m_config = &(*m_objects)[obj_idx_]->config;
|
||||
m_config = &(*m_objects)[obj_idx]->config;
|
||||
}
|
||||
else if (type & (itLayerRoot|itLayer)) {
|
||||
og_name = type & itLayerRoot ? _(L("Layers Editing")) : _(L("Layer Editing"));
|
||||
update_and_show_layers = true;
|
||||
|
||||
if (type & itLayer)
|
||||
m_config = &get_item_config(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1878,11 +2098,18 @@ void ObjectList::part_selection_changed()
|
|||
if (update_and_show_settings)
|
||||
wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " ");
|
||||
|
||||
if (printer_technology() == ptSLA)
|
||||
update_and_show_layers = false;
|
||||
else if (update_and_show_layers)
|
||||
wxGetApp().obj_layers()->get_og()->set_name(" " + og_name + " ");
|
||||
|
||||
Sidebar& panel = wxGetApp().sidebar();
|
||||
panel.Freeze();
|
||||
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
|
||||
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
|
||||
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
|
||||
wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
|
||||
wxGetApp().sidebar().show_info_sizer();
|
||||
|
||||
panel.Layout();
|
||||
|
@ -1928,6 +2155,9 @@ void ObjectList::add_object_to_list(size_t obj_idx)
|
|||
Expand(item);
|
||||
}
|
||||
|
||||
// Add layers if it has
|
||||
add_layer_root_item(item);
|
||||
|
||||
#ifndef __WXOSX__
|
||||
selection_changed();
|
||||
#endif //__WXMSW__
|
||||
|
@ -2074,16 +2304,196 @@ void ObjectList::remove()
|
|||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
|
||||
wxDataViewItem parent = wxDataViewItem(0);
|
||||
|
||||
for (auto& item : sels)
|
||||
{
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
|
||||
delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
|
||||
else {
|
||||
if (sels.size() == 1)
|
||||
if (m_objects_model->GetItemType(item) & itLayer) {
|
||||
parent = m_objects_model->GetParent(item);
|
||||
wxDataViewItemArray children;
|
||||
if (m_objects_model->GetChildren(parent, children) == 1)
|
||||
parent = m_objects_model->GetTopParent(item);
|
||||
}
|
||||
else if (sels.size() == 1)
|
||||
select_item(m_objects_model->GetParent(item));
|
||||
|
||||
del_subobject_item(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (parent)
|
||||
select_item(parent);
|
||||
}
|
||||
|
||||
void ObjectList::del_layer_range(const t_layer_height_range& range)
|
||||
{
|
||||
const int obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0) return;
|
||||
|
||||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
||||
wxDataViewItem selectable_item = GetSelection();
|
||||
|
||||
if (ranges.size() == 1)
|
||||
selectable_item = m_objects_model->GetParent(selectable_item);
|
||||
|
||||
wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, range);
|
||||
del_subobject_item(layer_item);
|
||||
|
||||
select_item(selectable_item);
|
||||
}
|
||||
|
||||
double get_min_layer_height(const int extruder_idx)
|
||||
{
|
||||
const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
return config.opt_float("min_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
|
||||
}
|
||||
|
||||
double get_max_layer_height(const int extruder_idx)
|
||||
{
|
||||
const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
return config.opt_float("max_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
|
||||
}
|
||||
|
||||
void ObjectList::add_layer_range_after_current(const t_layer_height_range& current_range)
|
||||
{
|
||||
const int obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0) return;
|
||||
|
||||
const wxDataViewItem layers_item = GetSelection();
|
||||
|
||||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
||||
const t_layer_height_range& last_range = (--ranges.end())->first;
|
||||
|
||||
if (current_range == last_range)
|
||||
{
|
||||
const t_layer_height_range& new_range = { last_range.second, last_range.second + 2.0f };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item);
|
||||
}
|
||||
else
|
||||
{
|
||||
const t_layer_height_range& next_range = (++ranges.find(current_range))->first;
|
||||
|
||||
if (current_range.second > next_range.first)
|
||||
return; // range division has no sense
|
||||
|
||||
const int layer_idx = m_objects_model->GetItemIdByLayerRange(obj_idx, next_range);
|
||||
if (layer_idx < 0)
|
||||
return;
|
||||
|
||||
if (current_range.second == next_range.first)
|
||||
{
|
||||
const auto old_config = ranges.at(next_range);
|
||||
|
||||
const coordf_t delta = (next_range.second - next_range.first);
|
||||
if (delta < get_min_layer_height(old_config.opt_int("extruder"))/*0.05f*/) // next range division has no sense
|
||||
return;
|
||||
|
||||
const coordf_t midl_layer = next_range.first + 0.5f * delta;
|
||||
|
||||
t_layer_height_range new_range = { midl_layer, next_range.second };
|
||||
|
||||
// delete old layer
|
||||
|
||||
wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, next_range);
|
||||
del_subobject_item(layer_item);
|
||||
|
||||
// create new 2 layers instead of deleted one
|
||||
|
||||
ranges[new_range] = old_config;
|
||||
add_layer_item(new_range, layers_item, layer_idx);
|
||||
|
||||
new_range = { current_range.second, midl_layer };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item, layer_idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
const t_layer_height_range new_range = { current_range.second, next_range.first };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item, layer_idx);
|
||||
}
|
||||
}
|
||||
|
||||
changed_object(obj_idx);
|
||||
|
||||
// select item to update layers sizer
|
||||
select_item(layers_item);
|
||||
}
|
||||
|
||||
void ObjectList::add_layer_item(const t_layer_height_range& range,
|
||||
const wxDataViewItem layers_item,
|
||||
const int layer_idx /* = -1*/)
|
||||
{
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(layers_item);
|
||||
if (obj_idx < 0) return;
|
||||
|
||||
const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range];
|
||||
if (!config.has("extruder"))
|
||||
return;
|
||||
|
||||
const auto layer_item = m_objects_model->AddLayersChild(layers_item,
|
||||
range,
|
||||
config.opt_int("extruder"),
|
||||
layer_idx);
|
||||
|
||||
if (config.keys().size() > 2)
|
||||
select_item(m_objects_model->AddSettingsChild(layer_item));
|
||||
}
|
||||
|
||||
bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
|
||||
{
|
||||
const int obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0)
|
||||
return false;
|
||||
|
||||
DynamicPrintConfig* config = &object(obj_idx)->layer_config_ranges[range];
|
||||
if (fabs(layer_height - config->opt_float("layer_height")) < EPSILON)
|
||||
return false;
|
||||
|
||||
const int extruder_idx = config->opt_int("extruder");
|
||||
|
||||
if (layer_height >= get_min_layer_height(extruder_idx) &&
|
||||
layer_height <= get_max_layer_height(extruder_idx))
|
||||
{
|
||||
config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range)
|
||||
{
|
||||
const int obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0) return false;
|
||||
|
||||
const ItemType sel_type = m_objects_model->GetItemType(GetSelection());
|
||||
|
||||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
||||
const DynamicPrintConfig config = ranges[range];
|
||||
|
||||
ranges.erase(range);
|
||||
ranges[new_range] = config;
|
||||
|
||||
wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx));
|
||||
m_objects_model->DeleteChildren(root_item);
|
||||
|
||||
if (root_item.IsOk())
|
||||
// create Layer item(s) according to the layer_config_ranges
|
||||
for (const auto r : ranges)
|
||||
add_layer_item(r.first, root_item);
|
||||
|
||||
select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
|
||||
Expand(root_item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectList::init_objects()
|
||||
|
@ -2113,11 +2523,12 @@ void ObjectList::update_selections()
|
|||
m_selection_mode = smInstance;
|
||||
|
||||
// We doesn't update selection if SettingsItem for the current object/part is selected
|
||||
if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
|
||||
// if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
|
||||
if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) & (itSettings | itLayerRoot | itLayer))
|
||||
{
|
||||
const auto item = GetSelection();
|
||||
if (selection.is_single_full_object()) {
|
||||
if ( m_objects_model->GetIdByItem(m_objects_model->GetParent(item)) == selection.get_object_idx())
|
||||
if (m_objects_model->GetObjectIdByItem(item) == selection.get_object_idx())
|
||||
return;
|
||||
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
|
||||
}
|
||||
|
@ -2238,22 +2649,18 @@ void ObjectList::update_selections_on_canvas()
|
|||
auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
|
||||
{
|
||||
const ItemType& type = m_objects_model->GetItemType(item);
|
||||
if ( type == itInstanceRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) {
|
||||
wxDataViewItem obj_item = type == itInstanceRoot ? m_objects_model->GetParent(item) : item;
|
||||
selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection);
|
||||
return;
|
||||
}
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
|
||||
if (type == itVolume) {
|
||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
|
||||
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
|
||||
selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
|
||||
}
|
||||
else if (type == itInstance) {
|
||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||
const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
|
||||
selection.add_instance(obj_idx, inst_idx, as_single_selection);
|
||||
}
|
||||
else
|
||||
selection.add_object(obj_idx, as_single_selection);
|
||||
};
|
||||
|
||||
// stores current instance idx before to clear the selection
|
||||
|
@ -2261,7 +2668,7 @@ void ObjectList::update_selections_on_canvas()
|
|||
|
||||
if (sel_cnt == 1) {
|
||||
wxDataViewItem item = GetSelection();
|
||||
if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot))
|
||||
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
|
||||
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true);
|
||||
else
|
||||
add_to_selection(item, selection, instance_idx, true);
|
||||
|
@ -2324,11 +2731,13 @@ void ObjectList::select_item_all_children()
|
|||
}
|
||||
else {
|
||||
const auto item = GetSelection();
|
||||
// Some volume(instance) is selected => select all volumes(instances) inside the current object
|
||||
if (m_objects_model->GetItemType(item) & (itVolume | itInstance))
|
||||
const ItemType item_type = m_objects_model->GetItemType(item);
|
||||
// Some volume/layer/instance is selected => select all volumes/layers/instances inside the current object
|
||||
if (item_type & (itVolume | itInstance | itLayer))
|
||||
m_objects_model->GetChildren(m_objects_model->GetParent(item), sels);
|
||||
|
||||
m_selection_mode = m_objects_model->GetItemType(item)&itVolume ? smVolume : smInstance;
|
||||
m_selection_mode = item_type&itVolume ? smVolume :
|
||||
item_type&itLayer ? smLayer : smInstance;
|
||||
}
|
||||
|
||||
SetSelections(sels);
|
||||
|
@ -2347,8 +2756,9 @@ void ObjectList::update_selection_mode()
|
|||
}
|
||||
|
||||
const ItemType type = m_objects_model->GetItemType(GetSelection());
|
||||
m_selection_mode = type&itSettings ? smUndef :
|
||||
type&itVolume ? smVolume : smInstance;
|
||||
m_selection_mode = type & itSettings ? smUndef :
|
||||
type & itLayer ? smLayer :
|
||||
type & itVolume ? smVolume : smInstance;
|
||||
}
|
||||
|
||||
// check last selected item. If is it possible to select it
|
||||
|
@ -2359,33 +2769,37 @@ bool ObjectList::check_last_selection(wxString& msg_str)
|
|||
|
||||
const bool is_shift_pressed = wxGetKeyState(WXK_SHIFT);
|
||||
|
||||
/* We can't mix Parts and Objects/Instances.
|
||||
/* We can't mix Volumes, Layers and Objects/Instances.
|
||||
* So, show information about it
|
||||
*/
|
||||
const ItemType type = m_objects_model->GetItemType(m_last_selected_item);
|
||||
|
||||
// check a case of a selection of the Parts from different Objects
|
||||
bool impossible_multipart_selection = false;
|
||||
if (type & itVolume && m_selection_mode == smVolume)
|
||||
{
|
||||
// check a case of a selection of the same type items from different Objects
|
||||
auto impossible_multi_selection = [type, this](const ItemType item_type, const SELECTION_MODE selection_mode) {
|
||||
if (!(type & item_type && m_selection_mode & selection_mode))
|
||||
return false;
|
||||
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
for (const auto& sel: sels)
|
||||
if (sel != m_last_selected_item &&
|
||||
m_objects_model->GetParent(sel) != m_objects_model->GetParent(m_last_selected_item))
|
||||
{
|
||||
impossible_multipart_selection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const auto& sel : sels)
|
||||
if (sel != m_last_selected_item &&
|
||||
m_objects_model->GetTopParent(sel) != m_objects_model->GetTopParent(m_last_selected_item))
|
||||
return true;
|
||||
|
||||
if (impossible_multipart_selection ||
|
||||
return false;
|
||||
};
|
||||
|
||||
if (impossible_multi_selection(itVolume, smVolume) ||
|
||||
impossible_multi_selection(itLayer, smLayer ) ||
|
||||
type & itSettings ||
|
||||
type & itVolume && m_selection_mode == smInstance ||
|
||||
!(type & itVolume) && m_selection_mode == smVolume)
|
||||
type & itVolume && !(m_selection_mode & smVolume ) ||
|
||||
type & itLayer && !(m_selection_mode & smLayer ) ||
|
||||
type & itInstance && !(m_selection_mode & smInstance)
|
||||
)
|
||||
{
|
||||
// Inform user why selection isn't complited
|
||||
const wxString item_type = m_selection_mode == smInstance ? _(L("Object or Instance")) : _(L("Part"));
|
||||
const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) :
|
||||
m_selection_mode & smVolume ? _(L("Part")) : _(L("Layer"));
|
||||
|
||||
msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" +
|
||||
_(L("You started your selection with %s Item.")) + "\n" +
|
||||
|
@ -2422,7 +2836,7 @@ void ObjectList::fix_multiselection_conflicts()
|
|||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
|
||||
if (m_selection_mode == smVolume)
|
||||
if (m_selection_mode & (smVolume|smLayer))
|
||||
{
|
||||
// identify correct parent of the initial selected item
|
||||
const wxDataViewItem& parent = m_objects_model->GetParent(m_last_selected_item == sels.front() ? sels.back() : sels.front());
|
||||
|
@ -2431,8 +2845,10 @@ void ObjectList::fix_multiselection_conflicts()
|
|||
wxDataViewItemArray children; // selected volumes from current parent
|
||||
m_objects_model->GetChildren(parent, children);
|
||||
|
||||
const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer;
|
||||
|
||||
for (const auto child : children)
|
||||
if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume)
|
||||
if (IsSelected(child) && m_objects_model->GetItemType(child) & item_type)
|
||||
sels.Add(child);
|
||||
|
||||
// If some part is selected, unselect all items except of selected parts of the current object
|
||||
|
@ -2599,6 +3015,87 @@ void ObjectList::update_settings_items()
|
|||
m_prevent_canvas_selection_update = false;
|
||||
}
|
||||
|
||||
// Update settings item for item had it
|
||||
void ObjectList::update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections)
|
||||
{
|
||||
const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item);
|
||||
select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item));
|
||||
|
||||
// If settings item was deleted from the list,
|
||||
// it's need to be deleted from selection array, if it was there
|
||||
if (settings_item != m_objects_model->GetSettingsItem(item) &&
|
||||
selections.Index(settings_item) != wxNOT_FOUND) {
|
||||
selections.Remove(settings_item);
|
||||
|
||||
// Select item, if settings_item doesn't exist for item anymore, but was selected
|
||||
if (selections.Index(item) == wxNOT_FOUND)
|
||||
selections.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectList::update_object_list_by_printer_technology()
|
||||
{
|
||||
m_prevent_canvas_selection_update = true;
|
||||
wxDataViewItemArray sel;
|
||||
GetSelections(sel); // stash selection
|
||||
|
||||
wxDataViewItemArray object_items;
|
||||
m_objects_model->GetChildren(wxDataViewItem(0), object_items);
|
||||
|
||||
for (auto& object_item : object_items) {
|
||||
// Update Settings Item for object
|
||||
update_settings_item_and_selection(object_item, sel);
|
||||
|
||||
// Update settings for Volumes
|
||||
wxDataViewItemArray all_object_subitems;
|
||||
m_objects_model->GetChildren(object_item, all_object_subitems);
|
||||
for (auto item : all_object_subitems)
|
||||
if (m_objects_model->GetItemType(item) & itVolume)
|
||||
// update settings for volume
|
||||
update_settings_item_and_selection(item, sel);
|
||||
|
||||
// Update Layers Items
|
||||
wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
|
||||
if (!layers_item)
|
||||
layers_item = add_layer_root_item(object_item);
|
||||
else if (printer_technology() == ptSLA) {
|
||||
// If layers root item will be deleted from the list, so
|
||||
// it's need to be deleted from selection array, if it was there
|
||||
wxDataViewItemArray del_items;
|
||||
bool some_layers_was_selected = false;
|
||||
m_objects_model->GetAllChildren(layers_item, del_items);
|
||||
for (auto& del_item:del_items)
|
||||
if (sel.Index(del_item) != wxNOT_FOUND) {
|
||||
some_layers_was_selected = true;
|
||||
sel.Remove(del_item);
|
||||
}
|
||||
if (sel.Index(layers_item) != wxNOT_FOUND) {
|
||||
some_layers_was_selected = true;
|
||||
sel.Remove(layers_item);
|
||||
}
|
||||
|
||||
// delete all "layers" items
|
||||
m_objects_model->Delete(layers_item);
|
||||
|
||||
// Select object_item, if layers_item doesn't exist for item anymore, but was some of layer items was/were selected
|
||||
if (some_layers_was_selected)
|
||||
sel.Add(object_item);
|
||||
}
|
||||
else {
|
||||
wxDataViewItemArray all_obj_layers;
|
||||
m_objects_model->GetChildren(layers_item, all_obj_layers);
|
||||
|
||||
for (auto item : all_obj_layers)
|
||||
// update settings for layer
|
||||
update_settings_item_and_selection(item, sel);
|
||||
}
|
||||
}
|
||||
|
||||
// restore selection:
|
||||
SetSelections(sel);
|
||||
m_prevent_canvas_selection_update = false;
|
||||
}
|
||||
|
||||
void ObjectList::update_object_menu()
|
||||
{
|
||||
append_menu_items_add_volume(&m_menu_object);
|
||||
|
@ -2772,7 +3269,8 @@ void ObjectList::msw_rescale()
|
|||
for (MenuWithSeparators* menu : { &m_menu_object,
|
||||
&m_menu_part,
|
||||
&m_menu_sla_object,
|
||||
&m_menu_instance })
|
||||
&m_menu_instance,
|
||||
&m_menu_layer })
|
||||
msw_rescale_menu(menu);
|
||||
|
||||
Layout();
|
||||
|
|
|
@ -33,6 +33,10 @@ typedef std::map< std::string, std::vector< std::pair<std::string, std::string>
|
|||
|
||||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
|
||||
|
@ -64,9 +68,10 @@ class ObjectList : public wxDataViewCtrl
|
|||
{
|
||||
enum SELECTION_MODE
|
||||
{
|
||||
smUndef,
|
||||
smVolume,
|
||||
smInstance
|
||||
smUndef = 0,
|
||||
smVolume = 1,
|
||||
smInstance = 2,
|
||||
smLayer = 4
|
||||
} m_selection_mode {smUndef};
|
||||
|
||||
struct dragged_item_data
|
||||
|
@ -119,12 +124,17 @@ class ObjectList : public wxDataViewCtrl
|
|||
MenuWithSeparators m_menu_part;
|
||||
MenuWithSeparators m_menu_sla_object;
|
||||
MenuWithSeparators m_menu_instance;
|
||||
wxMenuItem* m_menu_item_split { nullptr };
|
||||
wxMenuItem* m_menu_item_split_part { nullptr };
|
||||
MenuWithSeparators m_menu_layer;
|
||||
wxMenuItem* m_menu_item_settings { nullptr };
|
||||
wxMenuItem* m_menu_item_split_instances { nullptr };
|
||||
|
||||
std::vector<wxBitmap*> m_bmp_vector;
|
||||
ObjectDataViewModel *m_objects_model{ nullptr };
|
||||
DynamicPrintConfig *m_config {nullptr};
|
||||
std::vector<ModelObject*> *m_objects{ nullptr };
|
||||
|
||||
std::vector<wxBitmap*> m_bmp_vector;
|
||||
|
||||
t_layer_config_ranges m_layer_config_ranges_cache;
|
||||
|
||||
int m_selected_object_id = -1;
|
||||
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
|
||||
|
@ -153,11 +163,11 @@ public:
|
|||
|
||||
std::map<std::string, wxBitmap> CATEGORY_ICON;
|
||||
|
||||
ObjectDataViewModel *m_objects_model{ nullptr };
|
||||
DynamicPrintConfig *m_config {nullptr};
|
||||
|
||||
std::vector<ModelObject*> *m_objects{ nullptr };
|
||||
ObjectDataViewModel* GetModel() const { return m_objects_model; }
|
||||
DynamicPrintConfig* config() const { return m_config; }
|
||||
std::vector<ModelObject*>* objects() const { return m_objects; }
|
||||
|
||||
ModelObject* object(const int obj_idx) const ;
|
||||
|
||||
void create_objects_ctrl();
|
||||
void create_popup_menus();
|
||||
|
@ -192,6 +202,9 @@ public:
|
|||
void key_event(wxKeyEvent& event);
|
||||
#endif /* __WXOSX__ */
|
||||
|
||||
void copy();
|
||||
void paste();
|
||||
|
||||
void get_settings_choice(const wxString& category_name);
|
||||
void get_freq_settings_choice(const wxString& bundle_name);
|
||||
void update_settings_item();
|
||||
|
@ -199,6 +212,7 @@ public:
|
|||
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
|
||||
void append_menu_items_add_volume(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_split(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_settings(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
|
||||
|
@ -222,10 +236,17 @@ public:
|
|||
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
|
||||
void del_object(const int obj_idx);
|
||||
void del_subobject_item(wxDataViewItem& item);
|
||||
void del_settings_from_config();
|
||||
void del_settings_from_config(const wxDataViewItem& parent_item);
|
||||
void del_instances_from_object(const int obj_idx);
|
||||
void del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range);
|
||||
void del_layers_from_object(const int obj_idx);
|
||||
bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
|
||||
void split();
|
||||
void layers_editing();
|
||||
|
||||
wxDataViewItem add_layer_root_item(const wxDataViewItem obj_item);
|
||||
|
||||
DynamicPrintConfig get_default_layer_config(const int obj_idx);
|
||||
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
|
||||
bool is_splittable();
|
||||
bool selected_instances_of_same_object();
|
||||
|
@ -265,6 +286,14 @@ public:
|
|||
|
||||
// Remove objects/sub-object from the list
|
||||
void remove();
|
||||
void del_layer_range(const t_layer_height_range& range);
|
||||
void add_layer_range_after_current(const t_layer_height_range& current_range);
|
||||
void add_layer_item (const t_layer_height_range& range,
|
||||
const wxDataViewItem layers_item,
|
||||
const int layer_idx = -1);
|
||||
bool edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
|
||||
bool edit_layer_range(const t_layer_height_range& range,
|
||||
const t_layer_height_range& new_range);
|
||||
|
||||
void init_objects();
|
||||
bool multiple_selection() const ;
|
||||
|
@ -286,6 +315,8 @@ public:
|
|||
void last_volume_is_deleted(const int obj_idx);
|
||||
bool has_multi_part_objects();
|
||||
void update_settings_items();
|
||||
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
|
||||
void update_object_list_by_printer_technology();
|
||||
void update_object_menu();
|
||||
|
||||
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
|
||||
|
@ -295,6 +326,8 @@ public:
|
|||
void fix_through_netfabb();
|
||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||
|
||||
void fill_layer_config_ranges_cache();
|
||||
void paste_layers_into_list();
|
||||
void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
|
||||
void paste_objects_into_list(const std::vector<size_t>& object_idxs);
|
||||
|
||||
|
|
|
@ -68,10 +68,12 @@ void ObjectSettings::update_settings_list()
|
|||
m_settings_list_sizer->Clear(true);
|
||||
|
||||
auto objects_ctrl = wxGetApp().obj_list();
|
||||
auto objects_model = wxGetApp().obj_list()->m_objects_model;
|
||||
auto config = wxGetApp().obj_list()->m_config;
|
||||
auto objects_model = wxGetApp().obj_list()->GetModel();
|
||||
auto config = wxGetApp().obj_list()->config();
|
||||
|
||||
const auto item = objects_ctrl->GetSelection();
|
||||
const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
|
||||
|
||||
if (item && !objects_ctrl->multiple_selection() &&
|
||||
config && objects_model->IsSettingsItem(item))
|
||||
{
|
||||
|
@ -119,7 +121,8 @@ void ObjectSettings::update_settings_list()
|
|||
}
|
||||
|
||||
for (auto& cat : cat_options) {
|
||||
if (cat.second.size() == 1 && cat.second[0] == "extruder")
|
||||
if (cat.second.size() == 1 &&
|
||||
(cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
|
||||
continue;
|
||||
|
||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
||||
|
@ -129,14 +132,14 @@ void ObjectSettings::update_settings_list()
|
|||
optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
|
||||
wxGetApp().obj_list()->changed_object(); };
|
||||
|
||||
const bool is_extriders_cat = cat.first == "Extruders";
|
||||
const bool is_extruders_cat = cat.first == "Extruders";
|
||||
for (auto& opt : cat.second)
|
||||
{
|
||||
if (opt == "extruder")
|
||||
if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
|
||||
continue;
|
||||
Option option = optgroup->get_option(opt);
|
||||
option.opt.width = 12;
|
||||
if (is_extriders_cat)
|
||||
if (is_extruders_cat)
|
||||
option.opt.max = wxGetApp().extruders_cnt();
|
||||
optgroup->append_single_option_line(option);
|
||||
}
|
||||
|
|
|
@ -541,6 +541,26 @@ void Preview::on_checkbox_shells(wxCommandEvent& evt)
|
|||
refresh_print();
|
||||
}
|
||||
|
||||
void Preview::update_view_type()
|
||||
{
|
||||
const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config;
|
||||
|
||||
const wxString& choice = !config.option<ConfigOptionFloats>("colorprint_heights")->values.empty() &&
|
||||
wxGetApp().extruders_edited_cnt()==1 ?
|
||||
_(L("Color Print")) :
|
||||
config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
|
||||
_(L("Tool")) :
|
||||
_(L("Feature type"));
|
||||
|
||||
int type = m_choice_view_type->FindString(choice);
|
||||
if (m_choice_view_type->GetSelection() != type) {
|
||||
m_choice_view_type->SetSelection(type);
|
||||
if (0 <= type && type < (int)GCodePreviewData::Extrusion::Num_View_Types)
|
||||
m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
|
||||
m_preferred_color_mode = "feature";
|
||||
}
|
||||
}
|
||||
|
||||
void Preview::create_double_slider()
|
||||
{
|
||||
m_slider = new DoubleSlider(this, wxID_ANY, 0, 0, 0, 100);
|
||||
|
@ -553,23 +573,13 @@ void Preview::create_double_slider()
|
|||
|
||||
|
||||
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
|
||||
auto& config = wxGetApp().preset_bundle->project_config;
|
||||
((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues());
|
||||
m_schedule_background_process();
|
||||
wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights")->values = m_slider->GetTicksValues();
|
||||
m_schedule_background_process();
|
||||
|
||||
const wxString& choise = !config.option<ConfigOptionFloats>("colorprint_heights")->values.empty() ? _(L("Color Print")) :
|
||||
config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
|
||||
_(L("Tool")) : _(L("Feature type"));
|
||||
update_view_type();
|
||||
|
||||
int type = m_choice_view_type->FindString(choise);
|
||||
if (m_choice_view_type->GetSelection() != type) {
|
||||
m_choice_view_type->SetSelection(type);
|
||||
if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types))
|
||||
m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
|
||||
m_preferred_color_mode = "feature";
|
||||
}
|
||||
reload_print();
|
||||
});
|
||||
reload_print();
|
||||
});
|
||||
}
|
||||
|
||||
// Find an index of a value in a sorted vector, which is in <z-eps, z+eps>.
|
||||
|
@ -787,9 +797,14 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
|||
// Load the real G-code preview.
|
||||
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
|
||||
m_loaded = true;
|
||||
} else
|
||||
} else {
|
||||
// disable color change information for multi-material presets
|
||||
if (wxGetApp().extruders_edited_cnt() > 1)
|
||||
color_print_values.clear();
|
||||
|
||||
// Load the initial preview based on slices, not the final G-code.
|
||||
m_canvas->load_preview(colors, color_print_values);
|
||||
}
|
||||
show_hide_ui_elements(gcode_preview_data_valid ? "full" : "simple");
|
||||
// recalculates zs and update sliders accordingly
|
||||
std::vector<double> zs = m_canvas->get_current_print_zs(true);
|
||||
|
|
|
@ -127,6 +127,8 @@ public:
|
|||
void move_double_slider(wxKeyEvent& evt);
|
||||
void edit_double_slider(wxKeyEvent& evt);
|
||||
|
||||
void update_view_type();
|
||||
|
||||
private:
|
||||
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model);
|
||||
|
||||
|
|
|
@ -15,48 +15,6 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
class GLGizmoCutPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
GLGizmoCutPanel(wxWindow *parent);
|
||||
|
||||
void display(bool display);
|
||||
private:
|
||||
bool m_active;
|
||||
wxCheckBox *m_cb_rotate;
|
||||
wxButton *m_btn_cut;
|
||||
wxButton *m_btn_cancel;
|
||||
};
|
||||
|
||||
GLGizmoCutPanel::GLGizmoCutPanel(wxWindow *parent)
|
||||
: wxPanel(parent)
|
||||
, m_active(false)
|
||||
, m_cb_rotate(new wxCheckBox(this, wxID_ANY, _(L("Rotate lower part upwards"))))
|
||||
, m_btn_cut(new wxButton(this, wxID_OK, _(L("Perform cut"))))
|
||||
, m_btn_cancel(new wxButton(this, wxID_CANCEL, _(L("Cancel"))))
|
||||
{
|
||||
enum { MARGIN = 5 };
|
||||
|
||||
auto *sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto *label = new wxStaticText(this, wxID_ANY, _(L("Cut object:")));
|
||||
sizer->Add(label, 0, wxALL | wxALIGN_CENTER, MARGIN);
|
||||
sizer->Add(m_cb_rotate, 0, wxALL | wxALIGN_CENTER, MARGIN);
|
||||
sizer->AddStretchSpacer();
|
||||
sizer->Add(m_btn_cut, 0, wxALL | wxALIGN_CENTER, MARGIN);
|
||||
sizer->Add(m_btn_cancel, 0, wxALL | wxALIGN_CENTER, MARGIN);
|
||||
|
||||
SetSizer(sizer);
|
||||
}
|
||||
|
||||
void GLGizmoCutPanel::display(bool display)
|
||||
{
|
||||
Show(display);
|
||||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
|
||||
const double GLGizmoCut::Offset = 10.0;
|
||||
const double GLGizmoCut::Margin = 20.0;
|
||||
const std::array<float, 3> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0 };
|
||||
|
@ -188,7 +146,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co
|
|||
m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
ImGui::PushItemWidth(m_imgui->scaled(5.0f));
|
||||
bool _value_changed = ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f");
|
||||
ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
m_imgui->checkbox(_(L("Keep upper part")), m_keep_upper);
|
||||
m_imgui->checkbox(_(L("Keep lower part")), m_keep_lower);
|
||||
|
|
|
@ -259,6 +259,10 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
|
|||
|
||||
void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const
|
||||
{
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
|
||||
#endif
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
render_points(selection, true);
|
||||
}
|
||||
|
|
|
@ -326,9 +326,9 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>&
|
|||
int selection_out = -1;
|
||||
bool res = false;
|
||||
|
||||
const char *selection_str = selection < options.size() ? options[selection].c_str() : "";
|
||||
const char *selection_str = selection < (int)options.size() ? options[selection].c_str() : "";
|
||||
if (ImGui::BeginCombo("", selection_str)) {
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
for (int i = 0; i < (int)options.size(); i++) {
|
||||
if (ImGui::Selectable(options[i].c_str(), i == selection)) {
|
||||
selection_out = i;
|
||||
}
|
||||
|
|
|
@ -154,6 +154,9 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||
plater_shortcuts.push_back(Shortcut("I", L("Zoom in")));
|
||||
plater_shortcuts.push_back(Shortcut("O", L("Zoom out")));
|
||||
plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo / Clear selection")));
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
plater_shortcuts.push_back(Shortcut("T", L("Toggle picking pass texture rendering on/off")));
|
||||
#endif // ENABLE_RENDER_PICKING_PASS
|
||||
|
||||
m_full_shortcuts.push_back(std::make_pair(_(L("Plater Shortcuts")), std::make_pair(plater_shortcuts, szRight)));
|
||||
|
||||
|
|
|
@ -320,6 +320,17 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
|
|||
return retval;
|
||||
}
|
||||
|
||||
void OptionsGroup::clear_fields_except_of(const std::vector<std::string> left_fields)
|
||||
{
|
||||
auto it = m_fields.begin();
|
||||
while (it != m_fields.end()) {
|
||||
if (std::find(left_fields.begin(), left_fields.end(), it->first) == left_fields.end())
|
||||
it = m_fields.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsGroup::on_set_focus(const std::string& opt_key)
|
||||
{
|
||||
if (m_set_focus != nullptr)
|
||||
|
|
|
@ -160,6 +160,8 @@ public:
|
|||
m_show_modified_btns = show;
|
||||
}
|
||||
|
||||
void clear_fields_except_of(const std::vector<std::string> left_fields);
|
||||
|
||||
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
|
||||
column_t extra_clmn = nullptr) :
|
||||
m_parent(_parent), title(title),
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "GUI_App.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
|
@ -615,10 +616,11 @@ struct Sidebar::priv
|
|||
PresetComboBox *combo_printer;
|
||||
|
||||
wxBoxSizer *sizer_params;
|
||||
FreqChangedParams *frequently_changed_parameters;
|
||||
ObjectList *object_list;
|
||||
ObjectManipulation *object_manipulation;
|
||||
ObjectSettings *object_settings;
|
||||
FreqChangedParams *frequently_changed_parameters{ nullptr };
|
||||
ObjectList *object_list{ nullptr };
|
||||
ObjectManipulation *object_manipulation{ nullptr };
|
||||
ObjectSettings *object_settings{ nullptr };
|
||||
ObjectLayers *object_layers{ nullptr };
|
||||
ObjectInfo *object_info;
|
||||
SlicedInfo *sliced_info;
|
||||
|
||||
|
@ -627,10 +629,26 @@ struct Sidebar::priv
|
|||
wxButton *btn_send_gcode;
|
||||
|
||||
priv(Plater *plater) : plater(plater) {}
|
||||
~priv();
|
||||
|
||||
void show_preset_comboboxes();
|
||||
};
|
||||
|
||||
Sidebar::priv::~priv()
|
||||
{
|
||||
if (object_manipulation != nullptr)
|
||||
delete object_manipulation;
|
||||
|
||||
if (object_settings != nullptr)
|
||||
delete object_settings;
|
||||
|
||||
if (frequently_changed_parameters != nullptr)
|
||||
delete frequently_changed_parameters;
|
||||
|
||||
if (object_layers != nullptr)
|
||||
delete object_layers;
|
||||
}
|
||||
|
||||
void Sidebar::priv::show_preset_comboboxes()
|
||||
{
|
||||
const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
|
||||
|
@ -737,6 +755,11 @@ Sidebar::Sidebar(Plater *parent)
|
|||
p->object_settings = new ObjectSettings(p->scrolled);
|
||||
p->object_settings->Hide();
|
||||
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
||||
// Object Layers
|
||||
p->object_layers = new ObjectLayers(p->scrolled);
|
||||
p->object_layers->Hide();
|
||||
p->sizer_params->Add(p->object_layers->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
||||
// Info boxes
|
||||
p->object_info = new ObjectInfo(p->scrolled);
|
||||
|
@ -930,6 +953,7 @@ void Sidebar::msw_rescale()
|
|||
p->object_list->msw_rescale();
|
||||
p->object_manipulation->msw_rescale();
|
||||
p->object_settings->msw_rescale();
|
||||
p->object_layers->msw_rescale();
|
||||
|
||||
p->object_info->msw_rescale();
|
||||
|
||||
|
@ -951,6 +975,11 @@ ObjectSettings* Sidebar::obj_settings()
|
|||
return p->object_settings;
|
||||
}
|
||||
|
||||
ObjectLayers* Sidebar::obj_layers()
|
||||
{
|
||||
return p->object_layers;
|
||||
}
|
||||
|
||||
wxScrolledWindow* Sidebar::scrolled_panel()
|
||||
{
|
||||
return p->scrolled;
|
||||
|
@ -1264,6 +1293,7 @@ struct Plater::priv
|
|||
Preview *preview;
|
||||
|
||||
BackgroundSlicingProcess background_process;
|
||||
bool suppressed_backround_processing_update { false };
|
||||
|
||||
// A class to handle UI jobs like arranging and optimizing rotation.
|
||||
// These are not instant jobs, the user has to be informed about their
|
||||
|
@ -1516,6 +1546,7 @@ struct Plater::priv
|
|||
static const std::regex pattern_prusa;
|
||||
|
||||
priv(Plater *q, MainFrame *main_frame);
|
||||
~priv();
|
||||
|
||||
void update(bool force_full_scene_refresh = false);
|
||||
void select_view(const std::string& direction);
|
||||
|
@ -1705,7 +1736,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
panels.push_back(preview);
|
||||
|
||||
this->background_process_timer.SetOwner(this->q, 0);
|
||||
this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) { this->update_restart_background_process(false, false); });
|
||||
this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt)
|
||||
{
|
||||
if (!this->suppressed_backround_processing_update)
|
||||
this->update_restart_background_process(false, false);
|
||||
});
|
||||
|
||||
update();
|
||||
|
||||
|
@ -1795,6 +1830,12 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
this->take_snapshot(_(L("New Project")));
|
||||
}
|
||||
|
||||
Plater::priv::~priv()
|
||||
{
|
||||
if (config != nullptr)
|
||||
delete config;
|
||||
}
|
||||
|
||||
void Plater::priv::update(bool force_full_scene_refresh)
|
||||
{
|
||||
// the following line, when enabled, causes flickering on NVIDIA graphics cards
|
||||
|
@ -2170,9 +2211,6 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
}
|
||||
|
||||
object->ensure_on_bed();
|
||||
|
||||
// print.auto_assign_extruders(object);
|
||||
// print.add_model_object(object);
|
||||
}
|
||||
|
||||
#ifdef AUTOPLACEMENT_ON_LOAD
|
||||
|
@ -2957,8 +2995,14 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
|||
|
||||
// update plater with new config
|
||||
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||
/* Settings list can be changed after printer preset changing, so
|
||||
* update all settings items for all item had it.
|
||||
* Furthermore, Layers editing is implemented only for FFF printers
|
||||
* and for SLA presets they should be deleted
|
||||
*/
|
||||
if (preset_type == Preset::TYPE_PRINTER)
|
||||
wxGetApp().obj_list()->update_settings_items();
|
||||
// wxGetApp().obj_list()->update_settings_items();
|
||||
wxGetApp().obj_list()->update_object_list_by_printer_technology();
|
||||
}
|
||||
|
||||
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
||||
|
@ -3309,6 +3353,10 @@ bool Plater::priv::complit_init_object_menu()
|
|||
[this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
|
||||
object_menu.AppendSeparator();
|
||||
|
||||
// Layers Editing for object
|
||||
sidebar->obj_list()->append_menu_item_layers_editing(&object_menu);
|
||||
object_menu.AppendSeparator();
|
||||
|
||||
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
|
||||
|
||||
return true;
|
||||
|
@ -4000,6 +4048,9 @@ void Plater::reslice()
|
|||
}
|
||||
else if (!p->background_process.empty() && !p->background_process.idle())
|
||||
p->show_action_buttons(true);
|
||||
|
||||
// update type of preview
|
||||
p->preview->update_view_type();
|
||||
}
|
||||
|
||||
void Plater::reslice_SLA_supports(const ModelObject &object)
|
||||
|
@ -4257,9 +4308,25 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
|
|||
this->p->schedule_background_process();
|
||||
}
|
||||
|
||||
void Plater::schedule_background_process()
|
||||
void Plater::schedule_background_process(bool schedule/* = true*/)
|
||||
{
|
||||
this->p->schedule_background_process();
|
||||
if (schedule)
|
||||
this->p->schedule_background_process();
|
||||
|
||||
this->p->suppressed_backround_processing_update = false;
|
||||
}
|
||||
|
||||
bool Plater::is_background_process_running() const
|
||||
{
|
||||
return this->p->background_process_timer.IsRunning();
|
||||
}
|
||||
|
||||
void Plater::suppress_background_process(const bool stop_background_process)
|
||||
{
|
||||
if (stop_background_process)
|
||||
this->p->background_process_timer.Stop();
|
||||
|
||||
this->p->suppressed_backround_processing_update = true;
|
||||
}
|
||||
|
||||
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
|
||||
|
@ -4295,6 +4362,11 @@ void Plater::msw_rescale()
|
|||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
const Camera& Plater::get_camera() const
|
||||
{
|
||||
return p->camera;
|
||||
}
|
||||
|
||||
bool Plater::can_delete() const { return p->can_delete(); }
|
||||
bool Plater::can_delete_all() const { return p->can_delete_all(); }
|
||||
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
|
||||
|
@ -4338,4 +4410,15 @@ bool Plater::can_copy_to_clipboard() const
|
|||
return true;
|
||||
}
|
||||
|
||||
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
||||
m_was_running(wxGetApp().plater()->is_background_process_running())
|
||||
{
|
||||
wxGetApp().plater()->suppress_background_process(m_was_running);
|
||||
}
|
||||
|
||||
SuppressBackgroundProcessingUpdate::~SuppressBackgroundProcessingUpdate()
|
||||
{
|
||||
wxGetApp().plater()->schedule_background_process(m_was_running);
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
|
|
@ -33,6 +33,7 @@ class MainFrame;
|
|||
class ConfigOptionsGroup;
|
||||
class ObjectManipulation;
|
||||
class ObjectSettings;
|
||||
class ObjectLayers;
|
||||
class ObjectList;
|
||||
class GLCanvas3D;
|
||||
|
||||
|
@ -93,6 +94,7 @@ public:
|
|||
ObjectManipulation* obj_manipul();
|
||||
ObjectList* obj_list();
|
||||
ObjectSettings* obj_settings();
|
||||
ObjectLayers* obj_layers();
|
||||
wxScrolledWindow* scrolled_panel();
|
||||
wxPanel* presets_panel();
|
||||
|
||||
|
@ -175,7 +177,9 @@ public:
|
|||
void reslice_SLA_supports(const ModelObject &object);
|
||||
void changed_object(int obj_idx);
|
||||
void changed_objects(const std::vector<size_t>& object_idxs);
|
||||
void schedule_background_process();
|
||||
void schedule_background_process(bool schedule = true);
|
||||
bool is_background_process_running() const;
|
||||
void suppress_background_process(const bool stop_background_process) ;
|
||||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
||||
void send_gcode();
|
||||
|
||||
|
@ -221,11 +225,23 @@ public:
|
|||
|
||||
void msw_rescale();
|
||||
|
||||
const Camera& get_camera() const;
|
||||
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
|
||||
friend class SuppressBackgroundProcessingUpdate;
|
||||
};
|
||||
|
||||
class SuppressBackgroundProcessingUpdate
|
||||
{
|
||||
public:
|
||||
SuppressBackgroundProcessingUpdate();
|
||||
~SuppressBackgroundProcessingUpdate();
|
||||
private:
|
||||
bool m_was_running;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
|
|
@ -97,16 +97,6 @@ void PreferencesDialog::build()
|
|||
option = Option (def,"show_incompatible_presets");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
|
||||
// TODO: remove?
|
||||
def.label = L("Use legacy OpenGL 1.1 rendering");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If you have rendering issues caused by a buggy OpenGL 2.0 driver, "
|
||||
"you may try to check this checkbox. This will disable the layer height "
|
||||
"editing and anti aliasing, so it is likely better to upgrade your graphics driver.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("use_legacy_opengl") == "1" });
|
||||
option = Option (def,"use_legacy_opengl");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
|
||||
#if __APPLE__
|
||||
def.label = L("Use Retina resolution for the 3D scene");
|
||||
def.type = coBool;
|
||||
|
@ -150,8 +140,7 @@ void PreferencesDialog::build()
|
|||
|
||||
void PreferencesDialog::accept()
|
||||
{
|
||||
if (m_values.find("no_defaults") != m_values.end() ||
|
||||
m_values.find("use_legacy_opengl") != m_values.end()) {
|
||||
if (m_values.find("no_defaults") != m_values.end()) {
|
||||
warning_catcher(this, wxString::Format(_(L("You need to restart %s to make the changes effective.")), SLIC3R_APP_NAME));
|
||||
}
|
||||
|
||||
|
|
|
@ -824,11 +824,25 @@ const Preset* PresetCollection::get_selected_preset_parent() const
|
|||
if (this->get_selected_idx() == -1)
|
||||
// This preset collection has no preset activated yet. Only the get_edited_preset() is valid.
|
||||
return nullptr;
|
||||
const std::string &inherits = this->get_edited_preset().inherits();
|
||||
// const std::string &inherits = this->get_edited_preset().inherits();
|
||||
// if (inherits.empty())
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
|
||||
std::string inherits = this->get_edited_preset().inherits();
|
||||
if (inherits.empty())
|
||||
return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
{
|
||||
if (this->get_selected_preset().is_system || this->get_selected_preset().is_default)
|
||||
return &this->get_selected_preset();
|
||||
if (this->get_selected_preset().is_external)
|
||||
return nullptr;
|
||||
|
||||
inherits = m_type != Preset::Type::TYPE_PRINTER ? "- default -" :
|
||||
this->get_edited_preset().printer_technology() == ptFFF ?
|
||||
"- default FFF -" : "- default SLA -" ;
|
||||
}
|
||||
|
||||
const Preset* preset = this->find_preset(inherits, false);
|
||||
return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset;
|
||||
return (preset == nullptr/* || preset->is_default*/ || preset->is_external) ? nullptr : preset;
|
||||
}
|
||||
|
||||
const Preset* PresetCollection::get_preset_parent(const Preset& child) const
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "Gizmos/GLGizmoBase.hpp"
|
||||
#include "slic3r/GUI/3DScene.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "Camera.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
@ -347,6 +348,9 @@ void Selection::clear()
|
|||
|
||||
// resets the cache in the sidebar
|
||||
wxGetApp().obj_manipul()->reset_cache();
|
||||
|
||||
// #et_FIXME fake KillFocus from sidebar
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
|
||||
}
|
||||
|
||||
// Update the selection based on the new instance IDs.
|
||||
|
@ -1086,61 +1090,68 @@ void Selection::render_center(bool gizmo_is_dragging) const
|
|||
}
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
void Selection::render_sidebar_hints(const std::string& sidebar_field) const
|
||||
void Selection::render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const
|
||||
{
|
||||
if (sidebar_field.empty())
|
||||
return;
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
{
|
||||
shader.start_using();
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
}
|
||||
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
|
||||
const Vec3d& center = get_bounding_box().center();
|
||||
|
||||
if (is_single_full_instance() && ! wxGetApp().obj_manipul()->get_world_coordinates())
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
const Vec3d& center = get_bounding_box().center();
|
||||
|
||||
if (is_single_full_instance() && !wxGetApp().obj_manipul()->get_world_coordinates())
|
||||
{
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
if (boost::starts_with(sidebar_field, "scale"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::starts_with(sidebar_field, "rotation"))
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
{
|
||||
if (boost::ends_with(sidebar_field, "x"))
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
if (boost::starts_with(sidebar_field, "scale"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::ends_with(sidebar_field, "y"))
|
||||
else if (boost::starts_with(sidebar_field, "rotation"))
|
||||
{
|
||||
const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
|
||||
if (rotation(0) == 0.0)
|
||||
if (boost::ends_with(sidebar_field, "x"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else
|
||||
orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
|
||||
else if (boost::ends_with(sidebar_field, "y"))
|
||||
{
|
||||
const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
|
||||
if (rotation(0) == 0.0)
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else
|
||||
orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
}
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
}
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
else
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (requires_local_axes())
|
||||
else
|
||||
{
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (requires_local_axes())
|
||||
{
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1152,10 +1163,16 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
|
|||
render_sidebar_scale_hints(sidebar_field);
|
||||
else if (boost::starts_with(sidebar_field, "size"))
|
||||
render_sidebar_size_hints(sidebar_field);
|
||||
else if (boost::starts_with(sidebar_field, "layer"))
|
||||
render_sidebar_layers_hints(sidebar_field);
|
||||
|
||||
glsafe(::glPopMatrix());
|
||||
|
||||
glsafe(::glDisable(GL_LIGHTING));
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
{
|
||||
glsafe(::glDisable(GL_LIGHTING));
|
||||
shader.stop_using();
|
||||
}
|
||||
}
|
||||
|
||||
bool Selection::requires_local_axes() const
|
||||
|
@ -1179,7 +1196,7 @@ void Selection::copy_to_clipboard()
|
|||
static_cast<DynamicPrintConfig&>(dst_object->config) = static_cast<const DynamicPrintConfig&>(src_object->config);
|
||||
dst_object->sla_support_points = src_object->sla_support_points;
|
||||
dst_object->sla_points_status = src_object->sla_points_status;
|
||||
dst_object->layer_height_ranges = src_object->layer_height_ranges;
|
||||
dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment
|
||||
dst_object->layer_height_profile = src_object->layer_height_profile;
|
||||
dst_object->origin_translation = src_object->origin_translation;
|
||||
|
||||
|
@ -1725,6 +1742,78 @@ void Selection::render_sidebar_size_hints(const std::string& sidebar_field) cons
|
|||
render_sidebar_scale_hints(sidebar_field);
|
||||
}
|
||||
|
||||
void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) const
|
||||
{
|
||||
static const double Margin = 10.0;
|
||||
|
||||
std::string field = sidebar_field;
|
||||
|
||||
// extract max_z
|
||||
std::string::size_type pos = field.rfind("_");
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
|
||||
double max_z = std::stod(field.substr(pos + 1));
|
||||
|
||||
// extract min_z
|
||||
field = field.substr(0, pos);
|
||||
pos = field.rfind("_");
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
|
||||
double min_z = std::stod(field.substr(pos + 1));
|
||||
|
||||
// extract type
|
||||
field = field.substr(0, pos);
|
||||
pos = field.rfind("_");
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
|
||||
int type = std::stoi(field.substr(pos + 1));
|
||||
|
||||
const BoundingBoxf3& box = get_bounding_box();
|
||||
|
||||
const float min_x = box.min(0) - Margin;
|
||||
const float max_x = box.max(0) + Margin;
|
||||
const float min_y = box.min(1) - Margin;
|
||||
const float max_y = box.max(1) + Margin;
|
||||
|
||||
// view dependend order of rendering to keep correct transparency
|
||||
bool camera_on_top = wxGetApp().plater()->get_camera().get_theta() <= 90.0f;
|
||||
float z1 = camera_on_top ? min_z : max_z;
|
||||
float z2 = camera_on_top ? max_z : min_z;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
::glBegin(GL_QUADS);
|
||||
if ((camera_on_top && (type == 1)) || (!camera_on_top && (type == 2)))
|
||||
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
|
||||
else
|
||||
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
|
||||
::glVertex3f(min_x, min_y, z1);
|
||||
::glVertex3f(max_x, min_y, z1);
|
||||
::glVertex3f(max_x, max_y, z1);
|
||||
::glVertex3f(min_x, max_y, z1);
|
||||
glsafe(::glEnd());
|
||||
|
||||
::glBegin(GL_QUADS);
|
||||
if ((camera_on_top && (type == 2)) || (!camera_on_top && (type == 1)))
|
||||
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
|
||||
else
|
||||
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
|
||||
::glVertex3f(min_x, min_y, z2);
|
||||
::glVertex3f(max_x, min_y, z2);
|
||||
::glVertex3f(max_x, max_y, z2);
|
||||
::glVertex3f(min_x, max_y, z2);
|
||||
glsafe(::glEnd());
|
||||
|
||||
glsafe(::glEnable(GL_CULL_FACE));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void Selection::render_sidebar_position_hint(Axis axis) const
|
||||
{
|
||||
m_arrow.set_color(AXES_COLOR[axis], 3);
|
||||
|
|
|
@ -11,8 +11,8 @@ typedef class GLUquadric GLUquadricObj;
|
|||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
namespace Slic3r {
|
||||
class Shader;
|
||||
namespace GUI {
|
||||
|
||||
class TransformationType
|
||||
{
|
||||
public:
|
||||
|
@ -305,7 +305,7 @@ public:
|
|||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
void render_center(bool gizmo_is_dragging) const;
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
void render_sidebar_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const;
|
||||
|
||||
bool requires_local_axes() const;
|
||||
|
||||
|
@ -335,6 +335,7 @@ private:
|
|||
void render_sidebar_rotation_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_scale_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_size_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_layers_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_position_hint(Axis axis) const;
|
||||
void render_sidebar_rotation_hint(Axis axis) const;
|
||||
void render_sidebar_scale_hint(Axis axis) const;
|
||||
|
|
|
@ -423,7 +423,7 @@ void Tab::update_changed_ui()
|
|||
const ScalableBitmap *sys_icon = &m_bmp_value_lock;
|
||||
const ScalableBitmap *icon = &m_bmp_value_revert;
|
||||
|
||||
const wxColour *color = &m_sys_label_clr;
|
||||
const wxColour *color = m_is_default_preset ? &m_default_text_clr : &m_sys_label_clr;
|
||||
|
||||
const wxString *sys_tt = &m_tt_value_lock;
|
||||
const wxString *tt = &m_tt_value_revert;
|
||||
|
@ -590,7 +590,7 @@ void Tab::update_changed_tree_ui()
|
|||
}
|
||||
}
|
||||
|
||||
const wxColor *clr = sys_page ? &m_sys_label_clr :
|
||||
const wxColor *clr = sys_page ? (m_is_default_preset ? &m_default_text_clr : &m_sys_label_clr) :
|
||||
modified_page ? &m_modified_label_clr :
|
||||
&m_default_text_clr;
|
||||
|
||||
|
@ -2314,6 +2314,40 @@ void TabPrinter::build_unregular_pages()
|
|||
|
||||
auto optgroup = page->new_optgroup(_(L("Size")));
|
||||
optgroup->append_single_option_line("nozzle_diameter", extruder_idx);
|
||||
|
||||
optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
|
||||
{
|
||||
if (m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos)
|
||||
{
|
||||
SuppressBackgroundProcessingUpdate sbpu;
|
||||
const double new_nd = boost::any_cast<double>(value);
|
||||
std::vector<double> nozzle_diameters = static_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values;
|
||||
|
||||
// if value was changed
|
||||
if (fabs(nozzle_diameters[extruder_idx == 0 ? 1 : 0] - new_nd) > EPSILON)
|
||||
{
|
||||
const wxString msg_text = _(L("Do you want to change the diameter for all extruders?"));
|
||||
auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO);
|
||||
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog->ShowModal() == wxID_YES) {
|
||||
for (size_t i = 0; i < nozzle_diameters.size(); i++) {
|
||||
if (i==extruder_idx)
|
||||
continue;
|
||||
nozzle_diameters[i] = new_nd;
|
||||
}
|
||||
}
|
||||
else
|
||||
nozzle_diameters[extruder_idx] = nozzle_diameters[extruder_idx == 0 ? 1 : 0];
|
||||
|
||||
new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters));
|
||||
load_config(new_conf);
|
||||
}
|
||||
}
|
||||
|
||||
update_dirty();
|
||||
update();
|
||||
};
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Layer height limits")));
|
||||
optgroup->append_single_option_line("min_layer_height", extruder_idx);
|
||||
|
@ -2550,11 +2584,14 @@ void Tab::load_current_preset()
|
|||
// Reload preset pages with the new configuration values.
|
||||
reload_config();
|
||||
|
||||
m_bmp_non_system = m_presets->get_selected_preset_parent() ? &m_bmp_value_unlock : &m_bmp_white_bullet;
|
||||
m_ttg_non_system = m_presets->get_selected_preset_parent() ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
|
||||
m_tt_non_system = m_presets->get_selected_preset_parent() ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
|
||||
const Preset* selected_preset_parent = m_presets->get_selected_preset_parent();
|
||||
m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default;
|
||||
|
||||
m_undo_to_sys_btn->Enable(!preset.is_default);
|
||||
m_bmp_non_system = selected_preset_parent ? &m_bmp_value_unlock : &m_bmp_white_bullet;
|
||||
m_ttg_non_system = selected_preset_parent ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
|
||||
m_tt_non_system = selected_preset_parent ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
|
||||
|
||||
// m_undo_to_sys_btn->Enable(!preset.is_default);
|
||||
|
||||
#if 0
|
||||
// use CallAfter because some field triggers schedule on_change calls using CallAfter,
|
||||
|
@ -3140,18 +3177,18 @@ void Tab::fill_icon_descriptions()
|
|||
{
|
||||
m_icon_descriptions.emplace_back(&m_bmp_value_lock, L("LOCKED LOCK"),
|
||||
// TRN Description for "LOCKED LOCK"
|
||||
L("indicates that the settings are the same as the system values for the current option group"));
|
||||
L("indicates that the settings are the same as the system (or default) values for the current option group"));
|
||||
|
||||
m_icon_descriptions.emplace_back(&m_bmp_value_unlock, L("UNLOCKED LOCK"),
|
||||
// TRN Description for "UNLOCKED LOCK"
|
||||
L("indicates that some settings were changed and are not equal to the system values for "
|
||||
L("indicates that some settings were changed and are not equal to the system (or default) values for "
|
||||
"the current option group.\n"
|
||||
"Click the UNLOCKED LOCK icon to reset all settings for current option group to "
|
||||
"the system values."));
|
||||
"the system (or default) values."));
|
||||
|
||||
m_icon_descriptions.emplace_back(&m_bmp_white_bullet, L("WHITE BULLET"),
|
||||
// TRN Description for "WHITE BULLET"
|
||||
L("for the left button: \tindicates a non-system preset,\n"
|
||||
L("for the left button: \tindicates a non-system (or non-default) preset,\n"
|
||||
"for the right button: \tindicates that the settings hasn't been modified."));
|
||||
|
||||
m_icon_descriptions.emplace_back(&m_bmp_value_revert, L("BACK ARROW"),
|
||||
|
@ -3164,29 +3201,14 @@ void Tab::fill_icon_descriptions()
|
|||
|
||||
void Tab::set_tooltips_text()
|
||||
{
|
||||
// m_undo_to_sys_btn->SetToolTip(_(L( "LOCKED LOCK icon indicates that the settings are the same as the system values "
|
||||
// "for the current option group.\n"
|
||||
// "UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
|
||||
// "to the system values for the current option group.\n"
|
||||
// "WHITE BULLET icon indicates a non system preset.\n\n"
|
||||
// "Click the UNLOCKED LOCK icon to reset all settings for current option group to "
|
||||
// "the system values.")));
|
||||
//
|
||||
// m_undo_btn->SetToolTip(_(L( "WHITE BULLET icon indicates that the settings are the same as in the last saved"
|
||||
// "preset for the current option group.\n"
|
||||
// "BACK ARROW icon indicates that the settings were changed and are not equal to "
|
||||
// "the last saved preset for the current option group.\n\n"
|
||||
// "Click the BACK ARROW icon to reset all settings for the current option group to "
|
||||
// "the last saved preset.")));
|
||||
|
||||
// --- Tooltip text for reset buttons (for whole options group)
|
||||
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
|
||||
m_ttg_value_lock = _(L("LOCKED LOCK icon indicates that the settings are the same as the system values "
|
||||
m_ttg_value_lock = _(L("LOCKED LOCK icon indicates that the settings are the same as the system (or default) values "
|
||||
"for the current option group"));
|
||||
m_ttg_value_unlock = _(L("UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
|
||||
"to the system values for the current option group.\n"
|
||||
"Click to reset all settings for current option group to the system values."));
|
||||
m_ttg_white_bullet_ns = _(L("WHITE BULLET icon indicates a non system preset."));
|
||||
"to the system (or default) values for the current option group.\n"
|
||||
"Click to reset all settings for current option group to the system (or default) values."));
|
||||
m_ttg_white_bullet_ns = _(L("WHITE BULLET icon indicates a non system (or non default) preset."));
|
||||
m_ttg_non_system = &m_ttg_white_bullet_ns;
|
||||
// Text to be shown on the "Undo user changes" button next to each input field.
|
||||
m_ttg_white_bullet = _(L("WHITE BULLET icon indicates that the settings are the same as in the last saved "
|
||||
|
@ -3197,10 +3219,10 @@ void Tab::set_tooltips_text()
|
|||
|
||||
// --- Tooltip text for reset buttons (for each option in group)
|
||||
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
|
||||
m_tt_value_lock = _(L("LOCKED LOCK icon indicates that the value is the same as the system value."));
|
||||
m_tt_value_lock = _(L("LOCKED LOCK icon indicates that the value is the same as the system (or default) value."));
|
||||
m_tt_value_unlock = _(L("UNLOCKED LOCK icon indicates that the value was changed and is not equal "
|
||||
"to the system value.\n"
|
||||
"Click to reset current value to the system value."));
|
||||
"to the system (or default) value.\n"
|
||||
"Click to reset current value to the system (or default) value."));
|
||||
// m_tt_white_bullet_ns= _(L("WHITE BULLET icon indicates a non system preset."));
|
||||
m_tt_non_system = &m_ttg_white_bullet_ns;
|
||||
// Text to be shown on the "Undo user changes" button next to each input field.
|
||||
|
@ -3454,9 +3476,9 @@ void TabSLAMaterial::reload_config()
|
|||
void TabSLAMaterial::update()
|
||||
{
|
||||
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
||||
return; // #ys_FIXME
|
||||
return;
|
||||
|
||||
// #ys_FIXME
|
||||
// #ys_FIXME. Just a template for this function
|
||||
// m_update_cnt++;
|
||||
// ! something to update
|
||||
// m_update_cnt--;
|
||||
|
@ -3554,9 +3576,8 @@ void TabSLAPrint::reload_config()
|
|||
void TabSLAPrint::update()
|
||||
{
|
||||
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
||||
return; // #ys_FIXME
|
||||
return;
|
||||
|
||||
// #ys_FIXME
|
||||
m_update_cnt++;
|
||||
|
||||
double head_penetration = m_config->opt_float("support_head_penetration");
|
||||
|
|
|
@ -142,6 +142,12 @@ protected:
|
|||
PresetDependencies m_compatible_printers;
|
||||
PresetDependencies m_compatible_prints;
|
||||
|
||||
/* Indicates, that default preset or preset inherited from default is selected
|
||||
* This value is used for a options color updating
|
||||
* (use green color only for options, which values are equal to system values)
|
||||
*/
|
||||
bool m_is_default_preset {false};
|
||||
|
||||
ScalableButton* m_undo_btn;
|
||||
ScalableButton* m_undo_to_sys_btn;
|
||||
ScalableButton* m_question_btn;
|
||||
|
|
|
@ -437,27 +437,69 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
|||
m_type(type),
|
||||
m_extruder(wxEmptyString)
|
||||
{
|
||||
if (type == itSettings) {
|
||||
if (type == itSettings)
|
||||
m_name = "Settings to modified";
|
||||
}
|
||||
else if (type == itInstanceRoot) {
|
||||
else if (type == itInstanceRoot)
|
||||
m_name = _(L("Instances"));
|
||||
#ifdef __WXGTK__
|
||||
m_container = true;
|
||||
#endif //__WXGTK__
|
||||
}
|
||||
else if (type == itInstance) {
|
||||
else if (type == itInstance)
|
||||
{
|
||||
m_idx = parent->GetChildCount();
|
||||
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
|
||||
|
||||
set_action_icon();
|
||||
}
|
||||
else if (type == itLayerRoot)
|
||||
{
|
||||
m_bmp = create_scaled_bitmap(nullptr, "layers"); // FIXME: pass window ptr
|
||||
m_name = _(L("Layers"));
|
||||
}
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// it's necessary on GTK because of control have to know if this item will be container
|
||||
// in another case you couldn't to add subitem for this item
|
||||
// it will be produce "segmentation fault"
|
||||
if (type & (itInstanceRoot | itLayerRoot))
|
||||
m_container = true;
|
||||
#endif //__WXGTK__
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int idx /*= -1 */,
|
||||
const wxString& extruder) :
|
||||
m_parent(parent),
|
||||
m_type(itLayer),
|
||||
m_idx(idx),
|
||||
m_layer_range(layer_range),
|
||||
m_extruder(extruder)
|
||||
{
|
||||
const int children_cnt = parent->GetChildCount();
|
||||
if (idx < 0)
|
||||
m_idx = children_cnt;
|
||||
else
|
||||
{
|
||||
// update indexes for another Laeyr Nodes
|
||||
for (int i = m_idx; i < children_cnt; i++)
|
||||
parent->GetNthChild(i)->SetIdx(i + 1);
|
||||
}
|
||||
const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
|
||||
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
|
||||
m_bmp = create_scaled_bitmap(nullptr, "layers_white"); // FIXME: pass window ptr
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// it's necessary on GTK because of control have to know if this item will be container
|
||||
// in another case you couldn't to add subitem for this item
|
||||
// it will be produce "segmentation fault"
|
||||
m_container = true;
|
||||
#endif //__WXGTK__
|
||||
|
||||
set_action_icon();
|
||||
}
|
||||
|
||||
void ObjectDataViewModelNode::set_action_icon()
|
||||
{
|
||||
m_action_icon_name = m_type == itObject ? "advanced_plus" :
|
||||
m_type == itVolume ? "cog" : "set_separate_obj";
|
||||
m_action_icon_name = m_type & itObject ? "advanced_plus" :
|
||||
m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
|
||||
m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr
|
||||
}
|
||||
|
||||
|
@ -523,6 +565,22 @@ void ObjectDataViewModelNode::SetIdx(const int& idx)
|
|||
// ObjectDataViewModel
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
|
||||
{
|
||||
// because of istance_root and layers_root are at the end of the list, so
|
||||
// start locking from the end
|
||||
for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
|
||||
{
|
||||
// if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem
|
||||
if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
|
||||
break;
|
||||
if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
|
||||
return root_idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ObjectDataViewModel::ObjectDataViewModel()
|
||||
{
|
||||
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
|
||||
|
@ -567,10 +625,10 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
|
|||
|
||||
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
|
||||
|
||||
// because of istance_root is a last item of the object
|
||||
int insert_position = root->GetChildCount() - 1;
|
||||
if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot)
|
||||
insert_position = -1;
|
||||
// get insertion position according to the existed Layers and/or Instances Items
|
||||
int insert_position = get_root_idx(root, itLayerRoot);
|
||||
if (insert_position < 0)
|
||||
insert_position = get_root_idx(root, itInstanceRoot);
|
||||
|
||||
const bool obj_errors = root->m_bmp.IsOk();
|
||||
|
||||
|
@ -619,15 +677,30 @@ wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &paren
|
|||
return child;
|
||||
}
|
||||
|
||||
int get_istances_root_idx(ObjectDataViewModelNode *parent_node)
|
||||
/* return values:
|
||||
* true => root_node is created and added to the parent_root
|
||||
* false => root node alredy exists
|
||||
*/
|
||||
static bool append_root_node(ObjectDataViewModelNode *parent_node,
|
||||
ObjectDataViewModelNode **root_node,
|
||||
const ItemType root_type)
|
||||
{
|
||||
// because of istance_root is a last item of the object
|
||||
const int inst_root_idx = parent_node->GetChildCount()-1;
|
||||
const int inst_root_id = get_root_idx(parent_node, root_type);
|
||||
|
||||
if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->GetType() == itInstanceRoot)
|
||||
return inst_root_idx;
|
||||
*root_node = inst_root_id < 0 ?
|
||||
new ObjectDataViewModelNode(parent_node, root_type) :
|
||||
parent_node->GetNthChild(inst_root_id);
|
||||
|
||||
return -1;
|
||||
if (inst_root_id < 0) {
|
||||
if ((root_type&itInstanceRoot) ||
|
||||
(root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
|
||||
parent_node->Append(*root_node);
|
||||
else if (root_type&itLayerRoot)
|
||||
parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
|
||||
|
@ -635,20 +708,15 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
|
|||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return wxDataViewItem(0);
|
||||
|
||||
// Check and create/get instances root node
|
||||
const int inst_root_id = get_istances_root_idx(parent_node);
|
||||
// get InstanceRoot node
|
||||
ObjectDataViewModelNode *inst_root_node { nullptr };
|
||||
|
||||
ObjectDataViewModelNode *inst_root_node = inst_root_id < 0 ?
|
||||
new ObjectDataViewModelNode(parent_node, itInstanceRoot) :
|
||||
parent_node->GetNthChild(inst_root_id);
|
||||
const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot);
|
||||
const wxDataViewItem inst_root_item((void*)inst_root_node);
|
||||
if (!inst_root_node) return wxDataViewItem(0);
|
||||
|
||||
if (inst_root_id < 0) {
|
||||
parent_node->Append(inst_root_node);
|
||||
// notify control
|
||||
ItemAdded(parent_item, inst_root_item);
|
||||
// if (num == 1) num++;
|
||||
}
|
||||
if (appended)
|
||||
ItemAdded(parent_item, inst_root_item);// notify control
|
||||
|
||||
// Add instance nodes
|
||||
ObjectDataViewModelNode *instance_node = nullptr;
|
||||
|
@ -665,6 +733,63 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
|
|||
return wxDataViewItem((void*)instance_node);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
|
||||
{
|
||||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return wxDataViewItem(0);
|
||||
|
||||
// get LayerRoot node
|
||||
ObjectDataViewModelNode *layer_root_node{ nullptr };
|
||||
const bool appended = append_root_node(parent_node, &layer_root_node, itLayerRoot);
|
||||
if (!layer_root_node) return wxDataViewItem(0);
|
||||
|
||||
const wxDataViewItem layer_root_item((void*)layer_root_node);
|
||||
|
||||
if (appended)
|
||||
ItemAdded(parent_item, layer_root_item);// notify control
|
||||
|
||||
return layer_root_item;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int extruder/* = 0*/,
|
||||
const int index /* = -1*/)
|
||||
{
|
||||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return wxDataViewItem(0);
|
||||
|
||||
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
|
||||
|
||||
// get LayerRoot node
|
||||
ObjectDataViewModelNode *layer_root_node;
|
||||
wxDataViewItem layer_root_item;
|
||||
|
||||
if (parent_node->GetType() & itLayerRoot) {
|
||||
layer_root_node = parent_node;
|
||||
layer_root_item = parent_item;
|
||||
}
|
||||
else {
|
||||
const int root_idx = get_root_idx(parent_node, itLayerRoot);
|
||||
if (root_idx < 0) return wxDataViewItem(0);
|
||||
layer_root_node = parent_node->GetNthChild(root_idx);
|
||||
layer_root_item = wxDataViewItem((void*)layer_root_node);
|
||||
}
|
||||
|
||||
// Add layer node
|
||||
ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str);
|
||||
if (index < 0)
|
||||
layer_root_node->Append(layer_node);
|
||||
else
|
||||
layer_root_node->Insert(layer_node, index);
|
||||
|
||||
// notify control
|
||||
const wxDataViewItem layer_item((void*)layer_node);
|
||||
ItemAdded(layer_root_item, layer_item);
|
||||
|
||||
return layer_item;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
||||
{
|
||||
auto ret_item = wxDataViewItem(0);
|
||||
|
@ -679,9 +804,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
|
||||
// thus removing the node from it doesn't result in freeing it
|
||||
if (node_parent) {
|
||||
if (node->m_type == itInstanceRoot)
|
||||
if (node->m_type & (itInstanceRoot|itLayerRoot))
|
||||
{
|
||||
for (int i = node->GetChildCount() - 1; i > 0; i--)
|
||||
for (int i = node->GetChildCount() - 1; i >= (node->m_type & itInstanceRoot ? 1 : 0); i--)
|
||||
Delete(wxDataViewItem(node->GetNthChild(i)));
|
||||
return parent;
|
||||
}
|
||||
|
@ -690,7 +815,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
auto idx = node->GetIdx();
|
||||
|
||||
|
||||
if (node->m_type == itVolume) {
|
||||
if (node->m_type & (itVolume|itLayer)) {
|
||||
node_parent->m_volumes_cnt--;
|
||||
DeleteSettings(item);
|
||||
}
|
||||
|
@ -726,6 +851,22 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
delete node_parent;
|
||||
ret_item = wxDataViewItem(obj_node);
|
||||
|
||||
#ifndef __WXGTK__
|
||||
if (obj_node->GetChildCount() == 0)
|
||||
obj_node->m_container = false;
|
||||
#endif //__WXGTK__
|
||||
ItemDeleted(ret_item, wxDataViewItem(node_parent));
|
||||
return ret_item;
|
||||
}
|
||||
|
||||
// if there was last layer item, delete this one and layers root item
|
||||
if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
|
||||
{
|
||||
ObjectDataViewModelNode *obj_node = node_parent->GetParent();
|
||||
obj_node->GetChildren().Remove(node_parent);
|
||||
delete node_parent;
|
||||
ret_item = wxDataViewItem(obj_node);
|
||||
|
||||
#ifndef __WXGTK__
|
||||
if (obj_node->GetChildCount() == 0)
|
||||
obj_node->m_container = false;
|
||||
|
@ -735,7 +876,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
}
|
||||
|
||||
// if there is last volume item after deleting, delete this last volume too
|
||||
if (node_parent->GetChildCount() <= 3)
|
||||
if (node_parent->GetChildCount() <= 3) // 3??? #ys_FIXME
|
||||
{
|
||||
int vol_cnt = 0;
|
||||
int vol_idx = 0;
|
||||
|
@ -817,7 +958,7 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
|
|||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return ret_item;
|
||||
|
||||
const int inst_root_id = get_istances_root_idx(parent_node);
|
||||
const int inst_root_id = get_root_idx(parent_node, itInstanceRoot);
|
||||
if (inst_root_id < 0) return ret_item;
|
||||
|
||||
wxDataViewItemArray items;
|
||||
|
@ -974,28 +1115,67 @@ wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_id
|
|||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
|
||||
wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type)
|
||||
{
|
||||
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
||||
printf("Error! Out of objects range.\n");
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx]));
|
||||
if (!instances_item)
|
||||
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
|
||||
if (!item)
|
||||
return wxDataViewItem(0);
|
||||
|
||||
auto parent = (ObjectDataViewModelNode*)instances_item.GetID();;
|
||||
auto parent = (ObjectDataViewModelNode*)item.GetID();
|
||||
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
||||
if (parent->GetNthChild(i)->m_idx == inst_idx)
|
||||
if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
|
||||
return wxDataViewItem(parent->GetNthChild(i));
|
||||
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
|
||||
{
|
||||
return GetItemById(obj_idx, inst_idx, itInstanceRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
|
||||
{
|
||||
return GetItemById(obj_idx, layer_idx, itLayerRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
|
||||
{
|
||||
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
||||
printf("Error! Out of objects range.\n");
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
|
||||
if (!item)
|
||||
return wxDataViewItem(0);
|
||||
|
||||
auto parent = (ObjectDataViewModelNode*)item.GetID();
|
||||
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
||||
if (parent->GetNthChild(i)->m_layer_range == layer_range)
|
||||
return wxDataViewItem(parent->GetNthChild(i));
|
||||
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
int ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
|
||||
{
|
||||
wxDataViewItem item = GetItemByLayerRange(obj_idx, layer_range);
|
||||
if (!item)
|
||||
return -1;
|
||||
|
||||
return GetLayerIdByItem(item);
|
||||
}
|
||||
|
||||
int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
if(!item.IsOk())
|
||||
return -1;
|
||||
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
auto it = find(m_objects.begin(), m_objects.end(), node);
|
||||
|
@ -1030,13 +1210,28 @@ int ObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const
|
|||
return GetIdByItemAndType(item, itInstance);
|
||||
}
|
||||
|
||||
int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const
|
||||
{
|
||||
return GetIdByItemAndType(item, itLayer);
|
||||
}
|
||||
|
||||
t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewItem& item) const
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node || node->m_type != itLayer)
|
||||
return { 0.0f, 0.0f };
|
||||
return node->GetLayerRange();
|
||||
}
|
||||
|
||||
void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
type = itUndef;
|
||||
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node || node->GetIdx() <-1 || node->GetIdx() ==-1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot)))
|
||||
if (!node || node->GetIdx() <-1 || node->GetIdx() == -1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/)))
|
||||
return;
|
||||
|
||||
idx = node->GetIdx();
|
||||
|
@ -1044,9 +1239,10 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
|
|||
|
||||
ObjectDataViewModelNode *parent_node = node->GetParent();
|
||||
if (!parent_node) return;
|
||||
if (type == itInstance)
|
||||
parent_node = node->GetParent()->GetParent();
|
||||
if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; }
|
||||
|
||||
// get top parent (Object) node
|
||||
while (parent_node->m_type != itObject)
|
||||
parent_node = parent_node->GetParent();
|
||||
|
||||
auto it = find(m_objects.begin(), m_objects.end(), parent_node);
|
||||
if (it != m_objects.end())
|
||||
|
@ -1214,10 +1410,7 @@ wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) con
|
|||
|
||||
ObjectDataViewModelNode *parent_node = node->GetParent();
|
||||
while (parent_node->m_type != itObject)
|
||||
{
|
||||
node = parent_node;
|
||||
parent_node = node->GetParent();
|
||||
}
|
||||
parent_node = parent_node->GetParent();
|
||||
|
||||
return wxDataViewItem((void*)parent_node);
|
||||
}
|
||||
|
@ -1318,6 +1511,11 @@ wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &it
|
|||
return GetItemByType(item, itInstanceRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
|
||||
{
|
||||
return GetItemByType(item, itLayerRoot);
|
||||
}
|
||||
|
||||
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
|
||||
{
|
||||
if (!item.IsOk())
|
||||
|
@ -2027,6 +2225,9 @@ void DoubleSlider::draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord
|
|||
|
||||
void DoubleSlider::draw_ticks(wxDC& dc)
|
||||
{
|
||||
if (!m_is_enabled_tick_manipulation)
|
||||
return;
|
||||
|
||||
dc.SetPen(m_is_enabled_tick_manipulation ? DARK_GREY_PEN : LIGHT_GREY_PEN );
|
||||
int height, width;
|
||||
get_size(&width, &height);
|
||||
|
@ -2044,6 +2245,9 @@ void DoubleSlider::draw_ticks(wxDC& dc)
|
|||
|
||||
void DoubleSlider::draw_colored_band(wxDC& dc)
|
||||
{
|
||||
if (!m_is_enabled_tick_manipulation)
|
||||
return;
|
||||
|
||||
int height, width;
|
||||
get_size(&width, &height);
|
||||
|
||||
|
@ -2113,7 +2317,7 @@ void DoubleSlider::draw_one_layer_icon(wxDC& dc)
|
|||
|
||||
void DoubleSlider::draw_revert_icon(wxDC& dc)
|
||||
{
|
||||
if (m_ticks.empty())
|
||||
if (m_ticks.empty() || !m_is_enabled_tick_manipulation)
|
||||
return;
|
||||
|
||||
int width, height;
|
||||
|
@ -2218,7 +2422,7 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
|
|||
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
|
||||
if (!m_selection) m_selection = ssHigher;
|
||||
}
|
||||
else if (is_point_in_rect(pos, m_rect_revert_icon)) {
|
||||
else if (is_point_in_rect(pos, m_rect_revert_icon) && m_is_enabled_tick_manipulation) {
|
||||
// discard all color changes
|
||||
SetLowerValue(m_min_value);
|
||||
SetHigherValue(m_max_value);
|
||||
|
@ -2647,7 +2851,7 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
|
|||
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
|
||||
#endif // __WXOSX__
|
||||
|
||||
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, m_mode_btns.size() - 1));
|
||||
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
|
||||
Add(m_mode_btns.back());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ namespace Slic3r {
|
|||
enum class ModelVolumeType : int;
|
||||
};
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
|
||||
#ifdef __WXMSW__
|
||||
void msw_rescale_menu(wxMenu* menu);
|
||||
#else /* __WXMSW__ */
|
||||
|
@ -159,12 +162,14 @@ DECLARE_VARIANT_OBJECT(DataViewBitmapText)
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
enum ItemType {
|
||||
itUndef = 0,
|
||||
itObject = 1,
|
||||
itVolume = 2,
|
||||
itInstanceRoot = 4,
|
||||
itInstance = 8,
|
||||
itSettings = 16
|
||||
itUndef = 0,
|
||||
itObject = 1,
|
||||
itVolume = 2,
|
||||
itInstanceRoot = 4,
|
||||
itInstance = 8,
|
||||
itSettings = 16,
|
||||
itLayerRoot = 32,
|
||||
itLayer = 64,
|
||||
};
|
||||
|
||||
class ObjectDataViewModelNode;
|
||||
|
@ -177,6 +182,7 @@ class ObjectDataViewModelNode
|
|||
wxBitmap m_empty_bmp;
|
||||
size_t m_volumes_cnt = 0;
|
||||
std::vector< std::string > m_opt_categories;
|
||||
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
|
||||
|
||||
wxString m_name;
|
||||
wxBitmap& m_bmp = m_empty_bmp;
|
||||
|
@ -229,6 +235,11 @@ public:
|
|||
set_action_icon();
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int idx = -1,
|
||||
const wxString& extruder = wxEmptyString );
|
||||
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
|
||||
|
||||
~ObjectDataViewModelNode()
|
||||
|
@ -318,6 +329,7 @@ public:
|
|||
ItemType GetType() const { return m_type; }
|
||||
void SetIdx(const int& idx);
|
||||
int GetIdx() const { return m_idx; }
|
||||
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
||||
|
||||
// use this function only for childrens
|
||||
void AssignAllVal(ObjectDataViewModelNode& from_node)
|
||||
|
@ -348,7 +360,7 @@ public:
|
|||
}
|
||||
|
||||
// Set action icons for node
|
||||
void set_action_icon();
|
||||
void set_action_icon();
|
||||
|
||||
void update_settings_digest_bitmaps();
|
||||
bool update_settings_digest(const std::vector<std::string>& categories);
|
||||
|
@ -388,6 +400,11 @@ public:
|
|||
const bool create_frst_child = true);
|
||||
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
||||
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
|
||||
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int extruder = 0,
|
||||
const int index = -1);
|
||||
wxDataViewItem Delete(const wxDataViewItem &item);
|
||||
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
|
||||
void DeleteAll();
|
||||
|
@ -395,13 +412,18 @@ public:
|
|||
void DeleteVolumeChildren(wxDataViewItem& parent);
|
||||
void DeleteSettings(const wxDataViewItem& parent);
|
||||
wxDataViewItem GetItemById(int obj_idx);
|
||||
wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
|
||||
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
|
||||
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
|
||||
wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
|
||||
wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
||||
int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
||||
int GetIdByItem(const wxDataViewItem& item) const;
|
||||
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
|
||||
int GetObjectIdByItem(const wxDataViewItem& item) const;
|
||||
int GetVolumeIdByItem(const wxDataViewItem& item) const;
|
||||
int GetInstanceIdByItem(const wxDataViewItem& item) const;
|
||||
int GetLayerIdByItem(const wxDataViewItem& item) const;
|
||||
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
|
||||
int GetRowByItem(const wxDataViewItem& item) const;
|
||||
bool IsEmpty() { return m_objects.empty(); }
|
||||
|
@ -450,6 +472,7 @@ public:
|
|||
ItemType type) const;
|
||||
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
|
||||
bool IsSettingsItem(const wxDataViewItem &item) const;
|
||||
void UpdateSettingsDigest( const wxDataViewItem &item,
|
||||
const std::vector<std::string>& categories);
|
||||
|
@ -465,6 +488,7 @@ public:
|
|||
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
|
||||
const bool is_marked = false);
|
||||
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
||||
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue