Merge mainstream changes

This commit is contained in:
SoftFever 2022-10-04 12:24:49 +08:00
commit 764b7d62a0
204 changed files with 5425 additions and 1411 deletions

View file

@ -95,7 +95,7 @@ static void glfw_callback(int error_code, const char* description)
int CLI::run(int argc, char **argv)
{
// Mark the main thread for the debugger and for runtime checks.
set_current_thread_name("bambustudio_main");
set_current_thread_name("bambustu_main");
#ifdef __WXGTK__
// On Linux, wxGTK has no support for Wayland, and the app crashes on
@ -170,6 +170,7 @@ int CLI::run(int argc, char **argv)
if (start_gui) {
BOOST_LOG_TRIVIAL(info) << "no action, start gui directly" << std::endl;
::Label::initSysFont();
#ifdef SLIC3R_GUI
/*#if !defined(_WIN32) && !defined(__APPLE__)
// likely some linux / unix system
@ -1736,7 +1737,7 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
#if defined(_MSC_VER) || defined(__MINGW32__)
extern "C" {
__declspec(dllexport) int __stdcall bambustudio_main(int argc, wchar_t **argv)
__declspec(dllexport) int __stdcall bambustu_main(int argc, wchar_t **argv)
{
// Convert wchar_t arguments to UTF8.
std::vector<std::string> argv_narrow;

View file

@ -204,7 +204,7 @@ bool OpenGLVersionCheck::message_pump_exit = false;
extern "C" {
typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv);
Slic3rMainFunc bambustudio_main = nullptr;
Slic3rMainFunc bambustu_main = nullptr;
}
extern "C" {
@ -295,19 +295,19 @@ int wmain(int argc, wchar_t **argv)
}
// resolve function address here
bambustudio_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r,
bambustu_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r,
#ifdef _WIN64
// there is just a single calling conversion, therefore no mangling of the function name.
"bambustudio_main"
"bambustu_main"
#else // stdcall calling convention declaration
"_bambustudio_main@8"
"_bambustu_main@8"
#endif
);
if (bambustudio_main == nullptr) {
printf("could not locate the function bambustudio_main in BambuStudio.dll\n");
if (bambustu_main == nullptr) {
printf("could not locate the function bambustu_main in BambuStudio.dll\n");
return -1;
}
// argc minus the trailing nullptr of the argv
return bambustudio_main((int)argv_extended.size() - 1, argv_extended.data());
return bambustu_main((int)argv_extended.size() - 1, argv_extended.data());
}
}

View file

@ -118,6 +118,8 @@ endif (MINGW)
if (NOT WIN32 AND NOT APPLE)
# Binary name on unix like systems (Linux, Unix)
set_target_properties(BambuStudio PROPERTIES OUTPUT_NAME "bambu-studio")
set(SLIC3R_APP_CMD "bambu-studio")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/unix/BuildLinuxImage.sh.in ${CMAKE_CURRENT_BINARY_DIR}/BuildLinuxImage.sh @ONLY)
endif ()
target_link_libraries(BambuStudio libslic3r cereal)

View file

@ -2919,13 +2919,14 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
0x2000, 0x206F, // General Punctuation
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions
0x4e00, 0x9FAF, // CJK Ideograms
0xFF00, 0xFFEF // Half-width characters
};
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
if (!full_ranges[0])
{
memcpy(full_ranges, base_ranges, sizeof(base_ranges));
UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
//UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
}
return &full_ranges[0];
}

View file

@ -285,6 +285,10 @@ void AppConfig::set_defaults()
set("backup_interval", "10");
}
if (get("curr_bed_type").empty()) {
set("curr_bed_type", "0");
}
// #if BBL_RELEASE_TO_PUBLIC
if (get("iot_environment").empty()) {
set("iot_environment", "3");
@ -295,6 +299,10 @@ void AppConfig::set_defaults()
// }
// #endif
if (get("uniform_scale").empty()) {
set("uniform_scale", "1");
}
// Remove legacy window positions/sizes
erase("app", "main_frame_maximized");
erase("app", "main_frame_pos");
@ -525,7 +533,7 @@ void AppConfig::save()
{
// Returns "undefined" if the thread naming functionality is not supported by the operating system.
std::optional<std::string> current_thread_name = get_current_thread_name();
if (current_thread_name && *current_thread_name != "bambustudio_main")
if (current_thread_name && *current_thread_name != "bambustu_main")
throw CriticalException("Calling AppConfig::save() from a worker thread!");
}
@ -777,7 +785,7 @@ void AppConfig::save()
{
// Returns "undefined" if the thread naming functionality is not supported by the operating system.
std::optional<std::string> current_thread_name = get_current_thread_name();
if (current_thread_name && *current_thread_name != "bambustudio_main")
if (current_thread_name && *current_thread_name != "bambustu_main")
throw CriticalException("Calling AppConfig::save() from a worker thread!");
}

View file

@ -337,7 +337,7 @@ static ExPolygons top_level_outer_brim_area(const Print& print, const ConstPrint
no_brim_area_object.emplace_back(ex_poly.contour);
}
brimToWrite.at(object->id()).obj == false;
brimToWrite.at(object->id()).obj = false;
for (const PrintInstance& instance : object->instances()) {
if (!brim_area_object.empty())
append_and_translate(brim_area, brim_area_object, instance, print, brimAreaMap);
@ -375,7 +375,7 @@ static ExPolygons top_level_outer_brim_area(const Print& print, const ConstPrint
no_brim_area_support.emplace_back(ex_poly.contour);
}
}
brimToWrite.at(object->id()).sup == false;
brimToWrite.at(object->id()).sup = false;
for (const PrintInstance& instance : object->instances()) {
if (!brim_area_support.empty())
append_and_translate(brim_area, brim_area_support, instance, print, supportBrimAreaMap);
@ -521,7 +521,7 @@ static ExPolygons inner_brim_area(const Print& print, const ConstPrintObjectPtrs
append(holes_object, ex_poly.holes);
}
append(no_brim_area_object, offset_ex(object->layers().front()->lslices, brim_offset));
brimToWrite.at(object->id()).obj == false;
brimToWrite.at(object->id()).obj = false;
for (const PrintInstance& instance : object->instances()) {
if (!brim_area_object.empty())
append_and_translate(brim_area, brim_area_object, instance, print, innerBrimAreaMap);
@ -564,7 +564,7 @@ static ExPolygons inner_brim_area(const Print& print, const ConstPrintObjectPtrs
}
}
}
brimToWrite.at(object->id()).sup == false;
brimToWrite.at(object->id()).sup = false;
for (const PrintInstance& instance : object->instances()) {
if (!brim_area_support.empty())
append_and_translate(brim_area, brim_area_support, instance, print, innerSupportBrimAreaMap);
@ -1386,7 +1386,7 @@ static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtr
for (const PrintInstance& instance : object->instances())
append_and_translate(islands_area_ex, islands_area_ex_object, instance);
}
brimToWrite.at(object->id()).obj == false;
brimToWrite.at(object->id()).obj = false;
}
else {
for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) {
@ -1406,7 +1406,7 @@ static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtr
for (const PrintInstance& instance : object->instances())
append_and_translate(islands_area_ex, islands_area_ex_object, instance, print, innerbrimAreaMap);
}
brimToWrite.at(object->id()).obj == false;
brimToWrite.at(object->id()).obj = false;
}
if (innerbrimAreaMap.find(object->id()) != innerbrimAreaMap.end())
expolygons_append(islands_area_ex, innerbrimAreaMap[object->id()]);
@ -1422,7 +1422,7 @@ static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtr
for (const PrintInstance& instance : object->instances())
append_and_translate(islands_area_ex, islands_area_ex_support, instance);
}
brimToWrite.at(object->id()).sup == false;
brimToWrite.at(object->id()).sup = false;
}
else {
for (auto it = hole_island_pair_supports.begin(); it != hole_island_pair_supports.end(); it++) {
@ -1443,7 +1443,7 @@ static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtr
append_and_translate(islands_area_ex, islands_area_ex_support, instance, print, innerSupportBrimAreaMap);
}
brimToWrite.at(object->id()).sup == false;
brimToWrite.at(object->id()).sup = false;
}
if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end())
expolygons_append(islands_area_ex, innerSupportBrimAreaMap[object->id()]);

View file

@ -67,8 +67,6 @@ set(lisbslic3r_sources
Fill/FillBase.hpp
Fill/FillConcentric.cpp
Fill/FillConcentric.hpp
Fill/FillConcentricWGapFill.cpp
Fill/FillConcentricWGapFill.hpp
Fill/FillConcentricInternal.cpp
Fill/FillConcentricInternal.hpp
Fill/FillHoneycomb.cpp

View file

@ -12,6 +12,7 @@
#include "FillBase.hpp"
#include "FillRectilinear.hpp"
#include "FillConcentricInternal.hpp"
#include "FillConcentric.hpp"
#define NARROW_INFILL_AREA_THRESHOLD 3
@ -407,6 +408,11 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
assert(fill_concentric != nullptr);
fill_concentric->print_config = &this->object()->print()->config();
fill_concentric->print_object_config = &this->object()->config();
} else if (surface_fill.params.pattern == ipConcentric) {
FillConcentric *fill_concentric = dynamic_cast<FillConcentric *>(f.get());
assert(fill_concentric != nullptr);
fill_concentric->print_config = &this->object()->print()->config();
fill_concentric->print_object_config = &this->object()->config();
}
// calculate flow spacing for infill pattern generation
@ -434,6 +440,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.anchor_length = surface_fill.params.anchor_length;
params.anchor_length_max = surface_fill.params.anchor_length_max;
params.resolution = resolution;
params.use_arachne = surface_fill.params.pattern == ipConcentric;
// BBS
params.flow = surface_fill.params.flow;

View file

@ -9,6 +9,7 @@
#include "../PrintConfig.hpp"
#include "../Surface.hpp"
#include "../libslic3r.h"
#include "../VariableWidth.hpp"
#include "FillBase.hpp"
#include "FillConcentric.hpp"
@ -21,7 +22,6 @@
#include "FillAdaptive.hpp"
#include "FillLightning.hpp"
// BBS: new infill pattern header
#include "FillConcentricWGapFill.hpp"
#include "FillConcentricInternal.hpp"
// #define INFILL_DEBUG_OUTPUT
@ -58,7 +58,6 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipLightning: return new FillLightning::Filler();
#endif // HAS_LIGHTNING_INFILL
// BBS: for internal solid infill only
case ipConcentricGapFill: return new FillConcentricWGapFill();
case ipConcentricInternal: return new FillConcentricInternal();
// BBS: for bottom and top surface only
case ipMonotonicLine: return new FillMonotonicLineWGapFill();
@ -107,16 +106,31 @@ Polylines Fill::fill_surface(const Surface *surface, const FillParams &params)
return polylines_out;
}
ThickPolylines Fill::fill_surface_arachne(const Surface* surface, const FillParams& params)
{
// Perform offset.
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
// Create the infills for each of the regions.
ThickPolylines thick_polylines_out;
for (ExPolygon& expoly : expp)
_fill_surface_single(params, surface->thickness_layers, _infill_direction(surface), std::move(expoly), thick_polylines_out);
return thick_polylines_out;
}
// BBS: this method is used to fill the ExtrusionEntityCollection. It call fill_surface by default
void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out)
{
Polylines polylines;
ThickPolylines thick_polylines;
try {
polylines = this->fill_surface(surface, params);
if (params.use_arachne)
thick_polylines = this->fill_surface_arachne(surface, params);
else
polylines = this->fill_surface(surface, params);
}
catch (InfillFailedException&) {}
if (!polylines.empty()) {
if (!polylines.empty() || !thick_polylines.empty()) {
// calculate actual flow from spacing (which might have been adjusted by the infill
// pattern generator)
double flow_mm3_per_mm = params.flow.mm3_per_mm();
@ -136,10 +150,17 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
out.push_back(eec = new ExtrusionEntityCollection());
// Only concentric fills are not sorted.
eec->no_sort = this->no_sort();
extrusion_entities_append_paths(
eec->entities, std::move(polylines),
params.extrusion_role,
flow_mm3_per_mm, float(flow_width), params.flow.height());
if (params.use_arachne) {
Flow new_flow = params.flow.with_spacing(float(this->spacing));
variable_width(thick_polylines, params.extrusion_role, new_flow, eec->entities);
thick_polylines.clear();
}
else {
extrusion_entities_append_paths(
eec->entities, std::move(polylines),
params.extrusion_role,
flow_mm3_per_mm, float(flow_width), params.flow.height());
}
}
}

View file

@ -63,6 +63,9 @@ struct FillParams
// in this case we don't try to make more continuous paths
bool complete { false };
// For Concentric infill, to switch between Classic and Arachne.
bool use_arachne{ false };
// BBS
Flow flow;
ExtrusionRole extrusion_role{ ExtrusionRole(0) };
@ -121,6 +124,7 @@ public:
// Perform the fill.
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual ThickPolylines fill_surface_arachne(const Surface* surface, const FillParams& params);
// BBS: this method is used to fill the ExtrusionEntityCollection.
// It call fill_surface by default
@ -149,6 +153,13 @@ protected:
ExPolygon /* expolygon */,
Polylines & /* polylines_out */) {};
// Used for concentric infill to generate ThickPolylines using Arachne.
virtual void _fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
ThickPolylines& thick_polylines_out) {}
virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; }
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;

View file

@ -1,6 +1,8 @@
#include "../ClipperUtils.hpp"
#include "../ExPolygon.hpp"
#include "../Surface.hpp"
#include "../VariableWidth.hpp"
#include "Arachne/WallToolPaths.hpp"
#include "FillConcentric.hpp"
@ -61,4 +63,84 @@ void FillConcentric::_fill_surface_single(
// We want the loops to be split inside the G-code generator to get optimum path planning.
}
void FillConcentric::_fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
ThickPolylines& thick_polylines_out)
{
assert(params.use_arachne);
assert(this->print_config != nullptr && this->print_object_config != nullptr);
// no rotation is supported for this infill pattern
Point bbox_size = expolygon.contour.bounding_box().size();
coord_t min_spacing = scaled<coord_t>(this->spacing);
if (params.density > 0.9999f && !params.dont_adjust) {
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
Polygons polygons = offset(expolygon, float(min_spacing) / 2.f);
double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
Arachne::WallToolPathsParams input_params;
input_params.min_bead_width = 0.85 * min_nozzle_diameter;
input_params.min_feature_size = 0.1;
input_params.wall_transition_length = 1.0 * min_nozzle_diameter;
input_params.wall_transition_angle = 10;
input_params.wall_transition_filter_deviation = 0.25 * min_nozzle_diameter;
input_params.wall_distribution_count = 1;
input_params.wall_add_middle_threshold = 0.75;
input_params.wall_split_middle_threshold = 0.5;
Arachne::WallToolPaths wallToolPaths(polygons, min_spacing, min_spacing, loops_count, 0, input_params);
std::vector<Arachne::VariableWidthLines> loops = wallToolPaths.getToolPaths();
std::vector<const Arachne::ExtrusionLine*> all_extrusions;
for (Arachne::VariableWidthLines& loop : loops) {
if (loop.empty())
continue;
for (const Arachne::ExtrusionLine& wall : loop)
all_extrusions.emplace_back(&wall);
}
// Split paths using a nearest neighbor search.
size_t firts_poly_idx = thick_polylines_out.size();
Point last_pos(0, 0);
for (const Arachne::ExtrusionLine* extrusion : all_extrusions) {
if (extrusion->empty())
continue;
ThickPolyline thick_polyline = Arachne::to_thick_polyline(*extrusion);
if (extrusion->is_closed && thick_polyline.points.front() == thick_polyline.points.back() && thick_polyline.width.front() == thick_polyline.width.back()) {
thick_polyline.points.pop_back();
assert(thick_polyline.points.size() * 2 == thick_polyline.width.size());
int nearest_idx = last_pos.nearest_point_index(thick_polyline.points);
std::rotate(thick_polyline.points.begin(), thick_polyline.points.begin() + nearest_idx, thick_polyline.points.end());
std::rotate(thick_polyline.width.begin(), thick_polyline.width.begin() + 2 * nearest_idx, thick_polyline.width.end());
thick_polyline.points.emplace_back(thick_polyline.points.front());
}
thick_polylines_out.emplace_back(std::move(thick_polyline));
last_pos = thick_polylines_out.back().last_point();
}
// clip the paths to prevent the extruder from getting exactly on the first point of the loop
// Keep valid paths only.
size_t j = firts_poly_idx;
for (size_t i = firts_poly_idx; i < thick_polylines_out.size(); ++i) {
thick_polylines_out[i].clip_end(this->loop_clipping);
if (thick_polylines_out[i].is_valid()) {
if (j < i)
thick_polylines_out[j] = std::move(thick_polylines_out[i]);
++j;
}
}
if (j < thick_polylines_out.size())
thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end());
}
else {
Polylines polylines;
this->_fill_surface_single(params, thickness_layers, direction, expolygon, polylines);
append(thick_polylines_out, to_thick_polylines(std::move(polylines), min_spacing));
}
}
} // namespace Slic3r

View file

@ -19,7 +19,18 @@ protected:
ExPolygon expolygon,
Polylines &polylines_out) override;
void _fill_surface_single(const FillParams& params,
unsigned int thickness_layers,
const std::pair<float, Point>& direction,
ExPolygon expolygon,
ThickPolylines& thick_polylines_out) override;
bool no_sort() const override { return true; }
const PrintConfig* print_config = nullptr;
const PrintObjectConfig* print_object_config = nullptr;
friend class Layer;
};
} // namespace Slic3r

View file

@ -1,135 +0,0 @@
#include "../ClipperUtils.hpp"
#include "../ExPolygon.hpp"
#include "../Surface.hpp"
#include "../VariableWidth.hpp"
#include "../ShortestPath.hpp"
#include "FillConcentricWGapFill.hpp"
namespace Slic3r {
const float concentric_overlap_threshold = 0.02;
void FillConcentricWGapFill::fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out)
{
//BBS: FillConcentricWGapFill.cpp is absolutely newly add by BBL for narrow internal solid infill area to reduce vibration
// Because the area is narrow, we should not use the surface->expolygon which has overlap with perimeter, but
// use no_overlap_expolygons instead to avoid overflow in narrow area.
//Slic3r::ExPolygons expp = offset_ex(surface->expolygon, double(scale_(0 - 0.5 * this->spacing)));
float min_spacing = this->spacing * (1 - concentric_overlap_threshold);
Slic3r::ExPolygons expp = offset2_ex(this->no_overlap_expolygons, -double(scale_(0.5 * this->spacing + 0.5 * min_spacing) - 1),
+double(scale_(0.5 * min_spacing) - 1));
// Create the infills for each of the regions.
Polylines polylines_out;
for (size_t i = 0; i < expp.size(); ++i) {
ExPolygon expolygon = expp[i];
coord_t distance = scale_(this->spacing / params.density);
if (params.density > 0.9999f && !params.dont_adjust) {
distance = scale_(this->spacing);
}
ExPolygons gaps;
Polygons loops = (Polygons)expolygon;
ExPolygons last = { expolygon };
bool first = true;
while (!last.empty()) {
ExPolygons next_onion = offset2_ex(last, -double(distance + scale_(this->spacing) / 2), +double(scale_(this->spacing) / 2));
for (auto it = next_onion.begin(); it != next_onion.end(); it++) {
Polygons temp_loops = (Polygons)(*it);
loops.insert(loops.end(), temp_loops.begin(), temp_loops.end());
}
append(gaps, diff_ex(
offset(last, -0.5f * distance),
offset(next_onion, 0.5f * distance + 10))); // 10 is safty offset
last = next_onion;
if (first && !this->no_overlap_expolygons.empty()) {
gaps = intersection_ex(gaps, this->no_overlap_expolygons);
}
first = false;
}
ExtrusionRole good_role = params.extrusion_role;
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
coll_nosort->no_sort = this->no_sort(); //can be sorted inside the pass
extrusion_entities_append_loops(
coll_nosort->entities, std::move(loops),
good_role,
params.flow.mm3_per_mm(),
params.flow.width(),
params.flow.height());
//BBS: add internal gapfills between infill loops
if (!gaps.empty() && params.density >= 1) {
double min = 0.2 * distance * (1 - INSET_OVERLAP_TOLERANCE);
double max = 2. * distance;
ExPolygons gaps_ex = diff_ex(
offset2_ex(gaps, -float(min / 2), float(min / 2)),
offset2_ex(gaps, -float(max / 2), float(max / 2)),
ApplySafetyOffset::Yes);
//BBS: sort the gap_ex to avoid mess travel
Points ordering_points;
ordering_points.reserve(gaps_ex.size());
ExPolygons gaps_ex_sorted;
gaps_ex_sorted.reserve(gaps_ex.size());
for (const ExPolygon &ex : gaps_ex)
ordering_points.push_back(ex.contour.first_point());
std::vector<Points::size_type> order = chain_points(ordering_points);
for (size_t i : order)
gaps_ex_sorted.emplace_back(std::move(gaps_ex[i]));
ThickPolylines polylines;
for (ExPolygon& ex : gaps_ex_sorted) {
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION * 0.1);
ex.medial_axis(max, min, &polylines);
}
if (!polylines.empty() && !is_bridge(good_role)) {
ExtrusionEntityCollection gap_fill;
variable_width(polylines, erGapFill, params.flow, gap_fill.entities);
coll_nosort->append(std::move(gap_fill.entities));
}
}
if (!coll_nosort->entities.empty())
out.push_back(coll_nosort);
else
delete coll_nosort;
}
//BBS: add external gapfill between perimeter and infill
ExPolygons external_gaps = diff_ex(this->no_overlap_expolygons, offset_ex(expp, double(scale_(0.5 * this->spacing))), ApplySafetyOffset::Yes);
external_gaps = union_ex(external_gaps);
if (!this->no_overlap_expolygons.empty())
external_gaps = intersection_ex(external_gaps, this->no_overlap_expolygons);
if (!external_gaps.empty()) {
double min = 0.4 * scale_(params.flow.nozzle_diameter()) * (1 - INSET_OVERLAP_TOLERANCE);
double max = 2. * params.flow.scaled_width();
//BBS: collapse, be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
min = std::max(min, (double)Flow::rounded_rectangle_extrusion_width_from_spacing((float)EPSILON, (float)params.flow.height()));
ExPolygons external_gaps_collapsed = offset2_ex(external_gaps, double(-min / 2), double(+min / 2));
ThickPolylines polylines;
for (ExPolygon& ex : external_gaps_collapsed) {
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION * 0.1);
ex.medial_axis(max, min, &polylines);
}
ExtrusionEntityCollection* coll_external_gapfill = new ExtrusionEntityCollection();
coll_external_gapfill->no_sort = this->no_sort();
if (!polylines.empty() && !is_bridge(params.extrusion_role)) {
ExtrusionEntityCollection gap_fill;
variable_width(polylines, erGapFill, params.flow, gap_fill.entities);
coll_external_gapfill->append(std::move(gap_fill.entities));
}
if (!coll_external_gapfill->entities.empty())
out.push_back(coll_external_gapfill);
else
delete coll_external_gapfill;
}
}
}

View file

@ -1,21 +0,0 @@
#ifndef slic3r_FillConcentricWGapFil_hpp_
#define slic3r_FillConcentricWGapFil_hpp_
#include "FillBase.hpp"
namespace Slic3r {
class FillConcentricWGapFill : public Fill
{
public:
~FillConcentricWGapFill() override = default;
void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
protected:
Fill* clone() const override { return new FillConcentricWGapFill(*this); };
bool no_sort() const override { return true; }
};
} // namespace Slic3r
#endif // slic3r_FillConcentricWGapFil_hpp_

View file

@ -275,7 +275,7 @@ bool load_step(const char *path, Model *model, ImportStepProgressFn stepFn, Step
}
}
if (aNbTriangles == 0)
if (aNbTriangles == 0 || aNbNodes == 0)
// BBS: No triangulation on the shape.
continue;
@ -354,13 +354,16 @@ bool load_step(const char *path, Model *model, ImportStepProgressFn stepFn, Step
}
}
TriangleMesh triangle_mesh;
triangle_mesh.from_stl(stl[i]);
ModelVolume *new_volume = new_object->add_volume(std::move(triangle_mesh));
new_volume->name = namedSolids[i].name;
new_volume->source.input_file = path;
new_volume->source.object_idx = (int) model->objects.size() - 1;
new_volume->source.volume_idx = (int) new_object->volumes.size() - 1;
//BBS: maybe mesh is empty from step file. Don't add
if (stl[i].stats.number_of_facets > 0) {
TriangleMesh triangle_mesh;
triangle_mesh.from_stl(stl[i]);
ModelVolume* new_volume = new_object->add_volume(std::move(triangle_mesh));
new_volume->name = namedSolids[i].name;
new_volume->source.input_file = path;
new_volume->source.object_idx = (int)model->objects.size() - 1;
new_volume->source.volume_idx = (int)new_object->volumes.size() - 1;
}
}
shapeTool.reset(nullptr);

View file

@ -160,6 +160,8 @@ const unsigned int METADATA_STR_LEN = 9;
static constexpr const char* MODEL_TAG = "model";
static constexpr const char* RESOURCES_TAG = "resources";
static constexpr const char* COLOR_GROUP_TAG = "m:colorgroup";
static constexpr const char* COLOR_TAG = "m:color";
static constexpr const char* OBJECT_TAG = "object";
static constexpr const char* MESH_TAG = "mesh";
static constexpr const char* MESH_STAT_TAG = "mesh_stat";
@ -193,6 +195,7 @@ static constexpr const char* SLICE_HEADER_ITEM_TAG = "header_item";
// BBS: encrypt
static constexpr const char* RELATIONSHIP_TAG = "Relationship";
static constexpr const char* PID_ATTR = "pid";
static constexpr const char* PUUID_ATTR = "p:uuid";
static constexpr const char* PPATH_ATTR = "p:path";
static constexpr const char* OBJECT_UUID_SUFFIX = "-41cb-4c03-9d28-80fed5dfa1dc";
@ -203,6 +206,7 @@ static constexpr const char* RELS_TYPE_ATTR = "Type";
static constexpr const char* UNIT_ATTR = "unit";
static constexpr const char* NAME_ATTR = "name";
static constexpr const char* COLOR_ATTR = "color";
static constexpr const char* TYPE_ATTR = "type";
static constexpr const char* ID_ATTR = "id";
static constexpr const char* X_ATTR = "x";
@ -549,6 +553,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
//int subobject_id;
std::string name;
std::string uuid;
int pid{-1};
//bool is_model_object;
CurrentObject() { reset(); }
@ -713,6 +718,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
PlateData* m_curr_plater;
CurrentInstance m_curr_instance;
int m_current_color_group{-1};
std::map<int, std::string> m_group_id_to_color;
public:
_BBS_3MF_Importer();
~_BBS_3MF_Importer();
@ -778,6 +786,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _handle_start_object(const char** attributes, unsigned int num_attributes);
bool _handle_end_object();
bool _handle_start_color_group(const char **attributes, unsigned int num_attributes);
bool _handle_end_color_group();
bool _handle_start_color(const char **attributes, unsigned int num_attributes);
bool _handle_end_color();
bool _handle_start_mesh(const char** attributes, unsigned int num_attributes);
bool _handle_end_mesh();
@ -1314,6 +1328,20 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
}
std::map<int, int> color_group_id_to_extruder_id_map;
std::map<std::string, int> color_to_extruder_id_map;
int extruder_id = 0;
for (auto group_iter = m_group_id_to_color.begin(); group_iter != m_group_id_to_color.end(); ++group_iter) {
auto color_iter = color_to_extruder_id_map.find(group_iter->second);
if (color_iter == color_to_extruder_id_map.end()) {
++extruder_id;
color_to_extruder_id_map[group_iter->second] = extruder_id;
color_group_id_to_extruder_id_map[group_iter->first] = extruder_id;
} else {
color_group_id_to_extruder_id_map[group_iter->first] = color_iter->second;
}
}
for (const IdToModelObjectMap::value_type& object : m_objects) {
if (object.second >= int(m_model->objects.size())) {
add_error("invalid object, id: "+std::to_string(object.first.second));
@ -1383,6 +1411,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
volumes.emplace_back(object_id.second);
}
IdToCurrentObjectMap::const_iterator current_object = m_current_objects.find(object.first);
if (current_object != m_current_objects.end()) {
// get name
model_object->name = current_object->second.name;
// get color
auto extruder_itor = color_group_id_to_extruder_id_map.find(current_object->second.pid);
if (extruder_itor != color_group_id_to_extruder_id_map.end()) {
model_object->config.set_key_value("extruder", new ConfigOptionInt(extruder_itor->second));
}
}
// select as volumes
volumes_ptr = &volumes;
}
@ -2213,6 +2253,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
res = _handle_start_resources(attributes, num_attributes);
else if (::strcmp(OBJECT_TAG, name) == 0)
res = _handle_start_object(attributes, num_attributes);
else if (::strcmp(COLOR_GROUP_TAG, name) == 0)
res = _handle_start_color_group(attributes, num_attributes);
else if (::strcmp(COLOR_TAG, name) == 0)
res = _handle_start_color(attributes, num_attributes);
else if (::strcmp(MESH_TAG, name) == 0)
res = _handle_start_mesh(attributes, num_attributes);
else if (::strcmp(VERTICES_TAG, name) == 0)
@ -2251,6 +2295,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
res = _handle_end_resources();
else if (::strcmp(OBJECT_TAG, name) == 0)
res = _handle_end_object();
else if (::strcmp(COLOR_GROUP_TAG, name) == 0)
res = _handle_end_color_group();
else if (::strcmp(COLOR_TAG, name) == 0)
res = _handle_end_color();
else if (::strcmp(MESH_TAG, name) == 0)
res = _handle_end_mesh();
else if (::strcmp(VERTICES_TAG, name) == 0)
@ -2434,6 +2482,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
m_curr_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
m_curr_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR);
m_curr_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR);
}
return true;
@ -2543,6 +2592,31 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _BBS_3MF_Importer::_handle_start_color_group(const char **attributes, unsigned int num_attributes)
{
m_current_color_group = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR);
return true;
}
bool _BBS_3MF_Importer::_handle_end_color_group()
{
// do nothing
return true;
}
bool _BBS_3MF_Importer::_handle_start_color(const char **attributes, unsigned int num_attributes)
{
std::string color = bbs_get_attribute_value_string(attributes, num_attributes, COLOR_ATTR);
m_group_id_to_color[m_current_color_group] = color;
return true;
}
bool _BBS_3MF_Importer::_handle_end_color()
{
// do nothing
return true;
}
bool _BBS_3MF_Importer::_handle_start_mesh(const char** attributes, unsigned int num_attributes)
{
// reset current geometry
@ -5950,8 +6024,10 @@ private:
boost::posix_time::ptime start;
};
private:
_BBS_Backup_Manager() : m_thread(boost::ref(*this)) {
_BBS_Backup_Manager() {
m_next_backup = boost::get_system_time() + boost::posix_time::seconds(m_interval);
boost::unique_lock lock(m_mutex);
m_thread = std::move(boost::thread(boost::ref(*this)));
}
~_BBS_Backup_Manager() {

View file

@ -562,18 +562,10 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
for (int i = int(m_layer_tools.size()) - 2; i >= 0; -- i)
m_layer_tools[i].wipe_tower_partitions = std::max(m_layer_tools[i + 1].wipe_tower_partitions, m_layer_tools[i].wipe_tower_partitions);
// if enable_timelapse_print(), update all layer_tools parameters: wipe_tower_partitions
if (config.timelapse_type == TimelapseType::tlSmooth) {
for (LayerTools& layer_tools : m_layer_tools) {
if (layer_tools.wipe_tower_partitions == 0) {
layer_tools.wipe_tower_partitions = 1;
}
}
}
//FIXME this is a hack to get the ball rolling.
for (LayerTools &lt : m_layer_tools)
lt.has_wipe_tower = (lt.has_object && lt.wipe_tower_partitions > 0) || lt.print_z < object_bottom_z + EPSILON;
lt.has_wipe_tower = (lt.has_object && (config.timelapse_type == TimelapseType::tlSmooth || lt.wipe_tower_partitions > 0))
|| lt.print_z < object_bottom_z + EPSILON;
// Test for a raft, insert additional wipe tower layer to fill in the raft separation gap.
for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) {

View file

@ -183,7 +183,7 @@ public:
std::vector<LayerTools>::const_iterator end() const { return m_layer_tools.end(); }
bool empty() const { return m_layer_tools.empty(); }
std::vector<LayerTools>& layer_tools() { return m_layer_tools; }
bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; }
bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().has_wipe_tower; }
private:
void initialize_layers(std::vector<coordf_t> &zs);

View file

@ -1066,7 +1066,7 @@ WipeTower::box_coordinates WipeTower::align_perimeter(const WipeTower::box_coord
return aligned_box;
}
WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter)
WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool extruder_fill)
{
assert(! this->layer_finished());
m_current_layer_finished = true;
@ -1083,7 +1083,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter)
// Slow down on the 1st layer.
bool first_layer = is_first_layer();
// BBS: speed up perimeter speed to 90mm/s for non-first layer
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : 5400.f;
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y),
m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);
@ -1105,7 +1105,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter)
const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
float left = fill_box.lu.x() + 2*m_perimeter_width;
float right = fill_box.ru.x() - 2 * m_perimeter_width;
if (dy > m_perimeter_width)
if (extruder_fill && dy > m_perimeter_width)
{
writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
.append(";--------------------\n"
@ -1500,7 +1500,7 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
if (m_enable_timelapse_print) {
timelapse_wall = only_generate_out_wall();
}
finish_layer_tcr = finish_layer(m_enable_timelapse_print ? false : true);
finish_layer_tcr = finish_layer(m_enable_timelapse_print ? false : true, layer.extruder_fill);
}
for (int i=0; i<int(layer.tool_changes.size()); ++i) {
@ -1511,7 +1511,7 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
if (i == idx) {
layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool, m_enable_timelapse_print ? false : true));
// finish_layer will be called after this toolchange
finish_layer_tcr = finish_layer(false);
finish_layer_tcr = finish_layer(false, layer.extruder_fill);
}
else {
layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool));
@ -1541,7 +1541,6 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall()
{
size_t old_tool = m_current_tool;
m_extrusion_flow = 0.038f; // hard code
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
writer.set_extrusion_flow(m_extrusion_flow)
.set_z(m_z_pos)
@ -1551,7 +1550,7 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall()
// Slow down on the 1st layer.
bool first_layer = is_first_layer();
// BBS: speed up perimeter speed to 90mm/s for non-first layer
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : 5400.f;
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y), m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);

View file

@ -157,8 +157,11 @@ public:
float get_depth() const { return m_wipe_tower_depth; }
float get_brim_width() const { return m_wipe_tower_brim_width_real; }
void set_last_layer_extruder_fill(bool extruder_fill) {
if (!m_plan.empty()) {
m_plan.back().extruder_fill = extruder_fill;
}
}
// Switch to a next layer.
@ -218,7 +221,7 @@ public:
// Fill the unfilled space with a sparse infill.
// Call this method only if layer_finished() is false.
ToolChangeResult finish_layer(bool extruder_perimeter = true);
ToolChangeResult finish_layer(bool extruder_perimeter = true, bool extruder_fill = true);
// Is the current layer finished?
bool layer_finished() const {
@ -378,6 +381,7 @@ private:
float height; // layer height
float depth; // depth of the layer based on all layers above
float extra_spacing;
bool extruder_fill{true};
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
std::vector<ToolChange> tool_changes;

View file

@ -190,7 +190,7 @@ void Layer::make_perimeters()
if (layerms.size() == 1) { // optimization
(*layerm)->fill_surfaces.surfaces.clear();
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces, &(*layerm)->fill_no_overlap_expolygons);
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
} else {
SurfaceCollection new_slices;
@ -212,7 +212,9 @@ void Layer::make_perimeters()
// make perimeters
SurfaceCollection fill_surfaces;
layerm_config->make_perimeters(new_slices, &fill_surfaces);
//BBS
ExPolygons fill_no_overlap;
layerm_config->make_perimeters(new_slices, &fill_surfaces, &fill_no_overlap);
// assign fill_surfaces to each layer
if (!fill_surfaces.surfaces.empty()) {
@ -221,6 +223,8 @@ void Layer::make_perimeters()
ExPolygons expp = intersection_ex(fill_surfaces.surfaces, (*l)->slices.surfaces);
(*l)->fill_expolygons = expp;
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
//BBS: Separate fill_no_overlap
(*l)->fill_no_overlap_expolygons = intersection_ex((*l)->slices.surfaces, fill_no_overlap);
}
}
}

View file

@ -68,7 +68,8 @@ public:
void slices_to_fill_surfaces_clipped();
void prepare_fill_surfaces();
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
//BBS
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces, ExPolygons* fill_no_overlap);
void process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered);
double infill_area_threshold() const;
// Trim surfaces by trimming polygons. Used by the elephant foot compensation at the 1st layer.
@ -124,6 +125,7 @@ public:
// BBS
mutable ExPolygons sharp_tails;
mutable ExPolygons cantilevers;
mutable std::map<const ExPolygon*, float> sharp_tails_height;
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry

View file

