mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-20 15:21:21 -06:00
Merge branch 'master' into lm_sla_supports_auto
This commit is contained in:
commit
9571e7c209
46 changed files with 1136 additions and 581 deletions
|
@ -1872,6 +1872,7 @@ GUI::GLCanvas3DManager _3DScene::s_canvas_mgr;
|
|||
GLModel::GLModel()
|
||||
: m_useVBOs(false)
|
||||
{
|
||||
m_volume.shader_outside_printer_detection_enabled = false;
|
||||
}
|
||||
|
||||
GLModel::~GLModel()
|
||||
|
@ -1879,11 +1880,36 @@ GLModel::~GLModel()
|
|||
m_volume.release_geometry();
|
||||
}
|
||||
|
||||
void GLModel::set_color(float* color, unsigned int size)
|
||||
void GLModel::set_color(const float* color, unsigned int size)
|
||||
{
|
||||
m_volume.set_render_color(color, size);
|
||||
}
|
||||
|
||||
const Vec3d& GLModel::get_offset() const
|
||||
{
|
||||
return m_volume.get_volume_offset();
|
||||
}
|
||||
|
||||
void GLModel::set_offset(const Vec3d& offset)
|
||||
{
|
||||
m_volume.set_volume_offset(offset);
|
||||
}
|
||||
|
||||
const Vec3d& GLModel::get_rotation() const
|
||||
{
|
||||
return m_volume.get_volume_rotation();
|
||||
}
|
||||
|
||||
void GLModel::set_rotation(const Vec3d& rotation)
|
||||
{
|
||||
m_volume.set_volume_rotation(rotation);
|
||||
}
|
||||
|
||||
const Vec3d& GLModel::get_scale() const
|
||||
{
|
||||
return m_volume.get_volume_scaling_factor();
|
||||
}
|
||||
|
||||
void GLModel::set_scale(const Vec3d& scale)
|
||||
{
|
||||
m_volume.set_volume_scaling_factor(scale);
|
||||
|
@ -1894,8 +1920,7 @@ void GLModel::render() const
|
|||
if (m_useVBOs)
|
||||
render_VBOs();
|
||||
else
|
||||
{
|
||||
}
|
||||
render_legacy();
|
||||
}
|
||||
|
||||
void GLModel::render_VBOs() const
|
||||
|
@ -1910,8 +1935,9 @@ void GLModel::render_VBOs() const
|
|||
GLint current_program_id;
|
||||
::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id);
|
||||
GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1;
|
||||
GLint print_box_detection_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1;
|
||||
|
||||
m_volume.render_VBOs(color_id, -1, -1);
|
||||
m_volume.render_VBOs(color_id, print_box_detection_id, -1);
|
||||
|
||||
::glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
@ -1922,9 +1948,23 @@ void GLModel::render_VBOs() const
|
|||
::glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
GLArrow::GLArrow()
|
||||
: GLModel()
|
||||
void GLModel::render_legacy() const
|
||||
{
|
||||
::glEnable(GL_LIGHTING);
|
||||
::glEnable(GL_BLEND);
|
||||
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
::glCullFace(GL_BACK);
|
||||
::glEnableClientState(GL_VERTEX_ARRAY);
|
||||
::glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
m_volume.render_legacy();
|
||||
|
||||
::glDisableClientState(GL_VERTEX_ARRAY);
|
||||
::glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
::glDisable(GL_BLEND);
|
||||
::glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
bool GLArrow::on_init(bool useVBOs)
|
||||
|
@ -1932,7 +1972,7 @@ bool GLArrow::on_init(bool useVBOs)
|
|||
Pointf3s vertices;
|
||||
std::vector<Vec3crd> triangles;
|
||||
|
||||
// top face
|
||||
// bottom face
|
||||
vertices.emplace_back(0.5, 0.0, -0.1);
|
||||
vertices.emplace_back(0.5, 2.0, -0.1);
|
||||
vertices.emplace_back(1.0, 2.0, -0.1);
|
||||
|
@ -1941,7 +1981,7 @@ bool GLArrow::on_init(bool useVBOs)
|
|||
vertices.emplace_back(-0.5, 2.0, -0.1);
|
||||
vertices.emplace_back(-0.5, 0.0, -0.1);
|
||||
|
||||
// bottom face
|
||||
// top face
|
||||
vertices.emplace_back(0.5, 0.0, 0.1);
|
||||
vertices.emplace_back(0.5, 2.0, 0.1);
|
||||
vertices.emplace_back(1.0, 2.0, 0.1);
|
||||
|
@ -1990,6 +2030,126 @@ bool GLArrow::on_init(bool useVBOs)
|
|||
m_volume.finalize_geometry(m_useVBOs);
|
||||
return true;
|
||||
}
|
||||
|
||||
GLCurvedArrow::GLCurvedArrow(unsigned int resolution)
|
||||
: GLModel()
|
||||
, m_resolution(resolution)
|
||||
{
|
||||
if (m_resolution == 0)
|
||||
m_resolution = 1;
|
||||
}
|
||||
|
||||
bool GLCurvedArrow::on_init(bool useVBOs)
|
||||
{
|
||||
Pointf3s vertices;
|
||||
std::vector<Vec3crd> triangles;
|
||||
|
||||
double ext_radius = 2.5;
|
||||
double int_radius = 1.5;
|
||||
double step = 0.5 * (double)PI / (double)m_resolution;
|
||||
|
||||
unsigned int vertices_per_level = 4 + 2 * m_resolution;
|
||||
|
||||
// bottom face
|
||||
vertices.emplace_back(0.0, 1.5, -0.1);
|
||||
vertices.emplace_back(0.0, 1.0, -0.1);
|
||||
vertices.emplace_back(-1.0, 2.0, -0.1);
|
||||
vertices.emplace_back(0.0, 3.0, -0.1);
|
||||
vertices.emplace_back(0.0, 2.5, -0.1);
|
||||
|
||||
for (unsigned int i = 1; i <= m_resolution; ++i)
|
||||
{
|
||||
double angle = (double)i * step;
|
||||
double x = ext_radius * ::sin(angle);
|
||||
double y = ext_radius * ::cos(angle);
|
||||
|
||||
vertices.emplace_back(x, y, -0.1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_resolution; ++i)
|
||||
{
|
||||
double angle = (double)i * step;
|
||||
double x = int_radius * ::cos(angle);
|
||||
double y = int_radius * ::sin(angle);
|
||||
|
||||
vertices.emplace_back(x, y, -0.1);
|
||||
}
|
||||
|
||||
// top face
|
||||
vertices.emplace_back(0.0, 1.5, 0.1);
|
||||
vertices.emplace_back(0.0, 1.0, 0.1);
|
||||
vertices.emplace_back(-1.0, 2.0, 0.1);
|
||||
vertices.emplace_back(0.0, 3.0, 0.1);
|
||||
vertices.emplace_back(0.0, 2.5, 0.1);
|
||||
|
||||
for (unsigned int i = 1; i <= m_resolution; ++i)
|
||||
{
|
||||
double angle = (double)i * step;
|
||||
double x = ext_radius * ::sin(angle);
|
||||
double y = ext_radius * ::cos(angle);
|
||||
|
||||
vertices.emplace_back(x, y, 0.1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_resolution; ++i)
|
||||
{
|
||||
double angle = (double)i * step;
|
||||
double x = int_radius * ::cos(angle);
|
||||
double y = int_radius * ::sin(angle);
|
||||
|
||||
vertices.emplace_back(x, y, 0.1);
|
||||
}
|
||||
|
||||
// bottom face
|
||||
triangles.emplace_back(0, 1, 2);
|
||||
triangles.emplace_back(0, 2, 4);
|
||||
triangles.emplace_back(4, 2, 3);
|
||||
|
||||
int first_id = 4;
|
||||
int last_id = (int)vertices_per_level;
|
||||
triangles.emplace_back(last_id, 0, first_id);
|
||||
triangles.emplace_back(last_id, first_id, first_id + 1);
|
||||
for (unsigned int i = 1; i < m_resolution; ++i)
|
||||
{
|
||||
triangles.emplace_back(last_id - i, last_id - i + 1, first_id + i);
|
||||
triangles.emplace_back(last_id - i, first_id + i, first_id + i + 1);
|
||||
}
|
||||
|
||||
// top face
|
||||
last_id += 1;
|
||||
triangles.emplace_back(last_id + 0, last_id + 2, last_id + 1);
|
||||
triangles.emplace_back(last_id + 0, last_id + 4, last_id + 2);
|
||||
triangles.emplace_back(last_id + 4, last_id + 3, last_id + 2);
|
||||
|
||||
first_id = last_id + 4;
|
||||
last_id = last_id + 4 + 2 * (int)m_resolution;
|
||||
triangles.emplace_back(last_id, first_id, (int)vertices_per_level + 1);
|
||||
triangles.emplace_back(last_id, first_id + 1, first_id);
|
||||
for (unsigned int i = 1; i < m_resolution; ++i)
|
||||
{
|
||||
triangles.emplace_back(last_id - i, first_id + i, last_id - i + 1);
|
||||
triangles.emplace_back(last_id - i, first_id + i + 1, first_id + i);
|
||||
}
|
||||
|
||||
// side face
|
||||
for (unsigned int i = 0; i < 4 + 2 * (int)m_resolution; ++i)
|
||||
{
|
||||
triangles.emplace_back(i, vertices_per_level + 2 + i, i + 1);
|
||||
triangles.emplace_back(i, vertices_per_level + 1 + i, vertices_per_level + 2 + i);
|
||||
}
|
||||
triangles.emplace_back(vertices_per_level, vertices_per_level + 1, 0);
|
||||
triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1);
|
||||
|
||||
m_useVBOs = useVBOs;
|
||||
|
||||
if (m_useVBOs)
|
||||
m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles));
|
||||
else
|
||||
m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles));
|
||||
|
||||
m_volume.finalize_geometry(m_useVBOs);
|
||||
return true;
|
||||
}
|
||||
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
|
||||
std::string _3DScene::get_gl_info(bool format_as_html, bool extensions)
|
||||
|
|
|
@ -595,7 +595,13 @@ public:
|
|||
|
||||
bool init(bool useVBOs) { return on_init(useVBOs); }
|
||||
|
||||
void set_color(float* color, unsigned int size);
|
||||
void set_color(const float* color, unsigned int size);
|
||||
|
||||
const Vec3d& get_offset() const;
|
||||
void set_offset(const Vec3d& offset);
|
||||
const Vec3d& get_rotation() const;
|
||||
void set_rotation(const Vec3d& rotation);
|
||||
const Vec3d& get_scale() const;
|
||||
void set_scale(const Vec3d& scale);
|
||||
|
||||
void render() const;
|
||||
|
@ -605,12 +611,21 @@ protected:
|
|||
|
||||
private:
|
||||
void render_VBOs() const;
|
||||
void render_legacy() const;
|
||||
};
|
||||
|
||||
class GLArrow : public GLModel
|
||||
{
|
||||
protected:
|
||||
virtual bool on_init(bool useVBOs);
|
||||
};
|
||||
|
||||
class GLCurvedArrow : public GLModel
|
||||
{
|
||||
unsigned int m_resolution;
|
||||
|
||||
public:
|
||||
GLArrow();
|
||||
explicit GLCurvedArrow(unsigned int resolution);
|
||||
|
||||
protected:
|
||||
virtual bool on_init(bool useVBOs);
|
||||
|
|
|
@ -84,26 +84,7 @@ void BackgroundSlicingProcess::process_fff()
|
|||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
m_print->set_status(100, "G-code file exported to " + export_path);
|
||||
} else if (! m_upload_job.empty()) {
|
||||
// A print host upload job has been scheduled
|
||||
|
||||
// XXX: is fs::path::string() right?
|
||||
|
||||
// Generate a unique temp path to which the gcode is copied
|
||||
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
|
||||
/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode");
|
||||
|
||||
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
|
||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||
}
|
||||
|
||||
m_print->set_status(95, "Running post-processing scripts");
|
||||
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
||||
m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str());
|
||||
|
||||
m_upload_job.upload_data.source_path = std::move(source_path);
|
||||
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
|
||||
GUI::wxGetApp().printhost_job_queue().enqueue(std::move(m_upload_job));
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, "Slicing complete");
|
||||
}
|
||||
|
@ -170,6 +151,10 @@ void BackgroundSlicingProcess::process_sla()
|
|||
if (! m_export_path.empty()) {
|
||||
m_sla_print->export_raster<SLAZipFmt>(m_export_path);
|
||||
m_print->set_status(100, "Zip file exported to " + m_export_path);
|
||||
} else if (! m_upload_job.empty()) {
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, "Slicing complete");
|
||||
}
|
||||
this->set_step_done(bspsGCodeFinalize);
|
||||
}
|
||||
|
@ -440,4 +425,35 @@ bool BackgroundSlicingProcess::invalidate_all_steps()
|
|||
return m_step_state.invalidate_all([this](){ this->stop_internal(); });
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::prepare_upload()
|
||||
{
|
||||
// A print host upload job has been scheduled, enqueue it to the printhost job queue
|
||||
|
||||
// XXX: is fs::path::string() right?
|
||||
|
||||
// Generate a unique temp path to which the gcode/zip file is copied/exported
|
||||
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
|
||||
/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode");
|
||||
|
||||
if (m_print == m_fff_print) {
|
||||
m_print->set_status(95, "Running post-processing scripts");
|
||||
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
||||
|
||||
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
|
||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||
}
|
||||
|
||||
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
} else {
|
||||
m_sla_print->export_raster<SLAZipFmt>(source_path.string());
|
||||
// TODO: Also finalize upload path like with FFF when there are statistics for SLA print
|
||||
}
|
||||
|
||||
m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str());
|
||||
|
||||
m_upload_job.upload_data.source_path = std::move(source_path);
|
||||
|
||||
GUI::wxGetApp().printhost_job_queue().enqueue(std::move(m_upload_job));
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
@ -167,6 +167,7 @@ private:
|
|||
bool invalidate_all_steps();
|
||||
// If the background processing stop was requested, throw CanceledException.
|
||||
void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); }
|
||||
void prepare_upload();
|
||||
|
||||
// wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue.
|
||||
int m_event_slicing_completed_id = 0;
|
||||
|
|
|
@ -73,6 +73,11 @@ static const float DEFAULT_BG_LIGHT_COLOR[3] = { 0.753f, 0.753f, 0.753f };
|
|||
static const float ERROR_BG_DARK_COLOR[3] = { 0.478f, 0.192f, 0.039f };
|
||||
static const float ERROR_BG_LIGHT_COLOR[3] = { 0.753f, 0.192f, 0.039f };
|
||||
|
||||
#if ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
static const float UNIFORM_SCALE_COLOR[3] = { 1.0f, 0.38f, 0.0f };
|
||||
static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } };
|
||||
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
@ -1154,12 +1159,6 @@ GLCanvas3D::Selection::VolumeCache::VolumeCache(const Vec3d& position, const Vec
|
|||
}
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
#if ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
const float GLCanvas3D::Selection::RED[3] = { 1.0f, 0.0f, 0.0f };
|
||||
const float GLCanvas3D::Selection::GREEN[3] = { 0.0f, 1.0f, 0.0f };
|
||||
const float GLCanvas3D::Selection::BLUE[3] = { 0.0f, 0.0f, 1.0f };
|
||||
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
|
||||
GLCanvas3D::Selection::Selection()
|
||||
: m_volumes(nullptr)
|
||||
, m_model(nullptr)
|
||||
|
@ -1167,6 +1166,7 @@ GLCanvas3D::Selection::Selection()
|
|||
, m_type(Empty)
|
||||
, m_valid(false)
|
||||
, m_bounding_box_dirty(true)
|
||||
, m_curved_arrow(16)
|
||||
{
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
m_quadric = ::gluNewQuadric();
|
||||
|
@ -1192,13 +1192,16 @@ void GLCanvas3D::Selection::set_volumes(GLVolumePtrs* volumes)
|
|||
#if ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
bool GLCanvas3D::Selection::init(bool useVBOs)
|
||||
{
|
||||
if (m_arrow.init(useVBOs))
|
||||
{
|
||||
m_arrow.set_scale(5.0 * Vec3d::Ones());
|
||||
return true;
|
||||
}
|
||||
if (!m_arrow.init(useVBOs))
|
||||
return false;
|
||||
|
||||
return false;
|
||||
m_arrow.set_scale(5.0 * Vec3d::Ones());
|
||||
|
||||
if (!m_curved_arrow.init(useVBOs))
|
||||
return false;
|
||||
|
||||
m_curved_arrow.set_scale(5.0 * Vec3d::Ones());
|
||||
return true;
|
||||
}
|
||||
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
|
||||
|
@ -2094,14 +2097,22 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel
|
|||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
const GLVolume* volume = (*m_volumes)[*m_list.begin()];
|
||||
Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true) * volume->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
const Vec3d& offset = get_bounding_box().center();
|
||||
|
||||
::glTranslated(offset(0), offset(1), offset(2));
|
||||
::glMultMatrixd(orient_matrix.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
::glTranslated(center(0), center(1), center(2));
|
||||
if (requires_local_axes())
|
||||
{
|
||||
const GLVolume* volume = (*m_volumes)[*m_list.begin()];
|
||||
Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
::glMultMatrixd(orient_matrix.data());
|
||||
}
|
||||
}
|
||||
|
||||
if (boost::starts_with(sidebar_field, "position"))
|
||||
_render_sidebar_position_hints(sidebar_field);
|
||||
|
@ -2544,6 +2555,18 @@ void GLCanvas3D::Selection::_render_sidebar_position_hints(const std::string& si
|
|||
|
||||
void GLCanvas3D::Selection::_render_sidebar_rotation_hints(const std::string& sidebar_field) const
|
||||
{
|
||||
if (boost::ends_with(sidebar_field, "x"))
|
||||
{
|
||||
::glRotated(90.0, 0.0, 1.0, 0.0);
|
||||
_render_sidebar_rotation_hint(X);
|
||||
}
|
||||
else if (boost::ends_with(sidebar_field, "y"))
|
||||
{
|
||||
::glRotated(-90.0, 1.0, 0.0, 0.0);
|
||||
_render_sidebar_rotation_hint(Y);
|
||||
}
|
||||
else if (boost::ends_with(sidebar_field, "z"))
|
||||
_render_sidebar_rotation_hint(Z);
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sidebar_field) const
|
||||
|
@ -2579,33 +2602,22 @@ void GLCanvas3D::Selection::_render_sidebar_size_hints(const std::string& sideba
|
|||
|
||||
void GLCanvas3D::Selection::_render_sidebar_position_hint(Axis axis) const
|
||||
{
|
||||
float color[3];
|
||||
switch (axis)
|
||||
{
|
||||
case X: { ::memcpy((void*)color, (const void*)RED, 3 * sizeof(float)); break; }
|
||||
case Y: { ::memcpy((void*)color, (const void*)GREEN, 3 * sizeof(float)); break; }
|
||||
case Z: { ::memcpy((void*)color, (const void*)BLUE, 3 * sizeof(float)); break; }
|
||||
}
|
||||
|
||||
m_arrow.set_color(color, 3);
|
||||
m_arrow.set_color(AXES_COLOR[axis], 3);
|
||||
m_arrow.render();
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis, double length) const
|
||||
void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis) const
|
||||
{
|
||||
m_curved_arrow.set_color(AXES_COLOR[axis], 3);
|
||||
m_curved_arrow.render();
|
||||
|
||||
::glRotated(180.0, 0.0, 0.0, 1.0);
|
||||
m_curved_arrow.render();
|
||||
}
|
||||
|
||||
void GLCanvas3D::Selection::_render_sidebar_scale_hint(Axis axis) const
|
||||
{
|
||||
float color[3];
|
||||
switch (axis)
|
||||
{
|
||||
case X: { ::memcpy((void*)color, (const void*)RED, 3 * sizeof(float)); break; }
|
||||
case Y: { ::memcpy((void*)color, (const void*)GREEN, 3 * sizeof(float)); break; }
|
||||
case Z: { ::memcpy((void*)color, (const void*)BLUE, 3 * sizeof(float)); break; }
|
||||
}
|
||||
|
||||
m_arrow.set_color(color, 3);
|
||||
m_arrow.set_color((requires_uniform_scale() ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3);
|
||||
|
||||
::glTranslated(0.0, 5.0, 0.0);
|
||||
m_arrow.render();
|
||||
|
@ -3818,7 +3830,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
|||
, m_legend_texture_enabled(false)
|
||||
, m_picking_enabled(false)
|
||||
, m_moving_enabled(false)
|
||||
, m_shader_enabled(false)
|
||||
, m_dynamic_background_enabled(false)
|
||||
, m_multisample_allowed(false)
|
||||
, m_regenerate_volumes(true)
|
||||
|
@ -4132,11 +4143,6 @@ void GLCanvas3D::enable_toolbar(bool enable)
|
|||
m_toolbar.set_enabled(enable);
|
||||
}
|
||||
|
||||
void GLCanvas3D::enable_shader(bool enable)
|
||||
{
|
||||
m_shader_enabled = enable;
|
||||
}
|
||||
|
||||
void GLCanvas3D::enable_force_zoom_to_bed(bool enable)
|
||||
{
|
||||
m_force_zoom_to_bed_enabled = enable;
|
||||
|
@ -6310,9 +6316,7 @@ void GLCanvas3D::_render_objects() const
|
|||
::glEnable(GL_LIGHTING);
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
|
||||
if (!m_shader_enabled)
|
||||
_render_volumes(false);
|
||||
else if (m_use_VBOs)
|
||||
if (m_use_VBOs)
|
||||
{
|
||||
if (m_picking_enabled)
|
||||
{
|
||||
|
|
|
@ -369,12 +369,6 @@ class GLCanvas3D
|
|||
public:
|
||||
class Selection
|
||||
{
|
||||
#if ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
static const float RED[3];
|
||||
static const float GREEN[3];
|
||||
static const float BLUE[3];
|
||||
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
|
||||
public:
|
||||
typedef std::set<unsigned int> IndicesList;
|
||||
|
||||
|
@ -504,6 +498,7 @@ public:
|
|||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
#if ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
mutable GLArrow m_arrow;
|
||||
mutable GLCurvedArrow m_curved_arrow;
|
||||
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
|
||||
public:
|
||||
|
@ -619,7 +614,7 @@ public:
|
|||
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_position_hint(Axis axis) const;
|
||||
void _render_sidebar_rotation_hint(Axis axis, double length) const;
|
||||
void _render_sidebar_rotation_hint(Axis axis) const;
|
||||
void _render_sidebar_scale_hint(Axis axis) const;
|
||||
void _render_sidebar_size_hint(Axis axis, double length) const;
|
||||
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
|
||||
|
@ -855,7 +850,6 @@ private:
|
|||
bool m_legend_texture_enabled;
|
||||
bool m_picking_enabled;
|
||||
bool m_moving_enabled;
|
||||
bool m_shader_enabled;
|
||||
bool m_dynamic_background_enabled;
|
||||
bool m_multisample_allowed;
|
||||
bool m_regenerate_volumes;
|
||||
|
@ -955,7 +949,6 @@ public:
|
|||
void enable_moving(bool enable);
|
||||
void enable_gizmos(bool enable);
|
||||
void enable_toolbar(bool enable);
|
||||
void enable_shader(bool enable);
|
||||
void enable_force_zoom_to_bed(bool enable);
|
||||
void enable_dynamic_background(bool enable);
|
||||
void allow_multisample(bool allow);
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace GUI {
|
|||
|
||||
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||
{
|
||||
static const wxString defaults[FT_SIZE] = {
|
||||
static const std::string defaults[FT_SIZE] = {
|
||||
/* FT_STL */ "STL files (*.stl)|*.stl;*.STL",
|
||||
/* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ",
|
||||
/* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML",
|
||||
|
@ -57,13 +57,17 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
|||
/* FT_PNGZIP */"Zipped PNG files (*.zip)|*.zip;*.ZIP", // This is lame, but that's what we use for SLA
|
||||
};
|
||||
|
||||
wxString out = defaults[file_type];
|
||||
std::string out = defaults[file_type];
|
||||
if (! custom_extension.empty()) {
|
||||
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it.
|
||||
out += ";*";
|
||||
out += from_u8(custom_extension);
|
||||
// Find the custom extension in the template.
|
||||
if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) {
|
||||
// The custom extension was not found in the template.
|
||||
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it.
|
||||
boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|");
|
||||
out += std::string(";*") + custom_extension;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
return wxString::FromUTF8(out.c_str());
|
||||
}
|
||||
|
||||
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }
|
||||
|
@ -137,7 +141,7 @@ bool GUI_App::OnInit()
|
|||
std::cerr << "Creating main frame..." << std::endl;
|
||||
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
|
||||
wxImage::AddHandler(new wxPNGHandler());
|
||||
mainframe = new MainFrame(no_plater, false);
|
||||
mainframe = new MainFrame();
|
||||
sidebar().obj_list()->init_objects(); // propagate model objects to object list
|
||||
update_mode();
|
||||
SetTopWindow(mainframe);
|
||||
|
@ -177,6 +181,9 @@ bool GUI_App::OnInit()
|
|||
|
||||
if (app_config->dirty())
|
||||
app_config->save();
|
||||
|
||||
if (this->plater() != nullptr)
|
||||
this->obj_manipul()->update_if_dirty();
|
||||
});
|
||||
|
||||
// On OS X the UI tends to freeze in weird ways if modal dialogs(config wizard, update notifications, ...)
|
||||
|
@ -277,8 +284,8 @@ void GUI_App::recreate_GUI()
|
|||
{
|
||||
std::cerr << "recreate_GUI" << std::endl;
|
||||
|
||||
auto topwindow = GetTopWindow();
|
||||
mainframe = new MainFrame(no_plater,false);
|
||||
MainFrame* topwindow = dynamic_cast<MainFrame*>(GetTopWindow());
|
||||
mainframe = new MainFrame();
|
||||
sidebar().obj_list()->init_objects(); // propagate model objects to object list
|
||||
update_mode();
|
||||
|
||||
|
@ -287,6 +294,20 @@ void GUI_App::recreate_GUI()
|
|||
topwindow->Destroy();
|
||||
}
|
||||
|
||||
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
|
||||
|
||||
CallAfter([this]() {
|
||||
// temporary workaround for the correct behavior of the Scrolled sidebar panel
|
||||
auto& panel = sidebar();
|
||||
if (panel.obj_list()->GetMinHeight() > 200) {
|
||||
wxWindowUpdateLocker noUpdates_sidebar(&panel);
|
||||
panel.obj_list()->SetMinSize(wxSize(-1, 200));
|
||||
panel.Layout();
|
||||
}
|
||||
});
|
||||
|
||||
mainframe->Show(true);
|
||||
|
||||
// On OSX the UI was not initialized correctly if the wizard was called
|
||||
// before the UI was up and running.
|
||||
CallAfter([]() {
|
||||
|
|
|
@ -71,7 +71,6 @@ static wxString dots("…", wxConvUTF8);
|
|||
|
||||
class GUI_App : public wxApp
|
||||
{
|
||||
bool no_plater{ false };
|
||||
bool app_conf_exists{ false };
|
||||
|
||||
// Lock to guard the callback stack
|
||||
|
|
|
@ -47,6 +47,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
|
||||
m_og->m_fill_empty_value = [this](const std::string& opt_key)
|
||||
{
|
||||
this->update_if_dirty();
|
||||
|
||||
std::string param;
|
||||
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
|
||||
|
||||
|
@ -83,6 +85,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
|
||||
m_og->m_set_focus = [this](const std::string& opt_key)
|
||||
{
|
||||
this->update_if_dirty();
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, true);
|
||||
};
|
||||
|
||||
|
@ -179,22 +182,19 @@ bool ObjectManipulation::IsShown()
|
|||
|
||||
void ObjectManipulation::UpdateAndShow(const bool show)
|
||||
{
|
||||
if (show)
|
||||
if (show) {
|
||||
update_settings_value(wxGetApp().plater()->canvas3D()->get_selection());
|
||||
update_if_dirty();
|
||||
}
|
||||
|
||||
OG_Settings::UpdateAndShow(show);
|
||||
}
|
||||
|
||||
int ObjectManipulation::ol_selection()
|
||||
{
|
||||
return wxGetApp().obj_list()->get_selected_obj_idx();
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection)
|
||||
{
|
||||
wxString move_label = _(L("Position:"));
|
||||
wxString rotate_label = _(L("Rotation:"));
|
||||
wxString scale_label = _(L("Scale factors:"));
|
||||
m_new_move_label_string = L("Position:");
|
||||
m_new_rotate_label_string = L("Rotation:");
|
||||
m_new_scale_label_string = L("Scale factors:");
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
if (selection.is_single_full_instance())
|
||||
#else
|
||||
|
@ -205,10 +205,10 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
{
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
update_position_value(volume->get_offset());
|
||||
update_rotation_value(volume->get_rotation());
|
||||
update_scale_value(volume->get_scaling_factor());
|
||||
m_og->enable();
|
||||
m_new_position = volume->get_offset();
|
||||
m_new_rotation = volume->get_rotation();
|
||||
m_new_scale = volume->get_scaling_factor();
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else
|
||||
reset_settings_value();
|
||||
|
@ -219,143 +219,104 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
update_position_value(volume->get_instance_offset());
|
||||
update_rotation_value(volume->get_instance_rotation());
|
||||
update_scale_value(volume->get_instance_scaling_factor());
|
||||
update_size_value(volume->get_instance_transformation().get_matrix(true, true) * volume->bounding_box.size());
|
||||
m_new_position = volume->get_instance_offset();
|
||||
m_new_rotation = volume->get_instance_rotation();
|
||||
m_new_scale = volume->get_instance_scaling_factor();
|
||||
m_new_size = volume->get_instance_transformation().get_matrix(true, true) * volume->bounding_box.size();
|
||||
#else
|
||||
update_position_value(volume->get_offset());
|
||||
update_rotation_value(volume->get_rotation());
|
||||
update_scale_value(volume->get_scaling_factor());
|
||||
m_new_position = volume->get_offset();
|
||||
m_new_rotation = volume->get_rotation();
|
||||
m_new_scale = volume->get_scaling_factor();
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
m_og->enable();
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else if (selection.is_single_full_object())
|
||||
{
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
update_position_value(box.center());
|
||||
reset_rotation_value();
|
||||
reset_scale_value();
|
||||
update_size_value(box.size());
|
||||
rotate_label = _(L("Rotate:"));
|
||||
scale_label = _(L("Scale:"));
|
||||
m_og->enable();
|
||||
m_new_position = box.center();
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_scale = Vec3d(1.0, 1.0, 1.0);
|
||||
m_new_size = box.size();
|
||||
m_new_rotate_label_string = L("Rotate:");
|
||||
m_new_scale_label_string = L("Scale:");
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume())
|
||||
{
|
||||
// the selection contains a single volume
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
update_position_value(volume->get_volume_offset());
|
||||
update_rotation_value(volume->get_volume_rotation());
|
||||
update_scale_value(volume->get_volume_scaling_factor());
|
||||
update_size_value(volume->bounding_box.size());
|
||||
m_new_position = volume->get_volume_offset();
|
||||
m_new_rotation = volume->get_volume_rotation();
|
||||
m_new_scale = volume->get_volume_scaling_factor();
|
||||
m_new_size = volume->bounding_box.size();
|
||||
#else
|
||||
update_position_value(volume->get_offset());
|
||||
update_rotation_value(volume->get_rotation());
|
||||
update_scale_value(volume->get_scaling_factor());
|
||||
m_new_position = volume->get_offset();
|
||||
m_new_rotation = volume->get_rotation();
|
||||
m_new_scale = volume->get_scaling_factor();
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
m_og->enable();
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else if (wxGetApp().obj_list()->multiple_selection())
|
||||
{
|
||||
reset_settings_value();
|
||||
move_label = _(L("Translate:"));
|
||||
rotate_label = _(L("Rotate:"));
|
||||
scale_label = _(L("Scale:"));
|
||||
update_size_value(selection.get_bounding_box().size());
|
||||
m_og->enable();
|
||||
m_new_move_label_string = L("Translate:");
|
||||
m_new_rotate_label_string = L("Rotate:");
|
||||
m_new_scale_label_string = L("Scale:");
|
||||
m_new_size = selection.get_bounding_box().size();
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else
|
||||
reset_settings_value();
|
||||
|
||||
m_move_Label->SetLabel(move_label);
|
||||
m_rotate_Label->SetLabel(rotate_label);
|
||||
m_scale_Label->SetLabel(scale_label);
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_if_dirty()
|
||||
{
|
||||
if (! m_dirty)
|
||||
return;
|
||||
|
||||
m_move_Label->SetLabel(_(m_new_move_label_string));
|
||||
m_rotate_Label->SetLabel(_(m_new_rotate_label_string));
|
||||
m_scale_Label->SetLabel(_(m_new_scale_label_string));
|
||||
|
||||
m_og->set_value("position_x", double_to_string(m_new_position(0), 2));
|
||||
m_og->set_value("position_y", double_to_string(m_new_position(1), 2));
|
||||
m_og->set_value("position_z", double_to_string(m_new_position(2), 2));
|
||||
cache_position = m_new_position;
|
||||
|
||||
auto scale = m_new_scale * 100.0;
|
||||
m_og->set_value("scale_x", double_to_string(scale(0), 2));
|
||||
m_og->set_value("scale_y", double_to_string(scale(1), 2));
|
||||
m_og->set_value("scale_z", double_to_string(scale(2), 2));
|
||||
cache_scale = scale;
|
||||
|
||||
m_og->set_value("size_x", double_to_string(m_new_size(0), 2));
|
||||
m_og->set_value("size_y", double_to_string(m_new_size(1), 2));
|
||||
m_og->set_value("size_z", double_to_string(m_new_size(2), 2));
|
||||
cache_size = m_new_size;
|
||||
|
||||
m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(0)), 0), 2));
|
||||
m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(1)), 0), 2));
|
||||
m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(2)), 0), 2));
|
||||
cache_rotation = m_new_rotation;
|
||||
|
||||
if (m_new_enabled)
|
||||
m_og->enable();
|
||||
else
|
||||
m_og->disable();
|
||||
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
void ObjectManipulation::reset_settings_value()
|
||||
{
|
||||
reset_position_value();
|
||||
reset_rotation_value();
|
||||
reset_scale_value();
|
||||
m_og->disable();
|
||||
}
|
||||
|
||||
wxString def_0 {"0"};
|
||||
wxString def_100 {"100"};
|
||||
|
||||
void ObjectManipulation::reset_position_value()
|
||||
{
|
||||
m_og->set_value("position_x", def_0);
|
||||
m_og->set_value("position_y", def_0);
|
||||
m_og->set_value("position_z", def_0);
|
||||
|
||||
cache_position = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void ObjectManipulation::reset_rotation_value()
|
||||
{
|
||||
m_og->set_value("rotation_x", def_0);
|
||||
m_og->set_value("rotation_y", def_0);
|
||||
m_og->set_value("rotation_z", def_0);
|
||||
|
||||
cache_rotation = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void ObjectManipulation::reset_scale_value()
|
||||
{
|
||||
m_og->set_value("scale_x", def_100);
|
||||
m_og->set_value("scale_y", def_100);
|
||||
m_og->set_value("scale_z", def_100);
|
||||
|
||||
cache_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
}
|
||||
|
||||
void ObjectManipulation::reset_size_value()
|
||||
{
|
||||
m_og->set_value("size_x", def_0);
|
||||
m_og->set_value("size_y", def_0);
|
||||
m_og->set_value("size_z", def_0);
|
||||
|
||||
cache_size = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_position_value(const Vec3d& position)
|
||||
{
|
||||
m_og->set_value("position_x", double_to_string(position(0), 2));
|
||||
m_og->set_value("position_y", double_to_string(position(1), 2));
|
||||
m_og->set_value("position_z", double_to_string(position(2), 2));
|
||||
|
||||
cache_position = position;
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor)
|
||||
{
|
||||
auto scale = scaling_factor * 100.0;
|
||||
m_og->set_value("scale_x", double_to_string(scale(0), 2));
|
||||
m_og->set_value("scale_y", double_to_string(scale(1), 2));
|
||||
m_og->set_value("scale_z", double_to_string(scale(2), 2));
|
||||
|
||||
cache_scale = scale;
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_size_value(const Vec3d& size)
|
||||
{
|
||||
m_og->set_value("size_x", double_to_string(size(0), 2));
|
||||
m_og->set_value("size_y", double_to_string(size(1), 2));
|
||||
m_og->set_value("size_z", double_to_string(size(2), 2));
|
||||
|
||||
cache_size = size;
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_rotation_value(const Vec3d& rotation)
|
||||
{
|
||||
m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(rotation(0)), 0), 2));
|
||||
m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(rotation(1)), 0), 2));
|
||||
m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(rotation(2)), 0), 2));
|
||||
|
||||
cache_rotation = rotation;
|
||||
m_new_position = Vec3d::Zero();
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_scale = Vec3d(1.0, 1.0, 1.0);
|
||||
m_new_size = Vec3d::Zero();
|
||||
m_new_enabled = false;
|
||||
}
|
||||
|
||||
void ObjectManipulation::change_position_value(const Vec3d& position)
|
||||
|
|
|
@ -23,6 +23,19 @@ class ObjectManipulation : public OG_Settings
|
|||
wxStaticText* m_scale_Label = nullptr;
|
||||
wxStaticText* m_rotate_Label = nullptr;
|
||||
|
||||
|
||||
// Needs to be updated from OnIdle?
|
||||
bool m_dirty = false;
|
||||
// Cached labels for the delayed update, not localized!
|
||||
std::string m_new_move_label_string;
|
||||
std::string m_new_rotate_label_string;
|
||||
std::string m_new_scale_label_string;
|
||||
Vec3d m_new_position;
|
||||
Vec3d m_new_rotation;
|
||||
Vec3d m_new_scale;
|
||||
Vec3d m_new_size;
|
||||
bool m_new_enabled;
|
||||
|
||||
public:
|
||||
ObjectManipulation(wxWindow* parent);
|
||||
~ObjectManipulation() {}
|
||||
|
@ -31,19 +44,14 @@ public:
|
|||
bool IsShown() override;
|
||||
void UpdateAndShow(const bool show) override;
|
||||
|
||||
int ol_selection();
|
||||
void update_settings_value(const GLCanvas3D::Selection& selection);
|
||||
|
||||
void update_settings_value(const GLCanvas3D::Selection& selection);
|
||||
// Called from the App to update the UI if dirty.
|
||||
void update_if_dirty();
|
||||
|
||||
private:
|
||||
void reset_settings_value();
|
||||
void reset_position_value();
|
||||
void reset_rotation_value();
|
||||
void reset_scale_value();
|
||||
void reset_size_value();
|
||||
|
||||
// update position values displacements or "gizmos"
|
||||
void update_position_value(const Vec3d& position);
|
||||
// update scale values after scale unit changing or "gizmos"
|
||||
void update_scale_value(const Vec3d& scaling_factor);
|
||||
// update size values after scale unit changing or "gizmos"
|
||||
void update_size_value(const Vec3d& size);
|
||||
// update rotation value after "gizmos"
|
||||
|
|
|
@ -70,7 +70,6 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba
|
|||
m_canvas->set_config(config);
|
||||
m_canvas->enable_gizmos(true);
|
||||
m_canvas->enable_toolbar(true);
|
||||
m_canvas->enable_shader(true);
|
||||
m_canvas->enable_force_zoom_to_bed(true);
|
||||
|
||||
#if !ENABLE_IMGUI
|
||||
|
@ -214,7 +213,6 @@ Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundSli
|
|||
, m_preferred_color_mode("feature")
|
||||
, m_loaded(false)
|
||||
, m_enabled(false)
|
||||
, m_force_sliders_full_range(false)
|
||||
, m_schedule_background_process(schedule_background_process_func)
|
||||
{
|
||||
#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
|
@ -258,7 +256,6 @@ bool Preview::init(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundS
|
|||
_3DScene::add_canvas(m_canvas_widget);
|
||||
m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
|
||||
m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
|
||||
m_canvas->enable_shader(true);
|
||||
m_canvas->set_config(m_config);
|
||||
m_canvas->set_process(process);
|
||||
m_canvas->enable_legend_texture(true);
|
||||
|
@ -514,14 +511,14 @@ void Preview::show_hide_ui_elements(const std::string& what)
|
|||
void Preview::reset_sliders()
|
||||
{
|
||||
m_enabled = false;
|
||||
reset_double_slider();
|
||||
// reset_double_slider();
|
||||
m_double_slider_sizer->Hide((size_t)0);
|
||||
}
|
||||
|
||||
void Preview::update_sliders(const std::vector<double>& layers_z)
|
||||
{
|
||||
m_enabled = true;
|
||||
update_double_slider(layers_z, m_force_sliders_full_range);
|
||||
update_double_slider(layers_z);
|
||||
m_double_slider_sizer->Show((size_t)0);
|
||||
Layout();
|
||||
}
|
||||
|
@ -587,7 +584,8 @@ void Preview::create_double_slider()
|
|||
auto& config = wxGetApp().preset_bundle->project_config;
|
||||
((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues());
|
||||
m_schedule_background_process();
|
||||
int type = m_choice_view_type->FindString(_(L("Color Print")));
|
||||
bool color_print = !config.option<ConfigOptionFloats>("colorprint_heights")->values.empty();
|
||||
int type = m_choice_view_type->FindString(color_print ? _(L("Color Print")) : _(L("Feature type")) );
|
||||
if (m_choice_view_type->GetSelection() != type) {
|
||||
m_choice_view_type->SetSelection(type);
|
||||
if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types))
|
||||
|
@ -597,26 +595,70 @@ void Preview::create_double_slider()
|
|||
});
|
||||
}
|
||||
|
||||
// Find an index of a value in a sorted vector, which is in <z-eps, z+eps>.
|
||||
// Returns -1 if there is no such member.
|
||||
static int find_close_layer_idx(const std::vector<double>& zs, double &z, double eps)
|
||||
{
|
||||
if (zs.empty())
|
||||
return -1;
|
||||
auto it_h = std::lower_bound(zs.begin(), zs.end(), z);
|
||||
if (it_h == zs.end()) {
|
||||
auto it_l = it_h;
|
||||
-- it_l;
|
||||
if (z - *it_l < eps)
|
||||
return int(zs.size() - 1);
|
||||
} else if (it_h == zs.begin()) {
|
||||
if (*it_h - z < eps)
|
||||
return 0;
|
||||
} else {
|
||||
auto it_l = it_h;
|
||||
-- it_l;
|
||||
double dist_l = z - *it_l;
|
||||
double dist_h = *it_h - z;
|
||||
if (std::min(dist_l, dist_h) < eps) {
|
||||
return (dist_l < dist_h) ? int(it_l - zs.begin()) : int(it_h - zs.begin());
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Preview::update_double_slider(const std::vector<double>& layers_z, bool force_sliders_full_range)
|
||||
{
|
||||
// Save the initial slider span.
|
||||
double z_low = m_slider->GetLowerValueD();
|
||||
double z_high = m_slider->GetHigherValueD();
|
||||
bool was_empty = m_slider->GetMaxValue() == 0;
|
||||
bool span_changed = layers_z.empty() || std::abs(layers_z.back() - m_slider->GetMaxValueD()) > 1e-6;
|
||||
force_sliders_full_range |= was_empty | span_changed;
|
||||
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
|
||||
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
|
||||
|
||||
std::vector<std::pair<int, double>> values;
|
||||
fill_slider_values(values, layers_z);
|
||||
|
||||
m_slider->SetMaxValue(layers_z.size() - 1);
|
||||
if (force_sliders_full_range)
|
||||
m_slider->SetHigherValue(layers_z.size() - 1);
|
||||
|
||||
m_slider->SetSliderValues(values);
|
||||
const double z_low = m_slider->GetLowerValueD();
|
||||
const double z_high = m_slider->GetHigherValueD();
|
||||
assert(m_slider->GetMinValue() == 0);
|
||||
m_slider->SetMaxValue(layers_z.empty() ? 0 : layers_z.size() - 1);
|
||||
|
||||
int idx_low = 0;
|
||||
int idx_high = m_slider->GetMaxValue();
|
||||
if (! layers_z.empty()) {
|
||||
if (! snap_to_min) {
|
||||
int idx_new = find_close_layer_idx(layers_z, z_low, 1e-6);
|
||||
if (idx_new != -1)
|
||||
idx_low = idx_new;
|
||||
}
|
||||
if (! snap_to_max) {
|
||||
int idx_new = find_close_layer_idx(layers_z, z_high, 1e-6);
|
||||
if (idx_new != -1)
|
||||
idx_high = idx_new;
|
||||
}
|
||||
}
|
||||
m_slider->SetSelectionSpan(idx_low, idx_high);
|
||||
|
||||
const auto& config = wxGetApp().preset_bundle->project_config;
|
||||
const std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
|
||||
m_slider->SetTicksValues(ticks_from_config);
|
||||
|
||||
set_double_slider_thumbs(layers_z, z_low, z_high);
|
||||
|
||||
bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF);
|
||||
if (color_print_enable) {
|
||||
const auto& config = wxGetApp().preset_bundle->full_config();
|
||||
|
@ -638,8 +680,7 @@ void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
|
|||
// All ticks that would end up outside the slider range should be erased.
|
||||
// TODO: this should be placed into more appropriate part of code,
|
||||
// this function is e.g. not called when the last object is deleted
|
||||
auto& config = wxGetApp().preset_bundle->project_config;
|
||||
std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
std::vector<double> &ticks_from_config = (wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
unsigned int old_size = ticks_from_config.size();
|
||||
ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(),
|
||||
[values](double val) { return values.back().second < val; }),
|
||||
|
@ -648,32 +689,6 @@ void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
|
|||
m_schedule_background_process();
|
||||
}
|
||||
|
||||
void Preview::set_double_slider_thumbs(const std::vector<double> &layers_z,
|
||||
const double z_low,
|
||||
const double z_high)
|
||||
{
|
||||
// Force slider full range only when slider is created.
|
||||
// Support selected diapason on the all next steps
|
||||
if (z_high == 0.0) {
|
||||
m_slider->SetLowerValue(0);
|
||||
m_slider->SetHigherValue(layers_z.size() - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = layers_z.size() - 1; i >= 0; i--)
|
||||
// if (z_low >= layers_z[i]) {
|
||||
if (fabs(z_low - layers_z[i]) <= 1e-6) {
|
||||
m_slider->SetLowerValue(i);
|
||||
break;
|
||||
}
|
||||
for (int i = layers_z.size() - 1; i >= 0; i--)
|
||||
// if (z_high >= layers_z[i]) {
|
||||
if (fabs(z_high-layers_z[i]) <= 1e-6) {
|
||||
m_slider->SetHigherValue(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Preview::reset_double_slider()
|
||||
{
|
||||
m_slider->SetHigherValue(0);
|
||||
|
@ -692,7 +707,7 @@ void Preview::update_double_slider_from_canvas(wxKeyEvent& event)
|
|||
if (key == 'U' || key == 'D') {
|
||||
const int new_pos = key == 'U' ? m_slider->GetHigherValue() + 1 : m_slider->GetHigherValue() - 1;
|
||||
m_slider->SetHigherValue(new_pos);
|
||||
if (event.ShiftDown()) m_slider->SetLowerValue(m_slider->GetHigherValue());
|
||||
if (event.ShiftDown() || m_slider->is_one_layer()) m_slider->SetLowerValue(m_slider->GetHigherValue());
|
||||
}
|
||||
else if (key == 'S')
|
||||
m_slider->ChangeOneLayerLock();
|
||||
|
@ -778,12 +793,8 @@ void Preview::load_print_as_fff()
|
|||
|
||||
if (IsShown())
|
||||
{
|
||||
// used to set the sliders to the extremes of the current zs range
|
||||
m_force_sliders_full_range = false;
|
||||
|
||||
if (gcode_preview_data_valid)
|
||||
{
|
||||
m_force_sliders_full_range = (m_canvas->get_volumes_count() == 0);
|
||||
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
|
||||
show_hide_ui_elements("full");
|
||||
|
||||
|
@ -849,7 +860,6 @@ void Preview::load_print_as_sla()
|
|||
{
|
||||
std::vector<double> layer_zs;
|
||||
std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs));
|
||||
m_force_sliders_full_range = true;
|
||||
update_sliders(layer_zs);
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,6 @@ class Preview : public wxPanel
|
|||
|
||||
bool m_loaded;
|
||||
bool m_enabled;
|
||||
bool m_force_sliders_full_range;
|
||||
|
||||
PrusaDoubleSlider* m_slider {nullptr};
|
||||
|
||||
|
@ -177,12 +176,9 @@ private:
|
|||
|
||||
// Create/Update/Reset double slider on 3dPreview
|
||||
void create_double_slider();
|
||||
void update_double_slider(const std::vector<double>& layers_z, bool force_sliders_full_range);
|
||||
void update_double_slider(const std::vector<double>& layers_z, bool force_sliders_full_range = false);
|
||||
void fill_slider_values(std::vector<std::pair<int, double>> &values,
|
||||
const std::vector<double> &layers_z);
|
||||
void set_double_slider_thumbs( const std::vector<double> &layers_z,
|
||||
const double z_low,
|
||||
const double z_high);
|
||||
void reset_double_slider();
|
||||
// update DoubleSlider after keyDown in canvas
|
||||
void update_double_slider_from_canvas(wxKeyEvent& event);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "libslic3r/Utils.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include <wx/scrolwin.h>
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -19,41 +20,46 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
|
||||
// fonts
|
||||
wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold();
|
||||
head_font.SetPointSize(19);
|
||||
|
||||
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
font.SetPointSize(10);
|
||||
wxFont bold_font = font.Bold();
|
||||
#ifdef __WXOSX__
|
||||
font.SetPointSize(12);
|
||||
bold_font.SetPointSize(14);
|
||||
#endif /*__WXOSX__*/
|
||||
head_font.SetPointSize(14);
|
||||
#else
|
||||
head_font.SetPointSize(12);
|
||||
#endif // __WXOSX__
|
||||
|
||||
const wxFont& font = wxGetApp().small_font();
|
||||
const wxFont& bold_font = wxGetApp().bold_font();
|
||||
|
||||
fill_shortcuts();
|
||||
|
||||
auto panel = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(500, 600));
|
||||
panel->SetScrollbars(0, 20, 1, 2);
|
||||
auto sizer = new wxBoxSizer(wxVERTICAL);
|
||||
panel->SetSizer(sizer);
|
||||
auto panel = new wxPanel(this);
|
||||
auto main_grid_sizer = new wxFlexGridSizer(2, 10, 10);
|
||||
panel->SetSizer(main_grid_sizer);
|
||||
main_sizer->Add(panel, 1, wxEXPAND | wxALL, 0);
|
||||
|
||||
wxBoxSizer* l_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_grid_sizer->Add(l_sizer, 0);
|
||||
|
||||
wxBoxSizer* r_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_grid_sizer->Add(r_sizer, 0);
|
||||
|
||||
for (auto& sc : m_full_shortcuts)
|
||||
{
|
||||
auto sizer = sc.first == _(L("Main Shortcuts")) ? l_sizer : r_sizer;
|
||||
wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(hsizer, 0, wxEXPAND | wxTOP, 25);
|
||||
sizer->Add(hsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
|
||||
|
||||
// logo
|
||||
auto *logo = new wxStaticBitmap(panel, wxID_ANY, logo_bmp);
|
||||
hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 15);
|
||||
|
||||
// head
|
||||
wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(400,-1));
|
||||
wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(200,-1));
|
||||
head->SetFont(head_font);
|
||||
hsizer->Add(head, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
// Shortcuts list
|
||||
auto grid_sizer = new wxFlexGridSizer(2, 10, 25);
|
||||
sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT | wxTOP, 10);
|
||||
auto grid_sizer = new wxFlexGridSizer(2, 5, 15);
|
||||
sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT| wxRIGHT, 15);
|
||||
|
||||
for (auto pair : sc.second)
|
||||
{
|
||||
|
@ -69,9 +75,9 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
|
||||
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK);
|
||||
|
||||
this->SetEscapeId(wxID_CLOSE);
|
||||
this->SetEscapeId(wxID_OK);
|
||||
this->Bind(wxEVT_BUTTON, &KBShortcutsDialog::onCloseDialog, this, wxID_OK);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 15);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 15);
|
||||
|
||||
this->Bind(wxEVT_LEFT_DOWN, &KBShortcutsDialog::onCloseDialog, this);
|
||||
|
||||
|
@ -81,32 +87,40 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
|
||||
void KBShortcutsDialog::fill_shortcuts()
|
||||
{
|
||||
#ifdef __WXOSX__
|
||||
const std::string ctrl = "Cmd+"; // #ys_FIXME_cmd_smb // Change it for the accorded symbol
|
||||
const std::string alt = "Alt+"; // #ys_FIXME_cmd_smb // Change it for the accorded symbol
|
||||
#else
|
||||
const std::string ctrl = "Ctrl+";
|
||||
const std::string alt = "Alt+";
|
||||
#endif // __WXOSX__
|
||||
|
||||
Shortcuts main_shortcuts;
|
||||
main_shortcuts.reserve(25);
|
||||
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+O", L("Open project STL/OBJ/AMF/3MF with config, delete bed")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+I", L("Import STL//OBJ/AMF/3MF without config, keep bed")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+L", L("Load Config from .ini/amf/3mf/gcode")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+Alt+L", L("Load Config from .ini/amf/3mf/gcode and merge")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+G", L("Export Gcode")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+S", L("Save project (3MF)")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+R", L("(Re)slice")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+U", L("Quick slice")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+Alt+U", L("Quick slice and Save as")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+Shift+U", L("Repeat last quick slice")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+1", L("Select Plater Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+2", L("Select Print Settings Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+3", L("Select Filament Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+4", L("Select Printer Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+5", L("Switch to 3D")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+6", L("Switch to Preview")));
|
||||
main_shortcuts.push_back(Shortcut("Ctrl+P", L("Preferences")));
|
||||
main_shortcuts.push_back(Shortcut("0-6", L("Camera view ")));
|
||||
main_shortcuts.push_back(Shortcut("+", L("Add Instance to selected object ")));
|
||||
main_shortcuts.push_back(Shortcut("-", L("Remove Instance from selected object")));
|
||||
main_shortcuts.push_back(Shortcut("?", L("Show keyboard shortcuts list")));
|
||||
main_shortcuts.push_back(Shortcut("PgUp/PgDn", L("Switch between 3D and Preview")));
|
||||
main_shortcuts.push_back(Shortcut("Shift+LeftMouse",L("Select multiple object/Move multiple object")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"O" ,L("Open project STL/OBJ/AMF/3MF with config, delete bed")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"I" ,L("Import STL//OBJ/AMF/3MF without config, keep bed")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"L" ,L("Load Config from .ini/amf/3mf/gcode")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"G" ,L("Export Gcode")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"S" ,L("Save project (3MF)")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+alt+"L" ,L("Load Config from .ini/amf/3mf/gcode and merge")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"R" ,L("(Re)slice")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"U" ,L("Quick slice")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"Shift+U" ,L("Repeat last quick slice")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"1" ,L("Select Plater Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+alt+"U" ,L("Quick slice and Save as")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"2" ,L("Select Print Settings Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"3" ,L("Select Filament Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"4" ,L("Select Printer Setting Tab")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"5" ,L("Switch to 3D")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"6" ,L("Switch to Preview")));
|
||||
main_shortcuts.push_back(Shortcut(ctrl+"P" ,L("Preferences")));
|
||||
main_shortcuts.push_back(Shortcut("0-6" ,L("Camera view ")));
|
||||
main_shortcuts.push_back(Shortcut("+" ,L("Add Instance to selected object ")));
|
||||
main_shortcuts.push_back(Shortcut("-" ,L("Remove Instance from selected object")));
|
||||
main_shortcuts.push_back(Shortcut("?" ,L("Show keyboard shortcuts list")));
|
||||
main_shortcuts.push_back(Shortcut("PgUp/PgDn" ,L("Switch between 3D and Preview")));
|
||||
main_shortcuts.push_back(Shortcut("Shift+LeftMouse" ,L("Select multiple object/Move multiple object")));
|
||||
|
||||
m_full_shortcuts.emplace(_(L("Main Shortcuts")), main_shortcuts);
|
||||
|
||||
|
@ -115,9 +129,9 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||
plater_shortcuts.reserve(20);
|
||||
|
||||
plater_shortcuts.push_back(Shortcut("A", L("Arrange")));
|
||||
plater_shortcuts.push_back(Shortcut("Ctrl+A", L("Select All objects")));
|
||||
plater_shortcuts.push_back(Shortcut(ctrl+"A", L("Select All objects")));
|
||||
plater_shortcuts.push_back(Shortcut("Del", L("Delete selected")));
|
||||
plater_shortcuts.push_back(Shortcut("Ctrl+Del", L("Delete all")));
|
||||
plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete all")));
|
||||
plater_shortcuts.push_back(Shortcut("M", L("Gizmo move")));
|
||||
plater_shortcuts.push_back(Shortcut("S", L("Gizmo scale")));
|
||||
plater_shortcuts.push_back(Shortcut("R", L("Gizmo rotate")));
|
||||
|
|
|
@ -28,10 +28,8 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
MainFrame::MainFrame(const bool no_plater, const bool loaded) :
|
||||
MainFrame::MainFrame() :
|
||||
wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE),
|
||||
m_no_plater(no_plater),
|
||||
m_loaded(loaded),
|
||||
m_printhost_queue_dlg(new PrintHostQueueDialog(this))
|
||||
{
|
||||
// Load the icon either from the exe, or from the ico file.
|
||||
|
@ -125,11 +123,9 @@ void MainFrame::init_tabpanel()
|
|||
}
|
||||
});
|
||||
|
||||
if (!m_no_plater) {
|
||||
m_plater = new Slic3r::GUI::Plater(m_tabpanel, this);
|
||||
wxGetApp().plater_ = m_plater;
|
||||
m_tabpanel->AddPage(m_plater, _(L("Plater")));
|
||||
}
|
||||
m_plater = new Slic3r::GUI::Plater(m_tabpanel, this);
|
||||
wxGetApp().plater_ = m_plater;
|
||||
m_tabpanel->AddPage(m_plater, _(L("Plater")));
|
||||
|
||||
// The following event is emited by Tab implementation on config value change.
|
||||
Bind(EVT_TAB_VALUE_CHANGED, &MainFrame::on_value_changed, this);
|
||||
|
@ -380,7 +376,7 @@ void MainFrame::init_menubar()
|
|||
|
||||
windowMenu->AppendSeparator();
|
||||
append_menu_item(windowMenu, wxID_ANY, L("Print Host Upload Queue"), L("Display the Print Host Upload Queue window"),
|
||||
[this](wxCommandEvent&) { m_printhost_queue_dlg->ShowModal(); }, "arrow_up.png");
|
||||
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "arrow_up.png");
|
||||
}
|
||||
|
||||
// View menu
|
||||
|
|
|
@ -42,10 +42,7 @@ struct PresetTab {
|
|||
|
||||
class MainFrame : public wxFrame
|
||||
{
|
||||
bool m_no_plater;
|
||||
bool m_loaded;
|
||||
int m_lang_ch_event;
|
||||
int m_preferences_event;
|
||||
bool m_loaded {false};
|
||||
|
||||
wxString m_qs_last_input_file = wxEmptyString;
|
||||
wxString m_qs_last_output_file = wxEmptyString;
|
||||
|
@ -71,8 +68,7 @@ class MainFrame : public wxFrame
|
|||
bool can_delete_all() const;
|
||||
|
||||
public:
|
||||
MainFrame() {}
|
||||
MainFrame(const bool no_plater, const bool loaded);
|
||||
MainFrame();
|
||||
~MainFrame() {}
|
||||
|
||||
Plater* plater() { return m_plater; }
|
||||
|
|
|
@ -1117,6 +1117,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
view3D = new View3D(q, &model, config, &background_process);
|
||||
preview = new Preview(q, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); });
|
||||
// Let the Tab key switch between the 3D view and the layer preview.
|
||||
view3D->Bind(wxEVT_NAVIGATION_KEY, [this](wxNavigationKeyEvent &evt) { if (evt.IsFromTab()) this->q->select_view_3D("Preview"); });
|
||||
preview->Bind(wxEVT_NAVIGATION_KEY, [this](wxNavigationKeyEvent &evt) { if (evt.IsFromTab()) this->q->select_view_3D("3D"); });
|
||||
|
||||
panels.push_back(view3D);
|
||||
panels.push_back(preview);
|
||||
|
@ -1132,7 +1135,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
this->canvas3D->set_config(config);
|
||||
this->canvas3D->enable_gizmos(true);
|
||||
this->canvas3D->enable_toolbar(true);
|
||||
this->canvas3D->enable_shader(true);
|
||||
this->canvas3D->enable_force_zoom_to_bed(true);
|
||||
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
|
||||
|
@ -1162,9 +1164,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
hsizer->Add(sidebar, 0, wxEXPAND | wxLEFT | wxRIGHT, 0);
|
||||
q->SetSizer(hsizer);
|
||||
|
||||
#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
set_current_panel(view3D);
|
||||
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
//#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
// set_current_panel(view3D);
|
||||
//#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
|
||||
init_object_menu();
|
||||
|
||||
|
@ -1251,6 +1253,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
|
||||
update_ui_from_settings();
|
||||
q->Layout();
|
||||
|
||||
#if ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
set_current_panel(view3D);
|
||||
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
|
||||
}
|
||||
|
||||
void Plater::priv::update(bool force_full_scene_refresh)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <wx/debug.h>
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
|
@ -59,7 +60,8 @@ bool PrintHostSendDialog::start_print() const
|
|||
|
||||
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
||||
wxDEFINE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event);
|
||||
|
||||
PrintHostQueueDialog::Event::Event(wxEventType eventType, int winid, size_t job_id)
|
||||
: wxEvent(winid, eventType)
|
||||
|
@ -87,6 +89,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
|
|||
: wxDialog(parent, wxID_ANY, _(L("Print host upload queue")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
, on_progress_evt(this, EVT_PRINTHOST_PROGRESS, &PrintHostQueueDialog::on_progress, this)
|
||||
, on_error_evt(this, EVT_PRINTHOST_ERROR, &PrintHostQueueDialog::on_error, this)
|
||||
, on_cancel_evt(this, EVT_PRINTHOST_CANCEL, &PrintHostQueueDialog::on_cancel, this)
|
||||
{
|
||||
enum { HEIGHT = 800, WIDTH = 400, SPACING = 5 };
|
||||
|
||||
|
@ -95,22 +98,47 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
|
|||
auto *topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
job_list = new wxDataViewListCtrl(this, wxID_ANY);
|
||||
// Note: Keep these in sync with Column
|
||||
job_list->AppendTextColumn("ID", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendProgressColumn("Progress", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("Status", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("Host", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("Filename", wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn("error_message", wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN);
|
||||
|
||||
auto *btnsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto *btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected")));
|
||||
btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected")));
|
||||
btn_cancel->Disable();
|
||||
btn_error = new wxButton(this, wxID_ANY, _(L("Show error message")));
|
||||
btn_error->Disable();
|
||||
auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close")));
|
||||
btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING);
|
||||
btnsizer->Add(btn_error, 0);
|
||||
btnsizer->AddStretchSpacer();
|
||||
btnsizer->Add(btn_close);
|
||||
|
||||
topsizer->Add(job_list, 1, wxEXPAND | wxBOTTOM, SPACING);
|
||||
topsizer->Add(btnsizer, 0, wxEXPAND);
|
||||
SetSizer(topsizer);
|
||||
|
||||
job_list->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent&) { on_list_select(); });
|
||||
|
||||
btn_cancel->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
int selected = job_list->GetSelectedRow();
|
||||
if (selected == wxNOT_FOUND) { return; }
|
||||
|
||||
const JobState state = get_state(selected);
|
||||
if (state < ST_ERROR) {
|
||||
// TODO: cancel
|
||||
GUI::wxGetApp().printhost_job_queue().cancel(selected);
|
||||
}
|
||||
});
|
||||
|
||||
btn_error->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
int selected = job_list->GetSelectedRow();
|
||||
if (selected == wxNOT_FOUND) { return; }
|
||||
GUI::show_error(nullptr, job_list->GetTextValue(selected, COL_ERRORMSG));
|
||||
});
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::append_job(const PrintHostJob &job)
|
||||
|
@ -123,24 +151,82 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job)
|
|||
fields.push_back(wxVariant(_(L("Enqueued"))));
|
||||
fields.push_back(wxVariant(job.printhost->get_host()));
|
||||
fields.push_back(wxVariant(job.upload_data.upload_path.string()));
|
||||
job_list->AppendItem(fields);
|
||||
fields.push_back(wxVariant(""));
|
||||
job_list->AppendItem(fields, static_cast<wxUIntPtr>(ST_NEW));
|
||||
}
|
||||
|
||||
PrintHostQueueDialog::JobState PrintHostQueueDialog::get_state(int idx)
|
||||
{
|
||||
wxCHECK_MSG(idx >= 0 && idx < job_list->GetItemCount(), ST_ERROR, "Out of bounds access to job list");
|
||||
return static_cast<JobState>(job_list->GetItemData(job_list->RowToItem(idx)));
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::set_state(int idx, JobState state)
|
||||
{
|
||||
wxCHECK_RET(idx >= 0 && idx < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
job_list->SetItemData(job_list->RowToItem(idx), static_cast<wxUIntPtr>(state));
|
||||
|
||||
switch (state) {
|
||||
case ST_NEW: job_list->SetValue(_(L("Enqueued")), idx, COL_STATUS); break;
|
||||
case ST_PROGRESS: job_list->SetValue(_(L("Uploading")), idx, COL_STATUS); break;
|
||||
case ST_ERROR: job_list->SetValue(_(L("Error")), idx, COL_STATUS); break;
|
||||
case ST_CANCELLING: job_list->SetValue(_(L("Cancelling")), idx, COL_STATUS); break;
|
||||
case ST_CANCELLED: job_list->SetValue(_(L("Cancelled")), idx, COL_STATUS); break;
|
||||
case ST_COMPLETED: job_list->SetValue(_(L("Completed")), idx, COL_STATUS); break;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_list_select()
|
||||
{
|
||||
int selected = job_list->GetSelectedRow();
|
||||
if (selected != wxNOT_FOUND) {
|
||||
const JobState state = get_state(selected);
|
||||
btn_cancel->Enable(state < ST_ERROR);
|
||||
btn_error->Enable(state == ST_ERROR);
|
||||
Layout();
|
||||
} else {
|
||||
btn_cancel->Disable();
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_progress(Event &evt)
|
||||
{
|
||||
wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
|
||||
const wxVariant status(evt.progress < 100 ? _(L("Uploading")) : _(L("Complete")));
|
||||
if (evt.progress < 100) {
|
||||
set_state(evt.job_id, ST_PROGRESS);
|
||||
job_list->SetValue(wxVariant(evt.progress), evt.job_id, COL_PROGRESS);
|
||||
} else {
|
||||
set_state(evt.job_id, ST_COMPLETED);
|
||||
job_list->SetValue(wxVariant(100), evt.job_id, COL_PROGRESS);
|
||||
}
|
||||
|
||||
job_list->SetValue(wxVariant(evt.progress), evt.job_id, 1);
|
||||
job_list->SetValue(status, evt.job_id, 2);
|
||||
on_list_select();
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_error(Event &evt)
|
||||
{
|
||||
wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
|
||||
// TODO
|
||||
set_state(evt.job_id, ST_ERROR);
|
||||
|
||||
auto errormsg = wxString::Format("%s\n%s", _(L("Error uploading to print host:")), evt.error);
|
||||
job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS);
|
||||
job_list->SetValue(wxVariant(errormsg), evt.job_id, COL_ERRORMSG); // Stashes the error message into a hidden column for later
|
||||
|
||||
on_list_select();
|
||||
|
||||
GUI::show_error(nullptr, std::move(errormsg));
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_cancel(Event &evt)
|
||||
{
|
||||
wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list");
|
||||
|
||||
set_state(evt.job_id, ST_CANCELLED);
|
||||
job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS);
|
||||
|
||||
on_list_select();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@
|
|||
#include "MsgDialog.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
|
||||
class wxButton;
|
||||
class wxTextCtrl;
|
||||
class wxCheckBox;
|
||||
class wxDataViewListCtrl;
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct PrintHostJob;
|
||||
|
@ -60,17 +62,43 @@ public:
|
|||
|
||||
void append_job(const PrintHostJob &job);
|
||||
private:
|
||||
enum Column {
|
||||
COL_ID,
|
||||
COL_PROGRESS,
|
||||
COL_STATUS,
|
||||
COL_HOST,
|
||||
COL_FILENAME,
|
||||
COL_ERRORMSG,
|
||||
};
|
||||
|
||||
enum JobState {
|
||||
ST_NEW,
|
||||
ST_PROGRESS,
|
||||
ST_ERROR,
|
||||
ST_CANCELLING,
|
||||
ST_CANCELLED,
|
||||
ST_COMPLETED,
|
||||
};
|
||||
|
||||
wxButton *btn_cancel;
|
||||
wxButton *btn_error;
|
||||
wxDataViewListCtrl *job_list;
|
||||
// Note: EventGuard prevents delivery of progress evts to a freed PrintHostQueueDialog
|
||||
EventGuard on_progress_evt;
|
||||
EventGuard on_error_evt;
|
||||
EventGuard on_cancel_evt;
|
||||
|
||||
JobState get_state(int idx);
|
||||
void set_state(int idx, JobState);
|
||||
void on_list_select();
|
||||
void on_progress(Event&);
|
||||
void on_error(Event&);
|
||||
void on_cancel(Event&);
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event);
|
||||
wxDECLARE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event);
|
||||
wxDECLARE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event);
|
||||
|
||||
|
||||
}}
|
||||
|
|
|
@ -116,7 +116,7 @@ SysInfoDialog::SysInfoDialog()
|
|||
buttons->Insert(0, btn_copy_to_clipboard, 0, wxLEFT, 5);
|
||||
btn_copy_to_clipboard->Bind(wxEVT_BUTTON, &SysInfoDialog::onCopyToClipboard, this);
|
||||
|
||||
this->SetEscapeId(wxID_CLOSE);
|
||||
this->SetEscapeId(wxID_OK);
|
||||
this->Bind(wxEVT_BUTTON, &SysInfoDialog::onCloseDialog, this, wxID_OK);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3);
|
||||
|
||||
|
|
|
@ -1601,8 +1601,9 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
|
|||
optgroup->append_line(host_line);
|
||||
optgroup->append_single_option_line("printhost_apikey");
|
||||
|
||||
if (Http::ca_file_supported()) {
|
||||
const auto ca_file_hint = _(L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate."));
|
||||
|
||||
if (Http::ca_file_supported()) {
|
||||
Line cafile_line = optgroup->create_single_option_line("printhost_cafile");
|
||||
|
||||
auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) {
|
||||
|
@ -1625,19 +1626,31 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
|
|||
cafile_line.append_widget(printhost_cafile_browse);
|
||||
optgroup->append_line(cafile_line);
|
||||
|
||||
auto printhost_cafile_hint = [this, optgroup] (wxWindow* parent) {
|
||||
auto txt = new wxStaticText(parent, wxID_ANY,
|
||||
_(L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate.")));
|
||||
Line cafile_hint { "", "" };
|
||||
cafile_hint.full_width = 1;
|
||||
cafile_hint.widget = [this, ca_file_hint](wxWindow* parent) {
|
||||
auto txt = new wxStaticText(parent, wxID_ANY, ca_file_hint);
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(txt);
|
||||
return sizer;
|
||||
};
|
||||
optgroup->append_line(cafile_hint);
|
||||
} else {
|
||||
Line line { "", "" };
|
||||
line.full_width = 1;
|
||||
|
||||
line.widget = [this, ca_file_hint] (wxWindow* parent) {
|
||||
auto txt = new wxStaticText(parent, wxID_ANY, wxString::Format("%s\n\n\t%s",
|
||||
_(L("HTTPS CA File:\n\
|
||||
\tOn this system, Slic3r uses HTTPS certificates from the system Certificate Store or Keychain.\n\
|
||||
\tTo use a custom CA file, please import your CA file into Certificate Store / Keychain.")),
|
||||
ca_file_hint));
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(txt);
|
||||
return sizer;
|
||||
};
|
||||
|
||||
Line cafile_hint { "", "" };
|
||||
cafile_hint.full_width = 1;
|
||||
cafile_hint.widget = std::move(printhost_cafile_hint);
|
||||
optgroup->append_line(cafile_hint);
|
||||
|
||||
optgroup->append_line(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1506,6 +1506,21 @@ void PrusaDoubleSlider::SetHigherValue(const int higher_val)
|
|||
ProcessWindowEvent(e);
|
||||
}
|
||||
|
||||
void PrusaDoubleSlider::SetSelectionSpan(const int lower_val, const int higher_val)
|
||||
{
|
||||
m_lower_value = std::max(lower_val, m_min_value);
|
||||
m_higher_value = std::max(std::min(higher_val, m_max_value), m_lower_value);
|
||||
if (m_lower_value < m_higher_value)
|
||||
m_is_one_layer = false;
|
||||
|
||||
Refresh();
|
||||
Update();
|
||||
|
||||
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
ProcessWindowEvent(e);
|
||||
}
|
||||
|
||||
void PrusaDoubleSlider::SetMaxValue(const int max_value)
|
||||
{
|
||||
m_max_value = max_value;
|
||||
|
@ -2043,7 +2058,7 @@ void PrusaDoubleSlider::enter_window(wxMouseEvent& event, const bool enter)
|
|||
// - value decrease (if wxSL_HORIZONTAL)
|
||||
void PrusaDoubleSlider::move_current_thumb(const bool condition)
|
||||
{
|
||||
m_is_one_layer = wxGetKeyState(WXK_CONTROL);
|
||||
// m_is_one_layer = wxGetKeyState(WXK_CONTROL);
|
||||
int delta = condition ? -1 : 1;
|
||||
if (is_horizontal())
|
||||
delta *= -1;
|
||||
|
|
|
@ -697,18 +697,20 @@ public:
|
|||
const wxString& name = wxEmptyString);
|
||||
~PrusaDoubleSlider() {}
|
||||
|
||||
int GetLowerValue() const {
|
||||
return m_lower_value;
|
||||
}
|
||||
int GetHigherValue() const {
|
||||
return m_higher_value;
|
||||
}
|
||||
int GetMinValue() const { return m_min_value; }
|
||||
int GetMaxValue() const { return m_max_value; }
|
||||
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value].second; }
|
||||
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value].second; }
|
||||
int GetLowerValue() const { return m_lower_value; }
|
||||
int GetHigherValue() const { return m_higher_value; }
|
||||
int GetActiveValue() const;
|
||||
double GetLowerValueD() { return get_double_value(ssLower); }
|
||||
double GetHigherValueD() { return get_double_value(ssHigher); }
|
||||
wxSize DoGetBestSize() const override;
|
||||
void SetLowerValue(const int lower_val);
|
||||
void SetHigherValue(const int higher_val);
|
||||
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
|
||||
void SetSelectionSpan(const int lower_val, const int higher_val);
|
||||
void SetMaxValue(const int max_value);
|
||||
void SetKoefForLabels(const double koef) {
|
||||
m_label_koef = koef;
|
||||
|
@ -726,6 +728,12 @@ public:
|
|||
EnableTickManipulation(false);
|
||||
}
|
||||
|
||||
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
|
||||
bool is_one_layer() const { return m_is_one_layer; }
|
||||
bool is_lower_at_min() const { return m_lower_value == m_min_value; }
|
||||
bool is_higher_at_max() const { return m_higher_value == m_max_value; }
|
||||
bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); }
|
||||
|
||||
void OnPaint(wxPaintEvent& ) { render();}
|
||||
void OnLeftDown(wxMouseEvent& event);
|
||||
void OnMotion(wxMouseEvent& event);
|
||||
|
@ -762,7 +770,6 @@ protected:
|
|||
|
||||
bool is_point_in_rect(const wxPoint& pt, const wxRect& rect);
|
||||
int is_point_near_tick(const wxPoint& pt);
|
||||
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
|
||||
|
||||
double get_scroll_step();
|
||||
wxString get_label(const SelectedSlider& selection) const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue