mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-23 06:33:57 -06:00
Merge mainstream changes
This commit is contained in:
commit
764b7d62a0
204 changed files with 5425 additions and 1411 deletions
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
|
||||
|
|
|
@ -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()]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ¶ms)
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¶ms);
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 ¶ms, 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_
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 < : 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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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") {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
57
src/platform/unix/BuildLinuxImage.sh.in
Normal file
57
src/platform/unix/BuildLinuxImage.sh.in
Normal 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
|
30
src/platform/unix/build_appimage.sh.in
Normal file
30
src/platform/unix/build_appimage.sh.in
Normal 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}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
173
src/slic3r/GUI/ConfirmHintDialog.cpp
Normal file
173
src/slic3r/GUI/ConfirmHintDialog.cpp
Normal 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
|
45
src/slic3r/GUI/ConfirmHintDialog.hpp
Normal file
45
src/slic3r/GUI/ConfirmHintDialog.hpp
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -149,6 +149,8 @@ public:
|
|||
Status GetStatus() const { return m_status; }
|
||||
int GetLastError() const { return m_last_error; }
|
||||
|
||||
void Attached();
|
||||
|
||||
void Start();
|
||||
|
||||
void Retry();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue