Fixed conflicts after merge with master

This commit is contained in:
enricoturri1966 2020-03-25 14:41:47 +01:00
commit f12b39be25
171 changed files with 23530 additions and 14236 deletions

View file

@ -132,14 +132,18 @@ int CLI::run(int argc, char **argv)
Model model;
try {
// When loading an AMF or 3MF, config is imported as well, including the printer technology.
model = Model::read_from_file(file, &m_print_config, true);
PrinterTechnology other_printer_technology = get_printer_technology(m_print_config);
DynamicPrintConfig config;
model = Model::read_from_file(file, &config, true);
PrinterTechnology other_printer_technology = get_printer_technology(config);
if (printer_technology == ptUnknown) {
printer_technology = other_printer_technology;
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl;
return 1;
}
// config is applied to m_print_config before the current m_config values.
config += std::move(m_print_config);
m_print_config = std::move(config);
} catch (std::exception &e) {
boost::nowide::cerr << file << ": " << e.what() << std::endl;
return 1;
@ -642,6 +646,14 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn
<< "Other options:" << std::endl;
cli_misc_config_def.print_cli_help(boost::nowide::cout, false);
boost::nowide::cout
<< std::endl
<< "Print options are processed in the following order:" << std::endl
<< "\t1) Config keys from the command line, for example --fill-pattern=stars" << std::endl
<< "\t (highest priority, overwrites everything below)" << std::endl
<< "\t2) Config files loaded with --load" << std::endl
<< "\t3) Config values loaded from amf or 3mf files" << std::endl;
if (include_print_options) {
boost::nowide::cout << std::endl;
print_config_def.print_cli_help(boost::nowide::cout, true, [printer_technology](const ConfigOptionDef &def)

View file

@ -159,7 +159,7 @@ static int hid_wrapper_udev_init()
{
// Error, close the shared library handle and finish.
hid_wrapper_udev_close();
return -1;
return -2;
}
// Success.

5
src/imgui/README.md Normal file
View file

@ -0,0 +1,5 @@
** Dear ImGui is a bloat-free graphical user interface library for C++.**
For more information go to https://github.com/ocornut/imgui
THIS DIRECTORY CONTAINS THE imgui-1.75 58b3e02 SOURCE DISTRIBUTION.

View file

@ -3,10 +3,10 @@
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h)
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h)
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h"
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ dear imgui is used, which include
// the imgui*.cpp files but also _any_ of your code that uses imgui. This is because some compile-time options have an affect on data structures.
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include
// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
@ -14,25 +14,32 @@
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows.
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty)
//---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp.
//#define IMGUI_DISABLE_DEMO_WINDOWS
//---- Disable all of Dear ImGui or don't implement standard windows.
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf.
//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h.
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//---- Include imgui_user.h at the end of imgui.h as a convenience
@ -48,6 +55,10 @@
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library.
// Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
// #define IMGUI_USE_STB_SPRINTF
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
@ -60,9 +71,31 @@
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it.
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
// This adds a small runtime cost which is why it is not enabled by default.
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,10 @@
// stb_rect_pack.h - v0.11 - public domain - rectangle packing
// [DEAR IMGUI]
// This is a slightly modified version of stb_rect_pack.h 1.00.
// Those changes would need to be pushed into nothings/stb:
// - Added STBRP__CDECL
// Grep for [DEAR IMGUI] to find the changes.
// stb_rect_pack.h - v1.00 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
@ -31,9 +37,12 @@
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
//
// Version history:
//
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
@ -204,6 +213,7 @@ struct stbrp_context
#define STBRP_ASSERT assert
#endif
// [DEAR IMGUI] Added STBRP__CDECL
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
@ -349,6 +359,13 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
// if it can't possibly fit, bail immediately
if (width > c->width || height > c->height) {
fr.prev_link = NULL;
fr.x = fr.y = 0;
return fr;
}
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
@ -412,7 +429,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height < c->height) {
if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
@ -512,6 +529,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
return res;
}
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
@ -523,6 +541,7 @@ static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
return (p->w > q->w) ? -1 : (p->w < q->w);
}
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
@ -543,9 +562,6 @@ STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int nu
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
#endif
}
// sort according to heuristic

View file

@ -1,9 +1,10 @@
// [ImGui] this is a slightly modified version of stb_textedit.h 1.12. Those changes would need to be pushed into nothings/stb
// [ImGui] - 2018-06: fixed undo/redo after pasting large amount of text (over 32 kb). Redo will still fail when undo buffers are exhausted, but text won't be corrupted (see nothings/stb issue #620)
// [ImGui] - 2018-06: fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
// [ImGui] - fixed some minor warnings
// [DEAR IMGUI]
// This is a slightly modified version of stb_textedit.h 1.13.
// Those changes would need to be pushed into nothings/stb:
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
// Grep for [DEAR IMGUI] to find the changes.
// stb_textedit.h - v1.12 - public domain - Sean Barrett
// stb_textedit.h - v1.13 - public domain - Sean Barrett
// Development of this library was sponsored by RAD Game Tools
//
// This C header file implements the guts of a multi-line text-editing
@ -34,6 +35,7 @@
//
// VERSION HISTORY
//
// 1.13 (2019-02-07) fix bug in undo size management
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
@ -563,7 +565,6 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
// now scan to find xpos
find->x = r.x0;
i = 0;
for (i=0; first+i < n; ++i)
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
}
@ -693,7 +694,7 @@ static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state)
static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
if (STB_TEXT_HAS_SELECTION(state)) {
stb_textedit_delete_selection(str,state); // implicity clamps
stb_textedit_delete_selection(str,state); // implicitly clamps
state->has_preferred_x = 0;
return 1;
}
@ -745,7 +746,7 @@ retry:
state->has_preferred_x = 0;
}
} else {
stb_textedit_delete_selection(str,state); // implicity clamps
stb_textedit_delete_selection(str,state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
stb_text_makeundo_insert(state, state->cursor, 1);
++state->cursor;
@ -1133,7 +1134,14 @@ static void stb_textedit_discard_redo(StbUndoState *state)
state->undo_rec[i].char_storage += n;
}
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
// {DEAR IMGUI]
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
// now move redo_point to point to the new one
++state->redo_point;
}

View file

@ -1,4 +1,9 @@
// stb_truetype.h - v1.19 - public domain
// [DEAR IMGUI]
// This is a slightly modified version of stb_truetype.h 1.20.
// Mostly fixing for compiler and static analyzer warnings.
// Grep for [DEAR IMGUI] to find the changes.
// stb_truetype.h - v1.20 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
//
// This library processes TrueType files:
@ -49,6 +54,7 @@
//
// VERSION HISTORY
//
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
// 1.18 (2018-01-29) add missing function
// 1.17 (2017-07-23) make more arguments const; doc fix
@ -75,7 +81,7 @@
//
// USAGE
//
// Include this file in whatever places neeed to refer to it. In ONE C/C++
// Include this file in whatever places need to refer to it. In ONE C/C++
// file, write:
// #define STB_TRUETYPE_IMPLEMENTATION
// before the #include of this file. This expands out the actual
@ -247,8 +253,8 @@
// Documentation & header file 520 LOC \___ 660 LOC documentation
// Sample code 140 LOC /
// Truetype parsing 620 LOC ---- 620 LOC TrueType
// Software rasterization 240 LOC \ .
// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation
// Software rasterization 240 LOC \.
// Curve tessellation 120 LOC \__ 550 LOC Bitmap creation
// Bitmap management 100 LOC /
// Baked bitmap interface 70 LOC /
// Font name matching & access 150 LOC ---- 150
@ -556,6 +562,8 @@ STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int p
//
// It's inefficient; you might want to c&p it and optimize it.
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
// Query the font vertical metrics without having to create a font first.
//////////////////////////////////////////////////////////////////////////////
@ -641,6 +649,12 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
// To use with PackFontRangesGather etc., you must set it before calls
// call to PackFontRangesGatherRects.
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
// If skip != 0, this tells stb_truetype to skip any codepoints for which
// there is no corresponding glyph. If skip=0, which is the default, then
// codepoints without a glyph recived the font's "missing character" glyph,
// typically an empty box by convention.
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
int char_index, // character to display
float *xpos, float *ypos, // pointers to current position in screen pixel space
@ -669,6 +683,7 @@ struct stbtt_pack_context {
int height;
int stride_in_bytes;
int padding;
int skip_missing;
unsigned int h_oversample, v_oversample;
unsigned char *pixels;
void *nodes;
@ -694,7 +709,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
// file will only define one font and it always be at offset 0, so it will
// return '0' for index 0, and -1 for all other indices.
// The following structure is defined publically so you can declare one on
// The following structure is defined publicly so you can declare one on
// the stack or as a global or etc, but you should treat it as opaque.
struct stbtt_fontinfo
{
@ -733,6 +748,7 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep
// and you want a speed-up, call this function with the character you're
// going to process, then use glyph-based functions instead of the
// codepoint-based functions.
// Returns 0 if the character codepoint is not defined in the font.
//////////////////////////////////////////////////////////////////////////////
@ -820,7 +836,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
// returns # of vertices and fills *vertices with the pointer to them
// these are expressed in "unscaled" coordinates
//
// The shape is a series of countours. Each one starts with
// The shape is a series of contours. Each one starts with
// a STBTT_moveto, then consists of a series of mixed
// STBTT_lineto and STBTT_curveto segments. A lineto
// draws a line from previous endpoint to its x,y; a curveto
@ -916,7 +932,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
// These functions compute a discretized SDF field for a single character, suitable for storing
// in a single-channel texture, sampling with bilinear filtering, and testing against
// larger than some threshhold to produce scalable fonts.
// larger than some threshold to produce scalable fonts.
// info -- the font
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
// glyph/codepoint -- the character to generate the SDF for
@ -1825,7 +1841,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
if (comp_verts) STBTT_free(comp_verts, info->userdata);
return 0;
}
if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
if (vertices) STBTT_free(vertices, info->userdata);
vertices = tmp;
@ -2196,7 +2212,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
} break;
default:
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560
return STBTT__CSERR("reserved operator");
// push immediate
@ -2368,7 +2384,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
classDefTable = classDef1ValueArray + 2 * glyphCount;
// [DEAR IMGUI] Commented to fix static analyzer warning
//classDefTable = classDef1ValueArray + 2 * glyphCount;
} break;
case 2: {
@ -2392,7 +2409,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
}
classDefTable = classRangeRecords + 6 * classRangeCount;
// [DEAR IMGUI] Commented to fix static analyzer warning
//classDefTable = classRangeRecords + 6 * classRangeCount;
} break;
default: {
@ -3024,6 +3042,8 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
dx = -dx;
dy = -dy;
t = x0, x0 = xb, xb = t;
// [DEAR IMGUI] Fix static analyzer warning
(void)dx; // [ImGui: fix static analyzer warning]
}
x1 = (int) x_top;
@ -3161,7 +3181,13 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
if (e->y0 != e->y1) {
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
if (z != NULL) {
STBTT_assert(z->ey >= scan_y_top);
if (j == 0 && off_y != 0) {
if (z->ey < scan_y_top) {
// this can happen due to subpixel positioning and some kind of fp rounding error i think
z->ey = scan_y_top;
}
}
STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds
// insert at front
z->next = active;
active = z;
@ -3230,7 +3256,7 @@ static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
{
/* threshhold for transitioning to insertion sort */
/* threshold for transitioning to insertion sort */
while (n > 12) {
stbtt__edge t;
int c01,c12,c,m,i,j;
@ -3365,7 +3391,7 @@ static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
points[n].y = y;
}
// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching
static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
{
// midpoint
@ -3790,6 +3816,7 @@ STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, in
spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
spc->h_oversample = 1;
spc->v_oversample = 1;
spc->skip_missing = 0;
stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
@ -3815,6 +3842,11 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
spc->v_oversample = v_oversample;
}
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
{
spc->skip_missing = skip;
}
#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
@ -3968,13 +4000,17 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
int x0,y0,x1,y1;
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
int glyph = stbtt_FindGlyphIndex(info, codepoint);
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
scale * spc->h_oversample,
scale * spc->v_oversample,
0,0,
&x0,&y0,&x1,&y1);
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
if (glyph == 0 && spc->skip_missing) {
rects[k].w = rects[k].h = 0;
} else {
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
scale * spc->h_oversample,
scale * spc->v_oversample,
0,0,
&x0,&y0,&x1,&y1);
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
}
++k;
}
}
@ -4027,7 +4063,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const
sub_y = stbtt__oversample_shift(spc->v_oversample);
for (j=0; j < ranges[i].num_chars; ++j) {
stbrp_rect *r = &rects[k];
if (r->was_packed) {
if (r->was_packed && r->w != 0 && r->h != 0) {
stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
int advance, lsb, x0,y0,x1,y1;
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
@ -4141,6 +4177,19 @@ STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *
return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
}
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
{
int i_ascent, i_descent, i_lineGap;
float scale;
stbtt_fontinfo info;
stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
*ascent = (float) i_ascent * scale;
*descent = (float) i_descent * scale;
*lineGap = (float) i_lineGap * scale;
}
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
{
float ipw = 1.0f / pw, iph = 1.0f / ph;
@ -4253,7 +4302,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
int winding = 0;
orig[0] = x;
orig[1] = y;
//orig[1] = y; // [DEAR IMGUI] commmented double assignment
// make sure y never passes through a vertex of the shape
y_frac = (float) STBTT_fmod(y, 1.0f);

View file

@ -278,6 +278,8 @@ template<class RawShape> class EdgeCache {
inline Vertex coords(const ContourCache& cache, double distance) const {
assert(distance >= .0 && distance <= 1.0);
if (cache.distances.empty() || cache.emap.empty()) return Vertex{};
if (distance > 1.0) distance = std::fmod(distance, 1.0);
// distance is from 0.0 to 1.0, we scale it up to the full length of
// the circumference

View file

@ -43,7 +43,10 @@ protected:
Placer p{bin};
p.configure(pcfg);
if (itm.area() <= 0 || !p.pack(cpy)) it = c.erase(it);
if (itm.area() <= 0 || !p.pack(cpy)) {
static_cast<Item&>(*it).binId(BIN_ID_UNSET);
it = c.erase(it);
}
else it++;
}
}

View file

@ -577,7 +577,7 @@ void _arrange(
std::function<bool()> stopfn)
{
// Integer ceiling the min distance from the bed perimeters
coord_t md = minobjd - 2 * scaled(0.1 + EPSILON);
coord_t md = minobjd;
md = (md % 2) ? md / 2 + 1 : md / 2;
auto corrected_bin = bin;

View file

@ -62,7 +62,8 @@ std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Info& cus
for (const Item& custom_gcode : custom_gcode_per_print_z.gcodes)
if (custom_gcode.gcode == ToolChangeCode) {
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder));
assert(custom_gcode.extruder >= 0);
custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(size_t(custom_gcode.extruder) > num_extruders ? 1 : custom_gcode.extruder));
}
return custom_tool_changes;
}

View file

@ -1147,7 +1147,7 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
}
}
}
if (result.contour_idx != -1 && d_min <= double(search_radius)) {
if (result.contour_idx != size_t(-1) && d_min <= double(search_radius)) {
result.distance = d_min * sign_min;
result.t /= l2_seg_min;
assert(result.t >= 0. && result.t < 1.);

View file

@ -114,7 +114,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
if (surface.surface_type == stInternalVoid)
has_internal_voids = true;
else {
FlowRole extrusion_role = (surface.surface_type == stTop) ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
bool is_bridge = layer.id() > 0 && surface.is_bridge();
params.extruder = layerm.region()->extruder(extrusion_role);
params.pattern = layerm.region()->config().fill_pattern.value;
@ -132,7 +132,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
is_bridge ?
erBridgeInfill :
(surface.is_solid() ?
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
erInternalInfill);
params.bridge_angle = float(surface.bridge_angle);
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));

View file

@ -611,7 +611,7 @@ static inline SegmentPoint clip_start_segment_and_point(const Points &polyline,
SegmentPoint out;
if (polyline.size() >= 2) {
Vec2d pt_prev = polyline.front().cast<double>();
for (int i = 1; i < polyline.size(); ++ i) {
for (size_t i = 1; i < polyline.size(); ++ i) {
Vec2d pt = polyline[i].cast<double>();
Vec2d v = pt - pt_prev;
double l2 = v.squaredNorm();
@ -674,7 +674,7 @@ static inline double segment_point_distance_squared(const Vec2d &p1a, const Vec2
if (l2 < EPSILON)
// p1a == p1b
return (p2 - p1a).squaredNorm();
return segment_point_distance_squared(p1a, p1b, v, v.squaredNorm(), p2);
return segment_point_distance_squared(p1a, p1b, v, v.squaredNorm(), p2);
}
// Distance to the closest point of line.
@ -692,7 +692,7 @@ static inline double min_distance_of_segments(const Vec2d &p1a, const Vec2d &p1b
// p2a == p2b: Return distance of p2a from the (p1a, p1b) segment.
return segment_point_distance_squared(p1a, p1b, v1, l1_2, p2a);
return std::min(
return std::min(
std::min(segment_point_distance_squared(p1a, p1b, v1, l1_2, p2a), segment_point_distance_squared(p1a, p1b, v1, l1_2, p2b)),
std::min(segment_point_distance_squared(p2a, p2b, v2, l2_2, p1a), segment_point_distance_squared(p2a, p2b, v2, l2_2, p1b)));
}

View file

@ -156,7 +156,7 @@ void FillGyroid::_fill_surface_single(
Polylines &polylines_out)
{
float infill_angle = this->angle + (CorrectionAngle * 2*M_PI) / 360.;
if(abs(infill_angle) >= EPSILON)
if(std::abs(infill_angle) >= EPSILON)
expolygon.rotate(-infill_angle);
BoundingBox bb = expolygon.contour.bounding_box();
@ -197,8 +197,9 @@ void FillGyroid::_fill_surface_single(
append(polylines_out, std::move(polylines));
else
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
// new paths must be rotated back
if (abs(infill_angle) >= EPSILON) {
if (std::abs(infill_angle) >= EPSILON) {
for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it)
it->rotate(infill_angle);
}

View file

@ -3,9 +3,7 @@
#include "../Utils.hpp"
#include "../GCode.hpp"
#include "../Geometry.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "../GCode/ThumbnailData.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
#include "../I18N.hpp"
@ -47,9 +45,7 @@ const std::string MODEL_EXTENSION = ".model";
const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA
const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
const std::string RELATIONSHIPS_FILE = "_rels/.rels";
#if ENABLE_THUMBNAIL_GENERATOR
const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png";
#endif // ENABLE_THUMBNAIL_GENERATOR
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
@ -1722,7 +1718,7 @@ namespace Slic3r {
}
// Added because of github #3435, currently not used by PrusaSlicer
int instances_count_id = get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR);
// int instances_count_id = get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR);
m_objects_metadata.insert(IdToMetadataMap::value_type(object_id, ObjectMetadata()));
m_curr_config.object_id = object_id;
@ -1969,22 +1965,12 @@ namespace Slic3r {
bool m_fullpath_sources{ true };
public:
#if ENABLE_THUMBNAIL_GENERATOR
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
#else
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources);
#endif // ENABLE_THUMBNAIL_GENERATOR
private:
#if ENABLE_THUMBNAIL_GENERATOR
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data);
#else
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config);
#endif // ENABLE_THUMBNAIL_GENERATOR
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
#if ENABLE_THUMBNAIL_GENERATOR
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
bool _add_relationships_file_to_archive(mz_zip_archive& archive);
bool _add_model_file_to_archive(mz_zip_archive& archive, const Model& model, IdToObjectDataMap &objects_data);
bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
@ -1999,26 +1985,14 @@ namespace Slic3r {
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model);
};
#if ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
{
clear_errors();
m_fullpath_sources = fullpath_sources;
return _save_model_to_file(filename, model, config, thumbnail_data);
}
#else
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources)
{
clear_errors();
return _save_model_to_file(filename, model, config);
}
#endif // ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
#else
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
mz_zip_archive archive;
mz_zip_zero_struct(&archive);
@ -2037,7 +2011,6 @@ namespace Slic3r {
return false;
}
#if ENABLE_THUMBNAIL_GENERATOR
if ((thumbnail_data != nullptr) && thumbnail_data->is_valid())
{
// Adds the file Metadata/thumbnail.png.
@ -2048,7 +2021,6 @@ namespace Slic3r {
return false;
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
// Adds relationships file ("_rels/.rels").
// The content of this file is the same for each PrusaSlicer 3mf.
@ -2160,9 +2132,7 @@ namespace Slic3r {
stream << "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n";
stream << " <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />\n";
stream << " <Default Extension=\"model\" ContentType=\"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\" />\n";
#if ENABLE_THUMBNAIL_GENERATOR
stream << " <Default Extension=\"png\" ContentType=\"image/png\" />\n";
#endif // ENABLE_THUMBNAIL_GENERATOR
stream << "</Types>";
std::string out = stream.str();
@ -2176,7 +2146,6 @@ namespace Slic3r {
return true;
}
#if ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data)
{
bool res = false;
@ -2194,7 +2163,6 @@ namespace Slic3r {
return res;
}
#endif // ENABLE_THUMBNAIL_GENERATOR
bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive)
{
@ -2202,9 +2170,7 @@ namespace Slic3r {
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n";
stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\" />\n";
#if ENABLE_THUMBNAIL_GENERATOR
stream << " <Relationship Target=\"/" << THUMBNAIL_FILE << "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\" />\n";
#endif // ENABLE_THUMBNAIL_GENERATOR
stream << "</Relationships>";
std::string out = stream.str();
@ -2795,22 +2761,13 @@ bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool c
return res;
}
#if ENABLE_THUMBNAIL_GENERATOR
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
#else
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
if ((path == nullptr) || (model == nullptr))
return false;
_3MF_Exporter exporter;
#if ENABLE_THUMBNAIL_GENERATOR
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources, thumbnail_data);
#else
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources);
#endif // ENABLE_THUMBNAIL_GENERATOR
if (!res)
exporter.log_errors();

View file

@ -26,20 +26,14 @@ namespace Slic3r {
class Model;
class DynamicPrintConfig;
#if ENABLE_THUMBNAIL_GENERATOR
struct ThumbnailData;
#endif // ENABLE_THUMBNAIL_GENERATOR
// Load the content of a 3mf file into the given model and preset bundle.
extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version);
// Save the given model and the config data contained in the given Print into a 3mf file.
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
#if ENABLE_THUMBNAIL_GENERATOR
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
#else
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources);
#endif // ENABLE_THUMBNAIL_GENERATOR
}; // namespace Slic3r

View file

@ -20,9 +20,7 @@
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#if ENABLE_THUMBNAIL_GENERATOR
#include <boost/beast/core/detail/base64.hpp>
#endif // ENABLE_THUMBNAIL_GENERATOR
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/cstdio.hpp>
@ -291,7 +289,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
std::string gcode;
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines)
// We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
float alpha = m_wipe_tower_rotation/180.f * float(M_PI);
Vec2f start_pos = tcr.start_pos;
@ -431,7 +429,6 @@ std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower:
Vec2f pos = tcr.start_pos;
Vec2f transformed_pos = pos;
Vec2f old_pos(-1000.1f, -1000.1f);
std::string never_skip_tag = WipeTower::never_skip_tag();
while (gcode_str) {
std::getline(gcode_str, line); // we read the gcode line by line
@ -441,11 +438,11 @@ std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower:
// WT generator can override this by appending the never_skip_tag
if (line.find("G1 ") == 0) {
bool never_skip = false;
auto it = line.find(never_skip_tag);
auto it = line.find(WipeTower::never_skip_tag());
if (it != std::string::npos) {
// remove the tag and remember we saw it
never_skip = true;
line.erase(it, it+never_skip_tag.size());
line.erase(it, it+WipeTower::never_skip_tag().size());
}
std::ostringstream line_out;
std::istringstream line_str(line);
@ -701,11 +698,7 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
return layers_to_print;
}
#if ENABLE_THUMBNAIL_GENERATOR
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
#else
void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
PROFILE_CLEAR();
@ -731,11 +724,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
try {
m_placeholder_parser_failed_templates.clear();
#if ENABLE_THUMBNAIL_GENERATOR
this->_do_export(*print, file, thumbnail_cb);
#else
this->_do_export(*print, file);
#endif // ENABLE_THUMBNAIL_GENERATOR
fflush(file);
if (ferror(file)) {
fclose(file);
@ -975,7 +964,6 @@ namespace DoExport {
}
}
#if ENABLE_THUMBNAIL_GENERATOR
template<typename WriteToOutput, typename ThrowIfCanceledCallback>
static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector<Vec2d> &sizes, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled)
{
@ -1019,7 +1007,6 @@ namespace DoExport {
}
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
static std::string update_print_stats_and_format_filament_stats(
@ -1125,11 +1112,7 @@ std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Pri
return instances;
}
#if ENABLE_THUMBNAIL_GENERATOR
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
#else
void GCode::_do_export(Print& print, FILE* file)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
PROFILE_FUNC();
@ -1752,7 +1735,6 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
std::sort(sorted.begin(), sorted.end());
if (! sorted.empty()) {
const Print &print = *sorted.front().first->print();
out.reserve(sorted.size());
for (const PrintInstance *instance : *ordering) {
const PrintObject &print_object = *instance->print_object;
@ -1798,13 +1780,14 @@ namespace ProcessLayer
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
if (color_change || tool_change)
{
assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change.
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
// add tag for time estimator
gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != m600_extruder_before_layer
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
// && !MMU1
) {
//! FIXME_in_fw show message during print pause
@ -2880,11 +2863,12 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string description, dou
std::string GCode::extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, std::unique_ptr<EdgeGrid::Grid> &lower_layer_edge_grid)
{
std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) {
m_config.apply(print.regions()[&region - &by_region.front()]->config());
for (const ExtrusionEntity *ee : region.perimeters)
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
}
for (const ObjectByExtruder::Island::Region &region : by_region)
if (! region.perimeters.empty()) {
m_config.apply(print.regions()[&region - &by_region.front()]->config());
for (const ExtrusionEntity *ee : region.perimeters)
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
}
return gcode;
}
@ -2892,19 +2876,20 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region)
{
std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) {
m_config.apply(print.regions()[&region - &by_region.front()]->config());
ExtrusionEntitiesPtr extrusions { region.infills };
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
for (const ExtrusionEntity *fill : extrusions) {
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
if (eec) {
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
gcode += this->extrude_entity(*ee, "infill");
} else
gcode += this->extrude_entity(*fill, "infill");
for (const ObjectByExtruder::Island::Region &region : by_region)
if (! region.infills.empty()) {
m_config.apply(print.regions()[&region - &by_region.front()]->config());
ExtrusionEntitiesPtr extrusions { region.infills };
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
for (const ExtrusionEntity *fill : extrusions) {
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
if (eec) {
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
gcode += this->extrude_entity(*ee, "infill");
} else
gcode += this->extrude_entity(*fill, "infill");
}
}
}
return gcode;
}
@ -3370,17 +3355,18 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
has_overrides = true;
break;
}
// Data is cleared, but the memory is not.
by_region_per_copy_cache.clear();
if (! has_overrides)
// Simple case. No need to copy the regions.
return this->by_region;
return wiping_entities ? by_region_per_copy_cache : this->by_region;
// Complex case. Some of the extrusions of some object instances are to be printed first - those are the wiping extrusions.
// Some of the extrusions of some object instances are printed later - those are the clean print extrusions.
// Filter out the extrusions based on the infill_overrides / perimeter_overrides:
// Data is cleared, but the memory is not.
by_region_per_copy_cache.clear();
for (const auto& reg : by_region) {
by_region_per_copy_cache.emplace_back(); // creates a region in the newly created Island
@ -3441,15 +3427,17 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
// First we append the entities, there are eec->entities.size() of them:
size_t old_size = perimeters_or_infills->size();
perimeters_or_infills->reserve(perimeters_or_infills->size() + eec->entities.size());
size_t new_size = old_size + eec->entities.size();
perimeters_or_infills->reserve(new_size);
for (auto* ee : eec->entities)
perimeters_or_infills->emplace_back(ee);
if (copies_extruder != nullptr) {
perimeters_or_infills_overrides->reserve(old_size + eec->entities.size());
perimeters_or_infills_overrides->resize(old_size, nullptr);
for (unsigned int i = 0; i < eec->entities.size(); ++ i)
perimeters_or_infills_overrides->emplace_back(copies_extruder);
// Don't reallocate overrides if not needed.
// Missing overrides are implicitely considered non-overridden.
perimeters_or_infills_overrides->reserve(new_size);
perimeters_or_infills_overrides->resize(old_size, nullptr);
perimeters_or_infills_overrides->resize(new_size, copies_extruder);
}
}

View file

@ -17,9 +17,7 @@
#include "GCodeTimeEstimator.hpp"
#include "EdgeGrid.hpp"
#include "GCode/Analyzer.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "GCode/ThumbnailData.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
#include <memory>
#include <string>
@ -166,11 +164,7 @@ public:
// throws std::runtime_exception on error,
// throws CanceledException through print->throw_if_canceled().
#if ENABLE_THUMBNAIL_GENERATOR
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#else
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
#endif // ENABLE_THUMBNAIL_GENERATOR
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
const Vec2d& origin() const { return m_origin; }
@ -210,11 +204,7 @@ public:
};
private:
#if ENABLE_THUMBNAIL_GENERATOR
void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
#else
void _do_export(Print &print, FILE *file);
#endif //ENABLE_THUMBNAIL_GENERATOR
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);

View file

@ -444,8 +444,10 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
anyFound = true;
}
if (!anyFound)
if (!anyFound && ! line.has_unknown_axis())
{
// The G92 may be called for axes that PrusaSlicer does not recognize, for example see GH issue #3510,
// where G92 A0 B0 is called although the extruder axis is till E.
for (unsigned char a = X; a < Num_Axis; ++a)
{
_set_axis_origin((EAxis)a, _get_axis_position((EAxis)a));
@ -470,7 +472,7 @@ void GCodeAnalyzer::_processM106(const GCodeReader::GCodeLine& line)
// The absence of P means the print cooling fan, so ignore anything else.
float new_fan_speed;
if (line.has_value('S', new_fan_speed))
_set_fan_speed((100.0f / 256.0f) * new_fan_speed);
_set_fan_speed((100.0f / 255.0f) * new_fan_speed);
else
_set_fan_speed(100.0f);
}
@ -644,7 +646,7 @@ bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line)
if (pos != comment.npos)
{
pos = comment.find_last_of(",T");
int extruder = pos == comment.npos ? 0 : std::atoi(comment.substr(pos + 1, comment.npos).c_str());
unsigned extruder = pos == comment.npos ? 0 : std::stoi(comment.substr(pos + 1, comment.npos));
_process_color_change_tag(extruder);
return true;
}
@ -702,7 +704,7 @@ void GCodeAnalyzer::_process_height_tag(const std::string& comment, size_t pos)
_set_height((float)::strtod(comment.substr(pos + Height_Tag.length()).c_str(), nullptr));
}
void GCodeAnalyzer::_process_color_change_tag(int extruder)
void GCodeAnalyzer::_process_color_change_tag(unsigned extruder)
{
m_extruder_color[extruder] = m_extruders_count + m_state.cp_color_counter; // color_change position in list of color for preview
m_state.cp_color_counter++;

View file

@ -220,7 +220,7 @@ private:
void _process_height_tag(const std::string& comment, size_t pos);
// Processes color change tag
void _process_color_change_tag(int extruder);
void _process_color_change_tag(unsigned extruder);
// Processes pause print and custom gcode tag
void _process_pause_print_or_custom_code_tag();

View file

@ -72,7 +72,7 @@ Color GCodePreviewData::RangeBase::get_color_at(float value) const
{
// Input value scaled to the color range
float step = step_size();
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step_size() : 0.0f; // lower limit of 0.0f
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step : 0.0f; // lower limit of 0.0f
constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1;
@ -241,6 +241,7 @@ void GCodePreviewData::reset()
ranges.width.reset();
ranges.height.reset();
ranges.feedrate.reset();
ranges.fan_speed.reset();
ranges.volumetric_rate.reset();
extrusion.layers.clear();
travel.polylines.clear();

View file

@ -1,8 +1,6 @@
#include "libslic3r/libslic3r.h"
#include "ThumbnailData.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
namespace Slic3r {
void ThumbnailData::set(unsigned int w, unsigned int h)
@ -32,5 +30,3 @@ bool ThumbnailData::is_valid() const
}
} // namespace Slic3r
#endif // ENABLE_THUMBNAIL_GENERATOR

View file

@ -1,8 +1,6 @@
#ifndef slic3r_ThumbnailData_hpp_
#define slic3r_ThumbnailData_hpp_
#if ENABLE_THUMBNAIL_GENERATOR
#include <vector>
#include "libslic3r/Point.hpp"
@ -26,6 +24,4 @@ typedef std::function<void(ThumbnailsList & thumbnails, const Vec2ds & sizes, bo
} // namespace Slic3r
#endif // ENABLE_THUMBNAIL_GENERATOR
#endif // slic3r_ThumbnailData_hpp_

View file

@ -64,7 +64,7 @@ private:
std::map<const ExtrusionEntity*, ExtruderPerCopy> entity_map; // to keep track of who prints what
bool something_overridable = false;
bool something_overridden = false;
const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to
const LayerTools* m_layer_tools = nullptr; // so we know which LayerTools object this belongs to
};

View file

@ -492,6 +492,9 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
const std::vector<Vec2d>& bed_points = config.bed_shape.values;
m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed);
m_bed_width = float(BoundingBoxf(bed_points).size().x());
m_bed_bottom_left = m_bed_shape == RectangularBed
? Vec2f(bed_points.front().x(), bed_points.front().y())
: Vec2f::Zero();
}
@ -566,6 +569,8 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
// In case of a circular bed, place it so it goes across the diameter and hope it will fit
if (m_bed_shape == CircularBed)
cleaning_box.translate(-m_bed_width/2 + m_bed_width * 0.03f, -m_bed_width * 0.12f);
if (m_bed_shape == RectangularBed)
cleaning_box.translate(m_bed_bottom_left);
std::vector<ToolChangeResult> results;

View file

@ -21,7 +21,7 @@ enum GCodeFlavor : unsigned char;
class WipeTower
{
public:
static char const* never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
struct Extrusion
{
@ -189,8 +189,6 @@ public:
};
private:
WipeTower();
enum wipe_shape // A fill-in direction
{
SHAPE_NORMAL = 1,
@ -236,6 +234,7 @@ private:
CircularBed
} m_bed_shape;
float m_bed_width; // width of the bed bounding box
Vec2f m_bed_bottom_left; // bottom-left corner coordinates (for rectangular beds)
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.

View file

@ -40,7 +40,7 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
if (is_end_of_gcode_line(*c))
break;
// Check the name of the axis.
Axis axis = NUM_AXES;
Axis axis = NUM_AXES_WITH_UNKNOWN;
switch (*c) {
case 'X': axis = X; break;
case 'Y': axis = Y; break;
@ -49,15 +49,19 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
default:
if (*c == m_extrusion_axis)
axis = E;
else if (*c >= 'A' && *c <= 'Z')
// Unknown axis, but we still want to remember that such a axis was seen.
axis = UNKNOWN_AXIS;
break;
}
if (axis != NUM_AXES) {
if (axis != NUM_AXES_WITH_UNKNOWN) {
// Try to parse the numeric value.
char *pend = nullptr;
double v = strtod(++ c, &pend);
if (pend != nullptr && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
gline.m_axis[int(axis)] = float(v);
if (axis != UNKNOWN_AXIS)
gline.m_axis[int(axis)] = float(v);
gline.m_mask |= 1 << int(axis);
c = pend;
} else

View file

@ -58,6 +58,7 @@ public:
bool has_z() const { return this->has(Z); }
bool has_e() const { return this->has(E); }
bool has_f() const { return this->has(F); }
bool has_unknown_axis() const { return this->has(UNKNOWN_AXIS); }
float x() const { return m_axis[X]; }
float y() const { return m_axis[Y]; }
float z() const { return m_axis[Z]; }

View file

@ -112,72 +112,82 @@ void Layer::make_perimeters()
// keep track of regions whose perimeters we have already generated
std::vector<unsigned char> done(m_regions.size(), false);
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm) {
size_t region_id = layerm - m_regions.begin();
if (done[region_id])
continue;
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
done[region_id] = true;
const PrintRegionConfig &config = (*layerm)->region()->config();
// find compatible regions
LayerRegionPtrs layerms;
layerms.push_back(*layerm);
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it) {
LayerRegion* other_layerm = *it;
const PrintRegionConfig &other_config = other_layerm->region()->config();
if (config.perimeter_extruder == other_config.perimeter_extruder
&& config.perimeters == other_config.perimeters
&& config.perimeter_speed == other_config.perimeter_speed
&& config.external_perimeter_speed == other_config.external_perimeter_speed
&& config.gap_fill_speed == other_config.gap_fill_speed
&& config.overhangs == other_config.overhangs
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
&& config.thin_walls == other_config.thin_walls
&& config.external_perimeters_first == other_config.external_perimeters_first
&& config.infill_overlap == other_config.infill_overlap) {
layerms.push_back(other_layerm);
done[it - m_regions.begin()] = true;
}
}
if (layerms.size() == 1) { // optimization
(*layerm)->fill_surfaces.surfaces.clear();
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
} else {
SurfaceCollection new_slices;
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
LayerRegion *layerm_config = layerms.front();
{
// group slices (surfaces) according to number of extra perimeters
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
for (LayerRegion *layerm : layerms) {
for (Surface &surface : layerm->slices.surfaces)
slices[surface.extra_perimeters].emplace_back(surface);
if (layerm->region()->config().fill_density > layerm_config->region()->config().fill_density)
layerm_config = layerm;
}
// merge the surfaces assigned to each group
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
}
// make perimeters
SurfaceCollection fill_surfaces;
layerm_config->make_perimeters(new_slices, &fill_surfaces);
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm)
if ((*layerm)->slices.empty()) {
(*layerm)->perimeters.clear();
(*layerm)->fills.clear();
(*layerm)->thin_fills.clear();
} else {
size_t region_id = layerm - m_regions.begin();
if (done[region_id])
continue;
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
done[region_id] = true;
const PrintRegionConfig &config = (*layerm)->region()->config();
// find compatible regions
LayerRegionPtrs layerms;
layerms.push_back(*layerm);
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it)
if (! (*it)->slices.empty()) {
LayerRegion* other_layerm = *it;
const PrintRegionConfig &other_config = other_layerm->region()->config();
if (config.perimeter_extruder == other_config.perimeter_extruder
&& config.perimeters == other_config.perimeters
&& config.perimeter_speed == other_config.perimeter_speed
&& config.external_perimeter_speed == other_config.external_perimeter_speed
&& config.gap_fill_speed == other_config.gap_fill_speed
&& config.overhangs == other_config.overhangs
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
&& config.thin_walls == other_config.thin_walls
&& config.external_perimeters_first == other_config.external_perimeters_first
&& config.infill_overlap == other_config.infill_overlap)
{
other_layerm->perimeters.clear();
other_layerm->fills.clear();
other_layerm->thin_fills.clear();
layerms.push_back(other_layerm);
done[it - m_regions.begin()] = true;
}
}
if (layerms.size() == 1) { // optimization
(*layerm)->fill_surfaces.surfaces.clear();
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
} else {
SurfaceCollection new_slices;
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
LayerRegion *layerm_config = layerms.front();
{
// group slices (surfaces) according to number of extra perimeters
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
for (LayerRegion *layerm : layerms) {
for (Surface &surface : layerm->slices.surfaces)
slices[surface.extra_perimeters].emplace_back(surface);
if (layerm->region()->config().fill_density > layerm_config->region()->config().fill_density)
layerm_config = layerm;
}
// merge the surfaces assigned to each group
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
}
// make perimeters
SurfaceCollection fill_surfaces;
layerm_config->make_perimeters(new_slices, &fill_surfaces);
// assign fill_surfaces to each layer
if (!fill_surfaces.surfaces.empty()) {
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
// Separate the fill surfaces.
ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices);
(*l)->fill_expolygons = expp;
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
}
}
}
}
// assign fill_surfaces to each layer
if (!fill_surfaces.surfaces.empty()) {
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
// Separate the fill surfaces.
ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices);
(*l)->fill_expolygons = expp;
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
}
}
}
}
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
}

View file

@ -117,7 +117,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// Voids are sparse infills if infill rate is zero.
Polygons voids;
for (const Surface &surface : this->fill_surfaces.surfaces) {
if (surface.surface_type == stTop) {
if (surface.is_top()) {
// Collect the top surfaces, inflate them and trim them by the bottom surfaces.
// This gives the priority to bottom surfaces.
surfaces_append(top, offset_ex(surface.expolygon, margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS), surface);
@ -313,7 +313,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
s2.clear();
}
}
if (s1.surface_type == stTop)
if (s1.is_top())
// Trim the top surfaces by the bottom surfaces. This gives the priority to the bottom surfaces.
polys = diff(polys, bottom_polygons);
surfaces_append(

View file

@ -161,6 +161,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
} else if (
opt_key == "skirts"
|| opt_key == "skirt_height"
|| opt_key == "draft_shield"
|| opt_key == "skirt_distance"
|| opt_key == "min_skirt_length"
|| opt_key == "ooze_prevention"
@ -1146,14 +1147,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
bool Print::has_infinite_skirt() const
{
return (m_config.skirt_height == -1 && m_config.skirts > 0)
|| (m_config.ooze_prevention && this->extruders().size() > 1);
return (m_config.draft_shield && m_config.skirts > 0) || (m_config.ooze_prevention && this->extruders().size() > 1);
}
bool Print::has_skirt() const
{
return (m_config.skirt_height > 0 && m_config.skirts > 0)
|| this->has_infinite_skirt();
return (m_config.skirt_height > 0 && m_config.skirts > 0) || this->has_infinite_skirt();
}
static inline bool sequential_print_horizontal_clearance_valid(const Print &print)
@ -1623,11 +1622,7 @@ void Print::process()
// The export_gcode may die for various reasons (fails to process output_filename_format,
// write error into the G-code, cannot execute post-processing scripts).
// It is up to the caller to show an error message.
#if ENABLE_THUMBNAIL_GENERATOR
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
#else
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
// output everything to a G-code file
// The following call may die if the output_filename_format template substitution fails.
@ -1644,11 +1639,7 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa
// The following line may die for multiple reasons.
GCode gcode;
#if ENABLE_THUMBNAIL_GENERATOR
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
#else
gcode.do_export(this, path.c_str(), preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
return path.c_str();
}
@ -1936,7 +1927,7 @@ void Print::_make_brim()
// Find all pieces that the initial loop was split into.
size_t j = i + 1;
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].second == loops_trimmed_order[j].second; ++ j) ;
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
auto *loop = new ExtrusionLoop();
m_brim.entities.emplace_back(loop);
@ -2138,6 +2129,7 @@ std::string Print::output_filename(const std::string &filename_base) const
// Set the placeholders for the data know first after the G-code export is finished.
// These values will be just propagated into the output file name.
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
config.set_key_value("num_extruders", new ConfigOptionInt((int)m_config.nozzle_diameter.size()));
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
}

View file

@ -11,9 +11,7 @@
#include "Slicing.hpp"
#include "GCode/ToolOrdering.hpp"
#include "GCode/WipeTower.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "GCode/ThumbnailData.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
#include "libslic3r.h"
@ -364,11 +362,7 @@ public:
void process() override;
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
#if ENABLE_THUMBNAIL_GENERATOR
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#else
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
// methods for handling state
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }

View file

@ -254,7 +254,7 @@ void PrintConfigDef::init_fff_params()
"to clip the overlapping object parts one by the other "
"(2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc).");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
def->set_default_value(new ConfigOptionBool(true));
def = this->add("colorprint_heights", coFloats);
def->label = L("Colorprint height");
@ -1691,6 +1691,13 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(1));
def = this->add("draft_shield", coBool);
def->label = L("Draft shield");
def->tooltip = L("If enabled, the skirt will be as tall as a highest printed object. "
"This is useful to protect an ABS or ASA print from warping and detaching from print bed due to wind draft.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("skirts", coInt);
def->label = L("Loops (minimum)");
def->full_label = L("Skirt Loops");
@ -2998,6 +3005,11 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
} else if (opt_key == "support_material_pattern" && value == "pillars") {
// Slic3r PE does not support the pillars. They never worked well.
value = "rectilinear";
} else if (opt_key == "skirt_height" && value == "-1") {
// PrusaSlicer no more accepts skirt_height == -1 to print a draft shield to the top of the highest object.
// A new "draft_shield" boolean config value is used instead.
opt_key = "draft_shield";
value = "1";
} else if (opt_key == "octoprint_host") {
opt_key = "print_host";
} else if (opt_key == "octoprint_cafile") {
@ -3206,7 +3218,7 @@ std::string FullPrintConfig::validate()
return "Invalid value for --infill-every-layers";
// --skirt-height
if (this->skirt_height < -1) // -1 means as tall as the object
if (this->skirt_height < 0)
return "Invalid value for --skirt-height";
// --bridge-flow-ratio

View file

@ -800,6 +800,7 @@ public:
ConfigOptionBools retract_layer_change;
ConfigOptionFloat skirt_distance;
ConfigOptionInt skirt_height;
ConfigOptionBool draft_shield;
ConfigOptionInt skirts;
ConfigOptionInts slowdown_below_layer_time;
ConfigOptionBool spiral_vase;
@ -872,6 +873,7 @@ protected:
OPT_PTR(retract_layer_change);
OPT_PTR(skirt_distance);
OPT_PTR(skirt_height);
OPT_PTR(draft_shield);
OPT_PTR(skirts);
OPT_PTR(slowdown_below_layer_time);
OPT_PTR(spiral_vase);

View file

@ -817,11 +817,12 @@ void PrintObject::detect_surfaces_type()
m_layers[idx_layer]->m_regions[idx_region]->slices.surfaces = std::move(surfaces_new[idx_layer]);
}
if (spiral_vase && num_layers > 1) {
// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
Surfaces &surfaces = m_layers[num_layers - 1]->m_regions[idx_region]->slices.surfaces;
for (Surface &surface : surfaces)
surface.surface_type = stTop;
if (spiral_vase) {
if (num_layers > 1)
// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
m_layers[num_layers - 1]->m_regions[idx_region]->slices.set_type(stTop);
for (size_t i = num_layers; i < m_layers.size(); ++ i)
m_layers[i]->m_regions[idx_region]->slices.set_type(stInternal);
}
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - start";

View file

@ -101,6 +101,9 @@ public:
// Iterates over hits and holes and returns the true hit, possibly
// on the inside of a hole.
// This function is currently not used anywhere, it was written when the
// holes were subtracted on slices, that is, before we started using CGAL
// to actually cut the holes into the mesh.
hit_result filter_hits(const std::vector<EigenMesh3D::hit_result>& obj_hits) const;
class si_result {

View file

@ -34,6 +34,10 @@ public:
void remove_type(const SurfaceType type);
void remove_types(const SurfaceType *types, int ntypes);
void filter_by_type(SurfaceType type, Polygons* polygons);
void set_type(SurfaceType type) {
for (Surface &surface : this->surfaces)
surface.surface_type = type;
}
void clear() { surfaces.clear(); }
bool empty() const { return surfaces.empty(); }

View file

@ -1,5 +1,5 @@
#ifndef _technologies_h_
#define _technologies_h_
#ifndef _prusaslicer_technologies_h_
#define _prusaslicer_technologies_h_
//============
// debug techs
@ -17,37 +17,20 @@
#define ENABLE_CAMERA_STATISTICS 0
// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
#define ENABLE_RENDER_PICKING_PASS 0
//====================
// 1.42.0.alpha1 techs
//====================
#define ENABLE_1_42_0_ALPHA1 1
// Enable extracting thumbnails from selected gcode and save them as png files
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG 0
// Disable synchronization of unselected instances
#define DISABLE_INSTANCES_SYNCH (0 && ENABLE_1_42_0_ALPHA1)
#define DISABLE_INSTANCES_SYNCH 0
// Use wxDataViewRender instead of wxDataViewCustomRenderer
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING 0
//====================
// 2.2.0.alpha1 techs
//====================
#define ENABLE_2_2_0_ALPHA1 1
// Enable thumbnail generator
// When removing this technology, remove it also from stable branch,
// where it has been partially copied for patch 2.1.1
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1)
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
//==================
//================
// 2.2.0.rc1 techs
//==================
//================
#define ENABLE_2_2_0_RC1 1
// Enable hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
// Enable hack to remove crash when closing on OSX 10.9.5
#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
@ -56,8 +39,19 @@
//==================
#define ENABLE_2_2_0_FINAL 1
// Enable tooltips for GLCanvas3D using ImGUI
#define ENABLE_CANVAS_TOOLTIP_USING_IMGUI (1 && ENABLE_2_2_0_FINAL)
// Enable fix for dragging mouse event handling for gizmobar
#define ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX (1 && ENABLE_2_2_0_FINAL)
//===================
// 2.3.0.alpha1 techs
//===================
#define ENABLE_2_3_0_ALPHA1 1
// Moves GLCanvas3DManager from being a static member of _3DScene to be a normal member of GUI_App
#define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_2_0_FINAL)
#define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_3_0_ALPHA1)
#endif // _technologies_h_
#endif // _prusaslicer_technologies_h_

View file

@ -98,7 +98,17 @@ extern Semver SEMVER;
template<typename T, typename Q>
inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
enum Axis { X=0, Y, Z, E, F, NUM_AXES };
enum Axis {
X=0,
Y,
Z,
E,
F,
NUM_AXES,
// For the GCodeReader to mark a parsed axis, which is not in "XYZEF", it was parsed correctly.
UNKNOWN_AXIS = NUM_AXES,
NUM_AXES_WITH_UNKNOWN,
};
template <class T>
inline void append_to(std::vector<T> &dst, const std::vector<T> &src)

View file

@ -197,6 +197,10 @@ if(APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif()
if (SLIC3R_STATIC AND UNIX AND NOT APPLE)
target_compile_definitions(libslic3r_gui PRIVATE OPENSSL_CERT_OVERRIDE)
endif ()
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
endif ()

View file

@ -5,11 +5,12 @@
#include <time.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/filesystem/operations.hpp>
#include "libslic3r/libslic3r.h"
#include "libslic3r/Time.hpp"

View file

@ -6,7 +6,7 @@
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include "libslic3r/Semver.hpp"
#include "Version.hpp"
@ -18,7 +18,6 @@ class AppConfig;
namespace GUI {
namespace Config {
class Index;
// A snapshot contains:
// Slic3r.ini

View file

@ -2,8 +2,7 @@
#include <cctype>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/nowide/fstream.hpp>
#include "libslic3r/libslic3r.h"

View file

@ -4,7 +4,7 @@
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include "libslic3r/FileParserError.hpp"
#include "libslic3r/Semver.hpp"
@ -54,7 +54,7 @@ struct Version
class Index
{
public:
typedef std::vector<Version>::const_iterator const_iterator;
typedef std::vector<Version>::const_iterator const_iterator;
// Read a config index file in the simple format described in the Index class comment.
// Throws Slic3r::file_parser_error and the standard std file access exceptions.
size_t load(const boost::filesystem::path &path);

View file

@ -166,4 +166,4 @@ void Bed_2D::set_pos(const Vec2d& pos)
}
} // GUI
} // Slic3r
} // Slic3r

View file

@ -8,7 +8,6 @@
#include "GUI_App.hpp"
#include "PresetBundle.hpp"
#include "Gizmos/GLGizmoBase.hpp"
#include "GLCanvas3D.hpp"
#include <GL/glew.h>
@ -630,4 +629,4 @@ void Bed3D::reset()
}
} // GUI
} // Slic3r
} // Slic3r

View file

@ -17,23 +17,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <utility>
#include <assert.h>
#include <boost/log/trivial.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/nowide/cstdio.hpp>
#include <tbb/parallel_for.h>
#include <tbb/spin_mutex.h>
#include <Eigen/Dense>
#include "GUI.hpp"
#ifdef HAS_GLSAFE
void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name)
{

View file

@ -12,7 +12,6 @@
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#include <functional>
#include <memory>
#ifndef NDEBUG
#define HAS_GLSAFE
@ -36,13 +35,8 @@ struct Camera;
class GLToolbar;
} // namespace GUI
class Print;
class PrintObject;
class SLAPrint;
class SLAPrintObject;
enum SLAPrintObjectStep : unsigned int;
class Model;
class ModelObject;
class DynamicPrintConfig;
class ExtrusionPath;
class ExtrusionMultiPath;

View file

@ -2,8 +2,9 @@
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "wxExtensions.hpp"
namespace Slic3r {
namespace GUI {

View file

@ -1,8 +1,6 @@
#ifndef slic3r_GUI_AboutDialog_hpp_
#define slic3r_GUI_AboutDialog_hpp_
#include "GUI.hpp"
#include <wx/wx.h>
#include <wx/intl.h>
#include <wx/html/htmlwin.h>

View file

@ -2,22 +2,18 @@
#include "libslic3r/Utils.hpp"
#include "AppConfig.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <utility>
#include <assert.h>
#include <vector>
#include <stdexcept>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/exceptions.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/format.hpp>
#include <boost/format/format_fwd.hpp>
#include <wx/string.h>
#include "I18N.hpp"
@ -76,7 +72,7 @@ void AppConfig::set_defaults()
if (get("remember_output_path").empty())
set("remember_output_path", "1");
if (get("remember_output_path_removable").empty())
if (get("remember_output_path_removable").empty())
set("remember_output_path_removable", "1");
if (get("use_custom_toolbar_size").empty())
@ -280,7 +276,7 @@ void AppConfig::set_recent_projects(const std::vector<std::string>& recent_proje
}
}
void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed)
void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz)
{
std::string key = std::string("mouse_device:") + name;
auto it = m_storage.find(key);
@ -293,6 +289,7 @@ void AppConfig::set_mouse_device(const std::string& name, double translation_spe
it->second["rotation_speed"] = std::to_string(rotation_speed);
it->second["rotation_deadzone"] = std::to_string(rotation_deadzone);
it->second["zoom_speed"] = std::to_string(zoom_speed);
it->second["swap_yz"] = swap_yz ? "1" : "0";
}
std::vector<std::string> AppConfig::get_mouse_device_names() const

View file

@ -5,6 +5,8 @@
#include <map>
#include <string>
#include <boost/algorithm/string/trim_all.hpp>
#include "libslic3r/Config.hpp"
#include "libslic3r/Semver.hpp"
@ -52,7 +54,13 @@ public:
std::string get(const std::string &key) const
{ std::string value; this->get("", key, value); return value; }
void set(const std::string &section, const std::string &key, const std::string &value)
{
{
#ifndef _NDEBUG
std::string key_trimmed = key;
boost::trim_all(key_trimmed);
assert(key_trimmed == key);
assert(! key_trimmed.empty());
#endif _NDEBUG
std::string &old = m_storage[section][key];
if (old != value) {
old = value;
@ -133,7 +141,7 @@ public:
std::vector<std::string> get_recent_projects() const;
void set_recent_projects(const std::vector<std::string>& recent_projects);
void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed);
void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz);
std::vector<std::string> get_mouse_device_names() const;
bool get_mouse_device_translation_speed(const std::string& name, double& speed) const
{ return get_3dmouse_device_numeric_value(name, "translation_speed", speed); }
@ -145,6 +153,8 @@ public:
{ return get_3dmouse_device_numeric_value(name, "rotation_deadzone", deadzone); }
bool get_mouse_device_zoom_speed(const std::string& name, double& speed) const
{ return get_3dmouse_device_numeric_value(name, "zoom_speed", speed); }
bool get_mouse_device_swap_yz(const std::string& name, bool& swap) const
{ return get_3dmouse_device_numeric_value(name, "swap_yz", swap); }
static const std::string SECTION_FILAMENTS;
static const std::string SECTION_MATERIALS;

View file

@ -11,9 +11,7 @@
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#if ENABLE_THUMBNAIL_GENERATOR
#include <miniz.h>
#endif // ENABLE_THUMBNAIL_GENERATOR
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
#include "libslic3r/Print.hpp"
@ -26,17 +24,16 @@
#include <cassert>
#include <stdexcept>
#include <cctype>
#include <algorithm>
#include <boost/format.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp>
#include <boost/format/format_fwd.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/cstdio.hpp>
#include "I18N.hpp"
#include "GUI.hpp"
#include "RemovableDriveManager.hpp"
#include "slic3r/Utils/Thread.hpp"
namespace Slic3r {
BackgroundSlicingProcess::BackgroundSlicingProcess()
@ -90,19 +87,14 @@ void BackgroundSlicingProcess::process_fff()
assert(m_print == m_fff_print);
m_print->process();
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id));
#if ENABLE_THUMBNAIL_GENERATOR
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb);
#else
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
if (this->set_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {
//FIXME localize the messages
// Perform the final post-processing of the export path by applying the print statistics over the file name.
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
bool with_check = GUI::wxGetApp().removable_drive_manager()->is_path_on_removable_drive(export_path);
int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check);
int copy_ret_val = copy_file(m_temp_output_path, export_path, m_export_path_on_removable_media);
switch (copy_ret_val) {
case SUCCESS: break; // no error
case FAIL_COPY_FILE:
@ -137,7 +129,6 @@ void BackgroundSlicingProcess::process_fff()
}
}
#if ENABLE_THUMBNAIL_GENERATOR
static void write_thumbnail(Zipper& zipper, const ThumbnailData& data)
{
size_t png_size = 0;
@ -148,7 +139,6 @@ static void write_thumbnail(Zipper& zipper, const ThumbnailData& data)
mz_free(png_data);
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
void BackgroundSlicingProcess::process_sla()
{
@ -161,7 +151,6 @@ void BackgroundSlicingProcess::process_sla()
Zipper zipper(export_path);
m_sla_print->export_raster(zipper);
#if ENABLE_THUMBNAIL_GENERATOR
if (m_thumbnail_cb != nullptr)
{
ThumbnailsList thumbnails;
@ -173,7 +162,6 @@ void BackgroundSlicingProcess::process_sla()
write_thumbnail(zipper, data);
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
zipper.finalize();
@ -402,7 +390,7 @@ void BackgroundSlicingProcess::set_task(const PrintBase::TaskParams &params)
}
// Set the output path of the G-code.
void BackgroundSlicingProcess::schedule_export(const std::string &path)
void BackgroundSlicingProcess::schedule_export(const std::string &path, bool export_path_on_removable_media)
{
assert(m_export_path.empty());
if (! m_export_path.empty())
@ -412,6 +400,7 @@ void BackgroundSlicingProcess::schedule_export(const std::string &path)
tbb::mutex::scoped_lock lock(m_print->state_mutex());
this->invalidate_step(bspsGCodeFinalize);
m_export_path = path;
m_export_path_on_removable_media = export_path_on_removable_media;
}
void BackgroundSlicingProcess::schedule_upload(Slic3r::PrintHostJob upload_job)
@ -432,6 +421,7 @@ void BackgroundSlicingProcess::reset_export()
assert(! this->running());
if (! this->running()) {
m_export_path.clear();
m_export_path_on_removable_media = false;
// invalidate_step expects the mutex to be locked.
tbb::mutex::scoped_lock lock(m_print->state_mutex());
this->invalidate_step(bspsGCodeFinalize);
@ -486,7 +476,6 @@ void BackgroundSlicingProcess::prepare_upload()
Zipper zipper{source_path.string()};
m_sla_print->export_raster(zipper, m_upload_job.upload_data.upload_path.string());
#if ENABLE_THUMBNAIL_GENERATOR
if (m_thumbnail_cb != nullptr)
{
ThumbnailsList thumbnails;
@ -498,7 +487,6 @@ void BackgroundSlicingProcess::prepare_upload()
write_thumbnail(zipper, data);
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
zipper.finalize();
}

View file

@ -5,13 +5,13 @@
#include <condition_variable>
#include <mutex>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <wx/event.h>
#include "libslic3r/Print.hpp"
#include "slic3r/Utils/PrintHost.hpp"
#include "slic3r/Utils/Thread.hpp"
namespace Slic3r {
@ -49,9 +49,7 @@ public:
void set_fff_print(Print *print) { m_fff_print = print; }
void set_sla_print(SLAPrint *print) { m_sla_print = print; }
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; }
#if ENABLE_THUMBNAIL_GENERATOR
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
#endif // ENABLE_THUMBNAIL_GENERATOR
// The following wxCommandEvent will be sent to the UI thread / Plater window, when the slicing is finished
// and the background processing will transition into G-code export.
@ -98,7 +96,7 @@ public:
// Set the export path of the G-code.
// Once the path is set, the G-code
void schedule_export(const std::string &path);
void schedule_export(const std::string &path, bool export_path_on_removable_media);
// Set print host upload job data to be enqueued to the PrintHostJobQueue
// after current print slicing is complete
void schedule_upload(Slic3r::PrintHostJob upload_job);
@ -155,15 +153,14 @@ private:
SLAPrint *m_sla_print = nullptr;
// Data structure, to which the G-code export writes its annotations.
GCodePreviewData *m_gcode_preview_data = nullptr;
#if ENABLE_THUMBNAIL_GENERATOR
// Callback function, used to write thumbnails into gcode.
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
#endif // ENABLE_THUMBNAIL_GENERATOR
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
std::string m_temp_output_path;
// Output path provided by the user. The output path may be set even if the slicing is running,
// but once set, it cannot be re-set.
std::string m_export_path;
bool m_export_path_on_removable_media = false;
// Print host upload job to schedule after slicing is complete, used by schedule_upload(),
// empty by default (ie. no upload to schedule)
PrintHostJob m_upload_job;

View file

@ -1,9 +1,6 @@
#include "libslic3r/libslic3r.h"
#include "Camera.hpp"
#if !ENABLE_THUMBNAIL_GENERATOR
#include "3DScene.hpp"
#endif // !ENABLE_THUMBNAIL_GENERATOR
#include "GUI_App.hpp"
#include "AppConfig.hpp"
#if ENABLE_CAMERA_STATISTICS
@ -25,10 +22,8 @@ namespace Slic3r {
namespace GUI {
const double Camera::DefaultDistance = 1000.0;
#if ENABLE_THUMBNAIL_GENERATOR
const double Camera::DefaultZoomToBoxMarginFactor = 1.025;
const double Camera::DefaultZoomToVolumesMarginFactor = 1.025;
#endif // ENABLE_THUMBNAIL_GENERATOR
double Camera::FrustrumMinZRange = 50.0;
double Camera::FrustrumMinNearZ = 100.0;
double Camera::FrustrumZMargin = 10.0;
@ -219,18 +214,10 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
glsafe(::glMatrixMode(GL_MODELVIEW));
}
#if ENABLE_THUMBNAIL_GENERATOR
void Camera::zoom_to_box(const BoundingBoxf3& box, double margin_factor)
#else
void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
// Calculate the zoom factor needed to adjust the view around the given box.
#if ENABLE_THUMBNAIL_GENERATOR
double zoom = calc_zoom_to_bounding_box_factor(box, margin_factor);
#else
double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h);
#endif // ENABLE_THUMBNAIL_GENERATOR
if (zoom > 0.0)
{
m_zoom = zoom;
@ -239,7 +226,6 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
}
}
#if ENABLE_THUMBNAIL_GENERATOR
void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor)
{
Vec3d center;
@ -251,7 +237,6 @@ void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor)
set_target(center);
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_CAMERA_STATISTICS
void Camera::debug_render() const
@ -387,11 +372,7 @@ std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBo
return ret;
}
#if ENABLE_THUMBNAIL_GENERATOR
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double margin_factor) const
#else
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const
#endif // ENABLE_THUMBNAIL_GENERATOR
{
double max_bb_size = box.max_size();
if (max_bb_size == 0.0)
@ -423,11 +404,6 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
double max_x = -DBL_MAX;
double max_y = -DBL_MAX;
#if !ENABLE_THUMBNAIL_GENERATOR
// margin factor to give some empty space around the box
double margin_factor = 1.25;
#endif // !ENABLE_THUMBNAIL_GENERATOR
for (const Vec3d& v : vertices)
{
// project vertex on the plane perpendicular to camera forward axis
@ -458,7 +434,6 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
return std::min((double)m_viewport[2] / dx, (double)m_viewport[3] / dy);
}
#if ENABLE_THUMBNAIL_GENERATOR
double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& center, double margin_factor) const
{
if (volumes.empty())
@ -519,7 +494,6 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
return std::min((double)m_viewport[2] / dx, (double)m_viewport[3] / dy);
}
#endif // ENABLE_THUMBNAIL_GENERATOR
void Camera::set_distance(double distance) const
{

View file

@ -2,9 +2,7 @@
#define slic3r_Camera_hpp_
#include "libslic3r/BoundingBox.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "3DScene.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
#include <array>
namespace Slic3r {
@ -13,10 +11,8 @@ namespace GUI {
struct Camera
{
static const double DefaultDistance;
#if ENABLE_THUMBNAIL_GENERATOR
static const double DefaultZoomToBoxMarginFactor;
static const double DefaultZoomToVolumesMarginFactor;
#endif // ENABLE_THUMBNAIL_GENERATOR
static double FrustrumMinZRange;
static double FrustrumMinNearZ;
static double FrustrumZMargin;
@ -97,12 +93,8 @@ public:
// If larger z span is needed, pass the desired values of near and far z (negative values are ignored)
void apply_projection(const BoundingBoxf3& box, double near_z = -1.0, double far_z = -1.0) const;
#if ENABLE_THUMBNAIL_GENERATOR
void zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultZoomToBoxMarginFactor);
void zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor = DefaultZoomToVolumesMarginFactor);
#else
void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h);
#endif // ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_CAMERA_STATISTICS
void debug_render() const;
@ -138,12 +130,8 @@ private:
// returns tight values for nearZ and farZ plane around the given bounding box
// the camera MUST be outside of the bounding box in eye coordinate of the given box
std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const;
#if ENABLE_THUMBNAIL_GENERATOR
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double margin_factor = DefaultZoomToBoxMarginFactor) const;
double calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& center, double margin_factor = DefaultZoomToVolumesMarginFactor) const;
#else
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const;
#endif // ENABLE_THUMBNAIL_GENERATOR
void set_distance(double distance) const;
void set_default_orientation();

View file

@ -268,8 +268,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
"bridge_acceleration", "first_layer_acceleration" })
toggle_field(el, have_default_acceleration);
bool have_skirt = config->opt_int("skirts") > 0 || config->opt_float("min_skirt_length") > 0;
for (auto el : { "skirt_distance", "skirt_height" })
bool have_skirt = config->opt_int("skirts") > 0;
toggle_field("skirt_height", have_skirt && !config->opt_bool("draft_shield"));
for (auto el : { "skirt_distance", "draft_shield", "min_skirt_length" })
toggle_field(el, have_skirt);
bool have_brim = config->opt_float("brim_width") > 0;

View file

@ -188,7 +188,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
wxBitmap bitmap;
int bitmap_width = 0;
const wxString bitmap_file = GUI::from_u8(Slic3r::var((boost::format("printers/%1%_%2%.png") % vendor.id % model.id).str()));
const wxString bitmap_file = GUI::from_u8(Slic3r::resources_dir() + "/profiles/" + vendor.id + "/" + model.id + "_thumbnail.png");
if (wxFileExists(bitmap_file)) {
bitmap.LoadFile(bitmap_file, wxBITMAP_TYPE_PNG);
bitmap_width = bitmap.GetWidth();
@ -450,7 +450,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent)
% _utf8(ConfigWizard::name())).str())
))
, cbox_reset(append(
new wxCheckBox(this, wxID_ANY, _(L("Remove user profiles - install from scratch (a snapshot will be taken beforehand)")))
new wxCheckBox(this, wxID_ANY, _(L("Remove user profiles (a snapshot will be taken beforehand)")))
))
{
welcome_text->Hide();
@ -1473,12 +1473,41 @@ void ConfigWizard::priv::load_vendors()
pair.second.preset_bundle->load_installed_printers(appconfig_new);
}
if (app_config->has_section(AppConfig::SECTION_FILAMENTS)) {
appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS));
}
if (app_config->has_section(AppConfig::SECTION_MATERIALS)) {
appconfig_new.set_section(AppConfig::SECTION_MATERIALS, app_config->get_section(AppConfig::SECTION_MATERIALS));
}
// Copy installed filaments and SLA material names from app_config to appconfig_new
// while resolving current names of profiles, which were renamed in the meantime.
for (PrinterTechnology technology : { ptFFF, ptSLA }) {
const std::string &section_name = (technology == ptFFF) ? AppConfig::SECTION_FILAMENTS : AppConfig::SECTION_MATERIALS;
std::map<std::string, std::string> section_new;
if (app_config->has_section(section_name)) {
const std::map<std::string, std::string> &section_old = app_config->get_section(section_name);
for (const std::pair<std::string, std::string> &material_name_and_installed : section_old)
if (material_name_and_installed.second == "1") {
// Material is installed. Resolve it in bundles.
size_t num_found = 0;
const std::string &material_name = material_name_and_installed.first;
for (auto &bundle : bundles) {
const PresetCollection &materials = bundle.second.preset_bundle->materials(technology);
const Preset *preset = materials.find_preset(material_name);
if (preset == nullptr) {
// Not found. Maybe the material preset is there, bu it was was renamed?
const std::string *new_name = materials.get_preset_name_renamed(material_name);
if (new_name != nullptr)
preset = materials.find_preset(*new_name);
}
if (preset != nullptr) {
// Materal preset was found, mark it as installed.
section_new[preset->name] = "1";
++ num_found;
}
}
if (num_found == 0)
BOOST_LOG_TRIVIAL(error) << boost::format("Profile %1% was not found in installed vendor Preset Bundles.") % material_name;
else if (num_found > 1)
BOOST_LOG_TRIVIAL(error) << boost::format("Profile %1% was found in %2% vendor Preset Bundles.") % material_name % num_found;
}
}
appconfig_new.set_section(section_name, section_new);
};
}
void ConfigWizard::priv::add_page(ConfigWizardPage *page)
@ -1642,9 +1671,9 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker
}
}
// if at list one printer is selected but there in no one selected material,
// select materials which is default for selected printer(s)
select_default_materials_if_needed(pair.second.vendor_profile, page->technology, evt.model_id);
// When a printer model is picked, but there is no material installed compatible with this printer model,
// install default materials for selected printer model silently.
check_and_install_missing_materials(page->technology, evt.model_id);
}
if (page->technology & T_FFF) {
@ -1654,41 +1683,26 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker
}
}
void ConfigWizard::priv::select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel>& models, Technology technology, const std::string& model_id)
void ConfigWizard::priv::select_default_materials_for_printer_model(const VendorProfile::PrinterModel &printer_model, Technology technology)
{
PageMaterials* page_materials = technology & T_FFF ? page_filaments : page_sla_materials;
auto it = std::find_if(models.begin(), models.end(), [model_id](VendorProfile::PrinterModel model) {return model_id == model.id; });
if (it != models.end())
for (const std::string& material : it->default_materials)
appconfig_new.set(page_materials->materials->appconfig_section(), material, "1");
for (const std::string& material : printer_model.default_materials)
appconfig_new.set(page_materials->materials->appconfig_section(), material, "1");
}
void ConfigWizard::priv::select_default_materials_if_needed(VendorProfile* vendor_profile, Technology technology, const std::string& model_id)
void ConfigWizard::priv::select_default_materials_for_printer_models(Technology technology, const std::set<const VendorProfile::PrinterModel*> &printer_models)
{
if ((technology & T_FFF && !any_fff_selected) ||
(technology & T_SLA && !any_sla_selected) ||
check_materials_in_config(technology, false))
return;
PageMaterials *page_materials = technology & T_FFF ? page_filaments : page_sla_materials;
const std::string &appconfig_section = page_materials->materials->appconfig_section();
select_default_materials_for_printer_model(vendor_profile->models, technology, model_id);
}
void ConfigWizard::priv::selected_default_materials(Technology technology)
{
auto select_default_materials_for_printer_page = [this](PagePrinters * page_printers, Technology technology)
auto select_default_materials_for_printer_page = [this, appconfig_section, printer_models](PagePrinters *page_printers, Technology technology)
{
std::set<std::string> selected_models = page_printers->get_selected_models();
const std::string vendor_id = page_printers->get_vendor_id();
const std::string vendor_id = page_printers->get_vendor_id();
for (auto& pair : bundles)
{
if (pair.first != vendor_id)
continue;
for (const std::string& model_id : selected_models)
select_default_materials_for_printer_model(pair.second.vendor_profile->models, technology, model_id);
}
if (pair.first == vendor_id)
for (const VendorProfile::PrinterModel *printer_model : printer_models)
for (const std::string &material : printer_model->default_materials)
appconfig_new.set(appconfig_section, material, "1");
};
PagePrinters* page_printers = technology & T_FFF ? page_fff : page_msla;
@ -1702,7 +1716,7 @@ void ConfigWizard::priv::selected_default_materials(Technology technology)
}
update_materials(technology);
(technology& T_FFF ? page_filaments : page_sla_materials)->reload_presets();
((technology & T_FFF) ? page_filaments : page_sla_materials)->reload_presets();
}
void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install)
@ -1741,53 +1755,107 @@ bool ConfigWizard::priv::on_bnt_finish()
page_sla_materials->reload_presets();
// theres no need to check that filament is selected if we have only custom printer
if (custom_printer_selected && !any_fff_selected && !any_sla_selected) return true;
if (custom_printer_selected && !any_fff_selected && !any_sla_selected) return true;
// check, that there is selected at least one filament/material
return check_materials_in_config(T_ANY);
return check_and_install_missing_materials(T_ANY);
}
bool ConfigWizard::priv::check_materials_in_config(Technology technology, bool show_info_msg)
// This allmighty method verifies, whether there is at least a single compatible filament or SLA material installed
// for each Printer preset of each Printer Model installed.
//
// In case only_for_model_id is set, then the test is done for that particular printer model only, and the default materials are installed silently.
// Otherwise the user is quieried whether to install the missing default materials or not.
//
// Return true if the tested Printer Models already had materials installed.
// Return false if there were some Printer Models with missing materials, independent from whether the defaults were installed for these
// respective Printer Models or not.
bool ConfigWizard::priv::check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id)
{
const auto exist_preset = [this](const std::string& section, const Materials& materials)
// Walk over all installed Printer presets and verify whether there is a filament or SLA material profile installed at the same PresetBundle,
// which is compatible with it.
const auto printer_models_missing_materials = [this, only_for_model_id](PrinterTechnology technology, const std::string &section)
{
if (appconfig_new.has_section(section) &&
!appconfig_new.get_section(section).empty())
{
const std::map<std::string, std::string>& appconfig_presets = appconfig_new.get_section(section);
for (const auto& preset : appconfig_presets)
if (materials.exist_preset(preset.first))
return true;
const std::map<std::string, std::string> &appconfig_presets = appconfig_new.has_section(section) ? appconfig_new.get_section(section) : std::map<std::string, std::string>();
std::set<const VendorProfile::PrinterModel*> printer_models_without_material;
for (const auto &pair : bundles) {
const PresetCollection &materials = pair.second.preset_bundle->materials(technology);
for (const auto &printer : pair.second.preset_bundle->printers) {
if (printer.is_visible && printer.printer_technology() == technology) {
const VendorProfile::PrinterModel *printer_model = PresetUtils::system_printer_model(printer);
assert(printer_model != nullptr);
if ((only_for_model_id.empty() || only_for_model_id == printer_model->id) &&
printer_models_without_material.find(printer_model) == printer_models_without_material.end()) {
bool has_material = false;
for (const std::pair<std::string, std::string> &preset : appconfig_presets) {
if (preset.second == "1") {
const Preset *material = materials.find_preset(preset.first, false);
if (material != nullptr && is_compatible_with_printer(PresetWithVendorProfile(*material, nullptr), PresetWithVendorProfile(printer, nullptr))) {
has_material = true;
break;
}
}
}
if (! has_material)
printer_models_without_material.insert(printer_model);
}
}
}
}
return false;
assert(printer_models_without_material.empty() || only_for_model_id.empty() || only_for_model_id == (*printer_models_without_material.begin())->id);
return printer_models_without_material;
};
const auto ask_and_selected_default_materials = [this](wxString message, Technology technology)
const auto ask_and_select_default_materials = [this](const wxString &message, const std::set<const VendorProfile::PrinterModel*> &printer_models, Technology technology)
{
wxMessageDialog msg(q, message, _(L("Notice")), wxYES_NO);
if (msg.ShowModal() == wxID_YES)
selected_default_materials(technology);
select_default_materials_for_printer_models(technology, printer_models);
};
if (any_fff_selected && technology & T_FFF && !exist_preset(AppConfig::SECTION_FILAMENTS, filaments))
{
if (show_info_msg)
{
wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" +
_(L("Do you want to automatic select default filaments?"));
ask_and_selected_default_materials(message, T_FFF);
const auto printer_model_list = [](const std::set<const VendorProfile::PrinterModel*> &printer_models) -> wxString {
wxString out;
for (const VendorProfile::PrinterModel *printer_model : printer_models) {
out += "\t\t";
out += from_u8(printer_model->name);
out += "\n";
}
return out;
};
if (any_fff_selected && (technology & T_FFF)) {
std::set<const VendorProfile::PrinterModel*> printer_models_without_material = printer_models_missing_materials(ptFFF, AppConfig::SECTION_FILAMENTS);
if (! printer_models_without_material.empty()) {
if (only_for_model_id.empty())
ask_and_select_default_materials(
_L("The following FFF printer models have no filament selected:") +
"\n\n\t" +
printer_model_list(printer_models_without_material) +
"\n\n\t" +
_L("Do you want to select default filaments for these FFF printer models?"),
printer_models_without_material,
T_FFF);
else
select_default_materials_for_printer_model(**printer_models_without_material.begin(), T_FFF);
return false;
}
return false;
}
if (any_sla_selected && technology & T_SLA && !exist_preset(AppConfig::SECTION_MATERIALS, sla_materials))
{
if (show_info_msg)
{
wxString message = _(L("You have to select at least one material for selected printers")) + "\n\n\t" +
_(L("Do you want to automatic select default materials?"));
ask_and_selected_default_materials(message, T_SLA);
}
return false;
if (any_sla_selected && (technology & T_SLA)) {
std::set<const VendorProfile::PrinterModel*> printer_models_without_material = printer_models_missing_materials(ptSLA, AppConfig::SECTION_MATERIALS);
if (! printer_models_without_material.empty()) {
if (only_for_model_id.empty())
ask_and_select_default_materials(
_L("The following SLA printer models have no materials selected:") +
"\n\n\t" +
printer_model_list(printer_models_without_material) +
"\n\n\t" +
_L("Do you want to select default SLA materials for these printer models?"),
printer_models_without_material,
T_SLA);
else
select_default_materials_for_printer_model(**printer_models_without_material.begin(), T_SLA);
return false;
}
}
return true;
@ -1926,6 +1994,7 @@ void ConfigWizard::priv::update_presets_in_config(const std::string& section, co
const PresetAliases& aliases = section == AppConfig::SECTION_FILAMENTS ? aliases_fff : aliases_sla;
auto update = [this, add](const std::string& s, const std::string& key) {
assert(! s.empty());
if (add)
appconfig_new.set(s, key, "1");
else
@ -2061,8 +2130,11 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
{
// check, that there is selected at least one filament/material
ConfigWizardPage* active_page = this->p->index->active_page();
if ( (active_page == p->page_filaments || active_page == p->page_sla_materials)
&& !p->check_materials_in_config(dynamic_cast<PageMaterials*>(active_page)->materials->technology))
if (// Leaving the filaments or SLA materials page and
(active_page == p->page_filaments || active_page == p->page_sla_materials) &&
// some Printer models had no filament or SLA material selected.
! p->check_and_install_missing_materials(dynamic_cast<PageMaterials*>(active_page)->materials->technology))
// In that case don't leave the page and the function above queried the user whether to install default materials.
return;
this->p->index->go_next();
});

View file

@ -82,14 +82,6 @@ struct Materials
}
}
bool exist_preset(const std::string& preset_name) const
{
for (const Preset* preset : presets)
if (preset->name == preset_name)
return true;
return false;
}
static const std::string UNKNOWN;
static const std::string& get_filament_type(const Preset *preset);
static const std::string& get_filament_vendor(const Preset *preset);
@ -503,17 +495,12 @@ struct ConfigWizard::priv
void on_custom_setup(const bool custom_wanted);
void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt);
void select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel> &models,
Technology technology,
const std::string & model_id);
void select_default_materials_if_needed(VendorProfile* vendor_profile,
Technology technology,
const std::string &model_id);
void selected_default_materials(Technology technology);
void select_default_materials_for_printer_model(const VendorProfile::PrinterModel &printer_model, Technology technology);
void select_default_materials_for_printer_models(Technology technology, const std::set<const VendorProfile::PrinterModel*> &printer_models);
void on_3rdparty_install(const VendorProfile *vendor, bool install);
bool on_bnt_finish();
bool check_materials_in_config(Technology technology, bool show_info_msg = true);
bool check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id = std::string());
void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater);
// #ys_FIXME_alise
void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add);

View file

@ -375,12 +375,11 @@ void TextCtrl::BUILD() {
{
e.Skip();
#ifdef __WXOSX__
// OSX issue: For some unknown reason wxEVT_KILL_FOCUS is emitted twice in a row
// OSX issue: For some unknown reason wxEVT_KILL_FOCUS is emitted twice in a row in some cases
// (like when information dialog is shown during an update of the option value)
// Thus, suppress its second call
if (bKilledFocus) {
bKilledFocus = false;
if (bKilledFocus)
return;
}
bKilledFocus = true;
#endif // __WXOSX__
@ -391,6 +390,10 @@ void TextCtrl::BUILD() {
bEnterPressed = false;
else
propagate_value();
#ifdef __WXOSX__
// After processing of KILL_FOCUS event we should to invalidate a bKilledFocus flag
bKilledFocus = false;
#endif // __WXOSX__
}), temp->GetId());
// select all text using Ctrl+A
@ -511,7 +514,7 @@ void TextCtrl::disable() { dynamic_cast<wxTextCtrl*>(window)->Disable(); dynamic
#ifdef __WXGTK__
void TextCtrl::change_field_value(wxEvent& event)
{
if (bChangedValueEvent = (event.GetEventType()==wxEVT_KEY_UP))
if ((bChangedValueEvent = (event.GetEventType()==wxEVT_KEY_UP)))
on_change_field();
event.Skip();
};

View file

@ -7,9 +7,7 @@
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/PreviewData.hpp"
#if ENABLE_THUMBNAIL_GENERATOR
#include "libslic3r/GCode/ThumbnailData.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
#include "libslic3r/Geometry.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/Utils.hpp"
@ -24,8 +22,9 @@
#include "slic3r/GUI/GUI_Preview.hpp"
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#include "slic3r/GUI/GLCanvas3DManager.hpp"
#include "slic3r/GUI/Camera.hpp"
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include "slic3r/GUI/3DBed.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
@ -65,9 +64,11 @@
#include <algorithm>
#include <cmath>
#include "DoubleSlider.hpp"
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
#if ENABLE_RENDER_STATISTICS
#include <chrono>
#endif // ENABLE_RENDER_STATISTICS
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
#include <imgui/imgui_internal.h>
@ -671,7 +672,7 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
if (it != m_warnings.end()) // this warning is already set to be shown
return;
m_warnings.push_back(warning);
m_warnings.emplace_back(warning);
std::sort(m_warnings.begin(), m_warnings.end());
}
else {
@ -1309,14 +1310,14 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
if (model_object->instances.size() > 1)
owner.label += " (" + std::to_string(inst_idx + 1) + ")";
owner.selected = volume->selected;
owners.push_back(owner);
owners.emplace_back(owner);
}
}
}
// updates print order strings
if (sorted_instances.size() > 1) {
for (int i = 0; i < sorted_instances.size(); ++i) {
for (size_t i = 0; i < sorted_instances.size(); ++i) {
size_t id = sorted_instances[i]->id().id;
std::vector<Owner>::iterator it = std::find_if(owners.begin(), owners.end(), [id](const Owner& owner) {
return owner.model_instance_id == id;
@ -1390,6 +1391,60 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
}
}
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void GLCanvas3D::Tooltip::set_text(const std::string& text)
{
// If the mouse is inside an ImGUI dialog, then the tooltip is suppressed.
const std::string &new_text = m_in_imgui ? std::string() : text;
if (m_text != new_text)
{
if (m_text.empty())
m_start_time = std::chrono::steady_clock::now();
m_text = new_text;
}
}
void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas) const
{
static ImVec2 size(0.0f, 0.0f);
auto validate_position = [](const Vec2d& position, const GLCanvas3D& canvas, const ImVec2& wnd_size) {
Size cnv_size = canvas.get_canvas_size();
float x = std::clamp((float)position(0), 0.0f, (float)cnv_size.get_width() - wnd_size.x);
float y = std::clamp((float)position(1) + 16, 0.0f, (float)cnv_size.get_height() - wnd_size.y);
return Vec2f(x, y);
};
if (m_text.empty())
return;
// draw the tooltip as hidden until the delay is expired
// use a value of alpha slightly different from 0.0f because newer imgui does not calculate properly the window size if alpha == 0.0f
float alpha = (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_start_time).count() < 500) ? 0.01f : 1.0f;
Vec2f position = validate_position(mouse_position, canvas, size);
ImGuiWrapper& imgui = *wxGetApp().imgui();
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
imgui.set_next_window_pos(position(0), position(1), ImGuiCond_Always, 0.0f, 0.0f);
imgui.begin(_(L("canvas_tooltip")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing);
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
ImGui::TextUnformatted(m_text.c_str());
// force re-render while the windows gets to its final size (it may take several frames) or while hidden
if (alpha < 1.0f || ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowExpectedSize(ImGui::GetCurrentWindow()).x)
canvas.request_extra_frame();
size = ImGui::GetWindowSize();
imgui.end();
ImGui::PopStyleVar(2);
}
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
@ -1419,9 +1474,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
#if ENABLE_THUMBNAIL_GENERATOR
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
#endif // ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
@ -1705,12 +1758,14 @@ void GLCanvas3D::set_color_by(const std::string& value)
m_color_by = value;
}
#if ENABLE_NON_STATIC_CANVAS_MANAGER
void GLCanvas3D::refresh_camera_scene_box()
{
#if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box());
}
#else
m_camera.set_scene_box(scene_bounding_box());
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
}
BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const
{
@ -2036,6 +2091,38 @@ void GLCanvas3D::render()
m_camera.debug_render();
#endif // ENABLE_CAMERA_STATISTICS
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
std::string tooltip;
// Negative coordinate means out of the window, likely because the window was deactivated.
// In that case the tooltip should be hidden.
if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0.)
{
if (tooltip.empty())
tooltip = m_layers_editing.get_tooltip(*this);
if (tooltip.empty())
tooltip = m_gizmos.get_tooltip();
if (tooltip.empty())
tooltip = m_main_toolbar.get_tooltip();
if (tooltip.empty())
tooltip = m_undoredo_toolbar.get_tooltip();
if (tooltip.empty())
#if ENABLE_NON_STATIC_CANVAS_MANAGER
tooltip = wxGetApp().plater()->get_view_toolbar().get_tooltip();
#else
tooltip = m_view_toolbar.get_tooltip();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
}
set_tooltip(tooltip);
m_tooltip.render(m_mouse.position, *this);
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
wxGetApp().imgui()->render();
@ -2046,9 +2133,29 @@ void GLCanvas3D::render()
auto end_time = std::chrono::high_resolution_clock::now();
m_render_stats.last_frame = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
#endif // ENABLE_RENDER_STATISTICS
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
std::string tooltip = "";
if (tooltip.empty())
tooltip = m_layers_editing.get_tooltip(*this);
if (tooltip.empty())
tooltip = m_gizmos.get_tooltip();
if (tooltip.empty())
tooltip = m_main_toolbar.get_tooltip();
if (tooltip.empty())
tooltip = m_undoredo_toolbar.get_tooltip();
if (tooltip.empty())
tooltip = m_view_toolbar.get_tooltip();
set_tooltip(tooltip);
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
#if ENABLE_THUMBNAIL_GENERATOR
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const
{
switch (GLCanvas3DManager::get_framebuffers_type())
@ -2063,7 +2170,6 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w,
default: { _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
}
}
#endif // ENABLE_THUMBNAIL_GENERATOR
void GLCanvas3D::select_all()
{
@ -2129,7 +2235,7 @@ std::vector<int> GLCanvas3D::load_object(const ModelObject& model_object, int ob
{
for (unsigned int i = 0; i < model_object.instances.size(); ++i)
{
instance_idxs.push_back(i);
instance_idxs.emplace_back(i);
}
}
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized);
@ -2576,9 +2682,9 @@ static void load_gcode_retractions(const GCodePreviewData::Retraction& retractio
for (const GCodePreviewData::Retraction::Position& position : copy)
{
volume->print_zs.push_back(unscale<double>(position.position(2)));
volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size());
volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size());
volume->print_zs.emplace_back(unscale<double>(position.position(2)));
volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size());
volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size());
_3DScene::point3_to_verts(position.position, position.width, position.height, *volume);
@ -3320,16 +3426,32 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
evt.SetY(evt.GetY() * scale);
#endif
Point pos(evt.GetX(), evt.GetY());
Point pos(evt.GetX(), evt.GetY());
ImGuiWrapper *imgui = wxGetApp().imgui();
ImGuiWrapper* imgui = wxGetApp().imgui();
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (m_tooltip.is_in_imgui() && evt.LeftUp())
// ignore left up events coming from imgui windows and not processed by them
m_mouse.ignore_left_up = true;
m_tooltip.set_in_imgui(false);
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (imgui->update_mouse_data(evt)) {
m_mouse.position = evt.Leaving() ? Vec2d(-1.0, -1.0) : pos.cast<double>();
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
m_tooltip.set_in_imgui(true);
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
render();
#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str());
printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str());
#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
return;
// do not return if dragging or tooltip not empty to allow for tooltip update
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (!m_mouse.dragging && m_tooltip.is_empty())
return;
#else
if (!m_mouse.dragging && m_canvas->GetToolTipText().empty())
return;
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
#ifdef __WXMSW__
@ -3384,6 +3506,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
mouse_up_cleanup();
m_mouse.set_start_position_3D_as_invalid();
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
m_mouse.position = pos.cast<double>();
#endif /// ENABLE_CANVAS_TOOLTIP_USING_IMGUI
return;
}
@ -3589,9 +3714,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
if ((m_layers_editing.state != LayersEditing::Unknown) && (layer_editing_object_idx != -1))
{
set_tooltip("");
if (m_layers_editing.state == LayersEditing::Editing)
{
_perform_layer_editing_action(&evt);
m_mouse.position = pos.cast<double>();
}
}
// do not process the dragging if the left mouse was set down in another canvas
else if (evt.LeftIsDown())
@ -3600,19 +3727,28 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined())
{
const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.);
if (wxGetApp().app_config->get("use_free_camera") == "1")
// Virtual track ball (similar to the 3DConnexion mouse).
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (wxGetApp().plater()->get_mouse3d_controller().connected() || (wxGetApp().app_config->get("use_free_camera") == "1"))
// Virtual track ball (similar to the 3DConnexion mouse).
wxGetApp().plater()->get_camera().rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
else
wxGetApp().plater()->get_camera().rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
#else
if (wxGetApp().plater()->get_mouse3d_controller().connected() || (wxGetApp().app_config->get("use_free_camera") == "1"))
// Virtual track ball (similar to the 3DConnexion mouse).
m_camera.rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
else
{
// Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation.
// It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(),
// which checks an atomics (flushes CPU caches).
// See GH issue #3816.
#if ENABLE_NON_STATIC_CANVAS_MANAGER
Camera& camera = wxGetApp().plater()->get_camera();
camera.recover_from_free_camera();
camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
#else
m_camera.recover_from_free_camera();
m_camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
}
m_dirty = true;
}
@ -3629,13 +3765,24 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z);
#if ENABLE_NON_STATIC_CANVAS_MANAGER
Camera& camera = wxGetApp().plater()->get_camera();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
if (wxGetApp().app_config->get("use_free_camera") != "1")
// Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation.
// It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(),
// which checks an atomics (flushes CPU caches).
// See GH issue #3816.
#if ENABLE_NON_STATIC_CANVAS_MANAGER
camera.recover_from_free_camera();
camera.set_target(camera.get_target() + orig - cur_pos);
#else
m_camera.recover_from_free_camera();
m_camera.set_target(m_camera.get_target() + orig - cur_pos);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_dirty = true;
}
m_mouse.drag.start_position_2D = pos;
}
}
@ -3710,28 +3857,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if (evt.Moving())
{
m_mouse.position = pos.cast<double>();
std::string tooltip = "";
if (tooltip.empty())
tooltip = m_layers_editing.get_tooltip(*this);
if (tooltip.empty())
tooltip = m_gizmos.get_tooltip();
if (tooltip.empty())
tooltip = m_main_toolbar.get_tooltip();
if (tooltip.empty())
tooltip = m_undoredo_toolbar.get_tooltip();
if (tooltip.empty())
#if ENABLE_NON_STATIC_CANVAS_MANAGER
tooltip = wxGetApp().plater()->get_view_toolbar().get_tooltip();
#else
tooltip = m_view_toolbar.get_tooltip();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
set_tooltip(tooltip);
// updates gizmos overlay
if (m_selection.is_empty())
@ -3806,20 +3931,27 @@ void GLCanvas3D::set_tooltip(const std::string& tooltip) const
{
if (m_canvas != nullptr)
{
wxToolTip* t = m_canvas->GetToolTip();
if (t != nullptr)
{
if (tooltip.empty())
m_canvas->UnsetToolTip();
else
t->SetTip(wxString::FromUTF8(tooltip.data()));
}
else if (!tooltip.empty()) // Avoid "empty" tooltips => unset of the empty tooltip leads to application crash under OSX
m_canvas->SetToolTip(wxString::FromUTF8(tooltip.data()));
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
m_tooltip.set_text(tooltip);
#else
wxString txt = wxString::FromUTF8(tooltip.data());
if (m_canvas->GetToolTipText() != txt)
m_canvas->SetToolTip(txt);
// wxToolTip* t = m_canvas->GetToolTip();
// if (t != nullptr)
// {
// if (tooltip.empty())
// m_canvas->UnsetToolTip();
// else
// t->SetTip(wxString::FromUTF8(tooltip.data()));
// }
// else if (!tooltip.empty()) // Avoid "empty" tooltips => unset of the empty tooltip leads to application crash under OSX
// m_canvas->SetToolTip(wxString::FromUTF8(tooltip.data()));
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
}
void GLCanvas3D::do_move(const std::string& snapshot_type)
{
if (m_model == nullptr)
@ -4196,8 +4328,10 @@ static bool string_getter(const bool is_undo, int idx, const char** out_text)
return wxGetApp().plater()->undo_redo_string_getter(is_undo, idx, out_text);
}
void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
bool GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
{
bool action_taken = false;
ImGuiWrapper* imgui = wxGetApp().imgui();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
@ -4222,14 +4356,18 @@ void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
m_imgui_undo_redo_hovered_pos = -1;
if (selected >= 0)
{
is_undo ? wxGetApp().plater()->undo_to(selected) : wxGetApp().plater()->redo_to(selected);
action_taken = true;
}
imgui->text(wxString::Format(is_undo ? _L_PLURAL("Undo %1$d Action", "Undo %1$d Actions", hovered + 1) : _L_PLURAL("Redo %1$d Action", "Redo %1$d Actions", hovered + 1), hovered + 1));
imgui->end();
return action_taken;
}
#if ENABLE_THUMBNAIL_GENERATOR
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0
#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
static void debug_output_thumbnail(const ThumbnailData& thumbnail_data)
@ -4272,7 +4410,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
if (!vol->is_modifier && !vol->is_wipe_tower && (!parts_only || (vol->composite_id.volume_id >= 0)))
{
if (!printable_only || is_visible(*vol))
visible_volumes.push_back(vol);
visible_volumes.emplace_back(vol);
}
}
@ -4587,7 +4725,6 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne
m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height());
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
}
#endif // ENABLE_THUMBNAIL_GENERATOR
bool GLCanvas3D::_init_toolbars()
{
@ -4791,12 +4928,18 @@ bool GLCanvas3D::_init_undoredo_toolbar()
item.name = "undo";
item.icon_filename = "undo_toolbar.svg";
item.tooltip = _utf8(L("Undo")) + " [" + GUI::shortkey_ctrl_prefix() + "Z]\n" + _utf8(L("Click right mouse button to open History"));
item.tooltip = _utf8(L("Undo")) + " [" + GUI::shortkey_ctrl_prefix() + "Z]\n" + _utf8(L("Click right mouse button to open/close History"));
item.sprite_id = 0;
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_UNDO)); };
item.right.toggable = true;
item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; };
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(true, 0.5f * (left + right)); };
item.right.render_callback = [this](float left, float right, float, float) {
if (m_canvas != nullptr)
{
if (_render_undo_redo_stack(true, 0.5f * (left + right)))
_deactivate_undo_redo_toolbar_items();
}
};
item.enabling_callback = [this]()->bool {
bool can_undo = wxGetApp().plater()->can_undo();
int id = m_undoredo_toolbar.get_item_id("undo");
@ -4824,11 +4967,17 @@ bool GLCanvas3D::_init_undoredo_toolbar()
item.name = "redo";
item.icon_filename = "redo_toolbar.svg";
item.tooltip = _utf8(L("Redo")) + " [" + GUI::shortkey_ctrl_prefix() + "Y]\n" + _utf8(L("Click right mouse button to open History"));
item.tooltip = _utf8(L("Redo")) + " [" + GUI::shortkey_ctrl_prefix() + "Y]\n" + _utf8(L("Click right mouse button to open/close History"));
item.sprite_id = 1;
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_REDO)); };
item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; };
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(false, 0.5f * (left + right)); };
item.right.render_callback = [this](float left, float right, float, float) {
if (m_canvas != nullptr)
{
if (_render_undo_redo_stack(false, 0.5f * (left + right)))
_deactivate_undo_redo_toolbar_items();
}
};
item.enabling_callback = [this]()->bool {
bool can_redo = wxGetApp().plater()->can_redo();
int id = m_undoredo_toolbar.get_item_id("redo");
@ -4907,7 +5056,6 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
return bb;
}
#if ENABLE_THUMBNAIL_GENERATOR
void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box, double margin_factor)
{
#if ENABLE_NON_STATIC_CANVAS_MANAGER
@ -4917,14 +5065,6 @@ void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box, double margin_factor)
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_dirty = true;
}
#else
void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box)
{
const Size& cnv_size = get_canvas_size();
m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height());
m_dirty = true;
}
#endif // ENABLE_THUMBNAIL_GENERATOR
void GLCanvas3D::_update_camera_zoom(double zoom)
{
@ -4996,7 +5136,7 @@ void GLCanvas3D::_picking_pass() const
}
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
{
m_hover_volume_idxs.push_back(volume_id);
m_hover_volume_idxs.emplace_back(volume_id);
m_gizmos.set_hover_id(-1);
}
else
@ -5135,9 +5275,6 @@ void GLCanvas3D::_render_objects() const
if (m_volumes.empty())
return;
#if !ENABLE_THUMBNAIL_GENERATOR
glsafe(::glEnable(GL_LIGHTING));
#endif // !ENABLE_THUMBNAIL_GENERATOR
glsafe(::glEnable(GL_DEPTH_TEST));
m_camera_clipping_plane = m_gizmos.get_sla_clipping_plane();
@ -5203,9 +5340,6 @@ void GLCanvas3D::_render_objects() const
m_shader.stop_using();
m_camera_clipping_plane = ClippingPlane::ClipsNothing();
#if !ENABLE_THUMBNAIL_GENERATOR
glsafe(::glDisable(GL_LIGHTING));
#endif // !ENABLE_THUMBNAIL_GENERATOR
}
void GLCanvas3D::_render_selection() const
@ -5247,6 +5381,19 @@ void GLCanvas3D::_render_overlays() const
_render_gizmos_overlay();
_render_warning_texture();
_render_legend_texture();
// main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed
// to correctly place them
#if ENABLE_RETINA_GL
const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(true);
m_main_toolbar.set_scale(scale);
m_undoredo_toolbar.set_scale(scale);
#else
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(true));
m_main_toolbar.set_icons_size(size);
m_undoredo_toolbar.set_icons_size(size);
#endif // ENABLE_RETINA_GL
_render_main_toolbar();
_render_undoredo_toolbar();
_render_view_toolbar();
@ -5260,7 +5407,7 @@ void GLCanvas3D::_render_overlays() const
if (sequential_print) {
for (ModelObject* model_object : m_model->objects)
for (ModelInstance* model_instance : model_object->instances) {
sorted_instances.push_back(model_instance);
sorted_instances.emplace_back(model_instance);
}
}
m_labels.render(sorted_instances);
@ -5343,17 +5490,6 @@ void GLCanvas3D::_render_main_toolbar() const
if (!m_main_toolbar.is_enabled())
return;
#if ENABLE_RETINA_GL
// m_main_toolbar.set_scale(m_retina_helper->get_scale_factor());
const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(true);
m_main_toolbar.set_scale(scale); //! #ys_FIXME_experiment
#else
// m_main_toolbar.set_scale(m_canvas->GetContentScaleFactor());
// m_main_toolbar.set_scale(wxGetApp().em_unit()*0.1f);
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(true));
m_main_toolbar.set_icons_size(size); //! #ys_FIXME_experiment
#endif // ENABLE_RETINA_GL
Size cnv_size = get_canvas_size();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
@ -5373,17 +5509,6 @@ void GLCanvas3D::_render_undoredo_toolbar() const
if (!m_undoredo_toolbar.is_enabled())
return;
#if ENABLE_RETINA_GL
// m_undoredo_toolbar.set_scale(m_retina_helper->get_scale_factor());
const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(true);
m_undoredo_toolbar.set_scale(scale); //! #ys_FIXME_experiment
#else
// m_undoredo_toolbar.set_scale(m_canvas->GetContentScaleFactor());
// m_undoredo_toolbar.set_scale(wxGetApp().em_unit()*0.1f);
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(true));
m_undoredo_toolbar.set_icons_size(size); //! #ys_FIXME_experiment
#endif // ENABLE_RETINA_GL
Size cnv_size = get_canvas_size();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
@ -5783,29 +5908,26 @@ void GLCanvas3D::_load_print_toolpaths()
if ((skirt_height == 0) && (print->config().brim_width.value > 0))
skirt_height = 1;
// get first skirt_height layers (maybe this should be moved to a PrintObject method?)
const PrintObject* object0 = print->objects().front();
// Get first skirt_height layers.
//FIXME This code is fishy. It may not work for multiple objects with different layering due to variable layer height feature.
// This is not critical as this is just an initial preview.
const PrintObject* highest_object = *std::max_element(print->objects().begin(), print->objects().end(), [](auto l, auto r){ return l->layers().size() < r->layers().size(); });
std::vector<float> print_zs;
print_zs.reserve(skirt_height * 2);
for (size_t i = 0; i < std::min(skirt_height, object0->layers().size()); ++i)
{
print_zs.push_back(float(object0->layers()[i]->print_z));
}
//FIXME why there are support layers?
for (size_t i = 0; i < std::min(skirt_height, object0->support_layers().size()); ++i)
{
print_zs.push_back(float(object0->support_layers()[i]->print_z));
}
for (size_t i = 0; i < std::min(skirt_height, highest_object->layers().size()); ++ i)
print_zs.emplace_back(float(highest_object->layers()[i]->print_z));
// Only add skirt for the raft layers.
for (size_t i = 0; i < std::min(skirt_height, std::min(highest_object->slicing_parameters().raft_layers(), highest_object->support_layers().size())); ++ i)
print_zs.emplace_back(float(highest_object->support_layers()[i]->print_z));
sort_remove_duplicates(print_zs);
if (print_zs.size() > skirt_height)
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
skirt_height = std::min(skirt_height, print_zs.size());
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE);
for (size_t i = 0; i < skirt_height; ++i) {
volume->print_zs.push_back(print_zs[i]);
volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size());
volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size());
for (size_t i = 0; i < skirt_height; ++ i) {
volume->print_zs.emplace_back(print_zs[i]);
volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size());
volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size());
if (i == 0)
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume);
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume);
@ -5971,10 +6093,10 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
}
if (ctxt.has_perimeters || ctxt.has_infill)
for (const Layer *layer : print_object.layers())
ctxt.layers.push_back(layer);
ctxt.layers.emplace_back(layer);
if (ctxt.has_support)
for (const Layer *layer : print_object.support_layers())
ctxt.layers.push_back(layer);
ctxt.layers.emplace_back(layer);
std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; });
// Maximum size of an allocation block: 32MB / sizeof(float)
@ -6043,9 +6165,9 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
for (GLVolume *vol : vols)
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
vol->print_zs.push_back(layer->print_z);
vol->offsets.push_back(vol->indexed_vertex_array.quad_indices.size());
vol->offsets.push_back(vol->indexed_vertex_array.triangle_indices.size());
vol->print_zs.emplace_back(layer->print_z);
vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size());
vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size());
}
for (const PrintInstance &instance : *ctxt.shifted_copies) {
const Point &copy = instance.shift;
@ -6201,9 +6323,9 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
for (size_t i = 0; i < vols.size(); ++i) {
GLVolume &vol = *vols[i];
if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) {
vol.print_zs.push_back(layer.front().print_z);
vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
vol.print_zs.emplace_back(layer.front().print_z);
vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size());
}
}
for (const WipeTower::ToolChangeResult &extrusions : layer) {
@ -6416,9 +6538,9 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
assert(it_filter != filters.end() && key.first == it_filter->first);
GLVolume& vol = *it_filter->second;
vol.print_zs.push_back(layer.z);
vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
vol.print_zs.emplace_back(layer.z);
vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size());
_3DScene::extrusionentity_to_verts(path.polyline, path.width, path.height, layer.z, vol);
}
@ -6490,9 +6612,9 @@ inline void travel_paths_internal(
assert(it != by_type.end() && it->first == func_value(polyline));
GLVolume& vol = *it->second;
vol.print_zs.push_back(unscale<double>(polyline.polyline.bounding_box().min(2)));
vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
vol.print_zs.emplace_back(unscale<double>(polyline.polyline.bounding_box().min(2)));
vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size());
_3DScene::polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, vol);

View file

@ -3,24 +3,24 @@
#include <stddef.h>
#include <memory>
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
#include <chrono>
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
#include "3DScene.hpp"
#include "GLToolbar.hpp"
#include "GLShader.hpp"
#include "Event.hpp"
#include "3DBed.hpp"
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
#include "Camera.hpp"
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
#include "Selection.hpp"
#include "Gizmos/GLGizmosManager.hpp"
#include "GUI_ObjectLayers.hpp"
#include "GLSelectionRectangle.hpp"
#include "MeshUtils.hpp"
#include <float.h>
#include <wx/timer.h>
class wxWindow;
class wxSizeEvent;
class wxIdleEvent;
class wxKeyEvent;
@ -37,20 +37,16 @@ class wxGLContext;
namespace Slic3r {
class GLShader;
class ExPolygon;
class Bed3D;
struct Camera;
class BackgroundSlicingProcess;
class GCodePreviewData;
#if ENABLE_THUMBNAIL_GENERATOR
struct ThumbnailData;
#endif // ENABLE_THUMBNAIL_GENERATOR
struct SlicingParameters;
enum LayerHeightEditActionType : unsigned int;
namespace GUI {
class GLGizmoBase;
#if ENABLE_RETINA_GL
class RetinaHelper;
#endif
@ -118,9 +114,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
class GLCanvas3D
{
#if ENABLE_THUMBNAIL_GENERATOR
static const double DefaultCameraZoomToBoxMarginFactor;
#endif // ENABLE_THUMBNAIL_GENERATOR
public:
struct GCodePreviewVolumeIndex
@ -394,6 +388,24 @@ private:
void render(const std::vector<const ModelInstance*>& sorted_instances) const;
};
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
class Tooltip
{
std::string m_text;
std::chrono::steady_clock::time_point m_start_time;
// Indicator that the mouse is inside an ImGUI dialog, therefore the tooltip should be suppressed.
bool m_in_imgui = false;
public:
bool is_empty() const { return m_text.empty(); }
void set_text(const std::string& text);
void render(const Vec2d& mouse_position, GLCanvas3D& canvas) const;
// Indicates that the mouse is inside an ImGUI dialog, therefore the tooltip should be suppressed.
void set_in_imgui(bool b) { m_in_imgui = b; }
bool is_in_imgui() const { return m_in_imgui; }
};
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
public:
enum ECursorType : unsigned char
{
@ -474,6 +486,9 @@ private:
int m_selected_extruder;
Labels m_labels;
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
mutable Tooltip m_tooltip;
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
public:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
@ -576,11 +591,9 @@ public:
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
void render();
#if ENABLE_THUMBNAIL_GENERATOR
// printable_only == false -> render also non printable volumes as grayed
// parts_only == false -> render also sla support and pad
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
#endif // ENABLE_THUMBNAIL_GENERATOR
void select_all();
void deselect_all();
@ -702,11 +715,7 @@ private:
BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const;
#if ENABLE_THUMBNAIL_GENERATOR
void _zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultCameraZoomToBoxMarginFactor);
#else
void _zoom_to_box(const BoundingBoxf3& box);
#endif // ENABLE_THUMBNAIL_GENERATOR
void _update_camera_zoom(double zoom);
void _refresh_if_shown_on_screen();
@ -734,8 +743,7 @@ private:
#endif // ENABLE_SHOW_CAMERA_TARGET
void _render_sla_slices() const;
void _render_selection_sidebar_hints() const;
void _render_undo_redo_stack(const bool is_undo, float pos_x) const;
#if ENABLE_THUMBNAIL_GENERATOR
bool _render_undo_redo_stack(const bool is_undo, float pos_x) const;
void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
// render thumbnail using an off-screen framebuffer
void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
@ -743,7 +751,6 @@ private:
void _render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
// render thumbnail using the default framebuffer
void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
#endif // ENABLE_THUMBNAIL_GENERATOR
void _update_volumes_hover_state() const;

View file

@ -9,9 +9,12 @@
#include "slic3r/GUI/Camera.hpp"
#else
#include "../../slic3r/GUI/GLCanvas3D.hpp"
#include "../../slic3r/GUI/Camera.hpp"
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#include <GL/glew.h>
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//#include <GL/glew.h>
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#include <wx/event.h>
#include <wx/bitmap.h>
@ -91,7 +94,7 @@ bool GLToolbarItem::update_enabled_state()
void GLToolbarItem::render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const
{
auto uvs = [this](unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) ->GLTexture::Quad_UVs
auto uvs = [this](unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) -> GLTexture::Quad_UVs
{
assert((tex_width != 0) && (tex_height != 0));
GLTexture::Quad_UVs ret;
@ -159,7 +162,9 @@ GLToolbar::GLToolbar(GLToolbar::EType type, const std::string& name)
, m_name(name)
, m_enabled(false)
, m_icons_texture_dirty(true)
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
, m_tooltip("")
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
, m_pressed_toggable_id(-1)
{
}
@ -363,16 +368,37 @@ int GLToolbar::get_item_id(const std::string& name) const
return -1;
}
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
std::string GLToolbar::get_tooltip() const
{
std::string tooltip;
for (GLToolbarItem* item : m_items)
{
if (item->is_hovered())
{
tooltip = item->get_tooltip();
if (!item->is_pressed())
{
const std::string& additional_tooltip = item->get_additional_tooltip();
if (!additional_tooltip.empty())
tooltip += "\n" + additional_tooltip;
break;
}
}
}
return tooltip;
}
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void GLToolbar::get_additional_tooltip(int item_id, std::string& text)
{
if ((0 <= item_id) && (item_id < (int)m_items.size()))
if (0 <= item_id && item_id < (int)m_items.size())
{
GLToolbarItem* item = m_items[item_id];
if (item != nullptr)
{
text = item->get_additional_tooltip();
return;
}
text = m_items[item_id]->get_additional_tooltip();
return;
}
text.clear();
@ -380,12 +406,8 @@ void GLToolbar::get_additional_tooltip(int item_id, std::string& text)
void GLToolbar::set_additional_tooltip(int item_id, const std::string& text)
{
if ((0 <= item_id) && (item_id < (int)m_items.size()))
{
GLToolbarItem* item = m_items[item_id];
if (item != nullptr)
item->set_additional_tooltip(text);
}
if (0 <= item_id && item_id < (int)m_items.size())
m_items[item_id]->set_additional_tooltip(text);
}
bool GLToolbar::update_items_state()
@ -426,14 +448,62 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
// mouse anywhere
if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
{
if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()))
if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())) {
// prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it,
// as when switching between views
processed = true;
m_mouse_capture.reset();
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (contains_mouse(mouse_pos, parent) == -1)
// mouse is outside the toolbar
m_tooltip.clear();
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
return true;
}
m_mouse_capture.reset();
}
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (evt.Moving())
update_hover_state(mouse_pos, parent);
else if (evt.LeftUp())
{
if (m_mouse_capture.left)
{
processed = true;
m_mouse_capture.left = false;
}
else
return false;
}
else if (evt.MiddleUp())
{
if (m_mouse_capture.middle)
{
processed = true;
m_mouse_capture.middle = false;
}
else
return false;
}
else if (evt.RightUp())
{
if (m_mouse_capture.right)
{
processed = true;
m_mouse_capture.right = false;
}
else
return false;
}
else if (evt.Dragging())
{
if (m_mouse_capture.any())
// if the button down was done on this toolbar, prevent from dragging into the scene
processed = true;
else
return false;
}
#else
if (evt.Moving())
m_tooltip = update_hover_state(mouse_pos, parent);
else if (evt.LeftUp())
@ -445,14 +515,19 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
else if (evt.Dragging() && m_mouse_capture.any())
// if the button down was done on this toolbar, prevent from dragging into the scene
processed = true;
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
int item_id = contains_mouse(mouse_pos, parent);
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (item_id != -1)
#else
if (item_id == -1)
{
// mouse is outside the toolbar
m_tooltip.clear();
}
else
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{
// mouse inside toolbar
if (evt.LeftDown() || evt.LeftDClick())
@ -484,8 +559,10 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
parent.set_as_dirty();
}
}
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
else if (evt.LeftUp())
processed = true;
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
return processed;
@ -614,6 +691,20 @@ void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas
}
}
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void GLToolbar::update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent)
{
if (!m_enabled)
return;
switch (m_layout.type)
{
default:
case Layout::Horizontal: { update_hover_state_horizontal(mouse_pos, parent); break; }
case Layout::Vertical: { update_hover_state_vertical(mouse_pos, parent); break; }
}
}
#else
std::string GLToolbar::update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent)
{
if (!m_enabled)
@ -626,8 +717,13 @@ std::string GLToolbar::update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& pa
case Layout::Vertical: { return update_hover_state_vertical(mouse_pos, parent); }
}
}
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent)
#else
std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent)
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{
// NB: mouse_pos is already scaled appropriately
@ -652,8 +748,10 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
float left = m_layout.left + scaled_border;
float top = m_layout.top - scaled_border;
std::string tooltip = "";
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
std::string tooltip;
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
for (GLToolbarItem* item : m_items)
{
if (!item->is_visible())
@ -668,6 +766,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
GLToolbarItem::EState state = item->get_state();
bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top);
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (inside)
{
tooltip = item->get_tooltip();
@ -678,6 +777,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
tooltip += "\n" + additional_tooltip;
}
}
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
switch (state)
{
@ -721,21 +821,54 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
break;
}
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
case GLToolbarItem::Disabled:
{
if (inside)
{
item->set_state(GLToolbarItem::HoverDisabled);
parent.set_as_dirty();
}
break;
}
case GLToolbarItem::HoverDisabled:
{
if (!inside)
{
item->set_state(GLToolbarItem::Disabled);
parent.set_as_dirty();
}
break;
}
default:
{
break;
}
#else
default:
case GLToolbarItem::Disabled:
{
break;
}
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
left += icon_stride;
}
}
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
return tooltip;
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent)
#else
std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent)
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{
// NB: mouse_pos is already scaled appropriately
@ -759,7 +892,9 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
float left = m_layout.left + scaled_border;
float top = m_layout.top - scaled_border;
std::string tooltip = "";
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
std::string tooltip;
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
for (GLToolbarItem* item : m_items)
{
@ -775,6 +910,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
GLToolbarItem::EState state = item->get_state();
bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top);
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (inside)
{
tooltip = item->get_tooltip();
@ -785,6 +921,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
tooltip += "\n" + additional_tooltip;
}
}
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
switch (state)
{
@ -828,18 +965,47 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
break;
}
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
case GLToolbarItem::Disabled:
{
if (inside)
{
item->set_state(GLToolbarItem::HoverDisabled);
parent.set_as_dirty();
}
break;
}
case GLToolbarItem::HoverDisabled:
{
if (!inside)
{
item->set_state(GLToolbarItem::Disabled);
parent.set_as_dirty();
}
break;
}
default:
{
break;
}
#else
default:
case GLToolbarItem::Disabled:
{
break;
}
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
top -= icon_stride;
}
}
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
return tooltip;
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
int GLToolbar::contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const
@ -1204,19 +1370,37 @@ bool GLToolbar::generate_icons_texture() const
std::vector<std::pair<int, bool>> states;
if (m_name == "Top")
{
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
states.push_back({ 1, false }); // Normal
states.push_back({ 0, false }); // Pressed
states.push_back({ 2, false }); // Disabled
states.push_back({ 0, false }); // Hover
states.push_back({ 0, false }); // HoverPressed
states.push_back({ 2, false }); // HoverDisabled
#else
states.push_back(std::make_pair(1, false));
states.push_back(std::make_pair(0, false));
states.push_back(std::make_pair(2, false));
states.push_back(std::make_pair(0, false));
states.push_back(std::make_pair(0, false));
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
else if (m_name == "View")
{
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
states.push_back({ 1, false }); // Normal
states.push_back({ 1, true }); // Pressed
states.push_back({ 1, false }); // Disabled
states.push_back({ 0, false }); // Hover
states.push_back({ 1, true }); // HoverPressed
states.push_back({ 1, false }); // HoverDisabled
#else
states.push_back(std::make_pair(1, false));
states.push_back(std::make_pair(1, true));
states.push_back(std::make_pair(1, false));
states.push_back(std::make_pair(0, false));
states.push_back(std::make_pair(1, true));
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
unsigned int sprite_size_px = (unsigned int)(m_layout.icons_size * m_layout.scale);

View file

@ -61,6 +61,9 @@ public:
Disabled,
Hover,
HoverPressed,
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
HoverDisabled,
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
Num_States
};
@ -119,9 +122,15 @@ public:
void do_left_action() { m_last_action_type = Left; m_data.left.action_callback(); }
void do_right_action() { m_last_action_type = Right; m_data.right.action_callback(); }
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
bool is_enabled() const { return (m_state != Disabled) && (m_state != HoverDisabled); }
bool is_disabled() const { return (m_state == Disabled) || (m_state == HoverDisabled); }
bool is_hovered() const { return (m_state == Hover) || (m_state == HoverPressed) || (m_state == HoverDisabled); }
#else
bool is_enabled() const { return m_state != Disabled; }
bool is_disabled() const { return m_state == Disabled; }
bool is_hovered() const { return (m_state == Hover) || (m_state == HoverPressed); }
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
bool is_pressed() const { return (m_state == Pressed) || (m_state == HoverPressed); }
bool is_visible() const { return m_data.visible; }
bool is_separator() const { return m_type == Separator; }
@ -252,7 +261,9 @@ private:
};
MouseCapture m_mouse_capture;
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
std::string m_tooltip;
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
int m_pressed_toggable_id;
public:
@ -298,7 +309,11 @@ public:
void force_left_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Left, item_id, parent, false); }
void force_right_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Right, item_id, parent, false); }
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
std::string get_tooltip() const;
#else
const std::string& get_tooltip() const { return m_tooltip; }
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void get_additional_tooltip(int item_id, std::string& text);
void set_additional_tooltip(int item_id, const std::string& text);
@ -318,9 +333,15 @@ private:
float get_height_vertical() const;
float get_main_size() const;
void do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover);
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
void update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
void update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
void update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);
#else
std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
std::string update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
std::string update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
// returns the id of the item under the given mouse position or -1 if none
int contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;
int contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;