@ -63,7 +63,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
}
}
void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces, ExPolygons* fill_no_overlap)
{
this->perimeters.clear();
this->thin_fills.clear();
@ -90,7 +90,9 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
// output:
&this->perimeters,
&this->thin_fills,
fill_surfaces
fill_surfaces,
//BBS
fill_no_overlap
);
if (this->layer()->lower_layer != nullptr)
@ -105,9 +107,6 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
g.solid_infill_flow = this->flow(frSolidInfill);
g.process();
// BBS
this->fill_no_overlap_expolygons = g.fill_no_overlap;
}
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.
@ -117,7 +116,9 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered)
{
const bool has_infill = this->region().config().sparse_infill_density.value > 0.;
const float margin = float(scale_(EXTERNAL_INFILL_MARGIN));
//BBS
auto nozzle_diameter = this->region().nozzle_dmr_avg(this->layer()->object()->print()->config());
const float margin = std::min(float(scale_(EXTERNAL_INFILL_MARGIN)), float(scale_(nozzle_diameter * EXTERNAL_INFILL_MARGIN / 0.4)));
// BBS
const PrintObjectConfig& object_config = this->layer()->object()->config();

View file

@ -565,14 +565,13 @@ bool Model::looks_like_multipart_object() const
for (const ModelObject *obj : this->objects) {
if (obj->volumes.size() > 1 || obj->config.keys().size() > 1)
return false;
for (const ModelVolume *vol : obj->volumes) {
double zmin_this = vol->mesh().bounding_box().min(2);
if (zmin == std::numeric_limits<double>::max())
zmin = zmin_this;
else if (std::abs(zmin - zmin_this) > EPSILON)
// The volumes don't share zmin.
return true;
}
double zmin_this = obj->get_min_z();
if (zmin == std::numeric_limits<double>::max())
zmin = zmin_this;
else if (std::abs(zmin - zmin_this) > EPSILON)
// The Object don't share zmin.
return true;
}
return false;
}
@ -608,11 +607,15 @@ void Model::convert_multipart_object(unsigned int max_extruders)
// Revert the centering operation.
trafo_volume.set_offset(trafo_volume.get_offset() - o->origin_translation);
int counter = 1;
auto copy_volume = [o, max_extruders, &counter, &extruder_counter](ModelVolume *new_v) {
auto copy_volume = [o, v, max_extruders, &counter, &extruder_counter](ModelVolume *new_v) {
assert(new_v != nullptr);
new_v->name = (counter > 1) ? o->name + "_" + std::to_string(counter++) : o->name;
//BBS: use default extruder id
//new_v->config.set("extruder", auto_extruder_id(max_extruders, extruder_counter));
//BBS: Use extruder priority: volumn > object > default
if (v->config.option("extruder"))
new_v->config.set("extruder", v->config.extruder());
else if (o->config.option("extruder"))
new_v->config.set("extruder", o->config.extruder());
return new_v;
};
if (o->instances.empty()) {

View file

@ -982,44 +982,6 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vector<std::vector<Col
const ColoredLine colored_line = lines_colored[edge_it->cell()->source_index()];
const ColoredLine contour_line_prev = get_prev_contour_line(edge_it);
const ColoredLine contour_line_next = get_next_contour_line(edge_it);
bool has_color_change = false;
{
const double tolerance = 15 * SCALED_EPSILON;
double acc_len = 0.0;
size_t contour_line_local_idx = lines_colored[edge_it->cell()->source_index()].local_line_idx;
size_t poly_idx = lines_colored[edge_it->cell()->source_index()].poly_idx;
size_t contour_line_size = color_poly[poly_idx].size();
size_t contour_prev_local_idx = (contour_line_local_idx > 0) ? contour_line_local_idx - 1 : contour_line_size - 1;
while (!has_color_change) {
ColoredLine& prev_line = lines_colored[graph.get_global_index(poly_idx, contour_prev_local_idx)];
if (!has_same_color(prev_line, colored_line)) {
has_color_change = true;
break;
}
acc_len += prev_line.line.length();
if (acc_len >= tolerance)
break;
contour_prev_local_idx = (contour_prev_local_idx > 0) ? contour_prev_local_idx - 1 : contour_line_size - 1;
}
acc_len = 0.0;
size_t contour_next_local_idx = (contour_line_local_idx + 1) % contour_line_size;
while (!has_color_change) {
ColoredLine& next_line = lines_colored[graph.get_global_index(poly_idx, contour_next_local_idx)];
if (!has_same_color(colored_line, next_line)) {
has_color_change = true;
break;
}
acc_len += next_line.line.length();
if (acc_len >= tolerance)
break;
contour_next_local_idx = (contour_next_local_idx + 1) % contour_line_size;
}
}
if (edge_it->vertex0()->color() >= graph.nodes_count() || edge_it->vertex1()->color() >= graph.nodes_count()) {
enum class Vertex { VERTEX0, VERTEX1 };
@ -1054,12 +1016,12 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vector<std::vector<Col
const size_t to_idx = edge_it->vertex1()->color();
if (graph.is_vertex_on_contour(edge_it->vertex0())) {
if (is_point_closer_to_beginning_of_line(contour_line, edge_line.a)) {
if ((has_color_change || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line_prev.line, contour_line, edge_line.b)) {
if ((!has_same_color(contour_line_prev, colored_line) || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line_prev.line, contour_line, edge_line.b)) {
graph.append_edge(from_idx, to_idx);
force_edge_adding[colored_line.poly_idx] = false;
}
} else {
if ((has_color_change || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line, contour_line_next.line, edge_line.b)) {
if ((!has_same_color(contour_line_next, colored_line) || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line, contour_line_next.line, edge_line.b)) {
graph.append_edge(from_idx, to_idx);
force_edge_adding[colored_line.poly_idx] = false;
}
@ -1067,12 +1029,12 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vector<std::vector<Col
} else {
assert(graph.is_vertex_on_contour(edge_it->vertex1()));
if (is_point_closer_to_beginning_of_line(contour_line, edge_line.b)) {
if ((has_color_change || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line_prev.line, contour_line, edge_line.a)) {
if ((!has_same_color(contour_line_prev, colored_line) || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line_prev.line, contour_line, edge_line.a)) {
graph.append_edge(from_idx, to_idx);
force_edge_adding[colored_line.poly_idx] = false;
}
} else {
if ((has_color_change || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line, contour_line_next.line, edge_line.a)) {
if ((!has_same_color(contour_line_next, colored_line) || force_edge_adding[colored_line.poly_idx]) && points_inside(contour_line, contour_line_next.line, edge_line.a)) {
graph.append_edge(from_idx, to_idx);
force_edge_adding[colored_line.poly_idx] = false;
}
@ -1086,22 +1048,30 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vector<std::vector<Col
Point real_v1 = Point(coord_t(real_v1_double.x()), coord_t(real_v1_double.y()));
if (is_point_closer_to_beginning_of_line(contour_line, intersection)) {
if (has_color_change)
{
if (points_inside(contour_line_prev.line, contour_line, real_v0))
Line first_part(intersection, real_v0);
Line second_part(intersection, real_v1);
if (!has_same_color(contour_line_prev, colored_line)) {
if (points_inside(contour_line_prev.line, contour_line, first_part.b))
graph.append_edge(edge_it->vertex0()->color(), graph.get_border_arc(edge_it->cell()->source_index()).from_idx);
if (points_inside(contour_line_prev.line, contour_line, real_v1))
if (points_inside(contour_line_prev.line, contour_line, second_part.b))
graph.append_edge(edge_it->vertex1()->color(), graph.get_border_arc(edge_it->cell()->source_index()).from_idx);
}
} else {
if (has_color_change)
{
if (points_inside(contour_line, contour_line_next.line, real_v0))
graph.append_edge(edge_it->vertex0()->color(), graph.get_border_arc(edge_it->cell()->source_index()).to_idx);
const size_t int_point_idx = graph.get_border_arc(edge_it->cell()->source_index()).to_idx;
const Vec2d int_point_double = graph.nodes[int_point_idx].point;
const Point int_point = Point(coord_t(int_point_double.x()), coord_t(int_point_double.y()));
if (points_inside(contour_line, contour_line_next.line, real_v1))
graph.append_edge(edge_it->vertex1()->color(), graph.get_border_arc(edge_it->cell()->source_index()).to_idx);
const Line first_part(int_point, real_v0);
const Line second_part(int_point, real_v1);
if (!has_same_color(contour_line_next, colored_line)) {
if (points_inside(contour_line, contour_line_next.line, first_part.b))
graph.append_edge(edge_it->vertex0()->color(), int_point_idx);
if (points_inside(contour_line, contour_line_next.line, second_part.b))
graph.append_edge(edge_it->vertex1()->color(), int_point_idx);
}
}
}
@ -1147,13 +1117,17 @@ static std::vector<ExPolygons> extract_colored_segments(const MMU_Graph &graph,
{
std::vector<bool> used_arcs(graph.arcs.size(), false);
// When there is no next arc, then is returned original_arc or edge with is marked as used
auto get_next = [&graph, &used_arcs](const Linef &process_line, const MMU_Graph::Arc &original_arc) -> const MMU_Graph::Arc & {
auto get_next = [&graph, &used_arcs](const Linef &process_line, const MMU_Graph::Arc &original_arc, const int color) -> const MMU_Graph::Arc & {
std::vector<std::pair<const MMU_Graph::Arc *, double>> sorted_arcs;
for (const size_t &arc_idx : graph.nodes[original_arc.to_idx].arc_idxs) {
const MMU_Graph::Arc &arc = graph.arcs[arc_idx];
if (graph.nodes[arc.to_idx].point == process_line.a || used_arcs[arc_idx])
continue;
// BBS
if (original_arc.type == MMU_Graph::ARC_TYPE::BORDER && original_arc.color != color)
continue;
assert(original_arc.to_idx == arc.from_idx);
Vec2d process_line_vec_n = (process_line.a - process_line.b).normalized();
Vec2d neighbour_line_vec_n = (graph.nodes[arc.to_idx].point - graph.nodes[arc.from_idx].point).normalized();
@ -1202,7 +1176,7 @@ static std::vector<ExPolygons> extract_colored_segments(const MMU_Graph &graph,
Linef p_vec = process_line;
const MMU_Graph::Arc *p_arc = &arc;
do {
const MMU_Graph::Arc &next = get_next(p_vec, *p_arc);
const MMU_Graph::Arc& next = get_next(p_vec, *p_arc, arc.color);
size_t next_arc_idx = &next - &graph.arcs.front();
face_lines.emplace_back(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point);
if (used_arcs[next_arc_idx])
@ -1509,10 +1483,9 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
top_ex = opening_ex(top_ex, stat.small_region_threshold);
if (! top_ex.empty()) {
append(triangles_by_color_top[color_idx][layer_idx + layer_idx_offset], top_ex);
// BBS: propagate only 1 layer below
float offset = 0.f;
ExPolygons layer_slices_trimmed = input_expolygons[layer_idx];
for (int last_idx = int(layer_idx) - 1; last_idx >= std::max(int(layer_idx - 1), int(0)); --last_idx) {
for (int last_idx = int(layer_idx) - 1; last_idx >= std::max(int(layer_idx - stat.top_shell_layers), int(0)); --last_idx) {
//BBS: offset width should be 2*spacing to avoid too narrow area which has overlap of wall line
//offset -= stat.extrusion_width ;
offset -= (stat.extrusion_spacing + stat.extrusion_width);
@ -1530,10 +1503,9 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
bottom_ex = opening_ex(bottom_ex, stat.small_region_threshold);
if (! bottom_ex.empty()) {
append(triangles_by_color_bottom[color_idx][layer_idx + layer_idx_offset], bottom_ex);
// BBS: propogate only 1 layer above
float offset = 0.f;
ExPolygons layer_slices_trimmed = input_expolygons[layer_idx];
for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + 2, num_layers); ++last_idx) {
for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + stat.bottom_shell_layers, num_layers); ++last_idx) {
//BBS: offset width should be 2*spacing to avoid too narrow area which has overlap of wall line
//offset -= stat.extrusion_width;
offset -= (stat.extrusion_spacing + stat.extrusion_width);

View file

@ -765,7 +765,7 @@ void PerimeterGenerator::process()
double(-inset - infill_peri_overlap));
if (!top_fills.empty())
polyWithoutOverlap = union_ex(polyWithoutOverlap, top_infill_exp);
this->fill_no_overlap.insert(this->fill_no_overlap.end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
this->fill_no_overlap->insert(this->fill_no_overlap->end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
}
} // for each island

View file

@ -29,13 +29,14 @@ public:
ExtrusionEntityCollection *loops;
ExtrusionEntityCollection *gap_fill;
SurfaceCollection *fill_surfaces;
//BBS
ExPolygons *fill_no_overlap;
//BBS
Flow smaller_ext_perimeter_flow;
std::map<int, Polygons> m_lower_polygons_series;
std::map<int, Polygons> m_external_lower_polygons_series;
std::map<int, Polygons> m_smaller_external_lower_polygons_series;
ExPolygons fill_no_overlap;
PerimeterGenerator(
// Input:
@ -52,14 +53,16 @@ public:
// Gaps without the thin walls
ExtrusionEntityCollection* gap_fill,
// Infills without the gap fills
SurfaceCollection* fill_surfaces)
SurfaceCollection* fill_surfaces,
//BBS
ExPolygons* fill_no_overlap)
: slices(slices), upper_slices(nullptr), lower_slices(nullptr), layer_height(layer_height),
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config),
m_spiral_vase(spiral_mode),
m_scaled_resolution(scaled<double>(print_config->resolution.value > EPSILON ? print_config->resolution.value : EPSILON)),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces), fill_no_overlap(fill_no_overlap),
m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1), m_ext_mm3_per_mm_smaller_width(-1)
{}

View file

@ -239,6 +239,18 @@ public:
std::pair<bool,bool> endpoints;
};
inline ThickPolylines to_thick_polylines(Polylines&& polylines, const coordf_t width)
{
ThickPolylines out;
out.reserve(polylines.size());
for (Polyline& polyline : polylines) {
out.emplace_back();
out.back().width.assign((polyline.points.size() - 1) * 2, width);
out.back().points = std::move(polyline.points);
}
return out;
}
class Polyline3 : public MultiPoint3
{
public:

View file

@ -307,8 +307,8 @@ void Preset::update_suffix_modified(const std::string& new_suffix_modified)
// This converts a UI name to a unique preset identifier.
std::string Preset::remove_suffix_modified(const std::string &name)
{
return boost::algorithm::ends_with(name, g_suffix_modified) ?
name.substr(0, name.size() - g_suffix_modified.size()) :
return boost::algorithm::starts_with(name, g_suffix_modified) ?
name.substr(g_suffix_modified.size()) :
name;
}
@ -530,9 +530,10 @@ void Preset::save(DynamicPrintConfig* parent_config)
}
// Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty.
std::string Preset::label() const
std::string Preset::label(bool no_alias) const
{
return this->name + (this->is_dirty ? g_suffix_modified : "");
return (this->is_dirty ? g_suffix_modified : "")
+ ((no_alias || this->alias.empty()) ? this->name : this->alias);
}
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer)
@ -667,7 +668,7 @@ static std::vector<std::string> s_Preset_print_options {
//"independent_support_layer_height",
"support_angle", "support_interface_top_layers", "support_interface_bottom_layers",
"support_interface_pattern", "support_interface_spacing", "support_interface_loop_pattern",
"support_top_z_distance", "support_on_build_plate_only", "bridge_no_support", "thick_bridges", "max_bridge_length", "print_sequence",
"support_top_z_distance", "support_on_build_plate_only","support_critical_regions_only", "bridge_no_support", "thick_bridges", "max_bridge_length", "print_sequence",
"filename_format", "wall_filament",
"sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament",
"ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width",

View file

@ -245,7 +245,7 @@ public:
void save(DynamicPrintConfig* parent_config);
// Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty.
std::string label() const;
std::string label(bool no_alias) const;
// Set the is_dirty flag if the provided config is different from the active one.
void set_dirty(const DynamicPrintConfig &config) { this->is_dirty = ! this->config.diff(config).empty(); }

View file

@ -1314,6 +1314,31 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
update_multi_material_filament_presets();
}
unsigned int PresetBundle::sync_ams_list()
{
std::vector<std::string> filament_presets;
std::vector<std::string> filament_colors;
for (auto &ams : filament_ams_list) {
auto filament_id = ams.opt_string("filament_id", 0u);
auto filament_color = ams.opt_string("filament_colour", 0u);
auto iter = std::find_if(filaments.begin(), filaments.end(), [&filament_id](auto &f) { return f.is_compatible && f.is_system && f.filament_id == filament_id; });
if (iter == filaments.end()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
continue;
}
filament_presets.push_back(iter->name);
filament_colors.push_back(filament_color);
}
if (filament_presets.empty())
return 0;
this->filament_presets = filament_presets;
ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
filament_color->resize(filament_presets.size());
filament_color->values = filament_colors;
update_multi_material_filament_presets();
return filament_presets.size();
}
//BBS: check whether this is the only edited filament
bool PresetBundle::is_the_only_edited_filament(unsigned int filament_index)
{

View file

@ -79,6 +79,7 @@ public:
// BBS
void set_num_filaments(unsigned int n, std::string new_col = "");
unsigned int sync_ams_list();
//BBS: check whether this is the only edited filament
bool is_the_only_edited_filament(unsigned int filament_index);

View file

@ -38,6 +38,54 @@ PrintRegion::PrintRegion(PrintRegionConfig &&config) : PrintRegion(std::move(con
//BBS
float Print::min_skirt_length = 0;
void dfs_get_all_sorted_extruders(const std::vector<std::vector<float>>& wipe_volumes,
const std::vector<unsigned int>& all_extruders,
std::vector<unsigned int> & sorted_extruders,
float flush_volume,
std::map<float, std::vector<unsigned int>> & volumes_to_extruder_order)
{
if (sorted_extruders.size() == all_extruders.size()) {
volumes_to_extruder_order.insert(std::pair(flush_volume, sorted_extruders));
return;
}
for (auto extruder_id : all_extruders) {
if (sorted_extruders.empty()) {
sorted_extruders.push_back(extruder_id);
dfs_get_all_sorted_extruders(wipe_volumes, all_extruders, sorted_extruders, flush_volume, volumes_to_extruder_order);
sorted_extruders.pop_back();
} else {
auto itor = std::find(sorted_extruders.begin(), sorted_extruders.end(), extruder_id);
if (itor == sorted_extruders.end()) {
float delta_flush_volume = wipe_volumes[sorted_extruders.back()][extruder_id];
flush_volume += delta_flush_volume;
sorted_extruders.push_back(extruder_id);
dfs_get_all_sorted_extruders(wipe_volumes, all_extruders, sorted_extruders, flush_volume, volumes_to_extruder_order);
flush_volume -= delta_flush_volume;
sorted_extruders.pop_back();
}
}
}
}
std::vector<unsigned int> get_extruders_order(const std::vector<std::vector<float>> &wipe_volumes,
std::vector<unsigned int> all_extruders,
unsigned int start_extruder_id)
{
if (all_extruders.size() > 1) {
std::vector<unsigned int> sorted_extruders;
auto iter = std::find(all_extruders.begin(), all_extruders.end(), start_extruder_id);
if (iter != all_extruders.end()) {
sorted_extruders.push_back(start_extruder_id);
}
std::map<float, std::vector<unsigned int>> volumes_to_extruder_order;
dfs_get_all_sorted_extruders(wipe_volumes, all_extruders, sorted_extruders, 0, volumes_to_extruder_order);
if(volumes_to_extruder_order.size() > 0)
return volumes_to_extruder_order.begin()->second;
}
return all_extruders;
}
void Print::clear()
{
std::scoped_lock<std::mutex> lock(this->state_mutex());
@ -674,15 +722,16 @@ static StringObjectException layered_print_cleareance_valid(const Print &print,
float depth = print.wipe_tower_data(filaments_count).depth;
//float brim_width = print.wipe_tower_data(filaments_count).brim_width;
Polygon wipe_tower_convex_hull;
wipe_tower_convex_hull.points.emplace_back(scale_(x), scale_(y));
wipe_tower_convex_hull.points.emplace_back(scale_(x + width), scale_(y));
wipe_tower_convex_hull.points.emplace_back(scale_(x + width), scale_(y + depth));
wipe_tower_convex_hull.points.emplace_back(scale_(x), scale_(y + depth));
wipe_tower_convex_hull.rotate(a);
Polygons convex_hulls_temp;
convex_hulls_temp.push_back(wipe_tower_convex_hull);
if (print.has_wipe_tower()) {
Polygon wipe_tower_convex_hull;
wipe_tower_convex_hull.points.emplace_back(scale_(x), scale_(y));
wipe_tower_convex_hull.points.emplace_back(scale_(x + width), scale_(y));
wipe_tower_convex_hull.points.emplace_back(scale_(x + width), scale_(y + depth));
wipe_tower_convex_hull.points.emplace_back(scale_(x), scale_(y + depth));
wipe_tower_convex_hull.rotate(a);
convex_hulls_temp.push_back(wipe_tower_convex_hull);
}
if (!intersection(convex_hulls_other, convex_hulls_temp).empty()) {
if (warning) {
warning->string += L("Prime Tower") + L(" is too close to others, and collisions may be caused.\n");
@ -756,6 +805,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
}
if (m_config.print_sequence == PrintSequence::ByObject) {
if (m_config.timelapse_type == TimelapseType::tlSmooth)
return {L("Smooth mode of timelapse is not supported when \"by object\" sequence is enabled.")};
//BBS: refine seq-print validation logic
auto ret = sequential_print_clearance_valid(*this, collison_polygons, height_polygons);
if (!ret.string.empty())
@ -1850,6 +1902,9 @@ void Print::_make_wipe_tower()
if (!layer_tools.has_wipe_tower) continue;
bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front();
wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false);
layer_tools.extruders = get_extruders_order(wipe_volumes, layer_tools.extruders, current_extruder_id);
for (const auto extruder_id : layer_tools.extruders) {
// BBS: priming logic is removed, so no need to do toolchange for first extruder
if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */extruder_id != current_extruder_id) {
@ -1875,8 +1930,11 @@ void Print::_make_wipe_tower()
layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this);
// if enable timelapse, slice all layer
if (enable_timelapse_print())
if (enable_timelapse_print()) {
if (layer_tools.wipe_tower_partitions == 0)
wipe_tower.set_last_layer_extruder_fill(false);
continue;
}
if (&layer_tools == &m_wipe_tower_data.tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0)
break;

View file

@ -914,16 +914,16 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("zig-zag");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("monotonicline");
//def->enum_values.push_back("alignedrectilinear");
//def->enum_values.push_back("hilbertcurve");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("hilbertcurve");
//def->enum_values.push_back("archimedeanchords");
//def->enum_values.push_back("octagramspiral");
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Zig zag"));
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Monotonic line"));
//def->enum_labels.push_back(L("Aligned Rectilinear"));
//def->enum_labels.push_back(L("Hilbert Curve"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Hilbert Curve"));
//def->enum_labels.push_back(L("Archimedean Chords"));
//def->enum_labels.push_back(L("Octagram Spiral"));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
@ -1232,7 +1232,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("gyroid");
def->enum_values.push_back("honeycomb");
def->enum_values.push_back("adaptivecubic");
//def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("alignedrectilinear");
//def->enum_values.push_back("3dhoneycomb");
//def->enum_values.push_back("hilbertcurve");
//def->enum_values.push_back("archimedeanchords");
@ -1242,7 +1242,7 @@ void PrintConfigDef::init_fff_params()
//def->enum_values.push_back("lightning");
#endif // HAS_LIGHTNING_INFILL
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Zig zag"));
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Grid"));
def->enum_labels.push_back(L("Line"));
def->enum_labels.push_back(L("Cubic"));
@ -1251,7 +1251,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Gyroid"));
def->enum_labels.push_back(L("Honeycomb"));
def->enum_labels.push_back(L("Adaptive Cubic"));
//def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
//def->enum_labels.push_back(L("3D Honeycomb"));
//def->enum_labels.push_back(L("Hilbert Curve"));
//def->enum_labels.push_back(L("Archimedean Chords"));
@ -1985,7 +1985,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Wall loops");
def->category = L("Strength");
def->tooltip = L("Number of walls of every layer");
def->min = 1;
def->min = 0;
def->max = 1000;
def->set_default_value(new ConfigOptionInt(2));
@ -2397,6 +2397,14 @@ void PrintConfigDef::init_fff_params()
def->mode = comSimple;
def->set_default_value(new ConfigOptionBool(false));
// BBS
def = this->add("support_critical_regions_only", coBool);
def->label = L("Support critical regions only");
def->category = L("Support");
def->tooltip = L("Only create support for critical regions including sharp tail, cantilever, etc.");
def->mode = comSimple;
def->set_default_value(new ConfigOptionBool(false));
// BBS: change type to common float.
// It may be rounded to mulitple layer height when independent_support_layer_height is false.
def = this->add("support_top_z_distance", coFloat);
@ -3680,8 +3688,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
//But now these key-value must be absolute value.
//Reset to default value by erasing these key to avoid parsing error.
opt_key = "";
} else if (opt_key == "filament_type" && value == "PA-CF") {
value == "PA";
} else if (opt_key == "inherits_cummulative") {
opt_key = "inherits_group";
} else if (opt_key == "compatible_printers_condition_cummulative") {

View file

@ -54,7 +54,7 @@ enum AuthorizationType {
enum InfillPattern : int {
ipConcentric, ipRectilinear, ipGrid, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricGapFill, ipConcentricInternal,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal,
#if HAS_LIGHTNING_INFILL
ipLightning,
#endif // HAS_LIGHTNING_INFILL
@ -605,6 +605,7 @@ PRINT_CONFIG_CLASS_DEFINE(
// Direction of the support pattern (in XY plane).`
((ConfigOptionFloat, support_angle))
((ConfigOptionBool, support_on_build_plate_only))
((ConfigOptionBool, support_critical_regions_only))
((ConfigOptionFloat, support_top_z_distance))
((ConfigOptionInt, enforce_support_layers))
((ConfigOptionInt, support_filament))

View file

@ -702,6 +702,7 @@ bool PrintObject::invalidate_state_by_config_options(
opt_key == "support_type"
|| opt_key == "support_angle"
|| opt_key == "support_on_build_plate_only"
|| opt_key == "support_critical_regions_only"
|| opt_key == "enforce_support_layers"
|| opt_key == "support_filament"
|| opt_key == "support_line_width"

View file

@ -38,6 +38,8 @@
// Enable style editor in develop mode
#define ENABLE_IMGUI_STYLE_EDITOR 0
// Enable rework of Reload from disk command
#define ENABLE_RELOAD_FROM_DISK_REWORK 1
//====================
// 2.4.0.beta1 techs

View file

@ -673,6 +673,7 @@ void TreeSupport::detect_object_overhangs()
const coordf_t extrusion_width_scaled = scale_(extrusion_width);
const coordf_t max_bridge_length = scale_(config.max_bridge_length.value);
const bool bridge_no_support = max_bridge_length > 0;// config.bridge_no_support.value;
const bool support_critical_regions_only = config.support_critical_regions_only.value;
const int enforce_support_layers = config.enforce_support_layers.value;
const double area_thresh_well_supported = SQ(scale_(6)); // min: 6x6=36mm^2
const double length_thresh_well_supported = scale_(6); // min: 6mm
@ -694,6 +695,7 @@ void TreeSupport::detect_object_overhangs()
int min_layer = 1e7;
int max_layer = 0;
coordf_t offset = 0;
bool is_cantilever = false;
OverhangCluster(const ExPolygon* expoly, int layer_nr) {
push_back(expoly, layer_nr);
}
@ -822,8 +824,11 @@ void TreeSupport::detect_object_overhangs()
// normal overhang
ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
ExPolygons overhang_areas = std::move(diff_ex(curr_polys, lower_layer_offseted));
//overhang_areas = std::move(offset2_ex(overhang_areas, -0.1 * extrusion_width_scaled, 0.1 * extrusion_width_scaled));
overhang_areas.erase(std::remove_if(overhang_areas.begin(), overhang_areas.end(), [extrusion_width_scaled](ExPolygon& area) {return offset_ex(area, -0.1 * extrusion_width_scaled).empty(); }), overhang_areas.end());
// overhang_areas = std::move(offset2_ex(overhang_areas, -0.1 * extrusion_width_scaled, 0.1 * extrusion_width_scaled));
overhang_areas.erase(std::remove_if(overhang_areas.begin(), overhang_areas.end(),
[extrusion_width_scaled](ExPolygon &area) { return offset_ex(area, -0.1 * extrusion_width_scaled).empty(); }),
overhang_areas.end());
ExPolygons overhangs_sharp_tail;
if (is_auto && g_config_support_sharp_tails)
@ -854,7 +859,7 @@ void TreeSupport::detect_object_overhangs()
overhang_areas = union_ex(overhang_areas, overhangs_sharp_tail);
}
#else
// BBS
// BBS detect sharp tail
const ExPolygons& lower_layer_sharptails = lower_layer->sharp_tails;
auto& lower_layer_sharptails_height = lower_layer->sharp_tails_height;
for (ExPolygon& expoly : layer->lslices) {
@ -939,19 +944,8 @@ void TreeSupport::detect_object_overhangs()
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
for (ExPolygon& poly : overhang_areas) {
// NOTE: must push something into ts_layer->overhang_areas, can't be empty for any layer,
// otherwise remove_small_overhangs can't correctly cluster overhangs
#if 0
ExPolygons poly_simp = poly.simplify(scale_(radius_sample_resolution));
// simplify method may delete the entire polygon which is unwanted
if(!poly_simp.empty())
append(ts_layer->overhang_areas, poly_simp);
else
ts_layer->overhang_areas.emplace_back(poly);
#else
if (!offset_ex(poly, -0.1 * extrusion_width_scaled).empty())
ts_layer->overhang_areas.emplace_back(poly);
#endif
}
if (is_auto && g_config_remove_small_overhangs) {
@ -1004,6 +998,34 @@ void TreeSupport::detect_object_overhangs()
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers);
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
// check whether the overhang cluster is cantilever (far awary from main body)
for (auto& cluster : overhangClusters) {
Layer* layer = m_object->get_layer(cluster.min_layer);
if (layer->lower_layer == NULL) continue;
Layer* lower_layer = layer->lower_layer;
auto cluster_boundary = intersection(cluster.merged_poly, offset(lower_layer->lslices, scale_(0.5)));
double dist_max = 0;
Points cluster_pts;
for (auto& poly : cluster.merged_poly)
append(cluster_pts, poly.contour.points);
for (auto& pt : cluster_pts) {
double dist_pt = std::numeric_limits<double>::max();
for (auto& poly : cluster_boundary) {
double d = poly.distance_to(pt);
dist_pt = std::min(dist_pt, d);
}
dist_max = std::max(dist_max, dist_pt);
}
if (dist_max > scale_(5)) { // this cluster is cantilever, add all expolygons to sharp tail
for (auto it = cluster.layer_overhangs.begin(); it != cluster.layer_overhangs.end(); it++) {
int layer_nr = it->first;
auto p_overhang = it->second;
m_object->get_layer(layer_nr)->cantilevers.emplace_back(*p_overhang);
}
cluster.is_cantilever = true;
}
}
if (is_auto && g_config_remove_small_overhangs) {
if (blockers.size() < m_object->layer_count())
blockers.resize(m_object->layer_count());
@ -1045,25 +1067,8 @@ void TreeSupport::detect_object_overhangs()
}
if (is_sharp_tail) continue;
// 4. check whether the overhang cluster is cantilever (far awary from main body)
Layer* layer = m_object->get_layer(cluster.min_layer);
if (layer->lower_layer == NULL) continue;
Layer* lower_layer = layer->lower_layer;
auto cluster_boundary = intersection(cluster.merged_poly, offset(lower_layer->lslices, scale_(0.5)));
double dist_max = 0;
Points cluster_pts;
for (auto& poly : cluster.merged_poly)
append(cluster_pts, poly.contour.points);
for (auto& pt : cluster_pts) {
double dist_pt = std::numeric_limits<double>::max();
for (auto& poly : cluster_boundary) {
double d = poly.distance_to(pt);
dist_pt = std::min(dist_pt, d);
}
dist_max = std::max(dist_max, dist_pt);
}
if (dist_max > scale_(5))
continue;
// 4. check whether the overhang cluster is cantilever
if (cluster.is_cantilever) continue;
for (auto it = cluster.layer_overhangs.begin(); it != cluster.layer_overhangs.end(); it++) {
int layer_nr = it->first;
@ -1088,6 +1093,11 @@ void TreeSupport::detect_object_overhangs()
break;
TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers);
if (support_critical_regions_only) {
auto layer = m_object->get_layer(layer_nr);
ts_layer->overhang_areas = layer->sharp_tails;
append(ts_layer->overhang_areas, layer->cantilevers);
}
if (layer_nr < blockers.size()) {
Polygons& blocker = blockers[layer_nr];
@ -1822,6 +1832,24 @@ inline coordf_t calc_branch_radius(coordf_t base_radius, size_t layers_to_top, s
return radius;
}
ExPolygons avoid_object_remove_extra_small_parts(ExPolygons &expolys, const ExPolygons &avoid_region) {
ExPolygons expolys_out;
for (auto expoly : expolys) {
auto expolys_avoid = diff_ex(expoly, avoid_region);
int idx_max_area = -1;
float max_area = 0;
for (int i = 0; i < expolys_avoid.size(); ++i) {
auto a = expolys_avoid[i].area();
if (a > max_area) {
max_area = a;
idx_max_area = i;
}
}
if (idx_max_area >= 0) expolys_out.emplace_back(std::move(expolys_avoid[idx_max_area]));
}
return expolys_out;
}
void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_nodes)
{
const PrintObjectConfig &config = m_object->config();
@ -1898,7 +1926,6 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
//Draw the support areas and add the roofs appropriately to the support roof instead of normal areas.
ts_layer->lslices.reserve(contact_nodes[layer_nr].size());
#if 1
for (const Node* p_node : contact_nodes[layer_nr])
{
if (print->canceled())
@ -1949,59 +1976,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
if (layer_nr < brim_skirt_layers)
ts_layer->lslices.emplace_back(area);
}
#else
// some nodes may not have radius set
for (Node* p_node : contact_nodes[layer_nr])
{
size_t layers_to_top = p_node->distance_to_top;// std::min(node.distance_to_top, (size_t)300);
double scale = static_cast<double>(layers_to_top + 1) / tip_layers;
scale = layers_to_top < tip_layers ? (0.5 + scale / 2) : (1 + static_cast<double>(layers_to_top - tip_layers) * diameter_angle_scale_factor);
p_node->radius = scale * branch_radius;
}
{
// now this method is extremely slow. Need to optimize the speed before we can use it.
Polygons layer_contours = std::move(m_ts_data->get_contours_with_holes(layer_nr));
std::vector<double> radiis;
std::vector<bool> is_interface;
//Polygons lines = spanning_tree_to_polygon(m_spanning_trees[layer_nr], layer_contours, layer_nr, radiis);
Polygons lines = contact_nodes_to_polygon(contact_nodes[layer_nr], layer_contours, layer_nr, radiis, is_interface);
for (int k = 0; k < lines.size(); k++) {
auto line = lines[k];
double radius = radiis[k];
Polygons line_expanded;
if (line.size() == 1)
{
Polygon circle;
double scale = radiis[k] / branch_radius;
for (auto iter = branch_circle.points.begin(); iter != branch_circle.points.end(); iter++)
{
Point corner = (*iter) * scale;
circle.append(line.first_point() + corner);
}
line_expanded.emplace_back(circle);
}
else {
line_expanded = offset(line, scale_(radius), jtRound, scale_(g_config_tree_support_collision_resolution));
}
if (line_expanded.empty())
continue;
if (is_interface[k])
roof_areas.emplace_back(line_expanded[0]);
else
base_areas.emplace_back(line_expanded[0]);
if (layer_nr < brim_skirt_layers)
ts_layer->lslices.emplace_back(line_expanded[0]);
//if (radius > config.support_base_pattern_spacing * 2)
// ts_layer->need_infill = true;
}
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
draw_contours_and_nodes_to_svg( layer_nr, base_areas, to_expolygons(lines), m_ts_data->m_layer_outlines_below[layer_nr], {}, {}, "circles", { "lines","base_areas","outlines" });
#endif
}
#endif
ts_layer->lslices = std::move(union_ex(ts_layer->lslices));
//Must update bounding box which is used in avoid crossing perimeter
@ -2020,15 +1995,18 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
// avoid object
auto avoid_region_interface = m_ts_data->get_collision(m_ts_data->m_xy_distance, layer_nr);
roof_areas = std::move(diff_ex(roof_areas, avoid_region_interface));
roof_1st_layer = std::move(diff_ex(roof_1st_layer, avoid_region_interface));
//roof_areas = std::move(diff_ex(roof_areas, avoid_region_interface));
//roof_1st_layer = std::move(diff_ex(roof_1st_layer, avoid_region_interface));
roof_areas = avoid_object_remove_extra_small_parts(roof_areas, avoid_region_interface);
roof_1st_layer = avoid_object_remove_extra_small_parts(roof_1st_layer, avoid_region_interface);
// roof_1st_layer and roof_areas may intersect, so need to subtract roof_areas from roof_1st_layer
roof_1st_layer = std::move(diff_ex(roof_1st_layer, roof_areas));
// let supports touch objects when brim is on
auto avoid_region = m_ts_data->get_collision((layer_nr == 0 && has_brim) ? config.brim_object_gap : m_ts_data->m_xy_distance, layer_nr);
base_areas = std::move(diff_ex(base_areas, avoid_region));
// base_areas = std::move(diff_ex(base_areas, avoid_region));
base_areas = avoid_object_remove_extra_small_parts(base_areas, avoid_region);
base_areas = std::move(diff_ex(base_areas, roof_areas));
base_areas = std::move(diff_ex(base_areas, roof_1st_layer));

View file

@ -372,7 +372,7 @@ inline std::string short_time(const std::string &time)
else if (hours > 0)
::sprintf(buffer, "%dh%dm", hours, minutes);
else if (minutes > 0)
::sprintf(buffer, "%dm", minutes);
::sprintf(buffer, "%dm%ds", minutes, seconds);
else
::sprintf(buffer, "%ds", seconds);
return buffer;

View file

@ -0,0 +1,57 @@
#!/bin/bash
export ROOT=$(echo $ROOT | grep . || pwd)
export NCORES=`nproc --all`
while getopts ":ih" opt; do
case ${opt} in
i )
export BUILD_IMAGE="1"
;;
h ) echo "Usage: ./BuildLinuxImage.sh [-i]"
echo " -i: Generate Appimage (optional)"
exit 0
;;
esac
done
echo -n "[9/9] Generating Linux app..."
#{
# create directory and copy into it
if [ -d "package" ]
then
rm -rf package/*
rm -rf package/.* 2&>/dev/null
else
mkdir package
fi
mkdir package/bin
# copy Resources
cp -Rf ../resources package/resources
cp -f src/@SLIC3R_APP_CMD@ package/bin/@SLIC3R_APP_CMD@
# remove unneeded po from resources
## find package/resources/localization -name "*.po" -type f -delete ## FIXME: DD - do we need this?
# create bin
echo -e '#!/bin/bash\nDIR=$(readlink -f "$0" | xargs dirname)\nexport LD_LIBRARY_PATH="$DIR/bin"\nexec "$DIR/bin/@SLIC3R_APP_CMD@" "$@"' >@SLIC3R_APP_CMD@
chmod ug+x @SLIC3R_APP_CMD@
cp -f @SLIC3R_APP_CMD@ package/@SLIC3R_APP_CMD@
pushd package
tar -cvf ../@SLIC3R_APP_KEY@.tar . &>/dev/null
popd
#} &> $ROOT/Build.log # Capture all command output
echo "done"
if [[ -n "$BUILD_IMAGE" ]]
then
echo -n "Creating Appimage for distribution..."
#{
pushd package
chmod +x ../build_appimage.sh
../build_appimage.sh
popd
mv package/"@SLIC3R_APP_KEY@_ubu64.AppImage" "@SLIC3R_APP_KEY@_ubu64.AppImage"
#} &> $ROOT/Build.log # Capture all command output
echo "done"
fi

View file

@ -0,0 +1,30 @@
#!/bin/sh
APPIMAGETOOLURL="https://github.com/AppImage/AppImageKit/releases/latest/download/appimagetool-x86_64.AppImage"
APP_IMAGE="@SLIC3R_APP_KEY@_ubu64.AppImage"
wget ${APPIMAGETOOLURL} -O ../appimagetool.AppImage
chmod +x ../appimagetool.AppImage
sed -i -e 's#/usr#././#g' bin/@SLIC3R_APP_CMD@
mv @SLIC3R_APP_CMD@ AppRun
chmod +x AppRun
cp resources/images/@SLIC3R_APP_KEY@_192px.png @SLIC3R_APP_KEY@.png
mkdir -p usr/share/icons/hicolor/192x192/apps
cp resources/images/@SLIC3R_APP_KEY@_192px.png usr/share/icons/hicolor/192x192/apps/@SLIC3R_APP_KEY@.png
cat <<EOF > @SLIC3R_APP_KEY@.desktop
[Desktop Entry]
Name=@SLIC3R_APP_KEY@
Exec=AppRun %F
Icon=@SLIC3R_APP_KEY@
Type=Application
Categories=Utility;
MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;
EOF
../appimagetool.AppImage . $([ ! -z "${container}" ] && echo '--appimage-extract-and-run')
mv @SLIC3R_APP_KEY@-x86_64.AppImage ${APP_IMAGE}
chmod +x ${APP_IMAGE}

View file

@ -241,6 +241,8 @@ set(SLIC3R_GUI_SOURCES
GUI/ConfigManipulation.hpp
GUI/Field.cpp
GUI/Field.hpp
GUI/ConfirmHintDialog.cpp
GUI/ConfirmHintDialog.hpp
GUI/OptionsGroup.cpp
GUI/OptionsGroup.hpp
GUI/OG_CustomCtrl.cpp
@ -257,8 +259,8 @@ set(SLIC3R_GUI_SOURCES
GUI/wxExtensions.hpp
GUI/WipeTowerDialog.cpp
GUI/WipeTowerDialog.hpp
#GUI/RemovableDriveManager.cpp
#GUI/RemovableDriveManager.hpp
GUI/RemovableDriveManager.cpp
GUI/RemovableDriveManager.hpp
GUI/SendSystemInfoDialog.cpp
GUI/SendSystemInfoDialog.hpp
GUI/ImGuiWrapper.hpp
@ -409,8 +411,8 @@ if (APPLE)
list(APPEND SLIC3R_GUI_SOURCES
Utils/RetinaHelperImpl.mm
Utils/MacDarkMode.mm
#GUI/RemovableDriveManagerMM.mm
#GUI/RemovableDriveManagerMM.h
GUI/RemovableDriveManagerMM.mm
GUI/RemovableDriveManagerMM.h
GUI/Mouse3DHandlerMac.mm
#GUI/InstanceCheckMac.mm
#GUI/InstanceCheckMac.h
@ -438,7 +440,18 @@ target_link_libraries(libslic3r_gui libslic3r cereal imgui minilzo GLEW::GLEW Op
if (MSVC)
target_link_libraries(libslic3r_gui Setupapi.lib)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server)
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl)
FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client)
find_package(CURL REQUIRED)
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES} OSMesa)
target_link_libraries(libslic3r_gui
OpenGL::EGL
${WAYLAND_SERVER_LIBRARIES}
${WAYLAND_EGL_LIBRARIES}
${WAYLAND_CLIENT_LIBRARIES}
${CURL_LIBRARIES}
)
elseif (APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif()

View file

@ -36,10 +36,6 @@ BBLStatusBarBind::BBLStatusBarBind(wxWindow *parent, int id)
m_prog = new wxGauge(m_self, wxID_ANY, 100, wxDefaultPosition, wxSize(m_self->FromDIP(400), m_self->FromDIP(6)), wxGA_HORIZONTAL);
m_prog->SetValue(0);
block_left = new wxWindow(m_prog, wxID_ANY, wxPoint(0, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2));
block_left->SetBackgroundColour(wxColour(255, 255, 255));
block_right = new wxWindow(m_prog, wxID_ANY, wxPoint(m_prog->GetSize().GetWidth() - 2, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2));
block_right->SetBackgroundColour(wxColour(255, 255, 255));
m_stext_percent = new wxStaticText(m_self, wxID_ANY, _L(""), wxDefaultPosition, wxDefaultSize, 0);
m_stext_percent->SetForegroundColour(wxColour(107, 107, 107));
@ -61,8 +57,6 @@ BBLStatusBarBind::BBLStatusBarBind(wxWindow *parent, int id)
void BBLStatusBarBind::set_prog_block()
{
block_left->SetPosition(wxPoint(0, 0));
block_right->SetPosition(wxPoint(m_prog->GetSize().GetWidth() - 2, 0));
}
int BBLStatusBarBind::get_progress() const

View file

@ -35,8 +35,6 @@ class BBLStatusBarBind : public ProgressIndicator
wxStaticText *m_stext_percent;
wxBoxSizer * m_sizer;
wxBoxSizer * m_sizer_eline;
wxWindow * block_left;
wxWindow * block_right;
public:
BBLStatusBarBind(wxWindow *parent = nullptr, int id = -1);

View file

@ -131,7 +131,7 @@ void ConfigManipulation::check_bed_temperature_difference(int bed_type, DynamicP
}
if (first_layer_bed_temp > vitrification || bed_temp > vitrification) {
const wxString msg_text = wxString::Format(_L("Bed temperature is higher than vitrification temperature of this filament.\nThis may cause nozzle blocked and printing failure"));
const wxString msg_text = wxString::Format(_L("Bed temperature is higher than vitrification temperature of this filament.\nThis may cause nozzle blocked and printing failure\nPlease keep the printer open during the printing process to ensure air circulation or reduce the temperature of the hot bed"));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
is_msg_dlg_already_exist = true;
dialog.ShowModal();
@ -384,8 +384,8 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
wxString msg_text = GUI::format_wxstr(_L("%1% infill pattern doesn't support 100%% density."),
_(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()]));
if (is_global_config)
msg_text += "\n" + _L("Switch to zig-zag pattern?\n"
"Yes - switch to zig-zag pattern automaticlly\n"
msg_text += "\n" + _L("Switch to rectilinear pattern?\n"
"Yes - switch to rectilinear pattern automaticlly\n"
"No - reset density to default non 100% value automaticlly\n");
MessageDialog dialog(m_msg_dlg_parent, msg_text, "",
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) );
@ -513,9 +513,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "support_style", "support_base_pattern",
"support_base_pattern_spacing", "support_angle",
"support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers",
"bridge_no_support", "thick_bridges", "max_bridge_length", "support_top_z_distance",
"bridge_no_support", "max_bridge_length", "support_top_z_distance",
//BBS: add more support params to dependent of enable_support
"support_type","support_on_build_plate_only",
"support_type", "support_on_build_plate_only", "support_critical_regions_only",
"support_object_xy_distance", "independent_support_layer_height"})
toggle_field(el, have_support_material);
toggle_field("support_threshold_angle", have_support_material && (support_type == stNormalAuto || support_type == stTreeAuto || support_type==stHybridAuto));

View file

@ -0,0 +1,173 @@
#include "ConfirmHintDialog.hpp"
#include <slic3r/GUI/I18N.hpp>
#include <wx/dcgraph.h>
#include <wx/dcmemory.h>
#include <slic3r/GUI/Widgets/Label.hpp>
namespace Slic3r { namespace GUI {
wxDEFINE_EVENT(EVT_CONFIRM_HINT, wxCommandEvent);
ConfirmHintDialog::ConfirmHintDialog(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style)
: DPIDialog(parent, id, title, pos, size, style)
{
std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
auto* main_sizer = new wxBoxSizer(wxVERTICAL);
auto* button_sizer = new wxBoxSizer(wxHORIZONTAL);
wxPanel* m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
m_button_confirm = new Button(this, _L("Confirm"));
m_button_confirm->SetFont(Label::Body_14);
m_button_confirm->SetMinSize(wxSize(-1, FromDIP(24)));
m_button_confirm->SetCornerRadius(FromDIP(12));
StateColor confirm_btn_bg(std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 174, 66), StateColor::Normal));
m_button_confirm->SetBackgroundColor(confirm_btn_bg);
m_button_confirm->SetBorderColor(wxColour(0, 174, 66));
m_button_confirm->SetTextColor(*wxWHITE);
m_button_close = new Button(this, _L("Cancel"));
m_button_close->SetFont(Label::Body_14);
m_button_close->SetMinSize(wxSize(-1, FromDIP(24)));
m_button_close->SetCornerRadius(FromDIP(12));
StateColor close_btn_bg(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
m_button_close->SetBackgroundColor(close_btn_bg);
m_button_close->SetBorderColor(wxColour(38, 46, 48));
m_button_close->SetTextColor(wxColour(38, 46, 48));
button_sizer->AddStretchSpacer();
button_sizer->Add(m_button_confirm);
button_sizer->AddSpacer(FromDIP(20));
button_sizer->Add(m_button_close);
main_sizer->Add(m_line_top, 0, wxEXPAND, 0);
main_sizer->AddSpacer(wxSize(FromDIP(475), FromDIP(100)).y);
main_sizer->Add(button_sizer, 0, wxBOTTOM | wxRIGHT | wxEXPAND, FromDIP(25));
SetSizer(main_sizer);
CenterOnParent();
this->SetSize(wxSize(wxSize(FromDIP(475), FromDIP(100)).x, -1));
this->SetMinSize(wxSize(wxSize(FromDIP(475), FromDIP(100)).x, -1));
Layout();
Fit();
this->Bind(wxEVT_PAINT, &ConfirmHintDialog::OnPaint, this);
m_button_confirm->Bind(wxEVT_BUTTON, &ConfirmHintDialog::on_button_confirm, this);
m_button_close->Bind(wxEVT_BUTTON, &ConfirmHintDialog::on_button_close, this);
}
ConfirmHintDialog::~ConfirmHintDialog() {}
void ConfirmHintDialog::SetHint(const wxString& hint){
firm_up_hint = hint;
}
void ConfirmHintDialog::OnPaint(wxPaintEvent& event){
wxPaintDC dc(this);
render(dc);
}
void ConfirmHintDialog::render(wxDC& dc) {
wxSize size = GetSize();
dc.SetFont(Label::Body_14);
dc.SetTextForeground(text_color);
wxPoint pos_start = wxPoint(FromDIP(25), FromDIP(25));
wxSize firm_up_hint_size = dc.GetTextExtent(firm_up_hint);
wxPoint pos_firm_up_hint = pos_start;
if (firm_up_hint_size.x + pos_firm_up_hint.x + FromDIP(25) > wxSize(FromDIP(475), FromDIP(100)).x) {
bool is_ch = false;
if (firm_up_hint[0] > 0x80 && firm_up_hint[1] > 0x80)
is_ch = true;
wxString fisrt_line;
wxString remaining_line;
wxString count_txt;
int new_line_pos = 0;
for (int i = 0; i < firm_up_hint.length(); i++) {
count_txt += firm_up_hint[i];
auto text_size = dc.GetTextExtent(count_txt);
if (text_size.x + pos_firm_up_hint.x + FromDIP(25) < wxSize(FromDIP(475), FromDIP(100)).x)
{
if (firm_up_hint[i] == ' ' || firm_up_hint[i] == '\n')
new_line_pos = i;
}
else {
if (!is_ch) {
fisrt_line = firm_up_hint.SubString(0, new_line_pos);
remaining_line = firm_up_hint.SubString(new_line_pos + 1, firm_up_hint.length());
break;
}
else {
fisrt_line = firm_up_hint.SubString(0, i);
remaining_line = firm_up_hint.SubString(i, firm_up_hint.length());
break;
}
count_txt = "";
}
}
dc.DrawText(fisrt_line, pos_firm_up_hint);
count_txt = "";
new_line_pos = 0;
for (int i = 0; i < remaining_line.length(); i++) {
count_txt += remaining_line[i];
auto text_size = dc.GetTextExtent(count_txt);
if (text_size.x + FromDIP(25) + FromDIP(25) < wxSize(FromDIP(475), FromDIP(100)).x)
{
if (remaining_line[i] == ' ' || remaining_line[i] == '\n')
new_line_pos = i;
}
else {
if (!is_ch){
remaining_line[new_line_pos] = '\n';
}
else {
remaining_line.insert(i, '\n');
}
count_txt = "";
}
}
wxPoint pos_txt = pos_firm_up_hint;
pos_txt.y += dc.GetCharHeight();
dc.DrawText(remaining_line, pos_txt);
}
else
dc.DrawText(firm_up_hint, pos_firm_up_hint);
}
void ConfirmHintDialog::on_button_confirm(wxCommandEvent& event) {
wxCommandEvent evt(EVT_CONFIRM_HINT, GetId());
event.SetEventObject(this);
GetEventHandler()->ProcessEvent(evt);
if (this->IsModal())
this->EndModal(wxID_OK);
else
this->Close();
}
void ConfirmHintDialog::on_button_close(wxCommandEvent& event) {
this->Close();
}
void ConfirmHintDialog::on_dpi_changed(const wxRect& suggested_rect) {
m_button_confirm->SetMinSize(wxSize(-1, FromDIP(24)));
m_button_confirm->SetCornerRadius(FromDIP(12));
m_button_close->SetMinSize(wxSize(-1, FromDIP(24)));
m_button_close->SetCornerRadius(FromDIP(12));
Layout();
}
}} // namespace Slic3r::GUI

View file

@ -0,0 +1,45 @@
#ifndef slic3r_GUI_ConfirmHintDialog_hpp_
#define slic3r_GUI_ConfirmHintDialog_hpp_
#include "GUI_Utils.hpp"
#include <wx/statbmp.h>
#include "Widgets/Button.hpp"
#include <wx/stattext.h>
namespace Slic3r { namespace GUI {
wxDECLARE_EVENT(EVT_CONFIRM_HINT, wxCommandEvent);
class ConfirmHintDialog : public DPIDialog
{
private:
wxStaticText* m_staticText_hint;
Button* m_button_confirm;
Button* m_button_close;
wxStaticBitmap* m_bitmap_home;
ScalableBitmap m_home_bmp;
wxString firm_up_hint = "";
void OnPaint(wxPaintEvent& event);
void render(wxDC& dc);
void on_button_confirm(wxCommandEvent& event);
void on_button_close(wxCommandEvent& event);
void on_dpi_changed(const wxRect& suggested_rect) override;
public:
ConfirmHintDialog(wxWindow* parent,
wxWindowID id = wxID_ANY,
const wxString& title = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxCLOSE_BOX | wxCAPTION);
const wxColour text_color = wxColour(107, 107, 107);
void SetHint(const wxString &hint);
~ConfirmHintDialog();
};
}} // namespace Slic3r::GUI
#endif

View file

@ -5,9 +5,6 @@
#include "slic3r/Utils/ColorSpaceConvert.hpp"
#include "GUI_App.hpp"
#include "libslic3r/PlaceholderParser.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "MsgDialog.hpp"
#include "Plater.hpp"
#include "GUI_App.hpp"
@ -47,6 +44,10 @@ std::string PRINTING_STAGE_STR[PRINTING_STAGE_COUNT] = {
"extruder_absolute_flow_cali"
};
wxString get_stage_string(int stage)
{
switch(stage) {
@ -665,9 +666,11 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std
}
}
// is_support_ams_mapping
if (!is_support_ams_mapping()) {
BOOST_LOG_TRIVIAL(info) << "ams_mapping: do not support, use order mapping";
result.clear();
for (int i = 0; i < filaments.size(); i++) {
FilamentInfo info;
info.id = filaments[i].id;
@ -1162,7 +1165,7 @@ int MachineObject::command_request_push_all()
int MachineObject::command_upgrade_confirm()
{
BOOST_LOG_TRIVIAL(trace) << "command_upgrade_confirm";
BOOST_LOG_TRIVIAL(info) << "command_upgrade_confirm";
json j;
j["upgrade"]["command"] = "upgrade_confirm";
j["upgrade"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
@ -1170,6 +1173,16 @@ int MachineObject::command_upgrade_confirm()
return this->publish_json(j.dump());
}
int MachineObject::command_consistency_upgrade_confirm()
{
BOOST_LOG_TRIVIAL(info) << "command_consistency_upgrade_confirm";
json j;
j["upgrade"]["command"] = "consistency_confirm";
j["upgrade"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
j["upgrade"]["src_id"] = 1; // 1 for slicer
return this->publish_json(j.dump());
}
int MachineObject::command_upgrade_firmware(FirmwareInfo info)
{
std::string version = info.version;
@ -1258,55 +1271,23 @@ int MachineObject::command_ams_switch(int tray_index, int old_temp, int new_temp
int tray_id_int = tray_index;
std::string gcode = "";
Slic3r::Print & print = Slic3r::GUI::wxGetApp().plater()->get_partplate_list().get_current_fff_print();
const PrintConfig &print_config = print.config();
if (tray_index == 255) {
// unload gcode
gcode = "M620 S255\nM104 S250\nG28 X\nG91\nG1 Z3.0 F1200\nG90\n"
"G1 X70 F12000\nG1 Y245\nG1 Y265 F3000\nM109 S250\nG1 X120 F12000\n"
"G1 X20 Y50 F12000\nG1 Y-3\nT255\nM104 S25\nG1 X165 F5000\nG1 Y245\n"
"G91\nG1 Z-3.0 F1200\nG90\nM621 S255\n";
} else {
// load gcode
gcode = "M620 S[next_extruder]\nM104 S250\nG28 X\nG91\n\nG1 Z3.0 F1200\nG90\n"
"G1 X70 F12000\nG1 Y245\nG1 Y265 F3000\nM109 S250\nG1 X120 F12000\nG1 X20 Y50 F12000\nG1 Y-3"
"\nT[next_extruder]\nG1 X54 F12000\nG1 Y265\nM400\nM106 P1 S0\nG92 E0\nG1 E40 F200\nM400"
"\nM109 S[new_filament_temp]\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM400\nM106 P1 S0\nG1 X70 F9000"
"\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000\nG1 X70 F6000\nG1 X100 F5000\nG1 X70 F15000"
"\nG1 X100 F5000\nG1 X70 F15000\nG1 X165 F5000\nG1 Y245\nG91\nG1 Z-3.0 F1200\nG90\nM621 S[next_extruder]\n";
PlaceholderParser m_placeholder_parser;
m_placeholder_parser = print.placeholder_parser();
PlaceholderParser::ContextData m_placeholder_parser_context;
DynamicConfig dyn_config;
int old_filament_temp = old_temp;
int new_filament_temp = new_temp;
old_filament_temp = correct_filament_temperature(old_filament_temp);
new_filament_temp = correct_filament_temperature(new_filament_temp);
dyn_config.set_key_value("previous_extruder", new ConfigOptionInt(-1));
dyn_config.set_key_value("next_extruder", new ConfigOptionInt(tray_id_int));
dyn_config.set_key_value("layer_num", new ConfigOptionInt(0));
dyn_config.set_key_value("layer_z", new ConfigOptionFloat(0.3));
dyn_config.set_key_value("max_layer_z", new ConfigOptionFloat(10.));
dyn_config.set_key_value("relative_e_axis", new ConfigOptionBool(RELATIVE_E_AXIS));
dyn_config.set_key_value("toolchange_count", new ConfigOptionInt(1));
dyn_config.set_key_value("fan_speed", new ConfigOptionInt(0));
dyn_config.set_key_value("old_retract_length", new ConfigOptionFloat(2.));
dyn_config.set_key_value("new_retract_length", new ConfigOptionFloat(2.));
dyn_config.set_key_value("old_retract_length_toolchange", new ConfigOptionFloat(3.0));
dyn_config.set_key_value("new_retract_length_toolchange", new ConfigOptionFloat(3.0));
dyn_config.set_key_value("old_filament_temp", new ConfigOptionInt(old_filament_temp));
dyn_config.set_key_value("new_filament_temp", new ConfigOptionInt(new_filament_temp));
dyn_config.set_key_value("x_after_toolchange", new ConfigOptionFloat(50.));
dyn_config.set_key_value("y_after_toolchange", new ConfigOptionFloat(50.));
dyn_config.set_key_value("z_after_toolchange", new ConfigOptionFloat(10.));
dyn_config.set_key_value("flush_length_1", new ConfigOptionFloat(5.f));
dyn_config.set_key_value("flush_length_2", new ConfigOptionFloat(5.f));
dyn_config.set_key_value("flush_length_3", new ConfigOptionFloat(0.f));
dyn_config.set_key_value("flush_length_4", new ConfigOptionFloat(0.f));
dyn_config.set_key_value("old_filament_e_feedrate", new ConfigOptionInt(100));
dyn_config.set_key_value("new_filament_e_feedrate", new ConfigOptionInt(100));
try {
std::string parsed_command = m_placeholder_parser.process(print_config.change_filament_gcode.value, tray_id_int, &dyn_config, &m_placeholder_parser_context);
// config xyz coordinate mode
std::string auto_home_command = "G28 X\n";
parsed_command = "G90\n" + auto_home_command + parsed_command;
std::regex match_pattern(";.*\n");
std::string replace_pattern = "\n";
char result[1024] = {0};
std::regex_replace(result, parsed_command.begin(), parsed_command.end(), match_pattern, replace_pattern);
result[1023] = 0;
gcode = std::string(result);
} catch (Exception &e) {
BOOST_LOG_TRIVIAL(trace) << "exception, e=" << e.what();
return -1;
boost::replace_all(gcode, "[next_extruder]", std::to_string(tray_index));
boost::replace_all(gcode, "[new_filament_temp]", std::to_string(new_temp));
}
return this->publish_gcode(gcode);
@ -1723,6 +1704,18 @@ bool MachineObject::is_function_supported(PrinterFunction func)
case FUNC_CHAMBER_TEMP:
func_name = "FUNC_CHAMBER_TEMP";
break;
case FUNC_CAMERA_VIDEO:
func_name = "FUNC_CAMERA_VIDEO";
break;
case FUNC_MEDIA_FILE:
func_name = "FUNC_MEDIA_FILE";
break;
case FUNC_REMOTE_TUNNEL:
func_name = "FUNC_REMOTE_TUNNEL";
break;
case FUNC_LOCAL_TUNNEL:
func_name = "FUNC_LOCAL_TUNNEL";
break;
default:
return true;
}

View file

@ -65,6 +65,10 @@ enum PrinterFunction {
FUNC_FLOW_CALIBRATION,
FUNC_AUTO_LEVELING,
FUNC_CHAMBER_TEMP,
FUNC_CAMERA_VIDEO,
FUNC_MEDIA_FILE,
FUNC_REMOTE_TUNNEL,
FUNC_LOCAL_TUNNEL,
FUNC_MAX
};
@ -534,6 +538,7 @@ public:
/* command upgrade */
int command_upgrade_confirm();
int command_consistency_upgrade_confirm();
int command_upgrade_firmware(FirmwareInfo info);
/* control apis */

View file

@ -224,9 +224,19 @@ static wxString na_value() { return _(L("N/A")); }
void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true*/)
{
switch (m_opt.type) {
case coInt:
m_value = wxAtoi(str);
break;
case coInt: {
long val = 0;
if (!str.ToLong(&val)) {
if (!check_value) {
m_value.clear();
break;
}
show_error(m_parent, _(L("Invalid numeric.")));
set_value(int(val), true);
}
m_value = int(val);
break;
}
case coPercent:
case coPercents:
case coFloats:

View file

@ -302,7 +302,7 @@ void GCodeViewer::SequentialView::Marker::set_world_position(const Vec3f& positi
}
//BBS: GUI refactor: add canvas size from parameters
void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_height) const
void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_height, const EViewType& view_type, const std::vector<GCodeProcessorResult::MoveVertex>& moves, uint64_t curr_line_id) const
{
if (!m_visible)
return;
@ -330,43 +330,109 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he
static float last_window_width = 0.0f;
static size_t last_text_length = 0;
static const ImU32 text_name_clr = IM_COL32(38, 46, 48, 255);
static const ImU32 text_value_clr = IM_COL32(144, 144, 144, 255);
static const ImU32 window_bg_clr = IM_COL32(255, 255, 255, 255);
if (wxGetApp().get_mode() == ConfigOptionMode::comDevelop) {
ImGuiWrapper& imgui = *wxGetApp().imgui();
//BBS: GUI refactor: add canvas size from parameters
//Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
//imgui.set_next_window_pos(0.5f * static_cast<float>(cnv_size.get_width()), static_cast<float>(cnv_size.get_height()), ImGuiCond_Always, 0.5f, 1.0f);
imgui.set_next_window_pos(0.5f * static_cast<float>(canvas_width), static_cast<float>(canvas_height), ImGuiCond_Always, 0.5f, 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::SetNextWindowBgAlpha(0.25f);
imgui.begin(std::string("ExtruderPosition"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove);
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Extruder position") + ":");
ImGui::SameLine();
char buf[1024];
//BBS: minus the plate offset when show tool position
PartPlateList& partplate_list = wxGetApp().plater()->get_partplate_list();
PartPlate* plate = partplate_list.get_curr_plate();
const Vec3f position = m_world_position + m_world_offset;
sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x() - plate->get_origin().x(), position.y() - plate->get_origin().y(), position.z());
imgui.text(std::string(buf));
ImGuiWrapper& imgui = *wxGetApp().imgui();
//BBS: GUI refactor: add canvas size from parameters
imgui.set_next_window_pos(0.5f * static_cast<float>(canvas_width), static_cast<float>(canvas_height), ImGuiCond_Always, 0.5f, 1.0f);
imgui.push_toolbar_style(m_scale);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0, 4.0 * m_scale));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0 * m_scale, 6.0 * m_scale));
ImGui::PushStyleColor(ImGuiCol_WindowBg, window_bg_clr);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, text_name_clr);
ImGui::PushStyleColor(ImGuiCol_Text, text_value_clr);
imgui.begin(std::string("ExtruderPosition"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar);
ImGui::AlignTextToFramePadding();
//BBS: minus the plate offset when show tool position
PartPlateList& partplate_list = wxGetApp().plater()->get_partplate_list();
PartPlate* plate = partplate_list.get_curr_plate();
const Vec3f position = m_world_position + m_world_offset;
std::string x = ImGui::ColorMarkerStart + std::string("X: ") + ImGui::ColorMarkerEnd;
std::string y = ImGui::ColorMarkerStart + std::string("Y: ") + ImGui::ColorMarkerEnd;
std::string z = ImGui::ColorMarkerStart + std::string("Z: ") + ImGui::ColorMarkerEnd;
std::string speed = ImGui::ColorMarkerStart + _u8L("Speed: ") + ImGui::ColorMarkerEnd;
std::string flow = ImGui::ColorMarkerStart + _u8L("Flow: ") + ImGui::ColorMarkerEnd;
// force extra frame to automatically update window size
float width = ImGui::GetWindowWidth();
size_t length = strlen(buf);
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
std::ostringstream buffer;
char buf[1024];
if (view_type == EViewType::Feedrate) {
auto it = std::find_if(moves.begin(), moves.end(), [&curr_line_id](auto move) {
if (move.gcode_id == curr_line_id)
return true;
else
return false;
});
if (it != moves.end()) {
sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x());
imgui.text(buf);
ImGui::SameLine();
sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y());
imgui.text(buf);
sprintf(buf, "%s%.3f", z.c_str(), position.z());
imgui.text(buf);
ImGui::SameLine();
sprintf(buf, "%s%.f", speed.c_str(), it->feedrate);
imgui.text(buf);
}
imgui.end();
ImGui::PopStyleVar();
}
else if (view_type == EViewType::VolumetricRate) {
auto it = std::find_if(moves.begin(), moves.end(), [&curr_line_id](auto move) {
if (move.gcode_id == curr_line_id)
return true;
else
return false;
});
if (it != moves.end()) {
sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x());
imgui.text(buf);
ImGui::SameLine();
sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y());
imgui.text(buf);
sprintf(buf, "%s%.3f", z.c_str(), position.z());
imgui.text(buf);
ImGui::SameLine();
sprintf(buf, "%s%.f", flow.c_str(), it->volumetric_rate());
imgui.text(buf);
}
}
else {
sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x());
imgui.text(buf);
ImGui::SameLine();
sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y());
imgui.text(buf);
ImGui::SameLine();
sprintf(buf, "%s%.3f", z.c_str() , position.z());
imgui.text(buf);
}
// force extra frame to automatically update window size
float width = ImGui::GetWindowWidth();
//size_t length = strlen(buf);
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();
imgui.pop_toolbar_style();
ImGui::PopStyleVar(2);
ImGui::PopStyleColor(3);
}
void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& filename, std::vector<size_t> &&lines_ends)
@ -561,11 +627,10 @@ void GCodeViewer::SequentialView::GCodeWindow::stop_mapping_file()
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": finished mapping file " << m_filename;
}
}
//BBS: GUI refactor: move to the right
void GCodeViewer::SequentialView::render(float legend_height, int canvas_width, int canvas_height) const
void GCodeViewer::SequentialView::render(float legend_height, int canvas_width, int canvas_height, const EViewType& view_type, const std::vector<GCodeProcessorResult::MoveVertex>& moves) const
{
marker.render(canvas_width, canvas_height);
marker.render(canvas_width, canvas_height, view_type, moves, static_cast<uint64_t>(gcode_ids[current.last]));
//float bottom = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_height();
// BBS
#if 0
@ -766,6 +831,10 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle)
void GCodeViewer::set_scale(float scale)
{
if(m_scale != scale)m_scale = scale;
if (m_sequential_view.m_scale != scale) {
m_sequential_view.m_scale = scale;
m_sequential_view.marker.m_scale = scale;
}
}
void GCodeViewer::update_by_mode(ConfigOptionMode mode)
@ -804,6 +873,11 @@ void GCodeViewer::update_by_mode(ConfigOptionMode mode)
}
}
std::vector<int> GCodeViewer::get_plater_extruder()
{
return m_plater_extruder;
}
//BBS: always load shell at preview
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, const BuildVolume& build_volume,
const std::vector<BoundingBoxf3>& exclude_bounding_box, bool initialized, ConfigOptionMode mode, bool only_gcode)
@ -1125,7 +1199,7 @@ void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin)
m_sequential_view.marker.set_world_position(m_sequential_view.current_position);
m_sequential_view.marker.set_world_offset(m_sequential_view.current_offset);
//BBS fixed buttom margin. m_moves_slider.pos_y
m_sequential_view.render(legend_height, canvas_width - right_margin, canvas_height - bottom_margin);
m_sequential_view.render(legend_height, canvas_width - right_margin * m_scale, canvas_height - bottom_margin * m_scale, m_view_type, m_gcode_result->moves);
//}
#if ENABLE_GCODE_VIEWER_STATISTICS
render_statistics();
@ -2897,6 +2971,14 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const
sort_remove_duplicates(m_extruder_ids);
m_extruder_ids.shrink_to_fit();
std::vector<int> plater_extruder;
for (auto mid : m_extruder_ids){
int eid = mid;
plater_extruder.push_back(++eid);
}
m_plater_extruder = plater_extruder;
// set layers z range
if (!m_layers.empty())
m_layers_z_range = { 0, static_cast<unsigned int>(m_layers.size() - 1) };
@ -4122,7 +4204,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
}
else {
imgui.text(label);
/* BBS refactor do not show used_filament info
// BBS refactor do not show used_filament info
if (used_filament_m > 0.0) {
char buf[64];
ImGui::SameLine(offsets[0]);
@ -4131,7 +4213,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
ImGui::SameLine(offsets[1]);
::sprintf(buf, "%.2f g", used_filament_g);
imgui.text(buf);
}*/
}
}
ImGui::PopStyleVar(1);
@ -4318,6 +4400,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
std::vector<float> percents;
std::vector<double> used_filaments_m;
std::vector<double> used_filaments_g;
double total_flushed_filament_m = 0.0;
double total_flushed_filament_g = 0.0;
float max_percent = 0.0f;
@ -4418,19 +4502,31 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
used_filaments_g.push_back(used_filament_g);
}
for (size_t extruder_id : m_extruder_ids) {
if (m_print_statistics.flush_per_filament.find(extruder_id) == m_print_statistics.flush_per_filament.end()) continue;
double volume = m_print_statistics.flush_per_filament.at(extruder_id);
auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, extruder_id);
total_flushed_filament_m += flushed_filament_m;
total_flushed_filament_g += flushed_filament_g;
}
std::string longest_used_filament_string;
char buffer[64];
for (double item : used_filaments_m) {
char buffer[64];
::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", item);
if (::strlen(buffer) > longest_used_filament_string.length()) longest_used_filament_string = buffer;
}
::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", total_flushed_filament_m);
if (::strlen(buffer) > longest_used_filament_string.length()) longest_used_filament_string = buffer;
std::string longest_used_filament_g_string;
for (double item : used_filaments_g) {
char buffer[64];
::sprintf(buffer, imperial_units ? "%.2fg" : "%.2fg", item);
::sprintf(buffer, imperial_units ? "%.2f g" : "%.2f g", item);
if (::strlen(buffer) > longest_used_filament_g_string.length()) longest_used_filament_g_string = buffer;
}
::sprintf(buffer, imperial_units ? "%.2f g" : "%.2f g", total_flushed_filament_g);
if (::strlen(buffer) > longest_used_filament_g_string.length()) longest_used_filament_g_string = buffer;
// BBL XX is placeholder
offsets = calculate_offsets(labels, times, {_u8L("Filament N XX"), longest_used_filament_string, longest_used_filament_g_string, _u8L("Display")}, icon_size);
append_headers({ _u8L("Color Print"), _u8L("Comsumption"), "", "", _u8L("Display") }, offsets);
@ -4608,34 +4704,36 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
//BBS display filament change times
if (m_print_statistics.total_filamentchanges > 0) {
std::string flushed_filament_title_str = _u8L("Flushed filament");
std::string flushed_filament_str = _u8L("Filament");
std::string total_flushed_filament_str = _u8L("Total");
std::string filament_change_str = _u8L("Filament change times");
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
ImGui::Dummy({ window_padding, window_padding });
ImGui::SameLine();
imgui.title(flushed_filament_title_str);
//BBS: calculate total flushed filaments data
double total_flushed_filament_m = 0.0;
double total_flushed_filament_g = 0.0;
float max_len = 10.0f + ImGui::GetStyle().ItemSpacing.x;
max_len += ImGui::CalcTextSize(filament_change_str.c_str()).x;
for (size_t extruder_id : m_extruder_ids) {
if (m_print_statistics.flush_per_filament.find(extruder_id) == m_print_statistics.flush_per_filament.end())
continue;
if (m_print_statistics.flush_per_filament.find(extruder_id) == m_print_statistics.flush_per_filament.end()) continue;
double volume = m_print_statistics.flush_per_filament.at(extruder_id);
auto [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
total_flushed_filament_m += used_filament_m;
total_flushed_filament_g += used_filament_g;
append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_id], flushed_filament_str + " " + std::to_string(extruder_id + 1), true, "", 0.0f, 0.0f, offsets,
used_filament_m, used_filament_g);
}
std::string flushed_filament_str = _u8L("Flushed filament");
std::string filament_change_str = _u8L("Filament change times");
float max_len = 10.0f + ImGui::GetStyle().ItemSpacing.x;
max_len += std::max(ImGui::CalcTextSize(filament_change_str.c_str()).x, ImGui::CalcTextSize(flushed_filament_str.c_str()).x);
//BBS: display total flushed filament
{
ImGui::Dummy({window_padding, window_padding});
ImGui::SameLine();
imgui.text(flushed_filament_str + ":");
ImGui::SameLine(max_len);
imgui.text(total_flushed_filament_str + ":");
ImGui::SameLine(offsets[0]);
char buf[64];
::sprintf(buf, "%.2f m", total_flushed_filament_m);
imgui.text(buf);
ImGui::SameLine();
::sprintf(buf, " %.2f g", total_flushed_filament_g);
ImGui::SameLine(offsets[1]);
::sprintf(buf, "%.2f g", total_flushed_filament_g);
imgui.text(buf);
}
//BBS display filament change times
@ -4645,7 +4743,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
imgui.text(filament_change_str + ":");
ImGui::SameLine(max_len);
char temp_buf[64];
::sprintf(temp_buf, " %d", m_print_statistics.total_filamentchanges);
::sprintf(temp_buf, "%d", m_print_statistics.total_filamentchanges);
imgui.text(temp_buf);
}
}

