Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorenricoturri1966 <enricoturri@seznam.cz>2022-01-14 11:55:13 +0300
committerenricoturri1966 <enricoturri@seznam.cz>2022-01-14 11:55:13 +0300
commitb9b702d5509a1d4a03b4926de3ac92c116b01024 (patch)
tree225c0f61ef6e4f23e8239ec1d29f26d5d4046d66 /src/slic3r
parent1019792884d40632de77906f06e6c1f50958d6f3 (diff)
parentc07a8482578b279e2a7c6456da650390d120bded (diff)
Fixed conflicts after merge with branch devet_preview_layout
Diffstat (limited to 'src/slic3r')
-rw-r--r--src/slic3r/CMakeLists.txt10
-rw-r--r--src/slic3r/GUI/3DBed.cpp17
-rw-r--r--src/slic3r/GUI/3DScene.cpp188
-rw-r--r--src/slic3r/GUI/3DScene.hpp40
-rw-r--r--src/slic3r/GUI/AboutDialog.cpp17
-rw-r--r--src/slic3r/GUI/BackgroundSlicingProcess.cpp2
-rw-r--r--src/slic3r/GUI/BedShapeDialog.cpp4
-rw-r--r--src/slic3r/GUI/BitmapCache.cpp16
-rw-r--r--src/slic3r/GUI/BitmapCache.hpp9
-rw-r--r--src/slic3r/GUI/ConfigSnapshotDialog.cpp7
-rw-r--r--src/slic3r/GUI/ConfigWizard.cpp14
-rw-r--r--src/slic3r/GUI/DoubleSlider.cpp42
-rw-r--r--src/slic3r/GUI/DoubleSlider.hpp2
-rw-r--r--src/slic3r/GUI/DoubleSlider_Utils.hpp191
-rw-r--r--src/slic3r/GUI/Field.cpp6
-rw-r--r--src/slic3r/GUI/FirmwareDialog.cpp5
-rw-r--r--src/slic3r/GUI/GCodeViewer.cpp181
-rw-r--r--src/slic3r/GUI/GCodeViewer.hpp43
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp140
-rw-r--r--src/slic3r/GUI/GLCanvas3D.hpp2
-rw-r--r--src/slic3r/GUI/GLModel.cpp2
-rw-r--r--src/slic3r/GUI/GLModel.hpp7
-rw-r--r--src/slic3r/GUI/GLShader.cpp11
-rw-r--r--src/slic3r/GUI/GLShader.hpp7
-rw-r--r--src/slic3r/GUI/GUI_App.cpp115
-rw-r--r--src/slic3r/GUI/GUI_App.hpp3
-rw-r--r--src/slic3r/GUI/GUI_Factories.cpp7
-rw-r--r--src/slic3r/GUI/GUI_Init.cpp2
-rw-r--r--src/slic3r/GUI/GUI_ObjectManipulation.cpp2
-rw-r--r--src/slic3r/GUI/GUI_Preview.cpp3
-rw-r--r--src/slic3r/GUI/GUI_Utils.hpp8
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoBase.cpp52
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoBase.hpp34
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoCut.cpp11
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoCut.hpp1
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp40
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp13
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp43
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp92
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp14
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoMove.cpp10
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp12
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp6
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp14
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp1
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp20
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp11
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp4
-rw-r--r--src/slic3r/GUI/HintNotification.cpp6
-rw-r--r--src/slic3r/GUI/ImGuiWrapper.cpp57
-rw-r--r--src/slic3r/GUI/ImGuiWrapper.hpp22
-rw-r--r--src/slic3r/GUI/InstanceCheck.cpp5
-rw-r--r--src/slic3r/GUI/Jobs/ArrangeJob.cpp65
-rw-r--r--src/slic3r/GUI/Jobs/ArrangeJob.hpp26
-rw-r--r--src/slic3r/GUI/Jobs/BoostThreadWorker.cpp181
-rw-r--r--src/slic3r/GUI/Jobs/BoostThreadWorker.hpp140
-rw-r--r--src/slic3r/GUI/Jobs/BusyCursorJob.hpp48
-rw-r--r--src/slic3r/GUI/Jobs/FillBedJob.cpp30
-rw-r--r--src/slic3r/GUI/Jobs/FillBedJob.hpp21
-rw-r--r--src/slic3r/GUI/Jobs/Job.cpp158
-rw-r--r--src/slic3r/GUI/Jobs/Job.hpp136
-rw-r--r--src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp6
-rw-r--r--src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp2
-rw-r--r--src/slic3r/GUI/Jobs/PlaterJob.cpp17
-rw-r--r--src/slic3r/GUI/Jobs/PlaterJob.hpp24
-rw-r--r--src/slic3r/GUI/Jobs/PlaterWorker.hpp127
-rw-r--r--src/slic3r/GUI/Jobs/RotoptimizeJob.cpp33
-rw-r--r--src/slic3r/GUI/Jobs/RotoptimizeJob.hpp24
-rw-r--r--src/slic3r/GUI/Jobs/SLAImportDialog.hpp114
-rw-r--r--src/slic3r/GUI/Jobs/SLAImportJob.cpp149
-rw-r--r--src/slic3r/GUI/Jobs/SLAImportJob.hpp31
-rw-r--r--src/slic3r/GUI/Jobs/ThreadSafeQueue.hpp123
-rw-r--r--src/slic3r/GUI/Jobs/Worker.hpp119
-rw-r--r--src/slic3r/GUI/MainFrame.cpp10
-rw-r--r--src/slic3r/GUI/MsgDialog.cpp30
-rw-r--r--src/slic3r/GUI/NotificationManager.cpp2
-rw-r--r--src/slic3r/GUI/OG_CustomCtrl.cpp7
-rw-r--r--src/slic3r/GUI/OptionsGroup.cpp31
-rw-r--r--src/slic3r/GUI/Plater.cpp227
-rw-r--r--src/slic3r/GUI/Plater.hpp41
-rw-r--r--src/slic3r/GUI/Preferences.cpp44
-rw-r--r--src/slic3r/GUI/PresetComboBoxes.cpp20
-rw-r--r--src/slic3r/GUI/PrintHostDialogs.cpp4
-rw-r--r--src/slic3r/GUI/Selection.cpp83
-rw-r--r--src/slic3r/GUI/Selection.hpp6
-rw-r--r--src/slic3r/GUI/SendSystemInfoDialog.cpp6
-rw-r--r--src/slic3r/GUI/SysInfoDialog.cpp7
-rw-r--r--src/slic3r/GUI/Tab.cpp41
-rw-r--r--src/slic3r/GUI/Tab.hpp1
-rw-r--r--src/slic3r/GUI/UnsavedChangesDialog.cpp26
-rw-r--r--src/slic3r/GUI/UnsavedChangesDialog.hpp2
-rw-r--r--src/slic3r/GUI/WipeTowerDialog.cpp8
-rw-r--r--src/slic3r/GUI/wxExtensions.cpp7
-rw-r--r--src/slic3r/Utils/FixModelByWin10.cpp47
94 files changed, 1935 insertions, 1860 deletions
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 211a2c2e7..34c0efd01 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -169,9 +169,11 @@ set(SLIC3R_GUI_SOURCES
GUI/PrintHostDialogs.cpp
GUI/PrintHostDialogs.hpp
GUI/Jobs/Job.hpp
- GUI/Jobs/Job.cpp
- GUI/Jobs/PlaterJob.hpp
- GUI/Jobs/PlaterJob.cpp
+ GUI/Jobs/Worker.hpp
+ GUI/Jobs/BoostThreadWorker.hpp
+ GUI/Jobs/BoostThreadWorker.cpp
+ GUI/Jobs/BusyCursorJob.hpp
+ GUI/Jobs/PlaterWorker.hpp
GUI/Jobs/ArrangeJob.hpp
GUI/Jobs/ArrangeJob.cpp
GUI/Jobs/RotoptimizeJob.hpp
@@ -183,6 +185,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Jobs/ProgressIndicator.hpp
GUI/Jobs/NotificationProgressIndicator.hpp
GUI/Jobs/NotificationProgressIndicator.cpp
+ GUI/Jobs/ThreadSafeQueue.hpp
+ GUI/Jobs/SLAImportDialog.hpp
GUI/ProgressStatusBar.hpp
GUI/ProgressStatusBar.cpp
GUI/Mouse3DController.cpp
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index bd5ca9f52..21e23d402 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -19,8 +19,10 @@
#include <boost/log/trivial.hpp>
static const float GROUND_Z = -0.02f;
-static const std::array<float, 4> DEFAULT_MODEL_COLOR = { 0.235f, 0.235f, 0.235f, 1.0f };
-static const std::array<float, 4> PICKING_MODEL_COLOR = { 0.0f, 0.0f, 0.0f, 1.0f };
+static const Slic3r::ColorRGBA DEFAULT_MODEL_COLOR = Slic3r::ColorRGBA::DARK_GRAY();
+static const Slic3r::ColorRGBA PICKING_MODEL_COLOR = Slic3r::ColorRGBA::BLACK();
+static const Slic3r::ColorRGBA DEFAULT_SOLID_GRID_COLOR = { 0.9f, 0.9f, 0.9f, 1.0f };
+static const Slic3r::ColorRGBA DEFAULT_TRANSPARENT_GRID_COLOR = { 0.9f, 0.9f, 0.9f, 0.6f };
namespace Slic3r {
namespace GUI {
@@ -121,15 +123,15 @@ void Bed3D::Axes::render() const
shader->set_uniform("emission_factor", 0.0f);
// x axis
- const_cast<GLModel*>(&m_arrow)->set_color(-1, { 0.75f, 0.0f, 0.0f, 1.0f });
+ const_cast<GLModel*>(&m_arrow)->set_color(-1, ColorRGBA::X());
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast<float>());
// y axis
- const_cast<GLModel*>(&m_arrow)->set_color(-1, { 0.0f, 0.75f, 0.0f, 1.0f });
+ const_cast<GLModel*>(&m_arrow)->set_color(-1, ColorRGBA::Y());
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast<float>());
// z axis
- const_cast<GLModel*>(&m_arrow)->set_color(-1, { 0.0f, 0.0f, 0.75f, 1.0f });
+ const_cast<GLModel*>(&m_arrow)->set_color(-1, ColorRGBA::Z());
render_axis(Geometry::assemble_transform(m_origin).cast<float>());
shader->stop_using();
@@ -550,10 +552,7 @@ void Bed3D::render_default(bool bottom, bool picking) const
if (!picking) {
// draw grid
glsafe(::glLineWidth(1.5f * m_scale_factor));
- if (has_model && !bottom)
- glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 1.0f));
- else
- glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.6f));
+ glsafe(::glColor4fv(has_model && !bottom ? DEFAULT_SOLID_GRID_COLOR.data() : DEFAULT_TRANSPARENT_GRID_COLOR.data()));
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data()));
glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines.get_vertices_count()));
}
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 94b1f3156..93f0548bc 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -344,20 +344,20 @@ void GLVolume::SinkingContours::update()
m_model.reset();
}
-const std::array<float, 4> GLVolume::SELECTED_COLOR = { 0.0f, 1.0f, 0.0f, 1.0f };
-const std::array<float, 4> GLVolume::HOVER_SELECT_COLOR = { 0.4f, 0.9f, 0.1f, 1.0f };
-const std::array<float, 4> GLVolume::HOVER_DESELECT_COLOR = { 1.0f, 0.75f, 0.75f, 1.0f };
-const std::array<float, 4> GLVolume::OUTSIDE_COLOR = { 0.0f, 0.38f, 0.8f, 1.0f };
-const std::array<float, 4> GLVolume::SELECTED_OUTSIDE_COLOR = { 0.19f, 0.58f, 1.0f, 1.0f };
-const std::array<float, 4> GLVolume::DISABLED_COLOR = { 0.25f, 0.25f, 0.25f, 1.0f };
-const std::array<float, 4> GLVolume::SLA_SUPPORT_COLOR = { 0.75f, 0.75f, 0.75f, 1.0f };
-const std::array<float, 4> GLVolume::SLA_PAD_COLOR = { 0.0f, 0.2f, 0.0f, 1.0f };
-const std::array<float, 4> GLVolume::NEUTRAL_COLOR = { 0.9f, 0.9f, 0.9f, 1.0f };
-const std::array<std::array<float, 4>, 4> GLVolume::MODEL_COLOR = { {
- { 1.0f, 1.0f, 0.0f, 1.f },
- { 1.0f, 0.5f, 0.5f, 1.f },
- { 0.5f, 1.0f, 0.5f, 1.f },
- { 0.5f, 0.5f, 1.0f, 1.f }
+const ColorRGBA GLVolume::SELECTED_COLOR = ColorRGBA::GREEN();
+const ColorRGBA GLVolume::HOVER_SELECT_COLOR = { 0.4f, 0.9f, 0.1f, 1.0f };
+const ColorRGBA GLVolume::HOVER_DESELECT_COLOR = { 1.0f, 0.75f, 0.75f, 1.0f };
+const ColorRGBA GLVolume::OUTSIDE_COLOR = { 0.0f, 0.38f, 0.8f, 1.0f };
+const ColorRGBA GLVolume::SELECTED_OUTSIDE_COLOR = { 0.19f, 0.58f, 1.0f, 1.0f };
+const ColorRGBA GLVolume::DISABLED_COLOR = ColorRGBA::DARK_GRAY();
+const ColorRGBA GLVolume::SLA_SUPPORT_COLOR = ColorRGBA::LIGHT_GRAY();
+const ColorRGBA GLVolume::SLA_PAD_COLOR = { 0.0f, 0.2f, 0.0f, 1.0f };
+const ColorRGBA GLVolume::NEUTRAL_COLOR = { 0.9f, 0.9f, 0.9f, 1.0f };
+const std::array<ColorRGBA, 4> GLVolume::MODEL_COLOR = { {
+ ColorRGBA::YELLOW(),
+ { 1.0f, 0.5f, 0.5f, 1.0f },
+ { 0.5f, 1.0f, 0.5f, 1.0f },
+ { 0.5f, 0.5f, 1.0f, 1.0f }
} };
GLVolume::GLVolume(float r, float g, float b, float a)
@@ -388,21 +388,6 @@ GLVolume::GLVolume(float r, float g, float b, float a)
set_render_color(color);
}
-void GLVolume::set_color(const std::array<float, 4>& rgba)
-{
- color = rgba;
-}
-
-void GLVolume::set_render_color(float r, float g, float b, float a)
-{
- render_color = { r, g, b, a };
-}
-
-void GLVolume::set_render_color(const std::array<float, 4>& rgba)
-{
- render_color = rgba;
-}
-
void GLVolume::set_render_color()
{
bool outside = is_outside || is_below_printbed();
@@ -432,46 +417,28 @@ void GLVolume::set_render_color()
set_render_color(color);
}
- if (!printable) {
- render_color[0] /= 4;
- render_color[1] /= 4;
- render_color[2] /= 4;
- }
+ if (!printable)
+ render_color = saturate(render_color, 0.25f);
if (force_transparent)
- render_color[3] = color[3];
+ render_color.a(color.a());
}
-std::array<float, 4> color_from_model_volume(const ModelVolume& model_volume)
+ColorRGBA color_from_model_volume(const ModelVolume& model_volume)
{
- std::array<float, 4> color;
- if (model_volume.is_negative_volume()) {
- color[0] = 0.2f;
- color[1] = 0.2f;
- color[2] = 0.2f;
- }
- else if (model_volume.is_modifier()) {
-#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
- color[0] = 1.0f;
- color[1] = 1.0f;
- color[2] = 0.2f;
-#else
- color[0] = 0.2f;
- color[1] = 1.0f;
- color[2] = 0.2f;
-#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
- }
- else if (model_volume.is_support_blocker()) {
- color[0] = 1.0f;
- color[1] = 0.2f;
- color[2] = 0.2f;
- }
- else if (model_volume.is_support_enforcer()) {
- color[0] = 0.2f;
- color[1] = 0.2f;
- color[2] = 1.0f;
- }
- color[3] = model_volume.is_model_part() ? 1.f : 0.5f;
+ ColorRGBA color;
+ if (model_volume.is_negative_volume())
+ color = { 0.2f, 0.2f, 0.2f, 1.0f };
+ else if (model_volume.is_modifier())
+ color = { 1.0, 1.0f, 0.2f, 1.0f };
+ else if (model_volume.is_support_blocker())
+ color = { 1.0f, 0.2f, 0.2f, 1.0f };
+ else if (model_volume.is_support_enforcer())
+ color = { 0.2f, 0.2f, 1.0f, 1.0f };
+
+ if (!model_volume.is_model_part())
+ color.a(0.5f);
+
return color;
}
@@ -631,8 +598,8 @@ int GLVolumeCollection::load_object_volume(
const int extruder_id = model_volume->extruder_id();
const ModelInstance *instance = model_object->instances[instance_idx];
const TriangleMesh &mesh = model_volume->mesh();
- std::array<float, 4> color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4];
- color[3] = model_volume->is_model_part() ? 1.f : 0.5f;
+ ColorRGBA color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4];
+ color.a(model_volume->is_model_part() ? 1.0f : 0.5f);
this->volumes.emplace_back(new GLVolume(color));
GLVolume& v = *this->volumes.back();
v.set_color(color_from_model_volume(*model_volume));
@@ -713,13 +680,13 @@ int GLVolumeCollection::load_wipe_tower_preview(
height = 0.1f;
TriangleMesh mesh;
- std::array<float, 4> color = { 0.5f, 0.5f, 0.0f, 1.0f };
+ ColorRGBA color = ColorRGBA::DARK_YELLOW();
// In case we don't know precise dimensions of the wipe tower yet, we'll draw
// the box with different color with one side jagged:
if (size_unknown) {
- color[0] = 0.9f;
- color[1] = 0.6f;
+ color.r(0.9f);
+ color.g(0.6f);
// Too narrow tower would interfere with the teeth. The estimate is not precise anyway.
depth = std::max(depth, 10.f);
@@ -775,14 +742,14 @@ int GLVolumeCollection::load_wipe_tower_preview(
return int(volumes.size() - 1);
}
-GLVolume* GLVolumeCollection::new_toolpath_volume(const std::array<float, 4>& rgba, size_t reserve_vbo_floats)
+GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
{
GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats);
out->is_extrusion_path = true;
return out;
}
-GLVolume* GLVolumeCollection::new_nontoolpath_volume(const std::array<float, 4>& rgba, size_t reserve_vbo_floats)
+GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
{
GLVolume *out = new GLVolume(rgba);
out->is_extrusion_path = false;
@@ -799,7 +766,7 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
for (unsigned int i = 0; i < (unsigned int)volumes.size(); ++i) {
GLVolume* volume = volumes[i];
- bool is_transparent = (volume->render_color[3] < 1.0f);
+ bool is_transparent = volume->render_color.is_transparent();
if (((type == GLVolumeCollection::ERenderType::Opaque && !is_transparent) ||
(type == GLVolumeCollection::ERenderType::Transparent && is_transparent) ||
type == GLVolumeCollection::ERenderType::All) &&
@@ -845,15 +812,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
glsafe(::glDisable(GL_CULL_FACE));
for (GLVolumeWithIdAndZ& volume : to_render) {
-#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
if (type == ERenderType::Transparent)
volume.first->force_transparent = true;
-#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
volume.first->set_render_color();
-#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
if (type == ERenderType::Transparent)
volume.first->force_transparent = false;
-#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
// render sinking contours of non-hovered volumes
if (m_show_sinking_contours)
@@ -982,8 +945,7 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
void GLVolumeCollection::reset_outside_state()
{
- for (GLVolume* volume : this->volumes)
- {
+ for (GLVolume* volume : this->volumes) {
if (volume != nullptr)
volume->is_outside = false;
}
@@ -991,46 +953,18 @@ void GLVolumeCollection::reset_outside_state()
void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* config)
{
- static const float inv_255 = 1.0f / 255.0f;
+ using ColorItem = std::pair<std::string, ColorRGBA>;
+ std::vector<ColorItem> colors;
- struct Color
- {
- std::string text;
- unsigned char rgb[3];
-
- Color()
- : text("")
- {
- rgb[0] = 255;
- rgb[1] = 255;
- rgb[2] = 255;
- }
-
- void set(const std::string& text, unsigned char* rgb)
- {
- this->text = text;
- ::memcpy((void*)this->rgb, (const void*)rgb, 3 * sizeof(unsigned char));
- }
- };
-
- if (config == nullptr)
- return;
-
- unsigned char rgb[3];
- std::vector<Color> colors;
-
- if (static_cast<PrinterTechnology>(config->opt_int("printer_technology")) == ptSLA)
- {
+ if (static_cast<PrinterTechnology>(config->opt_int("printer_technology")) == ptSLA) {
const std::string& txt_color = config->opt_string("material_colour").empty() ?
print_config_def.get("material_colour")->get_default_value<ConfigOptionString>()->value :
config->opt_string("material_colour");
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb)) {
- colors.resize(1);
- colors[0].set(txt_color, rgb);
- }
- }
- else
- {
+ ColorRGBA rgba;
+ if (decode_color(txt_color, rgba))
+ colors.push_back({ txt_color, rgba });
+}
+ else {
const ConfigOptionStrings* extruders_opt = dynamic_cast<const ConfigOptionStrings*>(config->option("extruder_colour"));
if (extruders_opt == nullptr)
return;
@@ -1039,37 +973,35 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
if (filamemts_opt == nullptr)
return;
- unsigned int colors_count = std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size());
+ size_t colors_count = std::max(extruders_opt->values.size(), filamemts_opt->values.size());
if (colors_count == 0)
return;
colors.resize(colors_count);
for (unsigned int i = 0; i < colors_count; ++i) {
- const std::string& txt_color = config->opt_string("extruder_colour", i);
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
- colors[i].set(txt_color, rgb);
+ const std::string& ext_color = config->opt_string("extruder_colour", i);
+ ColorRGBA rgba;
+ if (decode_color(ext_color, rgba))
+ colors[i] = { ext_color, rgba };
else {
- const std::string& txt_color = config->opt_string("filament_colour", i);
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
- colors[i].set(txt_color, rgb);
+ const std::string& fil_color = config->opt_string("filament_colour", i);
+ if (decode_color(fil_color, rgba))
+ colors[i] = { fil_color, rgba };
}
}
}
for (GLVolume* volume : volumes) {
- if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0))
+ if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || volume->volume_idx() < 0)
continue;
int extruder_id = volume->extruder_id - 1;
if (extruder_id < 0 || (int)colors.size() <= extruder_id)
extruder_id = 0;
- const Color& color = colors[extruder_id];
- if (!color.text.empty()) {
- for (int i = 0; i < 3; ++i) {
- volume->color[i] = (float)color.rgb[i] * inv_255;
- }
- }
+ const ColorItem& color = colors[extruder_id];
+ if (!color.first.empty())
+ volume->color = color.second;
}
}
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index 6d82e3bb7..7ad12c354 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -7,6 +7,7 @@
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/Geometry.hpp"
+#include "libslic3r/Color.hpp"
#include "GLModel.hpp"
@@ -43,7 +44,7 @@ class ModelVolume;
enum ModelInstanceEPrintVolumeState : unsigned char;
// Return appropriate color based on the ModelVolume.
-std::array<float, 4> color_from_model_volume(const ModelVolume& model_volume);
+extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume);
// A container for interleaved arrays of 3D vertices and normals,
// possibly indexed by triangles and / or quads.
@@ -248,16 +249,16 @@ private:
class GLVolume {
public:
- static const std::array<float, 4> SELECTED_COLOR;
- static const std::array<float, 4> HOVER_SELECT_COLOR;
- static const std::array<float, 4> HOVER_DESELECT_COLOR;
- static const std::array<float, 4> OUTSIDE_COLOR;
- static const std::array<float, 4> SELECTED_OUTSIDE_COLOR;
- static const std::array<float, 4> DISABLED_COLOR;
- static const std::array<float, 4> SLA_SUPPORT_COLOR;
- static const std::array<float, 4> SLA_PAD_COLOR;
- static const std::array<float, 4> NEUTRAL_COLOR;
- static const std::array<std::array<float, 4>, 4> MODEL_COLOR;
+ static const ColorRGBA SELECTED_COLOR;
+ static const ColorRGBA HOVER_SELECT_COLOR;
+ static const ColorRGBA HOVER_DESELECT_COLOR;
+ static const ColorRGBA OUTSIDE_COLOR;
+ static const ColorRGBA SELECTED_OUTSIDE_COLOR;
+ static const ColorRGBA DISABLED_COLOR;
+ static const ColorRGBA SLA_SUPPORT_COLOR;
+ static const ColorRGBA SLA_PAD_COLOR;
+ static const ColorRGBA NEUTRAL_COLOR;
+ static const std::array<ColorRGBA, 4> MODEL_COLOR;
enum EHoverState : unsigned char
{
@@ -267,8 +268,8 @@ public:
HS_Deselect
};
- GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
- GLVolume(const std::array<float, 4>& rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
+ GLVolume(float r = 1.0f, float g = 1.0f, float b = 1.0f, float a = 1.0f);
+ GLVolume(const ColorRGBA& color) : GLVolume(color.r(), color.g(), color.b(), color.a()) {}
private:
Geometry::Transformation m_instance_transformation;
@@ -305,9 +306,9 @@ private:
public:
// Color of the triangles / quads held by this volume.
- std::array<float, 4> color;
+ ColorRGBA color;
// Color used to render this volume.
- std::array<float, 4> render_color;
+ ColorRGBA render_color;
struct CompositeID {
CompositeID(int object_id, int volume_id, int instance_id) : object_id(object_id), volume_id(volume_id), instance_id(instance_id) {}
@@ -393,9 +394,8 @@ public:
return out;
}
- void set_color(const std::array<float, 4>& rgba);
- void set_render_color(float r, float g, float b, float a);
- void set_render_color(const std::array<float, 4>& rgba);
+ void set_color(const ColorRGBA& rgba) { color = rgba; }
+ void set_render_color(const ColorRGBA& rgba) { render_color = rgba; }
// Sets render color in dependence of current state
void set_render_color();
// set color according to model volume
@@ -595,8 +595,8 @@ public:
int load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
- GLVolume* new_toolpath_volume(const std::array<float, 4>& rgba, size_t reserve_vbo_floats = 0);
- GLVolume* new_nontoolpath_volume(const std::array<float, 4>& rgba, size_t reserve_vbo_floats = 0);
+ GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
+ GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
// Render the volumes by OpenGL.
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp
index 05f301186..e444fb03c 100644
--- a/src/slic3r/GUI/AboutDialog.cpp
+++ b/src/slic3r/GUI/AboutDialog.cpp
@@ -2,6 +2,7 @@
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
@@ -132,13 +133,13 @@ wxString CopyrightsDialog::get_html_text()
{
wxColour bgr_clr = wxGetApp().get_window_default_clr();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
- const auto text_clr = wxGetApp().get_label_clr_default();// wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
- const auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- const auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
+ const auto text_clr = wxGetApp().get_label_clr_default();
+ const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
+ const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
- const wxString copyright_str = _(L("Copyright")) + "&copy; ";
+ const wxString copyright_str = _L("Copyright") + "&copy; ";
// TRN "Slic3r _is licensed under the_ License"
- const wxString header_str = _(L("License agreements of all following programs (libraries) are part of application license agreement"));
+ const wxString header_str = _L("License agreements of all following programs (libraries) are part of application license agreement");
wxString text = wxString::Format(
"<html>"
@@ -256,9 +257,9 @@ AboutDialog::AboutDialog()
{
m_html->SetMinSize(wxSize(-1, 16 * wxGetApp().em_unit()));
wxFont font = get_default_font(this);
- const auto text_clr = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
- auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
+ const auto text_clr = wxGetApp().get_label_clr_default();
+ const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
+ const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
const int fs = font.GetPointSize()-1;
int size[] = {fs,fs,fs,fs,fs,fs,fs};
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index e93f32b03..5f7b4e8d3 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -81,7 +81,7 @@ std::pair<std::string, bool> SlicingProcessCompletedEvent::format_error_message(
"be glad if you reported it."))) % SLIC3R_APP_NAME).str());
error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
} catch (const HardCrash &ex) {
- error = GUI::format("PrusaSlicer has encountered a fatal error: \"%1%\"", ex.what()) + "\n\n" +
+ error = GUI::format(_L("PrusaSlicer has encountered a fatal error: \"%1%\""), ex.what()) + "\n\n" +
_u8L("Please save your project and restart PrusaSlicer. "
"We would be glad if you reported the issue.");
} catch (PlaceholderParserError &ex) {
diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp
index 246c8b63e..27caedfc3 100644
--- a/src/slic3r/GUI/BedShapeDialog.cpp
+++ b/src/slic3r/GUI/BedShapeDialog.cpp
@@ -309,7 +309,7 @@ wxPanel* BedShapePanel::init_texture_panel()
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
if (lbl != nullptr) {
bool exists = (m_custom_texture == NONE) || boost::filesystem::exists(m_custom_texture);
- lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED));
+ lbl->SetForegroundColour(exists ? wxGetApp().get_label_clr_default() : wxColor(*wxRED));
wxString tooltip_text = "";
if (m_custom_texture != NONE) {
@@ -380,7 +380,7 @@ wxPanel* BedShapePanel::init_model_panel()
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
if (lbl != nullptr) {
bool exists = (m_custom_model == NONE) || boost::filesystem::exists(m_custom_model);
- lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED));
+ lbl->SetForegroundColour(exists ? wxGetApp().get_label_clr_default() : wxColor(*wxRED));
wxString tooltip_text = "";
if (m_custom_model != NONE) {
diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp
index 39ba849d3..e23591fb6 100644
--- a/src/slic3r/GUI/BitmapCache.cpp
+++ b/src/slic3r/GUI/BitmapCache.cpp
@@ -395,21 +395,5 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi
return wxImage_to_wxBitmap_with_alpha(std::move(image), scale);
}
-bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
-{
- rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
- if (scolor.size() != 7 || scolor.front() != '#')
- return false;
- const char* c = scolor.data() + 1;
- for (size_t i = 0; i < 3; ++i) {
- int digit1 = hex_digit_to_int(*c++);
- int digit2 = hex_digit_to_int(*c++);
- if (digit1 == -1 || digit2 == -1)
- return false;
- rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
- }
- return true;
-}
-
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp
index 4d1d383c4..5af90c5f7 100644
--- a/src/slic3r/GUI/BitmapCache.hpp
+++ b/src/slic3r/GUI/BitmapCache.hpp
@@ -9,9 +9,12 @@
#include <wx/wx.h>
#endif
+#include "libslic3r/Color.hpp"
+
struct NSVGimage;
-namespace Slic3r { namespace GUI {
+namespace Slic3r {
+namespace GUI {
class BitmapCache
{
@@ -43,11 +46,9 @@ public:
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false, const std::string& new_color = "");
wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false);
- wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); }
+ wxBitmap mksolid(size_t width, size_t height, const ColorRGB& rgb, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar(), wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); }
wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
- static bool parse_color(const std::string& scolor, unsigned char* rgb_out);
-
private:
std::map<std::string, wxBitmap*> m_map;
double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs)
diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp
index 7d2029e22..e2bea55d1 100644
--- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp
+++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp
@@ -5,6 +5,7 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/Time.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
#include "wxExtensions.hpp"
@@ -31,11 +32,9 @@ static wxString format_reason(const Config::Snapshot::Reason reason)
static std::string get_color(wxColour colour)
{
- wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue());
- return clr_str.ToStdString();
+ return encode_color(ColorRGB(colour.Red(), colour.Green(), colour.Blue()));
};
-
static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_even, bool snapshot_active, bool dark_mode)
{
// Start by declaring a row with an alternating background color.
@@ -105,7 +104,7 @@ static wxString generate_html_page(const Config::SnapshotDB &snapshot_db, const
wxString text =
"<html>"
"<body bgcolor=\"" + get_color(wxGetApp().get_window_default_clr()/*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)*/) + "\" cellspacing=\"2\" cellpadding=\"0\" border=\"0\" link=\"#800000\">"
- "<font color=\"" + get_color(wxGetApp().get_label_clr_default()/*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/) + "\">";
+ "<font color=\"" + get_color(wxGetApp().get_label_clr_default()) + "\">";
text += "<table style=\"width:100%\">";
for (size_t i_row = 0; i_row < snapshot_db.snapshots().size(); ++ i_row) {
const Config::Snapshot &snapshot = snapshot_db.snapshots()[snapshot_db.snapshots().size() - i_row - 1];
diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp
index bcc4ff3fa..4ff089882 100644
--- a/src/slic3r/GUI/ConfigWizard.cpp
+++ b/src/slic3r/GUI/ConfigWizard.cpp
@@ -36,6 +36,7 @@
#include "libslic3r/Config.hpp"
#include "libslic3r/libslic3r.h"
#include "libslic3r/Model.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
@@ -746,9 +747,9 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
wxSystemSettings::GetColour(wxSYS_COLOUR_MENU);
#endif
#endif
- const auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
- const auto text_clr = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
- const auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
+ const auto text_clr = wxGetApp().get_label_clr_default();
+ const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
+ const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
wxString first_line = format_wxstr(_L("%1% marked with <b>*</b> are <b>not</b> compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
wxString text;
if (all_printers) {
@@ -2729,8 +2730,11 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
return false;
}
else {
- bool is_filaments_changed = app_config->get_section(AppConfig::SECTION_FILAMENTS) != appconfig_new.get_section(AppConfig::SECTION_FILAMENTS);
- bool is_sla_materials_changed = app_config->get_section(AppConfig::SECTION_MATERIALS) != appconfig_new.get_section(AppConfig::SECTION_MATERIALS);
+ auto changed = [app_config, &appconfig_new = std::as_const(this->appconfig_new)](const std::string& section_name) {
+ return (app_config->has_section(section_name) ? app_config->get_section(section_name) : std::map<std::string, std::string>()) != appconfig_new.get_section(section_name);
+ };
+ bool is_filaments_changed = changed(AppConfig::SECTION_FILAMENTS);
+ bool is_sla_materials_changed = changed(AppConfig::SECTION_MATERIALS);
if ((check_unsaved_preset_changes = is_filaments_changed || is_sla_materials_changed)) {
header = is_filaments_changed ? _L("Some filaments were uninstalled.") : _L("Some SLA materials were uninstalled.");
if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp
index 3d914d5b6..ee5aacb19 100644
--- a/src/slic3r/GUI/DoubleSlider.cpp
+++ b/src/slic3r/GUI/DoubleSlider.cpp
@@ -2557,36 +2557,46 @@ bool Control::check_ticks_changed_event(Type type)
std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder)
{
+ auto opposite_one_color = [](const std::string& color) {
+ ColorRGB rgb;
+ decode_color(color, rgb);
+ return encode_color(opposite(rgb));
+ };
+ auto opposite_two_colors = [](const std::string& a, const std::string& b) {
+ ColorRGB rgb1; decode_color(a, rgb1);
+ ColorRGB rgb2; decode_color(b, rgb2);
+ return encode_color(opposite(rgb1, rgb2));
+ };
+
if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) {
#if 1
if (ticks.empty())
- return color_generator.get_opposite_color((*m_colors)[0]);
-
+ return opposite_one_color((*m_colors)[0]);
+
auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick);
- if (before_tick_it == ticks.end())
- {
+ if (before_tick_it == ticks.end()) {
while (before_tick_it != ticks.begin())
if (--before_tick_it; before_tick_it->type == ColorChange)
break;
if (before_tick_it->type == ColorChange)
- return color_generator.get_opposite_color(before_tick_it->color);
- return color_generator.get_opposite_color((*m_colors)[0]);
+ return opposite_one_color(before_tick_it->color);
+
+ return opposite_one_color((*m_colors)[0]);
}
- if (before_tick_it == ticks.begin())
- {
+ if (before_tick_it == ticks.begin()) {
const std::string& frst_color = (*m_colors)[0];
if (before_tick_it->type == ColorChange)
- return color_generator.get_opposite_color(frst_color, before_tick_it->color);
+ return opposite_two_colors(frst_color, before_tick_it->color);
auto next_tick_it = before_tick_it;
while (next_tick_it != ticks.end())
if (++next_tick_it; next_tick_it->type == ColorChange)
break;
if (next_tick_it->type == ColorChange)
- return color_generator.get_opposite_color(frst_color, next_tick_it->color);
+ return opposite_two_colors(frst_color, next_tick_it->color);
- return color_generator.get_opposite_color(frst_color);
+ return opposite_one_color(frst_color);
}
std::string frst_color = "";
@@ -2607,13 +2617,15 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int
if (before_tick_it->type == ColorChange) {
if (frst_color.empty())
- return color_generator.get_opposite_color(before_tick_it->color);
- return color_generator.get_opposite_color(before_tick_it->color, frst_color);
+ return opposite_one_color(before_tick_it->color);
+
+ return opposite_two_colors(before_tick_it->color, frst_color);
}
if (frst_color.empty())
- return color_generator.get_opposite_color((*m_colors)[0]);
- return color_generator.get_opposite_color((*m_colors)[0], frst_color);
+ return opposite_one_color((*m_colors)[0]);
+
+ return opposite_two_colors((*m_colors)[0], frst_color);
#else
const std::vector<std::string>& colors = ColorPrintColors::get();
if (ticks.empty())
diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp
index 23275cf2a..e0f713d87 100644
--- a/src/slic3r/GUI/DoubleSlider.hpp
+++ b/src/slic3r/GUI/DoubleSlider.hpp
@@ -3,7 +3,6 @@
#include "libslic3r/CustomGCode.hpp"
#include "wxExtensions.hpp"
-#include "DoubleSlider_Utils.hpp"
#include <wx/window.h>
#include <wx/control.h>
@@ -119,7 +118,6 @@ class TickCodeInfo
// int m_default_color_idx = 0;
std::vector<std::string>* m_colors {nullptr};
- ColorGenerator color_generator;
std::string get_color_for_tick(TickCode tick, Type type, const int extruder);
diff --git a/src/slic3r/GUI/DoubleSlider_Utils.hpp b/src/slic3r/GUI/DoubleSlider_Utils.hpp
index b5955f2fc..283d527fa 100644
--- a/src/slic3r/GUI/DoubleSlider_Utils.hpp
+++ b/src/slic3r/GUI/DoubleSlider_Utils.hpp
@@ -1,191 +1,8 @@
+#ifndef slic3r_GUI_DoubleSlider_Utils_hpp_
+#define slic3r_GUI_DoubleSlider_Utils_hpp_
+
#include <stdio.h>
#include <random>
-#include "wx/colour.h"
-
-class ColorGenerator
-{
- // Some of next code is borrowed from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
- typedef struct {
- double r; // a fraction between 0 and 1
- double g; // a fraction between 0 and 1
- double b; // a fraction between 0 and 1
- } rgb;
-
- typedef struct {
- double h; // angle in degrees
- double s; // a fraction between 0 and 1
- double v; // a fraction between 0 and 1
- } hsv;
-
- //static hsv rgb2hsv(rgb in);
- //static rgb hsv2rgb(hsv in);
-
- hsv rgb2hsv(rgb in)
- {
- hsv out;
- double min, max, delta;
-
- min = in.r < in.g ? in.r : in.g;
- min = min < in.b ? min : in.b;
-
- max = in.r > in.g ? in.r : in.g;
- max = max > in.b ? max : in.b;
-
- out.v = max; // v
- delta = max - min;
- if (delta < 0.00001)
- {
- out.s = 0;
- out.h = 0; // undefined, maybe nan?
- return out;
- }
- if (max > 0.0) { // NOTE: if Max is == 0, this divide would cause a crash
- out.s = (delta / max); // s
- }
- else {
- // if max is 0, then r = g = b = 0
- // s = 0, h is undefined
- out.s = 0.0;
- out.h = NAN; // its now undefined
- return out;
- }
- if (in.r >= max) // > is bogus, just keeps compilor happy
- out.h = (in.g - in.b) / delta; // between yellow & magenta
- else
- if (in.g >= max)
- out.h = 2.0 + (in.b - in.r) / delta; // between cyan & yellow
- else
- out.h = 4.0 + (in.r - in.g) / delta; // between magenta & cyan
-
- out.h *= 60.0; // degrees
-
- if (out.h < 0.0)
- out.h += 360.0;
-
- return out;
- }
-
- hsv rgb2hsv(const std::string& str_clr_in)
- {
- wxColour clr(str_clr_in);
- rgb in = { clr.Red() / 255.0, clr.Green() / 255.0, clr.Blue() / 255.0 };
- return rgb2hsv(in);
- }
-
-
- rgb hsv2rgb(hsv in)
- {
- double hh, p, q, t, ff;
- long i;
- rgb out;
-
- if (in.s <= 0.0) { // < is bogus, just shuts up warnings
- out.r = in.v;
- out.g = in.v;
- out.b = in.v;
- return out;
- }
- hh = in.h;
- if (hh >= 360.0) hh -= 360.0;//hh = 0.0;
- hh /= 60.0;
- i = (long)hh;
- ff = hh - i;
- p = in.v * (1.0 - in.s);
- q = in.v * (1.0 - (in.s * ff));
- t = in.v * (1.0 - (in.s * (1.0 - ff)));
-
- switch (i) {
- case 0:
- out.r = in.v;
- out.g = t;
- out.b = p;
- break;
- case 1:
- out.r = q;
- out.g = in.v;
- out.b = p;
- break;
- case 2:
- out.r = p;
- out.g = in.v;
- out.b = t;
- break;
-
- case 3:
- out.r = p;
- out.g = q;
- out.b = in.v;
- break;
- case 4:
- out.r = t;
- out.g = p;
- out.b = in.v;
- break;
- case 5:
- default:
- out.r = in.v;
- out.g = p;
- out.b = q;
- break;
- }
- return out;
- }
-
- std::random_device rd;
-
-public:
-
- ColorGenerator() {}
- ~ColorGenerator() {}
-
- double rand_val()
- {
- std::mt19937 rand_generator(rd());
-
- // this value will be used for Saturation and Value
- // to avoid extremely light/dark colors, take this value from range [0.65; 1.0]
- std::uniform_real_distribution<double> distrib(0.65, 1.0);
- return distrib(rand_generator);
- }
-
-
- std::string get_opposite_color(const std::string& color)
- {
- std::string opp_color = "";
-
- hsv hsv_clr = rgb2hsv(color);
- hsv_clr.h += 65; // 65 instead 60 to avoid circle values
- hsv_clr.s = rand_val();
- hsv_clr.v = rand_val();
-
- rgb rgb_opp_color = hsv2rgb(hsv_clr);
-
- wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
- opp_color = clr_str.ToStdString();
-
- return opp_color;
- }
-
- std::string get_opposite_color(const std::string& color_frst, const std::string& color_scnd)
- {
- std::string opp_color = "";
-
- hsv hsv_frst = rgb2hsv(color_frst);
- hsv hsv_scnd = rgb2hsv(color_scnd);
-
- double delta_h = fabs(hsv_frst.h - hsv_scnd.h);
- double start_h = delta_h > 180 ? std::min<double>(hsv_scnd.h, hsv_frst.h) : std::max<double>(hsv_scnd.h, hsv_frst.h);
- start_h += 5; // to avoid circle change of colors for 120 deg
- if (delta_h < 180)
- delta_h = 360 - delta_h;
-
- hsv hsv_opp = hsv{ start_h + 0.5 * delta_h, rand_val(), rand_val() };
- rgb rgb_opp_color = hsv2rgb(hsv_opp);
-
- wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
- opp_color = clr_str.ToStdString();
- return opp_color;
- }
-}; \ No newline at end of file
+#endif // slic3r_GUI_DoubleSlider_Utils_hpp_
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 5ec622b87..172a07f66 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -1389,10 +1389,8 @@ boost::any& ColourPicker::get_value()
auto colour = static_cast<wxColourPickerCtrl*>(window)->GetColour();
if (colour == wxTransparentColour)
m_value = std::string("");
- else {
- auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue());
- m_value = clr_str.ToStdString();
- }
+ else
+ m_value = encode_color(ColorRGB(colour.Red(), colour.Green(), colour.Blue()));
return m_value;
}
diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp
index 4966726ae..7600ef4fa 100644
--- a/src/slic3r/GUI/FirmwareDialog.cpp
+++ b/src/slic3r/GUI/FirmwareDialog.cpp
@@ -270,13 +270,12 @@ void FirmwareDialog::priv::flashing_start(unsigned tasks)
void FirmwareDialog::priv::flashing_done(AvrDudeComplete complete)
{
- auto text_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
port_picker->Enable();
btn_rescan->Enable();
hex_picker->Enable();
btn_close->Enable();
btn_flash->SetLabel(btn_flash_label_ready);
- txt_status->SetForegroundColour(text_color);
+ txt_status->SetForegroundColour(GUI::wxGetApp().get_label_clr_default());
timer_pulse.Stop();
progressbar->SetValue(progressbar->GetRange());
@@ -811,7 +810,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) :
panel->SetSizer(vsizer);
auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:")));
- p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr,
+ p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, /*wxFileSelectorPromptStr*/_L("Select a file"),
"Hex files (*.hex)|*.hex|All files|*.*");
p->hex_picker->GetPickerCtrl()->SetLabelText(_(L("Browse")));
diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp
index 3d16c7244..5edc321f7 100644
--- a/src/slic3r/GUI/GCodeViewer.cpp
+++ b/src/slic3r/GUI/GCodeViewer.cpp
@@ -47,32 +47,6 @@ static EMoveType buffer_type(unsigned char id) {
return static_cast<EMoveType>(static_cast<unsigned char>(EMoveType::Retract) + id);
}
-static std::array<float, 4> decode_color(const std::string& color) {
- static const float INV_255 = 1.0f / 255.0f;
-
- std::array<float, 4> ret = { 0.0f, 0.0f, 0.0f, 1.0f };
- const char* c = color.data() + 1;
- if (color.size() == 7 && color.front() == '#') {
- for (size_t j = 0; j < 3; ++j) {
- int digit1 = hex_digit_to_int(*c++);
- int digit2 = hex_digit_to_int(*c++);
- if (digit1 == -1 || digit2 == -1)
- break;
-
- ret[j] = float(digit1 * 16 + digit2) * INV_255;
- }
- }
- return ret;
-}
-
-static std::vector<std::array<float, 4>> decode_colors(const std::vector<std::string>& colors) {
- std::vector<std::array<float, 4>> output(colors.size(), { 0.0f, 0.0f, 0.0f, 1.0f });
- for (size_t i = 0; i < colors.size(); ++i) {
- output[i] = decode_color(colors[i]);
- }
- return output;
-}
-
// Round to a bin with minimum two digits resolution.
// Equivalent to conversion to string with sprintf(buf, "%.2g", value) and conversion back to float, but faster.
static float round_to_bin(const float value)
@@ -197,9 +171,9 @@ float GCodeViewer::Extrusions::Range::step_size(EType type) const
}
}
-GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value, EType type) const
+ColorRGBA GCodeViewer::Extrusions::Range::get_color_at(float value, EType type) const
#else
-GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) const
+ColorRGBA GCodeViewer::Extrusions::Range::get_color_at(float value) const
#endif // ENABLE_PREVIEW_LAYER_TIME
{
// Input value scaled to the colors range
@@ -222,18 +196,11 @@ GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) con
const size_t color_max_idx = Range_Colors.size() - 1;
// Compute the two colors just below (low) and above (high) the input value
- const size_t color_low_idx = std::clamp<size_t>(static_cast<size_t>(global_t), 0, color_max_idx);
+ const size_t color_low_idx = std::clamp<size_t>(static_cast<size_t>(global_t), 0, color_max_idx);
const size_t color_high_idx = std::clamp<size_t>(color_low_idx + 1, 0, color_max_idx);
- // Compute how far the value is between the low and high colors so that they can be interpolated
- const float local_t = std::clamp(global_t - static_cast<float>(color_low_idx), 0.0f, 1.0f);
-
// Interpolate between the low and high colors to find exactly which color the input value should get
- Color ret = { 0.0f, 0.0f, 0.0f, 1.0f };
- for (unsigned int i = 0; i < 3; ++i) {
- ret[i] = lerp(Range_Colors[color_low_idx][i], Range_Colors[color_high_idx][i], local_t);
- }
- return ret;
+ return lerp(Range_Colors[color_low_idx], Range_Colors[color_high_idx], global_t - static_cast<float>(color_low_idx));
}
GCodeViewer::SequentialRangeCap::~SequentialRangeCap() {
@@ -311,12 +278,7 @@ void GCodeViewer::SequentialView::Marker::render() const
if (width != last_window_width || length != last_text_length) {
last_window_width = width;
last_text_length = length;
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
imgui.set_requires_extra_frame();
-#else
- wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
- wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
}
imgui.end();
@@ -383,11 +345,11 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
return ret;
};
- static const ImVec4 LINE_NUMBER_COLOR = ImGuiWrapper::COL_ORANGE_LIGHT;
+ static const ImVec4 LINE_NUMBER_COLOR = ImGuiWrapper::COL_ORANGE_LIGHT;
static const ImVec4 SELECTION_RECT_COLOR = ImGuiWrapper::COL_ORANGE_DARK;
- static const ImVec4 COMMAND_COLOR = { 0.8f, 0.8f, 0.0f, 1.0f };
- static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
- static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
+ static const ImVec4 COMMAND_COLOR = { 0.8f, 0.8f, 0.0f, 1.0f };
+ static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
+ static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
if (!m_visible || m_filename.empty() || m_lines_ends.empty() || curr_line_id == 0)
return;
@@ -512,7 +474,7 @@ void GCodeViewer::SequentialView::render(float legend_height) const
gcode_window.render(legend_height, bottom, static_cast<uint64_t>(gcode_ids[current.last]));
}
-const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors {{
+const std::vector<ColorRGBA> GCodeViewer::Extrusion_Role_Colors{ {
{ 0.90f, 0.70f, 0.70f, 1.0f }, // erNone
{ 1.00f, 0.90f, 0.30f, 1.0f }, // erPerimeter
{ 1.00f, 0.49f, 0.22f, 1.0f }, // erExternalPerimeter
@@ -531,7 +493,7 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors {{
{ 0.00f, 0.00f, 0.00f, 1.0f } // erMixed
}};
-const std::vector<GCodeViewer::Color> GCodeViewer::Options_Colors {{
+const std::vector<ColorRGBA> GCodeViewer::Options_Colors{ {
{ 0.803f, 0.135f, 0.839f, 1.0f }, // Retractions
{ 0.287f, 0.679f, 0.810f, 1.0f }, // Unretractions
{ 0.900f, 0.900f, 0.900f, 1.0f }, // Seams
@@ -541,7 +503,7 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Options_Colors {{
{ 0.886f, 0.825f, 0.262f, 1.0f } // CustomGCodes
}};
-const std::vector<GCodeViewer::Color> GCodeViewer::Travel_Colors {{
+const std::vector<ColorRGBA> GCodeViewer::Travel_Colors{ {
{ 0.219f, 0.282f, 0.609f, 1.0f }, // Move
{ 0.112f, 0.422f, 0.103f, 1.0f }, // Extrude
{ 0.505f, 0.064f, 0.028f, 1.0f } // Retract
@@ -549,7 +511,7 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Travel_Colors {{
#if 1
// Normal ranges
-const std::vector<GCodeViewer::Color> GCodeViewer::Range_Colors {{
+const std::vector<ColorRGBA> GCodeViewer::Range_Colors{ {
{ 0.043f, 0.173f, 0.478f, 1.0f }, // bluish
{ 0.075f, 0.349f, 0.522f, 1.0f },
{ 0.110f, 0.533f, 0.569f, 1.0f },
@@ -564,7 +526,7 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Range_Colors {{
}};
#else
// Detailed ranges
-const std::vector<GCodeViewer::Color> GCodeViewer::Range_Colors{ {
+const std::vector<ColorRGBA> GCodeViewer::Range_Colors{ {
{ 0.043f, 0.173f, 0.478f, 1.0f }, // bluish
{ 0.5f * (0.043f + 0.075f), 0.5f * (0.173f + 0.349f), 0.5f * (0.478f + 0.522f), 1.0f },
{ 0.075f, 0.349f, 0.522f, 1.0f },
@@ -589,8 +551,8 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Range_Colors{ {
} };
#endif
-const GCodeViewer::Color GCodeViewer::Wipe_Color = { 1.0f, 1.0f, 0.0f, 1.0f };
-const GCodeViewer::Color GCodeViewer::Neutral_Color = { 0.25f, 0.25f, 0.25f, 1.0f };
+const ColorRGBA GCodeViewer::Wipe_Color = ColorRGBA::YELLOW();
+const ColorRGBA GCodeViewer::Neutral_Color = ColorRGBA::DARK_GRAY();
GCodeViewer::GCodeViewer()
{
@@ -761,14 +723,17 @@ void GCodeViewer::refresh(const GCodeProcessorResult& gcode_result, const std::v
if (m_view_type == EViewType::Tool && !gcode_result.extruder_colors.empty())
// update tool colors from config stored in the gcode
- m_tool_colors = decode_colors(gcode_result.extruder_colors);
+ decode_colors(gcode_result.extruder_colors, m_tool_colors);
else
// update tool colors
- m_tool_colors = decode_colors(str_tool_colors);
+ decode_colors(str_tool_colors, m_tool_colors);
+
+ ColorRGBA default_color;
+ decode_color("#FF8000", default_color);
// ensure there are enough colors defined
while (m_tool_colors.size() < std::max(size_t(1), gcode_result.extruders_count))
- m_tool_colors.push_back(decode_color("#FF8000"));
+ m_tool_colors.push_back(default_color);
// update ranges for coloring / legend
m_extrusions.reset_ranges();
@@ -850,7 +815,7 @@ void GCodeViewer::reset()
m_paths_bounding_box = BoundingBoxf3();
m_max_bounding_box = BoundingBoxf3();
m_max_print_height = 0.0f;
- m_tool_colors = std::vector<Color>();
+ m_tool_colors = std::vector<ColorRGBA>();
m_extruders_count = 0;
m_extruder_ids = std::vector<unsigned char>();
m_filament_diameters = std::vector<float>();
@@ -1040,7 +1005,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
return;
// collect color information to generate materials
- std::vector<Color> colors;
+ std::vector<ColorRGBA> colors;
for (const RenderPath& path : t_buffer.render_paths) {
colors.push_back(path.color);
}
@@ -1062,10 +1027,10 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
fprintf(fp, "# Generated by %s-%s based on Slic3r\n", SLIC3R_APP_NAME, SLIC3R_VERSION);
unsigned int colors_count = 1;
- for (const Color& color : colors) {
+ for (const ColorRGBA& color : colors) {
fprintf(fp, "\nnewmtl material_%d\n", colors_count++);
fprintf(fp, "Ka 1 1 1\n");
- fprintf(fp, "Kd %g %g %g\n", color[0], color[1], color[2]);
+ fprintf(fp, "Kd %g %g %g\n", color.r(), color.g(), color.b());
fprintf(fp, "Ks 0 0 0\n");
}
@@ -1126,7 +1091,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
}
size_t i = 0;
- for (const Color& color : colors) {
+ for (const ColorRGBA& color : colors) {
// save material triangles to file
fprintf(fp, "\nusemtl material_%zu\n", i + 1);
fprintf(fp, "# triangles material %zu\n", i + 1);
@@ -2097,6 +2062,16 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
sort_remove_duplicates(m_extruder_ids);
m_extruder_ids.shrink_to_fit();
+#if ENABLE_SPIRAL_VASE_LAYERS
+ // replace layers for spiral vase mode
+ if (!gcode_result.spiral_vase_layers.empty()) {
+ m_layers.reset();
+ for (const auto& layer : gcode_result.spiral_vase_layers) {
+ m_layers.append(layer.first, { layer.second.first, layer.second.second });
+ }
+ }
+#endif // ENABLE_SPIRAL_VASE_LAYERS
+
// set layers z range
if (!m_layers.empty())
m_layers_z_range = { 0, static_cast<unsigned int>(m_layers.size() - 1) };
@@ -2178,7 +2153,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
for (GLVolume* volume : m_shells.volumes.volumes) {
volume->zoom_to_volumes = false;
- volume->color[3] = 0.25f;
+ volume->color.a(0.25f);
volume->force_native_color = true;
volume->set_render_color();
}
@@ -2191,7 +2166,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#endif // ENABLE_GCODE_VIEWER_STATISTICS
auto extrusion_color = [this](const Path& path) {
- Color color;
+ ColorRGBA color;
switch (m_view_type)
{
case EViewType::FeatureType: { color = Extrusion_Role_Colors[static_cast<unsigned int>(path.role)]; break; }
@@ -2224,13 +2199,13 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
case EViewType::Tool: { color = m_tool_colors[path.extruder_id]; break; }
case EViewType::ColorPrint: {
if (path.cp_color_id >= static_cast<unsigned char>(m_tool_colors.size()))
- color = { 0.5f, 0.5f, 0.5f, 1.0f };
+ color = ColorRGBA::GRAY();
else
color = m_tool_colors[path.cp_color_id];
break;
}
- default: { color = { 1.0f, 1.0f, 1.0f, 1.0f }; break; }
+ default: { color = ColorRGBA::WHITE(); break; }
}
return color;
@@ -2429,7 +2404,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (m_sequential_view.current.last < sub_path.first.s_id || sub_path.last.s_id < m_sequential_view.current.first)
continue;
- Color color;
+ ColorRGBA color;
switch (path.type)
{
case EMoveType::Tool_change:
@@ -3081,7 +3056,7 @@ void GCodeViewer::render_legend(float& legend_height)
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
- auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
+ auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const ColorRGBA& color, const std::string& label,
bool visible = true, const std::string& time = "", float percent = 0.0f, float max_percent = 0.0f, const std::array<float, 4>& offsets = { 0.0f, 0.0f, 0.0f, 0.0f },
double used_filament_m = 0.0, double used_filament_g = 0.0,
std::function<void()> callback = nullptr) {
@@ -3094,21 +3069,21 @@ void GCodeViewer::render_legend(float& legend_height)
default:
case EItemType::Rect: {
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color));
break;
}
case EItemType::Circle: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
- draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
+ draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGuiWrapper::to_ImU32(color), 16);
break;
}
case EItemType::Hexagon: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
- draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6);
+ draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGuiWrapper::to_ImU32(color), 6);
break;
}
case EItemType::Line: {
- draw_list->AddLine({ pos.x + 1, pos.y + icon_size - 1 }, { pos.x + icon_size - 1, pos.y + 1 }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f);
+ draw_list->AddLine({ pos.x + 1, pos.y + icon_size - 1 }, { pos.x + icon_size - 1, pos.y + 1 }, ImGuiWrapper::to_ImU32(color), 3.0f);
break;
}
}
@@ -3133,12 +3108,7 @@ void GCodeViewer::render_legend(float& legend_height)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f);
// to avoid the tooltip to change size when moving the mouse
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
imgui.set_requires_extra_frame();
-#else
- wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
- wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
}
}
@@ -3283,7 +3253,7 @@ void GCodeViewer::render_legend(float& legend_height)
};
auto color_print_ranges = [this](unsigned char extruder_id, const std::vector<CustomGCode::Item>& custom_gcode_per_print_z) {
- std::vector<std::pair<Color, std::pair<double, double>>> ret;
+ std::vector<std::pair<ColorRGBA, std::pair<double, double>>> ret;
ret.reserve(custom_gcode_per_print_z.size());
for (const auto& item : custom_gcode_per_print_z) {
@@ -3302,8 +3272,11 @@ void GCodeViewer::render_legend(float& legend_height)
const double previous_z = (lower_b == zs.begin()) ? 0.0 : *(--lower_b);
// to avoid duplicate values, check adding values
- if (ret.empty() || !(ret.back().second.first == previous_z && ret.back().second.second == current_z))
- ret.push_back({ decode_color(item.color), { previous_z, current_z } });
+ if (ret.empty() || !(ret.back().second.first == previous_z && ret.back().second.second == current_z)) {
+ ColorRGBA color;
+ decode_color(item.color, color);
+ ret.push_back({ color, { previous_z, current_z } });
+ }
}
return ret;
@@ -3562,11 +3535,10 @@ void GCodeViewer::render_legend(float& legend_height)
if (need_scrollable)
ImGui::BeginChild("color_prints", { -1.0f, child_height }, false);
if (m_extruders_count == 1) { // single extruder use case
- const std::vector<std::pair<Color, std::pair<double, double>>> cp_values = color_print_ranges(0, custom_gcode_per_print_z);
+ const std::vector<std::pair<ColorRGBA, std::pair<double, double>>> cp_values = color_print_ranges(0, custom_gcode_per_print_z);
const int items_cnt = static_cast<int>(cp_values.size());
- if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode
+ if (items_cnt == 0) // There are no color changes, but there are some pause print or custom Gcode
append_item(EItemType::Rect, m_tool_colors.front(), _u8L("Default color"));
- }
else {
for (int i = items_cnt; i >= 0; --i) {
// create label for color change item
@@ -3585,11 +3557,11 @@ void GCodeViewer::render_legend(float& legend_height)
else { // multi extruder use case
// shows only extruders actually used
for (unsigned char i : m_extruder_ids) {
- const std::vector<std::pair<Color, std::pair<double, double>>> cp_values = color_print_ranges(i, custom_gcode_per_print_z);
+ const std::vector<std::pair<ColorRGBA, std::pair<double, double>>> cp_values = color_print_ranges(i, custom_gcode_per_print_z);
const int items_cnt = static_cast<int>(cp_values.size());
- if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode
+ if (items_cnt == 0)
+ // There are no color changes, but there are some pause print or custom Gcode
append_item(EItemType::Rect, m_tool_colors[i], _u8L("Extruder") + " " + std::to_string(i + 1) + " " + _u8L("default color"));
- }
else {
for (int j = items_cnt; j >= 0; --j) {
// create label for color change item
@@ -3638,10 +3610,10 @@ void GCodeViewer::render_legend(float& legend_height)
};
EType type;
int extruder_id;
- Color color1;
- Color color2;
+ ColorRGBA color1;
+ ColorRGBA color2;
Times times;
- std::pair<double, double> used_filament {0.0f, 0.0f};
+ std::pair<double, double> used_filament{ 0.0f, 0.0f };
};
using PartialTimes = std::vector<PartialTime>;
@@ -3650,7 +3622,7 @@ void GCodeViewer::render_legend(float& legend_height)
std::vector<CustomGCode::Item> custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z;
int extruders_count = wxGetApp().extruders_edited_cnt();
- std::vector<Color> last_color(extruders_count);
+ std::vector<ColorRGBA> last_color(extruders_count);
for (int i = 0; i < extruders_count; ++i) {
last_color[i] = m_tool_colors[i];
}
@@ -3662,8 +3634,8 @@ void GCodeViewer::render_legend(float& legend_height)
case CustomGCode::PausePrint: {
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
- items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], Color(), time_rec.second });
- items.push_back({ PartialTime::EType::Pause, it->extruder, Color(), Color(), time_rec.second });
+ items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], ColorRGBA::BLACK(), time_rec.second });
+ items.push_back({ PartialTime::EType::Pause, it->extruder, ColorRGBA::BLACK(), ColorRGBA::BLACK(), time_rec.second });
custom_gcode_per_print_z.erase(it);
}
break;
@@ -3671,14 +3643,16 @@ void GCodeViewer::render_legend(float& legend_height)
case CustomGCode::ColorChange: {
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
- items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], Color(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], it->extruder-1) });
- items.push_back({ PartialTime::EType::ColorChange, it->extruder, last_color[it->extruder - 1], decode_color(it->color), time_rec.second });
- last_color[it->extruder - 1] = decode_color(it->color);
+ items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], it->extruder - 1) });
+ ColorRGBA color;
+ decode_color(it->color, color);
+ items.push_back({ PartialTime::EType::ColorChange, it->extruder, last_color[it->extruder - 1], color, time_rec.second });
+ last_color[it->extruder - 1] = color;
last_extruder_id = it->extruder;
custom_gcode_per_print_z.erase(it);
}
else
- items.push_back({ PartialTime::EType::Print, last_extruder_id, last_color[last_extruder_id - 1], Color(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], last_extruder_id -1) });
+ items.push_back({ PartialTime::EType::Print, last_extruder_id, last_color[last_extruder_id - 1], ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], last_extruder_id - 1) });
break;
}
@@ -3689,7 +3663,7 @@ void GCodeViewer::render_legend(float& legend_height)
return items;
};
- auto append_color_change = [&imgui](const Color& color1, const Color& color2, const std::array<float, 4>& offsets, const Times& times) {
+ auto append_color_change = [&imgui](const ColorRGBA& color1, const ColorRGBA& color2, const std::array<float, 4>& offsets, const Times& times) {
imgui.text(_u8L("Color change"));
ImGui::SameLine();
@@ -3699,16 +3673,16 @@ void GCodeViewer::render_legend(float& legend_height)
pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color1[0], color1[1], color1[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color1));
pos.x += icon_size;
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color2[0], color2[1], color2[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color2));
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(times.second - times.first)));
};
- auto append_print = [&imgui, imperial_units](const Color& color, const std::array<float, 4>& offsets, const Times& times, std::pair<double, double> used_filament) {
+ auto append_print = [&imgui, imperial_units](const ColorRGBA& color, const std::array<float, 4>& offsets, const Times& times, std::pair<double, double> used_filament) {
imgui.text(_u8L("Print"));
ImGui::SameLine();
@@ -3718,7 +3692,7 @@ void GCodeViewer::render_legend(float& legend_height)
pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color));
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(times.second)));
@@ -3994,12 +3968,7 @@ void GCodeViewer::render_legend(float& legend_height)
if (m_view_type == EViewType::LayerTimeLinear || m_view_type == EViewType::LayerTimeLogarithmic)
refresh_render_paths(false, false);
#endif // ENABLE_PREVIEW_LAYER_TIME
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
imgui.set_requires_extra_frame();
-#else
- wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
- wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
}
}
};
@@ -4344,7 +4313,7 @@ void GCodeViewer::log_memory_used(const std::string& label, int64_t additional)
}
}
-GCodeViewer::Color GCodeViewer::option_color(EMoveType move_type) const
+ColorRGBA GCodeViewer::option_color(EMoveType move_type) const
{
switch (move_type)
{
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index d6371df89..f7adcc9eb 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -22,7 +22,6 @@ namespace GUI {
class GCodeViewer
{
using IBufferType = unsigned short;
- using Color = std::array<float, 4>;
using VertexBuffer = std::vector<float>;
using MultiVertexBuffer = std::vector<VertexBuffer>;
using IndexBuffer = std::vector<IBufferType>;
@@ -31,12 +30,12 @@ class GCodeViewer
using InstanceIdBuffer = std::vector<size_t>;
using InstancesOffsets = std::vector<Vec3f>;
- static const std::vector<Color> Extrusion_Role_Colors;
- static const std::vector<Color> Options_Colors;
- static const std::vector<Color> Travel_Colors;
- static const std::vector<Color> Range_Colors;
- static const Color Wipe_Color;
- static const Color Neutral_Color;
+ static const std::vector<ColorRGBA> Extrusion_Role_Colors;
+ static const std::vector<ColorRGBA> Options_Colors;
+ static const std::vector<ColorRGBA> Travel_Colors;
+ static const std::vector<ColorRGBA> Range_Colors;
+ static const ColorRGBA Wipe_Color;
+ static const ColorRGBA Neutral_Color;
enum class EOptionsColors : unsigned char
{
@@ -121,7 +120,7 @@ class GCodeViewer
// vbo id
unsigned int vbo{ 0 };
// Color to apply to the instances
- Color color;
+ ColorRGBA color;
};
std::vector<Range> ranges;
@@ -243,7 +242,7 @@ class GCodeViewer
// Index of the parent tbuffer
unsigned char tbuffer_id;
// Render path property
- Color color;
+ ColorRGBA color;
// Index of the buffer in TBuffer::indices
unsigned int ibuffer_id;
// Render path content
@@ -263,12 +262,10 @@ class GCodeViewer
bool operator() (const RenderPath &l, const RenderPath &r) const {
if (l.tbuffer_id < r.tbuffer_id)
return true;
- for (int i = 0; i < 3; ++i) {
- if (l.color[i] < r.color[i])
- return true;
- else if (l.color[i] > r.color[i])
- return false;
- }
+ if (l.color < r.color)
+ return true;
+ else if (l.color > r.color)
+ return false;
return l.ibuffer_id < r.ibuffer_id;
}
};
@@ -299,7 +296,7 @@ class GCodeViewer
struct Model
{
GLModel model;
- Color color;
+ ColorRGBA color;
InstanceVBuffer instances;
GLModel::InitializationData data;
@@ -408,10 +405,10 @@ class GCodeViewer
#if ENABLE_PREVIEW_LAYER_TIME
float step_size(EType type = EType::Linear) const;
- Color get_color_at(float value, EType type = EType::Linear) const;
+ ColorRGBA get_color_at(float value, EType type = EType::Linear) const;
#else
float step_size() const { return (max - min) / (static_cast<float>(Range_Colors.size()) - 1.0f); }
- Color get_color_at(float value) const;
+ ColorRGBA get_color_at(float value) const;
#endif // ENABLE_PREVIEW_LAYER_TIME
};
@@ -471,6 +468,7 @@ class GCodeViewer
size_t last{ 0 };
bool operator == (const Range& other) const { return first == other.first && last == other.last; }
+ bool operator != (const Range& other) const { return !operator==(other); }
bool contains(size_t id) const { return first <= id && id <= last; }
};
@@ -500,9 +498,8 @@ class GCodeViewer
bool operator != (const Layers& other) const {
if (m_zs != other.m_zs)
return true;
- if (!(m_ranges == other.m_ranges))
+ if (m_ranges != other.m_ranges)
return true;
-
return false;
}
};
@@ -514,7 +511,7 @@ class GCodeViewer
TBuffer* buffer{ nullptr };
unsigned int ibo{ 0 };
unsigned int vbo{ 0 };
- Color color;
+ ColorRGBA color;
~SequentialRangeCap();
bool is_renderable() const { return buffer != nullptr; }
@@ -722,7 +719,7 @@ private:
// bounding box of toolpaths + marker tools
BoundingBoxf3 m_max_bounding_box;
float m_max_print_height{ 0.0f };
- std::vector<Color> m_tool_colors;
+ std::vector<ColorRGBA> m_tool_colors;
Layers m_layers;
std::array<unsigned int, 2> m_layers_z_range;
std::vector<ExtrusionRole> m_roles;
@@ -838,7 +835,7 @@ private:
}
bool is_visible(const Path& path) const { return is_visible(path.role); }
void log_memory_used(const std::string& label, int64_t additional = 0) const;
- Color option_color(EMoveType move_type) const;
+ ColorRGBA option_color(EMoveType move_type) const;
};
} // namespace GUI
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index b03206090..fb22f9099 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -72,11 +72,10 @@
static constexpr const float TRACKBALLSIZE = 0.8f;
-static constexpr const float DEFAULT_BG_DARK_COLOR[3] = { 0.478f, 0.478f, 0.478f };
-static constexpr const float DEFAULT_BG_LIGHT_COLOR[3] = { 0.753f, 0.753f, 0.753f };
-static constexpr const float ERROR_BG_DARK_COLOR[3] = { 0.478f, 0.192f, 0.039f };
-static constexpr const float ERROR_BG_LIGHT_COLOR[3] = { 0.753f, 0.192f, 0.039f };
-//static constexpr const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } };
+static const Slic3r::ColorRGB DEFAULT_BG_DARK_COLOR = { 0.478f, 0.478f, 0.478f };
+static const Slic3r::ColorRGB DEFAULT_BG_LIGHT_COLOR = { 0.753f, 0.753f, 0.753f };
+static const Slic3r::ColorRGB ERROR_BG_DARK_COLOR = { 0.478f, 0.192f, 0.039f };
+static const Slic3r::ColorRGB ERROR_BG_LIGHT_COLOR = { 0.753f, 0.192f, 0.039f };
// Number of floats
static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB
@@ -731,13 +730,8 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
}
// force re-render while the windows gets to its final size (it takes several frames)
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
if (ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x)
imgui.set_requires_extra_frame();
-#else
- if (ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x)
- m_canvas.request_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
imgui.end();
ImGui::PopStyleColor();
@@ -783,13 +777,8 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas
ImGui::TextUnformatted(m_text.c_str());
// force re-render while the windows gets to its final size (it may take several frames) or while hidden
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
if (alpha < 1.0f || ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x)
imgui.set_requires_extra_frame();
-#else
- if (alpha < 1.0f || ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x)
- canvas.request_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
size = ImGui::GetWindowSize();
@@ -859,8 +848,8 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons
void GLCanvas3D::SequentialPrintClearance::render()
{
- std::array<float, 4> FILL_COLOR = { 1.0f, 0.0f, 0.0f, 0.5f };
- std::array<float, 4> NO_FILL_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f };
+ const ColorRGBA FILL_COLOR = { 1.0f, 0.0f, 0.0f, 0.5f };
+ const ColorRGBA NO_FILL_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f };
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
@@ -1126,10 +1115,9 @@ void GLCanvas3D::reset_volumes()
ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state() const
{
- assert(m_initialized);
-
- ModelInstanceEPrintVolumeState state;
- m_volumes.check_outside_state(m_bed.build_volume(), &state);
+ ModelInstanceEPrintVolumeState state = ModelInstanceEPrintVolumeState::ModelInstancePVS_Inside;
+ if (m_initialized)
+ m_volumes.check_outside_state(m_bed.build_volume(), &state);
return state;
}
@@ -1303,15 +1291,6 @@ bool GLCanvas3D::is_reload_delayed() const
void GLCanvas3D::enable_layers_editing(bool enable)
{
m_layers_editing.set_enabled(enable);
-#if !ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
- const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
- for (unsigned int idx : idxs) {
- GLVolume* v = m_volumes.volumes[idx];
- if (v->is_modifier)
- v->force_transparent = enable;
- }
-#endif // !ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
-
set_as_dirty();
}
@@ -2263,29 +2242,20 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this);
auto gizmo = wxGetApp().plater()->canvas3D()->get_gizmos_manager().get_current();
if (gizmo != nullptr) m_dirty |= gizmo->update_items_state();
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
// ImGuiWrapper::m_requires_extra_frame may have been set by a render made outside of the OnIdle mechanism
bool imgui_requires_extra_frame = wxGetApp().imgui()->requires_extra_frame();
m_dirty |= imgui_requires_extra_frame;
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
if (!m_dirty)
return;
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
// this needs to be done here.
// during the render launched by the refresh the value may be set again
wxGetApp().imgui()->reset_requires_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
_refresh_if_shown_on_screen();
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
if (m_extra_frame_requested || mouse3d_controller_applied || imgui_requires_extra_frame || wxGetApp().imgui()->requires_extra_frame()) {
-#else
- if (m_extra_frame_requested || mouse3d_controller_applied) {
- m_dirty = true;
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_extra_frame_requested = false;
evt.RequestMore();
}
@@ -4144,9 +4114,6 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
return ret;
};
- static const std::array<float, 4> orange = { 0.923f, 0.504f, 0.264f, 1.0f };
- static const std::array<float, 4> gray = { 0.64f, 0.64f, 0.64f, 1.0f };
-
GLVolumePtrs visible_volumes;
for (GLVolume* vol : volumes.volumes) {
@@ -4201,7 +4168,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
shader->set_uniform("emission_factor", 0.0f);
for (GLVolume* vol : visible_volumes) {
- shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : orange) : gray);
+ shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
// the volume may have been deactivated by an active gizmo
bool is_active = vol->is_active;
vol->is_active = true;
@@ -4932,19 +4899,20 @@ void GLCanvas3D::_picking_pass()
int volume_id = -1;
int gizmo_id = -1;
- GLubyte color[4] = { 0, 0, 0, 0 };
+ std::array<GLubyte, 4> color = { 0, 0, 0, 0 };
const Size& cnv_size = get_canvas_size();
bool inside = 0 <= m_mouse.position(0) && m_mouse.position(0) < cnv_size.get_width() && 0 <= m_mouse.position(1) && m_mouse.position(1) < cnv_size.get_height();
if (inside) {
- glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
+ glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position.y() - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color.data()));
if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3]) {
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
// we reserve color = (0,0,0) for occluders (as the printbed)
// volumes' id are shifted by 1
// see: _render_volumes_for_picking()
- volume_id = color[0] + (color[1] << 8) + (color[2] << 16) - 1;
+ unsigned int id = picking_encode(color[0], color[1], color[2]);
+ volume_id = id - 1;
// gizmos' id are instead properly encoded by the color
- gizmo_id = color[0] + (color[1] << 8) + (color[2] << 16);
+ gizmo_id = id;
}
}
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) {
@@ -5060,19 +5028,11 @@ void GLCanvas3D::_render_background() const
glsafe(::glDisable(GL_DEPTH_TEST));
::glBegin(GL_QUADS);
- if (use_error_color)
- ::glColor3fv(ERROR_BG_DARK_COLOR);
- else
- ::glColor3fv(DEFAULT_BG_DARK_COLOR);
-
+ ::glColor3fv(use_error_color ? ERROR_BG_DARK_COLOR.data(): DEFAULT_BG_DARK_COLOR.data());
::glVertex2f(-1.0f, -1.0f);
::glVertex2f(1.0f, -1.0f);
- if (use_error_color)
- ::glColor3fv(ERROR_BG_LIGHT_COLOR);
- else
- ::glColor3fv(DEFAULT_BG_LIGHT_COLOR);
-
+ ::glColor3fv(use_error_color ? ERROR_BG_LIGHT_COLOR.data() : DEFAULT_BG_LIGHT_COLOR.data());
::glVertex2f(1.0f, 1.0f);
::glVertex2f(-1.0f, 1.0f);
glsafe(::glEnd());
@@ -5355,8 +5315,6 @@ void GLCanvas3D::_render_overlays()
void GLCanvas3D::_render_volumes_for_picking() const
{
- static const GLfloat INV_255 = 1.0f / 255.0f;
-
// do not cull backfaces to show broken geometry, if any
glsafe(::glDisable(GL_CULL_FACE));
@@ -5371,13 +5329,9 @@ void GLCanvas3D::_render_volumes_for_picking() const
// Object picking mode. Render the object with a color encoding the object index.
// we reserve color = (0,0,0) for occluders (as the printbed)
// so we shift volumes' id by 1 to get the proper color
- unsigned int id = 1 + volume.second.first;
- unsigned int r = (id & (0x000000FF << 0)) << 0;
- unsigned int g = (id & (0x000000FF << 8)) >> 8;
- unsigned int b = (id & (0x000000FF << 16)) >> 16;
- unsigned int a = picking_checksum_alpha_channel(r, g, b);
- glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255));
- volume.first->render();
+ const unsigned int id = 1 + volume.second.first;
+ glsafe(::glColor4fv(picking_decode(id).data()));
+ volume.first->render();
}
}
@@ -5796,7 +5750,7 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume)
if (!print->has_skirt() && !print->has_brim())
return;
- const std::array<float, 4> color = { 0.5f, 1.0f, 0.5f, 1.0f }; // greenish
+ const ColorRGBA color = ColorRGBA::GREENISH();
// number of skirt layers
size_t total_layer_count = 0;
@@ -5843,7 +5797,8 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume)
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
{
- std::vector<std::array<float, 4>> tool_colors = _parse_colors(str_tool_colors);
+ std::vector<ColorRGBA> tool_colors;
+ decode_colors(str_tool_colors, tool_colors);
struct Ctxt
{
@@ -5852,20 +5807,20 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
bool has_perimeters;
bool has_infill;
bool has_support;
- const std::vector<std::array<float, 4>>* tool_colors;
+ const std::vector<ColorRGBA>* tool_colors;
bool is_single_material_print;
int extruders_cnt;
const std::vector<CustomGCode::Item>* color_print_values;
- static const std::array<float, 4>& color_perimeters() { static std::array<float, 4> color = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow
- static const std::array<float, 4>& color_infill() { static std::array<float, 4> color = { 1.0f, 0.5f, 0.5f, 1.f }; return color; } // redish
- static const std::array<float, 4>& color_support() { static std::array<float, 4> color = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish
- static const std::array<float, 4>& color_pause_or_custom_code() { static std::array<float, 4> color = { 0.5f, 0.5f, 0.5f, 1.f }; return color; } // gray
+ static ColorRGBA color_perimeters() { return ColorRGBA::YELLOW(); }
+ static ColorRGBA color_infill() { return ColorRGBA::REDISH(); }
+ static ColorRGBA color_support() { return ColorRGBA::GREENISH(); }
+ static ColorRGBA color_pause_or_custom_code() { return ColorRGBA::GRAY(); }
// For cloring by a tool, return a parsed color.
bool color_by_tool() const { return tool_colors != nullptr; }
size_t number_tools() const { return color_by_tool() ? tool_colors->size() : 0; }
- const std::array<float, 4>& color_tool(size_t tool) const { return (*tool_colors)[tool]; }
+ const ColorRGBA& color_tool(size_t tool) const { return (*tool_colors)[tool]; }
// For coloring by a color_print(M600), return a parsed color.
bool color_by_color_print() const { return color_print_values!=nullptr; }
@@ -6005,7 +5960,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
//FIXME Improve the heuristics for a grain size.
size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1));
tbb::spin_mutex new_volume_mutex;
- auto new_volume = [this, &new_volume_mutex](const std::array<float, 4>& color) {
+ auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) {
// Allocate the volume before locking.
GLVolume *volume = new GLVolume(color);
volume->is_extrusion_path = true;
@@ -6146,21 +6101,22 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
if (!print->is_step_done(psWipeTower))
return;
- std::vector<std::array<float, 4>> tool_colors = _parse_colors(str_tool_colors);
+ std::vector<ColorRGBA> tool_colors;
+ decode_colors(str_tool_colors, tool_colors);
struct Ctxt
{
const Print *print;
- const std::vector<std::array<float, 4>>* tool_colors;
+ const std::vector<ColorRGBA>* tool_colors;
Vec2f wipe_tower_pos;
float wipe_tower_angle;
- static const std::array<float, 4>& color_support() { static std::array<float, 4> color = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish
+ static ColorRGBA color_support() { return ColorRGBA::GREENISH(); }
// For cloring by a tool, return a parsed color.
bool color_by_tool() const { return tool_colors != nullptr; }
size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() : 0; }
- const std::array<float, 4>& color_tool(size_t tool) const { return (*tool_colors)[tool]; }
+ const ColorRGBA& color_tool(size_t tool) const { return (*tool_colors)[tool]; }
int volume_idx(int tool, int feature) const {
return this->color_by_tool() ? std::min<int>(this->number_tools() - 1, std::max<int>(tool, 0)) : feature;
}
@@ -6192,7 +6148,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
size_t n_items = print->wipe_tower_data().tool_changes.size() + (ctxt.priming.empty() ? 0 : 1);
size_t grain_size = std::max(n_items / 128, size_t(1));
tbb::spin_mutex new_volume_mutex;
- auto new_volume = [this, &new_volume_mutex](const std::array<float, 4>& color) {
+ auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) {
auto *volume = new GLVolume(color);
volume->is_extrusion_path = true;
tbb::spin_mutex::scoped_lock lock;
@@ -6311,7 +6267,7 @@ void GLCanvas3D::_load_sla_shells()
return;
auto add_volume = [this](const SLAPrintObject &object, int volume_id, const SLAPrintObject::Instance& instance,
- const TriangleMesh& mesh, const std::array<float, 4>& color, bool outside_printer_detection_enabled) {
+ const TriangleMesh& mesh, const ColorRGBA& color, bool outside_printer_detection_enabled) {
m_volumes.volumes.emplace_back(new GLVolume(color));
GLVolume& v = *m_volumes.volumes.back();
#if ENABLE_SMOOTH_NORMALS
@@ -6373,28 +6329,6 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
_set_warning_notification(warning, show);
}
-std::vector<std::array<float, 4>> GLCanvas3D::_parse_colors(const std::vector<std::string>& colors)
-{
- static const float INV_255 = 1.0f / 255.0f;
-
- std::vector<std::array<float, 4>> output(colors.size(), { 1.0f, 1.0f, 1.0f, 1.0f });
- for (size_t i = 0; i < colors.size(); ++i) {
- const std::string& color = colors[i];
- const char* c = color.data() + 1;
- if (color.size() == 7 && color.front() == '#') {
- for (size_t j = 0; j < 3; ++j) {
- int digit1 = hex_digit_to_int(*c++);
- int digit2 = hex_digit_to_int(*c++);
- if (digit1 == -1 || digit2 == -1)
- break;
-
- output[i][j] = float(digit1 * 16 + digit2) * INV_255;
- }
- }
- }
- return output;
-}
-
void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
{
enum ErrorType{
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 0cbd27ed0..ebffe4695 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -990,8 +990,6 @@ private:
bool _deactivate_arrange_menu();
float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); }
-
- static std::vector<std::array<float, 4>> _parse_colors(const std::vector<std::string>& colors);
};
} // namespace GUI
diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp
index 422b65408..fa804efc2 100644
--- a/src/slic3r/GUI/GLModel.cpp
+++ b/src/slic3r/GUI/GLModel.cpp
@@ -165,7 +165,7 @@ bool GLModel::init_from_file(const std::string& filename)
return true;
}
-void GLModel::set_color(int entity_id, const std::array<float, 4>& color)
+void GLModel::set_color(int entity_id, const ColorRGBA& color)
{
for (size_t i = 0; i < m_render_data.size(); ++i) {
if (entity_id == -1 || static_cast<int>(i) == entity_id)
diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp
index d47c56fd9..62722b18c 100644
--- a/src/slic3r/GUI/GLModel.hpp
+++ b/src/slic3r/GUI/GLModel.hpp
@@ -3,6 +3,7 @@
#include "libslic3r/Point.hpp"
#include "libslic3r/BoundingBox.hpp"
+#include "libslic3r/Color.hpp"
#include <vector>
#include <string>
@@ -33,7 +34,7 @@ namespace GUI {
unsigned int vbo_id{ 0 };
unsigned int ibo_id{ 0 };
size_t indices_count{ 0 };
- std::array<float, 4> color{ 1.0f, 1.0f, 1.0f, 1.0f };
+ ColorRGBA color;
};
struct InitializationData
@@ -44,7 +45,7 @@ namespace GUI {
std::vector<Vec3f> positions;
std::vector<Vec3f> normals;
std::vector<unsigned int> indices;
- std::array<float, 4> color{ 1.0f, 1.0f, 1.0f, 1.0f };
+ ColorRGBA color;
};
std::vector<Entity> entities;
@@ -74,7 +75,7 @@ namespace GUI {
bool init_from_file(const std::string& filename);
// if entity_id == -1 set the color of all entities
- void set_color(int entity_id, const std::array<float, 4>& color);
+ void set_color(int entity_id, const ColorRGBA& color);
void reset();
void render() const;
diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp
index 4c36efdd9..32b3d5960 100644
--- a/src/slic3r/GUI/GLShader.cpp
+++ b/src/slic3r/GUI/GLShader.cpp
@@ -4,6 +4,7 @@
#include "3DScene.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/format.hpp"
+#include "libslic3r/Color.hpp"
#include <boost/nowide/fstream.hpp>
#include <GL/glew.h>
@@ -306,6 +307,16 @@ void GLShaderProgram::set_uniform(int id, const Vec3d& value) const
set_uniform(id, static_cast<Vec3f>(value.cast<float>()));
}
+void GLShaderProgram::set_uniform(int id, const ColorRGB& value) const
+{
+ set_uniform(id, value.data(), 3);
+}
+
+void GLShaderProgram::set_uniform(int id, const ColorRGBA& value) const
+{
+ set_uniform(id, value.data(), 4);
+}
+
int GLShaderProgram::get_attrib_location(const char* name) const
{
assert(m_id > 0);
diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp
index 46e46b4f0..06a5c00e5 100644
--- a/src/slic3r/GUI/GLShader.hpp
+++ b/src/slic3r/GUI/GLShader.hpp
@@ -9,6 +9,9 @@
namespace Slic3r {
+class ColorRGB;
+class ColorRGBA;
+
class GLShaderProgram
{
public:
@@ -60,6 +63,8 @@ public:
void set_uniform(const char* name, const Matrix3f& value) const { set_uniform(get_uniform_location(name), value); }
void set_uniform(const char* name, const Vec3f& value) const { set_uniform(get_uniform_location(name), value); }
void set_uniform(const char* name, const Vec3d& value) const { set_uniform(get_uniform_location(name), value); }
+ void set_uniform(const char* name, const ColorRGB& value) const { set_uniform(get_uniform_location(name), value); }
+ void set_uniform(const char* name, const ColorRGBA& value) const { set_uniform(get_uniform_location(name), value); }
void set_uniform(int id, int value) const;
void set_uniform(int id, bool value) const;
@@ -77,6 +82,8 @@ public:
void set_uniform(int id, const Matrix3f& value) const;
void set_uniform(int id, const Vec3f& value) const;
void set_uniform(int id, const Vec3d& value) const;
+ void set_uniform(int id, const ColorRGB& value) const;
+ void set_uniform(int id, const ColorRGBA& value) const;
// returns -1 if not found
int get_attrib_location(const char* name) const;
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 5ebd5300a..93cd9073a 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -44,6 +44,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/I18N.hpp"
#include "libslic3r/PresetBundle.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI.hpp"
#include "GUI_Utils.hpp"
@@ -1143,15 +1144,27 @@ bool GUI_App::on_init_inner()
// Detect position (display) to show the splash screen
// Now this position is equal to the mainframe position
wxPoint splashscreen_pos = wxDefaultPosition;
- if (app_config->has("window_mainframe")) {
+ bool default_splashscreen_pos = true;
+ if (app_config->has("window_mainframe") && app_config->get("restore_win_position") == "1") {
auto metrics = WindowMetrics::deserialize(app_config->get("window_mainframe"));
- if (metrics)
+ default_splashscreen_pos = metrics == boost::none;
+ if (!default_splashscreen_pos)
splashscreen_pos = metrics->get_rect().GetPosition();
}
+ if (!default_splashscreen_pos) {
+ // workaround for crash related to the positioning of the window on secondary monitor
+ get_app_config()->set("restore_win_position", "crashed_at_splashscreen_pos");
+ get_app_config()->save();
+ }
+
// create splash screen with updated bmp
scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap("PrusaSlicer", nullptr, 400),
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 4000, splashscreen_pos);
+
+ if (!default_splashscreen_pos)
+ // revert "restore_win_position" value if application wasn't crashed
+ get_app_config()->set("restore_win_position", "1");
#ifndef __linux__
wxYield();
#endif
@@ -1308,6 +1321,35 @@ bool GUI_App::on_init_inner()
});
m_initialized = true;
+
+ if (const std::string& crash_reason = app_config->get("restore_win_position");
+ boost::starts_with(crash_reason,"crashed"))
+ {
+ wxString preferences_item = _L("Restore window position on start");
+ InfoDialog dialog(nullptr,
+ _L("PrusaSlicer is started in save mode"),
+ format_wxstr(_L("PrusaSlicer was crashed last time due to \"%1%\".\n"
+ "For more information see issues \"%2%\" and \"%3%\"\n\n"
+ "To avoid an application crash next time you have to disable\n"
+ "\"%4%\" in \"Preferences\""),
+ "<b>" + from_u8(crash_reason) + "</b>",
+ "<a href=http://github.com/prusa3d/PrusaSlicer/issues/2939>#2939</a>",
+ "<a href=http://github.com/prusa3d/PrusaSlicer/issues/5573>#5573</a>",
+ "<b>" + preferences_item + "</b>")
+ + "\n\n" +
+ format_wxstr(_L("Note: Enabling of the \"%1%\" will caused an application crash on next start."), preferences_item),
+ true, wxYES_NO);
+
+ dialog.SetButtonLabel(wxID_YES, format_wxstr(_L("Disable \"%1%\""), preferences_item));
+ dialog.SetButtonLabel(wxID_NO, format_wxstr(_L("Enable \"%1%\"") , preferences_item));
+
+ auto answer = dialog.ShowModal();
+ if (answer == wxID_YES)
+ app_config->set("restore_win_position", "0");
+ else if (answer == wxID_NO)
+ app_config->set("restore_win_position", "1");
+ }
+
return true;
}
@@ -1388,11 +1430,13 @@ void GUI_App::update_label_colours()
tab->update_label_colours();
}
+#ifdef _WIN32
static bool is_focused(HWND hWnd)
{
HWND hFocusedWnd = ::GetFocus();
return hFocusedWnd && hWnd == hFocusedWnd;
}
+#endif
void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool just_font/* = false*/)
{
@@ -1537,8 +1581,7 @@ void GUI_App::set_label_clr_modified(const wxColour& clr)
if (m_color_label_modified == clr)
return;
m_color_label_modified = clr;
- auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), clr.Red(), clr.Green(), clr.Blue());
- std::string str = clr_str.ToStdString();
+ const std::string str = encode_color(ColorRGB(clr.Red(), clr.Green(), clr.Blue()));
app_config->set("label_clr_modified", str);
app_config->save();
}
@@ -1548,8 +1591,7 @@ void GUI_App::set_label_clr_sys(const wxColour& clr)
if (m_color_label_sys == clr)
return;
m_color_label_sys = clr;
- auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), clr.Red(), clr.Green(), clr.Blue());
- std::string str = clr_str.ToStdString();
+ const std::string str = encode_color(ColorRGB(clr.Red(), clr.Green(), clr.Blue()));
app_config->set("label_clr_sys", str);
app_config->save();
}
@@ -2759,7 +2801,7 @@ wxString GUI_App::current_language_code_safe() const
void GUI_App::open_web_page_localized(const std::string &http_address)
{
- open_browser_with_warning_dialog(http_address + "&lng=" + this->current_language_code_safe());
+ open_browser_with_warning_dialog(http_address + "&lng=" + this->current_language_code_safe(), nullptr, false);
}
// If we are switching from the FFF-preset to the SLA, we should to control the printed objects if they have a part(s).
@@ -2901,8 +2943,24 @@ void GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &na
}
const wxRect& rect = metrics->get_rect();
- window->SetPosition(rect.GetPosition());
- window->SetSize(rect.GetSize());
+
+ if (app_config->get("restore_win_position") == "1") {
+ // workaround for crash related to the positioning of the window on secondary monitor
+ app_config->set("restore_win_position", (boost::format("crashed_at_%1%_pos") % name).str());
+ app_config->save();
+ window->SetPosition(rect.GetPosition());
+
+ // workaround for crash related to the positioning of the window on secondary monitor
+ app_config->set("restore_win_position", (boost::format("crashed_at_%1%_size") % name).str());
+ app_config->save();
+ window->SetSize(rect.GetSize());
+
+ // revert "restore_win_position" value if application wasn't crashed
+ app_config->set("restore_win_position", "1");
+ }
+ else
+ window->CenterOnScreen();
+
window->Maximize(metrics->get_maximized());
}
@@ -2963,19 +3021,40 @@ void GUI_App::check_updates(const bool verbose)
}
}
-bool GUI_App::open_browser_with_warning_dialog(const wxString& url, int flags/* = 0*/)
+bool GUI_App::open_browser_with_warning_dialog(const wxString& url, wxWindow* parent/* = nullptr*/, bool force_remember_choice /*= true*/, int flags/* = 0*/)
{
bool launch = true;
- if (get_app_config()->get("suppress_hyperlinks").empty()) {
- RichMessageDialog dialog(nullptr, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxICON_QUESTION | wxYES_NO);
- dialog.ShowCheckBox(_L("Remember my choice"));
- int answer = dialog.ShowModal();
- launch = answer == wxID_YES;
- get_app_config()->set("suppress_hyperlinks", dialog.IsCheckBoxChecked() ? (answer == wxID_NO ? "1" : "0") : "");
+ // warning dialog containes a "Remember my choice" checkbox
+ std::string option_key = "suppress_hyperlinks";
+ if (force_remember_choice || app_config->get(option_key).empty()) {
+ if (app_config->get(option_key).empty()) {
+ RichMessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxICON_QUESTION | wxYES_NO);
+ dialog.ShowCheckBox(_L("Remember my choice"));
+ auto answer = dialog.ShowModal();
+ launch = answer == wxID_YES;
+ if (dialog.IsCheckBoxChecked()) {
+ wxString preferences_item = _L("Suppress to open hyperlink in browser");
+ wxString msg =
+ _L("PrusaSlicer will remember your choice.") + "\n\n" +
+ _L("You will not be asked about it again on hyperlinks hovering.") + "\n\n" +
+ format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item);
+
+ MessageDialog msg_dlg(parent, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
+ if (msg_dlg.ShowModal() == wxID_CANCEL)
+ return false;
+ app_config->set(option_key, answer == wxID_NO ? "1" : "0");
+ }
+ }
+ if (launch)
+ launch = app_config->get(option_key) != "1";
+ }
+ // warning dialog doesn't containe a "Remember my choice" checkbox
+ // and will be shown only when "Suppress to open hyperlink in browser" is ON.
+ else if (app_config->get(option_key) == "1") {
+ MessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxICON_QUESTION | wxYES_NO);
+ launch = dialog.ShowModal() == wxID_YES;
}
- if (launch)
- launch = get_app_config()->get("suppress_hyperlinks") != "1";
return launch && wxLaunchDefaultBrowser(url, flags);
}
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index eddaf4a97..d3009a0fa 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -268,7 +268,8 @@ public:
virtual bool OnExceptionInMainLoop() override;
// Calls wxLaunchDefaultBrowser if user confirms in dialog.
- bool open_browser_with_warning_dialog(const wxString& url, int flags = 0);
+ // Add "Rememeber my choice" checkbox to question dialog, when it is forced or a "suppress_hyperlinks" option has empty value
+ bool open_browser_with_warning_dialog(const wxString& url, wxWindow* parent = nullptr, bool force_remember_choice = true, int flags = 0);
#ifdef __APPLE__
void OSXStoreOpenFiles(const wxArrayString &files) override;
// wxWidgets override to get an event on open files.
diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp
index 04a392169..c3aaa2f4e 100644
--- a/src/slic3r/GUI/GUI_Factories.cpp
+++ b/src/slic3r/GUI/GUI_Factories.cpp
@@ -716,7 +716,7 @@ void MenuFactory::append_menu_item_export_stl(wxMenu* menu)
[](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr,
[]() {
const Selection& selection = plater()->canvas3D()->get_selection();
- return selection.is_single_full_instance() || selection.is_single_full_object();
+ return selection.is_single_full_instance() || selection.is_single_full_object() || selection.is_single_volume() || selection.is_single_modifier();
}, m_parent);
menu->AppendSeparator();
}
@@ -792,14 +792,9 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
void MenuFactory::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu)
{
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
append_menu_item(menu, wxID_ANY, _L("Scale to print volume"), _L("Scale the selected object to fit the print volume"),
[](wxCommandEvent&) { plater()->scale_selection_to_fit_print_volume(); }, "", menu,
[]() { return plater()->can_scale_to_print_volume(); }, m_parent);
-#else
- append_menu_item(menu, wxID_ANY, _L("Scale to print volume"), _L("Scale the selected object to fit the print volume"),
- [](wxCommandEvent&) { plater()->scale_selection_to_fit_print_volume(); }, "", menu);
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
}
void MenuFactory::append_menu_items_convert_unit(wxMenu* menu, int insert_pos/* = 1*/)
diff --git a/src/slic3r/GUI/GUI_Init.cpp b/src/slic3r/GUI/GUI_Init.cpp
index 92223a767..000199f93 100644
--- a/src/slic3r/GUI/GUI_Init.cpp
+++ b/src/slic3r/GUI/GUI_Init.cpp
@@ -9,6 +9,8 @@
#include "slic3r/GUI/format.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/Plater.hpp"
+#include "slic3r/GUI/I18N.hpp"
+
// To show a message box if GUI initialization ends up with an exception thrown.
#include <wx/msgdlg.h>
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 201e5d78d..18e58efb8 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -495,7 +495,7 @@ void ObjectManipulation::update_ui_from_settings()
// update colors for edit-boxes
int axis_id = 0;
for (ManipulationEditor* editor : m_editors) {
-// editor->SetForegroundColour(m_use_colors ? wxColour(axes_color_text[axis_id]) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+// editor->SetForegroundColour(m_use_colors ? wxColour(axes_color_text[axis_id]) : wxGetApp().get_label_clr_default());
if (m_use_colors) {
editor->SetBackgroundColour(wxColour(axes_color_back[axis_id]));
if (wxGetApp().dark_mode())
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 9c8eaed4a..2cac5e356 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -795,7 +795,8 @@ void Preview::update_layers_slider_mode()
return false;
for (ModelVolume* volume : object->volumes)
- if ((volume->config.has("extruder") &&
+ if ((volume->config.has("extruder") &&
+ volume->config.option("extruder")->getInt() != 0 && // extruder isn't default
volume->config.option("extruder")->getInt() != extruder) ||
!volume->mmu_segmentation_facets.empty())
return false;
diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp
index a5ba218b5..d7d3529fe 100644
--- a/src/slic3r/GUI/GUI_Utils.hpp
+++ b/src/slic3r/GUI/GUI_Utils.hpp
@@ -406,14 +406,6 @@ public:
std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics);
-inline int hex_digit_to_int(const char c)
-{
- return
- (c >= '0' && c <= '9') ? int(c - '0') :
- (c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
- (c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
-}
-
class TaskTimer
{
std::chrono::milliseconds start_timer;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
index 97ab7094c..21b5c13e6 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
@@ -25,15 +25,9 @@ GLGizmoBase::Grabber::Grabber()
void GLGizmoBase::Grabber::render(bool hover, float size) const
{
- std::array<float, 4> render_color;
- if (hover) {
- render_color[0] = (1.0f - color[0]);
- render_color[1] = (1.0f - color[1]);
- render_color[2] = (1.0f - color[2]);
- render_color[3] = color[3];
- }
- else
- render_color = color;
+ ColorRGBA render_color = color;
+ if (hover)
+ render_color = complementary(render_color);
render(size, render_color, false);
}
@@ -48,7 +42,7 @@ float GLGizmoBase::Grabber::get_dragging_half_size(float size) const
return get_half_size(size) * DraggingScaleFactor;
}
-void GLGizmoBase::Grabber::render(float size, const std::array<float, 4>& render_color, bool picking) const
+void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color, bool picking) const
{
if (!cube.is_initialized()) {
// This cannot be done in constructor, OpenGL is not yet
@@ -99,11 +93,6 @@ void GLGizmoBase::set_hover_id(int id)
}
}
-void GLGizmoBase::set_highlight_color(const std::array<float, 4>& color)
-{
- m_highlight_color = color;
-}
-
void GLGizmoBase::enable_grabber(unsigned int id)
{
if (id < m_grabbers.size())
@@ -157,22 +146,13 @@ bool GLGizmoBase::update_items_state()
return res;
};
-std::array<float, 4> GLGizmoBase::picking_color_component(unsigned int id) const
+ColorRGBA GLGizmoBase::picking_color_component(unsigned int id) const
{
- static const float INV_255 = 1.0f / 255.0f;
-
id = BASE_ID - id;
-
if (m_group_id > -1)
id -= m_group_id;
- // color components are encoded to match the calculation of volume_id made into GLCanvas3D::_picking_pass()
- return std::array<float, 4> {
- float((id >> 0) & 0xff) * INV_255, // red
- float((id >> 8) & 0xff) * INV_255, // green
- float((id >> 16) & 0xff) * INV_255, // blue
- float(picking_checksum_alpha_channel(id & 0xff, (id >> 8) & 0xff, (id >> 16) & 0xff))* INV_255 // checksum for validating against unwanted alpha blending and multi sampling
- };
+ return picking_decode(id);
}
void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
@@ -200,8 +180,7 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) {
if (m_grabbers[i].enabled) {
- std::array<float, 4> color = picking_color_component(i);
- m_grabbers[i].color = color;
+ m_grabbers[i].color = picking_color_component(i);
m_grabbers[i].render_for_picking(mean_size);
}
}
@@ -239,22 +218,5 @@ std::string GLGizmoBase::get_name(bool include_shortcut) const
}
-
-// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
-// were not interpolated by alpha blending or multi sampling.
-unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue)
-{
- // 8 bit hash for the color
- unsigned char b = ((((37 * red) + green) & 0x0ff) * 37 + blue) & 0x0ff;
- // Increase enthropy by a bit reversal
- b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
- b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
- b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
- // Flip every second bit to increase the enthropy even more.
- b ^= 0x55;
- return b;
-}
-
-
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
index 1e2cd93fb..ca7e3f2f7 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
@@ -2,6 +2,7 @@
#define slic3r_GLGizmoBase_hpp_
#include "libslic3r/Point.hpp"
+#include "libslic3r/Color.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GLModel.hpp"
@@ -18,15 +19,11 @@ class ModelObject;
namespace GUI {
-static const std::array<float, 4> DEFAULT_BASE_COLOR = { 0.625f, 0.625f, 0.625f, 1.0f };
-static const std::array<float, 4> DEFAULT_DRAG_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
-static const std::array<float, 4> DEFAULT_HIGHLIGHT_COLOR = { 1.0f, 0.38f, 0.0f, 1.0f };
-static const std::array<std::array<float, 4>, 3> AXES_COLOR = {{
- { 0.75f, 0.0f, 0.0f, 1.0f },
- { 0.0f, 0.75f, 0.0f, 1.0f },
- { 0.0f, 0.0f, 0.75f, 1.0f }
- }};
-static const std::array<float, 4> CONSTRAINED_COLOR = { 0.5f, 0.5f, 0.5f, 1.0f };
+static const ColorRGBA DEFAULT_BASE_COLOR = { 0.625f, 0.625f, 0.625f, 1.0f };
+static const ColorRGBA DEFAULT_DRAG_COLOR = ColorRGBA::WHITE();
+static const ColorRGBA DEFAULT_HIGHLIGHT_COLOR = ColorRGBA::ORANGE();
+static const std::array<ColorRGBA, 3> AXES_COLOR = {{ ColorRGBA::X(), ColorRGBA::Y(), ColorRGBA::Z() }};
+static const ColorRGBA CONSTRAINED_COLOR = ColorRGBA::GRAY();
class ImGuiWrapper;
class GLCanvas3D;
@@ -50,7 +47,7 @@ protected:
Vec3d center;
Vec3d angles;
- std::array<float, 4> color;
+ ColorRGBA color;
bool enabled;
bool dragging;
@@ -63,7 +60,7 @@ protected:
float get_dragging_half_size(float size) const;
private:
- void render(float size, const std::array<float, 4>& render_color, bool picking) const;
+ void render(float size, const ColorRGBA& render_color, bool picking) const;
GLModel cube;
};
@@ -96,9 +93,9 @@ protected:
unsigned int m_sprite_id;
int m_hover_id;
bool m_dragging;
- std::array<float, 4> m_base_color;
- std::array<float, 4> m_drag_color;
- std::array<float, 4> m_highlight_color;
+ ColorRGBA m_base_color;
+ ColorRGBA m_drag_color;
+ ColorRGBA m_highlight_color;
mutable std::vector<Grabber> m_grabbers;
ImGuiWrapper* m_imgui;
bool m_first_input_window_render;
@@ -142,7 +139,7 @@ public:
int get_hover_id() const { return m_hover_id; }
void set_hover_id(int id);
- void set_highlight_color(const std::array<float, 4>& color);
+ void set_highlight_color(const ColorRGBA& color) { m_highlight_color = color; }
void enable_grabber(unsigned int id);
void disable_grabber(unsigned int id);
@@ -184,7 +181,8 @@ protected:
// Returns the picking color for the given id, based on the BASE_ID constant
// No check is made for clashing with other picking color (i.e. GLVolumes)
- std::array<float, 4> picking_color_component(unsigned int id) const;
+ ColorRGBA picking_color_component(unsigned int id) const;
+
void render_grabbers(const BoundingBoxf3& box) const;
void render_grabbers(float size) const;
void render_grabbers_for_picking(const BoundingBoxf3& box) const;
@@ -199,10 +197,6 @@ private:
bool m_dirty;
};
-// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
-// were not interpolated by alpha blending or multi sampling.
-extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
-
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
index d2c32d488..90e383e87 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
@@ -23,7 +23,8 @@ namespace GUI {
const double GLGizmoCut::Offset = 10.0;
const double GLGizmoCut::Margin = 20.0;
-const std::array<float, 4> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0, 1.0 };
+static const ColorRGBA GRABBER_COLOR = ColorRGBA::ORANGE();
+static const ColorRGBA PLANE_COLOR = { 0.8f, 0.8f, 0.8f, 0.5f };
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id)
@@ -103,7 +104,7 @@ void GLGizmoCut::on_render()
// Draw the cutting plane
::glBegin(GL_QUADS);
- ::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
+ ::glColor4fv(PLANE_COLOR.data());
::glVertex3f(min_x, min_y, plane_center.z());
::glVertex3f(max_x, min_y, plane_center.z());
::glVertex3f(max_x, max_y, plane_center.z());
@@ -134,7 +135,7 @@ void GLGizmoCut::on_render()
shader->start_using();
shader->set_uniform("emission_factor", 0.1f);
- m_grabbers[0].color = GrabberColor;
+ m_grabbers[0].color = GRABBER_COLOR;
m_grabbers[0].render(m_hover_id == 0, (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0));
shader->stop_using();
@@ -167,11 +168,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
if (last_h != win_h || last_y != y) {
// ask canvas for another frame to render the window in the correct position
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->set_requires_extra_frame();
-#else
- m_parent.request_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
if (last_h != win_h)
last_h = win_h;
if (last_y != y)
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
index 4007f89d4..44291a409 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp
@@ -13,7 +13,6 @@ class GLGizmoCut : public GLGizmoBase
{
static const double Offset;
static const double Margin;
- static const std::array<float, 4> GrabberColor;
double m_cut_z{ 0.0 };
double m_max_z{ 0.0 };
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
index cb8ccf282..d79d193d9 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
@@ -134,12 +134,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
caption_max += m_imgui->scaled(1.f);
const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left));
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
const float slider_icon_width = m_imgui->get_slider_icon_size().x;
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
-#else
- float window_width = minimal_slider_width + sliders_left_width;
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width);
window_width = std::max(window_width, split_triangles_checkbox_width);
@@ -174,15 +170,10 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height);
ImGui::SetCursorPosY(slider_start_position_y);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when "
"the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]);
if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) {
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data())) {
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg);
if (! m_parent.is_using_slope()) {
m_parent.use_slope(true);
@@ -194,11 +185,6 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::SetCursorPosY(std::max(position_before_text_y + slider_height, position_after_text_y));
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
-#if !ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when "
- "the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]), max_tooltip_width);
-#endif // !ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f);
ImGui::NewLine();
@@ -280,15 +266,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel"));
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled);
@@ -302,22 +281,12 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
m_imgui->text(m_desc["smart_fill_angle"] + ":");
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel")))
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data()))
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
-
-#if !ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width);
-#endif // !ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
}
ImGui::Separator();
@@ -335,18 +304,9 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true);
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
- m_c->object_clipper()->set_position(clp_dist, true);
-
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Ctrl + Mouse wheel"), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
index 9034d78d8..fd32c68fc 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
@@ -13,6 +13,8 @@
namespace Slic3r {
namespace GUI {
+static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f };
+static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f };
GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id)
@@ -74,11 +76,7 @@ void GLGizmoFlatten::on_render()
if (this->is_plane_update_necessary())
update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) {
- if (i == m_hover_id)
- glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.75f));
- else
- glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.5f));
-
+ glsafe(::glColor4fv(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR.data() : DEFAULT_PLANE_COLOR.data()));
if (m_planes[i].vbo.has_VBOs())
m_planes[i].vbo.render();
}
@@ -150,9 +148,9 @@ void GLGizmoFlatten::update_planes()
std::vector<bool> facet_visited(num_of_facets, false);
int facet_queue_cnt = 0;
const stl_normal* normal_ptr = nullptr;
+ int facet_idx = 0;
while (1) {
// Find next unvisited triangle:
- int facet_idx = 0;
for (; facet_idx < num_of_facets; ++ facet_idx)
if (!facet_visited[facet_idx]) {
facet_queue[facet_queue_cnt ++] = facet_idx;
@@ -249,7 +247,8 @@ void GLGizmoFlatten::update_planes()
}
if (discard) {
- m_planes.erase(m_planes.begin() + (polygon_id--));
+ m_planes[polygon_id--] = std::move(m_planes.back());
+ m_planes.pop_back();
continue;
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
index a001d5a81..16e3730b2 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
@@ -116,7 +116,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
glsafe(::glTranslated(0.0, 0.0, m_c->selection_info()->get_sla_shift()));
glsafe(::glMultMatrixd(instance_matrix.data()));
- std::array<float, 4> render_color;
+ ColorRGBA render_color;
const sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes;
size_t cache_size = drain_holes.size();
@@ -128,26 +128,18 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
continue;
// First decide about the color of the point.
- if (picking) {
- std::array<float, 4> color = picking_color_component(i);
- render_color = color;
- }
+ if (picking)
+ render_color = picking_color_component(i);
else {
- if (size_t(m_hover_id) == i) {
- render_color = {0.f, 1.f, 1.f, 1.f};
- }
+ if (size_t(m_hover_id) == i)
+ render_color = {0.0f, 1.0f, 1.0f, 1.0f};
else if (m_c->hollowed_mesh() &&
i < m_c->hollowed_mesh()->get_drainholes().size() &&
m_c->hollowed_mesh()->get_drainholes()[i].failed) {
- render_color = {1.f, 0.f, 0.f, .5f};
- }
- else { // neigher hover nor picking
-
- render_color[0] = point_selected ? 1.0f : 1.f;
- render_color[1] = point_selected ? 0.3f : 1.f;
- render_color[2] = point_selected ? 0.3f : 1.f;
- render_color[3] = 0.5f;
+ render_color = {1.0f, 0.0f, 0.0f, 0.5f};
}
+ else // neither hover nor picking
+ render_color = point_selected ? ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
}
const_cast<GLModel*>(&m_cylinder)->set_color(-1, render_color);
@@ -546,18 +538,11 @@ RENDER_AGAIN:
}
m_imgui->disabled_begin(! m_enable_hollowing);
- float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("offset"));
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
ImGui::PushItemWidth(window_width - settings_sliders_left);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm", 1.0f, true, _L(opts[0].second->tooltip));
-#else
- m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm");
- if (m_imgui->get_last_slider_status().hovered)
- m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
bool slider_edited =m_imgui->get_last_slider_status().edited; // someone is dragging the slider
@@ -567,13 +552,7 @@ RENDER_AGAIN:
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("quality"));
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f", 1.0f, true, _L(opts[1].second->tooltip));
-#else
- m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f");
- if (m_imgui->get_last_slider_status().hovered)
- m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
slider_clicked |= m_imgui->get_last_slider_status().clicked;
slider_edited |= m_imgui->get_last_slider_status().edited;
@@ -584,13 +563,7 @@ RENDER_AGAIN:
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("closing_distance"));
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm", 1.0f, true, _L(opts[2].second->tooltip));
-#else
- m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
- if (m_imgui->get_last_slider_status().hovered)
- m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
slider_clicked |= m_imgui->get_last_slider_status().clicked;
slider_edited |= m_imgui->get_last_slider_status().edited;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
index 285089357..f25a65020 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
@@ -56,18 +56,12 @@ bool GLGizmoMmuSegmentation::on_is_activable() const
return GLGizmoPainterBase::on_is_activable() && wxGetApp().extruders_edited_cnt() > 1;
}
-static std::vector<std::array<float, 4>> get_extruders_colors()
+static std::vector<ColorRGBA> get_extruders_colors()
{
- unsigned char rgb_color[3] = {};
- std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
- std::vector<std::array<float, 4>> colors_out(colors.size());
- for (const std::string &color : colors) {
- Slic3r::GUI::BitmapCache::parse_color(color, rgb_color);
- size_t color_idx = &color - &colors.front();
- colors_out[color_idx] = {float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f};
- }
-
- return colors_out;
+ std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
+ std::vector<ColorRGBA> ret;
+ decode_colors(colors, ret);
+ return ret;
}
static std::vector<std::string> get_extruders_names()
@@ -212,18 +206,14 @@ void GLGizmoMmuSegmentation::render_triangles(const Selection &selection) const
}
}
-static void render_extruders_combo(const std::string &label,
- const std::vector<std::string> &extruders,
- const std::vector<std::array<float, 4>> &extruders_colors,
- size_t &selection_idx)
+static void render_extruders_combo(const std::string& label,
+ const std::vector<std::string>& extruders,
+ const std::vector<ColorRGBA>& extruders_colors,
+ size_t& selection_idx)
{
assert(!extruders_colors.empty());
assert(extruders_colors.size() == extruders_colors.size());
- auto convert_to_imu32 = [](const std::array<float, 4> &color) -> ImU32 {
- return IM_COL32(uint8_t(color[0] * 255.f), uint8_t(color[1] * 255.f), uint8_t(color[2] * 255.f), uint8_t(color[3] * 255.f));
- };
-
size_t selection_out = selection_idx;
// It is necessary to use BeginGroup(). Otherwise, when using SameLine() is called, then other items will be drawn inside the combobox.
ImGui::BeginGroup();
@@ -239,7 +229,7 @@ static void render_extruders_combo(const std::string &labe
ImGui::SameLine();
ImGuiStyle &style = ImGui::GetStyle();
float height = ImGui::GetTextLineHeight();
- ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), convert_to_imu32(extruders_colors[extruder_idx]));
+ ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), ImGuiWrapper::to_ImU32(extruders_colors[extruder_idx]));
ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), IM_COL32_BLACK);
ImGui::SetCursorScreenPos(ImVec2(start_position.x + height + height / 2 + style.FramePadding.x, start_position.y));
@@ -257,7 +247,7 @@ static void render_extruders_combo(const std::string &labe
ImVec2 p = ImGui::GetCursorScreenPos();
float height = ImGui::GetTextLineHeight();
- ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), convert_to_imu32(extruders_colors[selection_idx]));
+ ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), ImGuiWrapper::to_ImU32(extruders_colors[selection_idx]));
ImGui::GetWindowDrawList()->AddRect(p, ImVec2(p.x + height + height / 2, p.y + height), IM_COL32_BLACK);
ImGui::SetCursorScreenPos(ImVec2(p.x + height + height / 2 + style.FramePadding.x, p.y));
@@ -312,12 +302,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
caption_max += m_imgui->scaled(1.f);
const float sliders_left_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left));
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
const float slider_icon_width = m_imgui->get_slider_icon_size().x;
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
-#else
- float window_width = minimal_slider_width + sliders_left_width;
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width);
window_width = std::max(window_width, split_triangles_checkbox_width);
@@ -343,10 +329,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
render_extruders_combo("##first_color_combo", m_original_extruders_names, m_original_extruders_colors, m_first_selected_extruder_idx);
ImGui::SameLine();
- const std::array<float, 4> &select_first_color = m_modified_extruders_colors[m_first_selected_extruder_idx];
- ImVec4 first_color = ImVec4(select_first_color[0], select_first_color[1], select_first_color[2], select_first_color[3]);
- if(ImGui::ColorEdit4("First color##color_picker", (float*)&first_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel))
- m_modified_extruders_colors[m_first_selected_extruder_idx] = {first_color.x, first_color.y, first_color.z, first_color.w};
+ const ColorRGBA& select_first_color = m_modified_extruders_colors[m_first_selected_extruder_idx];
+ ImVec4 first_color = ImGuiWrapper::to_ImVec4(select_first_color);
+ if (ImGui::ColorEdit4("First color##color_picker", (float*)&first_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel))
+ m_modified_extruders_colors[m_first_selected_extruder_idx] = ImGuiWrapper::from_ImVec4(first_color);
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("second_color"));
@@ -355,10 +341,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
render_extruders_combo("##second_color_combo", m_original_extruders_names, m_original_extruders_colors, m_second_selected_extruder_idx);
ImGui::SameLine();
- const std::array<float, 4> &select_second_color = m_modified_extruders_colors[m_second_selected_extruder_idx];
- ImVec4 second_color = ImVec4(select_second_color[0], select_second_color[1], select_second_color[2], select_second_color[3]);
- if(ImGui::ColorEdit4("Second color##color_picker", (float*)&second_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel))
- m_modified_extruders_colors[m_second_selected_extruder_idx] = {second_color.x, second_color.y, second_color.z, second_color.w};
+ const ColorRGBA& select_second_color = m_modified_extruders_colors[m_second_selected_extruder_idx];
+ ImVec4 second_color = ImGuiWrapper::to_ImVec4(select_second_color);
+ if (ImGui::ColorEdit4("Second color##color_picker", (float*)&second_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel))
+ m_modified_extruders_colors[m_second_selected_extruder_idx] = ImGuiWrapper::from_ImVec4(second_color);
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
@@ -445,15 +431,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel"));
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled);
@@ -469,23 +448,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Degree sign to use in the respective slider in MMU gizmo,"
"placed after the number with no whitespace in between.");
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel")))
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- if(m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data()))
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
-#if !ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width);
-#endif // !ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
-
ImGui::Separator();
}
@@ -500,18 +469,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true);
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
- m_c->object_clipper()->set_position(clp_dist, true);
-
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Ctrl + Mouse wheel"), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {
@@ -595,16 +555,18 @@ PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const
return PainterGizmoType::MMU_SEGMENTATION;
}
-std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_left_button_color() const
+ColorRGBA GLGizmoMmuSegmentation::get_cursor_sphere_left_button_color() const
{
- const std::array<float, 4> &color = m_modified_extruders_colors[m_first_selected_extruder_idx];
- return {color[0], color[1], color[2], 0.25f};
+ ColorRGBA color = m_modified_extruders_colors[m_first_selected_extruder_idx];
+ color.a(0.25f);
+ return color;
}
-std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_right_button_color() const
+ColorRGBA GLGizmoMmuSegmentation::get_cursor_sphere_right_button_color() const
{
- const std::array<float, 4> &color = m_modified_extruders_colors[m_second_selected_extruder_idx];
- return {color[0], color[1], color[2], 0.25f};
+ ColorRGBA color = m_modified_extruders_colors[m_second_selected_extruder_idx];
+ color.a(0.25f);
+ return color;
}
void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp
index 577db8ed5..70bb5241d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp
@@ -62,7 +62,7 @@ public:
class TriangleSelectorMmGui : public TriangleSelectorGUI {
public:
// Plus 1 in the initialization of m_gizmo_scene is because the first position is allocated for non-painted triangles, and the indices above colors.size() are allocated for seed fill.
- explicit TriangleSelectorMmGui(const TriangleMesh &mesh, const std::vector<std::array<float, 4>> &colors, const std::array<float, 4> &default_volume_color)
+ TriangleSelectorMmGui(const TriangleMesh& mesh, const std::vector<ColorRGBA>& colors, const ColorRGBA& default_volume_color)
: TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color), m_gizmo_scene(2 * (colors.size() + 1)) {}
~TriangleSelectorMmGui() override = default;
@@ -73,8 +73,8 @@ public:
private:
void update_render_data();
- const std::vector<std::array<float, 4>> &m_colors;
- const std::array<float, 4> m_default_volume_color;
+ const std::vector<ColorRGBA>& m_colors;
+ const ColorRGBA m_default_volume_color;
GLMmSegmentationGizmo3DScene m_gizmo_scene;
};
@@ -100,8 +100,8 @@ public:
const float get_cursor_radius_min() const override { return CursorRadiusMin; }
protected:
- std::array<float, 4> get_cursor_sphere_left_button_color() const override;
- std::array<float, 4> get_cursor_sphere_right_button_color() const override;
+ ColorRGBA get_cursor_sphere_left_button_color() const override;
+ ColorRGBA get_cursor_sphere_right_button_color() const override;
EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType(m_first_selected_extruder_idx + 1); }
EnforcerBlockerType get_right_button_state_type() const override { return EnforcerBlockerType(m_second_selected_extruder_idx + 1); }
@@ -121,8 +121,8 @@ protected:
size_t m_first_selected_extruder_idx = 0;
size_t m_second_selected_extruder_idx = 1;
std::vector<std::string> m_original_extruders_names;
- std::vector<std::array<float, 4>> m_original_extruders_colors;
- std::vector<std::array<float, 4>> m_modified_extruders_colors;
+ std::vector<ColorRGBA> m_original_extruders_colors;
+ std::vector<ColorRGBA> m_modified_extruders_colors;
std::vector<int> m_original_volumes_extruder_idxs;
static const constexpr float CursorRadiusMin = 0.1f; // cannot be zero
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
index d16f0ff2d..ff6a05847 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
@@ -195,13 +195,9 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0);
double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size);
- std::array<float, 4> color = m_grabbers[axis].color;
- if (!picking && m_hover_id != -1) {
- color[0] = 1.0f - color[0];
- color[1] = 1.0f - color[1];
- color[2] = 1.0f - color[2];
- color[3] = color[3];
- }
+ ColorRGBA color = m_grabbers[axis].color;
+ if (!picking && m_hover_id != -1)
+ color = complementary(color);
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
index fa59d7646..1f654dcc0 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
@@ -207,7 +207,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
if (is_left_handed)
glFrontFace(GL_CW);
- std::array<float, 4> render_color = {0.f, 0.f, 0.f, 0.25f};
+ ColorRGBA render_color = { 0.0f, 0.0f, 0.0f, 0.25f };
if (m_button_down == Button::Left)
render_color = this->get_cursor_sphere_left_button_color();
else if (m_button_down == Button::Right)
@@ -709,15 +709,15 @@ TriangleSelector::ClippingPlane GLGizmoPainterBase::get_clipping_plane_in_volume
return TriangleSelector::ClippingPlane({float(normal_transformed.x()), float(normal_transformed.y()), float(normal_transformed.z()), offset_transformed});
}
-std::array<float, 4> TriangleSelectorGUI::get_seed_fill_color(const std::array<float, 4> &base_color)
+ColorRGBA TriangleSelectorGUI::get_seed_fill_color(const ColorRGBA& base_color)
{
- return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f};
+ return saturate(base_color, 0.75f);
}
void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
{
- static constexpr std::array<float, 4> enforcers_color{0.47f, 0.47f, 1.f, 1.f};
- static constexpr std::array<float, 4> blockers_color{1.f, 0.44f, 0.44f, 1.f};
+ static const ColorRGBA enforcers_color = { 0.47f, 0.47f, 1.0f, 1.0f };
+ static const ColorRGBA blockers_color = { 1.0f, 0.44f, 0.44f, 1.0f };
if (m_update_render_data) {
update_render_data();
@@ -741,7 +741,7 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
for (auto &iva : m_iva_seed_fills)
if (iva.has_VBOs()) {
size_t color_idx = &iva - &m_iva_seed_fills.front();
- const std::array<float, 4> &color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color :
+ const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color :
color_idx == 2 ? blockers_color :
GLVolume::NEUTRAL_COLOR);
shader->set_uniform("uniform_color", color);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp
index ea6760a17..53c0f31b1 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp
@@ -86,7 +86,7 @@ public:
protected:
bool m_update_render_data = false;
- static std::array<float, 4> get_seed_fill_color(const std::array<float, 4> &base_color);
+ static ColorRGBA get_seed_fill_color(const ColorRGBA& base_color);
private:
void update_render_data();
@@ -135,8 +135,8 @@ protected:
virtual void update_model_object() const = 0;
virtual void update_from_model_object() = 0;
- virtual std::array<float, 4> get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; }
- virtual std::array<float, 4> get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; }
+ virtual ColorRGBA get_cursor_sphere_left_button_color() const { return { 0.0f, 0.0f, 1.0f, 0.25f }; }
+ virtual ColorRGBA get_cursor_sphere_right_button_color() const { return { 1.0f, 0.0f, 0.0f, 0.25f }; }
virtual EnforcerBlockerType get_left_button_state_type() const { return EnforcerBlockerType::ENFORCER; }
virtual EnforcerBlockerType get_right_button_state_type() const { return EnforcerBlockerType::BLOCKER; }
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
index a234a19ff..5046d1922 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
@@ -314,12 +314,9 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size);
- std::array<float, 4> color = m_grabbers[0].color;
- if (!picking && m_hover_id != -1) {
- color[0] = 1.0f - color[0];
- color[1] = 1.0f - color[1];
- color[2] = 1.0f - color[2];
- }
+ ColorRGBA color = m_grabbers[0].color;
+ if (!picking && m_hover_id != -1)
+ color = complementary(color);
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
@@ -540,11 +537,12 @@ GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
ImVec2 button_sz = {btn_txt_sz.x + padding.x, btn_txt_sz.y + padding.y};
ImGui::SetCursorPosX(padding.x + sz.x - button_sz.x);
- if (wxGetApp().plater()->is_any_job_running())
+ if (!wxGetApp().plater()->get_ui_job_worker().is_idle())
imgui->disabled_begin(true);
if ( imgui->button(btn_txt) ) {
- wxGetApp().plater()->optimize_rotation();
+ replace_job(wxGetApp().plater()->get_ui_job_worker(),
+ std::make_unique<RotoptimizeJob>());
}
imgui->disabled_end();
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
index af1ecf548..448efd98a 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
@@ -2,7 +2,6 @@
#define slic3r_GLGizmoRotate_hpp_
#include "GLGizmoBase.hpp"
-#include "../Jobs/RotoptimizeJob.hpp"
namespace Slic3r {
namespace GUI {
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
index b11a8bffd..00921aa9c 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
@@ -105,12 +105,8 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
caption_max += m_imgui->scaled(1.f);
const float sliders_left_width = std::max(cursor_size_slider_left, clipping_slider_left);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
const float slider_icon_width = m_imgui->get_slider_icon_size().x;
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
-#else
- float window_width = minimal_slider_width + sliders_left_width;
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width);
window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_sphere + cursor_type_radio_circle);
@@ -132,15 +128,8 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel"));
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Alt + Mouse wheel"), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_type"));
@@ -177,18 +166,9 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(sliders_left_width);
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true);
-#else
- ImGui::PushItemWidth(window_width - sliders_left_width);
- if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
- m_c->object_clipper()->set_position(clp_dist, true);
-
- if (ImGui::IsItemHovered())
- m_imgui->tooltip(_L("Ctrl + Mouse wheel"), max_tooltip_width);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 51551281a..37a107346 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -144,7 +144,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
glsafe(::glTranslated(0.0, 0.0, z_shift));
glsafe(::glMultMatrixd(instance_matrix.data()));
- std::array<float, 4> render_color;
+ ColorRGBA render_color;
for (size_t i = 0; i < cache_size; ++i) {
const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i];
const bool& point_selected = m_editing_mode ? m_editing_cache[i].selected : false;
@@ -226,10 +226,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
// Now render the drain holes:
if (has_holes && ! picking) {
- render_color[0] = 0.7f;
- render_color[1] = 0.7f;
- render_color[2] = 0.7f;
- render_color[3] = 0.7f;
+ render_color = { 0.7f, 0.7f, 0.7f, 0.7f };
const_cast<GLModel*>(&m_cylinder)->set_color(-1, render_color);
if (shader)
shader->set_uniform("emission_factor", 0.5f);
@@ -651,11 +648,7 @@ RENDER_AGAIN:
if ((last_h != win_h) || (last_y != y))
{
// ask canvas for another frame to render the window in the correct position
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
m_imgui->set_requires_extra_frame();
-#else
- m_parent.request_extra_frame();
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
if (last_h != win_h)
last_h = win_h;
if (last_y != y)
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
index d2a7e0d73..cc53f267c 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
@@ -216,8 +216,8 @@ void InstancesHider::render_cut() const
if (mv->is_model_part())
glsafe(::glColor3f(0.8f, 0.3f, 0.0f));
else {
- const std::array<float, 4>& c = color_from_model_volume(*mv);
- glsafe(::glColor4f(c[0], c[1], c[2], c[3]));
+ const ColorRGBA color = color_from_model_volume(*mv);
+ glsafe(::glColor4fv(color.data()));
}
glsafe(::glPushAttrib(GL_DEPTH_TEST));
glsafe(::glDisable(GL_DEPTH_TEST));
diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp
index 55bcc90a9..3e98374af 100644
--- a/src/slic3r/GUI/HintNotification.cpp
+++ b/src/slic3r/GUI/HintNotification.cpp
@@ -615,7 +615,7 @@ void NotificationManager::HintNotification::count_lines()
float width_of_a = ImGui::CalcTextSize("a").x;
int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a);
while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) {
- letter_count++;
+ letter_count += get_utf8_sequence_length(text, last_end + letter_count);
}
m_endlines.push_back(last_end + letter_count);
last_end += letter_count;
@@ -685,7 +685,7 @@ void NotificationManager::HintNotification::count_lines()
float width_of_a = ImGui::CalcTextSize("a").x;
int letter_count = (int)((m_window_width - m_window_width_offset - size_of_last_line) / width_of_a);
while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset - size_of_last_line) {
- letter_count++;
+ letter_count += get_utf8_sequence_length(text, last_end + letter_count);
}
m_endlines2.push_back(last_end + letter_count);
last_end += letter_count;
@@ -1058,4 +1058,4 @@ void NotificationManager::HintNotification::retrieve_data(bool new_hint/* = true
}
}
} //namespace Slic3r
-} //namespace GUI \ No newline at end of file
+} //namespace GUI
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 62af8012b..01eeef342 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -8,10 +8,8 @@
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/filesystem.hpp>
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
#include <boost/algorithm/string/predicate.hpp>
#include <boost/nowide/convert.hpp>
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
#include <wx/string.h>
#include <wx/event.h>
@@ -27,6 +25,7 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
+#include "libslic3r/Color.hpp"
#include "3DScene.hpp"
#include "GUI.hpp"
#include "I18N.hpp"
@@ -53,10 +52,8 @@ static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::RightArrowHoverButton , "notification_right_hover" },
{ImGui::PreferencesButton , "notification_preferences" },
{ImGui::PreferencesHoverButton, "notification_preferences_hover"},
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
{ImGui::SliderFloatEditBtnIcon, "edit_button" },
{ImGui::SliderFloatEditBtnPressedIcon, "edit_button_pressed" },
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
#if ENABLE_LEGEND_TOOLBAR_ICONS
{ImGui::LegendTravel , "legend_travel" },
{ImGui::LegendWipe , "legend_wipe" },
@@ -71,6 +68,7 @@ static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::LegendToolMarker , "legend_toolmarker" },
#endif // ENABLE_LEGEND_TOOLBAR_ICONS
};
+
static const std::map<const wchar_t, std::string> font_icons_large = {
{ImGui::CloseNotifButton , "notification_close" },
{ImGui::CloseNotifHoverButton , "notification_close_hover" },
@@ -96,14 +94,14 @@ static const std::map<const wchar_t, std::string> font_icons_extra_large = {
};
-const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f };
+const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.33f, 0.33f, 0.33f, 1.0f };
const ImVec4 ImGuiWrapper::COL_GREY_LIGHT = { 0.4f, 0.4f, 0.4f, 1.0f };
-const ImVec4 ImGuiWrapper::COL_ORANGE_DARK = { 0.757f, 0.404f, 0.216f, 1.0f };
-const ImVec4 ImGuiWrapper::COL_ORANGE_LIGHT = { 1.0f, 0.49f, 0.216f, 1.0f };
-const ImVec4 ImGuiWrapper::COL_WINDOW_BACKGROUND = { 0.133f, 0.133f, 0.133f, 0.8f };
+const ImVec4 ImGuiWrapper::COL_ORANGE_DARK = { 0.67f, 0.36f, 0.19f, 1.0f };
+const ImVec4 ImGuiWrapper::COL_ORANGE_LIGHT = to_ImVec4(ColorRGBA::ORANGE());
+const ImVec4 ImGuiWrapper::COL_WINDOW_BACKGROUND = { 0.13f, 0.13f, 0.13f, 0.8f };
const ImVec4 ImGuiWrapper::COL_BUTTON_BACKGROUND = COL_ORANGE_DARK;
const ImVec4 ImGuiWrapper::COL_BUTTON_HOVERED = COL_ORANGE_LIGHT;
-const ImVec4 ImGuiWrapper::COL_BUTTON_ACTIVE = ImGuiWrapper::COL_BUTTON_HOVERED;
+const ImVec4 ImGuiWrapper::COL_BUTTON_ACTIVE = COL_BUTTON_HOVERED;
ImGuiWrapper::ImGuiWrapper()
{
@@ -528,7 +526,6 @@ void ImGuiWrapper::tooltip(const wxString &label, float wrap_width)
ImGui::EndTooltip();
}
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImVec2 ImGuiWrapper::get_slider_icon_size() const
{
return this->calc_button_size(std::wstring(&ImGui::SliderFloatEditBtnIcon, 1));
@@ -677,26 +674,6 @@ bool ImGuiWrapper::image_button(ImTextureID user_texture_id, const ImVec2& size,
const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : g.Style.FramePadding;
return image_button_ex(id, user_texture_id, size, uv0, uv1, padding, bg_col, tint_col, flags);
}
-#else
-bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/, bool clamp /*= true*/)
-{
- bool ret = ImGui::SliderFloat(label, v, v_min, v_max, format, power);
- if (clamp)
- *v = std::clamp(*v, v_min, v_max);
- return ret;
-}
-
-bool ImGuiWrapper::slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/, bool clamp /*= true*/)
-{
- return this->slider_float(label.c_str(), v, v_min, v_max, format, power, clamp);
-}
-
-bool ImGuiWrapper::slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/, bool clamp /*= true*/)
-{
- auto label_utf8 = into_u8(label);
- return this->slider_float(label_utf8.c_str(), v, v_min, v_max, format, power, clamp);
-}
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>& options, int& selection, ImGuiComboFlags flags)
{
@@ -1166,6 +1143,26 @@ ImFontAtlasCustomRect* ImGuiWrapper::GetTextureCustomRect(const wchar_t& tex_id)
}
#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ImU32 ImGuiWrapper::to_ImU32(const ColorRGBA& color)
+{
+ return ImGui::GetColorU32({ color.r(), color.g(), color.b(), color.a() });
+}
+
+ImVec4 ImGuiWrapper::to_ImVec4(const ColorRGBA& color)
+{
+ return { color.r(), color.g(), color.b(), color.a() };
+}
+
+ColorRGBA ImGuiWrapper::from_ImU32(const ImU32& color)
+{
+ return from_ImVec4(ImGui::ColorConvertU32ToFloat4(color));
+}
+
+ColorRGBA ImGuiWrapper::from_ImVec4(const ImVec4& color)
+{
+ return { color.x, color.y, color.z, color.w };
+}
+
#ifdef __APPLE__
static const ImWchar ranges_keyboard_shortcuts[] =
{
diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp
index d85d6b387..f461bc970 100644
--- a/src/slic3r/GUI/ImGuiWrapper.hpp
+++ b/src/slic3r/GUI/ImGuiWrapper.hpp
@@ -9,10 +9,13 @@
#include <wx/string.h>
#include "libslic3r/Point.hpp"
+#include "libslic3r/Color.hpp"
-namespace Slic3r {namespace Search {
+namespace Slic3r {
+namespace Search {
struct OptionViewParameters;
-}}
+} // namespace Search
+} // namespace Slic3r
class wxString;
class wxMouseEvent;
@@ -36,9 +39,7 @@ class ImGuiWrapper
unsigned m_mouse_buttons{ 0 };
bool m_disabled{ false };
bool m_new_frame_open{ false };
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
bool m_requires_extra_frame{ false };
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
#if ENABLE_LEGEND_TOOLBAR_ICONS
std::map<wchar_t, int> m_custom_glyph_rects_ids;
#endif // ENABLE_LEGEND_TOOLBAR_ICONS
@@ -111,18 +112,12 @@ public:
void tooltip(const wxString &label, float wrap_width);
// Float sliders: Manually inserted values aren't clamped by ImGui.Using this wrapper function does (when clamp==true).
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
ImVec2 get_slider_icon_size() const;
bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true);
bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true);
bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true);
bool image_button(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0.0, 0.0), const ImVec2& uv1 = ImVec2(1.0, 1.0), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0.0, 0.0, 0.0, 0.0), const ImVec4& tint_col = ImVec4(1.0, 1.0, 1.0, 1.0), ImGuiButtonFlags flags = 0);
-#else
- bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true);
- bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true);
- bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true);
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
// Use selection = -1 to not mark any option as selected
bool combo(const wxString& label, const std::vector<std::string>& options, int& selection, ImGuiComboFlags flags = 0);
@@ -139,11 +134,14 @@ public:
bool want_text_input() const;
bool want_any_input() const;
-#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
bool requires_extra_frame() const { return m_requires_extra_frame; }
void set_requires_extra_frame() { m_requires_extra_frame = true; }
void reset_requires_extra_frame() { m_requires_extra_frame = false; }
-#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
+
+ static ImU32 to_ImU32(const ColorRGBA& color);
+ static ImVec4 to_ImVec4(const ColorRGBA& color);
+ static ColorRGBA from_ImU32(const ImU32& color);
+ static ColorRGBA from_ImVec4(const ImVec4& color);
#if ENABLE_LEGEND_TOOLBAR_ICONS
ImFontAtlasCustomRect* GetTextureCustomRect(const wchar_t& tex_id);
diff --git a/src/slic3r/GUI/InstanceCheck.cpp b/src/slic3r/GUI/InstanceCheck.cpp
index 38ea95f2c..81d5e01fe 100644
--- a/src/slic3r/GUI/InstanceCheck.cpp
+++ b/src/slic3r/GUI/InstanceCheck.cpp
@@ -199,7 +199,10 @@ namespace instance_check_internal
//else
// BOOST_LOG_TRIVIAL(error) << "success delete lockfile " << path;
#ifdef __APPLE__
- send_message_mac_closing(GUI::wxGetApp().get_instance_hash_string(),GUI::wxGetApp().get_instance_hash_string());
+ // Partial fix of #7583
+ // On price of incorrect working of single instances on older OSX
+ if (wxPlatformInfo::Get().GetOSMajorVersion() > 12)
+ send_message_mac_closing(GUI::wxGetApp().get_instance_hash_string(),GUI::wxGetApp().get_instance_hash_string());
#endif
}
}
diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp
index 2771f9d27..3c7dad0a6 100644
--- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp
+++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp
@@ -162,49 +162,43 @@ void ArrangeJob::prepare()
wxGetKeyState(WXK_SHIFT) ? prepare_selected() : prepare_all();
}
-void ArrangeJob::on_exception(const std::exception_ptr &eptr)
+void ArrangeJob::process(Ctl &ctl)
{
- try {
- if (eptr)
- std::rethrow_exception(eptr);
- } catch (libnest2d::GeometryException &) {
- show_error(m_plater, _(L("Could not arrange model objects! "
- "Some geometries may be invalid.")));
- } catch (std::exception &) {
- PlaterJob::on_exception(eptr);
- }
-}
+ static const auto arrangestr = _u8L("Arranging");
-void ArrangeJob::process()
-{
- static const auto arrangestr = _(L("Arranging"));
+ ctl.update_status(0, arrangestr);
+ ctl.call_on_main_thread([this]{ prepare(); }).wait();;
arrangement::ArrangeParams params = get_arrange_params(m_plater);
- auto count = unsigned(m_selected.size() + m_unprintable.size());
+ auto count = unsigned(m_selected.size() + m_unprintable.size());
Points bedpts = get_bed_shape(*m_plater->config());
-
- params.stopcondition = [this]() { return was_canceled(); };
-
- params.progressind = [this, count](unsigned st) {
+
+ params.stopcondition = [&ctl]() { return ctl.was_canceled(); };
+
+ params.progressind = [this, count, &ctl](unsigned st) {
st += m_unprintable.size();
- if (st > 0) update_status(int(count - st), arrangestr);
+ if (st > 0) ctl.update_status(int(count - st) * 100 / status_range(), arrangestr);
};
+ ctl.update_status(0, arrangestr);
+
arrangement::arrange(m_selected, m_unselected, bedpts, params);
- params.progressind = [this, count](unsigned st) {
- if (st > 0) update_status(int(count - st), arrangestr);
+ params.progressind = [this, count, &ctl](unsigned st) {
+ if (st > 0) ctl.update_status(int(count - st) * 100 / status_range(), arrangestr);
};
arrangement::arrange(m_unprintable, {}, bedpts, params);
// finalize just here.
- update_status(int(count),
- was_canceled() ? _(L("Arranging canceled."))
- : _(L("Arranging done.")));
+ ctl.update_status(int(count) * 100 / status_range(), ctl.was_canceled() ?
+ _u8L("Arranging canceled.") :
+ _u8L("Arranging done."));
}
+ArrangeJob::ArrangeJob() : m_plater{wxGetApp().plater()} {}
+
static std::string concat_strings(const std::set<std::string> &strings,
const std::string &delim = "\n")
{
@@ -215,10 +209,21 @@ static std::string concat_strings(const std::set<std::string> &strings,
});
}
-void ArrangeJob::finalize() {
- // Ignore the arrange result if aborted.
- if (was_canceled()) return;
-
+void ArrangeJob::finalize(bool canceled, std::exception_ptr &eptr) {
+ try {
+ if (eptr)
+ std::rethrow_exception(eptr);
+ } catch (libnest2d::GeometryException &) {
+ show_error(m_plater, _(L("Could not arrange model objects! "
+ "Some geometries may be invalid.")));
+ eptr = nullptr;
+ } catch(...) {
+ eptr = std::current_exception();
+ }
+
+ if (canceled || eptr)
+ return;
+
// Unprintable items go to the last virtual bed
int beds = 0;
@@ -250,8 +255,6 @@ void ArrangeJob::finalize() {
_L("Arrangement ignored the following objects which can't fit into a single bed:\n%s"),
concat_strings(names, "\n")));
}
-
- Job::finalize();
}
std::optional<arrangement::ArrangePolygon>
diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.hpp b/src/slic3r/GUI/Jobs/ArrangeJob.hpp
index a5ecc0c83..106cc57dd 100644
--- a/src/slic3r/GUI/Jobs/ArrangeJob.hpp
+++ b/src/slic3r/GUI/Jobs/ArrangeJob.hpp
@@ -1,7 +1,9 @@
#ifndef ARRANGEJOB_HPP
#define ARRANGEJOB_HPP
-#include "PlaterJob.hpp"
+#include <optional>
+
+#include "Job.hpp"
#include "libslic3r/Arrange.hpp"
namespace Slic3r {
@@ -10,13 +12,16 @@ class ModelInstance;
namespace GUI {
-class ArrangeJob : public PlaterJob
+class Plater;
+
+class ArrangeJob : public Job
{
using ArrangePolygon = arrangement::ArrangePolygon;
using ArrangePolygons = arrangement::ArrangePolygons;
ArrangePolygons m_selected, m_unselected, m_unprintable;
std::vector<ModelInstance*> m_unarranged;
+ Plater *m_plater;
// clear m_selected and m_unselected, reserve space for next usage
void clear_input();
@@ -30,25 +35,20 @@ class ArrangeJob : public PlaterJob
ArrangePolygon get_arrange_poly_(ModelInstance *mi);
-protected:
-
- void prepare() override;
+public:
- void on_exception(const std::exception_ptr &) override;
+ void prepare();
- void process() override;
+ void process(Ctl &ctl) override;
-public:
- ArrangeJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater)
- : PlaterJob{std::move(pri), plater}
- {}
+ ArrangeJob();
- int status_range() const override
+ int status_range() const
{
return int(m_selected.size() + m_unprintable.size());
}
- void finalize() override;
+ void finalize(bool canceled, std::exception_ptr &e) override;
};
std::optional<arrangement::ArrangePolygon> get_wipe_tower_arrangepoly(const Plater &);
diff --git a/src/slic3r/GUI/Jobs/BoostThreadWorker.cpp b/src/slic3r/GUI/Jobs/BoostThreadWorker.cpp
new file mode 100644
index 000000000..a4f22be55
--- /dev/null
+++ b/src/slic3r/GUI/Jobs/BoostThreadWorker.cpp
@@ -0,0 +1,181 @@
+#include <exception>
+
+#include "BoostThreadWorker.hpp"
+
+namespace Slic3r { namespace GUI {
+
+void BoostThreadWorker::WorkerMessage::deliver(BoostThreadWorker &runner)
+{
+ switch(MsgType(get_type())) {
+ case Empty: break;
+ case Status: {
+ auto info = boost::get<StatusInfo>(m_data);
+ if (runner.get_pri()) {
+ runner.get_pri()->set_progress(info.status);
+ runner.get_pri()->set_status_text(info.msg.c_str());
+ }
+ break;
+ }
+ case Finalize: {
+ auto& entry = boost::get<JobEntry>(m_data);
+ entry.job->finalize(entry.canceled, entry.eptr);
+
+ // Unhandled exceptions are rethrown without mercy.
+ if (entry.eptr)
+ std::rethrow_exception(entry.eptr);
+
+ break;
+ }
+ case MainThreadCall: {
+ auto &calldata = boost::get<MainThreadCallData >(m_data);
+ calldata.fn();
+ calldata.promise.set_value();
+
+ break;
+ }
+ }
+}
+
+void BoostThreadWorker::run()
+{
+ bool stop = false;
+ while (!stop) {
+ m_input_queue
+ .consume_one(BlockingWait{0, &m_running}, [this, &stop](JobEntry &e) {
+ if (!e.job)
+ stop = true;
+ else {
+ m_canceled.store(false);
+
+ try {
+ e.job->process(*this);
+ } catch (...) {
+ e.eptr = std::current_exception();
+ }
+
+ e.canceled = m_canceled.load();
+ m_output_queue.push(std::move(e)); // finalization message
+ }
+ m_running.store(false);
+ });
+ };
+}
+
+void BoostThreadWorker::update_status(int st, const std::string &msg)
+{
+ m_output_queue.push(st, msg);
+}
+
+std::future<void> BoostThreadWorker::call_on_main_thread(std::function<void ()> fn)
+{
+ MainThreadCallData cbdata{std::move(fn), {}};
+ std::future<void> future = cbdata.promise.get_future();
+
+ m_output_queue.push(std::move(cbdata));
+
+ return future;
+}
+
+BoostThreadWorker::BoostThreadWorker(std::shared_ptr<ProgressIndicator> pri,
+ boost::thread::attributes &attribs,
+ const char * name)
+ : m_progress(std::move(pri)), m_name{name}
+{
+ if (m_progress)
+ m_progress->set_cancel_callback([this](){ cancel(); });
+
+ m_thread = create_thread(attribs, [this] { this->run(); });
+
+ std::string nm{name};
+ if (!nm.empty()) set_thread_name(m_thread, name);
+}
+
+constexpr int ABORT_WAIT_MAX_MS = 10000;
+
+BoostThreadWorker::~BoostThreadWorker()
+{
+ bool joined = false;
+ try {
+ cancel_all();
+ wait_for_idle(ABORT_WAIT_MAX_MS);
+ m_input_queue.push(JobEntry{nullptr});
+ joined = join(ABORT_WAIT_MAX_MS);
+ } catch(...) {}
+
+ if (!joined)
+ BOOST_LOG_TRIVIAL(error)
+ << "Could not join worker thread '" << m_name << "'";
+}
+
+bool BoostThreadWorker::join(int timeout_ms)
+{
+ if (!m_thread.joinable())
+ return true;
+
+ if (timeout_ms <= 0) {
+ m_thread.join();
+ }
+ else if (m_thread.try_join_for(boost::chrono::milliseconds(timeout_ms))) {
+ return true;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+void BoostThreadWorker::process_events()
+{
+ while (m_output_queue.consume_one([this](WorkerMessage &msg) {
+ msg.deliver(*this);
+ }));
+}
+
+bool BoostThreadWorker::wait_for_current_job(unsigned timeout_ms)
+{
+ bool ret = true;
+
+ if (!is_idle()) {
+ bool was_finish = false;
+ bool timeout_reached = false;
+ while (!timeout_reached && !was_finish) {
+ timeout_reached =
+ !m_output_queue.consume_one(BlockingWait{timeout_ms},
+ [this, &was_finish](
+ WorkerMessage &msg) {
+ msg.deliver(*this);
+ if (msg.get_type() ==
+ WorkerMessage::Finalize)
+ was_finish = true;
+ });
+ }
+
+ ret = !timeout_reached;
+ }
+
+ return ret;
+}
+
+bool BoostThreadWorker::wait_for_idle(unsigned timeout_ms)
+{
+ bool timeout_reached = false;
+ while (!timeout_reached && !is_idle()) {
+ timeout_reached = !m_output_queue
+ .consume_one(BlockingWait{timeout_ms},
+ [this](WorkerMessage &msg) {
+ msg.deliver(*this);
+ });
+ }
+
+ return !timeout_reached;
+}
+
+bool BoostThreadWorker::push(std::unique_ptr<Job> job)
+{
+ if (job)
+ m_input_queue.push(JobEntry{std::move(job)});
+
+ return bool{job};
+}
+
+}} // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/Jobs/BoostThreadWorker.hpp b/src/slic3r/GUI/Jobs/BoostThreadWorker.hpp
new file mode 100644
index 000000000..2fe39c0a7
--- /dev/null
+++ b/src/slic3r/GUI/Jobs/BoostThreadWorker.hpp
@@ -0,0 +1,140 @@
+#ifndef BOOSTTHREADWORKER_HPP
+#define BOOSTTHREADWORKER_HPP
+
+#include <boost/variant.hpp>
+
+#include "Worker.hpp"
+
+#include <libslic3r/Thread.hpp>
+#include <boost/log/trivial.hpp>
+
+#include "ThreadSafeQueue.hpp"
+
+namespace Slic3r { namespace GUI {
+
+// An implementation of the Worker interface which uses the boost::thread
+// API and two thread safe message queues to communicate with the main thread
+// back and forth. The queue from the main thread to the worker thread holds the
+// job entries that will be performed on the worker. The other queue holds messages
+// from the worker to the main thread. These messages include status updates,
+// finishing operation and arbitrary functiors that need to be performed
+// on the main thread during the jobs execution, like displaying intermediate
+// results.
+class BoostThreadWorker : public Worker, private Job::Ctl
+{
+ struct JobEntry // Goes into worker and also out of worker as a finalize msg
+ {
+ std::unique_ptr<Job> job;
+ bool canceled = false;
+ std::exception_ptr eptr = nullptr;
+ };
+
+ // A message data for status updates. Only goes from worker to main thread.
+ struct StatusInfo { int status; std::string msg; };
+
+ // An arbitrary callback to be called on the main thread. Only from worker
+ // to main thread.
+ struct MainThreadCallData
+ {
+ std::function<void()> fn;
+ std::promise<void> promise;
+ };
+
+ struct EmptyMessage {};
+
+ class WorkerMessage
+ {
+ public:
+ enum MsgType { Empty, Status, Finalize, MainThreadCall };
+
+ private:
+ boost::variant<EmptyMessage, StatusInfo, JobEntry, MainThreadCallData> m_data;
+
+ public:
+ WorkerMessage() = default;
+ WorkerMessage(int s, std::string txt)
+ : m_data{StatusInfo{s, std::move(txt)}}
+ {}
+ WorkerMessage(JobEntry &&entry) : m_data{std::move(entry)} {}
+ WorkerMessage(MainThreadCallData fn) : m_data{std::move(fn)} {}
+
+ int get_type () const { return m_data.which(); }
+
+ void deliver(BoostThreadWorker &runner);
+ };
+
+ using JobQueue = ThreadSafeQueueSPSC<JobEntry>;
+ using MessageQueue = ThreadSafeQueueSPSC<WorkerMessage>;
+
+ boost::thread m_thread;
+ std::atomic<bool> m_running{false}, m_canceled{false};
+ std::shared_ptr<ProgressIndicator> m_progress;
+ JobQueue m_input_queue; // from main thread to worker
+ MessageQueue m_output_queue; // form worker to main thread
+ std::string m_name;
+
+ void run();
+
+ bool join(int timeout_ms = 0);
+
+protected:
+ // Implement Job::Ctl interface:
+
+ void update_status(int st, const std::string &msg = "") override;
+
+ bool was_canceled() const override { return m_canceled.load(); }
+
+ std::future<void> call_on_main_thread(std::function<void()> fn) override;
+
+public:
+ explicit BoostThreadWorker(std::shared_ptr<ProgressIndicator> pri,
+ boost::thread::attributes & attr,
+ const char * name = "");
+
+ explicit BoostThreadWorker(std::shared_ptr<ProgressIndicator> pri,
+ boost::thread::attributes && attr,
+ const char * name = "")
+ : BoostThreadWorker{std::move(pri), attr, name}
+ {}
+
+ explicit BoostThreadWorker(std::shared_ptr<ProgressIndicator> pri,
+ const char * name = "")
+ : BoostThreadWorker{std::move(pri), {}, name}
+ {}
+
+ ~BoostThreadWorker();
+
+ BoostThreadWorker(const BoostThreadWorker &) = delete;
+ BoostThreadWorker(BoostThreadWorker &&) = delete;
+ BoostThreadWorker &operator=(const BoostThreadWorker &) = delete;
+ BoostThreadWorker &operator=(BoostThreadWorker &&) = delete;
+
+ bool push(std::unique_ptr<Job> job) override;
+
+ bool is_idle() const override
+ {
+ // The assumption is that jobs can only be queued from a single main
+ // thread from which this method is also called. And the output
+ // messages are also processed only in this calling thread. In that
+ // case, if the input queue is empty, it will remain so during this
+ // function call. If the worker thread is also not running and the
+ // output queue is already processed, we can safely say that the
+ // worker is dormant.
+ return m_input_queue.empty() && !m_running.load() && m_output_queue.empty();
+ }
+
+ void cancel() override { m_canceled.store(true); }
+ void cancel_all() override { m_input_queue.clear(); cancel(); }
+
+ ProgressIndicator * get_pri() { return m_progress.get(); }
+ const ProgressIndicator * get_pri() const { return m_progress.get(); }
+
+ void process_events() override;
+ bool wait_for_current_job(unsigned timeout_ms = 0) override;
+ bool wait_for_idle(unsigned timeout_ms = 0) override;
+
+};
+
+}} // namespace Slic3r::GUI
+
+#endif // BOOSTTHREADWORKER_HPP
diff --git a/src/slic3r/GUI/Jobs/BusyCursorJob.hpp b/src/slic3r/GUI/Jobs/BusyCursorJob.hpp
new file mode 100644
index 000000000..530213b1d
--- /dev/null
+++ b/src/slic3r/GUI/Jobs/BusyCursorJob.hpp
@@ -0,0 +1,48 @@
+#ifndef BUSYCURSORJOB_HPP
+#define BUSYCURSORJOB_HPP
+
+#include "Job.hpp"
+
+#include <wx/utils.h>
+
+namespace Slic3r { namespace GUI {
+
+struct CursorSetterRAII
+{
+ Job::Ctl &ctl;
+ CursorSetterRAII(Job::Ctl &c) : ctl{c}
+ {
+ ctl.call_on_main_thread([] { wxBeginBusyCursor(); });
+ }
+ ~CursorSetterRAII()
+ {
+ ctl.call_on_main_thread([] { wxEndBusyCursor(); });
+ }
+};
+
+template<class JobSubclass>
+class BusyCursored: public Job {
+ JobSubclass m_job;
+
+public:
+ template<class... Args>
+ BusyCursored(Args &&...args) : m_job{std::forward<Args>(args)...}
+ {}
+
+ void process(Ctl &ctl) override
+ {
+ CursorSetterRAII cursor_setter{ctl};
+ m_job.process(ctl);
+ }
+
+ void finalize(bool canceled, std::exception_ptr &eptr) override
+ {
+ m_job.finalize(canceled, eptr);
+ }
+};
+
+
+}
+}
+
+#endif // BUSYCURSORJOB_HPP
diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp
index 870f31f2f..c7d69eb50 100644
--- a/src/slic3r/GUI/Jobs/FillBedJob.cpp
+++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp
@@ -3,6 +3,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/ClipperUtils.hpp"
+#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
@@ -102,8 +103,12 @@ void FillBedJob::prepare()
p.translation(X) -= p.bed_idx * stride;
}
-void FillBedJob::process()
+void FillBedJob::process(Ctl &ctl)
{
+ auto statustxt = _u8L("Filling bed");
+ ctl.call_on_main_thread([this] { prepare(); }).wait();
+ ctl.update_status(0, statustxt);
+
if (m_object_idx == -1 || m_selected.empty()) return;
const GLCanvas3D::ArrangeSettings &settings =
@@ -114,13 +119,13 @@ void FillBedJob::process()
params.min_obj_distance = scaled(settings.distance);
bool do_stop = false;
- params.stopcondition = [this, &do_stop]() {
- return was_canceled() || do_stop;
+ params.stopcondition = [&ctl, &do_stop]() {
+ return ctl.was_canceled() || do_stop;
};
- params.progressind = [this](unsigned st) {
+ params.progressind = [this, &ctl, &statustxt](unsigned st) {
if (st > 0)
- update_status(int(m_status_range - st), _(L("Filling bed")));
+ ctl.update_status(int(m_status_range - st) * 100 / status_range(), statustxt);
};
params.on_packed = [&do_stop] (const ArrangePolygon &ap) {
@@ -130,15 +135,18 @@ void FillBedJob::process()
arrangement::arrange(m_selected, m_unselected, m_bedpts, params);
// finalize just here.
- update_status(m_status_range, was_canceled() ?
- _(L("Bed filling canceled.")) :
- _(L("Bed filling done.")));
+ ctl.update_status(100, ctl.was_canceled() ?
+ _u8L("Bed filling canceled.") :
+ _u8L("Bed filling done."));
}
-void FillBedJob::finalize()
+FillBedJob::FillBedJob() : m_plater{wxGetApp().plater()} {}
+
+void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
{
// Ignore the arrange result if aborted.
- if (was_canceled()) return;
+ if (canceled || eptr)
+ return;
if (m_object_idx == -1) return;
@@ -167,8 +175,6 @@ void FillBedJob::finalize()
m_plater->sidebar()
.obj_list()->increase_object_instances(m_object_idx, size_t(added_cnt));
}
-
- Job::finalize();
}
}} // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/Jobs/FillBedJob.hpp b/src/slic3r/GUI/Jobs/FillBedJob.hpp
index bf407656d..b1417bbbd 100644
--- a/src/slic3r/GUI/Jobs/FillBedJob.hpp
+++ b/src/slic3r/GUI/Jobs/FillBedJob.hpp
@@ -7,9 +7,9 @@ namespace Slic3r { namespace GUI {
class Plater;
-class FillBedJob : public PlaterJob
+class FillBedJob : public Job
{
- int m_object_idx = -1;
+ int m_object_idx = -1;
using ArrangePolygon = arrangement::ArrangePolygon;
using ArrangePolygons = arrangement::ArrangePolygons;
@@ -20,23 +20,20 @@ class FillBedJob : public PlaterJob
Points m_bedpts;
int m_status_range = 0;
-
-protected:
-
- void prepare() override;
- void process() override;
+ Plater *m_plater;
public:
- FillBedJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater)
- : PlaterJob{std::move(pri), plater}
- {}
+ void prepare();
+ void process(Ctl &ctl) override;
+
+ FillBedJob();
- int status_range() const override
+ int status_range() const /*override*/
{
return m_status_range;
}
- void finalize() override;
+ void finalize(bool canceled, std::exception_ptr &e) override;
};
}} // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/Jobs/Job.cpp b/src/slic3r/GUI/Jobs/Job.cpp
deleted file mode 100644
index 9d0d4bc80..000000000
--- a/src/slic3r/GUI/Jobs/Job.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-#include <algorithm>
-#include <exception>
-
-#include "Job.hpp"
-#include <libslic3r/Thread.hpp>
-#include <boost/log/trivial.hpp>
-
-namespace Slic3r {
-
-void GUI::Job::run(std::exception_ptr &eptr)
-{
- m_running.store(true);
- try {
- process();
- } catch (...) {
- eptr = std::current_exception();
- }
-
- m_running.store(false);
-
- // ensure to call the last status to finalize the job
- update_status(status_range(), "");
-}
-
-void GUI::Job::update_status(int st, const wxString &msg)
-{
- auto evt = new wxThreadEvent(wxEVT_THREAD, m_thread_evt_id);
- evt->SetInt(st);
- evt->SetString(msg);
- wxQueueEvent(this, evt);
-}
-
-GUI::Job::Job(std::shared_ptr<ProgressIndicator> pri)
- : m_progress(std::move(pri))
-{
- m_thread_evt_id = wxNewId();
-
- Bind(wxEVT_THREAD, [this](const wxThreadEvent &evt) {
- if (m_finalizing) return;
-
- auto msg = evt.GetString();
- if (!msg.empty() && !m_worker_error)
- m_progress->set_status_text(msg.ToUTF8().data());
-
- if (m_finalized) return;
-
- m_progress->set_progress(evt.GetInt());
- if (evt.GetInt() == status_range() || m_worker_error) {
- // set back the original range and cancel callback
- m_progress->set_range(m_range);
- // Make sure progress indicators get the last value of their range
- // to make sure they close, fade out, whathever
- m_progress->set_progress(m_range);
- m_progress->set_cancel_callback();
- wxEndBusyCursor();
-
- if (m_worker_error) {
- m_finalized = true;
- m_progress->set_status_text("");
- m_progress->set_progress(m_range);
- on_exception(m_worker_error);
- }
- else {
- // This is an RAII solution to remember that finalization is
- // running. The run method calls update_status(status_range(), "")
- // at the end, which queues up a call to this handler in all cases.
- // If process also calls update_status with maxed out status arg
- // it will call this handler twice. It is not a problem unless
- // yield is called inside the finilize() method, which would
- // jump out of finalize and call this handler again.
- struct Finalizing {
- bool &flag;
- Finalizing (bool &f): flag(f) { flag = true; }
- ~Finalizing() { flag = false; }
- } fin(m_finalizing);
-
- finalize();
- }
-
- // dont do finalization again for the same process
- m_finalized = true;
- }
- }, m_thread_evt_id);
-}
-
-void GUI::Job::start()
-{ // Start the job. No effect if the job is already running
- if (!m_running.load()) {
- prepare();
-
- // Save the current status indicatior range and push the new one
- m_range = m_progress->get_range();
- m_progress->set_range(status_range());
-
- // init cancellation flag and set the cancel callback
- m_canceled.store(false);
- m_progress->set_cancel_callback(
- [this]() { m_canceled.store(true); });
-
- m_finalized = false;
- m_finalizing = false;
-
- // Changing cursor to busy
- wxBeginBusyCursor();
-
- try { // Execute the job
- m_worker_error = nullptr;
- m_thread = create_thread([this] { this->run(m_worker_error); });
- } catch (std::exception &) {
- update_status(status_range(),
- _(L("ERROR: not enough resources to "
- "execute a new job.")));
- }
-
- // The state changes will be undone when the process hits the
- // last status value, in the status update handler (see ctor)
- }
-}
-
-bool GUI::Job::join(int timeout_ms)
-{
- if (!m_thread.joinable()) return true;
-
- if (timeout_ms <= 0)
- m_thread.join();
- else if (!m_thread.try_join_for(boost::chrono::milliseconds(timeout_ms)))
- return false;
-
- return true;
-}
-
-void GUI::ExclusiveJobGroup::start(size_t jid) {
- assert(jid < m_jobs.size());
- stop_all();
- m_jobs[jid]->start();
-}
-
-void GUI::ExclusiveJobGroup::join_all(int wait_ms)
-{
- std::vector<bool> aborted(m_jobs.size(), false);
-
- for (size_t jid = 0; jid < m_jobs.size(); ++jid)
- aborted[jid] = m_jobs[jid]->join(wait_ms);
-
- if (!std::all_of(aborted.begin(), aborted.end(), [](bool t) { return t; }))
- BOOST_LOG_TRIVIAL(error) << "Could not abort a job!";
-}
-
-bool GUI::ExclusiveJobGroup::is_any_running() const
-{
- return std::any_of(m_jobs.begin(), m_jobs.end(),
- [](const std::unique_ptr<GUI::Job> &j) {
- return j->is_running();
- });
-}
-
-}
-
diff --git a/src/slic3r/GUI/Jobs/Job.hpp b/src/slic3r/GUI/Jobs/Job.hpp
index 8243ce943..824c0b830 100644
--- a/src/slic3r/GUI/Jobs/Job.hpp
+++ b/src/slic3r/GUI/Jobs/Job.hpp
@@ -3,119 +3,53 @@
#include <atomic>
#include <exception>
+#include <future>
#include "libslic3r/libslic3r.h"
-
-#include <slic3r/GUI/I18N.hpp>
-
#include "ProgressIndicator.hpp"
-#include <wx/event.h>
+namespace Slic3r { namespace GUI {
-#include <boost/thread.hpp>
+// A class representing a job that is to be run in the background, not blocking
+// the main thread. Running it is up to a Worker object (see Worker interface)
+class Job {
+public:
-namespace Slic3r { namespace GUI {
+ // A controller interface that informs the job about cancellation and
+ // makes it possible for the job to advertise its status.
+ class Ctl {
+ public:
+ virtual ~Ctl() = default;
-// A class to handle UI jobs like arranging and optimizing rotation.
-// These are not instant jobs, the user has to be informed about their
-// state in the status progress indicator. On the other hand they are
-// separated from the background slicing process. Ideally, these jobs should
-// run when the background process is not running.
-//
-// TODO: A mechanism would be useful for blocking the plater interactions:
-// objects would be frozen for the user. In case of arrange, an animation
-// could be shown, or with the optimize orientations, partial results
-// could be displayed.
-class Job : public wxEvtHandler
-{
- int m_range = 100;
- int m_thread_evt_id = wxID_ANY;
- boost::thread m_thread;
- std::atomic<bool> m_running{false}, m_canceled{false};
- bool m_finalized = false, m_finalizing = false;
- std::shared_ptr<ProgressIndicator> m_progress;
- std::exception_ptr m_worker_error = nullptr;
-
- void run(std::exception_ptr &);
-
-protected:
- // status range for a particular job
- virtual int status_range() const { return 100; }
-
- // status update, to be used from the work thread (process() method)
- void update_status(int st, const wxString &msg = "");
+ // status update, to be used from the work thread (process() method)
+ virtual void update_status(int st, const std::string &msg = "") = 0;
- bool was_canceled() const { return m_canceled.load(); }
+ // Returns true if the job was asked to cancel itself.
+ virtual bool was_canceled() const = 0;
- // Launched just before start(), a job can use it to prepare internals
- virtual void prepare() {}
+ // Execute a functor on the main thread. Note that the exact time of
+ // execution is hard to determine. This can be used to make modifications
+ // on the UI, like displaying some intermediate results or modify the
+ // cursor.
+ // This function returns a std::future<void> object which enables the
+ // caller to optionally wait for the main thread to finish the function call.
+ virtual std::future<void> call_on_main_thread(std::function<void()> fn) = 0;
+ };
- // The method where the actual work of the job should be defined.
- virtual void process() = 0;
-
- // Launched when the job is finished. It refreshes the 3Dscene by def.
- virtual void finalize() { m_finalized = true; }
+ virtual ~Job() = default;
- // Exceptions occuring in process() are redirected from the worker thread
- // into the main (UI) thread. This method is called from the main thread and
- // can be overriden to handle these exceptions.
- virtual void on_exception(const std::exception_ptr &eptr)
- {
- if (eptr) std::rethrow_exception(eptr);
- }
-
-public:
- Job(std::shared_ptr<ProgressIndicator> pri);
-
- bool is_finalized() const { return m_finalized; }
-
- Job(const Job &) = delete;
- Job(Job &&) = delete;
- Job &operator=(const Job &) = delete;
- Job &operator=(Job &&) = delete;
-
- void start();
-
- // To wait for the running job and join the threads. False is
- // returned if the timeout has been reached and the job is still
- // running. Call cancel() before this fn if you want to explicitly
- // end the job.
- bool join(int timeout_ms = 0);
-
- bool is_running() const { return m_running.load(); }
- void cancel() { m_canceled.store(true); }
-};
+ // The method where the actual work of the job should be defined. This is
+ // run on the worker thread.
+ virtual void process(Ctl &ctl) = 0;
-// Jobs defined inside the group class will be managed so that only one can
-// run at a time. Also, the background process will be stopped if a job is
-// started.
-class ExclusiveJobGroup
-{
- static const int ABORT_WAIT_MAX_MS = 10000;
-
- std::vector<std::unique_ptr<GUI::Job>> m_jobs;
-
-protected:
- virtual void before_start() {}
-
-public:
- virtual ~ExclusiveJobGroup() = default;
-
- size_t add_job(std::unique_ptr<GUI::Job> &&job)
- {
- m_jobs.emplace_back(std::move(job));
- return m_jobs.size() - 1;
- }
-
- void start(size_t jid);
-
- void cancel_all() { for (auto& j : m_jobs) j->cancel(); }
-
- void join_all(int wait_ms = 0);
-
- void stop_all() { cancel_all(); join_all(ABORT_WAIT_MAX_MS); }
-
- bool is_any_running() const;
+ // Launched when the job is finished on the UI thread.
+ // If the job was cancelled, the first parameter will have a true value.
+ // Exceptions occuring in process() are redirected from the worker thread
+ // into the main (UI) thread. This method receives the exception and can
+ // handle it properly. Assign nullptr to this second argument before
+ // function return to prevent further action. Leaving it with a non-null
+ // value will result in rethrowing by the worker.
+ virtual void finalize(bool /*canceled*/, std::exception_ptr &) {}
};
}} // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp
index cb7170568..f398f7333 100644
--- a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp
+++ b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp
@@ -12,11 +12,15 @@ void NotificationProgressIndicator::set_range(int range)
void NotificationProgressIndicator::set_cancel_callback(CancelFn fn)
{
- m_nm->progress_indicator_set_cancel_callback(std::move(fn));
+ m_cancelfn = std::move(fn);
+ m_nm->progress_indicator_set_cancel_callback(m_cancelfn);
}
void NotificationProgressIndicator::set_progress(int pr)
{
+ if (!pr)
+ set_cancel_callback(m_cancelfn);
+
m_nm->progress_indicator_set_progress(pr);
}
diff --git a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp
index 6b03af69d..b31cb7f7c 100644
--- a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp
+++ b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp
@@ -9,7 +9,7 @@ class NotificationManager;
class NotificationProgressIndicator: public ProgressIndicator {
NotificationManager *m_nm = nullptr;
-
+ CancelFn m_cancelfn;
public:
explicit NotificationProgressIndicator(NotificationManager *nm);
diff --git a/src/slic3r/GUI/Jobs/PlaterJob.cpp b/src/slic3r/GUI/Jobs/PlaterJob.cpp
deleted file mode 100644
index 4af205d41..000000000
--- a/src/slic3r/GUI/Jobs/PlaterJob.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "PlaterJob.hpp"
-#include "slic3r/GUI/GUI.hpp"
-#include "slic3r/GUI/Plater.hpp"
-
-namespace Slic3r { namespace GUI {
-
-void PlaterJob::on_exception(const std::exception_ptr &eptr)
-{
- try {
- if (eptr)
- std::rethrow_exception(eptr);
- } catch (std::exception &e) {
- show_error(m_plater, _(L("An unexpected error occured")) + ": "+ e.what());
- }
-}
-
-}} // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/Jobs/PlaterJob.hpp b/src/slic3r/GUI/Jobs/PlaterJob.hpp
deleted file mode 100644
index fcf0a54b8..000000000
--- a/src/slic3r/GUI/Jobs/PlaterJob.hpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef PLATERJOB_HPP
-#define PLATERJOB_HPP
-
-#include "Job.hpp"
-
-namespace Slic3r { namespace GUI {
-
-class Plater;
-
-class PlaterJob : public Job {
-protected:
- Plater *m_plater;
-
- void on_exception(const std::exception_ptr &) override;
-
-public:
-
- PlaterJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater):
- Job{std::move(pri)}, m_plater{plater} {}
-};
-
-}} // namespace Slic3r::GUI
-
-#endif // PLATERJOB_HPP
diff --git a/src/slic3r/GUI/Jobs/PlaterWorker.hpp b/src/slic3r/GUI/Jobs/PlaterWorker.hpp
new file mode 100644
index 000000000..573590272
--- /dev/null
+++ b/src/slic3r/GUI/Jobs/PlaterWorker.hpp
@@ -0,0 +1,127 @@
+#ifndef PLATERWORKER_HPP
+#define PLATERWORKER_HPP
+
+#include <map>
+
+#include "Worker.hpp"
+#include "BusyCursorJob.hpp"
+
+#include "slic3r/GUI/GUI.hpp"
+#include "slic3r/GUI/GUI_App.hpp"
+#include "slic3r/GUI/I18N.hpp"
+#include "slic3r/GUI/Plater.hpp"
+#include "slic3r/GUI/GLCanvas3D.hpp"
+
+namespace Slic3r { namespace GUI {
+
+class Plater;
+
+template<class WorkerSubclass>
+class PlaterWorker: public Worker {
+ WorkerSubclass m_w;
+ Plater *m_plater;
+
+ class PlaterJob : public Job {
+ std::unique_ptr<Job> m_job;
+ Plater *m_plater;
+
+ public:
+ void process(Ctl &c) override
+ {
+ // Ensure that wxWidgets processing wakes up to handle outgoing
+ // messages in plater's wxIdle handler. Otherwise it might happen
+ // that the message will only be processed when an event like mouse
+ // move comes along which might be too late.
+ struct WakeUpCtl: Ctl {
+ Ctl &ctl;
+ WakeUpCtl(Ctl &c) : ctl{c} {}
+
+ void update_status(int st, const std::string &msg = "") override
+ {
+ wxWakeUpIdle();
+ ctl.update_status(st, msg);
+ }
+
+ bool was_canceled() const override { return ctl.was_canceled(); }
+
+ std::future<void> call_on_main_thread(std::function<void()> fn) override
+ {
+ wxWakeUpIdle();
+ return ctl.call_on_main_thread(std::move(fn));
+ }
+
+ } wctl{c};
+
+ CursorSetterRAII busycursor{wctl};
+ m_job->process(wctl);
+ }
+
+ void finalize(bool canceled, std::exception_ptr &eptr) override
+ {
+ m_job->finalize(canceled, eptr);
+
+ if (eptr) try {
+ std::rethrow_exception(eptr);
+ } catch (std::exception &e) {
+ show_error(m_plater, _L("An unexpected error occured: ") + e.what());
+ eptr = nullptr;
+ }
+ }
+
+ PlaterJob(Plater *p, std::unique_ptr<Job> j)
+ : m_job{std::move(j)}, m_plater{p}
+ {
+ // TODO: decide if disabling slice button during UI job is what we
+ // want.
+ // if (m_plater)
+ // m_plater->sidebar().enable_buttons(false);
+ }
+
+ ~PlaterJob() override
+ {
+ // TODO: decide if disabling slice button during UI job is what we want.
+
+ // Reload scene ensures that the slice button gets properly
+ // enabled or disabled after the job finishes, depending on the
+ // state of slicing. This might be an overkill but works for now.
+ // if (m_plater)
+ // m_plater->canvas3D()->reload_scene(false);
+ }
+ };
+
+public:
+
+ template<class... WorkerArgs>
+ PlaterWorker(Plater *plater, WorkerArgs &&...args)
+ : m_w{std::forward<WorkerArgs>(args)...}, m_plater{plater}
+ {
+ // Ensure that messages from the worker thread to the UI thread are
+ // processed continuously.
+ plater->Bind(wxEVT_IDLE, [this](wxIdleEvent &) {
+ process_events();
+ });
+ }
+
+ // Always package the job argument into a PlaterJob
+ bool push(std::unique_ptr<Job> job) override
+ {
+ return m_w.push(std::make_unique<PlaterJob>(m_plater, std::move(job)));
+ }
+
+ bool is_idle() const override { return m_w.is_idle(); }
+ void cancel() override { m_w.cancel(); }
+ void cancel_all() override { m_w.cancel_all(); }
+ void process_events() override { m_w.process_events(); }
+ bool wait_for_current_job(unsigned timeout_ms = 0) override
+ {
+ return m_w.wait_for_current_job(timeout_ms);
+ }
+ bool wait_for_idle(unsigned timeout_ms = 0) override
+ {
+ return m_w.wait_for_idle(timeout_ms);
+ }
+};
+
+}} // namespace Slic3r::GUI
+
+#endif // PLATERJOB_HPP
diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
index 95821a674..e88d24fcd 100644
--- a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
+++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
@@ -12,6 +12,8 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "libslic3r/AppConfig.hpp"
+#include <slic3r/GUI/I18N.hpp>
+
namespace Slic3r { namespace GUI {
void RotoptimizeJob::prepare()
@@ -45,20 +47,23 @@ void RotoptimizeJob::prepare()
}
}
-void RotoptimizeJob::process()
+void RotoptimizeJob::process(Ctl &ctl)
{
int prev_status = 0;
+ auto statustxt = _u8L("Searching for optimal orientation");
+ ctl.update_status(0, statustxt);
+
auto params =
sla::RotOptimizeParams{}
.accuracy(m_accuracy)
.print_config(&m_default_print_cfg)
- .statucb([this, &prev_status](int s)
+ .statucb([this, &prev_status, &ctl, &statustxt](int s)
{
if (s > 0 && s < 100)
- update_status(prev_status + s / m_selected_object_ids.size(),
- _(L("Searching for optimal orientation")));
+ ctl.update_status(prev_status + s / m_selected_object_ids.size(),
+ statustxt);
- return !was_canceled();
+ return !ctl.was_canceled();
});
@@ -71,16 +76,20 @@ void RotoptimizeJob::process()
prev_status += 100 / m_selected_object_ids.size();
- if (was_canceled()) break;
+ if (ctl.was_canceled()) break;
}
- update_status(100, was_canceled() ? _(L("Orientation search canceled.")) :
- _(L("Orientation found.")));
+ ctl.update_status(100, ctl.was_canceled() ?
+ _u8L("Orientation search canceled.") :
+ _u8L("Orientation found."));
}
-void RotoptimizeJob::finalize()
+RotoptimizeJob::RotoptimizeJob() : m_plater{wxGetApp().plater()} { prepare(); }
+
+void RotoptimizeJob::finalize(bool canceled, std::exception_ptr &eptr)
{
- if (was_canceled()) return;
+ if (canceled || eptr)
+ return;
for (const ObjRot &objrot : m_selected_object_ids) {
ModelObject *o = m_plater->model().objects[size_t(objrot.idx)];
@@ -111,10 +120,8 @@ void RotoptimizeJob::finalize()
// m_plater->find_new_position(o->instances);
}
- if (!was_canceled())
+ if (!canceled)
m_plater->update();
-
- Job::finalize();
}
}}
diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
index cdb367f23..71a28deb7 100644
--- a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
+++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
@@ -1,16 +1,17 @@
#ifndef ROTOPTIMIZEJOB_HPP
#define ROTOPTIMIZEJOB_HPP
-#include "PlaterJob.hpp"
+#include "Job.hpp"
#include "libslic3r/SLA/Rotfinder.hpp"
#include "libslic3r/PrintConfig.hpp"
+#include "slic3r/GUI/I18N.hpp"
-namespace Slic3r {
+namespace Slic3r { namespace GUI {
-namespace GUI {
+class Plater;
-class RotoptimizeJob : public PlaterJob
+class RotoptimizeJob : public Job
{
using FindFn = std::function<Vec2d(const ModelObject & mo,
const sla::RotOptimizeParams &params)>;
@@ -44,19 +45,16 @@ class RotoptimizeJob : public PlaterJob
};
std::vector<ObjRot> m_selected_object_ids;
-
-protected:
-
- void prepare() override;
- void process() override;
+ Plater *m_plater;
public:
- RotoptimizeJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater)
- : PlaterJob{std::move(pri), plater}
- {}
+ void prepare();
+ void process(Ctl &ctl) override;
+
+ RotoptimizeJob();
- void finalize() override;
+ void finalize(bool canceled, std::exception_ptr &) override;
static constexpr size_t get_methods_count() { return std::size(Methods); }
diff --git a/src/slic3r/GUI/Jobs/SLAImportDialog.hpp b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp
new file mode 100644
index 000000000..7dbecff2a
--- /dev/null
+++ b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp
@@ -0,0 +1,114 @@
+#ifndef SLAIMPORTDIALOG_HPP
+#define SLAIMPORTDIALOG_HPP
+
+#include "SLAImportJob.hpp"
+
+#include <wx/dialog.h>
+#include <wx/stattext.h>
+#include <wx/combobox.h>
+#include <wx/filename.h>
+#include <wx/filepicker.h>
+
+#include "libslic3r/AppConfig.hpp"
+#include "slic3r/GUI/I18N.hpp"
+
+#include "slic3r/GUI/GUI.hpp"
+#include "slic3r/GUI/GUI_App.hpp"
+#include "slic3r/GUI/Plater.hpp"
+
+//#include "libslic3r/Model.hpp"
+//#include "libslic3r/PresetBundle.hpp"
+
+namespace Slic3r { namespace GUI {
+
+class SLAImportDialog: public wxDialog, public SLAImportJobView {
+ wxFilePickerCtrl *m_filepicker;
+ wxComboBox *m_import_dropdown, *m_quality_dropdown;
+
+public:
+ SLAImportDialog(Plater *plater)
+ : wxDialog{plater, wxID_ANY, "Import SLA archive"}
+ {
+ auto szvert = new wxBoxSizer{wxVERTICAL};
+ auto szfilepck = new wxBoxSizer{wxHORIZONTAL};
+
+ m_filepicker = new wxFilePickerCtrl(this, wxID_ANY,
+ from_u8(wxGetApp().app_config->get_last_dir()), _(L("Choose SLA archive:")),
+ "SL1 / SL1S archive files (*.sl1, *.sl1s, *.zip)|*.sl1;*.SL1;*.sl1s;*.SL1S;*.zip;*.ZIP",
+ wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE | wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+
+ szfilepck->Add(new wxStaticText(this, wxID_ANY, _L("Import file") + ": "), 0, wxALIGN_CENTER);
+ szfilepck->Add(m_filepicker, 1);
+ szvert->Add(szfilepck, 0, wxALL | wxEXPAND, 5);
+
+ auto szchoices = new wxBoxSizer{wxHORIZONTAL};
+
+ static const std::vector<wxString> inp_choices = {
+ _(L("Import model and profile")),
+ _(L("Import profile only")),
+ _(L("Import model only"))
+ };
+
+ m_import_dropdown = new wxComboBox(
+ this, wxID_ANY, inp_choices[0], wxDefaultPosition, wxDefaultSize,
+ inp_choices.size(), inp_choices.data(), wxCB_READONLY | wxCB_DROPDOWN);
+
+ szchoices->Add(m_import_dropdown);
+ szchoices->Add(new wxStaticText(this, wxID_ANY, _L("Quality") + ": "), 0, wxALIGN_CENTER | wxALL, 5);
+
+ static const std::vector<wxString> qual_choices = {
+ _(L("Accurate")),
+ _(L("Balanced")),
+ _(L("Quick"))
+ };
+
+ m_quality_dropdown = new wxComboBox(
+ this, wxID_ANY, qual_choices[0], wxDefaultPosition, wxDefaultSize,
+ qual_choices.size(), qual_choices.data(), wxCB_READONLY | wxCB_DROPDOWN);
+ szchoices->Add(m_quality_dropdown);
+
+ m_import_dropdown->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &) {
+ if (get_selection() == Sel::profileOnly)
+ m_quality_dropdown->Disable();
+ else m_quality_dropdown->Enable();
+ });
+
+ szvert->Add(szchoices, 0, wxALL, 5);
+ szvert->AddStretchSpacer(1);
+ auto szbtn = new wxBoxSizer(wxHORIZONTAL);
+ szbtn->Add(new wxButton{this, wxID_CANCEL});
+ szbtn->Add(new wxButton{this, wxID_OK});
+ szvert->Add(szbtn, 0, wxALIGN_RIGHT | wxALL, 5);
+
+ SetSizerAndFit(szvert);
+ }
+
+ Sel get_selection() const override
+ {
+ int sel = m_import_dropdown->GetSelection();
+ return Sel(std::min(int(Sel::modelOnly), std::max(0, sel)));
+ }
+
+ Vec2i get_marchsq_windowsize() const override
+ {
+ enum { Accurate, Balanced, Fast};
+
+ switch(m_quality_dropdown->GetSelection())
+ {
+ case Fast: return {8, 8};
+ case Balanced: return {4, 4};
+ default:
+ case Accurate:
+ return {2, 2};
+ }
+ }
+
+ std::string get_path() const override
+ {
+ return m_filepicker->GetPath().ToUTF8().data();
+ }
+};
+
+}} // namespace Slic3r::GUI
+
+#endif // SLAIMPORTDIALOG_HPP
diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp
index 0d42cec2d..1bb8cdf6c 100644
--- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp
+++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp
@@ -3,7 +3,6 @@
#include "libslic3r/Format/SL1.hpp"
#include "slic3r/GUI/GUI.hpp"
-#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/GUI/NotificationManager.hpp"
@@ -11,104 +10,10 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/PresetBundle.hpp"
-#include <wx/dialog.h>
-#include <wx/stattext.h>
-#include <wx/combobox.h>
#include <wx/filename.h>
-#include <wx/filepicker.h>
namespace Slic3r { namespace GUI {
-enum class Sel { modelAndProfile, profileOnly, modelOnly};
-
-class ImportDlg: public wxDialog {
- wxFilePickerCtrl *m_filepicker;
- wxComboBox *m_import_dropdown, *m_quality_dropdown;
-
-public:
- ImportDlg(Plater *plater)
- : wxDialog{plater, wxID_ANY, "Import SLA archive"}
- {
- auto szvert = new wxBoxSizer{wxVERTICAL};
- auto szfilepck = new wxBoxSizer{wxHORIZONTAL};
-
- m_filepicker = new wxFilePickerCtrl(this, wxID_ANY,
- from_u8(wxGetApp().app_config->get_last_dir()), _(L("Choose SLA archive:")),
- "SL1 / SL1S archive files (*.sl1, *.sl1s, *.zip)|*.sl1;*.SL1;*.sl1s;*.SL1S;*.zip;*.ZIP",
- wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE | wxFD_OPEN | wxFD_FILE_MUST_EXIST);
-
- szfilepck->Add(new wxStaticText(this, wxID_ANY, _L("Import file") + ": "), 0, wxALIGN_CENTER);
- szfilepck->Add(m_filepicker, 1);
- szvert->Add(szfilepck, 0, wxALL | wxEXPAND, 5);
-
- auto szchoices = new wxBoxSizer{wxHORIZONTAL};
-
- static const std::vector<wxString> inp_choices = {
- _(L("Import model and profile")),
- _(L("Import profile only")),
- _(L("Import model only"))
- };
-
- m_import_dropdown = new wxComboBox(
- this, wxID_ANY, inp_choices[0], wxDefaultPosition, wxDefaultSize,
- inp_choices.size(), inp_choices.data(), wxCB_READONLY | wxCB_DROPDOWN);
-
- szchoices->Add(m_import_dropdown);
- szchoices->Add(new wxStaticText(this, wxID_ANY, _L("Quality") + ": "), 0, wxALIGN_CENTER | wxALL, 5);
-
- static const std::vector<wxString> qual_choices = {
- _(L("Accurate")),
- _(L("Balanced")),
- _(L("Quick"))
- };
-
- m_quality_dropdown = new wxComboBox(
- this, wxID_ANY, qual_choices[0], wxDefaultPosition, wxDefaultSize,
- qual_choices.size(), qual_choices.data(), wxCB_READONLY | wxCB_DROPDOWN);
- szchoices->Add(m_quality_dropdown);
-
- m_import_dropdown->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &) {
- if (get_selection() == Sel::profileOnly)
- m_quality_dropdown->Disable();
- else m_quality_dropdown->Enable();
- });
-
- szvert->Add(szchoices, 0, wxALL, 5);
- szvert->AddStretchSpacer(1);
- auto szbtn = new wxBoxSizer(wxHORIZONTAL);
- szbtn->Add(new wxButton{this, wxID_CANCEL});
- szbtn->Add(new wxButton{this, wxID_OK});
- szvert->Add(szbtn, 0, wxALIGN_RIGHT | wxALL, 5);
-
- SetSizerAndFit(szvert);
- }
-
- Sel get_selection() const
- {
- int sel = m_import_dropdown->GetSelection();
- return Sel(std::min(int(Sel::modelOnly), std::max(0, sel)));
- }
-
- Vec2i get_marchsq_windowsize() const
- {
- enum { Accurate, Balanced, Fast};
-
- switch(m_quality_dropdown->GetSelection())
- {
- case Fast: return {8, 8};
- case Balanced: return {4, 4};
- default:
- case Accurate:
- return {2, 2};
- }
- }
-
- wxString get_path() const
- {
- return m_filepicker->GetPath();
- }
-};
-
class SLAImportJob::priv {
public:
Plater *plater;
@@ -122,23 +27,28 @@ public:
std::string err;
ConfigSubstitutions config_substitutions;
- ImportDlg import_dlg;
+ const SLAImportJobView * import_dlg;
- priv(Plater *plt) : plater{plt}, import_dlg{plt} {}
+ priv(Plater *plt, const SLAImportJobView *view) : plater{plt}, import_dlg{view} {}
};
-SLAImportJob::SLAImportJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater)
- : PlaterJob{std::move(pri), plater}, p{std::make_unique<priv>(plater)}
-{}
+SLAImportJob::SLAImportJob(const SLAImportJobView *view)
+ : p{std::make_unique<priv>(wxGetApp().plater(), view)}
+{
+ prepare();
+}
SLAImportJob::~SLAImportJob() = default;
-void SLAImportJob::process()
+void SLAImportJob::process(Ctl &ctl)
{
- auto progr = [this](int s) {
+ auto statustxt = _u8L("Importing SLA archive");
+ ctl.update_status(0, statustxt);
+
+ auto progr = [&ctl, &statustxt](int s) {
if (s < 100)
- update_status(int(s), _(L("Importing SLA archive")));
- return !was_canceled();
+ ctl.update_status(int(s), statustxt);
+ return !ctl.was_canceled();
};
if (p->path.empty()) return;
@@ -161,15 +71,15 @@ void SLAImportJob::process()
p->err = ex.what();
}
- update_status(100, was_canceled() ? _(L("Importing canceled.")) :
- _(L("Importing done.")));
+ ctl.update_status(100, ctl.was_canceled() ? _u8L("Importing canceled.") :
+ _u8L("Importing done."));
}
void SLAImportJob::reset()
{
p->sel = Sel::modelAndProfile;
p->mesh = {};
- p->profile = m_plater->sla_print().full_print_config();
+ p->profile = p->plater->sla_print().full_print_config();
p->win = {2, 2};
p->path.Clear();
}
@@ -178,22 +88,19 @@ void SLAImportJob::prepare()
{
reset();
- if (p->import_dlg.ShowModal() == wxID_OK) {
- auto path = p->import_dlg.get_path();
- auto nm = wxFileName(path);
- p->path = !nm.Exists(wxFILE_EXISTS_REGULAR) ? "" : nm.GetFullPath();
- p->sel = p->import_dlg.get_selection();
- p->win = p->import_dlg.get_marchsq_windowsize();
- p->config_substitutions.clear();
- } else {
- p->path = "";
- }
+ auto path = p->import_dlg->get_path();
+ auto nm = wxFileName(path);
+ p->path = !nm.Exists(wxFILE_EXISTS_REGULAR) ? "" : nm.GetFullPath();
+ p->sel = p->import_dlg->get_selection();
+ p->win = p->import_dlg->get_marchsq_windowsize();
+ p->config_substitutions.clear();
}
-void SLAImportJob::finalize()
+void SLAImportJob::finalize(bool canceled, std::exception_ptr &eptr)
{
// Ignore the arrange result if aborted.
- if (was_canceled()) return;
+ if (canceled || eptr)
+ return;
if (!p->err.empty()) {
show_error(p->plater, p->err);
@@ -204,7 +111,7 @@ void SLAImportJob::finalize()
std::string name = wxFileName(p->path).GetName().ToUTF8().data();
if (p->profile.empty()) {
- m_plater->get_notification_manager()->push_notification(
+ p->plater->get_notification_manager()->push_notification(
NotificationType::CustomNotification,
NotificationManager::NotificationLevel::WarningNotificationLevel,
_L("The imported SLA archive did not contain any presets. "
@@ -213,7 +120,7 @@ void SLAImportJob::finalize()
if (p->sel != Sel::modelOnly) {
if (p->profile.empty())
- p->profile = m_plater->sla_print().full_print_config();
+ p->profile = p->plater->sla_print().full_print_config();
const ModelObjectPtrs& objects = p->plater->model().objects;
for (auto object : objects)
diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.hpp b/src/slic3r/GUI/Jobs/SLAImportJob.hpp
index c2ca10ef6..b2aea8bf8 100644
--- a/src/slic3r/GUI/Jobs/SLAImportJob.hpp
+++ b/src/slic3r/GUI/Jobs/SLAImportJob.hpp
@@ -1,22 +1,37 @@
#ifndef SLAIMPORTJOB_HPP
#define SLAIMPORTJOB_HPP
-#include "PlaterJob.hpp"
+#include "Job.hpp"
+
+#include "libslic3r/Point.hpp"
namespace Slic3r { namespace GUI {
-class SLAImportJob : public PlaterJob {
+class SLAImportJobView {
+public:
+ enum Sel { modelAndProfile, profileOnly, modelOnly};
+
+ virtual ~SLAImportJobView() = default;
+
+ virtual Sel get_selection() const = 0;
+ virtual Vec2i get_marchsq_windowsize() const = 0;
+ virtual std::string get_path() const = 0;
+};
+
+class Plater;
+
+class SLAImportJob : public Job {
class priv;
std::unique_ptr<priv> p;
-
-protected:
- void prepare() override;
- void process() override;
- void finalize() override;
+ using Sel = SLAImportJobView::Sel;
public:
- SLAImportJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater);
+ void prepare();
+ void process(Ctl &ctl) override;
+ void finalize(bool canceled, std::exception_ptr &) override;
+
+ SLAImportJob(const SLAImportJobView *);
~SLAImportJob();
void reset();
diff --git a/src/slic3r/GUI/Jobs/ThreadSafeQueue.hpp b/src/slic3r/GUI/Jobs/ThreadSafeQueue.hpp
new file mode 100644
index 000000000..d40049013
--- /dev/null
+++ b/src/slic3r/GUI/Jobs/ThreadSafeQueue.hpp
@@ -0,0 +1,123 @@
+#ifndef THREADSAFEQUEUE_HPP
+#define THREADSAFEQUEUE_HPP
+
+#include <type_traits>
+#include <queue>
+#include <mutex>
+#include <condition_variable>
+#include <atomic>
+
+namespace Slic3r { namespace GUI {
+
+// Helper structure for overloads of ThreadSafeQueueSPSC::consume_one()
+// to block if the queue is empty.
+struct BlockingWait
+{
+ // Timeout to wait for the arrival of new element into the queue.
+ unsigned timeout_ms = 0;
+
+ // An optional atomic flag to set true if an incoming element gets
+ // consumed. The flag will be atomically set to true when popping the
+ // front of the queue.
+ std::atomic<bool> *pop_flag = nullptr;
+};
+
+// A thread safe queue for one producer and one consumer.
+template<class T,
+ template<class, class...> class Container = std::deque,
+ class... ContainerArgs>
+class ThreadSafeQueueSPSC
+{
+ std::queue<T, Container<T, ContainerArgs...>> m_queue;
+ mutable std::mutex m_mutex;
+ std::condition_variable m_cond_var;
+public:
+
+ // Consume one element, block if the queue is empty.
+ template<class Fn> bool consume_one(const BlockingWait &blkw, Fn &&fn)
+ {
+ static_assert(!std::is_reference_v<T>, "");
+ static_assert(std::is_default_constructible_v<T>, "");
+ static_assert(std::is_move_assignable_v<T> || std::is_copy_assignable_v<T>, "");
+
+ T el;
+ {
+ std::unique_lock lk{m_mutex};
+
+ auto pred = [this]{ return !m_queue.empty(); };
+ if (blkw.timeout_ms > 0) {
+ auto timeout = std::chrono::milliseconds(blkw.timeout_ms);
+ if (!m_cond_var.wait_for(lk, timeout, pred))
+ return false;
+ }
+ else
+ m_cond_var.wait(lk, pred);
+
+ if constexpr (std::is_move_assignable_v<T>)
+ el = std::move(m_queue.front());
+ else
+ el = m_queue.front();
+
+ m_queue.pop();
+
+ if (blkw.pop_flag)
+ // The optional flag is set before the lock us unlocked.
+ blkw.pop_flag->store(true);
+ }
+
+ fn(el);
+ return true;
+ }
+
+ // Consume one element, return true if consumed, false if queue was empty.
+ template<class Fn> bool consume_one(Fn &&fn)
+ {
+ T el;
+ {
+ std::unique_lock lk{m_mutex};
+ if (!m_queue.empty()) {
+ if constexpr (std::is_move_assignable_v<T>)
+ el = std::move(m_queue.front());
+ else
+ el = m_queue.front();
+
+ m_queue.pop();
+ } else
+ return false;
+ }
+
+ fn(el);
+
+ return true;
+ }
+
+ // Push element into the queue.
+ template<class...TArgs> void push(TArgs&&...el)
+ {
+ std::lock_guard lk{m_mutex};
+ m_queue.emplace(std::forward<TArgs>(el)...);
+ m_cond_var.notify_one();
+ }
+
+ bool empty() const
+ {
+ std::lock_guard lk{m_mutex};
+ return m_queue.empty();
+ }
+
+ size_t size() const
+ {
+ std::lock_guard lk{m_mutex};
+ return m_queue.size();
+ }
+
+ void clear()
+ {
+ std::lock_guard lk{m_mutex};
+ while (!m_queue.empty()) m_queue.pop();
+ }
+};
+
+}} // namespace Slic3r::GUI
+
+#endif // THREADSAFEQUEUE_HPP
diff --git a/src/slic3r/GUI/Jobs/Worker.hpp b/src/slic3r/GUI/Jobs/Worker.hpp
new file mode 100644
index 000000000..0bc7bc086
--- /dev/null
+++ b/src/slic3r/GUI/Jobs/Worker.hpp
@@ -0,0 +1,119 @@
+#ifndef PRUSALSICER_WORKER_HPP
+#define PRUSALSICER_WORKER_HPP
+
+#include <memory>
+
+#include "Job.hpp"
+
+namespace Slic3r { namespace GUI {
+
+// An interface of a worker that runs jobs on a dedicated worker thread, one
+// after the other. It is assumed that every method of this class is called
+// from the same main thread.
+class Worker {
+public:
+ // Queue up a new job after the current one. This call does not block.
+ // Returns false if the job gets discarded.
+ virtual bool push(std::unique_ptr<Job> job) = 0;
+
+ // Returns true if no job is running, the job queue is empty and no job
+ // message is left to be processed. This means that nothing is left to
+ // finalize or take care of in the main thread.
+ virtual bool is_idle() const = 0;
+
+ // Ask the current job gracefully to cancel. This call is not blocking and
+ // the job may or may not cancel eventually, depending on its
+ // implementation. Note that it is not trivial to kill a thread forcefully
+ // and we don't need that.
+ virtual void cancel() = 0;
+
+ // This method will delete the queued jobs and cancel the current one.
+ virtual void cancel_all() = 0;
+
+ // Needs to be called continuously to process events (like status update
+ // or finalizing of jobs) in the main thread. This can be done e.g. in a
+ // wxIdle handler.
+ virtual void process_events() = 0;
+
+ // Wait until the current job finishes. Timeout will only be considered
+ // if not zero. Returns false if timeout is reached but the job has not
+ // finished.
+ virtual bool wait_for_current_job(unsigned timeout_ms = 0) = 0;
+
+ // Wait until the whole job queue finishes. Timeout will only be considered
+ // if not zero. Returns false only if timeout is reached but the worker has
+ // not reached the idle state.
+ virtual bool wait_for_idle(unsigned timeout_ms = 0) = 0;
+
+ // The destructor shall properly close the worker thread.
+ virtual ~Worker() = default;
+};
+
+template<class Fn> constexpr bool IsProcessFn = std::is_invocable_v<Fn, Job::Ctl&>;
+template<class Fn> constexpr bool IsFinishFn = std::is_invocable_v<Fn, bool, std::exception_ptr&>;
+
+// Helper function to use the worker with arbitrary functors.
+template<class ProcessFn, class FinishFn,
+ class = std::enable_if_t<IsProcessFn<ProcessFn>>,
+ class = std::enable_if_t<IsFinishFn<FinishFn>> >
+bool queue_job(Worker &w, ProcessFn fn, FinishFn finishfn)
+{
+ struct LambdaJob: Job {
+ ProcessFn fn;
+ FinishFn finishfn;
+
+ LambdaJob(ProcessFn pfn, FinishFn ffn)
+ : fn{std::move(pfn)}, finishfn{std::move(ffn)}
+ {}
+
+ void process(Ctl &ctl) override { fn(ctl); }
+ void finalize(bool canceled, std::exception_ptr &eptr) override
+ {
+ finishfn(canceled, eptr);
+ }
+ };
+
+ auto j = std::make_unique<LambdaJob>(std::move(fn), std::move(finishfn));
+ return w.push(std::move(j));
+}
+
+template<class ProcessFn, class = std::enable_if_t<IsProcessFn<ProcessFn>>>
+bool queue_job(Worker &w, ProcessFn fn)
+{
+ return queue_job(w, std::move(fn), [](bool, std::exception_ptr &) {});
+}
+
+inline bool queue_job(Worker &w, std::unique_ptr<Job> j)
+{
+ return w.push(std::move(j));
+}
+
+// Replace the current job queue with a new job. The signature is the same
+// as for queue_job(). This cancels all jobs and
+// will not wait. The new job will begin after the queue cancels properly.
+// Note that this can be called from the UI thread and will not block it if
+// the jobs take longer to cancel.
+template<class...Args> bool replace_job(Worker &w, Args&& ...args)
+{
+ w.cancel_all();
+ return queue_job(w, std::forward<Args>(args)...);
+}
+
+// Cancel the current job and wait for it to actually be stopped.
+inline bool stop_current_job(Worker &w, unsigned timeout_ms = 0)
+{
+ w.cancel();
+ return w.wait_for_current_job(timeout_ms);
+}
+
+// Cancel all pending jobs including current one and wait until the worker
+// becomes idle.
+inline bool stop_queue(Worker &w, unsigned timeout_ms = 0)
+{
+ w.cancel_all();
+ return w.wait_for_idle(timeout_ms);
+}
+
+}} // namespace Slic3r::GUI
+
+#endif // WORKER_HPP
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 273417eee..dd6f45318 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -574,7 +574,7 @@ void MainFrame::shutdown()
#endif // _WIN32
if (m_plater != nullptr) {
- m_plater->stop_jobs();
+ m_plater->get_ui_job_worker().cancel_all();
// Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC,
// when closing the application using Command+Q, a mouse event is triggered after this lambda is completed,
@@ -1073,7 +1073,7 @@ static wxMenu* generate_help_menu()
append_menu_item(helpMenu, wxID_ANY, _L("Prusa 3D &Drivers"), _L("Open the Prusa3D drivers download page in your browser"),
[](wxCommandEvent&) { wxGetApp().open_web_page_localized("https://www.prusa3d.com/downloads"); });
append_menu_item(helpMenu, wxID_ANY, _L("Software &Releases"), _L("Open the software releases page in your browser"),
- [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); });
+ [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases", nullptr, false); });
//# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", "Check for new Slic3r versions", sub{
//# wxTheApp->check_version(1);
//# });
@@ -1090,7 +1090,7 @@ static wxMenu* generate_help_menu()
append_menu_item(helpMenu, wxID_ANY, _L("Show &Configuration Folder"), _L("Show user configuration folder (datadir)"),
[](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); });
append_menu_item(helpMenu, wxID_ANY, _L("Report an I&ssue"), wxString::Format(_L("Report an issue on %s"), SLIC3R_APP_NAME),
- [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/slic3r/issues/new"); });
+ [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/slic3r/issues/new", nullptr, false); });
if (wxGetApp().is_editor())
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("&About %s"), SLIC3R_APP_NAME), _L("Show about dialog"),
[](wxCommandEvent&) { Slic3r::GUI::about(); });
@@ -1211,7 +1211,7 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 / SL1S Archive") + dots, _L("Load an SL1 / Sl1S archive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
- [this](){return m_plater != nullptr && !m_plater->is_any_job_running(); }, this);
+ [this](){return m_plater != nullptr && m_plater->get_ui_job_worker().is_idle(); }, this);
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _L("Import &Config") + dots + "\tCtrl+L", _L("Load exported configuration file"),
@@ -1431,7 +1431,7 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
#if ENABLE_PREVIEW_LAYOUT
- append_menu_check_item(viewMenu, wxID_ANY, _L("Show legen&d") + sep + "L", _L("Show legend in preview"),
+ append_menu_check_item(viewMenu, wxID_ANY, _L("Show Legen&d") + sep + "L", _L("Show legend in preview"),
[this](wxCommandEvent&) { m_plater->show_legend(!m_plater->is_legend_shown()); }, this,
[this]() { return m_plater->is_preview_shown(); }, [this]() { return m_plater->is_legend_shown(); }, this);
#endif // ENABLE_PREVIEW_LAYOUT
diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp
index 80a8159c0..a2d65a73c 100644
--- a/src/slic3r/GUI/MsgDialog.cpp
+++ b/src/slic3r/GUI/MsgDialog.cpp
@@ -14,7 +14,9 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI.hpp"
+#include "format.hpp"
#include "I18N.hpp"
#include "ConfigWizard.hpp"
#include "wxExtensions.hpp"
@@ -24,7 +26,6 @@
namespace Slic3r {
namespace GUI {
-
MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, long style, wxBitmap bitmap)
: wxDialog(parent ? parent : dynamic_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, boldfont(wxGetApp().normal_font())
@@ -136,14 +137,10 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
wxFont monospace = wxGetApp().code_font();
-#ifdef _WIN32
wxColour text_clr = wxGetApp().get_label_clr_default();
-#else
- wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
-#endif
- wxColour bgr_clr = parent->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
- auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
+ wxColour bgr_clr = parent->GetBackgroundColour();
+ auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
+ auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
const int font_size = font.GetPointSize();
int size[] = { font_size, font_size, font_size, font_size, font_size, font_size, font_size };
html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size);
@@ -186,13 +183,26 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
}
html->SetMinSize(page_size);
- std::string msg_escaped = xml_escape(msg.ToUTF8().data(), is_marked_msg);
+ std::string msg_escaped = xml_escape(into_u8(msg), is_marked_msg);
boost::replace_all(msg_escaped, "\r\n", "<br>");
boost::replace_all(msg_escaped, "\n", "<br>");
if (monospaced_font)
// Code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
msg_escaped = std::string("<pre><code>") + msg_escaped + "</code></pre>";
- html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>");
+ html->SetPage(format_wxstr("<html>"
+ "<body bgcolor=%1% link=%2%>"
+ "<font color=%2%>"
+ "%3%"
+ "</font>"
+ "</body>"
+ "</html>",
+ bgr_clr_str, text_clr_str, from_u8(msg_escaped)));
+
+ html->Bind(wxEVT_HTML_LINK_CLICKED, [parent](wxHtmlLinkEvent& event) {
+ wxGetApp().open_browser_with_warning_dialog(event.GetLinkInfo().GetHref(), parent, false);
+ event.Skip(false);
+ });
+
content_sizer->Add(html, 1, wxEXPAND);
wxGetApp().UpdateDarkUI(html);
}
diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp
index 66c22cb9b..aab0dbbab 100644
--- a/src/slic3r/GUI/NotificationManager.cpp
+++ b/src/slic3r/GUI/NotificationManager.cpp
@@ -301,7 +301,7 @@ void NotificationManager::PopNotification::count_lines()
float width_of_a = ImGui::CalcTextSize("a").x;
int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a);
while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) {
- letter_count++;
+ letter_count += get_utf8_sequence_length(text, last_end + letter_count);
}
m_endlines.push_back(last_end + letter_count);
last_end += letter_count;
diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp
index ee19e5da5..83537fd54 100644
--- a/src/slic3r/GUI/OG_CustomCtrl.cpp
+++ b/src/slic3r/GUI/OG_CustomCtrl.cpp
@@ -699,12 +699,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxStr
#else
dc.SetFont(old_font.Bold().Underlined());
#endif
- dc.SetTextForeground(color ? *color :
-#ifdef _WIN32
- wxGetApp().get_label_clr_default());
-#else
- wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
-#endif /* _WIN32 */
+ dc.SetTextForeground(color ? *color : wxGetApp().get_label_clr_default());
dc.DrawText(out_text, pos);
dc.SetTextForeground(old_clr);
dc.SetFont(old_font);
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 64fc4b8c8..3238b0650 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -977,36 +977,7 @@ wxString OptionsGroup::get_url(const std::string& path_end)
bool OptionsGroup::launch_browser(const std::string& path_end)
{
- bool launch = true;
-
- if (get_app_config()->get("suppress_hyperlinks").empty()) {
- wxWindow* parent = wxGetApp().mainframe->m_tabpanel;
- RichMessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO);
- dialog.ShowCheckBox(_L("Remember my choice"));
- int answer = dialog.ShowModal();
- if (answer == wxID_CANCEL)
- return false;
-
- if (dialog.IsCheckBoxChecked()) {
- wxString preferences_item = _L("Suppress to open hyperlink in browser");
- wxString msg =
- _L("PrusaSlicer will remember your choice.") + "\n\n" +
- _L("You will not be asked about it again on label hovering.") + "\n\n" +
- format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item);
-
- MessageDialog msg_dlg(parent, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
- if (msg_dlg.ShowModal() == wxID_CANCEL)
- return false;
-
- get_app_config()->set("suppress_hyperlinks", dialog.IsCheckBoxChecked() ? (answer == wxID_NO ? "1" : "0") : "");
- }
-
- launch = answer == wxID_YES;
- }
- if (launch)
- launch = get_app_config()->get("suppress_hyperlinks") != "1";
-
- return launch && wxLaunchDefaultBrowser(OptionsGroup::get_url(path_end));
+ return wxGetApp().open_browser_with_warning_dialog(OptionsGroup::get_url(path_end), wxGetApp().mainframe->m_tabpanel);
}
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 1b3c001a4..21aa5fc12 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -73,7 +73,10 @@
#include "Jobs/FillBedJob.hpp"
#include "Jobs/RotoptimizeJob.hpp"
#include "Jobs/SLAImportJob.hpp"
+#include "Jobs/SLAImportDialog.hpp"
#include "Jobs/NotificationProgressIndicator.hpp"
+#include "Jobs/PlaterWorker.hpp"
+#include "Jobs/BoostThreadWorker.hpp"
#include "BackgroundSlicingProcess.hpp"
#include "PrintHostDialogs.hpp"
#include "ConfigWizard.hpp"
@@ -251,9 +254,9 @@ void ObjectInfo::update_warning_icon(const std::string& warning_icon_name)
enum SlicedInfoIdx
{
+ siFilament_g,
siFilament_m,
siFilament_mm3,
- siFilament_g,
siMateril_unit,
siCost,
siEstimatedTime,
@@ -293,9 +296,9 @@ SlicedInfo::SlicedInfo(wxWindow *parent) :
info_vec.push_back(std::pair<wxStaticText*, wxStaticText*>(text, info_label));
};
+ init_info_label(_L("Used Filament (g)"));
init_info_label(_L("Used Filament (m)"));
init_info_label(_L("Used Filament (mm³)"));
- init_info_label(_L("Used Filament (g)"));
init_info_label(_L("Used Material (unit)"));
init_info_label(_L("Cost (money)"));
init_info_label(_L("Estimated printing time"));
@@ -1638,54 +1641,12 @@ struct Plater::priv
BackgroundSlicingProcess background_process;
bool suppressed_backround_processing_update { false };
- // Jobs defined inside the group class will be managed so that only one can
- // run at a time. Also, the background process will be stopped if a job is
- // started. It is up the the plater to ensure that the background slicing
- // can't be restarted while a ui job is still running.
- class Jobs: public ExclusiveJobGroup
- {
- priv *m;
- size_t m_arrange_id, m_fill_bed_id, m_rotoptimize_id, m_sla_import_id;
- std::shared_ptr<NotificationProgressIndicator> m_pri;
-
- void before_start() override { m->background_process.stop(); }
-
- public:
- Jobs(priv *_m) :
- m(_m),
- m_pri{std::make_shared<NotificationProgressIndicator>(m->notification_manager.get())}
- {
- m_arrange_id = add_job(std::make_unique<ArrangeJob>(m_pri, m->q));
- m_fill_bed_id = add_job(std::make_unique<FillBedJob>(m_pri, m->q));
- m_rotoptimize_id = add_job(std::make_unique<RotoptimizeJob>(m_pri, m->q));
- m_sla_import_id = add_job(std::make_unique<SLAImportJob>(m_pri, m->q));
- }
-
- void arrange()
- {
- m->take_snapshot(_L("Arrange"));
- start(m_arrange_id);
- }
-
- void fill_bed()
- {
- m->take_snapshot(_L("Fill bed"));
- start(m_fill_bed_id);
- }
-
- void optimize_rotation()
- {
- m->take_snapshot(_L("Optimize Rotation"));
- start(m_rotoptimize_id);
- }
-
- void import_sla_arch()
- {
- m->take_snapshot(_L("Import SLA archive"));
- start(m_sla_import_id);
- }
-
- } m_ui_jobs;
+ // TODO: A mechanism would be useful for blocking the plater interactions:
+ // objects would be frozen for the user. In case of arrange, an animation
+ // could be shown, or with the optimize orientations, partial results
+ // could be displayed.
+ PlaterWorker<BoostThreadWorker> m_worker;
+ SLAImportDialog * m_sla_import_dlg;
bool delayed_scene_refresh;
std::string delayed_error_message;
@@ -1720,8 +1681,33 @@ struct Plater::priv
fs::path output_file = get_export_file_path(FT_3MF);
suggested_project_name = output_file.empty() ? _L("Untitled") : from_u8(output_file.stem().string());
}
- res = MessageDialog(mainframe, reason + "\n" + format_wxstr(_L("Do you want to save the changes to \"%1%\"?"), suggested_project_name),
- wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL).ShowModal();
+
+ std::string act_key = "default_action_on_dirty_project";
+ std::string act = wxGetApp().app_config->get(act_key);
+ if (act.empty()) {
+ RichMessageDialog dialog(mainframe, reason + "\n" + format_wxstr(_L("Do you want to save the changes to \"%1%\"?"), suggested_project_name), wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL);
+ dialog.ShowCheckBox(_L("Remember my choice"));
+ res = dialog.ShowModal();
+ if (res != wxID_CANCEL)
+ if (dialog.IsCheckBoxChecked()) {
+ wxString preferences_item = _L("Ask for unsaved changes in project");
+ wxString msg =
+ _L("PrusaSlicer will remember your choice.") + "\n\n" +
+ _L("You will not be asked about it again, when: \n"
+ "- Closing PrusaSlicer,\n"
+ "- Loading or creating a new project") + "\n\n" +
+ format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item);
+
+ MessageDialog msg_dlg(mainframe, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
+ if (msg_dlg.ShowModal() == wxID_CANCEL)
+ return wxID_CANCEL;
+
+ get_app_config()->set(act_key, res == wxID_YES ? "1" : "0");
+ }
+ }
+ else
+ res = (act == "1") ? wxID_YES : wxID_NO;
+
if (res == wxID_YES)
if (!mainframe->save_project_as(project_name))
res = wxID_CANCEL;
@@ -1923,9 +1909,7 @@ struct Plater::priv
bool can_reload_from_disk() const;
bool can_replace_with_stl() const;
bool can_split(bool to_objects) const;
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool can_scale_to_print_volume() const;
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type);
ThumbnailsList generate_thumbnails(const ThumbnailsParams& params, Camera::EType camera_type);
@@ -1997,7 +1981,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
}))
, sidebar(new Sidebar(q))
, notification_manager(std::make_unique<NotificationManager>(q))
- , m_ui_jobs(this)
+ , m_worker{q, std::make_unique<NotificationProgressIndicator>(notification_manager.get()), "ui_worker"}
+ , m_sla_import_dlg{new SLAImportDialog{q}}
, delayed_scene_refresh(false)
, view_toolbar(GLToolbar::Radio, "View")
, collapse_toolbar(GLToolbar::Normal, "Collapse")
@@ -2933,7 +2918,7 @@ void Plater::priv::remove(size_t obj_idx)
if (view3D->is_layers_editing_enabled())
view3D->enable_layers_editing(false);
- m_ui_jobs.cancel_all();
+ m_worker.cancel_all();
model.delete_object(obj_idx);
update();
// Delete object from Sidebar list. Do it after update, so that the GLScene selection is updated with the modified model.
@@ -2948,7 +2933,7 @@ void Plater::priv::delete_object_from_model(size_t obj_idx)
if (! model.objects[obj_idx]->name.empty())
snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str());
Plater::TakeSnapshot snapshot(q, snapshot_label);
- m_ui_jobs.cancel_all();
+ m_worker.cancel_all();
model.delete_object(obj_idx);
update();
object_list_changed();
@@ -2966,7 +2951,7 @@ void Plater::priv::delete_all_objects_from_model()
view3D->get_canvas3d()->reset_sequential_print_clearance();
- m_ui_jobs.cancel_all();
+ m_worker.cancel_all();
// Stop and reset the Print content.
background_process.reset();
@@ -2998,7 +2983,7 @@ void Plater::priv::reset()
view3D->get_canvas3d()->reset_sequential_print_clearance();
- m_ui_jobs.cancel_all();
+ m_worker.cancel_all();
// Stop and reset the Print content.
this->background_process.reset();
@@ -3099,11 +3084,7 @@ void Plater::priv::split_volume()
void Plater::priv::scale_selection_to_fit_print_volume()
{
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
this->view3D->get_canvas3d()->get_selection().scale_to_fit_print_volume(this->bed.build_volume());
-#else
- this->view3D->get_canvas3d()->get_selection().scale_to_fit_print_volume(*config);
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
}
void Plater::priv::schedule_background_process()
@@ -3299,7 +3280,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
bool Plater::priv::restart_background_process(unsigned int state)
{
- if (m_ui_jobs.is_any_running()) {
+ if (!m_worker.is_idle()) {
// Avoid a race condition
return false;
}
@@ -3385,11 +3366,39 @@ void Plater::priv::update_sla_scene()
this->update_restart_background_process(true, true);
}
+// class used to show a wxBusyCursor and a wxBusyInfo
+// and hide them on demand
+class Busy
+{
+ wxWindow* m_parent{ nullptr };
+ std::unique_ptr<wxBusyCursor> m_cursor;
+ std::unique_ptr<wxBusyInfo> m_dlg;
+
+public:
+ Busy(const wxString& message, wxWindow* parent = nullptr) {
+ m_parent = parent;
+ m_cursor = std::make_unique<wxBusyCursor>();
+ m_dlg = std::make_unique<wxBusyInfo>(message, m_parent);
+ }
+
+ ~Busy() { reset(); }
+
+ void update(const wxString& message) {
+ // this is ugly but necessary because the call to wxBusyInfo::UpdateLabel() is not working [WX 3.1.4]
+ m_dlg = std::make_unique<wxBusyInfo>(message, m_parent);
+// m_dlg->UpdateLabel(message);
+ }
+
+ void reset() {
+ m_cursor.reset();
+ m_dlg.reset();
+ }
+};
+
bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const fs::path& new_path, const wxString& snapshot)
{
const std::string path = new_path.string();
- wxBusyCursor wait;
- wxBusyInfo info(_L("Replace from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
+ Busy busy(_L("Replace from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
Model new_model;
try {
@@ -3399,8 +3408,10 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
model_object->ensure_on_bed();
}
}
- catch (std::exception&) {
+ catch (std::exception& e) {
// error while loading
+ busy.reset();
+ GUI::show_error(q, e.what());
return false;
}
@@ -3624,12 +3635,13 @@ void Plater::priv::reload_from_disk()
std::vector<wxString> fail_list;
+ Busy busy(_L("Reload from:"), q->get_current_canvas3D()->get_wxglcanvas());
+
// load one file at a time
for (size_t i = 0; i < input_paths.size(); ++i) {
const auto& path = input_paths[i].string();
- wxBusyCursor wait;
- wxBusyInfo info(_L("Reload from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
+ busy.update(_L("Reload from:") + " " + from_u8(path));
Model new_model;
try
@@ -3640,9 +3652,11 @@ void Plater::priv::reload_from_disk()
model_object->ensure_on_bed();
}
}
- catch (std::exception&)
+ catch (std::exception& e)
{
// error while loading
+ busy.reset();
+ GUI::show_error(q, e.what());
return;
}
@@ -3717,15 +3731,15 @@ void Plater::priv::reload_from_disk()
}
}
+ busy.reset();
+
for (size_t i = 0; i < replace_paths.size(); ++i) {
const auto& path = replace_paths[i].string();
for (const SelectedVolume& sel_v : selected_volumes) {
- ModelObject* old_model_object = model.objects[sel_v.object_idx];
- ModelVolume* old_volume = old_model_object->volumes[sel_v.volume_idx];
- bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string());
- if (!replace_volume_with_stl(sel_v.object_idx, sel_v.volume_idx, path, "")) {
- fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
- }
+// ModelObject* old_model_object = model.objects[sel_v.object_idx];
+// ModelVolume* old_volume = old_model_object->volumes[sel_v.volume_idx];
+// bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string());
+ replace_volume_with_stl(sel_v.object_idx, sel_v.volume_idx, path, "");
}
}
@@ -3927,7 +3941,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
{
if (evt.status.percent >= -1) {
- if (m_ui_jobs.is_any_running()) {
+ if (!m_worker.is_idle()) {
// Avoid a race condition
return;
}
@@ -4487,13 +4501,11 @@ bool Plater::priv::can_split(bool to_objects) const
return sidebar->obj_list()->is_splittable(to_objects);
}
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool Plater::priv::can_scale_to_print_volume() const
{
const BuildVolume::Type type = this->bed.build_volume().type();
return !view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle);
}
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool Plater::priv::layers_height_allowed() const
{
@@ -4618,7 +4630,7 @@ bool Plater::priv::can_simplify() const
bool Plater::priv::can_increase_instances() const
{
- if (m_ui_jobs.is_any_running()
+ if (!m_worker.is_idle()
|| q->canvas3D()->get_gizmos_manager().is_in_editing_mode())
return false;
@@ -4628,7 +4640,7 @@ bool Plater::priv::can_increase_instances() const
bool Plater::priv::can_decrease_instances() const
{
- if (m_ui_jobs.is_any_running()
+ if (!m_worker.is_idle()
|| q->canvas3D()->get_gizmos_manager().is_in_editing_mode())
return false;
@@ -4648,7 +4660,7 @@ bool Plater::priv::can_split_to_volumes() const
bool Plater::priv::can_arrange() const
{
- return !model.objects.empty() && !m_ui_jobs.is_any_running();
+ return !model.objects.empty() && m_worker.is_idle();
}
bool Plater::priv::can_layers_editing() const
@@ -5102,8 +5114,11 @@ void Plater::add_model(bool imperial_units/* = false*/)
void Plater::import_sl1_archive()
{
- if (!p->m_ui_jobs.is_any_running())
- p->m_ui_jobs.import_sla_arch();
+ auto &w = get_ui_job_worker();
+ if (w.is_idle() && p->m_sla_import_dlg->ShowModal() == wxID_OK) {
+ p->take_snapshot(_L("Import SLA archive"));
+ replace_job(w, std::make_unique<SLAImportJob>(p->m_sla_import_dlg));
+ }
}
void Plater::extract_config_from_project()
@@ -5385,12 +5400,9 @@ bool Plater::load_files(const wxArrayString& filenames)
void Plater::update() { p->update(); }
-void Plater::stop_jobs() { p->m_ui_jobs.stop_all(); }
+Worker &Plater::get_ui_job_worker() { return p->m_worker; }
-bool Plater::is_any_job_running() const
-{
- return p->m_ui_jobs.is_any_running();
-}
+const Worker &Plater::get_ui_job_worker() const { return p->m_worker; }
void Plater::update_ui_from_settings() { p->update_ui_from_settings(); }
@@ -5436,7 +5448,7 @@ void Plater::remove_selected()
return;
Plater::TakeSnapshot snapshot(this, _L("Delete Selected Objects"));
- p->m_ui_jobs.cancel_all();
+ get_ui_job_worker().cancel_all();
p->view3D->delete_selected();
}
@@ -5545,8 +5557,11 @@ void Plater::set_number_of_copies(/*size_t num*/)
void Plater::fill_bed_with_instances()
{
- if (!p->m_ui_jobs.is_any_running())
- p->m_ui_jobs.fill_bed();
+ auto &w = get_ui_job_worker();
+ if (w.is_idle()) {
+ p->take_snapshot(_L("Fill bed"));
+ replace_job(w, std::make_unique<FillBedJob>());
+ }
}
bool Plater::is_selection_empty() const
@@ -5738,7 +5753,7 @@ void Plater::export_stl(bool extended, bool selection_only)
mesh.merge(m);
}
}
- else if (0 <= instance_id && instance_id < mo.instances.size())
+ else if (0 <= instance_id && instance_id < int(mo.instances.size()))
mesh.transform(mo.instances[instance_id]->get_matrix(), true);
return mesh;
@@ -5749,13 +5764,15 @@ void Plater::export_stl(bool extended, bool selection_only)
if (selection_only) {
const ModelObject* model_object = p->model.objects[obj_idx];
if (selection.get_mode() == Selection::Instance)
- mesh = selection.is_single_full_object() ? mesh_to_export(*model_object, -1) : mesh_to_export(*model_object, selection.get_instance_idx());
+ mesh = mesh_to_export(*model_object, (selection.is_single_full_object() && model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
else {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
mesh = model_object->volumes[volume->volume_idx()]->mesh();
mesh.transform(volume->get_volume_transformation().get_matrix(), true);
- mesh.translate(-model_object->origin_translation.cast<float>());
}
+
+ if (!selection.is_single_full_object() || model_object->instances.size() == 1)
+ mesh.translate(-model_object->origin_translation.cast<float>());
}
else {
for (const ModelObject* o : p->model.objects) {
@@ -5947,8 +5964,14 @@ void Plater::reslice()
if (canvas3D()->get_gizmos_manager().is_in_editing_mode(true))
return;
- // Stop arrange and (or) optimize rotation tasks.
- this->stop_jobs();
+ // Stop the running (and queued) UI jobs and only proceed if they actually
+ // get stopped.
+ unsigned timeout_ms = 10000;
+ if (!stop_queue(this->get_ui_job_worker(), timeout_ms)) {
+ BOOST_LOG_TRIVIAL(error) << "Could not stop UI job within "
+ << timeout_ms << " milliseconds timeout!";
+ return;
+ }
if (printer_technology() == ptSLA) {
for (auto& object : model().objects)
@@ -6412,8 +6435,11 @@ GLCanvas3D* Plater::get_current_canvas3D()
void Plater::arrange()
{
- if (!p->m_ui_jobs.is_any_running())
- p->m_ui_jobs.arrange();
+ auto &w = get_ui_job_worker();
+ if (w.is_idle()) {
+ p->take_snapshot(_L("Arrange"));
+ replace_job(w, std::make_unique<ArrangeJob>());
+ }
}
void Plater::set_current_canvas_as_dirty()
@@ -6584,7 +6610,6 @@ void Plater::suppress_background_process(const bool stop_background_process)
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); }
-void Plater::optimize_rotation() { if (!p->m_ui_jobs.is_any_running()) p->m_ui_jobs.optimize_rotation(); }
void Plater::update_menus() { p->menus.update(); }
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
@@ -6822,9 +6847,7 @@ bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
bool Plater::can_replace_with_stl() const { return p->can_replace_with_stl(); }
bool Plater::can_mirror() const { return p->can_mirror(); }
bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); }
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool Plater::can_scale_to_print_volume() const { return p->can_scale_to_print_volume(); }
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); }
void Plater::clear_undo_redo_stack_main() { p->undo_redo_stack_main().clear(); }
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 20a64c6d5..0b26f09e1 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -14,6 +14,7 @@
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "Jobs/Job.hpp"
+#include "Jobs/Worker.hpp"
#include "Search.hpp"
class wxButton;
@@ -177,8 +178,41 @@ public:
const wxString& get_last_loaded_gcode() const { return m_last_loaded_gcode; }
void update();
- void stop_jobs();
- bool is_any_job_running() const;
+
+ // Get the worker handling the UI jobs (arrange, fill bed, etc...)
+ // Here is an example of starting up an ad-hoc job:
+ // queue_job(
+ // get_ui_job_worker(),
+ // [](Job::Ctl &ctl) {
+ // // Executed in the worker thread
+ //
+ // CursorSetterRAII cursor_setter{ctl};
+ // std::string msg = "Running";
+ //
+ // ctl.update_status(0, msg);
+ // for (int i = 0; i < 100; i++) {
+ // usleep(100000);
+ // if (ctl.was_canceled()) break;
+ // ctl.update_status(i + 1, msg);
+ // }
+ // ctl.update_status(100, msg);
+ // },
+ // [](bool, std::exception_ptr &e) {
+ // // Executed in UI thread after the work is done
+ //
+ // try {
+ // if (e) std::rethrow_exception(e);
+ // } catch (std::exception &e) {
+ // BOOST_LOG_TRIVIAL(error) << e.what();
+ // }
+ // e = nullptr;
+ // });
+ // This would result in quick run of the progress indicator notification
+ // from 0 to 100. Use replace_job() instead of queue_job() to cancel all
+ // pending jobs.
+ Worker& get_ui_job_worker();
+ const Worker & get_ui_job_worker() const;
+
void select_view(const std::string& direction);
void select_view_3D(const std::string& name);
@@ -307,7 +341,6 @@ public:
void mirror(Axis axis);
void split_object();
void split_volume();
- void optimize_rotation();
bool can_delete() const;
bool can_delete_all() const;
@@ -328,9 +361,7 @@ public:
bool can_replace_with_stl() const;
bool can_mirror() const;
bool can_split(bool to_objects) const;
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool can_scale_to_print_volume() const;
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void msw_rescale();
void sys_color_changed();
diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp
index fa1e84ea6..4b218bf66 100644
--- a/src/slic3r/GUI/Preferences.cpp
+++ b/src/slic3r/GUI/Preferences.cpp
@@ -175,6 +175,8 @@ void PreferencesDialog::build()
m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
if (opt_key == "default_action_on_close_application" || opt_key == "default_action_on_select_preset" || opt_key == "default_action_on_new_project")
m_values[opt_key] = boost::any_cast<bool>(value) ? "none" : "discard";
+ else if (opt_key == "default_action_on_dirty_project")
+ m_values[opt_key] = boost::any_cast<bool>(value) ? "" : "0";
else
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
};
@@ -259,21 +261,30 @@ void PreferencesDialog::build()
m_optgroup_general->append_separator();
+ append_bool_option(m_optgroup_general, "default_action_on_dirty_project",
+ L("Ask for unsaved changes in project"),
+ L("Always ask for unsaved changes in project, when: \n"
+ "- Closing PrusaSlicer,\n"
+ "- Loading or creating a new project"),
+ app_config->get("default_action_on_dirty_project").empty());
+
+ m_optgroup_general->append_separator();
+
append_bool_option(m_optgroup_general, "default_action_on_close_application",
- L("Ask to save unsaved changes when closing the application or when loading a new project"),
- L("Always ask for unsaved changes, when: \n"
+ L("Ask to save unsaved changes in presets when closing the application or when loading a new project"),
+ L("Always ask for unsaved changes in presets, when: \n"
"- Closing PrusaSlicer while some presets are modified,\n"
"- Loading a new project while some presets are modified"),
app_config->get("default_action_on_close_application") == "none");
append_bool_option(m_optgroup_general, "default_action_on_select_preset",
- L("Ask for unsaved changes when selecting new preset"),
- L("Always ask for unsaved changes when selecting new preset or resetting a preset"),
+ L("Ask for unsaved changes in presets when selecting new preset"),
+ L("Always ask for unsaved changes in presets when selecting new preset or resetting a preset"),
app_config->get("default_action_on_select_preset") == "none");
append_bool_option(m_optgroup_general, "default_action_on_new_project",
- L("Ask for unsaved changes when creating new project"),
- L("Always ask for unsaved changes when creating new project"),
+ L("Ask for unsaved changes in presets when creating new project"),
+ L("Always ask for unsaved changes in presets when creating new project"),
app_config->get("default_action_on_new_project") == "none");
}
#ifdef _WIN32
@@ -301,6 +312,11 @@ void PreferencesDialog::build()
L("Show splash screen"),
app_config->get("show_splash_screen") == "1");
+ append_bool_option(m_optgroup_general, "restore_win_position",
+ L("Restore window position on start"),
+ L("If enabled, PrusaSlicer will be open at the position it was closed"),
+ app_config->get("restore_win_position") == "1");
+
// Clear Undo / Redo stack on new project
append_bool_option(m_optgroup_general, "clear_undo_redo_stack_on_new_project",
L("Clear Undo / Redo stack on new project"),
@@ -377,8 +393,9 @@ void PreferencesDialog::build()
append_bool_option(m_optgroup_gui, "suppress_hyperlinks",
L("Suppress to open hyperlink in browser"),
- L("If enabled, the descriptions of configuration parameters in settings tabs wouldn't work as hyperlinks. "
- "If disabled, the descriptions of configuration parameters in settings tabs will work as hyperlinks."),
+ L("If enabled, PrusaSlicer will not open a hyperlinks in your browser."),
+ //L("If enabled, the descriptions of configuration parameters in settings tabs wouldn't work as hyperlinks. "
+ // "If disabled, the descriptions of configuration parameters in settings tabs will work as hyperlinks."),
app_config->get("suppress_hyperlinks") == "1");
append_bool_option(m_optgroup_gui, "color_mapinulation_panel",
@@ -568,10 +585,17 @@ void PreferencesDialog::accept(wxEvent&)
}
}
- for (const std::string& key : {"default_action_on_close_application", "default_action_on_select_preset"}) {
+ for (const std::string& key : { "default_action_on_close_application",
+ "default_action_on_select_preset",
+ "default_action_on_new_project" }) {
auto it = m_values.find(key);
if (it != m_values.end() && it->second != "none" && app_config->get(key) != "none")
- m_values.erase(it); // we shouldn't change value, if some of those parameters was selected, and then deselected
+ m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected
+ }
+ {
+ auto it = m_values.find("default_action_on_dirty_project");
+ if (it != m_values.end() && !it->second.empty() && !app_config->get("default_action_on_dirty_project").empty())
+ m_values.erase(it); // we shouldn't change value, if this parameter was selected, and then deselected
}
#if 0 //#ifdef _WIN32 // #ysDarkMSW - Allow it when we deside to support the sustem colors for application
diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp
index 2b53883be..ed4888a87 100644
--- a/src/slic3r/GUI/PresetComboBoxes.cpp
+++ b/src/slic3r/GUI/PresetComboBoxes.cpp
@@ -24,6 +24,7 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/PresetBundle.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
@@ -441,15 +442,14 @@ wxBitmap* PresetComboBox::get_bmp( std::string bitmap_key, bool wide_icons, con
// Paint a red flag for incompatible presets.
bmps.emplace_back(is_compatible ? bitmap_cache().mkclear(norm_icon_width, icon_height) : m_bitmapIncompatible.bmp());
- if (m_type == Preset::TYPE_FILAMENT && !filament_rgb.empty())
- {
- unsigned char rgb[3];
+ if (m_type == Preset::TYPE_FILAMENT && !filament_rgb.empty()) {
// Paint the color bars.
- bitmap_cache().parse_color(filament_rgb, rgb);
- bmps.emplace_back(bitmap_cache().mksolid(is_single_bar ? wide_icon_width : norm_icon_width, icon_height, rgb, false, 1, dark_mode));
+ ColorRGB color;
+ decode_color(filament_rgb, color);
+ bmps.emplace_back(bitmap_cache().mksolid(is_single_bar ? wide_icon_width : norm_icon_width, icon_height, color, false, 1, dark_mode));
if (!is_single_bar) {
- bitmap_cache().parse_color(extruder_rgb, rgb);
- bmps.emplace_back(bitmap_cache().mksolid(thin_icon_width, icon_height, rgb, false, 1, dark_mode));
+ decode_color(extruder_rgb, color);
+ bmps.emplace_back(bitmap_cache().mksolid(thin_icon_width, icon_height, color, false, 1, dark_mode));
}
// Paint a lock at the system presets.
bmps.emplace_back(bitmap_cache().mkclear(space_icon_width, icon_height));
@@ -767,11 +767,9 @@ void PlaterPresetComboBox::update()
const Preset* selected_filament_preset = nullptr;
std::string extruder_color;
- if (m_type == Preset::TYPE_FILAMENT)
- {
- unsigned char rgb[3];
+ if (m_type == Preset::TYPE_FILAMENT) {
extruder_color = m_preset_bundle->printers.get_edited_preset().config.opt_string("extruder_colour", (unsigned int)m_extruder_idx);
- if (!bitmap_cache().parse_color(extruder_color, rgb))
+ if (!can_decode_color(extruder_color))
// Extruder color is not defined.
extruder_color.clear();
selected_filament_preset = m_collection->find_preset(m_preset_bundle->filament_presets[m_extruder_idx]);
diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp
index 09ba48b58..af2494dc8 100644
--- a/src/slic3r/GUI/PrintHostDialogs.cpp
+++ b/src/slic3r/GUI/PrintHostDialogs.cpp
@@ -247,7 +247,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
job_list->AppendProgressColumn(_L("Progress"), wxDATAVIEW_CELL_INERT, widths[1], wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
append_text_column(_L("Status"),widths[2]);
append_text_column(_L("Host"), widths[3]);
- append_text_column(_CTX_utf8(L_CONTEXT("Size", "OfFile"), "OfFile"), widths[4]);
+ append_text_column(_CTX(L_CONTEXT("Size", "OfFile"), "OfFile"), widths[4]);
append_text_column(_L("Filename"), widths[5]);
append_text_column(_L("Error Message"), -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN);
@@ -324,7 +324,7 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job)
} else
stream << std::fixed << std::setprecision(2) << ((float)size_i / 1024 / 1024) << "MB";
fields.push_back(wxVariant(stream.str()));
- fields.push_back(wxVariant(job.upload_data.upload_path.string()));
+ fields.push_back(wxVariant(from_path(job.upload_data.upload_path)));
fields.push_back(wxVariant(""));
job_list->AppendItem(fields, static_cast<wxUIntPtr>(ST_NEW));
// Both strings are UTF-8 encoded.
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index 406617d5a..5aa2cb4d0 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -15,16 +15,16 @@
#include "libslic3r/LocalesUtils.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/PresetBundle.hpp"
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
#include "libslic3r/BuildVolume.hpp"
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
#include <GL/glew.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/log/trivial.hpp>
-static const std::array<float, 4> UNIFORM_SCALE_COLOR = { 0.923f, 0.504f, 0.264f, 1.0f };
+static const Slic3r::ColorRGBA UNIFORM_SCALE_COLOR = Slic3r::ColorRGBA::ORANGE();
+static const Slic3r::ColorRGBA SOLID_PLANE_COLOR = Slic3r::ColorRGBA::ORANGE();
+static const Slic3r::ColorRGBA TRANSPARENT_PLANE_COLOR = { 0.8f, 0.8f, 0.8f, 0.5f };
namespace Slic3r {
namespace GUI {
@@ -448,25 +448,17 @@ void Selection::clear()
if (m_list.empty())
return;
-#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
// ensure that the volumes get the proper color before next call to render (expecially needed for transparent volumes)
for (unsigned int i : m_list) {
GLVolume& volume = *(*m_volumes)[i];
volume.selected = false;
- bool transparent = volume.color[3] < 1.0f;
- if (transparent)
+ bool is_transparent = volume.color.is_transparent();
+ if (is_transparent)
volume.force_transparent = true;
volume.set_render_color();
- if (transparent)
+ if (is_transparent)
volume.force_transparent = false;
}
-#else
- for (unsigned int i : m_list) {
- (*m_volumes)[i]->selected = false;
- // ensure the volume gets the proper color before next call to render (expecially needed for transparent volumes)
- (*m_volumes)[i]->set_render_color();
- }
-#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
m_list.clear();
@@ -951,7 +943,6 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
}
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
{
auto fit = [this](double s, Vec3d offset) {
@@ -1039,50 +1030,6 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
default: { break; }
}
}
-#else
-void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
-{
- if (is_empty() || m_mode == Volume)
- return;
-
- // adds 1/100th of a mm on all sides to avoid false out of print volume detections due to floating-point roundings
- Vec3d box_size = get_bounding_box().size() + 0.01 * Vec3d::Ones();
-
- const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(config.option("bed_shape"));
- if (opt != nullptr) {
- BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
- BoundingBoxf3 print_volume({ unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0 }, { unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config.opt_float("max_print_height") });
- Vec3d print_volume_size = print_volume.size();
- double sx = (box_size(0) != 0.0) ? print_volume_size(0) / box_size(0) : 0.0;
- double sy = (box_size(1) != 0.0) ? print_volume_size(1) / box_size(1) : 0.0;
- double sz = (box_size(2) != 0.0) ? print_volume_size(2) / box_size(2) : 0.0;
- if (sx != 0.0 && sy != 0.0 && sz != 0.0)
- {
- double s = std::min(sx, std::min(sy, sz));
- if (s != 1.0) {
- wxGetApp().plater()->take_snapshot(_L("Scale To Fit"));
-
- TransformationType type;
- type.set_world();
- type.set_relative();
- type.set_joint();
-
- // apply scale
- start_dragging();
- scale(s * Vec3d::Ones(), type);
- wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot
-
- // center selection on print bed
- start_dragging();
- translate(print_volume.center() - get_bounding_box().center());
- wxGetApp().plater()->canvas3D()->do_move(""); // avoid storing another snapshot
-
- wxGetApp().obj_manipul()->set_dirty();
- }
- }
- }
-}
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void Selection::mirror(Axis axis)
{
@@ -1919,10 +1866,10 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) cons
glsafe(::glEnd());
}
-static std::array<float, 4> get_color(Axis axis)
+static ColorRGBA get_color(Axis axis)
{
- return { AXES_COLOR[axis][0], AXES_COLOR[axis][1], AXES_COLOR[axis][2], AXES_COLOR[axis][3] };
-};
+ return AXES_COLOR[axis];
+}
void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const
{
@@ -2052,10 +1999,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
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);
+ ::glColor4fv((camera_on_top && type == 1) || (!camera_on_top && type == 2) ?
+ SOLID_PLANE_COLOR.data() : TRANSPARENT_PLANE_COLOR.data());
::glVertex3f(min_x, min_y, z1);
::glVertex3f(max_x, min_y, z1);
::glVertex3f(max_x, max_y, z1);
@@ -2063,10 +2008,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
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);
+ ::glColor4fv((camera_on_top && type == 2) || (!camera_on_top && type == 1) ?
+ SOLID_PLANE_COLOR.data() : TRANSPARENT_PLANE_COLOR.data());
::glVertex3f(min_x, min_y, z2);
::glVertex3f(max_x, min_y, z2);
::glVertex3f(max_x, max_y, z2);
diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp
index c18d24eab..537c07207 100644
--- a/src/slic3r/GUI/Selection.hpp
+++ b/src/slic3r/GUI/Selection.hpp
@@ -17,9 +17,7 @@ class GLArrow;
class GLCurvedArrow;
class DynamicPrintConfig;
class GLShaderProgram;
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
class BuildVolume;
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
using GLVolumePtrs = std::vector<GLVolume*>;
using ModelObjectPtrs = std::vector<ModelObject*>;
@@ -323,11 +321,7 @@ public:
void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, TransformationType transformation_type);
-#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
void scale_to_fit_print_volume(const BuildVolume& volume);
-#else
- void scale_to_fit_print_volume(const DynamicPrintConfig& config);
-#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void mirror(Axis axis);
void translate(unsigned int object_idx, const Vec3d& displacement);
diff --git a/src/slic3r/GUI/SendSystemInfoDialog.cpp b/src/slic3r/GUI/SendSystemInfoDialog.cpp
index e8e23a44e..9a97532a7 100644
--- a/src/slic3r/GUI/SendSystemInfoDialog.cpp
+++ b/src/slic3r/GUI/SendSystemInfoDialog.cpp
@@ -4,6 +4,7 @@
#include "libslic3r/BlacklistedLibraryCheck.hpp"
#include "libslic3r/Platform.hpp"
#include "libslic3r/Utils.hpp"
+#include "libslic3r/Color.hpp"
#include "slic3r/GUI/format.hpp"
#include "slic3r/Utils/Http.hpp"
@@ -571,9 +572,8 @@ SendSystemInfoDialog::SendSystemInfoDialog(wxWindow* parent)
wxColour bgr_clr = wxGetApp().get_window_default_clr();
SetBackgroundColour(bgr_clr);
const auto text_clr = wxGetApp().get_label_clr_default();
- auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
-
+ auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
+ auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
auto *topSizer = new wxBoxSizer(wxVERTICAL);
auto *vsizer = new wxBoxSizer(wxVERTICAL);
diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp
index 1a8542438..06cf2b73d 100644
--- a/src/slic3r/GUI/SysInfoDialog.cpp
+++ b/src/slic3r/GUI/SysInfoDialog.cpp
@@ -15,6 +15,7 @@
#include "MainFrame.hpp"
#include "wxExtensions.hpp"
#include "../libslic3r/BlacklistedLibraryCheck.hpp"
+#include "../libslic3r/Color.hpp"
#include "format.hpp"
#ifdef _WIN32
@@ -113,9 +114,9 @@ SysInfoDialog::SysInfoDialog()
// main_info_text
wxFont font = get_default_font(this);
- const auto text_clr = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
- auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
+ const auto text_clr = wxGetApp().get_label_clr_default();
+ auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
+ auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
const int fs = font.GetPointSize() - 1;
int size[] = { static_cast<int>(fs*1.5), static_cast<int>(fs*1.4), static_cast<int>(fs*1.3), fs, fs, fs, fs };
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index ba7de0cd6..b3db76e99 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -2298,10 +2298,13 @@ void TabPrinter::build_fff()
}
}
if (opt_key == "gcode_flavor") {
- bool supports_travel_acceleration = (boost::any_cast<int>(value) == int(gcfMarlinFirmware));
- if (supports_travel_acceleration != m_supports_travel_acceleration) {
+ const int flavor = boost::any_cast<int>(value);
+ bool supports_travel_acceleration = (flavor == int(gcfMarlinFirmware) || flavor == int(gcfRepRapFirmware));
+ bool supports_min_feedrates = (flavor == int(gcfMarlinFirmware) || flavor == int(gcfMarlinLegacy));
+ if (supports_travel_acceleration != m_supports_travel_acceleration || supports_min_feedrates != m_supports_min_feedrates) {
m_rebuild_kinematics_page = true;
m_supports_travel_acceleration = supports_travel_acceleration;
+ m_supports_min_feedrates = supports_min_feedrates;
}
}
build_unregular_pages();
@@ -2586,9 +2589,11 @@ PageShp TabPrinter::build_kinematics_page()
append_option_line(optgroup, "machine_max_jerk_" + axis);
}
- optgroup = page->new_optgroup(L("Minimum feedrates"));
- append_option_line(optgroup, "machine_min_extruding_rate");
- append_option_line(optgroup, "machine_min_travel_rate");
+ if (m_supports_min_feedrates) {
+ optgroup = page->new_optgroup(L("Minimum feedrates"));
+ append_option_line(optgroup, "machine_min_extruding_rate");
+ append_option_line(optgroup, "machine_min_travel_rate");
+ }
return page;
}
@@ -2603,7 +2608,7 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/)
{
size_t n_before_extruders = 2; // Count of pages before Extruder pages
auto flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
- bool is_marlin_flavor = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware);
+ bool show_mach_limits = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware);
/* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages
* and be cause of application crash, when try to change Preset in moment,
@@ -2611,26 +2616,26 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/)
* */
Freeze();
- // Add/delete Kinematics page according to is_marlin_flavor
+ // Add/delete Kinematics page according to show_mach_limits
size_t existed_page = 0;
for (size_t i = n_before_extruders; i < m_pages.size(); ++i) // first make sure it's not there already
if (m_pages[i]->title().find(L("Machine limits")) != std::string::npos) {
- if (!is_marlin_flavor || m_rebuild_kinematics_page)
+ if (!show_mach_limits || m_rebuild_kinematics_page)
m_pages.erase(m_pages.begin() + i);
else
existed_page = i;
break;
}
- if (existed_page < n_before_extruders && (is_marlin_flavor || from_initial_build)) {
+ if (existed_page < n_before_extruders && (show_mach_limits || from_initial_build)) {
auto page = build_kinematics_page();
- if (from_initial_build && !is_marlin_flavor)
+ if (from_initial_build && !show_mach_limits)
page->clear();
else
m_pages.insert(m_pages.begin() + n_before_extruders, page);
}
- if (is_marlin_flavor)
+ if (show_mach_limits)
n_before_extruders++;
size_t n_after_single_extruder_MM = 2; // Count of pages after single_extruder_multi_material page
@@ -2868,13 +2873,13 @@ void TabPrinter::toggle_options()
if (!m_active_page || m_presets->get_edited_preset().printer_technology() == ptSLA)
return;
+ const GCodeFlavor flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
bool have_multiple_extruders = m_extruders_count > 1;
if (m_active_page->title() == "Custom G-code")
toggle_option("toolchange_gcode", have_multiple_extruders);
if (m_active_page->title() == "General") {
toggle_option("single_extruder_multi_material", have_multiple_extruders);
- auto flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
bool is_marlin_flavor = flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware;
// Disable silent mode for non-marlin firmwares.
toggle_option("silent_mode", is_marlin_flavor);
@@ -2944,8 +2949,9 @@ void TabPrinter::toggle_options()
}
if (m_active_page->title() == "Machine limits" && m_machine_limits_description_line) {
- assert(m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlinLegacy
- || m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlinFirmware);
+ assert(flavor == gcfMarlinLegacy
+ || flavor == gcfMarlinFirmware
+ || flavor == gcfRepRapFirmware);
const auto *machine_limits_usage = m_config->option<ConfigOptionEnum<MachineLimitsUsage>>("machine_limits_usage");
bool enabled = machine_limits_usage->value != MachineLimitsUsage::Ignore;
bool silent_mode = m_config->opt_bool("silent_mode");
@@ -2977,10 +2983,13 @@ void TabPrinter::update_fff()
m_use_silent_mode = m_config->opt_bool("silent_mode");
}
- bool supports_travel_acceleration = (m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlinFirmware);
- if (m_supports_travel_acceleration != supports_travel_acceleration) {
+ const auto flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
+ bool supports_travel_acceleration = (flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware);
+ bool supports_min_feedrates = (flavor == gcfMarlinFirmware || flavor == gcfMarlinLegacy);
+ if (m_supports_travel_acceleration != supports_travel_acceleration || m_supports_min_feedrates != supports_min_feedrates) {
m_rebuild_kinematics_page = true;
m_supports_travel_acceleration = supports_travel_acceleration;
+ m_supports_min_feedrates = supports_min_feedrates;
}
toggle_options();
diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp
index 45da27bf6..8ae2a5fdc 100644
--- a/src/slic3r/GUI/Tab.hpp
+++ b/src/slic3r/GUI/Tab.hpp
@@ -408,6 +408,7 @@ private:
bool m_has_single_extruder_MM_page = false;
bool m_use_silent_mode = false;
bool m_supports_travel_acceleration = false;
+ bool m_supports_min_feedrates = false;
void append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key);
bool m_rebuild_kinematics_page = false;
ogStaticText* m_machine_limits_description_line {nullptr};
diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp
index 38440b16a..ee057a7aa 100644
--- a/src/slic3r/GUI/UnsavedChangesDialog.cpp
+++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp
@@ -11,6 +11,7 @@
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/PresetBundle.hpp"
+#include "libslic3r/Color.hpp"
#include "format.hpp"
#include "GUI_App.hpp"
#include "Plater.hpp"
@@ -57,9 +58,8 @@ static std::string get_icon_name(Preset::Type type, PrinterTechnology pt) {
static std::string def_text_color()
{
- wxColour def_colour = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
- auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), def_colour.Red(), def_colour.Green(), def_colour.Blue());
- return clr_str.ToStdString();
+ wxColour def_colour = wxGetApp().get_label_clr_default();
+ return encode_color(ColorRGB(def_colour.Red(), def_colour.Green(), def_colour.Blue()));
}
static std::string grey = "#808080";
static std::string orange = "#ed6b21";
@@ -124,8 +124,8 @@ wxBitmap ModelNode::get_bitmap(const wxString& color)
const int icon_height = lround(1.6 * em);
BitmapCache bmp_cache;
- unsigned char rgb[3];
- BitmapCache::parse_color(into_u8(color), rgb);
+ ColorRGB rgb;
+ decode_color(into_u8(color), rgb);
// there is no need to scale created solid bitmap
#ifndef __linux__
return bmp_cache.mksolid(icon_width, icon_height, rgb, true);
@@ -891,12 +891,12 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
{
if (!evt.IsChecked())
return;
- wxString preferences_item = m_app_config_key == "default_action_on_new_project" ? _L("Ask for unsaved changes when creating new project") :
- m_app_config_key == "default_action_on_select_preset" ? _L("Ask for unsaved changes when selecting new preset") :
- _L("Ask to save unsaved changes when closing the application or when loading a new project") ;
- wxString action = m_app_config_key == "default_action_on_new_project" ? _L("You will not be asked about the unsaved changes the next time you create new project") :
- m_app_config_key == "default_action_on_select_preset" ? _L("You will not be asked about the unsaved changes the next time you switch a preset") :
- _L("You will not be asked about the unsaved changes the next time you: \n"
+ wxString preferences_item = m_app_config_key == "default_action_on_new_project" ? _L("Ask for unsaved changes in presets when creating new project") :
+ m_app_config_key == "default_action_on_select_preset" ? _L("Ask for unsaved changes in presets when selecting new preset") :
+ _L("Ask to save unsaved changes in presets when closing the application or when loading a new project") ;
+ wxString action = m_app_config_key == "default_action_on_new_project" ? _L("You will not be asked about the unsaved changes in presets the next time you create new project") :
+ m_app_config_key == "default_action_on_select_preset" ? _L("You will not be asked about the unsaved changes in presets the next time you switch a preset") :
+ _L("You will not be asked about the unsaved changes in presets the next time you: \n"
"- Closing PrusaSlicer while some presets are modified,\n"
"- Loading a new project while some presets are modified") ;
wxString msg = _L("PrusaSlicer will remember your action.") + "\n\n" + action + "\n\n" +
@@ -927,7 +927,7 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
void UnsavedChangesDialog::show_info_line(Action action, std::string preset_name)
{
- if (action == Action::Undef && !m_has_long_strings)
+ if (action == Action::Undef && !m_tree->has_long_strings())
m_info_line->Hide();
else {
wxString text;
@@ -1441,7 +1441,7 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
m_preset_bundle_left = std::make_unique<PresetBundle>(*wxGetApp().preset_bundle);
m_preset_bundle_right = std::make_unique<PresetBundle>(*wxGetApp().preset_bundle);
- m_top_info_line = new wxStaticText(this, wxID_ANY, "Select presets to compare");
+ m_top_info_line = new wxStaticText(this, wxID_ANY, _L("Select presets to compare"));
m_top_info_line->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold());
m_bottom_info_line = new wxStaticText(this, wxID_ANY, "");
diff --git a/src/slic3r/GUI/UnsavedChangesDialog.hpp b/src/slic3r/GUI/UnsavedChangesDialog.hpp
index 42f93f660..d9154850e 100644
--- a/src/slic3r/GUI/UnsavedChangesDialog.hpp
+++ b/src/slic3r/GUI/UnsavedChangesDialog.hpp
@@ -221,6 +221,7 @@ public:
void item_value_changed(wxDataViewEvent& event);
void set_em_unit(int em) { m_em_unit = em; }
bool has_unselected_options();
+ bool has_long_strings() { return m_has_long_strings; }
std::vector<std::string> options(Preset::Type type, bool selected);
std::vector<std::string> selected_options();
@@ -240,7 +241,6 @@ class UnsavedChangesDialog : public DPIDialog
wxStaticText* m_info_line { nullptr };
wxCheckBox* m_remember_choice { nullptr };
- bool m_has_long_strings { false };
int m_save_btn_id { wxID_ANY };
int m_move_btn_id { wxID_ANY };
int m_continue_btn_id { wxID_ANY };
diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp
index 71b87322f..4d117ff8d 100644
--- a/src/slic3r/GUI/WipeTowerDialog.cpp
+++ b/src/slic3r/GUI/WipeTowerDialog.cpp
@@ -7,6 +7,8 @@
#include "GUI_App.hpp"
#include "MsgDialog.hpp"
+#include "libslic3r/Color.hpp"
+
#include <wx/sizer.h>
int scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit(); }
@@ -226,9 +228,9 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
m_number_of_extruders = (int)(sqrt(matrix.size())+0.001);
for (const std::string& color : extruder_colours) {
- unsigned char rgb[3];
- Slic3r::GUI::BitmapCache::parse_color(color, rgb);
- m_colours.push_back(wxColor(rgb[0], rgb[1], rgb[2]));
+ Slic3r::ColorRGB rgb;
+ Slic3r::decode_color(color, rgb);
+ m_colours.push_back(wxColor(rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar()));
}
// Create two switched panels with their own sizers
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 9b70657e1..ebd854cc3 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -18,6 +18,8 @@
#include "BitmapComboBox.hpp"
#include "OG_CustomCtrl.hpp"
+#include "libslic3r/Color.hpp"
+
#ifndef __linux__
// msw_menuitem_bitmaps is used for MSW and OSX
static std::map<int, std::string> msw_menuitem_bitmaps;
@@ -472,8 +474,6 @@ std::vector<wxBitmap*> get_extruder_color_icons(bool thin_icon/* = false*/)
if (colors.empty())
return bmps;
- unsigned char rgb[3];
-
/* It's supposed that standard size of an icon is 36px*16px for 100% scaled display.
* So set sizes for solid_colored icons used for filament preset
* and scale them in respect to em_unit value
@@ -491,7 +491,8 @@ std::vector<wxBitmap*> get_extruder_color_icons(bool thin_icon/* = false*/)
wxBitmap* bitmap = bmp_cache.find(bitmap_key);
if (bitmap == nullptr) {
// Paint the color icon.
- Slic3r::GUI::BitmapCache::parse_color(color, rgb);
+ Slic3r::ColorRGB rgb;
+ Slic3r::decode_color(color, rgb);
// there is no neede to scale created solid bitmap
bitmap = bmp_cache.insert(bitmap_key, bmp_cache.mksolid(icon_width, icon_height, rgb, true, 1, dark_mode));
}
diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp
index 6f6b21f68..296c58622 100644
--- a/src/slic3r/Utils/FixModelByWin10.cpp
+++ b/src/slic3r/Utils/FixModelByWin10.cpp
@@ -284,29 +284,32 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
// Open the destination file.
FILE *fout = boost::nowide::fopen(path_dst.c_str(), "wb");
-
- Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- byte *buffer_ptr;
- bufferFactory->Create(65536 * 2048, buffer.GetAddressOf());
- {
- Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
- buffer.As(&bufferByteAccess);
- hr = bufferByteAccess->Buffer(&buffer_ptr);
- }
- uint32_t length;
- hr = buffer->get_Length(&length);
-
- Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
- for (;;) {
- hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
- status = winrt_async_await(asyncRead, throw_on_cancel);
- if (status != AsyncStatus::Completed)
- throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
+ try {
+ Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ byte *buffer_ptr;
+ bufferFactory->Create(65536 * 2048, buffer.GetAddressOf());
+ {
+ Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
+ buffer.As(&bufferByteAccess);
+ hr = bufferByteAccess->Buffer(&buffer_ptr);
+ }
+ uint32_t length;
hr = buffer->get_Length(&length);
- if (length == 0)
- break;
- fwrite(buffer_ptr, length, 1, fout);
- }
+ Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
+ for (;;) {
+ hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
+ status = winrt_async_await(asyncRead, throw_on_cancel);
+ if (status != AsyncStatus::Completed)
+ throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
+ hr = buffer->get_Length(&length);
+ if (length == 0)
+ break;
+ fwrite(buffer_ptr, length, 1, fout);
+ }
+ } catch (...) {
+ fclose(fout);
+ throw;
+ }
fclose(fout);
// Here all the COM objects will be released through the ComPtr destructors.
}