View file

@ -10,6 +10,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/convert.hpp>
#include <wx/stdpaths.h>
#include <wx/imagpng.h>
@ -50,6 +51,7 @@
#ifdef __WXMSW__
#include <Shlobj.h>
#include <dbt.h>
#endif // __WXMSW__
#if ENABLE_THUMBNAIL_GENERATOR_DEBUG
@ -60,6 +62,7 @@
namespace Slic3r {
namespace GUI {
class MainFrame;
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
{
@ -96,9 +99,9 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }
static void register_dpi_event()
{
#ifdef WIN32
static void register_win32_dpi_event()
{
enum { WM_DPICHANGED_ = 0x02e0 };
wxWindow::MSWRegisterMessageHandler(WM_DPICHANGED_, [](wxWindow *win, WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) {
@ -111,9 +114,52 @@ static void register_dpi_event()
return true;
});
#endif
}
static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 };
static void register_win32_device_notification_event()
{
enum { WM_DPICHANGED_ = 0x02e0 };
wxWindow::MSWRegisterMessageHandler(WM_DEVICECHANGE, [](wxWindow *win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) {
// Some messages are sent to top level windows by default, some messages are sent to only registered windows, and we explictely register on MainFrame only.
auto main_frame = dynamic_cast<MainFrame*>(win);
auto plater = (main_frame == nullptr) ? nullptr : main_frame->plater();
if (plater == nullptr)
// Maybe some other top level window like a dialog or maybe a pop-up menu?
return true;
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
switch (wParam) {
case DBT_DEVICEARRIVAL:
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
plater->GetEventHandler()->AddPendingEvent(VolumeAttachedEvent(EVT_VOLUME_ATTACHED));
else if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
PDEV_BROADCAST_DEVICEINTERFACE lpdbi = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
// if (lpdbi->dbcc_classguid == GUID_DEVINTERFACE_VOLUME) {
// printf("DBT_DEVICEARRIVAL %d - Media has arrived: %ws\n", msg_count, lpdbi->dbcc_name);
if (lpdbi->dbcc_classguid == GUID_DEVINTERFACE_HID)
plater->GetEventHandler()->AddPendingEvent(HIDDeviceAttachedEvent(EVT_HID_DEVICE_ATTACHED, boost::nowide::narrow(lpdbi->dbcc_name)));
}
break;
case DBT_DEVICEREMOVECOMPLETE:
if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
plater->GetEventHandler()->AddPendingEvent(VolumeDetachedEvent(EVT_VOLUME_DETACHED));
else if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
PDEV_BROADCAST_DEVICEINTERFACE lpdbi = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
// if (lpdbi->dbcc_classguid == GUID_DEVINTERFACE_VOLUME)
// printf("DBT_DEVICEARRIVAL %d - Media was removed: %ws\n", msg_count, lpdbi->dbcc_name);
if (lpdbi->dbcc_classguid == GUID_DEVINTERFACE_HID)
plater->GetEventHandler()->AddPendingEvent(HIDDeviceDetachedEvent(EVT_HID_DEVICE_DETACHED, boost::nowide::narrow(lpdbi->dbcc_name)));
}
break;
default:
break;
}
return true;
});
}
#endif // WIN32
static void generic_exception_handle()
{
@ -265,7 +311,10 @@ bool GUI_App::on_init_inner()
show_error(nullptr, ex.what());
}
register_dpi_event();
#ifdef WIN32
register_win32_dpi_event();
register_win32_device_notification_event();
#endif // WIN32
// Let the libslic3r know the callback, which will translate messages on demand.
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
@ -562,6 +611,12 @@ void GUI_App::load_project(wxWindow *parent, wxString& input_file) const
void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
{
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if (this->plater_ != nullptr)
// hides the tooltip
plater_->get_current_canvas3D()->set_tooltip("");
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
input_files.Clear();
wxFileDialog dialog(parent ? parent : GetTopWindow(),
_(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):")),

View file

@ -58,7 +58,7 @@ void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_ed
}
}
wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinusButton *delete_button, PlusMinusButton *add_button)
{
const bool is_last_edited_range = range == m_selectable_range;
@ -79,8 +79,8 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
// Add control for the "Min Z"
auto editor = new LayerRangeEditor(this, double_to_string(range.first), etMinZ,
set_focus_data, [range, update_focus_data, this](coordf_t min_z, bool enter_pressed)
auto editor = new LayerRangeEditor(this, double_to_string(range.first), etMinZ, set_focus_data,
[range, update_focus_data, this, delete_button, add_button](coordf_t min_z, bool enter_pressed, bool dont_update_ui)
{
if (fabs(min_z - range.first) < EPSILON) {
m_selection_type = etUndef;
@ -89,10 +89,14 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
// data for next focusing
coordf_t max_z = min_z < range.second ? range.second : min_z + 0.5;
const t_layer_height_range& new_range = { min_z, max_z };
const t_layer_height_range new_range = { min_z, max_z };
if (delete_button)
delete_button->range = new_range;
if (add_button)
add_button->range = new_range;
update_focus_data(new_range, etMinZ, enter_pressed);
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
return wxGetApp().obj_list()->edit_layer_range(range, new_range, dont_update_ui);
});
select_editor(editor, is_last_edited_range);
@ -100,8 +104,8 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
// Add control for the "Max Z"
editor = new LayerRangeEditor(this, double_to_string(range.second), etMaxZ,
set_focus_data, [range, update_focus_data, this](coordf_t max_z, bool enter_pressed)
editor = new LayerRangeEditor(this, double_to_string(range.second), etMaxZ, set_focus_data,
[range, update_focus_data, this, delete_button, add_button](coordf_t max_z, bool enter_pressed, bool dont_update_ui)
{
if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
m_selection_type = etUndef;
@ -110,9 +114,13 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
// data for next focusing
const t_layer_height_range& new_range = { range.first, max_z };
if (delete_button)
delete_button->range = new_range;
if (add_button)
add_button->range = new_range;
update_focus_data(new_range, etMaxZ, enter_pressed);
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
return wxGetApp().obj_list()->edit_layer_range(range, new_range, dont_update_ui);
});
select_editor(editor, is_last_edited_range);
@ -120,9 +128,8 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
// Add control for the "Layer height"
editor = new LayerRangeEditor(this,
double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()),
etLayerHeight, set_focus_data, [range, this](coordf_t layer_height, bool)
editor = new LayerRangeEditor(this, double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()), etLayerHeight, set_focus_data,
[range, this](coordf_t layer_height, bool, bool)
{
return wxGetApp().obj_list()->edit_layer_range(range, layer_height);
});
@ -141,30 +148,30 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
return sizer;
}
void ObjectLayers::create_layers_list()
{
for (const auto layer : m_object->layer_config_ranges)
{
const t_layer_height_range& range = layer.first;
auto sizer = create_layer(range);
auto del_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_delete);
auto del_btn = new PlusMinusButton(m_parent, m_bmp_delete, range);
del_btn->SetToolTip(_(L("Remove layer range")));
auto add_btn = new PlusMinusButton(m_parent, m_bmp_add, range);
wxString tooltip = wxGetApp().obj_list()->can_add_new_range_after_current(range);
add_btn->SetToolTip(tooltip.IsEmpty() ? _(L("Add layer range")) : tooltip);
add_btn->Enable(tooltip.IsEmpty());
auto sizer = create_layer(range, del_btn, add_btn);
sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
del_btn->Bind(wxEVT_BUTTON, [range](wxEvent &) {
wxGetApp().obj_list()->del_layer_range(range);
});
auto add_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_add);
add_btn->SetToolTip(_(L("Add layer range")));
sizer->Add(add_btn);
add_btn->Bind(wxEVT_BUTTON, [range](wxEvent &) {
wxGetApp().obj_list()->add_layer_range_after_current(range);
del_btn->Bind(wxEVT_BUTTON, [del_btn](wxEvent &) {
wxGetApp().obj_list()->del_layer_range(del_btn->range);
});
add_btn->Bind(wxEVT_BUTTON, [add_btn](wxEvent &) {
wxGetApp().obj_list()->add_layer_range_after_current(add_btn->range);
});
}
}
@ -204,7 +211,7 @@ void ObjectLayers::update_layers_list()
if (type & itLayerRoot)
create_layers_list();
else
create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item));
create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item), nullptr, nullptr);
m_parent->Layout();
}
@ -255,7 +262,7 @@ void ObjectLayers::msw_rescale()
{
wxSizerItem* b_item = item->GetSizer()->GetItem(btn);
if (b_item->IsWindow()) {
ScalableButton* button = dynamic_cast<ScalableButton*>(b_item->GetWindow());
auto button = dynamic_cast<PlusMinusButton*>(b_item->GetWindow());
if (button != nullptr)
button->msw_rescale();
}
@ -275,7 +282,7 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
const wxString& value,
EditorType type,
std::function<void(EditorType)> set_focus_data_fn,
std::function<bool(coordf_t, bool enter_pressed)> edit_fn
std::function<bool(coordf_t, bool, bool)> edit_fn
) :
m_valid_value(value),
m_type(type),
@ -293,13 +300,13 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
m_enter_pressed = true;
// If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
if (m_type&etLayerHeight) {
if (!edit_fn(get_value(), true))
if (!edit_fn(get_value(), true, false))
SetValue(m_valid_value);
else
m_valid_value = double_to_string(get_value());
m_call_kill_focus = true;
}
else if (!edit_fn(get_value(), true)) {
else if (!edit_fn(get_value(), true, false)) {
SetValue(m_valid_value);
m_call_kill_focus = true;
}
@ -319,13 +326,13 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
#endif // not __WXGTK__
// If LayersList wasn't updated/recreated, we should call e.Skip()
if (m_type & etLayerHeight) {
if (!edit_fn(get_value(), false))
if (!edit_fn(get_value(), false, dynamic_cast<ObjectLayers::PlusMinusButton*>(e.GetWindow()) != nullptr))
SetValue(m_valid_value);
else
m_valid_value = double_to_string(get_value());
e.Skip();
}
else if (!edit_fn(get_value(), false)) {
else if (!edit_fn(get_value(), false, dynamic_cast<ObjectLayers::PlusMinusButton*>(e.GetWindow()) != nullptr)) {
SetValue(m_valid_value);
e.Skip();
}
@ -387,4 +394,4 @@ void LayerRangeEditor::msw_rescale()
}
} //namespace GUI
} //namespace Slic3r
} //namespace Slic3r

View file

@ -43,7 +43,8 @@ public:
const wxString& value = wxEmptyString,
EditorType type = etUndef,
std::function<void(EditorType)> set_focus_data_fn = [](EditorType) {;},
std::function<bool(coordf_t, bool)> edit_fn = [](coordf_t, bool) {return false; }
// callback parameters: new value, from enter, dont't update panel UI (when called from edit field's kill focus handler for the PlusMinusButton)
std::function<bool(coordf_t, bool, bool)> edit_fn = [](coordf_t, bool, bool) {return false; }
);
~LayerRangeEditor() {}
@ -69,8 +70,23 @@ public:
ObjectLayers(wxWindow* parent);
~ObjectLayers() {}
// Button remembers the layer height range, for which it has been created.
// The layer height range for this button is updated when the low or high boundary of the layer height range is updated
// by the respective text edit field, so that this button emits an action for an up to date layer height range value.
class PlusMinusButton : public ScalableButton
{
public:
PlusMinusButton(wxWindow *parent, const ScalableBitmap &bitmap, std::pair<coordf_t, coordf_t> range) : ScalableButton(parent, wxID_ANY, bitmap), range(range) {}
// updated when the text edit field loses focus for any PlusMinusButton.
std::pair<coordf_t, coordf_t> range;
};
void select_editor(LayerRangeEditor* editor, const bool is_last_edited_range);
wxSizer* create_layer(const t_layer_height_range& range); // without_buttons
// Create sizer with layer height range and layer height text edit fields, without buttons.
// If the delete and add buttons are provided, the respective text edit fields will modify the layer height ranges of thes buttons
// on value change, so that these buttons work with up to date values.
wxSizer* create_layer(const t_layer_height_range& range, PlusMinusButton *delete_button, PlusMinusButton *add_button);
void create_layers_list();
void update_layers_list();

View file

@ -118,13 +118,20 @@ ObjectList::ObjectList(wxWindow* parent) :
// detect the current mouse position here, to pass it to list_manipulation() method
// if we detect it later, the user may have moved the mouse pointer while calculations are performed, and this would mess-up the HitTest() call performed into list_manipulation()
// see: https://github.com/prusa3d/PrusaSlicer/issues/3802
const wxPoint mouse_pos = get_mouse_position_in_control();
const wxPoint mouse_pos = this->get_mouse_position_in_control();
#ifndef __APPLE__
// On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called
// before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object
// manipulator cache with the following call to selection_changed()
wxGetApp().obj_manipul()->emulate_kill_focus();
// wxGetApp().obj_manipul()->emulate_kill_focus(); // It's not necessury anymore #ys_FIXME delete after testing
// On Windows and Linux:
// It's not invoked KillFocus event for "temporary" panels (like "Manipulation panel", "Settings", "Layer ranges"),
// if we change selection in object list.
// see https://github.com/prusa3d/PrusaSlicer/issues/3303
// But, if we call SetFocus() for ObjectList it will cause an invoking of a KillFocus event for "temporary" panels
this->SetFocus();
#else
// To avoid selection update from SetSelection() and UnselectAll() under osx
if (m_prevent_list_events)
@ -155,7 +162,7 @@ ObjectList::ObjectList(wxWindow* parent) :
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
wxDataViewItem item;
wxDataViewColumn *col;
this->HitTest(get_mouse_position_in_control(), item, col);
this->HitTest(this->get_mouse_position_in_control(), item, col);
new_selected_column = (col == nullptr) ? -1 : (int)col->GetModelColumn();
if (new_selected_item == m_last_selected_item && m_last_selected_column != -1 && m_last_selected_column != new_selected_column) {
// Mouse clicked on another column of the active row. Simulate keyboard enter to enter the editing mode of the current column.
@ -171,7 +178,7 @@ ObjectList::ObjectList(wxWindow* parent) :
selection_changed();
#ifndef __WXMSW__
set_tooltip_for_item(get_mouse_position_in_control());
set_tooltip_for_item(this->get_mouse_position_in_control());
#endif //__WXMSW__
#ifndef __WXOSX__
@ -211,7 +218,7 @@ ObjectList::ObjectList(wxWindow* parent) :
#ifdef __WXMSW__
GetMainWindow()->Bind(wxEVT_MOTION, [this](wxMouseEvent& event) {
set_tooltip_for_item(get_mouse_position_in_control());
set_tooltip_for_item(this->get_mouse_position_in_control());
event.Skip();
});
#endif //__WXMSW__
@ -419,14 +426,6 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt)
GetMainWindow()->SetToolTip(tooltip);
}
wxPoint ObjectList::get_mouse_position_in_control()
{
const wxPoint& pt = wxGetMousePosition();
// wxWindow* win = GetMainWindow();
// wxPoint screen_pos = win->GetScreenPosition();
return wxPoint(pt.x - /*win->*/GetScreenPosition().x, pt.y - /*win->*/GetScreenPosition().y);
}
int ObjectList::get_selected_obj_idx() const
{
if (GetSelectedItemsCount() == 1)
@ -484,7 +483,6 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder)
void ObjectList::update_objects_list_extruder_column(size_t extruders_count)
{
if (!this) return; // #ys_FIXME
if (printer_technology() == ptSLA)
extruders_count = 1;
@ -792,13 +790,7 @@ void ObjectList::OnChar(wxKeyEvent& event)
void ObjectList::OnContextMenu(wxDataViewEvent& evt)
{
// The mouse position returned by get_mouse_position_in_control() here is the one at the time the mouse button is released (mouse up event)
wxPoint mouse_pos = get_mouse_position_in_control();
// We check if the mouse down event was over the "Editing" column, if not, we change the mouse position so that the following call to list_simulation() does not show any context menu
// see: https://github.com/prusa3d/PrusaSlicer/issues/3802
wxDataViewColumn* column = evt.GetDataViewColumn();
if (column == nullptr || column->GetTitle() != _("Editing"))
mouse_pos.x = 0;
wxPoint mouse_pos = this->get_mouse_position_in_control();
// Do not show the context menu if the user pressed the right mouse button on the 3D scene and released it on the objects list
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
@ -811,6 +803,12 @@ void ObjectList::OnContextMenu(wxDataViewEvent& evt)
void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_menu/* = false*/)
{
// Interesting fact: when mouse_pos.x < 0, HitTest(mouse_pos, item, col) returns item = null, but column = last column.
// So, when mouse was moved to scene immediately after clicking in ObjectList, in the scene will be shown context menu for the Editing column.
// see: https://github.com/prusa3d/PrusaSlicer/issues/3802
if (mouse_pos.x < 0)
return;
wxDataViewItem item;
wxDataViewColumn* col = nullptr;
HitTest(mouse_pos, item, col);
@ -850,30 +848,32 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me
Select(item);
}
const wxString title = col->GetTitle();
if (title == " ")
toggle_printable_state(item);
else if (title == _("Editing"))
show_context_menu(evt_context_menu);
else if (title == _("Name"))
if (col != nullptr)
{
if (wxOSX)
show_context_menu(evt_context_menu); // return context menu under OSX (related to #2909)
const wxString title = col->GetTitle();
if (title == " ")
toggle_printable_state(item);
else if (title == _("Editing"))
show_context_menu(evt_context_menu);
else if (title == _("Name"))
{
if (wxOSX)
show_context_menu(evt_context_menu); // return context menu under OSX (related to #2909)
if (is_windows10())
{
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx, item);
if (is_windows10())
{
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx, item);
if (get_mesh_errors_count(obj_idx, vol_idx) > 0 &&
mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit())
fix_through_netfabb();
}
}
// workaround for extruder editing under OSX
else if (wxOSX && evt_context_menu && title == _("Extruder"))
extruder_editing();
if (get_mesh_errors_count(obj_idx, vol_idx) > 0 &&
mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit())
fix_through_netfabb();
}
}
// workaround for extruder editing under OSX
else if (wxOSX && evt_context_menu && title == _("Extruder"))
extruder_editing();
}
#ifndef __WXMSW__
GetMainWindow()->SetToolTip(""); // hide tooltip
@ -923,7 +923,7 @@ void ObjectList::extruder_editing()
const int column_width = GetColumn(colExtruder)->GetWidth() + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X) + 5;
wxPoint pos = get_mouse_position_in_control();
wxPoint pos = this->get_mouse_position_in_control();
wxSize size = wxSize(column_width, -1);
pos.x = GetColumn(colName)->GetWidth() + GetColumn(colPrint)->GetWidth() + 5;
pos.y -= GetTextExtent("m").y;
@ -1557,7 +1557,7 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
// If there are selected more then one instance but not all of them
// don't add settings menu items
const Selection& selection = scene_selection();
if (selection.is_multiple_full_instance() && !selection.is_single_full_object() ||
if ((selection.is_multiple_full_instance() && !selection.is_single_full_object()) ||
selection.is_multiple_volume() || selection.is_mixed() ) // more than one volume(part) is selected on the scene
return nullptr;
@ -2878,13 +2878,13 @@ void ObjectList::del_layer_range(const t_layer_height_range& range)
static double get_min_layer_height(const int extruder_idx)
{
const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
return config.opt_float("min_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
return config.opt_float("min_layer_height", std::max(0, extruder_idx - 1));
}
static double get_max_layer_height(const int extruder_idx)
{
const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
int extruder_idx_zero_based = extruder_idx <= 0 ? 0 : extruder_idx-1;
int extruder_idx_zero_based = std::max(0, extruder_idx - 1);
double max_layer_height = config.opt_float("max_layer_height", extruder_idx_zero_based);
// In case max_layer_height is set to zero, it should default to 75 % of nozzle diameter:
@ -2894,80 +2894,139 @@ static double get_max_layer_height(const int extruder_idx)
return max_layer_height;
}
void ObjectList::add_layer_range_after_current(const t_layer_height_range& current_range)
// When editing this function, please synchronize the conditions with can_add_new_range_after_current().
void ObjectList::add_layer_range_after_current(const t_layer_height_range current_range)
{
const int obj_idx = get_selected_obj_idx();
if (obj_idx < 0) return;
assert(obj_idx >= 0);
if (obj_idx < 0)
// This should not happen.
return;
const wxDataViewItem layers_item = GetSelection();
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
auto it_range = ranges.find(current_range);
assert(it_range != ranges.end());
if (it_range == ranges.end())
// This shoudl not happen.
return;
const t_layer_height_range& last_range = (--ranges.end())->first;
if (current_range == last_range)
auto it_next_range = it_range;
bool changed = false;
if (++ it_next_range == ranges.end())
{
// Adding a new layer height range after the last one.
take_snapshot(_(L("Add Height Range")));
changed = true;
const t_layer_height_range& new_range = { last_range.second, last_range.second + 2. };
const t_layer_height_range new_range = { current_range.second, current_range.second + 2. };
ranges[new_range] = get_default_layer_config(obj_idx);
add_layer_item(new_range, layers_item);
}
else
else if (const std::pair<coordf_t, coordf_t> &next_range = it_next_range->first; current_range.second <= next_range.first)
{
const t_layer_height_range& next_range = (++ranges.find(current_range))->first;
if (current_range.second > next_range.first)
return; // range division has no sense
const int layer_idx = m_objects_model->GetItemIdByLayerRange(obj_idx, next_range);
if (layer_idx < 0)
return;
if (current_range.second == next_range.first)
assert(layer_idx >= 0);
if (layer_idx >= 0)
{
const auto old_config = ranges.at(next_range);
if (current_range.second == next_range.first)
{
// Splitting the next layer height range to two.
const auto old_config = ranges.at(next_range);
const coordf_t delta = next_range.second - next_range.first;
// Layer height of the current layer.
const coordf_t old_min_layer_height = get_min_layer_height(old_config.opt_int("extruder"));
// Layer height of the layer to be inserted.
const coordf_t new_min_layer_height = get_min_layer_height(0);
if (delta >= old_min_layer_height + new_min_layer_height - EPSILON) {
const coordf_t middle_layer_z = (new_min_layer_height > 0.5 * delta) ?
next_range.second - new_min_layer_height :
next_range.first + std::max(old_min_layer_height, 0.5 * delta);
t_layer_height_range new_range = { middle_layer_z, next_range.second };
const coordf_t delta = (next_range.second - next_range.first);
if (delta < get_min_layer_height(old_config.opt_int("extruder"))/*0.05f*/) // next range division has no sense
return;
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add Height Range")));
changed = true;
const coordf_t midl_layer = next_range.first + 0.5 * delta;
t_layer_height_range new_range = { midl_layer, next_range.second };
// create new 2 layers instead of deleted one
// delete old layer
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add Height Range")));
wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, next_range);
del_subobject_item(layer_item);
// create new 2 layers instead of deleted one
ranges[new_range] = old_config;
add_layer_item(new_range, layers_item, layer_idx);
// delete old layer
new_range = { current_range.second, middle_layer_z };
ranges[new_range] = get_default_layer_config(obj_idx);
add_layer_item(new_range, layers_item, layer_idx);
}
}
else if (next_range.first - current_range.second >= get_min_layer_height(0) - EPSILON)
{
// Filling in a gap between the current and a new layer height range with a new one.
take_snapshot(_(L("Add Height Range")));
changed = true;
wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, next_range);
del_subobject_item(layer_item);
ranges[new_range] = old_config;
add_layer_item(new_range, layers_item, layer_idx);
new_range = { current_range.second, midl_layer };
ranges[new_range] = get_default_layer_config(obj_idx);
add_layer_item(new_range, layers_item, layer_idx);
const t_layer_height_range new_range = { current_range.second, next_range.first };
ranges[new_range] = get_default_layer_config(obj_idx);
add_layer_item(new_range, layers_item, layer_idx);
}
}
else
{
take_snapshot(_(L("Add Height Range")));
const t_layer_height_range new_range = { current_range.second, next_range.first };
ranges[new_range] = get_default_layer_config(obj_idx);
add_layer_item(new_range, layers_item, layer_idx);
}
}
changed_object(obj_idx);
if (changed)
changed_object(obj_idx);
// The layer range panel is updated even if this function does not change the layer ranges, as the panel update
// may have been postponed from the "kill focus" event of a text field, if the focus was lost for the "add layer" button.
// select item to update layers sizer
select_item(layers_item);
}
// Returning an empty string means that the layer could be added after the current layer.
// Otherwise an error tooltip is returned.
// When editing this function, please synchronize the conditions with add_layer_range_after_current().
wxString ObjectList::can_add_new_range_after_current(const t_layer_height_range current_range)
{
const int obj_idx = get_selected_obj_idx();
assert(obj_idx >= 0);
if (obj_idx < 0)
// This should not happen.
return "ObjectList assert";
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
auto it_range = ranges.find(current_range);
assert(it_range != ranges.end());
if (it_range == ranges.end())
// This shoudl not happen.
return "ObjectList assert";
auto it_next_range = it_range;
if (++ it_next_range == ranges.end())
// Adding a layer after the last layer is always possible.
return "";
if (const std::pair<coordf_t, coordf_t>& next_range = it_next_range->first; current_range.second <= next_range.first)
{
if (current_range.second == next_range.first) {
if (next_range.second - next_range.first < get_min_layer_height(it_next_range->second.opt_int("extruder")) + get_min_layer_height(0) - EPSILON)
return _(L("Cannot insert a new layer range after the current layer range.\n"
"The next layer range is too thin to be split to two\n"
"without violating the minimum layer height."));
} else if (next_range.first - current_range.second < get_min_layer_height(0) - EPSILON) {
return _(L("Cannot insert a new layer range between the current and the next layer range.\n"
"The gap between the current layer range and the next layer range\n"
"is thinner than the minimum layer height allowed."));
}
} else
return _(L("Cannot insert a new layer range after the current layer range.\n"
"Current layer range overlaps with the next layer range."));
// All right, new layer height range could be inserted.
return "";
}
void ObjectList::add_layer_item(const t_layer_height_range& range,
const wxDataViewItem layers_item,
const int layer_idx /* = -1*/)
@ -2988,7 +3047,10 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
{
const int obj_idx = get_selected_obj_idx();
// Use m_selected_object_id instead of get_selected_obj_idx()
// because of get_selected_obj_idx() return obj_idx for currently selected item.
// But edit_layer_range(...) function can be called, when Selection in ObjectList could be changed
const int obj_idx = m_selected_object_id ;
if (obj_idx < 0)
return false;
@ -3009,9 +3071,12 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t la
return false;
}
bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range)
bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range, bool dont_update_ui)
{
const int obj_idx = get_selected_obj_idx();
// Use m_selected_object_id instead of get_selected_obj_idx()
// because of get_selected_obj_idx() return obj_idx for currently selected item.
// But edit_layer_range(...) function can be called, when Selection in ObjectList could be changed
const int obj_idx = m_selected_object_id;
if (obj_idx < 0) return false;
take_snapshot(_(L("Edit Height Range")));
@ -3025,21 +3090,26 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
ranges.erase(range);
ranges[new_range] = config;
changed_object(obj_idx);
wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx));
// To avoid update selection after deleting of a selected item (under GTK)
// set m_prevent_list_events to true
m_prevent_list_events = true;
m_objects_model->DeleteChildren(root_item);
if (root_item.IsOk())
if (root_item.IsOk()) {
// create Layer item(s) according to the layer_config_ranges
for (const auto& r : ranges)
add_layer_item(r.first, root_item);
}
// if this function was invoked from wxEVT_CHANGE_SELECTION selected item could be other than itLayer or itLayerRoot
if (!dont_update_ui && (sel_type & (itLayer | itLayerRoot)))
select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
Expand(root_item);
m_prevent_list_events = false;
return true;
}