View file

@ -600,6 +600,7 @@ class GCodeViewer
#endif // ENABLE_GCODE_VIEWER_STATISTICS
public:
enum class EViewType : unsigned char;
struct SequentialView
{
class Marker
@ -615,6 +616,8 @@ public:
bool m_visible{ true };
public:
float m_scale = 1.0f;
void init(std::string filename);
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
@ -626,7 +629,7 @@ public:
void set_visible(bool visible) { m_visible = visible; }
//BBS: GUI refactor: add canvas size
void render(int canvas_width, int canvas_height) const;
void render(int canvas_width, int canvas_height, const EViewType& view_type, const std::vector<GCodeProcessorResult::MoveVertex>& moves, uint64_t curr_line_id) const;
};
class GCodeWindow
@ -683,9 +686,10 @@ public:
Marker marker;
GCodeWindow gcode_window;
std::vector<unsigned int> gcode_ids;
float m_scale = 1.0;
//BBS: GUI refactor: add canvas size
void render(float legend_height, int canvas_width, int canvas_height) const;
void render(float legend_height, int canvas_width, int canvas_height, const EViewType& view_type, const std::vector<GCodeProcessorResult::MoveVertex>& moves) const;
};
struct ETools
@ -710,6 +714,7 @@ public:
};
private:
std::vector<int> m_plater_extruder;
bool m_gl_data_initialized{ false };
unsigned int m_last_result_id{ 0 };
size_t m_moves_count{ 0 };
@ -799,6 +804,7 @@ public:
bool has_data() const { return !m_roles.empty(); }
bool can_export_toolpaths() const;
std::vector<int> get_plater_extruder();
const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }

View file

