Fixed conflicts after merge with master

This commit is contained in:
enricoturri1966 2020-11-24 13:37:52 +01:00
commit 9d71597e05
32 changed files with 6257 additions and 4486 deletions

View file

@ -249,5 +249,5 @@ else ()
install(TARGETS PrusaSlicer RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
# Install the symlink for gcodeviewer
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink prusa-slicer prusa-gcodeviewer WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})")
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink prusa-slicer prusa-gcodeviewer WORKING_DIRECTORY \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})")
endif ()

View file

@ -29,6 +29,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ip3DHoneycomb: return new Fill3DHoneycomb();
case ipGyroid: return new FillGyroid();
case ipRectilinear: return new FillRectilinear();
case ipAlignedRectilinear: return new FillAlignedRectilinear();
case ipMonotonic: return new FillMonotonic();
case ipLine: return new FillLine();
case ipGrid: return new FillGrid();

View file

@ -29,6 +29,17 @@ protected:
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
};
class FillAlignedRectilinear : public FillRectilinear
{
public:
Fill* clone() const override { return new FillAlignedRectilinear(*this); };
~FillAlignedRectilinear() override = default;
protected:
// Always generate infill at the same angle.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
class FillMonotonic : public FillRectilinear
{
public:

View file

@ -256,6 +256,10 @@ namespace Slic3r {
// subdivide the retraction in segments
if (!wipe_path.empty()) {
#if ENABLE_SHOW_WIPE_MOVES
// add tag for processor
gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n";
#endif // ENABLE_SHOW_WIPE_MOVES
for (const Line& line : wipe_path.lines()) {
double segment_length = line.length();
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
@ -270,6 +274,10 @@ namespace Slic3r {
"wipe and retract"
);
}
#if ENABLE_SHOW_WIPE_MOVES
// add tag for processor
gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";
#endif // ENABLE_SHOW_WIPE_MOVES
gcodegen.set_last_pos(wipe_path.points.back());
}

View file

@ -25,6 +25,10 @@ static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
namespace Slic3r {
const std::string GCodeProcessor::Extrusion_Role_Tag = "TYPE:";
#if ENABLE_SHOW_WIPE_MOVES
const std::string GCodeProcessor::Wipe_Start_Tag = "WIPE_START";
const std::string GCodeProcessor::Wipe_End_Tag = "WIPE_END";
#endif // ENABLE_SHOW_WIPE_MOVES
const std::string GCodeProcessor::Height_Tag = "HEIGHT:";
const std::string GCodeProcessor::Layer_Change_Tag = "LAYER_CHANGE";
const std::string GCodeProcessor::Color_Change_Tag = "COLOR_CHANGE";
@ -35,6 +39,11 @@ const std::string GCodeProcessor::First_Line_M73_Placeholder_Tag = "; _
const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER";
const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER";
#if ENABLE_SHOW_WIPE_MOVES
const float GCodeProcessor::Wipe_Width = 0.05f;
const float GCodeProcessor::Wipe_Height = 0.05f;
#endif // ENABLE_SHOW_WIPE_MOVES
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
@ -390,13 +399,11 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
};
// check for temporary lines
auto is_temporary_decoration = [](const std::string& gcode_line) {
auto is_temporary_decoration = [](const std::string_view gcode_line) {
// remove trailing '\n'
std::string line = gcode_line.substr(0, gcode_line.length() - 1);
if (line == ";" + Layer_Change_Tag)
return true;
else
return false;
assert(! gcode_line.empty());
assert(gcode_line.back() == '\n');
return gcode_line.substr(0, gcode_line.length() - 1) == ";" + Layer_Change_Tag;
};
// Iterators for the normal and silent cached time estimate entry recently processed, used by process_line_G1.
@ -591,9 +598,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
}
}
// ensure at least one (default) color is defined
std::string default_color = "#FF8000";
m_result.extruder_colors = std::vector<std::string>(1, default_color);
const ConfigOptionStrings* extruder_colour = config.option<ConfigOptionStrings>("extruder_colour");
if (extruder_colour != nullptr) {
// takes colors from config
@ -608,7 +612,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
}
}
// replace missing values with default
std::string default_color = "#FF8000";
for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) {
if (m_result.extruder_colors[i].empty())
m_result.extruder_colors[i] = default_color;
@ -725,6 +731,9 @@ void GCodeProcessor::reset()
m_end_position = { 0.0f, 0.0f, 0.0f, 0.0f };
m_origin = { 0.0f, 0.0f, 0.0f, 0.0f };
m_cached_position.reset();
#if ENABLE_SHOW_WIPE_MOVES
m_wiping = false;
#endif // ENABLE_SHOW_WIPE_MOVES
m_feedrate = 0.0f;
m_width = 0.0f;
@ -806,6 +815,16 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
process_gcode_line(line);
});
#if ENABLE_SHOW_WIPE_MOVES
// update width/height of wipe moves
for (MoveVertex& move : m_result.moves) {
if (move.type == EMoveType::Wipe) {
move.width = Wipe_Width;
move.height = Wipe_Height;
}
}
#endif // ENABLE_SHOW_WIPE_MOVES
// process the time blocks
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
TimeMachine& machine = m_time_processor.machines[i];
@ -817,10 +836,6 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
update_estimated_times_stats();
// ensure at least one (default) color is defined
if (m_result.extruder_colors.empty())
m_result.extruder_colors.push_back("#FF8000");
// post-process to add M73 lines into the gcode
if (apply_postprocess)
m_time_processor.post_process(filename);
@ -1031,6 +1046,20 @@ void GCodeProcessor::process_tags(const std::string_view comment)
return;
}
#if ENABLE_SHOW_WIPE_MOVES
// wipe start tag
if (starts_with(comment, Wipe_Start_Tag)) {
m_wiping = true;
return;
}
// wipe end tag
if (starts_with(comment, Wipe_End_Tag)) {
m_wiping = false;
return;
}
#endif // ENABLE_SHOW_WIPE_MOVES
if ((!m_producers_enabled || m_producer == EProducer::PrusaSlicer) &&
starts_with(comment, Height_Tag)) {
// height tag
@ -1427,7 +1456,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
auto move_type = [this](const AxisCoords& delta_pos) {
EMoveType type = EMoveType::Noop;
#if ENABLE_SHOW_WIPE_MOVES
if (m_wiping)
type = EMoveType::Wipe;
else if (delta_pos[E] < 0.0f)
#else
if (delta_pos[E] < 0.0f)
#endif // ENABLE_SHOW_WIPE_MOVES
type = (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) ? EMoveType::Travel : EMoveType::Retract;
else if (delta_pos[E] > 0.0f) {
if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f)

View file

@ -24,6 +24,9 @@ namespace Slic3r {
Pause_Print,
Custom_GCode,
Travel,
#if ENABLE_SHOW_WIPE_MOVES
Wipe,
#endif // ENABLE_SHOW_WIPE_MOVES
Extrude,
Count
};
@ -69,6 +72,10 @@ namespace Slic3r {
{
public:
static const std::string Extrusion_Role_Tag;
#if ENABLE_SHOW_WIPE_MOVES
static const std::string Wipe_Start_Tag;
static const std::string Wipe_End_Tag;
#endif // ENABLE_SHOW_WIPE_MOVES
static const std::string Height_Tag;
static const std::string Layer_Change_Tag;
static const std::string Color_Change_Tag;
@ -78,6 +85,11 @@ namespace Slic3r {
static const std::string Last_Line_M73_Placeholder_Tag;
static const std::string Estimated_Printing_Time_Placeholder_Tag;
#if ENABLE_SHOW_WIPE_MOVES
static const float Wipe_Width;
static const float Wipe_Height;
#endif // ENABLE_SHOW_WIPE_MOVES
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
static const std::string Width_Tag;
static const std::string Mm3_Per_Mm_Tag;
@ -390,6 +402,9 @@ namespace Slic3r {
AxisCoords m_end_position; // mm
AxisCoords m_origin; // mm
CachedPosition m_cached_position;
#if ENABLE_SHOW_WIPE_MOVES
bool m_wiping;
#endif // ENABLE_SHOW_WIPE_MOVES
float m_feedrate; // mm/s
float m_width; // mm

View file

@ -460,12 +460,14 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("concentric");
def->enum_values.push_back("hilbertcurve");
def->enum_values.push_back("archimedeanchords");
def->enum_values.push_back("octagramspiral");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Hilbert Curve"));
def->enum_labels.push_back(L("Archimedean Chords"));
@ -808,7 +810,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("filament_spool_weight", coFloats);
def->label = L("Spool weight");
def->tooltip = L("Enter weight of the spool without filament. This is only for statistical information.");
def->tooltip = L("Enter weight of the empty filament spool. "
"One may weigh a partially consumed filament spool before printing and one may compare the measured weight "
"with the calculated weight of the filament with the spool to find out whether the amount "
"of filament on the spool is sufficient to finish the print.");
def->sidetext = L("g");
def->min = 0;
def->set_default_value(new ConfigOptionFloats { 0. });
@ -878,6 +883,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Fill pattern for general low-density infill.");
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("grid");
def->enum_values.push_back("triangles");
def->enum_values.push_back("stars");
@ -893,6 +899,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("adaptivecubic");
def->enum_values.push_back("supportcubic");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Grid"));
def->enum_labels.push_back(L("Triangles"));
def->enum_labels.push_back(L("Stars"));
@ -1548,8 +1555,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("perimeter_acceleration", coFloat);
def->label = L("Perimeters");
def->tooltip = L("This is the acceleration your printer will use for perimeters. "
"A high value like 9000 usually gives good results if your hardware is up to the job. "
"Set zero to disable acceleration control for perimeters.");
"Set zero to disable acceleration control for perimeters.");
def->sidetext = L("mm/s²");
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));

View file

@ -44,7 +44,7 @@ enum AuthorizationType {
};
enum InfillPattern : int {
ipRectilinear, ipMonotonic, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipCount,
};
@ -145,6 +145,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
if (keys_map.empty()) {
keys_map["rectilinear"] = ipRectilinear;
keys_map["monotonic"] = ipMonotonic;
keys_map["alignedrectilinear"] = ipAlignedRectilinear;
keys_map["grid"] = ipGrid;
keys_map["triangles"] = ipTriangles;
keys_map["stars"] = ipStars;

View file

@ -79,6 +79,7 @@
//===================
#define ENABLE_2_3_0_BETA1 1
#define ENABLE_SHOW_WIPE_MOVES (1 && ENABLE_GCODE_VIEWER && ENABLE_2_3_0_BETA1)
#define ENABLE_DRAG_AND_DROP_FIX (1 && ENABLE_2_3_0_BETA1)
#endif // _prusaslicer_technologies_h_

View file

@ -18,9 +18,6 @@
#include <wx/bmpcbox.h>
#include <wx/statline.h>
#include <wx/dcclient.h>
#if !ENABLE_GCODE_VIEWER
#include <wx/numformatter.h>
#endif // !ENABLE_GCODE_VIEWER
#include <wx/colordlg.h>
#include <cmath>
@ -74,13 +71,8 @@ Control::Control( wxWindow *parent,
if (!is_osx)
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
#if ENABLE_GCODE_VIEWER
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "thumb_right") : ScalableBitmap(this, "thumb_up"));
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "thumb_left") : ScalableBitmap(this, "thumb_down"));
#else
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "right_half_circle.png") : ScalableBitmap(this, "thumb_up"));
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "left_half_circle.png" ) : ScalableBitmap(this, "thumb_down"));
#endif // ENABLE_GCODE_VIEWER
m_thumb_size = m_bmp_thumb_lower.GetBmpSize();
m_bmp_add_tick_on = ScalableBitmap(this, "colorchange_add");
@ -314,22 +306,14 @@ double Control::get_double_value(const SelectedSlider& selection)
Info Control::GetTicksValues() const
{
Info custom_gcode_per_print_z;
#if ENABLE_GCODE_VIEWER
std::vector<CustomGCode::Item>& values = custom_gcode_per_print_z.gcodes;
#else
std::vector<Item>& values = custom_gcode_per_print_z.gcodes;
#endif // ENABLE_GCODE_VIEWER
const int val_size = m_values.size();
if (!m_values.empty())
for (const TickCode& tick : m_ticks.ticks) {
if (tick.tick > val_size)
break;
#if ENABLE_GCODE_VIEWER
values.emplace_back(CustomGCode::Item{ m_values[tick.tick], tick.type, tick.extruder, tick.color, tick.extra });
#else
values.emplace_back(Item{m_values[tick.tick], tick.type, tick.extruder, tick.color, tick.extra});
#endif // ENABLE_GCODE_VIEWER
}
if (m_force_mode_apply)
@ -348,11 +332,7 @@ void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
const bool was_empty = m_ticks.empty();
m_ticks.ticks.clear();
#if ENABLE_GCODE_VIEWER
const std::vector<CustomGCode::Item>& heights = custom_gcode_per_print_z.gcodes;
#else
const std::vector<Item>& heights = custom_gcode_per_print_z.gcodes;
#endif // ENABLE_GCODE_VIEWER
for (auto h : heights) {
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon());
@ -442,15 +422,11 @@ void Control::draw_focus_rect()
void Control::render()
{
#if ENABLE_GCODE_VIEWER
#ifdef _WIN32
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#else
SetBackgroundColour(GetParent()->GetBackgroundColour());
#endif // _WIN32
#else
SetBackgroundColour(GetParent()->GetBackgroundColour());
#endif // ENABLE_GCODE_VIEWER
draw_focus_rect();
wxPaintDC dc(this);
@ -494,10 +470,8 @@ void Control::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
#if ENABLE_GCODE_VIEWER
if (!m_enable_action_icon)
return;
#endif // ENABLE_GCODE_VIEWER
// suppress add tick on first layer
if (tick == 0)
@ -651,13 +625,12 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer
if (value >= m_values.size())
return "ErrVal";
#if ENABLE_GCODE_VIEWER
if (m_draw_mode == dmSequentialGCodeView)
return wxString::Format("%d", static_cast<unsigned int>(m_values[value]));
else {
if (label_type == ltEstimatedTime) {
if (m_values.size() != m_layers_times.size())
return "time";
return wxEmptyString;
return short_and_splitted_time(get_time_dhms(m_layers_times[value]));
}
wxString str = m_values.empty() ?
@ -668,15 +641,7 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer
if (label_type == ltHeightWithLayer)
return format_wxstr("%1%\n(%2%)", str, m_values.empty() ? value : value + 1);
}
#else
const wxString str = m_values.empty() ?
wxNumberFormatter::ToString(m_label_koef * value, 2, wxNumberFormatter::Style_None) :
wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None);
if (label_type == ltHeight)
return str;
if (label_type == ltHeightWithLayer)
return format_wxstr("%1%\n(%2%)", str, m_values.empty() ? value : value + 1);
#endif // ENABLE_GCODE_VIEWER
return wxEmptyString;
}
@ -722,32 +687,8 @@ void Control::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider
void Control::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection)
{
#if ENABLE_GCODE_VIEWER
wxCoord x_draw = pos.x - int(0.5 * m_thumb_size.x);
wxCoord y_draw = pos.y - int(0.5 * m_thumb_size.y);
#else
wxCoord x_draw, y_draw;
if (selection == ssLower) {
if (is_horizontal()) {
x_draw = pos.x - m_thumb_size.x;
y_draw = pos.y - int(0.5*m_thumb_size.y);
}
else {
x_draw = pos.x - int(0.5*m_thumb_size.x);
y_draw = pos.y - int(0.5*m_thumb_size.y);
}
}
else {
if (is_horizontal()) {
x_draw = pos.x;
y_draw = pos.y - int(0.5*m_thumb_size.y);
}
else {
x_draw = pos.x - int(0.5*m_thumb_size.x);
y_draw = pos.y - int(0.5*m_thumb_size.y);
}
}
#endif // ENABLE_GCODE_VIEWER
dc.DrawBitmap(selection == ssLower ? m_bmp_thumb_lower.bmp() : m_bmp_thumb_higher.bmp(), x_draw, y_draw);
// Update thumb rect
@ -913,15 +854,11 @@ void Control::draw_colored_band(wxDC& dc)
// don't color a band for MultiExtruder mode
if (m_ticks.empty() || m_mode == MultiExtruder) {
#if ENABLE_GCODE_VIEWER
#ifdef _WIN32
draw_band(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW), main_band);
#else
draw_band(dc, GetParent()->GetBackgroundColour(), main_band);
#endif // _WIN32
#else
draw_band(dc, GetParent()->GetBackgroundColour(), main_band);
#endif // ENABLE_GCODE_VIEWER
return;
}
@ -1065,10 +1002,8 @@ void Control::draw_ruler(wxDC& dc)
void Control::draw_one_layer_icon(wxDC& dc)
{
#if ENABLE_GCODE_VIEWER
if (m_draw_mode == dmSequentialGCodeView)
return;
#endif // ENABLE_GCODE_VIEWER
const wxBitmap& icon = m_is_one_layer ?
m_focus == fiOneLayerIcon ? m_bmp_one_layer_lock_off.bmp() : m_bmp_one_layer_lock_on.bmp() :
@ -1107,26 +1042,21 @@ void Control::draw_revert_icon(wxDC& dc)
void Control::draw_cog_icon(wxDC& dc)
{
#if ENABLE_GCODE_VIEWER
if (m_draw_mode == dmSequentialGCodeView)
return;
#endif // ENABLE_GCODE_VIEWER
int width, height;
get_size(&width, &height);
wxCoord x_draw, y_draw;
#if ENABLE_GCODE_VIEWER
if (m_draw_mode == dmSequentialGCodeView) {
is_horizontal() ? x_draw = width - 2 : x_draw = 0.5 * width - 0.5 * m_cog_icon_dim;
is_horizontal() ? y_draw = 0.5 * height - 0.5 * m_cog_icon_dim : y_draw = height - 2;
}
else {
#endif // ENABLE_GCODE_VIEWER
is_horizontal() ? x_draw = width - 2 : x_draw = width - m_cog_icon_dim - 2;
is_horizontal() ? y_draw = height - m_cog_icon_dim - 2 : y_draw = height - 2;
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
dc.DrawBitmap(m_bmp_cog.bmp(), x_draw, y_draw);
@ -1273,19 +1203,15 @@ wxString Control::get_tooltip(int tick/*=-1*/)
if (m_focus == fiRevertIcon)
return _L("Discard all custom changes");
if (m_focus == fiCogIcon)
#if ENABLE_GCODE_VIEWER
{
if (m_draw_mode == dmSequentialGCodeView)
return _L("Jump to move") + " (Shift + G)";
else
#endif // ENABLE_GCODE_VIEWER
return m_mode == MultiAsSingle ?
GUI::from_u8((boost::format(_u8L("Jump to height %s Set ruler mode\n or "
"Set extruder sequence for the entire print")) % " (Shift + G)\n").str()) :
GUI::from_u8((boost::format(_u8L("Jump to height %s or Set ruler mode")) % " (Shift + G)\n").str());
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
if (m_focus == fiColorBand)
return m_mode != SingleExtruder ? "" :
_L("Edit current color - Right click the colored slider segment");
@ -1619,17 +1545,12 @@ void Control::OnWheel(wxMouseEvent& event)
if (m_selection == ssLower && !is_lower_thumb_editable())
m_selection = ssUndef;
#if ENABLE_GCODE_VIEWER
move_current_thumb((m_draw_mode == dmSequentialGCodeView) ? event.GetWheelRotation() < 0 : event.GetWheelRotation() > 0);
#else
move_current_thumb(event.GetWheelRotation() > 0);
#endif // ENABLE_GCODE_VIEWER
}
void Control::OnKeyDown(wxKeyEvent &event)
{
const int key = event.GetKeyCode();
#if ENABLE_GCODE_VIEWER
if (m_draw_mode != dmSequentialGCodeView && key == WXK_NUMPAD_ADD) {
// OnChar() is called immediately after OnKeyDown(), which can cause call of add_tick() twice.
// To avoid this case we should suppress second add_tick() call.
@ -1644,26 +1565,8 @@ void Control::OnKeyDown(wxKeyEvent &event)
}
else if (m_draw_mode != dmSequentialGCodeView && event.GetKeyCode() == WXK_SHIFT)
UseDefaultColors(false);
#else
if (key == WXK_NUMPAD_ADD) {
// OnChar() is called immediately after OnKeyDown(), which can cause call of add_tick() twice.
// To avoid this case we should suppress second add_tick() call.
m_ticks.suppress_plus(true);
add_current_tick(true);
}
else if (key == 390 || key == WXK_DELETE || key == WXK_BACK) {
// OnChar() is called immediately after OnKeyDown(), which can cause call of delete_tick() twice.
// To avoid this case we should suppress second delete_tick() call.
m_ticks.suppress_minus(true);
delete_current_tick();
}
else if (event.GetKeyCode() == WXK_SHIFT)
UseDefaultColors(false);
#endif // ENABLE_GCODE_VIEWER
else if (is_horizontal()) {
#if ENABLE_GCODE_VIEWER
if (m_is_focused) {
#endif // ENABLE_GCODE_VIEWER
if (key == WXK_LEFT || key == WXK_RIGHT)
move_current_thumb(key == WXK_LEFT);
else if (key == WXK_UP || key == WXK_DOWN) {
@ -1673,14 +1576,10 @@ void Control::OnKeyDown(wxKeyEvent &event)
m_selection = ssLower;
Refresh();
}
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
}
else {
#if ENABLE_GCODE_VIEWER
if (m_is_focused) {
#endif // ENABLE_GCODE_VIEWER
if (key == WXK_LEFT || key == WXK_RIGHT) {
if (key == WXK_LEFT)
m_selection = ssHigher;
@ -1690,9 +1589,7 @@ void Control::OnKeyDown(wxKeyEvent &event)
}
else if (key == WXK_UP || key == WXK_DOWN)
move_current_thumb(key == WXK_UP);
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
}
event.Skip(); // !Needed to have EVT_CHAR generated as well
@ -1713,10 +1610,7 @@ void Control::OnKeyUp(wxKeyEvent &event)
void Control::OnChar(wxKeyEvent& event)
{
const int key = event.GetKeyCode();
#if ENABLE_GCODE_VIEWER
if (m_draw_mode != dmSequentialGCodeView)
{
#endif // ENABLE_GCODE_VIEWER
if (m_draw_mode != dmSequentialGCodeView) {
if (key == '+' && !m_ticks.suppressed_plus()) {
add_current_tick(true);
m_ticks.suppress_plus(false);
@ -1725,15 +1619,9 @@ void Control::OnChar(wxKeyEvent& event)
delete_current_tick();
m_ticks.suppress_minus(false);
}
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
if (key == 'G')
#if ENABLE_GCODE_VIEWER
jump_to_value();
#else
jump_to_print_z();
#endif // ENABLE_GCODE_VIEWER
}
void Control::OnRightDown(wxMouseEvent& event)
@ -1920,11 +1808,7 @@ void Control::show_cog_icon_context_menu()
wxMenu menu;
append_menu_item(&menu, wxID_ANY, _L("Jump to height") + " (Shift+G)", "",
#if ENABLE_GCODE_VIEWER
[this](wxCommandEvent&) { jump_to_value(); }, "", & menu);
#else
[this](wxCommandEvent&) { jump_to_print_z(); }, "", &menu);
#endif // ENABLE_GCODE_VIEWER
[this](wxCommandEvent&) { jump_to_value(); }, "", & menu);
wxMenu* ruler_mode_menu = new wxMenu();
if (ruler_mode_menu) {
@ -2061,21 +1945,11 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
return into_u8(dlg.GetValue());
}
#if ENABLE_GCODE_VIEWER
static double get_value_to_jump(double active_value, double min_z, double max_z, DrawMode mode)
#else
static double get_print_z_to_jump(double active_print_z, double min_z, double max_z)
#endif // ENABLE_GCODE_VIEWER
{
#if ENABLE_GCODE_VIEWER
wxString msg_text = (mode == dmSequentialGCodeView) ? _L("Enter the move you want to jump to") + ":" : _L("Enter the height you want to jump to") + ":";
wxString msg_header = (mode == dmSequentialGCodeView) ? _L("Jump to move") : _L("Jump to height");
wxString msg_in = GUI::double_to_string(active_value);
#else
wxString msg_text = _L("Enter the height you want to jump to") + ":";
wxString msg_header = _L("Jump to height");
wxString msg_in = GUI::double_to_string(active_print_z);
#endif // ENABLE_GCODE_VIEWER
// get custom gcode
wxTextEntryDialog dlg(nullptr, msg_text, msg_header, msg_in, wxTextEntryDialogStyle);
@ -2277,7 +2151,6 @@ void Control::edit_extruder_sequence()
post_ticks_changed_event(ToolChange);
}
#if ENABLE_GCODE_VIEWER
void Control::jump_to_value()
{
double value = get_value_to_jump(m_values[m_selection == ssLower ? m_lower_value : m_higher_value],
@ -2293,23 +2166,6 @@ void Control::jump_to_value()
else
SetHigherValue(tick_value);
}
#else
void Control::jump_to_print_z()
{
double print_z = get_print_z_to_jump(m_values[m_selection == ssLower ? m_lower_value : m_higher_value],
m_values[m_min_value], m_values[m_max_value]);
if (print_z < 0)
return;
auto it = std::lower_bound(m_values.begin(), m_values.end(), print_z - epsilon());
int tick_value = it - m_values.begin();
if (m_selection == ssLower)
SetLowerValue(tick_value);
else
SetHigherValue(tick_value);
}
#endif // ENABLE_GCODE_VIEWER
void Control::post_ticks_changed_event(Type type /*= Custom*/)
{
@ -2378,11 +2234,7 @@ bool Control::check_ticks_changed_event(Type type)
std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder)
{
if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) {
#if ENABLE_GCODE_VIEWER
const std::vector<std::string>& colors = ColorPrintColors::get();
#else
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
#endif // ENABLE_GCODE_VIEWER
if (ticks.empty())
return colors[0];
m_default_color_idx++;

View file

@ -4,9 +4,6 @@
#include "libslic3r/CustomGCode.hpp"
#include "wxExtensions.hpp"
#if !ENABLE_GCODE_VIEWER
#include <wx/wx.h>
#endif // !ENABLE_GCODE_VIEWER
#include <wx/window.h>
#include <wx/control.h>
#include <wx/dc.h>
@ -79,9 +76,7 @@ enum DrawMode
dmRegular,
dmSlaPrint,
dmSequentialFffPrint,
#if ENABLE_GCODE_VIEWER
dmSequentialGCodeView,
#endif // ENABLE_GCODE_VIEWER
};
enum LabelType
@ -228,9 +223,7 @@ public:
void SetLayersTimes(const std::vector<double>& layers_times);
void SetDrawMode(bool is_sla_print, bool is_sequential_print);
#if ENABLE_GCODE_VIEWER
void SetDrawMode(DrawMode mode) { m_draw_mode = mode; }
#endif // ENABLE_GCODE_VIEWER
void SetManipulationMode(Mode mode) { m_mode = mode; }
Mode GetManipulationMode() const { return m_mode; }
@ -270,12 +263,8 @@ public:
void discard_all_thicks();
void move_current_thumb_to_pos(wxPoint pos);
void edit_extruder_sequence();
#if ENABLE_GCODE_VIEWER
void jump_to_value();
void enable_action_icon(bool enable) { m_enable_action_icon = enable; }
#else
void jump_to_print_z();
#endif // ENABLE_GCODE_VIEWER
void show_add_context_menu();
void show_edit_context_menu();
void show_cog_icon_context_menu();
@ -371,9 +360,7 @@ private:
bool m_is_one_layer = false;
bool m_is_focused = false;
bool m_force_mode_apply = true;
#if ENABLE_GCODE_VIEWER
bool m_enable_action_icon = true;
#endif // ENABLE_GCODE_VIEWER
DrawMode m_draw_mode = dmRegular;

View file

@ -1,7 +1,6 @@
#include "libslic3r/libslic3r.h"
#include "GCodeViewer.hpp"
#if ENABLE_GCODE_VIEWER
#include "libslic3r/Print.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Model.hpp"
@ -272,6 +271,10 @@ const std::vector<GCodeViewer::Color> GCodeViewer::Travel_Colors {{
{ 0.505f, 0.064f, 0.028f } // Retract
}};
#if ENABLE_SHOW_WIPE_MOVES
const GCodeViewer::Color GCodeViewer::Wipe_Color = { 1.0f, 1.0f, 0.0f };
#endif // ENABLE_SHOW_WIPE_MOVES
const std::vector<GCodeViewer::Color> GCodeViewer::Range_Colors {{
{ 0.043f, 0.173f, 0.478f }, // bluish
{ 0.075f, 0.349f, 0.522f },
@ -370,6 +373,10 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std:
// update tool colors
m_tool_colors = decode_colors(str_tool_colors);
// ensure at least one (default) color is defined
if (m_tool_colors.empty())
m_tool_colors.push_back(decode_color("#FF8000"));
// update ranges for coloring / legend
m_extrusions.reset_ranges();
for (size_t i = 0; i < m_moves_count; ++i) {
@ -456,6 +463,9 @@ void GCodeViewer::render() const
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
break;
}
#if ENABLE_SHOW_WIPE_MOVES
case EMoveType::Wipe:
#endif // ENABLE_SHOW_WIPE_MOVES
case EMoveType::Extrude: {
buffer.shader = "gouraud_light";
break;
@ -569,6 +579,9 @@ unsigned int GCodeViewer::get_options_visibility_flags() const
unsigned int flags = 0;
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Travel), is_toolpath_move_type_visible(EMoveType::Travel));
#if ENABLE_SHOW_WIPE_MOVES
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Wipe), is_toolpath_move_type_visible(EMoveType::Wipe));
#endif // ENABLE_SHOW_WIPE_MOVES
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Retractions), is_toolpath_move_type_visible(EMoveType::Retract));
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Unretractions), is_toolpath_move_type_visible(EMoveType::Unretract));
flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::ToolChanges), is_toolpath_move_type_visible(EMoveType::Tool_change));
@ -588,6 +601,9 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags)
};
set_toolpath_move_type_visible(EMoveType::Travel, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Travel)));
#if ENABLE_SHOW_WIPE_MOVES
set_toolpath_move_type_visible(EMoveType::Wipe, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Wipe)));
#endif // ENABLE_SHOW_WIPE_MOVES
set_toolpath_move_type_visible(EMoveType::Retract, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Retractions)));
set_toolpath_move_type_visible(EMoveType::Unretract, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Unretractions)));
set_toolpath_move_type_visible(EMoveType::Tool_change, is_flag_set(static_cast<unsigned int>(Preview::OptionType::ToolChanges)));
@ -925,6 +941,9 @@ void GCodeViewer::init()
buffer.vertices.format = VBuffer::EFormat::Position;
break;
}
#if ENABLE_SHOW_WIPE_MOVES
case EMoveType::Wipe:
#endif // ENABLE_SHOW_WIPE_MOVES
case EMoveType::Extrude:
{
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle;
@ -1392,6 +1411,14 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
#endif // ENABLE_SHOW_OPTION_POINT_LAYERS
}
#if ENABLE_SHOW_WIPE_MOVES
// move the wipe toolpaths half height up to render them on proper position
std::vector<float>& wipe_vertices = vertices[buffer_id(EMoveType::Wipe)];
for (size_t i = 2; i < wipe_vertices.size(); i += 3) {
wipe_vertices[i] += 0.5f * GCodeProcessor::Wipe_Height;
}
#endif // ENABLE_SHOW_WIPE_MOVES
log_memory_usage("Loaded G-code generated vertex buffers, ", vertices, indices);
// toolpaths data -> send vertices data to gpu
@ -1425,7 +1452,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
buffer.paths.clear();
}
// variable used to keep track of the current size (in vertices) of the vertex buffer
#if ENABLE_SHOW_WIPE_MOVES
std::vector<size_t> curr_buffer_vertices_size(m_buffers.size(), 0);
#else
size_t curr_buffer_vertices_size = 0;
#endif // ENABLE_SHOW_WIPE_MOVES
for (size_t i = 0; i < m_moves_count; ++i) {
// skip first vertex
if (i == 0)
@ -1453,7 +1484,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// create another index buffer, and move the current path indices into it
if (buffer_indices.back().size() >= THRESHOLD - static_cast<size_t>(buffer.indices_per_segment())) {
buffer_indices.push_back(IndexBuffer());
#if ENABLE_SHOW_WIPE_MOVES
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) {
#else
if (curr.type == EMoveType::Extrude || curr.type == EMoveType::Travel) {
#endif // ENABLE_SHOW_WIPE_MOVES
if (!(prev.type != curr.type || !buffer.paths.back().matches(curr))) {
Path& last_path = buffer.paths.back();
size_t delta_id = last_path.last.i_id - last_path.first.i_id;
@ -1484,7 +1519,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
break;
}
case TBuffer::ERenderPrimitiveType::Triangle: {
#if ENABLE_SHOW_WIPE_MOVES
add_indices_as_solid(prev, curr, buffer, curr_buffer_vertices_size[id], static_cast<unsigned int>(buffer_indices.size()) - 1, buffer_indices.back(), i);
#else
add_indices_as_solid(prev, curr, buffer, curr_buffer_vertices_size, static_cast<unsigned int>(buffer_indices.size()) - 1, buffer_indices.back(), i);
#endif // ENABLE_SHOW_WIPE_MOVES
break;
}
}
@ -1529,6 +1568,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
for (size_t i = 0; i < travel_buffer_indices.size(); ++i) {
m_statistics.travel_segments_count = travel_buffer_indices[i].size() / m_buffers[travel_buffer_id].indices_per_segment();
}
#if ENABLE_SHOW_WIPE_MOVES
unsigned int wipe_buffer_id = buffer_id(EMoveType::Wipe);
const MultiIndexBuffer& wipe_buffer_indices = indices[wipe_buffer_id];
for (size_t i = 0; i < wipe_buffer_indices.size(); ++i) {
m_statistics.wipe_segments_count = wipe_buffer_indices[i].size() / m_buffers[wipe_buffer_id].indices_per_segment();
}
#endif // ENABLE_SHOW_WIPE_MOVES
unsigned int extrude_buffer_id = buffer_id(EMoveType::Extrude);
const MultiIndexBuffer& extrude_buffer_indices = indices[extrude_buffer_id];
for (size_t i = 0; i < extrude_buffer_indices.size(); ++i) {
@ -1865,6 +1911,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
break;
}
#if ENABLE_SHOW_WIPE_MOVES
case EMoveType::Wipe: { color = Wipe_Color; break; }
#endif // ENABLE_SHOW_WIPE_MOVES
default: { color = { 0.0f, 0.0f, 0.0f }; break; }
}
@ -2597,6 +2646,28 @@ void GCodeViewer::render_legend() const
}
}
#if ENABLE_SHOW_WIPE_MOVES
// wipe paths section
if (m_buffers[buffer_id(EMoveType::Wipe)].visible) {
switch (m_view_type)
{
case EViewType::Feedrate:
case EViewType::Tool:
case EViewType::ColorPrint: { break; }
default: {
// title
ImGui::Spacing();
imgui.title(_u8L("Wipe"));
// items
append_item(EItemType::Line, Wipe_Color, _u8L("Wipe"));
break;
}
}
}
#endif // ENABLE_SHOW_WIPE_MOVES
auto any_option_available = [this]() {
auto available = [this](EMoveType type) {
const TBuffer& buffer = m_buffers[buffer_id(type)];
@ -2712,7 +2783,7 @@ void GCodeViewer::render_legend() const
ImGui::SameLine();
imgui.text(short_time(get_time_dhms(time_mode.time)));
auto show_mode_button = [this, &imgui](const std::string& label, PrintEstimatedTimeStatistics::ETimeMode mode) {
auto show_mode_button = [this, &imgui](const wxString& label, PrintEstimatedTimeStatistics::ETimeMode mode) {
bool show = false;
for (size_t i = 0; i < m_time_statistics.modes.size(); ++i) {
if (i != static_cast<size_t>(mode) &&
@ -2732,11 +2803,11 @@ void GCodeViewer::render_legend() const
switch (m_time_estimate_mode) {
case PrintEstimatedTimeStatistics::ETimeMode::Normal: {
show_mode_button(_u8L("Show stealth mode"), PrintEstimatedTimeStatistics::ETimeMode::Stealth);
show_mode_button(_L("Show stealth mode"), PrintEstimatedTimeStatistics::ETimeMode::Stealth);
break;
}
case PrintEstimatedTimeStatistics::ETimeMode::Stealth: {
show_mode_button(_u8L("Show normal mode"), PrintEstimatedTimeStatistics::ETimeMode::Normal);
show_mode_button(_L("Show normal mode"), PrintEstimatedTimeStatistics::ETimeMode::Normal);
break;
}
}
@ -2827,6 +2898,9 @@ void GCodeViewer::render_statistics() const
if (ImGui::CollapsingHeader("Other")) {
add_counter(std::string("Travel segments count:"), m_statistics.travel_segments_count);
#if ENABLE_SHOW_WIPE_MOVES
add_counter(std::string("Wipe segments count:"), m_statistics.wipe_segments_count);
#endif // ENABLE_SHOW_WIPE_MOVES
add_counter(std::string("Extrude segments count:"), m_statistics.extrude_segments_count);
add_counter(std::string("Max vertices in vertex buffer:"), m_statistics.max_vertices_in_vertex_buffer);
add_counter(std::string("Max indices in index buffer:"), m_statistics.max_indices_in_index_buffer);
@ -2863,4 +2937,3 @@ void GCodeViewer::log_memory_used(const std::string& label, long long additional
} // namespace GUI
} // namespace Slic3r
#endif // ENABLE_GCODE_VIEWER

View file

@ -1,7 +1,6 @@
#ifndef slic3r_GCodeViewer_hpp_
#define slic3r_GCodeViewer_hpp_
#if ENABLE_GCODE_VIEWER
#include "3DScene.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "GLModel.hpp"
@ -24,6 +23,9 @@ class GCodeViewer
static const std::vector<Color> Extrusion_Role_Colors;
static const std::vector<Color> Options_Colors;
static const std::vector<Color> Travel_Colors;
#if ENABLE_SHOW_WIPE_MOVES
static const Color Wipe_Color;
#endif // ENABLE_SHOW_WIPE_MOVES
static const std::vector<Color> Range_Colors;
enum class EOptionsColors : unsigned char
@ -327,6 +329,9 @@ class GCodeViewer
long long render_paths_size{ 0 };
// other
long long travel_segments_count{ 0 };
#if ENABLE_SHOW_WIPE_MOVES
long long wipe_segments_count{ 0 };
#endif // ENABLE_SHOW_WIPE_MOVES
long long extrude_segments_count{ 0 };
long long max_vertices_in_vertex_buffer{ 0 };
long long max_indices_in_index_buffer{ 0 };
@ -361,6 +366,9 @@ class GCodeViewer
void reset_others() {
travel_segments_count = 0;
#if ENABLE_SHOW_WIPE_MOVES
wipe_segments_count = 0;
#endif // ENABLE_SHOW_WIPE_MOVES
extrude_segments_count = 0;
max_vertices_in_vertex_buffer = 0;
max_indices_in_index_buffer = 0;
@ -513,7 +521,5 @@ private:
} // namespace GUI
} // namespace Slic3r
#endif // ENABLE_GCODE_VIEWER
#endif // slic3r_GCodeViewer_hpp_

View file

@ -1091,7 +1091,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
GLCanvas3D::ArrangeSettings load_arrange_settings()
static GLCanvas3D::ArrangeSettings load_arrange_settings()
{
GLCanvas3D::ArrangeSettings settings;
@ -3313,9 +3313,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
const float factor = m_retina_helper->get_scale_factor();
logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
#endif // ENABLE_RETINA_GL
if (!m_mouse.dragging)
if (!m_mouse.dragging) {
// do not post the event if the user is panning the scene
post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, { logical_pos, m_hover_volume_idxs.empty() }));
// or if right click was done over the wipe tower
bool post_right_click_event = m_hover_volume_idxs.empty() || !m_volumes.volumes[get_first_hover_volume_idx()]->is_wipe_tower;
if (post_right_click_event)
post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, { logical_pos, m_hover_volume_idxs.empty() }));
}
}
mouse_up_cleanup();

View file

@ -75,11 +75,9 @@ void GLTexture::Compressor::send_compressed_data_to_gpu()
glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.m_id));
// Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the dat of m_levels modified by the worker thread are accessible to the calling thread.
int num_compressed = (int)m_num_levels_compressed;
for (int i = 0; i < num_compressed; ++ i)
{
for (int i = 0; i < num_compressed; ++ i) {
Level& level = m_levels[i];
if (! level.sent_to_gpu && ! level.compressed_data.empty())
{
if (! level.sent_to_gpu && ! level.compressed_data.empty()) {
glsafe(::glCompressedTexSubImage2D(GL_TEXTURE_2D, (GLint)i, 0, 0, (GLsizei)level.w, (GLsizei)level.h, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)level.compressed_data.size(), (const GLvoid*)level.compressed_data.data()));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (i > 0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
@ -102,14 +100,13 @@ void GLTexture::Compressor::compress()
assert(m_num_levels_compressed == 0);
assert(m_abort_compressing == false);
for (Level& level : m_levels)
{
for (Level& level : m_levels) {
if (m_abort_compressing)
break;
// stb_dxt library, despite claiming that the needed size of the destination buffer is equal to (source buffer size)/4,
// crashes if doing so, requiring a minimum of 16 bytes and up to a third of the source buffer size, so we set the destination buffer initial size to be half the source buffer size
level.compressed_data = std::vector<unsigned char>(std::max((unsigned int)16, level.w * level.h * 2), 0);
// crashes if doing so, requiring a minimum of 64 bytes and up to a third of the source buffer size, so we set the destination buffer initial size to be half the source buffer size
level.compressed_data = std::vector<unsigned char>(std::max((unsigned int)64, (unsigned int)level.src_data.size() / 2), 0);
int compressed_size = 0;
rygCompress(level.compressed_data.data(), level.src_data.data(), level.w, level.h, 1, compressed_size);
level.compressed_data.resize(compressed_size);
@ -166,7 +163,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
{
reset();
if (filenames.empty() || states.empty() || (sprite_size_px == 0))
if (filenames.empty() || states.empty() || sprite_size_px == 0)
return false;
// every tile needs to have a 1px border around it to avoid artifacts when linear sampling on its edges
@ -180,8 +177,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
int sprite_stride = sprite_size_px_ex * 4;
int sprite_bytes = sprite_n_pixels * 4;
if (n_pixels <= 0)
{
if (n_pixels <= 0) {
reset();
return false;
}
@ -193,15 +189,13 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
std::vector<unsigned char> output_data(sprite_bytes, 0);
NSVGrasterizer* rast = nsvgCreateRasterizer();
if (rast == nullptr)
{
if (rast == nullptr) {
reset();
return false;
}
int sprite_id = -1;
for (const std::string& filename : filenames)
{
for (const std::string& filename : filenames) {
++sprite_id;
if (!boost::filesystem::exists(filename))
@ -221,8 +215,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
// makes white only copy of the sprite
::memcpy((void*)sprite_white_only_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i)
{
for (int i = 0; i < sprite_n_pixels; ++i) {
int offset = i * 4;
if (sprite_white_only_data.data()[offset] != 0)
::memset((void*)&sprite_white_only_data.data()[offset], 255, 3);
@ -230,8 +223,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
// makes gray only copy of the sprite
::memcpy((void*)sprite_gray_only_data.data(), (const void*)sprite_data.data(), sprite_bytes);
for (int i = 0; i < sprite_n_pixels; ++i)
{
for (int i = 0; i < sprite_n_pixels; ++i) {
int offset = i * 4;
if (sprite_gray_only_data.data()[offset] != 0)
::memset((void*)&sprite_gray_only_data.data()[offset], 128, 3);
@ -239,30 +231,26 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
int sprite_offset_px = sprite_id * (int)sprite_size_px_ex * m_width;
int state_id = -1;
for (const std::pair<int, bool>& state : states)
{
for (const std::pair<int, bool>& state : states) {
++state_id;
// select the sprite variant
std::vector<unsigned char>* src = nullptr;
switch (state.first)
{
case 1: { src = &sprite_white_only_data; break; }
case 2: { src = &sprite_gray_only_data; break; }
case 1: { src = &sprite_white_only_data; break; }
case 2: { src = &sprite_gray_only_data; break; }
default: { src = &sprite_data; break; }
}
::memcpy((void*)output_data.data(), (const void*)src->data(), sprite_bytes);
// applies background, if needed
if (state.second)
{
if (state.second) {
float inv_255 = 1.0f / 255.0f;
// offset by 1 to leave the first pixel empty (both in x and y)
for (unsigned int r = 1; r <= sprite_size_px; ++r)
{
for (unsigned int r = 1; r <= sprite_size_px; ++r) {
unsigned int offset_r = r * sprite_size_px_ex;
for (unsigned int c = 1; c <= sprite_size_px; ++c)
{
for (unsigned int c = 1; c <= sprite_size_px; ++c) {
unsigned int offset = (offset_r + c) * 4;
float alpha = (float)output_data.data()[offset + 3] * inv_255;
output_data.data()[offset + 0] = (unsigned char)(output_data.data()[offset + 0] * alpha);
@ -274,8 +262,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
}
int state_offset_px = sprite_offset_px + state_id * sprite_size_px_ex;
for (int j = 0; j < (int)sprite_size_px_ex; ++j)
{
for (int j = 0; j < (int)sprite_size_px_ex; ++j) {
::memcpy((void*)&data.data()[(state_offset_px + j * m_width) * 4], (const void*)&output_data.data()[j * sprite_stride], sprite_stride);
}
}
@ -309,11 +296,9 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
wxImage output(m_width, m_height);
output.InitAlpha();
for (int h = 0; h < m_height; ++h)
{
for (int h = 0; h < m_height; ++h) {
int px_h = h * m_width;
for (int w = 0; w < m_width; ++w)
{
for (int w = 0; w < m_width; ++w) {
int offset = (px_h + w) * 4;
output.SetRGB(w, h, data.data()[offset + 0], data.data()[offset + 1], data.data()[offset + 2]);
output.SetAlpha(w, h, data.data()[offset + 3]);
@ -373,8 +358,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
// Load a PNG with an alpha channel.
wxImage image;
if (!image.LoadFile(wxString::FromUTF8(filename.c_str()), wxBITMAP_TYPE_PNG))
{
if (!image.LoadFile(wxString::FromUTF8(filename.c_str()), wxBITMAP_TYPE_PNG)) {
reset();
return false;
}
@ -384,20 +368,17 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
bool requires_rescale = false;
if (compression_enabled && (compression_type == MultiThreaded))
{
if (compression_enabled && compression_type == MultiThreaded) {
// the stb_dxt compression library seems to like only texture sizes which are a multiple of 4
int width_rem = m_width % 4;
int height_rem = m_height % 4;
if (width_rem != 0)
{
if (width_rem != 0) {
m_width += (4 - width_rem);
requires_rescale = true;
}
if (height_rem != 0)
{
if (height_rem != 0) {
m_height += (4 - height_rem);
requires_rescale = true;
}
@ -407,16 +388,14 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
image = image.ResampleBicubic(m_width, m_height);
int n_pixels = m_width * m_height;
if (n_pixels <= 0)
{
if (n_pixels <= 0) {
reset();
return false;
}
// Get RGB & alpha raw data from wxImage, pack them into an array.
unsigned char* img_rgb = image.GetData();
if (img_rgb == nullptr)
{
if (img_rgb == nullptr) {
reset();
return false;
}
@ -424,8 +403,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
unsigned char* img_alpha = image.GetAlpha();
std::vector<unsigned char> data(n_pixels * 4, 0);
for (int i = 0; i < n_pixels; ++i)
{
for (int i = 0; i < n_pixels; ++i) {
int data_id = i * 4;
int img_id = i * 3;
data[data_id + 0] = img_rgb[img_id + 0];
@ -439,19 +417,16 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
glsafe(::glGenTextures(1, &m_id));
glsafe(::glBindTexture(GL_TEXTURE_2D, m_id));
if (apply_anisotropy)
{
if (apply_anisotropy) {
GLfloat max_anisotropy = OpenGLManager::get_gl_info().get_max_anisotropy();
if (max_anisotropy > 1.0f)
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
}
if (compression_enabled)
{
if (compression_enabled) {
if (compression_type == SingleThreaded)
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
else
{
else {
// initializes the texture on GPU
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
// and send the uncompressed data to the compressor
@ -461,14 +436,12 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
if (use_mipmaps)
{
if (use_mipmaps) {
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
int lod_w = m_width;
int lod_h = m_height;
GLint level = 0;
while ((lod_w > 1) || (lod_h > 1))
{
while (lod_w > 1 || lod_h > 1) {
++level;
lod_w = std::max(lod_w / 2, 1);
@ -482,8 +455,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
img_rgb = image.GetData();
img_alpha = image.GetAlpha();
for (int i = 0; i < n_pixels; ++i)
{
for (int i = 0; i < n_pixels; ++i) {
int data_id = i * 4;
int img_id = i * 3;
data[data_id + 0] = img_rgb[img_id + 0];
@ -492,12 +464,10 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255;
}
if (compression_enabled)
{
if (compression_enabled) {
if (compression_type == SingleThreaded)
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
else
{
else {
// initializes the texture on GPU
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
// and send the uncompressed data to the compressor
@ -508,14 +478,12 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
}
if (!compression_enabled)
{
if (!compression_enabled) {
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
}
}
else
{
else {
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
}
@ -526,7 +494,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
m_source = filename;
if (compression_enabled && (compression_type == MultiThreaded))
if (compression_enabled && compression_type == MultiThreaded)
// start asynchronous compression
m_compressor.start_compressing();
@ -538,8 +506,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
bool compression_enabled = compress && GLEW_EXT_texture_compression_s3tc;
NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f);
if (image == nullptr)
{
if (image == nullptr) {
reset();
return false;
}
@ -549,8 +516,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
m_width = (int)(scale * image->width);
m_height = (int)(scale * image->height);
if (compression_enabled)
{
if (compression_enabled) {
// the stb_dxt compression library seems to like only texture sizes which are a multiple of 4
int width_rem = m_width % 4;
int height_rem = m_height % 4;
@ -564,16 +530,14 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
int n_pixels = m_width * m_height;
if (n_pixels <= 0)
{
if (n_pixels <= 0) {
reset();
nsvgDelete(image);
return false;
}
NSVGrasterizer* rast = nsvgCreateRasterizer();
if (rast == nullptr)
{
if (rast == nullptr) {
nsvgDelete(image);
reset();
return false;
@ -588,15 +552,13 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
glsafe(::glGenTextures(1, &m_id));
glsafe(::glBindTexture(GL_TEXTURE_2D, m_id));
if (apply_anisotropy)
{
if (apply_anisotropy) {
GLfloat max_anisotropy = OpenGLManager::get_gl_info().get_max_anisotropy();
if (max_anisotropy > 1.0f)
glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
}
if (compression_enabled)
{
if (compression_enabled) {
// initializes the texture on GPU
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
// and send the uncompressed data to the compressor
@ -605,14 +567,12 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
if (use_mipmaps)
{
if (use_mipmaps) {
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
int lod_w = m_width;
int lod_h = m_height;
GLint level = 0;
while ((lod_w > 1) || (lod_h > 1))
{
while (lod_w > 1 || lod_h > 1) {
++level;
lod_w = std::max(lod_w / 2, 1);
@ -622,8 +582,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
data.resize(lod_w * lod_h * 4);
nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4);
if (compression_enabled)
{
if (compression_enabled) {
// initializes the texture on GPU
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
// and send the uncompressed data to the compressor
@ -633,14 +592,12 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
}
if (!compression_enabled)
{
if (!compression_enabled) {
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
}
}
else
{
else {
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
}

View file

@ -262,6 +262,9 @@ bool Preview::init(wxWindow* parent, Model* model)
m_combochecklist_options->Create(m_bottom_toolbar_panel, wxID_ANY, _L("Options"), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
std::string options_items = GUI::into_u8(
get_option_type_string(OptionType::Travel) + "|0|" +
#if ENABLE_SHOW_WIPE_MOVES
get_option_type_string(OptionType::Wipe) + "|0|" +
#endif // ENABLE_SHOW_WIPE_MOVES
get_option_type_string(OptionType::Retractions) + "|0|" +
get_option_type_string(OptionType::Unretractions) + "|0|" +
get_option_type_string(OptionType::ToolChanges) + "|0|" +
@ -689,7 +692,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
if (sla_print_technology)
m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times);
else
m_layers_slider->SetLayersTimes(m_gcode_result->time_statistics.modes[0].layers_times);
m_layers_slider->SetLayersTimes(m_gcode_result->time_statistics.modes.front().layers_times);
m_layers_slider_sizer->Show((size_t)0);
Layout();
@ -971,6 +974,9 @@ wxString Preview::get_option_type_string(OptionType type) const
switch (type)
{
case OptionType::Travel: { return _L("Travel"); }
#if ENABLE_SHOW_WIPE_MOVES
case OptionType::Wipe: { return _L("Wipe"); }
#endif // ENABLE_SHOW_WIPE_MOVES
case OptionType::Retractions: { return _L("Retractions"); }
case OptionType::Unretractions: { return _L("Deretractions"); }
case OptionType::ToolChanges: { return _L("Tool changes"); }

View file

@ -113,6 +113,9 @@ public:
enum class OptionType : unsigned int
{
Travel,
#if ENABLE_SHOW_WIPE_MOVES
Wipe,
#endif // ENABLE_SHOW_WIPE_MOVES
Retractions,
Unretractions,
ToolChanges,

View file

@ -41,7 +41,8 @@ public:
ret.poly.contour = std::move(ap);
ret.translation = scaled(m_pos);
ret.rotation = m_rotation;
ret.priority++;
++ret.priority;
return ret;
}
};
@ -74,11 +75,11 @@ void ArrangeJob::prepare_all() {
for (ModelObject *obj: m_plater->model().objects)
for (ModelInstance *mi : obj->instances) {
ArrangePolygons & cont = mi->printable ? m_selected : m_unprintable;
cont.emplace_back(get_arrange_poly(mi, m_plater));
cont.emplace_back(get_arrange_poly(PtrWrapper{mi}, m_plater));
}
if (auto wti = get_wipe_tower(*m_plater))
m_selected.emplace_back(wti.get_arrange_polygon());
if (auto wti = get_wipe_tower_arrangepoly(*m_plater))
m_selected.emplace_back(std::move(*wti));
}
void ArrangeJob::prepare_selected() {
@ -106,8 +107,9 @@ void ArrangeJob::prepare_selected() {
inst_sel[size_t(inst_id)] = true;
for (size_t i = 0; i < inst_sel.size(); ++i) {
ArrangePolygon &&ap = get_arrange_poly(mo->instances[i], m_plater);
ArrangePolygon &&ap =
get_arrange_poly(PtrWrapper{mo->instances[i]}, m_plater);
ArrangePolygons &cont = mo->instances[i]->printable ?
(inst_sel[i] ? m_selected :
m_unselected) :
@ -118,11 +120,11 @@ void ArrangeJob::prepare_selected() {
}
if (auto wti = get_wipe_tower(*m_plater)) {
ArrangePolygon &&ap = get_arrange_poly(&wti, m_plater);
m_plater->get_selection().is_wipe_tower() ?
m_selected.emplace_back(std::move(ap)) :
m_unselected.emplace_back(std::move(ap));
ArrangePolygon &&ap = get_arrange_poly(wti, m_plater);
auto &cont = m_plater->get_selection().is_wipe_tower() ? m_selected :
m_unselected;
cont.emplace_back(std::move(ap));
}
// If the selection was empty arrange everything
@ -212,18 +214,11 @@ std::optional<arrangement::ArrangePolygon>
get_wipe_tower_arrangepoly(const Plater &plater)
{
if (auto wti = get_wipe_tower(plater))
return wti.get_arrange_polygon();
return get_arrange_poly(wti, &plater);
return {};
}
void apply_wipe_tower_arrangepoly(Plater & plater,
const arrangement::ArrangePolygon &ap)
{
WipeTower{plater.canvas3D()->get_wipe_tower_info()}
.apply_arrange_result(ap.translation.cast<double>(), ap.rotation);
}
double bed_stride(const Plater *plater) {
double bedwidth = plater->bed_shape_bb().size().x();
return scaled<double>((1. + LOGICAL_BED_GAP) * bedwidth);

View file

@ -47,7 +47,6 @@ public:
};
std::optional<arrangement::ArrangePolygon> get_wipe_tower_arrangepoly(const Plater &);
void apply_wipe_tower_arrangepoly(Plater &plater, const arrangement::ArrangePolygon &ap);
// The gap between logical beds in the x axis expressed in ratio of
// the current bed width.
@ -56,20 +55,36 @@ static const constexpr double LOGICAL_BED_GAP = 1. / 5.;
// Stride between logical beds
double bed_stride(const Plater *plater);
template<class T> struct PtrWrapper
{
T *ptr;
explicit PtrWrapper(T *p) : ptr{p} {}
arrangement::ArrangePolygon get_arrange_polygon() const
{
return ptr->get_arrange_polygon();
}
void apply_arrange_result(const Vec2d &t, double rot)
{
ptr->apply_arrange_result(t, rot);
}
};
// Set up arrange polygon for a ModelInstance and Wipe tower
template<class T>
arrangement::ArrangePolygon get_arrange_poly(T *obj, const Plater *plater)
arrangement::ArrangePolygon get_arrange_poly(T obj, const Plater *plater)
{
using ArrangePolygon = arrangement::ArrangePolygon;
ArrangePolygon ap = obj->get_arrange_polygon();
ap.priority = 0;
ArrangePolygon ap = obj.get_arrange_polygon();
ap.bed_idx = ap.translation.x() / bed_stride(plater);
ap.setter = [obj, plater](const ArrangePolygon &p) {
if (p.is_arranged()) {
Vec2d t = p.translation.cast<double>();
t.x() += p.bed_idx * bed_stride(plater);
obj->apply_arrange_result(t, p.rotation);
T{obj}.apply_arrange_result(t, p.rotation);
}
};

View file

@ -28,7 +28,7 @@ void FillBedJob::prepare()
m_selected.reserve(model_object->instances.size());
for (ModelInstance *inst : model_object->instances)
if (inst->printable) {
ArrangePolygon ap = get_arrange_poly(inst, m_plater);
ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater);
++ap.priority; // need to be included in the result
m_selected.emplace_back(ap);
}
@ -40,8 +40,8 @@ void FillBedJob::prepare()
auto &objects = m_plater->model().objects;
for (size_t idx = 0; idx < objects.size(); ++idx)
if (int(idx) != m_object_idx)
for (const ModelInstance *mi : objects[idx]->instances) {
m_unselected.emplace_back(mi->get_arrange_polygon());
for (ModelInstance *mi : objects[idx]->instances) {
m_unselected.emplace_back(get_arrange_poly(PtrWrapper{mi}, m_plater));
m_unselected.back().bed_idx = 0;
}

View file

@ -150,7 +150,9 @@ private:
const int duration;
const std::string text1;
const std::string hypertext;
// Callback for hypertext - returns if notif shall close.
// Callback for hypertext - returns true if notification should close after triggering
// Usually sends event to UI thread thru wxEvtHandler.
// Examples in basic_notifications.
std::function<bool(wxEvtHandler*)> callback { nullptr };
const std::string text2;
};
@ -227,7 +229,8 @@ private:
void render_left_sign(ImGuiWrapper& imgui);
virtual void render_minimize_button(ImGuiWrapper& imgui,
const float win_pos_x, const float win_pos_y);
// Hypertext action, returns if close notification
// Hypertext action, returns true if notification should close.
// Action is stored in NotificationData::callback as std::function<bool(wxEvtHandler*)>
virtual bool on_text_click();
const NotificationData m_data;

View file

@ -8,6 +8,7 @@
#include <boost/algorithm/string/split.hpp>
#include "libslic3r/Utils.hpp"
#include "I18N.hpp"
#include "format.hpp"
namespace Slic3r { namespace GUI {
@ -243,8 +244,10 @@ void OG_CustomCtrl::OnMotion(wxMouseEvent& event)
for (CtrlLine& line : ctrl_lines) {
line.is_focused = is_point_in_rect(pos, line.rect_label);
if (line.is_focused && !suppress_hyperlinks) {
tooltip = get_url(line.og_line.label_path);
if (line.is_focused) {
if (!suppress_hyperlinks && !line.og_line.label_path.empty())
tooltip = get_url(line.og_line.label_path) +"\n\n";
tooltip += line.og_line.label_tooltip;
break;
}
@ -609,7 +612,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxStr
dc.GetMultiLineTextExtent(out_text, &text_width, &text_height);
pos.y = pos.y + lround((height - text_height) / 2);
if (width > 0 && is_url)
if (width > 0)
rect_label = wxRect(pos, wxSize(text_width, text_height));
wxColour old_clr = dc.GetTextForeground();
@ -671,21 +674,67 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBi
bool OG_CustomCtrl::CtrlLine::launch_browser() const
{
if (!is_focused || og_line.label_path.IsEmpty())
return false;
bool launch = true;
if (get_app_config()->get("suppress_hyperlinks").empty()) {
wxString preferences_item = _L("Suppress to open hyperlink in browser");
wxString msg =
_L("PrusaSlicer will remember your action.") + "\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 choise."), preferences_item) + "\n\n" +
_L("Should we suppress to use hyperlinks in PrusaSlicer?");
RememberChoiceDialog dialog(nullptr, _L("Should we open this hyperlink in your default browser?"), _L("PrusaSlicer: Open hyperlink"));
int answer = dialog.ShowModal();
launch = answer == wxID_YES;
wxMessageDialog dialog(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxYES | wxNO | wxICON_INFORMATION);
get_app_config()->set("suppress_hyperlinks", dialog.ShowModal() == wxID_YES ? "1" : "0");
get_app_config()->set("suppress_hyperlinks", dialog.remember_choice() ? (answer == wxID_NO ? "1" : "0") : "");
}
if (launch)
launch = get_app_config()->get("suppress_hyperlinks") != "1";
return get_app_config()->get("suppress_hyperlinks") == "0" && is_focused && !og_line.label_path.IsEmpty() && wxLaunchDefaultBrowser(get_url(og_line.label_path));
return launch && wxLaunchDefaultBrowser(get_url(og_line.label_path));
}
RememberChoiceDialog::RememberChoiceDialog(wxWindow* parent, const wxString& msg_text, const wxString& caption)
: wxDialog(parent, wxID_ANY, caption, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxICON_INFORMATION)
{
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
this->SetEscapeId(wxID_CLOSE);
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
m_remember_choice = new wxCheckBox(this, wxID_ANY, _L("Remember my choice"));
m_remember_choice->SetValue(false);
m_remember_choice->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& evt)
{
if (!evt.IsChecked())
return;
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);
wxMessageDialog dialog(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
if (dialog.ShowModal() == wxID_CANCEL)
m_remember_choice->SetValue(false);
});
// Add dialog's buttons
wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxYES | wxNO);
wxButton* btnYES = static_cast<wxButton*>(this->FindWindowById(wxID_YES, this));
wxButton* btnNO = static_cast<wxButton*>(this->FindWindowById(wxID_NO, this));
btnYES->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { this->EndModal(wxID_YES); });
btnNO->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { this->EndModal(wxID_NO); });
topSizer->Add(new wxStaticText(this, wxID_ANY, msg_text), 0, wxEXPAND | wxALL, 10);
topSizer->Add(m_remember_choice, 0, wxEXPAND | wxALL, 10);
topSizer->Add(btns, 0, wxEXPAND | wxALL, 10);
this->SetSizer(topSizer);
topSizer->SetSizeHints(this);
this->CenterOnScreen();
}
} // GUI
} // Slic3r

View file

@ -95,6 +95,20 @@ public:
};
//-----------------------------------------------
// RememberChoiceDialog
//-----------------------------------------------
class RememberChoiceDialog : public wxDialog
{
wxCheckBox* m_remember_choice;
public:
RememberChoiceDialog(wxWindow* parent, const wxString& msg_text, const wxString& caption);
~RememberChoiceDialog() {}
bool remember_choice() const { return m_remember_choice->GetValue(); }
};
}}
#endif /* slic3r_OG_CustomCtrl_hpp_ */

View file

@ -204,7 +204,11 @@ void PreferencesDialog::build()
m_optgroup_gui = std::make_shared<ConfigOptionsGroup>(this, _L("GUI"));
m_optgroup_gui->label_width = 40;
m_optgroup_gui->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
if (opt_key == "suppress_hyperlinks")
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "";
else
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
if (opt_key == "use_custom_toolbar_size") {
m_icon_size_sizer->ShowItems(boost::any_cast<bool>(value));
this->layout();