View file

@ -284,7 +284,7 @@ public:
bool selected_instances_of_same_object();
bool can_split_instances();
wxPoint get_mouse_position_in_control();
wxPoint get_mouse_position_in_control() const { return wxGetMousePosition() - this->GetScreenPosition(); }
wxBoxSizer* get_sizer() {return m_sizer;}
int get_selected_obj_idx() const;
DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
@ -320,13 +320,27 @@ public:
// Remove objects/sub-object from the list
void remove();
void del_layer_range(const t_layer_height_range& range);
void add_layer_range_after_current(const t_layer_height_range& current_range);
// Add a new layer height after the current range if possible.
// The current range is shortened and the new range is entered after the shortened current range if it fits.
// If no range fits after the current range, then no range is inserted.
// The layer range panel is updated even if this function does not change the layer ranges, as the panel update
// may have been postponed from the "kill focus" event of a text field, if the focus was lost for the "add layer" button.
// Rather providing the range by a value than by a reference, so that the memory referenced cannot be invalidated.
void add_layer_range_after_current(const t_layer_height_range current_range);
wxString can_add_new_range_after_current( t_layer_height_range current_range);
void add_layer_item (const t_layer_height_range& range,
const wxDataViewItem layers_item,
const int layer_idx = -1);
bool edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
// This function may be called when a text field loses focus for a "add layer" or "remove layer" button.
// In that case we don't want to destroy the panel with that "add layer" or "remove layer" buttons, as some messages
// are already planned for them and destroying these widgets leads to crashes at least on OSX.
// In that case the "add layer" or "remove layer" button handlers are responsible for always rebuilding the panel
// even if the "add layer" or "remove layer" buttons did not update the layer spans or layer heights.
bool edit_layer_range(const t_layer_height_range& range,
const t_layer_height_range& new_range);
const t_layer_height_range& new_range,
// Don't destroy the panel with the "add layer" or "remove layer" buttons.
bool suppress_ui_update = false);
void init_objects();
bool multiple_selection() const ;

View file

@ -21,6 +21,12 @@
namespace Slic3r {
namespace GUI {
#ifdef _WIN32
wxDEFINE_EVENT(EVT_HID_DEVICE_ATTACHED, HIDDeviceAttachedEvent);
wxDEFINE_EVENT(EVT_HID_DEVICE_DETACHED, HIDDeviceDetachedEvent);
wxDEFINE_EVENT(EVT_VOLUME_ATTACHED, VolumeAttachedEvent);
wxDEFINE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent);
#endif // _WIN32
wxTopLevelWindow* find_toplevel_parent(wxWindow *window)
{

View file

@ -18,6 +18,8 @@
#include <wx/debug.h>
#include <wx/settings.h>
#include "Event.hpp"
class wxCheckBox;
class wxTopLevelWindow;
class wxRect;
@ -26,6 +28,19 @@ class wxRect;
namespace Slic3r {
namespace GUI {
#ifdef _WIN32
// USB HID attach / detach events from Windows OS.
using HIDDeviceAttachedEvent = Event<std::string>;
using HIDDeviceDetachedEvent = Event<std::string>;
wxDECLARE_EVENT(EVT_HID_DEVICE_ATTACHED, HIDDeviceAttachedEvent);
wxDECLARE_EVENT(EVT_HID_DEVICE_DETACHED, HIDDeviceDetachedEvent);
// Disk aka Volume attach / detach events from Windows OS.
using VolumeAttachedEvent = SimpleEvent;
using VolumeDetachedEvent = SimpleEvent;
wxDECLARE_EVENT(EVT_VOLUME_ATTACHED, VolumeAttachedEvent);
wxDECLARE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent);
#endif /* _WIN32 */
wxTopLevelWindow* find_toplevel_parent(wxWindow *window);

View file

@ -262,12 +262,6 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
}
}
void GLGizmoBase::set_tooltip(const std::string& tooltip) const
{
m_parent.set_tooltip(tooltip);
}
std::string GLGizmoBase::format(float value, unsigned int decimals) const
{
return Slic3r::string_printf("%.*f", decimals, value);

View file

@ -100,6 +100,7 @@ protected:
mutable std::vector<Grabber> m_grabbers;
ImGuiWrapper* m_imgui;
bool m_first_input_window_render;
mutable std::string m_tooltip;
public:
GLGizmoBase(GLCanvas3D& parent,
@ -145,10 +146,12 @@ public:
void update(const UpdateData& data);
void render() const { on_render(); }
void render() const { m_tooltip.clear(); on_render(); }
void render_for_picking() const { on_render_for_picking(); }
void render_input_window(float x, float y, float bottom_limit);
virtual std::string get_tooltip() const { return ""; }
protected:
virtual bool on_init() = 0;
virtual void on_load(cereal::BinaryInputArchive& ar) {}
@ -174,7 +177,6 @@ protected:
void render_grabbers(float size) const;
void render_grabbers_for_picking(const BoundingBoxf3& box) const;
void set_tooltip(const std::string& tooltip) const;
std::string format(float value, unsigned int decimals) const;
};

View file

@ -30,6 +30,11 @@ GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, uns
, m_rotate_lower(false)
{}
std::string GLGizmoCut::get_tooltip() const
{
return (m_hover_id == 0 || m_grabbers[0].dragging) ? "Z: " + format(m_cut_z, 2) : "";
}
bool GLGizmoCut::on_init()
{
m_grabbers.emplace_back();
@ -79,10 +84,6 @@ void GLGizmoCut::on_update(const UpdateData& data)
void GLGizmoCut::on_render() const
{
if (m_grabbers[0].dragging) {
set_tooltip("Z: " + format(m_cut_z, 2));
}
const Selection& selection = m_parent.get_selection();
update_max_z(selection);

View file

@ -28,6 +28,8 @@ public:
double get_cut_z() const { return m_cut_z; }
void set_cut_z(double cut_z) const;
std::string get_tooltip() const override;
protected:
virtual bool on_init();
virtual void on_load(cereal::BinaryInputArchive& ar) { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); }

View file

@ -1,5 +1,6 @@
#include "GLGizmoHollow.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/Gizmos/GLGizmos.hpp"
#include <GL/glew.h>
@ -102,16 +103,11 @@ void GLGizmoHollow::on_render() const
return;
}
// !!! is it necessary?
//const_cast<GLGizmoHollow*>(this)->m_c->update_from_backend(m_parent, m_c->m_model_object);
glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST));
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
render_hollowed_mesh();
if (m_quadric != nullptr && selection.is_from_single_instance())
render_points(selection, false);
@ -123,28 +119,6 @@ void GLGizmoHollow::on_render() const
void GLGizmoHollow::render_hollowed_mesh() const
{
/*if (m_c->m_volume_with_cavity) {
m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift);
m_parent.get_shader().start_using();
GLint current_program_id;
glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_id));
GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
GLint print_box_detection_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1;
GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1;
glcheck();
m_c->m_volume_with_cavity->set_render_color();
const Geometry::Transformation& volume_trafo = m_c->m_model_object->volumes.front()->get_transformation();
m_c->m_volume_with_cavity->set_volume_transformation(volume_trafo);
m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation());
m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id);
m_parent.get_shader().stop_using();
}*/
}
void GLGizmoHollow::render_clipping_plane(const Selection& selection) const
{
if (m_c->m_clipping_plane_distance == 0.f)
@ -172,11 +146,6 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const
m_c->m_object_clipper->set_plane(*m_c->m_clipping_plane);
m_c->m_object_clipper->set_transformation(trafo);
// Next, ask the backend if supports are already calculated. If so, we are gonna cut them too.
//if (m_c->m_print_object_idx < 0)
// m_c->update_from_backend(m_parent, m_c->m_model_object);
if (m_c->m_print_object_idx >= 0) {
const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx];
@ -232,7 +201,6 @@ void GLGizmoHollow::on_render_for_picking() const
glsafe(::glEnable(GL_DEPTH_TEST));
render_points(selection, true);
render_hollowed_mesh();
}
void GLGizmoHollow::render_points(const Selection& selection, bool picking) const
@ -346,10 +314,6 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
if (! m_c->m_mesh_raycaster)
return false;
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
// !!! is it really necessary?
//m_c->update_from_backend(m_parent, m_c->m_model_object);
#if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera& camera = wxGetApp().plater()->get_camera();
#else
@ -572,87 +536,15 @@ void GLGizmoHollow::on_update(const UpdateData& data)
}
}
std::pair<const TriangleMesh *, sla::HollowingConfig> GLGizmoHollow::get_hollowing_parameters() const
{
// FIXME this function is probably obsolete, caller could
// get the data from model config himself
auto opts = get_config_options({"hollowing_min_thickness", "hollowing_quality", "hollowing_closing_distance"});
double offset = static_cast<const ConfigOptionFloat*>(opts[0].first)->value;
double quality = static_cast<const ConfigOptionFloat*>(opts[1].first)->value;
double closing_d = static_cast<const ConfigOptionFloat*>(opts[2].first)->value;
return std::make_pair(m_c->m_mesh, sla::HollowingConfig{offset, quality, closing_d});
}
void GLGizmoHollow::update_mesh_raycaster(std::unique_ptr<MeshRaycaster> &&rc)
{
m_c->m_mesh_raycaster = std::move(rc);
m_c->m_object_clipper.reset();
//m_c->m_volume_with_cavity.reset();
}
void GLGizmoHollow::hollow_mesh(bool postpone_error_messages)
{
// Trigger a UI job to hollow the mesh.
// wxGetApp().plater()->hollow();
wxGetApp().CallAfter([this, postpone_error_messages]() {
wxGetApp().plater()->reslice_SLA_hollowing(*m_c->m_model_object, postpone_error_messages);
});
}
void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh)
{
// Called from Plater when the UI job finishes
/*m_c->m_cavity_mesh = std::move(mesh);
if(m_c->m_cavity_mesh) {
// First subtract the holes:
if (! m_c->m_model_object->sla_drain_holes.empty()) {
TriangleMesh holes_mesh;
for (const sla::DrainHole& hole : m_c->m_model_object->sla_drain_holes) {
TriangleMesh hole_mesh = make_cylinder(hole.radius, hole.height, 2*M_PI/32);
Vec3d scaling = m_c->m_model_object->instances[m_c->m_active_instance]->get_scaling_factor();
Vec3d normal_transformed = Vec3d(hole.normal(0)/scaling(0), hole.normal(1)/scaling(1), hole.normal(2)/scaling(2));
normal_transformed.normalize();
// Rotate the cylinder appropriately
Eigen::Quaterniond q;
Transform3d m = Transform3d::Identity();
m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), normal_transformed).toRotationMatrix();
hole_mesh.transform(m);
// If the instance is scaled, undo the scaling of the hole
hole_mesh.scale(Vec3d(1/scaling(0), 1/scaling(1), 1/scaling(2)));
// Translate the hole into position and merge with the others
hole_mesh.translate(hole.pos);
holes_mesh.merge(hole_mesh);
holes_mesh.repair();
}
MeshBoolean::minus(*m_c->m_cavity_mesh.get(), holes_mesh);
}
// create a new GLVolume that only has the cavity inside
m_c->m_volume_with_cavity.reset(new GLVolume(GLVolume::MODEL_COLOR[2]));
m_c->m_volume_with_cavity->indexed_vertex_array.load_mesh(*m_c->m_cavity_mesh.get());
m_c->m_volume_with_cavity->finalize_geometry(true);
m_c->m_volume_with_cavity->force_transparent = false;
m_parent.toggle_model_objects_visibility(false, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(true, m_c->m_model_object, m_c->m_active_instance);
// Reset raycaster so it works with the new mesh:
m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh()));
}
if (m_c->m_clipping_plane_distance == 0.f) {
m_c->m_clipping_plane_distance = 0.5f;
update_clipping_plane();
}*/
}
std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>> GLGizmoHollow::get_config_options(const std::vector<std::string>& keys) const
{
std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>> out;
@ -840,7 +732,6 @@ RENDER_AGAIN:
bool remove_selected = false;
bool remove_all = false;
// m_imgui->text(" "); // vertical gap
ImGui::Separator();
float diameter_upper_cap = 15.;
@ -1024,10 +915,6 @@ void GLGizmoHollow::on_set_state()
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
}
// Set default head diameter from config.
//const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
//m_new_hole_radius = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
}
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off")));

View file

@ -36,11 +36,6 @@ public:
void delete_selected_points();
ClippingPlane get_sla_clipping_plane() const;
std::pair<const TriangleMesh *, sla::HollowingConfig> get_hollowing_parameters() const;
void update_mesh_raycaster(std::unique_ptr<MeshRaycaster> &&rc);
void update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh);
bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); }
void update_clipping_plane(bool keep_normal = false) const;
void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; }
@ -53,7 +48,6 @@ private:
void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const;
void render_hollowed_mesh() const;
void hollow_mesh(bool postpone_error_messages = false);
bool unsaved_changes() const;

View file

@ -31,6 +31,22 @@ GLGizmoMove3D::~GLGizmoMove3D()
::gluDeleteQuadric(m_quadric);
}
std::string GLGizmoMove3D::get_tooltip() const
{
const Selection& selection = m_parent.get_selection();
bool show_position = selection.is_single_full_instance();
const Vec3d& position = selection.get_bounding_box().center();
if (m_hover_id == 0 || m_grabbers[0].dragging)
return "X: " + format(show_position ? position(0) : m_displacement(0), 2);
else if (m_hover_id == 1 || m_grabbers[1].dragging)
return "Y: " + format(show_position ? position(1) : m_displacement(1), 2);
else if (m_hover_id == 2 || m_grabbers[2].dragging)
return "Z: " + format(show_position ? position(2) : m_displacement(2), 2);
else
return "";
}
bool GLGizmoMove3D::on_init()
{
for (int i = 0; i < 3; ++i)
@ -85,22 +101,6 @@ void GLGizmoMove3D::on_render() const
{
const Selection& selection = m_parent.get_selection();
bool show_position = selection.is_single_full_instance();
const Vec3d& position = selection.get_bounding_box().center();
if ((show_position && (m_hover_id == 0)) || m_grabbers[0].dragging)
set_tooltip("X: " + format(show_position ? position(0) : m_displacement(0), 2));
else if (!m_grabbers[0].dragging && (m_hover_id == 0))
set_tooltip("X");
else if ((show_position && (m_hover_id == 1)) || m_grabbers[1].dragging)
set_tooltip("Y: " + format(show_position ? position(1) : m_displacement(1), 2));
else if (!m_grabbers[1].dragging && (m_hover_id == 1))
set_tooltip("Y");
else if ((show_position && (m_hover_id == 2)) || m_grabbers[2].dragging)
set_tooltip("Z: " + format(show_position ? position(2) : m_displacement(2), 2));
else if (!m_grabbers[2].dragging && (m_hover_id == 2))
set_tooltip("Z");
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));

View file

@ -30,6 +30,8 @@ public:
const Vec3d& get_displacement() const { return m_displacement; }
std::string get_tooltip() const override;
protected:
virtual bool on_init();
virtual std::string on_get_name() const;

View file