@ -3889,6 +3889,14 @@ void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_typ
do_rotate(""); // avoid taking another snapshot
}
void GLCanvas3D::do_center()
{
if (m_model == nullptr)
return;
m_selection.center();
}
void GLCanvas3D::do_mirror(const std::string& snapshot_type)
{
if (m_model == nullptr)
@ -4074,15 +4082,15 @@ double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const
}
//BBS
std::vector<Vec2f> GLCanvas3D::get_empty_cells(const Vec2f start_point)
std::vector<Vec2f> GLCanvas3D::get_empty_cells(const Vec2f start_point, const Vec2f step)
{
PartPlate* plate = wxGetApp().plater()->get_partplate_list().get_curr_plate();
BoundingBoxf3 build_volume = plate->get_build_volume();
Vec2d vmin(build_volume.min.x(), build_volume.min.y()), vmax(build_volume.max.x(), build_volume.max.y());
BoundingBoxf bbox(vmin, vmax);
std::vector<Vec2f> cells;
for (float x = bbox.min.x(); x < bbox.max.x(); x+=10)
for (float y = bbox.min.y(); y < bbox.max.y(); y += 10)
for (float x = bbox.min.x(); x < bbox.max.x(); x += step(0))
for (float y = bbox.min.y(); y < bbox.max.y(); y += step(1))
{
cells.emplace_back(x, y);
}
@ -4124,9 +4132,9 @@ std::vector<Vec2f> GLCanvas3D::get_empty_cells(const Vec2f start_point)
return cells;
}
Vec2f GLCanvas3D::get_nearest_empty_cell(const Vec2f start_point)
Vec2f GLCanvas3D::get_nearest_empty_cell(const Vec2f start_point, const Vec2f step)
{
std::vector<Vec2f> empty_cells = get_empty_cells(start_point);
std::vector<Vec2f> empty_cells = get_empty_cells(start_point, step);
if (!empty_cells.empty())
return empty_cells.front();
else {

View file

@ -357,8 +357,7 @@ public:
struct ArrangeSettings
{
float distance = 1.;
// float distance_seq_print = 6.; // Used when sequential print is ON
float distance = 5.;
// float distance_sla = 6.;
float accuracy = 0.65f; // Unused currently
bool enable_rotation = false;
@ -784,6 +783,7 @@ public:
void do_rotate(const std::string& snapshot_type);
void do_scale(const std::string& snapshot_type);
void do_flatten(const Vec3d& normal, const std::string& snapshot_type);
void do_center();
void do_mirror(const std::string& snapshot_type);
void update_gizmos_on_off_state();
@ -831,11 +831,11 @@ public:
double get_size_proportional_to_max_bed_size(double factor) const;
// BBS: get empty cells to put new object
// start_point={-1,-1} means sort from bed center
std::vector<Vec2f> get_empty_cells(const Vec2f start_point);
// start_point={-1,-1} means sort from bed center, step is the unscaled x,y stride
std::vector<Vec2f> get_empty_cells(const Vec2f start_point, const Vec2f step = {10, 10});
// BBS: get the nearest empty cell
// start_point={-1,-1} means sort from bed center
Vec2f get_nearest_empty_cell(const Vec2f start_point);
Vec2f get_nearest_empty_cell(const Vec2f start_point, const Vec2f step = {10, 10});
void set_cursor(ECursorType type);
void msw_rescale();

View file

@ -771,7 +771,7 @@ 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 && OpenGLManager::use_manually_generated_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;
@ -800,8 +800,9 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
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 if (use_mipmaps && !OpenGLManager::use_manually_generated_mipmaps()) {
glGenerateMipmap(GL_TEXTURE_2D);
} else {
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
}

View file

@ -66,7 +66,7 @@
#include "SysInfoDialog.hpp"
#include "UpdateDialogs.hpp"
#include "Mouse3DController.hpp"
//#include "RemovableDriveManager.hpp"
#include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp"
#include "NotificationManager.hpp"
#include "UnsavedChangesDialog.hpp"
@ -1098,6 +1098,31 @@ void GUI_App::post_init()
std::string functional_config_file = Slic3r::resources_dir() + "/config.json";
DeviceManager::load_functional_config(encode_path(functional_config_file.c_str()));
// remove old log files over LOG_FILES_MAX_NUM
std::string log_addr = data_dir();
if (!log_addr.empty()) {
auto log_folder = boost::filesystem::path(log_addr) / "log";
if (boost::filesystem::exists(log_folder)) {
std::vector<std::pair<time_t, std::string>> files_vec;
for (auto& it : boost::filesystem::directory_iterator(log_folder)) {
auto temp_path = it.path();
std::time_t lw_t = boost::filesystem::last_write_time(temp_path) ;
files_vec.push_back({ lw_t, temp_path.filename().string() });
}
std::sort(files_vec.begin(), files_vec.end(), [](
std::pair<time_t, std::string> &a, std::pair<time_t, std::string> &b) {
return a.first > b.first;
});
while (files_vec.size() > LOG_FILES_MAX_NUM) {
auto full_path = log_folder / boost::filesystem::path(files_vec[files_vec.size() - 1].second);
BOOST_LOG_TRIVIAL(info) << "delete log file over " << LOG_FILES_MAX_NUM << ", filename: "<< files_vec[files_vec.size() - 1].second;
boost::filesystem::remove(full_path);
files_vec.pop_back();
}
}
}
BOOST_LOG_TRIVIAL(info) << "finished post_init";
//BBS: remove the single instance currently
/*#ifdef _WIN32
@ -1121,7 +1146,7 @@ GUI_App::GUI_App()
, m_em_unit(10)
, m_imgui(new ImGuiWrapper())
, hms_query(new HMSQuery())
//, m_removable_drive_manager(std::make_unique<RemovableDriveManager>())
, m_removable_drive_manager(std::make_unique<RemovableDriveManager>())
//, m_other_instance_message_handler(std::make_unique<OtherInstanceMessageHandler>())
{
//app config initializes early becasuse it is used in instance checking in BambuStudio.cpp
@ -1134,6 +1159,10 @@ void GUI_App::shutdown()
{
BOOST_LOG_TRIVIAL(info) << "shutdown";
if (m_removable_drive_manager) {
removable_drive_manager()->shutdown();
}
if (m_is_recreating_gui) return;
m_is_closing = true;
stop_sync_user_preset();
@ -1343,7 +1372,10 @@ int GUI_App::install_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
BOOST_LOG_TRIVIAL(info) << "[install_plugin] enter";
// get plugin folder
auto plugin_folder = boost::filesystem::path(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()) / "plugins";
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto plugin_folder = data_dir_path / "plugins";
//auto plugin_folder = boost::filesystem::path(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()) / "plugins";
auto backup_folder = plugin_folder/"backup";
if (!boost::filesystem::exists(plugin_folder)) {
BOOST_LOG_TRIVIAL(info) << "[install_plugin] will create directory "<<plugin_folder.string();
@ -1486,7 +1518,10 @@ void GUI_App::restart_networking()
void GUI_App::remove_old_networking_plugins()
{
auto plugin_folder = boost::filesystem::path(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()) / "plugins";
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto plugin_folder = data_dir_path / "plugins";
//auto plugin_folder = boost::filesystem::path(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()) / "plugins";
if (boost::filesystem::exists(plugin_folder)) {
BOOST_LOG_TRIVIAL(info) << "[remove_old_networking_plugins] remove the directory "<<plugin_folder.string();
try {
@ -1643,12 +1678,9 @@ void GUI_App::init_networking_callbacks()
if (obj) {
obj->parse_json(msg);
#if !BBL_RELEASE_TO_PUBLIC
if (obj->is_ams_need_update) {
GUI::wxGetApp().sidebar().load_ams_list(obj->amsList);
}
#endif
}
});
};
@ -2024,8 +2056,8 @@ bool GUI_App::on_init_inner()
if (!skip_this_version
|| evt.GetInt() != 0) {
UpdateVersionDialog dialog(this->mainframe);
wxString extmsg = wxString::FromUTF8(version_info.description);
dialog.update_version_info(extmsg, version_info.version_str);
//dialog.update_version_info(extmsg, version_info.version_str);
dialog.update_version_info(version_info.description);
if (evt.GetInt() != 0) {
dialog.m_remind_choice->Hide();
}
@ -2235,11 +2267,11 @@ bool GUI_App::on_init_inner()
// An ugly solution to GH #5537 in which GUI_App::init_opengl (normally called from events wxEVT_PAINT
// and wxEVT_SET_FOCUS before GUI_App::post_init is called) wasn't called before GUI_App::post_init and OpenGL wasn't initialized.
#ifdef __linux__
if (!m_post_initialized && m_opengl_initialized) {
#else
//#ifdef __linux__
// if (!m_post_initialized && m_opengl_initialized) {
//#else
if (!m_post_initialized) {
#endif
//#endif
m_post_initialized = true;
#ifdef WIN32
this->mainframe->register_win32_callbacks();
@ -2306,11 +2338,12 @@ __retry:
m_device_manager = new Slic3r::DeviceManager(m_agent);
else
m_device_manager->set_agent(m_agent);
std::string data_dir = wxStandardPaths::Get().GetUserDataDir().ToUTF8().data();
//std::string data_dir = wxStandardPaths::Get().GetUserDataDir().ToUTF8().data();
std::string data_directory = data_dir();
//BBS set config dir
if (m_agent) {
m_agent->set_config_dir(data_dir);
m_agent->set_config_dir(data_directory);
}
//BBS set cert dir
if (m_agent)
@ -4007,7 +4040,7 @@ bool GUI_App::load_language(wxString language, bool initial)
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
//wxSetlocale(LC_NUMERIC, "C");
Preset::update_suffix_modified((" (" + _L("*") + ")").ToUTF8().data());
Preset::update_suffix_modified((_L("*") + " ").ToUTF8().data());
return true;
}

View file

@ -28,6 +28,7 @@
#define BBL_HAS_FIRST_PAGE 1
#define STUDIO_INACTIVE_TIMEOUT 15*60*1000
#define LOG_FILES_MAX_NUM 30
class wxMenuItem;
class wxMenuBar;
@ -52,7 +53,7 @@ class NetworkAgent;
namespace GUI{
//class RemovableDriveManager;
class RemovableDriveManager;
class OtherInstanceMessageHandler;
class MainFrame;
class Sidebar;
@ -247,7 +248,7 @@ private:
const wxLanguageInfo *m_language_info_best = nullptr;
OpenGLManager m_opengl_mgr;
//std::unique_ptr<RemovableDriveManager> m_removable_drive_manager;
std::unique_ptr<RemovableDriveManager> m_removable_drive_manager;
std::unique_ptr<ImGuiWrapper> m_imgui;
std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue;
@ -484,7 +485,7 @@ public:
std::vector<Tab *> tabs_list;
std::vector<Tab *> model_tabs_list;
//RemovableDriveManager* removable_drive_manager() { return m_removable_drive_manager.get(); }
RemovableDriveManager* removable_drive_manager() { return m_removable_drive_manager.get(); }
//OtherInstanceMessageHandler* other_instance_message_handler() { return m_other_instance_message_handler.get(); }
//wxSingleInstanceChecker* single_instance_checker() {return m_single_instance_checker.get();}

View file

@ -55,7 +55,7 @@ static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF =
{ L("Infill") , { "sparse_infill_density", "sparse_infill_pattern" } },
// BBS
{ L("Support") , { "enable_support", "support_type", "support_threshold_angle",
"support_base_pattern", "support_on_build_plate_only",
"support_base_pattern", "support_on_build_plate_only","support_critical_regions_only",
"support_base_pattern_spacing" } }
//BBS
//{ L("Wipe options") , { "flush_into_infill", "flush_into_objects" } }
@ -81,7 +81,7 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::OBJECT_C
{"tree_support_branch_angle", "",10}, {"tree_support_wall_count", "",11},{"tree_support_with_infill", "",12},//tree support
{"support_top_z_distance", "",13},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15},
{"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19},
{"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22}
{"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23}
}},
{ L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13}
}}
@ -138,7 +138,7 @@ std::vector<SimpleSettingData> SettingsFactory::get_visible_options(const std::s
//Quality
"layer_height", "initial_layer_print_height", "adaptive_layer_height", "seam_position", "xy_hole_compensation", "xy_contour_compensation", "elefant_foot_compensation", "support_line_width",
//Support
"enable_support", "support_type", "support_threshold_angle", "support_on_build_plate_only", "enforce_support_layers",
"enable_support", "support_type", "support_threshold_angle", "support_on_build_plate_only", "support_critical_regions_only", "enforce_support_layers",
//tree support
"tree_support_wall_count", "tree_support_with_infill",
//support
@ -652,12 +652,18 @@ void MenuFactory::append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu)
void MenuFactory::append_menu_item_reload_from_disk(wxMenu* menu)
{
// BBS: change "Reload from disk" to "Reload item"
append_menu_item(menu, wxID_ANY, _L("Reload item"), _L("Reload items"),
append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected parts from disk"),
[](wxCommandEvent&) { plater()->reload_from_disk(); }, "", menu,
[]() { return plater()->can_reload_from_disk(); }, m_parent);
}
void MenuFactory::append_menu_item_replace_with_stl(wxMenu *menu)
{
append_menu_item(menu, wxID_ANY, _L("Replace with STL"), _L("Replace the selected part with new STL"),
[](wxCommandEvent &) { plater()->replace_with_stl(); }, "", menu,
[]() { return plater()->can_replace_with_stl(); }, m_parent);
}
void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
{
// BBS
@ -886,6 +892,8 @@ void MenuFactory::create_bbl_object_menu()
append_menu_item_fix_through_netfabb(&m_object_menu);
// Object Simplify
append_menu_item_simplify(&m_object_menu);
// Object Center
append_menu_item_center(&m_object_menu);
// Object Split
wxMenu* split_menu = new wxMenu();
if (!split_menu)
@ -915,6 +923,8 @@ void MenuFactory::create_bbl_object_menu()
// Enter per object parameters
append_menu_item_per_object_settings(&m_object_menu);
m_object_menu.AppendSeparator();
append_menu_item_reload_from_disk(&m_object_menu);
append_menu_item_replace_with_stl(&m_object_menu);
append_menu_item_export_stl(&m_object_menu);
}
@ -975,6 +985,7 @@ void MenuFactory::create_bbl_part_menu()
append_menu_item_delete(menu);
append_menu_item_fix_through_netfabb(menu);
append_menu_item_simplify(menu);
append_menu_item_center(menu);
append_menu_items_mirror(menu);
wxMenu* split_menu = new wxMenu();
if (!split_menu)
@ -992,6 +1003,8 @@ void MenuFactory::create_bbl_part_menu()
menu->AppendSeparator();
append_menu_item_per_object_settings(menu);
append_menu_item_change_type(menu);
append_menu_item_reload_from_disk(menu);
append_menu_item_replace_with_stl(menu);
}
void MenuFactory::create_bbl_assemble_part_menu()
@ -1172,6 +1185,7 @@ wxMenu* MenuFactory::multi_selection_menu()
append_menu_item_merge_to_multipart_object(menu);
index++;
}
append_menu_item_center(menu);
append_menu_item_fix_through_netfabb(menu);
//append_menu_item_simplify(menu);
append_menu_item_delete(menu);
@ -1186,6 +1200,7 @@ wxMenu* MenuFactory::multi_selection_menu()
append_menu_item_export_stl(menu, true);
}
else {
append_menu_item_center(menu);
append_menu_item_fix_through_netfabb(menu);
//append_menu_item_simplify(menu);
append_menu_item_delete(menu);
@ -1264,11 +1279,30 @@ void MenuFactory::append_menu_item_clone(wxMenu* menu)
void MenuFactory::append_menu_item_simplify(wxMenu* menu)
{
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Reduce Triangles"), "",
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Simplify Model"), "",
[](wxCommandEvent&) { obj_list()->simplify(); }, "", menu,
[]() {return plater()->can_simplify(); }, m_parent);
}
void MenuFactory::append_menu_item_center(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _L("Center") , "",
[this](wxCommandEvent&) {
plater()->center_selection();
}, "", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
else {
Selection& selection = plater()->get_view3D_canvas3D()->get_selection();
PartPlate* plate = plater()->get_partplate_list().get_selected_plate();
Vec3d model_pos = selection.get_bounding_box().center();
Vec3d center_pos = plate->get_center_origin();
return !( (model_pos.x() == center_pos.x()) && (model_pos.y() == center_pos.y()) );
} //disable if model is at center / not in View3D
}, m_parent);
}
void MenuFactory::append_menu_item_per_object_settings(wxMenu* menu)
{
const std::vector<wxString> names = { _L("Edit in Parameter Table"), _L("Edit print parameters for a single object") };
@ -1309,6 +1343,9 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
return;
std::vector<wxBitmap*> icons = get_extruder_color_icons(true);
if (icons.size() < filaments_cnt) {
BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%")%icons.size()%filaments_cnt;
}
wxMenu* extruder_selection_menu = new wxMenu();
const wxString& name = sels.Count() == 1 ? names[0] : names[1];

View file

@ -138,6 +138,7 @@ private:
//BBS add bbl menu item
void append_menu_item_clone(wxMenu* menu);
void append_menu_item_simplify(wxMenu* menu);
void append_menu_item_center(wxMenu* menu);
void append_menu_item_per_object_settings(wxMenu* menu);
void append_menu_item_change_filament(wxMenu* menu);
void append_menu_item_set_printable(wxMenu* menu);

View file

@ -3353,12 +3353,9 @@ void ObjectTableDialog::OnClose(wxCloseEvent &evt)
delete m_obj_panel;
m_obj_panel = nullptr;
}
DestroyChildren();
Destroy();
#endif
#ifdef __WXOSX_MAC__
#else
evt.Skip();
#endif
}

View file

@ -148,6 +148,12 @@ void View3D::delete_selected()
m_canvas->delete_selected();
}
void View3D::center_selected()
{
if (m_canvas != nullptr)
m_canvas->do_center();
}
void View3D::mirror_selection(Axis axis)
{
if (m_canvas != nullptr)

View file

@ -63,6 +63,7 @@ public:
void select_all();
void deselect_all();
void delete_selected();
void center_selected();
void mirror_selection(Axis axis);
bool is_dragging() const;

View file

@ -479,6 +479,13 @@ void GLGizmoAdvancedCut::on_render_input_window(float x, float y, float bottom_l
if (std::abs(m_buffered_movement - m_movement) > EPSILON) {
m_movement = m_buffered_movement;
m_buffered_movement = 0.0;
// update absolute height
Vec3d plane_normal = get_plane_normal();
m_height_delta = plane_normal(2) * m_movement;
m_height += m_height_delta;
m_buffered_height = m_height;
update_plane_points();
m_parent.post_event(SimpleEvent(wxEVT_PAINT));
}
@ -497,8 +504,7 @@ void GLGizmoAdvancedCut::on_render_input_window(float x, float y, float bottom_l
if (current_active_id != m_last_active_id) {
if (std::abs(m_buffered_height - m_height) > EPSILON) {
m_height_delta = m_buffered_height - m_height;
m_height = m_buffered_height;
//m_buffered_height = 0.0;
m_height = m_buffered_height;
update_plane_points();
m_parent.post_event(SimpleEvent(wxEVT_PAINT));
}

View file

@ -120,6 +120,16 @@ void GLGizmoScale3D::on_start_dragging()
void GLGizmoScale3D::on_update(const UpdateData& data)
{
bool uniform_scale = false;
AppConfig* config = wxGetApp().app_config;
if (config)
uniform_scale = config->get("uniform_scale") == "1" ? true : false;
if (uniform_scale) {
do_scale_uniform(data);
return;
}
if ((m_hover_id == 0) || (m_hover_id == 1))
do_scale_along_axis(X, data);
else if ((m_hover_id == 2) || (m_hover_id == 3))

View file

@ -569,7 +569,7 @@ void GLGizmoSimplify::apply_simplify() {
mv->calculate_convex_hull();
mv->set_new_unique_id();
mv->get_object()->invalidate_bounding_box();
mv->get_object()->ensure_on_bed(true); // allow negative z
mv->get_object()->ensure_on_bed();
// fix hollowing, sla support points, modifiers, ...
plater->changed_mesh(object_idx);

View file

@ -213,11 +213,6 @@ void GizmoObjectManipulation::update_if_dirty()
update(m_cache.rotation, m_cache.rotation_rounded, m_new_rotation);
}
if (selection.requires_uniform_scale()) {
m_uniform_scale = true;
}
update_reset_buttons_visibility();
//update_mirror_buttons_visibility();
@ -468,6 +463,9 @@ void GizmoObjectManipulation::set_uniform_scaling(const bool new_value)
}
}
m_uniform_scale = new_value;
AppConfig* config = wxGetApp().app_config;
if (config)
config->set("uniform_scale", new_value ? "1": "0");
}
static const char* label_values[2][3] = {
@ -899,6 +897,9 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
ImGui::Separator();
AppConfig* config = wxGetApp().app_config;
if (config)
this->m_uniform_scale = config->get("uniform_scale") == "1" ? true : false;
bool uniform_scale = this->m_uniform_scale;
const Selection &selection = m_glcanvas.get_selection();

View file

@ -81,6 +81,7 @@ public:
Vec3d m_buffered_size;
bool m_new_enabled {true};
bool m_uniform_scale {true};
bool m_uniform_config {false};
// Does the object manipulation panel work in World or Local coordinates?
bool m_world_coordinates = true;

View file

@ -150,9 +150,12 @@ wxString HMSQuery::query_hms_msg(std::string long_error_code)
if (m_hms_json.contains("device_hms")) {
if (m_hms_json["device_hms"].contains(lang_code)) {
for (auto item = m_hms_json["device_hms"][lang_code].begin(); item != m_hms_json["device_hms"][lang_code].end(); item++) {
if (item->contains("ecode") && (*item)["ecode"].get<std::string>() == long_error_code) {
if (item->contains("intro")) {
return wxString::FromUTF8((*item)["intro"].get<std::string>());
if (item->contains("ecode")) {
std::string temp_string = (*item)["ecode"].get<std::string>();
if (boost::to_upper_copy(temp_string) == long_error_code) {
if (item->contains("intro")) {
return wxString::FromUTF8((*item)["intro"].get<std::string>());
}
}
}
}

View file

@ -148,7 +148,13 @@ HMSPanel::~HMSPanel() {
void HMSPanel::append_hms_panel(HMSItem& item) {
m_notify_item = new HMSNotifyItem(m_scrolledWindow, item);
m_top_sizer->Add(m_notify_item, 0, wxALIGN_CENTER_HORIZONTAL);
wxString msg = wxGetApp().get_hms_query()->query_hms_msg(item.get_long_error_code());
if (!msg.empty())
m_top_sizer->Add(m_notify_item, 0, wxALIGN_CENTER_HORIZONTAL);
else {
// debug for hms display error info
m_top_sizer->Add(m_notify_item, 0, wxALIGN_CENTER_HORIZONTAL);
}
}
void HMSPanel::delete_hms_panels() {

View file

@ -1271,7 +1271,7 @@ void IMSlider::render_menu()
//BBS render this menu item only when extruder_num > 1
if (extruder_num > 1) {
if (!m_can_change_color) {
if (!m_can_change_color || m_draw_mode == dmSequentialFffPrint) {
begin_menu(_u8L("Change Filament").c_str(), false);
}
else if (begin_menu(_u8L("Change Filament").c_str())) {
@ -1360,9 +1360,7 @@ std::string IMSlider::get_label(int tick, LabelType label_type)
}
char layer_height[64];
m_values[value] == m_zero_layer_height ?
::sprintf(layer_height, "") :
::sprintf(layer_height, "%.2f", m_values.empty() ? m_label_koef * value : m_values[value]);
::sprintf(layer_height, "%.2f", m_values.empty() ? m_label_koef * value : m_values[value]);
if (label_type == ltHeight) return std::string(layer_height);
if (label_type == ltHeightWithLayer) {
char buffer[64];
@ -1370,7 +1368,7 @@ std::string IMSlider::get_label(int tick, LabelType label_type)
if (m_values[GetMinValueD()] == m_zero_layer_height) {
layer_number = m_is_wipe_tower ? get_layer_number(value, label_type): (m_values.empty() ? value : value);
m_values[value] == m_zero_layer_height ?
::sprintf(buffer, "%5s", std::to_string(layer_number).c_str()) :
::sprintf(buffer, "%5s\n%5s", _u8L("Start").c_str(), _u8L("G-code").c_str()) :
::sprintf(buffer, "%5s\n%5s", std::to_string(layer_number).c_str(), layer_height);
}
else {

View file

@ -71,8 +71,8 @@ static const std::map<const wchar_t, std::string> font_icons_large = {
{ImGui::CloseNotifButton , "notification_close" },
{ImGui::CloseNotifHoverButton , "notification_close_hover" },
//BBS removed
//{ImGui::EjectButton , "notification_eject_sd" },
//{ImGui::EjectHoverButton , "notification_eject_sd_hover" },
{ImGui::EjectButton , "notification_eject_sd" },
{ImGui::EjectHoverButton , "notification_eject_sd_hover" },
//{ImGui::WarningMarker , "notification_warning" },
//{ImGui::ErrorMarker , "notification_error" },
{ImGui::CancelButton , "notification_cancel" },
@ -118,6 +118,7 @@ int ImGuiWrapper::TOOLBAR_WINDOW_FLAGS = ImGuiWindowFlags_AlwaysAutoResize
| ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoTitleBar;
static float accer = 1.f;
bool get_data_from_svg(const std::string &filename, unsigned int max_size_px, ThumbnailData &thumbnail_data)
{
@ -195,21 +196,7 @@ bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const
if (axis == ImGuiAxis_Y)
mouse_wheel_responsive_region = ImRect(region.Min - ImVec2(0, handle_sz.y), region.Max + ImVec2(0, handle_sz.y));
if (ImGui::ItemHoverable(mouse_wheel_responsive_region, id)) {
#ifdef __APPLE__
if (io.KeyShift)
v_new = ImClamp(*out_value - 5 * (ImS32) (context.IO.MouseWheel), v_min, v_max);
else if (io.KeyCtrl)
v_new = ImClamp(*out_value + 5 * (ImS32) (context.IO.MouseWheel), v_min, v_max);
else {
v_new = ImClamp(*out_value + (ImS32) (context.IO.MouseWheel), v_min, v_max);
}
#else
if (io.KeyCtrl || io.KeyShift)
v_new = ImClamp(*out_value + 5 * (ImS32) (context.IO.MouseWheel), v_min, v_max);
else {
v_new = ImClamp(*out_value + (ImS32) (context.IO.MouseWheel), v_min, v_max);
}
#endif
v_new = ImClamp(*out_value + (ImS32)(context.IO.MouseWheel * accer), v_min, v_max);
}
// drag behavior
if (context.ActiveId == id)
@ -416,9 +403,9 @@ bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt)
io.MouseDown[1] = evt.RightIsDown();
io.MouseDown[2] = evt.MiddleIsDown();
float wheel_delta = static_cast<float>(evt.GetWheelDelta());
if (wheel_delta != 0.0f)
io.MouseWheel = static_cast<float>(evt.GetWheelRotation()) / wheel_delta;
if (wheel_delta != 0.0f) {
io.MouseWheel = evt.GetWheelRotation() > 0 ? 1.f : -1.f;
}
unsigned buttons = (evt.LeftIsDown() ? 1 : 0) | (evt.RightIsDown() ? 2 : 0) | (evt.MiddleIsDown() ? 4 : 0);
m_mouse_buttons = buttons;
@ -435,6 +422,19 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt)
ImGuiIO& io = ImGui::GetIO();
if (evt.CmdDown()) {
accer = 5.f;
}
else if (evt.ShiftDown()) {
#ifdef __APPLE__
accer = -5.f;
#else
accer = 5.f;
#endif
}
else
accer = 1.f;
if (evt.GetEventType() == wxEVT_CHAR) {
// Char event
const auto key = evt.GetUnicodeKey();

View file

@ -187,6 +187,9 @@ void ImageGrid::UpdateLayout()
{
if (!m_file_sys) return;
wxSize size = GetClientSize();
wxSize mask_size{0, 60 * em_unit(this) / 10};
if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE)
mask_size.y = 20 * em_unit(this) / 10;
int cell_width = m_cell_size.GetWidth();
int cell_height = m_cell_size.GetHeight();
int ncol = (size.GetWidth() - cell_width + m_image_size.GetWidth()) / cell_width;
@ -199,7 +202,6 @@ void ImageGrid::UpdateLayout()
if (m_row_offset >= m_row_count)
m_row_offset = m_row_count == 0 ? 0 : m_row_count - 1;
// create mask
wxSize mask_size{0, 60 * em_unit(this) / 10};
if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE) {
mask_size.x = (m_col_count - 1) * m_cell_size.GetWidth() + m_image_size.GetWidth();
}
@ -370,6 +372,8 @@ size_t Slic3r::GUI::ImageGrid::firstItem(wxSize const &size, wxPoint &off)
int index = (m_row_offset + 1 < m_row_count || m_row_count == 0) ?
m_row_offset / 4 * m_col_count :
((m_file_sys->GetCount() + m_col_count - 1) / m_col_count - (size.y + m_image_size.GetHeight() - 1) / m_cell_size.GetHeight()) * m_col_count;
if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE)
offy += m_mask.GetHeight();
off = wxPoint{offx, offy};
return index;
}
@ -523,12 +527,15 @@ void ImageGrid::render(wxDC& dc)
}
// Draw floating date range for non-group list
if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE && m_file_sys->GetCount() > 0) {
dc.DrawBitmap(m_mask, {off.x, 0});
//dc.DrawBitmap(m_mask, {off.x, 0});
dc.DrawRectangle({off.x, 0}, m_mask.GetSize());
auto & file1 = m_file_sys->GetFile(start);
auto & file2 = m_file_sys->GetFile(end - 1);
auto date1 = wxDateTime((time_t) file1.time).Format(_L(formats[m_file_sys->GetGroupMode()]));
auto date2 = wxDateTime((time_t) file2.time).Format(_L(formats[m_file_sys->GetGroupMode()]));
dc.DrawText(date1 + " - " + date2, wxPoint{off.x + 24, 16});
dc.SetFont(Label::Head_16);
dc.SetTextForeground(wxColor("#262E30"));
dc.DrawText(date1 + " - " + date2, wxPoint{off.x, 2});
}
// Draw bottom background
if (off.y < size.y)

View file

@ -412,7 +412,7 @@ void ArrangeJob::prepare()
//add the virtual object into unselect list if has
m_plater->get_partplate_list().preprocess_exclude_areas(m_unselected, MAX_NUM_PLATES);
#if SAVE_ARRANGE_POLY
if (1)
{ // subtract excluded region and get a polygon bed
@ -625,8 +625,11 @@ void ArrangeJob::finalize() {
//BBS: partplate
PartPlateList& plate_list = m_plater->get_partplate_list();
//clear all the relations before apply the arrangement results
plate_list.clear();
if (only_on_partplate) {
plate_list.clear(false, false, true, current_plate_index);
}
else
plate_list.clear(false, false, true, -1);
//BBS: adjust the bed_index, create new plates, get the max bed_index
for (ArrangePolygon& ap : m_selected) {
//if (ap.bed_idx < 0) continue; // bed_idx<0 means unarrangable
@ -709,7 +712,12 @@ void ArrangeJob::finalize() {
m_plater->get_notification_manager()->close_notification_of_type(NotificationType::ArrangeOngoing);
//BBS: reload all objects due to arrange
plate_list.rebuild_plates_after_arrangement(!only_on_partplate);
if (only_on_partplate) {
plate_list.rebuild_plates_after_arrangement(!only_on_partplate, true, current_plate_index);
}
else {
plate_list.rebuild_plates_after_arrangement(!only_on_partplate, true);
}
// BBS: update slice context and gcode result.
m_plater->update_slicing_context_to_current_partplate();

View file

@ -140,7 +140,7 @@ static wxIcon main_frame_icon(GUI_App::EAppMode app_mode)
}
// BBS
#ifdef __WINDOWS__
#ifndef __APPLE__
#define BORDERLESS_FRAME_STYLE (wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX)
#else
#define BORDERLESS_FRAME_STYLE (wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX)
@ -180,7 +180,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
// Fonts were created by the DPIFrame constructor for the monitor, on which the window opened.
wxGetApp().update_fonts(this);
#ifdef __WINDOWS__
#ifndef __APPLE__
m_topbar = new BBLTopbar(this);
#else
auto panel_topbar = new wxPanel(this, wxID_ANY);
@ -286,7 +286,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
//Bind(wxEVT_MENU, [this](wxCommandEvent&) { m_plater->cut_selection_to_clipboard(); }, wxID_HIGHEST + wxID_CUT);
Bind(wxEVT_SIZE, [this](wxSizeEvent&) {
BOOST_LOG_TRIVIAL(trace) << "mainframe: size changed, is maximized = " << this->IsMaximized();
#ifdef __WINDOWS__
#ifndef __APPLE__
if (this->IsMaximized()) {
m_topbar->SetWindowSize();
} else {
@ -328,7 +328,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
// initialize layout
m_main_sizer = new wxBoxSizer(wxVERTICAL);
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
#ifdef __WINDOWS__
#ifndef __APPLE__
sizer->Add(m_topbar, 0, wxEXPAND);
#else
sizer->Add(panel_topbar, 0, wxEXPAND);
@ -860,7 +860,7 @@ void MainFrame::init_tabpanel()
//monitor
}
#ifdef __WINDOWS__
#ifndef __APPLE__
if (sel == tp3DEditor) {
m_topbar->EnableUndoRedoItems();
}
@ -1552,7 +1552,7 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect)
dynamic_cast<Notebook*>(m_tabpanel)->Rescale();
#endif
#ifdef __WINDOWS__
#ifndef __APPLE__
// BBS
m_topbar->Rescale();
#endif
@ -1675,7 +1675,7 @@ static wxMenu* generate_help_menu()
return true;
});
// About
#ifdef __WINDOWS__
#ifndef __APPLE__
wxString about_title = wxString::Format(_L("&About %s"), SLIC3R_APP_FULL_NAME);
append_menu_item(helpMenu, wxID_ANY, about_title, about_title,
[](wxCommandEvent&) { Slic3r::GUI::about(); });
@ -1736,7 +1736,7 @@ void MainFrame::init_menubar_as_editor()
[this](){return can_start_new_project(); }, this);
// Open Project
#ifdef __WINDOWS__
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Open Project") + dots + "\tCtrl+O", _L("Open a project file"),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "menu_open", nullptr,
[this](){return can_open_project(); }, this);
@ -1767,7 +1767,7 @@ void MainFrame::init_menubar_as_editor()
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_open_project() && (m_recent_projects.GetCount() > 0)); }, recent_projects_submenu->GetId());
// BBS: close save project
#ifdef __WINDOWS__
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Save Project") + "\tCtrl+S", _L("Save current project to file"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(); }, "menu_save", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
@ -1778,7 +1778,7 @@ void MainFrame::init_menubar_as_editor()
#endif
#ifdef __WINDOWS__
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Save Project as") + dots + "\tCtrl+Shift+S", _L("Save current project as"),
[this](wxCommandEvent&) { if (m_plater) m_plater->save_project(true); }, "menu_save", nullptr,
[this](){return m_plater != nullptr && can_save_as(); }, this);
@ -1793,7 +1793,7 @@ void MainFrame::init_menubar_as_editor()
// BBS
wxMenu *import_menu = new wxMenu();
#ifdef __WINDOWS__
#ifndef __APPLE__
append_menu_item(import_menu, wxID_ANY, _L("Import 3MF/STL/STEP/OBJ/AMF") + dots + "\tCtrl+I", _L("Load a model"),
[this](wxCommandEvent&) { if (m_plater) {
m_plater->add_model();
@ -1836,7 +1836,7 @@ void MainFrame::init_menubar_as_editor()
fileMenu->AppendSeparator();
#ifdef __WINDOWS__
#ifndef __APPLE__
append_menu_item(fileMenu, wxID_EXIT, _L("Quit"), wxString::Format(_L("Quit")),
[this](wxCommandEvent&) { Close(false); }, "menu_exit", nullptr);
#else
@ -1857,7 +1857,7 @@ void MainFrame::init_menubar_as_editor()
wxString hotkey_delete = "Del";
#endif
#ifdef __WINDOWS__
#ifndef __APPLE__
// BBS undo
append_menu_item(editMenu, wxID_ANY, _L("Undo") + "\tCtrl+Z",
_L("Undo"), [this](wxCommandEvent&) { m_plater->undo(); },
@ -2131,7 +2131,7 @@ void MainFrame::init_menubar_as_editor()
auto helpMenu = generate_help_menu();
#ifdef __WINDOWS__
#ifndef __APPLE__
m_topbar->SetFileMenu(fileMenu);
if (editMenu)
m_topbar->AddDropDownSubMenu(editMenu, _L("Edit"));

View file

@ -31,6 +31,9 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent)
m_button_year = new ::Button(m_time_panel, _L("Year"), "", wxBORDER_NONE);
m_button_month = new ::Button(m_time_panel, _L("Month"), "", wxBORDER_NONE);
m_button_all = new ::Button(m_time_panel, _L("All Files"), "", wxBORDER_NONE);
m_button_year->SetToolTip(L("Group files by year, recent first."));
m_button_month->SetToolTip(L("Group files by month, recent first."));
m_button_all->SetToolTip(L("Show all files, recent first."));
m_button_all->SetFont(Label::Head_14); // sync with m_last_mode
for (auto b : {m_button_year, m_button_month, m_button_all}) {
b->SetBackgroundColor(StateColor());
@ -49,14 +52,22 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent)
top_sizer->Add(m_time_panel, 1, wxEXPAND);
// File type
StateColor background(
std::make_pair(0xEEEEEE, (int) StateColor::Checked),
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered),
std::make_pair(*wxWHITE, (int) StateColor::Normal));
m_type_panel = new ::StaticBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
m_type_panel->SetBackgroundColor(*wxWHITE);
m_type_panel->SetCornerRadius(FromDIP(5));
m_type_panel->SetMinSize({-1, 48 * em_unit(this) / 10});
m_button_timelapse = new ::Button(m_type_panel, _L("Timelapse"), "", wxBORDER_NONE);
m_button_timelapse->SetCanFocus(false);
m_button_timelapse->SetToolTip(L("Switch to timelapse files."));
m_button_video = new ::Button(m_type_panel, _L("Video"), "", wxBORDER_NONE);
m_button_video->SetCanFocus(false);
m_button_video->SetToolTip(L("Switch to video files."));
for (auto b : {m_button_timelapse, m_button_video} ) {
b->SetBackgroundColor(background);
b->SetCanFocus(false);
}
wxBoxSizer *type_sizer = new wxBoxSizer(wxHORIZONTAL);
type_sizer->Add(m_button_timelapse, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 24);
@ -68,13 +79,22 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent)
m_manage_panel = new ::StaticBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
m_manage_panel->SetBackgroundColor(StateColor());
m_button_delete = new ::Button(m_manage_panel, _L("Delete"));
m_button_delete->SetBackgroundColor(StateColor());
m_button_delete->SetCanFocus(false);
m_button_delete->SetToolTip(L("Delete selected files from printer."));
m_button_download = new ::Button(m_manage_panel, _L("Download"));
m_button_download->SetBackgroundColor(StateColor());
m_button_download->SetCanFocus(false);
m_button_download->SetToolTip(L("Download selected files from printer."));
m_button_management = new ::Button(m_manage_panel, _L("Management"));
m_button_management->SetBackgroundColor(StateColor());
m_button_management->SetToolTip(L("Batch manage files."));
for (auto b : {m_button_delete, m_button_download, m_button_management}) {
b->SetBackgroundColor(StateColor());
b->SetFont(Label::Body_12);
b->SetCornerRadius(12);
b->SetPaddingSize({10, 6});
b->SetCanFocus(false);
}
m_button_delete->SetBorderColor(wxColor("#FF6F00"));
m_button_delete->SetTextColor(wxColor("#FF6F00"));
m_button_management->SetBorderWidth(0);
m_button_management->SetBackgroundColor(wxColor("#00AE42"));
wxBoxSizer *manage_sizer = new wxBoxSizer(wxHORIZONTAL);
manage_sizer->AddStretchSpacer(1);
@ -174,6 +194,17 @@ MediaFilePanel::~MediaFilePanel()
void MediaFilePanel::SetMachineObject(MachineObject* obj)
{
std::string machine = obj ? obj->dev_id : "";
if (obj && obj->is_function_supported(PrinterFunction::FUNC_MEDIA_FILE)) {
m_lan_mode = obj->is_lan_mode_printer();
m_lan_ip = obj->is_function_supported(PrinterFunction::FUNC_LOCAL_TUNNEL) ? obj->dev_ip : "";
m_lan_passwd = obj->access_code;
m_tutk_support = obj->is_function_supported(PrinterFunction::FUNC_REMOTE_TUNNEL);
} else {
m_lan_mode = false;
m_lan_ip.clear();
m_lan_passwd.clear();
m_tutk_support = true;
}
if (machine == m_machine)
return;
m_machine = machine;
@ -185,8 +216,11 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj)
}
if (m_machine.empty()) {
m_image_grid->SetStatus(m_bmp_failed.bmp(), _L("No printers."));
} else if (m_lan_ip.empty() && (m_lan_mode && !m_tutk_support)) {
m_image_grid->SetStatus(m_bmp_failed.bmp(), _L("Not supported."));
} else {
boost::shared_ptr<PrinterFileSystem> fs(new PrinterFileSystem);
fs->Attached();
m_image_grid->SetFileType(m_last_type);
m_image_grid->SetFileSystem(fs);
fs->Bind(EVT_MODE_CHANGED, &MediaFilePanel::modeChanged, this);
@ -259,7 +293,17 @@ void MediaFilePanel::modeChanged(wxCommandEvent& e1)
void MediaFilePanel::fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs)
{
NetworkAgent* agent = wxGetApp().getAgent();
if (!m_lan_ip.empty()) {
std::string url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd;
boost::shared_ptr fs(wfs.lock());
if (!fs || fs != m_image_grid->GetFileSystem()) return;
fs->SetUrl(url);
return;
}
if (m_lan_mode && !m_tutk_support) { // not support tutk
return;
}
NetworkAgent *agent = wxGetApp().getAgent();
if (agent) {
agent->get_camera_url(m_machine,
[this, wfs](std::string url) {

View file

@ -65,7 +65,13 @@ private:
::Button *m_button_management = nullptr;
std::string m_machine;
ImageGrid * m_image_grid = nullptr;
std::string m_lan_ip;
std::string m_lan_user;
std::string m_lan_passwd;
bool m_lan_mode = false;
bool m_tutk_support = false;
ImageGrid * m_image_grid = nullptr;
int m_last_mode = 0;
int m_last_type = 0;

View file

@ -19,11 +19,15 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const w
m_button_play = new Button(this, "", "media_play", wxBORDER_NONE);
m_button_play->SetCanFocus(false);
m_label_status = new Label(this);
m_label_status = new Label(this, "", LB_HYPERLINK);
m_button_play->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto & e) { TogglePlay(); });
m_button_play->Bind(wxEVT_RIGHT_UP, [this](auto & e) { m_media_ctrl->Play(); });
m_label_status->Bind(wxEVT_LEFT_UP, [this](auto &e) {
auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/faq/live-view", L"en");
wxLaunchDefaultBrowser(url);
});
Bind(wxEVT_RIGHT_UP, [this](auto & e) { wxClipboard & c = *wxTheClipboard; if (c.Open()) { c.SetData(new wxTextDataObject(m_url)); c.Close(); } });
@ -48,6 +52,9 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const w
};
parent->Bind(wxEVT_SHOW, onShowHide);
parent->GetParent()->GetParent()->Bind(wxEVT_SHOW, onShowHide);
m_lan_user = "bblp";
m_lan_passwd = "bblp";
}
MediaPlayCtrl::~MediaPlayCtrl()
@ -63,6 +70,17 @@ MediaPlayCtrl::~MediaPlayCtrl()
void MediaPlayCtrl::SetMachineObject(MachineObject* obj)
{
std::string machine = obj ? obj->dev_id : "";
if (obj && obj->is_function_supported(PrinterFunction::FUNC_CAMERA_VIDEO)) {
m_lan_mode = obj->is_lan_mode_printer();
m_lan_ip = obj->is_function_supported(PrinterFunction::FUNC_LOCAL_TUNNEL) ? obj->dev_ip : "";
m_lan_passwd = obj->access_code;
m_tutk_support = obj->is_function_supported(PrinterFunction::FUNC_REMOTE_TUNNEL);
} else {
m_lan_mode = false;
m_lan_ip.clear();
m_lan_passwd.clear();
m_tutk_support = true;
}
if (machine == m_machine) {
if (m_last_state == MEDIASTATE_IDLE && m_next_retry.IsValid() && wxDateTime::Now() >= m_next_retry)
Play();
@ -92,10 +110,36 @@ void MediaPlayCtrl::Play()
if (m_last_state != MEDIASTATE_IDLE) {
return;
}
m_last_state = MEDIASTATE_INITIALIZING;
m_button_play->SetIcon("media_stop");
SetStatus(_L("Initializing..."));
if (!m_lan_ip.empty()) {
m_url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd;
m_last_state = MEDIASTATE_LOADING;
SetStatus(_L("Loading..."));
if (wxGetApp().app_config->get("dump_video") == "true") {
std::string file_h264 = data_dir() + "/video.h264";
std::string file_info = data_dir() + "/video.info";
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl dump video to " << file_h264;
// closed by BambuSource
FILE *dump_h264_file = boost::nowide::fopen(file_h264.c_str(), "wb");
FILE *dump_info_file = boost::nowide::fopen(file_info.c_str(), "wb");
m_url = m_url + "&dump_h264=" + boost::lexical_cast<std::string>(dump_h264_file);
m_url = m_url + "&dump_info=" + boost::lexical_cast<std::string>(dump_info_file);
}
boost::unique_lock lock(m_mutex);
m_tasks.push_back(m_url);
m_cond.notify_all();
return;
}
if (m_lan_mode && !m_tutk_support) { // not support tutk
Stop();
SetStatus(_L("Initialize failed (Not supported)!"));
return;
}
NetworkAgent* agent = wxGetApp().getAgent();
if (agent) {
@ -166,7 +210,11 @@ void MediaPlayCtrl::SetStatus(wxString const& msg2)
OutputDebugStringA("\n");
#endif // __WXMSW__
m_label_status->SetLabel(msg);
//m_label_status->SetForegroundColour(!msg.EndsWith("!") ? 0x42AE00 : 0x3B65E9);
long style = m_label_status->GetWindowStyle() & ~LB_HYPERLINK;
if (m_failed_code && msg != msg2) {
style |= LB_HYPERLINK;
}
m_label_status->SetWindowStyle(style);
Layout();
}
@ -240,6 +288,8 @@ void MediaPlayCtrl::onStateChanged(wxMediaEvent& event)
}
else if (event.GetId()) {
Stop();
if (m_failed_code == 0)
m_failed_code = 2;
SetStatus(_L("Load failed [%d]!"));
} else {
m_last_state = last_state;

View file

@ -58,6 +58,11 @@ private:
wxMediaCtrl2 * m_media_ctrl;
wxMediaState m_last_state = MEDIASTATE_IDLE;
std::string m_machine;
std::string m_lan_ip;
std::string m_lan_user;
std::string m_lan_passwd;
bool m_lan_mode = false;
bool m_tutk_support = false;
wxString m_url;
std::deque<wxString> m_tasks;

View file

@ -227,11 +227,6 @@ void MonitorPanel::set_default()
/* reset side tool*/
//m_bitmap_wifi_signal->SetBitmap(wxNullBitmap);
#if !BBL_RELEASE_TO_PUBLIC
/* reset time lapse panel */
m_media_file_panel->SetMachineObject(nullptr);
#endif
wxGetApp().sidebar().load_ams_list({});
}
@ -324,6 +319,13 @@ void MonitorPanel::on_printer_clicked(wxMouseEvent &event)
wxPoint pos = m_side_tools->ClientToScreen(wxPoint(0, 0));
pos.y += m_side_tools->GetRect().height;
m_select_machine.Position(pos, wxSize(0, 0));
#ifdef __linux__
m_select_machine.SetSize(wxSize(m_side_tools->GetSize().x, -1));
m_select_machine.SetMaxSize(wxSize(m_side_tools->GetSize().x, -1));
m_select_machine.SetMinSize(wxSize(m_side_tools->GetSize().x, -1));
#endif
m_select_machine.Popup();
}
}

View file

@ -34,7 +34,7 @@ static constexpr int FADING_OUT_TIMEOUT = 100;
namespace Slic3r {
namespace GUI {
//wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent);
wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent);
wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent);
wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent);
@ -801,11 +801,11 @@ void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper&
void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
PopNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
//if(m_to_removable && ! m_eject_pending)
// render_eject_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
if (m_to_removable && !m_eject_pending)
render_eject_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
/*void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
ImVec2 win_pos(win_pos_x, win_pos_y);
@ -818,23 +818,25 @@ void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiW
std::string button_text;
button_text = ImGui::EjectButton;
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y),
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y),
ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y),
true))
{
button_text = ImGui::EjectHoverButton;
// tooltip
//tooltip
long time_now = wxGetLocalTime();
if (m_hover_time > 0 && m_hover_time < time_now) {
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
ImGui::BeginTooltip();
imgui.text(_u8L("Eject drive") + " " + GUI::shortkey_ctrl_prefix() + "T");
ImGui::EndTooltip();
//ImGui::BeginTooltip();
//imgui.text(_u8L("Eject drive") + " " + GUI::shortkey_ctrl_prefix() + "T");
//ImGui::EndTooltip();
ImGui::PopStyleColor();
}
if (m_hover_time == 0)
m_hover_time = time_now;
} else
}
else
m_hover_time = 0;
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
@ -850,7 +852,7 @@ void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiW
}
//invisible large button
ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f);
ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f);
ImGui::SetCursorPosY(0);
if (imgui.button(" ", m_line_height * 2.f, win_size.y))
{
@ -860,7 +862,8 @@ void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiW
on_eject_click();
}
ImGui::PopStyleColor(5);
}*/
}
bool NotificationManager::ExportFinishedNotification::on_text_click()
{
open_folder(m_export_dir_path);

View file

@ -21,8 +21,8 @@
namespace Slic3r {
namespace GUI {
//using EjectDriveNotificationClickedEvent = SimpleEvent;
//wxDECLARE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent);
using EjectDriveNotificationClickedEvent = SimpleEvent;
wxDECLARE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent);
using ExportGcodeNotificationClickedEvent = SimpleEvent;
wxDECLARE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent);
using PresetUpdateAvailableClickedEvent = SimpleEvent;
@ -737,9 +737,9 @@ private:
void render_close_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
/*void render_eject_button(ImGuiWrapper& imgui,
void render_eject_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y);*/
const float win_pos_x, const float win_pos_y);
void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override
{ m_minimize_b_visible = false; }
bool on_text_click() override;

View file

@ -53,8 +53,9 @@ OG_CustomCtrl::OG_CustomCtrl( wxWindow* parent,
m_font = Label::Body_14;
SetFont(m_font);
m_em_unit = em_unit(m_parent);
m_v_gap = lround(1.0 * m_em_unit);
m_h_gap = lround(0.2 * m_em_unit);
m_v_gap = lround(1.2 * m_em_unit);
m_v_gap2 = lround(0.8 * m_em_unit);
m_h_gap = lround(0.2 * m_em_unit);
//m_bmp_mode_sz = get_bitmap_size(create_scaled_bitmap("mode_simple", this, wxOSX ? 10 : 12));
m_bmp_blinking_sz = get_bitmap_size(create_scaled_bitmap("blank_16", this));
@ -101,7 +102,7 @@ void OG_CustomCtrl::init_ctrl_lines()
wxSize label_sz = GetTextExtent(line.label);
if (opt_group->split_multi_line) {
if (option_set.size() > 1) // BBS
height = (label_sz.y + m_v_gap) * option_set.size();
height = (label_sz.y + m_v_gap2) * option_set.size() + m_v_gap - m_v_gap2;
else
height = label_sz.y * (label_sz.GetWidth() > int(opt_group->label_width * m_em_unit) ? 2 : 1) + m_v_gap;
} else {
@ -243,7 +244,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
break;
}
if (opt_group->split_multi_line) {// BBS
v_pos += ctrl_line.height / option_set.size();
v_pos += (ctrl_line.height - m_v_gap + m_v_gap2) / option_set.size();
} else {
// BBS: new layout
h_pos += field->getWindow()->GetSize().x;
@ -507,7 +508,7 @@ void OG_CustomCtrl::correct_window_position(wxWindow* win, const Line& line, Fie
int line_height = get_height(line);
if (opt_group->split_multi_line) { // BBS
if (line.get_options().size() > 1)
line_height /= line.get_options().size();
line_height = (line_height - m_v_gap + m_v_gap2) / line.get_options().size();
}
pos.y += std::max(0, int(0.5 * (line_height - win->GetSize().y)));
win->SetPosition(pos);
@ -544,7 +545,7 @@ int OG_CustomCtrl::get_title_width()
if (!GetLabel().IsEmpty())
return titleWidth;
else
return 1;
return 2;
}
void OG_CustomCtrl::set_max_win_width(int max_win_width)
@ -568,7 +569,8 @@ void OG_CustomCtrl::msw_rescale()
m_font = Label::Body_14;
SetFont(m_font);
m_em_unit = em_unit(m_parent);
m_v_gap = lround(1.5 * m_em_unit);
m_v_gap = lround(1.2 * m_em_unit);
m_v_gap2 = lround(0.8 * m_em_unit);
m_h_gap = lround(0.2 * m_em_unit);
//m_bmp_mode_sz = create_scaled_bitmap("mode_simple", this, wxOSX ? 10 : 12).GetSize();
@ -672,7 +674,7 @@ void OG_CustomCtrl::CtrlLine::msw_rescale()
if (ctrl->opt_group->split_multi_line) { // BBS
const std::vector<Option> &option_set = og_line.get_options();
if (option_set.size() > 1)
height = (label_sz.y + ctrl->m_v_gap) * option_set.size();
height = (label_sz.y + ctrl->m_v_gap2) * option_set.size() + ctrl->m_v_gap - ctrl->m_v_gap2;
else
height = label_sz.y * (label_sz.GetWidth() > int(ctrl->opt_group->label_width * ctrl->m_em_unit) ? 2 : 1) + ctrl->m_v_gap;
} else {
@ -878,7 +880,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord h_pos, wxCoord v_pos)
h_pos += lround(0.6 * ctrl->m_em_unit);
if (ctrl->opt_group->split_multi_line) { // BBS
v_pos += height / option_set.size();
v_pos += (height - ctrl->m_v_gap + ctrl->m_v_gap2) / option_set.size();
h_pos = h_pos2;
}
}
@ -894,7 +896,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC &dc, wxPoint pos, const wxString
if (ctrl->opt_group->split_multi_line && !is_main) { // BBS
const std::vector<Option> &option_set = og_line.get_options();
pos.y = pos.y + lround((height / option_set.size() - size.y) / 2);
pos.y = pos.y + lround(((height - ctrl->m_v_gap + ctrl->m_v_gap2) / option_set.size() - size.y) / 2);
} else {
pos.y = pos.y + lround((height - size.y) / 2);
}
@ -952,7 +954,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBi
if (ctrl->opt_group->split_multi_line) { // BBS
const std::vector<Option> &option_set = og_line.get_options();
if (option_set.size() > 1)
pos.y += lround((height / option_set.size() - get_bitmap_size(bmp_undo).GetHeight()) / 2);
pos.y += lround(((height - ctrl->m_v_gap + ctrl->m_v_gap2) / option_set.size() - get_bitmap_size(bmp_undo).GetHeight()) / 2);
else
pos.y += lround((height - get_bitmap_size(bmp_undo).GetHeight()) / 2);
} else {

View file

@ -27,6 +27,7 @@ class OG_CustomCtrl :public wxPanel
{
wxFont m_font;
int m_v_gap;
int m_v_gap2;
int m_h_gap;
int m_em_unit;

View file

@ -207,6 +207,7 @@ std::string OpenGLManager::GLInfo::to_string(bool for_github) const
OpenGLManager::GLInfo OpenGLManager::s_gl_info;
bool OpenGLManager::s_compressed_textures_supported = false;
bool OpenGLManager::m_use_manually_generated_mipmaps = true;
OpenGLManager::EMultisampleState OpenGLManager::s_multisample = OpenGLManager::EMultisampleState::Unknown;
OpenGLManager::EFramebufferType OpenGLManager::s_framebuffers_type = OpenGLManager::EFramebufferType::Unknown;
@ -276,6 +277,34 @@ bool OpenGLManager::init_gl()
wxMessageBox(message, _L("Error loading shaders"), wxOK | wxICON_ERROR);
}
}
#ifdef _WIN32
// Since AMD driver version 22.7.1, there is probably some bug in the driver that causes the issue with the missing
// texture of the bed. It seems that this issue only triggers when mipmaps are generated manually
// (combined with a texture compression) and when mipmaps are generated through OpenGL glGenerateMipmap is working.
// So, for newer drivers than 22.6.1, the last working driver version, we use mipmaps generated through OpenGL.
if (const auto gl_info = OpenGLManager::get_gl_info(); boost::contains(gl_info.get_vendor(), "ATI Technologies Inc.")) {
// WHQL drivers seem to have one more version number at the end besides non-WHQL drivers.
// WHQL: 4.6.14800 Compatibility Profile Context 22.6.1 30.0.21023.1015
// Non-WHQL: 4.6.0 Compatibility Profile Context 22.8.1.220810
std::regex version_rgx(R"(Compatibility\sProfile\sContext\s(\d+)\.(\d+)\.(\d+))");
if (std::smatch matches; std::regex_search(gl_info.get_version(), matches, version_rgx) && matches.size() == 4) {
int version_major = std::stoi(matches[1].str());
int version_minor = std::stoi(matches[2].str());
int version_patch = std::stoi(matches[3].str());
BOOST_LOG_TRIVIAL(debug) << "Found AMD driver version: " << version_major << "." << version_minor << "." << version_patch;
if (version_major > 22 || (version_major == 22 && version_minor > 6) || (version_major == 22 && version_minor == 6 && version_patch > 1)) {
m_use_manually_generated_mipmaps = false;
BOOST_LOG_TRIVIAL(debug) << "Mipmapping through OpenGL was enabled.";
}
} else {
BOOST_LOG_TRIVIAL(error) << "Not recognized format of version.";
}
} else {
BOOST_LOG_TRIVIAL(error) << "Unable to parse version of AMD driver.";
}
#endif
}
return true;

View file

@ -84,6 +84,7 @@ private:
static EMultisampleState s_multisample;
static EFramebufferType s_framebuffers_type;
static bool m_use_manually_generated_mipmaps;
public:
OpenGLManager() = default;
~OpenGLManager();
@ -100,6 +101,7 @@ public:
static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; }
static wxGLCanvas* create_wxglcanvas(wxWindow& parent);
static const GLInfo& get_gl_info() { return s_gl_info; }
static bool use_manually_generated_mipmaps() { return m_use_manually_generated_mipmaps; }
private:
static void detect_multisample(int* attribList);

View file