@ -67,6 +67,18 @@ void GLGizmoRotate::set_angle(double angle)
m_angle = angle;
}
std::string GLGizmoRotate::get_tooltip() const
{
std::string axis;
switch (m_axis)
{
case X: { axis = "X"; break; }
case Y: { axis = "Y"; break; }
case Z: { axis = "Z"; break; }
}
return (m_hover_id == 0 || m_grabbers[0].dragging) ? axis + ": " + format((float)Geometry::rad2deg(m_angle), 4) : "";
}
bool GLGizmoRotate::on_init()
{
m_grabbers.push_back(Grabber());
@ -127,19 +139,7 @@ void GLGizmoRotate::on_render() const
const Selection& selection = m_parent.get_selection();
const BoundingBoxf3& box = selection.get_bounding_box();
std::string axis;
switch (m_axis)
{
case X: { axis = "X"; break; }
case Y: { axis = "Y"; break; }
case Z: { axis = "Z"; break; }
}
if (!m_dragging && (m_hover_id == 0))
set_tooltip(axis);
else if (m_dragging)
set_tooltip(axis + ": " + format((float)Geometry::rad2deg(m_angle), 4) + "\u00B0");
else
if (m_hover_id != 0 && !m_grabbers[0].dragging)
{
m_center = box.center();
m_radius = Offset + box.radius();

View file

@ -49,6 +49,8 @@ public:
double get_angle() const { return m_angle; }
void set_angle(double angle);
std::string get_tooltip() const override;
protected:
virtual bool on_init();
virtual std::string on_get_name() const { return ""; }
@ -81,6 +83,16 @@ public:
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
std::string get_tooltip() const override
{
std::string tooltip = m_gizmos[X].get_tooltip();
if (tooltip.empty())
tooltip = m_gizmos[Y].get_tooltip();
if (tooltip.empty())
tooltip = m_gizmos[Z].get_tooltip();
return tooltip;
}
protected:
virtual bool on_init();
virtual std::string on_get_name() const;

View file

@ -20,6 +20,38 @@ GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filen
{
}
std::string GLGizmoScale3D::get_tooltip() const
{
const Selection& selection = m_parent.get_selection();
bool single_instance = selection.is_single_full_instance();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
bool single_selection = single_instance || single_volume;
Vec3f scale = 100.0f * Vec3f::Ones();
if (single_instance)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>();
else if (single_volume)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
return "X: " + format(scale(0), 4) + "%";
else if (m_hover_id == 2 || m_hover_id == 3 || m_grabbers[2].dragging || m_grabbers[3].dragging)
return "Y: " + format(scale(1), 4) + "%";
else if (m_hover_id == 4 || m_hover_id == 5 || m_grabbers[4].dragging || m_grabbers[5].dragging)
return "Z: " + format(scale(2), 4) + "%";
else if (m_hover_id == 6 || m_hover_id == 7 || m_hover_id == 8 || m_hover_id == 9 ||
m_grabbers[6].dragging || m_grabbers[7].dragging || m_grabbers[8].dragging || m_grabbers[9].dragging)
{
std::string tooltip = "X: " + format(scale(0), 4) + "%\n";
tooltip += "Y: " + format(scale(1), 4) + "%\n";
tooltip += "Z: " + format(scale(2), 4) + "%";
return tooltip;
}
else
return "";
}
bool GLGizmoScale3D::on_init()
{
for (int i = 0; i < 10; ++i)
@ -89,37 +121,6 @@ void GLGizmoScale3D::on_render() const
bool single_instance = selection.is_single_full_instance();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
bool single_selection = single_instance || single_volume;
Vec3f scale = 100.0f * Vec3f::Ones();
if (single_instance)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>();
else if (single_volume)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
if ((single_selection && ((m_hover_id == 0) || (m_hover_id == 1))) || m_grabbers[0].dragging || m_grabbers[1].dragging)
set_tooltip("X: " + format(scale(0), 4) + "%");
else if (!m_grabbers[0].dragging && !m_grabbers[1].dragging && ((m_hover_id == 0) || (m_hover_id == 1)))
set_tooltip("X");
else if ((single_selection && ((m_hover_id == 2) || (m_hover_id == 3))) || m_grabbers[2].dragging || m_grabbers[3].dragging)
set_tooltip("Y: " + format(scale(1), 4) + "%");
else if (!m_grabbers[2].dragging && !m_grabbers[3].dragging && ((m_hover_id == 2) || (m_hover_id == 3)))
set_tooltip("Y");
else if ((single_selection && ((m_hover_id == 4) || (m_hover_id == 5))) || m_grabbers[4].dragging || m_grabbers[5].dragging)
set_tooltip("Z: " + format(scale(2), 4) + "%");
else if (!m_grabbers[4].dragging && !m_grabbers[5].dragging && ((m_hover_id == 4) || (m_hover_id == 5)))
set_tooltip("Z");
else if ((single_selection && ((m_hover_id == 6) || (m_hover_id == 7) || (m_hover_id == 8) || (m_hover_id == 9)))
|| m_grabbers[6].dragging || m_grabbers[7].dragging || m_grabbers[8].dragging || m_grabbers[9].dragging)
{
std::string tooltip = "X: " + format(scale(0), 4) + "%\n";
tooltip += "Y: " + format(scale(1), 4) + "%\n";
tooltip += "Z: " + format(scale(2), 4) + "%";
set_tooltip(tooltip);
}
else if (!m_grabbers[6].dragging && !m_grabbers[7].dragging && !m_grabbers[8].dragging && !m_grabbers[9].dragging &&
((m_hover_id == 6) || (m_hover_id == 7) || (m_hover_id == 8) || (m_hover_id == 9)))
set_tooltip("X/Y/Z");
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));

View file

@ -42,6 +42,8 @@ public:
const Vec3d& get_offset() const { return m_offset; }
std::string get_tooltip() const override;
protected:
virtual bool on_init();
virtual std::string on_get_name() const;

View file

@ -1,6 +1,7 @@
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
#include "GLGizmoSlaSupports.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/Gizmos/GLGizmos.hpp"
#include <GL/glew.h>
@ -109,8 +110,6 @@ void GLGizmoSlaSupports::on_render() const
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
render_hollowed_mesh();
if (m_quadric != nullptr && selection.is_from_single_instance())
render_points(selection, false);
@ -122,29 +121,6 @@ void GLGizmoSlaSupports::on_render() const
void GLGizmoSlaSupports::render_hollowed_mesh() const
{
/*if (m_c->m_volume_with_cavity) {
m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift);
m_parent.get_shader().start_using();
GLint current_program_id;
glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_id));
GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
GLint print_box_detection_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1;
GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1;
glcheck();
m_c->m_volume_with_cavity->set_render_color();
const Geometry::Transformation& volume_trafo = m_c->m_model_object->volumes.front()->get_transformation();
m_c->m_volume_with_cavity->set_volume_transformation(volume_trafo);
m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation());
m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id);
m_parent.get_shader().stop_using();
}*/
}
void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
{
if (m_c->m_clipping_plane_distance == 0.f || m_c->m_mesh->empty())
@ -241,7 +217,6 @@ void GLGizmoSlaSupports::on_render_for_picking() const
glsafe(::glEnable(GL_DEPTH_TEST));
render_points(selection, true);
render_hollowed_mesh();
}
void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const
@ -638,8 +613,6 @@ void GLGizmoSlaSupports::delete_selected_points(bool force)
}
select_point(NoPoints);
//m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
void GLGizmoSlaSupports::on_update(const UpdateData& data)
@ -654,8 +627,6 @@ void GLGizmoSlaSupports::on_update(const UpdateData& data)
m_editing_cache[m_hover_id].support_point.pos = pos_and_normal.first;
m_editing_cache[m_hover_id].support_point.is_new_island = false;
m_editing_cache[m_hover_id].normal = pos_and_normal.second;
// Do not update immediately, wait until the mouse is released.
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
}
}

View file

@ -93,7 +93,6 @@ private:
//void render_selection_rectangle() const;
void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const;
void render_hollowed_mesh() const;
bool unsaved_changes() const;
bool m_lock_unique_islands = false;

View file

@ -11,8 +11,9 @@
#include "slic3r/Utils/UndoRedo.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "slic3r/GUI/MeshUtils.hpp"
#include "slic3r/GUI/Gizmos/GLGizmos.hpp"
#include "slic3r/GUI/Camera.hpp"
#include <GL/glew.h>
#include <wx/glcanvas.h>
namespace Slic3r {
@ -228,7 +229,7 @@ void GLGizmosManager::update_data()
set_scale(Vec3d::Ones());
set_rotation(Vec3d::Zero());
set_flattening_data(selection.is_from_single_object() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr);
set_sla_support_data(nullptr);
set_sla_support_data(selection.is_from_single_instance() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr);
}
}
@ -425,6 +426,15 @@ void GLGizmosManager::render_overlay() const
do_render_overlay();
}
std::string GLGizmosManager::get_tooltip() const
{
if (!m_tooltip.empty())
return m_tooltip;
const GLGizmoBase* curr = get_current();
return (curr != nullptr) ? curr->get_tooltip() : "";
}
bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt)
{
bool processed = false;
@ -450,6 +460,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
int selected_object_idx = selection.get_object_idx();
bool processed = false;
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
// mouse anywhere
if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
{
@ -459,10 +470,81 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
m_mouse_capture.reset();
}
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
// mouse anywhere
if (evt.Moving())
m_tooltip = update_hover_state(mouse_pos);
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
else if (evt.LeftUp())
{
if (m_mouse_capture.left)
{
processed = true;
m_mouse_capture.left = false;
}
else if (is_dragging())
{
switch (m_current) {
case Move: m_parent.do_move(L("Gizmo-Move")); break;
case Scale: m_parent.do_scale(L("Gizmo-Scale")); break;
case Rotate: m_parent.do_rotate(L("Gizmo-Rotate")); break;
default: break;
}
stop_dragging();
update_data();
wxGetApp().obj_manipul()->set_dirty();
// Let the plater know that the dragging finished, so a delayed refresh
// of the scene with the background processing data should be performed.
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
// updates camera target constraints
m_parent.refresh_camera_scene_box();
processed = true;
}
// else
// return false;
}
else if (evt.MiddleUp())
{
if (m_mouse_capture.middle)
{
processed = true;
m_mouse_capture.middle = false;
}
else
return false;
}
else if (evt.RightUp())
{
if (pending_right_up)
{
pending_right_up = false;
return true;
}
if (m_mouse_capture.right)
{
processed = true;
m_mouse_capture.right = false;
}
else
return false;
}
#if ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX
else if (evt.Dragging() && !is_dragging())
#else
else if (evt.Dragging())
#endif // ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX
{
if (m_mouse_capture.any())
// if the button down was done on this toolbar, prevent from dragging into the scene
processed = true;
// else
// return false;
}
#else
else if (evt.LeftUp())
m_mouse_capture.left = false;
else if (evt.MiddleUp())
@ -479,6 +561,55 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
else if (evt.Dragging() && m_mouse_capture.any())
// if the button down was done on this toolbar, prevent from dragging into the scene
processed = true;
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
#if ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX
else if (evt.Dragging() && is_dragging())
{
if (!m_parent.get_wxglcanvas()->HasCapture())
m_parent.get_wxglcanvas()->CaptureMouse();
m_parent.set_mouse_as_dragging();
update(m_parent.mouse_ray(pos), pos);
switch (m_current)
{
case Move:
{
// Apply new temporary offset
selection.translate(get_displacement());
wxGetApp().obj_manipul()->set_dirty();
break;
}
case Scale:
{
// Apply new temporary scale factors
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
if (evt.AltDown())
transformation_type.set_independent();
selection.scale(get_scale(), transformation_type);
if (evt.ControlDown())
selection.translate(get_scale_offset(), true);
wxGetApp().obj_manipul()->set_dirty();
break;
}
case Rotate:
{
// Apply new temporary rotations
TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (evt.AltDown())
transformation_type.set_independent();
selection.rotate(get_rotation(), transformation_type);
wxGetApp().obj_manipul()->set_dirty();
break;
}
default:
break;
}
m_parent.set_as_dirty();
processed = true;
}
#endif // ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX
if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined)
{
@ -521,6 +652,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
m_parent.set_as_dirty();
processed = true;
}
#if !ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX
else if (evt.Dragging() && is_dragging())
{
if (!m_parent.get_wxglcanvas()->HasCapture())
@ -567,6 +699,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
m_parent.set_as_dirty();
processed = true;
}
#endif // !ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
else if (evt.LeftUp() && is_dragging())
{
switch (m_current) {
@ -588,6 +722,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
processed = true;
}
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
else if (evt.LeftUp() && (m_current == SlaSupports || m_current == Hollow) && !m_parent.is_mouse_dragging())
{
// in case SLA gizmo is selected, we just pass the LeftUp event and stop processing - neither
@ -626,8 +761,10 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
m_mouse_capture.right = true;
m_mouse_capture.parent = &m_parent;
}
#if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
else if (evt.LeftUp())
processed = true;
#endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
}
return processed;

View file

@ -3,8 +3,8 @@
#include "slic3r/GUI/GLTexture.hpp"
#include "slic3r/GUI/GLToolbar.hpp"
#include "slic3r/GUI/Gizmos/GLGizmos.hpp"
#include "libslic3r/ObjectID.hpp"
#include "slic3r/GUI/Gizmos/GLGizmoBase.hpp"
#include <map>
@ -18,6 +18,8 @@ namespace GUI {
class GLCanvas3D;
class ClippingPlane;
enum class SLAGizmoEventType : unsigned char;
class CommonGizmosData;
class Rect
{
@ -204,7 +206,7 @@ public:
void render_overlay() const;
const std::string& get_tooltip() const { return m_tooltip; }
std::string get_tooltip() const;
bool on_mouse(wxMouseEvent& evt);
bool on_mouse_wheel(wxMouseEvent& evt);

View file

@ -1,10 +1,12 @@
#ifndef _
#define _(s) Slic3r::GUI::I18N::translate((s))
#define _(s) Slic3r::GUI::I18N::translate((s))
#define _L(s) Slic3r::GUI::I18N::translate((s))
#define _utf8(s) Slic3r::GUI::I18N::translate_utf8((s))
#define _u8L(s) Slic3r::GUI::I18N::translate_utf8((s))
#endif /* _ */
#ifndef _CTX
#define _CTX(s, ctx) Slic3r::GUI::I18N::translate((s), (ctx))
#define _CTX(s, ctx) Slic3r::GUI::I18N::translate((s), (ctx))
#define _CTX_utf8(s, ctx) Slic3r::GUI::I18N::translate_utf8((s), (ctx))
#endif /* _ */

View file

@ -441,15 +441,37 @@ bool ImGuiWrapper::want_any_input() const
return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput;
}
#ifdef __APPLE__
static const ImWchar ranges_keyboard_shortcuts[] =
{
0x21E7, 0x21E7, // OSX Shift Key symbol
0x2318, 0x2318, // OSX Command Key symbol
0x2325, 0x2325, // OSX Option Key symbol
0,
};
#endif // __APPLE__
void ImGuiWrapper::init_font(bool compress)
{
destroy_font();
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
//FIXME replace with io.Fonts->AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, m_font_size, nullptr, m_glyph_ranges);
// Create ranges of characters from m_glyph_ranges, possibly adding some OS specific special characters.
ImVector<ImWchar> ranges;
ImFontAtlas::GlyphRangesBuilder builder;
builder.AddRanges(m_glyph_ranges);
#ifdef __APPLE__
if (m_font_cjk)
// Apple keyboard shortcuts are only contained in the CJK fonts.
builder.AddRanges(ranges_keyboard_shortcuts);
#endif
builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
//FIXME replace with io.Fonts->AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, m_font_size, nullptr, ranges.Data);
//https://github.com/ocornut/imgui/issues/220
ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + (m_font_cjk ? "NotoSansCJK-Regular.ttc" : "NotoSans-Regular.ttf")).c_str(), m_font_size, nullptr, m_glyph_ranges);
ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + (m_font_cjk ? "NotoSansCJK-Regular.ttc" : "NotoSans-Regular.ttf")).c_str(), m_font_size, nullptr, ranges.Data);
if (font == nullptr) {
font = io.Fonts->AddFontDefault();
if (font == nullptr) {
@ -457,6 +479,16 @@ void ImGuiWrapper::init_font(bool compress)
}
}
#ifdef __APPLE__
ImFontConfig config;
config.MergeMode = true;
if (! m_font_cjk) {
// Apple keyboard shortcuts are only contained in the CJK fonts.
ImFont *font_cjk = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSansCJK-Regular.ttc").c_str(), m_font_size, &config, ranges_keyboard_shortcuts);
assert(font_cjk != nullptr);
}
#endif
// Build texture atlas
unsigned char* pixels;
int width, height;

View file

@ -144,9 +144,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ ctrl + "J", L("Print host upload queue") },
// View
{ "0-6", L("Camera view") },
#if ENABLE_SHOW_SCENE_LABELS
{ "E", L("Show/Hide object/instance labels") },
#endif // ENABLE_SHOW_SCENE_LABELS
// Configuration
{ ctrl + "P", L("Preferences") },
// Help

View file

@ -31,6 +31,10 @@
#include <fstream>
#include "GUI_App.hpp"
#ifdef _WIN32
#include <dbt.h>
#endif // _WIN32
namespace Slic3r {
namespace GUI {
@ -104,6 +108,31 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
update_title();
// declare events
Bind(wxEVT_CREATE, [this](wxWindowCreateEvent& event) {
#ifdef _WIN32
//static GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED };
//static GUID GUID_DEVINTERFACE_DISK = { 0x53f56307, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b };
//static GUID GUID_DEVINTERFACE_VOLUME = { 0x71a27cdd, 0x812a, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f };
static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 };
// Register USB HID (Human Interface Devices) notifications to trigger the 3DConnexion enumeration.
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter = { 0 };
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_HID;
m_hDeviceNotify = ::RegisterDeviceNotification(this->GetHWND(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
// or register for file handle change?
// DEV_BROADCAST_HANDLE NotificationFilter = { 0 };
// NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
// NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
#endif // _WIN32
// propagate event
event.Skip();
});
Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event) {
if (event.CanVeto() && !wxGetApp().check_unsaved_changes()) {
event.Veto();
@ -131,6 +160,11 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
// Called when closing the application and when switching the application language.
void MainFrame::shutdown()
{
#ifdef _WIN32
::UnregisterDeviceNotification(HDEVNOTIFY(m_hDeviceNotify));
m_hDeviceNotify = nullptr;
#endif // _WIN32
if (m_plater)
m_plater->stop_jobs();

View file

@ -141,6 +141,10 @@ public:
wxNotebook* m_tabpanel { nullptr };
wxProgressDialog* m_progress_dialog { nullptr };
std::shared_ptr<ProgressStatusBar> m_statusbar;
#ifdef _WIN32
void* m_hDeviceNotify { nullptr };
#endif // _WIN32
};
} // GUI

View file

@ -99,6 +99,25 @@ void Mouse3DController::State::append_button(unsigned int id, size_t /* input_qu
}
#ifdef WIN32
// Called by Win32 HID enumeration callback.
void Mouse3DController::device_attached(const std::string &device)
{
int vid = 0;
int pid = 0;
if (sscanf(device.c_str(), "\\\\?\\HID#VID_%x&PID_%x&", &vid, &pid) == 2) {
// BOOST_LOG_TRIVIAL(trace) << boost::format("Mouse3DController::device_attached(VID_%04xxPID_%04x)") % vid % pid;
// BOOST_LOG_TRIVIAL(trace) << "Mouse3DController::device_attached: " << device;
if (std::find(_3DCONNEXION_VENDORS.begin(), _3DCONNEXION_VENDORS.end(), vid) != _3DCONNEXION_VENDORS.end()) {
// Signal the worker thread to wake up and enumerate HID devices, if not connected at the moment.
// The message may come multiple times per each USB device. For example, some USB wireless dongles register as multiple HID sockets
// for multiple devices to connect to.
// Never mind, enumeration will be performed until connected.
m_wakeup = true;
m_stop_condition.notify_all();
}
}
}
// Filter out mouse scroll events produced by the 3DConnexion driver.
bool Mouse3DController::State::process_mouse_wheel()
{
@ -131,14 +150,16 @@ bool Mouse3DController::State::apply(const Mouse3DController::Params &params, Ca
for (const QueueItem &input_queue_item : input_queue) {
if (input_queue_item.is_translation()) {
const Vec3d& translation = input_queue_item.vector;
double zoom_factor = camera.min_zoom() / camera.get_zoom();
Vec3d translation = params.swap_yz ? Vec3d(input_queue_item.vector.x(), - input_queue_item.vector.z(), input_queue_item.vector.y()) : input_queue_item.vector;
double zoom_factor = camera.min_zoom() / camera.get_zoom();
camera.set_target(camera.get_target() + zoom_factor * params.translation.scale * (translation.x() * camera.get_dir_right() + translation.z() * camera.get_dir_up()));
if (translation.y() != 0.0)
camera.update_zoom(params.zoom.scale * translation.y());
} else if (input_queue_item.is_rotation()) {
Vec3d rot = params.rotation.scale * input_queue_item.vector * (PI / 180.);
camera.rotate_local_around_target(Vec3d(rot.x(), - rot.z(), rot.y()));
Vec3d rot = params.rotation.scale * input_queue_item.vector * (PI / 180.);
if (params.swap_yz)
rot = Vec3d(rot.x(), -rot.z(), rot.y());
camera.rotate_local_around_target(Vec3d(rot.x(), - rot.z(), rot.y()));
break;
} else {
assert(input_queue_item.is_buttons());
@ -166,19 +187,22 @@ void Mouse3DController::load_config(const AppConfig &appconfig)
double translation_deadzone = Params::DefaultTranslationDeadzone;
float rotation_deadzone = Params::DefaultRotationDeadzone;
double zoom_speed = 2.0;
appconfig.get_mouse_device_translation_speed(device_name, translation_speed);
bool swap_yz = false;
appconfig.get_mouse_device_translation_speed(device_name, translation_speed);
appconfig.get_mouse_device_translation_deadzone(device_name, translation_deadzone);
appconfig.get_mouse_device_rotation_speed(device_name, rotation_speed);
appconfig.get_mouse_device_rotation_deadzone(device_name, rotation_deadzone);
appconfig.get_mouse_device_zoom_speed(device_name, zoom_speed);
// clamp to valid values
appconfig.get_mouse_device_swap_yz(device_name, swap_yz);
// clamp to valid values
Params params;
params.translation.scale = Params::DefaultTranslationScale * std::clamp(translation_speed, 0.1, 10.0);
params.translation.deadzone = std::clamp(translation_deadzone, 0.0, Params::MaxTranslationDeadzone);
params.rotation.scale = Params::DefaultRotationScale * std::clamp(rotation_speed, 0.1f, 10.0f);
params.rotation.deadzone = std::clamp(rotation_deadzone, 0.0f, Params::MaxRotationDeadzone);
params.zoom.scale = Params::DefaultZoomScale * std::clamp(zoom_speed, 0.1, 10.0);
m_params_by_device[device_name] = std::move(params);
params.swap_yz = swap_yz;
m_params_by_device[device_name] = std::move(params);
}
}
@ -191,9 +215,9 @@ void Mouse3DController::save_config(AppConfig &appconfig) const
const std::string &device_name = key_value_pair.first;
const Params &params = key_value_pair.second;
// Store current device parameters into the config
appconfig.set_mouse_device(device_name, params.translation.scale / Params::DefaultTranslationScale, params.translation.deadzone,
params.rotation.scale / Params::DefaultRotationScale, params.rotation.deadzone, params.zoom.scale / Params::DefaultZoomScale);
}
appconfig.set_mouse_device(device_name, params.translation.scale / Params::DefaultTranslationScale, params.translation.deadzone,
params.rotation.scale / Params::DefaultRotationScale, params.rotation.deadzone, params.zoom.scale / Params::DefaultZoomScale, params.swap_yz);
}
}
bool Mouse3DController::apply(Camera& camera)
@ -296,6 +320,17 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
params_changed = true;
}
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Options:")));
ImGui::PopStyleColor();
bool swap_yz = params_copy.swap_yz;
if (imgui.checkbox("Swap Y/Z axes", swap_yz)) {
params_copy.swap_yz = swap_yz;
params_changed = true;
}
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
ImGui::Separator();
ImGui::Separator();
@ -388,9 +423,13 @@ void Mouse3DController::disconnected()
m_params_by_device[m_device_str] = m_params_ui;
m_device_str.clear();
m_connected = false;
wxGetApp().plater()->get_camera().recover_from_free_camera();
wxGetApp().plater()->set_current_canvas_as_dirty();
wxWakeUpIdle();
wxGetApp().plater()->CallAfter([]() {
Plater *plater = wxGetApp().plater();
if (plater != nullptr) {
plater->get_camera().recover_from_free_camera();
plater->set_current_canvas_as_dirty();
}
});
}
}
@ -473,10 +512,24 @@ void Mouse3DController::run()
int res = hid_init();
if (res != 0) {
// Give up.
BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library";
#if defined(__unix__) || defined(__unix) || defined(unix)
if (res == -1)
// Hopefully this error code comes from our bundled patched hidapi. In that case, -1 is returned by hid_wrapper_udev_init() and it mean
BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library: failed to load libudev.so.1 or libudev.so.0";
else if (res == -2)
// Hopefully this error code comes from our bundled patched hidapi. In that case, -2 is returned by hid_wrapper_udev_init() and it mean
BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library: failed to resolve some function from libudev.so.1 or libudev.so.0";
else
#endif // unixes
BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library";
return;
}
#ifdef _WIN32
// Enumerate once just after thread start.
m_wakeup = true;
#endif // _WIN32
for (;;) {
{
tbb::mutex::scoped_lock lock(m_params_ui_mutex);
@ -509,7 +562,13 @@ bool Mouse3DController::connect_device()
{
// Wait for 2 seconds, but cancellable by m_stop.
std::unique_lock<std::mutex> lock(m_stop_condition_mutex);
m_stop_condition.wait_for(lock, std::chrono::seconds(2), [this]{ return this->m_stop; });
#ifdef _WIN32
// Wait indifinetely for the stop signal.
m_stop_condition.wait(lock, [this]{ return m_stop || m_wakeup; });
m_wakeup = false;
#else
m_stop_condition.wait_for(lock, std::chrono::seconds(2), [this]{ return m_stop; });
#endif
}
if (m_stop)
@ -519,10 +578,14 @@ bool Mouse3DController::connect_device()
hid_device_info* devices = hid_enumerate(0, 0);
if (devices == nullptr)
{
BOOST_LOG_TRIVIAL(error) << "Unable to enumerate HID devices";
BOOST_LOG_TRIVIAL(trace) << "Mouse3DController::connect_device() - no HID device enumerated.";
return false;
}
#ifdef _WIN32
BOOST_LOG_TRIVIAL(trace) << "Mouse3DController::connect_device() - enumerating HID devices.";
#endif // _WIN32
// Searches for 1st connected 3Dconnexion device
struct DeviceData
{
@ -776,9 +839,17 @@ void Mouse3DController::disconnect_device()
}
m_device_str.clear();
m_connected = false;
wxGetApp().plater()->get_camera().recover_from_free_camera();
wxGetApp().plater()->set_current_canvas_as_dirty();
wxWakeUpIdle();
#ifdef _WIN32
// Enumerate once immediately after disconnect.
m_wakeup = true;
#endif // _WIN32
wxGetApp().plater()->CallAfter([]() {
Plater *plater = wxGetApp().plater();
if (plater != nullptr) {
plater->get_camera().recover_from_free_camera();
plater->set_current_canvas_as_dirty();
}
});
}
}

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