@ -113,10 +113,10 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
return field;
}
OptionsGroup::OptionsGroup( wxWindow* _parent, const wxString& title,
OptionsGroup::OptionsGroup(wxWindow *_parent, const wxString &title, const wxString &icon,
bool is_tab_opt /* = false */,
column_t extra_clmn /* = nullptr */) :
m_parent(_parent), title(title),
m_parent(_parent), title(title), icon(icon),
m_use_custom_ctrl(is_tab_opt),
// BBS: new layout
staticbox(!is_tab_opt), extra_column(extra_clmn)
@ -461,7 +461,7 @@ bool OptionsGroup::activate(std::function<void()> throw_if_canceled/* = [](){}*/
}
else {
// BBS: new layout
::StaticLine* stl = new ::StaticLine(m_parent, false, _(title));
::StaticLine* stl = new ::StaticLine(m_parent, false, _(title), icon);
stl->SetFont(Label::Head_14);
stl->SetForegroundColour("#262E30");
sizer = new wxBoxSizer(wxVERTICAL);
@ -850,6 +850,9 @@ void ConfigOptionsGroup::msw_rescale()
if (custom_ctrl)
custom_ctrl->msw_rescale();
if (auto line = dynamic_cast<::StaticLine*>(stb))
line->Rescale();
}
void ConfigOptionsGroup::sys_color_changed()
@ -1115,7 +1118,7 @@ boost::any ConfigOptionsGroup::get_config_value2(const DynamicPrintConfig& confi
ret = config.opt_bool(opt_key);
break;
case coBools:
ret = config.opt_bool(opt_key, idx);
ret = static_cast<unsigned char>(config.opt_bool(opt_key, idx));
break;
case coInt:
ret = config.opt_int(opt_key);

View file

@ -105,6 +105,7 @@ public:
bool option_label_at_right{false};
// BBS: new layout
wxWindow * stb;
const wxString icon;
const wxString title;
size_t label_width = 20 ;// {200};
wxSizer* sizer {nullptr};
@ -180,7 +181,7 @@ public:
void hide_labels() { label_width = 0; }
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
OptionsGroup(wxWindow *_parent, const wxString &title, const wxString &icon, bool is_tab_opt = false,
column_t extra_clmn = nullptr);
~OptionsGroup() { clear(true); }
@ -239,14 +240,17 @@ public:
class ConfigOptionsGroup: public OptionsGroup {
public:
ConfigOptionsGroup( wxWindow* parent, const wxString& title, const wxString& icon, DynamicPrintConfig* config = nullptr,
bool is_tab_opt = false, column_t extra_clmn = nullptr) :
OptionsGroup(parent, title, icon, is_tab_opt, extra_clmn), m_config(config) {}
ConfigOptionsGroup( wxWindow* parent, const wxString& title, DynamicPrintConfig* config = nullptr,
bool is_tab_opt = false, column_t extra_clmn = nullptr) :
OptionsGroup(parent, title, is_tab_opt, extra_clmn), m_config(config) {}
ConfigOptionsGroup(parent, title, wxEmptyString, config, is_tab_opt, extra_clmn) {}
ConfigOptionsGroup( wxWindow* parent, const wxString& title, ModelConfig* config,
bool is_tab_opt = false, column_t extra_clmn = nullptr) :
OptionsGroup(parent, title, is_tab_opt, extra_clmn), m_config(&config->get()), m_modelconfig(config) {}
OptionsGroup(parent, title, wxEmptyString, is_tab_opt, extra_clmn), m_config(&config->get()), m_modelconfig(config) {}
ConfigOptionsGroup( wxWindow* parent) :
OptionsGroup(parent, wxEmptyString, true, nullptr) {}
OptionsGroup(parent, wxEmptyString, wxEmptyString, true, nullptr) {}
const wxString& config_category() const throw() { return m_config_category; }
int config_type() const throw() { return m_config_type; }
@ -316,7 +320,7 @@ class ExtruderOptionsGroup : public ConfigOptionsGroup {
public:
ExtruderOptionsGroup(wxWindow* parent, const wxString& title, DynamicPrintConfig* config = nullptr,
bool is_tab_opt = false, column_t extra_clmn = nullptr) :
ConfigOptionsGroup(parent, title, config, is_tab_opt, extra_clmn) {}
ConfigOptionsGroup(parent, title, wxEmptyString, config, is_tab_opt, extra_clmn) {}
void on_change_OG(const t_config_option_key& opt_id, const boost::any& value) override;
};

View file

@ -1162,12 +1162,14 @@ void PartPlate::set_index(int index)
m_print->set_plate_index(index);
}
void PartPlate::clear()
void PartPlate::clear(bool clear_sliced_result)
{
obj_to_instance_set.clear();
instance_outside_set.clear();
m_ready_for_slice = true;
update_slice_result_valid_state(false);
if (clear_sliced_result) {
m_ready_for_slice = true;
update_slice_result_valid_state(false);
}
return;
}
@ -1250,7 +1252,7 @@ Vec3d PartPlate::get_center_origin()
Vec3d origin;
origin(0) = (m_bounding_box.min(0) + m_bounding_box.max(0)) / 2;//m_origin.x() + m_width / 2;
origin(1) = (m_bounding_box.min(0) + m_bounding_box.max(0)) / 2; //m_origin.y() + m_depth / 2;
origin(1) = (m_bounding_box.min(1) + m_bounding_box.max(1)) / 2; //m_origin.y() + m_depth / 2;
origin(2) = m_origin.z();
return origin;
@ -2415,14 +2417,19 @@ void PartPlateList::reset_size(int width, int depth, int height)
}
//clear all the instances in the plate, but keep the plates
void PartPlateList::clear(bool delete_plates, bool release_print_list)
void PartPlateList::clear(bool delete_plates, bool release_print_list, bool except_locked, int plate_index)
{
for (unsigned int i = 0; i < (unsigned int)m_plate_list.size(); ++i)
{
PartPlate* plate = m_plate_list[i];
assert(plate != NULL);
plate->clear();
if (except_locked && plate->is_locked())
plate->clear(false);
else if ((plate_index != -1) && (plate_index != i))
plate->clear(false);
else
plate->clear();
if (delete_plates)
delete plate;
}
@ -3202,12 +3209,12 @@ int PartPlateList::add_to_plate(int obj_id, int instance_id, int plate_id)
}
//reload all objects
int PartPlateList::reload_all_objects()
int PartPlateList::reload_all_objects(bool except_locked, int plate_index)
{
int ret = 0;
unsigned int i, j, k;
clear();
clear(false, false, except_locked, plate_index);
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": m_model->objects.size() is %1%") % m_model->objects.size();
//try to find a new plate
@ -3573,10 +3580,15 @@ void PartPlateList::postprocess_arrange_polygon(arrangement::ArrangePolygon& arr
{
if (arrange_polygon.bed_idx == -1)
{
//outarea for large object
// outarea for large object
arrange_polygon.bed_idx = m_plate_list.size();
arrange_polygon.translation(X) = scaled<double>(0.5 * plate_stride_x());
arrange_polygon.translation(Y) = scaled<double>(0.5 * plate_stride_y());
BoundingBox apbox(arrange_polygon.poly);
auto apbox_size = apbox.size();
//arrange_polygon.translation(X) = scaled<double>(0.5 * plate_stride_x());
//arrange_polygon.translation(Y) = scaled<double>(0.5 * plate_stride_y());
arrange_polygon.translation(X) = 0.5 * apbox_size[0];
arrange_polygon.translation(Y) = scaled<double>(static_cast<double>(m_plate_depth)) - 0.5 * apbox_size[1];
}
arrange_polygon.row = arrange_polygon.bed_idx / m_plate_cols;
@ -3945,7 +3957,7 @@ int PartPlateList::rebuild_plates_after_deserialize(std::vector<bool>& previous_
}
//retruct plates structures after auto-arrangement
int PartPlateList::rebuild_plates_after_arrangement(bool recycle_plates)
int PartPlateList::rebuild_plates_after_arrangement(bool recycle_plates, bool except_locked, int plate_index)
{
int ret = 0;
@ -3956,7 +3968,7 @@ int PartPlateList::rebuild_plates_after_arrangement(bool recycle_plates)
//for (auto object : m_model->objects)
// std::sort(object->instances.begin(), object->instances.end(), [](auto a, auto b) {return a->arrange_order < b->arrange_order; });
ret = reload_all_objects();
ret = reload_all_objects(except_locked, plate_index);
if (recycle_plates)
{

View file

@ -198,7 +198,7 @@ public:
bool operator<(PartPlate&) const;
//clear alll the instances in plate
void clear();
void clear(bool clear_sliced_result = true);
//static const int plate_x_offset = 20; //mm
//static const double plate_x_gap = 0.2;
@ -468,7 +468,7 @@ public:
//this may be happened after machine changed
void reset_size(int width, int depth, int height);
//clear all the instances in the plate, but keep the plates
void clear(bool delete_plates = false, bool release_print_list = false);
void clear(bool delete_plates = false, bool release_print_list = false, bool except_locked = false, int plate_index = -1);
//clear all the instances in the plate, and delete the plates, only keep the first default plate
void reset(bool do_init);
@ -563,7 +563,7 @@ public:
int add_to_plate(int obj_id, int instance_id, int plate_id);
//reload all objects
int reload_all_objects();
int reload_all_objects(bool except_locked = false, int plate_index = -1);
//reload objects for newly created plate
int construct_objects_list_for_new_plate(int plate_index);
@ -624,7 +624,7 @@ public:
int rebuild_plates_after_deserialize(std::vector<bool>& previous_sliced_result, std::vector<std::string>& previous_gcode_paths);
//retruct plates structures after auto-arrangement
int rebuild_plates_after_arrangement(bool recycle_plates = true);
int rebuild_plates_after_arrangement(bool recycle_plates = true, bool except_locked = false, int plate_index = -1);
/* load/store releted functions, with_gcode = true and plate_idx = -1, export all gcode
* if with_gcode = true and specify plate_idx, export plate_idx gcode only

View file

@ -91,7 +91,7 @@
#include "../Utils/UndoRedo.hpp"
#include "../Utils/PresetUpdater.hpp"
#include "../Utils/Process.hpp"
//#include "RemovableDriveManager.hpp"
#include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp"
#include "NotificationManager.hpp"
#include "PresetComboBoxes.hpp"
@ -290,6 +290,7 @@ struct Sidebar::priv
wxStaticText* m_staticText_filament_settings;
ScalableButton * m_bpButton_add_filament;
ScalableButton * m_bpButton_del_filament;
ScalableButton * m_bpButton_ams_filament;
ScalableButton * m_bpButton_set_filament;
wxPanel* m_panel_filament_content;
wxScrolledWindow* m_scrolledWindow_filament_content;
@ -552,7 +553,9 @@ Sidebar::Sidebar(Plater *parent)
wxLaunchDefaultBrowser("https://wiki.bambulab.com/en/x1/manual/compatibility-and-parameter-settings-of-filaments");
});
m_bed_type_list->Select(0);
AppConfig *app_config = wxGetApp().app_config;
std::string str_bed_type = app_config->get("curr_bed_type");
m_bed_type_list->Select(atoi(str_bed_type.c_str()));
bed_type_sizer->Add(bed_type_title, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(10));
bed_type_sizer->Add(m_bed_type_list, 1, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(10));
vsizer_printer->Add(bed_type_sizer, 0, wxEXPAND | wxTOP, FromDIP(5));
@ -650,6 +653,7 @@ Sidebar::Sidebar(Plater *parent)
bSizer39->Add(FromDIP(10), 0, 0, 0, 0 );
ScalableButton* add_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "add_filament");
add_btn->SetToolTip(_L("Add one filament"));
add_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent& e){
// BBS: limit filament choices to 16
if (p->combos_filament.size() >= 16)
@ -668,7 +672,8 @@ Sidebar::Sidebar(Plater *parent)
bSizer39->Add(FromDIP(10), 0, 0, 0, 0 );
ScalableButton* del_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "delete_filament");
del_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent& e){
del_btn->SetToolTip(_L("Remove last filament"));
del_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent &e) {
if (p->combos_filament.size() <= 1)
return;
@ -690,8 +695,20 @@ Sidebar::Sidebar(Plater *parent)
bSizer39->Add(del_btn, 0, wxALIGN_CENTER_VERTICAL, FromDIP(5));
bSizer39->Add(FromDIP(20), 0, 0, 0, 0);
ScalableButton *ams_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "ams_fila_sync", wxEmptyString, wxDefaultSize, wxDefaultPosition,
wxBU_EXACTFIT | wxNO_BORDER, false, 18);
ams_btn->SetToolTip(_L("Sync material list from AMS"));
ams_btn->Bind(wxEVT_BUTTON, [this, scrolled_sizer](wxCommandEvent &e) {
sync_ams_list();
});
p->m_bpButton_ams_filament = ams_btn;
bSizer39->Add(ams_btn, 0, wxALIGN_CENTER|wxALL, FromDIP(5));
bSizer39->Add(FromDIP(10), 0, 0, 0, 0 );
ScalableButton* set_btn = new ScalableButton(p->m_panel_filament_title, wxID_ANY, "settings");
set_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
set_btn->SetToolTip(_L("Set filaments to use"));
set_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
// p->editing_filament = -1;
// wxGetApp().params_dialog()->Popup();
// wxGetApp().get_tab(Preset::TYPE_FILAMENT)->restore_last_select_item();
@ -1006,6 +1023,7 @@ void Sidebar::msw_rescale()
p->m_filament_icon->msw_rescale();
p->m_bpButton_add_filament->msw_rescale();
p->m_bpButton_del_filament->msw_rescale();
p->m_bpButton_ams_filament->msw_rescale();
p->m_bpButton_set_filament->msw_rescale();
p->m_flushing_volume_btn->Rescale();
//BBS
@ -1185,42 +1203,9 @@ void Sidebar::load_ams_list(std::map<std::string, Ams *> const &list)
std::vector<DynamicPrintConfig> filament_ams_list;
for (auto ams : list) {
for (auto tray : ams.second->trayList) {
if (tray.second->setting_id.empty())
continue;
if (tray.second->setting_id.empty()) continue;
DynamicPrintConfig ams;
auto & filaments = wxGetApp().preset_bundle->filaments.get_presets();
auto iter = std::find_if(filaments.begin(), filaments.end(),
[&tray](auto &f) { return f.filament_id == tray.second->setting_id; });
if (iter != filaments.end()) {
ams.set_key_value("filament_settings_id", new ConfigOptionStrings{tray.second->setting_id});
} else {
/* std::shared_ptr<std::map<std::string, std::string>> preset(new std::map<std::string, std::string>);
(*preset)->setting_id = tray.second->setting_id;
ams.set_key_value("filament_settings_id", new ConfigOptionStrings{tray.second->setting_id});
//TODO: comment it currently
NetworkAgent* agent = wxGetApp().getAgent();
if (agent) {
agent->get_setting(tray.second->setting_id, *preset, [preset] {
wxGetApp().CallAfter([preset] {
if ((*preset)->name.empty())
return;
PresetsConfigSubstitutions substitutions;
wxGetApp().preset_bundle->filaments.load_user_presets({{(*preset)->name, *preset}},
PRESET_FILAMENT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Enable);
auto & ams_list = wxGetApp().preset_bundle->filament_ams_list;
for (auto& ams : ams_list) {
if (ams.opt_string("filament_settings_id", 0u) == (*preset)->setting_id) {
ams.set_key_value("filament_settings_id", new ConfigOptionStrings{(*preset)->name});
for (auto c : wxGetApp().sidebar().combos_filament()) c->update();
break;
}
}
});
});
}
*/
continue;
}
ams.set_key_value("filament_id", new ConfigOptionStrings{tray.second->setting_id});
ams.set_key_value("filament_colour", new ConfigOptionStrings{"#" + tray.second->color.substr(0, 6)});
filament_ams_list.emplace_back(std::move(ams));
}
@ -1230,6 +1215,34 @@ void Sidebar::load_ams_list(std::map<std::string, Ams *> const &list)
c->update();
}
void Sidebar::sync_ams_list()
{
auto & list = wxGetApp().preset_bundle->filament_ams_list;
if (list.empty()) {
MessageDialog dlg(this,
_L("No AMS filaments. Please select a printer in 'Device' page to load AMS info."),
_L("Sync filaments with AMS"), wxOK);
dlg.ShowModal();
return;
}
MessageDialog dlg(this,
_L("Sync filaments with AMS will drop all current selected filament presets and colors. Do you want to continue?"),
_L("Sync filaments with AMS"), wxYES_NO);
if (dlg.ShowModal() != wxID_YES) return;
auto n = wxGetApp().preset_bundle->sync_ams_list();
if (n == 0) {
MessageDialog dlg(this,
_L("There are no compatible filaments, and sync is not performed."),
_L("Sync filaments with AMS"), wxOK);
dlg.ShowModal();
return;
}
wxGetApp().plater()->on_filaments_change(n);
for (auto &c : p->combos_filament)
c->update();
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
}
ObjectList* Sidebar::obj_list()
{
// BBS
@ -1690,6 +1703,7 @@ struct Plater::priv
void delete_object_from_model(size_t obj_idx, bool refresh_immediately = true); //BBS
void delete_all_objects_from_model();
void reset(bool apply_presets_change = false);
void center_selection();
void mirror(Axis axis);
void split_object();
void split_volume();
@ -2257,12 +2271,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
//notification_manager = new NotificationManager(this->q);
if (wxGetApp().is_editor()) {
//this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); });
this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); });
this->q->Bind(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, [this](ExportGcodeNotificationClickedEvent&) { this->q->export_gcode(true); });
this->q->Bind(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, [](PresetUpdateAvailableClickedEvent&) { wxGetApp().get_preset_updater()->on_update_notification_confirm(); });
/* BBS do not handle removeable driver event */
/*
this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) {
if (evt.data.second) {
// BBS
@ -2285,14 +2298,13 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// Close notification ExportingFinished but only if last export was to removable
notification_manager->device_ejected();
});
*/
// Start the background thread and register this window as a target for update events.
//wxGetApp().removable_drive_manager()->init(this->q);
//#ifdef _WIN32
// Trigger enumeration of removable media on Win32 notification.
//this->q->Bind(EVT_VOLUME_ATTACHED, [this](VolumeAttachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); });
//this->q->Bind(EVT_VOLUME_DETACHED, [this](VolumeDetachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); });
//#endif /* _WIN32 */
wxGetApp().removable_drive_manager()->init(this->q);
#ifdef _WIN32
//Trigger enumeration of removable media on Win32 notification.
this->q->Bind(EVT_VOLUME_ATTACHED, [this](VolumeAttachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); });
this->q->Bind(EVT_VOLUME_DETACHED, [this](VolumeDetachedEvent &evt) { wxGetApp().removable_drive_manager()->volumes_changed(); });
#endif /* _WIN32 */
}
// Initialize the Undo / Redo stack with a first snapshot.
@ -2601,6 +2613,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
{
std::vector<size_t> empty_result;
bool dlg_cont = true;
bool is_user_cancel = false;
if (input_files.empty()) { return std::vector<size_t>(); }
@ -2713,7 +2726,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// BBS: backup & restore
model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, &config_substitutions, en_3mf_file_type, strategy, &plate_data, &project_presets,
&file_version,
[this, &dlg, real_filename, &progress_percent, &file_percent, stage_percent, INPUT_FILES_RATIO, total_files, i](int import_stage, int current, int total, bool &cancel) {
[this, &dlg, real_filename, &progress_percent, &file_percent, stage_percent, INPUT_FILES_RATIO, total_files, i,
&is_user_cancel](int import_stage, int current, int total, bool &cancel) {
bool cont = true;
float percent_float = (100.0f * (float)i / (float)total_files) + INPUT_FILES_RATIO * ((float)stage_percent[import_stage] + (float)current * (float)(stage_percent[import_stage + 1] - stage_percent[import_stage]) /(float) total) / (float)total_files;
BOOST_LOG_TRIVIAL(trace) << "load_3mf_file: percent(float)=" << percent_float << ", stage = " << import_stage << ", curr = " << current << ", total = " << total;
@ -2721,14 +2735,16 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
wxString msg = wxString::Format(_L("Loading file: %s"), from_path(real_filename));
cont = dlg.Update(progress_percent, msg);
cancel = !cont;
if (cancel)
is_user_cancel = cancel;
});
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__
<< boost::format(", plate_data.size %1%, project_preset.size %2%, is_bbs_3mf %3%, file_version %4% \n") % plate_data.size() %
project_presets.size() % (en_3mf_file_type == En3mfType::From_BBS) % file_version.to_string();
// 1. add extruder for prusa model if the number of existing extruders is not enough
// 2. add extruder for BBS model if only import geometry
if (en_3mf_file_type == En3mfType::From_Prusa || (en_3mf_file_type == En3mfType::From_BBS && load_model && !load_config)) {
// 2. add extruder for BBS or Other model if only import geometry
if (en_3mf_file_type == En3mfType::From_Prusa || (load_model && !load_config)) {
std::set<int> extruderIds;
for (ModelObject *o : model.objects) {
if (o->config.option("extruder")) extruderIds.insert(o->config.extruder());
@ -3038,7 +3054,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
GUI::show_error(q, message);
continue;
} catch (const std::exception &e) {
GUI::show_error(q, e.what());
if (!is_user_cancel)
GUI::show_error(q, e.what());
continue;
}
@ -3100,16 +3117,16 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// convert_model_if(model, answer_convert_from_imperial_units == wxID_YES);
}
// if (model.looks_like_multipart_object()) {
// MessageDialog msg_dlg(q, _L(
// "This file contains several objects positioned at multiple heights.\n"
// "Instead of considering them as multiple objects, should \n"
// "the file be loaded as a single object having multiple parts?") + "\n",
// _L("Multi-part object detected"), wxICON_WARNING | wxYES | wxNO);
// if (msg_dlg.ShowModal() == wxID_YES) {
// model.convert_multipart_object(filaments_cnt);
// }
//}
if (model.looks_like_multipart_object()) {
MessageDialog msg_dlg(q, _L(
"This file contains several objects positioned at multiple heights.\n"
"Instead of considering them as multiple objects, should \n"
"the file be loaded as a single object having multiple parts?") + "\n",
_L("Multi-part object detected"), wxICON_WARNING | wxYES | wxNO);
if (msg_dlg.ShowModal() == wxID_YES) {
model.convert_multipart_object(filaments_cnt);
}
}
}
// else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf) && model_has_advanced_features(model)) {
// MessageDialog msg_dlg(q, _L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?")+"\n",
@ -3271,8 +3288,10 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (tolal_model_count <= 0 && !q->m_exported_file) {
dlg.Hide();
MessageDialog msg(wxGetApp().mainframe, _L("The file does not contain any geometry data."), _L("Warning"), wxYES | wxICON_WARNING);
if (msg.ShowModal() == wxID_YES) {}
if (!is_user_cancel) {
MessageDialog msg(wxGetApp().mainframe, _L("The file does not contain any geometry data."), _L("Warning"), wxYES | wxICON_WARNING);
if (msg.ShowModal() == wxID_YES) {}
}
}
return obj_idxs;
}
@ -3714,6 +3733,11 @@ void Plater::priv::reset(bool apply_presets_change)
m_saved_timestamp = m_backup_timestamp = size_t(-1);
}
void Plater::priv::center_selection()
{
view3D->center_selected();
}
void Plater::priv::mirror(Axis axis)
{
view3D->mirror_selection(axis);
@ -3823,7 +3847,7 @@ void Plater::priv::update_print_volume_state()
//BBS: use the plate's bounding box instead of the bed's
PartPlate* pp = partplate_list.get_curr_plate();
BuildVolume build_volume(pp->get_shape(), this->bed.build_volume().printable_height());
this->q->model().update_print_volume_state(build_volume);
this->model.update_print_volume_state(build_volume);
}
void Plater::priv::process_validation_warning(StringObjectException const &warning) const
@ -3903,7 +3927,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
this->partplate_list.update_slice_context_to_current_plate(background_process);
this->preview->update_gcode_result(partplate_list.get_current_slice_result());
}
Print::ApplyStatus invalidated = background_process.apply(q->model(), wxGetApp().preset_bundle->full_config());
Print::ApplyStatus invalidated = background_process.apply(this->model, wxGetApp().preset_bundle->full_config());
if ((invalidated == Print::APPLY_STATUS_CHANGED) || (invalidated == Print::APPLY_STATUS_INVALIDATED))
// BBS: add only gcode mode
@ -4023,7 +4047,8 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
//BBS: add slice&&print status update logic
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: background data valid, return_state=%2%")%__LINE__%return_state;
if (background_process.finished())
PartPlate* cur_plate = background_process.get_current_plate();
if (background_process.finished() && cur_plate && cur_plate->is_slice_result_valid())
{
ready_to_slice = false;
this->main_frame->update_slice_print_status(MainFrame::eEventSliceUpdate, false);
@ -4291,55 +4316,91 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
void Plater::priv::replace_with_stl()
{
// BBS do not support replace with STL
//if (! q->get_view3D_canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::EType::Undefined))
// return;
if (! q->get_view3D_canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::EType::Undefined))
return;
//const Selection& selection = get_selection();
const Selection& selection = get_selection();
//if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1)
// return;
if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1)
return;
//const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
//int object_idx = v->object_idx();
//int volume_idx = v->volume_idx();
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
int object_idx = v->object_idx();
int volume_idx = v->volume_idx();
//// collects paths of files to load
// collects paths of files to load
//const ModelObject* object = model.objects[object_idx];
//const ModelVolume* volume = object->volumes[volume_idx];
const ModelObject* object = model.objects[object_idx];
const ModelVolume* volume = object->volumes[volume_idx];
//fs::path input_path;
//if (!volume->source.input_file.empty() && fs::exists(volume->source.input_file))
// input_path = volume->source.input_file;
fs::path input_path;
if (!volume->source.input_file.empty() && fs::exists(volume->source.input_file))
input_path = volume->source.input_file;
//wxString title = _L("Select the new file");
//title += ":";
//wxFileDialog dialog(q, title, "", from_u8(input_path.filename().string()), file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
//if (dialog.ShowModal() != wxID_OK)
// return;
wxString title = _L("Select a new file");
title += ":";
wxFileDialog dialog(q, title, "", from_u8(input_path.filename().string()), file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dialog.ShowModal() != wxID_OK)
return;
//fs::path out_path = dialog.GetPath().ToUTF8().data();
//if (out_path.empty()) {
// MessageDialog dlg(q, _L("File for the replace wasn't selected"), _L("Error during replace"), wxOK | wxOK_DEFAULT | wxICON_WARNING);
// dlg.ShowModal();
// return;
//}
fs::path out_path = dialog.GetPath().ToUTF8().data();
if (out_path.empty()) {
MessageDialog dlg(q, _L("File for the replace wasn't selected"), _L("Error during replace"), wxOK | wxOK_DEFAULT | wxICON_WARNING);
dlg.ShowModal();
return;
}
//if (!replace_volume_with_stl(object_idx, volume_idx, out_path, "Replace with STL"))
// return;
if (!replace_volume_with_stl(object_idx, volume_idx, out_path, "Replace with STL"))
return;
//// update 3D scene
//update();
// update 3D scene
update();
//// new GLVolumes have been created at this point, so update their printable state
//for (size_t i = 0; i < model.objects.size(); ++i) {
// view3D->get_canvas3d()->update_instance_printable_state_for_object(i);
//}
// new GLVolumes have been created at this point, so update their printable state
for (size_t i = 0; i < model.objects.size(); ++i) {
view3D->get_canvas3d()->update_instance_printable_state_for_object(i);
}
}
#if ENABLE_RELOAD_FROM_DISK_REWORK
static std::vector<std::pair<int, int>> reloadable_volumes(const Model &model, const Selection &selection)
{
std::vector<std::pair<int, int>> ret;
const std::set<unsigned int> & selected_volumes_idxs = selection.get_volume_idxs();
for (unsigned int idx : selected_volumes_idxs) {
const GLVolume &v = *selection.get_volume(idx);
const int o_idx = v.object_idx();
if (0 <= o_idx && o_idx < int(model.objects.size())) {
const ModelObject *obj = model.objects[o_idx];
const int v_idx = v.volume_idx();
if (0 <= v_idx && v_idx < int(obj->volumes.size())) {
const ModelVolume *vol = obj->volumes[v_idx];
if (!vol->source.is_from_builtin_objects && !vol->source.input_file.empty() && !fs::path(vol->source.input_file).extension().string().empty())
ret.push_back({o_idx, v_idx});
}
}
}
return ret;
}
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
void Plater::priv::reload_from_disk()
{
#if ENABLE_RELOAD_FROM_DISK_REWORK
// collect selected reloadable ModelVolumes
std::vector<std::pair<int, int>> selected_volumes = reloadable_volumes(model, get_selection());
// nothing to reload, return
if (selected_volumes.empty())
return;
std::sort(selected_volumes.begin(), selected_volumes.end(), [](const std::pair<int, int> &v1, const std::pair<int, int> &v2) {
return (v1.first < v2.first) || (v1.first == v2.first && v1.second < v2.second);
});
selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end(), [](const std::pair<int, int> &v1, const std::pair<int, int> &v2) {
return (v1.first == v2.first) && (v1.second == v2.second);
}), selected_volumes.end());
#else
Plater::TakeSnapshot snapshot(q, "Reload from disk");
const Selection& selection = get_selection();
@ -4372,10 +4433,36 @@ void Plater::priv::reload_from_disk()
}
std::sort(selected_volumes.begin(), selected_volumes.end());
selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end()), selected_volumes.end());
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
// collects paths of files to load
std::vector<fs::path> input_paths;
std::vector<fs::path> missing_input_paths;
#if ENABLE_RELOAD_FROM_DISK_REWORK
std::vector<std::pair<fs::path, fs::path>> replace_paths;
for (auto [obj_idx, vol_idx] : selected_volumes) {
const ModelObject *object = model.objects[obj_idx];
const ModelVolume *volume = object->volumes[vol_idx];
if (fs::exists(volume->source.input_file))
input_paths.push_back(volume->source.input_file);
else {
// searches the source in the same folder containing the object
bool found = false;
if (!object->input_file.empty()) {
fs::path object_path = fs::path(object->input_file).remove_filename();
if (!object_path.empty()) {
object_path /= fs::path(volume->source.input_file).filename();
if (fs::exists(object_path)) {
input_paths.push_back(object_path);
found = true;
}
}
}
if (!found)
missing_input_paths.push_back(volume->source.input_file);
}
}
#else
std::vector<fs::path> replace_paths;
for (const SelectedVolume& v : selected_volumes) {
const ModelObject* object = model.objects[v.object_idx];
@ -4405,6 +4492,7 @@ void Plater::priv::reload_from_disk()
else if (!object->input_file.empty() && volume->is_model_part() && !volume->name.empty() && !volume->source.is_from_builtin_objects)
missing_input_paths.push_back(volume->name);
}
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
std::sort(missing_input_paths.begin(), missing_input_paths.end());
missing_input_paths.erase(std::unique(missing_input_paths.begin(), missing_input_paths.end()), missing_input_paths.end());
@ -4446,7 +4534,11 @@ void Plater::priv::reload_from_disk()
wxString message = _devL("Do you want to replace it") + " ?";
MessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() == wxID_YES)
replace_paths.push_back(sel_filename_path);
#if ENABLE_RELOAD_FROM_DISK_REWORK
replace_paths.emplace_back(search, sel_filename_path);
#else
replace_paths.emplace_back(sel_filename_path);
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
missing_input_paths.pop_back();
}
}
@ -4457,6 +4549,10 @@ void Plater::priv::reload_from_disk()
std::sort(replace_paths.begin(), replace_paths.end());
replace_paths.erase(std::unique(replace_paths.begin(), replace_paths.end()), replace_paths.end());
#if ENABLE_RELOAD_FROM_DISK_REWORK
Plater::TakeSnapshot snapshot(q, "Reload from disk");
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
std::vector<wxString> fail_list;
// load one file at a time
@ -4497,6 +4593,93 @@ void Plater::priv::reload_from_disk()
return;
}
#if ENABLE_RELOAD_FROM_DISK_REWORK
for (auto [obj_idx, vol_idx] : selected_volumes) {
ModelObject *old_model_object = model.objects[obj_idx];
ModelVolume *old_volume = old_model_object->volumes[vol_idx];
bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
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());
bool has_name = !old_volume->name.empty() && boost::algorithm::iequals(old_volume->name, fs::path(path).filename().string());
if (has_source || has_name) {
int new_volume_idx = -1;
int new_object_idx = -1;
bool match_found = false;
// take idxs from the matching volume
if (has_source && old_volume->source.object_idx < int(new_model.objects.size())) {
const ModelObject *obj = new_model.objects[old_volume->source.object_idx];
if (old_volume->source.volume_idx < int(obj->volumes.size())) {
if (obj->volumes[old_volume->source.volume_idx]->name == old_volume->name) {
new_volume_idx = old_volume->source.volume_idx;
new_object_idx = old_volume->source.object_idx;
match_found = true;
}
}
}
if (!match_found && has_name) {
// take idxs from the 1st matching volume
for (size_t o = 0; o < new_model.objects.size(); ++o) {
ModelObject *obj = new_model.objects[o];
bool found = false;
for (size_t v = 0; v < obj->volumes.size(); ++v) {
if (obj->volumes[v]->name == old_volume->name) {
new_volume_idx = (int) v;
new_object_idx = (int) o;
found = true;
break;
}
}
if (found) break;
}
}
if (new_object_idx < 0 || int(new_model.objects.size()) <= new_object_idx) {
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
continue;
}
ModelObject *new_model_object = new_model.objects[new_object_idx];
if (new_volume_idx < 0 || int(new_model_object->volumes.size()) <= new_volume_idx) {
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
continue;
}
old_model_object->add_volume(*new_model_object->volumes[new_volume_idx]);
ModelVolume *new_volume = old_model_object->volumes.back();
new_volume->set_new_unique_id();
new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
#if 0// ENABLE_WORLD_COORDINATE
new_volume->set_transformation(Geometry::translation_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix_no_offset() * old_volume->source.transform.get_matrix_no_offset());
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#else
new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) * old_volume->get_transformation().get_matrix(true) *
old_volume->source.transform.get_matrix(true));
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#endif // ENABLE_WORLD_COORDINATE
new_volume->source.object_idx = old_volume->source.object_idx;
new_volume->source.volume_idx = old_volume->source.volume_idx;
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units();
else if (old_volume->source.is_converted_from_meters)
new_volume->convert_from_meters();
std::swap(old_model_object->volumes[vol_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
if (!sinking) old_model_object->ensure_on_bed();
old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
sla::reproject_points_and_holes(old_model_object);
// Fix warning icon in object list
wxGetApp().obj_list()->update_item_error_icon(obj_idx, vol_idx);
}
}
#else
// update the selected volumes whose source is the current file
for (const SelectedVolume& sel_v : selected_volumes) {
ModelObject* old_model_object = model.objects[sel_v.object_idx];
@ -4566,8 +4749,17 @@ void Plater::priv::reload_from_disk()
sla::reproject_points_and_holes(old_model_object);
}
}
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
}
#if ENABLE_RELOAD_FROM_DISK_REWORK
for (auto [src, dest] : replace_paths) {
for (auto [obj_idx, vol_idx] : selected_volumes) {
if (boost::algorithm::iequals(model.objects[obj_idx]->volumes[vol_idx]->source.input_file, src.string()))
replace_volume_with_stl(obj_idx, vol_idx, dest, "");
}
}
#else
for (size_t i = 0; i < replace_paths.size(); ++i) {
const auto& path = replace_paths[i].string();
for (const SelectedVolume& sel_v : selected_volumes) {
@ -4579,6 +4771,7 @@ void Plater::priv::reload_from_disk()
}
}
}
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
if (!fail_list.empty()) {
wxString message = _devL("Unable to reload:") + "\n";
@ -4893,6 +5086,10 @@ void Plater::priv::on_select_bed_type(wxCommandEvent &evt)
config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(bed_type));
// update plater with new config
q->on_config_change(wxGetApp().preset_bundle->full_config());
// update app_config
AppConfig *app_config = wxGetApp().app_config;
app_config->set("curr_bed_type", std::to_string(int(bed_type)));
}
}
}
@ -5257,16 +5454,16 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
notification_manager->close_notification_of_type(NotificationType::ExportOngoing);
}
// If writing to removable drive was scheduled, show notification with eject button
/*if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
//show_action_buttons(ready_to_slice);
this->main_frame->update_slice_print_status(MainFrame::eEventSliceUpdate, ready_to_slice, true);
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path,
// Don't offer the "Eject" button on ChromeOS, the Linux side has no control over it.
platform_flavor() != PlatformFlavor::LinuxOnChromium);
//wxGetApp().removable_drive_manager()->set_exporting_finished(true);
}else */
//if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
// notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
}else
if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
}
exporting_status = ExportingStatus::NOT_EXPORTING;
@ -6033,6 +6230,13 @@ bool Plater::priv::can_replace_with_stl() const
bool Plater::priv::can_reload_from_disk() const
{
#if ENABLE_RELOAD_FROM_DISK_REWORK
// collect selected reloadable ModelVolumes
std::vector<std::pair<int, int>> selected_volumes = reloadable_volumes(model, get_selection());
// nothing to reload, return
if (selected_volumes.empty())
return false;
#else
// struct to hold selected ModelVolumes by their indices
struct SelectedVolume
{
@ -6058,6 +6262,22 @@ bool Plater::priv::can_reload_from_disk() const
selected_volumes.push_back({ o_idx, v_idx });
}
}
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
#if ENABLE_RELOAD_FROM_DISK_REWORK
std::sort(selected_volumes.begin(), selected_volumes.end(), [](const std::pair<int, int> &v1, const std::pair<int, int> &v2) {
return (v1.first < v2.first) || (v1.first == v2.first && v1.second < v2.second);
});
selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end(), [](const std::pair<int, int> &v1, const std::pair<int, int> &v2) {
return (v1.first == v2.first) && (v1.second == v2.second);
}), selected_volumes.end());
// collects paths of files to load
std::vector<fs::path> paths;
for (auto [obj_idx, vol_idx] : selected_volumes) {
paths.push_back(model.objects[obj_idx]->volumes[vol_idx]->source.input_file);
}
#else
std::sort(selected_volumes.begin(), selected_volumes.end());
selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end()), selected_volumes.end());
@ -6071,6 +6291,7 @@ bool Plater::priv::can_reload_from_disk() const
else if (!object->input_file.empty() && !volume->name.empty() && !volume->source.is_from_builtin_objects)
paths.push_back(volume->name);
}
#endif // ENABLE_RELOAD_FROM_DISK_REWORK
std::sort(paths.begin(), paths.end());
paths.erase(std::unique(paths.begin(), paths.end()), paths.end());
@ -6607,7 +6828,8 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame)
bool Plater::Show(bool show)
{
wxGetApp().mainframe->show_option(show);
if (wxGetApp().mainframe)
wxGetApp().mainframe->show_option(show);
return wxPanel::Show(show);
}
@ -8031,16 +8253,16 @@ void Plater::export_gcode(bool prefer_removable)
}
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
AppConfig &appconfig = *wxGetApp().app_config;
//RemovableDriveManager &removable_drive_manager = *wxGetApp().removable_drive_manager();
RemovableDriveManager &removable_drive_manager = *wxGetApp().removable_drive_manager();
// Get a last save path, either to removable media or to an internal media.
std::string start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), prefer_removable);
/*if (prefer_removable) {
if (prefer_removable) {
// Returns a path to a removable media if it exists, prefering start_dir. Update the internal removable drives database.
start_dir = removable_drive_manager.get_removable_drive_path(start_dir);
if (start_dir.empty())
// Direct user to the last internal media.
start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), false);
}*/
}
fs::path output_path;
{
@ -8068,8 +8290,8 @@ void Plater::export_gcode(bool prefer_removable)
}
if (! output_path.empty()) {
//bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
bool path_on_removable_media = false;
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
//bool path_on_removable_media = false;
p->notification_manager->new_export_began(path_on_removable_media);
p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL;
p->last_output_path = output_path.string();
@ -8138,13 +8360,20 @@ void Plater::export_gcode_3mf()
p->notification_manager->new_export_began(path_on_removable_media);
p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL;
//BBS do not save last output path
//p->last_output_path = output_path.string();
p->last_output_path = output_path.string();
p->last_output_dir_path = output_path.parent_path().string();
int curr_plate_idx = get_partplate_list().get_curr_plate_index();
export_3mf(output_path, SaveStrategy::Silence | SaveStrategy::SplitModel | SaveStrategy::WithGcode | SaveStrategy::SkipModel, curr_plate_idx); // BBS: silence
// update lost output dir
RemovableDriveManager& removable_drive_manager = *wxGetApp().removable_drive_manager();
bool on_removable = removable_drive_manager.is_path_on_removable_drive(p->last_output_dir_path);
// update last output dir
appconfig.update_last_output_dir(output_path.parent_path().string(), false);
p->notification_manager->push_exporting_finished_notification(output_path.string(), p->last_output_dir_path, false);
p->notification_manager->push_exporting_finished_notification(output_path.string(), p->last_output_dir_path, on_removable);
}
}
@ -8556,6 +8785,7 @@ void Plater::reslice()
if (p->process_completed_with_error)
{
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": process_completed_with_error, return directly");
reset_gcode_toolpaths();
return;
}
@ -8830,11 +9060,12 @@ void Plater::print_job_finished(wxCommandEvent &evt)
}
// Called when the Eject button is pressed.
/*void Plater::eject_drive()
void Plater::eject_drive()
{
wxBusyCursor wait;
wxGetApp().removable_drive_manager()->eject_drive();
}*/
wxBusyCursor wait;
wxGetApp().removable_drive_manager()->set_and_verify_last_save_path(p->last_output_dir_path);
wxGetApp().removable_drive_manager()->eject_drive();
}
void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); }
//void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); }
@ -9367,6 +9598,7 @@ void Plater::suppress_background_process(const bool stop_background_process)
this->p->suppressed_backround_processing_update = true;
}
void Plater::center_selection() { p->center_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); }

View file

@ -117,7 +117,8 @@ public:
void on_filaments_change(size_t num_filaments);
// BBS
void on_bed_type_change(BedType bed_type);
void load_ams_list(std::map<std::string, Ams *> const & list);
void load_ams_list(std::map<std::string, Ams *> const &list);
void sync_ams_list();
ObjectList* obj_list();
ObjectSettings* obj_settings();
@ -333,7 +334,7 @@ public:
int export_config_3mf(int plate_idx = -1, Export3mfProgressFn proFn = nullptr);
//BBS jump to nonitor after print job finished
void print_job_finished(wxCommandEvent &evt);
//void eject_drive();
void eject_drive();
void take_snapshot(const std::string &snapshot_name);
//void take_snapshot(const wxString &snapshot_name);
@ -412,6 +413,7 @@ public:
void paste_from_clipboard();
//BBS: add clone logic
void clone_selection();
void center_selection();
void search(bool plater_is_active, Preset::Type type, wxWindow *tag, wxTextCtrl *etag, wxWindow *stag);
void mirror(Axis axis);
void split_object();

View file

@ -244,16 +244,6 @@ int PresetComboBox::update_ams_color()
return idx;
}
static std::string suffix(const Preset& preset)
{
return (preset.is_dirty ? Preset::suffix_modified() : "");
}
static std::string suffix(Preset* preset)
{
return (preset->is_dirty ? Preset::suffix_modified() : "");
}
wxColor PresetComboBox::different_color(wxColor const &clr)
{
if (clr.GetLuminance() < 0.51) return *wxWHITE;
@ -387,11 +377,11 @@ void PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
m_first_ams_filament = GetCount();
auto &filaments = m_collection->get_presets();
for (auto &f : m_preset_bundle->filament_ams_list) {
std::string setting_id = f.opt_string("filament_settings_id", 0u);
std::string filament_id = f.opt_string("filament_id", 0u);
auto iter = std::find_if(filaments.begin(), filaments.end(),
[&setting_id](auto &f) { return f.is_compatible && f.is_system && f.filament_id == setting_id; });
[&filament_id](auto &f) { return f.is_compatible && f.is_system && f.filament_id == filament_id; });
if (iter == filaments.end()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % setting_id;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
continue;
}
const_cast<Preset&>(*iter).is_visible = true;
@ -771,7 +761,7 @@ void PlaterPresetComboBox::switch_to_tab()
if (m_type == Preset::TYPE_FILAMENT)
{
const std::string& selected_preset = GetString(GetSelection()).ToUTF8().data();
if (!boost::algorithm::ends_with(selected_preset, Preset::suffix_modified()))
if (!boost::algorithm::starts_with(selected_preset, Preset::suffix_modified()))
{
const std::string& preset_name = wxGetApp().preset_bundle->filaments.get_preset_name_by_alias(selected_preset);
wxGetApp().get_tab(m_type)->select_preset(preset_name);
@ -869,8 +859,7 @@ void PlaterPresetComboBox::show_edit_menu()
wxString PlaterPresetComboBox::get_preset_name(const Preset& preset)
{
std::string name = preset.alias.empty() ? preset.name : preset.alias;
return from_u8(name + suffix(preset));
return from_u8(preset.label(false));
}
// Only the compatible presets are shown.
@ -979,10 +968,10 @@ void PlaterPresetComboBox::update()
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
if (preset.is_default || preset.is_system) {
//BBS: move system to the end
system_presets.emplace(wxString::FromUTF8((name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), bmp);
system_presets.emplace(get_preset_name(preset), bmp);
if (is_selected) {
tooltip = get_tooltip(preset);
selected_system_preset = wxString::FromUTF8((name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
selected_system_preset = get_preset_name(preset);
}
//Append(get_preset_name(preset), *bmp);
//validate_selection(is_selected);
@ -993,9 +982,9 @@ void PlaterPresetComboBox::update()
//BBS: add project embedded preset logic
else if (preset.is_project_embedded)
{
project_embedded_presets.emplace(wxString::FromUTF8((name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), bmp);
project_embedded_presets.emplace(get_preset_name(preset), bmp);
if (is_selected) {
selected_user_preset = wxString::FromUTF8((name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
selected_user_preset = get_preset_name(preset);
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
@ -1166,7 +1155,7 @@ void TabPresetComboBox::OnSelect(wxCommandEvent &evt)
wxString TabPresetComboBox::get_preset_name(const Preset& preset)
{
return from_u8(preset.name + suffix(preset));
return from_u8(preset.label(true));
}
// Update the choice UI from the list of presets.
@ -1221,9 +1210,9 @@ void TabPresetComboBox::update()
if (preset.is_default || preset.is_system) {
//BBS: move system to the end
system_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), std::pair<wxBitmap*, bool>(bmp, is_enabled));
system_presets.emplace(get_preset_name(preset), std::pair<wxBitmap *, bool>(bmp, is_enabled));
if (i == idx_selected)
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
selected = get_preset_name(preset);
//int item_id = Append(get_preset_name(preset), *bmp);
//if (!is_enabled)
// set_label_marker(item_id, LABEL_ITEM_DISABLED);
@ -1233,9 +1222,9 @@ void TabPresetComboBox::update()
else if (preset.is_project_embedded)
{
//std::pair<wxBitmap*, bool> pair(bmp, is_enabled);
project_embedded_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), std::pair<wxBitmap*, bool>(bmp, is_enabled));
project_embedded_presets.emplace(get_preset_name(preset), std::pair<wxBitmap *, bool>(bmp, is_enabled));
if (i == idx_selected)
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
selected = get_preset_name(preset);
}
else
{
@ -1364,7 +1353,7 @@ void TabPresetComboBox::update_dirty()
Preset* preset = m_collection->find_preset(preset_name, false);
if (preset) {
std::string new_label = preset->name + suffix(preset);
std::string new_label = preset->label(true);
if (marker == LABEL_ITEM_PHYSICAL_PRINTER)
new_label = ph_printer_name + PhysicalPrinter::separator() + new_label;

View file

@ -108,7 +108,7 @@ wxBoxSizer* PrintOptionsDialog::create_settings_group(wxWindow* parent)
auto sizer = new wxBoxSizer(wxVERTICAL);
auto line_sizer = new wxBoxSizer(wxHORIZONTAL);
m_cb_spaghetti = new CheckBox(parent);
text_spaghetti = new wxStaticText(parent, wxID_ANY, _L("Spaghetti Detection"));
text_spaghetti = new wxStaticText(parent, wxID_ANY, _L("Spaghetti and Excess Chute Pileup Detection"));
text_spaghetti->SetFont(Label::Body_14);
line_sizer->Add(FromDIP(5), 0, 0, 0);
line_sizer->Add(m_cb_spaghetti, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5));
@ -117,7 +117,7 @@ wxBoxSizer* PrintOptionsDialog::create_settings_group(wxWindow* parent)
line_sizer = new wxBoxSizer(wxHORIZONTAL);
m_cb_spaghetti_print_halt = new CheckBox(parent);
text_spaghetti_print_halt = new wxStaticText(parent, wxID_ANY, _L("Stop printing when spaghetti detected"));
text_spaghetti_print_halt = new wxStaticText(parent, wxID_ANY, _L("Stop printing when Spaghetti or Excess Chute Pileup is detected"));
text_spaghetti_print_halt->SetFont(Label::Body_14);
line_sizer->Add(FromDIP(30), 0, 0, 0);
line_sizer->Add(m_cb_spaghetti_print_halt, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5));

View file

@ -27,7 +27,6 @@ struct StaticBambuLib : BambuLib {
PrinterFileSystem::PrinterFileSystem()
: BambuLib(StaticBambuLib::get())
, m_recv_thread(&PrinterFileSystem::RecvMessageThread, this)
{
if (!default_thumbnail.IsOk())
default_thumbnail = wxImage(Slic3r::encode_path(Slic3r::var("live_stream_default.png").c_str()));
@ -41,7 +40,9 @@ PrinterFileSystem::PrinterFileSystem()
}
PrinterFileSystem::~PrinterFileSystem()
{ m_recv_thread.detach(); }
{
m_recv_thread.detach();
}
void PrinterFileSystem::SetFileType(FileType type)
{
@ -251,6 +252,15 @@ int PrinterFileSystem::RecvData(std::function<int(Bambu_Sample& sample)> const &
return result;
}
void PrinterFileSystem::Attached()
{
boost::unique_lock lock(m_mutex);
m_recv_thread = std::move(boost::thread([w = weak_from_this()] {
boost::shared_ptr<PrinterFileSystem> s = w.lock();
if (s) s->RecvMessageThread();
}));
}
void PrinterFileSystem::Start()
{
boost::unique_lock l(m_mutex);
@ -277,8 +287,6 @@ void PrinterFileSystem::Stop(bool quit)
boost::unique_lock l(m_mutex);
if (quit) {
m_session.owner = nullptr;
// let the thread delete this
m_callbacks.push_back([thiz = shared_from_this()](int result, json const &, unsigned char const *) { (void) thiz; });
} else if (m_stopped) {
return;
}
@ -490,6 +498,8 @@ size_t PrinterFileSystem::FindFile(size_t index, std::string const &name)
void PrinterFileSystem::FileRemoved(size_t index, std::string const &name)
{
index = FindFile(index, name);
if (index == size_t(-1))
return;
auto removeFromGroup = [](std::vector<size_t> &group, size_t index, int total) {
for (auto iter = group.begin(); iter != group.end(); ++iter) {
size_t index2 = -1;
@ -622,7 +632,7 @@ void PrinterFileSystem::RecvMessageThread()
if (m_stopped && (m_session.owner == nullptr || (m_messages.empty() && m_callbacks.empty()))) {
Reconnect(l, 0); // Close and wait start again
if (m_session.owner == nullptr) {
// clear callbacks may invoke destructor, so clear first
// clear callbacks first
auto callbacks(std::move(m_callbacks));
break;
}

View file

@ -149,6 +149,8 @@ public:
Status GetStatus() const { return m_status; }
int GetLastError() const { return m_last_error; }
void Attached();
void Start();
void Retry();

View file

@ -11,6 +11,7 @@
#include "Widgets/ProgressDialog.hpp"
#include "Widgets/RoundedRectangle.hpp"
#include "Widgets/StaticBox.hpp"
#include "Widgets/WebView.hpp"
#include <wx/progdlg.h>
#include <wx/clipbrd.h>
@ -129,11 +130,25 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
m_sizer_right->Add(0, 0, 1, wxTOP, FromDIP(15));
m_scrollwindw_release_note = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(560), FromDIP(430)), wxVSCROLL);
m_scrollwindw_release_note->SetScrollRate(5, 5);
//webview
m_scrollwindw_release_note = CreateTipView(this);
m_scrollwindw_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8));
m_scrollwindw_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430)));
m_scrollwindw_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430)));
m_scrollwindw_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
fs::path ph(data_dir());
ph /= "resources/tooltip/common/releasenote.html";
if (!fs::exists(ph)) {
ph = resources_dir();
ph /= "tooltip/releasenote.html";
}
auto url = ph.string();
std::replace(url.begin(), url.end(), '\\', '/');
url = "file:///" + url;
m_scrollwindw_release_note->LoadURL(from_u8(url));
m_remind_choice = new wxCheckBox( this, wxID_ANY, _L("Don't remind me of this version again"), wxDefaultPosition, wxDefaultSize, 0 );
m_remind_choice->SetValue(false);
m_remind_choice->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &UpdateVersionDialog::alter_choice,this);
@ -194,21 +209,95 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
UpdateVersionDialog::~UpdateVersionDialog() {}
wxWebView* UpdateVersionDialog::CreateTipView(wxWindow* parent)
{
wxWebView* tipView = WebView::CreateWebView(parent, "");
tipView->Bind(wxEVT_WEBVIEW_LOADED, &UpdateVersionDialog::OnLoaded, this);
tipView->Bind(wxEVT_WEBVIEW_NAVIGATED, &UpdateVersionDialog::OnTitleChanged, this);
tipView->Bind(wxEVT_WEBVIEW_ERROR, &UpdateVersionDialog::OnError, this);
return tipView;
}
void UpdateVersionDialog::OnLoaded(wxWebViewEvent& event)
{
event.Skip();
}
void UpdateVersionDialog::OnTitleChanged(wxWebViewEvent& event)
{
//ShowReleaseNote();
event.Skip();
}
void UpdateVersionDialog::OnError(wxWebViewEvent& event)
{
event.Skip();
}
static std::string url_encode(const std::string& value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char)c);
escaped << std::nouppercase;
}
return escaped.str();
}
bool UpdateVersionDialog::ShowReleaseNote(std::string content)
{
auto script = "window.showMarkdown('" + url_encode(content) + "', true);";
RunScript(script);
return true;
}
void UpdateVersionDialog::RunScript(std::string script)
{
WebView::RunScript(m_scrollwindw_release_note, script);
script.clear();
}
void UpdateVersionDialog::on_dpi_changed(const wxRect &suggested_rect) {
m_button_ok->Rescale();
m_button_cancel->Rescale();
}
void UpdateVersionDialog::update_version_info(wxString release_note, wxString version)
void UpdateVersionDialog::update_version_info(std::string url)
{
m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version));
/*m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version));
wxBoxSizer *sizer_text_release_note = new wxBoxSizer(wxVERTICAL);
auto m_staticText_release_note = new wxStaticText(m_scrollwindw_release_note, wxID_ANY, release_note, wxDefaultPosition, wxDefaultSize, 0);
m_staticText_release_note->Wrap(FromDIP(530));
sizer_text_release_note->Add(m_staticText_release_note, 0, wxALL, 5);
m_scrollwindw_release_note->SetSizer(sizer_text_release_note);
m_scrollwindw_release_note->Layout();
m_scrollwindw_release_note->Layout();*/
if (url.empty()) {
fs::path ph(data_dir());
ph /= "resources/tooltip/common/releasenote.html";
if (!fs::exists(ph)) {
ph = resources_dir();
ph /= "tooltip/releasenote.html";
}
auto url = ph.string();
std::replace(url.begin(), url.end(), '\\', '/');
url = "file:///" + url;
m_scrollwindw_release_note->LoadURL(from_u8(url));
}
else {
m_scrollwindw_release_note->LoadURL(from_u8(url));
}
}
}} // namespace Slic3r::GUI

View file

@ -33,6 +33,7 @@
#include "Widgets/ComboBox.hpp"
#include "Widgets/ScrolledWindow.hpp"
#include <wx/hashmap.h>
#include <wx/webview.h>
namespace Slic3r { namespace GUI {
@ -55,12 +56,18 @@ public:
UpdateVersionDialog(wxWindow *parent = nullptr);
~UpdateVersionDialog();
void on_dpi_changed(const wxRect &suggested_rect) override;
void update_version_info(wxString release_note, wxString version);
wxWebView* CreateTipView(wxWindow* parent);
void OnLoaded(wxWebViewEvent& event);
void OnTitleChanged(wxWebViewEvent& event);
void OnError(wxWebViewEvent& event);
bool ShowReleaseNote(std::string content);
void RunScript(std::string script);
void on_dpi_changed(const wxRect& suggested_rect) override;
void update_version_info(std::string url);
void alter_choice(wxCommandEvent& event);
wxStaticText * m_text_up_info{nullptr};
wxScrolledWindow *m_scrollwindw_release_note{nullptr};
wxWebView* m_scrollwindw_release_note{nullptr};
wxBoxSizer * sizer_text_release_note{nullptr};
wxStaticText * m_staticText_release_note{nullptr};
wxCheckBox* m_remind_choice;

View file

@ -387,6 +387,7 @@ std::string RemovableDriveManager::get_removable_drive_from_path(const std::stri
void RemovableDriveManager::init(wxEvtHandler *callback_evt_handler)
{
//no need use assert
assert(! m_initialized);
assert(m_callback_evt_handler == nullptr);
@ -442,7 +443,14 @@ bool RemovableDriveManager::set_and_verify_last_save_path(const std::string &pat
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
#ifdef __APPLE__
m_last_save_path = path;
#else
m_last_save_path = this->get_removable_drive_from_path(path);
#endif
m_exporting_finished = false;
return ! m_last_save_path.empty();
}

View file

@ -49,7 +49,7 @@ public:
RemovableDriveManager() = default;
RemovableDriveManager(RemovableDriveManager const&) = delete;
void operator=(RemovableDriveManager const&) = delete;
~RemovableDriveManager() { assert(! m_initialized); }
~RemovableDriveManager() { /*assert(! m_initialized);*/ }
// Start the background thread and register this window as a target for update events.
// Register for OSX notifications.

View file

@ -1927,7 +1927,7 @@ void SelectMachineDialog::on_selection_changed(wxCommandEvent &event)
void SelectMachineDialog::update_ams_check(MachineObject* obj)
{
if (obj && obj->ams_support_use_ams) {
if (obj && obj->ams_support_use_ams && obj->has_ams()) {
select_use_ams->Show();
} else {
select_use_ams->Hide();
@ -1991,6 +1991,18 @@ void SelectMachineDialog::update_show_status()
reset_timeout();
update_ams_check(obj_);
// do ams mapping if no ams result
if (obj_->has_ams() && m_ams_mapping_result.empty()) {
if (obj_->ams_support_use_ams) {
if (ams_check->GetValue()) {
do_ams_mapping(obj_);
} else {
m_ams_mapping_result.clear();
sync_ams_mapping_result(m_ams_mapping_result);
}
}
}
// reading done
if (obj_->is_in_upgrading()) {
show_status(PrintDialogStatus::PrintStatusInUpgrading);
@ -2214,7 +2226,9 @@ void SelectMachineDialog::set_default()
}
// material info
auto extruders = m_plater->get_partplate_list().get_curr_plate()->get_extruders();
//auto extruders1 = m_plater->get_partplate_list().get_curr_plate()->get_extruders();
auto extruders = wxGetApp().plater()->get_preview_canvas3D()->get_gcode_viewer().get_plater_extruder();
BitmapCache bmcache;
MaterialHash::iterator iter = m_materialList.begin();

Some files were not shown because too many files have changed in this diff Show more